Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 
 
 
 
 

5330 rindas
169 KiB

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