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

3600 rindas
110 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_CONFIG_SAVE_DELAY_MS (1000U)
  27. #define PLSR_POSITION_CHECKPOINT_MS (10U)
  28. #define PLSR_SHORT_PROFILE_MAX_PULSES (65535UL)
  29. #define PLSR_Q32_ONE (4294967296ULL)
  30. typedef struct
  31. {
  32. uint32_t fromHz;
  33. uint32_t toHz;
  34. uint32_t durationMs;
  35. uint32_t elapsedMs;
  36. uint8_t active;
  37. } PLSR_RAMP;
  38. typedef struct
  39. {
  40. uint32_t startHz;
  41. uint32_t peakHz;
  42. uint32_t endHz;
  43. uint16_t pulseCount;
  44. uint16_t entryPulses;
  45. uint16_t steadyPulses;
  46. uint16_t exitPulses;
  47. volatile uint16_t nextPeriod;
  48. uint64_t rampBoundaryQ32;
  49. uint64_t rampTotalAreaQ32;
  50. uint64_t rampTargetAreaQ32;
  51. uint64_t rampAreaStepQ32;
  52. uint32_t rampAreaRemainder;
  53. uint32_t rampRemainderAccumulator;
  54. uint64_t lastRampPhaseStepQ32;
  55. uint64_t entryFirstBoundaryQ32;
  56. uint64_t entrySecondBoundaryQ32;
  57. uint64_t exitFirstBoundaryQ32;
  58. uint64_t exitSecondBoundaryQ32;
  59. uint32_t lastRampFrequencyHz;
  60. volatile uint8_t active;
  61. } PLSR_SHORT_PROFILE;
  62. typedef struct
  63. {
  64. uint64_t magnitude;
  65. uint32_t firstFrequencyHz;
  66. PLSR_SHORT_PROFILE profile;
  67. uint8_t nextSegment;
  68. uint8_t positive;
  69. volatile uint8_t valid;
  70. } PLSR_HANDOFF_PLAN;
  71. typedef enum
  72. {
  73. PLSR_WORD_OK = 0,
  74. PLSR_WORD_ILLEGAL_ADDRESS,
  75. PLSR_WORD_ILLEGAL_VALUE
  76. } PLSR_WORD_RESULT;
  77. typedef enum
  78. {
  79. PLSR_COMMAND_MAILBOX_EMPTY = 0,
  80. PLSR_COMMAND_MAILBOX_PENDING,
  81. PLSR_COMMAND_MAILBOX_EXECUTING
  82. } PLSR_COMMAND_MAILBOX_STATE;
  83. typedef struct
  84. {
  85. PLSR_CONFIG startConfig;
  86. uint16_t command;
  87. volatile uint8_t state;
  88. } PLSR_COMMAND_MAILBOX;
  89. static const uint16_t PlsrSineProgressQ16[65] =
  90. {
  91. 0U, 39U, 158U, 355U, 630U, 982U, 1411U, 1915U,
  92. 2494U, 3146U, 3869U, 4662U, 5522U, 6448U, 7438U, 8488U,
  93. 9597U, 10762U, 11980U, 13248U, 14563U, 15922U, 17321U,
  94. 18758U, 20228U, 21728U, 23256U, 24806U, 26375U, 27960U,
  95. 29556U, 31160U, 32767U, 34375U, 35979U, 37575U, 39160U,
  96. 40729U, 42279U, 43807U, 45307U, 46777U, 48214U, 49613U,
  97. 50972U, 52287U, 53555U, 54773U, 55938U, 57047U, 58097U,
  98. 59087U, 60013U, 60873U, 61666U, 62389U, 63041U, 63620U,
  99. 64124U, 64553U, 64905U, 65180U, 65377U, 65496U, 65535U
  100. };
  101. static const uint32_t PlsrSmoothIntegralQ24[65] =
  102. {
  103. 0UL, 64UL, 504UL, 1688UL, 3968UL, 7688UL, 13176UL, 20752UL,
  104. 30720UL, 43376UL, 59000UL, 77864UL, 100224UL, 126328UL, 156408UL,
  105. 190688UL, 229376UL, 272672UL, 320760UL, 373816UL, 432000UL,
  106. 495464UL, 564344UL, 638768UL, 718848UL, 804688UL, 896376UL,
  107. 993992UL, 1097600UL, 1207256UL, 1323000UL, 1444864UL, 1572864UL,
  108. 1707008UL, 1847288UL, 1993688UL, 2146176UL, 2304712UL, 2469240UL,
  109. 2639696UL, 2816000UL, 2998064UL, 3185784UL, 3379048UL, 3577728UL,
  110. 3781688UL, 3990776UL, 4204832UL, 4423680UL, 4647136UL, 4875000UL,
  111. 5107064UL, 5343104UL, 5582888UL, 5826168UL, 6072688UL, 6322176UL,
  112. 6574352UL, 6828920UL, 7085576UL, 7344000UL, 7603864UL, 7864824UL,
  113. 8126528UL, 8388608UL
  114. };
  115. static const uint32_t PlsrSineIntegralQ24[65] =
  116. {
  117. 0UL, 53UL, 421UL, 1420UL, 3362UL, 6560UL, 11321UL, 17949UL,
  118. 26744UL, 38000UL, 52007UL, 69047UL, 89393UL, 113314UL, 141066UL,
  119. 172899UL, 209052UL, 249753UL, 295221UL, 345662UL, 401269UL,
  120. 462225UL, 528698UL, 600845UL, 678806UL, 762711UL, 852672UL,
  121. 948789UL, 1051146UL, 1159812UL, 1274841UL, 1396271UL, 1524127UL,
  122. 1658415UL, 1799129UL, 1946244UL, 2099722UL, 2259509UL, 2425536UL,
  123. 2597719UL, 2775958UL, 2960141UL, 3150138UL, 3345809UL, 3546997UL,
  124. 3753534UL, 3965237UL, 4181913UL, 4403356UL, 4629347UL, 4859658UL,
  125. 5094050UL, 5332273UL, 5574071UL, 5819175UL, 6067312UL, 6318200UL,
  126. 6571549UL, 6827065UL, 7084448UL, 7343394UL, 7603596UL, 7864741UL,
  127. 8126517UL, 8388608UL
  128. };
  129. static PLSR_CONFIG PlsrShadowConfig;
  130. static PLSR_CONFIG PlsrActiveConfig;
  131. static PLSR_CONFIG PlsrCandidateConfig;
  132. static volatile int32_t PlsrPosition;
  133. static volatile uint64_t PlsrRemainingPulses;
  134. static volatile uint8_t PlsrPulseActive;
  135. static volatile uint8_t PlsrCutRequested;
  136. static volatile uint8_t PlsrBoundaryPending;
  137. static volatile uint8_t PlsrBoundaryWasCut;
  138. static volatile uint8_t PlsrCountPositive;
  139. static volatile uint8_t PlsrCountOverflowPending;
  140. static volatile uint8_t PlsrPositionValid;
  141. static volatile uint8_t PlsrPositionCheckpointDirty;
  142. static volatile uint8_t PlsrFrequencyUpdatePending;
  143. static volatile uint8_t PlsrFrequencyUpdateSegment;
  144. static volatile uint8_t PlsrSeamlessHandoffPending;
  145. static volatile uint8_t PlsrTimerErrorPending;
  146. static volatile uint8_t PlsrDeferredFrequencyPending;
  147. static volatile uint32_t PlsrCurrentFrequencyHz;
  148. static volatile uint32_t PlsrQueuedFrequencyHz;
  149. static volatile uint32_t PlsrBoundaryFrequencyHz;
  150. static volatile uint32_t PlsrFrequencyUpdateTargetHz;
  151. static volatile uint32_t PlsrDeferredFrequencyHz;
  152. static volatile uint32_t PlsrSegmentEpoch;
  153. static volatile PLSR_STATUS PlsrRunStatus = PLSR_STATUS_UNINITIALIZED;
  154. static PLSR_ERROR PlsrError = PLSR_ERROR_NONE;
  155. static PLSR_RAMP PlsrRamp;
  156. static PLSR_SHORT_PROFILE PlsrShortProfile;
  157. static PLSR_HANDOFF_PLAN PlsrHandoffPlan;
  158. static PLSR_HANDOFF_PLAN
  159. PlsrPreparedHandoffPlans[2][PLSR_SEGMENT_COUNT_MAX];
  160. static volatile uint8_t PlsrPreparedHandoffBank;
  161. static uint8_t PlsrInitialized;
  162. static volatile uint8_t PlsrCurrentSegment;
  163. static uint8_t PlsrDirectionDelayActive;
  164. static uint16_t PlsrDirectionDelayRemainingMs;
  165. static volatile uint8_t PlsrSegmentClockStarted;
  166. static volatile uint32_t PlsrSegmentElapsedMs;
  167. static volatile uint32_t PlsrWaitElapsedMs;
  168. static volatile uint8_t PlsrExtPreviousLevel;
  169. static volatile uint8_t PlsrExtEdgePending;
  170. static volatile uint8_t PlsrStopRequested;
  171. static volatile uint8_t PlsrStopPulsesRemaining;
  172. static volatile uint8_t PlsrBoundaryRampStarted;
  173. static uint8_t PlsrLastDirectionValid;
  174. static uint8_t PlsrLastDirectionOutput;
  175. static uint8_t PlsrLastDirectionLevel;
  176. static uint8_t PlsrPersistenceDirty;
  177. static uint16_t PlsrPersistenceDelayMs;
  178. static uint8_t PlsrPositionCheckpointElapsedMs;
  179. static PLSR_COMMAND_MAILBOX PlsrCommandMailbox;
  180. static uint8_t PlsrIsBusy(void);
  181. static void PlsrSetDefaults(PLSR_CONFIG *config);
  182. static uint8_t PlsrConfigIsValid(const PLSR_CONFIG *config,
  183. uint8_t validateActivePath);
  184. static uint16_t PlsrReadConfigWord(const PLSR_CONFIG *config,
  185. uint16_t address);
  186. static PLSR_WORD_RESULT PlsrWriteConfigWord(PLSR_CONFIG *config,
  187. uint16_t address,
  188. uint16_t value);
  189. static uint8_t PlsrAddressIsDwordHalf(uint16_t address,
  190. uint16_t *pairedAddress);
  191. static PLSR_MB_RESULT PlsrQueueCommand(uint16_t command);
  192. static uint8_t PlsrPollCommandMailbox(void);
  193. static void PlsrExecuteStart(void);
  194. static uint8_t PlsrExecuteStop(void);
  195. static void PlsrExecuteClear(void);
  196. static uint8_t PlsrStartSegment(uint8_t segmentNumber,
  197. uint8_t allowCarry,
  198. uint32_t carryFrequencyHz);
  199. static uint8_t PlsrBeginSegmentOutput(uint32_t startFrequencyHz);
  200. static void PlsrHandleBoundary(uint8_t extEdge);
  201. static void PlsrTransitionToNext(uint8_t allowCarry);
  202. static void PlsrFinishCompleted(void);
  203. static void PlsrFinishStopped(void);
  204. static void PlsrEnterError(PLSR_ERROR error);
  205. static void PlsrMarkPersistenceDirty(uint16_t delayMs);
  206. static void PlsrCheckpointPosition(uint8_t wasBusy);
  207. static void PlsrPollPositionCheckpoint(void);
  208. static uint8_t PlsrTrySubsequentHandoff(void);
  209. static uint8_t PlsrPrepareShortProfile(PLSR_SHORT_PROFILE *profile,
  210. uint8_t segmentNumber,
  211. uint32_t startFrequencyHz,
  212. uint32_t targetFrequencyHz,
  213. uint64_t pulseCount);
  214. static uint32_t PlsrShortProfileTakeFrequency(PLSR_SHORT_PROFILE *profile);
  215. static uint8_t PlsrAdvanceShortProfile(uint8_t pulseOutput);
  216. static void PlsrCopyShortProfile(PLSR_SHORT_PROFILE *destination,
  217. const PLSR_SHORT_PROFILE *source);
  218. static void PlsrInvalidateHandoffPlans(void);
  219. static uint8_t PlsrBuildHandoffPlanBank(
  220. const PLSR_CONFIG *frequencyConfig);
  221. static uint8_t PlsrSelectPreparedHandoffPlan(PLSR_HANDOFF_PLAN *plan);
  222. static uint8_t PlsrPrimeHandoff(void);
  223. static uint8_t PlsrBuildHandoffPlan(uint8_t sourceSegment,
  224. const PLSR_CONFIG *frequencyConfig,
  225. PLSR_HANDOFF_PLAN *plan);
  226. static uint8_t PlsrIsBusy(void)
  227. {
  228. return ((PlsrRunStatus == PLSR_STATUS_ACCELERATING)
  229. || (PlsrRunStatus == PLSR_STATUS_RUNNING)
  230. || (PlsrRunStatus == PLSR_STATUS_DECELERATING)
  231. || (PlsrRunStatus == PLSR_STATUS_WAITING)
  232. || (PlsrRunStatus == PLSR_STATUS_PAUSED)) ? 1U : 0U;
  233. }
  234. static uint32_t PlsrJoinU32(uint16_t lowWord, uint16_t highWord)
  235. {
  236. return (uint32_t)lowWord | ((uint32_t)highWord << 16U);
  237. }
  238. static uint16_t PlsrLowWord(uint32_t value)
  239. {
  240. return (uint16_t)(value & 0xFFFFUL);
  241. }
  242. static uint16_t PlsrHighWord(uint32_t value)
  243. {
  244. return (uint16_t)(value >> 16U);
  245. }
  246. static void PlsrSetDefaults(PLSR_CONFIG *config)
  247. {
  248. uint8_t index;
  249. (void)memset(config, 0, sizeof(*config));
  250. config->pulseOutput = 0U;
  251. config->directionOutput = 0U;
  252. config->waitInput = 0U;
  253. config->extInput = 0U;
  254. config->sendMode = PLSR_SEND_COMPLETE;
  255. config->directionDelayMs = 10U;
  256. config->directionNegativeLogic = 0U;
  257. config->curveMode = 0U;
  258. config->positionMode = PLSR_POSITION_RELATIVE;
  259. config->segmentCount = 1U;
  260. config->startSegment = 1U;
  261. config->defaultSpeedHz = 1000UL;
  262. config->startSpeedHz = 100UL;
  263. config->stopSpeedHz = 100UL;
  264. config->accelerationTimeMs = 100U;
  265. config->decelerationTimeMs = 100U;
  266. for (index = 0U; index < PLSR_SEGMENT_COUNT_MAX; index++)
  267. {
  268. config->segments[index].frequencyHz = 1000UL;
  269. config->segments[index].pulses = (index == 0U) ? 1000L : 0L;
  270. config->segments[index].waitType = PLSR_EXT_OR_COMPLETE;
  271. config->segments[index].waitTimeMs = 0U;
  272. config->segments[index].actTimeMs = 0U;
  273. config->segments[index].jumpSegment = 0U;
  274. }
  275. }
  276. static uint8_t PlsrConfigIsValid(const PLSR_CONFIG *config,
  277. uint8_t validateActivePath)
  278. {
  279. uint8_t index;
  280. if ((config->pulseOutput > 3U) || (config->directionOutput > 3U)
  281. || (config->waitInput > 1U) || (config->extInput > 1U)
  282. || (config->sendMode > PLSR_SEND_SUBSEQUENT)
  283. || (config->directionNegativeLogic > 1U)
  284. || (config->curveMode > 2U)
  285. || (config->positionMode > PLSR_POSITION_ABSOLUTE)
  286. || (config->segmentCount == 0U)
  287. || (config->segmentCount > PLSR_SEGMENT_COUNT_MAX)
  288. || (config->startSegment == 0U)
  289. || (config->startSegment > PLSR_SEGMENT_COUNT_MAX)
  290. || (config->defaultSpeedHz == 0UL)
  291. || (config->defaultSpeedHz > PLSR_FREQUENCY_MAX_HZ)
  292. || (config->startSpeedHz > PLSR_FREQUENCY_MAX_HZ)
  293. || (config->stopSpeedHz > PLSR_FREQUENCY_MAX_HZ))
  294. {
  295. return 0U;
  296. }
  297. if ((validateActivePath != 0U)
  298. && (config->startSegment > config->segmentCount))
  299. {
  300. return 0U;
  301. }
  302. for (index = 0U; index < PLSR_SEGMENT_COUNT_MAX; index++)
  303. {
  304. const PLSR_SEGMENT_CONFIG *segment = &config->segments[index];
  305. if ((segment->frequencyHz == 0UL)
  306. || (segment->frequencyHz > PLSR_FREQUENCY_MAX_HZ)
  307. || (segment->waitType > PLSR_EXT_OR_COMPLETE)
  308. || (segment->jumpSegment > PLSR_SEGMENT_COUNT_MAX))
  309. {
  310. return 0U;
  311. }
  312. if ((validateActivePath != 0U)
  313. && (index < config->segmentCount)
  314. && (segment->jumpSegment > config->segmentCount))
  315. {
  316. return 0U;
  317. }
  318. }
  319. return 1U;
  320. }
  321. static uint16_t PlsrReadConfigWord(const PLSR_CONFIG *config,
  322. uint16_t address)
  323. {
  324. uint16_t offset;
  325. uint8_t segmentIndex;
  326. const PLSR_SEGMENT_CONFIG *segment;
  327. switch (address)
  328. {
  329. case 0x1000U: return config->pulseOutput;
  330. case 0x1001U: return config->directionOutput;
  331. case 0x1002U: return config->waitInput;
  332. case 0x1003U: return config->extInput;
  333. case 0x1004U: return config->sendMode;
  334. case 0x1005U: return config->directionDelayMs;
  335. case 0x1006U: return config->directionNegativeLogic;
  336. case 0x1007U: return config->curveMode;
  337. case 0x1008U: return config->positionMode;
  338. case 0x1009U: return config->segmentCount;
  339. case 0x100AU: return config->startSegment;
  340. case 0x100BU: return PlsrLowWord(config->defaultSpeedHz);
  341. case 0x100CU: return PlsrHighWord(config->defaultSpeedHz);
  342. case 0x100DU: return PlsrLowWord(config->startSpeedHz);
  343. case 0x100EU: return PlsrHighWord(config->startSpeedHz);
  344. case 0x1010U: return PlsrLowWord(config->stopSpeedHz);
  345. case 0x1011U: return PlsrHighWord(config->stopSpeedHz);
  346. case 0x1012U: return config->accelerationTimeMs;
  347. case 0x1013U: return config->decelerationTimeMs;
  348. default: break;
  349. }
  350. if ((address >= PLSR_SEGMENT_FIRST_ADDRESS)
  351. && (address <= PLSR_CONFIG_LAST_ADDRESS))
  352. {
  353. offset = (uint16_t)(address - PLSR_SEGMENT_FIRST_ADDRESS);
  354. segmentIndex = (uint8_t)(offset / PLSR_SEGMENT_STRIDE);
  355. offset = (uint16_t)(offset % PLSR_SEGMENT_STRIDE);
  356. segment = &config->segments[segmentIndex];
  357. switch (offset)
  358. {
  359. case 0U: return PlsrLowWord(segment->frequencyHz);
  360. case 1U: return PlsrHighWord(segment->frequencyHz);
  361. case 2U: return PlsrLowWord((uint32_t)segment->pulses);
  362. case 3U: return PlsrHighWord((uint32_t)segment->pulses);
  363. case 4U: return segment->waitType;
  364. case 5U: return segment->waitTimeMs;
  365. case 6U: return segment->actTimeMs;
  366. case 7U: return segment->jumpSegment;
  367. default: return 0U;
  368. }
  369. }
  370. /* 0x100F, 0x1014..0x10FF, and segment padding read as zero. */
  371. return 0U;
  372. }
  373. static PLSR_WORD_RESULT PlsrWriteConfigWord(PLSR_CONFIG *config,
  374. uint16_t address,
  375. uint16_t value)
  376. {
  377. uint16_t offset;
  378. uint8_t segmentIndex;
  379. PLSR_SEGMENT_CONFIG *segment;
  380. switch (address)
  381. {
  382. case 0x1000U: config->pulseOutput = value; return PLSR_WORD_OK;
  383. case 0x1001U: config->directionOutput = value; return PLSR_WORD_OK;
  384. case 0x1002U: config->waitInput = value; return PLSR_WORD_OK;
  385. case 0x1003U: config->extInput = value; return PLSR_WORD_OK;
  386. case 0x1004U: config->sendMode = value; return PLSR_WORD_OK;
  387. case 0x1005U: config->directionDelayMs = value; return PLSR_WORD_OK;
  388. case 0x1006U:
  389. config->directionNegativeLogic = value;
  390. return PLSR_WORD_OK;
  391. case 0x1007U: config->curveMode = value; return PLSR_WORD_OK;
  392. case 0x1008U: config->positionMode = value; return PLSR_WORD_OK;
  393. case 0x1009U: config->segmentCount = value; return PLSR_WORD_OK;
  394. case 0x100AU: config->startSegment = value; return PLSR_WORD_OK;
  395. case 0x100BU:
  396. config->defaultSpeedHz =
  397. PlsrJoinU32(value, PlsrHighWord(config->defaultSpeedHz));
  398. return PLSR_WORD_OK;
  399. case 0x100CU:
  400. config->defaultSpeedHz =
  401. PlsrJoinU32(PlsrLowWord(config->defaultSpeedHz), value);
  402. return PLSR_WORD_OK;
  403. case 0x100DU:
  404. config->startSpeedHz =
  405. PlsrJoinU32(value, PlsrHighWord(config->startSpeedHz));
  406. return PLSR_WORD_OK;
  407. case 0x100EU:
  408. config->startSpeedHz =
  409. PlsrJoinU32(PlsrLowWord(config->startSpeedHz), value);
  410. return PLSR_WORD_OK;
  411. case 0x100FU:
  412. return (value == 0U) ? PLSR_WORD_OK : PLSR_WORD_ILLEGAL_VALUE;
  413. case 0x1010U:
  414. config->stopSpeedHz =
  415. PlsrJoinU32(value, PlsrHighWord(config->stopSpeedHz));
  416. return PLSR_WORD_OK;
  417. case 0x1011U:
  418. config->stopSpeedHz =
  419. PlsrJoinU32(PlsrLowWord(config->stopSpeedHz), value);
  420. return PLSR_WORD_OK;
  421. case 0x1012U:
  422. config->accelerationTimeMs = value;
  423. return PLSR_WORD_OK;
  424. case 0x1013U:
  425. config->decelerationTimeMs = value;
  426. return PLSR_WORD_OK;
  427. default: break;
  428. }
  429. if ((address >= 0x1014U) && (address <= PLSR_COMMON_LAST_ADDRESS))
  430. {
  431. return (value == 0U) ? PLSR_WORD_OK : PLSR_WORD_ILLEGAL_VALUE;
  432. }
  433. if ((address < PLSR_SEGMENT_FIRST_ADDRESS)
  434. || (address > PLSR_CONFIG_LAST_ADDRESS))
  435. {
  436. return PLSR_WORD_ILLEGAL_ADDRESS;
  437. }
  438. offset = (uint16_t)(address - PLSR_SEGMENT_FIRST_ADDRESS);
  439. segmentIndex = (uint8_t)(offset / PLSR_SEGMENT_STRIDE);
  440. offset = (uint16_t)(offset % PLSR_SEGMENT_STRIDE);
  441. segment = &config->segments[segmentIndex];
  442. switch (offset)
  443. {
  444. case 0U:
  445. segment->frequencyHz =
  446. PlsrJoinU32(value, PlsrHighWord(segment->frequencyHz));
  447. return PLSR_WORD_OK;
  448. case 1U:
  449. segment->frequencyHz =
  450. PlsrJoinU32(PlsrLowWord(segment->frequencyHz), value);
  451. return PLSR_WORD_OK;
  452. case 2U:
  453. segment->pulses = (int32_t)PlsrJoinU32(
  454. value, PlsrHighWord((uint32_t)segment->pulses));
  455. return PLSR_WORD_OK;
  456. case 3U:
  457. segment->pulses = (int32_t)PlsrJoinU32(
  458. PlsrLowWord((uint32_t)segment->pulses), value);
  459. return PLSR_WORD_OK;
  460. case 4U: segment->waitType = value; return PLSR_WORD_OK;
  461. case 5U: segment->waitTimeMs = value; return PLSR_WORD_OK;
  462. case 6U: segment->actTimeMs = value; return PLSR_WORD_OK;
  463. case 7U: segment->jumpSegment = value; return PLSR_WORD_OK;
  464. default:
  465. return (value == 0U) ? PLSR_WORD_OK : PLSR_WORD_ILLEGAL_VALUE;
  466. }
  467. }
  468. static uint8_t PlsrAddressIsDwordHalf(uint16_t address,
  469. uint16_t *pairedAddress)
  470. {
  471. uint16_t offset;
  472. switch (address)
  473. {
  474. case 0x100BU: case 0x100DU: case 0x1010U:
  475. *pairedAddress = (uint16_t)(address + 1U);
  476. return 1U;
  477. case 0x100CU: case 0x100EU: case 0x1011U:
  478. *pairedAddress = (uint16_t)(address - 1U);
  479. return 1U;
  480. default: break;
  481. }
  482. if ((address >= PLSR_SEGMENT_FIRST_ADDRESS)
  483. && (address <= PLSR_CONFIG_LAST_ADDRESS))
  484. {
  485. offset = (uint16_t)((address - PLSR_SEGMENT_FIRST_ADDRESS)
  486. % PLSR_SEGMENT_STRIDE);
  487. if ((offset == 0U) || (offset == 2U))
  488. {
  489. *pairedAddress = (uint16_t)(address + 1U);
  490. return 1U;
  491. }
  492. if ((offset == 1U) || (offset == 3U))
  493. {
  494. *pairedAddress = (uint16_t)(address - 1U);
  495. return 1U;
  496. }
  497. }
  498. return 0U;
  499. }
  500. static uint8_t PlsrAddressIsProduct(uint16_t address)
  501. {
  502. return (((address >= PLSR_CONFIG_FIRST_ADDRESS)
  503. && (address <= PLSR_CONFIG_LAST_ADDRESS))
  504. || ((address >= PLSR_STATUS_FIRST_ADDRESS)
  505. && (address <= PLSR_STATUS_LAST_ADDRESS))
  506. || (address == PLSR_CONTROL_ADDRESS)) ? 1U : 0U;
  507. }
  508. static PLSR_MB_RESULT PlsrClassifyRange(uint16_t startAddress,
  509. uint16_t quantity)
  510. {
  511. uint32_t address;
  512. uint32_t endAddress;
  513. uint8_t foundProduct = 0U;
  514. uint8_t foundOther = 0U;
  515. if (quantity == 0U)
  516. {
  517. return PLSR_MB_ILLEGAL_VALUE;
  518. }
  519. endAddress = (uint32_t)startAddress + (uint32_t)quantity - 1UL;
  520. if (endAddress > 0xFFFFUL)
  521. {
  522. return PLSR_MB_ILLEGAL_ADDRESS;
  523. }
  524. for (address = startAddress; address <= endAddress; address++)
  525. {
  526. if (PlsrAddressIsProduct((uint16_t)address) != 0U)
  527. {
  528. foundProduct = 1U;
  529. }
  530. else
  531. {
  532. foundOther = 1U;
  533. }
  534. }
  535. if (foundProduct == 0U)
  536. {
  537. return PLSR_MB_NOT_HANDLED;
  538. }
  539. return (foundOther != 0U) ? PLSR_MB_ILLEGAL_ADDRESS : PLSR_MB_OK;
  540. }
  541. static uint32_t PlsrCurveProgressQ16(uint32_t elapsed,
  542. uint32_t duration,
  543. uint16_t curveMode)
  544. {
  545. uint32_t linear;
  546. if ((duration == 0UL) || (elapsed >= duration))
  547. {
  548. return 65535UL;
  549. }
  550. linear = (uint32_t)(((uint64_t)elapsed * 65535UL) / duration);
  551. if (curveMode == 1U)
  552. {
  553. uint64_t x = linear;
  554. uint64_t x2 = (x * x) / 65535UL;
  555. return (uint32_t)((x2 * (196605UL - 2UL * x)) / 65535UL);
  556. }
  557. if (curveMode == 2U)
  558. {
  559. uint32_t scaled = linear * 64UL;
  560. uint32_t index = scaled / 65535UL;
  561. uint32_t fraction = scaled % 65535UL;
  562. uint32_t first;
  563. uint32_t second;
  564. if (index >= 64UL)
  565. {
  566. return 65535UL;
  567. }
  568. first = PlsrSineProgressQ16[index];
  569. second = PlsrSineProgressQ16[index + 1UL];
  570. return first + (uint32_t)(((uint64_t)(second - first) * fraction)
  571. / 65535UL);
  572. }
  573. return linear;
  574. }
  575. static uint32_t PlsrRampDurationMs(uint32_t fromHz, uint32_t toHz)
  576. {
  577. uint32_t gap;
  578. uint32_t baseTimeMs;
  579. uint64_t duration;
  580. if (fromHz == toHz)
  581. {
  582. return 0UL;
  583. }
  584. gap = (fromHz > toHz) ? (fromHz - toHz) : (toHz - fromHz);
  585. baseTimeMs = (toHz > fromHz) ? PlsrActiveConfig.accelerationTimeMs
  586. : PlsrActiveConfig.decelerationTimeMs;
  587. if (baseTimeMs == 0UL)
  588. {
  589. return 0UL;
  590. }
  591. duration = ((uint64_t)gap * baseTimeMs
  592. + PlsrActiveConfig.defaultSpeedHz - 1UL)
  593. / PlsrActiveConfig.defaultSpeedHz;
  594. if (duration > 0xFFFFFFFFUL)
  595. {
  596. return 0xFFFFFFFFUL;
  597. }
  598. return (uint32_t)duration;
  599. }
  600. static void PlsrRampStart(uint32_t fromHz, uint32_t toHz)
  601. {
  602. PlsrRamp.fromHz = fromHz;
  603. PlsrRamp.toHz = toHz;
  604. PlsrRamp.durationMs = PlsrRampDurationMs(fromHz, toHz);
  605. PlsrRamp.elapsedMs = 0UL;
  606. PlsrRamp.active = (PlsrRamp.durationMs != 0UL) ? 1U : 0U;
  607. if (toHz > fromHz)
  608. {
  609. PlsrRunStatus = PLSR_STATUS_ACCELERATING;
  610. }
  611. else if (toHz < fromHz)
  612. {
  613. PlsrRunStatus = PLSR_STATUS_DECELERATING;
  614. }
  615. else
  616. {
  617. PlsrRunStatus = PLSR_STATUS_RUNNING;
  618. }
  619. }
  620. static uint8_t PlsrApplyFrequencyPair(uint32_t requestedFirstFrequencyHz,
  621. uint32_t requestedQueuedFrequencyHz,
  622. uint32_t expectedEpoch)
  623. {
  624. uint32_t criticalState;
  625. uint32_t actualFirstFrequencyHz;
  626. uint32_t actualQueuedFrequencyHz;
  627. uint32_t hardwareFirstFrequencyHz = requestedFirstFrequencyHz;
  628. uint32_t hardwareQueuedFrequencyHz = requestedQueuedFrequencyHz;
  629. PLSR_HANDOFF_PLAN candidatePlan;
  630. uint8_t haveCandidatePlan = 0U;
  631. criticalState = PlsrPlatformEnterCritical();
  632. if ((PlsrSegmentEpoch != expectedEpoch)
  633. || (PlsrBoundaryPending != 0U) || (PlsrRemainingPulses == 0UL))
  634. {
  635. PlsrPlatformExitCritical(criticalState);
  636. return 1U;
  637. }
  638. if (hardwareFirstFrequencyHz == 0UL)
  639. {
  640. if (PlsrPulseActive == 0U)
  641. {
  642. PlsrCurrentFrequencyHz = 0UL;
  643. PlsrQueuedFrequencyHz = 0UL;
  644. PlsrPlatformExitCritical(criticalState);
  645. return 1U;
  646. }
  647. hardwareFirstFrequencyHz = 1UL;
  648. }
  649. if (hardwareQueuedFrequencyHz == 0UL)
  650. {
  651. hardwareQueuedFrequencyHz = 1UL;
  652. }
  653. if (PlsrPulseActive != 0U)
  654. {
  655. if (PlsrHandoffPlan.valid != 0U)
  656. {
  657. PlsrPlatformExitCritical(criticalState);
  658. return 1U;
  659. }
  660. PlsrDeferredFrequencyHz = hardwareQueuedFrequencyHz;
  661. PlsrDeferredFrequencyPending = 1U;
  662. PlsrPlatformExitCritical(criticalState);
  663. return 1U;
  664. }
  665. else
  666. {
  667. if (PlsrSelectPreparedHandoffPlan(&candidatePlan) != 0U)
  668. {
  669. hardwareQueuedFrequencyHz = candidatePlan.firstFrequencyHz;
  670. haveCandidatePlan = 1U;
  671. }
  672. if (PlsrPlatformStartPulse((uint8_t)PlsrActiveConfig.pulseOutput,
  673. hardwareFirstFrequencyHz,
  674. hardwareQueuedFrequencyHz,
  675. &actualFirstFrequencyHz,
  676. &actualQueuedFrequencyHz) == 0U)
  677. {
  678. PlsrPlatformExitCritical(criticalState);
  679. return 0U;
  680. }
  681. PlsrPulseActive = 1U;
  682. PlsrCurrentFrequencyHz = actualFirstFrequencyHz;
  683. PlsrHandoffPlan.valid = 0U;
  684. if (haveCandidatePlan != 0U)
  685. {
  686. PlsrHandoffPlan.magnitude = candidatePlan.magnitude;
  687. PlsrHandoffPlan.firstFrequencyHz = actualQueuedFrequencyHz;
  688. PlsrCopyShortProfile(&PlsrHandoffPlan.profile,
  689. &candidatePlan.profile);
  690. PlsrHandoffPlan.nextSegment = candidatePlan.nextSegment;
  691. PlsrHandoffPlan.positive = candidatePlan.positive;
  692. PlsrHandoffPlan.valid = 1U;
  693. }
  694. }
  695. PlsrQueuedFrequencyHz = actualQueuedFrequencyHz;
  696. PlsrPlatformExitCritical(criticalState);
  697. return 1U;
  698. }
  699. static uint8_t PlsrApplyFrequency(uint32_t requestedFrequencyHz,
  700. uint32_t expectedEpoch)
  701. {
  702. return PlsrApplyFrequencyPair(requestedFrequencyHz,
  703. requestedFrequencyHz,
  704. expectedEpoch);
  705. }
  706. static uint8_t PlsrStopDrainPulseCount(void)
  707. {
  708. uint8_t deferredPending = PlsrDeferredFrequencyPending;
  709. uint32_t deferredFrequencyHz = PlsrDeferredFrequencyHz;
  710. uint32_t queuedFrequencyHz = PlsrQueuedFrequencyHz;
  711. uint32_t currentFrequencyHz = PlsrCurrentFrequencyHz;
  712. if ((deferredPending != 0U)
  713. && (deferredFrequencyHz != queuedFrequencyHz))
  714. {
  715. return 3U;
  716. }
  717. PlsrDeferredFrequencyPending = 0U;
  718. return (currentFrequencyHz == queuedFrequencyHz) ? 1U : 2U;
  719. }
  720. static uint8_t PlsrCommitDeferredFrequency(uint8_t pulseOutput)
  721. {
  722. uint32_t requestedFrequencyHz;
  723. uint32_t actualFrequencyHz;
  724. if (PlsrDeferredFrequencyPending == 0U)
  725. {
  726. return 1U;
  727. }
  728. requestedFrequencyHz = PlsrDeferredFrequencyHz;
  729. PlsrDeferredFrequencyPending = 0U;
  730. if (PlsrPlatformQueueFrequency(pulseOutput, requestedFrequencyHz,
  731. &actualFrequencyHz) == 0U)
  732. {
  733. return 0U;
  734. }
  735. PlsrQueuedFrequencyHz = actualFrequencyHz;
  736. return 1U;
  737. }
  738. static uint8_t PlsrRampAdvance(uint32_t expectedEpoch)
  739. {
  740. uint32_t progress;
  741. uint32_t frequency;
  742. uint32_t gap;
  743. uint32_t criticalState;
  744. uint32_t fromHz;
  745. uint32_t toHz;
  746. uint32_t durationMs;
  747. uint32_t elapsedMs;
  748. criticalState = PlsrPlatformEnterCritical();
  749. if ((PlsrSegmentEpoch != expectedEpoch) || (PlsrRamp.active == 0U))
  750. {
  751. PlsrPlatformExitCritical(criticalState);
  752. return 1U;
  753. }
  754. PlsrRamp.elapsedMs++;
  755. fromHz = PlsrRamp.fromHz;
  756. toHz = PlsrRamp.toHz;
  757. durationMs = PlsrRamp.durationMs;
  758. elapsedMs = PlsrRamp.elapsedMs;
  759. PlsrPlatformExitCritical(criticalState);
  760. progress = PlsrCurveProgressQ16(elapsedMs,
  761. durationMs,
  762. PlsrActiveConfig.curveMode);
  763. if (toHz >= fromHz)
  764. {
  765. gap = toHz - fromHz;
  766. frequency = fromHz
  767. + (uint32_t)(((uint64_t)gap * progress) / 65535UL);
  768. }
  769. else
  770. {
  771. gap = fromHz - toHz;
  772. frequency = fromHz
  773. - (uint32_t)(((uint64_t)gap * progress) / 65535UL);
  774. }
  775. if (PlsrApplyFrequency(frequency, expectedEpoch) == 0U)
  776. {
  777. return 0U;
  778. }
  779. criticalState = PlsrPlatformEnterCritical();
  780. if (PlsrSegmentEpoch != expectedEpoch)
  781. {
  782. PlsrPlatformExitCritical(criticalState);
  783. return 1U;
  784. }
  785. if (elapsedMs >= durationMs)
  786. {
  787. PlsrRamp.active = 0U;
  788. if (PlsrStopRequested == 0U)
  789. {
  790. PlsrRunStatus = PLSR_STATUS_RUNNING;
  791. }
  792. else
  793. {
  794. PlsrStopPulsesRemaining = PlsrStopDrainPulseCount();
  795. }
  796. }
  797. PlsrPlatformExitCritical(criticalState);
  798. return 1U;
  799. }
  800. static uint8_t PlsrGetNextSegment(uint8_t *nextSegment)
  801. {
  802. const PLSR_SEGMENT_CONFIG *segment =
  803. &PlsrActiveConfig.segments[PlsrCurrentSegment - 1U];
  804. if (segment->jumpSegment != 0U)
  805. {
  806. *nextSegment = (uint8_t)segment->jumpSegment;
  807. return 1U;
  808. }
  809. if (PlsrCurrentSegment < PlsrActiveConfig.segmentCount)
  810. {
  811. *nextSegment = (uint8_t)(PlsrCurrentSegment + 1U);
  812. return 1U;
  813. }
  814. return 0U;
  815. }
  816. static int64_t PlsrSegmentDisplacement(uint8_t segmentNumber,
  817. int32_t referencePosition)
  818. {
  819. int32_t configured =
  820. PlsrActiveConfig.segments[segmentNumber - 1U].pulses;
  821. if (PlsrActiveConfig.positionMode == PLSR_POSITION_ABSOLUTE)
  822. {
  823. return (int64_t)configured - (int64_t)referencePosition;
  824. }
  825. return configured;
  826. }
  827. static uint8_t PlsrPredictNextDirection(uint8_t nextSegment,
  828. uint8_t *positive)
  829. {
  830. uint32_t criticalState;
  831. uint64_t remaining;
  832. int32_t position;
  833. uint32_t predictedBits;
  834. int32_t predictedPosition;
  835. int64_t displacement;
  836. criticalState = PlsrPlatformEnterCritical();
  837. remaining = PlsrRemainingPulses;
  838. position = PlsrPosition;
  839. PlsrPlatformExitCritical(criticalState);
  840. predictedBits = (uint32_t)position;
  841. if (PlsrCountPositive != 0U)
  842. {
  843. predictedBits += (uint32_t)remaining;
  844. }
  845. else
  846. {
  847. predictedBits -= (uint32_t)remaining;
  848. }
  849. predictedPosition = (int32_t)predictedBits;
  850. displacement = PlsrSegmentDisplacement(nextSegment, predictedPosition);
  851. if (displacement == 0)
  852. {
  853. return 0U;
  854. }
  855. *positive = (displacement > 0) ? 1U : 0U;
  856. return 1U;
  857. }
  858. static uint64_t PlsrRemainingSnapshot(void)
  859. {
  860. uint32_t criticalState = PlsrPlatformEnterCritical();
  861. uint64_t remaining = PlsrRemainingPulses;
  862. PlsrPlatformExitCritical(criticalState);
  863. return remaining;
  864. }
  865. static uint64_t PlsrRampPulseEstimate(uint32_t fromHz, uint32_t toHz)
  866. {
  867. uint32_t duration = PlsrRampDurationMs(fromHz, toHz);
  868. uint64_t sum = (uint64_t)fromHz + toHz;
  869. return (sum * duration + 1999UL) / 2000UL + 2UL;
  870. }
  871. static uint16_t PlsrShortProfileRampTime(uint32_t fromHz, uint32_t toHz)
  872. {
  873. if (toHz > fromHz)
  874. {
  875. return PlsrActiveConfig.accelerationTimeMs;
  876. }
  877. if (toHz < fromHz)
  878. {
  879. return PlsrActiveConfig.decelerationTimeMs;
  880. }
  881. return 0U;
  882. }
  883. static uint64_t PlsrShortProfileRampWeight(uint32_t fromHz,
  884. uint32_t toHz,
  885. uint16_t timeMs)
  886. {
  887. uint64_t fromSquared = (uint64_t)fromHz * fromHz;
  888. uint64_t toSquared = (uint64_t)toHz * toHz;
  889. uint64_t difference = (fromSquared > toSquared)
  890. ? (fromSquared - toSquared)
  891. : (toSquared - fromSquared);
  892. return difference * timeMs;
  893. }
  894. static uint32_t PlsrIntegerSquareRoot(uint64_t value)
  895. {
  896. uint64_t bit = (uint64_t)1U << 62U;
  897. uint64_t root = 0UL;
  898. while (bit > value)
  899. {
  900. bit >>= 2U;
  901. }
  902. while (bit != 0UL)
  903. {
  904. if (value >= (root + bit))
  905. {
  906. value -= root + bit;
  907. root = (root >> 1U) + bit;
  908. }
  909. else
  910. {
  911. root >>= 1U;
  912. }
  913. bit >>= 2U;
  914. }
  915. return (uint32_t)root;
  916. }
  917. static uint32_t PlsrShortProfilePeak(uint32_t startHz,
  918. uint32_t targetHz,
  919. uint32_t endHz,
  920. uint16_t pulseCount)
  921. {
  922. uint32_t upperEndpoint = (startHz > endHz) ? startHz : endHz;
  923. uint32_t lowerEndpoint = (startHz < endHz) ? startHz : endHz;
  924. uint16_t entryTime;
  925. uint16_t exitTime;
  926. uint32_t timeSum;
  927. uint64_t weightedEndpoints;
  928. uint64_t availableArea;
  929. uint64_t peakSquared;
  930. uint32_t peakHz;
  931. if (targetHz > upperEndpoint)
  932. {
  933. entryTime = PlsrShortProfileRampTime(startHz, targetHz);
  934. exitTime = PlsrShortProfileRampTime(targetHz, endHz);
  935. timeSum = (uint32_t)entryTime + exitTime;
  936. if (timeSum == 0UL)
  937. {
  938. return targetHz;
  939. }
  940. weightedEndpoints = ((uint64_t)startHz * startHz * entryTime)
  941. + ((uint64_t)endHz * endHz * exitTime);
  942. availableArea = (uint64_t)2U * pulseCount
  943. * PlsrActiveConfig.defaultSpeedHz * 1000UL;
  944. peakSquared = (availableArea + weightedEndpoints) / timeSum;
  945. peakHz = PlsrIntegerSquareRoot(peakSquared);
  946. if (peakHz < upperEndpoint)
  947. {
  948. peakHz = upperEndpoint;
  949. }
  950. if (peakHz > targetHz)
  951. {
  952. peakHz = targetHz;
  953. }
  954. return peakHz;
  955. }
  956. if (targetHz < lowerEndpoint)
  957. {
  958. entryTime = PlsrShortProfileRampTime(startHz, targetHz);
  959. exitTime = PlsrShortProfileRampTime(targetHz, endHz);
  960. timeSum = (uint32_t)entryTime + exitTime;
  961. if (timeSum == 0UL)
  962. {
  963. return targetHz;
  964. }
  965. weightedEndpoints = ((uint64_t)startHz * startHz * entryTime)
  966. + ((uint64_t)endHz * endHz * exitTime);
  967. availableArea = (uint64_t)2U * pulseCount
  968. * PlsrActiveConfig.defaultSpeedHz * 1000UL;
  969. if (availableArea >= weightedEndpoints)
  970. {
  971. return targetHz;
  972. }
  973. peakSquared = (weightedEndpoints - availableArea) / timeSum;
  974. peakHz = PlsrIntegerSquareRoot(peakSquared);
  975. if (peakHz < targetHz)
  976. {
  977. peakHz = targetHz;
  978. }
  979. if (peakHz > lowerEndpoint)
  980. {
  981. peakHz = lowerEndpoint;
  982. }
  983. return peakHz;
  984. }
  985. return targetHz;
  986. }
  987. static uint64_t PlsrShortProfileRequiredSteps(uint64_t rampWeight)
  988. {
  989. uint64_t denominator = (uint64_t)2U
  990. * PlsrActiveConfig.defaultSpeedHz * 1000UL;
  991. if (rampWeight == 0UL)
  992. {
  993. return 0UL;
  994. }
  995. return (rampWeight + denominator - 1UL) / denominator;
  996. }
  997. static uint32_t PlsrShortProfileReachableFrequency(uint32_t fromHz,
  998. uint32_t towardHz,
  999. uint16_t pulseCount)
  1000. {
  1001. uint16_t baseTime = PlsrShortProfileRampTime(fromHz, towardHz);
  1002. uint64_t frequencySquared = (uint64_t)fromHz * fromHz;
  1003. uint64_t changeSquared;
  1004. uint32_t reachableHz;
  1005. if ((baseTime == 0U) || (fromHz == towardHz))
  1006. {
  1007. return towardHz;
  1008. }
  1009. changeSquared = (uint64_t)2U * pulseCount
  1010. * PlsrActiveConfig.defaultSpeedHz * 1000UL / baseTime;
  1011. if (towardHz > fromHz)
  1012. {
  1013. reachableHz = PlsrIntegerSquareRoot(frequencySquared + changeSquared);
  1014. return (reachableHz > towardHz) ? towardHz : reachableHz;
  1015. }
  1016. frequencySquared = (changeSquared >= frequencySquared)
  1017. ? 0UL : (frequencySquared - changeSquared);
  1018. reachableHz = PlsrIntegerSquareRoot(frequencySquared);
  1019. if (((uint64_t)reachableHz * reachableHz) < frequencySquared)
  1020. {
  1021. reachableHz++;
  1022. }
  1023. return (reachableHz < towardHz) ? towardHz : reachableHz;
  1024. }
  1025. static uint64_t PlsrCurveIntegralQ32(uint64_t progressQ32,
  1026. uint16_t curveMode)
  1027. {
  1028. uint64_t scaled;
  1029. uint32_t index;
  1030. uint32_t fraction;
  1031. uint64_t first;
  1032. uint64_t second;
  1033. const uint32_t *table;
  1034. if (progressQ32 >= PLSR_Q32_ONE)
  1035. {
  1036. return PLSR_Q32_ONE / 2ULL;
  1037. }
  1038. if (curveMode == 0U)
  1039. {
  1040. return (progressQ32 * progressQ32) >> 33U;
  1041. }
  1042. table = (curveMode == 1U) ? PlsrSmoothIntegralQ24
  1043. : PlsrSineIntegralQ24;
  1044. scaled = progressQ32 * 64ULL;
  1045. index = (uint32_t)(scaled >> 32U);
  1046. fraction = (uint32_t)scaled;
  1047. first = (uint64_t)table[index] << 8U;
  1048. second = (uint64_t)table[index + 1UL] << 8U;
  1049. return first + (((second - first) * fraction) >> 32U);
  1050. }
  1051. static uint64_t PlsrRampAreaQ32(uint32_t fromHz,
  1052. uint32_t toHz,
  1053. uint64_t progressQ32)
  1054. {
  1055. int64_t delta = (int64_t)toHz - (int64_t)fromHz;
  1056. int64_t area = (int64_t)((uint64_t)fromHz * progressQ32)
  1057. + delta * (int64_t)PlsrCurveIntegralQ32(
  1058. progressQ32, PlsrActiveConfig.curveMode);
  1059. return (uint64_t)area;
  1060. }
  1061. static uint32_t PlsrRampInstantFrequency(uint32_t fromHz,
  1062. uint32_t toHz,
  1063. uint64_t progressQ32)
  1064. {
  1065. uint64_t curveProgressQ32;
  1066. uint64_t scaled;
  1067. uint32_t index;
  1068. uint32_t tableSlopeQ32;
  1069. uint32_t gap;
  1070. const uint32_t *integralTable;
  1071. if (progressQ32 >= PLSR_Q32_ONE)
  1072. {
  1073. return toHz;
  1074. }
  1075. if (PlsrActiveConfig.curveMode != 0U)
  1076. {
  1077. scaled = progressQ32 * 64ULL;
  1078. index = (uint32_t)(scaled >> 32U);
  1079. integralTable = (PlsrActiveConfig.curveMode == 1U)
  1080. ? PlsrSmoothIntegralQ24
  1081. : PlsrSineIntegralQ24;
  1082. tableSlopeQ32 =
  1083. (integralTable[index + 1UL] - integralTable[index]) << 14U;
  1084. curveProgressQ32 = tableSlopeQ32;
  1085. }
  1086. else
  1087. {
  1088. curveProgressQ32 = progressQ32;
  1089. }
  1090. if (toHz >= fromHz)
  1091. {
  1092. gap = toHz - fromHz;
  1093. return fromHz
  1094. + (uint32_t)(((uint64_t)gap * curveProgressQ32) >> 32U);
  1095. }
  1096. gap = fromHz - toHz;
  1097. return fromHz
  1098. - (uint32_t)(((uint64_t)gap * curveProgressQ32) >> 32U);
  1099. }
  1100. static uint64_t PlsrExactRampBoundaryQ32(uint32_t fromHz,
  1101. uint32_t toHz,
  1102. uint64_t previousBoundaryQ32,
  1103. uint64_t targetAreaQ32)
  1104. {
  1105. uint64_t lowerQ32 = previousBoundaryQ32;
  1106. uint64_t upperQ32 = PLSR_Q32_ONE;
  1107. uint64_t middleQ32;
  1108. uint32_t iteration;
  1109. /* The Q32 domain is 2^32 units wide, so 32 fixed bisections are exact. */
  1110. for (iteration = 0UL; iteration < 32UL; iteration++)
  1111. {
  1112. middleQ32 = lowerQ32 + ((upperQ32 - lowerQ32) >> 1U);
  1113. if (PlsrRampAreaQ32(fromHz, toHz, middleQ32) < targetAreaQ32)
  1114. {
  1115. lowerQ32 = middleQ32;
  1116. }
  1117. else
  1118. {
  1119. upperQ32 = middleQ32;
  1120. }
  1121. }
  1122. return upperQ32;
  1123. }
  1124. static uint32_t PlsrCountLeadingZeros32(uint32_t value)
  1125. {
  1126. #if defined(__ICCARM__)
  1127. return __CLZ(value);
  1128. #else
  1129. uint32_t count = 0U;
  1130. if ((value & 0xFFFF0000UL) == 0UL)
  1131. {
  1132. count += 16U;
  1133. value <<= 16U;
  1134. }
  1135. if ((value & 0xFF000000UL) == 0UL)
  1136. {
  1137. count += 8U;
  1138. value <<= 8U;
  1139. }
  1140. if ((value & 0xF0000000UL) == 0UL)
  1141. {
  1142. count += 4U;
  1143. value <<= 4U;
  1144. }
  1145. if ((value & 0xC0000000UL) == 0UL)
  1146. {
  1147. count += 2U;
  1148. value <<= 2U;
  1149. }
  1150. if ((value & 0x80000000UL) == 0UL)
  1151. {
  1152. count++;
  1153. }
  1154. return count;
  1155. #endif
  1156. }
  1157. static uint32_t PlsrDivideU64Low(uint32_t highWord,
  1158. uint32_t lowWord,
  1159. uint32_t divisor,
  1160. uint32_t *remainder)
  1161. {
  1162. const uint32_t halfBase = 0x10000UL;
  1163. uint32_t shift = PlsrCountLeadingZeros32(divisor);
  1164. uint32_t normalizedDivisor = divisor << shift;
  1165. uint32_t divisorHigh = normalizedDivisor >> 16U;
  1166. uint32_t divisorLow = normalizedDivisor & 0xFFFFUL;
  1167. uint32_t normalizedHigh;
  1168. uint32_t normalizedLow = lowWord << shift;
  1169. uint32_t lowHigh = normalizedLow >> 16U;
  1170. uint32_t lowLow = normalizedLow & 0xFFFFUL;
  1171. uint32_t quotientHigh;
  1172. uint32_t quotientLow;
  1173. uint32_t partialRemainder;
  1174. uint32_t middle;
  1175. uint32_t normalizedRemainder;
  1176. if (shift == 0U)
  1177. {
  1178. normalizedHigh = highWord;
  1179. }
  1180. else
  1181. {
  1182. normalizedHigh = (highWord << shift)
  1183. | (lowWord >> (32U - shift));
  1184. }
  1185. quotientHigh = normalizedHigh / divisorHigh;
  1186. partialRemainder = normalizedHigh - quotientHigh * divisorHigh;
  1187. while ((quotientHigh >= halfBase)
  1188. || (quotientHigh * divisorLow
  1189. > (partialRemainder << 16U) + lowHigh))
  1190. {
  1191. quotientHigh--;
  1192. partialRemainder += divisorHigh;
  1193. if (partialRemainder >= halfBase)
  1194. {
  1195. break;
  1196. }
  1197. }
  1198. middle = normalizedHigh * halfBase + lowHigh
  1199. - quotientHigh * normalizedDivisor;
  1200. quotientLow = middle / divisorHigh;
  1201. partialRemainder = middle - quotientLow * divisorHigh;
  1202. while ((quotientLow >= halfBase)
  1203. || (quotientLow * divisorLow
  1204. > (partialRemainder << 16U) + lowLow))
  1205. {
  1206. quotientLow--;
  1207. partialRemainder += divisorHigh;
  1208. if (partialRemainder >= halfBase)
  1209. {
  1210. break;
  1211. }
  1212. }
  1213. normalizedRemainder = middle * halfBase + lowLow
  1214. - quotientLow * normalizedDivisor;
  1215. if (remainder != NULL)
  1216. {
  1217. *remainder = normalizedRemainder >> shift;
  1218. }
  1219. return quotientHigh * halfBase + quotientLow;
  1220. }
  1221. static uint64_t PlsrDivideU64ByU32(uint64_t dividend,
  1222. uint32_t divisor,
  1223. uint32_t *remainder)
  1224. {
  1225. uint32_t highWord = (uint32_t)(dividend >> 32U);
  1226. uint32_t lowWord = (uint32_t)dividend;
  1227. uint32_t quotientHigh = highWord / divisor;
  1228. uint32_t highRemainder = highWord - quotientHigh * divisor;
  1229. uint32_t quotientLow = PlsrDivideU64Low(highRemainder, lowWord,
  1230. divisor, remainder);
  1231. return ((uint64_t)quotientHigh << 32U) | quotientLow;
  1232. }
  1233. static void PlsrPrepareShortProfileBoundaries(PLSR_SHORT_PROFILE *profile)
  1234. {
  1235. uint64_t totalAreaQ32;
  1236. uint64_t areaStepQ32;
  1237. uint64_t targetAreaQ32;
  1238. uint32_t areaRemainder;
  1239. if (profile->entryPulses != 0U)
  1240. {
  1241. totalAreaQ32 = PlsrRampAreaQ32(
  1242. profile->startHz, profile->peakHz, PLSR_Q32_ONE);
  1243. areaStepQ32 = totalAreaQ32 / profile->entryPulses;
  1244. areaRemainder = (uint32_t)(totalAreaQ32 % profile->entryPulses);
  1245. profile->entryFirstBoundaryQ32 = PlsrExactRampBoundaryQ32(
  1246. profile->startHz, profile->peakHz, 0ULL, areaStepQ32);
  1247. if (profile->entryPulses > 1U)
  1248. {
  1249. targetAreaQ32 = areaStepQ32 * 2ULL
  1250. + (((uint64_t)areaRemainder * 2ULL)
  1251. / profile->entryPulses);
  1252. profile->entrySecondBoundaryQ32 = PlsrExactRampBoundaryQ32(
  1253. profile->startHz, profile->peakHz,
  1254. profile->entryFirstBoundaryQ32, targetAreaQ32);
  1255. }
  1256. }
  1257. if (profile->exitPulses != 0U)
  1258. {
  1259. totalAreaQ32 = PlsrRampAreaQ32(
  1260. profile->peakHz, profile->endHz, PLSR_Q32_ONE);
  1261. areaStepQ32 = totalAreaQ32 / profile->exitPulses;
  1262. areaRemainder = (uint32_t)(totalAreaQ32 % profile->exitPulses);
  1263. profile->exitFirstBoundaryQ32 = PlsrExactRampBoundaryQ32(
  1264. profile->peakHz, profile->endHz, 0ULL, areaStepQ32);
  1265. if (profile->exitPulses > 1U)
  1266. {
  1267. targetAreaQ32 = areaStepQ32 * 2ULL
  1268. + (((uint64_t)areaRemainder * 2ULL)
  1269. / profile->exitPulses);
  1270. profile->exitSecondBoundaryQ32 = PlsrExactRampBoundaryQ32(
  1271. profile->peakHz, profile->endHz,
  1272. profile->exitFirstBoundaryQ32, targetAreaQ32);
  1273. }
  1274. }
  1275. }
  1276. static uint64_t PlsrRampBoundaryQ32(uint32_t fromHz,
  1277. uint32_t toHz,
  1278. uint64_t previousBoundaryQ32,
  1279. uint64_t targetAreaQ32,
  1280. uint64_t predictedStepQ32)
  1281. {
  1282. uint64_t currentAreaQ32;
  1283. uint64_t candidateQ32;
  1284. uint64_t candidateAreaQ32;
  1285. uint64_t differenceQ32;
  1286. uint64_t correctionQ32;
  1287. uint32_t derivativeHz;
  1288. currentAreaQ32 = (previousBoundaryQ32 == 0ULL)
  1289. ? 0ULL
  1290. : PlsrRampAreaQ32(fromHz, toHz,
  1291. previousBoundaryQ32);
  1292. if (targetAreaQ32 <= currentAreaQ32)
  1293. {
  1294. return previousBoundaryQ32 + 1ULL;
  1295. }
  1296. if (predictedStepQ32 != 0ULL)
  1297. {
  1298. if (predictedStepQ32 >= PLSR_Q32_ONE - previousBoundaryQ32)
  1299. {
  1300. candidateQ32 = PLSR_Q32_ONE;
  1301. }
  1302. else
  1303. {
  1304. candidateQ32 = previousBoundaryQ32 + predictedStepQ32;
  1305. }
  1306. }
  1307. else
  1308. {
  1309. derivativeHz = PlsrRampInstantFrequency(fromHz, toHz,
  1310. previousBoundaryQ32);
  1311. if (derivativeHz == 0UL)
  1312. {
  1313. derivativeHz = 1UL;
  1314. }
  1315. differenceQ32 = targetAreaQ32 - currentAreaQ32;
  1316. correctionQ32 =
  1317. PlsrDivideU64ByU32(differenceQ32 + derivativeHz - 1UL,
  1318. derivativeHz, NULL);
  1319. if (correctionQ32 >= PLSR_Q32_ONE - previousBoundaryQ32)
  1320. {
  1321. candidateQ32 = PLSR_Q32_ONE;
  1322. }
  1323. else
  1324. {
  1325. candidateQ32 = previousBoundaryQ32 + correctionQ32;
  1326. }
  1327. }
  1328. candidateAreaQ32 = PlsrRampAreaQ32(fromHz, toHz, candidateQ32);
  1329. derivativeHz = PlsrRampInstantFrequency(fromHz, toHz, candidateQ32);
  1330. if (derivativeHz == 0UL)
  1331. {
  1332. derivativeHz = 1UL;
  1333. }
  1334. if (candidateAreaQ32 < targetAreaQ32)
  1335. {
  1336. differenceQ32 = targetAreaQ32 - candidateAreaQ32;
  1337. correctionQ32 =
  1338. PlsrDivideU64ByU32(differenceQ32 + derivativeHz - 1UL,
  1339. derivativeHz, NULL);
  1340. if (correctionQ32 >= PLSR_Q32_ONE - candidateQ32)
  1341. {
  1342. candidateQ32 = PLSR_Q32_ONE;
  1343. }
  1344. else
  1345. {
  1346. candidateQ32 += correctionQ32;
  1347. }
  1348. }
  1349. else if (candidateAreaQ32 > targetAreaQ32)
  1350. {
  1351. differenceQ32 = candidateAreaQ32 - targetAreaQ32;
  1352. correctionQ32 = PlsrDivideU64ByU32(differenceQ32, derivativeHz,
  1353. NULL);
  1354. if (correctionQ32 == 0ULL)
  1355. {
  1356. correctionQ32 = 1ULL;
  1357. }
  1358. if (correctionQ32 >= candidateQ32 - previousBoundaryQ32)
  1359. {
  1360. candidateQ32 = previousBoundaryQ32 + 1ULL;
  1361. }
  1362. else
  1363. {
  1364. candidateQ32 -= correctionQ32;
  1365. }
  1366. }
  1367. /* The corrected phase step seeds the next pulse and keeps ISR work fixed. */
  1368. return candidateQ32;
  1369. }
  1370. static uint32_t PlsrRampAverageFrequency(uint64_t areaIncrementQ32,
  1371. uint64_t firstBoundaryQ32,
  1372. uint64_t secondBoundaryQ32)
  1373. {
  1374. uint64_t denominator;
  1375. uint64_t frequencyHz;
  1376. if (secondBoundaryQ32 <= firstBoundaryQ32)
  1377. {
  1378. return 1UL;
  1379. }
  1380. denominator = secondBoundaryQ32 - firstBoundaryQ32;
  1381. if (denominator == PLSR_Q32_ONE)
  1382. {
  1383. frequencyHz = (areaIncrementQ32 + denominator / 2ULL) >> 32U;
  1384. }
  1385. else
  1386. {
  1387. frequencyHz = PlsrDivideU64ByU32(
  1388. areaIncrementQ32 + denominator / 2ULL,
  1389. (uint32_t)denominator, NULL);
  1390. }
  1391. if (frequencyHz == 0UL)
  1392. {
  1393. return 1UL;
  1394. }
  1395. if (frequencyHz > PLSR_FREQUENCY_MAX_HZ)
  1396. {
  1397. return PLSR_FREQUENCY_MAX_HZ;
  1398. }
  1399. return (uint32_t)frequencyHz;
  1400. }
  1401. static uint8_t PlsrPrepareShortProfile(PLSR_SHORT_PROFILE *profile,
  1402. uint8_t segmentNumber,
  1403. uint32_t startFrequencyHz,
  1404. uint32_t targetFrequencyHz,
  1405. uint64_t pulseCount)
  1406. {
  1407. const PLSR_SEGMENT_CONFIG *segment;
  1408. uint32_t endFrequencyHz;
  1409. uint32_t peakFrequencyHz;
  1410. uint16_t entryTime;
  1411. uint16_t exitTime;
  1412. uint16_t totalPulses;
  1413. uint64_t entryWeight;
  1414. uint64_t exitWeight;
  1415. uint64_t entryRequired;
  1416. uint64_t exitRequired;
  1417. uint64_t totalWeight;
  1418. uint64_t scaledEntry;
  1419. uint64_t durationWeight;
  1420. uint64_t singleFrequencyHz;
  1421. uint16_t directTime;
  1422. uint64_t directWeight;
  1423. uint64_t directRequired;
  1424. (void)memset(profile, 0, sizeof(*profile));
  1425. if ((pulseCount == 0UL)
  1426. || (pulseCount > PLSR_SHORT_PROFILE_MAX_PULSES)
  1427. || (segmentNumber != PlsrActiveConfig.segmentCount))
  1428. {
  1429. return 0U;
  1430. }
  1431. segment = &PlsrActiveConfig.segments[segmentNumber - 1U];
  1432. if (segment->jumpSegment != 0U)
  1433. {
  1434. return 0U;
  1435. }
  1436. endFrequencyHz = PlsrActiveConfig.stopSpeedHz;
  1437. totalPulses = (uint16_t)pulseCount;
  1438. directTime = PlsrShortProfileRampTime(startFrequencyHz, endFrequencyHz);
  1439. directWeight = PlsrShortProfileRampWeight(startFrequencyHz,
  1440. endFrequencyHz,
  1441. directTime);
  1442. directRequired = PlsrShortProfileRequiredSteps(directWeight);
  1443. if (directRequired > totalPulses)
  1444. {
  1445. profile->startHz = startFrequencyHz;
  1446. profile->peakHz = PlsrShortProfileReachableFrequency(
  1447. startFrequencyHz, endFrequencyHz, totalPulses);
  1448. profile->endHz = profile->peakHz;
  1449. profile->pulseCount = totalPulses;
  1450. profile->entryPulses = totalPulses;
  1451. profile->active = 1U;
  1452. PlsrPrepareShortProfileBoundaries(profile);
  1453. return 1U;
  1454. }
  1455. peakFrequencyHz = PlsrShortProfilePeak(startFrequencyHz,
  1456. targetFrequencyHz,
  1457. endFrequencyHz,
  1458. (uint16_t)pulseCount);
  1459. entryTime = PlsrShortProfileRampTime(startFrequencyHz, peakFrequencyHz);
  1460. exitTime = PlsrShortProfileRampTime(peakFrequencyHz, endFrequencyHz);
  1461. entryWeight = PlsrShortProfileRampWeight(startFrequencyHz,
  1462. peakFrequencyHz,
  1463. entryTime);
  1464. exitWeight = PlsrShortProfileRampWeight(peakFrequencyHz,
  1465. endFrequencyHz,
  1466. exitTime);
  1467. entryRequired = PlsrShortProfileRequiredSteps(entryWeight);
  1468. exitRequired = PlsrShortProfileRequiredSteps(exitWeight);
  1469. if ((entryRequired == 0UL) && (exitRequired == 0UL))
  1470. {
  1471. return 0U;
  1472. }
  1473. profile->startHz = startFrequencyHz;
  1474. profile->peakHz = peakFrequencyHz;
  1475. profile->endHz = endFrequencyHz;
  1476. profile->pulseCount = totalPulses;
  1477. if (totalPulses == 1U)
  1478. {
  1479. durationWeight =
  1480. (uint64_t)((peakFrequencyHz > startFrequencyHz)
  1481. ? (peakFrequencyHz - startFrequencyHz)
  1482. : (startFrequencyHz - peakFrequencyHz)) * entryTime
  1483. + (uint64_t)((peakFrequencyHz > endFrequencyHz)
  1484. ? (peakFrequencyHz - endFrequencyHz)
  1485. : (endFrequencyHz - peakFrequencyHz)) * exitTime;
  1486. if (durationWeight == 0UL)
  1487. {
  1488. return 0U;
  1489. }
  1490. singleFrequencyHz =
  1491. ((uint64_t)PlsrActiveConfig.defaultSpeedHz * 1000UL
  1492. + durationWeight / 2UL) / durationWeight;
  1493. if (singleFrequencyHz == 0UL)
  1494. {
  1495. singleFrequencyHz = 1UL;
  1496. }
  1497. if (singleFrequencyHz > PLSR_FREQUENCY_MAX_HZ)
  1498. {
  1499. singleFrequencyHz = PLSR_FREQUENCY_MAX_HZ;
  1500. }
  1501. profile->peakHz = (uint32_t)singleFrequencyHz;
  1502. profile->steadyPulses = 1U;
  1503. profile->active = 1U;
  1504. return 1U;
  1505. }
  1506. if ((exitRequired == 0UL) && (peakFrequencyHz != endFrequencyHz))
  1507. {
  1508. exitRequired = 1UL;
  1509. exitWeight = (uint64_t)2U
  1510. * PlsrActiveConfig.defaultSpeedHz * 1000UL;
  1511. }
  1512. if ((entryRequired + exitRequired) <= totalPulses)
  1513. {
  1514. profile->entryPulses = (uint16_t)entryRequired;
  1515. profile->exitPulses = (uint16_t)exitRequired;
  1516. profile->steadyPulses =
  1517. (uint16_t)(totalPulses - profile->entryPulses
  1518. - profile->exitPulses);
  1519. }
  1520. else if (entryRequired == 0UL)
  1521. {
  1522. profile->exitPulses = totalPulses;
  1523. }
  1524. else if (exitRequired == 0UL)
  1525. {
  1526. profile->entryPulses = totalPulses;
  1527. }
  1528. else
  1529. {
  1530. totalWeight = entryWeight + exitWeight;
  1531. /* Peak planning bounds both weights by this move's pulse budget. */
  1532. scaledEntry = ((uint64_t)totalPulses * entryWeight
  1533. + totalWeight / 2UL) / totalWeight;
  1534. if (scaledEntry == 0UL)
  1535. {
  1536. scaledEntry = 1UL;
  1537. }
  1538. if (scaledEntry >= totalPulses)
  1539. {
  1540. scaledEntry = totalPulses - 1U;
  1541. }
  1542. profile->entryPulses = (uint16_t)scaledEntry;
  1543. profile->exitPulses =
  1544. (uint16_t)(totalPulses - profile->entryPulses);
  1545. }
  1546. profile->active = 1U;
  1547. PlsrPrepareShortProfileBoundaries(profile);
  1548. return 1U;
  1549. }
  1550. static uint32_t PlsrShortProfileTakeFrequency(PLSR_SHORT_PROFILE *profile)
  1551. {
  1552. uint16_t period = profile->nextPeriod;
  1553. uint16_t relativePeriod;
  1554. uint16_t rampPulseCount;
  1555. uint32_t fromHz;
  1556. uint32_t toHz;
  1557. uint64_t firstBoundaryQ32;
  1558. uint64_t secondBoundaryQ32;
  1559. uint64_t previousTargetAreaQ32;
  1560. uint64_t areaIncrementQ32;
  1561. uint64_t firstCachedBoundaryQ32;
  1562. uint64_t secondCachedBoundaryQ32;
  1563. uint32_t frequencyHz;
  1564. if ((profile->active == 0U) || (period >= profile->pulseCount))
  1565. {
  1566. return (profile->endHz == 0UL) ? 1UL : profile->endHz;
  1567. }
  1568. profile->nextPeriod = (uint16_t)(period + 1U);
  1569. if (period < profile->entryPulses)
  1570. {
  1571. relativePeriod = period;
  1572. rampPulseCount = profile->entryPulses;
  1573. fromHz = profile->startHz;
  1574. toHz = profile->peakHz;
  1575. firstCachedBoundaryQ32 = profile->entryFirstBoundaryQ32;
  1576. secondCachedBoundaryQ32 = profile->entrySecondBoundaryQ32;
  1577. firstBoundaryQ32 = (relativePeriod == 0U)
  1578. ? 0ULL : profile->rampBoundaryQ32;
  1579. }
  1580. else if (period < (uint16_t)(profile->entryPulses
  1581. + profile->steadyPulses))
  1582. {
  1583. profile->lastRampFrequencyHz = 0UL;
  1584. return (profile->peakHz == 0UL) ? 1UL : profile->peakHz;
  1585. }
  1586. else
  1587. {
  1588. relativePeriod =
  1589. (uint16_t)(period - profile->entryPulses
  1590. - profile->steadyPulses);
  1591. rampPulseCount = profile->exitPulses;
  1592. fromHz = profile->peakHz;
  1593. toHz = profile->endHz;
  1594. firstCachedBoundaryQ32 = profile->exitFirstBoundaryQ32;
  1595. secondCachedBoundaryQ32 = profile->exitSecondBoundaryQ32;
  1596. firstBoundaryQ32 = (relativePeriod == 0U)
  1597. ? 0ULL : profile->rampBoundaryQ32;
  1598. }
  1599. if (relativePeriod == 0U)
  1600. {
  1601. profile->rampTotalAreaQ32 =
  1602. PlsrRampAreaQ32(fromHz, toHz, PLSR_Q32_ONE);
  1603. profile->rampAreaStepQ32 =
  1604. PlsrDivideU64ByU32(profile->rampTotalAreaQ32,
  1605. rampPulseCount,
  1606. &profile->rampAreaRemainder);
  1607. profile->rampRemainderAccumulator = 0UL;
  1608. profile->rampTargetAreaQ32 = 0ULL;
  1609. profile->rampBoundaryQ32 = 0ULL;
  1610. profile->lastRampPhaseStepQ32 = 0ULL;
  1611. profile->lastRampFrequencyHz = 0UL;
  1612. }
  1613. previousTargetAreaQ32 = profile->rampTargetAreaQ32;
  1614. profile->rampTargetAreaQ32 += profile->rampAreaStepQ32;
  1615. profile->rampRemainderAccumulator += profile->rampAreaRemainder;
  1616. if (profile->rampRemainderAccumulator >= rampPulseCount)
  1617. {
  1618. profile->rampTargetAreaQ32++;
  1619. profile->rampRemainderAccumulator -= rampPulseCount;
  1620. }
  1621. if ((uint16_t)(relativePeriod + 1U) >= rampPulseCount)
  1622. {
  1623. profile->rampTargetAreaQ32 = profile->rampTotalAreaQ32;
  1624. secondBoundaryQ32 = PLSR_Q32_ONE;
  1625. }
  1626. else if (relativePeriod == 0U)
  1627. {
  1628. secondBoundaryQ32 = firstCachedBoundaryQ32;
  1629. }
  1630. else if (relativePeriod == 1U)
  1631. {
  1632. secondBoundaryQ32 = secondCachedBoundaryQ32;
  1633. }
  1634. else
  1635. {
  1636. secondBoundaryQ32 = PlsrRampBoundaryQ32(
  1637. fromHz, toHz, firstBoundaryQ32,
  1638. profile->rampTargetAreaQ32,
  1639. (relativePeriod < 2U) ? 0ULL
  1640. : profile->lastRampPhaseStepQ32);
  1641. }
  1642. areaIncrementQ32 =
  1643. profile->rampTargetAreaQ32 - previousTargetAreaQ32;
  1644. profile->rampBoundaryQ32 = secondBoundaryQ32;
  1645. profile->lastRampPhaseStepQ32 =
  1646. secondBoundaryQ32 - firstBoundaryQ32;
  1647. frequencyHz = PlsrRampAverageFrequency(areaIncrementQ32, firstBoundaryQ32,
  1648. secondBoundaryQ32);
  1649. if ((profile->lastRampFrequencyHz != 0UL)
  1650. && (((toHz > fromHz)
  1651. && (frequencyHz < profile->lastRampFrequencyHz))
  1652. || ((toHz < fromHz)
  1653. && (frequencyHz > profile->lastRampFrequencyHz))))
  1654. {
  1655. frequencyHz = profile->lastRampFrequencyHz;
  1656. }
  1657. profile->lastRampFrequencyHz = frequencyHz;
  1658. return frequencyHz;
  1659. }
  1660. static void PlsrCopyShortProfile(PLSR_SHORT_PROFILE *destination,
  1661. const PLSR_SHORT_PROFILE *source)
  1662. {
  1663. destination->active = 0U;
  1664. destination->startHz = source->startHz;
  1665. destination->peakHz = source->peakHz;
  1666. destination->endHz = source->endHz;
  1667. destination->pulseCount = source->pulseCount;
  1668. destination->entryPulses = source->entryPulses;
  1669. destination->steadyPulses = source->steadyPulses;
  1670. destination->exitPulses = source->exitPulses;
  1671. destination->nextPeriod = source->nextPeriod;
  1672. destination->rampBoundaryQ32 = source->rampBoundaryQ32;
  1673. destination->rampTotalAreaQ32 = source->rampTotalAreaQ32;
  1674. destination->rampTargetAreaQ32 = source->rampTargetAreaQ32;
  1675. destination->rampAreaStepQ32 = source->rampAreaStepQ32;
  1676. destination->rampAreaRemainder = source->rampAreaRemainder;
  1677. destination->rampRemainderAccumulator =
  1678. source->rampRemainderAccumulator;
  1679. destination->lastRampPhaseStepQ32 = source->lastRampPhaseStepQ32;
  1680. destination->entryFirstBoundaryQ32 = source->entryFirstBoundaryQ32;
  1681. destination->entrySecondBoundaryQ32 = source->entrySecondBoundaryQ32;
  1682. destination->exitFirstBoundaryQ32 = source->exitFirstBoundaryQ32;
  1683. destination->exitSecondBoundaryQ32 = source->exitSecondBoundaryQ32;
  1684. destination->lastRampFrequencyHz = source->lastRampFrequencyHz;
  1685. destination->active = source->active;
  1686. }
  1687. static void PlsrInvalidateHandoffPlans(void)
  1688. {
  1689. uint8_t bank;
  1690. uint8_t index;
  1691. uint32_t criticalState = PlsrPlatformEnterCritical();
  1692. PlsrHandoffPlan.valid = 0U;
  1693. for (bank = 0U; bank < 2U; bank++)
  1694. {
  1695. for (index = 0U; index < PLSR_SEGMENT_COUNT_MAX; index++)
  1696. {
  1697. PlsrPreparedHandoffPlans[bank][index].valid = 0U;
  1698. }
  1699. }
  1700. PlsrPlatformExitCritical(criticalState);
  1701. }
  1702. static uint8_t PlsrAdvanceShortProfile(uint8_t pulseOutput)
  1703. {
  1704. uint32_t requestedFrequencyHz;
  1705. uint32_t actualFrequencyHz;
  1706. if ((PlsrShortProfile.active == 0U)
  1707. || (PlsrShortProfile.nextPeriod >= PlsrShortProfile.pulseCount))
  1708. {
  1709. return 1U;
  1710. }
  1711. requestedFrequencyHz =
  1712. PlsrShortProfileTakeFrequency(&PlsrShortProfile);
  1713. PlsrDeferredFrequencyPending = 0U;
  1714. if (PlsrPlatformQueueFrequency(pulseOutput,
  1715. requestedFrequencyHz,
  1716. &actualFrequencyHz) == 0U)
  1717. {
  1718. return 0U;
  1719. }
  1720. PlsrQueuedFrequencyHz = actualFrequencyHz;
  1721. if (actualFrequencyHz > PlsrCurrentFrequencyHz)
  1722. {
  1723. PlsrRunStatus = PLSR_STATUS_ACCELERATING;
  1724. }
  1725. else if (actualFrequencyHz < PlsrCurrentFrequencyHz)
  1726. {
  1727. PlsrRunStatus = PLSR_STATUS_DECELERATING;
  1728. }
  1729. else
  1730. {
  1731. PlsrRunStatus = PLSR_STATUS_RUNNING;
  1732. }
  1733. return 1U;
  1734. }
  1735. static void PlsrMaybePlanBoundaryRamp(uint32_t expectedEpoch)
  1736. {
  1737. const PLSR_SEGMENT_CONFIG *segment;
  1738. uint8_t nextSegment;
  1739. uint8_t nextPositive;
  1740. uint8_t hasNext;
  1741. uint32_t targetHz;
  1742. uint32_t criticalState;
  1743. uint64_t estimate;
  1744. uint64_t remaining;
  1745. if ((PlsrPulseActive == 0U) || (PlsrBoundaryRampStarted != 0U)
  1746. || (PlsrShortProfile.active != 0U)
  1747. || (PlsrHandoffPlan.valid != 0U)
  1748. || (PlsrStopRequested != 0U) || (PlsrCurrentSegment == 0U))
  1749. {
  1750. return;
  1751. }
  1752. segment = &PlsrActiveConfig.segments[PlsrCurrentSegment - 1U];
  1753. hasNext = PlsrGetNextSegment(&nextSegment);
  1754. targetHz = PlsrActiveConfig.stopSpeedHz;
  1755. if ((PlsrActiveConfig.sendMode == PLSR_SEND_SUBSEQUENT)
  1756. && (hasNext != 0U)
  1757. && (segment->waitType == PLSR_EXT_OR_COMPLETE))
  1758. {
  1759. if ((PlsrPredictNextDirection(nextSegment, &nextPositive) != 0U)
  1760. && (nextPositive == PlsrCountPositive))
  1761. {
  1762. targetHz = PlsrActiveConfig.segments[nextSegment - 1U].frequencyHz;
  1763. }
  1764. }
  1765. estimate = PlsrRampPulseEstimate(PlsrCurrentFrequencyHz, targetHz);
  1766. criticalState = PlsrPlatformEnterCritical();
  1767. remaining = PlsrRemainingPulses;
  1768. if ((PlsrSegmentEpoch != expectedEpoch)
  1769. || (PlsrBoundaryPending != 0U)
  1770. || (PlsrPulseActive == 0U)
  1771. || (PlsrBoundaryRampStarted != 0U)
  1772. || (PlsrShortProfile.active != 0U)
  1773. || (PlsrHandoffPlan.valid != 0U)
  1774. || (PlsrStopRequested != 0U))
  1775. {
  1776. PlsrPlatformExitCritical(criticalState);
  1777. return;
  1778. }
  1779. if (remaining > estimate)
  1780. {
  1781. PlsrPlatformExitCritical(criticalState);
  1782. return;
  1783. }
  1784. PlsrBoundaryRampStarted = 1U;
  1785. PlsrRampStart(PlsrCurrentFrequencyHz, targetHz);
  1786. PlsrPlatformExitCritical(criticalState);
  1787. if (PlsrRamp.active == 0U)
  1788. {
  1789. (void)PlsrApplyFrequency(targetHz, expectedEpoch);
  1790. }
  1791. }
  1792. static uint8_t PlsrBeginSegmentOutput(uint32_t startFrequencyHz)
  1793. {
  1794. uint32_t targetFrequencyHz =
  1795. PlsrActiveConfig.segments[PlsrCurrentSegment - 1U].frequencyHz;
  1796. uint32_t firstFrequencyHz;
  1797. uint32_t secondFrequencyHz;
  1798. PlsrSegmentClockStarted = 1U;
  1799. PlsrSegmentElapsedMs = 0UL;
  1800. if (PlsrPrepareShortProfile(&PlsrShortProfile,
  1801. PlsrCurrentSegment, startFrequencyHz,
  1802. targetFrequencyHz,
  1803. PlsrRemainingSnapshot()) != 0U)
  1804. {
  1805. PlsrRamp.active = 0U;
  1806. firstFrequencyHz =
  1807. PlsrShortProfileTakeFrequency(&PlsrShortProfile);
  1808. secondFrequencyHz =
  1809. (PlsrShortProfile.nextPeriod < PlsrShortProfile.pulseCount)
  1810. ? PlsrShortProfileTakeFrequency(&PlsrShortProfile)
  1811. : firstFrequencyHz;
  1812. if (secondFrequencyHz > firstFrequencyHz)
  1813. {
  1814. PlsrRunStatus = PLSR_STATUS_ACCELERATING;
  1815. }
  1816. else if (secondFrequencyHz < firstFrequencyHz)
  1817. {
  1818. PlsrRunStatus = PLSR_STATUS_DECELERATING;
  1819. }
  1820. else
  1821. {
  1822. PlsrRunStatus = PLSR_STATUS_RUNNING;
  1823. }
  1824. if (PlsrApplyFrequencyPair(firstFrequencyHz,
  1825. secondFrequencyHz,
  1826. PlsrSegmentEpoch) == 0U)
  1827. {
  1828. PlsrShortProfile.active = 0U;
  1829. return 0U;
  1830. }
  1831. return 1U;
  1832. }
  1833. PlsrRampStart(startFrequencyHz, targetFrequencyHz);
  1834. if (PlsrRamp.active == 0U)
  1835. {
  1836. if (PlsrApplyFrequency(targetFrequencyHz, PlsrSegmentEpoch) == 0U)
  1837. {
  1838. return 0U;
  1839. }
  1840. PlsrRunStatus = PLSR_STATUS_RUNNING;
  1841. }
  1842. else if ((startFrequencyHz != 0UL)
  1843. && (PlsrApplyFrequency(startFrequencyHz,
  1844. PlsrSegmentEpoch) == 0U))
  1845. {
  1846. return 0U;
  1847. }
  1848. return 1U;
  1849. }
  1850. static uint8_t PlsrStartSegment(uint8_t segmentNumber,
  1851. uint8_t allowCarry,
  1852. uint32_t carryFrequencyHz)
  1853. {
  1854. uint32_t criticalState;
  1855. int32_t position;
  1856. int64_t displacement;
  1857. uint64_t magnitude;
  1858. uint8_t positive;
  1859. uint8_t directionLevel;
  1860. uint8_t directionChanged;
  1861. uint32_t startFrequencyHz;
  1862. if ((segmentNumber == 0U)
  1863. || (segmentNumber > PlsrActiveConfig.segmentCount))
  1864. {
  1865. return 0U;
  1866. }
  1867. criticalState = PlsrPlatformEnterCritical();
  1868. position = PlsrPosition;
  1869. PlsrPlatformExitCritical(criticalState);
  1870. displacement = PlsrSegmentDisplacement(segmentNumber, position);
  1871. positive = (displacement >= 0) ? 1U : 0U;
  1872. magnitude = (displacement < 0) ? (uint64_t)(-displacement)
  1873. : (uint64_t)displacement;
  1874. PlsrSegmentEpoch++;
  1875. PlsrCurrentSegment = segmentNumber;
  1876. PlsrSegmentClockStarted = 0U;
  1877. PlsrSegmentElapsedMs = 0UL;
  1878. PlsrWaitElapsedMs = 0UL;
  1879. PlsrBoundaryRampStarted = 0U;
  1880. PlsrBoundaryPending = 0U;
  1881. PlsrBoundaryWasCut = 0U;
  1882. PlsrCutRequested = 0U;
  1883. PlsrStopPulsesRemaining = 0U;
  1884. PlsrFrequencyUpdatePending = 0U;
  1885. PlsrDeferredFrequencyPending = 0U;
  1886. PlsrCurrentFrequencyHz = 0UL;
  1887. PlsrQueuedFrequencyHz = 0UL;
  1888. PlsrHandoffPlan.valid = 0U;
  1889. PlsrShortProfile.active = 0U;
  1890. PlsrShortProfile.nextPeriod = 0U;
  1891. PlsrDirectionDelayActive = 0U;
  1892. PlsrDirectionDelayRemainingMs = 0U;
  1893. PlsrExtEdgePending = 0U;
  1894. PlsrExtPreviousLevel =
  1895. PlsrPlatformReadInput((uint8_t)PlsrActiveConfig.extInput);
  1896. criticalState = PlsrPlatformEnterCritical();
  1897. PlsrRemainingPulses = magnitude;
  1898. PlsrCountPositive = positive;
  1899. PlsrPlatformExitCritical(criticalState);
  1900. if ((PlsrActiveConfig.segments[segmentNumber - 1U].waitType
  1901. == PLSR_ACT_TIME)
  1902. && (PlsrActiveConfig.segments[segmentNumber - 1U].actTimeMs == 0U))
  1903. {
  1904. PlsrSegmentClockStarted = 1U;
  1905. PlsrRunStatus = PLSR_STATUS_RUNNING;
  1906. PlsrBoundaryFrequencyHz = (allowCarry != 0U) ? carryFrequencyHz : 0UL;
  1907. PlsrBoundaryWasCut = 1U;
  1908. PlsrBoundaryPending = 1U;
  1909. return 1U;
  1910. }
  1911. if (magnitude == 0UL)
  1912. {
  1913. PlsrSegmentClockStarted = 1U;
  1914. PlsrRunStatus = PLSR_STATUS_RUNNING;
  1915. PlsrBoundaryFrequencyHz = 0UL;
  1916. PlsrBoundaryPending = 1U;
  1917. return 1U;
  1918. }
  1919. directionLevel = positive;
  1920. if (PlsrActiveConfig.directionNegativeLogic != 0U)
  1921. {
  1922. directionLevel ^= 1U;
  1923. }
  1924. directionChanged = ((PlsrLastDirectionValid == 0U)
  1925. || (PlsrLastDirectionOutput
  1926. != (uint8_t)PlsrActiveConfig.directionOutput)
  1927. || (PlsrLastDirectionLevel != directionLevel)) ? 1U : 0U;
  1928. if (PlsrPlatformPrepare((uint8_t)PlsrActiveConfig.pulseOutput,
  1929. (uint8_t)PlsrActiveConfig.directionOutput,
  1930. directionLevel) == 0U)
  1931. {
  1932. return 0U;
  1933. }
  1934. PlsrLastDirectionValid = 1U;
  1935. PlsrLastDirectionOutput = (uint8_t)PlsrActiveConfig.directionOutput;
  1936. PlsrLastDirectionLevel = directionLevel;
  1937. if ((allowCarry != 0U) && (directionChanged == 0U)
  1938. && (carryFrequencyHz != 0UL))
  1939. {
  1940. startFrequencyHz = carryFrequencyHz;
  1941. }
  1942. else
  1943. {
  1944. startFrequencyHz = PlsrActiveConfig.startSpeedHz;
  1945. }
  1946. if ((directionChanged != 0U)
  1947. && (PlsrActiveConfig.directionDelayMs != 0U))
  1948. {
  1949. PlsrDirectionDelayActive = 1U;
  1950. PlsrDirectionDelayRemainingMs = PlsrActiveConfig.directionDelayMs;
  1951. PlsrRunStatus = PLSR_STATUS_ACCELERATING;
  1952. return 1U;
  1953. }
  1954. PlsrDirectionDelayActive = 0U;
  1955. return PlsrBeginSegmentOutput(startFrequencyHz);
  1956. }
  1957. static void PlsrMarkPersistenceDirty(uint16_t delayMs)
  1958. {
  1959. PlsrPersistenceDirty = 1U;
  1960. PlsrPersistenceDelayMs = delayMs;
  1961. }
  1962. static void PlsrCheckpointPosition(uint8_t wasBusy)
  1963. {
  1964. uint32_t criticalState;
  1965. int32_t position;
  1966. uint8_t positionValid;
  1967. criticalState = PlsrPlatformEnterCritical();
  1968. position = PlsrPosition;
  1969. positionValid = PlsrPositionValid;
  1970. PlsrPositionCheckpointDirty = 0U;
  1971. PlsrPlatformExitCritical(criticalState);
  1972. PlsrPlatformCheckpointPosition(position, positionValid, wasBusy);
  1973. PlsrPositionCheckpointElapsedMs = 0U;
  1974. }
  1975. static void PlsrPollPositionCheckpoint(void)
  1976. {
  1977. if (PlsrPositionCheckpointDirty == 0U)
  1978. {
  1979. PlsrPositionCheckpointElapsedMs = 0U;
  1980. return;
  1981. }
  1982. if (PlsrPositionCheckpointElapsedMs < PLSR_POSITION_CHECKPOINT_MS)
  1983. {
  1984. PlsrPositionCheckpointElapsedMs++;
  1985. }
  1986. if (PlsrPositionCheckpointElapsedMs >= PLSR_POSITION_CHECKPOINT_MS)
  1987. {
  1988. PlsrCheckpointPosition(1U);
  1989. }
  1990. }
  1991. static void PlsrFinishCompleted(void)
  1992. {
  1993. PlsrPlatformStopPulse((uint8_t)PlsrActiveConfig.pulseOutput);
  1994. PlsrRemainingPulses = 0UL;
  1995. PlsrPulseActive = 0U;
  1996. PlsrCutRequested = 0U;
  1997. PlsrBoundaryPending = 0U;
  1998. PlsrBoundaryWasCut = 0U;
  1999. PlsrCurrentFrequencyHz = 0UL;
  2000. PlsrQueuedFrequencyHz = 0UL;
  2001. PlsrCurrentSegment = 0U;
  2002. PlsrSegmentClockStarted = 0U;
  2003. PlsrDirectionDelayActive = 0U;
  2004. PlsrDirectionDelayRemainingMs = 0U;
  2005. PlsrExtEdgePending = 0U;
  2006. PlsrStopRequested = 0U;
  2007. PlsrStopPulsesRemaining = 0U;
  2008. PlsrSeamlessHandoffPending = 0U;
  2009. PlsrDeferredFrequencyPending = 0U;
  2010. PlsrShortProfile.active = 0U;
  2011. PlsrHandoffPlan.valid = 0U;
  2012. PlsrTimerErrorPending = 0U;
  2013. PlsrRamp.active = 0U;
  2014. PlsrInvalidateHandoffPlans();
  2015. PlsrRunStatus = PLSR_STATUS_COMPLETED;
  2016. PlsrError = PLSR_ERROR_NONE;
  2017. PlsrCheckpointPosition(0U);
  2018. PlsrMarkPersistenceDirty(PLSR_CONFIG_SAVE_DELAY_MS);
  2019. }
  2020. static void PlsrFinishStopped(void)
  2021. {
  2022. PlsrPlatformStopPulse((uint8_t)PlsrActiveConfig.pulseOutput);
  2023. PlsrRemainingPulses = 0UL;
  2024. PlsrPulseActive = 0U;
  2025. PlsrCutRequested = 0U;
  2026. PlsrBoundaryPending = 0U;
  2027. PlsrBoundaryWasCut = 0U;
  2028. PlsrCurrentFrequencyHz = 0UL;
  2029. PlsrQueuedFrequencyHz = 0UL;
  2030. PlsrCurrentSegment = 0U;
  2031. PlsrSegmentClockStarted = 0U;
  2032. PlsrDirectionDelayActive = 0U;
  2033. PlsrDirectionDelayRemainingMs = 0U;
  2034. PlsrExtEdgePending = 0U;
  2035. PlsrStopRequested = 0U;
  2036. PlsrStopPulsesRemaining = 0U;
  2037. PlsrSeamlessHandoffPending = 0U;
  2038. PlsrDeferredFrequencyPending = 0U;
  2039. PlsrShortProfile.active = 0U;
  2040. PlsrHandoffPlan.valid = 0U;
  2041. PlsrTimerErrorPending = 0U;
  2042. PlsrRamp.active = 0U;
  2043. PlsrInvalidateHandoffPlans();
  2044. PlsrRunStatus = PLSR_STATUS_STOPPED;
  2045. PlsrError = PLSR_ERROR_NONE;
  2046. PlsrCheckpointPosition(0U);
  2047. PlsrMarkPersistenceDirty(PLSR_CONFIG_SAVE_DELAY_MS);
  2048. }
  2049. static void PlsrEnterError(PLSR_ERROR error)
  2050. {
  2051. PlsrPlatformStopPulse((uint8_t)PlsrActiveConfig.pulseOutput);
  2052. PlsrRemainingPulses = 0UL;
  2053. PlsrPulseActive = 0U;
  2054. PlsrCutRequested = 0U;
  2055. PlsrBoundaryPending = 0U;
  2056. PlsrBoundaryWasCut = 0U;
  2057. PlsrCurrentFrequencyHz = 0UL;
  2058. PlsrQueuedFrequencyHz = 0UL;
  2059. PlsrCurrentSegment = 0U;
  2060. PlsrSegmentClockStarted = 0U;
  2061. PlsrDirectionDelayActive = 0U;
  2062. PlsrDirectionDelayRemainingMs = 0U;
  2063. PlsrExtEdgePending = 0U;
  2064. PlsrStopRequested = 0U;
  2065. PlsrStopPulsesRemaining = 0U;
  2066. PlsrSeamlessHandoffPending = 0U;
  2067. PlsrDeferredFrequencyPending = 0U;
  2068. PlsrShortProfile.active = 0U;
  2069. PlsrHandoffPlan.valid = 0U;
  2070. PlsrTimerErrorPending = 0U;
  2071. PlsrRamp.active = 0U;
  2072. PlsrInvalidateHandoffPlans();
  2073. PlsrRunStatus = PLSR_STATUS_ERROR;
  2074. PlsrError = error;
  2075. PlsrCheckpointPosition(0U);
  2076. PlsrMarkPersistenceDirty(PLSR_CONFIG_SAVE_DELAY_MS);
  2077. }
  2078. static void PlsrTransitionToNext(uint8_t allowCarry)
  2079. {
  2080. uint8_t nextSegment;
  2081. uint32_t carryFrequencyHz = PlsrBoundaryFrequencyHz;
  2082. if (PlsrGetNextSegment(&nextSegment) == 0U)
  2083. {
  2084. PlsrFinishCompleted();
  2085. return;
  2086. }
  2087. if (PlsrStartSegment(nextSegment, allowCarry, carryFrequencyHz) == 0U)
  2088. {
  2089. PlsrEnterError(PLSR_ERROR_INVALID_RESOURCE);
  2090. }
  2091. }
  2092. static uint8_t PlsrBuildHandoffPlan(uint8_t sourceSegment,
  2093. const PLSR_CONFIG *frequencyConfig,
  2094. PLSR_HANDOFF_PLAN *plan)
  2095. {
  2096. const PLSR_SEGMENT_CONFIG *segment;
  2097. uint8_t nextSegment;
  2098. int64_t displacement;
  2099. uint8_t positive;
  2100. plan->valid = 0U;
  2101. if ((PlsrActiveConfig.sendMode != PLSR_SEND_SUBSEQUENT)
  2102. || (sourceSegment == 0U)
  2103. || (sourceSegment > PlsrActiveConfig.segmentCount))
  2104. {
  2105. return 0U;
  2106. }
  2107. segment = &PlsrActiveConfig.segments[sourceSegment - 1U];
  2108. if (segment->waitType != PLSR_EXT_OR_COMPLETE)
  2109. {
  2110. return 0U;
  2111. }
  2112. if (segment->jumpSegment != 0U)
  2113. {
  2114. nextSegment = (uint8_t)segment->jumpSegment;
  2115. }
  2116. else if (sourceSegment < PlsrActiveConfig.segmentCount)
  2117. {
  2118. nextSegment = (uint8_t)(sourceSegment + 1U);
  2119. }
  2120. else
  2121. {
  2122. return 0U;
  2123. }
  2124. if (PlsrActiveConfig.positionMode == PLSR_POSITION_ABSOLUTE)
  2125. {
  2126. displacement = (int64_t)PlsrActiveConfig.segments[nextSegment - 1U].pulses
  2127. - (int64_t)segment->pulses;
  2128. }
  2129. else
  2130. {
  2131. displacement = PlsrActiveConfig.segments[nextSegment - 1U].pulses;
  2132. }
  2133. if (displacement == 0)
  2134. {
  2135. return 0U;
  2136. }
  2137. positive = (displacement > 0) ? 1U : 0U;
  2138. plan->magnitude = (displacement < 0) ? (uint64_t)(-displacement)
  2139. : (uint64_t)displacement;
  2140. plan->firstFrequencyHz =
  2141. frequencyConfig->segments[nextSegment - 1U].frequencyHz;
  2142. if (PlsrPrepareShortProfile(&plan->profile, nextSegment,
  2143. plan->firstFrequencyHz,
  2144. plan->firstFrequencyHz,
  2145. plan->magnitude) != 0U)
  2146. {
  2147. plan->firstFrequencyHz =
  2148. PlsrShortProfileTakeFrequency(&plan->profile);
  2149. }
  2150. plan->nextSegment = nextSegment;
  2151. plan->positive = positive;
  2152. plan->valid = 1U;
  2153. return 1U;
  2154. }
  2155. static uint8_t PlsrBuildHandoffPlanBank(
  2156. const PLSR_CONFIG *frequencyConfig)
  2157. {
  2158. uint8_t buildBank = (uint8_t)(PlsrPreparedHandoffBank ^ 1U);
  2159. uint8_t sourceSegment;
  2160. PLSR_HANDOFF_PLAN *destination;
  2161. for (sourceSegment = 0U;
  2162. sourceSegment < PLSR_SEGMENT_COUNT_MAX;
  2163. sourceSegment++)
  2164. {
  2165. PlsrPreparedHandoffPlans[buildBank][sourceSegment].valid = 0U;
  2166. }
  2167. for (sourceSegment = 1U;
  2168. sourceSegment <= PlsrActiveConfig.segmentCount;
  2169. sourceSegment++)
  2170. {
  2171. destination =
  2172. &PlsrPreparedHandoffPlans[buildBank][sourceSegment - 1U];
  2173. (void)PlsrBuildHandoffPlan(sourceSegment, frequencyConfig,
  2174. destination);
  2175. }
  2176. return buildBank;
  2177. }
  2178. static uint8_t PlsrSelectPreparedHandoffPlan(PLSR_HANDOFF_PLAN *plan)
  2179. {
  2180. const PLSR_HANDOFF_PLAN *prepared;
  2181. uint8_t preparedBank;
  2182. uint8_t currentSegment;
  2183. plan->valid = 0U;
  2184. currentSegment = PlsrCurrentSegment;
  2185. if ((PlsrRemainingPulses != 1UL)
  2186. || (PlsrActiveConfig.sendMode != PLSR_SEND_SUBSEQUENT)
  2187. || (PlsrStopRequested != 0U)
  2188. || (PlsrCountOverflowPending != 0U)
  2189. || (PlsrCutRequested != 0U)
  2190. || (currentSegment == 0U)
  2191. || (currentSegment > PlsrActiveConfig.segmentCount))
  2192. {
  2193. return 0U;
  2194. }
  2195. preparedBank = PlsrPreparedHandoffBank;
  2196. prepared = &PlsrPreparedHandoffPlans[preparedBank][currentSegment - 1U];
  2197. if ((prepared->valid == 0U)
  2198. || (prepared->positive != PlsrCountPositive))
  2199. {
  2200. return 0U;
  2201. }
  2202. plan->magnitude = prepared->magnitude;
  2203. plan->firstFrequencyHz = prepared->firstFrequencyHz;
  2204. PlsrCopyShortProfile(&plan->profile, &prepared->profile);
  2205. plan->nextSegment = prepared->nextSegment;
  2206. plan->positive = prepared->positive;
  2207. plan->valid = 1U;
  2208. return 1U;
  2209. }
  2210. static uint8_t PlsrPrimeHandoff(void)
  2211. {
  2212. PLSR_HANDOFF_PLAN candidatePlan;
  2213. uint32_t actualFrequencyHz;
  2214. PlsrHandoffPlan.valid = 0U;
  2215. if (PlsrSelectPreparedHandoffPlan(&candidatePlan) == 0U)
  2216. {
  2217. return 0U;
  2218. }
  2219. PlsrDeferredFrequencyPending = 0U;
  2220. if (PlsrPlatformQueueFrequency(
  2221. (uint8_t)PlsrActiveConfig.pulseOutput,
  2222. candidatePlan.firstFrequencyHz, &actualFrequencyHz) == 0U)
  2223. {
  2224. PlsrTimerErrorPending = 1U;
  2225. return 0U;
  2226. }
  2227. PlsrQueuedFrequencyHz = actualFrequencyHz;
  2228. PlsrHandoffPlan.magnitude = candidatePlan.magnitude;
  2229. PlsrHandoffPlan.firstFrequencyHz = actualFrequencyHz;
  2230. PlsrCopyShortProfile(&PlsrHandoffPlan.profile,
  2231. &candidatePlan.profile);
  2232. PlsrHandoffPlan.nextSegment = candidatePlan.nextSegment;
  2233. PlsrHandoffPlan.positive = candidatePlan.positive;
  2234. PlsrHandoffPlan.valid = 1U;
  2235. return 1U;
  2236. }
  2237. static uint8_t PlsrTrySubsequentHandoff(void)
  2238. {
  2239. uint32_t requestedQueuedFrequencyHz;
  2240. uint32_t actualQueuedFrequencyHz;
  2241. uint32_t currentFrequencyHz;
  2242. uint32_t queuedFrequencyHz;
  2243. uint8_t nextSegment = PlsrHandoffPlan.nextSegment;
  2244. uint64_t magnitude = PlsrHandoffPlan.magnitude;
  2245. uint8_t positive = PlsrHandoffPlan.positive;
  2246. if ((PlsrHandoffPlan.valid == 0U)
  2247. || (PlsrActiveConfig.sendMode != PLSR_SEND_SUBSEQUENT)
  2248. || (PlsrStopRequested != 0U)
  2249. || (PlsrCountOverflowPending != 0U)
  2250. || (PlsrCutRequested != 0U)
  2251. || (PlsrCurrentFrequencyHz != PlsrHandoffPlan.firstFrequencyHz)
  2252. || (nextSegment == 0U)
  2253. || (nextSegment > PlsrActiveConfig.segmentCount))
  2254. {
  2255. return 0U;
  2256. }
  2257. PlsrCopyShortProfile(&PlsrShortProfile,
  2258. &PlsrHandoffPlan.profile);
  2259. requestedQueuedFrequencyHz = PlsrCurrentFrequencyHz;
  2260. if ((PlsrShortProfile.active != 0U)
  2261. && (PlsrShortProfile.nextPeriod < PlsrShortProfile.pulseCount))
  2262. {
  2263. requestedQueuedFrequencyHz =
  2264. PlsrShortProfileTakeFrequency(&PlsrShortProfile);
  2265. }
  2266. PlsrDeferredFrequencyPending = 0U;
  2267. if (PlsrPlatformQueueFrequency(
  2268. (uint8_t)PlsrActiveConfig.pulseOutput,
  2269. requestedQueuedFrequencyHz, &actualQueuedFrequencyHz) == 0U)
  2270. {
  2271. PlsrShortProfile.active = 0U;
  2272. PlsrHandoffPlan.valid = 0U;
  2273. PlsrTimerErrorPending = 1U;
  2274. return 0U;
  2275. }
  2276. PlsrQueuedFrequencyHz = actualQueuedFrequencyHz;
  2277. PlsrSegmentEpoch++;
  2278. PlsrCurrentSegment = nextSegment;
  2279. PlsrRemainingPulses = magnitude;
  2280. PlsrCountPositive = positive;
  2281. PlsrBoundaryFrequencyHz = PlsrCurrentFrequencyHz;
  2282. PlsrSegmentClockStarted = 1U;
  2283. PlsrSegmentElapsedMs = 0UL;
  2284. PlsrWaitElapsedMs = 0UL;
  2285. PlsrBoundaryRampStarted = 0U;
  2286. PlsrBoundaryPending = 0U;
  2287. PlsrBoundaryWasCut = 0U;
  2288. PlsrCutRequested = 0U;
  2289. PlsrFrequencyUpdatePending = 0U;
  2290. PlsrDeferredFrequencyPending = 0U;
  2291. PlsrExtEdgePending = 0U;
  2292. PlsrExtPreviousLevel =
  2293. PlsrPlatformReadInput((uint8_t)PlsrActiveConfig.extInput);
  2294. PlsrSeamlessHandoffPending = 1U;
  2295. PlsrHandoffPlan.valid = 0U;
  2296. if (PlsrRemainingPulses == 1UL)
  2297. {
  2298. (void)PlsrPrimeHandoff();
  2299. }
  2300. queuedFrequencyHz = PlsrQueuedFrequencyHz;
  2301. currentFrequencyHz = PlsrCurrentFrequencyHz;
  2302. if (PlsrShortProfile.active != 0U)
  2303. {
  2304. if (queuedFrequencyHz > currentFrequencyHz)
  2305. {
  2306. PlsrRunStatus = PLSR_STATUS_ACCELERATING;
  2307. }
  2308. else if (queuedFrequencyHz < currentFrequencyHz)
  2309. {
  2310. PlsrRunStatus = PLSR_STATUS_DECELERATING;
  2311. }
  2312. else
  2313. {
  2314. PlsrRunStatus = PLSR_STATUS_RUNNING;
  2315. }
  2316. }
  2317. else
  2318. {
  2319. PlsrRunStatus = PLSR_STATUS_RUNNING;
  2320. }
  2321. return 1U;
  2322. }
  2323. static void PlsrHandleBoundary(uint8_t extEdge)
  2324. {
  2325. const PLSR_SEGMENT_CONFIG *segment;
  2326. uint8_t wasCut = PlsrBoundaryWasCut;
  2327. PlsrBoundaryPending = 0U;
  2328. PlsrBoundaryWasCut = 0U;
  2329. PlsrPulseActive = 0U;
  2330. PlsrCurrentFrequencyHz = 0UL;
  2331. PlsrQueuedFrequencyHz = 0UL;
  2332. PlsrShortProfile.active = 0U;
  2333. PlsrHandoffPlan.valid = 0U;
  2334. PlsrDeferredFrequencyPending = 0U;
  2335. PlsrCheckpointPosition(1U);
  2336. if (PlsrTimerErrorPending != 0U)
  2337. {
  2338. PlsrTimerErrorPending = 0U;
  2339. PlsrEnterError(PLSR_ERROR_TIMER);
  2340. return;
  2341. }
  2342. if (PlsrCountOverflowPending != 0U)
  2343. {
  2344. PlsrCountOverflowPending = 0U;
  2345. PlsrEnterError(PLSR_ERROR_COUNT);
  2346. return;
  2347. }
  2348. if (PlsrStopRequested != 0U)
  2349. {
  2350. PlsrFinishStopped();
  2351. return;
  2352. }
  2353. if ((PlsrCurrentSegment == 0U)
  2354. || (PlsrCurrentSegment > PlsrActiveConfig.segmentCount))
  2355. {
  2356. PlsrEnterError(PLSR_ERROR_INTERNAL);
  2357. return;
  2358. }
  2359. segment = &PlsrActiveConfig.segments[PlsrCurrentSegment - 1U];
  2360. if (wasCut != 0U)
  2361. {
  2362. PlsrTransitionToNext(
  2363. (PlsrActiveConfig.sendMode == PLSR_SEND_SUBSEQUENT) ? 1U : 0U);
  2364. return;
  2365. }
  2366. switch (segment->waitType)
  2367. {
  2368. case PLSR_WAIT_TIME:
  2369. PlsrWaitElapsedMs = 0UL;
  2370. PlsrRunStatus = PLSR_STATUS_WAITING;
  2371. break;
  2372. case PLSR_WAIT_SIGNAL:
  2373. if (PlsrPlatformReadInput((uint8_t)PlsrActiveConfig.waitInput) != 0U)
  2374. {
  2375. PlsrTransitionToNext(0U);
  2376. }
  2377. else
  2378. {
  2379. PlsrRunStatus = PLSR_STATUS_WAITING;
  2380. }
  2381. break;
  2382. case PLSR_ACT_TIME:
  2383. if (PlsrSegmentElapsedMs >= segment->actTimeMs)
  2384. {
  2385. PlsrTransitionToNext(0U);
  2386. }
  2387. else
  2388. {
  2389. PlsrRunStatus = PLSR_STATUS_WAITING;
  2390. }
  2391. break;
  2392. case PLSR_EXT_SIGNAL:
  2393. if (extEdge != 0U)
  2394. {
  2395. PlsrTransitionToNext(0U);
  2396. }
  2397. else
  2398. {
  2399. PlsrRunStatus = PLSR_STATUS_WAITING;
  2400. }
  2401. break;
  2402. case PLSR_EXT_OR_COMPLETE:
  2403. PlsrTransitionToNext(
  2404. (PlsrActiveConfig.sendMode == PLSR_SEND_SUBSEQUENT) ? 1U : 0U);
  2405. break;
  2406. default:
  2407. PlsrEnterError(PLSR_ERROR_INTERNAL);
  2408. break;
  2409. }
  2410. }
  2411. static void PlsrRequestCut(uint32_t expectedEpoch)
  2412. {
  2413. uint32_t criticalState = PlsrPlatformEnterCritical();
  2414. if (PlsrSegmentEpoch != expectedEpoch)
  2415. {
  2416. PlsrPlatformExitCritical(criticalState);
  2417. return;
  2418. }
  2419. if (PlsrBoundaryPending != 0U)
  2420. {
  2421. PlsrBoundaryWasCut = 1U;
  2422. }
  2423. else if (PlsrPulseActive != 0U)
  2424. {
  2425. PlsrCutRequested = 1U;
  2426. }
  2427. else
  2428. {
  2429. PlsrBoundaryFrequencyHz = PlsrCurrentFrequencyHz;
  2430. PlsrBoundaryWasCut = 1U;
  2431. PlsrBoundaryPending = 1U;
  2432. }
  2433. PlsrPlatformExitCritical(criticalState);
  2434. }
  2435. static void PlsrPollWaiting(uint8_t extEdge)
  2436. {
  2437. const PLSR_SEGMENT_CONFIG *segment =
  2438. &PlsrActiveConfig.segments[PlsrCurrentSegment - 1U];
  2439. switch (segment->waitType)
  2440. {
  2441. case PLSR_WAIT_TIME:
  2442. PlsrWaitElapsedMs++;
  2443. if (PlsrWaitElapsedMs >= segment->waitTimeMs)
  2444. {
  2445. PlsrTransitionToNext(0U);
  2446. }
  2447. break;
  2448. case PLSR_WAIT_SIGNAL:
  2449. if (PlsrPlatformReadInput((uint8_t)PlsrActiveConfig.waitInput) != 0U)
  2450. {
  2451. PlsrTransitionToNext(0U);
  2452. }
  2453. break;
  2454. case PLSR_ACT_TIME:
  2455. if (PlsrSegmentElapsedMs >= segment->actTimeMs)
  2456. {
  2457. PlsrTransitionToNext(0U);
  2458. }
  2459. break;
  2460. case PLSR_EXT_SIGNAL:
  2461. if (extEdge != 0U)
  2462. {
  2463. PlsrTransitionToNext(0U);
  2464. }
  2465. break;
  2466. default:
  2467. PlsrEnterError(PLSR_ERROR_INTERNAL);
  2468. break;
  2469. }
  2470. }
  2471. static void PlsrPollPersistence(void)
  2472. {
  2473. PLSR_PERSIST_PAYLOAD payload;
  2474. uint32_t criticalState;
  2475. if ((PlsrPersistenceDirty == 0U) || (PlsrIsBusy() != 0U))
  2476. {
  2477. return;
  2478. }
  2479. if (PlsrPersistenceDelayMs != 0U)
  2480. {
  2481. PlsrPersistenceDelayMs--;
  2482. return;
  2483. }
  2484. payload.config = PlsrShadowConfig;
  2485. criticalState = PlsrPlatformEnterCritical();
  2486. payload.position = PlsrPosition;
  2487. payload.positionValid = PlsrPositionValid;
  2488. PlsrPlatformExitCritical(criticalState);
  2489. payload.wasBusy = 0U;
  2490. payload.reserved = 0U;
  2491. if (PlsrPlatformSave(&payload) != 0U)
  2492. {
  2493. PlsrPersistenceDirty = 0U;
  2494. }
  2495. else
  2496. {
  2497. PlsrRunStatus = PLSR_STATUS_ERROR;
  2498. PlsrError = PLSR_ERROR_INTERNAL;
  2499. }
  2500. }
  2501. uint8_t PlsrInit(void)
  2502. {
  2503. PLSR_PERSIST_PAYLOAD payload;
  2504. PlsrInitialized = 0U;
  2505. PlsrRunStatus = PLSR_STATUS_UNINITIALIZED;
  2506. if (PlsrPlatformInit() == 0U)
  2507. {
  2508. return 0U;
  2509. }
  2510. if ((PlsrPlatformLoad(&payload) == 0U)
  2511. || (PlsrConfigIsValid(&payload.config, 0U) == 0U)
  2512. || (payload.positionValid > 1U) || (payload.wasBusy > 1U))
  2513. {
  2514. PlsrSetDefaults(&PlsrShadowConfig);
  2515. PlsrPosition = 0L;
  2516. PlsrPositionValid = 1U;
  2517. PlsrPlatformCheckpointConfig(&PlsrShadowConfig);
  2518. PlsrPlatformCheckpointPosition(0L, 1U, 0U);
  2519. PlsrMarkPersistenceDirty(PLSR_CONFIG_SAVE_DELAY_MS);
  2520. }
  2521. else
  2522. {
  2523. PlsrShadowConfig = payload.config;
  2524. PlsrPosition = payload.position;
  2525. PlsrPositionValid = ((payload.positionValid != 0U)
  2526. && (payload.wasBusy == 0U)) ? 1U : 0U;
  2527. PlsrPersistenceDirty = 0U;
  2528. PlsrPersistenceDelayMs = 0U;
  2529. }
  2530. (void)memset(&PlsrActiveConfig, 0, sizeof(PlsrActiveConfig));
  2531. (void)memset(&PlsrRamp, 0, sizeof(PlsrRamp));
  2532. (void)memset(&PlsrShortProfile, 0, sizeof(PlsrShortProfile));
  2533. (void)memset(&PlsrHandoffPlan, 0, sizeof(PlsrHandoffPlan));
  2534. (void)memset(PlsrPreparedHandoffPlans, 0,
  2535. sizeof(PlsrPreparedHandoffPlans));
  2536. PlsrPreparedHandoffBank = 0U;
  2537. PlsrRemainingPulses = 0UL;
  2538. PlsrPulseActive = 0U;
  2539. PlsrCutRequested = 0U;
  2540. PlsrBoundaryPending = 0U;
  2541. PlsrBoundaryWasCut = 0U;
  2542. PlsrCountOverflowPending = 0U;
  2543. PlsrPositionCheckpointDirty = 0U;
  2544. PlsrFrequencyUpdatePending = 0U;
  2545. PlsrDeferredFrequencyPending = 0U;
  2546. PlsrFrequencyUpdateSegment = 0U;
  2547. PlsrSeamlessHandoffPending = 0U;
  2548. PlsrTimerErrorPending = 0U;
  2549. PlsrCurrentFrequencyHz = 0UL;
  2550. PlsrQueuedFrequencyHz = 0UL;
  2551. PlsrBoundaryFrequencyHz = 0UL;
  2552. PlsrFrequencyUpdateTargetHz = 0UL;
  2553. PlsrDeferredFrequencyHz = 0UL;
  2554. PlsrSegmentEpoch = 0UL;
  2555. PlsrCurrentSegment = 0U;
  2556. PlsrDirectionDelayActive = 0U;
  2557. PlsrDirectionDelayRemainingMs = 0U;
  2558. PlsrSegmentClockStarted = 0U;
  2559. PlsrExtPreviousLevel = 0U;
  2560. PlsrExtEdgePending = 0U;
  2561. PlsrStopRequested = 0U;
  2562. PlsrStopPulsesRemaining = 0U;
  2563. PlsrLastDirectionValid = 0U;
  2564. PlsrPositionCheckpointElapsedMs = 0U;
  2565. PlsrCommandMailbox.command = 0U;
  2566. PlsrCommandMailbox.state = PLSR_COMMAND_MAILBOX_EMPTY;
  2567. PlsrError = PLSR_ERROR_NONE;
  2568. PlsrRunStatus = PLSR_STATUS_IDLE;
  2569. PlsrInitialized = 1U;
  2570. return 1U;
  2571. }
  2572. static PLSR_MB_RESULT PlsrQueueCommand(uint16_t command)
  2573. {
  2574. uint32_t criticalState;
  2575. PLSR_MB_RESULT result = PLSR_MB_OK;
  2576. if (PlsrInitialized == 0U)
  2577. {
  2578. return PLSR_MB_SERVER_FAILURE;
  2579. }
  2580. criticalState = PlsrPlatformEnterCritical();
  2581. /* Capacity one: repeats acknowledge the first command; conflicts wait. */
  2582. if (PlsrCommandMailbox.state != PLSR_COMMAND_MAILBOX_EMPTY)
  2583. {
  2584. result = (PlsrCommandMailbox.command == command)
  2585. ? PLSR_MB_OK : PLSR_MB_DEVICE_BUSY;
  2586. PlsrPlatformExitCritical(criticalState);
  2587. return result;
  2588. }
  2589. if (command == PLSR_COMMAND_START)
  2590. {
  2591. if ((PlsrIsBusy() != 0U)
  2592. || (PlsrRunStatus == PLSR_STATUS_ERROR))
  2593. {
  2594. result = PLSR_MB_DEVICE_BUSY;
  2595. }
  2596. else if ((PlsrRunStatus != PLSR_STATUS_IDLE)
  2597. && (PlsrRunStatus != PLSR_STATUS_COMPLETED)
  2598. && (PlsrRunStatus != PLSR_STATUS_STOPPED))
  2599. {
  2600. result = PLSR_MB_ILLEGAL_VALUE;
  2601. }
  2602. else if ((PlsrConfigIsValid(&PlsrShadowConfig, 1U) == 0U)
  2603. || ((PlsrShadowConfig.positionMode
  2604. == PLSR_POSITION_ABSOLUTE)
  2605. && (PlsrPositionValid == 0U)))
  2606. {
  2607. result = PLSR_MB_ILLEGAL_VALUE;
  2608. }
  2609. else
  2610. {
  2611. PlsrCommandMailbox.startConfig = PlsrShadowConfig;
  2612. }
  2613. }
  2614. else if ((command == PLSR_COMMAND_CLEAR) && (PlsrIsBusy() != 0U))
  2615. {
  2616. result = PLSR_MB_DEVICE_BUSY;
  2617. }
  2618. if (result == PLSR_MB_OK)
  2619. {
  2620. PlsrCommandMailbox.command = command;
  2621. PlsrCommandMailbox.state = PLSR_COMMAND_MAILBOX_PENDING;
  2622. }
  2623. PlsrPlatformExitCritical(criticalState);
  2624. return result;
  2625. }
  2626. static void PlsrExecuteStart(void)
  2627. {
  2628. uint32_t criticalState;
  2629. uint8_t handoffBank;
  2630. PlsrActiveConfig = PlsrCommandMailbox.startConfig;
  2631. handoffBank = PlsrBuildHandoffPlanBank(&PlsrActiveConfig);
  2632. criticalState = PlsrPlatformEnterCritical();
  2633. PlsrPreparedHandoffBank = handoffBank;
  2634. PlsrHandoffPlan.valid = 0U;
  2635. PlsrPlatformExitCritical(criticalState);
  2636. PlsrStopRequested = 0U;
  2637. PlsrTimerErrorPending = 0U;
  2638. PlsrShortProfile.active = 0U;
  2639. PlsrError = PLSR_ERROR_NONE;
  2640. PlsrLastDirectionValid = 0U;
  2641. PlsrCheckpointPosition(1U);
  2642. if (PlsrStartSegment((uint8_t)PlsrActiveConfig.startSegment, 0U, 0UL)
  2643. == 0U)
  2644. {
  2645. PlsrEnterError(PLSR_ERROR_INVALID_RESOURCE);
  2646. }
  2647. }
  2648. static uint8_t PlsrExecuteStop(void)
  2649. {
  2650. uint32_t criticalState;
  2651. uint32_t stopTargetHz;
  2652. if (PlsrIsBusy() == 0U)
  2653. {
  2654. return 0U;
  2655. }
  2656. criticalState = PlsrPlatformEnterCritical();
  2657. if (PlsrStopRequested != 0U)
  2658. {
  2659. PlsrPlatformExitCritical(criticalState);
  2660. return 0U;
  2661. }
  2662. PlsrStopRequested = 1U;
  2663. PlsrStopPulsesRemaining = 0U;
  2664. PlsrShortProfile.active = 0U;
  2665. PlsrHandoffPlan.valid = 0U;
  2666. PlsrInvalidateHandoffPlans();
  2667. if (PlsrBoundaryPending != 0U)
  2668. {
  2669. PlsrPlatformExitCritical(criticalState);
  2670. return 1U;
  2671. }
  2672. if (PlsrPulseActive == 0U)
  2673. {
  2674. PlsrPlatformExitCritical(criticalState);
  2675. PlsrFinishStopped();
  2676. return 1U;
  2677. }
  2678. stopTargetHz = PlsrActiveConfig.stopSpeedHz;
  2679. if (stopTargetHz > PlsrCurrentFrequencyHz)
  2680. {
  2681. stopTargetHz = PlsrCurrentFrequencyHz;
  2682. }
  2683. PlsrRampStart(PlsrCurrentFrequencyHz, stopTargetHz);
  2684. PlsrRunStatus = PLSR_STATUS_DECELERATING;
  2685. if (PlsrRamp.active == 0U)
  2686. {
  2687. if (PlsrApplyFrequency(stopTargetHz, PlsrSegmentEpoch) == 0U)
  2688. {
  2689. PlsrPlatformExitCritical(criticalState);
  2690. PlsrEnterError(PLSR_ERROR_TIMER);
  2691. return 1U;
  2692. }
  2693. PlsrStopPulsesRemaining = PlsrStopDrainPulseCount();
  2694. }
  2695. PlsrPlatformExitCritical(criticalState);
  2696. return 1U;
  2697. }
  2698. static void PlsrExecuteClear(void)
  2699. {
  2700. uint32_t criticalState;
  2701. criticalState = PlsrPlatformEnterCritical();
  2702. PlsrPosition = 0L;
  2703. PlsrPositionValid = 1U;
  2704. PlsrRemainingPulses = 0UL;
  2705. PlsrPlatformExitCritical(criticalState);
  2706. PlsrPlatformCheckpointPosition(0L, 1U, 0U);
  2707. PlsrCountOverflowPending = 0U;
  2708. PlsrPositionCheckpointDirty = 0U;
  2709. PlsrPositionCheckpointElapsedMs = 0U;
  2710. PlsrCurrentSegment = 0U;
  2711. PlsrCurrentFrequencyHz = 0UL;
  2712. PlsrQueuedFrequencyHz = 0UL;
  2713. PlsrCutRequested = 0U;
  2714. PlsrBoundaryPending = 0U;
  2715. PlsrBoundaryWasCut = 0U;
  2716. PlsrDirectionDelayActive = 0U;
  2717. PlsrDirectionDelayRemainingMs = 0U;
  2718. PlsrExtEdgePending = 0U;
  2719. PlsrShortProfile.active = 0U;
  2720. PlsrHandoffPlan.valid = 0U;
  2721. PlsrInvalidateHandoffPlans();
  2722. PlsrDeferredFrequencyPending = 0U;
  2723. PlsrTimerErrorPending = 0U;
  2724. PlsrRamp.active = 0U;
  2725. PlsrError = PLSR_ERROR_NONE;
  2726. PlsrRunStatus = PLSR_STATUS_IDLE;
  2727. PlsrMarkPersistenceDirty(PLSR_CONFIG_SAVE_DELAY_MS);
  2728. }
  2729. static uint8_t PlsrPollCommandMailbox(void)
  2730. {
  2731. uint16_t command;
  2732. uint8_t endPoll = 1U;
  2733. uint32_t criticalState;
  2734. criticalState = PlsrPlatformEnterCritical();
  2735. if (PlsrCommandMailbox.state != PLSR_COMMAND_MAILBOX_PENDING)
  2736. {
  2737. PlsrPlatformExitCritical(criticalState);
  2738. return 0U;
  2739. }
  2740. PlsrCommandMailbox.state = PLSR_COMMAND_MAILBOX_EXECUTING;
  2741. command = PlsrCommandMailbox.command;
  2742. PlsrPlatformExitCritical(criticalState);
  2743. switch (command)
  2744. {
  2745. case PLSR_COMMAND_START: PlsrExecuteStart(); break;
  2746. case PLSR_COMMAND_STOP: endPoll = PlsrExecuteStop(); break;
  2747. case PLSR_COMMAND_CLEAR: PlsrExecuteClear(); break;
  2748. default: PlsrEnterError(PLSR_ERROR_INTERNAL); break;
  2749. }
  2750. criticalState = PlsrPlatformEnterCritical();
  2751. PlsrCommandMailbox.command = 0U;
  2752. PlsrCommandMailbox.state = PLSR_COMMAND_MAILBOX_EMPTY;
  2753. PlsrPlatformExitCritical(criticalState);
  2754. return endPoll;
  2755. }
  2756. static void PlsrEnterErrorIfEpoch(PLSR_ERROR error, uint32_t expectedEpoch)
  2757. {
  2758. uint32_t criticalState = PlsrPlatformEnterCritical();
  2759. if (PlsrSegmentEpoch == expectedEpoch)
  2760. {
  2761. PlsrEnterError(error);
  2762. }
  2763. PlsrPlatformExitCritical(criticalState);
  2764. }
  2765. void PlsrPoll1ms(void)
  2766. {
  2767. uint8_t extLevel;
  2768. uint8_t extEdge;
  2769. uint8_t activeSegmentNumber;
  2770. uint8_t applyDynamicFrequency = 0U;
  2771. PLSR_SEGMENT_CONFIG *activeSegment;
  2772. uint32_t criticalState;
  2773. uint32_t newTargetHz;
  2774. uint32_t pollEpoch;
  2775. if (PlsrInitialized == 0U)
  2776. {
  2777. return;
  2778. }
  2779. if (PlsrPollCommandMailbox() != 0U)
  2780. {
  2781. return;
  2782. }
  2783. PlsrPollPositionCheckpoint();
  2784. criticalState = PlsrPlatformEnterCritical();
  2785. pollEpoch = PlsrSegmentEpoch;
  2786. extLevel = PlsrPlatformReadInput((uint8_t)PlsrActiveConfig.extInput);
  2787. extEdge = ((extLevel != 0U) && (PlsrExtPreviousLevel == 0U)) ? 1U : 0U;
  2788. PlsrExtPreviousLevel = extLevel;
  2789. if (PlsrExtEdgePending != 0U)
  2790. {
  2791. extEdge = 1U;
  2792. }
  2793. PlsrPlatformExitCritical(criticalState);
  2794. if (PlsrBoundaryPending != 0U)
  2795. {
  2796. PlsrExtEdgePending = 0U;
  2797. PlsrHandleBoundary(extEdge);
  2798. PlsrPollPersistence();
  2799. return;
  2800. }
  2801. if (PlsrIsBusy() == 0U)
  2802. {
  2803. PlsrExtEdgePending = 0U;
  2804. PlsrPollPersistence();
  2805. return;
  2806. }
  2807. if (PlsrSegmentEpoch != pollEpoch)
  2808. {
  2809. return;
  2810. }
  2811. if (PlsrDirectionDelayActive != 0U)
  2812. {
  2813. if (extEdge != 0U)
  2814. {
  2815. PlsrExtEdgePending = 1U;
  2816. }
  2817. if (PlsrDirectionDelayRemainingMs != 0U)
  2818. {
  2819. PlsrDirectionDelayRemainingMs--;
  2820. }
  2821. if (PlsrDirectionDelayRemainingMs == 0U)
  2822. {
  2823. PlsrDirectionDelayActive = 0U;
  2824. if (PlsrBeginSegmentOutput(PlsrActiveConfig.startSpeedHz) == 0U)
  2825. {
  2826. PlsrEnterError(PLSR_ERROR_TIMER);
  2827. }
  2828. }
  2829. return;
  2830. }
  2831. criticalState = PlsrPlatformEnterCritical();
  2832. if (PlsrSegmentEpoch != pollEpoch)
  2833. {
  2834. PlsrPlatformExitCritical(criticalState);
  2835. return;
  2836. }
  2837. PlsrExtEdgePending = 0U;
  2838. if (PlsrSegmentClockStarted != 0U)
  2839. {
  2840. PlsrSegmentElapsedMs++;
  2841. }
  2842. if (PlsrRunStatus == PLSR_STATUS_WAITING)
  2843. {
  2844. PlsrPlatformExitCritical(criticalState);
  2845. PlsrPollWaiting(extEdge);
  2846. return;
  2847. }
  2848. activeSegmentNumber = PlsrCurrentSegment;
  2849. if ((activeSegmentNumber == 0U)
  2850. || (activeSegmentNumber > PlsrActiveConfig.segmentCount))
  2851. {
  2852. PlsrPlatformExitCritical(criticalState);
  2853. PlsrEnterError(PLSR_ERROR_INTERNAL);
  2854. return;
  2855. }
  2856. activeSegment = &PlsrActiveConfig.segments[activeSegmentNumber - 1U];
  2857. if (PlsrSeamlessHandoffPending != 0U)
  2858. {
  2859. PlsrSeamlessHandoffPending = 0U;
  2860. if ((PlsrStopRequested == 0U)
  2861. && (PlsrShortProfile.active == 0U)
  2862. && (PlsrFrequencyUpdatePending == 0U))
  2863. {
  2864. PlsrRamp.active = 0U;
  2865. PlsrRunStatus = PLSR_STATUS_RUNNING;
  2866. }
  2867. }
  2868. newTargetHz = PlsrFrequencyUpdateTargetHz;
  2869. if ((PlsrStopRequested == 0U)
  2870. && (PlsrFrequencyUpdatePending != 0U)
  2871. && (PlsrFrequencyUpdateSegment == activeSegmentNumber))
  2872. {
  2873. PlsrFrequencyUpdatePending = 0U;
  2874. activeSegment->frequencyHz = newTargetHz;
  2875. PlsrShortProfile.active = 0U;
  2876. PlsrBoundaryRampStarted = 0U;
  2877. PlsrRampStart(PlsrCurrentFrequencyHz, newTargetHz);
  2878. if (PlsrRamp.active == 0U)
  2879. {
  2880. applyDynamicFrequency = 1U;
  2881. }
  2882. }
  2883. PlsrPlatformExitCritical(criticalState);
  2884. if (applyDynamicFrequency != 0U)
  2885. {
  2886. if (PlsrApplyFrequency(newTargetHz, pollEpoch) == 0U)
  2887. {
  2888. PlsrEnterErrorIfEpoch(PLSR_ERROR_TIMER, pollEpoch);
  2889. return;
  2890. }
  2891. criticalState = PlsrPlatformEnterCritical();
  2892. if (PlsrSegmentEpoch == pollEpoch)
  2893. {
  2894. PlsrRunStatus = PLSR_STATUS_RUNNING;
  2895. }
  2896. PlsrPlatformExitCritical(criticalState);
  2897. }
  2898. if ((PlsrShortProfile.active == 0U)
  2899. && (PlsrRamp.active != 0U)
  2900. && (PlsrRampAdvance(pollEpoch) == 0U))
  2901. {
  2902. PlsrEnterErrorIfEpoch(PLSR_ERROR_TIMER, pollEpoch);
  2903. return;
  2904. }
  2905. criticalState = PlsrPlatformEnterCritical();
  2906. if (PlsrSegmentEpoch != pollEpoch)
  2907. {
  2908. PlsrPlatformExitCritical(criticalState);
  2909. return;
  2910. }
  2911. if ((PlsrStopRequested != 0U) && (PlsrRamp.active == 0U))
  2912. {
  2913. if (PlsrStopPulsesRemaining == 0U)
  2914. {
  2915. PlsrStopPulsesRemaining = PlsrStopDrainPulseCount();
  2916. }
  2917. PlsrPlatformExitCritical(criticalState);
  2918. return;
  2919. }
  2920. PlsrPlatformExitCritical(criticalState);
  2921. if ((activeSegment->waitType == PLSR_ACT_TIME)
  2922. && (PlsrSegmentElapsedMs >= activeSegment->actTimeMs))
  2923. {
  2924. PlsrRequestCut(pollEpoch);
  2925. return;
  2926. }
  2927. if (((activeSegment->waitType == PLSR_EXT_SIGNAL)
  2928. || (activeSegment->waitType == PLSR_EXT_OR_COMPLETE))
  2929. && (extEdge != 0U))
  2930. {
  2931. PlsrRequestCut(pollEpoch);
  2932. return;
  2933. }
  2934. PlsrMaybePlanBoundaryRamp(pollEpoch);
  2935. }
  2936. void PlsrPulseTimerIrq(uint8_t pulseOutput)
  2937. {
  2938. uint32_t positionBits;
  2939. uint32_t completedFrequencyHz;
  2940. uint32_t activeFrequencyHz;
  2941. if ((PlsrPulseActive == 0U)
  2942. || (pulseOutput != (uint8_t)PlsrActiveConfig.pulseOutput))
  2943. {
  2944. return;
  2945. }
  2946. completedFrequencyHz = PlsrCurrentFrequencyHz;
  2947. activeFrequencyHz = PlsrPlatformActiveFrequency(pulseOutput);
  2948. if (activeFrequencyHz == 0UL)
  2949. {
  2950. PlsrTimerErrorPending = 1U;
  2951. return;
  2952. }
  2953. PlsrCurrentFrequencyHz = activeFrequencyHz;
  2954. if ((PlsrStopRequested != 0U) && (PlsrRamp.active == 0U)
  2955. && (PlsrStopPulsesRemaining != 0U))
  2956. {
  2957. PlsrStopPulsesRemaining--;
  2958. if (PlsrStopPulsesRemaining == 0U)
  2959. {
  2960. PlsrCutRequested = 1U;
  2961. }
  2962. }
  2963. positionBits = (uint32_t)PlsrPosition;
  2964. if (PlsrCountPositive != 0U)
  2965. {
  2966. if (PlsrPosition == INT32_MAX)
  2967. {
  2968. PlsrPositionValid = 0U;
  2969. PlsrCountOverflowPending = 1U;
  2970. }
  2971. positionBits++;
  2972. }
  2973. else
  2974. {
  2975. if (PlsrPosition == INT32_MIN)
  2976. {
  2977. PlsrPositionValid = 0U;
  2978. PlsrCountOverflowPending = 1U;
  2979. }
  2980. positionBits--;
  2981. }
  2982. PlsrPosition = (int32_t)positionBits;
  2983. PlsrPositionCheckpointDirty = 1U;
  2984. if (PlsrRemainingPulses != 0UL)
  2985. {
  2986. PlsrRemainingPulses--;
  2987. }
  2988. if ((PlsrRemainingPulses == 0UL) || (PlsrCutRequested != 0U)
  2989. || (PlsrCountOverflowPending != 0U))
  2990. {
  2991. if ((PlsrRemainingPulses == 0UL)
  2992. && (PlsrTrySubsequentHandoff() != 0U))
  2993. {
  2994. return;
  2995. }
  2996. PlsrShortProfile.active = 0U;
  2997. PlsrHandoffPlan.valid = 0U;
  2998. PlsrBoundaryFrequencyHz = completedFrequencyHz;
  2999. PlsrBoundaryWasCut = (PlsrCutRequested != 0U) ? 1U : 0U;
  3000. PlsrCutRequested = 0U;
  3001. PlsrPlatformStopPulse(pulseOutput);
  3002. PlsrPulseActive = 0U;
  3003. PlsrCurrentFrequencyHz = 0UL;
  3004. PlsrQueuedFrequencyHz = 0UL;
  3005. PlsrBoundaryPending = 1U;
  3006. return;
  3007. }
  3008. if ((PlsrShortProfile.active != 0U)
  3009. && (PlsrAdvanceShortProfile(pulseOutput) == 0U))
  3010. {
  3011. PlsrTimerErrorPending = 1U;
  3012. PlsrShortProfile.active = 0U;
  3013. PlsrHandoffPlan.valid = 0U;
  3014. PlsrBoundaryFrequencyHz = completedFrequencyHz;
  3015. PlsrBoundaryWasCut = 0U;
  3016. PlsrCutRequested = 0U;
  3017. PlsrPlatformStopPulse(pulseOutput);
  3018. PlsrPulseActive = 0U;
  3019. PlsrCurrentFrequencyHz = 0UL;
  3020. PlsrQueuedFrequencyHz = 0UL;
  3021. PlsrBoundaryPending = 1U;
  3022. return;
  3023. }
  3024. if ((PlsrShortProfile.active == 0U)
  3025. && (PlsrRemainingPulses == 1UL))
  3026. {
  3027. (void)PlsrPrimeHandoff();
  3028. }
  3029. if ((PlsrShortProfile.active == 0U)
  3030. && (PlsrHandoffPlan.valid == 0U)
  3031. && (PlsrCommitDeferredFrequency(pulseOutput) == 0U))
  3032. {
  3033. PlsrTimerErrorPending = 1U;
  3034. PlsrBoundaryFrequencyHz = completedFrequencyHz;
  3035. PlsrBoundaryWasCut = 0U;
  3036. PlsrCutRequested = 0U;
  3037. PlsrPlatformStopPulse(pulseOutput);
  3038. PlsrPulseActive = 0U;
  3039. PlsrCurrentFrequencyHz = 0UL;
  3040. PlsrQueuedFrequencyHz = 0UL;
  3041. PlsrBoundaryPending = 1U;
  3042. }
  3043. }
  3044. PLSR_MB_RESULT PlsrModbusReadHolding(uint16_t startAddress,
  3045. uint16_t quantity,
  3046. uint16_t *values)
  3047. {
  3048. PLSR_MB_RESULT classification;
  3049. uint16_t index;
  3050. uint32_t criticalState;
  3051. int32_t position;
  3052. uint32_t frequency;
  3053. uint16_t statusWords[7];
  3054. if (values == NULL)
  3055. {
  3056. return PLSR_MB_ILLEGAL_VALUE;
  3057. }
  3058. classification = PlsrClassifyRange(startAddress, quantity);
  3059. if (classification != PLSR_MB_OK)
  3060. {
  3061. return classification;
  3062. }
  3063. criticalState = PlsrPlatformEnterCritical();
  3064. position = PlsrPosition;
  3065. frequency = PlsrCurrentFrequencyHz;
  3066. statusWords[0] = PlsrLowWord((uint32_t)position);
  3067. statusWords[1] = PlsrHighWord((uint32_t)position);
  3068. statusWords[2] = PlsrLowWord(frequency);
  3069. statusWords[3] = PlsrHighWord(frequency);
  3070. statusWords[4] = (uint16_t)PlsrRunStatus;
  3071. statusWords[5] = PlsrCurrentSegment;
  3072. statusWords[6] = (uint16_t)PlsrError;
  3073. PlsrPlatformExitCritical(criticalState);
  3074. for (index = 0U; index < quantity; index++)
  3075. {
  3076. uint16_t address = (uint16_t)(startAddress + index);
  3077. if ((address >= PLSR_CONFIG_FIRST_ADDRESS)
  3078. && (address <= PLSR_CONFIG_LAST_ADDRESS))
  3079. {
  3080. values[index] = PlsrReadConfigWord(&PlsrShadowConfig, address);
  3081. }
  3082. else if ((address >= PLSR_STATUS_FIRST_ADDRESS)
  3083. && (address <= PLSR_STATUS_LAST_ADDRESS))
  3084. {
  3085. values[index] = statusWords[address - PLSR_STATUS_FIRST_ADDRESS];
  3086. }
  3087. else if (address == PLSR_CONTROL_ADDRESS)
  3088. {
  3089. values[index] = 0U;
  3090. }
  3091. else
  3092. {
  3093. return PLSR_MB_ILLEGAL_ADDRESS;
  3094. }
  3095. }
  3096. return PLSR_MB_OK;
  3097. }
  3098. PLSR_MB_RESULT PlsrModbusWriteHolding(uint16_t startAddress,
  3099. uint16_t quantity,
  3100. const uint16_t *values)
  3101. {
  3102. PLSR_MB_RESULT classification;
  3103. PLSR_WORD_RESULT wordResult;
  3104. uint16_t index;
  3105. uint16_t pairedAddress;
  3106. uint32_t requestEnd;
  3107. uint32_t criticalState;
  3108. uint8_t handoffBank = 0U;
  3109. uint8_t updateActiveFrequencies = 0U;
  3110. uint8_t drainedToDifferentSegment = 0U;
  3111. uint8_t segmentBeforeDrain;
  3112. uint32_t drainedSegmentTargetHz = 0UL;
  3113. if (values == NULL)
  3114. {
  3115. return PLSR_MB_ILLEGAL_VALUE;
  3116. }
  3117. classification = PlsrClassifyRange(startAddress, quantity);
  3118. if (classification != PLSR_MB_OK)
  3119. {
  3120. return classification;
  3121. }
  3122. if ((startAddress >= PLSR_STATUS_FIRST_ADDRESS)
  3123. && (startAddress <= PLSR_STATUS_LAST_ADDRESS))
  3124. {
  3125. return PLSR_MB_ILLEGAL_ADDRESS;
  3126. }
  3127. if (startAddress == PLSR_CONTROL_ADDRESS)
  3128. {
  3129. if (quantity != 1U)
  3130. {
  3131. return PLSR_MB_ILLEGAL_ADDRESS;
  3132. }
  3133. switch (values[0])
  3134. {
  3135. case 0U: return PLSR_MB_OK;
  3136. case PLSR_COMMAND_START:
  3137. case PLSR_COMMAND_STOP:
  3138. case PLSR_COMMAND_CLEAR:
  3139. return PlsrQueueCommand(values[0]);
  3140. default: return PLSR_MB_ILLEGAL_VALUE;
  3141. }
  3142. }
  3143. if ((startAddress < PLSR_CONFIG_FIRST_ADDRESS)
  3144. || ((uint32_t)startAddress + quantity - 1UL
  3145. > PLSR_CONFIG_LAST_ADDRESS))
  3146. {
  3147. return PLSR_MB_ILLEGAL_ADDRESS;
  3148. }
  3149. if ((PlsrIsBusy() != 0U)
  3150. && (startAddress <= 0x1001U)
  3151. && ((uint32_t)startAddress + quantity - 1UL >= 0x1000UL))
  3152. {
  3153. return PLSR_MB_DEVICE_BUSY;
  3154. }
  3155. requestEnd = (uint32_t)startAddress + quantity;
  3156. for (index = 0U; index < quantity; index++)
  3157. {
  3158. uint16_t address = (uint16_t)(startAddress + index);
  3159. if (PlsrAddressIsDwordHalf(address, &pairedAddress) != 0U)
  3160. {
  3161. if (((uint32_t)pairedAddress < startAddress)
  3162. || ((uint32_t)pairedAddress >= requestEnd))
  3163. {
  3164. return PLSR_MB_ILLEGAL_ADDRESS;
  3165. }
  3166. }
  3167. }
  3168. PlsrCandidateConfig = PlsrShadowConfig;
  3169. for (index = 0U; index < quantity; index++)
  3170. {
  3171. wordResult = PlsrWriteConfigWord(&PlsrCandidateConfig,
  3172. (uint16_t)(startAddress + index),
  3173. values[index]);
  3174. if (wordResult == PLSR_WORD_ILLEGAL_ADDRESS)
  3175. {
  3176. return PLSR_MB_ILLEGAL_ADDRESS;
  3177. }
  3178. if (wordResult == PLSR_WORD_ILLEGAL_VALUE)
  3179. {
  3180. return PLSR_MB_ILLEGAL_VALUE;
  3181. }
  3182. }
  3183. if (PlsrConfigIsValid(&PlsrCandidateConfig, 0U) == 0U)
  3184. {
  3185. return PLSR_MB_ILLEGAL_VALUE;
  3186. }
  3187. if (PlsrIsBusy() != 0U)
  3188. {
  3189. for (index = 0U; index < PlsrActiveConfig.segmentCount; index++)
  3190. {
  3191. if (PlsrCandidateConfig.segments[index].frequencyHz
  3192. != PlsrShadowConfig.segments[index].frequencyHz)
  3193. {
  3194. updateActiveFrequencies = 1U;
  3195. }
  3196. }
  3197. }
  3198. if (updateActiveFrequencies != 0U)
  3199. {
  3200. handoffBank = PlsrBuildHandoffPlanBank(&PlsrCandidateConfig);
  3201. }
  3202. criticalState = PlsrPlatformEnterCritical();
  3203. segmentBeforeDrain = PlsrCurrentSegment;
  3204. if ((updateActiveFrequencies != 0U) && (PlsrPulseActive != 0U))
  3205. {
  3206. PlsrPlatformDrainPendingPulse(
  3207. (uint8_t)PlsrActiveConfig.pulseOutput);
  3208. drainedToDifferentSegment =
  3209. (PlsrCurrentSegment != segmentBeforeDrain) ? 1U : 0U;
  3210. if ((drainedToDifferentSegment != 0U)
  3211. && (PlsrCurrentSegment != 0U)
  3212. && (PlsrCurrentSegment <= PlsrCandidateConfig.segmentCount))
  3213. {
  3214. drainedSegmentTargetHz =
  3215. PlsrCandidateConfig.segments[PlsrCurrentSegment - 1U].frequencyHz;
  3216. }
  3217. }
  3218. PlsrShadowConfig = PlsrCandidateConfig;
  3219. if (updateActiveFrequencies != 0U)
  3220. {
  3221. for (index = 0U; index < PlsrActiveConfig.segmentCount; index++)
  3222. {
  3223. uint8_t frequencyChanged =
  3224. (PlsrActiveConfig.segments[index].frequencyHz
  3225. != PlsrCandidateConfig.segments[index].frequencyHz)
  3226. ? 1U : 0U;
  3227. PlsrActiveConfig.segments[index].frequencyHz =
  3228. PlsrCandidateConfig.segments[index].frequencyHz;
  3229. if ((frequencyChanged != 0U)
  3230. && (index + 1U == PlsrCurrentSegment)
  3231. && (PlsrStopRequested == 0U)
  3232. && (PlsrRunStatus != PLSR_STATUS_WAITING))
  3233. {
  3234. PlsrFrequencyUpdateTargetHz =
  3235. PlsrCandidateConfig.segments[index].frequencyHz;
  3236. PlsrFrequencyUpdateSegment = (uint8_t)(index + 1U);
  3237. PlsrFrequencyUpdatePending = 1U;
  3238. }
  3239. }
  3240. PlsrPreparedHandoffBank = handoffBank;
  3241. PlsrHandoffPlan.valid = 0U;
  3242. if ((drainedToDifferentSegment != 0U)
  3243. && (PlsrPulseActive != 0U)
  3244. && (PlsrCurrentSegment != 0U)
  3245. && (PlsrCurrentSegment <= PlsrActiveConfig.segmentCount)
  3246. && (PlsrStopRequested == 0U)
  3247. && (PlsrRunStatus != PLSR_STATUS_WAITING)
  3248. && (PlsrCurrentFrequencyHz != drainedSegmentTargetHz))
  3249. {
  3250. PlsrFrequencyUpdateTargetHz =
  3251. drainedSegmentTargetHz;
  3252. PlsrFrequencyUpdateSegment = PlsrCurrentSegment;
  3253. PlsrFrequencyUpdatePending = 1U;
  3254. }
  3255. if ((PlsrPulseActive != 0U)
  3256. && (PlsrShortProfile.active == 0U)
  3257. && (PlsrRemainingPulses == 1UL))
  3258. {
  3259. (void)PlsrPrimeHandoff();
  3260. }
  3261. }
  3262. PlsrPlatformExitCritical(criticalState);
  3263. if ((drainedToDifferentSegment != 0U)
  3264. && (PlsrFrequencyUpdatePending != 0U))
  3265. {
  3266. uint32_t drainEpoch = PlsrSegmentEpoch;
  3267. uint32_t actualDrainFrequencyHz;
  3268. if (PlsrPlatformQueueFrequency(
  3269. (uint8_t)PlsrActiveConfig.pulseOutput,
  3270. drainedSegmentTargetHz, &actualDrainFrequencyHz) == 0U)
  3271. {
  3272. PlsrTimerErrorPending = 1U;
  3273. }
  3274. else
  3275. {
  3276. uint32_t currentEpoch;
  3277. uint8_t updateSegment;
  3278. uint8_t currentSegment;
  3279. criticalState = PlsrPlatformEnterCritical();
  3280. currentEpoch = PlsrSegmentEpoch;
  3281. updateSegment = PlsrFrequencyUpdateSegment;
  3282. currentSegment = PlsrCurrentSegment;
  3283. if ((currentEpoch == drainEpoch)
  3284. && (updateSegment == currentSegment))
  3285. {
  3286. PlsrQueuedFrequencyHz = actualDrainFrequencyHz;
  3287. PlsrFrequencyUpdatePending = 0U;
  3288. PlsrRamp.active = 0U;
  3289. PlsrRunStatus = PLSR_STATUS_RUNNING;
  3290. }
  3291. PlsrPlatformExitCritical(criticalState);
  3292. }
  3293. }
  3294. PlsrPlatformCheckpointConfig(&PlsrShadowConfig);
  3295. PlsrMarkPersistenceDirty(PLSR_CONFIG_SAVE_DELAY_MS);
  3296. return PLSR_MB_OK;
  3297. }
  3298. #ifdef PLSR_HOST_TEST
  3299. uint64_t PlsrTestDivideU64ByU32(uint64_t dividend,
  3300. uint32_t divisor,
  3301. uint32_t *remainder)
  3302. {
  3303. return PlsrDivideU64ByU32(dividend, divisor, remainder);
  3304. }
  3305. void PlsrTestSetPosition(int32_t position, uint8_t positionValid)
  3306. {
  3307. uint32_t criticalState = PlsrPlatformEnterCritical();
  3308. PlsrPosition = position;
  3309. PlsrPositionValid = (positionValid != 0U) ? 1U : 0U;
  3310. PlsrRemainingPulses = 0UL;
  3311. PlsrPositionCheckpointDirty = 0U;
  3312. PlsrPlatformExitCritical(criticalState);
  3313. PlsrPlatformCheckpointPosition(position, PlsrPositionValid, 0U);
  3314. }
  3315. #endif