Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 
 

4899 строки
153 KiB

  1. #include "plsr.h"
  2. #include "plsr_internal.h"
  3. #include "plsr_planner.h"
  4. #include "plsr_platform.h"
  5. #include <stddef.h>
  6. #include <string.h>
  7. #if defined(__ICCARM__)
  8. #include <intrinsics.h>
  9. #endif
  10. #define PLSR_COMMON_FIRST_ADDRESS (0x1000U)
  11. #define PLSR_COMMON_LAST_ADDRESS (0x10FFU)
  12. #define PLSR_SEGMENT_FIRST_ADDRESS (0x1100U)
  13. #define PLSR_SEGMENT_STRIDE (0x0010U)
  14. #define PLSR_SEGMENT_DEFINED_WORDS (8U)
  15. #define PLSR_WAIT_TIME (0U)
  16. #define PLSR_WAIT_SIGNAL (1U)
  17. #define PLSR_ACT_TIME (2U)
  18. #define PLSR_EXT_SIGNAL (3U)
  19. #define PLSR_EXT_OR_COMPLETE (4U)
  20. #define PLSR_SEND_COMPLETE (0U)
  21. #define PLSR_SEND_SUBSEQUENT (1U)
  22. #define PLSR_POSITION_RELATIVE (0U)
  23. #define PLSR_POSITION_ABSOLUTE (1U)
  24. #define PLSR_COMMAND_START (0x0001U)
  25. #define PLSR_COMMAND_STOP (0x0002U)
  26. #define PLSR_COMMAND_CLEAR (0x0004U)
  27. #define PLSR_DIAG_FLAG_MONITORING (0x0001U)
  28. #define PLSR_DIAG_FLAG_COUNT_CHECKED (0x0002U)
  29. #define PLSR_DIAG_FLAG_COUNT_PASS (0x0004U)
  30. #define PLSR_DIAG_FLAG_FREQUENCY_CHECKED (0x0008U)
  31. #define PLSR_DIAG_FLAG_FREQUENCY_PASS (0x0010U)
  32. #define PLSR_DIAG_FLAG_CURVE_CHECKED (0x0020U)
  33. #define PLSR_DIAG_FLAG_CURVE_PASS (0x0040U)
  34. #define PLSR_DIAG_FLAG_FAULT_LATCHED (0x0080U)
  35. #define PLSR_DIAG_REASON_NONE (0U)
  36. #define PLSR_DIAG_REASON_COUNT (1U)
  37. #define PLSR_DIAG_REASON_FREQUENCY (2U)
  38. #define PLSR_DIAG_REASON_CURVE (3U)
  39. #define PLSR_DIAG_REASON_INVALID_SAMPLE (4U)
  40. #define PLSR_CONFIG_SAVE_DELAY_MS (1000U)
  41. #define PLSR_POSITION_CHECKPOINT_MS (10U)
  42. #define PLSR_PROFILE_QUEUE_CAPACITY (1024U)
  43. #define PLSR_PROFILE_QUEUE_MASK (PLSR_PROFILE_QUEUE_CAPACITY - 1U)
  44. #define PLSR_HANDOFF_WARMUP_ITEMS (8U)
  45. #define PLSR_REPLAN_WARMUP_ITEMS (8U)
  46. #define PLSR_RAMP_POLL_RESERVE_AREA_DIVISOR (20ULL)
  47. /* 功能诊断(计数/频率/曲线检查)总开关。
  48. * 0 = 全部关闭:诊断采集、结算与锁定均不执行,Modbus 诊断寄存器保持全 0,
  49. * 诊断控制字写入仍被接受(无操作)。运动核心先行跑通;曲线校准阶段再置 1。 */
  50. #define PLSR_DIAGNOSTIC_ENABLED (0U)
  51. /* 计数错误停机检查:暂时关闭。counted 流计数同步与执行器重构对齐期间,
  52. * 实际输出与预期的偏差只做数据钳制(delta=remaining),不再进 PLSR_ERROR_COUNT。 */
  53. #define PLSR_COUNT_ERROR_CHECK_ENABLED (0U)
  54. typedef struct
  55. {
  56. uint32_t fromHz;
  57. uint32_t toHz;
  58. uint32_t durationMs;
  59. uint32_t elapsedMs;
  60. uint8_t active;
  61. } PLSR_RAMP;
  62. typedef struct
  63. {
  64. PLSR_PLANNER_CONTEXT planner;
  65. PLSR_STREAM_ITEM pendingItem;
  66. uint32_t startHz;
  67. uint32_t peakHz;
  68. uint32_t endHz;
  69. uint32_t pulseCount;
  70. uint32_t entryPulses;
  71. uint32_t steadyPulses;
  72. uint32_t exitPulses;
  73. volatile uint32_t nextPeriod;
  74. uint32_t pendingRepeats;
  75. uint32_t lastRampFrequencyHz;
  76. volatile uint8_t active;
  77. } PLSR_SHORT_PROFILE;
  78. typedef struct
  79. {
  80. PLSR_PLATFORM_TIMER_SETTING setting;
  81. uint32_t requestedFrequencyHz;
  82. uint32_t repeatCount;
  83. uint8_t startsNextSegment;
  84. } PLSR_PROFILE_ENTRY;
  85. typedef struct
  86. {
  87. PLSR_PROFILE_ENTRY entries[PLSR_PROFILE_QUEUE_CAPACITY];
  88. PLSR_SHORT_PROFILE producerProfile;
  89. volatile uint32_t readIndex;
  90. volatile uint32_t writeIndex;
  91. volatile uint32_t generation;
  92. uint32_t producerEpoch;
  93. volatile uint32_t repeatRemaining;
  94. uint8_t producerSegment;
  95. uint8_t preparedHandoffBank;
  96. volatile uint8_t active;
  97. volatile uint8_t generatorComplete;
  98. } PLSR_PROFILE_QUEUE;
  99. typedef struct
  100. {
  101. uint64_t magnitude;
  102. uint32_t firstFrequencyHz;
  103. uint32_t secondFrequencyHz;
  104. uint32_t firstRequestedFrequencyHz;
  105. uint32_t secondRequestedFrequencyHz;
  106. uint32_t firstRepeatCount;
  107. uint32_t secondRepeatCount;
  108. PLSR_PLATFORM_TIMER_SETTING firstSetting;
  109. PLSR_PLATFORM_TIMER_SETTING secondSetting;
  110. PLSR_PROFILE_ENTRY warmup[PLSR_HANDOFF_WARMUP_ITEMS];
  111. PLSR_SHORT_PROFILE profile;
  112. uint8_t warmupCount;
  113. uint8_t nextSegment;
  114. uint8_t positive;
  115. volatile uint8_t valid;
  116. } PLSR_HANDOFF_PLAN;
  117. typedef enum
  118. {
  119. PLSR_WORD_OK = 0,
  120. PLSR_WORD_ILLEGAL_ADDRESS,
  121. PLSR_WORD_ILLEGAL_VALUE
  122. } PLSR_WORD_RESULT;
  123. typedef enum
  124. {
  125. PLSR_COMMAND_MAILBOX_EMPTY = 0,
  126. PLSR_COMMAND_MAILBOX_PENDING,
  127. PLSR_COMMAND_MAILBOX_EXECUTING
  128. } PLSR_COMMAND_MAILBOX_STATE;
  129. typedef struct
  130. {
  131. PLSR_CONFIG startConfig;
  132. uint16_t command;
  133. volatile uint8_t state;
  134. } PLSR_COMMAND_MAILBOX;
  135. typedef struct
  136. {
  137. volatile PLSR_EXEC_MODE mode;
  138. volatile uint32_t generation;
  139. } PLSR_EXECUTOR;
  140. typedef struct
  141. {
  142. uint16_t flags;
  143. uint16_t reason;
  144. uint16_t lastSegment;
  145. uint16_t modeDirection;
  146. uint32_t expectedCycles;
  147. uint32_t observedCycles;
  148. int32_t countError;
  149. uint32_t requestedHz;
  150. uint32_t expectedTimerHz;
  151. uint32_t activeTimerHz;
  152. int32_t requestErrorHz;
  153. uint32_t curveSampleCount;
  154. uint32_t curveMismatchCount;
  155. uint32_t curveMaxAbsErrorHz;
  156. uint32_t firstMismatchSample;
  157. } PLSR_DIAGNOSTIC;
  158. static const uint16_t PlsrSineProgressQ16[65] =
  159. {
  160. 0U, 39U, 158U, 355U, 630U, 982U, 1411U, 1915U,
  161. 2494U, 3146U, 3869U, 4662U, 5522U, 6448U, 7438U, 8488U,
  162. 9597U, 10762U, 11980U, 13248U, 14563U, 15922U, 17321U,
  163. 18758U, 20228U, 21728U, 23256U, 24806U, 26375U, 27960U,
  164. 29556U, 31160U, 32767U, 34375U, 35979U, 37575U, 39160U,
  165. 40729U, 42279U, 43807U, 45307U, 46777U, 48214U, 49613U,
  166. 50972U, 52287U, 53555U, 54773U, 55938U, 57047U, 58097U,
  167. 59087U, 60013U, 60873U, 61666U, 62389U, 63041U, 63620U,
  168. 64124U, 64553U, 64905U, 65180U, 65377U, 65496U, 65535U
  169. };
  170. static PLSR_CONFIG PlsrShadowConfig;
  171. static PLSR_CONFIG PlsrActiveConfig;
  172. static PLSR_CONFIG PlsrCandidateConfig;
  173. static volatile int32_t PlsrPosition;
  174. static volatile uint64_t PlsrRemainingPulses;
  175. static volatile uint8_t PlsrPulseActive;
  176. static volatile uint8_t PlsrCutRequested;
  177. static volatile uint8_t PlsrBoundaryPending;
  178. static volatile uint8_t PlsrBoundaryWasCut;
  179. static volatile uint8_t PlsrCountPositive;
  180. static volatile uint8_t PlsrCountOverflowPending;
  181. static volatile uint8_t PlsrPositionValid;
  182. static volatile uint8_t PlsrPositionCheckpointDirty;
  183. static volatile uint8_t PlsrFrequencyUpdatePending;
  184. static volatile uint8_t PlsrFrequencyUpdateSegment;
  185. static volatile uint8_t PlsrSeamlessHandoffPending;
  186. static volatile uint8_t PlsrTimerErrorPending;
  187. static volatile uint8_t PlsrDeferredFrequencyPending;
  188. static volatile uint32_t PlsrCurrentFrequencyHz;
  189. static volatile uint32_t PlsrQueuedFrequencyHz;
  190. static volatile uint32_t PlsrBoundaryFrequencyHz;
  191. static volatile uint32_t PlsrFrequencyUpdateTargetHz;
  192. static volatile uint32_t PlsrDeferredFrequencyHz;
  193. static volatile uint32_t PlsrSegmentEpoch;
  194. static volatile PLSR_STATUS PlsrRunStatus = PLSR_STATUS_UNINITIALIZED;
  195. static PLSR_ERROR PlsrError = PLSR_ERROR_NONE;
  196. static PLSR_RAMP PlsrRamp;
  197. static PLSR_SHORT_PROFILE PlsrShortProfile;
  198. static PLSR_PROFILE_QUEUE PlsrProfileQueue;
  199. static PLSR_HANDOFF_PLAN PlsrHandoffPlan;
  200. static volatile uint64_t PlsrCountedObservedPublished;
  201. static volatile uint8_t PlsrCountedHandoffStaged;
  202. /* 段边界/流故障事件:IRQ 只置事件并快照(handoff 计划 + 边界累计计数),
  203. 全部簿记由 1ms 任务消费事件时完成(IRQ 内不做状态转换与错误标志写入)。 */
  204. static volatile uint8_t PlsrCountedBoundaryEvent;
  205. static volatile PLSR_HANDOFF_PLAN PlsrCountedBoundaryPlan;
  206. static volatile uint64_t PlsrCountedBoundaryObserved;
  207. static volatile uint8_t PlsrCountedFaultEvent;
  208. static PLSR_HANDOFF_PLAN
  209. PlsrPreparedHandoffPlans[2][PLSR_SEGMENT_COUNT_MAX];
  210. static volatile uint8_t PlsrPreparedHandoffBank;
  211. #ifdef PLSR_HOST_TEST
  212. static uint32_t PlsrHostTestEventSequence;
  213. static uint32_t PlsrHostTestLastGateEvent;
  214. static uint32_t PlsrHostTestLastDiagnosticFinishEvent;
  215. #endif
  216. static uint8_t PlsrInitialized;
  217. static volatile uint8_t PlsrCurrentSegment;
  218. static uint8_t PlsrDirectionDelayActive;
  219. static uint16_t PlsrDirectionDelayRemainingMs;
  220. static volatile uint8_t PlsrSegmentClockStarted;
  221. static volatile uint32_t PlsrSegmentElapsedMs;
  222. static volatile uint32_t PlsrWaitElapsedMs;
  223. static volatile uint8_t PlsrExtPreviousLevel;
  224. static volatile uint8_t PlsrExtEdgePending;
  225. static volatile uint8_t PlsrStopRequested;
  226. static volatile uint8_t PlsrStopPulsesRemaining;
  227. static volatile uint8_t PlsrAbStopArmed;
  228. static volatile uint8_t PlsrBoundaryRampStarted;
  229. static uint8_t PlsrLastDirectionValid;
  230. static uint8_t PlsrLastDirectionOutput;
  231. static uint8_t PlsrLastDirectionLevel;
  232. static uint8_t PlsrPersistenceDirty;
  233. static uint16_t PlsrPersistenceDelayMs;
  234. static uint8_t PlsrPositionCheckpointElapsedMs;
  235. static PLSR_COMMAND_MAILBOX PlsrCommandMailbox;
  236. static PLSR_EXECUTOR PlsrExecutor;
  237. static volatile PLSR_DIAGNOSTIC PlsrDiagnostic;
  238. static volatile uint64_t PlsrDiagnosticSegmentCounterBase;
  239. static volatile uint32_t PlsrDiagnosticQueuedExpectedHz;
  240. static volatile uint16_t PlsrDiagnosticFailedChecks;
  241. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0)
  242. volatile uint32_t PlsrProfileProducerItemCount;
  243. volatile uint32_t PlsrProfileProducerTotalCycles;
  244. volatile uint32_t PlsrProfileProducerMaxItemCycles;
  245. #endif
  246. static uint8_t PlsrIsBusy(void);
  247. static void PlsrSetDefaults(PLSR_CONFIG *config);
  248. static uint8_t PlsrConfigIsValid(const PLSR_CONFIG *config,
  249. uint8_t validateActivePath);
  250. static uint32_t PlsrResolvedSegmentFrequency(const PLSR_CONFIG *config,
  251. uint8_t segmentIndex);
  252. static uint16_t PlsrReadConfigWord(const PLSR_CONFIG *config,
  253. uint16_t address);
  254. static PLSR_WORD_RESULT PlsrWriteConfigWord(PLSR_CONFIG *config,
  255. uint16_t address,
  256. uint16_t value);
  257. static uint8_t PlsrAddressIsDwordHalf(uint16_t address,
  258. uint16_t *pairedAddress);
  259. static PLSR_MB_RESULT PlsrQueueCommand(uint16_t command);
  260. static uint8_t PlsrPollCommandMailbox(void);
  261. static void PlsrExecuteStart(void);
  262. static uint8_t PlsrExecuteStop(void);
  263. static void PlsrExecuteClear(void);
  264. static uint8_t PlsrStartSegment(uint8_t segmentNumber,
  265. uint8_t allowCarry,
  266. uint32_t carryFrequencyHz);
  267. static uint32_t PlsrEffectiveStartFrequency(uint32_t segmentFrequencyHz,
  268. uint8_t allowCarry,
  269. uint8_t directionChanged,
  270. uint32_t carryFrequencyHz);
  271. static uint32_t PlsrEffectiveStopFrequency(uint32_t segmentFrequencyHz);
  272. static uint8_t PlsrBeginSegmentOutput(uint32_t startFrequencyHz);
  273. static void PlsrHandleBoundary(uint8_t extEdge);
  274. static void PlsrTransitionToNext(uint8_t allowCarry);
  275. static void PlsrFinishCompleted(void);
  276. static void PlsrFinishStopped(void);
  277. static void PlsrEnterError(PLSR_ERROR error);
  278. static void PlsrEnterErrorIfEpoch(PLSR_ERROR error,
  279. uint32_t expectedEpoch);
  280. static void PlsrMarkPersistenceDirty(uint16_t delayMs);
  281. static void PlsrCheckpointPosition(uint8_t wasBusy);
  282. static void PlsrPollPositionCheckpoint(void);
  283. static PLSR_PLATFORM_QUEUE_RESULT PlsrTryContinuousHandoff(void);
  284. static uint8_t PlsrPrepareShortProfile(PLSR_SHORT_PROFILE *profile,
  285. uint8_t segmentNumber,
  286. uint32_t startFrequencyHz,
  287. uint32_t targetFrequencyHz,
  288. uint64_t pulseCount);
  289. static uint8_t PlsrShortProfileTakeRun(PLSR_SHORT_PROFILE *profile,
  290. PLSR_PROFILE_ENTRY *entry);
  291. static uint8_t PlsrReplanPulseDir(uint32_t targetHz,
  292. uint32_t totalPulses);
  293. static void PlsrProfileQueueReset(void);
  294. static void PlsrProfileQueueInvalidateGeneration(void);
  295. static uint8_t PlsrProfileQueueBegin(
  296. const PLSR_SHORT_PROFILE *producerProfile,
  297. uint32_t producerEpoch,
  298. uint8_t producerSegment,
  299. uint8_t preparedHandoffBank);
  300. static uint8_t PlsrProfileQueueFill(uint16_t targetCount);
  301. static uint8_t PlsrStageCountedHandoff(void);
  302. static PLSR_PLATFORM_QUEUE_RESULT PlsrProfileQueueCommitNext(
  303. uint8_t pulseOutput);
  304. static uint8_t PlsrPrepareFutureHandoffQueue(void);
  305. static void PlsrActivateHandoffQueueFromIrq(
  306. const PLSR_HANDOFF_PLAN *plan,
  307. uint32_t producerEpoch);
  308. static void PlsrCopyShortProfile(PLSR_SHORT_PROFILE *destination,
  309. const PLSR_SHORT_PROFILE *source);
  310. static void PlsrInvalidateHandoffPlans(void);
  311. static uint8_t PlsrBuildHandoffPlanBank(
  312. const PLSR_CONFIG *frequencyConfig);
  313. static uint8_t PlsrSelectPreparedHandoffPlan(PLSR_HANDOFF_PLAN *plan);
  314. static PLSR_PLATFORM_QUEUE_RESULT PlsrPrimeHandoff(void);
  315. static uint8_t PlsrBuildHandoffPlan(uint8_t sourceSegment,
  316. const PLSR_CONFIG *frequencyConfig,
  317. uint32_t carryFrequencyHz,
  318. PLSR_HANDOFF_PLAN *plan);
  319. static void PlsrRefreshCurrentHandoffPlan(uint32_t terminalFrequencyHz);
  320. static void PlsrDiagnosticReset(void);
  321. static void PlsrDiagnosticBeginSegment(uint8_t segmentNumber,
  322. uint64_t expectedCycles,
  323. uint8_t directionPositive);
  324. static void PlsrDiagnosticFinishSegment(uint8_t completedNormally);
  325. static uint8_t PlsrDiagnosticStartPulse(uint8_t pulseOutput,
  326. uint32_t requestedFirstHz,
  327. uint32_t requestedQueuedHz,
  328. uint32_t *actualFirstHz,
  329. uint32_t *actualQueuedHz);
  330. static PLSR_PLATFORM_QUEUE_RESULT PlsrDiagnosticQueueFrequency(
  331. uint8_t pulseOutput,
  332. uint32_t requestedHz,
  333. uint32_t *actualHz);
  334. static void PlsrDiagnosticCheckActiveFrequency(uint32_t activeHz);
  335. static uint8_t PlsrArmFinalAbBoundaryLocked(void);
  336. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  337. && !defined(PLSR_HOST_TEST)
  338. static uint32_t PlsrProfileTimingNow(void);
  339. #endif
  340. static uint8_t PlsrQueueFinalAbBoundaryFromIrq(void);
  341. static uint8_t PlsrIsBusy(void)
  342. {
  343. return ((PlsrRunStatus == PLSR_STATUS_ACCELERATING)
  344. || (PlsrRunStatus == PLSR_STATUS_RUNNING)
  345. || (PlsrRunStatus == PLSR_STATUS_DECELERATING)
  346. || (PlsrRunStatus == PLSR_STATUS_WAITING)
  347. || (PlsrRunStatus == PLSR_STATUS_PAUSED)) ? 1U : 0U;
  348. }
  349. static uint32_t PlsrJoinU32(uint16_t lowWord, uint16_t highWord)
  350. {
  351. return (uint32_t)lowWord | ((uint32_t)highWord << 16U);
  352. }
  353. static uint16_t PlsrLowWord(uint32_t value)
  354. {
  355. return (uint16_t)(value & 0xFFFFUL);
  356. }
  357. static uint16_t PlsrHighWord(uint32_t value)
  358. {
  359. return (uint16_t)(value >> 16U);
  360. }
  361. static uint8_t PlsrFinalAbBoundaryRequired(void)
  362. {
  363. uint8_t finalBoundary;
  364. if (PlsrActiveConfig.outputMode != PLSR_OUTPUT_AB)
  365. {
  366. return 0U;
  367. }
  368. finalBoundary = ((PlsrCutRequested != 0U)
  369. || ((PlsrStopRequested != 0U)
  370. && (PlsrStopPulsesRemaining == 1U))
  371. || ((PlsrRemainingPulses == 1UL)
  372. && (PlsrHandoffPlan.valid == 0U))) ? 1U : 0U;
  373. return ((PlsrPulseActive != 0U) && (finalBoundary != 0U)) ? 1U : 0U;
  374. }
  375. static uint8_t PlsrCompleteFinalAbArmLocked(void)
  376. {
  377. PLSR_PLATFORM_STOP_RESULT result;
  378. uint8_t pulseOutput = (uint8_t)PlsrActiveConfig.pulseOutput;
  379. result = PlsrPlatformRequestStopLocked(pulseOutput, 1U);
  380. if (result == PLSR_PLATFORM_STOP_PENDING)
  381. {
  382. PlsrQueuedFrequencyHz = PlsrCurrentFrequencyHz;
  383. PlsrDiagnosticQueuedExpectedHz = PlsrCurrentFrequencyHz;
  384. PlsrDeferredFrequencyHz = PlsrCurrentFrequencyHz;
  385. PlsrDeferredFrequencyPending = 0U;
  386. PlsrFrequencyUpdatePending = 0U;
  387. PlsrShortProfile.active = 0U;
  388. PlsrHandoffPlan.valid = 0U;
  389. PlsrRamp.active = 0U;
  390. return 1U;
  391. }
  392. PlsrTimerErrorPending = 1U;
  393. PlsrPlatformStopPulse(pulseOutput);
  394. PlsrAbStopArmed = 0U;
  395. PlsrPulseActive = 0U;
  396. PlsrBoundaryFrequencyHz = PlsrCurrentFrequencyHz;
  397. PlsrBoundaryWasCut = (PlsrCutRequested != 0U) ? 1U : 0U;
  398. PlsrCutRequested = 0U;
  399. PlsrCurrentFrequencyHz = 0UL;
  400. PlsrQueuedFrequencyHz = 0UL;
  401. PlsrBoundaryPending = 1U;
  402. return 0U;
  403. }
  404. static uint8_t PlsrArmFinalAbBoundaryLocked(void)
  405. {
  406. if (PlsrFinalAbBoundaryRequired() == 0U)
  407. {
  408. return 1U;
  409. }
  410. if (PlsrAbStopArmed != 0U)
  411. {
  412. return 1U;
  413. }
  414. PlsrAbStopArmed = 1U;
  415. return PlsrCompleteFinalAbArmLocked();
  416. }
  417. static uint8_t PlsrQueueFinalAbBoundaryFromIrq(void)
  418. {
  419. uint32_t criticalState;
  420. if ((PlsrFinalAbBoundaryRequired() == 0U)
  421. || (PlsrAbStopArmed != 0U))
  422. {
  423. return 1U;
  424. }
  425. PlsrAbStopArmed = 1U;
  426. if (PlsrPlatformQueueFinalArmFromIrq(
  427. (uint8_t)PlsrActiveConfig.pulseOutput) != 0U)
  428. {
  429. return 1U;
  430. }
  431. criticalState = PlsrPlatformEnterCritical();
  432. if ((PlsrAbStopArmed == 0U)
  433. || (PlsrFinalAbBoundaryRequired() == 0U))
  434. {
  435. PlsrPlatformExitCritical(criticalState);
  436. return 1U;
  437. }
  438. {
  439. uint8_t result = PlsrCompleteFinalAbArmLocked();
  440. PlsrPlatformExitCritical(criticalState);
  441. return result;
  442. }
  443. }
  444. void PlsrFinalArmJobIrq(uint8_t pulseOutput)
  445. {
  446. uint32_t criticalState = PlsrPlatformEnterCritical();
  447. if ((PlsrAbStopArmed == 0U) || (PlsrPulseActive == 0U)
  448. || (pulseOutput != (uint8_t)PlsrActiveConfig.pulseOutput)
  449. || (PlsrFinalAbBoundaryRequired() == 0U))
  450. {
  451. if ((PlsrPulseActive != 0U)
  452. && (pulseOutput == (uint8_t)PlsrActiveConfig.pulseOutput))
  453. {
  454. PlsrAbStopArmed = 0U;
  455. }
  456. PlsrPlatformExitCritical(criticalState);
  457. return;
  458. }
  459. (void)PlsrCompleteFinalAbArmLocked();
  460. PlsrPlatformExitCritical(criticalState);
  461. }
  462. #if PLSR_DIAGNOSTIC_ENABLED
  463. static uint32_t PlsrAbsDifferenceU32(uint32_t first, uint32_t second)
  464. {
  465. return (first >= second) ? (first - second) : (second - first);
  466. }
  467. static int32_t PlsrDifferenceI32(uint32_t first, uint32_t second)
  468. {
  469. int64_t difference = (int64_t)first - (int64_t)second;
  470. if (difference > INT32_MAX)
  471. {
  472. return INT32_MAX;
  473. }
  474. if (difference < INT32_MIN)
  475. {
  476. return INT32_MIN;
  477. }
  478. return (int32_t)difference;
  479. }
  480. #endif
  481. #if PLSR_DIAGNOSTIC_ENABLED
  482. static void PlsrDiagnosticLatch(uint16_t reason)
  483. {
  484. PlsrDiagnostic.flags |= PLSR_DIAG_FLAG_FAULT_LATCHED;
  485. if (PlsrDiagnostic.reason == PLSR_DIAG_REASON_NONE)
  486. {
  487. PlsrDiagnostic.reason = reason;
  488. }
  489. }
  490. #endif
  491. static void PlsrDiagnosticReset(void)
  492. {
  493. #if PLSR_DIAGNOSTIC_ENABLED
  494. (void)memset((void *)&PlsrDiagnostic, 0, sizeof(PlsrDiagnostic));
  495. PlsrDiagnostic.firstMismatchSample = 0xFFFFFFFFUL;
  496. PlsrDiagnosticSegmentCounterBase = 0UL;
  497. PlsrDiagnosticQueuedExpectedHz = 0UL;
  498. PlsrDiagnosticFailedChecks = 0U;
  499. #else
  500. /* 关闭状态保持诊断区清零,Modbus 读诊断寄存器恒为 0。 */
  501. (void)memset((void *)&PlsrDiagnostic, 0, sizeof(PlsrDiagnostic));
  502. #endif
  503. }
  504. static void PlsrDiagnosticBeginSegment(uint8_t segmentNumber,
  505. uint64_t expectedCycles,
  506. uint8_t directionPositive)
  507. {
  508. #if PLSR_DIAGNOSTIC_ENABLED
  509. if (expectedCycles > 0xFFFFFFFFUL)
  510. {
  511. PlsrDiagnostic.expectedCycles = 0xFFFFFFFFUL;
  512. PlsrDiagnosticLatch(PLSR_DIAG_REASON_INVALID_SAMPLE);
  513. }
  514. else
  515. {
  516. PlsrDiagnostic.expectedCycles = (uint32_t)expectedCycles;
  517. }
  518. PlsrDiagnostic.flags &= (uint16_t)~(PLSR_DIAG_FLAG_COUNT_CHECKED
  519. | PLSR_DIAG_FLAG_COUNT_PASS);
  520. PlsrDiagnostic.flags |= PLSR_DIAG_FLAG_MONITORING;
  521. PlsrDiagnostic.lastSegment = segmentNumber;
  522. PlsrDiagnostic.modeDirection =
  523. (uint16_t)(PlsrActiveConfig.outputMode
  524. | ((uint16_t)directionPositive << 8U));
  525. PlsrDiagnostic.observedCycles = 0UL;
  526. PlsrDiagnostic.countError = 0L;
  527. PlsrDiagnosticSegmentCounterBase = PlsrPlatformObservedPulses(
  528. (uint8_t)PlsrActiveConfig.pulseOutput);
  529. #else
  530. (void)segmentNumber;
  531. (void)expectedCycles;
  532. (void)directionPositive;
  533. #endif
  534. }
  535. static void PlsrDiagnosticFinishSegment(uint8_t completedNormally)
  536. {
  537. #if PLSR_DIAGNOSTIC_ENABLED
  538. uint64_t now;
  539. uint64_t observed;
  540. uint32_t observedCycles;
  541. uint32_t expectedCycles;
  542. if ((PlsrDiagnostic.flags & PLSR_DIAG_FLAG_MONITORING) == 0U)
  543. {
  544. return;
  545. }
  546. #ifdef PLSR_HOST_TEST
  547. PlsrHostTestEventSequence++;
  548. PlsrHostTestLastDiagnosticFinishEvent = PlsrHostTestEventSequence;
  549. #endif
  550. now = PlsrPlatformObservedPulses(
  551. (uint8_t)PlsrActiveConfig.pulseOutput);
  552. observed = (now >= PlsrDiagnosticSegmentCounterBase)
  553. ? (now - PlsrDiagnosticSegmentCounterBase) : 0UL;
  554. if (observed > 0xFFFFFFFFUL)
  555. {
  556. PlsrDiagnostic.observedCycles = 0xFFFFFFFFUL;
  557. PlsrDiagnosticFailedChecks |= PLSR_DIAG_FLAG_COUNT_PASS;
  558. PlsrDiagnostic.flags &= (uint16_t)~PLSR_DIAG_FLAG_COUNT_PASS;
  559. PlsrDiagnosticLatch(PLSR_DIAG_REASON_INVALID_SAMPLE);
  560. }
  561. else
  562. {
  563. PlsrDiagnostic.observedCycles = (uint32_t)observed;
  564. }
  565. PlsrDiagnostic.flags &= (uint16_t)~PLSR_DIAG_FLAG_MONITORING;
  566. if (completedNormally == 0U)
  567. {
  568. PlsrDiagnostic.countError = 0L;
  569. PlsrDiagnostic.flags &= (uint16_t)~(PLSR_DIAG_FLAG_COUNT_CHECKED
  570. | PLSR_DIAG_FLAG_COUNT_PASS);
  571. return;
  572. }
  573. observedCycles = PlsrDiagnostic.observedCycles;
  574. expectedCycles = PlsrDiagnostic.expectedCycles;
  575. PlsrDiagnostic.countError =
  576. PlsrDifferenceI32(observedCycles, expectedCycles);
  577. PlsrDiagnostic.flags |= PLSR_DIAG_FLAG_COUNT_CHECKED;
  578. if (PlsrDiagnostic.countError != 0L)
  579. {
  580. PlsrDiagnosticFailedChecks |= PLSR_DIAG_FLAG_COUNT_PASS;
  581. PlsrDiagnostic.flags &= (uint16_t)~PLSR_DIAG_FLAG_COUNT_PASS;
  582. PlsrDiagnosticLatch(PLSR_DIAG_REASON_COUNT);
  583. }
  584. else if ((PlsrDiagnosticFailedChecks & PLSR_DIAG_FLAG_COUNT_PASS) == 0U)
  585. {
  586. PlsrDiagnostic.flags |= PLSR_DIAG_FLAG_COUNT_PASS;
  587. }
  588. #else
  589. (void)completedNormally;
  590. #endif
  591. }
  592. static void PlsrDiagnosticRecordFrequency(uint32_t requestedHz,
  593. uint32_t expectedHz,
  594. uint32_t actualHz)
  595. {
  596. #if PLSR_DIAGNOSTIC_ENABLED
  597. uint32_t error = PlsrAbsDifferenceU32(actualHz, expectedHz);
  598. PlsrDiagnostic.requestedHz = requestedHz;
  599. PlsrDiagnostic.expectedTimerHz = expectedHz;
  600. PlsrDiagnostic.activeTimerHz = actualHz;
  601. /* Request error is divider quantization, not a diagnostic deviation. */
  602. PlsrDiagnostic.requestErrorHz = PlsrDifferenceI32(expectedHz, requestedHz);
  603. PlsrDiagnostic.flags |= PLSR_DIAG_FLAG_FREQUENCY_CHECKED;
  604. if (actualHz != expectedHz)
  605. {
  606. PlsrDiagnosticFailedChecks |= PLSR_DIAG_FLAG_FREQUENCY_PASS;
  607. PlsrDiagnostic.flags &= (uint16_t)~PLSR_DIAG_FLAG_FREQUENCY_PASS;
  608. PlsrDiagnosticLatch(PLSR_DIAG_REASON_FREQUENCY);
  609. }
  610. else if ((PlsrDiagnosticFailedChecks
  611. & PLSR_DIAG_FLAG_FREQUENCY_PASS) == 0U)
  612. {
  613. PlsrDiagnostic.flags |= PLSR_DIAG_FLAG_FREQUENCY_PASS;
  614. }
  615. if (error > PlsrDiagnostic.curveMaxAbsErrorHz)
  616. {
  617. PlsrDiagnostic.curveMaxAbsErrorHz = error;
  618. }
  619. #else
  620. (void)requestedHz;
  621. (void)expectedHz;
  622. (void)actualHz;
  623. #endif
  624. }
  625. #if PLSR_DIAGNOSTIC_ENABLED
  626. static void PlsrDiagnosticRecordCurveSample(uint32_t expectedHz,
  627. uint32_t actualHz)
  628. {
  629. uint32_t error = PlsrAbsDifferenceU32(expectedHz, actualHz);
  630. if (PlsrDiagnostic.curveSampleCount != 0xFFFFFFFFUL)
  631. {
  632. PlsrDiagnostic.curveSampleCount++;
  633. }
  634. PlsrDiagnostic.flags |= PLSR_DIAG_FLAG_CURVE_CHECKED;
  635. if (error == 0UL)
  636. {
  637. if ((PlsrDiagnosticFailedChecks & PLSR_DIAG_FLAG_CURVE_PASS) == 0U)
  638. {
  639. PlsrDiagnostic.flags |= PLSR_DIAG_FLAG_CURVE_PASS;
  640. }
  641. }
  642. else
  643. {
  644. PlsrDiagnosticFailedChecks |= PLSR_DIAG_FLAG_CURVE_PASS;
  645. PlsrDiagnostic.flags &= (uint16_t)~PLSR_DIAG_FLAG_CURVE_PASS;
  646. if (PlsrDiagnostic.curveMismatchCount != 0xFFFFFFFFUL)
  647. {
  648. PlsrDiagnostic.curveMismatchCount++;
  649. }
  650. if (PlsrDiagnostic.firstMismatchSample == 0xFFFFFFFFUL)
  651. {
  652. PlsrDiagnostic.firstMismatchSample =
  653. PlsrDiagnostic.curveSampleCount;
  654. }
  655. if (error > PlsrDiagnostic.curveMaxAbsErrorHz)
  656. {
  657. PlsrDiagnostic.curveMaxAbsErrorHz = error;
  658. }
  659. PlsrDiagnosticLatch(PLSR_DIAG_REASON_CURVE);
  660. }
  661. }
  662. #endif
  663. static uint8_t PlsrDiagnosticStartPulse(uint8_t pulseOutput,
  664. uint32_t requestedFirstHz,
  665. uint32_t requestedQueuedHz,
  666. uint32_t *actualFirstHz,
  667. uint32_t *actualQueuedHz)
  668. {
  669. PLSR_PLATFORM_TIMER_SETTING firstSetting;
  670. PLSR_PLATFORM_TIMER_SETTING queuedSetting;
  671. if ((PlsrPlatformBuildTimerSetting(
  672. pulseOutput, (uint8_t)PlsrActiveConfig.outputMode,
  673. requestedFirstHz, &firstSetting) == 0U)
  674. || (PlsrPlatformBuildTimerSetting(
  675. pulseOutput, (uint8_t)PlsrActiveConfig.outputMode,
  676. requestedQueuedHz, &queuedSetting) == 0U)
  677. || (PlsrPlatformStartPrepared(pulseOutput, &firstSetting,
  678. &queuedSetting, actualFirstHz,
  679. actualQueuedHz) == 0U))
  680. {
  681. PlsrDiagnosticFinishSegment(0U);
  682. return 0U;
  683. }
  684. #if PLSR_DIAGNOSTIC_ENABLED
  685. PlsrDiagnosticRecordFrequency(requestedFirstHz,
  686. firstSetting.actualFrequencyHz,
  687. *actualFirstHz);
  688. PlsrDiagnosticRecordCurveSample(firstSetting.actualFrequencyHz,
  689. *actualFirstHz);
  690. PlsrDiagnosticQueuedExpectedHz = queuedSetting.actualFrequencyHz;
  691. #endif
  692. return 1U;
  693. }
  694. static PLSR_PLATFORM_QUEUE_RESULT PlsrDiagnosticQueueFrequency(
  695. uint8_t pulseOutput,
  696. uint32_t requestedHz,
  697. uint32_t *actualHz)
  698. {
  699. PLSR_PLATFORM_QUEUE_RESULT result;
  700. #if PLSR_DIAGNOSTIC_ENABLED
  701. uint32_t expectedHz;
  702. if (PlsrPlatformExpectedFrequency(
  703. pulseOutput, (uint8_t)PlsrActiveConfig.outputMode,
  704. requestedHz, &expectedHz) == 0U)
  705. {
  706. PlsrDiagnosticFinishSegment(0U);
  707. return PLSR_PLATFORM_QUEUE_FAILED;
  708. }
  709. #endif
  710. result = PlsrPlatformQueueFrequency(pulseOutput, requestedHz, actualHz);
  711. if (result == PLSR_PLATFORM_QUEUE_FAILED)
  712. {
  713. PlsrDiagnosticFinishSegment(0U);
  714. return result;
  715. }
  716. if (result == PLSR_PLATFORM_QUEUE_STALE)
  717. {
  718. return result;
  719. }
  720. #if PLSR_DIAGNOSTIC_ENABLED
  721. PlsrDiagnosticRecordFrequency(requestedHz, expectedHz, *actualHz);
  722. PlsrDiagnosticQueuedExpectedHz = expectedHz;
  723. #endif
  724. return PLSR_PLATFORM_QUEUE_APPLIED;
  725. }
  726. static void PlsrDiagnosticCheckActiveFrequency(uint32_t activeHz)
  727. {
  728. #if PLSR_DIAGNOSTIC_ENABLED
  729. uint16_t platformFault = PlsrPlatformDiagnosticFault();
  730. uint32_t observedHz = activeHz;
  731. if (platformFault == PLSR_DIAG_REASON_FREQUENCY)
  732. {
  733. observedHz = PlsrPlatformActiveFrequency(
  734. (uint8_t)PlsrActiveConfig.pulseOutput);
  735. if (observedHz == 0UL)
  736. {
  737. observedHz = activeHz;
  738. }
  739. PlsrDiagnosticFailedChecks |= PLSR_DIAG_FLAG_FREQUENCY_PASS;
  740. PlsrDiagnostic.flags |= PLSR_DIAG_FLAG_FREQUENCY_CHECKED;
  741. PlsrDiagnostic.flags &= (uint16_t)~PLSR_DIAG_FLAG_FREQUENCY_PASS;
  742. PlsrDiagnosticLatch(PLSR_DIAG_REASON_FREQUENCY);
  743. }
  744. if ((platformFault != PLSR_DIAG_REASON_NONE)
  745. && (PlsrDiagnosticQueuedExpectedHz != 0UL))
  746. {
  747. PlsrDiagnostic.activeTimerHz = observedHz;
  748. if (platformFault == PLSR_DIAG_REASON_CURVE)
  749. {
  750. if (PlsrDiagnostic.curveSampleCount != 0xFFFFFFFFUL)
  751. {
  752. PlsrDiagnostic.curveSampleCount++;
  753. }
  754. PlsrDiagnostic.flags |= PLSR_DIAG_FLAG_CURVE_CHECKED;
  755. PlsrDiagnostic.flags &= (uint16_t)~PLSR_DIAG_FLAG_CURVE_PASS;
  756. PlsrDiagnosticFailedChecks |= PLSR_DIAG_FLAG_CURVE_PASS;
  757. if (PlsrDiagnostic.curveMismatchCount != 0xFFFFFFFFUL)
  758. {
  759. PlsrDiagnostic.curveMismatchCount++;
  760. }
  761. if (PlsrDiagnostic.firstMismatchSample == 0xFFFFFFFFUL)
  762. {
  763. PlsrDiagnostic.firstMismatchSample =
  764. PlsrDiagnostic.curveSampleCount;
  765. }
  766. PlsrDiagnosticLatch(PLSR_DIAG_REASON_CURVE);
  767. }
  768. else if (platformFault == PLSR_DIAG_REASON_FREQUENCY)
  769. {
  770. PlsrDiagnosticRecordCurveSample(PlsrDiagnosticQueuedExpectedHz,
  771. observedHz);
  772. }
  773. }
  774. #else
  775. (void)activeHz;
  776. #endif
  777. }
  778. static void PlsrSetDefaults(PLSR_CONFIG *config)
  779. {
  780. uint8_t index;
  781. (void)memset(config, 0, sizeof(*config));
  782. config->pulseOutput = 0U;
  783. config->directionOutput = 0U;
  784. config->waitInput = 0U;
  785. config->extInput = 0U;
  786. config->sendMode = PLSR_SEND_COMPLETE;
  787. config->directionDelayMs = 10U;
  788. config->directionNegativeLogic = 0U;
  789. config->curveMode = 0U;
  790. config->positionMode = PLSR_POSITION_RELATIVE;
  791. config->segmentCount = 1U;
  792. config->startSegment = 1U;
  793. config->defaultSpeedHz = 1000UL;
  794. config->startSpeedHz = 100UL;
  795. config->stopSpeedHz = 100UL;
  796. config->accelerationTimeMs = 100U;
  797. config->decelerationTimeMs = 100U;
  798. config->outputMode = PLSR_OUTPUT_PULSE_DIR;
  799. for (index = 0U; index < PLSR_SEGMENT_COUNT_MAX; index++)
  800. {
  801. config->segments[index].frequencyHz = 1000UL;
  802. config->segments[index].pulses = (index == 0U) ? 1000L : 0L;
  803. config->segments[index].waitType = PLSR_EXT_OR_COMPLETE;
  804. config->segments[index].waitTimeMs = 0U;
  805. config->segments[index].actTimeMs = 0U;
  806. config->segments[index].jumpSegment = 0U;
  807. }
  808. }
  809. static uint8_t PlsrConfigIsValid(const PLSR_CONFIG *config,
  810. uint8_t validateActivePath)
  811. {
  812. uint8_t index;
  813. if ((config->pulseOutput > 3U) || (config->directionOutput > 3U)
  814. || (config->waitInput > 1U) || (config->extInput > 1U)
  815. || (config->sendMode > PLSR_SEND_SUBSEQUENT)
  816. || (config->directionNegativeLogic > 1U)
  817. || (config->curveMode > 2U)
  818. || (config->positionMode > PLSR_POSITION_ABSOLUTE)
  819. || (config->outputMode > PLSR_OUTPUT_AB)
  820. || ((config->outputMode == PLSR_OUTPUT_AB)
  821. && ((config->pulseOutput & 1U) != 0U))
  822. || (config->segmentCount == 0U)
  823. || (config->segmentCount > PLSR_SEGMENT_COUNT_MAX)
  824. || (config->startSegment == 0U)
  825. || (config->startSegment > PLSR_SEGMENT_COUNT_MAX)
  826. || (config->defaultSpeedHz == 0UL)
  827. || (config->defaultSpeedHz > PLSR_FREQUENCY_MAX_HZ)
  828. || (config->startSpeedHz > PLSR_FREQUENCY_MAX_HZ)
  829. || (config->stopSpeedHz > PLSR_FREQUENCY_MAX_HZ))
  830. {
  831. return 0U;
  832. }
  833. if ((validateActivePath != 0U)
  834. && (config->startSegment > config->segmentCount))
  835. {
  836. return 0U;
  837. }
  838. for (index = 0U; index < PLSR_SEGMENT_COUNT_MAX; index++)
  839. {
  840. const PLSR_SEGMENT_CONFIG *segment = &config->segments[index];
  841. if ((segment->frequencyHz > PLSR_FREQUENCY_MAX_HZ)
  842. || (segment->waitType > PLSR_EXT_OR_COMPLETE)
  843. || (segment->jumpSegment > PLSR_SEGMENT_COUNT_MAX))
  844. {
  845. return 0U;
  846. }
  847. if ((validateActivePath != 0U)
  848. && (index < config->segmentCount)
  849. && (segment->jumpSegment > config->segmentCount))
  850. {
  851. return 0U;
  852. }
  853. }
  854. return 1U;
  855. }
  856. static uint16_t PlsrReadConfigWord(const PLSR_CONFIG *config,
  857. uint16_t address)
  858. {
  859. uint16_t offset;
  860. uint8_t segmentIndex;
  861. const PLSR_SEGMENT_CONFIG *segment;
  862. switch (address)
  863. {
  864. case 0x1000U: return config->pulseOutput;
  865. case 0x1001U: return config->directionOutput;
  866. case 0x1002U: return config->waitInput;
  867. case 0x1003U: return config->extInput;
  868. case 0x1004U: return config->sendMode;
  869. case 0x1005U: return config->directionDelayMs;
  870. case 0x1006U: return config->directionNegativeLogic;
  871. case 0x1007U: return config->curveMode;
  872. case 0x1008U: return config->positionMode;
  873. case 0x1009U: return config->segmentCount;
  874. case 0x100AU: return config->startSegment;
  875. case 0x100BU: return PlsrLowWord(config->defaultSpeedHz);
  876. case 0x100CU: return PlsrHighWord(config->defaultSpeedHz);
  877. case 0x100DU: return PlsrLowWord(config->startSpeedHz);
  878. case 0x100EU: return PlsrHighWord(config->startSpeedHz);
  879. case 0x1010U: return PlsrLowWord(config->stopSpeedHz);
  880. case 0x1011U: return PlsrHighWord(config->stopSpeedHz);
  881. case 0x1012U: return config->accelerationTimeMs;
  882. case 0x1013U: return config->decelerationTimeMs;
  883. default: break;
  884. }
  885. if ((address >= PLSR_SEGMENT_FIRST_ADDRESS)
  886. && (address <= PLSR_CONFIG_LAST_ADDRESS))
  887. {
  888. offset = (uint16_t)(address - PLSR_SEGMENT_FIRST_ADDRESS);
  889. segmentIndex = (uint8_t)(offset / PLSR_SEGMENT_STRIDE);
  890. offset = (uint16_t)(offset % PLSR_SEGMENT_STRIDE);
  891. segment = &config->segments[segmentIndex];
  892. switch (offset)
  893. {
  894. case 0U: return PlsrLowWord(segment->frequencyHz);
  895. case 1U: return PlsrHighWord(segment->frequencyHz);
  896. case 2U: return PlsrLowWord((uint32_t)segment->pulses);
  897. case 3U: return PlsrHighWord((uint32_t)segment->pulses);
  898. case 4U: return segment->waitType;
  899. case 5U: return segment->waitTimeMs;
  900. case 6U: return segment->actTimeMs;
  901. case 7U: return segment->jumpSegment;
  902. default: return 0U;
  903. }
  904. }
  905. /* 0x100F, 0x1014..0x10FF, and segment padding read as zero. */
  906. return 0U;
  907. }
  908. static PLSR_WORD_RESULT PlsrWriteConfigWord(PLSR_CONFIG *config,
  909. uint16_t address,
  910. uint16_t value)
  911. {
  912. uint16_t offset;
  913. uint8_t segmentIndex;
  914. PLSR_SEGMENT_CONFIG *segment;
  915. switch (address)
  916. {
  917. case 0x1000U: config->pulseOutput = value; return PLSR_WORD_OK;
  918. case 0x1001U: config->directionOutput = value; return PLSR_WORD_OK;
  919. case 0x1002U: config->waitInput = value; return PLSR_WORD_OK;
  920. case 0x1003U: config->extInput = value; return PLSR_WORD_OK;
  921. case 0x1004U: config->sendMode = value; return PLSR_WORD_OK;
  922. case 0x1005U: config->directionDelayMs = value; return PLSR_WORD_OK;
  923. case 0x1006U:
  924. config->directionNegativeLogic = value;
  925. return PLSR_WORD_OK;
  926. case 0x1007U: config->curveMode = value; return PLSR_WORD_OK;
  927. case 0x1008U: config->positionMode = value; return PLSR_WORD_OK;
  928. case 0x1009U: config->segmentCount = value; return PLSR_WORD_OK;
  929. case 0x100AU: config->startSegment = value; return PLSR_WORD_OK;
  930. case 0x100BU:
  931. config->defaultSpeedHz =
  932. PlsrJoinU32(value, PlsrHighWord(config->defaultSpeedHz));
  933. return PLSR_WORD_OK;
  934. case 0x100CU:
  935. config->defaultSpeedHz =
  936. PlsrJoinU32(PlsrLowWord(config->defaultSpeedHz), value);
  937. return PLSR_WORD_OK;
  938. case 0x100DU:
  939. config->startSpeedHz =
  940. PlsrJoinU32(value, PlsrHighWord(config->startSpeedHz));
  941. return PLSR_WORD_OK;
  942. case 0x100EU:
  943. config->startSpeedHz =
  944. PlsrJoinU32(PlsrLowWord(config->startSpeedHz), value);
  945. return PLSR_WORD_OK;
  946. case 0x100FU:
  947. return (value == 0U) ? PLSR_WORD_OK : PLSR_WORD_ILLEGAL_VALUE;
  948. case 0x1010U:
  949. config->stopSpeedHz =
  950. PlsrJoinU32(value, PlsrHighWord(config->stopSpeedHz));
  951. return PLSR_WORD_OK;
  952. case 0x1011U:
  953. config->stopSpeedHz =
  954. PlsrJoinU32(PlsrLowWord(config->stopSpeedHz), value);
  955. return PLSR_WORD_OK;
  956. case 0x1012U:
  957. config->accelerationTimeMs = value;
  958. return PLSR_WORD_OK;
  959. case 0x1013U:
  960. config->decelerationTimeMs = value;
  961. return PLSR_WORD_OK;
  962. default: break;
  963. }
  964. if ((address >= 0x1014U) && (address <= PLSR_COMMON_LAST_ADDRESS))
  965. {
  966. return (value == 0U) ? PLSR_WORD_OK : PLSR_WORD_ILLEGAL_VALUE;
  967. }
  968. if ((address < PLSR_SEGMENT_FIRST_ADDRESS)
  969. || (address > PLSR_CONFIG_LAST_ADDRESS))
  970. {
  971. return PLSR_WORD_ILLEGAL_ADDRESS;
  972. }
  973. offset = (uint16_t)(address - PLSR_SEGMENT_FIRST_ADDRESS);
  974. segmentIndex = (uint8_t)(offset / PLSR_SEGMENT_STRIDE);
  975. offset = (uint16_t)(offset % PLSR_SEGMENT_STRIDE);
  976. segment = &config->segments[segmentIndex];
  977. switch (offset)
  978. {
  979. case 0U:
  980. segment->frequencyHz =
  981. PlsrJoinU32(value, PlsrHighWord(segment->frequencyHz));
  982. return PLSR_WORD_OK;
  983. case 1U:
  984. segment->frequencyHz =
  985. PlsrJoinU32(PlsrLowWord(segment->frequencyHz), value);
  986. return PLSR_WORD_OK;
  987. case 2U:
  988. segment->pulses = (int32_t)PlsrJoinU32(
  989. value, PlsrHighWord((uint32_t)segment->pulses));
  990. return PLSR_WORD_OK;
  991. case 3U:
  992. segment->pulses = (int32_t)PlsrJoinU32(
  993. PlsrLowWord((uint32_t)segment->pulses), value);
  994. return PLSR_WORD_OK;
  995. case 4U: segment->waitType = value; return PLSR_WORD_OK;
  996. case 5U: segment->waitTimeMs = value; return PLSR_WORD_OK;
  997. case 6U: segment->actTimeMs = value; return PLSR_WORD_OK;
  998. case 7U: segment->jumpSegment = value; return PLSR_WORD_OK;
  999. default:
  1000. return (value == 0U) ? PLSR_WORD_OK : PLSR_WORD_ILLEGAL_VALUE;
  1001. }
  1002. }
  1003. static uint8_t PlsrAddressIsDwordHalf(uint16_t address,
  1004. uint16_t *pairedAddress)
  1005. {
  1006. uint16_t offset;
  1007. switch (address)
  1008. {
  1009. case 0x100BU: case 0x100DU: case 0x1010U:
  1010. *pairedAddress = (uint16_t)(address + 1U);
  1011. return 1U;
  1012. case 0x100CU: case 0x100EU: case 0x1011U:
  1013. *pairedAddress = (uint16_t)(address - 1U);
  1014. return 1U;
  1015. default: break;
  1016. }
  1017. if ((address >= PLSR_SEGMENT_FIRST_ADDRESS)
  1018. && (address <= PLSR_CONFIG_LAST_ADDRESS))
  1019. {
  1020. offset = (uint16_t)((address - PLSR_SEGMENT_FIRST_ADDRESS)
  1021. % PLSR_SEGMENT_STRIDE);
  1022. if ((offset == 0U) || (offset == 2U))
  1023. {
  1024. *pairedAddress = (uint16_t)(address + 1U);
  1025. return 1U;
  1026. }
  1027. if ((offset == 1U) || (offset == 3U))
  1028. {
  1029. *pairedAddress = (uint16_t)(address - 1U);
  1030. return 1U;
  1031. }
  1032. }
  1033. return 0U;
  1034. }
  1035. static uint8_t PlsrAddressIsProduct(uint16_t address)
  1036. {
  1037. return (((address >= PLSR_CONFIG_FIRST_ADDRESS)
  1038. && (address <= PLSR_CONFIG_LAST_ADDRESS))
  1039. || (address == PLSR_OUTPUT_MODE_ADDRESS)
  1040. || ((address >= PLSR_STATUS_FIRST_ADDRESS)
  1041. && (address <= PLSR_STATUS_LAST_ADDRESS))
  1042. || ((address >= PLSR_DIAGNOSTIC_FIRST_ADDRESS)
  1043. && (address <= PLSR_DIAGNOSTIC_LAST_ADDRESS))
  1044. || (address == PLSR_CONTROL_ADDRESS)
  1045. || (address == PLSR_DIAGNOSTIC_CONTROL_ADDRESS)) ? 1U : 0U;
  1046. }
  1047. static PLSR_MB_RESULT PlsrClassifyRange(uint16_t startAddress,
  1048. uint16_t quantity)
  1049. {
  1050. uint32_t address;
  1051. uint32_t endAddress;
  1052. uint8_t foundProduct = 0U;
  1053. uint8_t foundOther = 0U;
  1054. if (quantity == 0U)
  1055. {
  1056. return PLSR_MB_ILLEGAL_VALUE;
  1057. }
  1058. endAddress = (uint32_t)startAddress + (uint32_t)quantity - 1UL;
  1059. if (endAddress > 0xFFFFUL)
  1060. {
  1061. return PLSR_MB_ILLEGAL_ADDRESS;
  1062. }
  1063. for (address = startAddress; address <= endAddress; address++)
  1064. {
  1065. if (PlsrAddressIsProduct((uint16_t)address) != 0U)
  1066. {
  1067. foundProduct = 1U;
  1068. }
  1069. else
  1070. {
  1071. foundOther = 1U;
  1072. }
  1073. }
  1074. if (foundProduct == 0U)
  1075. {
  1076. return PLSR_MB_NOT_HANDLED;
  1077. }
  1078. return (foundOther != 0U) ? PLSR_MB_ILLEGAL_ADDRESS : PLSR_MB_OK;
  1079. }
  1080. static uint32_t PlsrCurveProgressQ16(uint32_t elapsed,
  1081. uint32_t duration,
  1082. uint16_t curveMode)
  1083. {
  1084. uint32_t linear;
  1085. if ((duration == 0UL) || (elapsed >= duration))
  1086. {
  1087. return 65535UL;
  1088. }
  1089. linear = (uint32_t)(((uint64_t)elapsed * 65535UL) / duration);
  1090. if (curveMode == 1U)
  1091. {
  1092. uint64_t x = linear;
  1093. uint64_t x2 = (x * x) / 65535UL;
  1094. return (uint32_t)((x2 * (196605UL - 2UL * x)) / 65535UL);
  1095. }
  1096. if (curveMode == 2U)
  1097. {
  1098. uint32_t scaled = linear * 64UL;
  1099. uint32_t index = scaled / 65535UL;
  1100. uint32_t fraction = scaled % 65535UL;
  1101. uint32_t first;
  1102. uint32_t second;
  1103. if (index >= 64UL)
  1104. {
  1105. return 65535UL;
  1106. }
  1107. first = PlsrSineProgressQ16[index];
  1108. second = PlsrSineProgressQ16[index + 1UL];
  1109. return first + (uint32_t)(((uint64_t)(second - first) * fraction)
  1110. / 65535UL);
  1111. }
  1112. return linear;
  1113. }
  1114. static uint32_t PlsrRampDurationMs(uint32_t fromHz, uint32_t toHz)
  1115. {
  1116. uint32_t gap;
  1117. uint32_t baseTimeMs;
  1118. uint64_t duration;
  1119. if (fromHz == toHz)
  1120. {
  1121. return 0UL;
  1122. }
  1123. gap = (fromHz > toHz) ? (fromHz - toHz) : (toHz - fromHz);
  1124. baseTimeMs = (toHz > fromHz) ? PlsrActiveConfig.accelerationTimeMs
  1125. : PlsrActiveConfig.decelerationTimeMs;
  1126. if (baseTimeMs == 0UL)
  1127. {
  1128. return 0UL;
  1129. }
  1130. duration = ((uint64_t)gap * baseTimeMs
  1131. + PlsrActiveConfig.defaultSpeedHz - 1UL)
  1132. / PlsrActiveConfig.defaultSpeedHz;
  1133. if (duration > 0xFFFFFFFFUL)
  1134. {
  1135. return 0xFFFFFFFFUL;
  1136. }
  1137. return (uint32_t)duration;
  1138. }
  1139. static uint32_t PlsrEffectiveStartFrequency(uint32_t segmentFrequencyHz,
  1140. uint8_t allowCarry,
  1141. uint8_t directionChanged,
  1142. uint32_t carryFrequencyHz)
  1143. {
  1144. if ((allowCarry != 0U) && (directionChanged == 0U)
  1145. && (carryFrequencyHz != 0UL))
  1146. {
  1147. return carryFrequencyHz;
  1148. }
  1149. if (PlsrActiveConfig.accelerationTimeMs == 0U)
  1150. {
  1151. return segmentFrequencyHz;
  1152. }
  1153. return PlsrActiveConfig.startSpeedHz;
  1154. }
  1155. static uint32_t PlsrEffectiveStopFrequency(uint32_t segmentFrequencyHz)
  1156. {
  1157. return (PlsrActiveConfig.decelerationTimeMs == 0U)
  1158. ? segmentFrequencyHz : PlsrActiveConfig.stopSpeedHz;
  1159. }
  1160. static void PlsrRampStart(uint32_t fromHz, uint32_t toHz)
  1161. {
  1162. PlsrRamp.fromHz = fromHz;
  1163. PlsrRamp.toHz = toHz;
  1164. PlsrRamp.durationMs = PlsrRampDurationMs(fromHz, toHz);
  1165. PlsrRamp.elapsedMs = 0UL;
  1166. PlsrRamp.active = (PlsrRamp.durationMs != 0UL) ? 1U : 0U;
  1167. if (toHz > fromHz)
  1168. {
  1169. PlsrRunStatus = PLSR_STATUS_ACCELERATING;
  1170. }
  1171. else if (toHz < fromHz)
  1172. {
  1173. PlsrRunStatus = PLSR_STATUS_DECELERATING;
  1174. }
  1175. else
  1176. {
  1177. PlsrRunStatus = PLSR_STATUS_RUNNING;
  1178. }
  1179. }
  1180. static uint8_t PlsrApplyFrequencyPair(uint32_t requestedFirstFrequencyHz,
  1181. uint32_t requestedQueuedFrequencyHz,
  1182. uint32_t expectedEpoch)
  1183. {
  1184. uint32_t criticalState;
  1185. uint32_t actualFirstFrequencyHz;
  1186. uint32_t actualQueuedFrequencyHz;
  1187. uint32_t hardwareFirstFrequencyHz = requestedFirstFrequencyHz;
  1188. uint32_t hardwareQueuedFrequencyHz = requestedQueuedFrequencyHz;
  1189. PLSR_HANDOFF_PLAN candidatePlan;
  1190. uint8_t haveCandidatePlan = 0U;
  1191. criticalState = PlsrPlatformEnterCritical();
  1192. if ((PlsrSegmentEpoch != expectedEpoch)
  1193. || (PlsrBoundaryPending != 0U) || (PlsrRemainingPulses == 0UL))
  1194. {
  1195. PlsrPlatformExitCritical(criticalState);
  1196. return 1U;
  1197. }
  1198. if (hardwareFirstFrequencyHz == 0UL)
  1199. {
  1200. if (PlsrPulseActive == 0U)
  1201. {
  1202. PlsrCurrentFrequencyHz = 0UL;
  1203. PlsrQueuedFrequencyHz = 0UL;
  1204. PlsrPlatformExitCritical(criticalState);
  1205. return 1U;
  1206. }
  1207. hardwareFirstFrequencyHz = 1UL;
  1208. }
  1209. if (hardwareQueuedFrequencyHz == 0UL)
  1210. {
  1211. hardwareQueuedFrequencyHz = 1UL;
  1212. }
  1213. if (PlsrPulseActive != 0U)
  1214. {
  1215. if (PlsrAbStopArmed != 0U)
  1216. {
  1217. PlsrPlatformExitCritical(criticalState);
  1218. return 1U;
  1219. }
  1220. if (PlsrHandoffPlan.valid != 0U)
  1221. {
  1222. PlsrPlatformExitCritical(criticalState);
  1223. return 1U;
  1224. }
  1225. PlsrDeferredFrequencyHz = hardwareQueuedFrequencyHz;
  1226. PlsrDeferredFrequencyPending = 1U;
  1227. PlsrPlatformExitCritical(criticalState);
  1228. return 1U;
  1229. }
  1230. else
  1231. {
  1232. if (PlsrSelectPreparedHandoffPlan(&candidatePlan) != 0U)
  1233. {
  1234. hardwareQueuedFrequencyHz = candidatePlan.firstFrequencyHz;
  1235. haveCandidatePlan = 1U;
  1236. }
  1237. if (PlsrDiagnosticStartPulse(
  1238. (uint8_t)PlsrActiveConfig.pulseOutput,
  1239. hardwareFirstFrequencyHz, hardwareQueuedFrequencyHz,
  1240. &actualFirstFrequencyHz, &actualQueuedFrequencyHz) == 0U)
  1241. {
  1242. PlsrPlatformExitCritical(criticalState);
  1243. return 0U;
  1244. }
  1245. PlsrPulseActive = 1U;
  1246. PlsrCurrentFrequencyHz = actualFirstFrequencyHz;
  1247. PlsrHandoffPlan.valid = 0U;
  1248. if (haveCandidatePlan != 0U)
  1249. {
  1250. PlsrHandoffPlan = candidatePlan;
  1251. PlsrHandoffPlan.firstFrequencyHz = actualQueuedFrequencyHz;
  1252. PlsrHandoffPlan.valid = 1U;
  1253. }
  1254. }
  1255. PlsrQueuedFrequencyHz = actualQueuedFrequencyHz;
  1256. if (PlsrArmFinalAbBoundaryLocked() == 0U)
  1257. {
  1258. PlsrPlatformExitCritical(criticalState);
  1259. return 0U;
  1260. }
  1261. PlsrPlatformExitCritical(criticalState);
  1262. return 1U;
  1263. }
  1264. static PLSR_PLATFORM_QUEUE_RESULT PlsrApplyFrequency(
  1265. uint32_t requestedFrequencyHz,
  1266. uint32_t expectedEpoch)
  1267. {
  1268. return (PlsrApplyFrequencyPair(requestedFrequencyHz,
  1269. requestedFrequencyHz,
  1270. expectedEpoch) != 0U)
  1271. ? PLSR_PLATFORM_QUEUE_APPLIED
  1272. : PLSR_PLATFORM_QUEUE_FAILED;
  1273. }
  1274. static uint8_t PlsrStopDrainPulseCount(void)
  1275. {
  1276. uint8_t deferredPending = PlsrDeferredFrequencyPending;
  1277. uint32_t deferredFrequencyHz = PlsrDeferredFrequencyHz;
  1278. uint32_t queuedFrequencyHz = PlsrQueuedFrequencyHz;
  1279. uint32_t currentFrequencyHz = PlsrCurrentFrequencyHz;
  1280. if ((deferredPending != 0U)
  1281. && (deferredFrequencyHz != queuedFrequencyHz))
  1282. {
  1283. return 3U;
  1284. }
  1285. PlsrDeferredFrequencyPending = 0U;
  1286. return (currentFrequencyHz == queuedFrequencyHz) ? 1U : 2U;
  1287. }
  1288. static uint8_t PlsrArmStopDrainLocked(void)
  1289. {
  1290. uint32_t drainPulses = PlsrStopDrainPulseCount();
  1291. PlsrStopPulsesRemaining = (uint8_t)drainPulses;
  1292. return PlsrArmFinalAbBoundaryLocked();
  1293. }
  1294. static PLSR_PLATFORM_QUEUE_RESULT PlsrCommitDeferredFrequency(
  1295. uint8_t pulseOutput)
  1296. {
  1297. uint32_t requestedFrequencyHz;
  1298. uint32_t actualFrequencyHz;
  1299. PLSR_PLATFORM_QUEUE_RESULT result;
  1300. if (PlsrDeferredFrequencyPending == 0U)
  1301. {
  1302. return PLSR_PLATFORM_QUEUE_APPLIED;
  1303. }
  1304. requestedFrequencyHz = PlsrDeferredFrequencyHz;
  1305. result = PlsrDiagnosticQueueFrequency(pulseOutput, requestedFrequencyHz,
  1306. &actualFrequencyHz);
  1307. if (result != PLSR_PLATFORM_QUEUE_APPLIED)
  1308. {
  1309. return result;
  1310. }
  1311. if ((PlsrDeferredFrequencyPending != 0U)
  1312. && (PlsrDeferredFrequencyHz == requestedFrequencyHz))
  1313. {
  1314. PlsrDeferredFrequencyPending = 0U;
  1315. }
  1316. PlsrQueuedFrequencyHz = actualFrequencyHz;
  1317. return PLSR_PLATFORM_QUEUE_APPLIED;
  1318. }
  1319. static uint8_t PlsrRampAdvance(uint32_t expectedEpoch)
  1320. {
  1321. uint32_t progress;
  1322. uint32_t frequency;
  1323. uint32_t gap;
  1324. uint32_t criticalState;
  1325. uint32_t fromHz;
  1326. uint32_t toHz;
  1327. uint32_t durationMs;
  1328. uint32_t elapsedMs;
  1329. PLSR_PLATFORM_QUEUE_RESULT applyResult;
  1330. criticalState = PlsrPlatformEnterCritical();
  1331. if ((PlsrSegmentEpoch != expectedEpoch) || (PlsrRamp.active == 0U))
  1332. {
  1333. PlsrPlatformExitCritical(criticalState);
  1334. return 1U;
  1335. }
  1336. if (PlsrRamp.elapsedMs < PlsrRamp.durationMs)
  1337. {
  1338. PlsrRamp.elapsedMs++;
  1339. }
  1340. fromHz = PlsrRamp.fromHz;
  1341. toHz = PlsrRamp.toHz;
  1342. durationMs = PlsrRamp.durationMs;
  1343. elapsedMs = PlsrRamp.elapsedMs;
  1344. PlsrPlatformExitCritical(criticalState);
  1345. progress = PlsrCurveProgressQ16(elapsedMs,
  1346. durationMs,
  1347. PlsrActiveConfig.curveMode);
  1348. if (toHz >= fromHz)
  1349. {
  1350. gap = toHz - fromHz;
  1351. frequency = fromHz
  1352. + (uint32_t)(((uint64_t)gap * progress) / 65535UL);
  1353. }
  1354. else
  1355. {
  1356. gap = fromHz - toHz;
  1357. frequency = fromHz
  1358. - (uint32_t)(((uint64_t)gap * progress) / 65535UL);
  1359. }
  1360. applyResult = PlsrApplyFrequency(frequency, expectedEpoch);
  1361. if (applyResult == PLSR_PLATFORM_QUEUE_FAILED)
  1362. {
  1363. return 0U;
  1364. }
  1365. if (applyResult == PLSR_PLATFORM_QUEUE_STALE)
  1366. {
  1367. return 1U;
  1368. }
  1369. criticalState = PlsrPlatformEnterCritical();
  1370. if (PlsrSegmentEpoch != expectedEpoch)
  1371. {
  1372. PlsrPlatformExitCritical(criticalState);
  1373. return 1U;
  1374. }
  1375. if (elapsedMs >= durationMs)
  1376. {
  1377. PlsrRamp.active = 0U;
  1378. if (PlsrStopRequested == 0U)
  1379. {
  1380. PlsrRunStatus = PLSR_STATUS_RUNNING;
  1381. }
  1382. else
  1383. {
  1384. (void)PlsrArmStopDrainLocked();
  1385. }
  1386. }
  1387. PlsrPlatformExitCritical(criticalState);
  1388. return 1U;
  1389. }
  1390. static uint8_t PlsrGetNextSegment(uint8_t *nextSegment)
  1391. {
  1392. const PLSR_SEGMENT_CONFIG *segment =
  1393. &PlsrActiveConfig.segments[PlsrCurrentSegment - 1U];
  1394. if (segment->jumpSegment != 0U)
  1395. {
  1396. *nextSegment = (uint8_t)segment->jumpSegment;
  1397. return 1U;
  1398. }
  1399. if (PlsrCurrentSegment < PlsrActiveConfig.segmentCount)
  1400. {
  1401. *nextSegment = (uint8_t)(PlsrCurrentSegment + 1U);
  1402. return 1U;
  1403. }
  1404. return 0U;
  1405. }
  1406. static uint32_t PlsrResolvedSegmentFrequency(const PLSR_CONFIG *config,
  1407. uint8_t segmentIndex)
  1408. {
  1409. uint32_t frequencyHz = config->segments[segmentIndex].frequencyHz;
  1410. return (frequencyHz == 0UL) ? config->defaultSpeedHz : frequencyHz;
  1411. }
  1412. static int64_t PlsrSegmentDisplacement(uint8_t segmentNumber,
  1413. int32_t referencePosition)
  1414. {
  1415. int32_t configured =
  1416. PlsrActiveConfig.segments[segmentNumber - 1U].pulses;
  1417. if (PlsrActiveConfig.positionMode == PLSR_POSITION_ABSOLUTE)
  1418. {
  1419. return (int64_t)configured - (int64_t)referencePosition;
  1420. }
  1421. return configured;
  1422. }
  1423. static uint8_t PlsrPredictNextDirection(uint8_t nextSegment,
  1424. uint8_t *positive)
  1425. {
  1426. uint32_t criticalState;
  1427. uint64_t remaining;
  1428. int32_t position;
  1429. uint32_t predictedBits;
  1430. int32_t predictedPosition;
  1431. int64_t displacement;
  1432. criticalState = PlsrPlatformEnterCritical();
  1433. remaining = PlsrRemainingPulses;
  1434. position = PlsrPosition;
  1435. PlsrPlatformExitCritical(criticalState);
  1436. predictedBits = (uint32_t)position;
  1437. if (PlsrCountPositive != 0U)
  1438. {
  1439. predictedBits += (uint32_t)remaining;
  1440. }
  1441. else
  1442. {
  1443. predictedBits -= (uint32_t)remaining;
  1444. }
  1445. predictedPosition = (int32_t)predictedBits;
  1446. displacement = PlsrSegmentDisplacement(nextSegment, predictedPosition);
  1447. if (displacement == 0)
  1448. {
  1449. return 0U;
  1450. }
  1451. *positive = (displacement > 0) ? 1U : 0U;
  1452. return 1U;
  1453. }
  1454. static uint64_t PlsrRemainingSnapshot(void)
  1455. {
  1456. uint32_t criticalState = PlsrPlatformEnterCritical();
  1457. uint64_t remaining = PlsrRemainingPulses;
  1458. PlsrPlatformExitCritical(criticalState);
  1459. return remaining;
  1460. }
  1461. static uint64_t PlsrRampPulseEstimate(uint32_t fromHz,
  1462. uint32_t toHz,
  1463. uint32_t rateBoundHz)
  1464. {
  1465. uint32_t duration = PlsrRampDurationMs(fromHz, toHz);
  1466. uint64_t sum = (uint64_t)fromHz + toHz;
  1467. uint64_t discreteArea = sum * duration;
  1468. uint64_t rampArea;
  1469. uint64_t pollReserve = 0ULL;
  1470. uint64_t candidateReserve =
  1471. ((uint64_t)rateBoundHz + 999UL) / 1000UL;
  1472. uint64_t endpointCorrection = 0ULL;
  1473. /* RampAdvance applies samples at 1/duration through duration/duration.
  1474. For all supported symmetric curves this right-endpoint sum differs
  1475. from the continuous trapezoid by half the endpoint delta. */
  1476. if (toHz >= fromHz)
  1477. {
  1478. discreteArea += (uint64_t)toHz - fromHz;
  1479. }
  1480. else
  1481. {
  1482. discreteArea -= (uint64_t)fromHz - toHz;
  1483. endpointCorrection =
  1484. ((uint64_t)fromHz - toHz + 1999UL) / 2000UL;
  1485. }
  1486. rampArea = (discreteArea + 1999UL) / 2000UL;
  1487. if (candidateReserve
  1488. <= rampArea / PLSR_RAMP_POLL_RESERVE_AREA_DIVISOR)
  1489. {
  1490. pollReserve = candidateReserve + endpointCorrection;
  1491. }
  1492. /* A full poll reserve on shorter ramps would dominate their area and
  1493. leave stop-speed tail pulses. */
  1494. return rampArea + pollReserve;
  1495. }
  1496. static uint8_t PlsrPrepareShortProfile(PLSR_SHORT_PROFILE *profile,
  1497. uint8_t segmentNumber,
  1498. uint32_t startFrequencyHz,
  1499. uint32_t targetFrequencyHz,
  1500. uint64_t pulseCount)
  1501. {
  1502. PLSR_MOTION_BLOCK block;
  1503. PLSR_PLANNER_STATUS status;
  1504. const PLSR_SEGMENT_CONFIG *segment;
  1505. uint8_t nextSegment = 0U;
  1506. uint8_t currentPositive;
  1507. uint8_t nextPositive;
  1508. (void)memset(profile, 0, sizeof(*profile));
  1509. if ((PlsrActiveConfig.outputMode != PLSR_OUTPUT_PULSE_DIR)
  1510. || (pulseCount == 0ULL) || (pulseCount > 0xFFFFFFFFULL)
  1511. || (segmentNumber == 0U)
  1512. || (segmentNumber > PlsrActiveConfig.segmentCount))
  1513. {
  1514. return 0U;
  1515. }
  1516. block.entryHz = startFrequencyHz;
  1517. block.cruiseHz = targetFrequencyHz;
  1518. block.exitHz = PlsrEffectiveStopFrequency(targetFrequencyHz);
  1519. block.pulseBudget = (uint32_t)pulseCount;
  1520. block.referenceSpeedHz = PlsrActiveConfig.defaultSpeedHz;
  1521. block.accelerationTimeMs = PlsrActiveConfig.accelerationTimeMs;
  1522. block.decelerationTimeMs = PlsrActiveConfig.decelerationTimeMs;
  1523. block.curveMode = PlsrActiveConfig.curveMode;
  1524. block.pulseOutput = (uint8_t)PlsrActiveConfig.pulseOutput;
  1525. block.boundary = PLSR_BOUNDARY_STOP;
  1526. segment = &PlsrActiveConfig.segments[segmentNumber - 1U];
  1527. if (segment->waitType == PLSR_EXT_OR_COMPLETE)
  1528. {
  1529. nextSegment = (segment->jumpSegment != 0U)
  1530. ? (uint8_t)segment->jumpSegment
  1531. : ((segmentNumber < PlsrActiveConfig.segmentCount)
  1532. ? (uint8_t)(segmentNumber + 1U) : 0U);
  1533. }
  1534. if (nextSegment != 0U)
  1535. {
  1536. currentPositive = PlsrCountPositive;
  1537. if (PlsrActiveConfig.positionMode == PLSR_POSITION_RELATIVE)
  1538. {
  1539. currentPositive = (segment->pulses >= 0L) ? 1U : 0U;
  1540. nextPositive =
  1541. (PlsrActiveConfig.segments[nextSegment - 1U].pulses >= 0L)
  1542. ? 1U : 0U;
  1543. }
  1544. else if ((segmentNumber == PlsrCurrentSegment)
  1545. && (PlsrPredictNextDirection(nextSegment,
  1546. &nextPositive) != 0U))
  1547. {
  1548. /* direction resolved from the live absolute position */
  1549. }
  1550. else
  1551. {
  1552. nextPositive = (uint8_t)(currentPositive ^ 1U);
  1553. }
  1554. if (nextPositive == currentPositive)
  1555. {
  1556. block.exitHz = targetFrequencyHz;
  1557. block.boundary = PLSR_BOUNDARY_NEXT_CARRY;
  1558. }
  1559. }
  1560. status = PlsrPlannerBegin(&profile->planner, &block,
  1561. startFrequencyHz, 0ULL);
  1562. if ((status != PLSR_PLANNER_OK)
  1563. && (status != PLSR_PLANNER_CLIPPED))
  1564. {
  1565. return 0U;
  1566. }
  1567. profile->startHz = profile->planner.startHz;
  1568. profile->peakHz = profile->planner.peakHz;
  1569. profile->endHz = profile->planner.endHz;
  1570. profile->pulseCount = profile->planner.block.pulseBudget;
  1571. profile->entryPulses = profile->planner.entryPulses;
  1572. profile->steadyPulses = profile->planner.steadyPulses;
  1573. profile->exitPulses = profile->planner.exitPulses;
  1574. profile->active = 1U;
  1575. return 1U;
  1576. }
  1577. static uint8_t PlsrShortProfileTakeRun(PLSR_SHORT_PROFILE *profile,
  1578. PLSR_PROFILE_ENTRY *entry)
  1579. {
  1580. uint32_t repeatCount;
  1581. if ((profile->nextPeriod >= profile->pulseCount)
  1582. || (entry == NULL))
  1583. {
  1584. return 0U;
  1585. }
  1586. if (profile->pendingRepeats == 0UL)
  1587. {
  1588. if (PlsrPlannerGenerate(&profile->planner,
  1589. &profile->pendingItem, 1U) == 0U)
  1590. {
  1591. profile->active = 0U;
  1592. return 0U;
  1593. }
  1594. profile->pendingRepeats = profile->pendingItem.repeatCount;
  1595. }
  1596. repeatCount = profile->pendingRepeats;
  1597. if (repeatCount > profile->pulseCount - profile->nextPeriod)
  1598. {
  1599. repeatCount = profile->pulseCount - profile->nextPeriod;
  1600. }
  1601. if (repeatCount == 0UL)
  1602. {
  1603. profile->active = 0U;
  1604. return 0U;
  1605. }
  1606. entry->setting = profile->pendingItem.setting;
  1607. entry->requestedFrequencyHz = entry->setting.actualFrequencyHz;
  1608. entry->repeatCount = repeatCount;
  1609. entry->startsNextSegment = 0U;
  1610. profile->pendingRepeats -= repeatCount;
  1611. profile->nextPeriod += repeatCount;
  1612. profile->lastRampFrequencyHz = entry->setting.actualFrequencyHz;
  1613. if (profile->nextPeriod >= profile->pulseCount)
  1614. {
  1615. profile->active = 0U;
  1616. }
  1617. return 1U;
  1618. }
  1619. /* Caller holds the platform critical section. The currently preloaded
  1620. period is the single committed pulse; the new stream starts after it. */
  1621. static uint8_t PlsrReplanPulseDir(uint32_t targetHz,
  1622. uint32_t totalPulses)
  1623. {
  1624. uint32_t appliedHz;
  1625. uint32_t epoch;
  1626. uint8_t segmentNumber;
  1627. uint8_t handoffBank;
  1628. PlsrRamp.active = 0U;
  1629. PlsrShortProfile.active = 0U;
  1630. PlsrProfileQueueInvalidateGeneration();
  1631. PlsrHandoffPlan.valid = 0U;
  1632. if (totalPulses <= 1UL)
  1633. {
  1634. return 1U;
  1635. }
  1636. appliedHz = PlsrQueuedFrequencyHz;
  1637. if (appliedHz == 0UL)
  1638. {
  1639. appliedHz = PlsrCurrentFrequencyHz;
  1640. }
  1641. if ((appliedHz == 0UL)
  1642. || (PlsrPrepareShortProfile(&PlsrShortProfile,
  1643. PlsrCurrentSegment,
  1644. appliedHz, targetHz,
  1645. totalPulses - 1UL) == 0U))
  1646. {
  1647. return 0U;
  1648. }
  1649. PlsrRefreshCurrentHandoffPlan(PlsrShortProfile.endHz);
  1650. epoch = PlsrSegmentEpoch;
  1651. segmentNumber = PlsrCurrentSegment;
  1652. handoffBank = PlsrPreparedHandoffBank;
  1653. (void)PlsrProfileQueueBegin(&PlsrShortProfile, epoch,
  1654. segmentNumber, handoffBank);
  1655. if (PlsrProfileQueueFill(PLSR_REPLAN_WARMUP_ITEMS) == 0U)
  1656. {
  1657. PlsrProfileQueueReset();
  1658. PlsrShortProfile.active = 0U;
  1659. return 0U;
  1660. }
  1661. PlsrExecutor.generation++;
  1662. PlsrExecutor.mode = PLSR_EXEC_STREAM;
  1663. return 1U;
  1664. }
  1665. static void PlsrCopyShortProfile(PLSR_SHORT_PROFILE *destination,
  1666. const PLSR_SHORT_PROFILE *source)
  1667. {
  1668. *destination = *source;
  1669. }
  1670. static uint16_t PlsrProfileQueueCount(void)
  1671. {
  1672. uint32_t writeIndex = PlsrProfileQueue.writeIndex;
  1673. uint32_t readIndex = PlsrProfileQueue.readIndex;
  1674. return (uint16_t)(writeIndex - readIndex);
  1675. }
  1676. static void PlsrProfileQueueReset(void)
  1677. {
  1678. uint32_t criticalState = PlsrPlatformEnterCritical();
  1679. PlsrProfileQueue.generation++;
  1680. PlsrProfileQueue.readIndex = 0U;
  1681. PlsrProfileQueue.writeIndex = 0U;
  1682. PlsrProfileQueue.active = 0U;
  1683. PlsrProfileQueue.generatorComplete = 0U;
  1684. PlsrProfileQueue.producerEpoch = 0UL;
  1685. PlsrProfileQueue.repeatRemaining = 0UL;
  1686. PlsrProfileQueue.producerSegment = 0U;
  1687. PlsrProfileQueue.preparedHandoffBank = 0U;
  1688. PlsrProfileQueue.producerProfile.active = 0U;
  1689. PlsrPlatformExitCritical(criticalState);
  1690. }
  1691. static uint8_t PlsrProfileQueueBegin(
  1692. const PLSR_SHORT_PROFILE *producerProfile,
  1693. uint32_t producerEpoch,
  1694. uint8_t producerSegment,
  1695. uint8_t preparedHandoffBank)
  1696. {
  1697. uint32_t criticalState = PlsrPlatformEnterCritical();
  1698. PlsrProfileQueue.generation++;
  1699. PlsrProfileQueue.readIndex = 0U;
  1700. PlsrProfileQueue.writeIndex = 0U;
  1701. PlsrProfileQueue.producerEpoch = producerEpoch;
  1702. PlsrProfileQueue.producerSegment = producerSegment;
  1703. PlsrProfileQueue.preparedHandoffBank = preparedHandoffBank;
  1704. PlsrProfileQueue.generatorComplete = 0U;
  1705. PlsrProfileQueue.repeatRemaining = 0UL;
  1706. PlsrCopyShortProfile(&PlsrProfileQueue.producerProfile,
  1707. producerProfile);
  1708. PlsrProfileQueue.active =
  1709. ((producerProfile->active != 0U)
  1710. && (producerProfile->nextPeriod < producerProfile->pulseCount))
  1711. ? 1U : 0U;
  1712. if (PlsrProfileQueue.active == 0U)
  1713. {
  1714. PlsrProfileQueue.generatorComplete = 1U;
  1715. }
  1716. PlsrPlatformExitCritical(criticalState);
  1717. return 1U;
  1718. }
  1719. static void PlsrProfileQueueInvalidateGeneration(void)
  1720. {
  1721. uint32_t criticalState = PlsrPlatformEnterCritical();
  1722. PlsrProfileQueue.generation++;
  1723. PlsrProfileQueue.active = 0U;
  1724. PlsrProfileQueue.generatorComplete = 0U;
  1725. PlsrProfileQueue.readIndex = 0U;
  1726. PlsrProfileQueue.writeIndex = 0U;
  1727. PlsrProfileQueue.repeatRemaining = 0UL;
  1728. PlsrPlatformExitCritical(criticalState);
  1729. }
  1730. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  1731. && !defined(PLSR_HOST_TEST)
  1732. static uint32_t PlsrProfileTimingNow(void)
  1733. {
  1734. return *((volatile uint32_t *)0xE0001004UL);
  1735. }
  1736. static void PlsrProfileRecordProducerCycles(uint32_t startCycles)
  1737. {
  1738. uint32_t elapsed = PlsrProfileTimingNow() - startCycles;
  1739. uint32_t total = PlsrProfileProducerTotalCycles;
  1740. if (PlsrProfileProducerItemCount != 0xFFFFFFFFUL)
  1741. {
  1742. PlsrProfileProducerItemCount++;
  1743. }
  1744. PlsrProfileProducerTotalCycles =
  1745. (elapsed > (0xFFFFFFFFUL - total)) ? 0xFFFFFFFFUL
  1746. : total + elapsed;
  1747. if (elapsed > PlsrProfileProducerMaxItemCycles)
  1748. {
  1749. PlsrProfileProducerMaxItemCycles = elapsed;
  1750. }
  1751. }
  1752. #endif
  1753. static uint8_t PlsrProfileQueueFill(uint16_t targetCount)
  1754. {
  1755. PLSR_SHORT_PROFILE candidate;
  1756. PLSR_PROFILE_ENTRY entry;
  1757. uint32_t generation;
  1758. uint32_t producerEpoch;
  1759. uint32_t criticalState;
  1760. uint32_t writeIndex;
  1761. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  1762. && !defined(PLSR_HOST_TEST)
  1763. uint32_t startCycles;
  1764. #endif
  1765. if ((targetCount == 0U)
  1766. || (targetCount > PLSR_PROFILE_QUEUE_CAPACITY))
  1767. {
  1768. targetCount = PLSR_PROFILE_QUEUE_CAPACITY;
  1769. }
  1770. while (1)
  1771. {
  1772. criticalState = PlsrPlatformEnterCritical();
  1773. if ((PlsrProfileQueue.active == 0U)
  1774. || (PlsrProfileQueue.generatorComplete != 0U)
  1775. || (PlsrProfileQueueCount() >= targetCount))
  1776. {
  1777. PlsrPlatformExitCritical(criticalState);
  1778. return 1U;
  1779. }
  1780. generation = PlsrProfileQueue.generation;
  1781. producerEpoch = PlsrProfileQueue.producerEpoch;
  1782. PlsrCopyShortProfile(&candidate,
  1783. &PlsrProfileQueue.producerProfile);
  1784. PlsrPlatformExitCritical(criticalState);
  1785. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  1786. && !defined(PLSR_HOST_TEST)
  1787. startCycles = PlsrProfileTimingNow();
  1788. #endif
  1789. if (PlsrShortProfileTakeRun(&candidate, &entry) == 0U)
  1790. {
  1791. return 0U;
  1792. }
  1793. criticalState = PlsrPlatformEnterCritical();
  1794. if ((PlsrProfileQueue.active == 0U)
  1795. || (PlsrProfileQueue.generation != generation)
  1796. || (PlsrProfileQueue.producerEpoch != producerEpoch)
  1797. || (PlsrProfileQueueCount() >= PLSR_PROFILE_QUEUE_CAPACITY))
  1798. {
  1799. PlsrPlatformExitCritical(criticalState);
  1800. continue;
  1801. }
  1802. writeIndex = PlsrProfileQueue.writeIndex;
  1803. PlsrProfileQueue.entries[writeIndex & PLSR_PROFILE_QUEUE_MASK] = entry;
  1804. PlsrCopyShortProfile(&PlsrProfileQueue.producerProfile, &candidate);
  1805. PlsrProfileQueue.writeIndex = writeIndex + 1UL;
  1806. if ((candidate.active == 0U)
  1807. || (candidate.nextPeriod >= candidate.pulseCount))
  1808. {
  1809. PlsrProfileQueue.generatorComplete = 1U;
  1810. }
  1811. PlsrPlatformExitCritical(criticalState);
  1812. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  1813. && !defined(PLSR_HOST_TEST)
  1814. PlsrProfileRecordProducerCycles(startCycles);
  1815. #endif
  1816. }
  1817. }
  1818. static PLSR_PLATFORM_QUEUE_RESULT PlsrProfileQueueCommitNext(
  1819. uint8_t pulseOutput)
  1820. {
  1821. const PLSR_PROFILE_ENTRY *entry;
  1822. uint32_t readIndex;
  1823. uint32_t nextReadIndex;
  1824. uint32_t writeIndex;
  1825. uint32_t actualFrequencyHz;
  1826. PLSR_PLATFORM_QUEUE_RESULT result;
  1827. if (PlsrProfileQueue.repeatRemaining != 0UL)
  1828. {
  1829. PlsrProfileQueue.repeatRemaining--;
  1830. return PLSR_PLATFORM_QUEUE_APPLIED;
  1831. }
  1832. if (PlsrProfileQueue.active == 0U)
  1833. {
  1834. if (PlsrProfileQueue.generatorComplete != 0U)
  1835. {
  1836. PlsrShortProfile.active = 0U;
  1837. }
  1838. return PLSR_PLATFORM_QUEUE_APPLIED;
  1839. }
  1840. readIndex = PlsrProfileQueue.readIndex;
  1841. if (readIndex == PlsrProfileQueue.writeIndex)
  1842. {
  1843. if (PlsrProfileQueue.generatorComplete != 0U)
  1844. {
  1845. PlsrProfileQueue.active = 0U;
  1846. PlsrShortProfile.active = 0U;
  1847. return PLSR_PLATFORM_QUEUE_APPLIED;
  1848. }
  1849. return PLSR_PLATFORM_QUEUE_FAILED;
  1850. }
  1851. entry = &PlsrProfileQueue.entries[readIndex & PLSR_PROFILE_QUEUE_MASK];
  1852. result = PlsrPlatformLoadPreparedFromIrq(pulseOutput, &entry->setting,
  1853. &actualFrequencyHz);
  1854. if (result != PLSR_PLATFORM_QUEUE_APPLIED)
  1855. {
  1856. return result;
  1857. }
  1858. nextReadIndex = readIndex + 1UL;
  1859. PlsrProfileQueue.readIndex = nextReadIndex;
  1860. PlsrProfileQueue.repeatRemaining = entry->repeatCount - 1UL;
  1861. PlsrDeferredFrequencyPending = 0U;
  1862. PlsrQueuedFrequencyHz = actualFrequencyHz;
  1863. PlsrDiagnosticRecordFrequency(entry->requestedFrequencyHz,
  1864. entry->setting.actualFrequencyHz,
  1865. actualFrequencyHz);
  1866. PlsrDiagnosticQueuedExpectedHz = entry->setting.actualFrequencyHz;
  1867. if (actualFrequencyHz > PlsrCurrentFrequencyHz)
  1868. {
  1869. PlsrRunStatus = PLSR_STATUS_ACCELERATING;
  1870. }
  1871. else if (actualFrequencyHz < PlsrCurrentFrequencyHz)
  1872. {
  1873. PlsrRunStatus = PLSR_STATUS_DECELERATING;
  1874. }
  1875. else
  1876. {
  1877. PlsrRunStatus = PLSR_STATUS_RUNNING;
  1878. }
  1879. writeIndex = PlsrProfileQueue.writeIndex;
  1880. if ((nextReadIndex == writeIndex)
  1881. && (PlsrProfileQueue.generatorComplete != 0U))
  1882. {
  1883. PlsrProfileQueue.active = 0U;
  1884. PlsrShortProfile.active = 0U;
  1885. }
  1886. return PLSR_PLATFORM_QUEUE_APPLIED;
  1887. }
  1888. static void PlsrInvalidateHandoffPlans(void)
  1889. {
  1890. uint8_t bank;
  1891. uint8_t index;
  1892. uint32_t criticalState = PlsrPlatformEnterCritical();
  1893. PlsrHandoffPlan.valid = 0U;
  1894. PlsrCountedHandoffStaged = 0U;
  1895. for (bank = 0U; bank < 2U; bank++)
  1896. {
  1897. for (index = 0U; index < PLSR_SEGMENT_COUNT_MAX; index++)
  1898. {
  1899. PlsrPreparedHandoffPlans[bank][index].valid = 0U;
  1900. }
  1901. }
  1902. PlsrPlatformExitCritical(criticalState);
  1903. }
  1904. static void PlsrMaybePlanBoundaryRamp(uint32_t expectedEpoch)
  1905. {
  1906. const PLSR_SEGMENT_CONFIG *segment;
  1907. uint8_t nextSegment;
  1908. uint8_t nextPositive;
  1909. uint8_t hasNext;
  1910. uint32_t targetHz;
  1911. uint32_t criticalState;
  1912. uint32_t currentHz;
  1913. uint32_t queuedHz;
  1914. uint32_t deferredHz;
  1915. uint32_t rateBoundHz;
  1916. uint8_t deferredPending;
  1917. uint64_t estimate;
  1918. uint64_t candidateEstimate;
  1919. uint64_t remaining;
  1920. uint8_t rampActive;
  1921. if ((PlsrPulseActive == 0U)
  1922. || (PlsrBoundaryRampStarted != 0U)
  1923. || (PlsrShortProfile.active != 0U)
  1924. || (PlsrHandoffPlan.valid != 0U)
  1925. || (PlsrStopRequested != 0U) || (PlsrCurrentSegment == 0U))
  1926. {
  1927. return;
  1928. }
  1929. segment = &PlsrActiveConfig.segments[PlsrCurrentSegment - 1U];
  1930. hasNext = PlsrGetNextSegment(&nextSegment);
  1931. targetHz = PlsrEffectiveStopFrequency(segment->frequencyHz);
  1932. if ((hasNext != 0U)
  1933. && (segment->waitType == PLSR_EXT_OR_COMPLETE))
  1934. {
  1935. if ((PlsrPredictNextDirection(nextSegment, &nextPositive) != 0U)
  1936. && (nextPositive == PlsrCountPositive))
  1937. {
  1938. targetHz = PlsrActiveConfig.segments[nextSegment - 1U].frequencyHz;
  1939. }
  1940. }
  1941. criticalState = PlsrPlatformEnterCritical();
  1942. currentHz = PlsrCurrentFrequencyHz;
  1943. queuedHz = PlsrQueuedFrequencyHz;
  1944. deferredHz = PlsrDeferredFrequencyHz;
  1945. deferredPending = PlsrDeferredFrequencyPending;
  1946. if ((PlsrSegmentEpoch != expectedEpoch)
  1947. || (PlsrBoundaryPending != 0U)
  1948. || (PlsrPulseActive == 0U)
  1949. || (PlsrBoundaryRampStarted != 0U)
  1950. || (PlsrShortProfile.active != 0U)
  1951. || (PlsrHandoffPlan.valid != 0U)
  1952. || (PlsrStopRequested != 0U)
  1953. || (PlsrAbStopArmed != 0U))
  1954. {
  1955. PlsrPlatformExitCritical(criticalState);
  1956. return;
  1957. }
  1958. PlsrPlatformExitCritical(criticalState);
  1959. rateBoundHz = (currentHz > queuedHz) ? currentHz : queuedHz;
  1960. if ((deferredPending != 0U) && (deferredHz > rateBoundHz))
  1961. {
  1962. rateBoundHz = deferredHz;
  1963. }
  1964. estimate = PlsrRampPulseEstimate(currentHz, targetHz, rateBoundHz);
  1965. candidateEstimate = PlsrRampPulseEstimate(queuedHz, targetHz,
  1966. rateBoundHz);
  1967. if (candidateEstimate > estimate)
  1968. {
  1969. estimate = candidateEstimate;
  1970. }
  1971. if (deferredPending != 0U)
  1972. {
  1973. candidateEstimate = PlsrRampPulseEstimate(deferredHz, targetHz,
  1974. rateBoundHz);
  1975. if (candidateEstimate > estimate)
  1976. {
  1977. estimate = candidateEstimate;
  1978. }
  1979. }
  1980. criticalState = PlsrPlatformEnterCritical();
  1981. remaining = PlsrRemainingPulses;
  1982. if ((PlsrSegmentEpoch != expectedEpoch)
  1983. || (PlsrBoundaryPending != 0U)
  1984. || (PlsrPulseActive == 0U)
  1985. || (PlsrBoundaryRampStarted != 0U)
  1986. || (PlsrShortProfile.active != 0U)
  1987. || (PlsrHandoffPlan.valid != 0U)
  1988. || (PlsrStopRequested != 0U)
  1989. || (PlsrAbStopArmed != 0U))
  1990. {
  1991. PlsrPlatformExitCritical(criticalState);
  1992. return;
  1993. }
  1994. if (remaining > estimate)
  1995. {
  1996. PlsrPlatformExitCritical(criticalState);
  1997. return;
  1998. }
  1999. PlsrBoundaryRampStarted = 1U;
  2000. PlsrRampStart(PlsrCurrentFrequencyHz, targetHz);
  2001. rampActive = PlsrRamp.active;
  2002. PlsrPlatformExitCritical(criticalState);
  2003. if (rampActive != 0U)
  2004. {
  2005. if (PlsrRampAdvance(expectedEpoch) == 0U)
  2006. {
  2007. PlsrEnterErrorIfEpoch(PLSR_ERROR_TIMER, expectedEpoch);
  2008. }
  2009. }
  2010. else
  2011. {
  2012. (void)PlsrApplyFrequency(targetHz, expectedEpoch);
  2013. }
  2014. }
  2015. static uint8_t PlsrBeginSegmentOutput(uint32_t startFrequencyHz)
  2016. {
  2017. uint32_t targetFrequencyHz =
  2018. PlsrActiveConfig.segments[PlsrCurrentSegment - 1U].frequencyHz;
  2019. uint32_t firstFrequencyHz;
  2020. uint32_t secondFrequencyHz;
  2021. uint32_t actualFrequencyHz;
  2022. uint32_t profileEpoch;
  2023. uint8_t profileSegment;
  2024. uint8_t profileHandoffBank;
  2025. PLSR_PROFILE_ENTRY firstRun;
  2026. PlsrSegmentClockStarted = 1U;
  2027. PlsrSegmentElapsedMs = 0UL;
  2028. if (PlsrPrepareShortProfile(&PlsrShortProfile,
  2029. PlsrCurrentSegment, startFrequencyHz,
  2030. targetFrequencyHz,
  2031. PlsrRemainingSnapshot()) != 0U)
  2032. {
  2033. PlsrRamp.active = 0U;
  2034. PlsrRefreshCurrentHandoffPlan(PlsrShortProfile.endHz);
  2035. if (PlsrShortProfileTakeRun(&PlsrShortProfile, &firstRun) == 0U)
  2036. {
  2037. return 0U;
  2038. }
  2039. firstFrequencyHz = firstRun.setting.actualFrequencyHz;
  2040. secondFrequencyHz = firstFrequencyHz;
  2041. profileEpoch = PlsrSegmentEpoch;
  2042. profileSegment = PlsrCurrentSegment;
  2043. profileHandoffBank = PlsrPreparedHandoffBank;
  2044. (void)PlsrProfileQueueBegin(&PlsrShortProfile,
  2045. profileEpoch,
  2046. profileSegment,
  2047. profileHandoffBank);
  2048. if (PlsrProfileQueueFill(PLSR_PROFILE_QUEUE_CAPACITY) == 0U)
  2049. {
  2050. PlsrProfileQueueReset();
  2051. PlsrShortProfile.active = 0U;
  2052. return 0U;
  2053. }
  2054. PlsrCountedHandoffStaged = 0U;
  2055. if ((PlsrStageCountedHandoff() == 0U)
  2056. || (PlsrProfileQueueFill(PLSR_PROFILE_QUEUE_CAPACITY) == 0U))
  2057. {
  2058. PlsrProfileQueueReset();
  2059. PlsrShortProfile.active = 0U;
  2060. return 0U;
  2061. }
  2062. {
  2063. uint32_t readIndex = PlsrProfileQueue.readIndex;
  2064. uint32_t writeIndex = PlsrProfileQueue.writeIndex;
  2065. if (readIndex != writeIndex)
  2066. {
  2067. secondFrequencyHz = PlsrProfileQueue.entries[
  2068. readIndex & PLSR_PROFILE_QUEUE_MASK]
  2069. .setting.actualFrequencyHz;
  2070. }
  2071. }
  2072. if (secondFrequencyHz > firstFrequencyHz)
  2073. {
  2074. PlsrRunStatus = PLSR_STATUS_ACCELERATING;
  2075. }
  2076. else if (secondFrequencyHz < firstFrequencyHz)
  2077. {
  2078. PlsrRunStatus = PLSR_STATUS_DECELERATING;
  2079. }
  2080. else
  2081. {
  2082. PlsrRunStatus = PLSR_STATUS_RUNNING;
  2083. }
  2084. PlsrCurrentFrequencyHz = firstFrequencyHz;
  2085. PlsrQueuedFrequencyHz = secondFrequencyHz;
  2086. PlsrDiagnosticQueuedExpectedHz = firstRun.setting.actualFrequencyHz;
  2087. PlsrCountedObservedPublished = PlsrPlatformObservedPulses(
  2088. (uint8_t)PlsrActiveConfig.pulseOutput);
  2089. PlsrPulseActive = 1U;
  2090. PlsrExecutor.generation++;
  2091. PlsrExecutor.mode = (PlsrProfileQueue.generatorComplete != 0U)
  2092. ? PLSR_EXEC_STEP_TABLE
  2093. : PLSR_EXEC_STREAM;
  2094. if (PlsrPlatformStartCountedStreamPrepared(
  2095. (uint8_t)PlsrActiveConfig.pulseOutput,
  2096. &firstRun.setting, firstRun.repeatCount,
  2097. &actualFrequencyHz) == 0U)
  2098. {
  2099. PlsrPulseActive = 0U;
  2100. PlsrExecutor.mode = PLSR_EXEC_IDLE;
  2101. PlsrProfileQueueReset();
  2102. PlsrShortProfile.active = 0U;
  2103. return 0U;
  2104. }
  2105. PlsrCurrentFrequencyHz = actualFrequencyHz;
  2106. PlsrDiagnosticRecordFrequency(firstRun.requestedFrequencyHz,
  2107. firstRun.setting.actualFrequencyHz,
  2108. actualFrequencyHz);
  2109. return 1U;
  2110. }
  2111. if (PlsrActiveConfig.outputMode == PLSR_OUTPUT_PULSE_DIR)
  2112. {
  2113. return 0U;
  2114. }
  2115. PlsrProfileQueueReset();
  2116. PlsrRampStart(startFrequencyHz, targetFrequencyHz);
  2117. if (PlsrRamp.active == 0U)
  2118. {
  2119. if (PlsrApplyFrequency(targetFrequencyHz, PlsrSegmentEpoch) == 0U)
  2120. {
  2121. return 0U;
  2122. }
  2123. PlsrRunStatus = PLSR_STATUS_RUNNING;
  2124. }
  2125. else if ((startFrequencyHz != 0UL)
  2126. && (PlsrApplyFrequency(startFrequencyHz,
  2127. PlsrSegmentEpoch) == 0U))
  2128. {
  2129. return 0U;
  2130. }
  2131. if (PlsrPrepareFutureHandoffQueue() == 0U)
  2132. {
  2133. return 0U;
  2134. }
  2135. PlsrExecutor.generation++;
  2136. PlsrExecutor.mode = PLSR_EXEC_AB_LEGACY;
  2137. return 1U;
  2138. }
  2139. static uint8_t PlsrStartSegment(uint8_t segmentNumber,
  2140. uint8_t allowCarry,
  2141. uint32_t carryFrequencyHz)
  2142. {
  2143. uint32_t criticalState;
  2144. int32_t position;
  2145. int64_t displacement;
  2146. uint64_t magnitude;
  2147. uint8_t positive;
  2148. uint8_t directionLevel;
  2149. uint8_t directionChanged;
  2150. uint32_t startFrequencyHz;
  2151. if ((segmentNumber == 0U)
  2152. || (segmentNumber > PlsrActiveConfig.segmentCount))
  2153. {
  2154. return 0U;
  2155. }
  2156. criticalState = PlsrPlatformEnterCritical();
  2157. position = PlsrPosition;
  2158. PlsrPlatformExitCritical(criticalState);
  2159. displacement = PlsrSegmentDisplacement(segmentNumber, position);
  2160. positive = (displacement >= 0) ? 1U : 0U;
  2161. magnitude = (displacement < 0) ? (uint64_t)(-displacement)
  2162. : (uint64_t)displacement;
  2163. PlsrSegmentEpoch++;
  2164. PlsrCurrentSegment = segmentNumber;
  2165. PlsrSegmentClockStarted = 0U;
  2166. PlsrSegmentElapsedMs = 0UL;
  2167. PlsrWaitElapsedMs = 0UL;
  2168. PlsrBoundaryRampStarted = 0U;
  2169. PlsrBoundaryPending = 0U;
  2170. PlsrBoundaryWasCut = 0U;
  2171. PlsrCutRequested = 0U;
  2172. PlsrStopPulsesRemaining = 0U;
  2173. PlsrAbStopArmed = 0U;
  2174. PlsrFrequencyUpdatePending = 0U;
  2175. PlsrDeferredFrequencyPending = 0U;
  2176. PlsrCurrentFrequencyHz = 0UL;
  2177. PlsrQueuedFrequencyHz = 0UL;
  2178. PlsrHandoffPlan.valid = 0U;
  2179. PlsrShortProfile.active = 0U;
  2180. PlsrShortProfile.nextPeriod = 0U;
  2181. if ((allowCarry == 0U) || (PlsrProfileQueue.active == 0U)
  2182. || (PlsrProfileQueue.producerEpoch != PlsrSegmentEpoch)
  2183. || (PlsrProfileQueue.producerSegment != segmentNumber))
  2184. {
  2185. PlsrProfileQueueReset();
  2186. }
  2187. PlsrDirectionDelayActive = 0U;
  2188. PlsrDirectionDelayRemainingMs = 0U;
  2189. PlsrExtEdgePending = 0U;
  2190. PlsrExtPreviousLevel =
  2191. PlsrPlatformReadInput((uint8_t)PlsrActiveConfig.extInput);
  2192. criticalState = PlsrPlatformEnterCritical();
  2193. PlsrRemainingPulses = magnitude;
  2194. PlsrCountPositive = positive;
  2195. PlsrPlatformExitCritical(criticalState);
  2196. if ((PlsrActiveConfig.segments[segmentNumber - 1U].waitType
  2197. == PLSR_ACT_TIME)
  2198. && (PlsrActiveConfig.segments[segmentNumber - 1U].actTimeMs == 0U))
  2199. {
  2200. PlsrSegmentClockStarted = 1U;
  2201. PlsrRunStatus = PLSR_STATUS_RUNNING;
  2202. PlsrBoundaryFrequencyHz = (allowCarry != 0U) ? carryFrequencyHz : 0UL;
  2203. PlsrBoundaryWasCut = 1U;
  2204. PlsrBoundaryPending = 1U;
  2205. PlsrDiagnosticBeginSegment(segmentNumber, 0UL, positive);
  2206. PlsrDiagnosticFinishSegment(1U);
  2207. return 1U;
  2208. }
  2209. if (magnitude == 0UL)
  2210. {
  2211. PlsrSegmentClockStarted = 1U;
  2212. PlsrRunStatus = PLSR_STATUS_RUNNING;
  2213. PlsrBoundaryFrequencyHz = 0UL;
  2214. PlsrBoundaryPending = 1U;
  2215. PlsrDiagnosticBeginSegment(segmentNumber, 0UL, positive);
  2216. PlsrDiagnosticFinishSegment(1U);
  2217. return 1U;
  2218. }
  2219. directionLevel = positive;
  2220. if ((PlsrActiveConfig.outputMode == PLSR_OUTPUT_PULSE_DIR)
  2221. && (PlsrActiveConfig.directionNegativeLogic != 0U))
  2222. {
  2223. directionLevel ^= 1U;
  2224. }
  2225. directionChanged = ((PlsrLastDirectionValid == 0U)
  2226. || (PlsrLastDirectionOutput
  2227. != (uint8_t)PlsrActiveConfig.directionOutput)
  2228. || (PlsrLastDirectionLevel != directionLevel)) ? 1U : 0U;
  2229. if (PlsrPlatformPrepare((uint8_t)PlsrActiveConfig.pulseOutput,
  2230. (uint8_t)PlsrActiveConfig.directionOutput,
  2231. directionLevel,
  2232. (uint8_t)PlsrActiveConfig.outputMode,
  2233. positive) == 0U)
  2234. {
  2235. return 0U;
  2236. }
  2237. PlsrDiagnosticBeginSegment(segmentNumber, magnitude, positive);
  2238. PlsrLastDirectionValid = 1U;
  2239. PlsrLastDirectionOutput = (uint8_t)PlsrActiveConfig.directionOutput;
  2240. PlsrLastDirectionLevel = directionLevel;
  2241. startFrequencyHz = PlsrEffectiveStartFrequency(
  2242. PlsrActiveConfig.segments[segmentNumber - 1U].frequencyHz,
  2243. allowCarry, directionChanged, carryFrequencyHz);
  2244. if ((PlsrActiveConfig.outputMode == PLSR_OUTPUT_PULSE_DIR)
  2245. && (directionChanged != 0U)
  2246. && (PlsrActiveConfig.directionDelayMs != 0U))
  2247. {
  2248. PlsrDirectionDelayActive = 1U;
  2249. PlsrDirectionDelayRemainingMs = PlsrActiveConfig.directionDelayMs;
  2250. PlsrRunStatus = PLSR_STATUS_ACCELERATING;
  2251. return 1U;
  2252. }
  2253. PlsrDirectionDelayActive = 0U;
  2254. return PlsrBeginSegmentOutput(startFrequencyHz);
  2255. }
  2256. static void PlsrMarkPersistenceDirty(uint16_t delayMs)
  2257. {
  2258. PlsrPersistenceDirty = 1U;
  2259. PlsrPersistenceDelayMs = delayMs;
  2260. }
  2261. static void PlsrCheckpointPosition(uint8_t wasBusy)
  2262. {
  2263. uint32_t criticalState;
  2264. int32_t position;
  2265. uint8_t positionValid;
  2266. criticalState = PlsrPlatformEnterCritical();
  2267. position = PlsrPosition;
  2268. positionValid = PlsrPositionValid;
  2269. PlsrPositionCheckpointDirty = 0U;
  2270. PlsrPlatformExitCritical(criticalState);
  2271. PlsrPlatformCheckpointPosition(position, positionValid, wasBusy);
  2272. PlsrPositionCheckpointElapsedMs = 0U;
  2273. }
  2274. static void PlsrPollPositionCheckpoint(void)
  2275. {
  2276. if (PlsrPositionCheckpointDirty == 0U)
  2277. {
  2278. PlsrPositionCheckpointElapsedMs = 0U;
  2279. return;
  2280. }
  2281. if (PlsrPositionCheckpointElapsedMs < PLSR_POSITION_CHECKPOINT_MS)
  2282. {
  2283. PlsrPositionCheckpointElapsedMs++;
  2284. }
  2285. if (PlsrPositionCheckpointElapsedMs >= PLSR_POSITION_CHECKPOINT_MS)
  2286. {
  2287. PlsrCheckpointPosition(1U);
  2288. }
  2289. }
  2290. static void PlsrFinishCompleted(void)
  2291. {
  2292. PlsrPlatformStopPulse((uint8_t)PlsrActiveConfig.pulseOutput);
  2293. PlsrRemainingPulses = 0UL;
  2294. PlsrPulseActive = 0U;
  2295. PlsrCutRequested = 0U;
  2296. PlsrBoundaryPending = 0U;
  2297. PlsrBoundaryWasCut = 0U;
  2298. PlsrCurrentFrequencyHz = 0UL;
  2299. PlsrQueuedFrequencyHz = 0UL;
  2300. PlsrCurrentSegment = 0U;
  2301. PlsrSegmentClockStarted = 0U;
  2302. PlsrDirectionDelayActive = 0U;
  2303. PlsrDirectionDelayRemainingMs = 0U;
  2304. PlsrExtEdgePending = 0U;
  2305. PlsrStopRequested = 0U;
  2306. PlsrStopPulsesRemaining = 0U;
  2307. PlsrAbStopArmed = 0U;
  2308. PlsrSeamlessHandoffPending = 0U;
  2309. PlsrDeferredFrequencyPending = 0U;
  2310. PlsrShortProfile.active = 0U;
  2311. PlsrProfileQueueReset();
  2312. PlsrHandoffPlan.valid = 0U;
  2313. PlsrTimerErrorPending = 0U;
  2314. PlsrRamp.active = 0U;
  2315. PlsrExecutor.mode = PLSR_EXEC_IDLE;
  2316. PlsrInvalidateHandoffPlans();
  2317. PlsrRunStatus = PLSR_STATUS_COMPLETED;
  2318. PlsrError = PLSR_ERROR_NONE;
  2319. PlsrCheckpointPosition(0U);
  2320. PlsrMarkPersistenceDirty(PLSR_CONFIG_SAVE_DELAY_MS);
  2321. }
  2322. static void PlsrFinishStopped(void)
  2323. {
  2324. PlsrDiagnosticFinishSegment(0U);
  2325. PlsrPlatformStopPulse((uint8_t)PlsrActiveConfig.pulseOutput);
  2326. PlsrRemainingPulses = 0UL;
  2327. PlsrPulseActive = 0U;
  2328. PlsrCutRequested = 0U;
  2329. PlsrBoundaryPending = 0U;
  2330. PlsrBoundaryWasCut = 0U;
  2331. PlsrCurrentFrequencyHz = 0UL;
  2332. PlsrQueuedFrequencyHz = 0UL;
  2333. PlsrCurrentSegment = 0U;
  2334. PlsrSegmentClockStarted = 0U;
  2335. PlsrDirectionDelayActive = 0U;
  2336. PlsrDirectionDelayRemainingMs = 0U;
  2337. PlsrExtEdgePending = 0U;
  2338. PlsrStopRequested = 0U;
  2339. PlsrStopPulsesRemaining = 0U;
  2340. PlsrAbStopArmed = 0U;
  2341. PlsrSeamlessHandoffPending = 0U;
  2342. PlsrDeferredFrequencyPending = 0U;
  2343. PlsrShortProfile.active = 0U;
  2344. PlsrProfileQueueReset();
  2345. PlsrHandoffPlan.valid = 0U;
  2346. PlsrTimerErrorPending = 0U;
  2347. PlsrRamp.active = 0U;
  2348. PlsrExecutor.mode = PLSR_EXEC_IDLE;
  2349. PlsrInvalidateHandoffPlans();
  2350. PlsrRunStatus = PLSR_STATUS_STOPPED;
  2351. PlsrError = PLSR_ERROR_NONE;
  2352. PlsrCheckpointPosition(0U);
  2353. PlsrMarkPersistenceDirty(PLSR_CONFIG_SAVE_DELAY_MS);
  2354. }
  2355. static void PlsrEnterError(PLSR_ERROR error)
  2356. {
  2357. PlsrDiagnosticFinishSegment(0U);
  2358. PlsrPlatformStopPulse((uint8_t)PlsrActiveConfig.pulseOutput);
  2359. PlsrRemainingPulses = 0UL;
  2360. PlsrPulseActive = 0U;
  2361. PlsrCutRequested = 0U;
  2362. PlsrBoundaryPending = 0U;
  2363. PlsrBoundaryWasCut = 0U;
  2364. PlsrCurrentFrequencyHz = 0UL;
  2365. PlsrQueuedFrequencyHz = 0UL;
  2366. PlsrCurrentSegment = 0U;
  2367. PlsrSegmentClockStarted = 0U;
  2368. PlsrDirectionDelayActive = 0U;
  2369. PlsrDirectionDelayRemainingMs = 0U;
  2370. PlsrExtEdgePending = 0U;
  2371. PlsrStopRequested = 0U;
  2372. PlsrStopPulsesRemaining = 0U;
  2373. PlsrAbStopArmed = 0U;
  2374. PlsrSeamlessHandoffPending = 0U;
  2375. PlsrDeferredFrequencyPending = 0U;
  2376. PlsrShortProfile.active = 0U;
  2377. PlsrProfileQueueReset();
  2378. PlsrHandoffPlan.valid = 0U;
  2379. PlsrTimerErrorPending = 0U;
  2380. PlsrRamp.active = 0U;
  2381. PlsrExecutor.mode = PLSR_EXEC_IDLE;
  2382. PlsrInvalidateHandoffPlans();
  2383. PlsrRunStatus = PLSR_STATUS_ERROR;
  2384. PlsrError = error;
  2385. PlsrCheckpointPosition(0U);
  2386. PlsrMarkPersistenceDirty(PLSR_CONFIG_SAVE_DELAY_MS);
  2387. }
  2388. static void PlsrTransitionToNext(uint8_t allowCarry)
  2389. {
  2390. uint8_t nextSegment;
  2391. uint32_t carryFrequencyHz = PlsrBoundaryFrequencyHz;
  2392. if (PlsrGetNextSegment(&nextSegment) == 0U)
  2393. {
  2394. PlsrFinishCompleted();
  2395. return;
  2396. }
  2397. if (PlsrStartSegment(nextSegment, allowCarry, carryFrequencyHz) == 0U)
  2398. {
  2399. PlsrEnterError(PLSR_ERROR_INVALID_RESOURCE);
  2400. }
  2401. }
  2402. static uint8_t PlsrBuildHandoffPlan(uint8_t sourceSegment,
  2403. const PLSR_CONFIG *frequencyConfig,
  2404. uint32_t carryFrequencyHz,
  2405. PLSR_HANDOFF_PLAN *plan)
  2406. {
  2407. const PLSR_SEGMENT_CONFIG *segment;
  2408. uint8_t nextSegment;
  2409. int64_t displacement;
  2410. uint32_t nextFrequencyHz;
  2411. uint8_t positive;
  2412. uint8_t warmupIndex;
  2413. plan->valid = 0U;
  2414. if ((sourceSegment == 0U)
  2415. || (sourceSegment > PlsrActiveConfig.segmentCount))
  2416. {
  2417. return 0U;
  2418. }
  2419. segment = &PlsrActiveConfig.segments[sourceSegment - 1U];
  2420. if (segment->waitType != PLSR_EXT_OR_COMPLETE)
  2421. {
  2422. return 0U;
  2423. }
  2424. if (segment->jumpSegment != 0U)
  2425. {
  2426. nextSegment = (uint8_t)segment->jumpSegment;
  2427. }
  2428. else if (sourceSegment < PlsrActiveConfig.segmentCount)
  2429. {
  2430. nextSegment = (uint8_t)(sourceSegment + 1U);
  2431. }
  2432. else
  2433. {
  2434. return 0U;
  2435. }
  2436. if (PlsrActiveConfig.positionMode == PLSR_POSITION_ABSOLUTE)
  2437. {
  2438. displacement = (int64_t)PlsrActiveConfig.segments[nextSegment - 1U].pulses
  2439. - (int64_t)segment->pulses;
  2440. }
  2441. else
  2442. {
  2443. displacement = PlsrActiveConfig.segments[nextSegment - 1U].pulses;
  2444. }
  2445. if (displacement == 0)
  2446. {
  2447. return 0U;
  2448. }
  2449. positive = (displacement > 0) ? 1U : 0U;
  2450. plan->magnitude = (displacement < 0) ? (uint64_t)(-displacement)
  2451. : (uint64_t)displacement;
  2452. if (carryFrequencyHz == 0UL)
  2453. {
  2454. carryFrequencyHz =
  2455. PlsrResolvedSegmentFrequency(frequencyConfig, sourceSegment - 1U);
  2456. }
  2457. nextFrequencyHz =
  2458. PlsrResolvedSegmentFrequency(frequencyConfig, nextSegment - 1U);
  2459. if (PlsrPrepareShortProfile(&plan->profile, nextSegment,
  2460. carryFrequencyHz, nextFrequencyHz,
  2461. plan->magnitude) == 0U)
  2462. {
  2463. return 0U;
  2464. }
  2465. {
  2466. PLSR_PROFILE_ENTRY firstEntry;
  2467. PLSR_PROFILE_ENTRY secondEntry;
  2468. if (PlsrShortProfileTakeRun(&plan->profile, &firstEntry) == 0U)
  2469. {
  2470. return 0U;
  2471. }
  2472. plan->firstSetting = firstEntry.setting;
  2473. plan->firstFrequencyHz = firstEntry.setting.actualFrequencyHz;
  2474. plan->firstRequestedFrequencyHz = firstEntry.requestedFrequencyHz;
  2475. plan->firstRepeatCount = firstEntry.repeatCount;
  2476. if (PlsrShortProfileTakeRun(&plan->profile, &secondEntry) != 0U)
  2477. {
  2478. plan->secondSetting = secondEntry.setting;
  2479. plan->secondFrequencyHz = secondEntry.setting.actualFrequencyHz;
  2480. plan->secondRequestedFrequencyHz =
  2481. secondEntry.requestedFrequencyHz;
  2482. plan->secondRepeatCount = secondEntry.repeatCount;
  2483. }
  2484. else
  2485. {
  2486. plan->secondSetting = firstEntry.setting;
  2487. plan->secondFrequencyHz = firstEntry.setting.actualFrequencyHz;
  2488. plan->secondRequestedFrequencyHz =
  2489. firstEntry.requestedFrequencyHz;
  2490. plan->secondRepeatCount = 0UL;
  2491. }
  2492. }
  2493. if ((plan->firstRepeatCount == 0UL)
  2494. || (plan->firstFrequencyHz == 0UL))
  2495. {
  2496. return 0U;
  2497. }
  2498. plan->warmupCount = 0U;
  2499. for (warmupIndex = 0U;
  2500. (warmupIndex < PLSR_HANDOFF_WARMUP_ITEMS)
  2501. && (plan->profile.nextPeriod < plan->profile.pulseCount);
  2502. warmupIndex++)
  2503. {
  2504. PLSR_PROFILE_ENTRY *entry = &plan->warmup[warmupIndex];
  2505. if (PlsrShortProfileTakeRun(&plan->profile, entry) == 0U)
  2506. {
  2507. return 0U;
  2508. }
  2509. plan->warmupCount++;
  2510. }
  2511. plan->firstFrequencyHz = plan->firstSetting.actualFrequencyHz;
  2512. plan->secondFrequencyHz = plan->secondSetting.actualFrequencyHz;
  2513. plan->nextSegment = nextSegment;
  2514. plan->positive = positive;
  2515. plan->valid = 1U;
  2516. return 1U;
  2517. }
  2518. static uint8_t PlsrBuildHandoffPlanBank(
  2519. const PLSR_CONFIG *frequencyConfig)
  2520. {
  2521. uint8_t buildBank = (uint8_t)(PlsrPreparedHandoffBank ^ 1U);
  2522. uint8_t sourceSegment;
  2523. PLSR_HANDOFF_PLAN *destination;
  2524. for (sourceSegment = 0U;
  2525. sourceSegment < PLSR_SEGMENT_COUNT_MAX;
  2526. sourceSegment++)
  2527. {
  2528. PlsrPreparedHandoffPlans[buildBank][sourceSegment].valid = 0U;
  2529. }
  2530. for (sourceSegment = 1U;
  2531. sourceSegment <= PlsrActiveConfig.segmentCount;
  2532. sourceSegment++)
  2533. {
  2534. destination =
  2535. &PlsrPreparedHandoffPlans[buildBank][sourceSegment - 1U];
  2536. (void)PlsrBuildHandoffPlan(sourceSegment, frequencyConfig, 0UL,
  2537. destination);
  2538. }
  2539. return buildBank;
  2540. }
  2541. static void PlsrRefreshCurrentHandoffPlan(uint32_t terminalFrequencyHz)
  2542. {
  2543. PLSR_PLATFORM_TIMER_SETTING terminalSetting;
  2544. PLSR_HANDOFF_PLAN *destination;
  2545. uint8_t currentSegment = PlsrCurrentSegment;
  2546. uint8_t preparedBank = PlsrPreparedHandoffBank;
  2547. if ((currentSegment == 0U)
  2548. || (currentSegment > PlsrActiveConfig.segmentCount)
  2549. || (PlsrPlatformBuildTimerSetting(
  2550. (uint8_t)PlsrActiveConfig.pulseOutput,
  2551. (uint8_t)PlsrActiveConfig.outputMode,
  2552. terminalFrequencyHz, &terminalSetting) == 0U))
  2553. {
  2554. return;
  2555. }
  2556. destination = &PlsrPreparedHandoffPlans[preparedBank]
  2557. [currentSegment - 1U];
  2558. (void)PlsrBuildHandoffPlan(currentSegment, &PlsrActiveConfig,
  2559. terminalSetting.actualFrequencyHz,
  2560. destination);
  2561. }
  2562. static uint8_t PlsrSelectPreparedHandoffPlan(PLSR_HANDOFF_PLAN *plan)
  2563. {
  2564. const PLSR_HANDOFF_PLAN *prepared;
  2565. uint8_t preparedBank;
  2566. uint8_t currentSegment;
  2567. plan->valid = 0U;
  2568. currentSegment = PlsrCurrentSegment;
  2569. if ((PlsrRemainingPulses != 1UL)
  2570. || (PlsrStopRequested != 0U)
  2571. || (PlsrCountOverflowPending != 0U)
  2572. || (PlsrCutRequested != 0U)
  2573. || (PlsrAbStopArmed != 0U)
  2574. || (currentSegment == 0U)
  2575. || (currentSegment > PlsrActiveConfig.segmentCount))
  2576. {
  2577. return 0U;
  2578. }
  2579. preparedBank = PlsrPreparedHandoffBank;
  2580. prepared = &PlsrPreparedHandoffPlans[preparedBank][currentSegment - 1U];
  2581. if ((prepared->valid == 0U)
  2582. || (prepared->positive != PlsrCountPositive))
  2583. {
  2584. return 0U;
  2585. }
  2586. *plan = *prepared;
  2587. return 1U;
  2588. }
  2589. static uint8_t PlsrStageCountedHandoff(void)
  2590. {
  2591. const PLSR_HANDOFF_PLAN *prepared;
  2592. PLSR_HANDOFF_PLAN candidate;
  2593. PLSR_PROFILE_ENTRY entry;
  2594. uint32_t criticalState;
  2595. uint32_t writeIndex;
  2596. uint16_t required;
  2597. uint8_t currentSegment;
  2598. uint8_t index;
  2599. if ((PlsrActiveConfig.outputMode != PLSR_OUTPUT_PULSE_DIR)
  2600. || (PlsrCountedHandoffStaged != 0U)
  2601. || (PlsrStopRequested != 0U)
  2602. || (PlsrCutRequested != 0U)
  2603. || (PlsrProfileQueue.generatorComplete == 0U))
  2604. {
  2605. return 1U;
  2606. }
  2607. currentSegment = PlsrCurrentSegment;
  2608. if ((currentSegment == 0U)
  2609. || (currentSegment > PlsrActiveConfig.segmentCount))
  2610. {
  2611. return 1U;
  2612. }
  2613. prepared = &PlsrPreparedHandoffPlans[PlsrPreparedHandoffBank]
  2614. [currentSegment - 1U];
  2615. if ((prepared->valid == 0U)
  2616. || (prepared->positive != PlsrCountPositive))
  2617. {
  2618. return 1U;
  2619. }
  2620. candidate = *prepared;
  2621. required = (uint16_t)(1U + candidate.warmupCount
  2622. + ((candidate.secondRepeatCount != 0UL)
  2623. ? 1U : 0U));
  2624. criticalState = PlsrPlatformEnterCritical();
  2625. if ((PlsrCountedHandoffStaged != 0U)
  2626. || (PlsrProfileQueue.generatorComplete == 0U)
  2627. || ((uint16_t)(PLSR_PROFILE_QUEUE_CAPACITY
  2628. - PlsrProfileQueueCount()) < required))
  2629. {
  2630. PlsrPlatformExitCritical(criticalState);
  2631. return 1U;
  2632. }
  2633. writeIndex = PlsrProfileQueue.writeIndex;
  2634. entry.setting = candidate.firstSetting;
  2635. entry.requestedFrequencyHz = candidate.firstRequestedFrequencyHz;
  2636. entry.repeatCount = candidate.firstRepeatCount;
  2637. entry.startsNextSegment = 1U;
  2638. PlsrProfileQueue.entries[writeIndex & PLSR_PROFILE_QUEUE_MASK] = entry;
  2639. writeIndex++;
  2640. if (candidate.secondRepeatCount != 0UL)
  2641. {
  2642. entry.setting = candidate.secondSetting;
  2643. entry.requestedFrequencyHz =
  2644. candidate.secondRequestedFrequencyHz;
  2645. entry.repeatCount = candidate.secondRepeatCount;
  2646. entry.startsNextSegment = 0U;
  2647. PlsrProfileQueue.entries[writeIndex & PLSR_PROFILE_QUEUE_MASK] = entry;
  2648. writeIndex++;
  2649. }
  2650. for (index = 0U; index < candidate.warmupCount; index++)
  2651. {
  2652. entry = candidate.warmup[index];
  2653. entry.startsNextSegment = 0U;
  2654. PlsrProfileQueue.entries[writeIndex & PLSR_PROFILE_QUEUE_MASK] = entry;
  2655. writeIndex++;
  2656. }
  2657. PlsrProfileQueue.writeIndex = writeIndex;
  2658. PlsrCopyShortProfile(&PlsrProfileQueue.producerProfile,
  2659. &candidate.profile);
  2660. PlsrProfileQueue.producerEpoch = PlsrSegmentEpoch + 1UL;
  2661. PlsrProfileQueue.producerSegment = candidate.nextSegment;
  2662. PlsrProfileQueue.generatorComplete =
  2663. ((candidate.profile.active == 0U)
  2664. || (candidate.profile.nextPeriod >= candidate.profile.pulseCount))
  2665. ? 1U : 0U;
  2666. PlsrProfileQueue.active = 1U;
  2667. PlsrHandoffPlan = candidate;
  2668. PlsrHandoffPlan.valid = 1U;
  2669. PlsrCountedHandoffStaged = 1U;
  2670. PlsrPlatformExitCritical(criticalState);
  2671. return 1U;
  2672. }
  2673. static uint8_t PlsrSyncCountedProgress(void)
  2674. {
  2675. uint64_t observed;
  2676. uint64_t delta;
  2677. uint64_t remaining;
  2678. int64_t nextPosition;
  2679. observed = PlsrPlatformObservedPulses(
  2680. (uint8_t)PlsrActiveConfig.pulseOutput);
  2681. if (observed < PlsrCountedObservedPublished)
  2682. {
  2683. return 0U;
  2684. }
  2685. delta = observed - PlsrCountedObservedPublished;
  2686. if (delta == 0ULL)
  2687. {
  2688. return 1U;
  2689. }
  2690. remaining = PlsrRemainingPulses;
  2691. if (delta > remaining)
  2692. {
  2693. delta = remaining;
  2694. #if PLSR_COUNT_ERROR_CHECK_ENABLED
  2695. PlsrCountOverflowPending = 1U;
  2696. #endif
  2697. }
  2698. if (PlsrCountPositive != 0U)
  2699. {
  2700. nextPosition = (int64_t)PlsrPosition + (int64_t)delta;
  2701. }
  2702. else
  2703. {
  2704. nextPosition = (int64_t)PlsrPosition - (int64_t)delta;
  2705. }
  2706. if ((nextPosition > (int64_t)INT32_MAX)
  2707. || (nextPosition < (int64_t)INT32_MIN))
  2708. {
  2709. PlsrPositionValid = 0U;
  2710. #if PLSR_COUNT_ERROR_CHECK_ENABLED
  2711. PlsrCountOverflowPending = 1U;
  2712. #endif
  2713. }
  2714. else
  2715. {
  2716. PlsrPosition = (int32_t)nextPosition;
  2717. }
  2718. PlsrRemainingPulses = remaining - delta;
  2719. PlsrCountedObservedPublished = observed;
  2720. PlsrPositionCheckpointDirty = 1U;
  2721. return 1U;
  2722. }
  2723. uint8_t PlsrExecTakeCountedRunIrq(
  2724. uint8_t pulseOutput,
  2725. PLSR_PLATFORM_TIMER_SETTING *setting,
  2726. uint32_t *pulseCount,
  2727. uint8_t *startsNextSegment)
  2728. {
  2729. const PLSR_PROFILE_ENTRY *entry;
  2730. uint32_t readIndex;
  2731. uint32_t nextReadIndex;
  2732. if ((pulseOutput != (uint8_t)PlsrActiveConfig.pulseOutput)
  2733. || (setting == NULL) || (pulseCount == NULL)
  2734. || (startsNextSegment == NULL)
  2735. || (PlsrPulseActive == 0U))
  2736. {
  2737. return PLSR_EXEC_RUN_FAILED;
  2738. }
  2739. readIndex = PlsrProfileQueue.readIndex;
  2740. if (readIndex == PlsrProfileQueue.writeIndex)
  2741. {
  2742. if (PlsrProfileQueue.generatorComplete != 0U)
  2743. {
  2744. return PLSR_EXEC_RUN_DONE;
  2745. }
  2746. return PLSR_EXEC_RUN_FAILED;
  2747. }
  2748. entry = &PlsrProfileQueue.entries[readIndex & PLSR_PROFILE_QUEUE_MASK];
  2749. if (entry->repeatCount == 0UL)
  2750. {
  2751. return PLSR_EXEC_RUN_FAILED;
  2752. }
  2753. /* 先校验 handoff 前置条件,再推进读索引:失败时该项不被消费。
  2754. 不在此处更新任何执行状态(Pending/active 等),全部由任务消费事件时做。 */
  2755. if (entry->startsNextSegment != 0U)
  2756. {
  2757. if ((PlsrCountedHandoffStaged == 0U)
  2758. || (PlsrHandoffPlan.valid == 0U))
  2759. {
  2760. return PLSR_EXEC_RUN_FAILED;
  2761. }
  2762. }
  2763. *setting = entry->setting;
  2764. *pulseCount = entry->repeatCount;
  2765. *startsNextSegment = entry->startsNextSegment;
  2766. nextReadIndex = readIndex + 1UL;
  2767. PlsrProfileQueue.readIndex = nextReadIndex;
  2768. /* 记录硬件即将生效的频率(事实镜像),不做任何状态转换。 */
  2769. PlsrQueuedFrequencyHz = entry->setting.actualFrequencyHz;
  2770. return PLSR_EXEC_RUN_READY;
  2771. }
  2772. void PlsrExecCountedSegmentBoundaryIrq(uint8_t pulseOutput,
  2773. uint32_t completedPulses)
  2774. {
  2775. if (pulseOutput != (uint8_t)PlsrActiveConfig.pulseOutput)
  2776. {
  2777. return;
  2778. }
  2779. if (PlsrHandoffPlan.valid == 0U)
  2780. {
  2781. PlsrCountedFaultEvent = 1U;
  2782. return;
  2783. }
  2784. /* 只置事件并快照:handoff 计划 + 边界累计计数(由平台层在 run 完成
  2785. 累加后传入,IRQ 内不做带副作用的计数读取)。段切换簿记全部由任务
  2786. 在 PlsrExecServiceCountedBoundaryEvent 完成。 */
  2787. PlsrCountedBoundaryPlan = PlsrHandoffPlan;
  2788. PlsrCountedBoundaryObserved = completedPulses;
  2789. PlsrCountedBoundaryEvent = 1U;
  2790. }
  2791. static void PlsrExecServiceCountedBoundaryEvent(void);
  2792. /* 任务上下文:消费 counted 流的全部 IRQ 事件(流故障 + 段边界)。
  2793. 段切换簿记与错误标志写入均在此完成,IRQ 内不再做状态转换。 */
  2794. static void PlsrExecServiceCountedEvents(void)
  2795. {
  2796. if (PlsrCountedFaultEvent != 0U)
  2797. {
  2798. PlsrCountedFaultEvent = 0U;
  2799. PlsrTimerErrorPending = 1U;
  2800. }
  2801. PlsrExecServiceCountedBoundaryEvent();
  2802. }
  2803. /* 任务上下文:消费段边界事件,完成全部段切换簿记。
  2804. 硬件连续性不依赖本函数(下一段首 run 已由队列预装载),晚 1ms 消费无影响。 */
  2805. static void PlsrExecServiceCountedBoundaryEvent(void)
  2806. {
  2807. PLSR_HANDOFF_PLAN plan;
  2808. uint64_t observed;
  2809. uint64_t delta;
  2810. int64_t nextPosition;
  2811. uint32_t currentFrequencyHz;
  2812. uint32_t queuedFrequencyHz;
  2813. uint8_t nextSegment;
  2814. if (PlsrCountedBoundaryEvent == 0U)
  2815. {
  2816. return;
  2817. }
  2818. PlsrCountedBoundaryEvent = 0U;
  2819. plan = PlsrCountedBoundaryPlan;
  2820. observed = PlsrCountedBoundaryObserved;
  2821. nextSegment = plan.nextSegment;
  2822. if ((nextSegment == 0U)
  2823. || (nextSegment > PlsrActiveConfig.segmentCount))
  2824. {
  2825. PlsrTimerErrorPending = 1U;
  2826. return;
  2827. }
  2828. /* 用 IRQ 边界时刻的计数快照结算旧段:任务消费时下一 run 可能已发出
  2829. 若干脉冲,直接读当前硬件计数会把下一段脉冲算进旧段。 */
  2830. if (observed < PlsrCountedObservedPublished)
  2831. {
  2832. PlsrTimerErrorPending = 1U;
  2833. return;
  2834. }
  2835. delta = observed - PlsrCountedObservedPublished;
  2836. if (delta > PlsrRemainingPulses)
  2837. {
  2838. delta = PlsrRemainingPulses;
  2839. #if PLSR_COUNT_ERROR_CHECK_ENABLED
  2840. PlsrCountOverflowPending = 1U;
  2841. #endif
  2842. }
  2843. if (PlsrCountPositive != 0U)
  2844. {
  2845. nextPosition = (int64_t)PlsrPosition + (int64_t)delta;
  2846. }
  2847. else
  2848. {
  2849. nextPosition = (int64_t)PlsrPosition - (int64_t)delta;
  2850. }
  2851. if ((nextPosition > (int64_t)INT32_MAX)
  2852. || (nextPosition < (int64_t)INT32_MIN))
  2853. {
  2854. PlsrPositionValid = 0U;
  2855. #if PLSR_COUNT_ERROR_CHECK_ENABLED
  2856. PlsrCountOverflowPending = 1U;
  2857. #endif
  2858. }
  2859. else
  2860. {
  2861. PlsrPosition = (int32_t)nextPosition;
  2862. }
  2863. PlsrRemainingPulses -= delta;
  2864. PlsrCountedObservedPublished = observed;
  2865. PlsrPositionCheckpointDirty = 1U;
  2866. if (PlsrRemainingPulses != 0ULL)
  2867. {
  2868. PlsrTimerErrorPending = 1U;
  2869. return;
  2870. }
  2871. PlsrDiagnosticFinishSegment(1U);
  2872. PlsrSegmentEpoch++;
  2873. PlsrCurrentSegment = nextSegment;
  2874. PlsrRemainingPulses = plan.magnitude;
  2875. PlsrCountPositive = plan.positive;
  2876. PlsrCurrentFrequencyHz = plan.firstFrequencyHz;
  2877. PlsrBoundaryFrequencyHz = plan.firstFrequencyHz;
  2878. PlsrSegmentClockStarted = 1U;
  2879. PlsrSegmentElapsedMs = 0UL;
  2880. PlsrWaitElapsedMs = 0UL;
  2881. PlsrBoundaryRampStarted = 0U;
  2882. PlsrBoundaryPending = 0U;
  2883. PlsrBoundaryWasCut = 0U;
  2884. PlsrCutRequested = 0U;
  2885. PlsrFrequencyUpdatePending = 0U;
  2886. PlsrDeferredFrequencyPending = 0U;
  2887. PlsrExtEdgePending = 0U;
  2888. PlsrExtPreviousLevel =
  2889. PlsrPlatformReadInput((uint8_t)PlsrActiveConfig.extInput);
  2890. PlsrCopyShortProfile(&PlsrShortProfile,
  2891. &PlsrProfileQueue.producerProfile);
  2892. PlsrDiagnosticBeginSegment(nextSegment, plan.magnitude, plan.positive);
  2893. PlsrSeamlessHandoffPending = 1U;
  2894. PlsrCountedHandoffStaged = 0U;
  2895. PlsrHandoffPlan.valid = 0U;
  2896. PlsrExecutor.generation++;
  2897. PlsrExecutor.mode = (PlsrProfileQueue.generatorComplete != 0U)
  2898. ? PLSR_EXEC_STEP_TABLE
  2899. : PLSR_EXEC_STREAM;
  2900. currentFrequencyHz = PlsrCurrentFrequencyHz;
  2901. queuedFrequencyHz = PlsrQueuedFrequencyHz;
  2902. if (queuedFrequencyHz > currentFrequencyHz)
  2903. {
  2904. PlsrRunStatus = PLSR_STATUS_ACCELERATING;
  2905. }
  2906. else if (queuedFrequencyHz < currentFrequencyHz)
  2907. {
  2908. PlsrRunStatus = PLSR_STATUS_DECELERATING;
  2909. }
  2910. else
  2911. {
  2912. PlsrRunStatus = PLSR_STATUS_RUNNING;
  2913. }
  2914. }
  2915. void PlsrExecCountedStreamFaultIrq(uint8_t pulseOutput)
  2916. {
  2917. if (pulseOutput == (uint8_t)PlsrActiveConfig.pulseOutput)
  2918. {
  2919. /* 只置事件:任务消费时统一置 PlsrTimerErrorPending。 */
  2920. PlsrCountedFaultEvent = 1U;
  2921. }
  2922. }
  2923. static uint8_t PlsrPrepareFutureHandoffQueue(void)
  2924. {
  2925. const PLSR_HANDOFF_PLAN *prepared;
  2926. uint8_t currentSegment = PlsrCurrentSegment;
  2927. uint8_t preparedBank = PlsrPreparedHandoffBank;
  2928. PlsrProfileQueueReset();
  2929. if ((currentSegment == 0U)
  2930. || (currentSegment > PlsrActiveConfig.segmentCount))
  2931. {
  2932. return 1U;
  2933. }
  2934. prepared = &PlsrPreparedHandoffPlans[preparedBank][currentSegment - 1U];
  2935. if ((prepared->valid == 0U) || (prepared->profile.active == 0U)
  2936. || (prepared->profile.nextPeriod >= prepared->profile.pulseCount))
  2937. {
  2938. return 1U;
  2939. }
  2940. (void)PlsrProfileQueueBegin(&prepared->profile,
  2941. PlsrSegmentEpoch + 1UL,
  2942. prepared->nextSegment,
  2943. preparedBank);
  2944. if (PlsrProfileQueueFill(PLSR_PROFILE_QUEUE_CAPACITY) == 0U)
  2945. {
  2946. PlsrProfileQueueReset();
  2947. return 0U;
  2948. }
  2949. return 1U;
  2950. }
  2951. /* The first two periods are already in the timer pipeline. Seed a small
  2952. precomputed tail here so the 1 ms producer has time to resume without
  2953. doing planner math in the pulse IRQ. */
  2954. static void PlsrActivateHandoffQueueFromIrq(
  2955. const PLSR_HANDOFF_PLAN *plan,
  2956. uint32_t producerEpoch)
  2957. {
  2958. uint8_t index;
  2959. PlsrProfileQueue.generation++;
  2960. PlsrProfileQueue.readIndex = 0U;
  2961. PlsrProfileQueue.writeIndex = plan->warmupCount;
  2962. for (index = 0U; index < plan->warmupCount; index++)
  2963. {
  2964. PlsrProfileQueue.entries[index] = plan->warmup[index];
  2965. }
  2966. PlsrCopyShortProfile(&PlsrProfileQueue.producerProfile,
  2967. &plan->profile);
  2968. PlsrProfileQueue.producerEpoch = producerEpoch;
  2969. PlsrProfileQueue.producerSegment = plan->nextSegment;
  2970. PlsrProfileQueue.preparedHandoffBank = PlsrPreparedHandoffBank;
  2971. PlsrProfileQueue.generatorComplete =
  2972. (plan->profile.active == 0U) ? 1U : 0U;
  2973. PlsrProfileQueue.active =
  2974. ((plan->warmupCount != 0U) || (plan->profile.active != 0U))
  2975. ? 1U : 0U;
  2976. PlsrCopyShortProfile(&PlsrShortProfile, &plan->profile);
  2977. if (PlsrProfileQueue.active != 0U)
  2978. {
  2979. PlsrShortProfile.active = 1U;
  2980. }
  2981. }
  2982. static PLSR_PLATFORM_QUEUE_RESULT PlsrPrimeHandoff(void)
  2983. {
  2984. PLSR_HANDOFF_PLAN candidatePlan;
  2985. uint32_t actualFrequencyHz;
  2986. PLSR_PLATFORM_QUEUE_RESULT result;
  2987. PlsrHandoffPlan.valid = 0U;
  2988. if (PlsrAbStopArmed != 0U)
  2989. {
  2990. return PLSR_PLATFORM_QUEUE_FAILED;
  2991. }
  2992. if (PlsrSelectPreparedHandoffPlan(&candidatePlan) == 0U)
  2993. {
  2994. return PLSR_PLATFORM_QUEUE_FAILED;
  2995. }
  2996. PlsrDeferredFrequencyPending = 0U;
  2997. result = PlsrPlatformLoadPreparedFromIrq(
  2998. (uint8_t)PlsrActiveConfig.pulseOutput,
  2999. &candidatePlan.firstSetting, &actualFrequencyHz);
  3000. if (result != PLSR_PLATFORM_QUEUE_APPLIED)
  3001. {
  3002. if (result == PLSR_PLATFORM_QUEUE_FAILED)
  3003. {
  3004. PlsrTimerErrorPending = 1U;
  3005. }
  3006. return result;
  3007. }
  3008. PlsrDiagnosticRecordFrequency(candidatePlan.firstRequestedFrequencyHz,
  3009. candidatePlan.firstSetting.actualFrequencyHz,
  3010. actualFrequencyHz);
  3011. PlsrDiagnosticQueuedExpectedHz =
  3012. candidatePlan.firstSetting.actualFrequencyHz;
  3013. PlsrQueuedFrequencyHz = actualFrequencyHz;
  3014. PlsrHandoffPlan = candidatePlan;
  3015. PlsrHandoffPlan.firstFrequencyHz = actualFrequencyHz;
  3016. PlsrHandoffPlan.valid = 1U;
  3017. return PLSR_PLATFORM_QUEUE_APPLIED;
  3018. }
  3019. static PLSR_PLATFORM_QUEUE_RESULT PlsrTryContinuousHandoff(void)
  3020. {
  3021. uint32_t actualQueuedFrequencyHz;
  3022. uint32_t currentFrequencyHz;
  3023. uint32_t queuedFrequencyHz;
  3024. uint8_t nextSegment = PlsrHandoffPlan.nextSegment;
  3025. uint64_t magnitude = PlsrHandoffPlan.magnitude;
  3026. uint8_t positive = PlsrHandoffPlan.positive;
  3027. PLSR_PLATFORM_QUEUE_RESULT result;
  3028. if ((PlsrHandoffPlan.valid == 0U)
  3029. || (PlsrStopRequested != 0U)
  3030. || (PlsrCountOverflowPending != 0U)
  3031. || (PlsrCutRequested != 0U)
  3032. || (PlsrAbStopArmed != 0U)
  3033. || (PlsrCurrentFrequencyHz != PlsrHandoffPlan.firstFrequencyHz)
  3034. || (nextSegment == 0U)
  3035. || (nextSegment > PlsrActiveConfig.segmentCount))
  3036. {
  3037. return PLSR_PLATFORM_QUEUE_FAILED;
  3038. }
  3039. PlsrDeferredFrequencyPending = 0U;
  3040. result = PlsrPlatformLoadPreparedFromIrq(
  3041. (uint8_t)PlsrActiveConfig.pulseOutput,
  3042. &PlsrHandoffPlan.secondSetting, &actualQueuedFrequencyHz);
  3043. if (result == PLSR_PLATFORM_QUEUE_STALE)
  3044. {
  3045. return result;
  3046. }
  3047. if (result == PLSR_PLATFORM_QUEUE_FAILED)
  3048. {
  3049. PlsrShortProfile.active = 0U;
  3050. PlsrHandoffPlan.valid = 0U;
  3051. PlsrTimerErrorPending = 1U;
  3052. return result;
  3053. }
  3054. PlsrDiagnosticRecordFrequency(
  3055. PlsrHandoffPlan.secondRequestedFrequencyHz,
  3056. PlsrHandoffPlan.secondSetting.actualFrequencyHz,
  3057. actualQueuedFrequencyHz);
  3058. PlsrDiagnosticQueuedExpectedHz =
  3059. PlsrHandoffPlan.secondSetting.actualFrequencyHz;
  3060. PlsrQueuedFrequencyHz = actualQueuedFrequencyHz;
  3061. PlsrDiagnosticFinishSegment(1U);
  3062. PlsrSegmentEpoch++;
  3063. PlsrActivateHandoffQueueFromIrq(&PlsrHandoffPlan,
  3064. PlsrSegmentEpoch);
  3065. PlsrCurrentSegment = nextSegment;
  3066. PlsrRemainingPulses = magnitude;
  3067. PlsrCountPositive = positive;
  3068. PlsrBoundaryFrequencyHz = PlsrCurrentFrequencyHz;
  3069. PlsrSegmentClockStarted = 1U;
  3070. PlsrSegmentElapsedMs = 0UL;
  3071. PlsrWaitElapsedMs = 0UL;
  3072. PlsrBoundaryRampStarted = 0U;
  3073. PlsrBoundaryPending = 0U;
  3074. PlsrBoundaryWasCut = 0U;
  3075. PlsrCutRequested = 0U;
  3076. PlsrFrequencyUpdatePending = 0U;
  3077. PlsrDeferredFrequencyPending = 0U;
  3078. PlsrExtEdgePending = 0U;
  3079. PlsrExtPreviousLevel =
  3080. PlsrPlatformReadInput((uint8_t)PlsrActiveConfig.extInput);
  3081. PlsrDiagnosticBeginSegment(nextSegment, magnitude, positive);
  3082. PlsrSeamlessHandoffPending = 1U;
  3083. PlsrHandoffPlan.valid = 0U;
  3084. if (PlsrRemainingPulses == 1UL)
  3085. {
  3086. result = PlsrPrimeHandoff();
  3087. if (result == PLSR_PLATFORM_QUEUE_STALE)
  3088. {
  3089. return result;
  3090. }
  3091. }
  3092. (void)PlsrQueueFinalAbBoundaryFromIrq();
  3093. queuedFrequencyHz = PlsrQueuedFrequencyHz;
  3094. currentFrequencyHz = PlsrCurrentFrequencyHz;
  3095. if (PlsrShortProfile.active != 0U)
  3096. {
  3097. if (queuedFrequencyHz > currentFrequencyHz)
  3098. {
  3099. PlsrRunStatus = PLSR_STATUS_ACCELERATING;
  3100. }
  3101. else if (queuedFrequencyHz < currentFrequencyHz)
  3102. {
  3103. PlsrRunStatus = PLSR_STATUS_DECELERATING;
  3104. }
  3105. else
  3106. {
  3107. PlsrRunStatus = PLSR_STATUS_RUNNING;
  3108. }
  3109. }
  3110. else
  3111. {
  3112. PlsrRunStatus = PLSR_STATUS_RUNNING;
  3113. }
  3114. return PLSR_PLATFORM_QUEUE_APPLIED;
  3115. }
  3116. static void PlsrHandleBoundary(uint8_t extEdge)
  3117. {
  3118. const PLSR_SEGMENT_CONFIG *segment;
  3119. uint8_t wasCut = PlsrBoundaryWasCut;
  3120. PlsrPlatformStopPulse((uint8_t)PlsrActiveConfig.pulseOutput);
  3121. PlsrBoundaryPending = 0U;
  3122. PlsrBoundaryWasCut = 0U;
  3123. PlsrPulseActive = 0U;
  3124. PlsrCurrentFrequencyHz = 0UL;
  3125. PlsrQueuedFrequencyHz = 0UL;
  3126. PlsrShortProfile.active = 0U;
  3127. PlsrProfileQueueReset();
  3128. PlsrHandoffPlan.valid = 0U;
  3129. PlsrDeferredFrequencyPending = 0U;
  3130. PlsrAbStopArmed = 0U;
  3131. PlsrCheckpointPosition(1U);
  3132. if (PlsrTimerErrorPending != 0U)
  3133. {
  3134. PlsrTimerErrorPending = 0U;
  3135. PlsrEnterError(PLSR_ERROR_TIMER);
  3136. return;
  3137. }
  3138. #if PLSR_COUNT_ERROR_CHECK_ENABLED
  3139. if (PlsrCountOverflowPending != 0U)
  3140. {
  3141. PlsrCountOverflowPending = 0U;
  3142. PlsrEnterError(PLSR_ERROR_COUNT);
  3143. return;
  3144. }
  3145. #else
  3146. /* 计数错误检查暂时关闭:偏差已由同步路径钳制,标志直接清除。 */
  3147. PlsrCountOverflowPending = 0U;
  3148. #endif
  3149. if (PlsrStopRequested != 0U)
  3150. {
  3151. PlsrFinishStopped();
  3152. return;
  3153. }
  3154. if ((PlsrCurrentSegment == 0U)
  3155. || (PlsrCurrentSegment > PlsrActiveConfig.segmentCount))
  3156. {
  3157. PlsrEnterError(PLSR_ERROR_INTERNAL);
  3158. return;
  3159. }
  3160. segment = &PlsrActiveConfig.segments[PlsrCurrentSegment - 1U];
  3161. if (wasCut != 0U)
  3162. {
  3163. PlsrTransitionToNext(
  3164. (PlsrActiveConfig.sendMode == PLSR_SEND_SUBSEQUENT) ? 1U : 0U);
  3165. return;
  3166. }
  3167. switch (segment->waitType)
  3168. {
  3169. case PLSR_WAIT_TIME:
  3170. PlsrWaitElapsedMs = 0UL;
  3171. PlsrRunStatus = PLSR_STATUS_WAITING;
  3172. break;
  3173. case PLSR_WAIT_SIGNAL:
  3174. if (PlsrPlatformReadInput((uint8_t)PlsrActiveConfig.waitInput) != 0U)
  3175. {
  3176. PlsrTransitionToNext(0U);
  3177. }
  3178. else
  3179. {
  3180. PlsrRunStatus = PLSR_STATUS_WAITING;
  3181. }
  3182. break;
  3183. case PLSR_ACT_TIME:
  3184. if (PlsrSegmentElapsedMs >= segment->actTimeMs)
  3185. {
  3186. PlsrTransitionToNext(0U);
  3187. }
  3188. else
  3189. {
  3190. PlsrRunStatus = PLSR_STATUS_WAITING;
  3191. }
  3192. break;
  3193. case PLSR_EXT_SIGNAL:
  3194. if (extEdge != 0U)
  3195. {
  3196. PlsrTransitionToNext(0U);
  3197. }
  3198. else
  3199. {
  3200. PlsrRunStatus = PLSR_STATUS_WAITING;
  3201. }
  3202. break;
  3203. case PLSR_EXT_OR_COMPLETE:
  3204. PlsrTransitionToNext(1U);
  3205. break;
  3206. default:
  3207. PlsrEnterError(PLSR_ERROR_INTERNAL);
  3208. break;
  3209. }
  3210. }
  3211. static void PlsrRequestCut(uint32_t expectedEpoch)
  3212. {
  3213. uint32_t criticalState = PlsrPlatformEnterCritical();
  3214. if (PlsrSegmentEpoch != expectedEpoch)
  3215. {
  3216. PlsrPlatformExitCritical(criticalState);
  3217. return;
  3218. }
  3219. if (PlsrBoundaryPending != 0U)
  3220. {
  3221. PlsrBoundaryWasCut = 1U;
  3222. }
  3223. else if (PlsrPulseActive != 0U)
  3224. {
  3225. PlsrCutRequested = 1U;
  3226. (void)PlsrArmFinalAbBoundaryLocked();
  3227. }
  3228. else
  3229. {
  3230. PlsrBoundaryFrequencyHz = PlsrCurrentFrequencyHz;
  3231. PlsrBoundaryWasCut = 1U;
  3232. PlsrBoundaryPending = 1U;
  3233. }
  3234. PlsrPlatformExitCritical(criticalState);
  3235. }
  3236. static void PlsrPollWaiting(uint8_t extEdge)
  3237. {
  3238. const PLSR_SEGMENT_CONFIG *segment =
  3239. &PlsrActiveConfig.segments[PlsrCurrentSegment - 1U];
  3240. switch (segment->waitType)
  3241. {
  3242. case PLSR_WAIT_TIME:
  3243. PlsrWaitElapsedMs++;
  3244. if (PlsrWaitElapsedMs >= segment->waitTimeMs)
  3245. {
  3246. PlsrTransitionToNext(0U);
  3247. }
  3248. break;
  3249. case PLSR_WAIT_SIGNAL:
  3250. if (PlsrPlatformReadInput((uint8_t)PlsrActiveConfig.waitInput) != 0U)
  3251. {
  3252. PlsrTransitionToNext(0U);
  3253. }
  3254. break;
  3255. case PLSR_ACT_TIME:
  3256. if (PlsrSegmentElapsedMs >= segment->actTimeMs)
  3257. {
  3258. PlsrTransitionToNext(0U);
  3259. }
  3260. break;
  3261. case PLSR_EXT_SIGNAL:
  3262. if (extEdge != 0U)
  3263. {
  3264. PlsrTransitionToNext(0U);
  3265. }
  3266. break;
  3267. default:
  3268. PlsrEnterError(PLSR_ERROR_INTERNAL);
  3269. break;
  3270. }
  3271. }
  3272. static void PlsrPollPersistenceDelay(void)
  3273. {
  3274. if ((PlsrPersistenceDirty != 0U)
  3275. && (PlsrIsBusy() == 0U)
  3276. && (PlsrPersistenceDelayMs != 0U))
  3277. {
  3278. PlsrPersistenceDelayMs--;
  3279. }
  3280. }
  3281. void PlsrServicePersistence(void)
  3282. {
  3283. PLSR_PERSIST_PAYLOAD payload;
  3284. PLSR_PLATFORM_SERVICE_RESULT serviceResult;
  3285. uint32_t criticalState;
  3286. if (PlsrIsBusy() != 0U)
  3287. {
  3288. return;
  3289. }
  3290. serviceResult = PlsrPlatformServicePersistence();
  3291. if (serviceResult == PLSR_PLATFORM_SERVICE_FAILED)
  3292. {
  3293. PlsrRunStatus = PLSR_STATUS_ERROR;
  3294. PlsrError = PLSR_ERROR_INTERNAL;
  3295. return;
  3296. }
  3297. if ((serviceResult == PLSR_PLATFORM_SERVICE_DEFERRED)
  3298. || (PlsrPersistenceDirty == 0U))
  3299. {
  3300. return;
  3301. }
  3302. if (PlsrPersistenceDelayMs != 0U)
  3303. {
  3304. return;
  3305. }
  3306. payload.config = PlsrShadowConfig;
  3307. criticalState = PlsrPlatformEnterCritical();
  3308. payload.position = PlsrPosition;
  3309. payload.positionValid = PlsrPositionValid;
  3310. PlsrPlatformExitCritical(criticalState);
  3311. payload.wasBusy = 0U;
  3312. payload.reserved = 0U;
  3313. if (PlsrPlatformSave(&payload) != 0U)
  3314. {
  3315. PlsrPersistenceDirty = 0U;
  3316. }
  3317. else
  3318. {
  3319. PlsrRunStatus = PLSR_STATUS_ERROR;
  3320. PlsrError = PLSR_ERROR_INTERNAL;
  3321. }
  3322. }
  3323. uint8_t PlsrInit(void)
  3324. {
  3325. PLSR_PERSIST_PAYLOAD payload;
  3326. PlsrInitialized = 0U;
  3327. PlsrRunStatus = PLSR_STATUS_UNINITIALIZED;
  3328. if (PlsrPlatformInit() == 0U)
  3329. {
  3330. return 0U;
  3331. }
  3332. if ((PlsrPlatformLoad(&payload) == 0U)
  3333. || (PlsrConfigIsValid(&payload.config, 0U) == 0U)
  3334. || (payload.positionValid > 1U) || (payload.wasBusy > 1U))
  3335. {
  3336. PlsrSetDefaults(&PlsrShadowConfig);
  3337. PlsrPosition = 0L;
  3338. PlsrPositionValid = 1U;
  3339. PlsrPlatformCheckpointConfig(&PlsrShadowConfig);
  3340. PlsrPlatformCheckpointPosition(0L, 1U, 0U);
  3341. PlsrMarkPersistenceDirty(PLSR_CONFIG_SAVE_DELAY_MS);
  3342. }
  3343. else
  3344. {
  3345. PlsrShadowConfig = payload.config;
  3346. PlsrPosition = payload.position;
  3347. PlsrPositionValid = ((payload.positionValid != 0U)
  3348. && (payload.wasBusy == 0U)) ? 1U : 0U;
  3349. PlsrPersistenceDirty = 0U;
  3350. PlsrPersistenceDelayMs = 0U;
  3351. }
  3352. (void)memset(&PlsrActiveConfig, 0, sizeof(PlsrActiveConfig));
  3353. (void)memset(&PlsrRamp, 0, sizeof(PlsrRamp));
  3354. (void)memset(&PlsrShortProfile, 0, sizeof(PlsrShortProfile));
  3355. (void)memset(&PlsrProfileQueue, 0, sizeof(PlsrProfileQueue));
  3356. (void)memset(&PlsrHandoffPlan, 0, sizeof(PlsrHandoffPlan));
  3357. (void)memset(&PlsrExecutor, 0, sizeof(PlsrExecutor));
  3358. (void)memset(PlsrPreparedHandoffPlans, 0,
  3359. sizeof(PlsrPreparedHandoffPlans));
  3360. PlsrPreparedHandoffBank = 0U;
  3361. PlsrRemainingPulses = 0UL;
  3362. PlsrPulseActive = 0U;
  3363. PlsrCutRequested = 0U;
  3364. PlsrBoundaryPending = 0U;
  3365. PlsrBoundaryWasCut = 0U;
  3366. PlsrCountOverflowPending = 0U;
  3367. PlsrCountedObservedPublished = 0ULL;
  3368. PlsrCountedHandoffStaged = 0U;
  3369. PlsrCountedBoundaryEvent = 0U;
  3370. PlsrCountedBoundaryPlan.valid = 0U;
  3371. PlsrCountedBoundaryObserved = 0ULL;
  3372. PlsrCountedFaultEvent = 0U;
  3373. PlsrPositionCheckpointDirty = 0U;
  3374. PlsrFrequencyUpdatePending = 0U;
  3375. PlsrDeferredFrequencyPending = 0U;
  3376. PlsrFrequencyUpdateSegment = 0U;
  3377. PlsrSeamlessHandoffPending = 0U;
  3378. PlsrTimerErrorPending = 0U;
  3379. PlsrCurrentFrequencyHz = 0UL;
  3380. PlsrQueuedFrequencyHz = 0UL;
  3381. PlsrBoundaryFrequencyHz = 0UL;
  3382. PlsrFrequencyUpdateTargetHz = 0UL;
  3383. PlsrDeferredFrequencyHz = 0UL;
  3384. PlsrSegmentEpoch = 0UL;
  3385. PlsrCurrentSegment = 0U;
  3386. PlsrDirectionDelayActive = 0U;
  3387. PlsrDirectionDelayRemainingMs = 0U;
  3388. PlsrSegmentClockStarted = 0U;
  3389. PlsrExtPreviousLevel = 0U;
  3390. PlsrExtEdgePending = 0U;
  3391. PlsrStopRequested = 0U;
  3392. PlsrStopPulsesRemaining = 0U;
  3393. PlsrAbStopArmed = 0U;
  3394. PlsrLastDirectionValid = 0U;
  3395. PlsrPositionCheckpointElapsedMs = 0U;
  3396. PlsrCommandMailbox.command = 0U;
  3397. PlsrCommandMailbox.state = PLSR_COMMAND_MAILBOX_EMPTY;
  3398. PlsrDiagnosticReset();
  3399. #ifdef PLSR_HOST_TEST
  3400. PlsrHostTestEventSequence = 0UL;
  3401. PlsrHostTestLastGateEvent = 0UL;
  3402. PlsrHostTestLastDiagnosticFinishEvent = 0UL;
  3403. #endif
  3404. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0)
  3405. PlsrProfileProducerItemCount = 0UL;
  3406. PlsrProfileProducerTotalCycles = 0UL;
  3407. PlsrProfileProducerMaxItemCycles = 0UL;
  3408. #endif
  3409. PlsrError = PLSR_ERROR_NONE;
  3410. PlsrRunStatus = PLSR_STATUS_IDLE;
  3411. PlsrInitialized = 1U;
  3412. return 1U;
  3413. }
  3414. static PLSR_MB_RESULT PlsrQueueCommand(uint16_t command)
  3415. {
  3416. uint32_t criticalState;
  3417. PLSR_MB_RESULT result = PLSR_MB_OK;
  3418. if (PlsrInitialized == 0U)
  3419. {
  3420. return PLSR_MB_SERVER_FAILURE;
  3421. }
  3422. criticalState = PlsrPlatformEnterCritical();
  3423. /* Capacity one: repeats acknowledge the first command; conflicts wait. */
  3424. if (PlsrCommandMailbox.state != PLSR_COMMAND_MAILBOX_EMPTY)
  3425. {
  3426. result = (PlsrCommandMailbox.command == command)
  3427. ? PLSR_MB_OK : PLSR_MB_DEVICE_BUSY;
  3428. PlsrPlatformExitCritical(criticalState);
  3429. return result;
  3430. }
  3431. if (command == PLSR_COMMAND_START)
  3432. {
  3433. if ((PlsrIsBusy() != 0U)
  3434. || (PlsrRunStatus == PLSR_STATUS_ERROR))
  3435. {
  3436. result = PLSR_MB_DEVICE_BUSY;
  3437. }
  3438. else if ((PlsrRunStatus != PLSR_STATUS_IDLE)
  3439. && (PlsrRunStatus != PLSR_STATUS_COMPLETED)
  3440. && (PlsrRunStatus != PLSR_STATUS_STOPPED))
  3441. {
  3442. result = PLSR_MB_ILLEGAL_VALUE;
  3443. }
  3444. else if ((PlsrConfigIsValid(&PlsrShadowConfig, 1U) == 0U)
  3445. || ((PlsrShadowConfig.positionMode
  3446. == PLSR_POSITION_ABSOLUTE)
  3447. && (PlsrPositionValid == 0U)))
  3448. {
  3449. result = PLSR_MB_ILLEGAL_VALUE;
  3450. }
  3451. else
  3452. {
  3453. PlsrCommandMailbox.startConfig = PlsrShadowConfig;
  3454. }
  3455. }
  3456. else if ((command == PLSR_COMMAND_CLEAR) && (PlsrIsBusy() != 0U))
  3457. {
  3458. result = PLSR_MB_DEVICE_BUSY;
  3459. }
  3460. if (result == PLSR_MB_OK)
  3461. {
  3462. PlsrCommandMailbox.command = command;
  3463. PlsrCommandMailbox.state = PLSR_COMMAND_MAILBOX_PENDING;
  3464. }
  3465. PlsrPlatformExitCritical(criticalState);
  3466. return result;
  3467. }
  3468. static void PlsrExecuteStart(void)
  3469. {
  3470. uint32_t criticalState;
  3471. uint8_t handoffBank;
  3472. uint8_t index;
  3473. PlsrActiveConfig = PlsrCommandMailbox.startConfig;
  3474. for (index = 0U; index < PlsrActiveConfig.segmentCount; index++)
  3475. {
  3476. PlsrActiveConfig.segments[index].frequencyHz =
  3477. PlsrResolvedSegmentFrequency(&PlsrActiveConfig, index);
  3478. }
  3479. handoffBank = PlsrBuildHandoffPlanBank(&PlsrActiveConfig);
  3480. criticalState = PlsrPlatformEnterCritical();
  3481. PlsrPreparedHandoffBank = handoffBank;
  3482. PlsrHandoffPlan.valid = 0U;
  3483. PlsrPlatformExitCritical(criticalState);
  3484. PlsrStopRequested = 0U;
  3485. PlsrTimerErrorPending = 0U;
  3486. PlsrShortProfile.active = 0U;
  3487. PlsrError = PLSR_ERROR_NONE;
  3488. PlsrLastDirectionValid = 0U;
  3489. PlsrCheckpointPosition(1U);
  3490. if (PlsrStartSegment((uint8_t)PlsrActiveConfig.startSegment, 0U, 0UL)
  3491. == 0U)
  3492. {
  3493. PlsrEnterError((PlsrTimerErrorPending != 0U)
  3494. ? PLSR_ERROR_TIMER
  3495. : PLSR_ERROR_INVALID_RESOURCE);
  3496. }
  3497. }
  3498. static uint8_t PlsrExecuteStop(void)
  3499. {
  3500. uint32_t criticalState;
  3501. uint32_t stopTargetHz;
  3502. uint32_t appliedHz;
  3503. uint64_t drainPulses;
  3504. if (PlsrIsBusy() == 0U)
  3505. {
  3506. return 0U;
  3507. }
  3508. criticalState = PlsrPlatformEnterCritical();
  3509. if (PlsrStopRequested != 0U)
  3510. {
  3511. PlsrPlatformExitCritical(criticalState);
  3512. return 0U;
  3513. }
  3514. PlsrStopRequested = 1U;
  3515. PlsrStopPulsesRemaining = 0U;
  3516. PlsrShortProfile.active = 0U;
  3517. PlsrProfileQueueInvalidateGeneration();
  3518. PlsrHandoffPlan.valid = 0U;
  3519. PlsrInvalidateHandoffPlans();
  3520. if (PlsrBoundaryPending != 0U)
  3521. {
  3522. PlsrPlatformExitCritical(criticalState);
  3523. return 1U;
  3524. }
  3525. if (PlsrPulseActive == 0U)
  3526. {
  3527. PlsrPlatformExitCritical(criticalState);
  3528. PlsrFinishStopped();
  3529. return 1U;
  3530. }
  3531. stopTargetHz = PlsrEffectiveStopFrequency(
  3532. PlsrActiveConfig.segments[PlsrCurrentSegment - 1U].frequencyHz);
  3533. appliedHz = (PlsrQueuedFrequencyHz != 0UL)
  3534. ? PlsrQueuedFrequencyHz : PlsrCurrentFrequencyHz;
  3535. if (stopTargetHz > appliedHz)
  3536. {
  3537. stopTargetHz = appliedHz;
  3538. }
  3539. if (PlsrActiveConfig.outputMode == PLSR_OUTPUT_PULSE_DIR)
  3540. {
  3541. drainPulses = PlsrRampPulseEstimate(appliedHz, stopTargetHz,
  3542. appliedHz) + 1ULL;
  3543. if (drainPulses > PlsrRemainingPulses)
  3544. {
  3545. drainPulses = PlsrRemainingPulses;
  3546. }
  3547. if (drainPulses == 0ULL)
  3548. {
  3549. drainPulses = 1ULL;
  3550. }
  3551. PlsrRemainingPulses = drainPulses;
  3552. if (PlsrReplanPulseDir(stopTargetHz,
  3553. (uint32_t)drainPulses) == 0U)
  3554. {
  3555. PlsrPlatformExitCritical(criticalState);
  3556. PlsrEnterError(PLSR_ERROR_TIMER);
  3557. return 1U;
  3558. }
  3559. PlsrRunStatus = PLSR_STATUS_DECELERATING;
  3560. PlsrPlatformExitCritical(criticalState);
  3561. return 1U;
  3562. }
  3563. PlsrRampStart(PlsrCurrentFrequencyHz, stopTargetHz);
  3564. PlsrRunStatus = PLSR_STATUS_DECELERATING;
  3565. if (PlsrRamp.active == 0U)
  3566. {
  3567. if (PlsrApplyFrequency(stopTargetHz, PlsrSegmentEpoch) == 0U)
  3568. {
  3569. PlsrPlatformExitCritical(criticalState);
  3570. PlsrEnterError(PLSR_ERROR_TIMER);
  3571. return 1U;
  3572. }
  3573. (void)PlsrArmStopDrainLocked();
  3574. }
  3575. PlsrPlatformExitCritical(criticalState);
  3576. return 1U;
  3577. }
  3578. static void PlsrExecuteClear(void)
  3579. {
  3580. uint32_t criticalState;
  3581. criticalState = PlsrPlatformEnterCritical();
  3582. PlsrPosition = 0L;
  3583. PlsrPositionValid = 1U;
  3584. PlsrRemainingPulses = 0UL;
  3585. PlsrPlatformExitCritical(criticalState);
  3586. PlsrPlatformCheckpointPosition(0L, 1U, 0U);
  3587. PlsrCountOverflowPending = 0U;
  3588. PlsrPositionCheckpointDirty = 0U;
  3589. PlsrPositionCheckpointElapsedMs = 0U;
  3590. PlsrCurrentSegment = 0U;
  3591. PlsrCurrentFrequencyHz = 0UL;
  3592. PlsrQueuedFrequencyHz = 0UL;
  3593. PlsrCutRequested = 0U;
  3594. PlsrBoundaryPending = 0U;
  3595. PlsrBoundaryWasCut = 0U;
  3596. PlsrDirectionDelayActive = 0U;
  3597. PlsrDirectionDelayRemainingMs = 0U;
  3598. PlsrExtEdgePending = 0U;
  3599. PlsrShortProfile.active = 0U;
  3600. PlsrProfileQueueReset();
  3601. PlsrHandoffPlan.valid = 0U;
  3602. PlsrInvalidateHandoffPlans();
  3603. PlsrDeferredFrequencyPending = 0U;
  3604. PlsrTimerErrorPending = 0U;
  3605. PlsrRamp.active = 0U;
  3606. PlsrExecutor.mode = PLSR_EXEC_IDLE;
  3607. PlsrError = PLSR_ERROR_NONE;
  3608. PlsrRunStatus = PLSR_STATUS_IDLE;
  3609. PlsrMarkPersistenceDirty(PLSR_CONFIG_SAVE_DELAY_MS);
  3610. }
  3611. static uint8_t PlsrPollCommandMailbox(void)
  3612. {
  3613. uint16_t command;
  3614. uint8_t endPoll = 1U;
  3615. uint32_t criticalState;
  3616. criticalState = PlsrPlatformEnterCritical();
  3617. if (PlsrCommandMailbox.state != PLSR_COMMAND_MAILBOX_PENDING)
  3618. {
  3619. PlsrPlatformExitCritical(criticalState);
  3620. return 0U;
  3621. }
  3622. PlsrCommandMailbox.state = PLSR_COMMAND_MAILBOX_EXECUTING;
  3623. command = PlsrCommandMailbox.command;
  3624. PlsrPlatformExitCritical(criticalState);
  3625. switch (command)
  3626. {
  3627. case PLSR_COMMAND_START: PlsrExecuteStart(); break;
  3628. case PLSR_COMMAND_STOP: endPoll = PlsrExecuteStop(); break;
  3629. case PLSR_COMMAND_CLEAR: PlsrExecuteClear(); break;
  3630. default: PlsrEnterError(PLSR_ERROR_INTERNAL); break;
  3631. }
  3632. criticalState = PlsrPlatformEnterCritical();
  3633. PlsrCommandMailbox.command = 0U;
  3634. PlsrCommandMailbox.state = PLSR_COMMAND_MAILBOX_EMPTY;
  3635. PlsrPlatformExitCritical(criticalState);
  3636. return endPoll;
  3637. }
  3638. static void PlsrEnterErrorIfEpoch(PLSR_ERROR error, uint32_t expectedEpoch)
  3639. {
  3640. uint32_t criticalState = PlsrPlatformEnterCritical();
  3641. if (PlsrSegmentEpoch == expectedEpoch)
  3642. {
  3643. PlsrEnterError(error);
  3644. }
  3645. PlsrPlatformExitCritical(criticalState);
  3646. }
  3647. static uint8_t PlsrServiceCountedExecutor(void)
  3648. {
  3649. uint32_t completedPulses;
  3650. uint32_t completedFrequencyHz;
  3651. uint32_t activeFrequencyHz;
  3652. uint32_t queuedFrequencyHz;
  3653. uint8_t completedNormally;
  3654. if ((PlsrPulseActive == 0U)
  3655. || ((PlsrExecutor.mode != PLSR_EXEC_STEP_TABLE)
  3656. && (PlsrExecutor.mode != PLSR_EXEC_STREAM)
  3657. && (PlsrExecutor.mode != PLSR_EXEC_STOPPING)))
  3658. {
  3659. return 0U;
  3660. }
  3661. if (PlsrSyncCountedProgress() == 0U)
  3662. {
  3663. #if PLSR_COUNT_ERROR_CHECK_ENABLED
  3664. PlsrEnterError(PLSR_ERROR_COUNT);
  3665. return 1U;
  3666. #else
  3667. /* 计数错误检查暂时关闭:observed 回退(平台计数器基准重置造成的
  3668. 视图回退)时重新校准发布点,继续运行,不进错误。 */
  3669. PlsrCountedObservedPublished = PlsrPlatformObservedPulses(
  3670. (uint8_t)PlsrActiveConfig.pulseOutput);
  3671. return 0U;
  3672. #endif
  3673. }
  3674. activeFrequencyHz = PlsrPlatformActiveFrequency(
  3675. (uint8_t)PlsrActiveConfig.pulseOutput);
  3676. if (activeFrequencyHz != 0UL)
  3677. {
  3678. PlsrCurrentFrequencyHz = activeFrequencyHz;
  3679. PlsrDiagnosticCheckActiveFrequency(activeFrequencyHz);
  3680. queuedFrequencyHz = PlsrQueuedFrequencyHz;
  3681. if (queuedFrequencyHz > activeFrequencyHz)
  3682. {
  3683. PlsrRunStatus = PLSR_STATUS_ACCELERATING;
  3684. }
  3685. else if (queuedFrequencyHz < activeFrequencyHz)
  3686. {
  3687. PlsrRunStatus = PLSR_STATUS_DECELERATING;
  3688. }
  3689. else
  3690. {
  3691. PlsrRunStatus = PLSR_STATUS_RUNNING;
  3692. }
  3693. }
  3694. if (PlsrPlatformTakeFiniteCompletion(
  3695. (uint8_t)PlsrActiveConfig.pulseOutput,
  3696. &completedPulses) == 0U)
  3697. {
  3698. return 0U;
  3699. }
  3700. (void)completedPulses;
  3701. (void)PlsrSyncCountedProgress();
  3702. completedFrequencyHz = PlsrCurrentFrequencyHz;
  3703. completedNormally = ((PlsrRemainingPulses == 0ULL)
  3704. && (PlsrCutRequested == 0U)
  3705. && (PlsrCountOverflowPending == 0U)
  3706. && (PlsrTimerErrorPending == 0U)) ? 1U : 0U;
  3707. PlsrDiagnosticFinishSegment(completedNormally);
  3708. PlsrShortProfile.active = 0U;
  3709. PlsrProfileQueue.active = 0U;
  3710. PlsrHandoffPlan.valid = 0U;
  3711. PlsrCountedHandoffStaged = 0U;
  3712. PlsrBoundaryFrequencyHz = completedFrequencyHz;
  3713. PlsrBoundaryWasCut = (PlsrCutRequested != 0U) ? 1U : 0U;
  3714. PlsrCutRequested = 0U;
  3715. PlsrPulseActive = 0U;
  3716. PlsrCurrentFrequencyHz = 0UL;
  3717. PlsrQueuedFrequencyHz = 0UL;
  3718. PlsrBoundaryPending = 1U;
  3719. PlsrExecutor.mode = PLSR_EXEC_IDLE;
  3720. return 1U;
  3721. }
  3722. void PlsrPoll1ms(void)
  3723. {
  3724. uint8_t extLevel;
  3725. uint8_t extEdge;
  3726. uint8_t activeSegmentNumber;
  3727. uint8_t applyDynamicFrequency = 0U;
  3728. uint8_t pulseDirReplanFailed = 0U;
  3729. PLSR_SEGMENT_CONFIG *activeSegment;
  3730. uint32_t criticalState;
  3731. uint32_t newTargetHz;
  3732. uint32_t pollEpoch;
  3733. if (PlsrInitialized == 0U)
  3734. {
  3735. return;
  3736. }
  3737. if (PlsrPollCommandMailbox() != 0U)
  3738. {
  3739. return;
  3740. }
  3741. /* 段边界事件必须在任何计数同步之前消费:快照是 IRQ 边界时刻的
  3742. 硬件计数,晚消费会把下一 run 的脉冲算进旧段。 */
  3743. PlsrExecServiceCountedEvents();
  3744. PlsrPollPositionCheckpoint();
  3745. if (PlsrServiceCountedExecutor() != 0U)
  3746. {
  3747. if (PlsrBoundaryPending != 0U)
  3748. {
  3749. PlsrHandleBoundary(0U);
  3750. }
  3751. PlsrPollPersistenceDelay();
  3752. return;
  3753. }
  3754. if (((PlsrExecutor.mode == PLSR_EXEC_STEP_TABLE)
  3755. || (PlsrExecutor.mode == PLSR_EXEC_STREAM))
  3756. && (PlsrProfileQueue.active != 0U)
  3757. && (PlsrProfileQueue.generatorComplete == 0U)
  3758. && (PlsrProfileQueueFill(PLSR_PROFILE_QUEUE_CAPACITY) == 0U))
  3759. {
  3760. PlsrEnterError(PLSR_ERROR_TIMER);
  3761. return;
  3762. }
  3763. if (((PlsrExecutor.mode == PLSR_EXEC_STEP_TABLE)
  3764. || (PlsrExecutor.mode == PLSR_EXEC_STREAM))
  3765. && ((PlsrStageCountedHandoff() == 0U)
  3766. || (PlsrProfileQueueFill(PLSR_PROFILE_QUEUE_CAPACITY) == 0U)))
  3767. {
  3768. PlsrEnterError(PLSR_ERROR_TIMER);
  3769. return;
  3770. }
  3771. criticalState = PlsrPlatformEnterCritical();
  3772. pollEpoch = PlsrSegmentEpoch;
  3773. extLevel = PlsrPlatformReadInput((uint8_t)PlsrActiveConfig.extInput);
  3774. extEdge = ((extLevel != 0U) && (PlsrExtPreviousLevel == 0U)) ? 1U : 0U;
  3775. PlsrExtPreviousLevel = extLevel;
  3776. if (PlsrExtEdgePending != 0U)
  3777. {
  3778. extEdge = 1U;
  3779. }
  3780. PlsrPlatformExitCritical(criticalState);
  3781. if (PlsrBoundaryPending != 0U)
  3782. {
  3783. PlsrExtEdgePending = 0U;
  3784. PlsrHandleBoundary(extEdge);
  3785. PlsrPollPersistenceDelay();
  3786. return;
  3787. }
  3788. if (PlsrIsBusy() == 0U)
  3789. {
  3790. PlsrExtEdgePending = 0U;
  3791. PlsrPollPersistenceDelay();
  3792. return;
  3793. }
  3794. if (PlsrSegmentEpoch != pollEpoch)
  3795. {
  3796. return;
  3797. }
  3798. if (PlsrDirectionDelayActive != 0U)
  3799. {
  3800. if (extEdge != 0U)
  3801. {
  3802. PlsrExtEdgePending = 1U;
  3803. }
  3804. if (PlsrDirectionDelayRemainingMs != 0U)
  3805. {
  3806. PlsrDirectionDelayRemainingMs--;
  3807. }
  3808. if (PlsrDirectionDelayRemainingMs == 0U)
  3809. {
  3810. PlsrDirectionDelayActive = 0U;
  3811. if (PlsrBeginSegmentOutput(PlsrEffectiveStartFrequency(
  3812. PlsrActiveConfig.segments[PlsrCurrentSegment - 1U]
  3813. .frequencyHz,
  3814. 0U, 1U, 0UL)) == 0U)
  3815. {
  3816. PlsrEnterError(PLSR_ERROR_TIMER);
  3817. }
  3818. }
  3819. return;
  3820. }
  3821. criticalState = PlsrPlatformEnterCritical();
  3822. if (PlsrSegmentEpoch != pollEpoch)
  3823. {
  3824. PlsrPlatformExitCritical(criticalState);
  3825. return;
  3826. }
  3827. PlsrExtEdgePending = 0U;
  3828. if (PlsrSegmentClockStarted != 0U)
  3829. {
  3830. PlsrSegmentElapsedMs++;
  3831. }
  3832. if (PlsrRunStatus == PLSR_STATUS_WAITING)
  3833. {
  3834. PlsrPlatformExitCritical(criticalState);
  3835. PlsrPollWaiting(extEdge);
  3836. return;
  3837. }
  3838. activeSegmentNumber = PlsrCurrentSegment;
  3839. if ((activeSegmentNumber == 0U)
  3840. || (activeSegmentNumber > PlsrActiveConfig.segmentCount))
  3841. {
  3842. PlsrPlatformExitCritical(criticalState);
  3843. PlsrEnterError(PLSR_ERROR_INTERNAL);
  3844. return;
  3845. }
  3846. activeSegment = &PlsrActiveConfig.segments[activeSegmentNumber - 1U];
  3847. if (PlsrSeamlessHandoffPending != 0U)
  3848. {
  3849. PlsrSeamlessHandoffPending = 0U;
  3850. if ((PlsrStopRequested == 0U)
  3851. && (PlsrShortProfile.active == 0U)
  3852. && (PlsrFrequencyUpdatePending == 0U))
  3853. {
  3854. PlsrRamp.active = 0U;
  3855. PlsrRunStatus = PLSR_STATUS_RUNNING;
  3856. }
  3857. }
  3858. newTargetHz = PlsrFrequencyUpdateTargetHz;
  3859. if ((PlsrStopRequested == 0U)
  3860. && (PlsrFrequencyUpdatePending != 0U)
  3861. && (PlsrAbStopArmed == 0U)
  3862. && (PlsrFrequencyUpdateSegment == activeSegmentNumber))
  3863. {
  3864. PlsrFrequencyUpdatePending = 0U;
  3865. activeSegment->frequencyHz = newTargetHz;
  3866. PlsrShortProfile.active = 0U;
  3867. PlsrProfileQueueInvalidateGeneration();
  3868. PlsrBoundaryRampStarted = 0U;
  3869. if (PlsrActiveConfig.outputMode == PLSR_OUTPUT_PULSE_DIR)
  3870. {
  3871. uint64_t remaining = PlsrRemainingPulses;
  3872. if ((remaining == 0ULL) || (remaining > 0xFFFFFFFFULL)
  3873. || (PlsrReplanPulseDir(newTargetHz,
  3874. (uint32_t)remaining) == 0U))
  3875. {
  3876. pulseDirReplanFailed = 1U;
  3877. }
  3878. }
  3879. else
  3880. {
  3881. PlsrRampStart(PlsrCurrentFrequencyHz, newTargetHz);
  3882. if (PlsrRamp.active == 0U)
  3883. {
  3884. applyDynamicFrequency = 1U;
  3885. }
  3886. }
  3887. }
  3888. PlsrPlatformExitCritical(criticalState);
  3889. if (pulseDirReplanFailed != 0U)
  3890. {
  3891. PlsrEnterErrorIfEpoch(PLSR_ERROR_TIMER, pollEpoch);
  3892. return;
  3893. }
  3894. if (applyDynamicFrequency != 0U)
  3895. {
  3896. if (PlsrApplyFrequency(newTargetHz, pollEpoch) == 0U)
  3897. {
  3898. PlsrEnterErrorIfEpoch(PLSR_ERROR_TIMER, pollEpoch);
  3899. return;
  3900. }
  3901. criticalState = PlsrPlatformEnterCritical();
  3902. if (PlsrSegmentEpoch == pollEpoch)
  3903. {
  3904. PlsrRunStatus = PLSR_STATUS_RUNNING;
  3905. }
  3906. PlsrPlatformExitCritical(criticalState);
  3907. }
  3908. if ((PlsrActiveConfig.outputMode == PLSR_OUTPUT_AB)
  3909. && (PlsrShortProfile.active == 0U)
  3910. && (PlsrRamp.active != 0U)
  3911. && (PlsrRampAdvance(pollEpoch) == 0U))
  3912. {
  3913. PlsrEnterErrorIfEpoch(PLSR_ERROR_TIMER, pollEpoch);
  3914. return;
  3915. }
  3916. criticalState = PlsrPlatformEnterCritical();
  3917. if (PlsrSegmentEpoch != pollEpoch)
  3918. {
  3919. PlsrPlatformExitCritical(criticalState);
  3920. return;
  3921. }
  3922. if ((PlsrActiveConfig.outputMode == PLSR_OUTPUT_AB)
  3923. && (PlsrStopRequested != 0U) && (PlsrRamp.active == 0U))
  3924. {
  3925. if (PlsrStopPulsesRemaining == 0U)
  3926. {
  3927. if (PlsrArmStopDrainLocked() == 0U)
  3928. {
  3929. PlsrPlatformExitCritical(criticalState);
  3930. PlsrEnterError(PLSR_ERROR_TIMER);
  3931. return;
  3932. }
  3933. }
  3934. else
  3935. {
  3936. (void)PlsrArmFinalAbBoundaryLocked();
  3937. }
  3938. PlsrPlatformExitCritical(criticalState);
  3939. return;
  3940. }
  3941. PlsrPlatformExitCritical(criticalState);
  3942. if ((activeSegment->waitType == PLSR_ACT_TIME)
  3943. && (PlsrSegmentElapsedMs >= activeSegment->actTimeMs))
  3944. {
  3945. PlsrRequestCut(pollEpoch);
  3946. return;
  3947. }
  3948. if (((activeSegment->waitType == PLSR_EXT_SIGNAL)
  3949. || (activeSegment->waitType == PLSR_EXT_OR_COMPLETE))
  3950. && (extEdge != 0U))
  3951. {
  3952. PlsrRequestCut(pollEpoch);
  3953. return;
  3954. }
  3955. if (PlsrActiveConfig.outputMode == PLSR_OUTPUT_AB)
  3956. {
  3957. PlsrMaybePlanBoundaryRamp(pollEpoch);
  3958. }
  3959. }
  3960. void PlsrPulseTimerIrq(uint8_t pulseOutput)
  3961. {
  3962. uint32_t positionBits;
  3963. uint32_t completedFrequencyHz;
  3964. uint64_t remainingPulses;
  3965. PLSR_PLATFORM_QUEUE_RESULT queueResult;
  3966. if ((PlsrPulseActive == 0U)
  3967. || (pulseOutput != (uint8_t)PlsrActiveConfig.pulseOutput))
  3968. {
  3969. return;
  3970. }
  3971. if ((PlsrExecutor.mode == PLSR_EXEC_STEP_TABLE)
  3972. || (PlsrExecutor.mode == PLSR_EXEC_STREAM)
  3973. || (PlsrExecutor.mode == PLSR_EXEC_STOPPING))
  3974. {
  3975. return;
  3976. }
  3977. completedFrequencyHz = PlsrCurrentFrequencyHz;
  3978. PlsrDiagnosticCheckActiveFrequency(completedFrequencyHz);
  3979. PlsrCurrentFrequencyHz = PlsrPlatformActiveFrequency(pulseOutput);
  3980. if (PlsrCurrentFrequencyHz == 0UL)
  3981. {
  3982. PlsrCurrentFrequencyHz = PlsrQueuedFrequencyHz;
  3983. }
  3984. if ((PlsrStopRequested != 0U) && (PlsrRamp.active == 0U)
  3985. && (PlsrStopPulsesRemaining != 0U))
  3986. {
  3987. PlsrStopPulsesRemaining--;
  3988. if (PlsrStopPulsesRemaining == 0U)
  3989. {
  3990. PlsrCutRequested = 1U;
  3991. }
  3992. }
  3993. positionBits = (uint32_t)PlsrPosition;
  3994. if (PlsrCountPositive != 0U)
  3995. {
  3996. if (positionBits == (uint32_t)INT32_MAX)
  3997. {
  3998. PlsrPositionValid = 0U;
  3999. #if PLSR_COUNT_ERROR_CHECK_ENABLED
  4000. PlsrCountOverflowPending = 1U;
  4001. #endif
  4002. }
  4003. positionBits++;
  4004. }
  4005. else
  4006. {
  4007. if (positionBits == (uint32_t)INT32_MIN)
  4008. {
  4009. PlsrPositionValid = 0U;
  4010. #if PLSR_COUNT_ERROR_CHECK_ENABLED
  4011. PlsrCountOverflowPending = 1U;
  4012. #endif
  4013. }
  4014. positionBits--;
  4015. }
  4016. PlsrPosition = (int32_t)positionBits;
  4017. PlsrPositionCheckpointDirty = 1U;
  4018. remainingPulses = PlsrRemainingPulses;
  4019. if (remainingPulses != 0UL)
  4020. {
  4021. remainingPulses--;
  4022. PlsrRemainingPulses = remainingPulses;
  4023. }
  4024. if ((remainingPulses == 0UL) || (PlsrCutRequested != 0U)
  4025. || (PlsrCountOverflowPending != 0U))
  4026. {
  4027. if (remainingPulses == 0UL)
  4028. {
  4029. queueResult = PlsrTryContinuousHandoff();
  4030. if (queueResult != PLSR_PLATFORM_QUEUE_FAILED)
  4031. {
  4032. return;
  4033. }
  4034. }
  4035. PlsrPlatformGateFromIrq(pulseOutput);
  4036. #ifdef PLSR_HOST_TEST
  4037. PlsrHostTestEventSequence++;
  4038. PlsrHostTestLastGateEvent = PlsrHostTestEventSequence;
  4039. #endif
  4040. PlsrDiagnosticFinishSegment(
  4041. ((remainingPulses == 0UL)
  4042. && (PlsrCutRequested == 0U)
  4043. && (PlsrCountOverflowPending == 0U)) ? 1U : 0U);
  4044. PlsrShortProfile.active = 0U;
  4045. PlsrHandoffPlan.valid = 0U;
  4046. PlsrBoundaryFrequencyHz = completedFrequencyHz;
  4047. PlsrBoundaryWasCut = (PlsrCutRequested != 0U) ? 1U : 0U;
  4048. PlsrCutRequested = 0U;
  4049. PlsrAbStopArmed = 0U;
  4050. PlsrPulseActive = 0U;
  4051. PlsrCurrentFrequencyHz = 0UL;
  4052. PlsrQueuedFrequencyHz = 0UL;
  4053. PlsrBoundaryPending = 1U;
  4054. return;
  4055. }
  4056. if (PlsrShortProfile.active != 0U)
  4057. {
  4058. queueResult = PlsrProfileQueueCommitNext(pulseOutput);
  4059. if (queueResult == PLSR_PLATFORM_QUEUE_STALE)
  4060. {
  4061. return;
  4062. }
  4063. if (queueResult == PLSR_PLATFORM_QUEUE_FAILED)
  4064. {
  4065. PlsrDiagnosticFinishSegment(0U);
  4066. PlsrTimerErrorPending = 1U;
  4067. PlsrShortProfile.active = 0U;
  4068. PlsrHandoffPlan.valid = 0U;
  4069. PlsrBoundaryFrequencyHz = completedFrequencyHz;
  4070. PlsrBoundaryWasCut = 0U;
  4071. PlsrCutRequested = 0U;
  4072. PlsrPlatformGateFromIrq(pulseOutput);
  4073. PlsrAbStopArmed = 0U;
  4074. PlsrPulseActive = 0U;
  4075. PlsrCurrentFrequencyHz = 0UL;
  4076. PlsrQueuedFrequencyHz = 0UL;
  4077. PlsrBoundaryPending = 1U;
  4078. return;
  4079. }
  4080. }
  4081. if ((PlsrShortProfile.active == 0U)
  4082. && (remainingPulses == 1UL))
  4083. {
  4084. if (PlsrPrimeHandoff() == PLSR_PLATFORM_QUEUE_STALE)
  4085. {
  4086. return;
  4087. }
  4088. }
  4089. if ((PlsrShortProfile.active == 0U)
  4090. && (PlsrHandoffPlan.valid == 0U)
  4091. && (PlsrDeferredFrequencyPending != 0U))
  4092. {
  4093. queueResult = PlsrCommitDeferredFrequency(pulseOutput);
  4094. if (queueResult == PLSR_PLATFORM_QUEUE_STALE)
  4095. {
  4096. return;
  4097. }
  4098. if (queueResult == PLSR_PLATFORM_QUEUE_FAILED)
  4099. {
  4100. PlsrDiagnosticFinishSegment(0U);
  4101. PlsrTimerErrorPending = 1U;
  4102. PlsrBoundaryFrequencyHz = completedFrequencyHz;
  4103. PlsrBoundaryWasCut = 0U;
  4104. PlsrCutRequested = 0U;
  4105. PlsrPlatformGateFromIrq(pulseOutput);
  4106. PlsrAbStopArmed = 0U;
  4107. PlsrPulseActive = 0U;
  4108. PlsrCurrentFrequencyHz = 0UL;
  4109. PlsrQueuedFrequencyHz = 0UL;
  4110. PlsrBoundaryPending = 1U;
  4111. return;
  4112. }
  4113. }
  4114. if ((PlsrActiveConfig.outputMode == PLSR_OUTPUT_AB)
  4115. && (PlsrQueueFinalAbBoundaryFromIrq() == 0U))
  4116. {
  4117. return;
  4118. }
  4119. }
  4120. PLSR_MB_RESULT PlsrModbusReadHolding(uint16_t startAddress,
  4121. uint16_t quantity,
  4122. uint16_t *values)
  4123. {
  4124. PLSR_MB_RESULT classification;
  4125. uint16_t index;
  4126. uint32_t criticalState;
  4127. int32_t position;
  4128. uint32_t frequency;
  4129. uint16_t statusWords[7];
  4130. uint16_t diagnosticWords[26];
  4131. if (values == NULL)
  4132. {
  4133. return PLSR_MB_ILLEGAL_VALUE;
  4134. }
  4135. classification = PlsrClassifyRange(startAddress, quantity);
  4136. if (classification != PLSR_MB_OK)
  4137. {
  4138. return classification;
  4139. }
  4140. criticalState = PlsrPlatformEnterCritical();
  4141. position = PlsrPosition;
  4142. frequency = PlsrCurrentFrequencyHz;
  4143. statusWords[0] = PlsrLowWord((uint32_t)position);
  4144. statusWords[1] = PlsrHighWord((uint32_t)position);
  4145. statusWords[2] = PlsrLowWord(frequency);
  4146. statusWords[3] = PlsrHighWord(frequency);
  4147. statusWords[4] = (uint16_t)PlsrRunStatus;
  4148. statusWords[5] = PlsrCurrentSegment;
  4149. statusWords[6] = (uint16_t)PlsrError;
  4150. diagnosticWords[0] = PlsrDiagnostic.flags;
  4151. diagnosticWords[1] = PlsrDiagnostic.reason;
  4152. diagnosticWords[2] = PlsrDiagnostic.lastSegment;
  4153. diagnosticWords[3] = PlsrDiagnostic.modeDirection;
  4154. diagnosticWords[4] = PlsrLowWord(PlsrDiagnostic.expectedCycles);
  4155. diagnosticWords[5] = PlsrHighWord(PlsrDiagnostic.expectedCycles);
  4156. diagnosticWords[6] = PlsrLowWord(PlsrDiagnostic.observedCycles);
  4157. diagnosticWords[7] = PlsrHighWord(PlsrDiagnostic.observedCycles);
  4158. diagnosticWords[8] = PlsrLowWord((uint32_t)PlsrDiagnostic.countError);
  4159. diagnosticWords[9] = PlsrHighWord((uint32_t)PlsrDiagnostic.countError);
  4160. diagnosticWords[10] = PlsrLowWord(PlsrDiagnostic.requestedHz);
  4161. diagnosticWords[11] = PlsrHighWord(PlsrDiagnostic.requestedHz);
  4162. diagnosticWords[12] = PlsrLowWord(PlsrDiagnostic.expectedTimerHz);
  4163. diagnosticWords[13] = PlsrHighWord(PlsrDiagnostic.expectedTimerHz);
  4164. diagnosticWords[14] = PlsrLowWord(PlsrDiagnostic.activeTimerHz);
  4165. diagnosticWords[15] = PlsrHighWord(PlsrDiagnostic.activeTimerHz);
  4166. diagnosticWords[16] =
  4167. PlsrLowWord((uint32_t)PlsrDiagnostic.requestErrorHz);
  4168. diagnosticWords[17] =
  4169. PlsrHighWord((uint32_t)PlsrDiagnostic.requestErrorHz);
  4170. diagnosticWords[18] = PlsrLowWord(PlsrDiagnostic.curveSampleCount);
  4171. diagnosticWords[19] = PlsrHighWord(PlsrDiagnostic.curveSampleCount);
  4172. diagnosticWords[20] = PlsrLowWord(PlsrDiagnostic.curveMismatchCount);
  4173. diagnosticWords[21] = PlsrHighWord(PlsrDiagnostic.curveMismatchCount);
  4174. diagnosticWords[22] = PlsrLowWord(PlsrDiagnostic.curveMaxAbsErrorHz);
  4175. diagnosticWords[23] = PlsrHighWord(PlsrDiagnostic.curveMaxAbsErrorHz);
  4176. diagnosticWords[24] = PlsrLowWord(PlsrDiagnostic.firstMismatchSample);
  4177. diagnosticWords[25] = PlsrHighWord(PlsrDiagnostic.firstMismatchSample);
  4178. PlsrPlatformExitCritical(criticalState);
  4179. for (index = 0U; index < quantity; index++)
  4180. {
  4181. uint16_t address = (uint16_t)(startAddress + index);
  4182. if ((address >= PLSR_CONFIG_FIRST_ADDRESS)
  4183. && (address <= PLSR_CONFIG_LAST_ADDRESS))
  4184. {
  4185. values[index] = PlsrReadConfigWord(&PlsrShadowConfig, address);
  4186. }
  4187. else if (address == PLSR_OUTPUT_MODE_ADDRESS)
  4188. {
  4189. values[index] = PlsrShadowConfig.outputMode;
  4190. }
  4191. else if ((address >= PLSR_STATUS_FIRST_ADDRESS)
  4192. && (address <= PLSR_STATUS_LAST_ADDRESS))
  4193. {
  4194. values[index] = statusWords[address - PLSR_STATUS_FIRST_ADDRESS];
  4195. }
  4196. else if ((address >= PLSR_DIAGNOSTIC_FIRST_ADDRESS)
  4197. && (address <= PLSR_DIAGNOSTIC_LAST_ADDRESS))
  4198. {
  4199. values[index] =
  4200. diagnosticWords[address - PLSR_DIAGNOSTIC_FIRST_ADDRESS];
  4201. }
  4202. else if (address == PLSR_CONTROL_ADDRESS)
  4203. {
  4204. values[index] = 0U;
  4205. }
  4206. else if (address == PLSR_DIAGNOSTIC_CONTROL_ADDRESS)
  4207. {
  4208. values[index] = 0U;
  4209. }
  4210. else
  4211. {
  4212. return PLSR_MB_ILLEGAL_ADDRESS;
  4213. }
  4214. }
  4215. return PLSR_MB_OK;
  4216. }
  4217. PLSR_MB_RESULT PlsrModbusWriteHolding(uint16_t startAddress,
  4218. uint16_t quantity,
  4219. const uint16_t *values)
  4220. {
  4221. PLSR_MB_RESULT classification;
  4222. PLSR_WORD_RESULT wordResult;
  4223. uint16_t index;
  4224. uint16_t pairedAddress;
  4225. uint32_t requestEnd;
  4226. uint32_t criticalState;
  4227. uint8_t handoffBank = 0U;
  4228. uint8_t updateActiveFrequencies = 0U;
  4229. uint8_t drainedToDifferentSegment = 0U;
  4230. uint8_t segmentBeforeDrain;
  4231. uint32_t drainedSegmentTargetHz = 0UL;
  4232. PLSR_PLATFORM_QUEUE_RESULT queueResult;
  4233. if (values == NULL)
  4234. {
  4235. return PLSR_MB_ILLEGAL_VALUE;
  4236. }
  4237. classification = PlsrClassifyRange(startAddress, quantity);
  4238. if (classification != PLSR_MB_OK)
  4239. {
  4240. return classification;
  4241. }
  4242. if ((startAddress >= PLSR_STATUS_FIRST_ADDRESS)
  4243. && (startAddress <= PLSR_STATUS_LAST_ADDRESS))
  4244. {
  4245. return PLSR_MB_ILLEGAL_ADDRESS;
  4246. }
  4247. if ((startAddress >= PLSR_DIAGNOSTIC_FIRST_ADDRESS)
  4248. && (startAddress <= PLSR_DIAGNOSTIC_LAST_ADDRESS))
  4249. {
  4250. return PLSR_MB_ILLEGAL_ADDRESS;
  4251. }
  4252. if (startAddress == PLSR_DIAGNOSTIC_CONTROL_ADDRESS)
  4253. {
  4254. if (quantity != 1U)
  4255. {
  4256. return PLSR_MB_ILLEGAL_ADDRESS;
  4257. }
  4258. if ((values[0] != 0U) && (values[0] != 1U))
  4259. {
  4260. return PLSR_MB_ILLEGAL_VALUE;
  4261. }
  4262. if ((values[0] != 0U) && (PlsrIsBusy() != 0U))
  4263. {
  4264. return PLSR_MB_DEVICE_BUSY;
  4265. }
  4266. if (values[0] != 0U)
  4267. {
  4268. criticalState = PlsrPlatformEnterCritical();
  4269. PlsrDiagnosticReset();
  4270. PlsrPlatformExitCritical(criticalState);
  4271. }
  4272. return PLSR_MB_OK;
  4273. }
  4274. if (startAddress == PLSR_CONTROL_ADDRESS)
  4275. {
  4276. if (quantity != 1U)
  4277. {
  4278. return PLSR_MB_ILLEGAL_ADDRESS;
  4279. }
  4280. switch (values[0])
  4281. {
  4282. case 0U: return PLSR_MB_OK;
  4283. case PLSR_COMMAND_START:
  4284. case PLSR_COMMAND_STOP:
  4285. case PLSR_COMMAND_CLEAR:
  4286. return PlsrQueueCommand(values[0]);
  4287. default: return PLSR_MB_ILLEGAL_VALUE;
  4288. }
  4289. }
  4290. if (startAddress == PLSR_OUTPUT_MODE_ADDRESS)
  4291. {
  4292. if (quantity != 1U)
  4293. {
  4294. return PLSR_MB_ILLEGAL_ADDRESS;
  4295. }
  4296. if (PlsrIsBusy() != 0U)
  4297. {
  4298. return PLSR_MB_DEVICE_BUSY;
  4299. }
  4300. PlsrCandidateConfig = PlsrShadowConfig;
  4301. PlsrCandidateConfig.outputMode = values[0];
  4302. if (PlsrConfigIsValid(&PlsrCandidateConfig, 0U) == 0U)
  4303. {
  4304. return PLSR_MB_ILLEGAL_VALUE;
  4305. }
  4306. criticalState = PlsrPlatformEnterCritical();
  4307. PlsrShadowConfig = PlsrCandidateConfig;
  4308. PlsrPlatformExitCritical(criticalState);
  4309. PlsrPlatformCheckpointConfig(&PlsrShadowConfig);
  4310. PlsrMarkPersistenceDirty(PLSR_CONFIG_SAVE_DELAY_MS);
  4311. return PLSR_MB_OK;
  4312. }
  4313. if ((startAddress < PLSR_CONFIG_FIRST_ADDRESS)
  4314. || ((uint32_t)startAddress + quantity - 1UL
  4315. > PLSR_CONFIG_LAST_ADDRESS))
  4316. {
  4317. return PLSR_MB_ILLEGAL_ADDRESS;
  4318. }
  4319. if ((PlsrIsBusy() != 0U)
  4320. && (startAddress <= 0x1001U)
  4321. && ((uint32_t)startAddress + quantity - 1UL >= 0x1000UL))
  4322. {
  4323. return PLSR_MB_DEVICE_BUSY;
  4324. }
  4325. requestEnd = (uint32_t)startAddress + quantity;
  4326. for (index = 0U; index < quantity; index++)
  4327. {
  4328. uint16_t address = (uint16_t)(startAddress + index);
  4329. if (PlsrAddressIsDwordHalf(address, &pairedAddress) != 0U)
  4330. {
  4331. if (((uint32_t)pairedAddress < startAddress)
  4332. || ((uint32_t)pairedAddress >= requestEnd))
  4333. {
  4334. return PLSR_MB_ILLEGAL_ADDRESS;
  4335. }
  4336. }
  4337. }
  4338. PlsrCandidateConfig = PlsrShadowConfig;
  4339. for (index = 0U; index < quantity; index++)
  4340. {
  4341. wordResult = PlsrWriteConfigWord(&PlsrCandidateConfig,
  4342. (uint16_t)(startAddress + index),
  4343. values[index]);
  4344. if (wordResult == PLSR_WORD_ILLEGAL_ADDRESS)
  4345. {
  4346. return PLSR_MB_ILLEGAL_ADDRESS;
  4347. }
  4348. if (wordResult == PLSR_WORD_ILLEGAL_VALUE)
  4349. {
  4350. return PLSR_MB_ILLEGAL_VALUE;
  4351. }
  4352. }
  4353. if (PlsrConfigIsValid(&PlsrCandidateConfig, 0U) == 0U)
  4354. {
  4355. return PLSR_MB_ILLEGAL_VALUE;
  4356. }
  4357. if (PlsrIsBusy() != 0U)
  4358. {
  4359. for (index = 0U; index < PlsrActiveConfig.segmentCount; index++)
  4360. {
  4361. if (PlsrCandidateConfig.segments[index].frequencyHz
  4362. != PlsrShadowConfig.segments[index].frequencyHz)
  4363. {
  4364. updateActiveFrequencies = 1U;
  4365. }
  4366. }
  4367. }
  4368. if (updateActiveFrequencies != 0U)
  4369. {
  4370. handoffBank = PlsrBuildHandoffPlanBank(&PlsrCandidateConfig);
  4371. }
  4372. criticalState = PlsrPlatformEnterCritical();
  4373. segmentBeforeDrain = PlsrCurrentSegment;
  4374. if ((updateActiveFrequencies != 0U) && (PlsrPulseActive != 0U))
  4375. {
  4376. PlsrPlatformDrainPendingPulse(
  4377. (uint8_t)PlsrActiveConfig.pulseOutput);
  4378. drainedToDifferentSegment =
  4379. (PlsrCurrentSegment != segmentBeforeDrain) ? 1U : 0U;
  4380. if ((drainedToDifferentSegment != 0U)
  4381. && (PlsrCurrentSegment != 0U)
  4382. && (PlsrCurrentSegment <= PlsrCandidateConfig.segmentCount))
  4383. {
  4384. drainedSegmentTargetHz = PlsrResolvedSegmentFrequency(
  4385. &PlsrCandidateConfig, PlsrCurrentSegment - 1U);
  4386. }
  4387. }
  4388. PlsrShadowConfig = PlsrCandidateConfig;
  4389. if (updateActiveFrequencies != 0U)
  4390. {
  4391. for (index = 0U; index < PlsrActiveConfig.segmentCount; index++)
  4392. {
  4393. uint8_t frequencyChanged =
  4394. (PlsrActiveConfig.segments[index].frequencyHz
  4395. != PlsrResolvedSegmentFrequency(&PlsrCandidateConfig, index))
  4396. ? 1U : 0U;
  4397. PlsrActiveConfig.segments[index].frequencyHz =
  4398. PlsrResolvedSegmentFrequency(&PlsrCandidateConfig, index);
  4399. if ((frequencyChanged != 0U)
  4400. && (index + 1U == PlsrCurrentSegment)
  4401. && (PlsrStopRequested == 0U)
  4402. && (PlsrAbStopArmed == 0U)
  4403. && (PlsrRunStatus != PLSR_STATUS_WAITING))
  4404. {
  4405. PlsrFrequencyUpdateTargetHz =
  4406. PlsrResolvedSegmentFrequency(&PlsrCandidateConfig,
  4407. index);
  4408. PlsrFrequencyUpdateSegment = (uint8_t)(index + 1U);
  4409. PlsrFrequencyUpdatePending = 1U;
  4410. }
  4411. }
  4412. PlsrPreparedHandoffBank = handoffBank;
  4413. PlsrHandoffPlan.valid = 0U;
  4414. PlsrProfileQueueInvalidateGeneration();
  4415. if ((drainedToDifferentSegment == 0U)
  4416. && (PlsrPulseActive != 0U)
  4417. && (PlsrAbStopArmed == 0U)
  4418. && (PlsrShortProfile.active == 0U)
  4419. && (PlsrRemainingPulses == 1UL))
  4420. {
  4421. (void)PlsrPrimeHandoff();
  4422. }
  4423. if ((drainedToDifferentSegment != 0U)
  4424. && (PlsrPulseActive != 0U)
  4425. && (PlsrCurrentSegment != 0U)
  4426. && (PlsrCurrentSegment <= PlsrActiveConfig.segmentCount)
  4427. && (PlsrStopRequested == 0U)
  4428. && (PlsrAbStopArmed == 0U)
  4429. && (PlsrRunStatus != PLSR_STATUS_WAITING)
  4430. && (PlsrCurrentFrequencyHz != drainedSegmentTargetHz))
  4431. {
  4432. PlsrFrequencyUpdateTargetHz =
  4433. drainedSegmentTargetHz;
  4434. PlsrFrequencyUpdateSegment = PlsrCurrentSegment;
  4435. PlsrFrequencyUpdatePending = 1U;
  4436. }
  4437. }
  4438. PlsrPlatformExitCritical(criticalState);
  4439. if ((updateActiveFrequencies != 0U)
  4440. && (PlsrPulseActive != 0U)
  4441. && (PlsrAbStopArmed == 0U)
  4442. && (PlsrFrequencyUpdatePending == 0U)
  4443. && (PlsrPrepareFutureHandoffQueue() == 0U))
  4444. {
  4445. PlsrTimerErrorPending = 1U;
  4446. }
  4447. if ((drainedToDifferentSegment != 0U)
  4448. && (PlsrAbStopArmed == 0U)
  4449. && (PlsrFrequencyUpdatePending != 0U))
  4450. {
  4451. uint32_t drainEpoch = PlsrSegmentEpoch;
  4452. uint32_t actualDrainFrequencyHz;
  4453. queueResult = PlsrDiagnosticQueueFrequency(
  4454. (uint8_t)PlsrActiveConfig.pulseOutput,
  4455. drainedSegmentTargetHz, &actualDrainFrequencyHz);
  4456. if (queueResult == PLSR_PLATFORM_QUEUE_FAILED)
  4457. {
  4458. PlsrTimerErrorPending = 1U;
  4459. }
  4460. else if (queueResult == PLSR_PLATFORM_QUEUE_APPLIED)
  4461. {
  4462. uint32_t currentEpoch;
  4463. uint8_t updateSegment;
  4464. uint8_t currentSegment;
  4465. criticalState = PlsrPlatformEnterCritical();
  4466. currentEpoch = PlsrSegmentEpoch;
  4467. updateSegment = PlsrFrequencyUpdateSegment;
  4468. currentSegment = PlsrCurrentSegment;
  4469. if ((currentEpoch == drainEpoch)
  4470. && (updateSegment == currentSegment))
  4471. {
  4472. PlsrQueuedFrequencyHz = actualDrainFrequencyHz;
  4473. PlsrFrequencyUpdatePending = 0U;
  4474. PlsrRamp.active = 0U;
  4475. PlsrRunStatus = PLSR_STATUS_RUNNING;
  4476. }
  4477. PlsrPlatformExitCritical(criticalState);
  4478. }
  4479. }
  4480. PlsrPlatformCheckpointConfig(&PlsrShadowConfig);
  4481. PlsrMarkPersistenceDirty(PLSR_CONFIG_SAVE_DELAY_MS);
  4482. return PLSR_MB_OK;
  4483. }
  4484. #ifdef PLSR_HOST_TEST
  4485. void PlsrTestSetPosition(int32_t position, uint8_t positionValid)
  4486. {
  4487. uint32_t criticalState = PlsrPlatformEnterCritical();
  4488. PlsrPosition = position;
  4489. PlsrPositionValid = (positionValid != 0U) ? 1U : 0U;
  4490. PlsrRemainingPulses = 0UL;
  4491. PlsrPositionCheckpointDirty = 0U;
  4492. PlsrPlatformExitCritical(criticalState);
  4493. PlsrPlatformCheckpointPosition(position, PlsrPositionValid, 0U);
  4494. }
  4495. void PlsrTestSetDiagnosticCurveCounts(uint32_t sampleCount,
  4496. uint32_t mismatchCount)
  4497. {
  4498. PlsrDiagnostic.curveSampleCount = sampleCount;
  4499. PlsrDiagnostic.curveMismatchCount = mismatchCount;
  4500. }
  4501. void PlsrTestForceProfileQueueEmpty(void)
  4502. {
  4503. PlsrProfileQueue.readIndex = PlsrProfileQueue.writeIndex;
  4504. PlsrProfileQueue.generatorComplete = 0U;
  4505. PlsrProfileQueue.active = 1U;
  4506. }
  4507. uint16_t PlsrTestProfileQueueCount(void)
  4508. {
  4509. return PlsrProfileQueueCount();
  4510. }
  4511. uint32_t PlsrTestProfileQueueGeneration(void)
  4512. {
  4513. return PlsrProfileQueue.generation;
  4514. }
  4515. uint32_t PlsrTestProfileQueueReadIndex(void)
  4516. {
  4517. return PlsrProfileQueue.readIndex;
  4518. }
  4519. uint32_t PlsrTestProfileQueueWriteIndex(void)
  4520. {
  4521. return PlsrProfileQueue.writeIndex;
  4522. }
  4523. uint32_t PlsrTestProfileQueueHeadFrequency(void)
  4524. {
  4525. uint32_t readIndex = PlsrProfileQueue.readIndex;
  4526. if (readIndex == PlsrProfileQueue.writeIndex)
  4527. {
  4528. return 0UL;
  4529. }
  4530. return PlsrProfileQueue
  4531. .entries[readIndex & PLSR_PROFILE_QUEUE_MASK].requestedFrequencyHz;
  4532. }
  4533. uint16_t PlsrTestProfileProducerNextPeriod(void)
  4534. {
  4535. return PlsrProfileQueue.producerProfile.nextPeriod;
  4536. }
  4537. uint16_t PlsrTestActiveProfileNextPeriod(void)
  4538. {
  4539. return PlsrShortProfile.nextPeriod;
  4540. }
  4541. uint32_t PlsrTestLastGateEvent(void)
  4542. {
  4543. return PlsrHostTestLastGateEvent;
  4544. }
  4545. uint32_t PlsrTestLastDiagnosticFinishEvent(void)
  4546. {
  4547. return PlsrHostTestLastDiagnosticFinishEvent;
  4548. }
  4549. #endif