You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

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