25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4306 lines
134 KiB

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