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

4814 lines
151 KiB

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