Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 
 
 

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