Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 
 
 

7346 řádky
243 KiB

  1. #include "plsr.h"
  2. #include "plsr_internal.h"
  3. #include "plsr_planner.h"
  4. #include "plsr_platform.h"
  5. #include <stddef.h>
  6. #include <string.h>
  7. #if defined(__ICCARM__)
  8. #include <intrinsics.h>
  9. #endif
  10. #define PLSR_COMMON_FIRST_ADDRESS (0x1000U)
  11. #define PLSR_COMMON_LAST_ADDRESS (0x10FFU)
  12. #define PLSR_SEGMENT_FIRST_ADDRESS (0x1100U)
  13. #define PLSR_SEGMENT_STRIDE (0x0010U)
  14. #define PLSR_SEGMENT_DEFINED_WORDS (8U)
  15. #define PLSR_WAIT_TIME (0U)
  16. #define PLSR_WAIT_SIGNAL (1U)
  17. #define PLSR_ACT_TIME (2U)
  18. #define PLSR_EXT_SIGNAL (3U)
  19. #define PLSR_EXT_OR_COMPLETE (4U)
  20. #define PLSR_SEND_COMPLETE (0U)
  21. #define PLSR_SEND_SUBSEQUENT (1U)
  22. #define PLSR_POSITION_RELATIVE (0U)
  23. #define PLSR_POSITION_ABSOLUTE (1U)
  24. #define PLSR_COMMAND_START (0x0001U)
  25. #define PLSR_COMMAND_STOP (0x0002U)
  26. #define PLSR_COMMAND_CLEAR (0x0004U)
  27. #define PLSR_DIAG_FLAG_MONITORING (0x0001U)
  28. #define PLSR_DIAG_FLAG_COUNT_CHECKED (0x0002U)
  29. #define PLSR_DIAG_FLAG_COUNT_PASS (0x0004U)
  30. #define PLSR_DIAG_FLAG_FREQUENCY_CHECKED (0x0008U)
  31. #define PLSR_DIAG_FLAG_FREQUENCY_PASS (0x0010U)
  32. #define PLSR_DIAG_FLAG_CURVE_CHECKED (0x0020U)
  33. #define PLSR_DIAG_FLAG_CURVE_PASS (0x0040U)
  34. #define PLSR_DIAG_FLAG_FAULT_LATCHED (0x0080U)
  35. #define PLSR_DIAG_REASON_NONE (0U)
  36. #define PLSR_DIAG_REASON_COUNT (1U)
  37. #define PLSR_DIAG_REASON_FREQUENCY (2U)
  38. #define PLSR_DIAG_REASON_CURVE (3U)
  39. #define PLSR_DIAG_REASON_INVALID_SAMPLE (4U)
  40. #define PLSR_CONFIG_SAVE_DELAY_MS (1000U)
  41. #define PLSR_POSITION_CHECKPOINT_MS (10U)
  42. #define PLSR_DIRECTION_DELAY_DEFAULT_MS (10U)
  43. #define PLSR_PROFILE_QUEUE_CAPACITY (1024U)
  44. #define PLSR_PROFILE_QUEUE_MASK (PLSR_PROFILE_QUEUE_CAPACITY - 1U)
  45. #if ((PLSR_PROFILE_QUEUE_CAPACITY == 0U) \
  46. || ((PLSR_PROFILE_QUEUE_CAPACITY \
  47. & (PLSR_PROFILE_QUEUE_CAPACITY - 1U)) != 0U) \
  48. || (PLSR_PROFILE_QUEUE_CAPACITY > 65535U))
  49. #error "PLSR profile queue capacity must be a power of two not exceeding 65535"
  50. #endif
  51. /* At the 100 kHz limit these thresholds prefill and refill toward 8 ms of
  52. queued profile data. The caller bounds each producer service pass. */
  53. #define PLSR_PROFILE_STARTUP_TARGET (800U)
  54. #define PLSR_PROFILE_STARTUP_BUDGET (800U)
  55. #define PLSR_PROFILE_REFILL_TARGET (800U)
  56. #define PLSR_PROFILE_PRODUCER_BATCH_ITEMS (16U)
  57. #define PLSR_TIMED_START_BUILD_BUDGET (32U)
  58. #define PLSR_TIMED_START_READY_ITEMS PLSR_PROFILE_STARTUP_BUDGET
  59. #define PLSR_PROFILE_LOW_WATER (100U)
  60. #define PLSR_PROFILE_LOW_WATER_CLEAR (200U)
  61. #define PLSR_UNDERRUN_HOLD_TIME_US (2000UL)
  62. #define PLSR_UNDERRUN_HOLD_MAX_PULSES (200UL)
  63. #define PLSR_HANDOFF_WARMUP_ITEMS (8U)
  64. #define PLSR_REPLAN_PREFIX_ITEMS (512U)
  65. #define PLSR_REPLAN_PREFIX_TIME_US (5000ULL)
  66. #define PLSR_REPLAN_BUILD_ITEMS (400U)
  67. /* Cap equal-frequency counted runs so an online update never waits behind an
  68. arbitrarily long steady run. At low speed one complete pulse is the limit. */
  69. #define PLSR_COUNTED_RUN_MAX_TIME_US (2000ULL)
  70. #define PLSR_BOUNDARY_EVENT_CAPACITY (2U)
  71. #if ((PLSR_BOUNDARY_EVENT_CAPACITY == 0U) \
  72. || ((PLSR_BOUNDARY_EVENT_CAPACITY \
  73. & (PLSR_BOUNDARY_EVENT_CAPACITY - 1U)) != 0U) \
  74. || (PLSR_BOUNDARY_EVENT_CAPACITY > 127U))
  75. #error "PLSR boundary event capacity must be a power of two up to 127"
  76. #endif
  77. #define PLSR_QUEUE_DIAG_LOW_WATER (0x0001U)
  78. #define PLSR_QUEUE_DIAG_UNDERRUN (0x0002U)
  79. #define PLSR_QUEUE_DIAG_PLANNER_CLIPPED (0x0004U)
  80. #define PLSR_RAMP_POLL_RESERVE_AREA_DIVISOR (20ULL)
  81. /* 功能诊断(计数/频率/曲线检查)总开关。
  82. * 0 = 全部关闭:诊断采集、结算与锁定均不执行,Modbus 诊断寄存器保持全 0,
  83. * 诊断控制字写入仍被接受(无操作)。运动核心先行跑通;曲线校准阶段再置 1。 */
  84. #define PLSR_DIAGNOSTIC_ENABLED (0U)
  85. /* 计数错误停机检查:暂时关闭。counted 流计数同步与执行器重构对齐期间,
  86. * 实际输出与预期的偏差只做数据钳制(delta=remaining),不再进 PLSR_ERROR_COUNT。 */
  87. #define PLSR_COUNT_ERROR_CHECK_ENABLED (0U)
  88. typedef struct
  89. {
  90. uint32_t fromHz;
  91. uint32_t toHz;
  92. uint32_t durationMs;
  93. uint32_t elapsedMs;
  94. uint8_t active;
  95. } PLSR_RAMP;
  96. typedef struct
  97. {
  98. PLSR_PLANNER_CONTEXT planner;
  99. PLSR_STREAM_ITEM pendingItem;
  100. uint32_t startHz;
  101. uint32_t peakHz;
  102. uint32_t endHz;
  103. uint32_t pulseCount;
  104. uint32_t entryPulses;
  105. uint32_t steadyPulses;
  106. uint32_t exitPulses;
  107. volatile uint32_t nextPeriod;
  108. uint32_t pendingRepeats;
  109. uint32_t lastRampFrequencyHz;
  110. volatile uint8_t active;
  111. } PLSR_SHORT_PROFILE;
  112. typedef struct
  113. {
  114. PLSR_PLATFORM_TIMER_SETTING setting;
  115. //这一档已经量化好的定时器参数,发波直接用
  116. uint32_t requestedFrequencyHz;
  117. //公式算出来的 Hz(量化前),给诊断/对照,硬件不拿它发波
  118. uint32_t repeatCount;
  119. //这一档连续发几个脉冲
  120. uint8_t startsNextSegment;
  121. //1 = 这项是下一段的第一拍(handoff),0 = 还在本段
  122. } PLSR_PROFILE_ENTRY;
  123. typedef struct
  124. {
  125. PLSR_PROFILE_ENTRY entries[PLSR_PROFILE_QUEUE_CAPACITY];
  126. PLSR_SHORT_PROFILE producerProfile;
  127. volatile uint32_t readIndex;
  128. volatile uint32_t writeIndex;
  129. volatile uint32_t generation;
  130. uint32_t producerEpoch;
  131. volatile uint32_t repeatRemaining;
  132. volatile uint32_t underrunDebtPulses;
  133. PLSR_PLATFORM_TIMER_SETTING lastSetting;
  134. uint8_t producerSegment;
  135. uint8_t preparedHandoffBank;
  136. volatile uint8_t haveLastSetting;
  137. volatile uint8_t active;
  138. volatile uint8_t generatorComplete;
  139. } PLSR_PROFILE_QUEUE;
  140. /* WAIT_TIME and WAIT_SIGNAL boundaries are cold starts, but their planner
  141. work is predictable while the source segment is still running or waiting.
  142. Build that next stream in the inactive queue bank and publish it only after
  143. the startup horizon is ready. The release path then has no planner loop. */
  144. typedef struct
  145. {
  146. PLSR_PROFILE_ENTRY firstRun;
  147. uint64_t magnitude;
  148. int64_t resolvedDisplacement;
  149. uint32_t sourceEpoch;
  150. uint32_t queueGeneration;
  151. uint16_t generatedItems;
  152. uint8_t sourceSegment;
  153. uint8_t nextSegment;
  154. uint8_t positive;
  155. uint8_t directionLevel;
  156. uint8_t directionChanged;
  157. uint8_t queueBank;
  158. uint8_t nextActTimedCut;
  159. volatile uint8_t building;
  160. volatile uint8_t valid;
  161. volatile uint8_t pendingActivation;
  162. } PLSR_TIMED_START;
  163. typedef struct
  164. {
  165. uint64_t magnitude;
  166. uint64_t commandMagnitude;
  167. uint32_t firstFrequencyHz;
  168. uint32_t secondFrequencyHz;
  169. uint32_t firstRequestedFrequencyHz;
  170. uint32_t secondRequestedFrequencyHz;
  171. uint32_t firstRepeatCount;
  172. uint32_t secondRepeatCount;
  173. PLSR_PLATFORM_TIMER_SETTING firstSetting;
  174. PLSR_PLATFORM_TIMER_SETTING secondSetting;
  175. PLSR_PROFILE_ENTRY warmup[PLSR_HANDOFF_WARMUP_ITEMS];
  176. PLSR_SHORT_PROFILE profile;
  177. uint8_t warmupCount;
  178. uint8_t nextSegment;
  179. uint8_t positive;
  180. uint8_t nextActTimedCut;
  181. volatile uint8_t valid;
  182. } PLSR_HANDOFF_PLAN;
  183. typedef struct
  184. {
  185. uint64_t magnitude;
  186. uint64_t commandMagnitude;
  187. uint32_t firstFrequencyHz;
  188. uint32_t completedPulses;
  189. uint8_t nextSegment;
  190. uint8_t positive;
  191. uint8_t nextActTimedCut;
  192. } PLSR_COUNTED_BOUNDARY_EVENT;
  193. typedef enum
  194. {
  195. PLSR_WORD_OK = 0,
  196. PLSR_WORD_ILLEGAL_ADDRESS,
  197. PLSR_WORD_ILLEGAL_VALUE
  198. } PLSR_WORD_RESULT;
  199. typedef enum
  200. {
  201. PLSR_COMMAND_MAILBOX_EMPTY = 0,
  202. PLSR_COMMAND_MAILBOX_PENDING,
  203. PLSR_COMMAND_MAILBOX_EXECUTING
  204. } PLSR_COMMAND_MAILBOX_STATE;
  205. typedef enum
  206. {
  207. PLSR_SEGMENT_ENTRY_COMMAND_START = 0,
  208. PLSR_SEGMENT_ENTRY_INTERNAL_RESTART,
  209. PLSR_SEGMENT_ENTRY_CARRY
  210. } PLSR_SEGMENT_ENTRY;
  211. typedef struct
  212. {
  213. PLSR_CONFIG startConfig;
  214. uint16_t command;
  215. volatile uint8_t state;
  216. } PLSR_COMMAND_MAILBOX;
  217. typedef struct
  218. {
  219. volatile PLSR_EXEC_MODE mode;
  220. volatile uint32_t generation;
  221. } PLSR_EXECUTOR;
  222. typedef struct
  223. {
  224. uint16_t flags;
  225. uint16_t reason;
  226. uint16_t lastSegment;
  227. uint16_t modeDirection;
  228. uint32_t expectedCycles;
  229. uint32_t observedCycles;
  230. int32_t countError;
  231. uint32_t requestedHz;
  232. uint32_t expectedTimerHz;
  233. uint32_t activeTimerHz;
  234. int32_t requestErrorHz;
  235. uint32_t curveSampleCount;
  236. uint32_t curveMismatchCount;
  237. uint32_t curveMaxAbsErrorHz;
  238. uint32_t firstMismatchSample;
  239. } PLSR_DIAGNOSTIC;
  240. static const uint16_t PlsrSineProgressQ16[65] =
  241. {
  242. 0U, 39U, 158U, 355U, 630U, 982U, 1411U, 1915U,
  243. 2494U, 3146U, 3869U, 4662U, 5522U, 6448U, 7438U, 8488U,
  244. 9597U, 10762U, 11980U, 13248U, 14563U, 15922U, 17321U,
  245. 18758U, 20228U, 21728U, 23256U, 24806U, 26375U, 27960U,
  246. 29556U, 31160U, 32767U, 34375U, 35979U, 37575U, 39160U,
  247. 40729U, 42279U, 43807U, 45307U, 46777U, 48214U, 49613U,
  248. 50972U, 52287U, 53555U, 54773U, 55938U, 57047U, 58097U,
  249. 59087U, 60013U, 60873U, 61666U, 62389U, 63041U, 63620U,
  250. 64124U, 64553U, 64905U, 65180U, 65377U, 65496U, 65535U
  251. };
  252. static PLSR_CONFIG PlsrShadowConfig;
  253. static PLSR_CONFIG PlsrActiveConfig;
  254. static PLSR_CONFIG PlsrCandidateConfig;
  255. static volatile int32_t PlsrPosition;
  256. static volatile uint64_t PlsrRemainingPulses;
  257. /* Full configured displacement still available in the active segment. ACT
  258. may publish a shorter execution profile without discarding this ceiling. */
  259. static volatile uint64_t PlsrCommandRemainingPulses;
  260. static volatile uint8_t PlsrPulseActive;
  261. static volatile uint8_t PlsrCutRequested;
  262. static volatile uint8_t PlsrActTimedCutPlanned;
  263. static volatile uint8_t PlsrBoundaryPending;
  264. static volatile uint8_t PlsrBoundaryWasCut;
  265. static volatile uint8_t PlsrCountPositive;
  266. static volatile uint8_t PlsrCountOverflowPending;
  267. static volatile uint8_t PlsrPositionValid;
  268. static volatile uint8_t PlsrPositionCheckpointDirty;
  269. static volatile uint8_t PlsrFrequencyUpdatePending;
  270. static volatile uint8_t PlsrFrequencyUpdateSegment;
  271. static volatile uint8_t PlsrSeamlessHandoffPending;
  272. static volatile uint8_t PlsrTimerErrorPending;
  273. static volatile uint8_t PlsrDeferredFrequencyPending;
  274. static volatile uint32_t PlsrCurrentFrequencyHz;
  275. static volatile uint32_t PlsrQueuedFrequencyHz;
  276. static volatile uint32_t PlsrBoundaryFrequencyHz;
  277. static volatile uint32_t PlsrFrequencyUpdateTargetHz;
  278. static volatile uint32_t PlsrDeferredFrequencyHz;
  279. static volatile uint32_t PlsrSegmentEpoch;
  280. static PLSR_SEGMENT_ENTRY PlsrDelayedEntryType;
  281. static uint8_t PlsrPulseDirMotionStarted;
  282. static volatile PLSR_STATUS PlsrRunStatus = PLSR_STATUS_UNINITIALIZED;
  283. static PLSR_ERROR PlsrError = PLSR_ERROR_NONE;
  284. static PLSR_RAMP PlsrRamp;
  285. static PLSR_SHORT_PROFILE PlsrShortProfile;
  286. static PLSR_PROFILE_QUEUE PlsrProfileQueues[2];
  287. static volatile uint8_t PlsrProfileQueueBank;
  288. #define PlsrProfileQueue (PlsrProfileQueues[PlsrProfileQueueBank])
  289. static PLSR_TIMED_START PlsrTimedStart;
  290. static PLSR_HANDOFF_PLAN PlsrHandoffPlan;
  291. static volatile uint64_t PlsrCountedObservedPublished;
  292. static volatile uint8_t PlsrCountedHandoffStaged;
  293. /* 段边界/流故障事件:IRQ 只置事件并快照(handoff 计划 + 边界累计计数),
  294. 全部簿记由 1ms 任务消费事件时完成(IRQ 内不做状态转换与错误标志写入)。 */
  295. static PLSR_COUNTED_BOUNDARY_EVENT
  296. PlsrCountedBoundaryEvents[PLSR_BOUNDARY_EVENT_CAPACITY];
  297. static volatile uint8_t PlsrCountedBoundaryWriteIndex;
  298. static volatile uint8_t PlsrCountedBoundaryReadIndex;
  299. static volatile uint8_t PlsrCountedBoundaryBusy;
  300. static volatile uint8_t PlsrCountedFaultEvent;
  301. static PLSR_HANDOFF_PLAN
  302. PlsrPreparedHandoffPlans[2][PLSR_SEGMENT_COUNT_MAX];
  303. static volatile uint8_t PlsrPreparedHandoffBank;
  304. #ifdef PLSR_HOST_TEST
  305. static uint32_t PlsrHostTestEventSequence;
  306. static uint32_t PlsrHostTestLastGateEvent;
  307. static uint32_t PlsrHostTestLastDiagnosticFinishEvent;
  308. #endif
  309. static uint8_t PlsrInitialized;
  310. static volatile uint8_t PlsrCurrentSegment;
  311. static uint8_t PlsrDirectionDelayActive;
  312. static uint16_t PlsrDirectionDelayRemainingMs;
  313. static uint8_t PlsrInitialDirectionPreparePending;
  314. static uint8_t PlsrInitialDirectionPrepareLevel;
  315. static uint32_t PlsrInitialDirectionPrepareEpoch;
  316. static volatile uint8_t PlsrSegmentClockStarted;
  317. static volatile uint32_t PlsrSegmentElapsedMs;
  318. static volatile uint32_t PlsrWaitElapsedMs;
  319. static volatile uint8_t PlsrExtPreviousLevel;
  320. static volatile uint8_t PlsrExtEdgePending;
  321. static volatile uint8_t PlsrExtEdgePendingSegment;
  322. static volatile uint32_t PlsrExtEdgePendingEpoch;
  323. static volatile uint8_t PlsrExtCaptureSegment;
  324. static volatile uint32_t PlsrExtCaptureEpoch;
  325. static volatile uint8_t PlsrWaitSignalArmedMask;
  326. static volatile uint8_t PlsrWaitSignalPendingMask;
  327. static volatile uint8_t PlsrStopRequested;
  328. static volatile uint8_t PlsrStopPulsesRemaining;
  329. static volatile uint8_t PlsrAbStopArmed;
  330. static volatile uint8_t PlsrBoundaryRampStarted;
  331. static uint8_t PlsrLastDirectionValid;
  332. static uint8_t PlsrLastDirectionOutput;
  333. static uint8_t PlsrLastDirectionLevel;
  334. static uint8_t PlsrPersistenceDirty;
  335. static uint16_t PlsrPersistenceDelayMs;
  336. static uint8_t PlsrPositionCheckpointElapsedMs;
  337. static PLSR_COMMAND_MAILBOX PlsrCommandMailbox;
  338. static PLSR_EXECUTOR PlsrExecutor;
  339. static volatile PLSR_DIAGNOSTIC PlsrDiagnostic;
  340. static volatile uint64_t PlsrDiagnosticSegmentCounterBase;
  341. static volatile uint32_t PlsrDiagnosticQueuedExpectedHz;
  342. static volatile uint16_t PlsrDiagnosticFailedChecks;
  343. static volatile uint16_t PlsrProfileQueueMinimumDepth;
  344. static volatile uint16_t PlsrProfileQueueDiagnosticFlags;
  345. static volatile uint8_t PlsrProfileQueueLowWaterLatched;
  346. static volatile uint32_t PlsrProfileQueueLowWaterEvents;
  347. static volatile uint32_t PlsrProfileQueueUnderruns;
  348. static volatile uint32_t PlsrPlannerClippedCount;
  349. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0)
  350. volatile uint32_t PlsrProfileProducerItemCount;
  351. volatile uint32_t PlsrProfileProducerTotalCycles;
  352. volatile uint32_t PlsrProfileProducerMaxItemCycles;
  353. #endif
  354. static uint8_t PlsrIsBusy(void);
  355. static void PlsrSetDefaults(PLSR_CONFIG *config);
  356. static uint8_t PlsrConfigIsValid(const PLSR_CONFIG *config,
  357. uint8_t validateActivePath);
  358. static uint32_t PlsrResolvedSegmentFrequency(const PLSR_CONFIG *config,
  359. uint8_t segmentIndex);
  360. static uint16_t PlsrReadConfigWord(const PLSR_CONFIG *config,
  361. uint16_t address);
  362. static PLSR_WORD_RESULT PlsrWriteConfigWord(PLSR_CONFIG *config,
  363. uint16_t address,
  364. uint16_t value);
  365. static uint8_t PlsrAddressIsDwordHalf(uint16_t address,
  366. uint16_t *pairedAddress);
  367. static PLSR_MB_RESULT PlsrQueueCommand(uint16_t command);
  368. static uint8_t PlsrPollCommandMailbox(void);
  369. static void PlsrExecuteStart(void);
  370. static uint8_t PlsrExecuteStop(void);
  371. static void PlsrExecuteClear(void);
  372. static uint8_t PlsrStartSegment(uint8_t segmentNumber,
  373. PLSR_SEGMENT_ENTRY entryType,
  374. uint32_t carryFrequencyHz);
  375. static uint32_t PlsrEffectiveStartFrequency(uint32_t segmentFrequencyHz,
  376. uint8_t allowCarry,
  377. uint8_t directionChanged,
  378. uint32_t carryFrequencyHz);
  379. static uint32_t PlsrPulseDirStartFrequency(
  380. uint32_t segmentFrequencyHz,
  381. PLSR_SEGMENT_ENTRY entryType,
  382. uint8_t directionChanged,
  383. uint32_t carryFrequencyHz);
  384. static uint32_t PlsrEffectiveStopFrequency(uint32_t segmentFrequencyHz);
  385. static uint8_t PlsrBeginSegmentOutput(uint32_t startFrequencyHz);
  386. static uint8_t PlsrServiceInitialDirectionPrepare(void);
  387. static void PlsrHandleBoundary(uint8_t extEdge);
  388. static void PlsrTransitionToNext(uint8_t allowCarry);
  389. static void PlsrRequestCut(uint32_t expectedEpoch);
  390. static void PlsrFinishCompleted(void);
  391. static void PlsrFinishStopped(void);
  392. static void PlsrEnterError(PLSR_ERROR error);
  393. static void PlsrEnterErrorIfEpoch(PLSR_ERROR error,
  394. uint32_t expectedEpoch);
  395. static void PlsrMarkPersistenceDirty(uint16_t delayMs);
  396. static void PlsrCheckpointPosition(uint8_t wasBusy);
  397. static void PlsrPollPositionCheckpoint(void);
  398. static void PlsrArmWaitSignal(uint8_t inputSelection);
  399. static void PlsrDisarmWaitSignal(void);
  400. static uint8_t PlsrWaitSignalDetected(uint8_t inputSelection);
  401. static PLSR_PLATFORM_QUEUE_RESULT PlsrTryContinuousHandoff(void);
  402. static uint8_t PlsrPrepareShortProfile(PLSR_SHORT_PROFILE *profile,
  403. const PLSR_CONFIG *frequencyConfig,
  404. uint8_t segmentNumber,
  405. uint32_t startFrequencyHz,
  406. uint32_t targetFrequencyHz,
  407. uint64_t pulseCount,
  408. uint8_t currentPositive,
  409. uint8_t forceTerminalExit);
  410. static uint8_t PlsrShortProfileTakeRun(PLSR_SHORT_PROFILE *profile,
  411. PLSR_PROFILE_ENTRY *entry);
  412. static uint8_t PlsrShortProfileTakeRunLimited(
  413. PLSR_SHORT_PROFILE *profile,
  414. PLSR_PROFILE_ENTRY *entry,
  415. uint32_t maximumRepeats);
  416. static uint32_t PlsrProfileRunLimit(uint32_t frequencyHz);
  417. static uint8_t PlsrLimitProfileToActTime(
  418. PLSR_SHORT_PROFILE *profile,
  419. uint16_t actTimeMs,
  420. uint8_t *timedCutPlanned);
  421. static uint8_t PlsrLimitProfileToActTimeUs(
  422. PLSR_SHORT_PROFILE *profile,
  423. uint32_t actTimeUs,
  424. uint8_t *timedCutPlanned);
  425. static void PlsrProfileRecordPlannerStatus(
  426. const PLSR_SHORT_PROFILE *profile);
  427. static uint8_t PlsrApplyCountedProgressSnapshot(
  428. uint64_t observed,
  429. uint64_t *appliedPulses);
  430. static PLSR_PLATFORM_SERVICE_RESULT PlsrReplanPulseDir(
  431. uint32_t targetHz,
  432. uint32_t totalPulses,
  433. uint8_t forceTerminalExit);
  434. static void PlsrProfileQueueReset(void);
  435. static void PlsrProfileQueueResetBankLocked(uint8_t bank);
  436. static void PlsrInvalidateTimedStartLocked(void);
  437. static void PlsrServiceTimedStartPreparation(void);
  438. static PLSR_PLATFORM_SERVICE_RESULT PlsrTryStartPreparedTimedSegment(
  439. uint8_t segmentNumber,
  440. int64_t resolvedDisplacement);
  441. static uint8_t PlsrStartPreparedTimedOutput(void);
  442. static void PlsrProfileQueueInvalidateGeneration(void);
  443. static uint8_t PlsrProfileQueueBegin(
  444. const PLSR_SHORT_PROFILE *producerProfile,
  445. uint32_t producerEpoch,
  446. uint8_t producerSegment,
  447. uint8_t preparedHandoffBank);
  448. static uint8_t PlsrProfileQueueFill(uint16_t targetCount,
  449. uint16_t *itemBudget);
  450. static uint8_t PlsrTimerSettingsEqual(
  451. const PLSR_PLATFORM_TIMER_SETTING *first,
  452. const PLSR_PLATFORM_TIMER_SETTING *second);
  453. static uint8_t PlsrProfileEntryTryMerge(
  454. PLSR_PROFILE_ENTRY *previous,
  455. const PLSR_PROFILE_ENTRY *entry);
  456. static uint8_t PlsrProfileQueueAppendLocked(
  457. PLSR_PROFILE_QUEUE *queue,
  458. const PLSR_PROFILE_ENTRY *entry);
  459. static uint8_t PlsrStageCountedHandoff(void);
  460. static PLSR_PLATFORM_QUEUE_RESULT PlsrProfileQueueCommitNext(
  461. uint8_t pulseOutput);
  462. static uint8_t PlsrPrepareFutureHandoffQueue(void);
  463. static void PlsrActivateHandoffQueueFromIrq(
  464. const PLSR_HANDOFF_PLAN *plan,
  465. uint32_t producerEpoch);
  466. static void PlsrCopyShortProfile(PLSR_SHORT_PROFILE *destination,
  467. const PLSR_SHORT_PROFILE *source);
  468. static void PlsrInvalidateHandoffPlans(void);
  469. static uint8_t PlsrBuildHandoffPlanBank(
  470. const PLSR_CONFIG *frequencyConfig);
  471. static uint8_t PlsrSelectPreparedHandoffPlan(PLSR_HANDOFF_PLAN *plan);
  472. static PLSR_PLATFORM_QUEUE_RESULT PlsrPrimeHandoff(void);
  473. static uint8_t PlsrBuildHandoffPlan(uint8_t sourceSegment,
  474. const PLSR_CONFIG *frequencyConfig,
  475. uint32_t carryFrequencyHz,
  476. PLSR_HANDOFF_PLAN *plan);
  477. static void PlsrRefreshCurrentHandoffPlan(uint32_t terminalFrequencyHz);
  478. static void PlsrDiagnosticReset(void);
  479. static void PlsrDiagnosticBeginSegment(uint8_t segmentNumber,
  480. uint64_t expectedCycles,
  481. uint8_t directionPositive);
  482. static void PlsrDiagnosticFinishSegment(uint8_t completedNormally);
  483. static uint8_t PlsrDiagnosticStartPulse(uint8_t pulseOutput,
  484. uint32_t requestedFirstHz,
  485. uint32_t requestedQueuedHz,
  486. uint32_t *actualFirstHz,
  487. uint32_t *actualQueuedHz);
  488. static PLSR_PLATFORM_QUEUE_RESULT PlsrDiagnosticQueueFrequency(
  489. uint8_t pulseOutput,
  490. uint32_t requestedHz,
  491. uint32_t *actualHz);
  492. static void PlsrDiagnosticCheckActiveFrequency(uint32_t activeHz);
  493. static uint8_t PlsrArmFinalAbBoundaryLocked(void);
  494. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  495. && !defined(PLSR_HOST_TEST)
  496. static uint32_t PlsrProfileTimingNow(void);
  497. #endif
  498. static uint8_t PlsrQueueFinalAbBoundaryFromIrq(void);
  499. static uint8_t PlsrIsBusy(void)
  500. {
  501. return ((PlsrRunStatus == PLSR_STATUS_ACCELERATING)
  502. || (PlsrRunStatus == PLSR_STATUS_RUNNING)
  503. || (PlsrRunStatus == PLSR_STATUS_DECELERATING)
  504. || (PlsrRunStatus == PLSR_STATUS_WAITING)
  505. || (PlsrRunStatus == PLSR_STATUS_PAUSED)) ? 1U : 0U;
  506. }
  507. static uint32_t PlsrJoinU32(uint16_t lowWord, uint16_t highWord)
  508. {
  509. return (uint32_t)lowWord | ((uint32_t)highWord << 16U);
  510. }
  511. static uint16_t PlsrLowWord(uint32_t value)
  512. {
  513. return (uint16_t)(value & 0xFFFFUL);
  514. }
  515. static uint16_t PlsrHighWord(uint32_t value)
  516. {
  517. return (uint16_t)(value >> 16U);
  518. }
  519. static uint8_t PlsrFinalAbBoundaryRequired(void)
  520. {
  521. uint8_t finalBoundary;
  522. if (PlsrActiveConfig.outputMode != PLSR_OUTPUT_AB)
  523. {
  524. return 0U;
  525. }
  526. finalBoundary = ((PlsrCutRequested != 0U)
  527. || ((PlsrStopRequested != 0U)
  528. && (PlsrStopPulsesRemaining == 1U))
  529. || ((PlsrRemainingPulses == 1UL)
  530. && (PlsrHandoffPlan.valid == 0U))) ? 1U : 0U;
  531. return ((PlsrPulseActive != 0U) && (finalBoundary != 0U)) ? 1U : 0U;
  532. }
  533. static uint8_t PlsrCompleteFinalAbArmLocked(void)
  534. {
  535. PLSR_PLATFORM_STOP_RESULT result;
  536. uint8_t pulseOutput = (uint8_t)PlsrActiveConfig.pulseOutput;
  537. result = PlsrPlatformRequestStopLocked(pulseOutput, 1U);
  538. if (result == PLSR_PLATFORM_STOP_PENDING)
  539. {
  540. PlsrQueuedFrequencyHz = PlsrCurrentFrequencyHz;
  541. PlsrDiagnosticQueuedExpectedHz = PlsrCurrentFrequencyHz;
  542. PlsrDeferredFrequencyHz = PlsrCurrentFrequencyHz;
  543. PlsrDeferredFrequencyPending = 0U;
  544. PlsrFrequencyUpdatePending = 0U;
  545. PlsrShortProfile.active = 0U;
  546. PlsrHandoffPlan.valid = 0U;
  547. PlsrRamp.active = 0U;
  548. return 1U;
  549. }
  550. PlsrTimerErrorPending = 1U;
  551. PlsrPlatformStopPulse(pulseOutput);
  552. PlsrAbStopArmed = 0U;
  553. PlsrPulseActive = 0U;
  554. PlsrBoundaryFrequencyHz = PlsrCurrentFrequencyHz;
  555. PlsrBoundaryWasCut = (PlsrCutRequested != 0U) ? 1U : 0U;
  556. PlsrCutRequested = 0U;
  557. PlsrCurrentFrequencyHz = 0UL;
  558. PlsrQueuedFrequencyHz = 0UL;
  559. PlsrBoundaryPending = 1U;
  560. return 0U;
  561. }
  562. static uint8_t PlsrArmFinalAbBoundaryLocked(void)
  563. {
  564. if (PlsrFinalAbBoundaryRequired() == 0U)
  565. {
  566. return 1U;
  567. }
  568. if (PlsrAbStopArmed != 0U)
  569. {
  570. return 1U;
  571. }
  572. PlsrAbStopArmed = 1U;
  573. return PlsrCompleteFinalAbArmLocked();
  574. }
  575. static uint8_t PlsrQueueFinalAbBoundaryFromIrq(void)
  576. {
  577. uint32_t criticalState;
  578. if ((PlsrFinalAbBoundaryRequired() == 0U)
  579. || (PlsrAbStopArmed != 0U))
  580. {
  581. return 1U;
  582. }
  583. PlsrAbStopArmed = 1U;
  584. if (PlsrPlatformQueueFinalArmFromIrq(
  585. (uint8_t)PlsrActiveConfig.pulseOutput) != 0U)
  586. {
  587. return 1U;
  588. }
  589. criticalState = PlsrPlatformEnterCritical();
  590. if ((PlsrAbStopArmed == 0U)
  591. || (PlsrFinalAbBoundaryRequired() == 0U))
  592. {
  593. PlsrPlatformExitCritical(criticalState);
  594. return 1U;
  595. }
  596. {
  597. uint8_t result = PlsrCompleteFinalAbArmLocked();
  598. PlsrPlatformExitCritical(criticalState);
  599. return result;
  600. }
  601. }
  602. void PlsrFinalArmJobIrq(uint8_t pulseOutput)
  603. {
  604. uint32_t criticalState = PlsrPlatformEnterCritical();
  605. if ((PlsrAbStopArmed == 0U) || (PlsrPulseActive == 0U)
  606. || (pulseOutput != (uint8_t)PlsrActiveConfig.pulseOutput)
  607. || (PlsrFinalAbBoundaryRequired() == 0U))
  608. {
  609. if ((PlsrPulseActive != 0U)
  610. && (pulseOutput == (uint8_t)PlsrActiveConfig.pulseOutput))
  611. {
  612. PlsrAbStopArmed = 0U;
  613. }
  614. PlsrPlatformExitCritical(criticalState);
  615. return;
  616. }
  617. (void)PlsrCompleteFinalAbArmLocked();
  618. PlsrPlatformExitCritical(criticalState);
  619. }
  620. #if PLSR_DIAGNOSTIC_ENABLED
  621. static uint32_t PlsrAbsDifferenceU32(uint32_t first, uint32_t second)
  622. {
  623. return (first >= second) ? (first - second) : (second - first);
  624. }
  625. static int32_t PlsrDifferenceI32(uint32_t first, uint32_t second)
  626. {
  627. int64_t difference = (int64_t)first - (int64_t)second;
  628. if (difference > INT32_MAX)
  629. {
  630. return INT32_MAX;
  631. }
  632. if (difference < INT32_MIN)
  633. {
  634. return INT32_MIN;
  635. }
  636. return (int32_t)difference;
  637. }
  638. #endif
  639. #if PLSR_DIAGNOSTIC_ENABLED
  640. static void PlsrDiagnosticLatch(uint16_t reason)
  641. {
  642. PlsrDiagnostic.flags |= PLSR_DIAG_FLAG_FAULT_LATCHED;
  643. if (PlsrDiagnostic.reason == PLSR_DIAG_REASON_NONE)
  644. {
  645. PlsrDiagnostic.reason = reason;
  646. }
  647. }
  648. #endif
  649. static void PlsrDiagnosticReset(void)
  650. {
  651. #if PLSR_DIAGNOSTIC_ENABLED
  652. (void)memset((void *)&PlsrDiagnostic, 0, sizeof(PlsrDiagnostic));
  653. PlsrDiagnostic.firstMismatchSample = 0xFFFFFFFFUL;
  654. PlsrDiagnosticSegmentCounterBase = 0UL;
  655. PlsrDiagnosticQueuedExpectedHz = 0UL;
  656. PlsrDiagnosticFailedChecks = 0U;
  657. #else
  658. /* 关闭状态保持诊断区清零,Modbus 读诊断寄存器恒为 0。 */
  659. (void)memset((void *)&PlsrDiagnostic, 0, sizeof(PlsrDiagnostic));
  660. #endif
  661. PlsrProfileQueueMinimumDepth = 0xFFFFU;
  662. PlsrProfileQueueDiagnosticFlags = 0U;
  663. PlsrProfileQueueLowWaterLatched = 0U;
  664. PlsrProfileQueueLowWaterEvents = 0UL;
  665. PlsrProfileQueueUnderruns = 0UL;
  666. PlsrPlannerClippedCount = 0UL;
  667. }
  668. static void PlsrDiagnosticBeginSegment(uint8_t segmentNumber,
  669. uint64_t expectedCycles,
  670. uint8_t directionPositive)
  671. {
  672. #if PLSR_DIAGNOSTIC_ENABLED
  673. if (expectedCycles > 0xFFFFFFFFUL)
  674. {
  675. PlsrDiagnostic.expectedCycles = 0xFFFFFFFFUL;
  676. PlsrDiagnosticLatch(PLSR_DIAG_REASON_INVALID_SAMPLE);
  677. }
  678. else
  679. {
  680. PlsrDiagnostic.expectedCycles = (uint32_t)expectedCycles;
  681. }
  682. PlsrDiagnostic.flags &= (uint16_t)~(PLSR_DIAG_FLAG_COUNT_CHECKED
  683. | PLSR_DIAG_FLAG_COUNT_PASS);
  684. PlsrDiagnostic.flags |= PLSR_DIAG_FLAG_MONITORING;
  685. PlsrDiagnostic.lastSegment = segmentNumber;
  686. PlsrDiagnostic.modeDirection =
  687. (uint16_t)(PlsrActiveConfig.outputMode
  688. | ((uint16_t)directionPositive << 8U));
  689. PlsrDiagnostic.observedCycles = 0UL;
  690. PlsrDiagnostic.countError = 0L;
  691. PlsrDiagnosticSegmentCounterBase = PlsrPlatformObservedPulses(
  692. (uint8_t)PlsrActiveConfig.pulseOutput);
  693. #else
  694. (void)segmentNumber;
  695. (void)expectedCycles;
  696. (void)directionPositive;
  697. #endif
  698. }
  699. static void PlsrDiagnosticFinishSegment(uint8_t completedNormally)
  700. {
  701. #if PLSR_DIAGNOSTIC_ENABLED
  702. uint64_t now;
  703. uint64_t observed;
  704. uint32_t observedCycles;
  705. uint32_t expectedCycles;
  706. if ((PlsrDiagnostic.flags & PLSR_DIAG_FLAG_MONITORING) == 0U)
  707. {
  708. return;
  709. }
  710. #ifdef PLSR_HOST_TEST
  711. PlsrHostTestEventSequence++;
  712. PlsrHostTestLastDiagnosticFinishEvent = PlsrHostTestEventSequence;
  713. #endif
  714. now = PlsrPlatformObservedPulses(
  715. (uint8_t)PlsrActiveConfig.pulseOutput);
  716. observed = (now >= PlsrDiagnosticSegmentCounterBase)
  717. ? (now - PlsrDiagnosticSegmentCounterBase) : 0UL;
  718. if (observed > 0xFFFFFFFFUL)
  719. {
  720. PlsrDiagnostic.observedCycles = 0xFFFFFFFFUL;
  721. PlsrDiagnosticFailedChecks |= PLSR_DIAG_FLAG_COUNT_PASS;
  722. PlsrDiagnostic.flags &= (uint16_t)~PLSR_DIAG_FLAG_COUNT_PASS;
  723. PlsrDiagnosticLatch(PLSR_DIAG_REASON_INVALID_SAMPLE);
  724. }
  725. else
  726. {
  727. PlsrDiagnostic.observedCycles = (uint32_t)observed;
  728. }
  729. PlsrDiagnostic.flags &= (uint16_t)~PLSR_DIAG_FLAG_MONITORING;
  730. if (completedNormally == 0U)
  731. {
  732. PlsrDiagnostic.countError = 0L;
  733. PlsrDiagnostic.flags &= (uint16_t)~(PLSR_DIAG_FLAG_COUNT_CHECKED
  734. | PLSR_DIAG_FLAG_COUNT_PASS);
  735. return;
  736. }
  737. observedCycles = PlsrDiagnostic.observedCycles;
  738. expectedCycles = PlsrDiagnostic.expectedCycles;
  739. PlsrDiagnostic.countError =
  740. PlsrDifferenceI32(observedCycles, expectedCycles);
  741. PlsrDiagnostic.flags |= PLSR_DIAG_FLAG_COUNT_CHECKED;
  742. if (PlsrDiagnostic.countError != 0L)
  743. {
  744. PlsrDiagnosticFailedChecks |= PLSR_DIAG_FLAG_COUNT_PASS;
  745. PlsrDiagnostic.flags &= (uint16_t)~PLSR_DIAG_FLAG_COUNT_PASS;
  746. PlsrDiagnosticLatch(PLSR_DIAG_REASON_COUNT);
  747. }
  748. else if ((PlsrDiagnosticFailedChecks & PLSR_DIAG_FLAG_COUNT_PASS) == 0U)
  749. {
  750. PlsrDiagnostic.flags |= PLSR_DIAG_FLAG_COUNT_PASS;
  751. }
  752. #else
  753. (void)completedNormally;
  754. #endif
  755. }
  756. static void PlsrDiagnosticRecordFrequency(uint32_t requestedHz,
  757. uint32_t expectedHz,
  758. uint32_t actualHz)
  759. {
  760. #if PLSR_DIAGNOSTIC_ENABLED
  761. uint32_t error = PlsrAbsDifferenceU32(actualHz, expectedHz);
  762. PlsrDiagnostic.requestedHz = requestedHz;
  763. PlsrDiagnostic.expectedTimerHz = expectedHz;
  764. PlsrDiagnostic.activeTimerHz = actualHz;
  765. /* Request error is divider quantization, not a diagnostic deviation. */
  766. PlsrDiagnostic.requestErrorHz = PlsrDifferenceI32(expectedHz, requestedHz);
  767. PlsrDiagnostic.flags |= PLSR_DIAG_FLAG_FREQUENCY_CHECKED;
  768. if (actualHz != expectedHz)
  769. {
  770. PlsrDiagnosticFailedChecks |= PLSR_DIAG_FLAG_FREQUENCY_PASS;
  771. PlsrDiagnostic.flags &= (uint16_t)~PLSR_DIAG_FLAG_FREQUENCY_PASS;
  772. PlsrDiagnosticLatch(PLSR_DIAG_REASON_FREQUENCY);
  773. }
  774. else if ((PlsrDiagnosticFailedChecks
  775. & PLSR_DIAG_FLAG_FREQUENCY_PASS) == 0U)
  776. {
  777. PlsrDiagnostic.flags |= PLSR_DIAG_FLAG_FREQUENCY_PASS;
  778. }
  779. if (error > PlsrDiagnostic.curveMaxAbsErrorHz)
  780. {
  781. PlsrDiagnostic.curveMaxAbsErrorHz = error;
  782. }
  783. #else
  784. (void)requestedHz;
  785. (void)expectedHz;
  786. (void)actualHz;
  787. #endif
  788. }
  789. #if PLSR_DIAGNOSTIC_ENABLED
  790. static void PlsrDiagnosticRecordCurveSample(uint32_t expectedHz,
  791. uint32_t actualHz)
  792. {
  793. uint32_t error = PlsrAbsDifferenceU32(expectedHz, actualHz);
  794. if (PlsrDiagnostic.curveSampleCount != 0xFFFFFFFFUL)
  795. {
  796. PlsrDiagnostic.curveSampleCount++;
  797. }
  798. PlsrDiagnostic.flags |= PLSR_DIAG_FLAG_CURVE_CHECKED;
  799. if (error == 0UL)
  800. {
  801. if ((PlsrDiagnosticFailedChecks & PLSR_DIAG_FLAG_CURVE_PASS) == 0U)
  802. {
  803. PlsrDiagnostic.flags |= PLSR_DIAG_FLAG_CURVE_PASS;
  804. }
  805. }
  806. else
  807. {
  808. PlsrDiagnosticFailedChecks |= PLSR_DIAG_FLAG_CURVE_PASS;
  809. PlsrDiagnostic.flags &= (uint16_t)~PLSR_DIAG_FLAG_CURVE_PASS;
  810. if (PlsrDiagnostic.curveMismatchCount != 0xFFFFFFFFUL)
  811. {
  812. PlsrDiagnostic.curveMismatchCount++;
  813. }
  814. if (PlsrDiagnostic.firstMismatchSample == 0xFFFFFFFFUL)
  815. {
  816. PlsrDiagnostic.firstMismatchSample =
  817. PlsrDiagnostic.curveSampleCount;
  818. }
  819. if (error > PlsrDiagnostic.curveMaxAbsErrorHz)
  820. {
  821. PlsrDiagnostic.curveMaxAbsErrorHz = error;
  822. }
  823. PlsrDiagnosticLatch(PLSR_DIAG_REASON_CURVE);
  824. }
  825. }
  826. #endif
  827. static uint8_t PlsrDiagnosticStartPulse(uint8_t pulseOutput,
  828. uint32_t requestedFirstHz,
  829. uint32_t requestedQueuedHz,
  830. uint32_t *actualFirstHz,
  831. uint32_t *actualQueuedHz)
  832. {
  833. PLSR_PLATFORM_TIMER_SETTING firstSetting;
  834. PLSR_PLATFORM_TIMER_SETTING queuedSetting;
  835. if ((PlsrPlatformBuildTimerSetting(
  836. pulseOutput, (uint8_t)PlsrActiveConfig.outputMode,
  837. requestedFirstHz, &firstSetting) == 0U)
  838. || (PlsrPlatformBuildTimerSetting(
  839. pulseOutput, (uint8_t)PlsrActiveConfig.outputMode,
  840. requestedQueuedHz, &queuedSetting) == 0U)
  841. || (PlsrPlatformStartPrepared(pulseOutput, &firstSetting,
  842. &queuedSetting, actualFirstHz,
  843. actualQueuedHz) == 0U))
  844. {
  845. PlsrDiagnosticFinishSegment(0U);
  846. return 0U;
  847. }
  848. #if PLSR_DIAGNOSTIC_ENABLED
  849. PlsrDiagnosticRecordFrequency(requestedFirstHz,
  850. firstSetting.actualFrequencyHz,
  851. *actualFirstHz);
  852. PlsrDiagnosticRecordCurveSample(firstSetting.actualFrequencyHz,
  853. *actualFirstHz);
  854. PlsrDiagnosticQueuedExpectedHz = queuedSetting.actualFrequencyHz;
  855. #endif
  856. return 1U;
  857. }
  858. static PLSR_PLATFORM_QUEUE_RESULT PlsrDiagnosticQueueFrequency(
  859. uint8_t pulseOutput,
  860. uint32_t requestedHz,
  861. uint32_t *actualHz)
  862. {
  863. PLSR_PLATFORM_QUEUE_RESULT result;
  864. #if PLSR_DIAGNOSTIC_ENABLED
  865. uint32_t expectedHz;
  866. if (PlsrPlatformExpectedFrequency(
  867. pulseOutput, (uint8_t)PlsrActiveConfig.outputMode,
  868. requestedHz, &expectedHz) == 0U)
  869. {
  870. PlsrDiagnosticFinishSegment(0U);
  871. return PLSR_PLATFORM_QUEUE_FAILED;
  872. }
  873. #endif
  874. result = PlsrPlatformQueueFrequency(pulseOutput, requestedHz, actualHz);
  875. if (result == PLSR_PLATFORM_QUEUE_FAILED)
  876. {
  877. PlsrDiagnosticFinishSegment(0U);
  878. return result;
  879. }
  880. if (result == PLSR_PLATFORM_QUEUE_STALE)
  881. {
  882. return result;
  883. }
  884. #if PLSR_DIAGNOSTIC_ENABLED
  885. PlsrDiagnosticRecordFrequency(requestedHz, expectedHz, *actualHz);
  886. PlsrDiagnosticQueuedExpectedHz = expectedHz;
  887. #endif
  888. return PLSR_PLATFORM_QUEUE_APPLIED;
  889. }
  890. static void PlsrDiagnosticCheckActiveFrequency(uint32_t activeHz)
  891. {
  892. #if PLSR_DIAGNOSTIC_ENABLED
  893. uint16_t platformFault = PlsrPlatformDiagnosticFault();
  894. uint32_t observedHz = activeHz;
  895. if (platformFault == PLSR_DIAG_REASON_FREQUENCY)
  896. {
  897. observedHz = PlsrPlatformActiveFrequency(
  898. (uint8_t)PlsrActiveConfig.pulseOutput);
  899. if (observedHz == 0UL)
  900. {
  901. observedHz = activeHz;
  902. }
  903. PlsrDiagnosticFailedChecks |= PLSR_DIAG_FLAG_FREQUENCY_PASS;
  904. PlsrDiagnostic.flags |= PLSR_DIAG_FLAG_FREQUENCY_CHECKED;
  905. PlsrDiagnostic.flags &= (uint16_t)~PLSR_DIAG_FLAG_FREQUENCY_PASS;
  906. PlsrDiagnosticLatch(PLSR_DIAG_REASON_FREQUENCY);
  907. }
  908. if ((platformFault != PLSR_DIAG_REASON_NONE)
  909. && (PlsrDiagnosticQueuedExpectedHz != 0UL))
  910. {
  911. PlsrDiagnostic.activeTimerHz = observedHz;
  912. if (platformFault == PLSR_DIAG_REASON_CURVE)
  913. {
  914. if (PlsrDiagnostic.curveSampleCount != 0xFFFFFFFFUL)
  915. {
  916. PlsrDiagnostic.curveSampleCount++;
  917. }
  918. PlsrDiagnostic.flags |= PLSR_DIAG_FLAG_CURVE_CHECKED;
  919. PlsrDiagnostic.flags &= (uint16_t)~PLSR_DIAG_FLAG_CURVE_PASS;
  920. PlsrDiagnosticFailedChecks |= PLSR_DIAG_FLAG_CURVE_PASS;
  921. if (PlsrDiagnostic.curveMismatchCount != 0xFFFFFFFFUL)
  922. {
  923. PlsrDiagnostic.curveMismatchCount++;
  924. }
  925. if (PlsrDiagnostic.firstMismatchSample == 0xFFFFFFFFUL)
  926. {
  927. PlsrDiagnostic.firstMismatchSample =
  928. PlsrDiagnostic.curveSampleCount;
  929. }
  930. PlsrDiagnosticLatch(PLSR_DIAG_REASON_CURVE);
  931. }
  932. else if (platformFault == PLSR_DIAG_REASON_FREQUENCY)
  933. {
  934. PlsrDiagnosticRecordCurveSample(PlsrDiagnosticQueuedExpectedHz,
  935. observedHz);
  936. }
  937. }
  938. #else
  939. (void)activeHz;
  940. #endif
  941. }
  942. static void PlsrSetDefaults(PLSR_CONFIG *config)
  943. {
  944. uint8_t index;
  945. (void)memset(config, 0, sizeof(*config));
  946. config->pulseOutput = 0U;
  947. config->directionOutput = 0U;
  948. config->waitInput = 0U;
  949. config->extInput = 0U;
  950. config->sendMode = PLSR_SEND_COMPLETE;
  951. config->directionDelayMs = PLSR_DIRECTION_DELAY_DEFAULT_MS;
  952. config->directionNegativeLogic = 0U;
  953. config->curveMode = 0U;
  954. config->positionMode = PLSR_POSITION_RELATIVE;
  955. config->segmentCount = 1U;
  956. config->startSegment = 1U;
  957. config->defaultSpeedHz = 1000UL;
  958. config->startSpeedHz = 100UL;
  959. config->stopSpeedHz = 100UL;
  960. config->accelerationTimeMs = 100U;
  961. config->decelerationTimeMs = 100U;
  962. config->outputMode = PLSR_OUTPUT_PULSE_DIR;
  963. for (index = 0U; index < PLSR_SEGMENT_COUNT_MAX; index++)
  964. {
  965. config->segments[index].frequencyHz = 1000UL;
  966. config->segments[index].pulses = (index == 0U) ? 1000L : 0L;
  967. config->segments[index].waitType = PLSR_EXT_OR_COMPLETE;
  968. config->segments[index].waitTimeMs = 0U;
  969. config->segments[index].actTimeMs = 0U;
  970. config->segments[index].jumpSegment = 0U;
  971. }
  972. }
  973. static uint8_t PlsrConfigIsValid(const PLSR_CONFIG *config,
  974. uint8_t validateActivePath)
  975. {
  976. uint8_t index;
  977. if ((config->pulseOutput > 3U) || (config->directionOutput > 3U)
  978. || (config->waitInput > 1U) || (config->extInput > 1U)
  979. || (config->sendMode > PLSR_SEND_SUBSEQUENT)
  980. || (config->directionNegativeLogic > 1U)
  981. || (config->curveMode > 2U)
  982. || (config->positionMode > PLSR_POSITION_ABSOLUTE)
  983. || (config->outputMode > PLSR_OUTPUT_AB)
  984. || ((config->outputMode == PLSR_OUTPUT_AB)
  985. && ((config->pulseOutput & 1U) != 0U))
  986. || (config->segmentCount == 0U)
  987. || (config->segmentCount > PLSR_SEGMENT_COUNT_MAX)
  988. || (config->startSegment == 0U)
  989. || (config->startSegment > PLSR_SEGMENT_COUNT_MAX)
  990. || (config->defaultSpeedHz == 0UL)
  991. || (config->defaultSpeedHz > PLSR_FREQUENCY_MAX_HZ)
  992. || (config->startSpeedHz > PLSR_FREQUENCY_MAX_HZ)
  993. || (config->stopSpeedHz > PLSR_FREQUENCY_MAX_HZ))
  994. {
  995. return 0U;
  996. }
  997. if ((validateActivePath != 0U)
  998. && (config->startSegment > config->segmentCount))
  999. {
  1000. return 0U;
  1001. }
  1002. for (index = 0U; index < PLSR_SEGMENT_COUNT_MAX; index++)
  1003. {
  1004. const PLSR_SEGMENT_CONFIG *segment = &config->segments[index];
  1005. if ((segment->frequencyHz > PLSR_FREQUENCY_MAX_HZ)
  1006. || (segment->waitType > PLSR_EXT_OR_COMPLETE)
  1007. || (segment->jumpSegment > PLSR_SEGMENT_COUNT_MAX))
  1008. {
  1009. return 0U;
  1010. }
  1011. if ((validateActivePath != 0U)
  1012. && (index < config->segmentCount)
  1013. && (segment->jumpSegment > config->segmentCount))
  1014. {
  1015. return 0U;
  1016. }
  1017. }
  1018. return 1U;
  1019. }
  1020. static uint16_t PlsrReadConfigWord(const PLSR_CONFIG *config,
  1021. uint16_t address)
  1022. {
  1023. uint16_t offset;
  1024. uint8_t segmentIndex;
  1025. const PLSR_SEGMENT_CONFIG *segment;
  1026. switch (address)
  1027. {
  1028. case 0x1000U: return config->pulseOutput;
  1029. case 0x1001U: return config->directionOutput;
  1030. case 0x1002U: return config->waitInput;
  1031. case 0x1003U: return config->extInput;
  1032. case 0x1004U: return config->sendMode;
  1033. case 0x1005U: return config->directionDelayMs;
  1034. case 0x1006U: return config->directionNegativeLogic;
  1035. case 0x1007U: return config->curveMode;
  1036. case 0x1008U: return config->positionMode;
  1037. case 0x1009U: return config->segmentCount;
  1038. case 0x100AU: return config->startSegment;
  1039. case 0x100BU: return PlsrLowWord(config->defaultSpeedHz);
  1040. case 0x100CU: return PlsrHighWord(config->defaultSpeedHz);
  1041. case 0x100DU: return PlsrLowWord(config->startSpeedHz);
  1042. case 0x100EU: return PlsrHighWord(config->startSpeedHz);
  1043. case 0x1010U: return PlsrLowWord(config->stopSpeedHz);
  1044. case 0x1011U: return PlsrHighWord(config->stopSpeedHz);
  1045. case 0x1012U: return config->accelerationTimeMs;
  1046. case 0x1013U: return config->decelerationTimeMs;
  1047. default: break;
  1048. }
  1049. if ((address >= PLSR_SEGMENT_FIRST_ADDRESS)
  1050. && (address <= PLSR_CONFIG_LAST_ADDRESS))
  1051. {
  1052. offset = (uint16_t)(address - PLSR_SEGMENT_FIRST_ADDRESS);
  1053. segmentIndex = (uint8_t)(offset / PLSR_SEGMENT_STRIDE);
  1054. offset = (uint16_t)(offset % PLSR_SEGMENT_STRIDE);
  1055. segment = &config->segments[segmentIndex];
  1056. switch (offset)
  1057. {
  1058. case 0U: return PlsrLowWord(segment->frequencyHz);
  1059. case 1U: return PlsrHighWord(segment->frequencyHz);
  1060. case 2U: return PlsrLowWord((uint32_t)segment->pulses);
  1061. case 3U: return PlsrHighWord((uint32_t)segment->pulses);
  1062. case 4U: return segment->waitType;
  1063. case 5U: return segment->waitTimeMs;
  1064. case 6U: return segment->actTimeMs;
  1065. case 7U: return segment->jumpSegment;
  1066. default: return 0U;
  1067. }
  1068. }
  1069. /* 0x100F, 0x1014..0x10FF, and segment padding read as zero. */
  1070. return 0U;
  1071. }
  1072. static PLSR_WORD_RESULT PlsrWriteConfigWord(PLSR_CONFIG *config,
  1073. uint16_t address,
  1074. uint16_t value)
  1075. {
  1076. uint16_t offset;
  1077. uint8_t segmentIndex;
  1078. PLSR_SEGMENT_CONFIG *segment;
  1079. switch (address)
  1080. {
  1081. case 0x1000U: config->pulseOutput = value; return PLSR_WORD_OK;
  1082. case 0x1001U: config->directionOutput = value; return PLSR_WORD_OK;
  1083. case 0x1002U: config->waitInput = value; return PLSR_WORD_OK;
  1084. case 0x1003U: config->extInput = value; return PLSR_WORD_OK;
  1085. case 0x1004U: config->sendMode = value; return PLSR_WORD_OK;
  1086. case 0x1005U: config->directionDelayMs = value; return PLSR_WORD_OK;
  1087. case 0x1006U:
  1088. config->directionNegativeLogic = value;
  1089. return PLSR_WORD_OK;
  1090. case 0x1007U: config->curveMode = value; return PLSR_WORD_OK;
  1091. case 0x1008U: config->positionMode = value; return PLSR_WORD_OK;
  1092. case 0x1009U: config->segmentCount = value; return PLSR_WORD_OK;
  1093. case 0x100AU: config->startSegment = value; return PLSR_WORD_OK;
  1094. case 0x100BU:
  1095. config->defaultSpeedHz =
  1096. PlsrJoinU32(value, PlsrHighWord(config->defaultSpeedHz));
  1097. return PLSR_WORD_OK;
  1098. case 0x100CU:
  1099. config->defaultSpeedHz =
  1100. PlsrJoinU32(PlsrLowWord(config->defaultSpeedHz), value);
  1101. return PLSR_WORD_OK;
  1102. case 0x100DU:
  1103. config->startSpeedHz =
  1104. PlsrJoinU32(value, PlsrHighWord(config->startSpeedHz));
  1105. return PLSR_WORD_OK;
  1106. case 0x100EU:
  1107. config->startSpeedHz =
  1108. PlsrJoinU32(PlsrLowWord(config->startSpeedHz), value);
  1109. return PLSR_WORD_OK;
  1110. case 0x100FU:
  1111. return (value == 0U) ? PLSR_WORD_OK : PLSR_WORD_ILLEGAL_VALUE;
  1112. case 0x1010U:
  1113. config->stopSpeedHz =
  1114. PlsrJoinU32(value, PlsrHighWord(config->stopSpeedHz));
  1115. return PLSR_WORD_OK;
  1116. case 0x1011U:
  1117. config->stopSpeedHz =
  1118. PlsrJoinU32(PlsrLowWord(config->stopSpeedHz), value);
  1119. return PLSR_WORD_OK;
  1120. case 0x1012U:
  1121. config->accelerationTimeMs = value;
  1122. return PLSR_WORD_OK;
  1123. case 0x1013U:
  1124. config->decelerationTimeMs = value;
  1125. return PLSR_WORD_OK;
  1126. default: break;
  1127. }
  1128. if ((address >= 0x1014U) && (address <= PLSR_COMMON_LAST_ADDRESS))
  1129. {
  1130. return (value == 0U) ? PLSR_WORD_OK : PLSR_WORD_ILLEGAL_VALUE;
  1131. }
  1132. if ((address < PLSR_SEGMENT_FIRST_ADDRESS)
  1133. || (address > PLSR_CONFIG_LAST_ADDRESS))
  1134. {
  1135. return PLSR_WORD_ILLEGAL_ADDRESS;
  1136. }
  1137. offset = (uint16_t)(address - PLSR_SEGMENT_FIRST_ADDRESS);
  1138. segmentIndex = (uint8_t)(offset / PLSR_SEGMENT_STRIDE);
  1139. offset = (uint16_t)(offset % PLSR_SEGMENT_STRIDE);
  1140. segment = &config->segments[segmentIndex];
  1141. switch (offset)
  1142. {
  1143. case 0U:
  1144. segment->frequencyHz =
  1145. PlsrJoinU32(value, PlsrHighWord(segment->frequencyHz));
  1146. return PLSR_WORD_OK;
  1147. case 1U:
  1148. segment->frequencyHz =
  1149. PlsrJoinU32(PlsrLowWord(segment->frequencyHz), value);
  1150. return PLSR_WORD_OK;
  1151. case 2U:
  1152. segment->pulses = (int32_t)PlsrJoinU32(
  1153. value, PlsrHighWord((uint32_t)segment->pulses));
  1154. return PLSR_WORD_OK;
  1155. case 3U:
  1156. segment->pulses = (int32_t)PlsrJoinU32(
  1157. PlsrLowWord((uint32_t)segment->pulses), value);
  1158. return PLSR_WORD_OK;
  1159. case 4U: segment->waitType = value; return PLSR_WORD_OK;
  1160. case 5U: segment->waitTimeMs = value; return PLSR_WORD_OK;
  1161. case 6U: segment->actTimeMs = value; return PLSR_WORD_OK;
  1162. case 7U: segment->jumpSegment = value; return PLSR_WORD_OK;
  1163. default:
  1164. return (value == 0U) ? PLSR_WORD_OK : PLSR_WORD_ILLEGAL_VALUE;
  1165. }
  1166. }
  1167. static uint8_t PlsrAddressIsDwordHalf(uint16_t address,
  1168. uint16_t *pairedAddress)
  1169. {
  1170. uint16_t offset;
  1171. switch (address)
  1172. {
  1173. case 0x100BU: case 0x100DU: case 0x1010U:
  1174. *pairedAddress = (uint16_t)(address + 1U);
  1175. return 1U;
  1176. case 0x100CU: case 0x100EU: case 0x1011U:
  1177. *pairedAddress = (uint16_t)(address - 1U);
  1178. return 1U;
  1179. default: break;
  1180. }
  1181. if ((address >= PLSR_SEGMENT_FIRST_ADDRESS)
  1182. && (address <= PLSR_CONFIG_LAST_ADDRESS))
  1183. {
  1184. offset = (uint16_t)((address - PLSR_SEGMENT_FIRST_ADDRESS)
  1185. % PLSR_SEGMENT_STRIDE);
  1186. if ((offset == 0U) || (offset == 2U))
  1187. {
  1188. *pairedAddress = (uint16_t)(address + 1U);
  1189. return 1U;
  1190. }
  1191. if ((offset == 1U) || (offset == 3U))
  1192. {
  1193. *pairedAddress = (uint16_t)(address - 1U);
  1194. return 1U;
  1195. }
  1196. }
  1197. return 0U;
  1198. }
  1199. static uint8_t PlsrAddressIsProduct(uint16_t address)
  1200. {
  1201. return (((address >= PLSR_CONFIG_FIRST_ADDRESS)
  1202. && (address <= PLSR_CONFIG_LAST_ADDRESS))
  1203. || (address == PLSR_OUTPUT_MODE_ADDRESS)
  1204. || ((address >= PLSR_STATUS_FIRST_ADDRESS)
  1205. && (address <= PLSR_STATUS_LAST_ADDRESS))
  1206. || ((address >= PLSR_DIAGNOSTIC_FIRST_ADDRESS)
  1207. && (address <= PLSR_DIAGNOSTIC_LAST_ADDRESS))
  1208. || ((address >= PLSR_QUEUE_DIAGNOSTIC_FIRST_ADDRESS)
  1209. && (address <= PLSR_QUEUE_DIAGNOSTIC_LAST_ADDRESS))
  1210. || (address == PLSR_CONTROL_ADDRESS)
  1211. || (address == PLSR_DIAGNOSTIC_CONTROL_ADDRESS)) ? 1U : 0U;
  1212. }
  1213. static PLSR_MB_RESULT PlsrClassifyRange(uint16_t startAddress,
  1214. uint16_t quantity)
  1215. {
  1216. uint32_t address;
  1217. uint32_t endAddress;
  1218. uint8_t foundProduct = 0U;
  1219. uint8_t foundOther = 0U;
  1220. if (quantity == 0U)
  1221. {
  1222. return PLSR_MB_ILLEGAL_VALUE;
  1223. }
  1224. endAddress = (uint32_t)startAddress + (uint32_t)quantity - 1UL;
  1225. if (endAddress > 0xFFFFUL)
  1226. {
  1227. return PLSR_MB_ILLEGAL_ADDRESS;
  1228. }
  1229. for (address = startAddress; address <= endAddress; address++)
  1230. {
  1231. if (PlsrAddressIsProduct((uint16_t)address) != 0U)
  1232. {
  1233. foundProduct = 1U;
  1234. }
  1235. else
  1236. {
  1237. foundOther = 1U;
  1238. }
  1239. }
  1240. if (foundProduct == 0U)
  1241. {
  1242. return PLSR_MB_NOT_HANDLED;
  1243. }
  1244. return (foundOther != 0U) ? PLSR_MB_ILLEGAL_ADDRESS : PLSR_MB_OK;
  1245. }
  1246. static uint32_t PlsrCurveProgressQ16(uint32_t elapsed,
  1247. uint32_t duration,
  1248. uint16_t curveMode)
  1249. {
  1250. uint32_t linear;
  1251. if ((duration == 0UL) || (elapsed >= duration))
  1252. {
  1253. return 65535UL;
  1254. }
  1255. linear = (uint32_t)(((uint64_t)elapsed * 65535UL) / duration);
  1256. if (curveMode == 1U)
  1257. {
  1258. uint64_t x = linear;
  1259. uint64_t x2 = (x * x) / 65535UL;
  1260. return (uint32_t)((x2 * (196605UL - 2UL * x)) / 65535UL);
  1261. }
  1262. if (curveMode == 2U)
  1263. {
  1264. uint32_t scaled = linear * 64UL;
  1265. uint32_t index = scaled / 65535UL;
  1266. uint32_t fraction = scaled % 65535UL;
  1267. uint32_t first;
  1268. uint32_t second;
  1269. if (index >= 64UL)
  1270. {
  1271. return 65535UL;
  1272. }
  1273. first = PlsrSineProgressQ16[index];
  1274. second = PlsrSineProgressQ16[index + 1UL];
  1275. return first + (uint32_t)(((uint64_t)(second - first) * fraction)
  1276. / 65535UL);
  1277. }
  1278. return linear;
  1279. }
  1280. static uint32_t PlsrRampDurationMs(uint32_t fromHz, uint32_t toHz)
  1281. {
  1282. uint32_t gap;
  1283. uint32_t baseTimeMs;
  1284. uint64_t duration;
  1285. if (fromHz == toHz)
  1286. {
  1287. return 0UL;
  1288. }
  1289. gap = (fromHz > toHz) ? (fromHz - toHz) : (toHz - fromHz);
  1290. baseTimeMs = (toHz > fromHz) ? PlsrActiveConfig.accelerationTimeMs
  1291. : PlsrActiveConfig.decelerationTimeMs;
  1292. if (baseTimeMs == 0UL)
  1293. {
  1294. return 0UL;
  1295. }
  1296. duration = ((uint64_t)gap * baseTimeMs
  1297. + PlsrActiveConfig.defaultSpeedHz - 1UL)
  1298. / PlsrActiveConfig.defaultSpeedHz;
  1299. if (duration > 0xFFFFFFFFUL)
  1300. {
  1301. return 0xFFFFFFFFUL;
  1302. }
  1303. return (uint32_t)duration;
  1304. }
  1305. static uint32_t PlsrEffectiveStartFrequency(uint32_t segmentFrequencyHz,
  1306. uint8_t allowCarry,
  1307. uint8_t directionChanged,
  1308. uint32_t carryFrequencyHz)
  1309. {
  1310. if ((allowCarry != 0U) && (directionChanged == 0U)
  1311. && (carryFrequencyHz != 0UL))
  1312. {
  1313. return carryFrequencyHz;
  1314. }
  1315. if (PlsrActiveConfig.accelerationTimeMs == 0U)
  1316. {
  1317. return segmentFrequencyHz;
  1318. }
  1319. return PlsrActiveConfig.startSpeedHz;
  1320. }
  1321. static uint32_t PlsrPulseDirStartFrequency(
  1322. uint32_t segmentFrequencyHz,
  1323. PLSR_SEGMENT_ENTRY entryType,
  1324. uint8_t directionChanged,
  1325. uint32_t carryFrequencyHz)
  1326. {
  1327. if ((entryType == PLSR_SEGMENT_ENTRY_CARRY)
  1328. && (directionChanged == 0U) && (carryFrequencyHz != 0UL))
  1329. {
  1330. return carryFrequencyHz;
  1331. }
  1332. if (PlsrActiveConfig.accelerationTimeMs == 0U)
  1333. {
  1334. return segmentFrequencyHz;
  1335. }
  1336. if ((entryType == PLSR_SEGMENT_ENTRY_COMMAND_START)
  1337. || (PlsrPulseDirMotionStarted == 0U))
  1338. {
  1339. return PlsrActiveConfig.startSpeedHz;
  1340. }
  1341. return 0UL;
  1342. }
  1343. static uint16_t PlsrEffectiveDirectionDelayMs(void)
  1344. {
  1345. return (PlsrActiveConfig.directionDelayMs != 0U)
  1346. ? PlsrActiveConfig.directionDelayMs
  1347. : PLSR_DIRECTION_DELAY_DEFAULT_MS;
  1348. }
  1349. static uint32_t PlsrEffectiveStopFrequency(uint32_t segmentFrequencyHz)
  1350. {
  1351. return (PlsrActiveConfig.decelerationTimeMs == 0U)
  1352. ? segmentFrequencyHz : PlsrActiveConfig.stopSpeedHz;
  1353. }
  1354. static void PlsrRampStart(uint32_t fromHz, uint32_t toHz)
  1355. {
  1356. PlsrRamp.fromHz = fromHz;
  1357. PlsrRamp.toHz = toHz;
  1358. PlsrRamp.durationMs = PlsrRampDurationMs(fromHz, toHz);
  1359. PlsrRamp.elapsedMs = 0UL;
  1360. PlsrRamp.active = (PlsrRamp.durationMs != 0UL) ? 1U : 0U;
  1361. if (toHz > fromHz)
  1362. {
  1363. PlsrRunStatus = PLSR_STATUS_ACCELERATING;
  1364. }
  1365. else if (toHz < fromHz)
  1366. {
  1367. PlsrRunStatus = PLSR_STATUS_DECELERATING;
  1368. }
  1369. else
  1370. {
  1371. PlsrRunStatus = PLSR_STATUS_RUNNING;
  1372. }
  1373. }
  1374. static uint8_t PlsrApplyFrequencyPair(uint32_t requestedFirstFrequencyHz,
  1375. uint32_t requestedQueuedFrequencyHz,
  1376. uint32_t expectedEpoch)
  1377. {
  1378. uint32_t criticalState;
  1379. uint32_t actualFirstFrequencyHz;
  1380. uint32_t actualQueuedFrequencyHz;
  1381. uint32_t hardwareFirstFrequencyHz = requestedFirstFrequencyHz;
  1382. uint32_t hardwareQueuedFrequencyHz = requestedQueuedFrequencyHz;
  1383. PLSR_HANDOFF_PLAN candidatePlan;
  1384. uint8_t haveCandidatePlan = 0U;
  1385. criticalState = PlsrPlatformEnterCritical();
  1386. if ((PlsrSegmentEpoch != expectedEpoch)
  1387. || (PlsrBoundaryPending != 0U) || (PlsrRemainingPulses == 0UL))
  1388. {
  1389. PlsrPlatformExitCritical(criticalState);
  1390. return 1U;
  1391. }
  1392. if (hardwareFirstFrequencyHz == 0UL)
  1393. {
  1394. if (PlsrPulseActive == 0U)
  1395. {
  1396. PlsrCurrentFrequencyHz = 0UL;
  1397. PlsrQueuedFrequencyHz = 0UL;
  1398. PlsrPlatformExitCritical(criticalState);
  1399. return 1U;
  1400. }
  1401. hardwareFirstFrequencyHz = 1UL;
  1402. }
  1403. if (hardwareQueuedFrequencyHz == 0UL)
  1404. {
  1405. hardwareQueuedFrequencyHz = 1UL;
  1406. }
  1407. if (PlsrPulseActive != 0U)
  1408. {
  1409. if (PlsrAbStopArmed != 0U)
  1410. {
  1411. PlsrPlatformExitCritical(criticalState);
  1412. return 1U;
  1413. }
  1414. if (PlsrHandoffPlan.valid != 0U)
  1415. {
  1416. PlsrPlatformExitCritical(criticalState);
  1417. return 1U;
  1418. }
  1419. PlsrDeferredFrequencyHz = hardwareQueuedFrequencyHz;
  1420. PlsrDeferredFrequencyPending = 1U;
  1421. PlsrPlatformExitCritical(criticalState);
  1422. return 1U;
  1423. }
  1424. else
  1425. {
  1426. if (PlsrSelectPreparedHandoffPlan(&candidatePlan) != 0U)
  1427. {
  1428. hardwareQueuedFrequencyHz = candidatePlan.firstFrequencyHz;
  1429. haveCandidatePlan = 1U;
  1430. }
  1431. if (PlsrDiagnosticStartPulse(
  1432. (uint8_t)PlsrActiveConfig.pulseOutput,
  1433. hardwareFirstFrequencyHz, hardwareQueuedFrequencyHz,
  1434. &actualFirstFrequencyHz, &actualQueuedFrequencyHz) == 0U)
  1435. {
  1436. PlsrPlatformExitCritical(criticalState);
  1437. return 0U;
  1438. }
  1439. PlsrPulseActive = 1U;
  1440. PlsrCurrentFrequencyHz = actualFirstFrequencyHz;
  1441. PlsrHandoffPlan.valid = 0U;
  1442. if (haveCandidatePlan != 0U)
  1443. {
  1444. PlsrHandoffPlan = candidatePlan;
  1445. PlsrHandoffPlan.firstFrequencyHz = actualQueuedFrequencyHz;
  1446. PlsrHandoffPlan.valid = 1U;
  1447. }
  1448. }
  1449. PlsrQueuedFrequencyHz = actualQueuedFrequencyHz;
  1450. if (PlsrArmFinalAbBoundaryLocked() == 0U)
  1451. {
  1452. PlsrPlatformExitCritical(criticalState);
  1453. return 0U;
  1454. }
  1455. PlsrPlatformExitCritical(criticalState);
  1456. return 1U;
  1457. }
  1458. static PLSR_PLATFORM_QUEUE_RESULT PlsrApplyFrequency(
  1459. uint32_t requestedFrequencyHz,
  1460. uint32_t expectedEpoch)
  1461. {
  1462. return (PlsrApplyFrequencyPair(requestedFrequencyHz,
  1463. requestedFrequencyHz,
  1464. expectedEpoch) != 0U)
  1465. ? PLSR_PLATFORM_QUEUE_APPLIED
  1466. : PLSR_PLATFORM_QUEUE_FAILED;
  1467. }
  1468. static uint8_t PlsrStopDrainPulseCount(void)
  1469. {
  1470. uint8_t deferredPending = PlsrDeferredFrequencyPending;
  1471. uint32_t deferredFrequencyHz = PlsrDeferredFrequencyHz;
  1472. uint32_t queuedFrequencyHz = PlsrQueuedFrequencyHz;
  1473. uint32_t currentFrequencyHz = PlsrCurrentFrequencyHz;
  1474. if ((deferredPending != 0U)
  1475. && (deferredFrequencyHz != queuedFrequencyHz))
  1476. {
  1477. return 3U;
  1478. }
  1479. PlsrDeferredFrequencyPending = 0U;
  1480. return (currentFrequencyHz == queuedFrequencyHz) ? 1U : 2U;
  1481. }
  1482. static uint8_t PlsrArmStopDrainLocked(void)
  1483. {
  1484. uint32_t drainPulses = PlsrStopDrainPulseCount();
  1485. PlsrStopPulsesRemaining = (uint8_t)drainPulses;
  1486. return PlsrArmFinalAbBoundaryLocked();
  1487. }
  1488. static PLSR_PLATFORM_QUEUE_RESULT PlsrCommitDeferredFrequency(
  1489. uint8_t pulseOutput)
  1490. {
  1491. uint32_t requestedFrequencyHz;
  1492. uint32_t actualFrequencyHz;
  1493. PLSR_PLATFORM_QUEUE_RESULT result;
  1494. if (PlsrDeferredFrequencyPending == 0U)
  1495. {
  1496. return PLSR_PLATFORM_QUEUE_APPLIED;
  1497. }
  1498. requestedFrequencyHz = PlsrDeferredFrequencyHz;
  1499. result = PlsrDiagnosticQueueFrequency(pulseOutput, requestedFrequencyHz,
  1500. &actualFrequencyHz);
  1501. if (result != PLSR_PLATFORM_QUEUE_APPLIED)
  1502. {
  1503. return result;
  1504. }
  1505. if ((PlsrDeferredFrequencyPending != 0U)
  1506. && (PlsrDeferredFrequencyHz == requestedFrequencyHz))
  1507. {
  1508. PlsrDeferredFrequencyPending = 0U;
  1509. }
  1510. PlsrQueuedFrequencyHz = actualFrequencyHz;
  1511. return PLSR_PLATFORM_QUEUE_APPLIED;
  1512. }
  1513. static uint8_t PlsrRampAdvance(uint32_t expectedEpoch)
  1514. {
  1515. uint32_t progress;
  1516. uint32_t frequency;
  1517. uint32_t gap;
  1518. uint32_t criticalState;
  1519. uint32_t fromHz;
  1520. uint32_t toHz;
  1521. uint32_t durationMs;
  1522. uint32_t elapsedMs;
  1523. PLSR_PLATFORM_QUEUE_RESULT applyResult;
  1524. criticalState = PlsrPlatformEnterCritical();
  1525. if ((PlsrSegmentEpoch != expectedEpoch) || (PlsrRamp.active == 0U))
  1526. {
  1527. PlsrPlatformExitCritical(criticalState);
  1528. return 1U;
  1529. }
  1530. if (PlsrRamp.elapsedMs < PlsrRamp.durationMs)
  1531. {
  1532. PlsrRamp.elapsedMs++;
  1533. }
  1534. fromHz = PlsrRamp.fromHz;
  1535. toHz = PlsrRamp.toHz;
  1536. durationMs = PlsrRamp.durationMs;
  1537. elapsedMs = PlsrRamp.elapsedMs;
  1538. PlsrPlatformExitCritical(criticalState);
  1539. progress = PlsrCurveProgressQ16(elapsedMs,
  1540. durationMs,
  1541. PlsrActiveConfig.curveMode);
  1542. if (toHz >= fromHz)
  1543. {
  1544. gap = toHz - fromHz;
  1545. frequency = fromHz
  1546. + (uint32_t)(((uint64_t)gap * progress) / 65535UL);
  1547. }
  1548. else
  1549. {
  1550. gap = fromHz - toHz;
  1551. frequency = fromHz
  1552. - (uint32_t)(((uint64_t)gap * progress) / 65535UL);
  1553. }
  1554. applyResult = PlsrApplyFrequency(frequency, expectedEpoch);
  1555. if (applyResult == PLSR_PLATFORM_QUEUE_FAILED)
  1556. {
  1557. return 0U;
  1558. }
  1559. if (applyResult == PLSR_PLATFORM_QUEUE_STALE)
  1560. {
  1561. return 1U;
  1562. }
  1563. criticalState = PlsrPlatformEnterCritical();
  1564. if (PlsrSegmentEpoch != expectedEpoch)
  1565. {
  1566. PlsrPlatformExitCritical(criticalState);
  1567. return 1U;
  1568. }
  1569. if (elapsedMs >= durationMs)
  1570. {
  1571. PlsrRamp.active = 0U;
  1572. if (PlsrStopRequested == 0U)
  1573. {
  1574. PlsrRunStatus = PLSR_STATUS_RUNNING;
  1575. }
  1576. else
  1577. {
  1578. (void)PlsrArmStopDrainLocked();
  1579. }
  1580. }
  1581. PlsrPlatformExitCritical(criticalState);
  1582. return 1U;
  1583. }
  1584. static uint32_t PlsrResolvedSegmentFrequency(const PLSR_CONFIG *config,
  1585. uint8_t segmentIndex)
  1586. {
  1587. uint32_t frequencyHz = config->segments[segmentIndex].frequencyHz;
  1588. return (frequencyHz == 0UL) ? config->defaultSpeedHz : frequencyHz;
  1589. }
  1590. static int64_t PlsrSegmentDisplacement(uint8_t segmentNumber,
  1591. int32_t referencePosition)
  1592. {
  1593. int32_t configured =
  1594. PlsrActiveConfig.segments[segmentNumber - 1U].pulses;
  1595. if (PlsrActiveConfig.positionMode == PLSR_POSITION_ABSOLUTE)
  1596. {
  1597. return (int64_t)configured - (int64_t)referencePosition;
  1598. }
  1599. return configured;
  1600. }
  1601. static uint8_t PlsrSegmentSuccessor(uint8_t segmentNumber,
  1602. uint8_t *nextSegment)
  1603. {
  1604. const PLSR_SEGMENT_CONFIG *segment;
  1605. if ((segmentNumber == 0U) || (nextSegment == NULL)
  1606. || (segmentNumber > PlsrActiveConfig.segmentCount))
  1607. {
  1608. return 0U;
  1609. }
  1610. segment = &PlsrActiveConfig.segments[segmentNumber - 1U];
  1611. if (segment->jumpSegment != 0U)
  1612. {
  1613. *nextSegment = (uint8_t)segment->jumpSegment;
  1614. return 1U;
  1615. }
  1616. if (segmentNumber < PlsrActiveConfig.segmentCount)
  1617. {
  1618. *nextSegment = (uint8_t)(segmentNumber + 1U);
  1619. return 1U;
  1620. }
  1621. return 0U;
  1622. }
  1623. /* Absolute targets are converted here, before any planner/queue code sees the
  1624. segment. Zero relative displacement is a true no-op: follow its successor
  1625. (including jump rules) until a motion segment is found. The bounded walk
  1626. also turns an all-zero or zero-only jump loop into end-of-motion. */
  1627. static uint8_t PlsrResolveMotionSegment(uint8_t candidateSegment,
  1628. int32_t referencePosition,
  1629. uint8_t *motionSegment,
  1630. int64_t *displacement)
  1631. {
  1632. uint8_t inspected;
  1633. if ((motionSegment == NULL) || (displacement == NULL))
  1634. {
  1635. return 0U;
  1636. }
  1637. for (inspected = 0U;
  1638. inspected < PlsrActiveConfig.segmentCount;
  1639. inspected++)
  1640. {
  1641. if ((candidateSegment == 0U)
  1642. || (candidateSegment > PlsrActiveConfig.segmentCount))
  1643. {
  1644. return 0U;
  1645. }
  1646. *displacement = PlsrSegmentDisplacement(candidateSegment,
  1647. referencePosition);
  1648. if (*displacement != 0)
  1649. {
  1650. *motionSegment = candidateSegment;
  1651. return 1U;
  1652. }
  1653. if (PlsrSegmentSuccessor(candidateSegment,
  1654. &candidateSegment) == 0U)
  1655. {
  1656. return 0U;
  1657. }
  1658. }
  1659. return 0U;
  1660. }
  1661. static uint8_t PlsrResolveNextMotionSegment(uint8_t sourceSegment,
  1662. int32_t referencePosition,
  1663. uint8_t *motionSegment,
  1664. int64_t *displacement)
  1665. {
  1666. uint8_t candidateSegment;
  1667. if (PlsrSegmentSuccessor(sourceSegment, &candidateSegment) == 0U)
  1668. {
  1669. return 0U;
  1670. }
  1671. return PlsrResolveMotionSegment(candidateSegment, referencePosition,
  1672. motionSegment, displacement);
  1673. }
  1674. static uint8_t PlsrPredictNextMotion(uint8_t *nextSegment,
  1675. uint8_t *positive)
  1676. {
  1677. uint32_t criticalState;
  1678. uint64_t remaining;
  1679. int32_t position;
  1680. int64_t predictedPosition;
  1681. int64_t displacement;
  1682. uint8_t countPositive;
  1683. criticalState = PlsrPlatformEnterCritical();
  1684. remaining = PlsrRemainingPulses;
  1685. position = PlsrPosition;
  1686. countPositive = PlsrCountPositive;
  1687. PlsrPlatformExitCritical(criticalState);
  1688. predictedPosition = (countPositive != 0U)
  1689. ? (int64_t)position + (int64_t)remaining
  1690. : (int64_t)position - (int64_t)remaining;
  1691. if ((predictedPosition > (int64_t)INT32_MAX)
  1692. || (predictedPosition < (int64_t)INT32_MIN))
  1693. {
  1694. return 0U;
  1695. }
  1696. if (PlsrResolveNextMotionSegment(
  1697. PlsrCurrentSegment, (int32_t)predictedPosition,
  1698. nextSegment, &displacement) == 0U)
  1699. {
  1700. return 0U;
  1701. }
  1702. *positive = (displacement > 0) ? 1U : 0U;
  1703. return 1U;
  1704. }
  1705. static uint64_t PlsrRemainingSnapshot(void)
  1706. {
  1707. uint32_t criticalState = PlsrPlatformEnterCritical();
  1708. uint64_t remaining = PlsrRemainingPulses;
  1709. PlsrPlatformExitCritical(criticalState);
  1710. return remaining;
  1711. }
  1712. static uint64_t PlsrRampPulseEstimate(uint32_t fromHz,
  1713. uint32_t toHz,
  1714. uint32_t rateBoundHz)
  1715. {
  1716. uint32_t duration = PlsrRampDurationMs(fromHz, toHz);
  1717. uint64_t sum = (uint64_t)fromHz + toHz;
  1718. uint64_t discreteArea = sum * duration;
  1719. uint64_t rampArea;
  1720. uint64_t pollReserve = 0ULL;
  1721. uint64_t candidateReserve =
  1722. ((uint64_t)rateBoundHz + 999UL) / 1000UL;
  1723. uint64_t endpointCorrection = 0ULL;
  1724. /* RampAdvance applies samples at 1/duration through duration/duration.
  1725. For all supported symmetric curves this right-endpoint sum differs
  1726. from the continuous trapezoid by half the endpoint delta. */
  1727. if (toHz >= fromHz)
  1728. {
  1729. discreteArea += (uint64_t)toHz - fromHz;
  1730. }
  1731. else
  1732. {
  1733. discreteArea -= (uint64_t)fromHz - toHz;
  1734. endpointCorrection =
  1735. ((uint64_t)fromHz - toHz + 1999UL) / 2000UL;
  1736. }
  1737. rampArea = (discreteArea + 1999UL) / 2000UL;
  1738. if (candidateReserve
  1739. <= rampArea / PLSR_RAMP_POLL_RESERVE_AREA_DIVISOR)
  1740. {
  1741. pollReserve = candidateReserve + endpointCorrection;
  1742. }
  1743. /* A full poll reserve on shorter ramps would dominate their area and
  1744. leave stop-speed tail pulses. */
  1745. return rampArea + pollReserve;
  1746. }
  1747. static uint8_t PlsrPrepareShortProfile(PLSR_SHORT_PROFILE *profile,
  1748. const PLSR_CONFIG *frequencyConfig,
  1749. uint8_t segmentNumber,
  1750. uint32_t startFrequencyHz,
  1751. uint32_t targetFrequencyHz,
  1752. uint64_t pulseCount,
  1753. uint8_t currentPositive,
  1754. uint8_t forceTerminalExit)
  1755. {
  1756. PLSR_MOTION_BLOCK block;
  1757. PLSR_PLANNER_STATUS status;
  1758. const PLSR_SEGMENT_CONFIG *segment;
  1759. int64_t nextDisplacement;
  1760. int32_t boundaryPosition;
  1761. uint8_t nextSegment = 0U;
  1762. uint8_t nextPositive;
  1763. (void)memset(profile, 0, sizeof(*profile));
  1764. if ((frequencyConfig == NULL)
  1765. || (PlsrActiveConfig.outputMode != PLSR_OUTPUT_PULSE_DIR)
  1766. || (pulseCount == 0ULL) || (pulseCount > 0xFFFFFFFFULL)
  1767. || (segmentNumber == 0U)
  1768. || (segmentNumber > PlsrActiveConfig.segmentCount))
  1769. {
  1770. return 0U;
  1771. }
  1772. block.entryHz = startFrequencyHz;
  1773. block.cruiseHz = targetFrequencyHz;
  1774. /* A configured stop speed belongs to the command endpoint. Internal
  1775. discontinuities use the zero endpoint; continuous boundaries override
  1776. it according to the configured send mode below. */
  1777. block.exitHz = 0UL;
  1778. block.pulseBudget = (uint32_t)pulseCount;
  1779. block.referenceSpeedHz = PlsrActiveConfig.defaultSpeedHz;
  1780. block.accelerationTimeMs = frequencyConfig->accelerationTimeMs;
  1781. block.decelerationTimeMs = frequencyConfig->decelerationTimeMs;
  1782. block.curveMode = frequencyConfig->curveMode;
  1783. block.pulseOutput = (uint8_t)PlsrActiveConfig.pulseOutput;
  1784. block.boundary = PLSR_BOUNDARY_STOP;
  1785. segment = &PlsrActiveConfig.segments[segmentNumber - 1U];
  1786. boundaryPosition = (PlsrActiveConfig.positionMode
  1787. == PLSR_POSITION_ABSOLUTE)
  1788. ? segment->pulses : 0L;
  1789. if (PlsrResolveNextMotionSegment(
  1790. segmentNumber, boundaryPosition,
  1791. &nextSegment, &nextDisplacement) == 0U)
  1792. {
  1793. nextSegment = 0U;
  1794. }
  1795. if (forceTerminalExit != 0U)
  1796. {
  1797. block.exitHz = targetFrequencyHz;
  1798. }
  1799. else if (nextSegment == 0U)
  1800. {
  1801. block.exitHz = (frequencyConfig->decelerationTimeMs == 0U)
  1802. ? targetFrequencyHz
  1803. : PlsrActiveConfig.stopSpeedHz;
  1804. }
  1805. else if (segment->waitType == PLSR_EXT_OR_COMPLETE)
  1806. {
  1807. nextPositive = (nextDisplacement > 0) ? 1U : 0U;
  1808. if (nextPositive == currentPositive)
  1809. {
  1810. block.exitHz =
  1811. (PlsrActiveConfig.sendMode == PLSR_SEND_SUBSEQUENT)
  1812. ? PlsrResolvedSegmentFrequency(
  1813. frequencyConfig, nextSegment - 1U)
  1814. : targetFrequencyHz;
  1815. block.boundary = PLSR_BOUNDARY_NEXT_CARRY;
  1816. }
  1817. }
  1818. status = PlsrPlannerBegin(&profile->planner, &block,
  1819. startFrequencyHz, 0ULL);
  1820. if ((status != PLSR_PLANNER_OK)
  1821. && (status != PLSR_PLANNER_CLIPPED))
  1822. {
  1823. return 0U;
  1824. }
  1825. profile->startHz = profile->planner.startHz;
  1826. profile->peakHz = profile->planner.peakHz;
  1827. profile->endHz = profile->planner.endHz;
  1828. profile->pulseCount = profile->planner.block.pulseBudget;
  1829. profile->entryPulses = profile->planner.entryPulses;
  1830. profile->steadyPulses = profile->planner.steadyPulses;
  1831. profile->exitPulses = profile->planner.exitPulses;
  1832. profile->active = 1U;
  1833. return 1U;
  1834. }
  1835. static uint8_t PlsrShortProfileTakeRun(PLSR_SHORT_PROFILE *profile,
  1836. PLSR_PROFILE_ENTRY *entry)
  1837. {
  1838. return PlsrShortProfileTakeRunLimited(profile, entry, 0xFFFFFFFFUL);
  1839. }
  1840. static uint32_t PlsrProfileRunLimit(uint32_t frequencyHz)
  1841. {
  1842. uint64_t limit;
  1843. if (PlsrActiveConfig.outputMode != PLSR_OUTPUT_PULSE_DIR)
  1844. {
  1845. return 0xFFFFFFFFUL;
  1846. }
  1847. if (frequencyHz == 0UL)
  1848. {
  1849. return 1UL;
  1850. }
  1851. limit = ((uint64_t)frequencyHz * PLSR_COUNTED_RUN_MAX_TIME_US
  1852. + 999999ULL) / 1000000ULL;
  1853. if (limit == 0ULL)
  1854. {
  1855. return 1UL;
  1856. }
  1857. return (limit > 0xFFFFFFFFULL) ? 0xFFFFFFFFUL : (uint32_t)limit;
  1858. }
  1859. /*******************************************************************************
  1860. * 函数名称: PlsrShortProfileTakeRunLimited
  1861. * 功能描述: 从短轮廓中切出一项 counted run,写入 entry。
  1862. * 若规划器一次生成过长的同频项,则按上限将其拆成可入队的短 run。
  1863. * 输入参数: profile - 短轮廓对象,含规划上下文、已输出脉冲数、
  1864. * 尚未切完的同频项
  1865. * maximumRepeats - 本项允许的最大脉冲数;QueueFill 还债时传入
  1866. * 当前欠债脉冲数
  1867. * 输出参数: entry - 切出的队列节点
  1868. * setting : 量化后的定时器参数
  1869. * requestedFrequencyHz : 规划请求频率
  1870. * repeatCount : 本 run 连续脉冲数
  1871. * startsNextSegment : 本函数恒写 0
  1872. * 返 回 值: 1 - 切出成功,entry 有效,profile 账本已推进
  1873. * 0 - 失败,entry 无效。失败原因包括:
  1874. * 本段脉冲已全部切出、入口指针非法、maximumRepeats 为 0、
  1875. * 规划器无法再生成、或裁切后脉冲数为 0
  1876. * 注意事项: 1. 本项脉冲数取下列三者的最小值:
  1877. * 规划器剩余同频脉冲、本段尚未切出的脉冲、maximumRepeats。
  1878. * 2. maximumRepeats 还会被 PlsrProfileRunLimit() 再次压缩,
  1879. * 使单次硬件 run 不超过约 2 ms(PLSR_COUNTED_RUN_MAX_TIME_US)。
  1880. * 3. pendingRepeats 未耗尽时不调用规划器,继续切上一档同频项。
  1881. * 4. 还债路径由调用方传入欠债作为 maximumRepeats,并自行决定
  1882. * 不入队;本函数仍会填写 entry 并推进 nextPeriod。
  1883. * 5. 段边界标志 startsNextSegment 不在本函数置位,由
  1884. * counted-handoff 路径单独盖章。
  1885. * 6. 本段切尽时将 profile->active 清 0;generatorComplete
  1886. * 仍由 QueueFill 在欠债还清后置位。
  1887. ******************************************************************************/
  1888. static uint8_t PlsrShortProfileTakeRunLimited(
  1889. PLSR_SHORT_PROFILE *profile,
  1890. PLSR_PROFILE_ENTRY *entry,
  1891. uint32_t maximumRepeats)
  1892. {
  1893. uint32_t repeatCount;
  1894. /* 本段已切完、出口无效、或允许脉冲数为 0,无法再切。 */
  1895. if ((profile->nextPeriod >= profile->pulseCount)
  1896. || (entry == NULL) || (maximumRepeats == 0UL))
  1897. {
  1898. return 0U;
  1899. }
  1900. /* 上一档同频项已切完,向规划器再取一档。 */
  1901. if (profile->pendingRepeats == 0UL)
  1902. {
  1903. if (PlsrPlannerGenerate(&profile->planner, &profile->pendingItem, 1U) == 0U)
  1904. {
  1905. profile->active = 0U;
  1906. return 0U;
  1907. }
  1908. profile->pendingRepeats = profile->pendingItem.repeatCount;
  1909. }
  1910. {
  1911. uint32_t runLimit = PlsrProfileRunLimit(
  1912. profile->pendingItem.setting.actualFrequencyHz);
  1913. /* 限制单次 run 时长,避免在线改频阻塞在超长匀速之后。 */
  1914. if (maximumRepeats > runLimit)
  1915. {
  1916. maximumRepeats = runLimit;
  1917. }
  1918. }
  1919. /* 本项脉冲数 = min(本档剩余, 本段剩余, 调用方上限)。 */
  1920. repeatCount = profile->pendingRepeats;
  1921. if (repeatCount > profile->pulseCount - profile->nextPeriod)
  1922. {
  1923. repeatCount = profile->pulseCount - profile->nextPeriod;
  1924. }
  1925. if (repeatCount > maximumRepeats)
  1926. {
  1927. repeatCount = maximumRepeats;
  1928. }
  1929. if (repeatCount == 0UL)
  1930. {
  1931. profile->active = 0U;
  1932. return 0U;
  1933. }
  1934. entry->setting = profile->pendingItem.setting;
  1935. entry->requestedFrequencyHz =
  1936. profile->pendingItem.requestedFrequencyHz;
  1937. entry->repeatCount = repeatCount;
  1938. entry->startsNextSegment = 0U; /* 段边界不由本函数标记 */
  1939. profile->pendingRepeats -= repeatCount;
  1940. profile->nextPeriod += repeatCount;
  1941. profile->lastRampFrequencyHz = entry->setting.actualFrequencyHz;
  1942. if (profile->nextPeriod >= profile->pulseCount)
  1943. {
  1944. profile->active = 0U;
  1945. }
  1946. return 1U;
  1947. }
  1948. /* ACT_TIME never replans the source block into a different trajectory. The
  1949. full configured block is prepared first; this function locates the ACT
  1950. deadline in that block and limits generation to the corresponding prefix.
  1951. The planner prediction uses the same curve integrals and timer quantization
  1952. as the stream generator, so its terminal frequency is safe to carry into
  1953. the next block. */
  1954. static uint8_t PlsrLimitProfileToActTime(
  1955. PLSR_SHORT_PROFILE *profile,
  1956. uint16_t actTimeMs,
  1957. uint8_t *timedCutPlanned)
  1958. {
  1959. return PlsrLimitProfileToActTimeUs(
  1960. profile, (uint32_t)actTimeMs * 1000UL, timedCutPlanned);
  1961. }
  1962. static uint8_t PlsrLimitProfileToActTimeUs(
  1963. PLSR_SHORT_PROFILE *profile,
  1964. uint32_t actTimeUs,
  1965. uint8_t *timedCutPlanned)
  1966. {
  1967. PLSR_PLANNER_TIME_PREDICTION prediction;
  1968. if ((profile == NULL) || (timedCutPlanned == NULL))
  1969. {
  1970. return 0U;
  1971. }
  1972. *timedCutPlanned = 0U;
  1973. if (PlsrPlannerPredictTime(&profile->planner, actTimeUs,
  1974. &prediction) == 0U)
  1975. {
  1976. return 0U;
  1977. }
  1978. if (prediction.deadlineInProfile == 0U)
  1979. {
  1980. return 1U;
  1981. }
  1982. if (prediction.pulseCount > profile->pulseCount)
  1983. {
  1984. return 0U;
  1985. }
  1986. profile->pulseCount = prediction.pulseCount;
  1987. profile->endHz = prediction.actualFrequencyHz;
  1988. if (profile->pulseCount == 0UL)
  1989. {
  1990. profile->active = 0U;
  1991. }
  1992. *timedCutPlanned = 1U;
  1993. return 1U;
  1994. }
  1995. /* Build the replacement stream in the inactive queue bank while the IRQ keeps
  1996. consuming the published bank. A bounded prefix from the old queue bridges
  1997. the construction interval; the final bank flip is the only critical part. */
  1998. static PLSR_PLATFORM_SERVICE_RESULT PlsrReplanPulseDir(
  1999. uint32_t targetHz,
  2000. uint32_t totalPulses,
  2001. uint8_t forceTerminalExit)
  2002. {
  2003. PLSR_PROFILE_QUEUE *source;
  2004. PLSR_PROFILE_QUEUE *destination;
  2005. PLSR_SHORT_PROFILE replacement;
  2006. PLSR_SHORT_PROFILE candidate;
  2007. PLSR_PROFILE_ENTRY entry;
  2008. uint64_t observedPulses;
  2009. uint64_t observedDelta = 0ULL;
  2010. uint64_t appliedPulses = 0ULL;
  2011. uint64_t committedTimeUs;
  2012. uint64_t prefixTimeUs = 0ULL;
  2013. uint64_t prefixTimeLimitUs = PLSR_REPLAN_PREFIX_TIME_US;
  2014. uint64_t prefixPulses = 0ULL;
  2015. uint64_t remainingActTimeUs = 0ULL;
  2016. uint32_t committedPulses;
  2017. uint32_t tailFrequencyHz;
  2018. uint32_t sourceGeneration;
  2019. uint32_t snapshotReadIndex;
  2020. uint32_t snapshotWriteIndex;
  2021. uint32_t currentReadIndex;
  2022. uint32_t availablePlanPulses;
  2023. uint32_t replacementPulses;
  2024. uint32_t prefixCount = 0UL;
  2025. uint32_t replacementStartIndex;
  2026. uint32_t consumedPrefix;
  2027. uint32_t sourceIndex;
  2028. uint32_t criticalState;
  2029. uint32_t epoch;
  2030. uint32_t segmentElapsedMs;
  2031. uint8_t segmentNumber;
  2032. uint8_t handoffBank;
  2033. uint8_t sourceBank;
  2034. uint8_t destinationBank;
  2035. uint8_t boundaryWriteIndex;
  2036. uint8_t pipelineStartsNextSegment = 0U;
  2037. uint8_t tailWasClipped = 0U;
  2038. uint8_t actTimeLimited = 0U;
  2039. uint8_t actTimedCutPlanned = 0U;
  2040. uint16_t fillBudget = PLSR_REPLAN_BUILD_ITEMS;
  2041. criticalState = PlsrPlatformEnterCritical();
  2042. sourceBank = PlsrProfileQueueBank;
  2043. destinationBank = (uint8_t)(sourceBank ^ 1U);
  2044. source = &PlsrProfileQueues[sourceBank];
  2045. destination = &PlsrProfileQueues[destinationBank];
  2046. sourceGeneration = source->generation;
  2047. snapshotReadIndex = source->readIndex;
  2048. snapshotWriteIndex = source->writeIndex;
  2049. epoch = PlsrSegmentEpoch;
  2050. segmentNumber = PlsrCurrentSegment;
  2051. segmentElapsedMs = PlsrSegmentElapsedMs;
  2052. handoffBank = PlsrPreparedHandoffBank;
  2053. boundaryWriteIndex = PlsrCountedBoundaryWriteIndex;
  2054. if ((PlsrPulseActive == 0U) || (segmentNumber == 0U)
  2055. || (segmentNumber > PlsrActiveConfig.segmentCount)
  2056. || (PlsrCountedFaultEvent != 0U))
  2057. {
  2058. PlsrPlatformExitCritical(criticalState);
  2059. return PLSR_PLATFORM_SERVICE_FAILED;
  2060. }
  2061. if (boundaryWriteIndex != PlsrCountedBoundaryReadIndex)
  2062. {
  2063. PlsrPlatformExitCritical(criticalState);
  2064. return PLSR_PLATFORM_SERVICE_DEFERRED;
  2065. }
  2066. if ((forceTerminalExit == 0U)
  2067. && (PlsrActiveConfig.segments[segmentNumber - 1U].waitType
  2068. == PLSR_ACT_TIME))
  2069. {
  2070. uint32_t actTimeMs =
  2071. PlsrActiveConfig.segments[segmentNumber - 1U].actTimeMs;
  2072. actTimeLimited = 1U;
  2073. if (actTimeMs > segmentElapsedMs)
  2074. {
  2075. remainingActTimeUs =
  2076. (uint64_t)(actTimeMs - segmentElapsedMs) * 1000ULL;
  2077. }
  2078. }
  2079. if (PlsrPlatformFinitePipelineSnapshot(
  2080. (uint8_t)PlsrActiveConfig.pulseOutput,
  2081. &observedPulses, &committedPulses, &committedTimeUs,
  2082. &tailFrequencyHz,
  2083. &pipelineStartsNextSegment) == 0U)
  2084. {
  2085. PlsrPlatformExitCritical(criticalState);
  2086. return PLSR_PLATFORM_SERVICE_FAILED;
  2087. }
  2088. if (pipelineStartsNextSegment != 0U)
  2089. {
  2090. PlsrPlatformExitCritical(criticalState);
  2091. return PLSR_PLATFORM_SERVICE_DEFERRED;
  2092. }
  2093. if (forceTerminalExit == 0U)
  2094. {
  2095. /* Reconcile the logical budget to the exact counter sample used to
  2096. calculate the committed hardware tail. A later independent count
  2097. read would reopen the same several-pulse replan race. */
  2098. if (observedPulses < PlsrCountedObservedPublished)
  2099. {
  2100. PlsrPlatformExitCritical(criticalState);
  2101. return PLSR_PLATFORM_SERVICE_FAILED;
  2102. }
  2103. observedDelta = observedPulses - PlsrCountedObservedPublished;
  2104. if ((observedDelta > totalPulses)
  2105. || (observedDelta > PlsrRemainingPulses)
  2106. || (observedDelta > PlsrCommandRemainingPulses))
  2107. {
  2108. PlsrPlatformExitCritical(criticalState);
  2109. return PLSR_PLATFORM_SERVICE_FAILED;
  2110. }
  2111. totalPulses -= (uint32_t)observedDelta;
  2112. if ((totalPulses < committedPulses)
  2113. || (PlsrApplyCountedProgressSnapshot(
  2114. observedPulses, &appliedPulses) == 0U)
  2115. || (appliedPulses != observedDelta))
  2116. {
  2117. PlsrPlatformExitCritical(criticalState);
  2118. return PLSR_PLATFORM_SERVICE_FAILED;
  2119. }
  2120. }
  2121. /* The replacement stream owns the inactive bank from this point. */
  2122. PlsrInvalidateTimedStartLocked();
  2123. PlsrPlatformExitCritical(criticalState);
  2124. if (totalPulses < committedPulses)
  2125. {
  2126. totalPulses = committedPulses;
  2127. }
  2128. availablePlanPulses = totalPulses - committedPulses;
  2129. if (actTimeLimited != 0U)
  2130. {
  2131. if (committedTimeUs >= remainingActTimeUs)
  2132. {
  2133. prefixTimeLimitUs = 0ULL;
  2134. actTimedCutPlanned = 1U;
  2135. }
  2136. else if ((remainingActTimeUs - committedTimeUs)
  2137. < prefixTimeLimitUs)
  2138. {
  2139. prefixTimeLimitUs = remainingActTimeUs - committedTimeUs;
  2140. }
  2141. }
  2142. destination->readIndex = 0UL;
  2143. destination->writeIndex = 0UL;
  2144. destination->repeatRemaining = 0UL;
  2145. destination->underrunDebtPulses = 0UL;
  2146. destination->haveLastSetting = 0U;
  2147. destination->producerEpoch = epoch;
  2148. destination->producerSegment = segmentNumber;
  2149. destination->preparedHandoffBank = handoffBank;
  2150. destination->generatorComplete = 0U;
  2151. destination->active = 0U;
  2152. destination->producerProfile.active = 0U;
  2153. sourceIndex = snapshotReadIndex;
  2154. while ((sourceIndex != snapshotWriteIndex)
  2155. && (prefixCount < PLSR_REPLAN_PREFIX_ITEMS)
  2156. && (prefixPulses < availablePlanPulses)
  2157. && (prefixTimeUs < prefixTimeLimitUs))
  2158. {
  2159. uint32_t remainingPrefixPulses =
  2160. availablePlanPulses - (uint32_t)prefixPulses;
  2161. uint32_t frequencyHz;
  2162. uint64_t remainingPrefixTimeUs;
  2163. uint64_t timeLimitedPulses;
  2164. entry = source->entries[sourceIndex & PLSR_PROFILE_QUEUE_MASK];
  2165. if ((entry.repeatCount == 0UL)
  2166. || (entry.startsNextSegment != 0U))
  2167. {
  2168. break;
  2169. }
  2170. frequencyHz = entry.setting.actualFrequencyHz;
  2171. if (frequencyHz == 0UL)
  2172. {
  2173. return PLSR_PLATFORM_SERVICE_FAILED;
  2174. }
  2175. remainingPrefixTimeUs =
  2176. prefixTimeLimitUs - prefixTimeUs;
  2177. timeLimitedPulses =
  2178. (remainingPrefixTimeUs * frequencyHz + 999999ULL) / 1000000ULL;
  2179. if (timeLimitedPulses == 0ULL)
  2180. {
  2181. timeLimitedPulses = 1ULL;
  2182. }
  2183. if (entry.repeatCount > timeLimitedPulses)
  2184. {
  2185. entry.repeatCount = (uint32_t)timeLimitedPulses;
  2186. tailWasClipped = 1U;
  2187. }
  2188. if (entry.repeatCount > remainingPrefixPulses)
  2189. {
  2190. entry.repeatCount = remainingPrefixPulses;
  2191. tailWasClipped = 1U;
  2192. }
  2193. destination->entries[prefixCount] = entry;
  2194. prefixCount++;
  2195. sourceIndex++;
  2196. prefixPulses += entry.repeatCount;
  2197. prefixTimeUs +=
  2198. ((uint64_t)entry.repeatCount * 1000000ULL
  2199. + frequencyHz - 1UL) / frequencyHz;
  2200. tailFrequencyHz = frequencyHz;
  2201. }
  2202. replacementPulses = availablePlanPulses - (uint32_t)prefixPulses;
  2203. if ((actTimeLimited != 0U)
  2204. && ((committedTimeUs + prefixTimeUs) >= remainingActTimeUs))
  2205. {
  2206. replacementPulses = 0UL;
  2207. totalPulses = committedPulses + (uint32_t)prefixPulses;
  2208. actTimedCutPlanned = 1U;
  2209. }
  2210. replacementStartIndex = prefixCount;
  2211. if (replacementPulses != 0UL)
  2212. {
  2213. if ((tailFrequencyHz == 0UL)
  2214. || (PlsrPrepareShortProfile(&replacement, &PlsrActiveConfig,
  2215. segmentNumber,
  2216. tailFrequencyHz, targetHz,
  2217. replacementPulses,
  2218. PlsrCountPositive,
  2219. forceTerminalExit) == 0U))
  2220. {
  2221. return PLSR_PLATFORM_SERVICE_FAILED;
  2222. }
  2223. if (actTimeLimited != 0U)
  2224. {
  2225. uint64_t consumedTimeUs = committedTimeUs + prefixTimeUs;
  2226. uint64_t replacementTimeUs =
  2227. (remainingActTimeUs > consumedTimeUs)
  2228. ? remainingActTimeUs - consumedTimeUs : 0ULL;
  2229. if ((replacementTimeUs > 0xFFFFFFFFULL)
  2230. || (PlsrLimitProfileToActTimeUs(
  2231. &replacement, (uint32_t)replacementTimeUs,
  2232. &actTimedCutPlanned) == 0U))
  2233. {
  2234. return PLSR_PLATFORM_SERVICE_FAILED;
  2235. }
  2236. replacementPulses = replacement.pulseCount;
  2237. totalPulses = committedPulses + (uint32_t)prefixPulses
  2238. + replacementPulses;
  2239. }
  2240. PlsrCopyShortProfile(&destination->producerProfile, &replacement);
  2241. destination->active = 1U;
  2242. candidate = replacement;
  2243. while ((fillBudget != 0U)
  2244. && (prefixCount < PLSR_PROFILE_QUEUE_CAPACITY)
  2245. && (candidate.active != 0U))
  2246. {
  2247. fillBudget--;
  2248. if (PlsrShortProfileTakeRun(&candidate, &entry) == 0U)
  2249. {
  2250. return PLSR_PLATFORM_SERVICE_FAILED;
  2251. }
  2252. if ((prefixCount > replacementStartIndex)
  2253. && (destination->entries[prefixCount - 1UL]
  2254. .startsNextSegment == 0U)
  2255. && (PlsrTimerSettingsEqual(
  2256. &destination->entries[prefixCount - 1UL].setting,
  2257. &entry.setting) != 0U)
  2258. && (entry.repeatCount <= PlsrProfileRunLimit(
  2259. entry.setting.actualFrequencyHz))
  2260. && (destination->entries[prefixCount - 1UL].repeatCount
  2261. <= (PlsrProfileRunLimit(entry.setting.actualFrequencyHz)
  2262. - entry.repeatCount))
  2263. && (destination->entries[prefixCount - 1UL].repeatCount
  2264. <= (0xFFFFFFFFUL - entry.repeatCount)))
  2265. {
  2266. destination->entries[prefixCount - 1UL].repeatCount +=
  2267. entry.repeatCount;
  2268. }
  2269. else
  2270. {
  2271. destination->entries[prefixCount++] = entry;
  2272. }
  2273. }
  2274. PlsrCopyShortProfile(&destination->producerProfile, &candidate);
  2275. destination->generatorComplete =
  2276. ((candidate.active == 0U)
  2277. || (candidate.nextPeriod >= candidate.pulseCount)) ? 1U : 0U;
  2278. }
  2279. else
  2280. {
  2281. (void)memset(&replacement, 0, sizeof(replacement));
  2282. replacement.endHz = tailFrequencyHz;
  2283. destination->generatorComplete = 1U;
  2284. destination->active = (prefixCount != 0UL) ? 1U : 0U;
  2285. }
  2286. destination->writeIndex = prefixCount;
  2287. criticalState = PlsrPlatformEnterCritical();
  2288. source = &PlsrProfileQueues[sourceBank];
  2289. currentReadIndex = source->readIndex;
  2290. if ((PlsrProfileQueueBank != sourceBank)
  2291. || (source->generation != sourceGeneration)
  2292. || (source->writeIndex != snapshotWriteIndex)
  2293. || (PlsrSegmentEpoch != epoch)
  2294. || (PlsrCurrentSegment != segmentNumber)
  2295. || (PlsrCountedBoundaryWriteIndex != boundaryWriteIndex)
  2296. || (PlsrCountedFaultEvent != 0U)
  2297. || (currentReadIndex < snapshotReadIndex)
  2298. || ((currentReadIndex - snapshotReadIndex) > prefixCount)
  2299. || ((tailWasClipped != 0U)
  2300. && ((currentReadIndex - snapshotReadIndex) >= prefixCount)))
  2301. {
  2302. PlsrPlatformExitCritical(criticalState);
  2303. return PLSR_PLATFORM_SERVICE_DEFERRED;
  2304. }
  2305. consumedPrefix = currentReadIndex - snapshotReadIndex;
  2306. destination->readIndex = consumedPrefix;
  2307. destination->generation = sourceGeneration + 1UL;
  2308. PlsrRamp.active = 0U;
  2309. PlsrHandoffPlan.valid = 0U;
  2310. PlsrCountedHandoffStaged = 0U;
  2311. PlsrActTimedCutPlanned = actTimedCutPlanned;
  2312. PlsrProfileQueueBank = destinationBank;
  2313. PlsrCopyShortProfile(&PlsrShortProfile,
  2314. &destination->producerProfile);
  2315. PlsrRemainingPulses = totalPulses;
  2316. PlsrProfileQueueMinimumDepth =
  2317. (uint16_t)(prefixCount - consumedPrefix);
  2318. PlsrProfileQueueLowWaterLatched = 0U;
  2319. PlsrExecutor.generation++;
  2320. PlsrExecutor.mode = (destination->generatorComplete != 0U)
  2321. ? PLSR_EXEC_STEP_TABLE : PLSR_EXEC_STREAM;
  2322. PlsrPlatformExitCritical(criticalState);
  2323. PlsrProfileRecordPlannerStatus(&replacement);
  2324. PlsrRefreshCurrentHandoffPlan(replacement.endHz);
  2325. return PLSR_PLATFORM_SERVICE_READY;
  2326. }
  2327. static void PlsrCopyShortProfile(PLSR_SHORT_PROFILE *destination,
  2328. const PLSR_SHORT_PROFILE *source)
  2329. {
  2330. *destination = *source;
  2331. }
  2332. static uint16_t PlsrProfileQueueCount(void)
  2333. {
  2334. uint32_t writeIndex = PlsrProfileQueue.writeIndex;
  2335. uint32_t readIndex = PlsrProfileQueue.readIndex;
  2336. return (uint16_t)(writeIndex - readIndex);
  2337. }
  2338. static void PlsrProfileQueueRecordDepth(uint16_t depth)
  2339. {
  2340. if (depth < PlsrProfileQueueMinimumDepth)
  2341. {
  2342. PlsrProfileQueueMinimumDepth = depth;
  2343. }
  2344. if (depth <= PLSR_PROFILE_LOW_WATER)
  2345. {
  2346. PlsrProfileQueueDiagnosticFlags |= PLSR_QUEUE_DIAG_LOW_WATER;
  2347. if (PlsrProfileQueueLowWaterLatched == 0U)
  2348. {
  2349. PlsrProfileQueueLowWaterLatched = 1U;
  2350. if (PlsrProfileQueueLowWaterEvents != 0xFFFFFFFFUL)
  2351. {
  2352. PlsrProfileQueueLowWaterEvents++;
  2353. }
  2354. }
  2355. }
  2356. else if (depth >= PLSR_PROFILE_LOW_WATER_CLEAR)
  2357. {
  2358. PlsrProfileQueueLowWaterLatched = 0U;
  2359. }
  2360. }
  2361. static void PlsrProfileQueueRecordUnderrun(void)
  2362. {
  2363. PlsrProfileQueueDiagnosticFlags |= PLSR_QUEUE_DIAG_UNDERRUN;
  2364. if (PlsrProfileQueueUnderruns != 0xFFFFFFFFUL)
  2365. {
  2366. PlsrProfileQueueUnderruns++;
  2367. }
  2368. }
  2369. static void PlsrProfileRecordPlannerStatus(
  2370. const PLSR_SHORT_PROFILE *profile)
  2371. {
  2372. if ((profile != NULL) && (profile->planner.clipped != 0U))
  2373. {
  2374. uint32_t criticalState = PlsrPlatformEnterCritical();
  2375. PlsrProfileQueueDiagnosticFlags |=
  2376. PLSR_QUEUE_DIAG_PLANNER_CLIPPED;
  2377. if (PlsrPlannerClippedCount != 0xFFFFFFFFUL)
  2378. {
  2379. PlsrPlannerClippedCount++;
  2380. }
  2381. PlsrPlatformExitCritical(criticalState);
  2382. }
  2383. }
  2384. static void PlsrInvalidateTimedStartLocked(void)
  2385. {
  2386. PlsrTimedStart.building = 0U;
  2387. PlsrTimedStart.valid = 0U;
  2388. PlsrTimedStart.pendingActivation = 0U;
  2389. PlsrTimedStart.nextActTimedCut = 0U;
  2390. PlsrTimedStart.resolvedDisplacement = 0;
  2391. }
  2392. static void PlsrProfileQueueResetBankLocked(uint8_t bank)
  2393. {
  2394. PLSR_PROFILE_QUEUE *queue = &PlsrProfileQueues[bank & 1U];
  2395. queue->generation++;
  2396. queue->readIndex = 0U;
  2397. queue->writeIndex = 0U;
  2398. queue->active = 0U;
  2399. queue->generatorComplete = 0U;
  2400. queue->producerEpoch = 0UL;
  2401. queue->repeatRemaining = 0UL;
  2402. queue->underrunDebtPulses = 0UL;
  2403. queue->producerSegment = 0U;
  2404. queue->preparedHandoffBank = 0U;
  2405. queue->haveLastSetting = 0U;
  2406. queue->producerProfile.active = 0U;
  2407. }
  2408. static void PlsrProfileQueueReset(void)
  2409. {
  2410. uint32_t criticalState = PlsrPlatformEnterCritical();
  2411. uint8_t bank;
  2412. PlsrInvalidateTimedStartLocked();
  2413. for (bank = 0U; bank < 2U; bank++)
  2414. {
  2415. PlsrProfileQueueResetBankLocked(bank);
  2416. }
  2417. PlsrProfileQueueBank = 0U;
  2418. PlsrProfileQueueLowWaterLatched = 0U;
  2419. PlsrPlatformExitCritical(criticalState);
  2420. }
  2421. static uint8_t PlsrProfileQueueBegin(
  2422. const PLSR_SHORT_PROFILE *producerProfile,
  2423. uint32_t producerEpoch,
  2424. uint8_t producerSegment,
  2425. uint8_t preparedHandoffBank)
  2426. {
  2427. uint32_t criticalState = PlsrPlatformEnterCritical();
  2428. PLSR_PROFILE_QUEUE *queue =
  2429. &PlsrProfileQueues[PlsrProfileQueueBank];
  2430. queue->generation++;
  2431. queue->readIndex = 0U;
  2432. queue->writeIndex = 0U;
  2433. queue->producerEpoch = producerEpoch;
  2434. queue->producerSegment = producerSegment;
  2435. queue->preparedHandoffBank = preparedHandoffBank;
  2436. queue->generatorComplete = 0U;
  2437. queue->repeatRemaining = 0UL;
  2438. queue->underrunDebtPulses = 0UL;
  2439. queue->haveLastSetting = 0U;
  2440. PlsrProfileQueueMinimumDepth = PLSR_PROFILE_QUEUE_CAPACITY;
  2441. PlsrProfileQueueLowWaterLatched = 0U;
  2442. PlsrCopyShortProfile(&queue->producerProfile, producerProfile);
  2443. PlsrProfileRecordPlannerStatus(producerProfile);
  2444. queue->active =
  2445. ((producerProfile->active != 0U)
  2446. && (producerProfile->nextPeriod < producerProfile->pulseCount))
  2447. ? 1U : 0U;
  2448. if (queue->active == 0U)
  2449. {
  2450. queue->generatorComplete = 1U;
  2451. }
  2452. PlsrPlatformExitCritical(criticalState);
  2453. return 1U;
  2454. }
  2455. static void PlsrProfileQueueInvalidateGeneration(void)
  2456. {
  2457. uint32_t criticalState = PlsrPlatformEnterCritical();
  2458. PLSR_PROFILE_QUEUE *queue =
  2459. &PlsrProfileQueues[PlsrProfileQueueBank];
  2460. queue->generation++;
  2461. queue->active = 0U;
  2462. queue->generatorComplete = 0U;
  2463. queue->readIndex = 0U;
  2464. queue->writeIndex = 0U;
  2465. queue->repeatRemaining = 0UL;
  2466. queue->underrunDebtPulses = 0UL;
  2467. queue->haveLastSetting = 0U;
  2468. PlsrPlatformExitCritical(criticalState);
  2469. }
  2470. /* Called with pulse IRQs masked. Quantized-equal adjacent settings form one
  2471. hardware run even if their requested ramp frequencies differ. Segment
  2472. markers remain separate because their completion owns the boundary event. */
  2473. static uint8_t PlsrTimerSettingsEqual(
  2474. const PLSR_PLATFORM_TIMER_SETTING *first,
  2475. const PLSR_PLATFORM_TIMER_SETTING *second)
  2476. {
  2477. return ((first->actualFrequencyHz == second->actualFrequencyHz)
  2478. && (first->prescaler == second->prescaler)
  2479. && (first->pairPrescaler == second->pairPrescaler)
  2480. && (first->period == second->period)
  2481. && (first->compare == second->compare)) ? 1U : 0U;
  2482. }
  2483. static uint8_t PlsrProfileEntryTryMerge(
  2484. PLSR_PROFILE_ENTRY *previous,
  2485. const PLSR_PROFILE_ENTRY *entry)
  2486. {
  2487. uint32_t runLimit;
  2488. if ((previous == NULL) || (entry == NULL)
  2489. || (previous->startsNextSegment != 0U)
  2490. || (entry->startsNextSegment != 0U)
  2491. || (PlsrTimerSettingsEqual(&previous->setting,
  2492. &entry->setting) == 0U))
  2493. {
  2494. return 0U;
  2495. }
  2496. runLimit = PlsrProfileRunLimit(
  2497. previous->setting.actualFrequencyHz);
  2498. if ((entry->repeatCount > runLimit)
  2499. || (previous->repeatCount > (runLimit - entry->repeatCount))
  2500. || (previous->repeatCount
  2501. > (0xFFFFFFFFUL - entry->repeatCount)))
  2502. {
  2503. return 0U;
  2504. }
  2505. previous->repeatCount += entry->repeatCount;
  2506. return 1U;
  2507. }
  2508. static uint8_t PlsrProfileQueueAppendLocked(
  2509. PLSR_PROFILE_QUEUE *queue,
  2510. const PLSR_PROFILE_ENTRY *entry)
  2511. {
  2512. PLSR_PROFILE_ENTRY *previous;
  2513. uint32_t writeIndex;
  2514. if ((queue == NULL) || (entry == NULL) || (entry->repeatCount == 0UL))
  2515. {
  2516. return 0U;
  2517. }
  2518. writeIndex = queue->writeIndex;
  2519. if (writeIndex != queue->readIndex)
  2520. {
  2521. previous = &queue->entries[
  2522. (writeIndex - 1UL) & PLSR_PROFILE_QUEUE_MASK];
  2523. if (PlsrProfileEntryTryMerge(previous, entry) != 0U)
  2524. {
  2525. return 1U;
  2526. }
  2527. }
  2528. if ((writeIndex - queue->readIndex) >= PLSR_PROFILE_QUEUE_CAPACITY)
  2529. {
  2530. return 0U;
  2531. }
  2532. queue->entries[writeIndex & PLSR_PROFILE_QUEUE_MASK] = *entry;
  2533. queue->writeIndex = writeIndex + 1UL;
  2534. return 1U;
  2535. }
  2536. static void PlsrServiceTimedStartPreparation(void)
  2537. {
  2538. PLSR_PROFILE_QUEUE *queue;
  2539. PLSR_SHORT_PROFILE profile;
  2540. PLSR_PROFILE_ENTRY entry;
  2541. PLSR_HANDOFF_PLAN *handoff;
  2542. uint32_t criticalState;
  2543. uint32_t sourceEpoch;
  2544. uint32_t queueGeneration;
  2545. uint32_t targetFrequencyHz;
  2546. uint32_t startFrequencyHz;
  2547. uint64_t remaining;
  2548. int64_t predictedPosition;
  2549. int64_t displacement;
  2550. uint64_t magnitude;
  2551. int32_t position;
  2552. uint16_t budget;
  2553. uint16_t sourceWaitType;
  2554. uint8_t sourceSegment;
  2555. uint8_t nextSegment;
  2556. uint8_t positive;
  2557. uint8_t directionLevel;
  2558. uint8_t directionChanged;
  2559. uint8_t queueBank;
  2560. uint8_t nextActTimedCut = 0U;
  2561. uint8_t sourceWaiting;
  2562. uint8_t coldStartBoundary;
  2563. if ((PlsrActiveConfig.outputMode != PLSR_OUTPUT_PULSE_DIR)
  2564. || (PlsrStopRequested != 0U)
  2565. || (PlsrTimedStart.pendingActivation != 0U))
  2566. {
  2567. return;
  2568. }
  2569. criticalState = PlsrPlatformEnterCritical();
  2570. sourceEpoch = PlsrSegmentEpoch;
  2571. sourceSegment = PlsrCurrentSegment;
  2572. sourceWaiting = (PlsrRunStatus == PLSR_STATUS_WAITING) ? 1U : 0U;
  2573. if ((sourceSegment == 0U)
  2574. || (sourceSegment > PlsrActiveConfig.segmentCount))
  2575. {
  2576. PlsrInvalidateTimedStartLocked();
  2577. PlsrPlatformExitCritical(criticalState);
  2578. return;
  2579. }
  2580. sourceWaitType =
  2581. PlsrActiveConfig.segments[sourceSegment - 1U].waitType;
  2582. if ((PlsrTimedStart.building != 0U)
  2583. || (PlsrTimedStart.valid != 0U))
  2584. {
  2585. if ((PlsrTimedStart.sourceEpoch != sourceEpoch)
  2586. || (PlsrTimedStart.sourceSegment != sourceSegment)
  2587. || (PlsrTimedStart.queueBank == PlsrProfileQueueBank)
  2588. || (PlsrProfileQueues[PlsrTimedStart.queueBank].generation
  2589. != PlsrTimedStart.queueGeneration))
  2590. {
  2591. PlsrInvalidateTimedStartLocked();
  2592. }
  2593. else
  2594. {
  2595. PlsrPlatformExitCritical(criticalState);
  2596. if (PlsrTimedStart.valid != 0U)
  2597. {
  2598. return;
  2599. }
  2600. goto fill_timed_start;
  2601. }
  2602. }
  2603. position = PlsrPosition;
  2604. remaining = PlsrRemainingPulses;
  2605. positive = PlsrCountPositive;
  2606. PlsrPlatformExitCritical(criticalState);
  2607. if (positive != 0U)
  2608. {
  2609. predictedPosition = (int64_t)position + (int64_t)remaining;
  2610. }
  2611. else
  2612. {
  2613. predictedPosition = (int64_t)position - (int64_t)remaining;
  2614. }
  2615. if ((predictedPosition > (int64_t)INT32_MAX)
  2616. || (predictedPosition < (int64_t)INT32_MIN))
  2617. {
  2618. return;
  2619. }
  2620. if (PlsrResolveNextMotionSegment(
  2621. sourceSegment, (int32_t)predictedPosition,
  2622. &nextSegment, &displacement) == 0U)
  2623. {
  2624. return;
  2625. }
  2626. positive = (displacement > 0) ? 1U : 0U;
  2627. magnitude = (displacement < 0) ? (uint64_t)(-displacement)
  2628. : (uint64_t)displacement;
  2629. if (magnitude > 0xFFFFFFFFULL)
  2630. {
  2631. return;
  2632. }
  2633. directionLevel = positive;
  2634. if (PlsrActiveConfig.directionNegativeLogic != 0U)
  2635. {
  2636. directionLevel ^= 1U;
  2637. }
  2638. directionChanged = ((PlsrLastDirectionValid == 0U)
  2639. || (PlsrLastDirectionOutput
  2640. != (uint8_t)PlsrActiveConfig.directionOutput)
  2641. || (PlsrLastDirectionLevel != directionLevel)) ? 1U : 0U;
  2642. coldStartBoundary = ((sourceWaitType == PLSR_WAIT_TIME)
  2643. || (sourceWaitType == PLSR_WAIT_SIGNAL)
  2644. || (((sourceWaitType == PLSR_ACT_TIME)
  2645. || (sourceWaitType == PLSR_EXT_SIGNAL))
  2646. && (sourceWaiting != 0U))) ? 1U : 0U;
  2647. if ((coldStartBoundary == 0U) && (directionChanged == 0U))
  2648. {
  2649. criticalState = PlsrPlatformEnterCritical();
  2650. PlsrInvalidateTimedStartLocked();
  2651. PlsrPlatformExitCritical(criticalState);
  2652. return;
  2653. }
  2654. targetFrequencyHz =
  2655. PlsrActiveConfig.segments[nextSegment - 1U].frequencyHz;
  2656. startFrequencyHz = PlsrPulseDirStartFrequency(
  2657. targetFrequencyHz, PLSR_SEGMENT_ENTRY_INTERNAL_RESTART,
  2658. directionChanged, 0UL);
  2659. if (PlsrPrepareShortProfile(&profile, &PlsrActiveConfig, nextSegment,
  2660. startFrequencyHz, targetFrequencyHz,
  2661. magnitude, positive, 0U) == 0U)
  2662. {
  2663. return;
  2664. }
  2665. if ((PlsrActiveConfig.segments[nextSegment - 1U].waitType
  2666. == PLSR_ACT_TIME)
  2667. && ((PlsrLimitProfileToActTime(
  2668. &profile,
  2669. PlsrActiveConfig.segments[nextSegment - 1U].actTimeMs,
  2670. &nextActTimedCut) == 0U)
  2671. || (profile.pulseCount == 0UL)))
  2672. {
  2673. return;
  2674. }
  2675. magnitude = profile.pulseCount;
  2676. if (PlsrShortProfileTakeRun(&profile, &entry) == 0U)
  2677. {
  2678. return;
  2679. }
  2680. /* Keep the seamless plan for this future segment consistent with its
  2681. possibly clipped terminal frequency. */
  2682. handoff = &PlsrPreparedHandoffPlans[PlsrPreparedHandoffBank]
  2683. [nextSegment - 1U];
  2684. (void)PlsrBuildHandoffPlan(nextSegment, &PlsrActiveConfig,
  2685. profile.endHz, handoff);
  2686. criticalState = PlsrPlatformEnterCritical();
  2687. if ((PlsrSegmentEpoch != sourceEpoch)
  2688. || (PlsrCurrentSegment != sourceSegment))
  2689. {
  2690. PlsrPlatformExitCritical(criticalState);
  2691. return;
  2692. }
  2693. queueBank = (uint8_t)(PlsrProfileQueueBank ^ 1U);
  2694. PlsrProfileQueueResetBankLocked(queueBank);
  2695. queue = &PlsrProfileQueues[queueBank];
  2696. queue->producerEpoch = sourceEpoch + 1UL;
  2697. queue->producerSegment = nextSegment;
  2698. queue->preparedHandoffBank = PlsrPreparedHandoffBank;
  2699. queue->repeatRemaining = 0UL;
  2700. queue->underrunDebtPulses = 0UL;
  2701. queue->haveLastSetting = 0U;
  2702. PlsrCopyShortProfile(&queue->producerProfile, &profile);
  2703. queue->active = 1U;
  2704. queue->generatorComplete = (profile.active == 0U) ? 1U : 0U;
  2705. PlsrTimedStart.firstRun = entry;
  2706. PlsrTimedStart.magnitude = magnitude;
  2707. PlsrTimedStart.resolvedDisplacement = displacement;
  2708. PlsrTimedStart.sourceEpoch = sourceEpoch;
  2709. PlsrTimedStart.queueGeneration = queue->generation;
  2710. PlsrTimedStart.generatedItems = 0U;
  2711. PlsrTimedStart.sourceSegment = sourceSegment;
  2712. PlsrTimedStart.nextSegment = nextSegment;
  2713. PlsrTimedStart.positive = positive;
  2714. PlsrTimedStart.directionLevel = directionLevel;
  2715. PlsrTimedStart.directionChanged = directionChanged;
  2716. PlsrTimedStart.queueBank = queueBank;
  2717. PlsrTimedStart.nextActTimedCut = nextActTimedCut;
  2718. PlsrTimedStart.valid = (queue->generatorComplete != 0U) ? 1U : 0U;
  2719. PlsrTimedStart.building = (PlsrTimedStart.valid == 0U) ? 1U : 0U;
  2720. PlsrTimedStart.pendingActivation = 0U;
  2721. PlsrPlatformExitCritical(criticalState);
  2722. PlsrProfileRecordPlannerStatus(&profile);
  2723. fill_timed_start:
  2724. budget = PLSR_TIMED_START_BUILD_BUDGET;
  2725. while (budget != 0U)
  2726. {
  2727. criticalState = PlsrPlatformEnterCritical();
  2728. queueBank = PlsrTimedStart.queueBank;
  2729. queue = &PlsrProfileQueues[queueBank];
  2730. queueGeneration = PlsrTimedStart.queueGeneration;
  2731. if ((PlsrTimedStart.building == 0U)
  2732. || (PlsrTimedStart.sourceEpoch != PlsrSegmentEpoch)
  2733. || (PlsrTimedStart.sourceSegment != PlsrCurrentSegment)
  2734. || (queueBank == PlsrProfileQueueBank)
  2735. || (queue->generation != queueGeneration))
  2736. {
  2737. PlsrInvalidateTimedStartLocked();
  2738. PlsrPlatformExitCritical(criticalState);
  2739. return;
  2740. }
  2741. PlsrCopyShortProfile(&profile, &queue->producerProfile);
  2742. PlsrPlatformExitCritical(criticalState);
  2743. if (PlsrShortProfileTakeRun(&profile, &entry) == 0U)
  2744. {
  2745. criticalState = PlsrPlatformEnterCritical();
  2746. if ((PlsrTimedStart.building != 0U)
  2747. && (queue->generation == queueGeneration))
  2748. {
  2749. queue->generatorComplete = 1U;
  2750. PlsrTimedStart.building = 0U;
  2751. PlsrTimedStart.valid = 1U;
  2752. }
  2753. PlsrPlatformExitCritical(criticalState);
  2754. return;
  2755. }
  2756. criticalState = PlsrPlatformEnterCritical();
  2757. if ((PlsrTimedStart.building == 0U)
  2758. || (PlsrTimedStart.sourceEpoch != PlsrSegmentEpoch)
  2759. || (queueBank == PlsrProfileQueueBank)
  2760. || (queue->generation != queueGeneration))
  2761. {
  2762. PlsrInvalidateTimedStartLocked();
  2763. PlsrPlatformExitCritical(criticalState);
  2764. return;
  2765. }
  2766. if (PlsrProfileQueueAppendLocked(queue, &entry) == 0U)
  2767. {
  2768. PlsrInvalidateTimedStartLocked();
  2769. PlsrPlatformExitCritical(criticalState);
  2770. return;
  2771. }
  2772. PlsrCopyShortProfile(&queue->producerProfile, &profile);
  2773. if (PlsrTimedStart.generatedItems != 0xFFFFU)
  2774. {
  2775. PlsrTimedStart.generatedItems++;
  2776. }
  2777. if ((profile.active == 0U)
  2778. || (profile.nextPeriod >= profile.pulseCount))
  2779. {
  2780. queue->generatorComplete = 1U;
  2781. }
  2782. if ((PlsrTimedStart.generatedItems
  2783. >= PLSR_TIMED_START_READY_ITEMS)
  2784. || (queue->generatorComplete != 0U))
  2785. {
  2786. PlsrTimedStart.building = 0U;
  2787. PlsrTimedStart.valid = 1U;
  2788. PlsrPlatformExitCritical(criticalState);
  2789. return;
  2790. }
  2791. PlsrPlatformExitCritical(criticalState);
  2792. budget--;
  2793. }
  2794. }
  2795. /* Boundary-triggered reversals are normally prepared incrementally while the
  2796. source segment is running. If a very short segment reaches its boundary
  2797. first, finish the bounded remainder before changing the direction pin so
  2798. planner time is never included in the configured direction setup time. */
  2799. static void PlsrCompleteTimedStartPreparation(void)
  2800. {
  2801. uint16_t pass;
  2802. uint32_t criticalState;
  2803. uint8_t building;
  2804. uint8_t valid;
  2805. for (pass = 0U;
  2806. pass < (uint16_t)(PLSR_TIMED_START_READY_ITEMS
  2807. / PLSR_TIMED_START_BUILD_BUDGET + 2U);
  2808. pass++)
  2809. {
  2810. criticalState = PlsrPlatformEnterCritical();
  2811. building = PlsrTimedStart.building;
  2812. valid = PlsrTimedStart.valid;
  2813. PlsrPlatformExitCritical(criticalState);
  2814. if (valid != 0U)
  2815. {
  2816. return;
  2817. }
  2818. PlsrServiceTimedStartPreparation();
  2819. criticalState = PlsrPlatformEnterCritical();
  2820. if ((PlsrTimedStart.building == 0U)
  2821. && (PlsrTimedStart.valid == 0U)
  2822. && (building == 0U))
  2823. {
  2824. PlsrPlatformExitCritical(criticalState);
  2825. return;
  2826. }
  2827. PlsrPlatformExitCritical(criticalState);
  2828. }
  2829. }
  2830. /* Prepare the current segment before PlsrPlatformPrepare changes the
  2831. direction pin. The delay interval then contains no bulk startup-profile
  2832. generation or queue fill; expiry publishes this inactive bank and starts
  2833. the timer. */
  2834. static PLSR_PLATFORM_SERVICE_RESULT PlsrPrepareDelayedCurrentOutput(
  2835. uint32_t startFrequencyHz,
  2836. uint8_t directionLevel,
  2837. uint8_t directionChanged)
  2838. {
  2839. PLSR_SHORT_PROFILE profile;
  2840. PLSR_PROFILE_ENTRY firstRun;
  2841. PLSR_PROFILE_ENTRY entry;
  2842. PLSR_PROFILE_QUEUE *queue;
  2843. uint64_t remainingPulses = PlsrRemainingSnapshot();
  2844. uint32_t targetFrequencyHz =
  2845. PlsrActiveConfig.segments[PlsrCurrentSegment - 1U].frequencyHz;
  2846. uint32_t criticalState;
  2847. uint32_t queueGeneration;
  2848. uint16_t generatedItems = 0U;
  2849. uint8_t countPositive;
  2850. uint8_t queueBank;
  2851. uint8_t timedCutPlanned = 0U;
  2852. criticalState = PlsrPlatformEnterCritical();
  2853. countPositive = PlsrCountPositive;
  2854. PlsrPlatformExitCritical(criticalState);
  2855. if (PlsrPrepareShortProfile(&profile, &PlsrActiveConfig,
  2856. PlsrCurrentSegment,
  2857. startFrequencyHz, targetFrequencyHz,
  2858. remainingPulses,
  2859. countPositive, 0U) == 0U)
  2860. {
  2861. return PLSR_PLATFORM_SERVICE_FAILED;
  2862. }
  2863. if ((PlsrActiveConfig.segments[PlsrCurrentSegment - 1U].waitType
  2864. == PLSR_ACT_TIME)
  2865. && (PlsrLimitProfileToActTime(
  2866. &profile,
  2867. PlsrActiveConfig.segments[PlsrCurrentSegment - 1U].actTimeMs,
  2868. &timedCutPlanned) == 0U))
  2869. {
  2870. return PLSR_PLATFORM_SERVICE_FAILED;
  2871. }
  2872. if (profile.pulseCount == 0UL)
  2873. {
  2874. return PLSR_PLATFORM_SERVICE_DEFERRED;
  2875. }
  2876. if (PlsrShortProfileTakeRun(&profile, &firstRun) == 0U)
  2877. {
  2878. return PLSR_PLATFORM_SERVICE_FAILED;
  2879. }
  2880. criticalState = PlsrPlatformEnterCritical();
  2881. queueBank = (uint8_t)(PlsrProfileQueueBank ^ 1U);
  2882. PlsrProfileQueueResetBankLocked(queueBank);
  2883. queue = &PlsrProfileQueues[queueBank];
  2884. queueGeneration = queue->generation;
  2885. queue->producerEpoch = PlsrSegmentEpoch;
  2886. queue->producerSegment = PlsrCurrentSegment;
  2887. queue->preparedHandoffBank = PlsrPreparedHandoffBank;
  2888. queue->repeatRemaining = 0UL;
  2889. queue->underrunDebtPulses = 0UL;
  2890. queue->haveLastSetting = 0U;
  2891. PlsrCopyShortProfile(&queue->producerProfile, &profile);
  2892. queue->active = 1U;
  2893. queue->generatorComplete = (profile.active == 0U) ? 1U : 0U;
  2894. PlsrPlatformExitCritical(criticalState);
  2895. while ((generatedItems < PLSR_TIMED_START_READY_ITEMS)
  2896. && (profile.active != 0U))
  2897. {
  2898. if (PlsrShortProfileTakeRun(&profile, &entry) == 0U)
  2899. {
  2900. return PLSR_PLATFORM_SERVICE_FAILED;
  2901. }
  2902. criticalState = PlsrPlatformEnterCritical();
  2903. queue = &PlsrProfileQueues[queueBank];
  2904. if ((queue->generation != queueGeneration)
  2905. || (queueBank == PlsrProfileQueueBank)
  2906. || (PlsrProfileQueueAppendLocked(queue, &entry) == 0U))
  2907. {
  2908. PlsrPlatformExitCritical(criticalState);
  2909. return PLSR_PLATFORM_SERVICE_FAILED;
  2910. }
  2911. PlsrCopyShortProfile(&queue->producerProfile, &profile);
  2912. if ((profile.active == 0U)
  2913. || (profile.nextPeriod >= profile.pulseCount))
  2914. {
  2915. queue->generatorComplete = 1U;
  2916. }
  2917. PlsrPlatformExitCritical(criticalState);
  2918. generatedItems++;
  2919. }
  2920. criticalState = PlsrPlatformEnterCritical();
  2921. queue = &PlsrProfileQueues[queueBank];
  2922. if ((queue->generation != queueGeneration)
  2923. || (queueBank == PlsrProfileQueueBank))
  2924. {
  2925. PlsrPlatformExitCritical(criticalState);
  2926. return PLSR_PLATFORM_SERVICE_FAILED;
  2927. }
  2928. PlsrTimedStart.firstRun = firstRun;
  2929. PlsrTimedStart.magnitude = profile.pulseCount;
  2930. PlsrTimedStart.resolvedDisplacement = (countPositive != 0U)
  2931. ? (int64_t)remainingPulses
  2932. : -(int64_t)remainingPulses;
  2933. PlsrTimedStart.sourceEpoch = PlsrSegmentEpoch - 1UL;
  2934. PlsrTimedStart.queueGeneration = queueGeneration;
  2935. PlsrTimedStart.generatedItems = generatedItems;
  2936. PlsrTimedStart.sourceSegment = PlsrCurrentSegment;
  2937. PlsrTimedStart.nextSegment = PlsrCurrentSegment;
  2938. PlsrTimedStart.positive = countPositive;
  2939. PlsrTimedStart.directionLevel = directionLevel;
  2940. PlsrTimedStart.directionChanged = directionChanged;
  2941. PlsrTimedStart.queueBank = queueBank;
  2942. PlsrTimedStart.nextActTimedCut = timedCutPlanned;
  2943. PlsrTimedStart.building = 0U;
  2944. PlsrTimedStart.valid = 1U;
  2945. PlsrTimedStart.pendingActivation = 1U;
  2946. PlsrRemainingPulses = profile.pulseCount;
  2947. PlsrActTimedCutPlanned = timedCutPlanned;
  2948. PlsrPlatformExitCritical(criticalState);
  2949. PlsrProfileRecordPlannerStatus(&profile);
  2950. return PLSR_PLATFORM_SERVICE_READY;
  2951. }
  2952. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  2953. && !defined(PLSR_HOST_TEST)
  2954. static uint32_t PlsrProfileTimingNow(void)
  2955. {
  2956. return *((volatile uint32_t *)0xE0001004UL);
  2957. }
  2958. static void PlsrProfileRecordProducerCycles(uint32_t startCycles,
  2959. uint16_t itemCount)
  2960. {
  2961. uint32_t elapsed = PlsrProfileTimingNow() - startCycles;
  2962. uint32_t total = PlsrProfileProducerTotalCycles;
  2963. uint32_t perItemCycles;
  2964. if (itemCount == 0U)
  2965. {
  2966. return;
  2967. }
  2968. if (PlsrProfileProducerItemCount
  2969. <= (0xFFFFFFFFUL - (uint32_t)itemCount))
  2970. {
  2971. PlsrProfileProducerItemCount += itemCount;
  2972. }
  2973. else
  2974. {
  2975. PlsrProfileProducerItemCount = 0xFFFFFFFFUL;
  2976. }
  2977. PlsrProfileProducerTotalCycles =
  2978. (elapsed > (0xFFFFFFFFUL - total)) ? 0xFFFFFFFFUL
  2979. : total + elapsed;
  2980. perItemCycles = (elapsed + itemCount - 1UL) / itemCount;
  2981. if (perItemCycles > PlsrProfileProducerMaxItemCycles)
  2982. {
  2983. PlsrProfileProducerMaxItemCycles = perItemCycles;
  2984. }
  2985. }
  2986. #endif
  2987. static uint8_t PlsrProfileQueueFill(uint16_t targetCount,
  2988. uint16_t *itemBudget)
  2989. {
  2990. PLSR_SHORT_PROFILE candidate;
  2991. PLSR_PROFILE_ENTRY entries[PLSR_PROFILE_PRODUCER_BATCH_ITEMS];
  2992. PLSR_PROFILE_ENTRY entry;
  2993. uint32_t generation;
  2994. uint32_t producerEpoch;
  2995. uint32_t criticalState;
  2996. uint32_t underrunDebt;
  2997. uint32_t queueReadIndex;
  2998. uint32_t queueWriteIndex;
  2999. uint32_t queueCount;
  3000. uint32_t currentGeneration;
  3001. uint32_t currentProducerEpoch;
  3002. uint32_t targetSpace;
  3003. PLSR_PROFILE_QUEUE *queue;
  3004. uint16_t batchLimit;
  3005. uint16_t generatedItems;
  3006. uint16_t entryCount;
  3007. uint16_t index;
  3008. uint8_t queueBank;
  3009. uint8_t currentBank;
  3010. uint8_t queueActive;
  3011. uint8_t generatorComplete;
  3012. uint8_t payingUnderrunDebt;
  3013. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  3014. && !defined(PLSR_HOST_TEST)
  3015. uint32_t startCycles;
  3016. #endif
  3017. if (itemBudget == NULL)
  3018. {
  3019. return 0U;
  3020. }
  3021. if ((targetCount == 0U)
  3022. || (targetCount > PLSR_PROFILE_QUEUE_CAPACITY))
  3023. {
  3024. targetCount = PLSR_PROFILE_QUEUE_CAPACITY;
  3025. }
  3026. while (1)
  3027. {
  3028. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  3029. && !defined(PLSR_HOST_TEST)
  3030. startCycles = PlsrProfileTimingNow();
  3031. #endif
  3032. criticalState = PlsrPlatformEnterCritical();
  3033. queueBank = PlsrProfileQueueBank;
  3034. queue = &PlsrProfileQueues[queueBank];
  3035. queueActive = queue->active;
  3036. generatorComplete = queue->generatorComplete;
  3037. queueWriteIndex = queue->writeIndex;
  3038. queueReadIndex = queue->readIndex;
  3039. queueCount = queueWriteIndex - queueReadIndex;
  3040. if ((queueActive == 0U)
  3041. || (generatorComplete != 0U)
  3042. || (queueCount >= targetCount)
  3043. || (*itemBudget == 0U))
  3044. {
  3045. PlsrPlatformExitCritical(criticalState);
  3046. return 1U;
  3047. }
  3048. generation = queue->generation;
  3049. producerEpoch = queue->producerEpoch;
  3050. underrunDebt = queue->underrunDebtPulses;
  3051. payingUnderrunDebt = (underrunDebt != 0UL) ? 1U : 0U;
  3052. batchLimit = *itemBudget;
  3053. if (batchLimit > PLSR_PROFILE_PRODUCER_BATCH_ITEMS)
  3054. {
  3055. batchLimit = PLSR_PROFILE_PRODUCER_BATCH_ITEMS;
  3056. }
  3057. targetSpace = targetCount - queueCount;
  3058. if ((uint32_t)batchLimit > targetSpace)
  3059. {
  3060. batchLimit = (uint16_t)targetSpace;
  3061. }
  3062. if (payingUnderrunDebt != 0U)
  3063. {
  3064. /* Debt changes the queue generation and must be paid against the
  3065. latest published amount, so keep this exceptional path single. */
  3066. batchLimit = 1U;
  3067. }
  3068. PlsrCopyShortProfile(&candidate, &queue->producerProfile);
  3069. PlsrPlatformExitCritical(criticalState);
  3070. generatedItems = 0U;
  3071. entryCount = 0U;
  3072. while ((generatedItems < batchLimit)
  3073. && (candidate.active != 0U))
  3074. {
  3075. if (PlsrShortProfileTakeRunLimited(
  3076. &candidate, &entry,
  3077. (payingUnderrunDebt != 0U)
  3078. ? underrunDebt : 0xFFFFFFFFUL) == 0U)
  3079. {
  3080. return 0U;
  3081. }
  3082. generatedItems++;
  3083. if ((entryCount == 0U)
  3084. || (PlsrProfileEntryTryMerge(
  3085. &entries[entryCount - 1U], &entry) == 0U))
  3086. {
  3087. entries[entryCount] = entry;
  3088. entryCount++;
  3089. }
  3090. if (payingUnderrunDebt != 0U)
  3091. {
  3092. break;
  3093. }
  3094. }
  3095. if ((generatedItems == 0U) || (entryCount == 0U))
  3096. {
  3097. return 0U;
  3098. }
  3099. *itemBudget = (uint16_t)(*itemBudget - generatedItems);
  3100. criticalState = PlsrPlatformEnterCritical();
  3101. currentBank = PlsrProfileQueueBank;
  3102. queueActive = queue->active;
  3103. currentGeneration = queue->generation;
  3104. currentProducerEpoch = queue->producerEpoch;
  3105. queueWriteIndex = queue->writeIndex;
  3106. queueReadIndex = queue->readIndex;
  3107. queueCount = queueWriteIndex - queueReadIndex;
  3108. if ((currentBank != queueBank)
  3109. || (queueActive == 0U)
  3110. || (currentGeneration != generation)
  3111. || (currentProducerEpoch != producerEpoch)
  3112. || ((payingUnderrunDebt == 0U)
  3113. && ((queueCount + entryCount)
  3114. > PLSR_PROFILE_QUEUE_CAPACITY)))
  3115. {
  3116. PlsrPlatformExitCritical(criticalState);
  3117. continue;
  3118. }
  3119. if (payingUnderrunDebt != 0U)
  3120. {
  3121. underrunDebt = queue->underrunDebtPulses;
  3122. if (underrunDebt < entries[0].repeatCount)
  3123. {
  3124. PlsrPlatformExitCritical(criticalState);
  3125. continue;
  3126. }
  3127. queue->underrunDebtPulses =
  3128. underrunDebt - entries[0].repeatCount;
  3129. }
  3130. else
  3131. {
  3132. for (index = 0U; index < entryCount; index++)
  3133. {
  3134. if (PlsrProfileQueueAppendLocked(
  3135. queue, &entries[index]) == 0U)
  3136. {
  3137. PlsrPlatformExitCritical(criticalState);
  3138. return 0U;
  3139. }
  3140. }
  3141. }
  3142. PlsrCopyShortProfile(&queue->producerProfile, &candidate);
  3143. queueWriteIndex = queue->writeIndex;
  3144. queueReadIndex = queue->readIndex;
  3145. queueCount = queueWriteIndex - queueReadIndex;
  3146. if (queueCount >= PLSR_PROFILE_LOW_WATER_CLEAR)
  3147. {
  3148. PlsrProfileQueueLowWaterLatched = 0U;
  3149. }
  3150. if (((candidate.active == 0U)
  3151. || (candidate.nextPeriod >= candidate.pulseCount))
  3152. && (queue->underrunDebtPulses == 0UL))
  3153. {
  3154. queue->generatorComplete = 1U;
  3155. }
  3156. PlsrPlatformExitCritical(criticalState);
  3157. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  3158. && !defined(PLSR_HOST_TEST)
  3159. PlsrProfileRecordProducerCycles(startCycles, generatedItems);
  3160. #endif
  3161. }
  3162. }
  3163. static PLSR_PLATFORM_QUEUE_RESULT PlsrProfileQueueCommitNext(
  3164. uint8_t pulseOutput)
  3165. {
  3166. const PLSR_PROFILE_ENTRY *entry;
  3167. uint32_t readIndex;
  3168. uint32_t nextReadIndex;
  3169. uint32_t writeIndex;
  3170. uint32_t actualFrequencyHz;
  3171. uint32_t repeatRemaining;
  3172. uint16_t queueDepth;
  3173. PLSR_PLATFORM_QUEUE_RESULT result;
  3174. repeatRemaining = PlsrProfileQueue.repeatRemaining;
  3175. if (repeatRemaining != 0UL)
  3176. {
  3177. PlsrProfileQueue.repeatRemaining = repeatRemaining - 1UL;
  3178. return PLSR_PLATFORM_QUEUE_APPLIED;
  3179. }
  3180. if (PlsrProfileQueue.active == 0U)
  3181. {
  3182. if (PlsrProfileQueue.generatorComplete != 0U)
  3183. {
  3184. PlsrShortProfile.active = 0U;
  3185. }
  3186. return PLSR_PLATFORM_QUEUE_APPLIED;
  3187. }
  3188. readIndex = PlsrProfileQueue.readIndex;
  3189. if (readIndex == PlsrProfileQueue.writeIndex)
  3190. {
  3191. if (PlsrProfileQueue.generatorComplete != 0U)
  3192. {
  3193. PlsrProfileQueue.active = 0U;
  3194. PlsrShortProfile.active = 0U;
  3195. return PLSR_PLATFORM_QUEUE_APPLIED;
  3196. }
  3197. PlsrProfileQueueRecordUnderrun();
  3198. return PLSR_PLATFORM_QUEUE_FAILED;
  3199. }
  3200. entry = &PlsrProfileQueue.entries[readIndex & PLSR_PROFILE_QUEUE_MASK];
  3201. result = PlsrPlatformLoadPreparedFromIrq(pulseOutput, &entry->setting,
  3202. &actualFrequencyHz);
  3203. if (result != PLSR_PLATFORM_QUEUE_APPLIED)
  3204. {
  3205. return result;
  3206. }
  3207. nextReadIndex = readIndex + 1UL;
  3208. PlsrProfileQueue.readIndex = nextReadIndex;
  3209. PlsrProfileQueue.repeatRemaining = entry->repeatCount - 1UL;
  3210. queueDepth = (uint16_t)(PlsrProfileQueue.writeIndex - nextReadIndex);
  3211. if (PlsrProfileQueue.generatorComplete == 0U)
  3212. {
  3213. PlsrProfileQueueRecordDepth(queueDepth);
  3214. }
  3215. PlsrDeferredFrequencyPending = 0U;
  3216. PlsrQueuedFrequencyHz = actualFrequencyHz;
  3217. PlsrDiagnosticRecordFrequency(entry->requestedFrequencyHz,
  3218. entry->setting.actualFrequencyHz,
  3219. actualFrequencyHz);
  3220. PlsrDiagnosticQueuedExpectedHz = entry->setting.actualFrequencyHz;
  3221. if (actualFrequencyHz > PlsrCurrentFrequencyHz)
  3222. {
  3223. PlsrRunStatus = PLSR_STATUS_ACCELERATING;
  3224. }
  3225. else if (actualFrequencyHz < PlsrCurrentFrequencyHz)
  3226. {
  3227. PlsrRunStatus = PLSR_STATUS_DECELERATING;
  3228. }
  3229. else
  3230. {
  3231. PlsrRunStatus = PLSR_STATUS_RUNNING;
  3232. }
  3233. writeIndex = PlsrProfileQueue.writeIndex;
  3234. if ((nextReadIndex == writeIndex)
  3235. && (PlsrProfileQueue.generatorComplete != 0U))
  3236. {
  3237. PlsrProfileQueue.active = 0U;
  3238. PlsrShortProfile.active = 0U;
  3239. }
  3240. return PLSR_PLATFORM_QUEUE_APPLIED;
  3241. }
  3242. static void PlsrInvalidateHandoffPlans(void)
  3243. {
  3244. uint8_t bank;
  3245. uint8_t index;
  3246. uint32_t criticalState = PlsrPlatformEnterCritical();
  3247. PlsrHandoffPlan.valid = 0U;
  3248. PlsrCountedHandoffStaged = 0U;
  3249. for (bank = 0U; bank < 2U; bank++)
  3250. {
  3251. for (index = 0U; index < PLSR_SEGMENT_COUNT_MAX; index++)
  3252. {
  3253. PlsrPreparedHandoffPlans[bank][index].valid = 0U;
  3254. }
  3255. }
  3256. PlsrPlatformExitCritical(criticalState);
  3257. }
  3258. static void PlsrMaybePlanBoundaryRamp(uint32_t expectedEpoch)
  3259. {
  3260. const PLSR_SEGMENT_CONFIG *segment;
  3261. uint8_t nextSegment;
  3262. uint8_t nextPositive;
  3263. uint8_t hasNext;
  3264. uint32_t targetHz;
  3265. uint32_t criticalState;
  3266. uint32_t currentHz;
  3267. uint32_t queuedHz;
  3268. uint32_t deferredHz;
  3269. uint32_t rateBoundHz;
  3270. uint8_t deferredPending;
  3271. uint64_t estimate;
  3272. uint64_t candidateEstimate;
  3273. uint64_t remaining;
  3274. uint8_t rampActive;
  3275. if ((PlsrPulseActive == 0U)
  3276. || (PlsrBoundaryRampStarted != 0U)
  3277. || (PlsrShortProfile.active != 0U)
  3278. || (PlsrHandoffPlan.valid != 0U)
  3279. || (PlsrStopRequested != 0U) || (PlsrCurrentSegment == 0U))
  3280. {
  3281. return;
  3282. }
  3283. segment = &PlsrActiveConfig.segments[PlsrCurrentSegment - 1U];
  3284. hasNext = PlsrPredictNextMotion(&nextSegment, &nextPositive);
  3285. targetHz = PlsrEffectiveStopFrequency(segment->frequencyHz);
  3286. if ((hasNext != 0U)
  3287. && (segment->waitType == PLSR_EXT_OR_COMPLETE))
  3288. {
  3289. if (nextPositive == PlsrCountPositive)
  3290. {
  3291. targetHz = PlsrActiveConfig.segments[nextSegment - 1U].frequencyHz;
  3292. }
  3293. }
  3294. criticalState = PlsrPlatformEnterCritical();
  3295. currentHz = PlsrCurrentFrequencyHz;
  3296. queuedHz = PlsrQueuedFrequencyHz;
  3297. deferredHz = PlsrDeferredFrequencyHz;
  3298. deferredPending = PlsrDeferredFrequencyPending;
  3299. if ((PlsrSegmentEpoch != expectedEpoch)
  3300. || (PlsrBoundaryPending != 0U)
  3301. || (PlsrPulseActive == 0U)
  3302. || (PlsrBoundaryRampStarted != 0U)
  3303. || (PlsrShortProfile.active != 0U)
  3304. || (PlsrHandoffPlan.valid != 0U)
  3305. || (PlsrStopRequested != 0U)
  3306. || (PlsrAbStopArmed != 0U))
  3307. {
  3308. PlsrPlatformExitCritical(criticalState);
  3309. return;
  3310. }
  3311. PlsrPlatformExitCritical(criticalState);
  3312. rateBoundHz = (currentHz > queuedHz) ? currentHz : queuedHz;
  3313. if ((deferredPending != 0U) && (deferredHz > rateBoundHz))
  3314. {
  3315. rateBoundHz = deferredHz;
  3316. }
  3317. estimate = PlsrRampPulseEstimate(currentHz, targetHz, rateBoundHz);
  3318. candidateEstimate = PlsrRampPulseEstimate(queuedHz, targetHz,
  3319. rateBoundHz);
  3320. if (candidateEstimate > estimate)
  3321. {
  3322. estimate = candidateEstimate;
  3323. }
  3324. if (deferredPending != 0U)
  3325. {
  3326. candidateEstimate = PlsrRampPulseEstimate(deferredHz, targetHz,
  3327. rateBoundHz);
  3328. if (candidateEstimate > estimate)
  3329. {
  3330. estimate = candidateEstimate;
  3331. }
  3332. }
  3333. criticalState = PlsrPlatformEnterCritical();
  3334. remaining = PlsrRemainingPulses;
  3335. if ((PlsrSegmentEpoch != expectedEpoch)
  3336. || (PlsrBoundaryPending != 0U)
  3337. || (PlsrPulseActive == 0U)
  3338. || (PlsrBoundaryRampStarted != 0U)
  3339. || (PlsrShortProfile.active != 0U)
  3340. || (PlsrHandoffPlan.valid != 0U)
  3341. || (PlsrStopRequested != 0U)
  3342. || (PlsrAbStopArmed != 0U))
  3343. {
  3344. PlsrPlatformExitCritical(criticalState);
  3345. return;
  3346. }
  3347. if (remaining > estimate)
  3348. {
  3349. PlsrPlatformExitCritical(criticalState);
  3350. return;
  3351. }
  3352. PlsrBoundaryRampStarted = 1U;
  3353. PlsrRampStart(PlsrCurrentFrequencyHz, targetHz);
  3354. rampActive = PlsrRamp.active;
  3355. PlsrPlatformExitCritical(criticalState);
  3356. if (rampActive != 0U)
  3357. {
  3358. if (PlsrRampAdvance(expectedEpoch) == 0U)
  3359. {
  3360. PlsrEnterErrorIfEpoch(PLSR_ERROR_TIMER, expectedEpoch);
  3361. }
  3362. }
  3363. else
  3364. {
  3365. (void)PlsrApplyFrequency(targetHz, expectedEpoch);
  3366. }
  3367. }
  3368. static uint8_t PlsrStartPreparedTimedOutput(void)
  3369. {
  3370. PLSR_PROFILE_QUEUE *queue;
  3371. PLSR_PROFILE_ENTRY firstRun;
  3372. uint32_t criticalState;
  3373. uint32_t firstFrequencyHz;
  3374. uint32_t secondFrequencyHz;
  3375. uint32_t actualFrequencyHz;
  3376. uint32_t queueReadIndex;
  3377. uint32_t queueWriteIndex;
  3378. uint8_t queueBank;
  3379. criticalState = PlsrPlatformEnterCritical();
  3380. queueBank = PlsrTimedStart.queueBank;
  3381. queue = &PlsrProfileQueues[queueBank];
  3382. if ((PlsrTimedStart.pendingActivation == 0U)
  3383. || (PlsrTimedStart.valid == 0U)
  3384. || (PlsrCurrentSegment != PlsrTimedStart.nextSegment)
  3385. || (PlsrSegmentEpoch != PlsrTimedStart.sourceEpoch + 1UL)
  3386. || (queueBank == PlsrProfileQueueBank)
  3387. || (queue->generation != PlsrTimedStart.queueGeneration)
  3388. || (queue->producerEpoch != PlsrSegmentEpoch)
  3389. || (queue->producerSegment != PlsrCurrentSegment))
  3390. {
  3391. PlsrPlatformExitCritical(criticalState);
  3392. return 0U;
  3393. }
  3394. firstRun = PlsrTimedStart.firstRun;
  3395. PlsrProfileQueueResetBankLocked(PlsrProfileQueueBank);
  3396. PlsrProfileQueueBank = queueBank;
  3397. PlsrCopyShortProfile(&PlsrShortProfile, &queue->producerProfile);
  3398. PlsrTimedStart.pendingActivation = 0U;
  3399. PlsrTimedStart.valid = 0U;
  3400. PlsrTimedStart.building = 0U;
  3401. PlsrPlatformExitCritical(criticalState);
  3402. PlsrSegmentClockStarted = 1U;
  3403. PlsrSegmentElapsedMs = 0UL;
  3404. PlsrRamp.active = 0U;
  3405. PlsrCountedHandoffStaged = 0U;
  3406. PlsrRefreshCurrentHandoffPlan(PlsrShortProfile.endHz);
  3407. if (PlsrStageCountedHandoff() == 0U)
  3408. {
  3409. return 0U;
  3410. }
  3411. firstFrequencyHz = firstRun.setting.actualFrequencyHz;
  3412. secondFrequencyHz = firstFrequencyHz;
  3413. criticalState = PlsrPlatformEnterCritical();
  3414. queueReadIndex = queue->readIndex;
  3415. queueWriteIndex = queue->writeIndex;
  3416. if (queueReadIndex != queueWriteIndex)
  3417. {
  3418. secondFrequencyHz = queue->entries[
  3419. queueReadIndex & PLSR_PROFILE_QUEUE_MASK]
  3420. .setting.actualFrequencyHz;
  3421. }
  3422. queue->lastSetting = firstRun.setting;
  3423. queue->haveLastSetting = 1U;
  3424. PlsrPlatformExitCritical(criticalState);
  3425. if (secondFrequencyHz > firstFrequencyHz)
  3426. {
  3427. PlsrRunStatus = PLSR_STATUS_ACCELERATING;
  3428. }
  3429. else if (secondFrequencyHz < firstFrequencyHz)
  3430. {
  3431. PlsrRunStatus = PLSR_STATUS_DECELERATING;
  3432. }
  3433. else
  3434. {
  3435. PlsrRunStatus = PLSR_STATUS_RUNNING;
  3436. }
  3437. PlsrCurrentFrequencyHz = firstFrequencyHz;
  3438. PlsrQueuedFrequencyHz = secondFrequencyHz;
  3439. PlsrDiagnosticQueuedExpectedHz = firstRun.setting.actualFrequencyHz;
  3440. PlsrCountedObservedPublished = PlsrPlatformObservedPulses(
  3441. (uint8_t)PlsrActiveConfig.pulseOutput);
  3442. PlsrProfileQueueMinimumDepth = PlsrProfileQueueCount();
  3443. PlsrProfileQueueLowWaterLatched = 0U;
  3444. PlsrPulseActive = 1U;
  3445. PlsrExecutor.generation++;
  3446. PlsrExecutor.mode = (queue->generatorComplete != 0U)
  3447. ? PLSR_EXEC_STEP_TABLE
  3448. : PLSR_EXEC_STREAM;
  3449. if (PlsrPlatformStartCountedStreamPrepared(
  3450. (uint8_t)PlsrActiveConfig.pulseOutput,
  3451. &firstRun.setting, firstRun.repeatCount,
  3452. &actualFrequencyHz) == 0U)
  3453. {
  3454. PlsrPulseActive = 0U;
  3455. PlsrExecutor.mode = PLSR_EXEC_IDLE;
  3456. PlsrProfileQueueReset();
  3457. PlsrShortProfile.active = 0U;
  3458. return 0U;
  3459. }
  3460. PlsrPulseDirMotionStarted = 1U;
  3461. PlsrCurrentFrequencyHz = actualFrequencyHz;
  3462. PlsrDiagnosticRecordFrequency(firstRun.requestedFrequencyHz,
  3463. firstRun.setting.actualFrequencyHz,
  3464. actualFrequencyHz);
  3465. return 1U;
  3466. }
  3467. static PLSR_PLATFORM_SERVICE_RESULT PlsrTryStartPreparedTimedSegment(
  3468. uint8_t segmentNumber,
  3469. int64_t resolvedDisplacement)
  3470. {
  3471. PLSR_PROFILE_QUEUE *queue;
  3472. uint32_t criticalState;
  3473. uint64_t magnitude;
  3474. uint8_t positive;
  3475. uint8_t directionLevel;
  3476. uint8_t directionChanged;
  3477. criticalState = PlsrPlatformEnterCritical();
  3478. queue = &PlsrProfileQueues[PlsrTimedStart.queueBank];
  3479. if ((PlsrTimedStart.valid == 0U)
  3480. || (PlsrTimedStart.pendingActivation != 0U)
  3481. || (PlsrTimedStart.sourceEpoch != PlsrSegmentEpoch)
  3482. || (PlsrTimedStart.sourceSegment != PlsrCurrentSegment)
  3483. || (PlsrTimedStart.queueBank == PlsrProfileQueueBank)
  3484. || (queue->generation != PlsrTimedStart.queueGeneration))
  3485. {
  3486. PlsrPlatformExitCritical(criticalState);
  3487. return PLSR_PLATFORM_SERVICE_DEFERRED;
  3488. }
  3489. if ((PlsrTimedStart.nextSegment != segmentNumber)
  3490. || (PlsrTimedStart.resolvedDisplacement != resolvedDisplacement))
  3491. {
  3492. /* An unpredictable boundary (notably an early EXT cut) can change the
  3493. next segment's resolved relative move. Never publish a profile
  3494. built for the old endpoint. */
  3495. PlsrProfileQueueResetBankLocked(PlsrTimedStart.queueBank);
  3496. PlsrInvalidateTimedStartLocked();
  3497. PlsrPlatformExitCritical(criticalState);
  3498. return PLSR_PLATFORM_SERVICE_DEFERRED;
  3499. }
  3500. magnitude = PlsrTimedStart.magnitude;
  3501. positive = PlsrTimedStart.positive;
  3502. directionLevel = PlsrTimedStart.directionLevel;
  3503. directionChanged = PlsrTimedStart.directionChanged;
  3504. PlsrSegmentEpoch++;
  3505. PlsrCurrentSegment = segmentNumber;
  3506. PlsrExtCaptureSegment = segmentNumber;
  3507. PlsrExtCaptureEpoch = PlsrSegmentEpoch;
  3508. PlsrSegmentClockStarted = 0U;
  3509. PlsrSegmentElapsedMs = 0UL;
  3510. PlsrWaitElapsedMs = 0UL;
  3511. PlsrBoundaryRampStarted = 0U;
  3512. PlsrBoundaryPending = 0U;
  3513. PlsrBoundaryWasCut = 0U;
  3514. PlsrCutRequested = 0U;
  3515. PlsrStopPulsesRemaining = 0U;
  3516. PlsrAbStopArmed = 0U;
  3517. PlsrFrequencyUpdatePending = 0U;
  3518. PlsrDeferredFrequencyPending = 0U;
  3519. PlsrCurrentFrequencyHz = 0UL;
  3520. PlsrQueuedFrequencyHz = 0UL;
  3521. PlsrHandoffPlan.valid = 0U;
  3522. PlsrShortProfile.active = 0U;
  3523. PlsrShortProfile.nextPeriod = 0U;
  3524. PlsrDirectionDelayActive = 0U;
  3525. PlsrDirectionDelayRemainingMs = 0U;
  3526. PlsrRemainingPulses = magnitude;
  3527. PlsrCommandRemainingPulses =
  3528. (resolvedDisplacement < 0)
  3529. ? (uint64_t)(-resolvedDisplacement)
  3530. : (uint64_t)resolvedDisplacement;
  3531. PlsrCountPositive = positive;
  3532. PlsrActTimedCutPlanned = PlsrTimedStart.nextActTimedCut;
  3533. PlsrTimedStart.pendingActivation = 1U;
  3534. PlsrPlatformExitCritical(criticalState);
  3535. PlsrExtPreviousLevel =
  3536. PlsrPlatformReadInput((uint8_t)PlsrActiveConfig.extInput);
  3537. if (PlsrPlatformPrepare((uint8_t)PlsrActiveConfig.pulseOutput,
  3538. (uint8_t)PlsrActiveConfig.directionOutput,
  3539. directionLevel,
  3540. (uint8_t)PlsrActiveConfig.outputMode,
  3541. positive) == 0U)
  3542. {
  3543. criticalState = PlsrPlatformEnterCritical();
  3544. PlsrInvalidateTimedStartLocked();
  3545. PlsrPlatformExitCritical(criticalState);
  3546. return PLSR_PLATFORM_SERVICE_FAILED;
  3547. }
  3548. PlsrDiagnosticBeginSegment(segmentNumber, magnitude, positive);
  3549. PlsrLastDirectionValid = 1U;
  3550. PlsrLastDirectionOutput = (uint8_t)PlsrActiveConfig.directionOutput;
  3551. PlsrLastDirectionLevel = directionLevel;
  3552. if (directionChanged != 0U)
  3553. {
  3554. PlsrDelayedEntryType = PLSR_SEGMENT_ENTRY_INTERNAL_RESTART;
  3555. PlsrDirectionDelayActive = 1U;
  3556. PlsrDirectionDelayRemainingMs = PlsrEffectiveDirectionDelayMs();
  3557. PlsrRunStatus = PLSR_STATUS_ACCELERATING;
  3558. return PLSR_PLATFORM_SERVICE_READY;
  3559. }
  3560. if (PlsrStartPreparedTimedOutput() == 0U)
  3561. {
  3562. return PLSR_PLATFORM_SERVICE_FAILED;
  3563. }
  3564. return PLSR_PLATFORM_SERVICE_READY;
  3565. }
  3566. static uint8_t PlsrBeginSegmentOutput(uint32_t startFrequencyHz)
  3567. {
  3568. uint32_t targetFrequencyHz =
  3569. PlsrActiveConfig.segments[PlsrCurrentSegment - 1U].frequencyHz;
  3570. uint32_t firstFrequencyHz;
  3571. uint32_t secondFrequencyHz;
  3572. uint32_t actualFrequencyHz;
  3573. uint32_t profileEpoch;
  3574. uint64_t remainingPulses;
  3575. uint8_t profileSegment;
  3576. uint8_t profileHandoffBank;
  3577. uint8_t countPositive;
  3578. uint8_t timedCutPlanned = 0U;
  3579. uint16_t fillBudget = PLSR_PROFILE_STARTUP_BUDGET;
  3580. PLSR_PROFILE_ENTRY firstRun;
  3581. PlsrSegmentClockStarted = 1U;
  3582. PlsrSegmentElapsedMs = 0UL;
  3583. profileSegment = PlsrCurrentSegment;
  3584. countPositive = PlsrCountPositive;
  3585. remainingPulses = PlsrRemainingSnapshot();
  3586. if (PlsrPrepareShortProfile(&PlsrShortProfile, &PlsrActiveConfig,
  3587. profileSegment, startFrequencyHz,
  3588. targetFrequencyHz,
  3589. remainingPulses,
  3590. countPositive, 0U) != 0U)
  3591. {
  3592. PlsrRamp.active = 0U;
  3593. if ((PlsrActiveConfig.segments[profileSegment - 1U].waitType
  3594. == PLSR_ACT_TIME)
  3595. && (PlsrLimitProfileToActTime(
  3596. &PlsrShortProfile,
  3597. PlsrActiveConfig.segments[profileSegment - 1U].actTimeMs,
  3598. &timedCutPlanned) == 0U))
  3599. {
  3600. return 0U;
  3601. }
  3602. PlsrActTimedCutPlanned = timedCutPlanned;
  3603. if (timedCutPlanned != 0U)
  3604. {
  3605. uint32_t criticalState = PlsrPlatformEnterCritical();
  3606. PlsrRemainingPulses = PlsrShortProfile.pulseCount;
  3607. PlsrPlatformExitCritical(criticalState);
  3608. PlsrDiagnosticBeginSegment(profileSegment,
  3609. PlsrShortProfile.pulseCount,
  3610. countPositive);
  3611. if (PlsrShortProfile.pulseCount == 0UL)
  3612. {
  3613. PlsrRunStatus = PLSR_STATUS_WAITING;
  3614. return 1U;
  3615. }
  3616. }
  3617. PlsrRefreshCurrentHandoffPlan(PlsrShortProfile.endHz);
  3618. if (PlsrShortProfileTakeRun(&PlsrShortProfile, &firstRun) == 0U)
  3619. {
  3620. return 0U;
  3621. }
  3622. firstFrequencyHz = firstRun.setting.actualFrequencyHz;
  3623. secondFrequencyHz = firstFrequencyHz;
  3624. profileEpoch = PlsrSegmentEpoch;
  3625. profileHandoffBank = PlsrPreparedHandoffBank;
  3626. (void)PlsrProfileQueueBegin(&PlsrShortProfile,
  3627. profileEpoch,
  3628. profileSegment,
  3629. profileHandoffBank);
  3630. if (PlsrProfileQueueFill(PLSR_PROFILE_STARTUP_TARGET,
  3631. &fillBudget) == 0U)
  3632. {
  3633. PlsrProfileQueueReset();
  3634. PlsrShortProfile.active = 0U;
  3635. return 0U;
  3636. }
  3637. PlsrCountedHandoffStaged = 0U;
  3638. if ((PlsrStageCountedHandoff() == 0U)
  3639. || (PlsrProfileQueueFill(PLSR_PROFILE_STARTUP_TARGET,
  3640. &fillBudget) == 0U))
  3641. {
  3642. PlsrProfileQueueReset();
  3643. PlsrShortProfile.active = 0U;
  3644. return 0U;
  3645. }
  3646. {
  3647. uint32_t readIndex = PlsrProfileQueue.readIndex;
  3648. uint32_t writeIndex = PlsrProfileQueue.writeIndex;
  3649. if (readIndex != writeIndex)
  3650. {
  3651. secondFrequencyHz = PlsrProfileQueue.entries[
  3652. readIndex & PLSR_PROFILE_QUEUE_MASK]
  3653. .setting.actualFrequencyHz;
  3654. }
  3655. }
  3656. if (secondFrequencyHz > firstFrequencyHz)
  3657. {
  3658. PlsrRunStatus = PLSR_STATUS_ACCELERATING;
  3659. }
  3660. else if (secondFrequencyHz < firstFrequencyHz)
  3661. {
  3662. PlsrRunStatus = PLSR_STATUS_DECELERATING;
  3663. }
  3664. else
  3665. {
  3666. PlsrRunStatus = PLSR_STATUS_RUNNING;
  3667. }
  3668. PlsrCurrentFrequencyHz = firstFrequencyHz;
  3669. PlsrQueuedFrequencyHz = secondFrequencyHz;
  3670. PlsrProfileQueue.lastSetting = firstRun.setting;
  3671. PlsrProfileQueue.haveLastSetting = 1U;
  3672. PlsrDiagnosticQueuedExpectedHz = firstRun.setting.actualFrequencyHz;
  3673. PlsrCountedObservedPublished = PlsrPlatformObservedPulses(
  3674. (uint8_t)PlsrActiveConfig.pulseOutput);
  3675. PlsrProfileQueueMinimumDepth = PlsrProfileQueueCount();
  3676. PlsrProfileQueueLowWaterLatched = 0U;
  3677. PlsrPulseActive = 1U;
  3678. PlsrExecutor.generation++;
  3679. PlsrExecutor.mode = (PlsrProfileQueue.generatorComplete != 0U)
  3680. ? PLSR_EXEC_STEP_TABLE
  3681. : PLSR_EXEC_STREAM;
  3682. if (PlsrPlatformStartCountedStreamPrepared(
  3683. (uint8_t)PlsrActiveConfig.pulseOutput,
  3684. &firstRun.setting, firstRun.repeatCount,
  3685. &actualFrequencyHz) == 0U)
  3686. {
  3687. PlsrPulseActive = 0U;
  3688. PlsrExecutor.mode = PLSR_EXEC_IDLE;
  3689. PlsrProfileQueueReset();
  3690. PlsrShortProfile.active = 0U;
  3691. return 0U;
  3692. }
  3693. PlsrPulseDirMotionStarted = 1U;
  3694. PlsrCurrentFrequencyHz = actualFrequencyHz;
  3695. PlsrDiagnosticRecordFrequency(firstRun.requestedFrequencyHz,
  3696. firstRun.setting.actualFrequencyHz,
  3697. actualFrequencyHz);
  3698. return 1U;
  3699. }
  3700. if (PlsrActiveConfig.outputMode == PLSR_OUTPUT_PULSE_DIR)
  3701. {
  3702. return 0U;
  3703. }
  3704. PlsrProfileQueueReset();
  3705. PlsrRampStart(startFrequencyHz, targetFrequencyHz);
  3706. if (PlsrRamp.active == 0U)
  3707. {
  3708. if (PlsrApplyFrequency(targetFrequencyHz, PlsrSegmentEpoch) == 0U)
  3709. {
  3710. return 0U;
  3711. }
  3712. PlsrRunStatus = PLSR_STATUS_RUNNING;
  3713. }
  3714. else if ((startFrequencyHz != 0UL)
  3715. && (PlsrApplyFrequency(startFrequencyHz,
  3716. PlsrSegmentEpoch) == 0U))
  3717. {
  3718. return 0U;
  3719. }
  3720. if (PlsrPrepareFutureHandoffQueue() == 0U)
  3721. {
  3722. return 0U;
  3723. }
  3724. PlsrExecutor.generation++;
  3725. PlsrExecutor.mode = PLSR_EXEC_AB_LEGACY;
  3726. return 1U;
  3727. }
  3728. static uint8_t PlsrStartSegment(uint8_t segmentNumber,
  3729. PLSR_SEGMENT_ENTRY entryType,
  3730. uint32_t carryFrequencyHz)
  3731. {
  3732. PLSR_PLATFORM_SERVICE_RESULT delayedPrepareResult =
  3733. PLSR_PLATFORM_SERVICE_DEFERRED;
  3734. uint32_t criticalState;
  3735. int32_t position;
  3736. int64_t displacement;
  3737. uint64_t magnitude;
  3738. uint8_t positive;
  3739. uint8_t directionLevel;
  3740. uint8_t directionChanged;
  3741. uint32_t startFrequencyHz;
  3742. PLSR_PROFILE_QUEUE *queue;
  3743. uint8_t allowCarry = (entryType == PLSR_SEGMENT_ENTRY_CARRY) ? 1U : 0U;
  3744. if ((segmentNumber == 0U)
  3745. || (segmentNumber > PlsrActiveConfig.segmentCount))
  3746. {
  3747. return 0U;
  3748. }
  3749. PlsrDisarmWaitSignal();
  3750. criticalState = PlsrPlatformEnterCritical();
  3751. position = PlsrPosition;
  3752. PlsrPlatformExitCritical(criticalState);
  3753. if (PlsrResolveMotionSegment(segmentNumber, position,
  3754. &segmentNumber, &displacement) == 0U)
  3755. {
  3756. PlsrFinishCompleted();
  3757. return 1U;
  3758. }
  3759. positive = (displacement >= 0) ? 1U : 0U;
  3760. magnitude = (displacement < 0) ? (uint64_t)(-displacement)
  3761. : (uint64_t)displacement;
  3762. criticalState = PlsrPlatformEnterCritical();
  3763. PlsrSegmentEpoch++;
  3764. PlsrCurrentSegment = segmentNumber;
  3765. PlsrExtCaptureSegment = segmentNumber;
  3766. PlsrExtCaptureEpoch = PlsrSegmentEpoch;
  3767. PlsrPlatformExitCritical(criticalState);
  3768. PlsrSegmentClockStarted = 0U;
  3769. PlsrSegmentElapsedMs = 0UL;
  3770. PlsrWaitElapsedMs = 0UL;
  3771. PlsrBoundaryRampStarted = 0U;
  3772. PlsrBoundaryPending = 0U;
  3773. PlsrBoundaryWasCut = 0U;
  3774. PlsrCutRequested = 0U;
  3775. PlsrActTimedCutPlanned = 0U;
  3776. PlsrStopPulsesRemaining = 0U;
  3777. PlsrAbStopArmed = 0U;
  3778. PlsrFrequencyUpdatePending = 0U;
  3779. PlsrDeferredFrequencyPending = 0U;
  3780. PlsrCurrentFrequencyHz = 0UL;
  3781. PlsrQueuedFrequencyHz = 0UL;
  3782. PlsrHandoffPlan.valid = 0U;
  3783. PlsrShortProfile.active = 0U;
  3784. PlsrShortProfile.nextPeriod = 0U;
  3785. queue = &PlsrProfileQueues[PlsrProfileQueueBank];
  3786. if ((allowCarry == 0U) || (queue->active == 0U)
  3787. || (queue->producerEpoch != PlsrSegmentEpoch)
  3788. || (queue->producerSegment != segmentNumber))
  3789. {
  3790. PlsrProfileQueueReset();
  3791. }
  3792. PlsrDirectionDelayActive = 0U;
  3793. PlsrDirectionDelayRemainingMs = 0U;
  3794. PlsrExtPreviousLevel =
  3795. PlsrPlatformReadInput((uint8_t)PlsrActiveConfig.extInput);
  3796. directionLevel = positive;
  3797. if ((PlsrActiveConfig.outputMode == PLSR_OUTPUT_PULSE_DIR)
  3798. && (PlsrActiveConfig.directionNegativeLogic != 0U))
  3799. {
  3800. directionLevel ^= 1U;
  3801. }
  3802. directionChanged = ((PlsrLastDirectionValid == 0U)
  3803. || (PlsrLastDirectionOutput
  3804. != (uint8_t)PlsrActiveConfig.directionOutput)
  3805. || (PlsrLastDirectionLevel != directionLevel)) ? 1U : 0U;
  3806. if (PlsrActiveConfig.outputMode == PLSR_OUTPUT_PULSE_DIR)
  3807. {
  3808. startFrequencyHz = PlsrPulseDirStartFrequency(
  3809. PlsrActiveConfig.segments[segmentNumber - 1U].frequencyHz,
  3810. entryType, directionChanged, carryFrequencyHz);
  3811. }
  3812. else
  3813. {
  3814. startFrequencyHz = PlsrEffectiveStartFrequency(
  3815. PlsrActiveConfig.segments[segmentNumber - 1U].frequencyHz,
  3816. allowCarry, directionChanged, carryFrequencyHz);
  3817. }
  3818. criticalState = PlsrPlatformEnterCritical();
  3819. PlsrRemainingPulses = magnitude;
  3820. PlsrCommandRemainingPulses = magnitude;
  3821. PlsrCountPositive = positive;
  3822. PlsrPlatformExitCritical(criticalState);
  3823. if ((PlsrActiveConfig.segments[segmentNumber - 1U].waitType
  3824. == PLSR_ACT_TIME)
  3825. && (PlsrActiveConfig.segments[segmentNumber - 1U].actTimeMs == 0U))
  3826. {
  3827. PlsrSegmentClockStarted = 1U;
  3828. PlsrRunStatus = PLSR_STATUS_RUNNING;
  3829. PlsrBoundaryFrequencyHz = (allowCarry != 0U) ? carryFrequencyHz : 0UL;
  3830. PlsrBoundaryWasCut = 1U;
  3831. PlsrBoundaryPending = 1U;
  3832. PlsrDiagnosticBeginSegment(segmentNumber, 0UL, positive);
  3833. PlsrDiagnosticFinishSegment(1U);
  3834. return 1U;
  3835. }
  3836. if ((PlsrActiveConfig.outputMode == PLSR_OUTPUT_PULSE_DIR)
  3837. && (directionChanged != 0U))
  3838. {
  3839. delayedPrepareResult = PlsrPrepareDelayedCurrentOutput(
  3840. startFrequencyHz, directionLevel, directionChanged);
  3841. if (delayedPrepareResult == PLSR_PLATFORM_SERVICE_FAILED)
  3842. {
  3843. return 0U;
  3844. }
  3845. if (delayedPrepareResult == PLSR_PLATFORM_SERVICE_READY)
  3846. {
  3847. magnitude = PlsrRemainingSnapshot();
  3848. }
  3849. }
  3850. if ((PlsrActiveConfig.outputMode == PLSR_OUTPUT_PULSE_DIR)
  3851. && (directionChanged != 0U)
  3852. && (entryType == PLSR_SEGMENT_ENTRY_COMMAND_START))
  3853. {
  3854. /* Keep the expensive initial profile preparation and the direction
  3855. GPIO edge in different real 1 ms polls. The next poll publishes
  3856. direction and loads the full delay without decrementing it. */
  3857. PlsrInitialDirectionPrepareLevel = directionLevel;
  3858. PlsrInitialDirectionPrepareEpoch = PlsrSegmentEpoch;
  3859. PlsrInitialDirectionPreparePending = 1U;
  3860. PlsrDelayedEntryType = entryType;
  3861. PlsrRunStatus = PLSR_STATUS_ACCELERATING;
  3862. return 1U;
  3863. }
  3864. if (PlsrPlatformPrepare((uint8_t)PlsrActiveConfig.pulseOutput,
  3865. (uint8_t)PlsrActiveConfig.directionOutput,
  3866. directionLevel,
  3867. (uint8_t)PlsrActiveConfig.outputMode,
  3868. positive) == 0U)
  3869. {
  3870. if (delayedPrepareResult == PLSR_PLATFORM_SERVICE_READY)
  3871. {
  3872. criticalState = PlsrPlatformEnterCritical();
  3873. PlsrInvalidateTimedStartLocked();
  3874. PlsrPlatformExitCritical(criticalState);
  3875. }
  3876. return 0U;
  3877. }
  3878. PlsrDiagnosticBeginSegment(segmentNumber, magnitude, positive);
  3879. PlsrLastDirectionValid = 1U;
  3880. PlsrLastDirectionOutput = (uint8_t)PlsrActiveConfig.directionOutput;
  3881. PlsrLastDirectionLevel = directionLevel;
  3882. if ((PlsrActiveConfig.outputMode == PLSR_OUTPUT_PULSE_DIR)
  3883. && (directionChanged != 0U))
  3884. {
  3885. PlsrDelayedEntryType = entryType;
  3886. PlsrDirectionDelayActive = 1U;
  3887. PlsrDirectionDelayRemainingMs = PlsrEffectiveDirectionDelayMs();
  3888. PlsrRunStatus = PLSR_STATUS_ACCELERATING;
  3889. return 1U;
  3890. }
  3891. PlsrDirectionDelayActive = 0U;
  3892. return PlsrBeginSegmentOutput(startFrequencyHz);
  3893. }
  3894. static uint8_t PlsrServiceInitialDirectionPrepare(void)
  3895. {
  3896. uint64_t magnitude;
  3897. uint32_t criticalState;
  3898. uint8_t segmentNumber;
  3899. uint8_t positive;
  3900. uint8_t directionLevel;
  3901. if (PlsrInitialDirectionPreparePending == 0U)
  3902. {
  3903. return 0U;
  3904. }
  3905. if ((PlsrInitialDirectionPrepareEpoch != PlsrSegmentEpoch)
  3906. || (PlsrCurrentSegment == 0U)
  3907. || (PlsrCurrentSegment > PlsrActiveConfig.segmentCount)
  3908. || (PlsrActiveConfig.outputMode != PLSR_OUTPUT_PULSE_DIR)
  3909. || (PlsrRunStatus != PLSR_STATUS_ACCELERATING))
  3910. {
  3911. PlsrInitialDirectionPreparePending = 0U;
  3912. PlsrEnterError(PLSR_ERROR_INTERNAL);
  3913. return 1U;
  3914. }
  3915. directionLevel = PlsrInitialDirectionPrepareLevel;
  3916. segmentNumber = PlsrCurrentSegment;
  3917. positive = PlsrCountPositive;
  3918. PlsrInitialDirectionPreparePending = 0U;
  3919. if (PlsrPlatformPrepare((uint8_t)PlsrActiveConfig.pulseOutput,
  3920. (uint8_t)PlsrActiveConfig.directionOutput,
  3921. directionLevel,
  3922. (uint8_t)PlsrActiveConfig.outputMode,
  3923. positive) == 0U)
  3924. {
  3925. criticalState = PlsrPlatformEnterCritical();
  3926. PlsrInvalidateTimedStartLocked();
  3927. PlsrPlatformExitCritical(criticalState);
  3928. PlsrEnterError(PLSR_ERROR_INVALID_RESOURCE);
  3929. return 1U;
  3930. }
  3931. magnitude = PlsrRemainingSnapshot();
  3932. PlsrDiagnosticBeginSegment(segmentNumber, magnitude, positive);
  3933. PlsrLastDirectionValid = 1U;
  3934. PlsrLastDirectionOutput = (uint8_t)PlsrActiveConfig.directionOutput;
  3935. PlsrLastDirectionLevel = directionLevel;
  3936. PlsrDirectionDelayRemainingMs = PlsrEffectiveDirectionDelayMs();
  3937. PlsrDirectionDelayActive = 1U;
  3938. return 1U;
  3939. }
  3940. static void PlsrMarkPersistenceDirty(uint16_t delayMs)
  3941. {
  3942. PlsrPersistenceDirty = 1U;
  3943. PlsrPersistenceDelayMs = delayMs;
  3944. }
  3945. static void PlsrCheckpointPosition(uint8_t wasBusy)
  3946. {
  3947. uint32_t criticalState;
  3948. int32_t position;
  3949. uint8_t positionValid;
  3950. criticalState = PlsrPlatformEnterCritical();
  3951. position = PlsrPosition;
  3952. positionValid = PlsrPositionValid;
  3953. PlsrPositionCheckpointDirty = 0U;
  3954. PlsrPlatformExitCritical(criticalState);
  3955. PlsrPlatformCheckpointPosition(position, positionValid, wasBusy);
  3956. PlsrPositionCheckpointElapsedMs = 0U;
  3957. }
  3958. static void PlsrPollPositionCheckpoint(void)
  3959. {
  3960. if (PlsrPositionCheckpointDirty == 0U)
  3961. {
  3962. PlsrPositionCheckpointElapsedMs = 0U;
  3963. return;
  3964. }
  3965. if (PlsrPositionCheckpointElapsedMs < PLSR_POSITION_CHECKPOINT_MS)
  3966. {
  3967. PlsrPositionCheckpointElapsedMs++;
  3968. }
  3969. if (PlsrPositionCheckpointElapsedMs >= PLSR_POSITION_CHECKPOINT_MS)
  3970. {
  3971. PlsrCheckpointPosition(1U);
  3972. }
  3973. }
  3974. static void PlsrFinishCompleted(void)
  3975. {
  3976. PlsrDisarmWaitSignal();
  3977. PlsrPlatformStopPulse((uint8_t)PlsrActiveConfig.pulseOutput);
  3978. PlsrRemainingPulses = 0UL;
  3979. PlsrCommandRemainingPulses = 0ULL;
  3980. PlsrPulseActive = 0U;
  3981. PlsrCutRequested = 0U;
  3982. PlsrActTimedCutPlanned = 0U;
  3983. PlsrBoundaryPending = 0U;
  3984. PlsrBoundaryWasCut = 0U;
  3985. PlsrCurrentFrequencyHz = 0UL;
  3986. PlsrQueuedFrequencyHz = 0UL;
  3987. PlsrCurrentSegment = 0U;
  3988. PlsrSegmentClockStarted = 0U;
  3989. PlsrDirectionDelayActive = 0U;
  3990. PlsrDirectionDelayRemainingMs = 0U;
  3991. PlsrInitialDirectionPreparePending = 0U;
  3992. PlsrExtCaptureSegment = 0U;
  3993. PlsrExtEdgePending = 0U;
  3994. PlsrStopRequested = 0U;
  3995. PlsrStopPulsesRemaining = 0U;
  3996. PlsrAbStopArmed = 0U;
  3997. PlsrSeamlessHandoffPending = 0U;
  3998. PlsrDeferredFrequencyPending = 0U;
  3999. PlsrShortProfile.active = 0U;
  4000. PlsrProfileQueueReset();
  4001. PlsrHandoffPlan.valid = 0U;
  4002. PlsrCountedBoundaryWriteIndex = 0U;
  4003. PlsrCountedBoundaryReadIndex = 0U;
  4004. PlsrCountedBoundaryBusy = 0U;
  4005. PlsrCountedFaultEvent = 0U;
  4006. PlsrTimerErrorPending = 0U;
  4007. PlsrRamp.active = 0U;
  4008. PlsrExecutor.mode = PLSR_EXEC_IDLE;
  4009. PlsrInvalidateHandoffPlans();
  4010. PlsrRunStatus = PLSR_STATUS_COMPLETED;
  4011. PlsrError = PLSR_ERROR_NONE;
  4012. PlsrCheckpointPosition(0U);
  4013. PlsrMarkPersistenceDirty(PLSR_CONFIG_SAVE_DELAY_MS);
  4014. }
  4015. static void PlsrFinishStopped(void)
  4016. {
  4017. PlsrDisarmWaitSignal();
  4018. PlsrDiagnosticFinishSegment(0U);
  4019. PlsrPlatformStopPulse((uint8_t)PlsrActiveConfig.pulseOutput);
  4020. PlsrRemainingPulses = 0UL;
  4021. PlsrCommandRemainingPulses = 0ULL;
  4022. PlsrPulseActive = 0U;
  4023. PlsrCutRequested = 0U;
  4024. PlsrActTimedCutPlanned = 0U;
  4025. PlsrBoundaryPending = 0U;
  4026. PlsrBoundaryWasCut = 0U;
  4027. PlsrCurrentFrequencyHz = 0UL;
  4028. PlsrQueuedFrequencyHz = 0UL;
  4029. PlsrCurrentSegment = 0U;
  4030. PlsrSegmentClockStarted = 0U;
  4031. PlsrDirectionDelayActive = 0U;
  4032. PlsrDirectionDelayRemainingMs = 0U;
  4033. PlsrInitialDirectionPreparePending = 0U;
  4034. PlsrExtCaptureSegment = 0U;
  4035. PlsrExtEdgePending = 0U;
  4036. PlsrStopRequested = 0U;
  4037. PlsrStopPulsesRemaining = 0U;
  4038. PlsrAbStopArmed = 0U;
  4039. PlsrSeamlessHandoffPending = 0U;
  4040. PlsrDeferredFrequencyPending = 0U;
  4041. PlsrShortProfile.active = 0U;
  4042. PlsrProfileQueueReset();
  4043. PlsrHandoffPlan.valid = 0U;
  4044. PlsrCountedBoundaryWriteIndex = 0U;
  4045. PlsrCountedBoundaryReadIndex = 0U;
  4046. PlsrCountedBoundaryBusy = 0U;
  4047. PlsrCountedFaultEvent = 0U;
  4048. PlsrTimerErrorPending = 0U;
  4049. PlsrRamp.active = 0U;
  4050. PlsrExecutor.mode = PLSR_EXEC_IDLE;
  4051. PlsrInvalidateHandoffPlans();
  4052. PlsrRunStatus = PLSR_STATUS_STOPPED;
  4053. PlsrError = PLSR_ERROR_NONE;
  4054. PlsrCheckpointPosition(0U);
  4055. PlsrMarkPersistenceDirty(PLSR_CONFIG_SAVE_DELAY_MS);
  4056. }
  4057. static void PlsrEnterError(PLSR_ERROR error)
  4058. {
  4059. PlsrDisarmWaitSignal();
  4060. PlsrDiagnosticFinishSegment(0U);
  4061. PlsrPlatformStopPulse((uint8_t)PlsrActiveConfig.pulseOutput);
  4062. PlsrRemainingPulses = 0UL;
  4063. PlsrCommandRemainingPulses = 0ULL;
  4064. PlsrPulseActive = 0U;
  4065. PlsrCutRequested = 0U;
  4066. PlsrActTimedCutPlanned = 0U;
  4067. PlsrBoundaryPending = 0U;
  4068. PlsrBoundaryWasCut = 0U;
  4069. PlsrCurrentFrequencyHz = 0UL;
  4070. PlsrQueuedFrequencyHz = 0UL;
  4071. PlsrCurrentSegment = 0U;
  4072. PlsrSegmentClockStarted = 0U;
  4073. PlsrDirectionDelayActive = 0U;
  4074. PlsrDirectionDelayRemainingMs = 0U;
  4075. PlsrInitialDirectionPreparePending = 0U;
  4076. PlsrExtCaptureSegment = 0U;
  4077. PlsrExtEdgePending = 0U;
  4078. PlsrStopRequested = 0U;
  4079. PlsrStopPulsesRemaining = 0U;
  4080. PlsrAbStopArmed = 0U;
  4081. PlsrSeamlessHandoffPending = 0U;
  4082. PlsrDeferredFrequencyPending = 0U;
  4083. PlsrShortProfile.active = 0U;
  4084. PlsrProfileQueueReset();
  4085. PlsrHandoffPlan.valid = 0U;
  4086. PlsrCountedBoundaryWriteIndex = 0U;
  4087. PlsrCountedBoundaryReadIndex = 0U;
  4088. PlsrCountedBoundaryBusy = 0U;
  4089. PlsrCountedFaultEvent = 0U;
  4090. PlsrTimerErrorPending = 0U;
  4091. PlsrRamp.active = 0U;
  4092. PlsrExecutor.mode = PLSR_EXEC_IDLE;
  4093. PlsrInvalidateHandoffPlans();
  4094. PlsrRunStatus = PLSR_STATUS_ERROR;
  4095. PlsrError = error;
  4096. PlsrCheckpointPosition(0U);
  4097. PlsrMarkPersistenceDirty(PLSR_CONFIG_SAVE_DELAY_MS);
  4098. }
  4099. static void PlsrTransitionToNext(uint8_t allowCarry)
  4100. {
  4101. uint8_t nextSegment;
  4102. int32_t position;
  4103. int64_t displacement;
  4104. uint32_t criticalState;
  4105. uint32_t carryFrequencyHz = PlsrBoundaryFrequencyHz;
  4106. PLSR_PLATFORM_SERVICE_RESULT preparedResult;
  4107. criticalState = PlsrPlatformEnterCritical();
  4108. position = PlsrPosition;
  4109. PlsrPlatformExitCritical(criticalState);
  4110. if (PlsrResolveNextMotionSegment(
  4111. PlsrCurrentSegment, position,
  4112. &nextSegment, &displacement) == 0U)
  4113. {
  4114. PlsrFinishCompleted();
  4115. return;
  4116. }
  4117. if (PlsrActiveConfig.outputMode == PLSR_OUTPUT_PULSE_DIR)
  4118. {
  4119. PlsrCompleteTimedStartPreparation();
  4120. }
  4121. if ((allowCarry == 0U)
  4122. || (PlsrActiveConfig.outputMode == PLSR_OUTPUT_PULSE_DIR))
  4123. {
  4124. preparedResult = PlsrTryStartPreparedTimedSegment(
  4125. nextSegment, displacement);
  4126. if (preparedResult == PLSR_PLATFORM_SERVICE_READY)
  4127. {
  4128. return;
  4129. }
  4130. if (preparedResult == PLSR_PLATFORM_SERVICE_FAILED)
  4131. {
  4132. PlsrEnterError(PLSR_ERROR_INVALID_RESOURCE);
  4133. return;
  4134. }
  4135. }
  4136. if (PlsrStartSegment(
  4137. nextSegment,
  4138. (allowCarry != 0U) ? PLSR_SEGMENT_ENTRY_CARRY
  4139. : PLSR_SEGMENT_ENTRY_INTERNAL_RESTART,
  4140. carryFrequencyHz) == 0U)
  4141. {
  4142. PlsrEnterError(PLSR_ERROR_INVALID_RESOURCE);
  4143. }
  4144. }
  4145. static uint8_t PlsrBuildHandoffPlan(uint8_t sourceSegment,
  4146. const PLSR_CONFIG *frequencyConfig,
  4147. uint32_t carryFrequencyHz,
  4148. PLSR_HANDOFF_PLAN *plan)
  4149. {
  4150. const PLSR_SEGMENT_CONFIG *segment;
  4151. uint8_t nextSegment;
  4152. int64_t displacement;
  4153. int64_t sourceEndpoint;
  4154. uint64_t sourceRemaining;
  4155. int32_t sourcePosition;
  4156. uint32_t nextFrequencyHz;
  4157. uint32_t criticalState;
  4158. uint8_t positive;
  4159. uint8_t warmupIndex;
  4160. uint8_t sourceActTimed;
  4161. uint8_t nextActTimedCut = 0U;
  4162. uint8_t sourcePositive;
  4163. plan->valid = 0U;
  4164. if ((sourceSegment == 0U)
  4165. || (sourceSegment > PlsrActiveConfig.segmentCount))
  4166. {
  4167. return 0U;
  4168. }
  4169. segment = &PlsrActiveConfig.segments[sourceSegment - 1U];
  4170. sourceActTimed = ((segment->waitType == PLSR_ACT_TIME)
  4171. && (sourceSegment == PlsrCurrentSegment)
  4172. && (PlsrActTimedCutPlanned != 0U)) ? 1U : 0U;
  4173. if ((segment->waitType != PLSR_EXT_OR_COMPLETE)
  4174. && (sourceActTimed == 0U))
  4175. {
  4176. return 0U;
  4177. }
  4178. sourceEndpoint = 0;
  4179. if (PlsrActiveConfig.positionMode == PLSR_POSITION_ABSOLUTE)
  4180. {
  4181. sourceEndpoint = segment->pulses;
  4182. if (sourceActTimed != 0U)
  4183. {
  4184. criticalState = PlsrPlatformEnterCritical();
  4185. sourcePosition = PlsrPosition;
  4186. sourceRemaining = PlsrRemainingPulses;
  4187. sourcePositive = PlsrCountPositive;
  4188. PlsrPlatformExitCritical(criticalState);
  4189. sourceEndpoint = (sourcePositive != 0U)
  4190. ? (int64_t)sourcePosition
  4191. + (int64_t)sourceRemaining
  4192. : (int64_t)sourcePosition
  4193. - (int64_t)sourceRemaining;
  4194. }
  4195. }
  4196. if ((sourceEndpoint > (int64_t)INT32_MAX)
  4197. || (sourceEndpoint < (int64_t)INT32_MIN)
  4198. || (PlsrResolveNextMotionSegment(
  4199. sourceSegment, (int32_t)sourceEndpoint,
  4200. &nextSegment, &displacement) == 0U))
  4201. {
  4202. return 0U;
  4203. }
  4204. positive = (displacement > 0) ? 1U : 0U;
  4205. plan->magnitude = (displacement < 0) ? (uint64_t)(-displacement)
  4206. : (uint64_t)displacement;
  4207. plan->commandMagnitude = plan->magnitude;
  4208. if (carryFrequencyHz == 0UL)
  4209. {
  4210. carryFrequencyHz =
  4211. PlsrResolvedSegmentFrequency(frequencyConfig, sourceSegment - 1U);
  4212. }
  4213. nextFrequencyHz =
  4214. PlsrResolvedSegmentFrequency(frequencyConfig, nextSegment - 1U);
  4215. if (PlsrPrepareShortProfile(&plan->profile, frequencyConfig, nextSegment,
  4216. carryFrequencyHz, nextFrequencyHz,
  4217. plan->magnitude, positive, 0U) == 0U)
  4218. {
  4219. return 0U;
  4220. }
  4221. if (PlsrActiveConfig.segments[nextSegment - 1U].waitType
  4222. == PLSR_ACT_TIME)
  4223. {
  4224. if ((PlsrActiveConfig.segments[nextSegment - 1U].actTimeMs == 0U)
  4225. || (PlsrLimitProfileToActTime(
  4226. &plan->profile,
  4227. PlsrActiveConfig.segments[nextSegment - 1U].actTimeMs,
  4228. &nextActTimedCut) == 0U)
  4229. || (plan->profile.pulseCount == 0UL))
  4230. {
  4231. return 0U;
  4232. }
  4233. plan->magnitude = plan->profile.pulseCount;
  4234. }
  4235. {
  4236. PLSR_PROFILE_ENTRY firstEntry;
  4237. PLSR_PROFILE_ENTRY secondEntry;
  4238. if (PlsrShortProfileTakeRun(&plan->profile, &firstEntry) == 0U)
  4239. {
  4240. return 0U;
  4241. }
  4242. plan->firstSetting = firstEntry.setting;
  4243. plan->firstFrequencyHz = firstEntry.setting.actualFrequencyHz;
  4244. plan->firstRequestedFrequencyHz = firstEntry.requestedFrequencyHz;
  4245. plan->firstRepeatCount = firstEntry.repeatCount;
  4246. if (PlsrShortProfileTakeRun(&plan->profile, &secondEntry) != 0U)
  4247. {
  4248. plan->secondSetting = secondEntry.setting;
  4249. plan->secondFrequencyHz = secondEntry.setting.actualFrequencyHz;
  4250. plan->secondRequestedFrequencyHz =
  4251. secondEntry.requestedFrequencyHz;
  4252. plan->secondRepeatCount = secondEntry.repeatCount;
  4253. }
  4254. else
  4255. {
  4256. plan->secondSetting = firstEntry.setting;
  4257. plan->secondFrequencyHz = firstEntry.setting.actualFrequencyHz;
  4258. plan->secondRequestedFrequencyHz =
  4259. firstEntry.requestedFrequencyHz;
  4260. plan->secondRepeatCount = 0UL;
  4261. }
  4262. }
  4263. if ((plan->firstRepeatCount == 0UL)
  4264. || (plan->firstFrequencyHz == 0UL))
  4265. {
  4266. return 0U;
  4267. }
  4268. plan->warmupCount = 0U;
  4269. for (warmupIndex = 0U;
  4270. (warmupIndex < PLSR_HANDOFF_WARMUP_ITEMS)
  4271. && (plan->profile.nextPeriod < plan->profile.pulseCount);
  4272. warmupIndex++)
  4273. {
  4274. PLSR_PROFILE_ENTRY *entry = &plan->warmup[warmupIndex];
  4275. if (PlsrShortProfileTakeRun(&plan->profile, entry) == 0U)
  4276. {
  4277. return 0U;
  4278. }
  4279. plan->warmupCount++;
  4280. }
  4281. plan->firstFrequencyHz = plan->firstSetting.actualFrequencyHz;
  4282. plan->secondFrequencyHz = plan->secondSetting.actualFrequencyHz;
  4283. plan->nextSegment = nextSegment;
  4284. plan->positive = positive;
  4285. plan->nextActTimedCut = nextActTimedCut;
  4286. plan->valid = 1U;
  4287. return 1U;
  4288. }
  4289. static uint8_t PlsrBuildHandoffPlanBank(
  4290. const PLSR_CONFIG *frequencyConfig)
  4291. {
  4292. uint8_t buildBank = (uint8_t)(PlsrPreparedHandoffBank ^ 1U);
  4293. uint8_t sourceSegment;
  4294. PLSR_HANDOFF_PLAN *destination;
  4295. for (sourceSegment = 0U;
  4296. sourceSegment < PLSR_SEGMENT_COUNT_MAX;
  4297. sourceSegment++)
  4298. {
  4299. PlsrPreparedHandoffPlans[buildBank][sourceSegment].valid = 0U;
  4300. }
  4301. for (sourceSegment = 1U;
  4302. sourceSegment <= PlsrActiveConfig.segmentCount;
  4303. sourceSegment++)
  4304. {
  4305. destination =
  4306. &PlsrPreparedHandoffPlans[buildBank][sourceSegment - 1U];
  4307. (void)PlsrBuildHandoffPlan(sourceSegment, frequencyConfig, 0UL,
  4308. destination);
  4309. }
  4310. return buildBank;
  4311. }
  4312. static void PlsrRefreshCurrentHandoffPlan(uint32_t terminalFrequencyHz)
  4313. {
  4314. PLSR_PLATFORM_TIMER_SETTING terminalSetting;
  4315. PLSR_HANDOFF_PLAN *destination;
  4316. uint8_t currentSegment = PlsrCurrentSegment;
  4317. uint8_t preparedBank = PlsrPreparedHandoffBank;
  4318. if ((currentSegment == 0U)
  4319. || (currentSegment > PlsrActiveConfig.segmentCount)
  4320. || (PlsrPlatformBuildTimerSetting(
  4321. (uint8_t)PlsrActiveConfig.pulseOutput,
  4322. (uint8_t)PlsrActiveConfig.outputMode,
  4323. terminalFrequencyHz, &terminalSetting) == 0U))
  4324. {
  4325. return;
  4326. }
  4327. destination = &PlsrPreparedHandoffPlans[preparedBank]
  4328. [currentSegment - 1U];
  4329. (void)PlsrBuildHandoffPlan(currentSegment, &PlsrActiveConfig,
  4330. terminalSetting.actualFrequencyHz,
  4331. destination);
  4332. }
  4333. static uint8_t PlsrSelectPreparedHandoffPlan(PLSR_HANDOFF_PLAN *plan)
  4334. {
  4335. const PLSR_HANDOFF_PLAN *prepared;
  4336. uint8_t preparedBank;
  4337. uint8_t currentSegment;
  4338. plan->valid = 0U;
  4339. currentSegment = PlsrCurrentSegment;
  4340. if ((PlsrRemainingPulses != 1UL)
  4341. || (PlsrStopRequested != 0U)
  4342. || (PlsrCountOverflowPending != 0U)
  4343. || (PlsrCutRequested != 0U)
  4344. || (PlsrAbStopArmed != 0U)
  4345. || (currentSegment == 0U)
  4346. || (currentSegment > PlsrActiveConfig.segmentCount))
  4347. {
  4348. return 0U;
  4349. }
  4350. preparedBank = PlsrPreparedHandoffBank;
  4351. prepared = &PlsrPreparedHandoffPlans[preparedBank][currentSegment - 1U];
  4352. if ((prepared->valid == 0U)
  4353. || (prepared->positive != PlsrCountPositive))
  4354. {
  4355. return 0U;
  4356. }
  4357. *plan = *prepared;
  4358. return 1U;
  4359. }
  4360. static uint8_t PlsrStageCountedHandoff(void)
  4361. {
  4362. const PLSR_HANDOFF_PLAN *prepared;
  4363. PLSR_HANDOFF_PLAN candidate;
  4364. PLSR_PROFILE_ENTRY entry;
  4365. uint32_t criticalState;
  4366. uint32_t writeIndex;
  4367. uint16_t required;
  4368. uint8_t currentSegment;
  4369. uint8_t index;
  4370. PLSR_PROFILE_QUEUE *queue =
  4371. &PlsrProfileQueues[PlsrProfileQueueBank];
  4372. if ((PlsrActiveConfig.outputMode != PLSR_OUTPUT_PULSE_DIR)
  4373. || (PlsrCountedHandoffStaged != 0U)
  4374. || (PlsrStopRequested != 0U)
  4375. || (PlsrCutRequested != 0U)
  4376. || (queue->generatorComplete == 0U))
  4377. {
  4378. return 1U;
  4379. }
  4380. currentSegment = PlsrCurrentSegment;
  4381. if ((currentSegment == 0U)
  4382. || (currentSegment > PlsrActiveConfig.segmentCount))
  4383. {
  4384. return 1U;
  4385. }
  4386. prepared = &PlsrPreparedHandoffPlans[PlsrPreparedHandoffBank]
  4387. [currentSegment - 1U];
  4388. if ((prepared->valid == 0U)
  4389. || (prepared->positive != PlsrCountPositive))
  4390. {
  4391. return 1U;
  4392. }
  4393. candidate = *prepared;
  4394. required = (uint16_t)(1U + candidate.warmupCount
  4395. + ((candidate.secondRepeatCount != 0UL)
  4396. ? 1U : 0U));
  4397. criticalState = PlsrPlatformEnterCritical();
  4398. if ((PlsrCountedHandoffStaged != 0U)
  4399. || (queue->generatorComplete == 0U)
  4400. || ((uint16_t)(PLSR_PROFILE_QUEUE_CAPACITY
  4401. - PlsrProfileQueueCount()) < required))
  4402. {
  4403. PlsrPlatformExitCritical(criticalState);
  4404. return 1U;
  4405. }
  4406. writeIndex = queue->writeIndex;
  4407. entry.setting = candidate.firstSetting;
  4408. entry.requestedFrequencyHz = candidate.firstRequestedFrequencyHz;
  4409. entry.repeatCount = candidate.firstRepeatCount;
  4410. entry.startsNextSegment = 1U;
  4411. queue->entries[writeIndex & PLSR_PROFILE_QUEUE_MASK] = entry;
  4412. writeIndex++;
  4413. if (candidate.secondRepeatCount != 0UL)
  4414. {
  4415. entry.setting = candidate.secondSetting;
  4416. entry.requestedFrequencyHz =
  4417. candidate.secondRequestedFrequencyHz;
  4418. entry.repeatCount = candidate.secondRepeatCount;
  4419. entry.startsNextSegment = 0U;
  4420. queue->entries[writeIndex & PLSR_PROFILE_QUEUE_MASK] = entry;
  4421. writeIndex++;
  4422. }
  4423. for (index = 0U; index < candidate.warmupCount; index++)
  4424. {
  4425. entry = candidate.warmup[index];
  4426. entry.startsNextSegment = 0U;
  4427. queue->entries[writeIndex & PLSR_PROFILE_QUEUE_MASK] = entry;
  4428. writeIndex++;
  4429. }
  4430. queue->writeIndex = writeIndex;
  4431. PlsrCopyShortProfile(&queue->producerProfile, &candidate.profile);
  4432. queue->producerEpoch = PlsrSegmentEpoch + 1UL;
  4433. queue->producerSegment = candidate.nextSegment;
  4434. queue->generatorComplete =
  4435. ((candidate.profile.active == 0U)
  4436. || (candidate.profile.nextPeriod >= candidate.profile.pulseCount))
  4437. ? 1U : 0U;
  4438. queue->active = 1U;
  4439. PlsrHandoffPlan = candidate;
  4440. PlsrHandoffPlan.valid = 1U;
  4441. PlsrCountedHandoffStaged = 1U;
  4442. PlsrPlatformExitCritical(criticalState);
  4443. return 1U;
  4444. }
  4445. static uint8_t PlsrApplyCountedProgressSnapshot(
  4446. uint64_t observed,
  4447. uint64_t *appliedPulses)
  4448. {
  4449. uint64_t delta;
  4450. uint64_t remaining;
  4451. int64_t nextPosition;
  4452. if (observed < PlsrCountedObservedPublished)
  4453. {
  4454. return 0U;
  4455. }
  4456. delta = observed - PlsrCountedObservedPublished;
  4457. if (delta == 0ULL)
  4458. {
  4459. if (appliedPulses != NULL)
  4460. {
  4461. *appliedPulses = 0ULL;
  4462. }
  4463. return 1U;
  4464. }
  4465. remaining = PlsrRemainingPulses;
  4466. if (delta > remaining)
  4467. {
  4468. delta = remaining;
  4469. #if PLSR_COUNT_ERROR_CHECK_ENABLED
  4470. PlsrCountOverflowPending = 1U;
  4471. #endif
  4472. }
  4473. if (PlsrCountPositive != 0U)
  4474. {
  4475. nextPosition = (int64_t)PlsrPosition + (int64_t)delta;
  4476. }
  4477. else
  4478. {
  4479. nextPosition = (int64_t)PlsrPosition - (int64_t)delta;
  4480. }
  4481. if ((nextPosition > (int64_t)INT32_MAX)
  4482. || (nextPosition < (int64_t)INT32_MIN))
  4483. {
  4484. PlsrPositionValid = 0U;
  4485. #if PLSR_COUNT_ERROR_CHECK_ENABLED
  4486. PlsrCountOverflowPending = 1U;
  4487. #endif
  4488. }
  4489. else
  4490. {
  4491. PlsrPosition = (int32_t)nextPosition;
  4492. }
  4493. PlsrRemainingPulses = remaining - delta;
  4494. if (delta >= PlsrCommandRemainingPulses)
  4495. {
  4496. PlsrCommandRemainingPulses = 0ULL;
  4497. }
  4498. else
  4499. {
  4500. PlsrCommandRemainingPulses -= delta;
  4501. }
  4502. PlsrCountedObservedPublished = observed;
  4503. PlsrPositionCheckpointDirty = 1U;
  4504. if (appliedPulses != NULL)
  4505. {
  4506. *appliedPulses = delta;
  4507. }
  4508. return 1U;
  4509. }
  4510. static uint8_t PlsrSyncCountedProgress(void)
  4511. {
  4512. uint64_t observed = PlsrPlatformObservedPulses(
  4513. (uint8_t)PlsrActiveConfig.pulseOutput);
  4514. return PlsrApplyCountedProgressSnapshot(observed, NULL);
  4515. }
  4516. uint8_t PlsrExecTakeCountedRunIrq(
  4517. uint8_t pulseOutput,
  4518. PLSR_PLATFORM_TIMER_SETTING *setting,
  4519. uint32_t *pulseCount,
  4520. uint8_t *startsNextSegment)
  4521. {
  4522. const PLSR_PROFILE_ENTRY *entry;
  4523. PLSR_PROFILE_QUEUE *queue;
  4524. uint32_t readIndex;
  4525. uint32_t nextReadIndex;
  4526. if ((pulseOutput != (uint8_t)PlsrActiveConfig.pulseOutput)
  4527. || (setting == NULL) || (pulseCount == NULL)
  4528. || (startsNextSegment == NULL)
  4529. || (PlsrPulseActive == 0U))
  4530. {
  4531. return PLSR_EXEC_RUN_FAILED;
  4532. }
  4533. queue = &PlsrProfileQueues[PlsrProfileQueueBank];
  4534. readIndex = queue->readIndex;
  4535. if (readIndex == queue->writeIndex)
  4536. {
  4537. uint32_t availablePulses;
  4538. uint32_t holdPulses;
  4539. uint32_t holdFrequencyHz;
  4540. uint32_t producerRemaining;
  4541. if (queue->generatorComplete != 0U)
  4542. {
  4543. return PLSR_EXEC_RUN_DONE;
  4544. }
  4545. PlsrProfileQueueRecordUnderrun();
  4546. /* A producer miss must not immediately turn the last scheduled edge
  4547. into an abrupt stop. Borrow at most 2 ms of still-unplanned logical
  4548. pulses and hold the last applied timer setting. The task repays
  4549. this debt by advancing (without enqueueing) the same number of
  4550. planner pulses, so segment pulse count remains exact. */
  4551. producerRemaining =
  4552. (queue->producerProfile.pulseCount
  4553. > queue->producerProfile.nextPeriod)
  4554. ? queue->producerProfile.pulseCount
  4555. - queue->producerProfile.nextPeriod
  4556. : 0UL;
  4557. if (producerRemaining > queue->underrunDebtPulses)
  4558. {
  4559. availablePulses =
  4560. producerRemaining - queue->underrunDebtPulses;
  4561. }
  4562. else
  4563. {
  4564. /* Every remaining planner pulse is already represented by a
  4565. borrowed run. The current committed run is the terminal tail;
  4566. stopping after it is completion, not a stream underrun. */
  4567. return PLSR_EXEC_RUN_DONE;
  4568. }
  4569. holdFrequencyHz = queue->lastSetting.actualFrequencyHz;
  4570. holdPulses = (uint32_t)(
  4571. ((uint64_t)holdFrequencyHz * PLSR_UNDERRUN_HOLD_TIME_US
  4572. + 999999ULL) / 1000000ULL);
  4573. if (holdPulses == 0UL)
  4574. {
  4575. holdPulses = 1UL;
  4576. }
  4577. if (holdPulses > PLSR_UNDERRUN_HOLD_MAX_PULSES)
  4578. {
  4579. holdPulses = PLSR_UNDERRUN_HOLD_MAX_PULSES;
  4580. }
  4581. if (holdPulses > availablePulses)
  4582. {
  4583. holdPulses = availablePulses;
  4584. }
  4585. if ((queue->active == 0U) || (queue->haveLastSetting == 0U)
  4586. || (holdFrequencyHz == 0UL) || (holdPulses == 0UL))
  4587. {
  4588. return PLSR_EXEC_RUN_FAILED;
  4589. }
  4590. queue->underrunDebtPulses += holdPulses;
  4591. queue->generation++;
  4592. *setting = queue->lastSetting;
  4593. *pulseCount = holdPulses;
  4594. *startsNextSegment = 0U;
  4595. PlsrQueuedFrequencyHz = holdFrequencyHz;
  4596. return PLSR_EXEC_RUN_READY;
  4597. }
  4598. entry = &queue->entries[readIndex & PLSR_PROFILE_QUEUE_MASK];
  4599. if (entry->repeatCount == 0UL)
  4600. {
  4601. return PLSR_EXEC_RUN_FAILED;
  4602. }
  4603. /* 先校验 handoff 前置条件,再推进读索引:失败时该项不被消费。
  4604. 不在此处更新任何执行状态(Pending/active 等),全部由任务消费事件时做。 */
  4605. if (entry->startsNextSegment != 0U)
  4606. {
  4607. if ((PlsrCountedHandoffStaged == 0U)
  4608. || (PlsrHandoffPlan.valid == 0U))
  4609. {
  4610. return PLSR_EXEC_RUN_FAILED;
  4611. }
  4612. }
  4613. *setting = entry->setting;
  4614. *pulseCount = entry->repeatCount;
  4615. *startsNextSegment = entry->startsNextSegment;
  4616. nextReadIndex = readIndex + 1UL;
  4617. queue->readIndex = nextReadIndex;
  4618. queue->lastSetting = entry->setting;
  4619. queue->haveLastSetting = 1U;
  4620. if (queue->generatorComplete == 0U)
  4621. {
  4622. PlsrProfileQueueRecordDepth(
  4623. (uint16_t)(queue->writeIndex - nextReadIndex));
  4624. }
  4625. /* 记录硬件即将生效的频率(事实镜像),不做任何状态转换。 */
  4626. PlsrQueuedFrequencyHz = entry->setting.actualFrequencyHz;
  4627. return PLSR_EXEC_RUN_READY;
  4628. }
  4629. void PlsrExecCountedSegmentBoundaryIrq(uint8_t pulseOutput,
  4630. uint32_t completedPulses)
  4631. {
  4632. PLSR_COUNTED_BOUNDARY_EVENT *event;
  4633. uint8_t writeIndex;
  4634. uint8_t previousExtSegment;
  4635. uint8_t hardwareExtPending;
  4636. uint32_t previousExtEpoch;
  4637. if (pulseOutput != (uint8_t)PlsrActiveConfig.pulseOutput)
  4638. {
  4639. return;
  4640. }
  4641. if (PlsrHandoffPlan.valid == 0U)
  4642. {
  4643. PlsrCountedFaultEvent = 1U;
  4644. return;
  4645. }
  4646. writeIndex = PlsrCountedBoundaryWriteIndex;
  4647. if ((PlsrCountedBoundaryBusy != 0U)
  4648. || ((uint8_t)(writeIndex - PlsrCountedBoundaryReadIndex)
  4649. >= PLSR_BOUNDARY_EVENT_CAPACITY))
  4650. {
  4651. PlsrCountedFaultEvent = 1U;
  4652. return;
  4653. }
  4654. event = &PlsrCountedBoundaryEvents[
  4655. writeIndex & (PLSR_BOUNDARY_EVENT_CAPACITY - 1U)];
  4656. event->magnitude = PlsrHandoffPlan.magnitude;
  4657. event->commandMagnitude = PlsrHandoffPlan.commandMagnitude;
  4658. event->firstFrequencyHz = PlsrHandoffPlan.firstFrequencyHz;
  4659. event->completedPulses = completedPulses;
  4660. event->nextSegment = PlsrHandoffPlan.nextSegment;
  4661. event->positive = PlsrHandoffPlan.positive;
  4662. event->nextActTimedCut = PlsrHandoffPlan.nextActTimedCut;
  4663. previousExtSegment = PlsrExtCaptureSegment;
  4664. previousExtEpoch = PlsrExtCaptureEpoch;
  4665. hardwareExtPending = PlsrPlatformTakeInputExtiPending(
  4666. (uint8_t)PlsrActiveConfig.extInput);
  4667. if (hardwareExtPending != 0U)
  4668. {
  4669. /* The lower-priority EXTI ISR has not run yet. The natural boundary
  4670. consumes this source-segment edge, so discard any matching software
  4671. latch as well and do not let either reach the next segment. */
  4672. PlsrExtEdgePending = 0U;
  4673. }
  4674. else if ((PlsrExtEdgePending != 0U)
  4675. && (PlsrExtEdgePendingSegment == previousExtSegment)
  4676. && (PlsrExtEdgePendingEpoch == previousExtEpoch))
  4677. {
  4678. /* The EXTI ISR already captured the source-segment edge. Natural
  4679. completion satisfies EXT_OR_COMPLETE, preventing a double step. */
  4680. PlsrExtEdgePending = 0U;
  4681. }
  4682. PlsrExtCaptureSegment = event->nextSegment;
  4683. PlsrExtCaptureEpoch = previousExtEpoch + 1UL;
  4684. #if defined(__ICCARM__)
  4685. __DMB();
  4686. #endif
  4687. PlsrCountedBoundaryWriteIndex = (uint8_t)(writeIndex + 1U);
  4688. }
  4689. static void PlsrExecServiceCountedBoundaryEvent(void);
  4690. /* 任务上下文:消费 counted 流的全部 IRQ 事件(流故障 + 段边界)。
  4691. 段切换簿记与错误标志写入均在此完成,IRQ 内不再做状态转换。 */
  4692. static void PlsrExecServiceCountedEvents(void)
  4693. {
  4694. if (PlsrCountedFaultEvent != 0U)
  4695. {
  4696. PlsrCountedFaultEvent = 0U;
  4697. PlsrTimerErrorPending = 1U;
  4698. return;
  4699. }
  4700. PlsrExecServiceCountedBoundaryEvent();
  4701. }
  4702. /* 任务上下文:消费段边界事件,完成全部段切换簿记。
  4703. 硬件连续性不依赖本函数(下一段首 run 已由队列预装载),晚 1ms 消费无影响。 */
  4704. static void PlsrExecServiceCountedBoundaryEvent(void)
  4705. {
  4706. PLSR_COUNTED_BOUNDARY_EVENT event;
  4707. uint64_t observed;
  4708. uint64_t delta;
  4709. int64_t nextPosition;
  4710. uint32_t currentFrequencyHz;
  4711. uint32_t queuedFrequencyHz;
  4712. uint8_t nextSegment;
  4713. uint32_t criticalState;
  4714. uint8_t readIndex;
  4715. criticalState = PlsrPlatformEnterCritical();
  4716. readIndex = PlsrCountedBoundaryReadIndex;
  4717. if (readIndex == PlsrCountedBoundaryWriteIndex)
  4718. {
  4719. PlsrPlatformExitCritical(criticalState);
  4720. return;
  4721. }
  4722. event = PlsrCountedBoundaryEvents[
  4723. readIndex & (PLSR_BOUNDARY_EVENT_CAPACITY - 1U)];
  4724. PlsrCountedBoundaryReadIndex = (uint8_t)(readIndex + 1U);
  4725. PlsrCountedBoundaryBusy = 1U;
  4726. PlsrPlatformExitCritical(criticalState);
  4727. observed = event.completedPulses;
  4728. nextSegment = event.nextSegment;
  4729. if ((nextSegment == 0U)
  4730. || (nextSegment > PlsrActiveConfig.segmentCount))
  4731. {
  4732. PlsrTimerErrorPending = 1U;
  4733. return;
  4734. }
  4735. /* 用 IRQ 边界时刻的计数快照结算旧段:任务消费时下一 run 可能已发出
  4736. 若干脉冲,直接读当前硬件计数会把下一段脉冲算进旧段。 */
  4737. if (observed < PlsrCountedObservedPublished)
  4738. {
  4739. PlsrTimerErrorPending = 1U;
  4740. return;
  4741. }
  4742. delta = observed - PlsrCountedObservedPublished;
  4743. if (delta > PlsrRemainingPulses)
  4744. {
  4745. delta = PlsrRemainingPulses;
  4746. #if PLSR_COUNT_ERROR_CHECK_ENABLED
  4747. PlsrCountOverflowPending = 1U;
  4748. #endif
  4749. }
  4750. if (PlsrCountPositive != 0U)
  4751. {
  4752. nextPosition = (int64_t)PlsrPosition + (int64_t)delta;
  4753. }
  4754. else
  4755. {
  4756. nextPosition = (int64_t)PlsrPosition - (int64_t)delta;
  4757. }
  4758. if ((nextPosition > (int64_t)INT32_MAX)
  4759. || (nextPosition < (int64_t)INT32_MIN))
  4760. {
  4761. PlsrPositionValid = 0U;
  4762. #if PLSR_COUNT_ERROR_CHECK_ENABLED
  4763. PlsrCountOverflowPending = 1U;
  4764. #endif
  4765. }
  4766. else
  4767. {
  4768. PlsrPosition = (int32_t)nextPosition;
  4769. }
  4770. PlsrRemainingPulses -= delta;
  4771. PlsrCountedObservedPublished = observed;
  4772. PlsrPositionCheckpointDirty = 1U;
  4773. if (PlsrRemainingPulses != 0ULL)
  4774. {
  4775. PlsrTimerErrorPending = 1U;
  4776. return;
  4777. }
  4778. PlsrDiagnosticFinishSegment(1U);
  4779. PlsrSegmentEpoch++;
  4780. PlsrCurrentSegment = nextSegment;
  4781. PlsrRemainingPulses = event.magnitude;
  4782. PlsrCommandRemainingPulses = event.commandMagnitude;
  4783. PlsrCountPositive = event.positive;
  4784. PlsrCurrentFrequencyHz = event.firstFrequencyHz;
  4785. PlsrBoundaryFrequencyHz = event.firstFrequencyHz;
  4786. PlsrSegmentClockStarted = 1U;
  4787. PlsrSegmentElapsedMs = 0UL;
  4788. PlsrWaitElapsedMs = 0UL;
  4789. PlsrBoundaryRampStarted = 0U;
  4790. PlsrBoundaryPending = 0U;
  4791. PlsrBoundaryWasCut = 0U;
  4792. PlsrCutRequested = 0U;
  4793. PlsrActTimedCutPlanned = event.nextActTimedCut;
  4794. if (PlsrFrequencyUpdatePending != 0U)
  4795. {
  4796. /* An online frequency transaction that met a latched segment marker
  4797. follows the hardware into the new segment instead of invalidating
  4798. the old handoff metadata. */
  4799. PlsrFrequencyUpdateSegment = nextSegment;
  4800. PlsrFrequencyUpdateTargetHz =
  4801. PlsrActiveConfig.segments[nextSegment - 1U].frequencyHz;
  4802. }
  4803. PlsrDeferredFrequencyPending = 0U;
  4804. PlsrExtPreviousLevel =
  4805. PlsrPlatformReadInput((uint8_t)PlsrActiveConfig.extInput);
  4806. PlsrCopyShortProfile(&PlsrShortProfile,
  4807. &PlsrProfileQueue.producerProfile);
  4808. PlsrRefreshCurrentHandoffPlan(PlsrShortProfile.endHz);
  4809. PlsrDiagnosticBeginSegment(nextSegment, event.magnitude, event.positive);
  4810. PlsrSeamlessHandoffPending = 1U;
  4811. PlsrCountedHandoffStaged = 0U;
  4812. PlsrHandoffPlan.valid = 0U;
  4813. PlsrExecutor.generation++;
  4814. PlsrExecutor.mode = (PlsrProfileQueue.generatorComplete != 0U)
  4815. ? PLSR_EXEC_STEP_TABLE
  4816. : PLSR_EXEC_STREAM;
  4817. currentFrequencyHz = PlsrCurrentFrequencyHz;
  4818. queuedFrequencyHz = PlsrQueuedFrequencyHz;
  4819. if (queuedFrequencyHz > currentFrequencyHz)
  4820. {
  4821. PlsrRunStatus = PLSR_STATUS_ACCELERATING;
  4822. }
  4823. else if (queuedFrequencyHz < currentFrequencyHz)
  4824. {
  4825. PlsrRunStatus = PLSR_STATUS_DECELERATING;
  4826. }
  4827. else
  4828. {
  4829. PlsrRunStatus = PLSR_STATUS_RUNNING;
  4830. }
  4831. criticalState = PlsrPlatformEnterCritical();
  4832. PlsrCountedBoundaryBusy = 0U;
  4833. PlsrPlatformExitCritical(criticalState);
  4834. }
  4835. void PlsrExecCountedStreamFaultIrq(uint8_t pulseOutput)
  4836. {
  4837. if (pulseOutput == (uint8_t)PlsrActiveConfig.pulseOutput)
  4838. {
  4839. /* 只置事件:任务消费时统一置 PlsrTimerErrorPending。 */
  4840. PlsrCountedFaultEvent = 1U;
  4841. }
  4842. }
  4843. static uint8_t PlsrPrepareFutureHandoffQueue(void)
  4844. {
  4845. const PLSR_HANDOFF_PLAN *prepared;
  4846. uint8_t currentSegment = PlsrCurrentSegment;
  4847. uint8_t preparedBank = PlsrPreparedHandoffBank;
  4848. uint16_t fillBudget = PLSR_PROFILE_STARTUP_BUDGET;
  4849. PlsrProfileQueueReset();
  4850. if ((currentSegment == 0U)
  4851. || (currentSegment > PlsrActiveConfig.segmentCount))
  4852. {
  4853. return 1U;
  4854. }
  4855. prepared = &PlsrPreparedHandoffPlans[preparedBank][currentSegment - 1U];
  4856. if ((prepared->valid == 0U) || (prepared->profile.active == 0U)
  4857. || (prepared->profile.nextPeriod >= prepared->profile.pulseCount))
  4858. {
  4859. return 1U;
  4860. }
  4861. (void)PlsrProfileQueueBegin(&prepared->profile,
  4862. PlsrSegmentEpoch + 1UL,
  4863. prepared->nextSegment,
  4864. preparedBank);
  4865. if (PlsrProfileQueueFill(PLSR_PROFILE_STARTUP_TARGET,
  4866. &fillBudget) == 0U)
  4867. {
  4868. PlsrProfileQueueReset();
  4869. return 0U;
  4870. }
  4871. return 1U;
  4872. }
  4873. /* The first two periods are already in the timer pipeline. Seed a small
  4874. precomputed tail here so the 1 ms producer has time to resume without
  4875. doing planner math in the pulse IRQ. */
  4876. static void PlsrActivateHandoffQueueFromIrq(
  4877. const PLSR_HANDOFF_PLAN *plan,
  4878. uint32_t producerEpoch)
  4879. {
  4880. uint8_t index;
  4881. PLSR_PROFILE_QUEUE *queue =
  4882. &PlsrProfileQueues[PlsrProfileQueueBank];
  4883. uint32_t readIndex = queue->readIndex;
  4884. uint32_t writeIndex = queue->writeIndex;
  4885. uint32_t queuedEpoch = queue->producerEpoch;
  4886. uint8_t queuedSegment = queue->producerSegment;
  4887. uint8_t queueActive = queue->active;
  4888. if ((queueActive != 0U) && (queuedEpoch == producerEpoch)
  4889. && (queuedSegment == plan->nextSegment)
  4890. && (readIndex != writeIndex))
  4891. {
  4892. PlsrCopyShortProfile(&PlsrShortProfile,
  4893. &queue->producerProfile);
  4894. PlsrShortProfile.active = 1U;
  4895. PlsrProfileQueueMinimumDepth = PlsrProfileQueueCount();
  4896. PlsrProfileQueueLowWaterLatched = 0U;
  4897. return;
  4898. }
  4899. /* Fallback for a stale/missing prepared bank. This path is fault
  4900. containment only; normal AB handoff uses the 400-item task-built queue. */
  4901. queue->generation++;
  4902. queue->readIndex = 0U;
  4903. queue->writeIndex = plan->warmupCount;
  4904. for (index = 0U; index < plan->warmupCount; index++)
  4905. {
  4906. queue->entries[index] = plan->warmup[index];
  4907. }
  4908. PlsrCopyShortProfile(&queue->producerProfile, &plan->profile);
  4909. queue->producerEpoch = producerEpoch;
  4910. queue->producerSegment = plan->nextSegment;
  4911. queue->preparedHandoffBank = PlsrPreparedHandoffBank;
  4912. queue->generatorComplete =
  4913. (plan->profile.active == 0U) ? 1U : 0U;
  4914. queue->active =
  4915. ((plan->warmupCount != 0U) || (plan->profile.active != 0U))
  4916. ? 1U : 0U;
  4917. PlsrCopyShortProfile(&PlsrShortProfile, &plan->profile);
  4918. if (queue->active != 0U)
  4919. {
  4920. PlsrShortProfile.active = 1U;
  4921. }
  4922. }
  4923. static PLSR_PLATFORM_QUEUE_RESULT PlsrPrimeHandoff(void)
  4924. {
  4925. PLSR_HANDOFF_PLAN candidatePlan;
  4926. uint32_t actualFrequencyHz;
  4927. PLSR_PLATFORM_QUEUE_RESULT result;
  4928. PlsrHandoffPlan.valid = 0U;
  4929. if (PlsrAbStopArmed != 0U)
  4930. {
  4931. return PLSR_PLATFORM_QUEUE_FAILED;
  4932. }
  4933. if (PlsrSelectPreparedHandoffPlan(&candidatePlan) == 0U)
  4934. {
  4935. return PLSR_PLATFORM_QUEUE_FAILED;
  4936. }
  4937. PlsrDeferredFrequencyPending = 0U;
  4938. result = PlsrPlatformLoadPreparedFromIrq(
  4939. (uint8_t)PlsrActiveConfig.pulseOutput,
  4940. &candidatePlan.firstSetting, &actualFrequencyHz);
  4941. if (result != PLSR_PLATFORM_QUEUE_APPLIED)
  4942. {
  4943. if (result == PLSR_PLATFORM_QUEUE_FAILED)
  4944. {
  4945. PlsrTimerErrorPending = 1U;
  4946. }
  4947. return result;
  4948. }
  4949. PlsrDiagnosticRecordFrequency(candidatePlan.firstRequestedFrequencyHz,
  4950. candidatePlan.firstSetting.actualFrequencyHz,
  4951. actualFrequencyHz);
  4952. PlsrDiagnosticQueuedExpectedHz =
  4953. candidatePlan.firstSetting.actualFrequencyHz;
  4954. PlsrQueuedFrequencyHz = actualFrequencyHz;
  4955. PlsrHandoffPlan = candidatePlan;
  4956. PlsrHandoffPlan.firstFrequencyHz = actualFrequencyHz;
  4957. PlsrHandoffPlan.valid = 1U;
  4958. return PLSR_PLATFORM_QUEUE_APPLIED;
  4959. }
  4960. static PLSR_PLATFORM_QUEUE_RESULT PlsrTryContinuousHandoff(void)
  4961. {
  4962. uint32_t actualQueuedFrequencyHz;
  4963. uint32_t currentFrequencyHz;
  4964. uint32_t queuedFrequencyHz;
  4965. uint8_t nextSegment = PlsrHandoffPlan.nextSegment;
  4966. uint64_t magnitude = PlsrHandoffPlan.magnitude;
  4967. uint8_t positive = PlsrHandoffPlan.positive;
  4968. PLSR_PLATFORM_QUEUE_RESULT result;
  4969. if ((PlsrHandoffPlan.valid == 0U)
  4970. || (PlsrStopRequested != 0U)
  4971. || (PlsrCountOverflowPending != 0U)
  4972. || (PlsrCutRequested != 0U)
  4973. || (PlsrAbStopArmed != 0U)
  4974. || (PlsrCurrentFrequencyHz != PlsrHandoffPlan.firstFrequencyHz)
  4975. || (nextSegment == 0U)
  4976. || (nextSegment > PlsrActiveConfig.segmentCount))
  4977. {
  4978. return PLSR_PLATFORM_QUEUE_FAILED;
  4979. }
  4980. PlsrDeferredFrequencyPending = 0U;
  4981. result = PlsrPlatformLoadPreparedFromIrq(
  4982. (uint8_t)PlsrActiveConfig.pulseOutput,
  4983. &PlsrHandoffPlan.secondSetting, &actualQueuedFrequencyHz);
  4984. if (result == PLSR_PLATFORM_QUEUE_STALE)
  4985. {
  4986. return result;
  4987. }
  4988. if (result == PLSR_PLATFORM_QUEUE_FAILED)
  4989. {
  4990. PlsrShortProfile.active = 0U;
  4991. PlsrHandoffPlan.valid = 0U;
  4992. PlsrTimerErrorPending = 1U;
  4993. return result;
  4994. }
  4995. PlsrDiagnosticRecordFrequency(
  4996. PlsrHandoffPlan.secondRequestedFrequencyHz,
  4997. PlsrHandoffPlan.secondSetting.actualFrequencyHz,
  4998. actualQueuedFrequencyHz);
  4999. PlsrDiagnosticQueuedExpectedHz =
  5000. PlsrHandoffPlan.secondSetting.actualFrequencyHz;
  5001. PlsrQueuedFrequencyHz = actualQueuedFrequencyHz;
  5002. PlsrDiagnosticFinishSegment(1U);
  5003. PlsrSegmentEpoch++;
  5004. PlsrActivateHandoffQueueFromIrq(&PlsrHandoffPlan,
  5005. PlsrSegmentEpoch);
  5006. PlsrCurrentSegment = nextSegment;
  5007. PlsrRemainingPulses = magnitude;
  5008. PlsrCommandRemainingPulses = PlsrHandoffPlan.commandMagnitude;
  5009. PlsrCountPositive = positive;
  5010. PlsrActTimedCutPlanned = PlsrHandoffPlan.nextActTimedCut;
  5011. PlsrBoundaryFrequencyHz = PlsrCurrentFrequencyHz;
  5012. PlsrSegmentClockStarted = 1U;
  5013. PlsrSegmentElapsedMs = 0UL;
  5014. PlsrWaitElapsedMs = 0UL;
  5015. PlsrBoundaryRampStarted = 0U;
  5016. PlsrBoundaryPending = 0U;
  5017. PlsrBoundaryWasCut = 0U;
  5018. PlsrCutRequested = 0U;
  5019. PlsrFrequencyUpdatePending = 0U;
  5020. PlsrDeferredFrequencyPending = 0U;
  5021. PlsrExtEdgePending = 0U;
  5022. PlsrExtPreviousLevel =
  5023. PlsrPlatformReadInput((uint8_t)PlsrActiveConfig.extInput);
  5024. PlsrDiagnosticBeginSegment(nextSegment, magnitude, positive);
  5025. PlsrSeamlessHandoffPending = 1U;
  5026. PlsrHandoffPlan.valid = 0U;
  5027. if (PlsrRemainingPulses == 1UL)
  5028. {
  5029. result = PlsrPrimeHandoff();
  5030. if (result == PLSR_PLATFORM_QUEUE_STALE)
  5031. {
  5032. return result;
  5033. }
  5034. }
  5035. (void)PlsrQueueFinalAbBoundaryFromIrq();
  5036. queuedFrequencyHz = PlsrQueuedFrequencyHz;
  5037. currentFrequencyHz = PlsrCurrentFrequencyHz;
  5038. if (PlsrShortProfile.active != 0U)
  5039. {
  5040. if (queuedFrequencyHz > currentFrequencyHz)
  5041. {
  5042. PlsrRunStatus = PLSR_STATUS_ACCELERATING;
  5043. }
  5044. else if (queuedFrequencyHz < currentFrequencyHz)
  5045. {
  5046. PlsrRunStatus = PLSR_STATUS_DECELERATING;
  5047. }
  5048. else
  5049. {
  5050. PlsrRunStatus = PLSR_STATUS_RUNNING;
  5051. }
  5052. }
  5053. else
  5054. {
  5055. PlsrRunStatus = PLSR_STATUS_RUNNING;
  5056. }
  5057. return PLSR_PLATFORM_QUEUE_APPLIED;
  5058. }
  5059. /* EXTI records an input edge. WAIT remains latch-only; active EXT also arms
  5060. the bounded finite-cut path so pulse output stops at the next complete
  5061. falling edge. Planning and segment transitions remain in task context. */
  5062. void PlsrWaitInputExtiIrq(uint8_t inputSelection)
  5063. {
  5064. uint8_t bit;
  5065. uint8_t captureSegment;
  5066. uint32_t captureEpoch;
  5067. uint16_t waitType;
  5068. if (inputSelection > 1U)
  5069. {
  5070. return;
  5071. }
  5072. bit = (uint8_t)(1U << inputSelection);
  5073. if ((PlsrWaitSignalArmedMask & bit) != 0U)
  5074. {
  5075. PlsrWaitSignalPendingMask |= bit;
  5076. }
  5077. captureEpoch = PlsrExtCaptureEpoch;
  5078. captureSegment = PlsrExtCaptureSegment;
  5079. if ((PlsrActiveConfig.outputMode != PLSR_OUTPUT_PULSE_DIR)
  5080. || (inputSelection != (uint8_t)PlsrActiveConfig.extInput)
  5081. || (captureSegment == 0U)
  5082. || (captureSegment > PlsrActiveConfig.segmentCount))
  5083. {
  5084. return;
  5085. }
  5086. waitType = PlsrActiveConfig.segments[captureSegment - 1U].waitType;
  5087. if (((waitType == PLSR_EXT_SIGNAL)
  5088. || (waitType == PLSR_EXT_OR_COMPLETE))
  5089. && (captureEpoch == PlsrExtCaptureEpoch)
  5090. && (captureSegment == PlsrExtCaptureSegment))
  5091. {
  5092. PlsrExtEdgePendingSegment = captureSegment;
  5093. PlsrExtEdgePendingEpoch = captureEpoch;
  5094. PlsrExtEdgePending = 1U;
  5095. if (PlsrPulseActive != 0U)
  5096. {
  5097. PlsrRequestCut(captureEpoch);
  5098. }
  5099. }
  5100. }
  5101. static void PlsrArmWaitSignal(uint8_t inputSelection)
  5102. {
  5103. uint32_t criticalState;
  5104. uint8_t bit;
  5105. if (inputSelection > 1U)
  5106. {
  5107. return;
  5108. }
  5109. bit = (uint8_t)(1U << inputSelection);
  5110. criticalState = PlsrPlatformEnterCritical();
  5111. PlsrWaitSignalPendingMask = 0U;
  5112. PlsrWaitSignalArmedMask = bit;
  5113. PlsrPlatformExitCritical(criticalState);
  5114. }
  5115. static void PlsrDisarmWaitSignal(void)
  5116. {
  5117. uint32_t criticalState = PlsrPlatformEnterCritical();
  5118. PlsrWaitSignalArmedMask = 0U;
  5119. PlsrWaitSignalPendingMask = 0U;
  5120. PlsrPlatformExitCritical(criticalState);
  5121. }
  5122. static uint8_t PlsrWaitSignalDetected(uint8_t inputSelection)
  5123. {
  5124. uint32_t criticalState;
  5125. uint8_t bit;
  5126. if (inputSelection > 1U)
  5127. {
  5128. return 0U;
  5129. }
  5130. bit = (uint8_t)(1U << inputSelection);
  5131. criticalState = PlsrPlatformEnterCritical();
  5132. if ((PlsrWaitSignalPendingMask & bit) != 0U)
  5133. {
  5134. PlsrWaitSignalPendingMask &= (uint8_t)~bit;
  5135. PlsrWaitSignalArmedMask &= (uint8_t)~bit;
  5136. PlsrPlatformExitCritical(criticalState);
  5137. return 1U;
  5138. }
  5139. PlsrPlatformExitCritical(criticalState);
  5140. /* Preserve the original level semantics: a signal already high when the
  5141. segment enters WAIT must release it even though no new EXTI edge occurs. */
  5142. if (PlsrPlatformReadInput(inputSelection) != 0U)
  5143. {
  5144. criticalState = PlsrPlatformEnterCritical();
  5145. PlsrWaitSignalPendingMask &= (uint8_t)~bit;
  5146. PlsrWaitSignalArmedMask &= (uint8_t)~bit;
  5147. PlsrPlatformExitCritical(criticalState);
  5148. return 1U;
  5149. }
  5150. return 0U;
  5151. }
  5152. static void PlsrHandleBoundary(uint8_t extEdge)
  5153. {
  5154. const PLSR_SEGMENT_CONFIG *segment;
  5155. uint32_t criticalState;
  5156. uint32_t currentEpoch;
  5157. uint8_t wasCut = PlsrBoundaryWasCut;
  5158. uint8_t preserveTimedStart;
  5159. uint8_t currentSegment;
  5160. PlsrPlatformStopPulse((uint8_t)PlsrActiveConfig.pulseOutput);
  5161. PlsrBoundaryPending = 0U;
  5162. PlsrBoundaryWasCut = 0U;
  5163. PlsrPulseActive = 0U;
  5164. PlsrCurrentFrequencyHz = 0UL;
  5165. PlsrQueuedFrequencyHz = 0UL;
  5166. PlsrShortProfile.active = 0U;
  5167. criticalState = PlsrPlatformEnterCritical();
  5168. preserveTimedStart =
  5169. (((PlsrTimedStart.valid != 0U)
  5170. || (PlsrTimedStart.building != 0U))
  5171. && (PlsrTimedStart.sourceEpoch == PlsrSegmentEpoch)
  5172. && (PlsrTimedStart.sourceSegment == PlsrCurrentSegment)
  5173. && (PlsrTimedStart.queueBank != PlsrProfileQueueBank)) ? 1U : 0U;
  5174. if (preserveTimedStart != 0U)
  5175. {
  5176. PlsrProfileQueueResetBankLocked(PlsrProfileQueueBank);
  5177. PlsrProfileQueueLowWaterLatched = 0U;
  5178. }
  5179. PlsrPlatformExitCritical(criticalState);
  5180. if (preserveTimedStart == 0U)
  5181. {
  5182. PlsrProfileQueueReset();
  5183. }
  5184. PlsrHandoffPlan.valid = 0U;
  5185. PlsrDeferredFrequencyPending = 0U;
  5186. PlsrAbStopArmed = 0U;
  5187. PlsrCheckpointPosition(1U);
  5188. if (PlsrTimerErrorPending != 0U)
  5189. {
  5190. PlsrTimerErrorPending = 0U;
  5191. PlsrEnterError(PLSR_ERROR_TIMER);
  5192. return;
  5193. }
  5194. #if PLSR_COUNT_ERROR_CHECK_ENABLED
  5195. if (PlsrCountOverflowPending != 0U)
  5196. {
  5197. PlsrCountOverflowPending = 0U;
  5198. PlsrEnterError(PLSR_ERROR_COUNT);
  5199. return;
  5200. }
  5201. #else
  5202. /* 计数错误检查暂时关闭:偏差已由同步路径钳制,标志直接清除。 */
  5203. PlsrCountOverflowPending = 0U;
  5204. #endif
  5205. if (PlsrStopRequested != 0U)
  5206. {
  5207. PlsrFinishStopped();
  5208. return;
  5209. }
  5210. if ((PlsrCurrentSegment == 0U)
  5211. || (PlsrCurrentSegment > PlsrActiveConfig.segmentCount))
  5212. {
  5213. PlsrEnterError(PLSR_ERROR_INTERNAL);
  5214. return;
  5215. }
  5216. segment = &PlsrActiveConfig.segments[PlsrCurrentSegment - 1U];
  5217. if (wasCut != 0U)
  5218. {
  5219. uint8_t allowCarry =
  5220. ((segment->waitType == PLSR_ACT_TIME)
  5221. || (PlsrActiveConfig.sendMode == PLSR_SEND_SUBSEQUENT))
  5222. ? 1U : 0U;
  5223. if ((PlsrActiveConfig.outputMode == PLSR_OUTPUT_PULSE_DIR)
  5224. && ((segment->waitType == PLSR_EXT_SIGNAL)
  5225. || (segment->waitType == PLSR_EXT_OR_COMPLETE)))
  5226. {
  5227. allowCarry = 1U;
  5228. }
  5229. PlsrTransitionToNext(allowCarry);
  5230. return;
  5231. }
  5232. switch (segment->waitType)
  5233. {
  5234. case PLSR_WAIT_TIME:
  5235. PlsrWaitElapsedMs = 0UL;
  5236. if (segment->waitTimeMs == 0UL)
  5237. {
  5238. PlsrTransitionToNext(0U);
  5239. }
  5240. else
  5241. {
  5242. PlsrRunStatus = PLSR_STATUS_WAITING;
  5243. }
  5244. break;
  5245. case PLSR_WAIT_SIGNAL:
  5246. PlsrRunStatus = PLSR_STATUS_WAITING;
  5247. PlsrArmWaitSignal((uint8_t)PlsrActiveConfig.waitInput);
  5248. if (PlsrWaitSignalDetected(
  5249. (uint8_t)PlsrActiveConfig.waitInput) != 0U)
  5250. {
  5251. PlsrTransitionToNext(0U);
  5252. }
  5253. break;
  5254. case PLSR_ACT_TIME:
  5255. if (PlsrSegmentElapsedMs >= segment->actTimeMs)
  5256. {
  5257. PlsrTransitionToNext(0U);
  5258. }
  5259. else
  5260. {
  5261. PlsrRunStatus = PLSR_STATUS_WAITING;
  5262. }
  5263. break;
  5264. case PLSR_EXT_SIGNAL:
  5265. criticalState = PlsrPlatformEnterCritical();
  5266. currentEpoch = PlsrSegmentEpoch;
  5267. currentSegment = PlsrCurrentSegment;
  5268. if ((PlsrExtEdgePending != 0U)
  5269. && (PlsrExtEdgePendingEpoch == currentEpoch)
  5270. && (PlsrExtEdgePendingSegment == currentSegment))
  5271. {
  5272. extEdge = 1U;
  5273. PlsrExtEdgePending = 0U;
  5274. }
  5275. PlsrPlatformExitCritical(criticalState);
  5276. if (extEdge != 0U)
  5277. {
  5278. PlsrTransitionToNext(0U);
  5279. }
  5280. else
  5281. {
  5282. PlsrRunStatus = PLSR_STATUS_WAITING;
  5283. }
  5284. break;
  5285. case PLSR_EXT_OR_COMPLETE:
  5286. PlsrTransitionToNext(1U);
  5287. break;
  5288. default:
  5289. PlsrEnterError(PLSR_ERROR_INTERNAL);
  5290. break;
  5291. }
  5292. }
  5293. static void PlsrRequestCut(uint32_t expectedEpoch)
  5294. {
  5295. uint32_t criticalState = PlsrPlatformEnterCritical();
  5296. if (PlsrSegmentEpoch != expectedEpoch)
  5297. {
  5298. PlsrPlatformExitCritical(criticalState);
  5299. return;
  5300. }
  5301. if (PlsrBoundaryPending != 0U)
  5302. {
  5303. PlsrBoundaryWasCut = 1U;
  5304. }
  5305. else if (PlsrPulseActive != 0U)
  5306. {
  5307. PlsrCutRequested = 1U;
  5308. if ((PlsrActiveConfig.outputMode == PLSR_OUTPUT_PULSE_DIR)
  5309. && ((PlsrExecutor.mode == PLSR_EXEC_STEP_TABLE)
  5310. || (PlsrExecutor.mode == PLSR_EXEC_STREAM)
  5311. || (PlsrExecutor.mode == PLSR_EXEC_STOPPING)))
  5312. {
  5313. /* Freeze both producer-side handoff state and the platform's
  5314. latched next run. Hardware stops at the next safe falling
  5315. edge; normal counted completion performs boundary bookkeeping
  5316. in the task context. */
  5317. PlsrHandoffPlan.valid = 0U;
  5318. PlsrCountedHandoffStaged = 0U;
  5319. PlsrExecutor.mode = PLSR_EXEC_STOPPING;
  5320. (void)PlsrPlatformRequestFiniteCut(
  5321. (uint8_t)PlsrActiveConfig.pulseOutput);
  5322. }
  5323. else
  5324. {
  5325. (void)PlsrArmFinalAbBoundaryLocked();
  5326. }
  5327. }
  5328. else
  5329. {
  5330. PlsrBoundaryFrequencyHz = PlsrCurrentFrequencyHz;
  5331. PlsrBoundaryWasCut = 1U;
  5332. PlsrBoundaryPending = 1U;
  5333. }
  5334. PlsrPlatformExitCritical(criticalState);
  5335. }
  5336. static void PlsrPollWaiting(uint8_t extEdge)
  5337. {
  5338. const PLSR_SEGMENT_CONFIG *segment =
  5339. &PlsrActiveConfig.segments[PlsrCurrentSegment - 1U];
  5340. switch (segment->waitType)
  5341. {
  5342. case PLSR_WAIT_TIME:
  5343. PlsrWaitElapsedMs++;
  5344. if (PlsrWaitElapsedMs >= segment->waitTimeMs)
  5345. {
  5346. PlsrTransitionToNext(0U);
  5347. }
  5348. break;
  5349. case PLSR_WAIT_SIGNAL:
  5350. if (PlsrWaitSignalDetected(
  5351. (uint8_t)PlsrActiveConfig.waitInput) != 0U)
  5352. {
  5353. PlsrTransitionToNext(0U);
  5354. }
  5355. break;
  5356. case PLSR_ACT_TIME:
  5357. if (PlsrSegmentElapsedMs >= segment->actTimeMs)
  5358. {
  5359. PlsrTransitionToNext(0U);
  5360. }
  5361. break;
  5362. case PLSR_EXT_SIGNAL:
  5363. if (extEdge != 0U)
  5364. {
  5365. PlsrTransitionToNext(0U);
  5366. }
  5367. break;
  5368. default:
  5369. PlsrEnterError(PLSR_ERROR_INTERNAL);
  5370. break;
  5371. }
  5372. }
  5373. static void PlsrPollPersistenceDelay(void)
  5374. {
  5375. if ((PlsrPersistenceDirty != 0U)
  5376. && (PlsrIsBusy() == 0U)
  5377. && (PlsrPersistenceDelayMs != 0U))
  5378. {
  5379. PlsrPersistenceDelayMs--;
  5380. }
  5381. }
  5382. void PlsrServicePersistence(void)
  5383. {
  5384. PLSR_PERSIST_PAYLOAD payload;
  5385. PLSR_PLATFORM_SERVICE_RESULT serviceResult;
  5386. uint32_t criticalState;
  5387. if (PlsrIsBusy() != 0U)
  5388. {
  5389. return;
  5390. }
  5391. serviceResult = PlsrPlatformServicePersistence();
  5392. if (serviceResult == PLSR_PLATFORM_SERVICE_FAILED)
  5393. {
  5394. PlsrRunStatus = PLSR_STATUS_ERROR;
  5395. PlsrError = PLSR_ERROR_INTERNAL;
  5396. return;
  5397. }
  5398. if ((serviceResult == PLSR_PLATFORM_SERVICE_DEFERRED)
  5399. || (PlsrPersistenceDirty == 0U))
  5400. {
  5401. return;
  5402. }
  5403. if (PlsrPersistenceDelayMs != 0U)
  5404. {
  5405. return;
  5406. }
  5407. payload.config = PlsrShadowConfig;
  5408. criticalState = PlsrPlatformEnterCritical();
  5409. payload.position = PlsrPosition;
  5410. payload.positionValid = PlsrPositionValid;
  5411. PlsrPlatformExitCritical(criticalState);
  5412. payload.wasBusy = 0U;
  5413. payload.reserved = 0U;
  5414. if (PlsrPlatformSave(&payload) != 0U)
  5415. {
  5416. PlsrPersistenceDirty = 0U;
  5417. }
  5418. else
  5419. {
  5420. PlsrRunStatus = PLSR_STATUS_ERROR;
  5421. PlsrError = PLSR_ERROR_INTERNAL;
  5422. }
  5423. }
  5424. uint8_t PlsrInit(void)
  5425. {
  5426. PLSR_PERSIST_PAYLOAD payload;
  5427. PlsrInitialized = 0U;
  5428. PlsrRunStatus = PLSR_STATUS_UNINITIALIZED;
  5429. if (PlsrPlatformInit() == 0U)
  5430. {
  5431. return 0U;
  5432. }
  5433. if ((PlsrPlatformLoad(&payload) == 0U)
  5434. || (PlsrConfigIsValid(&payload.config, 0U) == 0U)
  5435. || (payload.positionValid > 1U) || (payload.wasBusy > 1U))
  5436. {
  5437. PlsrSetDefaults(&PlsrShadowConfig);
  5438. PlsrPosition = 0L;
  5439. PlsrPositionValid = 1U;
  5440. PlsrPlatformCheckpointConfig(&PlsrShadowConfig);
  5441. PlsrPlatformCheckpointPosition(0L, 1U, 0U);
  5442. PlsrMarkPersistenceDirty(PLSR_CONFIG_SAVE_DELAY_MS);
  5443. }
  5444. else
  5445. {
  5446. PlsrShadowConfig = payload.config;
  5447. PlsrPosition = payload.position;
  5448. PlsrPositionValid = ((payload.positionValid != 0U)
  5449. && (payload.wasBusy == 0U)) ? 1U : 0U;
  5450. PlsrPersistenceDirty = 0U;
  5451. PlsrPersistenceDelayMs = 0U;
  5452. }
  5453. (void)memset(&PlsrActiveConfig, 0, sizeof(PlsrActiveConfig));
  5454. (void)memset(&PlsrRamp, 0, sizeof(PlsrRamp));
  5455. (void)memset(&PlsrShortProfile, 0, sizeof(PlsrShortProfile));
  5456. (void)memset(PlsrProfileQueues, 0, sizeof(PlsrProfileQueues));
  5457. PlsrProfileQueueBank = 0U;
  5458. (void)memset(&PlsrHandoffPlan, 0, sizeof(PlsrHandoffPlan));
  5459. (void)memset(&PlsrExecutor, 0, sizeof(PlsrExecutor));
  5460. (void)memset(PlsrPreparedHandoffPlans, 0,
  5461. sizeof(PlsrPreparedHandoffPlans));
  5462. PlsrPreparedHandoffBank = 0U;
  5463. PlsrRemainingPulses = 0UL;
  5464. PlsrCommandRemainingPulses = 0ULL;
  5465. PlsrPulseActive = 0U;
  5466. PlsrCutRequested = 0U;
  5467. PlsrActTimedCutPlanned = 0U;
  5468. PlsrBoundaryPending = 0U;
  5469. PlsrBoundaryWasCut = 0U;
  5470. PlsrCountOverflowPending = 0U;
  5471. PlsrCountedObservedPublished = 0ULL;
  5472. PlsrCountedHandoffStaged = 0U;
  5473. PlsrCountedBoundaryWriteIndex = 0U;
  5474. PlsrCountedBoundaryReadIndex = 0U;
  5475. PlsrCountedBoundaryBusy = 0U;
  5476. (void)memset(PlsrCountedBoundaryEvents, 0,
  5477. sizeof(PlsrCountedBoundaryEvents));
  5478. PlsrCountedFaultEvent = 0U;
  5479. PlsrPositionCheckpointDirty = 0U;
  5480. PlsrFrequencyUpdatePending = 0U;
  5481. PlsrDeferredFrequencyPending = 0U;
  5482. PlsrFrequencyUpdateSegment = 0U;
  5483. PlsrSeamlessHandoffPending = 0U;
  5484. PlsrTimerErrorPending = 0U;
  5485. PlsrCurrentFrequencyHz = 0UL;
  5486. PlsrQueuedFrequencyHz = 0UL;
  5487. PlsrBoundaryFrequencyHz = 0UL;
  5488. PlsrFrequencyUpdateTargetHz = 0UL;
  5489. PlsrDeferredFrequencyHz = 0UL;
  5490. PlsrSegmentEpoch = 0UL;
  5491. PlsrDelayedEntryType = PLSR_SEGMENT_ENTRY_COMMAND_START;
  5492. PlsrPulseDirMotionStarted = 0U;
  5493. PlsrCurrentSegment = 0U;
  5494. PlsrDirectionDelayActive = 0U;
  5495. PlsrDirectionDelayRemainingMs = 0U;
  5496. PlsrInitialDirectionPreparePending = 0U;
  5497. PlsrInitialDirectionPrepareLevel = 0U;
  5498. PlsrInitialDirectionPrepareEpoch = 0UL;
  5499. PlsrSegmentClockStarted = 0U;
  5500. PlsrExtPreviousLevel = 0U;
  5501. PlsrExtEdgePending = 0U;
  5502. PlsrExtEdgePendingSegment = 0U;
  5503. PlsrExtEdgePendingEpoch = 0UL;
  5504. PlsrExtCaptureSegment = 0U;
  5505. PlsrExtCaptureEpoch = 0UL;
  5506. PlsrWaitSignalArmedMask = 0U;
  5507. PlsrWaitSignalPendingMask = 0U;
  5508. PlsrStopRequested = 0U;
  5509. PlsrStopPulsesRemaining = 0U;
  5510. PlsrAbStopArmed = 0U;
  5511. PlsrLastDirectionValid = 0U;
  5512. PlsrPositionCheckpointElapsedMs = 0U;
  5513. PlsrCommandMailbox.command = 0U;
  5514. PlsrCommandMailbox.state = PLSR_COMMAND_MAILBOX_EMPTY;
  5515. PlsrDiagnosticReset();
  5516. #ifdef PLSR_HOST_TEST
  5517. PlsrHostTestEventSequence = 0UL;
  5518. PlsrHostTestLastGateEvent = 0UL;
  5519. PlsrHostTestLastDiagnosticFinishEvent = 0UL;
  5520. #endif
  5521. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0)
  5522. PlsrProfileProducerItemCount = 0UL;
  5523. PlsrProfileProducerTotalCycles = 0UL;
  5524. PlsrProfileProducerMaxItemCycles = 0UL;
  5525. #if !defined(PLSR_HOST_TEST)
  5526. PlsrPlannerTimingReset();
  5527. #endif
  5528. #endif
  5529. PlsrError = PLSR_ERROR_NONE;
  5530. PlsrRunStatus = PLSR_STATUS_IDLE;
  5531. PlsrInitialized = 1U;
  5532. return 1U;
  5533. }
  5534. static PLSR_MB_RESULT PlsrQueueCommand(uint16_t command)
  5535. {
  5536. uint32_t criticalState;
  5537. PLSR_MB_RESULT result = PLSR_MB_OK;
  5538. if (PlsrInitialized == 0U)
  5539. {
  5540. return PLSR_MB_SERVER_FAILURE;
  5541. }
  5542. criticalState = PlsrPlatformEnterCritical();
  5543. /* Capacity one: repeats acknowledge the first command; conflicts wait. */
  5544. if (PlsrCommandMailbox.state != PLSR_COMMAND_MAILBOX_EMPTY)
  5545. {
  5546. result = (PlsrCommandMailbox.command == command)
  5547. ? PLSR_MB_OK : PLSR_MB_DEVICE_BUSY;
  5548. PlsrPlatformExitCritical(criticalState);
  5549. return result;
  5550. }
  5551. if (command == PLSR_COMMAND_START)
  5552. {
  5553. if ((PlsrIsBusy() != 0U)
  5554. || (PlsrRunStatus == PLSR_STATUS_ERROR))
  5555. {
  5556. result = PLSR_MB_DEVICE_BUSY;
  5557. }
  5558. else if ((PlsrRunStatus != PLSR_STATUS_IDLE)
  5559. && (PlsrRunStatus != PLSR_STATUS_COMPLETED)
  5560. && (PlsrRunStatus != PLSR_STATUS_STOPPED))
  5561. {
  5562. result = PLSR_MB_ILLEGAL_VALUE;
  5563. }
  5564. else if ((PlsrConfigIsValid(&PlsrShadowConfig, 1U) == 0U)
  5565. || ((PlsrShadowConfig.positionMode
  5566. == PLSR_POSITION_ABSOLUTE)
  5567. && (PlsrPositionValid == 0U)))
  5568. {
  5569. result = PLSR_MB_ILLEGAL_VALUE;
  5570. }
  5571. else
  5572. {
  5573. PlsrCommandMailbox.startConfig = PlsrShadowConfig;
  5574. }
  5575. }
  5576. else if ((command == PLSR_COMMAND_CLEAR) && (PlsrIsBusy() != 0U))
  5577. {
  5578. result = PLSR_MB_DEVICE_BUSY;
  5579. }
  5580. if (result == PLSR_MB_OK)
  5581. {
  5582. PlsrCommandMailbox.command = command;
  5583. PlsrCommandMailbox.state = PLSR_COMMAND_MAILBOX_PENDING;
  5584. }
  5585. PlsrPlatformExitCritical(criticalState);
  5586. return result;
  5587. }
  5588. static void PlsrExecuteStart(void)
  5589. {
  5590. uint32_t criticalState;
  5591. uint8_t handoffBank;
  5592. uint8_t index;
  5593. PlsrActiveConfig = PlsrCommandMailbox.startConfig;
  5594. for (index = 0U; index < PlsrActiveConfig.segmentCount; index++)
  5595. {
  5596. PlsrActiveConfig.segments[index].frequencyHz =
  5597. PlsrResolvedSegmentFrequency(&PlsrActiveConfig, index);
  5598. }
  5599. handoffBank = PlsrBuildHandoffPlanBank(&PlsrActiveConfig);
  5600. criticalState = PlsrPlatformEnterCritical();
  5601. PlsrPreparedHandoffBank = handoffBank;
  5602. PlsrHandoffPlan.valid = 0U;
  5603. PlsrPlatformExitCritical(criticalState);
  5604. PlsrStopRequested = 0U;
  5605. PlsrTimerErrorPending = 0U;
  5606. PlsrShortProfile.active = 0U;
  5607. PlsrError = PLSR_ERROR_NONE;
  5608. PlsrLastDirectionValid = 0U;
  5609. PlsrInitialDirectionPreparePending = 0U;
  5610. PlsrDelayedEntryType = PLSR_SEGMENT_ENTRY_COMMAND_START;
  5611. PlsrPulseDirMotionStarted = 0U;
  5612. PlsrCheckpointPosition(1U);
  5613. if (PlsrStartSegment((uint8_t)PlsrActiveConfig.startSegment,
  5614. PLSR_SEGMENT_ENTRY_COMMAND_START, 0UL)
  5615. == 0U)
  5616. {
  5617. PlsrEnterError((PlsrTimerErrorPending != 0U)
  5618. ? PLSR_ERROR_TIMER
  5619. : PLSR_ERROR_INVALID_RESOURCE);
  5620. }
  5621. }
  5622. static uint8_t PlsrExecuteStop(void)
  5623. {
  5624. uint32_t criticalState;
  5625. uint32_t stopTargetHz;
  5626. uint32_t appliedHz;
  5627. uint64_t drainPulses;
  5628. if (PlsrIsBusy() == 0U)
  5629. {
  5630. return 0U;
  5631. }
  5632. criticalState = PlsrPlatformEnterCritical();
  5633. if (PlsrStopRequested != 0U)
  5634. {
  5635. PlsrPlatformExitCritical(criticalState);
  5636. return 0U;
  5637. }
  5638. PlsrStopRequested = 1U;
  5639. PlsrStopPulsesRemaining = 0U;
  5640. if (PlsrBoundaryPending != 0U)
  5641. {
  5642. PlsrPlatformExitCritical(criticalState);
  5643. return 1U;
  5644. }
  5645. if (PlsrPulseActive == 0U)
  5646. {
  5647. PlsrPlatformExitCritical(criticalState);
  5648. PlsrFinishStopped();
  5649. return 1U;
  5650. }
  5651. if (PlsrActiveConfig.outputMode != PLSR_OUTPUT_PULSE_DIR)
  5652. {
  5653. PlsrShortProfile.active = 0U;
  5654. PlsrProfileQueueInvalidateGeneration();
  5655. PlsrHandoffPlan.valid = 0U;
  5656. PlsrInvalidateHandoffPlans();
  5657. }
  5658. stopTargetHz = PlsrEffectiveStopFrequency(
  5659. PlsrActiveConfig.segments[PlsrCurrentSegment - 1U].frequencyHz);
  5660. appliedHz = (PlsrQueuedFrequencyHz != 0UL)
  5661. ? PlsrQueuedFrequencyHz : PlsrCurrentFrequencyHz;
  5662. if (stopTargetHz > appliedHz)
  5663. {
  5664. stopTargetHz = appliedHz;
  5665. }
  5666. if (PlsrActiveConfig.outputMode == PLSR_OUTPUT_PULSE_DIR)
  5667. {
  5668. drainPulses = PlsrRampPulseEstimate(appliedHz, stopTargetHz,
  5669. appliedHz) + 1ULL;
  5670. if (drainPulses > PlsrRemainingPulses)
  5671. {
  5672. drainPulses = PlsrRemainingPulses;
  5673. }
  5674. if (drainPulses == 0ULL)
  5675. {
  5676. drainPulses = 1ULL;
  5677. }
  5678. PlsrRemainingPulses = drainPulses;
  5679. PlsrCommandRemainingPulses = drainPulses;
  5680. PlsrPlatformExitCritical(criticalState);
  5681. if (PlsrReplanPulseDir(stopTargetHz,
  5682. (uint32_t)drainPulses, 1U)
  5683. != PLSR_PLATFORM_SERVICE_READY)
  5684. {
  5685. PlsrEnterError(PLSR_ERROR_TIMER);
  5686. return 1U;
  5687. }
  5688. PlsrInvalidateHandoffPlans();
  5689. criticalState = PlsrPlatformEnterCritical();
  5690. PlsrRunStatus = PLSR_STATUS_DECELERATING;
  5691. PlsrPlatformExitCritical(criticalState);
  5692. return 1U;
  5693. }
  5694. PlsrRampStart(PlsrCurrentFrequencyHz, stopTargetHz);
  5695. PlsrRunStatus = PLSR_STATUS_DECELERATING;
  5696. if (PlsrRamp.active == 0U)
  5697. {
  5698. if (PlsrApplyFrequency(stopTargetHz, PlsrSegmentEpoch) == 0U)
  5699. {
  5700. PlsrPlatformExitCritical(criticalState);
  5701. PlsrEnterError(PLSR_ERROR_TIMER);
  5702. return 1U;
  5703. }
  5704. (void)PlsrArmStopDrainLocked();
  5705. }
  5706. PlsrPlatformExitCritical(criticalState);
  5707. return 1U;
  5708. }
  5709. static void PlsrExecuteClear(void)
  5710. {
  5711. uint32_t criticalState;
  5712. PlsrDisarmWaitSignal();
  5713. criticalState = PlsrPlatformEnterCritical();
  5714. PlsrPosition = 0L;
  5715. PlsrPositionValid = 1U;
  5716. PlsrRemainingPulses = 0UL;
  5717. PlsrCommandRemainingPulses = 0ULL;
  5718. PlsrPlatformExitCritical(criticalState);
  5719. PlsrPlatformCheckpointPosition(0L, 1U, 0U);
  5720. PlsrCountOverflowPending = 0U;
  5721. PlsrPositionCheckpointDirty = 0U;
  5722. PlsrPositionCheckpointElapsedMs = 0U;
  5723. PlsrCurrentSegment = 0U;
  5724. PlsrCurrentFrequencyHz = 0UL;
  5725. PlsrQueuedFrequencyHz = 0UL;
  5726. PlsrCutRequested = 0U;
  5727. PlsrActTimedCutPlanned = 0U;
  5728. PlsrBoundaryPending = 0U;
  5729. PlsrBoundaryWasCut = 0U;
  5730. PlsrDirectionDelayActive = 0U;
  5731. PlsrDirectionDelayRemainingMs = 0U;
  5732. PlsrInitialDirectionPreparePending = 0U;
  5733. PlsrExtCaptureSegment = 0U;
  5734. PlsrExtEdgePending = 0U;
  5735. PlsrShortProfile.active = 0U;
  5736. PlsrProfileQueueReset();
  5737. PlsrHandoffPlan.valid = 0U;
  5738. PlsrInvalidateHandoffPlans();
  5739. PlsrDeferredFrequencyPending = 0U;
  5740. PlsrTimerErrorPending = 0U;
  5741. PlsrRamp.active = 0U;
  5742. PlsrExecutor.mode = PLSR_EXEC_IDLE;
  5743. PlsrError = PLSR_ERROR_NONE;
  5744. PlsrRunStatus = PLSR_STATUS_IDLE;
  5745. PlsrMarkPersistenceDirty(PLSR_CONFIG_SAVE_DELAY_MS);
  5746. }
  5747. static uint8_t PlsrPollCommandMailbox(void)
  5748. {
  5749. uint16_t command;
  5750. uint8_t endPoll = 1U;
  5751. uint32_t criticalState;
  5752. criticalState = PlsrPlatformEnterCritical();
  5753. if (PlsrCommandMailbox.state != PLSR_COMMAND_MAILBOX_PENDING)
  5754. {
  5755. PlsrPlatformExitCritical(criticalState);
  5756. return 0U;
  5757. }
  5758. PlsrCommandMailbox.state = PLSR_COMMAND_MAILBOX_EXECUTING;
  5759. command = PlsrCommandMailbox.command;
  5760. PlsrPlatformExitCritical(criticalState);
  5761. switch (command)
  5762. {
  5763. case PLSR_COMMAND_START: PlsrExecuteStart(); break;
  5764. case PLSR_COMMAND_STOP: endPoll = PlsrExecuteStop(); break;
  5765. case PLSR_COMMAND_CLEAR: PlsrExecuteClear(); break;
  5766. default: PlsrEnterError(PLSR_ERROR_INTERNAL); break;
  5767. }
  5768. criticalState = PlsrPlatformEnterCritical();
  5769. PlsrCommandMailbox.command = 0U;
  5770. PlsrCommandMailbox.state = PLSR_COMMAND_MAILBOX_EMPTY;
  5771. PlsrPlatformExitCritical(criticalState);
  5772. return endPoll;
  5773. }
  5774. static void PlsrEnterErrorIfEpoch(PLSR_ERROR error, uint32_t expectedEpoch)
  5775. {
  5776. uint32_t criticalState = PlsrPlatformEnterCritical();
  5777. if (PlsrSegmentEpoch == expectedEpoch)
  5778. {
  5779. PlsrEnterError(error);
  5780. }
  5781. PlsrPlatformExitCritical(criticalState);
  5782. }
  5783. static uint8_t PlsrServiceCountedExecutor(void)
  5784. {
  5785. uint32_t completedPulses;
  5786. uint32_t completedFrequencyHz;
  5787. uint32_t activeFrequencyHz;
  5788. uint32_t queuedFrequencyHz;
  5789. uint8_t completedNormally;
  5790. if ((PlsrPulseActive == 0U)
  5791. || ((PlsrExecutor.mode != PLSR_EXEC_STEP_TABLE)
  5792. && (PlsrExecutor.mode != PLSR_EXEC_STREAM)
  5793. && (PlsrExecutor.mode != PLSR_EXEC_STOPPING)))
  5794. {
  5795. return 0U;
  5796. }
  5797. if (PlsrSyncCountedProgress() == 0U)
  5798. {
  5799. PlsrEnterError(PLSR_ERROR_COUNT);
  5800. return 1U;
  5801. }
  5802. activeFrequencyHz = PlsrPlatformActiveFrequency(
  5803. (uint8_t)PlsrActiveConfig.pulseOutput);
  5804. if (activeFrequencyHz != 0UL)
  5805. {
  5806. PlsrCurrentFrequencyHz = activeFrequencyHz;
  5807. PlsrDiagnosticCheckActiveFrequency(activeFrequencyHz);
  5808. queuedFrequencyHz = PlsrQueuedFrequencyHz;
  5809. if (queuedFrequencyHz > activeFrequencyHz)
  5810. {
  5811. PlsrRunStatus = PLSR_STATUS_ACCELERATING;
  5812. }
  5813. else if (queuedFrequencyHz < activeFrequencyHz)
  5814. {
  5815. PlsrRunStatus = PLSR_STATUS_DECELERATING;
  5816. }
  5817. else
  5818. {
  5819. PlsrRunStatus = PLSR_STATUS_RUNNING;
  5820. }
  5821. }
  5822. if (PlsrPlatformTakeFiniteCompletion(
  5823. (uint8_t)PlsrActiveConfig.pulseOutput,
  5824. &completedPulses) == 0U)
  5825. {
  5826. return 0U;
  5827. }
  5828. (void)completedPulses;
  5829. if (PlsrSyncCountedProgress() == 0U)
  5830. {
  5831. PlsrEnterError(PLSR_ERROR_COUNT);
  5832. return 1U;
  5833. }
  5834. completedFrequencyHz = PlsrCurrentFrequencyHz;
  5835. completedNormally = ((PlsrRemainingPulses == 0ULL)
  5836. && (PlsrCutRequested == 0U)
  5837. && (PlsrCountOverflowPending == 0U)
  5838. && (PlsrTimerErrorPending == 0U)) ? 1U : 0U;
  5839. PlsrDiagnosticFinishSegment(completedNormally);
  5840. PlsrShortProfile.active = 0U;
  5841. PlsrProfileQueue.active = 0U;
  5842. PlsrHandoffPlan.valid = 0U;
  5843. PlsrCountedHandoffStaged = 0U;
  5844. PlsrBoundaryFrequencyHz = completedFrequencyHz;
  5845. PlsrBoundaryWasCut = ((PlsrCutRequested != 0U)
  5846. || (PlsrActTimedCutPlanned != 0U)) ? 1U : 0U;
  5847. PlsrCutRequested = 0U;
  5848. PlsrActTimedCutPlanned = 0U;
  5849. PlsrPulseActive = 0U;
  5850. PlsrCurrentFrequencyHz = 0UL;
  5851. PlsrQueuedFrequencyHz = 0UL;
  5852. PlsrBoundaryPending = 1U;
  5853. PlsrExecutor.mode = PLSR_EXEC_IDLE;
  5854. return 1U;
  5855. }
  5856. uint8_t PlsrServiceProfileProducer(uint16_t itemBudget)
  5857. {
  5858. uint8_t executorMode;
  5859. if ((PlsrInitialized == 0U) || (itemBudget == 0U))
  5860. {
  5861. return 0U;
  5862. }
  5863. executorMode = PlsrExecutor.mode;
  5864. if (((executorMode == PLSR_EXEC_STEP_TABLE)
  5865. || (executorMode == PLSR_EXEC_STREAM)
  5866. || (executorMode == PLSR_EXEC_AB_LEGACY))
  5867. && (PlsrProfileQueue.active != 0U)
  5868. && (PlsrProfileQueue.generatorComplete == 0U)
  5869. && (PlsrProfileQueueFill(PLSR_PROFILE_REFILL_TARGET,
  5870. &itemBudget) == 0U))
  5871. {
  5872. PlsrEnterError(PLSR_ERROR_TIMER);
  5873. return 0U;
  5874. }
  5875. executorMode = PlsrExecutor.mode;
  5876. if (((executorMode == PLSR_EXEC_STEP_TABLE)
  5877. || (executorMode == PLSR_EXEC_STREAM))
  5878. && ((PlsrStageCountedHandoff() == 0U)
  5879. || (PlsrProfileQueueFill(PLSR_PROFILE_REFILL_TARGET,
  5880. &itemBudget) == 0U)))
  5881. {
  5882. PlsrEnterError(PLSR_ERROR_TIMER);
  5883. return 0U;
  5884. }
  5885. executorMode = PlsrExecutor.mode;
  5886. if (((executorMode == PLSR_EXEC_STEP_TABLE)
  5887. || (executorMode == PLSR_EXEC_STREAM)
  5888. || (executorMode == PLSR_EXEC_AB_LEGACY))
  5889. && (PlsrProfileQueue.active != 0U)
  5890. && (PlsrProfileQueue.generatorComplete == 0U)
  5891. && (PlsrProfileQueueCount() < PLSR_PROFILE_REFILL_TARGET))
  5892. {
  5893. return 1U;
  5894. }
  5895. return 0U;
  5896. }
  5897. void PlsrPoll1ms(void)
  5898. {
  5899. uint8_t extLevel;//这一拍读到的 EXT 引脚电平。后面才用,这段没用
  5900. uint8_t extEdge;//这一拍有没有上升沿。后面才用
  5901. uint8_t activeSegmentNumber;//当前段号的快照
  5902. uint8_t applyDynamicFrequency = 0U;//要不要改目标频率。0 = 先当不用改
  5903. uint8_t pulseDirReplanRequested = 0U;//要不要对 PULSE/DIR 整段重规划。0 = 不要
  5904. uint8_t pulseDirReplanFailed = 0U;//重规划失败标志。先清零
  5905. PLSR_SEGMENT_CONFIG *activeSegment;//指向当前段配置。后面才赋值
  5906. uint32_t criticalState;//进临界区前的中断状态,退出时原样恢复。这段还没进临界区
  5907. uint32_t newTargetHz;//改频后的新目标。后面才用
  5908. uint32_t pulseDirReplanPulses = 0UL;//重规划还剩多少脉冲。先 0
  5909. uint32_t pollEpoch;//这一拍看到的段世代号,防止用过期段的 EXT/改频
  5910. PLSR_PLATFORM_SERVICE_RESULT pulseDirReplanResult =
  5911. PLSR_PLATFORM_SERVICE_READY;//重规划结果,先当成功
  5912. if (PlsrInitialized == 0U)
  5913. {
  5914. return;
  5915. }
  5916. #if !defined(PLSR_HOST_TEST)
  5917. /* Run the target throughput benchmark only while idle. It blocks task
  5918. context while measuring but never starts pulse output. */
  5919. if ((PlsrPlannerBenchmarkRequest != 0UL)
  5920. && (PlsrIsBusy() == 0U))
  5921. {
  5922. PlsrPlannerBenchmarkService();
  5923. return;
  5924. }
  5925. #endif
  5926. if (PlsrPollCommandMailbox() != 0U)
  5927. {
  5928. /*看邮箱有没有 START / STOP / CLEAR。
  5929. 有命令:当场执行(启动、停止、清位置)。
  5930. 返回 非 0:这拍到此结束(常见是 STOP 认为后面不用再 poll)。
  5931. 返回 0:没命令,或 STOP 说还可以继续 → 往下走。*/
  5932. return;
  5933. }
  5934. if (PlsrServiceInitialDirectionPrepare() != 0U)
  5935. {
  5936. /* Direction changed in this poll. Leave the complete configured
  5937. delay untouched until the following real 1 ms poll. */
  5938. return;
  5939. }
  5940. /* 段边界事件必须在任何计数同步之前消费:快照是 IRQ 边界时刻的
  5941. 硬件计数,晚消费会把下一 run 的脉冲算进旧段。 */
  5942. PlsrExecServiceCountedEvents();//把 IRQ 丢进边界事件环的东西在任务里消化:切段、记账。只做账,不算频率
  5943. if (PlsrTimerErrorPending != 0U)
  5944. {
  5945. /*IRQ 或平台已经锁存了定时器故障。
  5946. 进错误态,停后续。故障了还 Fill 会越帮越忙*/
  5947. PlsrEnterError(PLSR_ERROR_TIMER);
  5948. return;
  5949. }
  5950. PlsrPollPositionCheckpoint();//该把位置/配置写到掉电保存就写。和发波、队列无关,夹在中间是因为 1ms 顺手做
  5951. if (PlsrServiceCountedExecutor() != 0U)
  5952. {
  5953. /*给正在按队列发波 的执行器做服务:用硬件计数更新剩余脉冲和位置;
  5954. 若 整段已经发完(硬件 completion),清队列、置 BoundaryPending,返回 1。
  5955. 还在跑 → 返回 0,if 不进。
  5956. 已经发完 → 进大括号*/
  5957. if (PlsrBoundaryPending != 0U)
  5958. {
  5959. PlsrHandleBoundary(0U);
  5960. //有段边界待处理:接下一段、等待、完成发送等。参数 0 = 不是从脉冲 IRQ 里来的
  5961. }
  5962. PlsrPollPersistenceDelay();//掉电保存的延时到了就存
  5963. return;//这段波已经结束,本拍不要再补队列。Fill 是给还在跑的段用的
  5964. }
  5965. /* This work is bounded and targets only the inactive bank. It is done
  5966. after servicing the live queue so preparation cannot starve output. */
  5967. PlsrServiceTimedStartPreparation();
  5968. criticalState = PlsrPlatformEnterCritical();
  5969. pollEpoch = PlsrSegmentEpoch;
  5970. activeSegmentNumber = PlsrCurrentSegment;
  5971. extLevel = PlsrPlatformReadInput((uint8_t)PlsrActiveConfig.extInput);
  5972. extEdge = ((extLevel != 0U) && (PlsrExtPreviousLevel == 0U)) ? 1U : 0U;
  5973. PlsrExtPreviousLevel = extLevel;
  5974. if (PlsrExtEdgePending != 0U)
  5975. {
  5976. if ((PlsrExtEdgePendingEpoch == pollEpoch)
  5977. && (PlsrExtEdgePendingSegment == activeSegmentNumber))
  5978. {
  5979. extEdge = 1U;
  5980. }
  5981. PlsrExtEdgePending = 0U;
  5982. }
  5983. PlsrPlatformExitCritical(criticalState);
  5984. if (PlsrBoundaryPending != 0U)
  5985. {
  5986. PlsrHandleBoundary(extEdge);
  5987. PlsrPollPersistenceDelay();
  5988. return;
  5989. }
  5990. if (PlsrIsBusy() == 0U)
  5991. {
  5992. PlsrExtEdgePending = 0U;
  5993. PlsrPollPersistenceDelay();
  5994. return;
  5995. }
  5996. if (PlsrSegmentEpoch != pollEpoch)
  5997. {
  5998. return;
  5999. }
  6000. if (PlsrDirectionDelayActive != 0U)
  6001. {
  6002. activeSegmentNumber = PlsrCurrentSegment;
  6003. if ((extEdge != 0U)
  6004. && (activeSegmentNumber != 0U)
  6005. && (activeSegmentNumber <= PlsrActiveConfig.segmentCount)
  6006. && ((PlsrActiveConfig.segments[activeSegmentNumber - 1U].waitType
  6007. == PLSR_EXT_SIGNAL)
  6008. || (PlsrActiveConfig.segments[
  6009. activeSegmentNumber - 1U].waitType
  6010. == PLSR_EXT_OR_COMPLETE)))
  6011. {
  6012. PlsrRequestCut(pollEpoch);
  6013. return;
  6014. }
  6015. if (PlsrDirectionDelayRemainingMs != 0U)
  6016. {
  6017. PlsrDirectionDelayRemainingMs--;
  6018. }
  6019. if (PlsrDirectionDelayRemainingMs == 0U)
  6020. {
  6021. PlsrDirectionDelayActive = 0U;
  6022. if (PlsrTimedStart.pendingActivation != 0U)
  6023. {
  6024. if (PlsrStartPreparedTimedOutput() == 0U)
  6025. {
  6026. PlsrEnterError(PLSR_ERROR_TIMER);
  6027. }
  6028. }
  6029. else if (PlsrBeginSegmentOutput(
  6030. PlsrPulseDirStartFrequency(
  6031. PlsrActiveConfig.segments[
  6032. PlsrCurrentSegment - 1U].frequencyHz,
  6033. PlsrDelayedEntryType, 1U, 0UL)) == 0U)
  6034. {
  6035. PlsrEnterError(PLSR_ERROR_TIMER);
  6036. }
  6037. }
  6038. return;
  6039. }
  6040. criticalState = PlsrPlatformEnterCritical();
  6041. if (PlsrSegmentEpoch != pollEpoch)
  6042. {
  6043. PlsrPlatformExitCritical(criticalState);
  6044. return;
  6045. }
  6046. if (PlsrSegmentClockStarted != 0U)
  6047. {
  6048. PlsrSegmentElapsedMs++;
  6049. }
  6050. if (PlsrRunStatus == PLSR_STATUS_WAITING)
  6051. {
  6052. PlsrPlatformExitCritical(criticalState);
  6053. PlsrPollWaiting(extEdge);
  6054. return;
  6055. }
  6056. activeSegmentNumber = PlsrCurrentSegment;
  6057. if ((activeSegmentNumber == 0U)
  6058. || (activeSegmentNumber > PlsrActiveConfig.segmentCount))
  6059. {
  6060. PlsrPlatformExitCritical(criticalState);
  6061. PlsrEnterError(PLSR_ERROR_INTERNAL);
  6062. return;
  6063. }
  6064. activeSegment = &PlsrActiveConfig.segments[activeSegmentNumber - 1U];
  6065. if (PlsrSeamlessHandoffPending != 0U)
  6066. {
  6067. PlsrSeamlessHandoffPending = 0U;
  6068. if ((PlsrStopRequested == 0U)
  6069. && (PlsrShortProfile.active == 0U)
  6070. && (PlsrFrequencyUpdatePending == 0U))
  6071. {
  6072. PlsrRamp.active = 0U;
  6073. PlsrRunStatus = PLSR_STATUS_RUNNING;
  6074. }
  6075. }
  6076. newTargetHz = PlsrFrequencyUpdateTargetHz;
  6077. if ((PlsrStopRequested == 0U)
  6078. && (PlsrFrequencyUpdatePending != 0U)
  6079. && (PlsrAbStopArmed == 0U)
  6080. && (PlsrFrequencyUpdateSegment == activeSegmentNumber))
  6081. {
  6082. activeSegment->frequencyHz = newTargetHz;
  6083. PlsrBoundaryRampStarted = 0U;
  6084. if (PlsrActiveConfig.outputMode == PLSR_OUTPUT_PULSE_DIR)
  6085. {
  6086. uint64_t remaining =
  6087. (activeSegment->waitType == PLSR_ACT_TIME)
  6088. ? PlsrCommandRemainingPulses : PlsrRemainingPulses;
  6089. if (PlsrCountedHandoffStaged != 0U)
  6090. {
  6091. /* The marker and its metadata are one published transaction.
  6092. Leave both untouched; the boundary consumer retargets this
  6093. pending update to the segment that hardware enters. */
  6094. }
  6095. else if ((activeSegment->waitType == PLSR_ACT_TIME)
  6096. && (PlsrSegmentElapsedMs >= activeSegment->actTimeMs))
  6097. {
  6098. /* The normal deadline path below owns the full-pulse cut. */
  6099. PlsrFrequencyUpdatePending = 0U;
  6100. }
  6101. else if ((remaining == 0ULL) || (remaining > 0xFFFFFFFFULL))
  6102. {
  6103. PlsrFrequencyUpdatePending = 0U;
  6104. pulseDirReplanFailed = 1U;
  6105. }
  6106. else
  6107. {
  6108. PlsrFrequencyUpdatePending = 0U;
  6109. pulseDirReplanPulses = (uint32_t)remaining;
  6110. pulseDirReplanRequested = 1U;
  6111. }
  6112. }
  6113. else
  6114. {
  6115. PlsrFrequencyUpdatePending = 0U;
  6116. PlsrShortProfile.active = 0U;
  6117. PlsrProfileQueueInvalidateGeneration();
  6118. PlsrRampStart(PlsrCurrentFrequencyHz, newTargetHz);
  6119. if (PlsrRamp.active == 0U)
  6120. {
  6121. applyDynamicFrequency = 1U;
  6122. }
  6123. }
  6124. }
  6125. PlsrPlatformExitCritical(criticalState);
  6126. if (pulseDirReplanRequested != 0U)
  6127. {
  6128. pulseDirReplanResult = PlsrReplanPulseDir(
  6129. newTargetHz, pulseDirReplanPulses, 0U);
  6130. if (pulseDirReplanResult == PLSR_PLATFORM_SERVICE_FAILED)
  6131. {
  6132. pulseDirReplanFailed = 1U;
  6133. }
  6134. else if (pulseDirReplanResult == PLSR_PLATFORM_SERVICE_DEFERRED)
  6135. {
  6136. /* A segment-marker run may already be latched. Keep the old
  6137. published stream intact and retry against whichever segment is
  6138. active after the boundary event is settled. */
  6139. criticalState = PlsrPlatformEnterCritical();
  6140. if ((PlsrSegmentEpoch == pollEpoch)
  6141. && (PlsrStopRequested == 0U))
  6142. {
  6143. PlsrFrequencyUpdateTargetHz = newTargetHz;
  6144. PlsrFrequencyUpdateSegment = activeSegmentNumber;
  6145. PlsrFrequencyUpdatePending = 1U;
  6146. }
  6147. PlsrPlatformExitCritical(criticalState);
  6148. }
  6149. }
  6150. if (pulseDirReplanFailed != 0U)
  6151. {
  6152. PlsrEnterErrorIfEpoch(PLSR_ERROR_TIMER, pollEpoch);
  6153. return;
  6154. }
  6155. if (applyDynamicFrequency != 0U)
  6156. {
  6157. if (PlsrApplyFrequency(newTargetHz, pollEpoch) == 0U)
  6158. {
  6159. PlsrEnterErrorIfEpoch(PLSR_ERROR_TIMER, pollEpoch);
  6160. return;
  6161. }
  6162. criticalState = PlsrPlatformEnterCritical();
  6163. if (PlsrSegmentEpoch == pollEpoch)
  6164. {
  6165. PlsrRunStatus = PLSR_STATUS_RUNNING;
  6166. }
  6167. PlsrPlatformExitCritical(criticalState);
  6168. }
  6169. if ((PlsrActiveConfig.outputMode == PLSR_OUTPUT_AB)
  6170. && (PlsrShortProfile.active == 0U)
  6171. && (PlsrRamp.active != 0U)
  6172. && (PlsrRampAdvance(pollEpoch) == 0U))
  6173. {
  6174. PlsrEnterErrorIfEpoch(PLSR_ERROR_TIMER, pollEpoch);
  6175. return;
  6176. }
  6177. criticalState = PlsrPlatformEnterCritical();
  6178. if (PlsrSegmentEpoch != pollEpoch)
  6179. {
  6180. PlsrPlatformExitCritical(criticalState);
  6181. return;
  6182. }
  6183. if ((PlsrActiveConfig.outputMode == PLSR_OUTPUT_AB)
  6184. && (PlsrStopRequested != 0U) && (PlsrRamp.active == 0U))
  6185. {
  6186. if (PlsrStopPulsesRemaining == 0U)
  6187. {
  6188. if (PlsrArmStopDrainLocked() == 0U)
  6189. {
  6190. PlsrPlatformExitCritical(criticalState);
  6191. PlsrEnterError(PLSR_ERROR_TIMER);
  6192. return;
  6193. }
  6194. }
  6195. else
  6196. {
  6197. (void)PlsrArmFinalAbBoundaryLocked();
  6198. }
  6199. PlsrPlatformExitCritical(criticalState);
  6200. return;
  6201. }
  6202. PlsrPlatformExitCritical(criticalState);
  6203. if ((activeSegment->waitType == PLSR_ACT_TIME)
  6204. && (PlsrSegmentElapsedMs >= activeSegment->actTimeMs)
  6205. && ((PlsrActiveConfig.outputMode != PLSR_OUTPUT_PULSE_DIR)
  6206. || (PlsrActTimedCutPlanned == 0U)))
  6207. {
  6208. PlsrRequestCut(pollEpoch);
  6209. return;
  6210. }
  6211. if (((activeSegment->waitType == PLSR_EXT_SIGNAL)
  6212. || (activeSegment->waitType == PLSR_EXT_OR_COMPLETE))
  6213. && (extEdge != 0U))
  6214. {
  6215. PlsrRequestCut(pollEpoch);
  6216. return;
  6217. }
  6218. if (PlsrActiveConfig.outputMode == PLSR_OUTPUT_AB)
  6219. {
  6220. PlsrMaybePlanBoundaryRamp(pollEpoch);
  6221. }
  6222. }
  6223. void PlsrPulseTimerIrq(uint8_t pulseOutput)
  6224. {
  6225. uint32_t positionBits;
  6226. uint32_t completedFrequencyHz;
  6227. uint64_t remainingPulses;
  6228. PLSR_PLATFORM_QUEUE_RESULT queueResult;
  6229. if ((PlsrPulseActive == 0U)
  6230. || (pulseOutput != (uint8_t)PlsrActiveConfig.pulseOutput))
  6231. {
  6232. return;
  6233. }
  6234. if ((PlsrExecutor.mode == PLSR_EXEC_STEP_TABLE)
  6235. || (PlsrExecutor.mode == PLSR_EXEC_STREAM)
  6236. || (PlsrExecutor.mode == PLSR_EXEC_STOPPING))
  6237. {
  6238. return;
  6239. }
  6240. completedFrequencyHz = PlsrCurrentFrequencyHz;
  6241. PlsrDiagnosticCheckActiveFrequency(completedFrequencyHz);
  6242. PlsrCurrentFrequencyHz = PlsrPlatformActiveFrequency(pulseOutput);
  6243. if (PlsrCurrentFrequencyHz == 0UL)
  6244. {
  6245. PlsrCurrentFrequencyHz = PlsrQueuedFrequencyHz;
  6246. }
  6247. if ((PlsrStopRequested != 0U) && (PlsrRamp.active == 0U)
  6248. && (PlsrStopPulsesRemaining != 0U))
  6249. {
  6250. PlsrStopPulsesRemaining--;
  6251. if (PlsrStopPulsesRemaining == 0U)
  6252. {
  6253. PlsrCutRequested = 1U;
  6254. }
  6255. }
  6256. positionBits = (uint32_t)PlsrPosition;
  6257. if (PlsrCountPositive != 0U)
  6258. {
  6259. if (positionBits == (uint32_t)INT32_MAX)
  6260. {
  6261. PlsrPositionValid = 0U;
  6262. #if PLSR_COUNT_ERROR_CHECK_ENABLED
  6263. PlsrCountOverflowPending = 1U;
  6264. #endif
  6265. }
  6266. positionBits++;
  6267. }
  6268. else
  6269. {
  6270. if (positionBits == (uint32_t)INT32_MIN)
  6271. {
  6272. PlsrPositionValid = 0U;
  6273. #if PLSR_COUNT_ERROR_CHECK_ENABLED
  6274. PlsrCountOverflowPending = 1U;
  6275. #endif
  6276. }
  6277. positionBits--;
  6278. }
  6279. PlsrPosition = (int32_t)positionBits;
  6280. PlsrPositionCheckpointDirty = 1U;
  6281. remainingPulses = PlsrRemainingPulses;
  6282. if (remainingPulses != 0UL)
  6283. {
  6284. remainingPulses--;
  6285. PlsrRemainingPulses = remainingPulses;
  6286. if (PlsrCommandRemainingPulses != 0ULL)
  6287. {
  6288. PlsrCommandRemainingPulses--;
  6289. }
  6290. }
  6291. if ((remainingPulses == 0UL) || (PlsrCutRequested != 0U)
  6292. || (PlsrCountOverflowPending != 0U))
  6293. {
  6294. if (remainingPulses == 0UL)
  6295. {
  6296. queueResult = PlsrTryContinuousHandoff();
  6297. if (queueResult != PLSR_PLATFORM_QUEUE_FAILED)
  6298. {
  6299. return;
  6300. }
  6301. }
  6302. PlsrPlatformGateFromIrq(pulseOutput);
  6303. #ifdef PLSR_HOST_TEST
  6304. PlsrHostTestEventSequence++;
  6305. PlsrHostTestLastGateEvent = PlsrHostTestEventSequence;
  6306. #endif
  6307. PlsrDiagnosticFinishSegment(
  6308. ((remainingPulses == 0UL)
  6309. && (PlsrCutRequested == 0U)
  6310. && (PlsrCountOverflowPending == 0U)) ? 1U : 0U);
  6311. PlsrShortProfile.active = 0U;
  6312. PlsrHandoffPlan.valid = 0U;
  6313. PlsrBoundaryFrequencyHz = completedFrequencyHz;
  6314. PlsrBoundaryWasCut = (PlsrCutRequested != 0U) ? 1U : 0U;
  6315. PlsrCutRequested = 0U;
  6316. PlsrAbStopArmed = 0U;
  6317. PlsrPulseActive = 0U;
  6318. PlsrCurrentFrequencyHz = 0UL;
  6319. PlsrQueuedFrequencyHz = 0UL;
  6320. PlsrBoundaryPending = 1U;
  6321. return;
  6322. }
  6323. if (PlsrShortProfile.active != 0U)
  6324. {
  6325. queueResult = PlsrProfileQueueCommitNext(pulseOutput);
  6326. if (queueResult == PLSR_PLATFORM_QUEUE_STALE)
  6327. {
  6328. return;
  6329. }
  6330. if (queueResult == PLSR_PLATFORM_QUEUE_FAILED)
  6331. {
  6332. PlsrDiagnosticFinishSegment(0U);
  6333. PlsrTimerErrorPending = 1U;
  6334. PlsrShortProfile.active = 0U;
  6335. PlsrHandoffPlan.valid = 0U;
  6336. PlsrBoundaryFrequencyHz = completedFrequencyHz;
  6337. PlsrBoundaryWasCut = 0U;
  6338. PlsrCutRequested = 0U;
  6339. PlsrPlatformGateFromIrq(pulseOutput);
  6340. PlsrAbStopArmed = 0U;
  6341. PlsrPulseActive = 0U;
  6342. PlsrCurrentFrequencyHz = 0UL;
  6343. PlsrQueuedFrequencyHz = 0UL;
  6344. PlsrBoundaryPending = 1U;
  6345. return;
  6346. }
  6347. }
  6348. if ((PlsrShortProfile.active == 0U)
  6349. && (remainingPulses == 1UL))
  6350. {
  6351. if (PlsrPrimeHandoff() == PLSR_PLATFORM_QUEUE_STALE)
  6352. {
  6353. return;
  6354. }
  6355. }
  6356. if ((PlsrShortProfile.active == 0U)
  6357. && (PlsrHandoffPlan.valid == 0U)
  6358. && (PlsrDeferredFrequencyPending != 0U))
  6359. {
  6360. queueResult = PlsrCommitDeferredFrequency(pulseOutput);
  6361. if (queueResult == PLSR_PLATFORM_QUEUE_STALE)
  6362. {
  6363. return;
  6364. }
  6365. if (queueResult == PLSR_PLATFORM_QUEUE_FAILED)
  6366. {
  6367. PlsrDiagnosticFinishSegment(0U);
  6368. PlsrTimerErrorPending = 1U;
  6369. PlsrBoundaryFrequencyHz = completedFrequencyHz;
  6370. PlsrBoundaryWasCut = 0U;
  6371. PlsrCutRequested = 0U;
  6372. PlsrPlatformGateFromIrq(pulseOutput);
  6373. PlsrAbStopArmed = 0U;
  6374. PlsrPulseActive = 0U;
  6375. PlsrCurrentFrequencyHz = 0UL;
  6376. PlsrQueuedFrequencyHz = 0UL;
  6377. PlsrBoundaryPending = 1U;
  6378. return;
  6379. }
  6380. }
  6381. if ((PlsrActiveConfig.outputMode == PLSR_OUTPUT_AB)
  6382. && (PlsrQueueFinalAbBoundaryFromIrq() == 0U))
  6383. {
  6384. return;
  6385. }
  6386. }
  6387. PLSR_MB_RESULT PlsrModbusReadHolding(uint16_t startAddress,
  6388. uint16_t quantity,
  6389. uint16_t *values)
  6390. {
  6391. PLSR_MB_RESULT classification;
  6392. uint16_t index;
  6393. uint32_t criticalState;
  6394. int32_t position;
  6395. uint32_t frequency;
  6396. uint16_t statusWords[7];
  6397. uint16_t diagnosticWords[26];
  6398. uint16_t queueDiagnosticWords[9];
  6399. if (values == NULL)
  6400. {
  6401. return PLSR_MB_ILLEGAL_VALUE;
  6402. }
  6403. classification = PlsrClassifyRange(startAddress, quantity);
  6404. if (classification != PLSR_MB_OK)
  6405. {
  6406. return classification;
  6407. }
  6408. criticalState = PlsrPlatformEnterCritical();
  6409. position = PlsrPosition;
  6410. frequency = PlsrCurrentFrequencyHz;
  6411. statusWords[0] = PlsrLowWord((uint32_t)position);
  6412. statusWords[1] = PlsrHighWord((uint32_t)position);
  6413. statusWords[2] = PlsrLowWord(frequency);
  6414. statusWords[3] = PlsrHighWord(frequency);
  6415. statusWords[4] = (uint16_t)PlsrRunStatus;
  6416. statusWords[5] = PlsrCurrentSegment;
  6417. statusWords[6] = (uint16_t)PlsrError;
  6418. diagnosticWords[0] = PlsrDiagnostic.flags;
  6419. diagnosticWords[1] = PlsrDiagnostic.reason;
  6420. diagnosticWords[2] = PlsrDiagnostic.lastSegment;
  6421. diagnosticWords[3] = PlsrDiagnostic.modeDirection;
  6422. diagnosticWords[4] = PlsrLowWord(PlsrDiagnostic.expectedCycles);
  6423. diagnosticWords[5] = PlsrHighWord(PlsrDiagnostic.expectedCycles);
  6424. diagnosticWords[6] = PlsrLowWord(PlsrDiagnostic.observedCycles);
  6425. diagnosticWords[7] = PlsrHighWord(PlsrDiagnostic.observedCycles);
  6426. diagnosticWords[8] = PlsrLowWord((uint32_t)PlsrDiagnostic.countError);
  6427. diagnosticWords[9] = PlsrHighWord((uint32_t)PlsrDiagnostic.countError);
  6428. diagnosticWords[10] = PlsrLowWord(PlsrDiagnostic.requestedHz);
  6429. diagnosticWords[11] = PlsrHighWord(PlsrDiagnostic.requestedHz);
  6430. diagnosticWords[12] = PlsrLowWord(PlsrDiagnostic.expectedTimerHz);
  6431. diagnosticWords[13] = PlsrHighWord(PlsrDiagnostic.expectedTimerHz);
  6432. diagnosticWords[14] = PlsrLowWord(PlsrDiagnostic.activeTimerHz);
  6433. diagnosticWords[15] = PlsrHighWord(PlsrDiagnostic.activeTimerHz);
  6434. diagnosticWords[16] =
  6435. PlsrLowWord((uint32_t)PlsrDiagnostic.requestErrorHz);
  6436. diagnosticWords[17] =
  6437. PlsrHighWord((uint32_t)PlsrDiagnostic.requestErrorHz);
  6438. diagnosticWords[18] = PlsrLowWord(PlsrDiagnostic.curveSampleCount);
  6439. diagnosticWords[19] = PlsrHighWord(PlsrDiagnostic.curveSampleCount);
  6440. diagnosticWords[20] = PlsrLowWord(PlsrDiagnostic.curveMismatchCount);
  6441. diagnosticWords[21] = PlsrHighWord(PlsrDiagnostic.curveMismatchCount);
  6442. diagnosticWords[22] = PlsrLowWord(PlsrDiagnostic.curveMaxAbsErrorHz);
  6443. diagnosticWords[23] = PlsrHighWord(PlsrDiagnostic.curveMaxAbsErrorHz);
  6444. diagnosticWords[24] = PlsrLowWord(PlsrDiagnostic.firstMismatchSample);
  6445. diagnosticWords[25] = PlsrHighWord(PlsrDiagnostic.firstMismatchSample);
  6446. queueDiagnosticWords[0] = PlsrProfileQueueDiagnosticFlags;
  6447. queueDiagnosticWords[1] = PlsrProfileQueueMinimumDepth;
  6448. queueDiagnosticWords[2] = PlsrProfileQueueCount();
  6449. queueDiagnosticWords[3] = PlsrLowWord(PlsrProfileQueueLowWaterEvents);
  6450. queueDiagnosticWords[4] = PlsrHighWord(PlsrProfileQueueLowWaterEvents);
  6451. queueDiagnosticWords[5] = PlsrLowWord(PlsrProfileQueueUnderruns);
  6452. queueDiagnosticWords[6] = PlsrHighWord(PlsrProfileQueueUnderruns);
  6453. queueDiagnosticWords[7] = PlsrLowWord(PlsrPlannerClippedCount);
  6454. queueDiagnosticWords[8] = PlsrHighWord(PlsrPlannerClippedCount);
  6455. PlsrPlatformExitCritical(criticalState);
  6456. for (index = 0U; index < quantity; index++)
  6457. {
  6458. uint16_t address = (uint16_t)(startAddress + index);
  6459. if ((address >= PLSR_CONFIG_FIRST_ADDRESS)
  6460. && (address <= PLSR_CONFIG_LAST_ADDRESS))
  6461. {
  6462. values[index] = PlsrReadConfigWord(&PlsrShadowConfig, address);
  6463. }
  6464. else if (address == PLSR_OUTPUT_MODE_ADDRESS)
  6465. {
  6466. values[index] = PlsrShadowConfig.outputMode;
  6467. }
  6468. else if ((address >= PLSR_STATUS_FIRST_ADDRESS)
  6469. && (address <= PLSR_STATUS_LAST_ADDRESS))
  6470. {
  6471. values[index] = statusWords[address - PLSR_STATUS_FIRST_ADDRESS];
  6472. }
  6473. else if ((address >= PLSR_DIAGNOSTIC_FIRST_ADDRESS)
  6474. && (address <= PLSR_DIAGNOSTIC_LAST_ADDRESS))
  6475. {
  6476. values[index] =
  6477. diagnosticWords[address - PLSR_DIAGNOSTIC_FIRST_ADDRESS];
  6478. }
  6479. else if ((address >= PLSR_QUEUE_DIAGNOSTIC_FIRST_ADDRESS)
  6480. && (address <= PLSR_QUEUE_DIAGNOSTIC_LAST_ADDRESS))
  6481. {
  6482. values[index] = queueDiagnosticWords[
  6483. address - PLSR_QUEUE_DIAGNOSTIC_FIRST_ADDRESS];
  6484. }
  6485. else if (address == PLSR_CONTROL_ADDRESS)
  6486. {
  6487. values[index] = 0U;
  6488. }
  6489. else if (address == PLSR_DIAGNOSTIC_CONTROL_ADDRESS)
  6490. {
  6491. values[index] = 0U;
  6492. }
  6493. else
  6494. {
  6495. return PLSR_MB_ILLEGAL_ADDRESS;
  6496. }
  6497. }
  6498. return PLSR_MB_OK;
  6499. }
  6500. PLSR_MB_RESULT PlsrModbusWriteHolding(uint16_t startAddress,
  6501. uint16_t quantity,
  6502. const uint16_t *values)
  6503. {
  6504. PLSR_MB_RESULT classification;
  6505. PLSR_WORD_RESULT wordResult;
  6506. uint16_t index;
  6507. uint16_t pairedAddress;
  6508. uint32_t requestEnd;
  6509. uint32_t criticalState;
  6510. uint8_t handoffBank = 0U;
  6511. uint8_t updateActiveFrequencies = 0U;
  6512. uint8_t updateActivePlannerParameters = 0U;
  6513. uint8_t drainedToDifferentSegment = 0U;
  6514. uint8_t segmentBeforeDrain;
  6515. uint32_t drainedSegmentTargetHz = 0UL;
  6516. PLSR_PLATFORM_QUEUE_RESULT queueResult;
  6517. if (values == NULL)
  6518. {
  6519. return PLSR_MB_ILLEGAL_VALUE;
  6520. }
  6521. classification = PlsrClassifyRange(startAddress, quantity);
  6522. if (classification != PLSR_MB_OK)
  6523. {
  6524. return classification;
  6525. }
  6526. if ((startAddress >= PLSR_STATUS_FIRST_ADDRESS)
  6527. && (startAddress <= PLSR_STATUS_LAST_ADDRESS))
  6528. {
  6529. return PLSR_MB_ILLEGAL_ADDRESS;
  6530. }
  6531. if ((startAddress >= PLSR_DIAGNOSTIC_FIRST_ADDRESS)
  6532. && (startAddress <= PLSR_DIAGNOSTIC_LAST_ADDRESS))
  6533. {
  6534. return PLSR_MB_ILLEGAL_ADDRESS;
  6535. }
  6536. if ((startAddress >= PLSR_QUEUE_DIAGNOSTIC_FIRST_ADDRESS)
  6537. && (startAddress <= PLSR_QUEUE_DIAGNOSTIC_LAST_ADDRESS))
  6538. {
  6539. return PLSR_MB_ILLEGAL_ADDRESS;
  6540. }
  6541. if (startAddress == PLSR_DIAGNOSTIC_CONTROL_ADDRESS)
  6542. {
  6543. if (quantity != 1U)
  6544. {
  6545. return PLSR_MB_ILLEGAL_ADDRESS;
  6546. }
  6547. if ((values[0] != 0U) && (values[0] != 1U))
  6548. {
  6549. return PLSR_MB_ILLEGAL_VALUE;
  6550. }
  6551. if ((values[0] != 0U) && (PlsrIsBusy() != 0U))
  6552. {
  6553. return PLSR_MB_DEVICE_BUSY;
  6554. }
  6555. if (values[0] != 0U)
  6556. {
  6557. criticalState = PlsrPlatformEnterCritical();
  6558. PlsrDiagnosticReset();
  6559. PlsrPlatformExitCritical(criticalState);
  6560. }
  6561. return PLSR_MB_OK;
  6562. }
  6563. if (startAddress == PLSR_CONTROL_ADDRESS)
  6564. {
  6565. if (quantity != 1U)
  6566. {
  6567. return PLSR_MB_ILLEGAL_ADDRESS;
  6568. }
  6569. switch (values[0])
  6570. {
  6571. case 0U: return PLSR_MB_OK;
  6572. case PLSR_COMMAND_START:
  6573. case PLSR_COMMAND_STOP:
  6574. case PLSR_COMMAND_CLEAR:
  6575. return PlsrQueueCommand(values[0]);
  6576. default: return PLSR_MB_ILLEGAL_VALUE;
  6577. }
  6578. }
  6579. if (startAddress == PLSR_OUTPUT_MODE_ADDRESS)
  6580. {
  6581. if (quantity != 1U)
  6582. {
  6583. return PLSR_MB_ILLEGAL_ADDRESS;
  6584. }
  6585. if (PlsrIsBusy() != 0U)
  6586. {
  6587. return PLSR_MB_DEVICE_BUSY;
  6588. }
  6589. PlsrCandidateConfig = PlsrShadowConfig;
  6590. PlsrCandidateConfig.outputMode = values[0];
  6591. if (PlsrConfigIsValid(&PlsrCandidateConfig, 0U) == 0U)
  6592. {
  6593. return PLSR_MB_ILLEGAL_VALUE;
  6594. }
  6595. criticalState = PlsrPlatformEnterCritical();
  6596. PlsrShadowConfig = PlsrCandidateConfig;
  6597. PlsrPlatformExitCritical(criticalState);
  6598. PlsrPlatformCheckpointConfig(&PlsrShadowConfig);
  6599. PlsrMarkPersistenceDirty(PLSR_CONFIG_SAVE_DELAY_MS);
  6600. return PLSR_MB_OK;
  6601. }
  6602. if ((startAddress < PLSR_CONFIG_FIRST_ADDRESS)
  6603. || ((uint32_t)startAddress + quantity - 1UL
  6604. > PLSR_CONFIG_LAST_ADDRESS))
  6605. {
  6606. return PLSR_MB_ILLEGAL_ADDRESS;
  6607. }
  6608. if ((PlsrIsBusy() != 0U)
  6609. && (startAddress <= 0x1001U)
  6610. && ((uint32_t)startAddress + quantity - 1UL >= 0x1000UL))
  6611. {
  6612. return PLSR_MB_DEVICE_BUSY;
  6613. }
  6614. requestEnd = (uint32_t)startAddress + quantity;
  6615. for (index = 0U; index < quantity; index++)
  6616. {
  6617. uint16_t address = (uint16_t)(startAddress + index);
  6618. if (PlsrAddressIsDwordHalf(address, &pairedAddress) != 0U)
  6619. {
  6620. if (((uint32_t)pairedAddress < startAddress)
  6621. || ((uint32_t)pairedAddress >= requestEnd))
  6622. {
  6623. return PLSR_MB_ILLEGAL_ADDRESS;
  6624. }
  6625. }
  6626. }
  6627. PlsrCandidateConfig = PlsrShadowConfig;
  6628. for (index = 0U; index < quantity; index++)
  6629. {
  6630. wordResult = PlsrWriteConfigWord(&PlsrCandidateConfig,
  6631. (uint16_t)(startAddress + index),
  6632. values[index]);
  6633. if (wordResult == PLSR_WORD_ILLEGAL_ADDRESS)
  6634. {
  6635. return PLSR_MB_ILLEGAL_ADDRESS;
  6636. }
  6637. if (wordResult == PLSR_WORD_ILLEGAL_VALUE)
  6638. {
  6639. return PLSR_MB_ILLEGAL_VALUE;
  6640. }
  6641. }
  6642. if (PlsrConfigIsValid(&PlsrCandidateConfig, 0U) == 0U)
  6643. {
  6644. return PLSR_MB_ILLEGAL_VALUE;
  6645. }
  6646. if (PlsrIsBusy() != 0U)
  6647. {
  6648. for (index = 0U; index < PlsrActiveConfig.segmentCount; index++)
  6649. {
  6650. if (PlsrCandidateConfig.segments[index].frequencyHz
  6651. != PlsrShadowConfig.segments[index].frequencyHz)
  6652. {
  6653. updateActiveFrequencies = 1U;
  6654. }
  6655. }
  6656. if ((PlsrActiveConfig.outputMode == PLSR_OUTPUT_PULSE_DIR)
  6657. && ((PlsrCandidateConfig.accelerationTimeMs
  6658. != PlsrShadowConfig.accelerationTimeMs)
  6659. || (PlsrCandidateConfig.decelerationTimeMs
  6660. != PlsrShadowConfig.decelerationTimeMs)
  6661. || (PlsrCandidateConfig.curveMode
  6662. != PlsrShadowConfig.curveMode)))
  6663. {
  6664. updateActivePlannerParameters = 1U;
  6665. }
  6666. }
  6667. if ((updateActiveFrequencies != 0U)
  6668. || (updateActivePlannerParameters != 0U))
  6669. {
  6670. handoffBank = PlsrBuildHandoffPlanBank(&PlsrCandidateConfig);
  6671. }
  6672. criticalState = PlsrPlatformEnterCritical();
  6673. segmentBeforeDrain = PlsrCurrentSegment;
  6674. if ((updateActiveFrequencies != 0U) && (PlsrPulseActive != 0U)
  6675. && (PlsrActiveConfig.outputMode != PLSR_OUTPUT_PULSE_DIR))
  6676. {
  6677. PlsrPlatformDrainPendingPulse(
  6678. (uint8_t)PlsrActiveConfig.pulseOutput);
  6679. drainedToDifferentSegment =
  6680. (PlsrCurrentSegment != segmentBeforeDrain) ? 1U : 0U;
  6681. if ((drainedToDifferentSegment != 0U)
  6682. && (PlsrCurrentSegment != 0U)
  6683. && (PlsrCurrentSegment <= PlsrCandidateConfig.segmentCount))
  6684. {
  6685. drainedSegmentTargetHz = PlsrResolvedSegmentFrequency(
  6686. &PlsrCandidateConfig, PlsrCurrentSegment - 1U);
  6687. }
  6688. }
  6689. PlsrShadowConfig = PlsrCandidateConfig;
  6690. if ((updateActiveFrequencies != 0U)
  6691. || (updateActivePlannerParameters != 0U))
  6692. {
  6693. PlsrInvalidateTimedStartLocked();
  6694. if (updateActivePlannerParameters != 0U)
  6695. {
  6696. PlsrActiveConfig.accelerationTimeMs =
  6697. PlsrCandidateConfig.accelerationTimeMs;
  6698. PlsrActiveConfig.decelerationTimeMs =
  6699. PlsrCandidateConfig.decelerationTimeMs;
  6700. PlsrActiveConfig.curveMode = PlsrCandidateConfig.curveMode;
  6701. }
  6702. for (index = 0U; index < PlsrActiveConfig.segmentCount; index++)
  6703. {
  6704. uint8_t frequencyChanged =
  6705. (PlsrActiveConfig.segments[index].frequencyHz
  6706. != PlsrResolvedSegmentFrequency(&PlsrCandidateConfig, index))
  6707. ? 1U : 0U;
  6708. PlsrActiveConfig.segments[index].frequencyHz =
  6709. PlsrResolvedSegmentFrequency(&PlsrCandidateConfig, index);
  6710. if ((frequencyChanged != 0U)
  6711. && (index + 1U == PlsrCurrentSegment)
  6712. && (PlsrStopRequested == 0U)
  6713. && (PlsrAbStopArmed == 0U)
  6714. && (PlsrRunStatus != PLSR_STATUS_WAITING))
  6715. {
  6716. PlsrFrequencyUpdateTargetHz =
  6717. PlsrResolvedSegmentFrequency(&PlsrCandidateConfig,
  6718. index);
  6719. PlsrFrequencyUpdateSegment = (uint8_t)(index + 1U);
  6720. PlsrFrequencyUpdatePending = 1U;
  6721. }
  6722. }
  6723. PlsrPreparedHandoffBank = handoffBank;
  6724. if ((updateActiveFrequencies != 0U)
  6725. && (PlsrActiveConfig.outputMode == PLSR_OUTPUT_PULSE_DIR))
  6726. {
  6727. /* Publish the new prepared-plan bank without touching the stream
  6728. or handoff metadata already visible to the counter IRQ. A
  6729. task-context replan replaces the current tail atomically. If
  6730. the segment marker was already latched, the request remains
  6731. pending and is retargeted by the boundary event. */
  6732. if ((PlsrPulseActive != 0U)
  6733. && (PlsrStopRequested == 0U)
  6734. && (PlsrAbStopArmed == 0U)
  6735. && (PlsrRunStatus != PLSR_STATUS_WAITING)
  6736. && (PlsrCurrentSegment != 0U)
  6737. && (PlsrCurrentSegment
  6738. <= PlsrActiveConfig.segmentCount))
  6739. {
  6740. PlsrFrequencyUpdateSegment = PlsrCurrentSegment;
  6741. PlsrFrequencyUpdateTargetHz =
  6742. PlsrActiveConfig.segments[
  6743. PlsrCurrentSegment - 1U].frequencyHz;
  6744. PlsrFrequencyUpdatePending = 1U;
  6745. }
  6746. }
  6747. else if (updateActiveFrequencies != 0U)
  6748. {
  6749. PlsrHandoffPlan.valid = 0U;
  6750. PlsrProfileQueueInvalidateGeneration();
  6751. if ((drainedToDifferentSegment == 0U)
  6752. && (PlsrPulseActive != 0U)
  6753. && (PlsrAbStopArmed == 0U)
  6754. && (PlsrShortProfile.active == 0U)
  6755. && (PlsrRemainingPulses == 1UL))
  6756. {
  6757. (void)PlsrPrimeHandoff();
  6758. }
  6759. }
  6760. if ((drainedToDifferentSegment != 0U)
  6761. && (PlsrPulseActive != 0U)
  6762. && (PlsrCurrentSegment != 0U)
  6763. && (PlsrCurrentSegment <= PlsrActiveConfig.segmentCount)
  6764. && (PlsrStopRequested == 0U)
  6765. && (PlsrAbStopArmed == 0U)
  6766. && (PlsrRunStatus != PLSR_STATUS_WAITING)
  6767. && (PlsrCurrentFrequencyHz != drainedSegmentTargetHz))
  6768. {
  6769. PlsrFrequencyUpdateTargetHz =
  6770. drainedSegmentTargetHz;
  6771. PlsrFrequencyUpdateSegment = PlsrCurrentSegment;
  6772. PlsrFrequencyUpdatePending = 1U;
  6773. }
  6774. }
  6775. PlsrPlatformExitCritical(criticalState);
  6776. if ((updateActiveFrequencies != 0U)
  6777. && (PlsrPulseActive != 0U)
  6778. && (PlsrActiveConfig.outputMode != PLSR_OUTPUT_PULSE_DIR)
  6779. && (PlsrAbStopArmed == 0U)
  6780. && (PlsrFrequencyUpdatePending == 0U)
  6781. && (PlsrPrepareFutureHandoffQueue() == 0U))
  6782. {
  6783. PlsrTimerErrorPending = 1U;
  6784. }
  6785. if ((drainedToDifferentSegment != 0U)
  6786. && (PlsrAbStopArmed == 0U)
  6787. && (PlsrFrequencyUpdatePending != 0U))
  6788. {
  6789. uint32_t drainEpoch = PlsrSegmentEpoch;
  6790. uint32_t actualDrainFrequencyHz;
  6791. queueResult = PlsrDiagnosticQueueFrequency(
  6792. (uint8_t)PlsrActiveConfig.pulseOutput,
  6793. drainedSegmentTargetHz, &actualDrainFrequencyHz);
  6794. if (queueResult == PLSR_PLATFORM_QUEUE_FAILED)
  6795. {
  6796. PlsrTimerErrorPending = 1U;
  6797. }
  6798. else if (queueResult == PLSR_PLATFORM_QUEUE_APPLIED)
  6799. {
  6800. uint32_t currentEpoch;
  6801. uint8_t updateSegment;
  6802. uint8_t currentSegment;
  6803. criticalState = PlsrPlatformEnterCritical();
  6804. currentEpoch = PlsrSegmentEpoch;
  6805. updateSegment = PlsrFrequencyUpdateSegment;
  6806. currentSegment = PlsrCurrentSegment;
  6807. if ((currentEpoch == drainEpoch)
  6808. && (updateSegment == currentSegment))
  6809. {
  6810. PlsrQueuedFrequencyHz = actualDrainFrequencyHz;
  6811. PlsrFrequencyUpdatePending = 0U;
  6812. PlsrRamp.active = 0U;
  6813. PlsrRunStatus = PLSR_STATUS_RUNNING;
  6814. }
  6815. PlsrPlatformExitCritical(criticalState);
  6816. }
  6817. }
  6818. PlsrPlatformCheckpointConfig(&PlsrShadowConfig);
  6819. PlsrMarkPersistenceDirty(PLSR_CONFIG_SAVE_DELAY_MS);
  6820. return PLSR_MB_OK;
  6821. }
  6822. #ifdef PLSR_HOST_TEST
  6823. void PlsrTestSetPosition(int32_t position, uint8_t positionValid)
  6824. {
  6825. uint32_t criticalState = PlsrPlatformEnterCritical();
  6826. PlsrPosition = position;
  6827. PlsrPositionValid = (positionValid != 0U) ? 1U : 0U;
  6828. PlsrRemainingPulses = 0UL;
  6829. PlsrCommandRemainingPulses = 0ULL;
  6830. PlsrPositionCheckpointDirty = 0U;
  6831. PlsrPlatformExitCritical(criticalState);
  6832. PlsrPlatformCheckpointPosition(position, PlsrPositionValid, 0U);
  6833. }
  6834. void PlsrTestSetDiagnosticCurveCounts(uint32_t sampleCount,
  6835. uint32_t mismatchCount)
  6836. {
  6837. PlsrDiagnostic.curveSampleCount = sampleCount;
  6838. PlsrDiagnostic.curveMismatchCount = mismatchCount;
  6839. }
  6840. void PlsrTestForceProfileQueueEmpty(void)
  6841. {
  6842. PlsrProfileQueue.readIndex = PlsrProfileQueue.writeIndex;
  6843. PlsrProfileQueue.generatorComplete = 0U;
  6844. PlsrProfileQueue.active = 1U;
  6845. }
  6846. uint16_t PlsrTestProfileQueueCount(void)
  6847. {
  6848. return PlsrProfileQueueCount();
  6849. }
  6850. uint32_t PlsrTestProfileQueueGeneration(void)
  6851. {
  6852. return PlsrProfileQueue.generation;
  6853. }
  6854. uint32_t PlsrTestProfileQueueReadIndex(void)
  6855. {
  6856. return PlsrProfileQueue.readIndex;
  6857. }
  6858. uint32_t PlsrTestProfileQueueWriteIndex(void)
  6859. {
  6860. return PlsrProfileQueue.writeIndex;
  6861. }
  6862. uint32_t PlsrTestProfileQueueHeadFrequency(void)
  6863. {
  6864. uint32_t readIndex = PlsrProfileQueue.readIndex;
  6865. if (readIndex == PlsrProfileQueue.writeIndex)
  6866. {
  6867. return 0UL;
  6868. }
  6869. return PlsrProfileQueue
  6870. .entries[readIndex & PLSR_PROFILE_QUEUE_MASK].requestedFrequencyHz;
  6871. }
  6872. uint16_t PlsrTestProfileProducerNextPeriod(void)
  6873. {
  6874. return PlsrProfileQueue.producerProfile.nextPeriod;
  6875. }
  6876. uint16_t PlsrTestActiveProfileNextPeriod(void)
  6877. {
  6878. return PlsrShortProfile.nextPeriod;
  6879. }
  6880. uint32_t PlsrTestLastGateEvent(void)
  6881. {
  6882. return PlsrHostTestLastGateEvent;
  6883. }
  6884. uint32_t PlsrTestLastDiagnosticFinishEvent(void)
  6885. {
  6886. return PlsrHostTestLastDiagnosticFinishEvent;
  6887. }
  6888. uint8_t PlsrTestInitialDirectionPreparePending(void)
  6889. {
  6890. return PlsrInitialDirectionPreparePending;
  6891. }
  6892. #endif