Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 
 
 
 

7156 righe
239 KiB

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