|
- #include "plsr.h"
- #include "plsr_internal.h"
- #include "plsr_platform.h"
- #include <stddef.h>
- #include <string.h>
-
- #if defined(__ICCARM__)
- #include <intrinsics.h>
- #endif
-
- #define PLSR_COMMON_FIRST_ADDRESS (0x1000U)
- #define PLSR_COMMON_LAST_ADDRESS (0x10FFU)
- #define PLSR_SEGMENT_FIRST_ADDRESS (0x1100U)
- #define PLSR_SEGMENT_STRIDE (0x0010U)
- #define PLSR_SEGMENT_DEFINED_WORDS (8U)
-
- #define PLSR_WAIT_TIME (0U)
- #define PLSR_WAIT_SIGNAL (1U)
- #define PLSR_ACT_TIME (2U)
- #define PLSR_EXT_SIGNAL (3U)
- #define PLSR_EXT_OR_COMPLETE (4U)
-
- #define PLSR_SEND_COMPLETE (0U)
- #define PLSR_SEND_SUBSEQUENT (1U)
- #define PLSR_POSITION_RELATIVE (0U)
- #define PLSR_POSITION_ABSOLUTE (1U)
-
- #define PLSR_COMMAND_START (0x0001U)
- #define PLSR_COMMAND_STOP (0x0002U)
- #define PLSR_COMMAND_CLEAR (0x0004U)
-
- #define PLSR_CONFIG_SAVE_DELAY_MS (1000U)
- #define PLSR_POSITION_CHECKPOINT_MS (10U)
- #define PLSR_SHORT_PROFILE_MAX_PULSES (65535UL)
- #define PLSR_Q32_ONE (4294967296ULL)
-
- typedef struct
- {
- uint32_t fromHz;
- uint32_t toHz;
- uint32_t durationMs;
- uint32_t elapsedMs;
- uint8_t active;
- } PLSR_RAMP;
-
- typedef struct
- {
- uint32_t startHz;
- uint32_t peakHz;
- uint32_t endHz;
- uint16_t pulseCount;
- uint16_t entryPulses;
- uint16_t steadyPulses;
- uint16_t exitPulses;
- volatile uint16_t nextPeriod;
- uint64_t rampBoundaryQ32;
- uint64_t rampTotalAreaQ32;
- uint64_t rampTargetAreaQ32;
- uint64_t rampAreaStepQ32;
- uint32_t rampAreaRemainder;
- uint32_t rampRemainderAccumulator;
- uint64_t lastRampPhaseStepQ32;
- uint64_t entryFirstBoundaryQ32;
- uint64_t entrySecondBoundaryQ32;
- uint64_t exitFirstBoundaryQ32;
- uint64_t exitSecondBoundaryQ32;
- uint32_t lastRampFrequencyHz;
- volatile uint8_t active;
- } PLSR_SHORT_PROFILE;
-
- typedef struct
- {
- uint64_t magnitude;
- uint32_t firstFrequencyHz;
- PLSR_SHORT_PROFILE profile;
- uint8_t nextSegment;
- uint8_t positive;
- volatile uint8_t valid;
- } PLSR_HANDOFF_PLAN;
-
- typedef enum
- {
- PLSR_WORD_OK = 0,
- PLSR_WORD_ILLEGAL_ADDRESS,
- PLSR_WORD_ILLEGAL_VALUE
- } PLSR_WORD_RESULT;
-
- typedef enum
- {
- PLSR_COMMAND_MAILBOX_EMPTY = 0,
- PLSR_COMMAND_MAILBOX_PENDING,
- PLSR_COMMAND_MAILBOX_EXECUTING
- } PLSR_COMMAND_MAILBOX_STATE;
-
- typedef struct
- {
- PLSR_CONFIG startConfig;
- uint16_t command;
- volatile uint8_t state;
- } PLSR_COMMAND_MAILBOX;
-
- static const uint16_t PlsrSineProgressQ16[65] =
- {
- 0U, 39U, 158U, 355U, 630U, 982U, 1411U, 1915U,
- 2494U, 3146U, 3869U, 4662U, 5522U, 6448U, 7438U, 8488U,
- 9597U, 10762U, 11980U, 13248U, 14563U, 15922U, 17321U,
- 18758U, 20228U, 21728U, 23256U, 24806U, 26375U, 27960U,
- 29556U, 31160U, 32767U, 34375U, 35979U, 37575U, 39160U,
- 40729U, 42279U, 43807U, 45307U, 46777U, 48214U, 49613U,
- 50972U, 52287U, 53555U, 54773U, 55938U, 57047U, 58097U,
- 59087U, 60013U, 60873U, 61666U, 62389U, 63041U, 63620U,
- 64124U, 64553U, 64905U, 65180U, 65377U, 65496U, 65535U
- };
-
- static const uint32_t PlsrSmoothIntegralQ24[65] =
- {
- 0UL, 64UL, 504UL, 1688UL, 3968UL, 7688UL, 13176UL, 20752UL,
- 30720UL, 43376UL, 59000UL, 77864UL, 100224UL, 126328UL, 156408UL,
- 190688UL, 229376UL, 272672UL, 320760UL, 373816UL, 432000UL,
- 495464UL, 564344UL, 638768UL, 718848UL, 804688UL, 896376UL,
- 993992UL, 1097600UL, 1207256UL, 1323000UL, 1444864UL, 1572864UL,
- 1707008UL, 1847288UL, 1993688UL, 2146176UL, 2304712UL, 2469240UL,
- 2639696UL, 2816000UL, 2998064UL, 3185784UL, 3379048UL, 3577728UL,
- 3781688UL, 3990776UL, 4204832UL, 4423680UL, 4647136UL, 4875000UL,
- 5107064UL, 5343104UL, 5582888UL, 5826168UL, 6072688UL, 6322176UL,
- 6574352UL, 6828920UL, 7085576UL, 7344000UL, 7603864UL, 7864824UL,
- 8126528UL, 8388608UL
- };
-
- static const uint32_t PlsrSineIntegralQ24[65] =
- {
- 0UL, 53UL, 421UL, 1420UL, 3362UL, 6560UL, 11321UL, 17949UL,
- 26744UL, 38000UL, 52007UL, 69047UL, 89393UL, 113314UL, 141066UL,
- 172899UL, 209052UL, 249753UL, 295221UL, 345662UL, 401269UL,
- 462225UL, 528698UL, 600845UL, 678806UL, 762711UL, 852672UL,
- 948789UL, 1051146UL, 1159812UL, 1274841UL, 1396271UL, 1524127UL,
- 1658415UL, 1799129UL, 1946244UL, 2099722UL, 2259509UL, 2425536UL,
- 2597719UL, 2775958UL, 2960141UL, 3150138UL, 3345809UL, 3546997UL,
- 3753534UL, 3965237UL, 4181913UL, 4403356UL, 4629347UL, 4859658UL,
- 5094050UL, 5332273UL, 5574071UL, 5819175UL, 6067312UL, 6318200UL,
- 6571549UL, 6827065UL, 7084448UL, 7343394UL, 7603596UL, 7864741UL,
- 8126517UL, 8388608UL
- };
-
- static PLSR_CONFIG PlsrShadowConfig;
- static PLSR_CONFIG PlsrActiveConfig;
- static PLSR_CONFIG PlsrCandidateConfig;
- static volatile int32_t PlsrPosition;
- static volatile uint64_t PlsrRemainingPulses;
- static volatile uint8_t PlsrPulseActive;
- static volatile uint8_t PlsrCutRequested;
- static volatile uint8_t PlsrBoundaryPending;
- static volatile uint8_t PlsrBoundaryWasCut;
- static volatile uint8_t PlsrCountPositive;
- static volatile uint8_t PlsrCountOverflowPending;
- static volatile uint8_t PlsrPositionValid;
- static volatile uint8_t PlsrPositionCheckpointDirty;
- static volatile uint8_t PlsrFrequencyUpdatePending;
- static volatile uint8_t PlsrFrequencyUpdateSegment;
- static volatile uint8_t PlsrSeamlessHandoffPending;
- static volatile uint8_t PlsrTimerErrorPending;
- static volatile uint8_t PlsrDeferredFrequencyPending;
- static volatile uint32_t PlsrCurrentFrequencyHz;
- static volatile uint32_t PlsrQueuedFrequencyHz;
- static volatile uint32_t PlsrBoundaryFrequencyHz;
- static volatile uint32_t PlsrFrequencyUpdateTargetHz;
- static volatile uint32_t PlsrDeferredFrequencyHz;
- static volatile uint32_t PlsrSegmentEpoch;
-
- static volatile PLSR_STATUS PlsrRunStatus = PLSR_STATUS_UNINITIALIZED;
- static PLSR_ERROR PlsrError = PLSR_ERROR_NONE;
- static PLSR_RAMP PlsrRamp;
- static PLSR_SHORT_PROFILE PlsrShortProfile;
- static PLSR_HANDOFF_PLAN PlsrHandoffPlan;
- static PLSR_HANDOFF_PLAN
- PlsrPreparedHandoffPlans[2][PLSR_SEGMENT_COUNT_MAX];
- static volatile uint8_t PlsrPreparedHandoffBank;
- static uint8_t PlsrInitialized;
- static volatile uint8_t PlsrCurrentSegment;
- static uint8_t PlsrDirectionDelayActive;
- static uint16_t PlsrDirectionDelayRemainingMs;
- static volatile uint8_t PlsrSegmentClockStarted;
- static volatile uint32_t PlsrSegmentElapsedMs;
- static volatile uint32_t PlsrWaitElapsedMs;
- static volatile uint8_t PlsrExtPreviousLevel;
- static volatile uint8_t PlsrExtEdgePending;
- static volatile uint8_t PlsrStopRequested;
- static volatile uint8_t PlsrStopPulsesRemaining;
- static volatile uint8_t PlsrBoundaryRampStarted;
- static uint8_t PlsrLastDirectionValid;
- static uint8_t PlsrLastDirectionOutput;
- static uint8_t PlsrLastDirectionLevel;
- static uint8_t PlsrPersistenceDirty;
- static uint16_t PlsrPersistenceDelayMs;
- static uint8_t PlsrPositionCheckpointElapsedMs;
- static PLSR_COMMAND_MAILBOX PlsrCommandMailbox;
-
- static uint8_t PlsrIsBusy(void);
- static void PlsrSetDefaults(PLSR_CONFIG *config);
- static uint8_t PlsrConfigIsValid(const PLSR_CONFIG *config,
- uint8_t validateActivePath);
- static uint16_t PlsrReadConfigWord(const PLSR_CONFIG *config,
- uint16_t address);
- static PLSR_WORD_RESULT PlsrWriteConfigWord(PLSR_CONFIG *config,
- uint16_t address,
- uint16_t value);
- static uint8_t PlsrAddressIsDwordHalf(uint16_t address,
- uint16_t *pairedAddress);
- static PLSR_MB_RESULT PlsrQueueCommand(uint16_t command);
- static uint8_t PlsrPollCommandMailbox(void);
- static void PlsrExecuteStart(void);
- static uint8_t PlsrExecuteStop(void);
- static void PlsrExecuteClear(void);
- static uint8_t PlsrStartSegment(uint8_t segmentNumber,
- uint8_t allowCarry,
- uint32_t carryFrequencyHz);
- static uint8_t PlsrBeginSegmentOutput(uint32_t startFrequencyHz);
- static void PlsrHandleBoundary(uint8_t extEdge);
- static void PlsrTransitionToNext(uint8_t allowCarry);
- static void PlsrFinishCompleted(void);
- static void PlsrFinishStopped(void);
- static void PlsrEnterError(PLSR_ERROR error);
- static void PlsrMarkPersistenceDirty(uint16_t delayMs);
- static void PlsrCheckpointPosition(uint8_t wasBusy);
- static void PlsrPollPositionCheckpoint(void);
- static uint8_t PlsrTrySubsequentHandoff(void);
- static uint8_t PlsrPrepareShortProfile(PLSR_SHORT_PROFILE *profile,
- uint8_t segmentNumber,
- uint32_t startFrequencyHz,
- uint32_t targetFrequencyHz,
- uint64_t pulseCount);
- static uint32_t PlsrShortProfileTakeFrequency(PLSR_SHORT_PROFILE *profile);
- static uint8_t PlsrAdvanceShortProfile(uint8_t pulseOutput);
- static void PlsrCopyShortProfile(PLSR_SHORT_PROFILE *destination,
- const PLSR_SHORT_PROFILE *source);
- static void PlsrInvalidateHandoffPlans(void);
- static uint8_t PlsrBuildHandoffPlanBank(
- const PLSR_CONFIG *frequencyConfig);
- static uint8_t PlsrSelectPreparedHandoffPlan(PLSR_HANDOFF_PLAN *plan);
- static uint8_t PlsrPrimeHandoff(void);
- static uint8_t PlsrBuildHandoffPlan(uint8_t sourceSegment,
- const PLSR_CONFIG *frequencyConfig,
- PLSR_HANDOFF_PLAN *plan);
-
- static uint8_t PlsrIsBusy(void)
- {
- return ((PlsrRunStatus == PLSR_STATUS_ACCELERATING)
- || (PlsrRunStatus == PLSR_STATUS_RUNNING)
- || (PlsrRunStatus == PLSR_STATUS_DECELERATING)
- || (PlsrRunStatus == PLSR_STATUS_WAITING)
- || (PlsrRunStatus == PLSR_STATUS_PAUSED)) ? 1U : 0U;
- }
-
- static uint32_t PlsrJoinU32(uint16_t lowWord, uint16_t highWord)
- {
- return (uint32_t)lowWord | ((uint32_t)highWord << 16U);
- }
-
- static uint16_t PlsrLowWord(uint32_t value)
- {
- return (uint16_t)(value & 0xFFFFUL);
- }
-
- static uint16_t PlsrHighWord(uint32_t value)
- {
- return (uint16_t)(value >> 16U);
- }
-
- static void PlsrSetDefaults(PLSR_CONFIG *config)
- {
- uint8_t index;
-
- (void)memset(config, 0, sizeof(*config));
- config->pulseOutput = 0U;
- config->directionOutput = 0U;
- config->waitInput = 0U;
- config->extInput = 0U;
- config->sendMode = PLSR_SEND_COMPLETE;
- config->directionDelayMs = 10U;
- config->directionNegativeLogic = 0U;
- config->curveMode = 0U;
- config->positionMode = PLSR_POSITION_RELATIVE;
- config->segmentCount = 1U;
- config->startSegment = 1U;
- config->defaultSpeedHz = 1000UL;
- config->startSpeedHz = 100UL;
- config->stopSpeedHz = 100UL;
- config->accelerationTimeMs = 100U;
- config->decelerationTimeMs = 100U;
-
- for (index = 0U; index < PLSR_SEGMENT_COUNT_MAX; index++)
- {
- config->segments[index].frequencyHz = 1000UL;
- config->segments[index].pulses = (index == 0U) ? 1000L : 0L;
- config->segments[index].waitType = PLSR_EXT_OR_COMPLETE;
- config->segments[index].waitTimeMs = 0U;
- config->segments[index].actTimeMs = 0U;
- config->segments[index].jumpSegment = 0U;
- }
- }
-
- static uint8_t PlsrConfigIsValid(const PLSR_CONFIG *config,
- uint8_t validateActivePath)
- {
- uint8_t index;
-
- if ((config->pulseOutput > 3U) || (config->directionOutput > 3U)
- || (config->waitInput > 1U) || (config->extInput > 1U)
- || (config->sendMode > PLSR_SEND_SUBSEQUENT)
- || (config->directionNegativeLogic > 1U)
- || (config->curveMode > 2U)
- || (config->positionMode > PLSR_POSITION_ABSOLUTE)
- || (config->segmentCount == 0U)
- || (config->segmentCount > PLSR_SEGMENT_COUNT_MAX)
- || (config->startSegment == 0U)
- || (config->startSegment > PLSR_SEGMENT_COUNT_MAX)
- || (config->defaultSpeedHz == 0UL)
- || (config->defaultSpeedHz > PLSR_FREQUENCY_MAX_HZ)
- || (config->startSpeedHz > PLSR_FREQUENCY_MAX_HZ)
- || (config->stopSpeedHz > PLSR_FREQUENCY_MAX_HZ))
- {
- return 0U;
- }
-
- if ((validateActivePath != 0U)
- && (config->startSegment > config->segmentCount))
- {
- return 0U;
- }
-
- for (index = 0U; index < PLSR_SEGMENT_COUNT_MAX; index++)
- {
- const PLSR_SEGMENT_CONFIG *segment = &config->segments[index];
-
- if ((segment->frequencyHz == 0UL)
- || (segment->frequencyHz > PLSR_FREQUENCY_MAX_HZ)
- || (segment->waitType > PLSR_EXT_OR_COMPLETE)
- || (segment->jumpSegment > PLSR_SEGMENT_COUNT_MAX))
- {
- return 0U;
- }
-
- if ((validateActivePath != 0U)
- && (index < config->segmentCount)
- && (segment->jumpSegment > config->segmentCount))
- {
- return 0U;
- }
- }
-
- return 1U;
- }
-
- static uint16_t PlsrReadConfigWord(const PLSR_CONFIG *config,
- uint16_t address)
- {
- uint16_t offset;
- uint8_t segmentIndex;
- const PLSR_SEGMENT_CONFIG *segment;
-
- switch (address)
- {
- case 0x1000U: return config->pulseOutput;
- case 0x1001U: return config->directionOutput;
- case 0x1002U: return config->waitInput;
- case 0x1003U: return config->extInput;
- case 0x1004U: return config->sendMode;
- case 0x1005U: return config->directionDelayMs;
- case 0x1006U: return config->directionNegativeLogic;
- case 0x1007U: return config->curveMode;
- case 0x1008U: return config->positionMode;
- case 0x1009U: return config->segmentCount;
- case 0x100AU: return config->startSegment;
- case 0x100BU: return PlsrLowWord(config->defaultSpeedHz);
- case 0x100CU: return PlsrHighWord(config->defaultSpeedHz);
- case 0x100DU: return PlsrLowWord(config->startSpeedHz);
- case 0x100EU: return PlsrHighWord(config->startSpeedHz);
- case 0x1010U: return PlsrLowWord(config->stopSpeedHz);
- case 0x1011U: return PlsrHighWord(config->stopSpeedHz);
- case 0x1012U: return config->accelerationTimeMs;
- case 0x1013U: return config->decelerationTimeMs;
- default: break;
- }
-
- if ((address >= PLSR_SEGMENT_FIRST_ADDRESS)
- && (address <= PLSR_CONFIG_LAST_ADDRESS))
- {
- offset = (uint16_t)(address - PLSR_SEGMENT_FIRST_ADDRESS);
- segmentIndex = (uint8_t)(offset / PLSR_SEGMENT_STRIDE);
- offset = (uint16_t)(offset % PLSR_SEGMENT_STRIDE);
- segment = &config->segments[segmentIndex];
-
- switch (offset)
- {
- case 0U: return PlsrLowWord(segment->frequencyHz);
- case 1U: return PlsrHighWord(segment->frequencyHz);
- case 2U: return PlsrLowWord((uint32_t)segment->pulses);
- case 3U: return PlsrHighWord((uint32_t)segment->pulses);
- case 4U: return segment->waitType;
- case 5U: return segment->waitTimeMs;
- case 6U: return segment->actTimeMs;
- case 7U: return segment->jumpSegment;
- default: return 0U;
- }
- }
-
- /* 0x100F, 0x1014..0x10FF, and segment padding read as zero. */
- return 0U;
- }
-
- static PLSR_WORD_RESULT PlsrWriteConfigWord(PLSR_CONFIG *config,
- uint16_t address,
- uint16_t value)
- {
- uint16_t offset;
- uint8_t segmentIndex;
- PLSR_SEGMENT_CONFIG *segment;
-
- switch (address)
- {
- case 0x1000U: config->pulseOutput = value; return PLSR_WORD_OK;
- case 0x1001U: config->directionOutput = value; return PLSR_WORD_OK;
- case 0x1002U: config->waitInput = value; return PLSR_WORD_OK;
- case 0x1003U: config->extInput = value; return PLSR_WORD_OK;
- case 0x1004U: config->sendMode = value; return PLSR_WORD_OK;
- case 0x1005U: config->directionDelayMs = value; return PLSR_WORD_OK;
- case 0x1006U:
- config->directionNegativeLogic = value;
- return PLSR_WORD_OK;
- case 0x1007U: config->curveMode = value; return PLSR_WORD_OK;
- case 0x1008U: config->positionMode = value; return PLSR_WORD_OK;
- case 0x1009U: config->segmentCount = value; return PLSR_WORD_OK;
- case 0x100AU: config->startSegment = value; return PLSR_WORD_OK;
- case 0x100BU:
- config->defaultSpeedHz =
- PlsrJoinU32(value, PlsrHighWord(config->defaultSpeedHz));
- return PLSR_WORD_OK;
- case 0x100CU:
- config->defaultSpeedHz =
- PlsrJoinU32(PlsrLowWord(config->defaultSpeedHz), value);
- return PLSR_WORD_OK;
- case 0x100DU:
- config->startSpeedHz =
- PlsrJoinU32(value, PlsrHighWord(config->startSpeedHz));
- return PLSR_WORD_OK;
- case 0x100EU:
- config->startSpeedHz =
- PlsrJoinU32(PlsrLowWord(config->startSpeedHz), value);
- return PLSR_WORD_OK;
- case 0x100FU:
- return (value == 0U) ? PLSR_WORD_OK : PLSR_WORD_ILLEGAL_VALUE;
- case 0x1010U:
- config->stopSpeedHz =
- PlsrJoinU32(value, PlsrHighWord(config->stopSpeedHz));
- return PLSR_WORD_OK;
- case 0x1011U:
- config->stopSpeedHz =
- PlsrJoinU32(PlsrLowWord(config->stopSpeedHz), value);
- return PLSR_WORD_OK;
- case 0x1012U:
- config->accelerationTimeMs = value;
- return PLSR_WORD_OK;
- case 0x1013U:
- config->decelerationTimeMs = value;
- return PLSR_WORD_OK;
- default: break;
- }
-
- if ((address >= 0x1014U) && (address <= PLSR_COMMON_LAST_ADDRESS))
- {
- return (value == 0U) ? PLSR_WORD_OK : PLSR_WORD_ILLEGAL_VALUE;
- }
-
- if ((address < PLSR_SEGMENT_FIRST_ADDRESS)
- || (address > PLSR_CONFIG_LAST_ADDRESS))
- {
- return PLSR_WORD_ILLEGAL_ADDRESS;
- }
-
- offset = (uint16_t)(address - PLSR_SEGMENT_FIRST_ADDRESS);
- segmentIndex = (uint8_t)(offset / PLSR_SEGMENT_STRIDE);
- offset = (uint16_t)(offset % PLSR_SEGMENT_STRIDE);
- segment = &config->segments[segmentIndex];
-
- switch (offset)
- {
- case 0U:
- segment->frequencyHz =
- PlsrJoinU32(value, PlsrHighWord(segment->frequencyHz));
- return PLSR_WORD_OK;
- case 1U:
- segment->frequencyHz =
- PlsrJoinU32(PlsrLowWord(segment->frequencyHz), value);
- return PLSR_WORD_OK;
- case 2U:
- segment->pulses = (int32_t)PlsrJoinU32(
- value, PlsrHighWord((uint32_t)segment->pulses));
- return PLSR_WORD_OK;
- case 3U:
- segment->pulses = (int32_t)PlsrJoinU32(
- PlsrLowWord((uint32_t)segment->pulses), value);
- return PLSR_WORD_OK;
- case 4U: segment->waitType = value; return PLSR_WORD_OK;
- case 5U: segment->waitTimeMs = value; return PLSR_WORD_OK;
- case 6U: segment->actTimeMs = value; return PLSR_WORD_OK;
- case 7U: segment->jumpSegment = value; return PLSR_WORD_OK;
- default:
- return (value == 0U) ? PLSR_WORD_OK : PLSR_WORD_ILLEGAL_VALUE;
- }
- }
-
- static uint8_t PlsrAddressIsDwordHalf(uint16_t address,
- uint16_t *pairedAddress)
- {
- uint16_t offset;
-
- switch (address)
- {
- case 0x100BU: case 0x100DU: case 0x1010U:
- *pairedAddress = (uint16_t)(address + 1U);
- return 1U;
- case 0x100CU: case 0x100EU: case 0x1011U:
- *pairedAddress = (uint16_t)(address - 1U);
- return 1U;
- default: break;
- }
-
- if ((address >= PLSR_SEGMENT_FIRST_ADDRESS)
- && (address <= PLSR_CONFIG_LAST_ADDRESS))
- {
- offset = (uint16_t)((address - PLSR_SEGMENT_FIRST_ADDRESS)
- % PLSR_SEGMENT_STRIDE);
- if ((offset == 0U) || (offset == 2U))
- {
- *pairedAddress = (uint16_t)(address + 1U);
- return 1U;
- }
- if ((offset == 1U) || (offset == 3U))
- {
- *pairedAddress = (uint16_t)(address - 1U);
- return 1U;
- }
- }
-
- return 0U;
- }
-
- static uint8_t PlsrAddressIsProduct(uint16_t address)
- {
- return (((address >= PLSR_CONFIG_FIRST_ADDRESS)
- && (address <= PLSR_CONFIG_LAST_ADDRESS))
- || ((address >= PLSR_STATUS_FIRST_ADDRESS)
- && (address <= PLSR_STATUS_LAST_ADDRESS))
- || (address == PLSR_CONTROL_ADDRESS)) ? 1U : 0U;
- }
-
- static PLSR_MB_RESULT PlsrClassifyRange(uint16_t startAddress,
- uint16_t quantity)
- {
- uint32_t address;
- uint32_t endAddress;
- uint8_t foundProduct = 0U;
- uint8_t foundOther = 0U;
-
- if (quantity == 0U)
- {
- return PLSR_MB_ILLEGAL_VALUE;
- }
-
- endAddress = (uint32_t)startAddress + (uint32_t)quantity - 1UL;
- if (endAddress > 0xFFFFUL)
- {
- return PLSR_MB_ILLEGAL_ADDRESS;
- }
-
- for (address = startAddress; address <= endAddress; address++)
- {
- if (PlsrAddressIsProduct((uint16_t)address) != 0U)
- {
- foundProduct = 1U;
- }
- else
- {
- foundOther = 1U;
- }
- }
-
- if (foundProduct == 0U)
- {
- return PLSR_MB_NOT_HANDLED;
- }
- return (foundOther != 0U) ? PLSR_MB_ILLEGAL_ADDRESS : PLSR_MB_OK;
- }
-
- static uint32_t PlsrCurveProgressQ16(uint32_t elapsed,
- uint32_t duration,
- uint16_t curveMode)
- {
- uint32_t linear;
-
- if ((duration == 0UL) || (elapsed >= duration))
- {
- return 65535UL;
- }
-
- linear = (uint32_t)(((uint64_t)elapsed * 65535UL) / duration);
- if (curveMode == 1U)
- {
- uint64_t x = linear;
- uint64_t x2 = (x * x) / 65535UL;
- return (uint32_t)((x2 * (196605UL - 2UL * x)) / 65535UL);
- }
- if (curveMode == 2U)
- {
- uint32_t scaled = linear * 64UL;
- uint32_t index = scaled / 65535UL;
- uint32_t fraction = scaled % 65535UL;
- uint32_t first;
- uint32_t second;
-
- if (index >= 64UL)
- {
- return 65535UL;
- }
- first = PlsrSineProgressQ16[index];
- second = PlsrSineProgressQ16[index + 1UL];
- return first + (uint32_t)(((uint64_t)(second - first) * fraction)
- / 65535UL);
- }
- return linear;
- }
-
- static uint32_t PlsrRampDurationMs(uint32_t fromHz, uint32_t toHz)
- {
- uint32_t gap;
- uint32_t baseTimeMs;
- uint64_t duration;
-
- if (fromHz == toHz)
- {
- return 0UL;
- }
- gap = (fromHz > toHz) ? (fromHz - toHz) : (toHz - fromHz);
- baseTimeMs = (toHz > fromHz) ? PlsrActiveConfig.accelerationTimeMs
- : PlsrActiveConfig.decelerationTimeMs;
- if (baseTimeMs == 0UL)
- {
- return 0UL;
- }
-
- duration = ((uint64_t)gap * baseTimeMs
- + PlsrActiveConfig.defaultSpeedHz - 1UL)
- / PlsrActiveConfig.defaultSpeedHz;
- if (duration > 0xFFFFFFFFUL)
- {
- return 0xFFFFFFFFUL;
- }
- return (uint32_t)duration;
- }
-
- static void PlsrRampStart(uint32_t fromHz, uint32_t toHz)
- {
- PlsrRamp.fromHz = fromHz;
- PlsrRamp.toHz = toHz;
- PlsrRamp.durationMs = PlsrRampDurationMs(fromHz, toHz);
- PlsrRamp.elapsedMs = 0UL;
- PlsrRamp.active = (PlsrRamp.durationMs != 0UL) ? 1U : 0U;
-
- if (toHz > fromHz)
- {
- PlsrRunStatus = PLSR_STATUS_ACCELERATING;
- }
- else if (toHz < fromHz)
- {
- PlsrRunStatus = PLSR_STATUS_DECELERATING;
- }
- else
- {
- PlsrRunStatus = PLSR_STATUS_RUNNING;
- }
- }
-
- static uint8_t PlsrApplyFrequencyPair(uint32_t requestedFirstFrequencyHz,
- uint32_t requestedQueuedFrequencyHz,
- uint32_t expectedEpoch)
- {
- uint32_t criticalState;
- uint32_t actualFirstFrequencyHz;
- uint32_t actualQueuedFrequencyHz;
- uint32_t hardwareFirstFrequencyHz = requestedFirstFrequencyHz;
- uint32_t hardwareQueuedFrequencyHz = requestedQueuedFrequencyHz;
- PLSR_HANDOFF_PLAN candidatePlan;
- uint8_t haveCandidatePlan = 0U;
-
- criticalState = PlsrPlatformEnterCritical();
- if ((PlsrSegmentEpoch != expectedEpoch)
- || (PlsrBoundaryPending != 0U) || (PlsrRemainingPulses == 0UL))
- {
- PlsrPlatformExitCritical(criticalState);
- return 1U;
- }
-
- if (hardwareFirstFrequencyHz == 0UL)
- {
- if (PlsrPulseActive == 0U)
- {
- PlsrCurrentFrequencyHz = 0UL;
- PlsrQueuedFrequencyHz = 0UL;
- PlsrPlatformExitCritical(criticalState);
- return 1U;
- }
- hardwareFirstFrequencyHz = 1UL;
- }
- if (hardwareQueuedFrequencyHz == 0UL)
- {
- hardwareQueuedFrequencyHz = 1UL;
- }
-
- if (PlsrPulseActive != 0U)
- {
- if (PlsrHandoffPlan.valid != 0U)
- {
- PlsrPlatformExitCritical(criticalState);
- return 1U;
- }
- PlsrDeferredFrequencyHz = hardwareQueuedFrequencyHz;
- PlsrDeferredFrequencyPending = 1U;
- PlsrPlatformExitCritical(criticalState);
- return 1U;
- }
- else
- {
- if (PlsrSelectPreparedHandoffPlan(&candidatePlan) != 0U)
- {
- hardwareQueuedFrequencyHz = candidatePlan.firstFrequencyHz;
- haveCandidatePlan = 1U;
- }
- if (PlsrPlatformStartPulse((uint8_t)PlsrActiveConfig.pulseOutput,
- hardwareFirstFrequencyHz,
- hardwareQueuedFrequencyHz,
- &actualFirstFrequencyHz,
- &actualQueuedFrequencyHz) == 0U)
- {
- PlsrPlatformExitCritical(criticalState);
- return 0U;
- }
- PlsrPulseActive = 1U;
- PlsrCurrentFrequencyHz = actualFirstFrequencyHz;
- PlsrHandoffPlan.valid = 0U;
- if (haveCandidatePlan != 0U)
- {
- PlsrHandoffPlan.magnitude = candidatePlan.magnitude;
- PlsrHandoffPlan.firstFrequencyHz = actualQueuedFrequencyHz;
- PlsrCopyShortProfile(&PlsrHandoffPlan.profile,
- &candidatePlan.profile);
- PlsrHandoffPlan.nextSegment = candidatePlan.nextSegment;
- PlsrHandoffPlan.positive = candidatePlan.positive;
- PlsrHandoffPlan.valid = 1U;
- }
- }
-
- PlsrQueuedFrequencyHz = actualQueuedFrequencyHz;
- PlsrPlatformExitCritical(criticalState);
- return 1U;
- }
-
- static uint8_t PlsrApplyFrequency(uint32_t requestedFrequencyHz,
- uint32_t expectedEpoch)
- {
- return PlsrApplyFrequencyPair(requestedFrequencyHz,
- requestedFrequencyHz,
- expectedEpoch);
- }
-
- static uint8_t PlsrStopDrainPulseCount(void)
- {
- uint8_t deferredPending = PlsrDeferredFrequencyPending;
- uint32_t deferredFrequencyHz = PlsrDeferredFrequencyHz;
- uint32_t queuedFrequencyHz = PlsrQueuedFrequencyHz;
- uint32_t currentFrequencyHz = PlsrCurrentFrequencyHz;
-
- if ((deferredPending != 0U)
- && (deferredFrequencyHz != queuedFrequencyHz))
- {
- return 3U;
- }
- PlsrDeferredFrequencyPending = 0U;
- return (currentFrequencyHz == queuedFrequencyHz) ? 1U : 2U;
- }
-
- static uint8_t PlsrCommitDeferredFrequency(uint8_t pulseOutput)
- {
- uint32_t requestedFrequencyHz;
- uint32_t actualFrequencyHz;
-
- if (PlsrDeferredFrequencyPending == 0U)
- {
- return 1U;
- }
- requestedFrequencyHz = PlsrDeferredFrequencyHz;
- PlsrDeferredFrequencyPending = 0U;
- if (PlsrPlatformQueueFrequency(pulseOutput, requestedFrequencyHz,
- &actualFrequencyHz) == 0U)
- {
- return 0U;
- }
- PlsrQueuedFrequencyHz = actualFrequencyHz;
- return 1U;
- }
-
- static uint8_t PlsrRampAdvance(uint32_t expectedEpoch)
- {
- uint32_t progress;
- uint32_t frequency;
- uint32_t gap;
- uint32_t criticalState;
- uint32_t fromHz;
- uint32_t toHz;
- uint32_t durationMs;
- uint32_t elapsedMs;
-
- criticalState = PlsrPlatformEnterCritical();
- if ((PlsrSegmentEpoch != expectedEpoch) || (PlsrRamp.active == 0U))
- {
- PlsrPlatformExitCritical(criticalState);
- return 1U;
- }
- PlsrRamp.elapsedMs++;
- fromHz = PlsrRamp.fromHz;
- toHz = PlsrRamp.toHz;
- durationMs = PlsrRamp.durationMs;
- elapsedMs = PlsrRamp.elapsedMs;
- PlsrPlatformExitCritical(criticalState);
-
- progress = PlsrCurveProgressQ16(elapsedMs,
- durationMs,
- PlsrActiveConfig.curveMode);
- if (toHz >= fromHz)
- {
- gap = toHz - fromHz;
- frequency = fromHz
- + (uint32_t)(((uint64_t)gap * progress) / 65535UL);
- }
- else
- {
- gap = fromHz - toHz;
- frequency = fromHz
- - (uint32_t)(((uint64_t)gap * progress) / 65535UL);
- }
-
- if (PlsrApplyFrequency(frequency, expectedEpoch) == 0U)
- {
- return 0U;
- }
-
- criticalState = PlsrPlatformEnterCritical();
- if (PlsrSegmentEpoch != expectedEpoch)
- {
- PlsrPlatformExitCritical(criticalState);
- return 1U;
- }
- if (elapsedMs >= durationMs)
- {
- PlsrRamp.active = 0U;
- if (PlsrStopRequested == 0U)
- {
- PlsrRunStatus = PLSR_STATUS_RUNNING;
- }
- else
- {
- PlsrStopPulsesRemaining = PlsrStopDrainPulseCount();
- }
- }
- PlsrPlatformExitCritical(criticalState);
- return 1U;
- }
-
- static uint8_t PlsrGetNextSegment(uint8_t *nextSegment)
- {
- const PLSR_SEGMENT_CONFIG *segment =
- &PlsrActiveConfig.segments[PlsrCurrentSegment - 1U];
-
- if (segment->jumpSegment != 0U)
- {
- *nextSegment = (uint8_t)segment->jumpSegment;
- return 1U;
- }
- if (PlsrCurrentSegment < PlsrActiveConfig.segmentCount)
- {
- *nextSegment = (uint8_t)(PlsrCurrentSegment + 1U);
- return 1U;
- }
- return 0U;
- }
-
- static int64_t PlsrSegmentDisplacement(uint8_t segmentNumber,
- int32_t referencePosition)
- {
- int32_t configured =
- PlsrActiveConfig.segments[segmentNumber - 1U].pulses;
-
- if (PlsrActiveConfig.positionMode == PLSR_POSITION_ABSOLUTE)
- {
- return (int64_t)configured - (int64_t)referencePosition;
- }
- return configured;
- }
-
- static uint8_t PlsrPredictNextDirection(uint8_t nextSegment,
- uint8_t *positive)
- {
- uint32_t criticalState;
- uint64_t remaining;
- int32_t position;
- uint32_t predictedBits;
- int32_t predictedPosition;
- int64_t displacement;
-
- criticalState = PlsrPlatformEnterCritical();
- remaining = PlsrRemainingPulses;
- position = PlsrPosition;
- PlsrPlatformExitCritical(criticalState);
-
- predictedBits = (uint32_t)position;
- if (PlsrCountPositive != 0U)
- {
- predictedBits += (uint32_t)remaining;
- }
- else
- {
- predictedBits -= (uint32_t)remaining;
- }
- predictedPosition = (int32_t)predictedBits;
- displacement = PlsrSegmentDisplacement(nextSegment, predictedPosition);
- if (displacement == 0)
- {
- return 0U;
- }
- *positive = (displacement > 0) ? 1U : 0U;
- return 1U;
- }
-
- static uint64_t PlsrRemainingSnapshot(void)
- {
- uint32_t criticalState = PlsrPlatformEnterCritical();
- uint64_t remaining = PlsrRemainingPulses;
- PlsrPlatformExitCritical(criticalState);
- return remaining;
- }
-
- static uint64_t PlsrRampPulseEstimate(uint32_t fromHz, uint32_t toHz)
- {
- uint32_t duration = PlsrRampDurationMs(fromHz, toHz);
- uint64_t sum = (uint64_t)fromHz + toHz;
-
- return (sum * duration + 1999UL) / 2000UL + 2UL;
- }
-
- static uint16_t PlsrShortProfileRampTime(uint32_t fromHz, uint32_t toHz)
- {
- if (toHz > fromHz)
- {
- return PlsrActiveConfig.accelerationTimeMs;
- }
- if (toHz < fromHz)
- {
- return PlsrActiveConfig.decelerationTimeMs;
- }
- return 0U;
- }
-
- static uint64_t PlsrShortProfileRampWeight(uint32_t fromHz,
- uint32_t toHz,
- uint16_t timeMs)
- {
- uint64_t fromSquared = (uint64_t)fromHz * fromHz;
- uint64_t toSquared = (uint64_t)toHz * toHz;
- uint64_t difference = (fromSquared > toSquared)
- ? (fromSquared - toSquared)
- : (toSquared - fromSquared);
-
- return difference * timeMs;
- }
-
- static uint32_t PlsrIntegerSquareRoot(uint64_t value)
- {
- uint64_t bit = (uint64_t)1U << 62U;
- uint64_t root = 0UL;
-
- while (bit > value)
- {
- bit >>= 2U;
- }
- while (bit != 0UL)
- {
- if (value >= (root + bit))
- {
- value -= root + bit;
- root = (root >> 1U) + bit;
- }
- else
- {
- root >>= 1U;
- }
- bit >>= 2U;
- }
- return (uint32_t)root;
- }
-
- static uint32_t PlsrShortProfilePeak(uint32_t startHz,
- uint32_t targetHz,
- uint32_t endHz,
- uint16_t pulseCount)
- {
- uint32_t upperEndpoint = (startHz > endHz) ? startHz : endHz;
- uint32_t lowerEndpoint = (startHz < endHz) ? startHz : endHz;
- uint16_t entryTime;
- uint16_t exitTime;
- uint32_t timeSum;
- uint64_t weightedEndpoints;
- uint64_t availableArea;
- uint64_t peakSquared;
- uint32_t peakHz;
-
- if (targetHz > upperEndpoint)
- {
- entryTime = PlsrShortProfileRampTime(startHz, targetHz);
- exitTime = PlsrShortProfileRampTime(targetHz, endHz);
- timeSum = (uint32_t)entryTime + exitTime;
- if (timeSum == 0UL)
- {
- return targetHz;
- }
- weightedEndpoints = ((uint64_t)startHz * startHz * entryTime)
- + ((uint64_t)endHz * endHz * exitTime);
- availableArea = (uint64_t)2U * pulseCount
- * PlsrActiveConfig.defaultSpeedHz * 1000UL;
- peakSquared = (availableArea + weightedEndpoints) / timeSum;
- peakHz = PlsrIntegerSquareRoot(peakSquared);
- if (peakHz < upperEndpoint)
- {
- peakHz = upperEndpoint;
- }
- if (peakHz > targetHz)
- {
- peakHz = targetHz;
- }
- return peakHz;
- }
-
- if (targetHz < lowerEndpoint)
- {
- entryTime = PlsrShortProfileRampTime(startHz, targetHz);
- exitTime = PlsrShortProfileRampTime(targetHz, endHz);
- timeSum = (uint32_t)entryTime + exitTime;
- if (timeSum == 0UL)
- {
- return targetHz;
- }
- weightedEndpoints = ((uint64_t)startHz * startHz * entryTime)
- + ((uint64_t)endHz * endHz * exitTime);
- availableArea = (uint64_t)2U * pulseCount
- * PlsrActiveConfig.defaultSpeedHz * 1000UL;
- if (availableArea >= weightedEndpoints)
- {
- return targetHz;
- }
- peakSquared = (weightedEndpoints - availableArea) / timeSum;
- peakHz = PlsrIntegerSquareRoot(peakSquared);
- if (peakHz < targetHz)
- {
- peakHz = targetHz;
- }
- if (peakHz > lowerEndpoint)
- {
- peakHz = lowerEndpoint;
- }
- return peakHz;
- }
-
- return targetHz;
- }
-
- static uint64_t PlsrShortProfileRequiredSteps(uint64_t rampWeight)
- {
- uint64_t denominator = (uint64_t)2U
- * PlsrActiveConfig.defaultSpeedHz * 1000UL;
-
- if (rampWeight == 0UL)
- {
- return 0UL;
- }
- return (rampWeight + denominator - 1UL) / denominator;
- }
-
- static uint32_t PlsrShortProfileReachableFrequency(uint32_t fromHz,
- uint32_t towardHz,
- uint16_t pulseCount)
- {
- uint16_t baseTime = PlsrShortProfileRampTime(fromHz, towardHz);
- uint64_t frequencySquared = (uint64_t)fromHz * fromHz;
- uint64_t changeSquared;
- uint32_t reachableHz;
-
- if ((baseTime == 0U) || (fromHz == towardHz))
- {
- return towardHz;
- }
- changeSquared = (uint64_t)2U * pulseCount
- * PlsrActiveConfig.defaultSpeedHz * 1000UL / baseTime;
- if (towardHz > fromHz)
- {
- reachableHz = PlsrIntegerSquareRoot(frequencySquared + changeSquared);
- return (reachableHz > towardHz) ? towardHz : reachableHz;
- }
-
- frequencySquared = (changeSquared >= frequencySquared)
- ? 0UL : (frequencySquared - changeSquared);
- reachableHz = PlsrIntegerSquareRoot(frequencySquared);
- if (((uint64_t)reachableHz * reachableHz) < frequencySquared)
- {
- reachableHz++;
- }
- return (reachableHz < towardHz) ? towardHz : reachableHz;
- }
-
- static uint64_t PlsrCurveIntegralQ32(uint64_t progressQ32,
- uint16_t curveMode)
- {
- uint64_t scaled;
- uint32_t index;
- uint32_t fraction;
- uint64_t first;
- uint64_t second;
- const uint32_t *table;
-
- if (progressQ32 >= PLSR_Q32_ONE)
- {
- return PLSR_Q32_ONE / 2ULL;
- }
- if (curveMode == 0U)
- {
- return (progressQ32 * progressQ32) >> 33U;
- }
-
- table = (curveMode == 1U) ? PlsrSmoothIntegralQ24
- : PlsrSineIntegralQ24;
- scaled = progressQ32 * 64ULL;
- index = (uint32_t)(scaled >> 32U);
- fraction = (uint32_t)scaled;
- first = (uint64_t)table[index] << 8U;
- second = (uint64_t)table[index + 1UL] << 8U;
- return first + (((second - first) * fraction) >> 32U);
- }
-
- static uint64_t PlsrRampAreaQ32(uint32_t fromHz,
- uint32_t toHz,
- uint64_t progressQ32)
- {
- int64_t delta = (int64_t)toHz - (int64_t)fromHz;
- int64_t area = (int64_t)((uint64_t)fromHz * progressQ32)
- + delta * (int64_t)PlsrCurveIntegralQ32(
- progressQ32, PlsrActiveConfig.curveMode);
- return (uint64_t)area;
- }
-
- static uint32_t PlsrRampInstantFrequency(uint32_t fromHz,
- uint32_t toHz,
- uint64_t progressQ32)
- {
- uint64_t curveProgressQ32;
- uint64_t scaled;
- uint32_t index;
- uint32_t tableSlopeQ32;
- uint32_t gap;
- const uint32_t *integralTable;
-
- if (progressQ32 >= PLSR_Q32_ONE)
- {
- return toHz;
- }
- if (PlsrActiveConfig.curveMode != 0U)
- {
- scaled = progressQ32 * 64ULL;
- index = (uint32_t)(scaled >> 32U);
- integralTable = (PlsrActiveConfig.curveMode == 1U)
- ? PlsrSmoothIntegralQ24
- : PlsrSineIntegralQ24;
- tableSlopeQ32 =
- (integralTable[index + 1UL] - integralTable[index]) << 14U;
- curveProgressQ32 = tableSlopeQ32;
- }
- else
- {
- curveProgressQ32 = progressQ32;
- }
-
- if (toHz >= fromHz)
- {
- gap = toHz - fromHz;
- return fromHz
- + (uint32_t)(((uint64_t)gap * curveProgressQ32) >> 32U);
- }
- gap = fromHz - toHz;
- return fromHz
- - (uint32_t)(((uint64_t)gap * curveProgressQ32) >> 32U);
- }
-
- static uint64_t PlsrExactRampBoundaryQ32(uint32_t fromHz,
- uint32_t toHz,
- uint64_t previousBoundaryQ32,
- uint64_t targetAreaQ32)
- {
- uint64_t lowerQ32 = previousBoundaryQ32;
- uint64_t upperQ32 = PLSR_Q32_ONE;
- uint64_t middleQ32;
- uint32_t iteration;
-
- /* The Q32 domain is 2^32 units wide, so 32 fixed bisections are exact. */
- for (iteration = 0UL; iteration < 32UL; iteration++)
- {
- middleQ32 = lowerQ32 + ((upperQ32 - lowerQ32) >> 1U);
- if (PlsrRampAreaQ32(fromHz, toHz, middleQ32) < targetAreaQ32)
- {
- lowerQ32 = middleQ32;
- }
- else
- {
- upperQ32 = middleQ32;
- }
- }
- return upperQ32;
- }
-
- static uint32_t PlsrCountLeadingZeros32(uint32_t value)
- {
- #if defined(__ICCARM__)
- return __CLZ(value);
- #else
- uint32_t count = 0U;
-
- if ((value & 0xFFFF0000UL) == 0UL)
- {
- count += 16U;
- value <<= 16U;
- }
- if ((value & 0xFF000000UL) == 0UL)
- {
- count += 8U;
- value <<= 8U;
- }
- if ((value & 0xF0000000UL) == 0UL)
- {
- count += 4U;
- value <<= 4U;
- }
- if ((value & 0xC0000000UL) == 0UL)
- {
- count += 2U;
- value <<= 2U;
- }
- if ((value & 0x80000000UL) == 0UL)
- {
- count++;
- }
- return count;
- #endif
- }
-
- static uint32_t PlsrDivideU64Low(uint32_t highWord,
- uint32_t lowWord,
- uint32_t divisor,
- uint32_t *remainder)
- {
- const uint32_t halfBase = 0x10000UL;
- uint32_t shift = PlsrCountLeadingZeros32(divisor);
- uint32_t normalizedDivisor = divisor << shift;
- uint32_t divisorHigh = normalizedDivisor >> 16U;
- uint32_t divisorLow = normalizedDivisor & 0xFFFFUL;
- uint32_t normalizedHigh;
- uint32_t normalizedLow = lowWord << shift;
- uint32_t lowHigh = normalizedLow >> 16U;
- uint32_t lowLow = normalizedLow & 0xFFFFUL;
- uint32_t quotientHigh;
- uint32_t quotientLow;
- uint32_t partialRemainder;
- uint32_t middle;
- uint32_t normalizedRemainder;
-
- if (shift == 0U)
- {
- normalizedHigh = highWord;
- }
- else
- {
- normalizedHigh = (highWord << shift)
- | (lowWord >> (32U - shift));
- }
-
- quotientHigh = normalizedHigh / divisorHigh;
- partialRemainder = normalizedHigh - quotientHigh * divisorHigh;
- while ((quotientHigh >= halfBase)
- || (quotientHigh * divisorLow
- > (partialRemainder << 16U) + lowHigh))
- {
- quotientHigh--;
- partialRemainder += divisorHigh;
- if (partialRemainder >= halfBase)
- {
- break;
- }
- }
-
- middle = normalizedHigh * halfBase + lowHigh
- - quotientHigh * normalizedDivisor;
- quotientLow = middle / divisorHigh;
- partialRemainder = middle - quotientLow * divisorHigh;
- while ((quotientLow >= halfBase)
- || (quotientLow * divisorLow
- > (partialRemainder << 16U) + lowLow))
- {
- quotientLow--;
- partialRemainder += divisorHigh;
- if (partialRemainder >= halfBase)
- {
- break;
- }
- }
-
- normalizedRemainder = middle * halfBase + lowLow
- - quotientLow * normalizedDivisor;
- if (remainder != NULL)
- {
- *remainder = normalizedRemainder >> shift;
- }
- return quotientHigh * halfBase + quotientLow;
- }
-
- static uint64_t PlsrDivideU64ByU32(uint64_t dividend,
- uint32_t divisor,
- uint32_t *remainder)
- {
- uint32_t highWord = (uint32_t)(dividend >> 32U);
- uint32_t lowWord = (uint32_t)dividend;
- uint32_t quotientHigh = highWord / divisor;
- uint32_t highRemainder = highWord - quotientHigh * divisor;
- uint32_t quotientLow = PlsrDivideU64Low(highRemainder, lowWord,
- divisor, remainder);
-
- return ((uint64_t)quotientHigh << 32U) | quotientLow;
- }
-
- static void PlsrPrepareShortProfileBoundaries(PLSR_SHORT_PROFILE *profile)
- {
- uint64_t totalAreaQ32;
- uint64_t areaStepQ32;
- uint64_t targetAreaQ32;
- uint32_t areaRemainder;
-
- if (profile->entryPulses != 0U)
- {
- totalAreaQ32 = PlsrRampAreaQ32(
- profile->startHz, profile->peakHz, PLSR_Q32_ONE);
- areaStepQ32 = totalAreaQ32 / profile->entryPulses;
- areaRemainder = (uint32_t)(totalAreaQ32 % profile->entryPulses);
- profile->entryFirstBoundaryQ32 = PlsrExactRampBoundaryQ32(
- profile->startHz, profile->peakHz, 0ULL, areaStepQ32);
- if (profile->entryPulses > 1U)
- {
- targetAreaQ32 = areaStepQ32 * 2ULL
- + (((uint64_t)areaRemainder * 2ULL)
- / profile->entryPulses);
- profile->entrySecondBoundaryQ32 = PlsrExactRampBoundaryQ32(
- profile->startHz, profile->peakHz,
- profile->entryFirstBoundaryQ32, targetAreaQ32);
- }
- }
- if (profile->exitPulses != 0U)
- {
- totalAreaQ32 = PlsrRampAreaQ32(
- profile->peakHz, profile->endHz, PLSR_Q32_ONE);
- areaStepQ32 = totalAreaQ32 / profile->exitPulses;
- areaRemainder = (uint32_t)(totalAreaQ32 % profile->exitPulses);
- profile->exitFirstBoundaryQ32 = PlsrExactRampBoundaryQ32(
- profile->peakHz, profile->endHz, 0ULL, areaStepQ32);
- if (profile->exitPulses > 1U)
- {
- targetAreaQ32 = areaStepQ32 * 2ULL
- + (((uint64_t)areaRemainder * 2ULL)
- / profile->exitPulses);
- profile->exitSecondBoundaryQ32 = PlsrExactRampBoundaryQ32(
- profile->peakHz, profile->endHz,
- profile->exitFirstBoundaryQ32, targetAreaQ32);
- }
- }
- }
-
- static uint64_t PlsrRampBoundaryQ32(uint32_t fromHz,
- uint32_t toHz,
- uint64_t previousBoundaryQ32,
- uint64_t targetAreaQ32,
- uint64_t predictedStepQ32)
- {
- uint64_t currentAreaQ32;
- uint64_t candidateQ32;
- uint64_t candidateAreaQ32;
- uint64_t differenceQ32;
- uint64_t correctionQ32;
- uint32_t derivativeHz;
-
- currentAreaQ32 = (previousBoundaryQ32 == 0ULL)
- ? 0ULL
- : PlsrRampAreaQ32(fromHz, toHz,
- previousBoundaryQ32);
- if (targetAreaQ32 <= currentAreaQ32)
- {
- return previousBoundaryQ32 + 1ULL;
- }
-
- if (predictedStepQ32 != 0ULL)
- {
- if (predictedStepQ32 >= PLSR_Q32_ONE - previousBoundaryQ32)
- {
- candidateQ32 = PLSR_Q32_ONE;
- }
- else
- {
- candidateQ32 = previousBoundaryQ32 + predictedStepQ32;
- }
- }
- else
- {
- derivativeHz = PlsrRampInstantFrequency(fromHz, toHz,
- previousBoundaryQ32);
- if (derivativeHz == 0UL)
- {
- derivativeHz = 1UL;
- }
- differenceQ32 = targetAreaQ32 - currentAreaQ32;
- correctionQ32 =
- PlsrDivideU64ByU32(differenceQ32 + derivativeHz - 1UL,
- derivativeHz, NULL);
- if (correctionQ32 >= PLSR_Q32_ONE - previousBoundaryQ32)
- {
- candidateQ32 = PLSR_Q32_ONE;
- }
- else
- {
- candidateQ32 = previousBoundaryQ32 + correctionQ32;
- }
- }
-
- candidateAreaQ32 = PlsrRampAreaQ32(fromHz, toHz, candidateQ32);
- derivativeHz = PlsrRampInstantFrequency(fromHz, toHz, candidateQ32);
- if (derivativeHz == 0UL)
- {
- derivativeHz = 1UL;
- }
- if (candidateAreaQ32 < targetAreaQ32)
- {
- differenceQ32 = targetAreaQ32 - candidateAreaQ32;
- correctionQ32 =
- PlsrDivideU64ByU32(differenceQ32 + derivativeHz - 1UL,
- derivativeHz, NULL);
- if (correctionQ32 >= PLSR_Q32_ONE - candidateQ32)
- {
- candidateQ32 = PLSR_Q32_ONE;
- }
- else
- {
- candidateQ32 += correctionQ32;
- }
- }
- else if (candidateAreaQ32 > targetAreaQ32)
- {
- differenceQ32 = candidateAreaQ32 - targetAreaQ32;
- correctionQ32 = PlsrDivideU64ByU32(differenceQ32, derivativeHz,
- NULL);
- if (correctionQ32 == 0ULL)
- {
- correctionQ32 = 1ULL;
- }
- if (correctionQ32 >= candidateQ32 - previousBoundaryQ32)
- {
- candidateQ32 = previousBoundaryQ32 + 1ULL;
- }
- else
- {
- candidateQ32 -= correctionQ32;
- }
- }
-
- /* The corrected phase step seeds the next pulse and keeps ISR work fixed. */
- return candidateQ32;
- }
-
- static uint32_t PlsrRampAverageFrequency(uint64_t areaIncrementQ32,
- uint64_t firstBoundaryQ32,
- uint64_t secondBoundaryQ32)
- {
- uint64_t denominator;
- uint64_t frequencyHz;
-
- if (secondBoundaryQ32 <= firstBoundaryQ32)
- {
- return 1UL;
- }
- denominator = secondBoundaryQ32 - firstBoundaryQ32;
- if (denominator == PLSR_Q32_ONE)
- {
- frequencyHz = (areaIncrementQ32 + denominator / 2ULL) >> 32U;
- }
- else
- {
- frequencyHz = PlsrDivideU64ByU32(
- areaIncrementQ32 + denominator / 2ULL,
- (uint32_t)denominator, NULL);
- }
- if (frequencyHz == 0UL)
- {
- return 1UL;
- }
- if (frequencyHz > PLSR_FREQUENCY_MAX_HZ)
- {
- return PLSR_FREQUENCY_MAX_HZ;
- }
- return (uint32_t)frequencyHz;
- }
-
- static uint8_t PlsrPrepareShortProfile(PLSR_SHORT_PROFILE *profile,
- uint8_t segmentNumber,
- uint32_t startFrequencyHz,
- uint32_t targetFrequencyHz,
- uint64_t pulseCount)
- {
- const PLSR_SEGMENT_CONFIG *segment;
- uint32_t endFrequencyHz;
- uint32_t peakFrequencyHz;
- uint16_t entryTime;
- uint16_t exitTime;
- uint16_t totalPulses;
- uint64_t entryWeight;
- uint64_t exitWeight;
- uint64_t entryRequired;
- uint64_t exitRequired;
- uint64_t totalWeight;
- uint64_t scaledEntry;
-
- uint64_t durationWeight;
- uint64_t singleFrequencyHz;
- uint16_t directTime;
- uint64_t directWeight;
- uint64_t directRequired;
-
- (void)memset(profile, 0, sizeof(*profile));
- if ((pulseCount == 0UL)
- || (pulseCount > PLSR_SHORT_PROFILE_MAX_PULSES)
- || (segmentNumber != PlsrActiveConfig.segmentCount))
- {
- return 0U;
- }
-
- segment = &PlsrActiveConfig.segments[segmentNumber - 1U];
- if (segment->jumpSegment != 0U)
- {
- return 0U;
- }
-
- endFrequencyHz = PlsrActiveConfig.stopSpeedHz;
- totalPulses = (uint16_t)pulseCount;
- directTime = PlsrShortProfileRampTime(startFrequencyHz, endFrequencyHz);
- directWeight = PlsrShortProfileRampWeight(startFrequencyHz,
- endFrequencyHz,
- directTime);
- directRequired = PlsrShortProfileRequiredSteps(directWeight);
- if (directRequired > totalPulses)
- {
- profile->startHz = startFrequencyHz;
- profile->peakHz = PlsrShortProfileReachableFrequency(
- startFrequencyHz, endFrequencyHz, totalPulses);
- profile->endHz = profile->peakHz;
- profile->pulseCount = totalPulses;
- profile->entryPulses = totalPulses;
- profile->active = 1U;
- PlsrPrepareShortProfileBoundaries(profile);
- return 1U;
- }
-
- peakFrequencyHz = PlsrShortProfilePeak(startFrequencyHz,
- targetFrequencyHz,
- endFrequencyHz,
- (uint16_t)pulseCount);
- entryTime = PlsrShortProfileRampTime(startFrequencyHz, peakFrequencyHz);
- exitTime = PlsrShortProfileRampTime(peakFrequencyHz, endFrequencyHz);
- entryWeight = PlsrShortProfileRampWeight(startFrequencyHz,
- peakFrequencyHz,
- entryTime);
- exitWeight = PlsrShortProfileRampWeight(peakFrequencyHz,
- endFrequencyHz,
- exitTime);
- entryRequired = PlsrShortProfileRequiredSteps(entryWeight);
- exitRequired = PlsrShortProfileRequiredSteps(exitWeight);
- if ((entryRequired == 0UL) && (exitRequired == 0UL))
- {
- return 0U;
- }
-
- profile->startHz = startFrequencyHz;
- profile->peakHz = peakFrequencyHz;
- profile->endHz = endFrequencyHz;
- profile->pulseCount = totalPulses;
-
- if (totalPulses == 1U)
- {
- durationWeight =
- (uint64_t)((peakFrequencyHz > startFrequencyHz)
- ? (peakFrequencyHz - startFrequencyHz)
- : (startFrequencyHz - peakFrequencyHz)) * entryTime
- + (uint64_t)((peakFrequencyHz > endFrequencyHz)
- ? (peakFrequencyHz - endFrequencyHz)
- : (endFrequencyHz - peakFrequencyHz)) * exitTime;
- if (durationWeight == 0UL)
- {
- return 0U;
- }
- singleFrequencyHz =
- ((uint64_t)PlsrActiveConfig.defaultSpeedHz * 1000UL
- + durationWeight / 2UL) / durationWeight;
- if (singleFrequencyHz == 0UL)
- {
- singleFrequencyHz = 1UL;
- }
- if (singleFrequencyHz > PLSR_FREQUENCY_MAX_HZ)
- {
- singleFrequencyHz = PLSR_FREQUENCY_MAX_HZ;
- }
- profile->peakHz = (uint32_t)singleFrequencyHz;
- profile->steadyPulses = 1U;
- profile->active = 1U;
- return 1U;
- }
-
- if ((exitRequired == 0UL) && (peakFrequencyHz != endFrequencyHz))
- {
- exitRequired = 1UL;
- exitWeight = (uint64_t)2U
- * PlsrActiveConfig.defaultSpeedHz * 1000UL;
- }
-
- if ((entryRequired + exitRequired) <= totalPulses)
- {
- profile->entryPulses = (uint16_t)entryRequired;
- profile->exitPulses = (uint16_t)exitRequired;
- profile->steadyPulses =
- (uint16_t)(totalPulses - profile->entryPulses
- - profile->exitPulses);
- }
- else if (entryRequired == 0UL)
- {
- profile->exitPulses = totalPulses;
- }
- else if (exitRequired == 0UL)
- {
- profile->entryPulses = totalPulses;
- }
- else
- {
- totalWeight = entryWeight + exitWeight;
- /* Peak planning bounds both weights by this move's pulse budget. */
- scaledEntry = ((uint64_t)totalPulses * entryWeight
- + totalWeight / 2UL) / totalWeight;
- if (scaledEntry == 0UL)
- {
- scaledEntry = 1UL;
- }
- if (scaledEntry >= totalPulses)
- {
- scaledEntry = totalPulses - 1U;
- }
- profile->entryPulses = (uint16_t)scaledEntry;
- profile->exitPulses =
- (uint16_t)(totalPulses - profile->entryPulses);
- }
-
- profile->active = 1U;
- PlsrPrepareShortProfileBoundaries(profile);
- return 1U;
- }
-
- static uint32_t PlsrShortProfileTakeFrequency(PLSR_SHORT_PROFILE *profile)
- {
- uint16_t period = profile->nextPeriod;
- uint16_t relativePeriod;
- uint16_t rampPulseCount;
- uint32_t fromHz;
- uint32_t toHz;
- uint64_t firstBoundaryQ32;
- uint64_t secondBoundaryQ32;
- uint64_t previousTargetAreaQ32;
- uint64_t areaIncrementQ32;
- uint64_t firstCachedBoundaryQ32;
- uint64_t secondCachedBoundaryQ32;
- uint32_t frequencyHz;
-
- if ((profile->active == 0U) || (period >= profile->pulseCount))
- {
- return (profile->endHz == 0UL) ? 1UL : profile->endHz;
- }
- profile->nextPeriod = (uint16_t)(period + 1U);
-
- if (period < profile->entryPulses)
- {
- relativePeriod = period;
- rampPulseCount = profile->entryPulses;
- fromHz = profile->startHz;
- toHz = profile->peakHz;
- firstCachedBoundaryQ32 = profile->entryFirstBoundaryQ32;
- secondCachedBoundaryQ32 = profile->entrySecondBoundaryQ32;
- firstBoundaryQ32 = (relativePeriod == 0U)
- ? 0ULL : profile->rampBoundaryQ32;
- }
- else if (period < (uint16_t)(profile->entryPulses
- + profile->steadyPulses))
- {
- profile->lastRampFrequencyHz = 0UL;
- return (profile->peakHz == 0UL) ? 1UL : profile->peakHz;
- }
- else
- {
- relativePeriod =
- (uint16_t)(period - profile->entryPulses
- - profile->steadyPulses);
- rampPulseCount = profile->exitPulses;
- fromHz = profile->peakHz;
- toHz = profile->endHz;
- firstCachedBoundaryQ32 = profile->exitFirstBoundaryQ32;
- secondCachedBoundaryQ32 = profile->exitSecondBoundaryQ32;
- firstBoundaryQ32 = (relativePeriod == 0U)
- ? 0ULL : profile->rampBoundaryQ32;
- }
-
- if (relativePeriod == 0U)
- {
- profile->rampTotalAreaQ32 =
- PlsrRampAreaQ32(fromHz, toHz, PLSR_Q32_ONE);
- profile->rampAreaStepQ32 =
- PlsrDivideU64ByU32(profile->rampTotalAreaQ32,
- rampPulseCount,
- &profile->rampAreaRemainder);
- profile->rampRemainderAccumulator = 0UL;
- profile->rampTargetAreaQ32 = 0ULL;
- profile->rampBoundaryQ32 = 0ULL;
- profile->lastRampPhaseStepQ32 = 0ULL;
- profile->lastRampFrequencyHz = 0UL;
- }
- previousTargetAreaQ32 = profile->rampTargetAreaQ32;
- profile->rampTargetAreaQ32 += profile->rampAreaStepQ32;
- profile->rampRemainderAccumulator += profile->rampAreaRemainder;
- if (profile->rampRemainderAccumulator >= rampPulseCount)
- {
- profile->rampTargetAreaQ32++;
- profile->rampRemainderAccumulator -= rampPulseCount;
- }
- if ((uint16_t)(relativePeriod + 1U) >= rampPulseCount)
- {
- profile->rampTargetAreaQ32 = profile->rampTotalAreaQ32;
- secondBoundaryQ32 = PLSR_Q32_ONE;
- }
- else if (relativePeriod == 0U)
- {
- secondBoundaryQ32 = firstCachedBoundaryQ32;
- }
- else if (relativePeriod == 1U)
- {
- secondBoundaryQ32 = secondCachedBoundaryQ32;
- }
- else
- {
- secondBoundaryQ32 = PlsrRampBoundaryQ32(
- fromHz, toHz, firstBoundaryQ32,
- profile->rampTargetAreaQ32,
- (relativePeriod < 2U) ? 0ULL
- : profile->lastRampPhaseStepQ32);
- }
- areaIncrementQ32 =
- profile->rampTargetAreaQ32 - previousTargetAreaQ32;
- profile->rampBoundaryQ32 = secondBoundaryQ32;
- profile->lastRampPhaseStepQ32 =
- secondBoundaryQ32 - firstBoundaryQ32;
- frequencyHz = PlsrRampAverageFrequency(areaIncrementQ32, firstBoundaryQ32,
- secondBoundaryQ32);
- if ((profile->lastRampFrequencyHz != 0UL)
- && (((toHz > fromHz)
- && (frequencyHz < profile->lastRampFrequencyHz))
- || ((toHz < fromHz)
- && (frequencyHz > profile->lastRampFrequencyHz))))
- {
- frequencyHz = profile->lastRampFrequencyHz;
- }
- profile->lastRampFrequencyHz = frequencyHz;
- return frequencyHz;
- }
-
- static void PlsrCopyShortProfile(PLSR_SHORT_PROFILE *destination,
- const PLSR_SHORT_PROFILE *source)
- {
- destination->active = 0U;
- destination->startHz = source->startHz;
- destination->peakHz = source->peakHz;
- destination->endHz = source->endHz;
- destination->pulseCount = source->pulseCount;
- destination->entryPulses = source->entryPulses;
- destination->steadyPulses = source->steadyPulses;
- destination->exitPulses = source->exitPulses;
- destination->nextPeriod = source->nextPeriod;
- destination->rampBoundaryQ32 = source->rampBoundaryQ32;
- destination->rampTotalAreaQ32 = source->rampTotalAreaQ32;
- destination->rampTargetAreaQ32 = source->rampTargetAreaQ32;
- destination->rampAreaStepQ32 = source->rampAreaStepQ32;
- destination->rampAreaRemainder = source->rampAreaRemainder;
- destination->rampRemainderAccumulator =
- source->rampRemainderAccumulator;
- destination->lastRampPhaseStepQ32 = source->lastRampPhaseStepQ32;
- destination->entryFirstBoundaryQ32 = source->entryFirstBoundaryQ32;
- destination->entrySecondBoundaryQ32 = source->entrySecondBoundaryQ32;
- destination->exitFirstBoundaryQ32 = source->exitFirstBoundaryQ32;
- destination->exitSecondBoundaryQ32 = source->exitSecondBoundaryQ32;
- destination->lastRampFrequencyHz = source->lastRampFrequencyHz;
- destination->active = source->active;
- }
-
- static void PlsrInvalidateHandoffPlans(void)
- {
- uint8_t bank;
- uint8_t index;
- uint32_t criticalState = PlsrPlatformEnterCritical();
-
- PlsrHandoffPlan.valid = 0U;
- for (bank = 0U; bank < 2U; bank++)
- {
- for (index = 0U; index < PLSR_SEGMENT_COUNT_MAX; index++)
- {
- PlsrPreparedHandoffPlans[bank][index].valid = 0U;
- }
- }
- PlsrPlatformExitCritical(criticalState);
- }
-
- static uint8_t PlsrAdvanceShortProfile(uint8_t pulseOutput)
- {
- uint32_t requestedFrequencyHz;
- uint32_t actualFrequencyHz;
-
- if ((PlsrShortProfile.active == 0U)
- || (PlsrShortProfile.nextPeriod >= PlsrShortProfile.pulseCount))
- {
- return 1U;
- }
-
- requestedFrequencyHz =
- PlsrShortProfileTakeFrequency(&PlsrShortProfile);
- PlsrDeferredFrequencyPending = 0U;
- if (PlsrPlatformQueueFrequency(pulseOutput,
- requestedFrequencyHz,
- &actualFrequencyHz) == 0U)
- {
- return 0U;
- }
- PlsrQueuedFrequencyHz = actualFrequencyHz;
- if (actualFrequencyHz > PlsrCurrentFrequencyHz)
- {
- PlsrRunStatus = PLSR_STATUS_ACCELERATING;
- }
- else if (actualFrequencyHz < PlsrCurrentFrequencyHz)
- {
- PlsrRunStatus = PLSR_STATUS_DECELERATING;
- }
- else
- {
- PlsrRunStatus = PLSR_STATUS_RUNNING;
- }
- return 1U;
- }
-
- static void PlsrMaybePlanBoundaryRamp(uint32_t expectedEpoch)
- {
- const PLSR_SEGMENT_CONFIG *segment;
- uint8_t nextSegment;
- uint8_t nextPositive;
- uint8_t hasNext;
- uint32_t targetHz;
- uint32_t criticalState;
- uint64_t estimate;
- uint64_t remaining;
-
- if ((PlsrPulseActive == 0U) || (PlsrBoundaryRampStarted != 0U)
- || (PlsrShortProfile.active != 0U)
- || (PlsrHandoffPlan.valid != 0U)
- || (PlsrStopRequested != 0U) || (PlsrCurrentSegment == 0U))
- {
- return;
- }
-
- segment = &PlsrActiveConfig.segments[PlsrCurrentSegment - 1U];
- hasNext = PlsrGetNextSegment(&nextSegment);
- targetHz = PlsrActiveConfig.stopSpeedHz;
-
- if ((PlsrActiveConfig.sendMode == PLSR_SEND_SUBSEQUENT)
- && (hasNext != 0U)
- && (segment->waitType == PLSR_EXT_OR_COMPLETE))
- {
- if ((PlsrPredictNextDirection(nextSegment, &nextPositive) != 0U)
- && (nextPositive == PlsrCountPositive))
- {
- targetHz = PlsrActiveConfig.segments[nextSegment - 1U].frequencyHz;
- }
- }
-
- estimate = PlsrRampPulseEstimate(PlsrCurrentFrequencyHz, targetHz);
- criticalState = PlsrPlatformEnterCritical();
- remaining = PlsrRemainingPulses;
- if ((PlsrSegmentEpoch != expectedEpoch)
- || (PlsrBoundaryPending != 0U)
- || (PlsrPulseActive == 0U)
- || (PlsrBoundaryRampStarted != 0U)
- || (PlsrShortProfile.active != 0U)
- || (PlsrHandoffPlan.valid != 0U)
- || (PlsrStopRequested != 0U))
- {
- PlsrPlatformExitCritical(criticalState);
- return;
- }
- if (remaining > estimate)
- {
- PlsrPlatformExitCritical(criticalState);
- return;
- }
-
- PlsrBoundaryRampStarted = 1U;
- PlsrRampStart(PlsrCurrentFrequencyHz, targetHz);
- PlsrPlatformExitCritical(criticalState);
- if (PlsrRamp.active == 0U)
- {
- (void)PlsrApplyFrequency(targetHz, expectedEpoch);
- }
- }
-
- static uint8_t PlsrBeginSegmentOutput(uint32_t startFrequencyHz)
- {
- uint32_t targetFrequencyHz =
- PlsrActiveConfig.segments[PlsrCurrentSegment - 1U].frequencyHz;
- uint32_t firstFrequencyHz;
- uint32_t secondFrequencyHz;
-
- PlsrSegmentClockStarted = 1U;
- PlsrSegmentElapsedMs = 0UL;
- if (PlsrPrepareShortProfile(&PlsrShortProfile,
- PlsrCurrentSegment, startFrequencyHz,
- targetFrequencyHz,
- PlsrRemainingSnapshot()) != 0U)
- {
- PlsrRamp.active = 0U;
- firstFrequencyHz =
- PlsrShortProfileTakeFrequency(&PlsrShortProfile);
- secondFrequencyHz =
- (PlsrShortProfile.nextPeriod < PlsrShortProfile.pulseCount)
- ? PlsrShortProfileTakeFrequency(&PlsrShortProfile)
- : firstFrequencyHz;
- if (secondFrequencyHz > firstFrequencyHz)
- {
- PlsrRunStatus = PLSR_STATUS_ACCELERATING;
- }
- else if (secondFrequencyHz < firstFrequencyHz)
- {
- PlsrRunStatus = PLSR_STATUS_DECELERATING;
- }
- else
- {
- PlsrRunStatus = PLSR_STATUS_RUNNING;
- }
- if (PlsrApplyFrequencyPair(firstFrequencyHz,
- secondFrequencyHz,
- PlsrSegmentEpoch) == 0U)
- {
- PlsrShortProfile.active = 0U;
- return 0U;
- }
- return 1U;
- }
-
- PlsrRampStart(startFrequencyHz, targetFrequencyHz);
-
- if (PlsrRamp.active == 0U)
- {
- if (PlsrApplyFrequency(targetFrequencyHz, PlsrSegmentEpoch) == 0U)
- {
- return 0U;
- }
- PlsrRunStatus = PLSR_STATUS_RUNNING;
- }
- else if ((startFrequencyHz != 0UL)
- && (PlsrApplyFrequency(startFrequencyHz,
- PlsrSegmentEpoch) == 0U))
- {
- return 0U;
- }
- return 1U;
- }
-
- static uint8_t PlsrStartSegment(uint8_t segmentNumber,
- uint8_t allowCarry,
- uint32_t carryFrequencyHz)
- {
- uint32_t criticalState;
- int32_t position;
- int64_t displacement;
- uint64_t magnitude;
- uint8_t positive;
- uint8_t directionLevel;
- uint8_t directionChanged;
- uint32_t startFrequencyHz;
-
- if ((segmentNumber == 0U)
- || (segmentNumber > PlsrActiveConfig.segmentCount))
- {
- return 0U;
- }
-
- criticalState = PlsrPlatformEnterCritical();
- position = PlsrPosition;
- PlsrPlatformExitCritical(criticalState);
- displacement = PlsrSegmentDisplacement(segmentNumber, position);
- positive = (displacement >= 0) ? 1U : 0U;
- magnitude = (displacement < 0) ? (uint64_t)(-displacement)
- : (uint64_t)displacement;
-
- PlsrSegmentEpoch++;
- PlsrCurrentSegment = segmentNumber;
- PlsrSegmentClockStarted = 0U;
- PlsrSegmentElapsedMs = 0UL;
- PlsrWaitElapsedMs = 0UL;
- PlsrBoundaryRampStarted = 0U;
- PlsrBoundaryPending = 0U;
- PlsrBoundaryWasCut = 0U;
- PlsrCutRequested = 0U;
- PlsrStopPulsesRemaining = 0U;
- PlsrFrequencyUpdatePending = 0U;
- PlsrDeferredFrequencyPending = 0U;
- PlsrCurrentFrequencyHz = 0UL;
- PlsrQueuedFrequencyHz = 0UL;
- PlsrHandoffPlan.valid = 0U;
- PlsrShortProfile.active = 0U;
- PlsrShortProfile.nextPeriod = 0U;
- PlsrDirectionDelayActive = 0U;
- PlsrDirectionDelayRemainingMs = 0U;
- PlsrExtEdgePending = 0U;
- PlsrExtPreviousLevel =
- PlsrPlatformReadInput((uint8_t)PlsrActiveConfig.extInput);
-
- criticalState = PlsrPlatformEnterCritical();
- PlsrRemainingPulses = magnitude;
- PlsrCountPositive = positive;
- PlsrPlatformExitCritical(criticalState);
-
- if ((PlsrActiveConfig.segments[segmentNumber - 1U].waitType
- == PLSR_ACT_TIME)
- && (PlsrActiveConfig.segments[segmentNumber - 1U].actTimeMs == 0U))
- {
- PlsrSegmentClockStarted = 1U;
- PlsrRunStatus = PLSR_STATUS_RUNNING;
- PlsrBoundaryFrequencyHz = (allowCarry != 0U) ? carryFrequencyHz : 0UL;
- PlsrBoundaryWasCut = 1U;
- PlsrBoundaryPending = 1U;
- return 1U;
- }
-
- if (magnitude == 0UL)
- {
- PlsrSegmentClockStarted = 1U;
- PlsrRunStatus = PLSR_STATUS_RUNNING;
- PlsrBoundaryFrequencyHz = 0UL;
- PlsrBoundaryPending = 1U;
- return 1U;
- }
-
- directionLevel = positive;
- if (PlsrActiveConfig.directionNegativeLogic != 0U)
- {
- directionLevel ^= 1U;
- }
- directionChanged = ((PlsrLastDirectionValid == 0U)
- || (PlsrLastDirectionOutput
- != (uint8_t)PlsrActiveConfig.directionOutput)
- || (PlsrLastDirectionLevel != directionLevel)) ? 1U : 0U;
-
- if (PlsrPlatformPrepare((uint8_t)PlsrActiveConfig.pulseOutput,
- (uint8_t)PlsrActiveConfig.directionOutput,
- directionLevel) == 0U)
- {
- return 0U;
- }
- PlsrLastDirectionValid = 1U;
- PlsrLastDirectionOutput = (uint8_t)PlsrActiveConfig.directionOutput;
- PlsrLastDirectionLevel = directionLevel;
-
- if ((allowCarry != 0U) && (directionChanged == 0U)
- && (carryFrequencyHz != 0UL))
- {
- startFrequencyHz = carryFrequencyHz;
- }
- else
- {
- startFrequencyHz = PlsrActiveConfig.startSpeedHz;
- }
-
- if ((directionChanged != 0U)
- && (PlsrActiveConfig.directionDelayMs != 0U))
- {
- PlsrDirectionDelayActive = 1U;
- PlsrDirectionDelayRemainingMs = PlsrActiveConfig.directionDelayMs;
- PlsrRunStatus = PLSR_STATUS_ACCELERATING;
- return 1U;
- }
-
- PlsrDirectionDelayActive = 0U;
- return PlsrBeginSegmentOutput(startFrequencyHz);
- }
-
- static void PlsrMarkPersistenceDirty(uint16_t delayMs)
- {
- PlsrPersistenceDirty = 1U;
- PlsrPersistenceDelayMs = delayMs;
- }
-
- static void PlsrCheckpointPosition(uint8_t wasBusy)
- {
- uint32_t criticalState;
- int32_t position;
- uint8_t positionValid;
-
- criticalState = PlsrPlatformEnterCritical();
- position = PlsrPosition;
- positionValid = PlsrPositionValid;
- PlsrPositionCheckpointDirty = 0U;
- PlsrPlatformExitCritical(criticalState);
- PlsrPlatformCheckpointPosition(position, positionValid, wasBusy);
- PlsrPositionCheckpointElapsedMs = 0U;
- }
-
- static void PlsrPollPositionCheckpoint(void)
- {
- if (PlsrPositionCheckpointDirty == 0U)
- {
- PlsrPositionCheckpointElapsedMs = 0U;
- return;
- }
- if (PlsrPositionCheckpointElapsedMs < PLSR_POSITION_CHECKPOINT_MS)
- {
- PlsrPositionCheckpointElapsedMs++;
- }
- if (PlsrPositionCheckpointElapsedMs >= PLSR_POSITION_CHECKPOINT_MS)
- {
- PlsrCheckpointPosition(1U);
- }
- }
-
- static void PlsrFinishCompleted(void)
- {
- PlsrPlatformStopPulse((uint8_t)PlsrActiveConfig.pulseOutput);
- PlsrRemainingPulses = 0UL;
- PlsrPulseActive = 0U;
- PlsrCutRequested = 0U;
- PlsrBoundaryPending = 0U;
- PlsrBoundaryWasCut = 0U;
- PlsrCurrentFrequencyHz = 0UL;
- PlsrQueuedFrequencyHz = 0UL;
- PlsrCurrentSegment = 0U;
- PlsrSegmentClockStarted = 0U;
- PlsrDirectionDelayActive = 0U;
- PlsrDirectionDelayRemainingMs = 0U;
- PlsrExtEdgePending = 0U;
- PlsrStopRequested = 0U;
- PlsrStopPulsesRemaining = 0U;
- PlsrSeamlessHandoffPending = 0U;
- PlsrDeferredFrequencyPending = 0U;
- PlsrShortProfile.active = 0U;
- PlsrHandoffPlan.valid = 0U;
- PlsrTimerErrorPending = 0U;
- PlsrRamp.active = 0U;
- PlsrInvalidateHandoffPlans();
- PlsrRunStatus = PLSR_STATUS_COMPLETED;
- PlsrError = PLSR_ERROR_NONE;
- PlsrCheckpointPosition(0U);
- PlsrMarkPersistenceDirty(PLSR_CONFIG_SAVE_DELAY_MS);
- }
-
- static void PlsrFinishStopped(void)
- {
- PlsrPlatformStopPulse((uint8_t)PlsrActiveConfig.pulseOutput);
- PlsrRemainingPulses = 0UL;
- PlsrPulseActive = 0U;
- PlsrCutRequested = 0U;
- PlsrBoundaryPending = 0U;
- PlsrBoundaryWasCut = 0U;
- PlsrCurrentFrequencyHz = 0UL;
- PlsrQueuedFrequencyHz = 0UL;
- PlsrCurrentSegment = 0U;
- PlsrSegmentClockStarted = 0U;
- PlsrDirectionDelayActive = 0U;
- PlsrDirectionDelayRemainingMs = 0U;
- PlsrExtEdgePending = 0U;
- PlsrStopRequested = 0U;
- PlsrStopPulsesRemaining = 0U;
- PlsrSeamlessHandoffPending = 0U;
- PlsrDeferredFrequencyPending = 0U;
- PlsrShortProfile.active = 0U;
- PlsrHandoffPlan.valid = 0U;
- PlsrTimerErrorPending = 0U;
- PlsrRamp.active = 0U;
- PlsrInvalidateHandoffPlans();
- PlsrRunStatus = PLSR_STATUS_STOPPED;
- PlsrError = PLSR_ERROR_NONE;
- PlsrCheckpointPosition(0U);
- PlsrMarkPersistenceDirty(PLSR_CONFIG_SAVE_DELAY_MS);
- }
-
- static void PlsrEnterError(PLSR_ERROR error)
- {
- PlsrPlatformStopPulse((uint8_t)PlsrActiveConfig.pulseOutput);
- PlsrRemainingPulses = 0UL;
- PlsrPulseActive = 0U;
- PlsrCutRequested = 0U;
- PlsrBoundaryPending = 0U;
- PlsrBoundaryWasCut = 0U;
- PlsrCurrentFrequencyHz = 0UL;
- PlsrQueuedFrequencyHz = 0UL;
- PlsrCurrentSegment = 0U;
- PlsrSegmentClockStarted = 0U;
- PlsrDirectionDelayActive = 0U;
- PlsrDirectionDelayRemainingMs = 0U;
- PlsrExtEdgePending = 0U;
- PlsrStopRequested = 0U;
- PlsrStopPulsesRemaining = 0U;
- PlsrSeamlessHandoffPending = 0U;
- PlsrDeferredFrequencyPending = 0U;
- PlsrShortProfile.active = 0U;
- PlsrHandoffPlan.valid = 0U;
- PlsrTimerErrorPending = 0U;
- PlsrRamp.active = 0U;
- PlsrInvalidateHandoffPlans();
- PlsrRunStatus = PLSR_STATUS_ERROR;
- PlsrError = error;
- PlsrCheckpointPosition(0U);
- PlsrMarkPersistenceDirty(PLSR_CONFIG_SAVE_DELAY_MS);
- }
-
- static void PlsrTransitionToNext(uint8_t allowCarry)
- {
- uint8_t nextSegment;
- uint32_t carryFrequencyHz = PlsrBoundaryFrequencyHz;
-
- if (PlsrGetNextSegment(&nextSegment) == 0U)
- {
- PlsrFinishCompleted();
- return;
- }
-
- if (PlsrStartSegment(nextSegment, allowCarry, carryFrequencyHz) == 0U)
- {
- PlsrEnterError(PLSR_ERROR_INVALID_RESOURCE);
- }
- }
-
- static uint8_t PlsrBuildHandoffPlan(uint8_t sourceSegment,
- const PLSR_CONFIG *frequencyConfig,
- PLSR_HANDOFF_PLAN *plan)
- {
- const PLSR_SEGMENT_CONFIG *segment;
- uint8_t nextSegment;
- int64_t displacement;
- uint8_t positive;
-
- plan->valid = 0U;
- if ((PlsrActiveConfig.sendMode != PLSR_SEND_SUBSEQUENT)
- || (sourceSegment == 0U)
- || (sourceSegment > PlsrActiveConfig.segmentCount))
- {
- return 0U;
- }
-
- segment = &PlsrActiveConfig.segments[sourceSegment - 1U];
- if (segment->waitType != PLSR_EXT_OR_COMPLETE)
- {
- return 0U;
- }
- if (segment->jumpSegment != 0U)
- {
- nextSegment = (uint8_t)segment->jumpSegment;
- }
- else if (sourceSegment < PlsrActiveConfig.segmentCount)
- {
- nextSegment = (uint8_t)(sourceSegment + 1U);
- }
- else
- {
- return 0U;
- }
-
- if (PlsrActiveConfig.positionMode == PLSR_POSITION_ABSOLUTE)
- {
- displacement = (int64_t)PlsrActiveConfig.segments[nextSegment - 1U].pulses
- - (int64_t)segment->pulses;
- }
- else
- {
- displacement = PlsrActiveConfig.segments[nextSegment - 1U].pulses;
- }
- if (displacement == 0)
- {
- return 0U;
- }
- positive = (displacement > 0) ? 1U : 0U;
-
- plan->magnitude = (displacement < 0) ? (uint64_t)(-displacement)
- : (uint64_t)displacement;
- plan->firstFrequencyHz =
- frequencyConfig->segments[nextSegment - 1U].frequencyHz;
- if (PlsrPrepareShortProfile(&plan->profile, nextSegment,
- plan->firstFrequencyHz,
- plan->firstFrequencyHz,
- plan->magnitude) != 0U)
- {
- plan->firstFrequencyHz =
- PlsrShortProfileTakeFrequency(&plan->profile);
- }
- plan->nextSegment = nextSegment;
- plan->positive = positive;
- plan->valid = 1U;
- return 1U;
- }
-
- static uint8_t PlsrBuildHandoffPlanBank(
- const PLSR_CONFIG *frequencyConfig)
- {
- uint8_t buildBank = (uint8_t)(PlsrPreparedHandoffBank ^ 1U);
- uint8_t sourceSegment;
- PLSR_HANDOFF_PLAN *destination;
-
- for (sourceSegment = 0U;
- sourceSegment < PLSR_SEGMENT_COUNT_MAX;
- sourceSegment++)
- {
- PlsrPreparedHandoffPlans[buildBank][sourceSegment].valid = 0U;
- }
- for (sourceSegment = 1U;
- sourceSegment <= PlsrActiveConfig.segmentCount;
- sourceSegment++)
- {
- destination =
- &PlsrPreparedHandoffPlans[buildBank][sourceSegment - 1U];
- (void)PlsrBuildHandoffPlan(sourceSegment, frequencyConfig,
- destination);
- }
- return buildBank;
- }
-
- static uint8_t PlsrSelectPreparedHandoffPlan(PLSR_HANDOFF_PLAN *plan)
- {
- const PLSR_HANDOFF_PLAN *prepared;
- uint8_t preparedBank;
- uint8_t currentSegment;
-
- plan->valid = 0U;
- currentSegment = PlsrCurrentSegment;
- if ((PlsrRemainingPulses != 1UL)
- || (PlsrActiveConfig.sendMode != PLSR_SEND_SUBSEQUENT)
- || (PlsrStopRequested != 0U)
- || (PlsrCountOverflowPending != 0U)
- || (PlsrCutRequested != 0U)
- || (currentSegment == 0U)
- || (currentSegment > PlsrActiveConfig.segmentCount))
- {
- return 0U;
- }
- preparedBank = PlsrPreparedHandoffBank;
- prepared = &PlsrPreparedHandoffPlans[preparedBank][currentSegment - 1U];
- if ((prepared->valid == 0U)
- || (prepared->positive != PlsrCountPositive))
- {
- return 0U;
- }
-
- plan->magnitude = prepared->magnitude;
- plan->firstFrequencyHz = prepared->firstFrequencyHz;
- PlsrCopyShortProfile(&plan->profile, &prepared->profile);
- plan->nextSegment = prepared->nextSegment;
- plan->positive = prepared->positive;
- plan->valid = 1U;
- return 1U;
- }
-
- static uint8_t PlsrPrimeHandoff(void)
- {
- PLSR_HANDOFF_PLAN candidatePlan;
- uint32_t actualFrequencyHz;
-
- PlsrHandoffPlan.valid = 0U;
- if (PlsrSelectPreparedHandoffPlan(&candidatePlan) == 0U)
- {
- return 0U;
- }
- PlsrDeferredFrequencyPending = 0U;
- if (PlsrPlatformQueueFrequency(
- (uint8_t)PlsrActiveConfig.pulseOutput,
- candidatePlan.firstFrequencyHz, &actualFrequencyHz) == 0U)
- {
- PlsrTimerErrorPending = 1U;
- return 0U;
- }
-
- PlsrQueuedFrequencyHz = actualFrequencyHz;
- PlsrHandoffPlan.magnitude = candidatePlan.magnitude;
- PlsrHandoffPlan.firstFrequencyHz = actualFrequencyHz;
- PlsrCopyShortProfile(&PlsrHandoffPlan.profile,
- &candidatePlan.profile);
- PlsrHandoffPlan.nextSegment = candidatePlan.nextSegment;
- PlsrHandoffPlan.positive = candidatePlan.positive;
- PlsrHandoffPlan.valid = 1U;
- return 1U;
- }
-
- static uint8_t PlsrTrySubsequentHandoff(void)
- {
- uint32_t requestedQueuedFrequencyHz;
- uint32_t actualQueuedFrequencyHz;
- uint32_t currentFrequencyHz;
- uint32_t queuedFrequencyHz;
- uint8_t nextSegment = PlsrHandoffPlan.nextSegment;
- uint64_t magnitude = PlsrHandoffPlan.magnitude;
- uint8_t positive = PlsrHandoffPlan.positive;
-
- if ((PlsrHandoffPlan.valid == 0U)
- || (PlsrActiveConfig.sendMode != PLSR_SEND_SUBSEQUENT)
- || (PlsrStopRequested != 0U)
- || (PlsrCountOverflowPending != 0U)
- || (PlsrCutRequested != 0U)
- || (PlsrCurrentFrequencyHz != PlsrHandoffPlan.firstFrequencyHz)
- || (nextSegment == 0U)
- || (nextSegment > PlsrActiveConfig.segmentCount))
- {
- return 0U;
- }
-
- PlsrCopyShortProfile(&PlsrShortProfile,
- &PlsrHandoffPlan.profile);
- requestedQueuedFrequencyHz = PlsrCurrentFrequencyHz;
- if ((PlsrShortProfile.active != 0U)
- && (PlsrShortProfile.nextPeriod < PlsrShortProfile.pulseCount))
- {
- requestedQueuedFrequencyHz =
- PlsrShortProfileTakeFrequency(&PlsrShortProfile);
- }
- PlsrDeferredFrequencyPending = 0U;
- if (PlsrPlatformQueueFrequency(
- (uint8_t)PlsrActiveConfig.pulseOutput,
- requestedQueuedFrequencyHz, &actualQueuedFrequencyHz) == 0U)
- {
- PlsrShortProfile.active = 0U;
- PlsrHandoffPlan.valid = 0U;
- PlsrTimerErrorPending = 1U;
- return 0U;
- }
-
- PlsrQueuedFrequencyHz = actualQueuedFrequencyHz;
- PlsrSegmentEpoch++;
- PlsrCurrentSegment = nextSegment;
- PlsrRemainingPulses = magnitude;
- PlsrCountPositive = positive;
- PlsrBoundaryFrequencyHz = PlsrCurrentFrequencyHz;
- PlsrSegmentClockStarted = 1U;
- PlsrSegmentElapsedMs = 0UL;
- PlsrWaitElapsedMs = 0UL;
- PlsrBoundaryRampStarted = 0U;
- PlsrBoundaryPending = 0U;
- PlsrBoundaryWasCut = 0U;
- PlsrCutRequested = 0U;
- PlsrFrequencyUpdatePending = 0U;
- PlsrDeferredFrequencyPending = 0U;
- PlsrExtEdgePending = 0U;
- PlsrExtPreviousLevel =
- PlsrPlatformReadInput((uint8_t)PlsrActiveConfig.extInput);
- PlsrSeamlessHandoffPending = 1U;
- PlsrHandoffPlan.valid = 0U;
- if (PlsrRemainingPulses == 1UL)
- {
- (void)PlsrPrimeHandoff();
- }
- queuedFrequencyHz = PlsrQueuedFrequencyHz;
- currentFrequencyHz = PlsrCurrentFrequencyHz;
- if (PlsrShortProfile.active != 0U)
- {
- if (queuedFrequencyHz > currentFrequencyHz)
- {
- PlsrRunStatus = PLSR_STATUS_ACCELERATING;
- }
- else if (queuedFrequencyHz < currentFrequencyHz)
- {
- PlsrRunStatus = PLSR_STATUS_DECELERATING;
- }
- else
- {
- PlsrRunStatus = PLSR_STATUS_RUNNING;
- }
- }
- else
- {
- PlsrRunStatus = PLSR_STATUS_RUNNING;
- }
- return 1U;
- }
-
- static void PlsrHandleBoundary(uint8_t extEdge)
- {
- const PLSR_SEGMENT_CONFIG *segment;
- uint8_t wasCut = PlsrBoundaryWasCut;
-
- PlsrBoundaryPending = 0U;
- PlsrBoundaryWasCut = 0U;
- PlsrPulseActive = 0U;
- PlsrCurrentFrequencyHz = 0UL;
- PlsrQueuedFrequencyHz = 0UL;
- PlsrShortProfile.active = 0U;
- PlsrHandoffPlan.valid = 0U;
- PlsrDeferredFrequencyPending = 0U;
- PlsrCheckpointPosition(1U);
-
- if (PlsrTimerErrorPending != 0U)
- {
- PlsrTimerErrorPending = 0U;
- PlsrEnterError(PLSR_ERROR_TIMER);
- return;
- }
- if (PlsrCountOverflowPending != 0U)
- {
- PlsrCountOverflowPending = 0U;
- PlsrEnterError(PLSR_ERROR_COUNT);
- return;
- }
-
- if (PlsrStopRequested != 0U)
- {
- PlsrFinishStopped();
- return;
- }
- if ((PlsrCurrentSegment == 0U)
- || (PlsrCurrentSegment > PlsrActiveConfig.segmentCount))
- {
- PlsrEnterError(PLSR_ERROR_INTERNAL);
- return;
- }
-
- segment = &PlsrActiveConfig.segments[PlsrCurrentSegment - 1U];
- if (wasCut != 0U)
- {
- PlsrTransitionToNext(
- (PlsrActiveConfig.sendMode == PLSR_SEND_SUBSEQUENT) ? 1U : 0U);
- return;
- }
-
- switch (segment->waitType)
- {
- case PLSR_WAIT_TIME:
- PlsrWaitElapsedMs = 0UL;
- PlsrRunStatus = PLSR_STATUS_WAITING;
- break;
-
- case PLSR_WAIT_SIGNAL:
- if (PlsrPlatformReadInput((uint8_t)PlsrActiveConfig.waitInput) != 0U)
- {
- PlsrTransitionToNext(0U);
- }
- else
- {
- PlsrRunStatus = PLSR_STATUS_WAITING;
- }
- break;
-
- case PLSR_ACT_TIME:
- if (PlsrSegmentElapsedMs >= segment->actTimeMs)
- {
- PlsrTransitionToNext(0U);
- }
- else
- {
- PlsrRunStatus = PLSR_STATUS_WAITING;
- }
- break;
-
- case PLSR_EXT_SIGNAL:
- if (extEdge != 0U)
- {
- PlsrTransitionToNext(0U);
- }
- else
- {
- PlsrRunStatus = PLSR_STATUS_WAITING;
- }
- break;
-
- case PLSR_EXT_OR_COMPLETE:
- PlsrTransitionToNext(
- (PlsrActiveConfig.sendMode == PLSR_SEND_SUBSEQUENT) ? 1U : 0U);
- break;
-
- default:
- PlsrEnterError(PLSR_ERROR_INTERNAL);
- break;
- }
- }
-
- static void PlsrRequestCut(uint32_t expectedEpoch)
- {
- uint32_t criticalState = PlsrPlatformEnterCritical();
-
- if (PlsrSegmentEpoch != expectedEpoch)
- {
- PlsrPlatformExitCritical(criticalState);
- return;
- }
- if (PlsrBoundaryPending != 0U)
- {
- PlsrBoundaryWasCut = 1U;
- }
- else if (PlsrPulseActive != 0U)
- {
- PlsrCutRequested = 1U;
- }
- else
- {
- PlsrBoundaryFrequencyHz = PlsrCurrentFrequencyHz;
- PlsrBoundaryWasCut = 1U;
- PlsrBoundaryPending = 1U;
- }
- PlsrPlatformExitCritical(criticalState);
- }
-
- static void PlsrPollWaiting(uint8_t extEdge)
- {
- const PLSR_SEGMENT_CONFIG *segment =
- &PlsrActiveConfig.segments[PlsrCurrentSegment - 1U];
-
- switch (segment->waitType)
- {
- case PLSR_WAIT_TIME:
- PlsrWaitElapsedMs++;
- if (PlsrWaitElapsedMs >= segment->waitTimeMs)
- {
- PlsrTransitionToNext(0U);
- }
- break;
- case PLSR_WAIT_SIGNAL:
- if (PlsrPlatformReadInput((uint8_t)PlsrActiveConfig.waitInput) != 0U)
- {
- PlsrTransitionToNext(0U);
- }
- break;
- case PLSR_ACT_TIME:
- if (PlsrSegmentElapsedMs >= segment->actTimeMs)
- {
- PlsrTransitionToNext(0U);
- }
- break;
- case PLSR_EXT_SIGNAL:
- if (extEdge != 0U)
- {
- PlsrTransitionToNext(0U);
- }
- break;
- default:
- PlsrEnterError(PLSR_ERROR_INTERNAL);
- break;
- }
- }
-
- static void PlsrPollPersistence(void)
- {
- PLSR_PERSIST_PAYLOAD payload;
- uint32_t criticalState;
-
- if ((PlsrPersistenceDirty == 0U) || (PlsrIsBusy() != 0U))
- {
- return;
- }
- if (PlsrPersistenceDelayMs != 0U)
- {
- PlsrPersistenceDelayMs--;
- return;
- }
-
- payload.config = PlsrShadowConfig;
- criticalState = PlsrPlatformEnterCritical();
- payload.position = PlsrPosition;
- payload.positionValid = PlsrPositionValid;
- PlsrPlatformExitCritical(criticalState);
- payload.wasBusy = 0U;
- payload.reserved = 0U;
- if (PlsrPlatformSave(&payload) != 0U)
- {
- PlsrPersistenceDirty = 0U;
- }
- else
- {
- PlsrRunStatus = PLSR_STATUS_ERROR;
- PlsrError = PLSR_ERROR_INTERNAL;
- }
- }
-
- uint8_t PlsrInit(void)
- {
- PLSR_PERSIST_PAYLOAD payload;
-
- PlsrInitialized = 0U;
- PlsrRunStatus = PLSR_STATUS_UNINITIALIZED;
- if (PlsrPlatformInit() == 0U)
- {
- return 0U;
- }
-
- if ((PlsrPlatformLoad(&payload) == 0U)
- || (PlsrConfigIsValid(&payload.config, 0U) == 0U)
- || (payload.positionValid > 1U) || (payload.wasBusy > 1U))
- {
- PlsrSetDefaults(&PlsrShadowConfig);
- PlsrPosition = 0L;
- PlsrPositionValid = 1U;
- PlsrPlatformCheckpointConfig(&PlsrShadowConfig);
- PlsrPlatformCheckpointPosition(0L, 1U, 0U);
- PlsrMarkPersistenceDirty(PLSR_CONFIG_SAVE_DELAY_MS);
- }
- else
- {
- PlsrShadowConfig = payload.config;
- PlsrPosition = payload.position;
- PlsrPositionValid = ((payload.positionValid != 0U)
- && (payload.wasBusy == 0U)) ? 1U : 0U;
- PlsrPersistenceDirty = 0U;
- PlsrPersistenceDelayMs = 0U;
- }
-
- (void)memset(&PlsrActiveConfig, 0, sizeof(PlsrActiveConfig));
- (void)memset(&PlsrRamp, 0, sizeof(PlsrRamp));
- (void)memset(&PlsrShortProfile, 0, sizeof(PlsrShortProfile));
- (void)memset(&PlsrHandoffPlan, 0, sizeof(PlsrHandoffPlan));
- (void)memset(PlsrPreparedHandoffPlans, 0,
- sizeof(PlsrPreparedHandoffPlans));
- PlsrPreparedHandoffBank = 0U;
- PlsrRemainingPulses = 0UL;
- PlsrPulseActive = 0U;
- PlsrCutRequested = 0U;
- PlsrBoundaryPending = 0U;
- PlsrBoundaryWasCut = 0U;
- PlsrCountOverflowPending = 0U;
- PlsrPositionCheckpointDirty = 0U;
- PlsrFrequencyUpdatePending = 0U;
- PlsrDeferredFrequencyPending = 0U;
- PlsrFrequencyUpdateSegment = 0U;
- PlsrSeamlessHandoffPending = 0U;
- PlsrTimerErrorPending = 0U;
- PlsrCurrentFrequencyHz = 0UL;
- PlsrQueuedFrequencyHz = 0UL;
- PlsrBoundaryFrequencyHz = 0UL;
- PlsrFrequencyUpdateTargetHz = 0UL;
- PlsrDeferredFrequencyHz = 0UL;
- PlsrSegmentEpoch = 0UL;
- PlsrCurrentSegment = 0U;
- PlsrDirectionDelayActive = 0U;
- PlsrDirectionDelayRemainingMs = 0U;
- PlsrSegmentClockStarted = 0U;
- PlsrExtPreviousLevel = 0U;
- PlsrExtEdgePending = 0U;
- PlsrStopRequested = 0U;
- PlsrStopPulsesRemaining = 0U;
- PlsrLastDirectionValid = 0U;
- PlsrPositionCheckpointElapsedMs = 0U;
- PlsrCommandMailbox.command = 0U;
- PlsrCommandMailbox.state = PLSR_COMMAND_MAILBOX_EMPTY;
- PlsrError = PLSR_ERROR_NONE;
- PlsrRunStatus = PLSR_STATUS_IDLE;
- PlsrInitialized = 1U;
- return 1U;
- }
-
- static PLSR_MB_RESULT PlsrQueueCommand(uint16_t command)
- {
- uint32_t criticalState;
- PLSR_MB_RESULT result = PLSR_MB_OK;
-
- if (PlsrInitialized == 0U)
- {
- return PLSR_MB_SERVER_FAILURE;
- }
-
- criticalState = PlsrPlatformEnterCritical();
- /* Capacity one: repeats acknowledge the first command; conflicts wait. */
- if (PlsrCommandMailbox.state != PLSR_COMMAND_MAILBOX_EMPTY)
- {
- result = (PlsrCommandMailbox.command == command)
- ? PLSR_MB_OK : PLSR_MB_DEVICE_BUSY;
- PlsrPlatformExitCritical(criticalState);
- return result;
- }
-
- if (command == PLSR_COMMAND_START)
- {
- if ((PlsrIsBusy() != 0U)
- || (PlsrRunStatus == PLSR_STATUS_ERROR))
- {
- result = PLSR_MB_DEVICE_BUSY;
- }
- else if ((PlsrRunStatus != PLSR_STATUS_IDLE)
- && (PlsrRunStatus != PLSR_STATUS_COMPLETED)
- && (PlsrRunStatus != PLSR_STATUS_STOPPED))
- {
- result = PLSR_MB_ILLEGAL_VALUE;
- }
- else if ((PlsrConfigIsValid(&PlsrShadowConfig, 1U) == 0U)
- || ((PlsrShadowConfig.positionMode
- == PLSR_POSITION_ABSOLUTE)
- && (PlsrPositionValid == 0U)))
- {
- result = PLSR_MB_ILLEGAL_VALUE;
- }
- else
- {
- PlsrCommandMailbox.startConfig = PlsrShadowConfig;
- }
- }
- else if ((command == PLSR_COMMAND_CLEAR) && (PlsrIsBusy() != 0U))
- {
- result = PLSR_MB_DEVICE_BUSY;
- }
-
- if (result == PLSR_MB_OK)
- {
- PlsrCommandMailbox.command = command;
- PlsrCommandMailbox.state = PLSR_COMMAND_MAILBOX_PENDING;
- }
- PlsrPlatformExitCritical(criticalState);
- return result;
- }
-
- static void PlsrExecuteStart(void)
- {
- uint32_t criticalState;
- uint8_t handoffBank;
-
- PlsrActiveConfig = PlsrCommandMailbox.startConfig;
- handoffBank = PlsrBuildHandoffPlanBank(&PlsrActiveConfig);
- criticalState = PlsrPlatformEnterCritical();
- PlsrPreparedHandoffBank = handoffBank;
- PlsrHandoffPlan.valid = 0U;
- PlsrPlatformExitCritical(criticalState);
- PlsrStopRequested = 0U;
- PlsrTimerErrorPending = 0U;
- PlsrShortProfile.active = 0U;
- PlsrError = PLSR_ERROR_NONE;
- PlsrLastDirectionValid = 0U;
- PlsrCheckpointPosition(1U);
- if (PlsrStartSegment((uint8_t)PlsrActiveConfig.startSegment, 0U, 0UL)
- == 0U)
- {
- PlsrEnterError(PLSR_ERROR_INVALID_RESOURCE);
- }
- }
-
- static uint8_t PlsrExecuteStop(void)
- {
- uint32_t criticalState;
- uint32_t stopTargetHz;
-
- if (PlsrIsBusy() == 0U)
- {
- return 0U;
- }
- criticalState = PlsrPlatformEnterCritical();
- if (PlsrStopRequested != 0U)
- {
- PlsrPlatformExitCritical(criticalState);
- return 0U;
- }
-
- PlsrStopRequested = 1U;
- PlsrStopPulsesRemaining = 0U;
- PlsrShortProfile.active = 0U;
- PlsrHandoffPlan.valid = 0U;
- PlsrInvalidateHandoffPlans();
- if (PlsrBoundaryPending != 0U)
- {
- PlsrPlatformExitCritical(criticalState);
- return 1U;
- }
- if (PlsrPulseActive == 0U)
- {
- PlsrPlatformExitCritical(criticalState);
- PlsrFinishStopped();
- return 1U;
- }
-
- stopTargetHz = PlsrActiveConfig.stopSpeedHz;
- if (stopTargetHz > PlsrCurrentFrequencyHz)
- {
- stopTargetHz = PlsrCurrentFrequencyHz;
- }
- PlsrRampStart(PlsrCurrentFrequencyHz, stopTargetHz);
- PlsrRunStatus = PLSR_STATUS_DECELERATING;
- if (PlsrRamp.active == 0U)
- {
- if (PlsrApplyFrequency(stopTargetHz, PlsrSegmentEpoch) == 0U)
- {
- PlsrPlatformExitCritical(criticalState);
- PlsrEnterError(PLSR_ERROR_TIMER);
- return 1U;
- }
- PlsrStopPulsesRemaining = PlsrStopDrainPulseCount();
- }
- PlsrPlatformExitCritical(criticalState);
- return 1U;
- }
-
- static void PlsrExecuteClear(void)
- {
- uint32_t criticalState;
-
- criticalState = PlsrPlatformEnterCritical();
- PlsrPosition = 0L;
- PlsrPositionValid = 1U;
- PlsrRemainingPulses = 0UL;
- PlsrPlatformExitCritical(criticalState);
- PlsrPlatformCheckpointPosition(0L, 1U, 0U);
- PlsrCountOverflowPending = 0U;
- PlsrPositionCheckpointDirty = 0U;
- PlsrPositionCheckpointElapsedMs = 0U;
- PlsrCurrentSegment = 0U;
- PlsrCurrentFrequencyHz = 0UL;
- PlsrQueuedFrequencyHz = 0UL;
- PlsrCutRequested = 0U;
- PlsrBoundaryPending = 0U;
- PlsrBoundaryWasCut = 0U;
- PlsrDirectionDelayActive = 0U;
- PlsrDirectionDelayRemainingMs = 0U;
- PlsrExtEdgePending = 0U;
- PlsrShortProfile.active = 0U;
- PlsrHandoffPlan.valid = 0U;
- PlsrInvalidateHandoffPlans();
- PlsrDeferredFrequencyPending = 0U;
- PlsrTimerErrorPending = 0U;
- PlsrRamp.active = 0U;
- PlsrError = PLSR_ERROR_NONE;
- PlsrRunStatus = PLSR_STATUS_IDLE;
- PlsrMarkPersistenceDirty(PLSR_CONFIG_SAVE_DELAY_MS);
- }
-
- static uint8_t PlsrPollCommandMailbox(void)
- {
- uint16_t command;
- uint8_t endPoll = 1U;
- uint32_t criticalState;
-
- criticalState = PlsrPlatformEnterCritical();
- if (PlsrCommandMailbox.state != PLSR_COMMAND_MAILBOX_PENDING)
- {
- PlsrPlatformExitCritical(criticalState);
- return 0U;
- }
- PlsrCommandMailbox.state = PLSR_COMMAND_MAILBOX_EXECUTING;
- command = PlsrCommandMailbox.command;
- PlsrPlatformExitCritical(criticalState);
-
- switch (command)
- {
- case PLSR_COMMAND_START: PlsrExecuteStart(); break;
- case PLSR_COMMAND_STOP: endPoll = PlsrExecuteStop(); break;
- case PLSR_COMMAND_CLEAR: PlsrExecuteClear(); break;
- default: PlsrEnterError(PLSR_ERROR_INTERNAL); break;
- }
-
- criticalState = PlsrPlatformEnterCritical();
- PlsrCommandMailbox.command = 0U;
- PlsrCommandMailbox.state = PLSR_COMMAND_MAILBOX_EMPTY;
- PlsrPlatformExitCritical(criticalState);
- return endPoll;
- }
-
- static void PlsrEnterErrorIfEpoch(PLSR_ERROR error, uint32_t expectedEpoch)
- {
- uint32_t criticalState = PlsrPlatformEnterCritical();
-
- if (PlsrSegmentEpoch == expectedEpoch)
- {
- PlsrEnterError(error);
- }
- PlsrPlatformExitCritical(criticalState);
- }
-
- void PlsrPoll1ms(void)
- {
- uint8_t extLevel;
- uint8_t extEdge;
- uint8_t activeSegmentNumber;
- uint8_t applyDynamicFrequency = 0U;
- PLSR_SEGMENT_CONFIG *activeSegment;
- uint32_t criticalState;
- uint32_t newTargetHz;
- uint32_t pollEpoch;
-
- if (PlsrInitialized == 0U)
- {
- return;
- }
-
- if (PlsrPollCommandMailbox() != 0U)
- {
- return;
- }
-
- PlsrPollPositionCheckpoint();
-
- criticalState = PlsrPlatformEnterCritical();
- pollEpoch = PlsrSegmentEpoch;
- extLevel = PlsrPlatformReadInput((uint8_t)PlsrActiveConfig.extInput);
- extEdge = ((extLevel != 0U) && (PlsrExtPreviousLevel == 0U)) ? 1U : 0U;
- PlsrExtPreviousLevel = extLevel;
- if (PlsrExtEdgePending != 0U)
- {
- extEdge = 1U;
- }
- PlsrPlatformExitCritical(criticalState);
-
- if (PlsrBoundaryPending != 0U)
- {
- PlsrExtEdgePending = 0U;
- PlsrHandleBoundary(extEdge);
- PlsrPollPersistence();
- return;
- }
-
- if (PlsrIsBusy() == 0U)
- {
- PlsrExtEdgePending = 0U;
- PlsrPollPersistence();
- return;
- }
-
- if (PlsrSegmentEpoch != pollEpoch)
- {
- return;
- }
-
- if (PlsrDirectionDelayActive != 0U)
- {
- if (extEdge != 0U)
- {
- PlsrExtEdgePending = 1U;
- }
- if (PlsrDirectionDelayRemainingMs != 0U)
- {
- PlsrDirectionDelayRemainingMs--;
- }
- if (PlsrDirectionDelayRemainingMs == 0U)
- {
- PlsrDirectionDelayActive = 0U;
- if (PlsrBeginSegmentOutput(PlsrActiveConfig.startSpeedHz) == 0U)
- {
- PlsrEnterError(PLSR_ERROR_TIMER);
- }
- }
- return;
- }
-
- criticalState = PlsrPlatformEnterCritical();
- if (PlsrSegmentEpoch != pollEpoch)
- {
- PlsrPlatformExitCritical(criticalState);
- return;
- }
- PlsrExtEdgePending = 0U;
- if (PlsrSegmentClockStarted != 0U)
- {
- PlsrSegmentElapsedMs++;
- }
- if (PlsrRunStatus == PLSR_STATUS_WAITING)
- {
- PlsrPlatformExitCritical(criticalState);
- PlsrPollWaiting(extEdge);
- return;
- }
-
- activeSegmentNumber = PlsrCurrentSegment;
- if ((activeSegmentNumber == 0U)
- || (activeSegmentNumber > PlsrActiveConfig.segmentCount))
- {
- PlsrPlatformExitCritical(criticalState);
- PlsrEnterError(PLSR_ERROR_INTERNAL);
- return;
- }
- activeSegment = &PlsrActiveConfig.segments[activeSegmentNumber - 1U];
- if (PlsrSeamlessHandoffPending != 0U)
- {
- PlsrSeamlessHandoffPending = 0U;
- if ((PlsrStopRequested == 0U)
- && (PlsrShortProfile.active == 0U)
- && (PlsrFrequencyUpdatePending == 0U))
- {
- PlsrRamp.active = 0U;
- PlsrRunStatus = PLSR_STATUS_RUNNING;
- }
- }
- newTargetHz = PlsrFrequencyUpdateTargetHz;
- if ((PlsrStopRequested == 0U)
- && (PlsrFrequencyUpdatePending != 0U)
- && (PlsrFrequencyUpdateSegment == activeSegmentNumber))
- {
- PlsrFrequencyUpdatePending = 0U;
- activeSegment->frequencyHz = newTargetHz;
- PlsrShortProfile.active = 0U;
- PlsrBoundaryRampStarted = 0U;
- PlsrRampStart(PlsrCurrentFrequencyHz, newTargetHz);
- if (PlsrRamp.active == 0U)
- {
- applyDynamicFrequency = 1U;
- }
- }
- PlsrPlatformExitCritical(criticalState);
-
- if (applyDynamicFrequency != 0U)
- {
- if (PlsrApplyFrequency(newTargetHz, pollEpoch) == 0U)
- {
- PlsrEnterErrorIfEpoch(PLSR_ERROR_TIMER, pollEpoch);
- return;
- }
- criticalState = PlsrPlatformEnterCritical();
- if (PlsrSegmentEpoch == pollEpoch)
- {
- PlsrRunStatus = PLSR_STATUS_RUNNING;
- }
- PlsrPlatformExitCritical(criticalState);
- }
-
- if ((PlsrShortProfile.active == 0U)
- && (PlsrRamp.active != 0U)
- && (PlsrRampAdvance(pollEpoch) == 0U))
- {
- PlsrEnterErrorIfEpoch(PLSR_ERROR_TIMER, pollEpoch);
- return;
- }
-
- criticalState = PlsrPlatformEnterCritical();
- if (PlsrSegmentEpoch != pollEpoch)
- {
- PlsrPlatformExitCritical(criticalState);
- return;
- }
- if ((PlsrStopRequested != 0U) && (PlsrRamp.active == 0U))
- {
- if (PlsrStopPulsesRemaining == 0U)
- {
- PlsrStopPulsesRemaining = PlsrStopDrainPulseCount();
- }
- PlsrPlatformExitCritical(criticalState);
- return;
- }
- PlsrPlatformExitCritical(criticalState);
-
- if ((activeSegment->waitType == PLSR_ACT_TIME)
- && (PlsrSegmentElapsedMs >= activeSegment->actTimeMs))
- {
- PlsrRequestCut(pollEpoch);
- return;
- }
- if (((activeSegment->waitType == PLSR_EXT_SIGNAL)
- || (activeSegment->waitType == PLSR_EXT_OR_COMPLETE))
- && (extEdge != 0U))
- {
- PlsrRequestCut(pollEpoch);
- return;
- }
-
- PlsrMaybePlanBoundaryRamp(pollEpoch);
- }
-
- void PlsrPulseTimerIrq(uint8_t pulseOutput)
- {
- uint32_t positionBits;
- uint32_t completedFrequencyHz;
- uint32_t activeFrequencyHz;
-
- if ((PlsrPulseActive == 0U)
- || (pulseOutput != (uint8_t)PlsrActiveConfig.pulseOutput))
- {
- return;
- }
-
- completedFrequencyHz = PlsrCurrentFrequencyHz;
- activeFrequencyHz = PlsrPlatformActiveFrequency(pulseOutput);
- if (activeFrequencyHz == 0UL)
- {
- PlsrTimerErrorPending = 1U;
- return;
- }
- PlsrCurrentFrequencyHz = activeFrequencyHz;
- if ((PlsrStopRequested != 0U) && (PlsrRamp.active == 0U)
- && (PlsrStopPulsesRemaining != 0U))
- {
- PlsrStopPulsesRemaining--;
- if (PlsrStopPulsesRemaining == 0U)
- {
- PlsrCutRequested = 1U;
- }
- }
- positionBits = (uint32_t)PlsrPosition;
- if (PlsrCountPositive != 0U)
- {
- if (PlsrPosition == INT32_MAX)
- {
- PlsrPositionValid = 0U;
- PlsrCountOverflowPending = 1U;
- }
- positionBits++;
- }
- else
- {
- if (PlsrPosition == INT32_MIN)
- {
- PlsrPositionValid = 0U;
- PlsrCountOverflowPending = 1U;
- }
- positionBits--;
- }
- PlsrPosition = (int32_t)positionBits;
- PlsrPositionCheckpointDirty = 1U;
-
- if (PlsrRemainingPulses != 0UL)
- {
- PlsrRemainingPulses--;
- }
-
- if ((PlsrRemainingPulses == 0UL) || (PlsrCutRequested != 0U)
- || (PlsrCountOverflowPending != 0U))
- {
- if ((PlsrRemainingPulses == 0UL)
- && (PlsrTrySubsequentHandoff() != 0U))
- {
- return;
- }
- PlsrShortProfile.active = 0U;
- PlsrHandoffPlan.valid = 0U;
- PlsrBoundaryFrequencyHz = completedFrequencyHz;
- PlsrBoundaryWasCut = (PlsrCutRequested != 0U) ? 1U : 0U;
- PlsrCutRequested = 0U;
- PlsrPlatformStopPulse(pulseOutput);
- PlsrPulseActive = 0U;
- PlsrCurrentFrequencyHz = 0UL;
- PlsrQueuedFrequencyHz = 0UL;
- PlsrBoundaryPending = 1U;
- return;
- }
-
- if ((PlsrShortProfile.active != 0U)
- && (PlsrAdvanceShortProfile(pulseOutput) == 0U))
- {
- PlsrTimerErrorPending = 1U;
- PlsrShortProfile.active = 0U;
- PlsrHandoffPlan.valid = 0U;
- PlsrBoundaryFrequencyHz = completedFrequencyHz;
- PlsrBoundaryWasCut = 0U;
- PlsrCutRequested = 0U;
- PlsrPlatformStopPulse(pulseOutput);
- PlsrPulseActive = 0U;
- PlsrCurrentFrequencyHz = 0UL;
- PlsrQueuedFrequencyHz = 0UL;
- PlsrBoundaryPending = 1U;
- return;
- }
-
- if ((PlsrShortProfile.active == 0U)
- && (PlsrRemainingPulses == 1UL))
- {
- (void)PlsrPrimeHandoff();
- }
- if ((PlsrShortProfile.active == 0U)
- && (PlsrHandoffPlan.valid == 0U)
- && (PlsrCommitDeferredFrequency(pulseOutput) == 0U))
- {
- PlsrTimerErrorPending = 1U;
- PlsrBoundaryFrequencyHz = completedFrequencyHz;
- PlsrBoundaryWasCut = 0U;
- PlsrCutRequested = 0U;
- PlsrPlatformStopPulse(pulseOutput);
- PlsrPulseActive = 0U;
- PlsrCurrentFrequencyHz = 0UL;
- PlsrQueuedFrequencyHz = 0UL;
- PlsrBoundaryPending = 1U;
- }
- }
-
- PLSR_MB_RESULT PlsrModbusReadHolding(uint16_t startAddress,
- uint16_t quantity,
- uint16_t *values)
- {
- PLSR_MB_RESULT classification;
- uint16_t index;
- uint32_t criticalState;
- int32_t position;
- uint32_t frequency;
- uint16_t statusWords[7];
-
- if (values == NULL)
- {
- return PLSR_MB_ILLEGAL_VALUE;
- }
- classification = PlsrClassifyRange(startAddress, quantity);
- if (classification != PLSR_MB_OK)
- {
- return classification;
- }
-
- criticalState = PlsrPlatformEnterCritical();
- position = PlsrPosition;
- frequency = PlsrCurrentFrequencyHz;
- statusWords[0] = PlsrLowWord((uint32_t)position);
- statusWords[1] = PlsrHighWord((uint32_t)position);
- statusWords[2] = PlsrLowWord(frequency);
- statusWords[3] = PlsrHighWord(frequency);
- statusWords[4] = (uint16_t)PlsrRunStatus;
- statusWords[5] = PlsrCurrentSegment;
- statusWords[6] = (uint16_t)PlsrError;
- PlsrPlatformExitCritical(criticalState);
-
- for (index = 0U; index < quantity; index++)
- {
- uint16_t address = (uint16_t)(startAddress + index);
-
- if ((address >= PLSR_CONFIG_FIRST_ADDRESS)
- && (address <= PLSR_CONFIG_LAST_ADDRESS))
- {
- values[index] = PlsrReadConfigWord(&PlsrShadowConfig, address);
- }
- else if ((address >= PLSR_STATUS_FIRST_ADDRESS)
- && (address <= PLSR_STATUS_LAST_ADDRESS))
- {
- values[index] = statusWords[address - PLSR_STATUS_FIRST_ADDRESS];
- }
- else if (address == PLSR_CONTROL_ADDRESS)
- {
- values[index] = 0U;
- }
- else
- {
- return PLSR_MB_ILLEGAL_ADDRESS;
- }
- }
- return PLSR_MB_OK;
- }
-
- PLSR_MB_RESULT PlsrModbusWriteHolding(uint16_t startAddress,
- uint16_t quantity,
- const uint16_t *values)
- {
- PLSR_MB_RESULT classification;
- PLSR_WORD_RESULT wordResult;
- uint16_t index;
- uint16_t pairedAddress;
- uint32_t requestEnd;
- uint32_t criticalState;
- uint8_t handoffBank = 0U;
- uint8_t updateActiveFrequencies = 0U;
- uint8_t drainedToDifferentSegment = 0U;
- uint8_t segmentBeforeDrain;
- uint32_t drainedSegmentTargetHz = 0UL;
-
- if (values == NULL)
- {
- return PLSR_MB_ILLEGAL_VALUE;
- }
- classification = PlsrClassifyRange(startAddress, quantity);
- if (classification != PLSR_MB_OK)
- {
- return classification;
- }
-
- if ((startAddress >= PLSR_STATUS_FIRST_ADDRESS)
- && (startAddress <= PLSR_STATUS_LAST_ADDRESS))
- {
- return PLSR_MB_ILLEGAL_ADDRESS;
- }
-
- if (startAddress == PLSR_CONTROL_ADDRESS)
- {
- if (quantity != 1U)
- {
- return PLSR_MB_ILLEGAL_ADDRESS;
- }
- switch (values[0])
- {
- case 0U: return PLSR_MB_OK;
- case PLSR_COMMAND_START:
- case PLSR_COMMAND_STOP:
- case PLSR_COMMAND_CLEAR:
- return PlsrQueueCommand(values[0]);
- default: return PLSR_MB_ILLEGAL_VALUE;
- }
- }
-
- if ((startAddress < PLSR_CONFIG_FIRST_ADDRESS)
- || ((uint32_t)startAddress + quantity - 1UL
- > PLSR_CONFIG_LAST_ADDRESS))
- {
- return PLSR_MB_ILLEGAL_ADDRESS;
- }
- if ((PlsrIsBusy() != 0U)
- && (startAddress <= 0x1001U)
- && ((uint32_t)startAddress + quantity - 1UL >= 0x1000UL))
- {
- return PLSR_MB_DEVICE_BUSY;
- }
-
- requestEnd = (uint32_t)startAddress + quantity;
- for (index = 0U; index < quantity; index++)
- {
- uint16_t address = (uint16_t)(startAddress + index);
- if (PlsrAddressIsDwordHalf(address, &pairedAddress) != 0U)
- {
- if (((uint32_t)pairedAddress < startAddress)
- || ((uint32_t)pairedAddress >= requestEnd))
- {
- return PLSR_MB_ILLEGAL_ADDRESS;
- }
- }
- }
-
- PlsrCandidateConfig = PlsrShadowConfig;
- for (index = 0U; index < quantity; index++)
- {
- wordResult = PlsrWriteConfigWord(&PlsrCandidateConfig,
- (uint16_t)(startAddress + index),
- values[index]);
- if (wordResult == PLSR_WORD_ILLEGAL_ADDRESS)
- {
- return PLSR_MB_ILLEGAL_ADDRESS;
- }
- if (wordResult == PLSR_WORD_ILLEGAL_VALUE)
- {
- return PLSR_MB_ILLEGAL_VALUE;
- }
- }
-
- if (PlsrConfigIsValid(&PlsrCandidateConfig, 0U) == 0U)
- {
- return PLSR_MB_ILLEGAL_VALUE;
- }
-
- if (PlsrIsBusy() != 0U)
- {
- for (index = 0U; index < PlsrActiveConfig.segmentCount; index++)
- {
- if (PlsrCandidateConfig.segments[index].frequencyHz
- != PlsrShadowConfig.segments[index].frequencyHz)
- {
- updateActiveFrequencies = 1U;
- }
- }
- }
- if (updateActiveFrequencies != 0U)
- {
- handoffBank = PlsrBuildHandoffPlanBank(&PlsrCandidateConfig);
- }
-
- criticalState = PlsrPlatformEnterCritical();
- segmentBeforeDrain = PlsrCurrentSegment;
- if ((updateActiveFrequencies != 0U) && (PlsrPulseActive != 0U))
- {
- PlsrPlatformDrainPendingPulse(
- (uint8_t)PlsrActiveConfig.pulseOutput);
- drainedToDifferentSegment =
- (PlsrCurrentSegment != segmentBeforeDrain) ? 1U : 0U;
- if ((drainedToDifferentSegment != 0U)
- && (PlsrCurrentSegment != 0U)
- && (PlsrCurrentSegment <= PlsrCandidateConfig.segmentCount))
- {
- drainedSegmentTargetHz =
- PlsrCandidateConfig.segments[PlsrCurrentSegment - 1U].frequencyHz;
- }
- }
- PlsrShadowConfig = PlsrCandidateConfig;
- if (updateActiveFrequencies != 0U)
- {
- for (index = 0U; index < PlsrActiveConfig.segmentCount; index++)
- {
- uint8_t frequencyChanged =
- (PlsrActiveConfig.segments[index].frequencyHz
- != PlsrCandidateConfig.segments[index].frequencyHz)
- ? 1U : 0U;
-
- PlsrActiveConfig.segments[index].frequencyHz =
- PlsrCandidateConfig.segments[index].frequencyHz;
- if ((frequencyChanged != 0U)
- && (index + 1U == PlsrCurrentSegment)
- && (PlsrStopRequested == 0U)
- && (PlsrRunStatus != PLSR_STATUS_WAITING))
- {
- PlsrFrequencyUpdateTargetHz =
- PlsrCandidateConfig.segments[index].frequencyHz;
- PlsrFrequencyUpdateSegment = (uint8_t)(index + 1U);
- PlsrFrequencyUpdatePending = 1U;
- }
- }
- PlsrPreparedHandoffBank = handoffBank;
- PlsrHandoffPlan.valid = 0U;
- if ((drainedToDifferentSegment != 0U)
- && (PlsrPulseActive != 0U)
- && (PlsrCurrentSegment != 0U)
- && (PlsrCurrentSegment <= PlsrActiveConfig.segmentCount)
- && (PlsrStopRequested == 0U)
- && (PlsrRunStatus != PLSR_STATUS_WAITING)
- && (PlsrCurrentFrequencyHz != drainedSegmentTargetHz))
- {
- PlsrFrequencyUpdateTargetHz =
- drainedSegmentTargetHz;
- PlsrFrequencyUpdateSegment = PlsrCurrentSegment;
- PlsrFrequencyUpdatePending = 1U;
- }
- if ((PlsrPulseActive != 0U)
- && (PlsrShortProfile.active == 0U)
- && (PlsrRemainingPulses == 1UL))
- {
- (void)PlsrPrimeHandoff();
- }
- }
- PlsrPlatformExitCritical(criticalState);
-
- if ((drainedToDifferentSegment != 0U)
- && (PlsrFrequencyUpdatePending != 0U))
- {
- uint32_t drainEpoch = PlsrSegmentEpoch;
- uint32_t actualDrainFrequencyHz;
-
- if (PlsrPlatformQueueFrequency(
- (uint8_t)PlsrActiveConfig.pulseOutput,
- drainedSegmentTargetHz, &actualDrainFrequencyHz) == 0U)
- {
- PlsrTimerErrorPending = 1U;
- }
- else
- {
- uint32_t currentEpoch;
- uint8_t updateSegment;
- uint8_t currentSegment;
-
- criticalState = PlsrPlatformEnterCritical();
- currentEpoch = PlsrSegmentEpoch;
- updateSegment = PlsrFrequencyUpdateSegment;
- currentSegment = PlsrCurrentSegment;
- if ((currentEpoch == drainEpoch)
- && (updateSegment == currentSegment))
- {
- PlsrQueuedFrequencyHz = actualDrainFrequencyHz;
- PlsrFrequencyUpdatePending = 0U;
- PlsrRamp.active = 0U;
- PlsrRunStatus = PLSR_STATUS_RUNNING;
- }
- PlsrPlatformExitCritical(criticalState);
- }
- }
- PlsrPlatformCheckpointConfig(&PlsrShadowConfig);
- PlsrMarkPersistenceDirty(PLSR_CONFIG_SAVE_DELAY_MS);
- return PLSR_MB_OK;
- }
-
- #ifdef PLSR_HOST_TEST
- uint64_t PlsrTestDivideU64ByU32(uint64_t dividend,
- uint32_t divisor,
- uint32_t *remainder)
- {
- return PlsrDivideU64ByU32(dividend, divisor, remainder);
- }
-
- void PlsrTestSetPosition(int32_t position, uint8_t positionValid)
- {
- uint32_t criticalState = PlsrPlatformEnterCritical();
-
- PlsrPosition = position;
- PlsrPositionValid = (positionValid != 0U) ? 1U : 0U;
- PlsrRemainingPulses = 0UL;
- PlsrPositionCheckpointDirty = 0U;
- PlsrPlatformExitCritical(criticalState);
- PlsrPlatformCheckpointPosition(position, PlsrPositionValid, 0U);
- }
- #endif
|