25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 
 
 
 

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