#include "plsr.h" #include #include #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_ERROR_TIMER (4U) #define PLSR_ERROR_COUNT (5U) #define PLSR_OUTPUT_MODE_PULSE_DIR (0U) #define PLSR_OUTPUT_MODE_AB (1U) #define PLSR_DIAG_FLAGS_ADDRESS (0x2100U) #define PLSR_DIAG_REASON_ADDRESS (0x2101U) #define PLSR_DIAG_SEGMENT_ADDRESS (0x2102U) #define PLSR_DIAG_MODE_DIRECTION_ADDRESS (0x2103U) #define PLSR_DIAG_EXPECTED_COUNT_ADDRESS (0x2104U) #define PLSR_DIAG_OBSERVED_COUNT_ADDRESS (0x2106U) #define PLSR_DIAG_COUNT_ERROR_ADDRESS (0x2108U) #define PLSR_DIAG_REQUESTED_FREQUENCY_ADDRESS (0x210AU) #define PLSR_DIAG_EXPECTED_TIMER_ADDRESS (0x210CU) #define PLSR_DIAG_ACTIVE_TIMER_ADDRESS (0x210EU) #define PLSR_DIAG_REQUEST_ERROR_ADDRESS (0x2110U) #define PLSR_DIAG_SAMPLE_COUNT_ADDRESS (0x2112U) #define PLSR_DIAG_MISMATCH_COUNT_ADDRESS (0x2114U) #define PLSR_DIAG_MAX_ERROR_ADDRESS (0x2116U) #define PLSR_DIAG_FIRST_MISMATCH_ADDRESS (0x2118U) #define PLSR_DIAG_MONITORING_ACTIVE (0x0001U) #define PLSR_DIAG_COUNT_CHECKED (0x0002U) #define PLSR_DIAG_COUNT_PASS (0x0004U) #define PLSR_DIAG_FREQUENCY_CHECKED (0x0008U) #define PLSR_DIAG_FREQUENCY_PASS (0x0010U) #define PLSR_DIAG_CURVE_CHECKED (0x0020U) #define PLSR_DIAG_CURVE_PASS (0x0040U) #define PLSR_DIAG_FAULT_LATCHED (0x0080U) #define PLSR_DIAG_REASON_NONE (0U) #define PLSR_DIAG_REASON_COUNT (1U) #define PLSR_DIAG_REASON_FREQUENCY (2U) #define PLSR_DIAG_REASON_CURVE (3U) void PlsrTestSetDiagnosticCurveCounts(uint32_t sampleCount, uint32_t mismatchCount); uint8_t PlsrTestFlashNeedsStartupRecovery( uint8_t haveValidRecord, uint8_t sectorAHasProgrammedSlot, uint32_t sectorAFirstErasedAddress, uint8_t sectorBHasProgrammedSlot, uint32_t sectorBFirstErasedAddress); static const char *CurrentTest; static unsigned int AssertionCount; static unsigned int FailureCount; static void ExpectCompletedDiagnostic(uint32_t pulseCount); static void ExpectUnsigned(unsigned long expected, unsigned long actual, const char *expression, int line) { AssertionCount++; if (expected != actual) { FailureCount++; (void)printf("FAIL %s:%d: %s expected %lu, got %lu\n", CurrentTest, line, expression, expected, actual); } } static void ExpectSigned(long expected, long actual, const char *expression, int line) { AssertionCount++; if (expected != actual) { FailureCount++; (void)printf("FAIL %s:%d: %s expected %ld, got %ld\n", CurrentTest, line, expression, expected, actual); } } static void ExpectTrue(int condition, const char *expression, int line) { AssertionCount++; if (!condition) { FailureCount++; (void)printf("FAIL %s:%d: expected true: %s\n", CurrentTest, line, expression); } } #define EXPECT_U(expected, actual) \ ExpectUnsigned((unsigned long)(expected), \ (unsigned long)(actual), #actual, __LINE__) #define EXPECT_I(expected, actual) \ ExpectSigned((long)(expected), (long)(actual), #actual, __LINE__) #define EXPECT_TRUE(expression) ExpectTrue((expression), #expression, __LINE__) static uint16_t LowWord(uint32_t value) { return (uint16_t)(value & 0xFFFFUL); } static uint16_t HighWord(uint32_t value) { return (uint16_t)(value >> 16U); } static uint64_t PulsePeriodNs(uint32_t frequencyHz) { return (1000000000ULL + frequencyHz / 2UL) / frequencyHz; } static uint64_t UnsignedDifference64(uint64_t first, uint64_t second) { return (first > second) ? (first - second) : (second - first); } static uint32_t IntegerSquareRoot64(uint64_t value) { uint64_t bit = (uint64_t)1U << 62U; uint64_t root = 0ULL; while (bit > value) { bit >>= 2U; } while (bit != 0ULL) { if (value >= root + bit) { value -= root + bit; root = (root >> 1U) + bit; } else { root >>= 1U; } bit >>= 2U; } return (uint32_t)root; } static PLSR_MB_RESULT WriteWord(uint16_t address, uint16_t value) { return PlsrModbusWriteHolding(address, 1U, &value); } static PLSR_MB_RESULT WriteU32(uint16_t address, uint32_t value) { uint16_t words[2]; words[0] = LowWord(value); words[1] = HighWord(value); return PlsrModbusWriteHolding(address, 2U, words); } static PLSR_MB_RESULT WriteI32(uint16_t address, int32_t value) { return WriteU32(address, (uint32_t)value); } static uint16_t ReadWord(uint16_t address) { uint16_t value = 0xDEADU; PLSR_MB_RESULT result = PlsrModbusReadHolding(address, 1U, &value); EXPECT_U(PLSR_MB_OK, result); return value; } static uint32_t ReadU32(uint16_t address) { uint16_t words[2] = {0xDEADU, 0xBEEFU}; PLSR_MB_RESULT result = PlsrModbusReadHolding(address, 2U, words); EXPECT_U(PLSR_MB_OK, result); return (uint32_t)words[0] | ((uint32_t)words[1] << 16U); } static int32_t ReadI32(uint16_t address) { return (int32_t)ReadU32(address); } static int32_t ReadPosition(void) { return (int32_t)ReadU32(PLSR_STATUS_FIRST_ADDRESS); } static uint32_t ReadFrequency(void) { return ReadU32((uint16_t)(PLSR_STATUS_FIRST_ADDRESS + 2U)); } static uint16_t ReadStatus(void) { return ReadWord((uint16_t)(PLSR_STATUS_FIRST_ADDRESS + 4U)); } static uint16_t ReadCurrentSegment(void) { return ReadWord((uint16_t)(PLSR_STATUS_FIRST_ADDRESS + 5U)); } static uint16_t ReadError(void) { return ReadWord((uint16_t)(PLSR_STATUS_FIRST_ADDRESS + 6U)); } static PLSR_MB_RESULT QueueCommand(uint16_t command) { return PlsrModbusWriteHolding(PLSR_CONTROL_ADDRESS, 1U, &command); } static PLSR_MB_RESULT SendCommand(uint16_t command) { PLSR_MB_RESULT result = QueueCommand(command); if (result == PLSR_MB_OK) { PlsrPoll1ms(); } return result; } static void ResetCore(void) { PlsrTestClearPersistentStorage(); EXPECT_U(1U, PlsrInit()); EXPECT_U(PLSR_STATUS_IDLE, ReadStatus()); } static void ConfigureCommon(uint16_t curveMode, uint16_t positionMode, uint16_t segmentCount, uint16_t sendMode, uint32_t defaultSpeedHz, uint32_t startSpeedHz, uint32_t stopSpeedHz, uint16_t accelerationTimeMs, uint16_t decelerationTimeMs) { uint16_t words[0x14U]; PLSR_MB_RESULT result; result = PlsrModbusReadHolding(0x1000U, 0x14U, words); EXPECT_U(PLSR_MB_OK, result); words[0x04U] = sendMode; words[0x05U] = 0U; words[0x07U] = curveMode; words[0x08U] = positionMode; words[0x09U] = segmentCount; words[0x0AU] = 1U; words[0x0BU] = LowWord(defaultSpeedHz); words[0x0CU] = HighWord(defaultSpeedHz); words[0x0DU] = LowWord(startSpeedHz); words[0x0EU] = HighWord(startSpeedHz); words[0x0FU] = 0U; words[0x10U] = LowWord(stopSpeedHz); words[0x11U] = HighWord(stopSpeedHz); words[0x12U] = accelerationTimeMs; words[0x13U] = decelerationTimeMs; result = PlsrModbusWriteHolding(0x1000U, 0x14U, words); EXPECT_U(PLSR_MB_OK, result); } static PLSR_MB_RESULT SetSegment(uint8_t segmentNumber, uint32_t frequencyHz, int32_t pulses, uint16_t waitType, uint16_t waitTimeMs, uint16_t actTimeMs, uint16_t jumpSegment) { uint16_t words[8]; uint16_t address = (uint16_t)(0x1100U + ((uint16_t)segmentNumber - 1U) * 0x10U); words[0] = LowWord(frequencyHz); words[1] = HighWord(frequencyHz); words[2] = LowWord((uint32_t)pulses); words[3] = HighWord((uint32_t)pulses); words[4] = waitType; words[5] = waitTimeMs; words[6] = actTimeMs; words[7] = jumpSegment; return PlsrModbusWriteHolding(address, 8U, words); } static void StopAndSettle(void) { unsigned int pulse; EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_STOP)); for (pulse = 0U; (pulse < 4U) && (PlsrTestPulseIsActive() != 0U); pulse++) { PlsrTestEmitPulses(1UL); } PlsrPoll1ms(); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_U(PLSR_STATUS_STOPPED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); } static void TestFiniteConstantPulseTrainBoundaries(void) { static const int32_t counts[] = { 1L, 2L, 65535L, 65536L, 65537L, 100000L, -1L, -2L, -65535L, -65536L, -65537L, -100000L }; uint32_t index; for (index = 0U; index < (uint32_t)(sizeof(counts) / sizeof(counts[0])); index++) { int32_t pulses = counts[index]; uint32_t magnitude = (pulses < 0) ? (uint32_t)(-pulses) : (uint32_t)pulses; ResetCore(); PlsrTestEnableFinitePulseTrain(1U); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 100000UL, 100000UL, 100000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 100000UL, pulses, PLSR_WAIT_TIME, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(1U, PlsrTestFinitePulseTrainActive()); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_U(100000UL, ReadFrequency()); PlsrTestCompleteFinitePulseTrain(); EXPECT_U(0U, PlsrTestFinitePulseTrainActive()); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_I(0L, ReadPosition()); PlsrPoll1ms(); EXPECT_I(pulses, ReadPosition()); EXPECT_U(PLSR_STATUS_WAITING, ReadStatus()); EXPECT_U(PLSR_DIAG_COUNT_PASS, ReadWord(PLSR_DIAG_FLAGS_ADDRESS) & PLSR_DIAG_COUNT_PASS); EXPECT_U(magnitude, ReadU32(PLSR_DIAG_OBSERVED_COUNT_ADDRESS)); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); } } static void TestFiniteProfileCurvesUseHardwareCounting(void) { uint16_t curveMode; for (curveMode = 0U; curveMode <= 2U; curveMode++) { uint32_t tick; uint32_t peakFrequency = 0UL; uint8_t reachedHigh = 0U; uint8_t sawDeceleration = 0U; int32_t midpointPosition = 0L; ResetCore(); PlsrTestEnableFinitePulseTrain(1U); ConfigureCommon(curveMode, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 50000UL, 10000UL, 10000UL, 100U, 100U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 50000UL, 20000L, PLSR_WAIT_TIME, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(1U, PlsrTestFinitePulseTrainActive()); EXPECT_U(10000UL, ReadFrequency()); for (tick = 0UL; (tick < 1000UL) && (PlsrTestFinitePulseTrainActive() != 0U); tick++) { uint32_t frequency = PlsrTestOutputFrequency(); uint32_t pulsesThisMs = (frequency + 999UL) / 1000UL; if (frequency > peakFrequency) { peakFrequency = frequency; } if (frequency >= 45000UL) { reachedHigh = 1U; } if ((reachedHigh != 0U) && (frequency <= 30000UL)) { sawDeceleration = 1U; } PlsrTestEmitPulses(pulsesThisMs); PlsrPoll1ms(); if (tick == 100UL) { midpointPosition = ReadPosition(); } } EXPECT_TRUE(midpointPosition > 0L); EXPECT_TRUE(peakFrequency >= 49000UL); EXPECT_U(1U, reachedHigh); EXPECT_U(1U, sawDeceleration); EXPECT_U(0U, PlsrTestFinitePulseTrainActive()); EXPECT_I(20000L, ReadPosition()); EXPECT_U(PLSR_DIAG_COUNT_PASS, ReadWord(PLSR_DIAG_FLAGS_ADDRESS) & PLSR_DIAG_COUNT_PASS); EXPECT_U(20000UL, ReadU32(PLSR_DIAG_OBSERVED_COUNT_ADDRESS)); PlsrPoll1ms(); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); } } static void TestFiniteCompleteMultiSegmentUsesHardwareCounting(void) { static const int32_t pulses[4] = {65537L, 2L, -65536L, -1L}; static const uint16_t jumps[4] = {3U, 4U, 2U, 0U}; static const uint8_t order[4] = {1U, 3U, 2U, 4U}; uint8_t index; ResetCore(); PlsrTestEnableFinitePulseTrain(1U); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 4U, PLSR_SEND_COMPLETE, 100000UL, 100000UL, 100000UL, 0U, 0U); for (index = 0U; index < 4U; index++) { EXPECT_U(PLSR_MB_OK, SetSegment((uint8_t)(index + 1U), 100000UL, pulses[index], PLSR_WAIT_TIME, 0U, 0U, jumps[index])); } EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); for (index = 0U; index < 4U; index++) { uint8_t segment = order[index]; uint32_t magnitude = (pulses[segment - 1U] < 0) ? (uint32_t)(-pulses[segment - 1U]) : (uint32_t)pulses[segment - 1U]; EXPECT_U(segment, ReadCurrentSegment()); EXPECT_U(1U, PlsrTestFinitePulseTrainActive()); if (magnitude > 65536UL) { PlsrTestEmitPulses(65536UL); PlsrPoll1ms(); EXPECT_U(1U, PlsrTestFinitePulseTrainActive()); } PlsrTestCompleteFinitePulseTrain(); PlsrPoll1ms(); PlsrPoll1ms(); PlsrPoll1ms(); } EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_I(2L, ReadPosition()); EXPECT_U(0U, ReadCurrentSegment()); } static void TestFiniteCompleteStartsAtConfiguredSegment(void) { ResetCore(); PlsrTestEnableFinitePulseTrain(1U); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 3U, PLSR_SEND_COMPLETE, 25000UL, 25000UL, 25000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, WriteWord(0x100AU, 3U)); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 25000UL, 11L, PLSR_WAIT_TIME, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(2U, 25000UL, 22L, PLSR_WAIT_TIME, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(3U, 25000UL, 70000L, PLSR_WAIT_TIME, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(3U, ReadCurrentSegment()); EXPECT_U(1U, PlsrTestFinitePulseTrainActive()); PlsrTestEmitPulses(65536UL); PlsrPoll1ms(); EXPECT_I(65536L, ReadPosition()); PlsrTestCompleteFinitePulseTrain(); PlsrPoll1ms(); PlsrPoll1ms(); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_I(70000L, ReadPosition()); } static void TestFiniteZeroDurationRampAppliesTargetImmediately(void) { ResetCore(); PlsrTestEnableFinitePulseTrain(1U); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 2U, PLSR_SEND_COMPLETE, 1000UL, 400UL, 100UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 400UL, 200L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(2U, 900UL, 200L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(400UL, PlsrTestOutputFrequency()); PlsrTestEmitPulses(200UL); PlsrPoll1ms(); EXPECT_U(2U, ReadCurrentSegment()); EXPECT_U(1U, PlsrTestFinitePulseTrainActive()); EXPECT_U(900UL, PlsrTestOutputFrequency()); PlsrTestEmitPulses(200UL); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); } static void TestFiniteRampUsesPulseBoundaryProfile(void) { ResetCore(); PlsrTestEnableFinitePulseTrain(1U); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 2000UL, 100UL, 2000UL, 2U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 2000UL, 100L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_TRUE(PlsrTestOutputFrequency() > 700UL); EXPECT_TRUE(PlsrTestOutputFrequency() < 800UL); PlsrTestEmitPulses(1UL); EXPECT_TRUE(PlsrTestOutputFrequency() > 1600UL); EXPECT_TRUE(PlsrTestOutputFrequency() < 1800UL); PlsrTestEmitPulses(1UL); EXPECT_U(2000UL, PlsrTestOutputFrequency()); PlsrTestCompleteFinitePulseTrain(); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); } static void TestFiniteSubsequentThreeSegmentsWithoutPoll(void) { ResetCore(); PlsrTestEnableFinitePulseTrain(1U); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 3U, PLSR_SEND_SUBSEQUENT, 100000UL, 100000UL, 100000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 100000UL, 1L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(2U, 100000UL, 1L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(3U, 100000UL, 1L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(1U, PlsrTestFinitePulseTrainActive()); PlsrTestEmitPulses(1UL); EXPECT_U(1U, PlsrTestFinitePulseTrainActive()); PlsrTestEmitPulses(1UL); EXPECT_U(1U, PlsrTestFinitePulseTrainActive()); PlsrTestEmitPulses(1UL); EXPECT_U(0U, PlsrTestFinitePulseTrainActive()); PlsrPoll1ms(); PlsrPoll1ms(); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_I(3L, ReadPosition()); EXPECT_U(1UL, ReadU32(PLSR_DIAG_EXPECTED_COUNT_ADDRESS)); EXPECT_I(0L, ReadI32(PLSR_DIAG_COUNT_ERROR_ADDRESS)); } static void TestFiniteSubsequentTenSegmentJumpChain(void) { static const uint8_t jumps[10] = {3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 2U, 0U}; uint8_t index; ResetCore(); PlsrTestEnableFinitePulseTrain(1U); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 10U, PLSR_SEND_SUBSEQUENT, 100000UL, 10000UL, 100000UL, 0U, 0U); for (index = 0U; index < 10U; index++) { EXPECT_U(PLSR_MB_OK, SetSegment((uint8_t)(index + 1U), (uint32_t)(10000UL * (index + 1U)), 1L, PLSR_EXT_OR_COMPLETE, 0U, 0U, jumps[index])); } EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); for (index = 0U; index < 10U; index++) { EXPECT_U(1U, PlsrTestFinitePulseTrainActive()); PlsrTestEmitPulses(1UL); } EXPECT_U(0U, PlsrTestFinitePulseTrainActive()); PlsrPoll1ms(); PlsrPoll1ms(); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_I(10L, ReadPosition()); EXPECT_U(10U, ReadWord(PLSR_DIAG_SEGMENT_ADDRESS)); } static void TestFiniteSubsequentCrossesCounterBlocks(void) { ResetCore(); PlsrTestEnableFinitePulseTrain(1U); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 2U, PLSR_SEND_SUBSEQUENT, 100000UL, 100000UL, 100000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 100000UL, 65537L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(2U, 50000UL, 65536L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitPulses(65536UL); EXPECT_U(1U, PlsrTestFinitePulseTrainActive()); PlsrTestEmitPulses(1UL); EXPECT_U(1U, PlsrTestFinitePulseTrainActive()); EXPECT_U(50000UL, PlsrTestOutputFrequency()); PlsrTestEmitPulses(65536UL); EXPECT_U(0U, PlsrTestFinitePulseTrainActive()); PlsrPoll1ms(); PlsrPoll1ms(); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_I(131073L, ReadPosition()); EXPECT_I(0L, ReadI32(PLSR_DIAG_COUNT_ERROR_ADDRESS)); } static void TestFiniteSubsequentDirectionReversalRestarts(void) { ResetCore(); PlsrTestEnableFinitePulseTrain(1U); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 2U, PLSR_SEND_SUBSEQUENT, 100000UL, 100000UL, 100000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, WriteWord(0x1005U, 1U)); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 100000UL, 2L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(2U, 100000UL, -3L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrPoll1ms(); EXPECT_U(1U, PlsrTestFinitePulseTrainActive()); PlsrTestCompleteFinitePulseTrain(); PlsrPoll1ms(); EXPECT_U(2U, ReadCurrentSegment()); EXPECT_U(0U, PlsrTestFinitePulseTrainActive()); PlsrPoll1ms(); EXPECT_U(1U, PlsrTestFinitePulseTrainActive()); EXPECT_U(0U, PlsrTestDirectionLevel()); PlsrTestCompleteFinitePulseTrain(); PlsrPoll1ms(); PlsrPoll1ms(); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_I(-1L, ReadPosition()); } static void TestProtocolBoundaries(void) { uint16_t value = 0U; uint16_t values[2]; uint16_t before; ResetCore(); EXPECT_U(PLSR_MB_NOT_HANDLED, PlsrModbusReadHolding(0x0FFEU, 1U, &value)); EXPECT_U(PLSR_MB_NOT_HANDLED, PlsrModbusReadHolding(0x1198U, 1U, &value)); EXPECT_U(PLSR_MB_ILLEGAL_ADDRESS, PlsrModbusReadHolding(0x11FFU, 2U, values)); EXPECT_U(PLSR_MB_NOT_HANDLED, PlsrModbusReadHolding(0x1201U, 1U, &value)); EXPECT_U(PLSR_MB_ILLEGAL_ADDRESS, PlsrModbusReadHolding(0x0FFFU, 2U, values)); EXPECT_U(PLSR_MB_ILLEGAL_ADDRESS, PlsrModbusReadHolding(0x1197U, 2U, values)); EXPECT_U(PLSR_MB_ILLEGAL_ADDRESS, PlsrModbusReadHolding(0x2006U, 2U, values)); EXPECT_U(PLSR_MB_ILLEGAL_ADDRESS, PlsrModbusReadHolding(0x2119U, 2U, values)); EXPECT_U(PLSR_MB_NOT_HANDLED, PlsrModbusReadHolding(0x211AU, 1U, &value)); EXPECT_U(PLSR_MB_ILLEGAL_ADDRESS, PlsrModbusReadHolding(0xFFFFU, 2U, values)); EXPECT_U(PLSR_MB_ILLEGAL_VALUE, PlsrModbusReadHolding(0x1000U, 0U, &value)); EXPECT_U(PLSR_MB_ILLEGAL_VALUE, PlsrModbusReadHolding(0x1000U, 1U, NULL)); EXPECT_U(0U, ReadWord(0x100FU)); EXPECT_U(PLSR_MB_OK, WriteWord(0x100FU, 0U)); EXPECT_U(PLSR_MB_ILLEGAL_VALUE, WriteWord(0x100FU, 1U)); EXPECT_U(0U, ReadWord(0x1108U)); EXPECT_U(PLSR_MB_OK, WriteWord(0x1108U, 0U)); EXPECT_U(PLSR_MB_ILLEGAL_VALUE, WriteWord(0x1108U, 1U)); EXPECT_U(PLSR_MB_ILLEGAL_ADDRESS, WriteWord(0x100BU, 2000U)); EXPECT_U(PLSR_MB_OK, WriteU32(0x100BU, 2000UL)); EXPECT_U(2000UL, ReadU32(0x100BU)); EXPECT_U(PLSR_MB_ILLEGAL_VALUE, WriteU32(0x100BU, 100001UL)); EXPECT_U(2000UL, ReadU32(0x100BU)); before = ReadWord(0x1013U); values[0] = 77U; values[1] = 1U; EXPECT_U(PLSR_MB_ILLEGAL_VALUE, PlsrModbusWriteHolding(0x1013U, 2U, values)); EXPECT_U(before, ReadWord(0x1013U)); EXPECT_U(PLSR_MB_ILLEGAL_ADDRESS, PlsrModbusWriteHolding(0x2000U, 1U, &value)); EXPECT_U(PLSR_MB_ILLEGAL_ADDRESS, PlsrModbusWriteHolding(PLSR_DIAGNOSTIC_FIRST_ADDRESS, 1U, &value)); EXPECT_U(PLSR_MB_ILLEGAL_ADDRESS, PlsrModbusWriteHolding(0x3000U, 2U, values)); value = 3U; EXPECT_U(PLSR_MB_ILLEGAL_VALUE, PlsrModbusWriteHolding(0x3000U, 1U, &value)); value = 0U; EXPECT_U(PLSR_MB_OK, PlsrModbusWriteHolding(0x3000U, 1U, &value)); EXPECT_U(0U, ReadWord(0x3000U)); EXPECT_U(PLSR_MB_OK, WriteWord(0x1197U, 0U)); EXPECT_U(0U, ReadWord(0x1197U)); EXPECT_U(PLSR_MB_NOT_HANDLED, WriteWord(0x1198U, 0U)); EXPECT_U(PLSR_OUTPUT_MODE_PULSE_DIR, ReadWord(PLSR_OUTPUT_MODE_ADDRESS)); EXPECT_U(PLSR_MB_OK, WriteWord(PLSR_OUTPUT_MODE_ADDRESS, PLSR_OUTPUT_MODE_AB)); EXPECT_U(PLSR_OUTPUT_MODE_AB, ReadWord(PLSR_OUTPUT_MODE_ADDRESS)); EXPECT_U(PLSR_MB_ILLEGAL_VALUE, WriteWord(PLSR_OUTPUT_MODE_ADDRESS, 2U)); EXPECT_U(PLSR_OUTPUT_MODE_AB, ReadWord(PLSR_OUTPUT_MODE_ADDRESS)); EXPECT_U(0U, ReadWord(PLSR_DIAGNOSTIC_CONTROL_ADDRESS)); EXPECT_U(PLSR_MB_OK, WriteWord(PLSR_DIAGNOSTIC_CONTROL_ADDRESS, 0U)); EXPECT_U(PLSR_MB_OK, WriteWord(PLSR_DIAGNOSTIC_CONTROL_ADDRESS, 1U)); EXPECT_U(PLSR_MB_ILLEGAL_VALUE, WriteWord(PLSR_DIAGNOSTIC_CONTROL_ADDRESS, 2U)); EXPECT_U(PLSR_MB_ILLEGAL_ADDRESS, PlsrModbusWriteHolding(PLSR_DIAGNOSTIC_CONTROL_ADDRESS, 2U, values)); EXPECT_U(0U, ReadWord(PLSR_DIAGNOSTIC_CONTROL_ADDRESS)); } static void ConfigureAbMotion(uint16_t pulseOutput, int32_t pulses, uint32_t frequencyHz, uint32_t startStopFrequencyHz, uint16_t accelerationTimeMs, uint16_t decelerationTimeMs) { ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, frequencyHz, startStopFrequencyHz, startStopFrequencyHz, accelerationTimeMs, decelerationTimeMs); EXPECT_U(PLSR_MB_OK, WriteWord(0x1000U, pulseOutput)); EXPECT_U(PLSR_MB_OK, WriteWord(PLSR_OUTPUT_MODE_ADDRESS, PLSR_OUTPUT_MODE_AB)); EXPECT_U(PLSR_MB_OK, SetSegment(1U, frequencyHz, pulses, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); } static void ExpectDiagnosticCleared(void) { uint16_t words[0x1AU]; uint16_t index; EXPECT_U(PLSR_MB_OK, PlsrModbusReadHolding(PLSR_DIAGNOSTIC_FIRST_ADDRESS, 0x1AU, words)); for (index = 0U; index < 0x18U; index++) { EXPECT_U(0U, words[index]); } EXPECT_U(0xFFFFU, words[0x18U]); EXPECT_U(0xFFFFU, words[0x19U]); } static void ClearDiagnostic(void) { EXPECT_U(PLSR_MB_OK, WriteWord(PLSR_DIAGNOSTIC_CONTROL_ADDRESS, 1U)); ExpectDiagnosticCleared(); } static void ExpectDiagnosticInterrupted(uint32_t expectedCycles, uint32_t observedCycles) { uint16_t flags = ReadWord(PLSR_DIAG_FLAGS_ADDRESS); EXPECT_U(0U, flags & PLSR_DIAG_MONITORING_ACTIVE); EXPECT_U(0U, flags & (PLSR_DIAG_COUNT_CHECKED | PLSR_DIAG_COUNT_PASS)); EXPECT_U(0U, flags & PLSR_DIAG_FAULT_LATCHED); EXPECT_U(PLSR_DIAG_REASON_NONE, ReadWord(PLSR_DIAG_REASON_ADDRESS)); EXPECT_U(expectedCycles, ReadU32(PLSR_DIAG_EXPECTED_COUNT_ADDRESS)); EXPECT_U(observedCycles, ReadU32(PLSR_DIAG_OBSERVED_COUNT_ADDRESS)); EXPECT_I(0L, ReadI32(PLSR_DIAG_COUNT_ERROR_ADDRESS)); } static void TestAbOutputPairsAndPhaseSequence(void) { static const uint8_t positivePhases[4] = {2U, 3U, 1U, 0U}; static const uint8_t negativePhases[4] = {1U, 3U, 2U, 0U}; uint32_t transitionsBefore; uint16_t quarter; ResetCore(); ConfigureAbMotion(0U, 2L, 1000UL, 1000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, WriteWord(0x1001U, 3U)); EXPECT_U(PLSR_MB_OK, WriteWord(0x1005U, 250U)); EXPECT_U(PLSR_MB_OK, WriteWord(0x1006U, 1U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_U(0U, PlsrTestAbPhase()); EXPECT_U(0U, PlsrTestAbTransitionCount()); EXPECT_U(1U, ReadCurrentSegment()); EXPECT_U(0x0101U, ReadWord(PLSR_DIAG_MODE_DIRECTION_ADDRESS)); for (quarter = 0U; quarter < 4U; quarter++) { PlsrTestEmitAbQuarters(1UL); EXPECT_U(positivePhases[quarter], PlsrTestAbPhase()); EXPECT_U((uint32_t)quarter + 1UL, PlsrTestAbTransitionCount()); EXPECT_I((quarter == 3U) ? 1L : 0L, ReadPosition()); } EXPECT_U(1U, PlsrTestPulseIsActive()); transitionsBefore = PlsrTestAbTransitionCount(); PlsrTestEmitPulses(1UL); EXPECT_U(transitionsBefore + 4UL, PlsrTestAbTransitionCount()); EXPECT_U(0U, PlsrTestAbPhase()); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_I(2L, ReadPosition()); ResetCore(); ConfigureAbMotion(2U, -1L, 2000UL, 2000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, WriteWord(0x1001U, 0U)); EXPECT_U(PLSR_MB_OK, WriteWord(0x1005U, 250U)); EXPECT_U(PLSR_MB_OK, WriteWord(0x1006U, 1U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_U(0U, PlsrTestAbPhase()); EXPECT_U(0x0001U, ReadWord(PLSR_DIAG_MODE_DIRECTION_ADDRESS)); for (quarter = 0U; quarter < 4U; quarter++) { PlsrTestEmitAbQuarters(1UL); EXPECT_U(negativePhases[quarter], PlsrTestAbPhase()); EXPECT_I((quarter == 3U) ? -1L : 0L, ReadPosition()); } EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_U(0U, PlsrTestAbPhase()); EXPECT_U(1UL, PlsrTestAbFastGateCount()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_I(-1L, ReadPosition()); } static void TestAbSinglePulseMaximumFrequencyMatrix(void) { static const uint16_t outputs[2] = {0U, 2U}; static const int32_t directions[2] = {1L, -1L}; uint32_t transitionsBefore; uint16_t outputIndex; uint16_t directionIndex; for (outputIndex = 0U; outputIndex < 2U; outputIndex++) { for (directionIndex = 0U; directionIndex < 2U; directionIndex++) { ResetCore(); ConfigureAbMotion(outputs[outputIndex], directions[directionIndex], 100000UL, 100000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_U(0U, PlsrTestAbPhase()); EXPECT_U(0UL, PlsrTestAbTransitionCount()); PlsrTestEmitAbQuarters(4UL); EXPECT_U(0U, PlsrTestAbPhase()); EXPECT_U(4UL, PlsrTestAbTransitionCount()); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_I(directions[directionIndex], ReadPosition()); EXPECT_U(1UL, PlsrTestAbFastGateCount()); transitionsBefore = PlsrTestAbTransitionCount(); PlsrTestEmitAbQuarters(8UL); EXPECT_U(transitionsBefore, PlsrTestAbTransitionCount()); EXPECT_I(directions[directionIndex], ReadPosition()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_U(1UL, ReadU32(PLSR_DIAG_EXPECTED_COUNT_ADDRESS)); EXPECT_U(1UL, ReadU32(PLSR_DIAG_OBSERVED_COUNT_ADDRESS)); EXPECT_U(0U, ReadWord(PLSR_DIAG_REASON_ADDRESS)); } } } static void TestAbFastGateCleanupIsDeferredToPoll(void) { ResetCore(); ConfigureAbMotion(0U, 1L, 100000UL, 100000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(0UL, PlsrTestAbCleanupCount()); PlsrTestEmitAbQuarters(4UL); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_U(1UL, PlsrTestAbFastGateCount()); EXPECT_U(0UL, PlsrTestAbCleanupCount()); EXPECT_I(1L, ReadPosition()); EXPECT_U(1UL, ReadU32(PLSR_DIAG_OBSERVED_COUNT_ADDRESS)); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(1UL, PlsrTestAbCleanupCount()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); } static void TestAbFinalArmJobTailChainsOnce(void) { static const uint16_t outputs[2] = {0U, 2U}; static const int32_t displacements[2] = {2L, -2L}; uint16_t index; for (index = 0U; index < 2U; index++) { ResetCore(); ConfigureAbMotion(outputs[index], displacements[index], 100000UL, 100000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitAbQuarters(4UL); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_U(0U, PlsrTestAbPhase()); EXPECT_U(0UL, PlsrTestAbFastGateCount()); EXPECT_I((displacements[index] > 0L) ? 1L : -1L, ReadPosition()); PlsrTestEmitAbQuarters(4UL); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_U(0U, PlsrTestAbPhase()); EXPECT_U(8UL, PlsrTestAbTransitionCount()); EXPECT_U(1UL, PlsrTestAbFastGateCount()); EXPECT_I(displacements[index], ReadPosition()); PlsrTestServiceFinalArmJob(); EXPECT_I(displacements[index], ReadPosition()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_U(2UL, ReadU32(PLSR_DIAG_EXPECTED_COUNT_ADDRESS)); EXPECT_U(2UL, ReadU32(PLSR_DIAG_OBSERVED_COUNT_ADDRESS)); } } static void TestAbFinalBoundaryBeforeArmJobIsNoOp(void) { ResetCore(); ConfigureAbMotion(0U, 2L, 100000UL, 100000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestDeferFinalArmJob(1U); PlsrTestEmitAbQuarters(4UL); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_I(1L, ReadPosition()); PlsrTestEmitAbQuarters(4UL); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_U(0U, PlsrTestAbPhase()); EXPECT_U(8UL, PlsrTestAbTransitionCount()); EXPECT_I(2L, ReadPosition()); PlsrTestServiceFinalArmJob(); PlsrTestDeferFinalArmJob(0U); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_I(2L, ReadPosition()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_U(2UL, ReadU32(PLSR_DIAG_OBSERVED_COUNT_ADDRESS)); } static void TestAbFinalArmJobFailureDoesNotCountFinalPulse(void) { ResetCore(); ConfigureAbMotion(2U, -2L, 100000UL, 100000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestDeferFinalArmJob(1U); PlsrTestEmitAbQuarters(4UL); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_I(-1L, ReadPosition()); PlsrTestFailNextStopRequest(); PlsrTestServiceFinalArmJob(); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_U(0U, PlsrTestAbPhase()); EXPECT_I(-1L, ReadPosition()); PlsrTestEmitAbQuarters(8UL); EXPECT_I(-1L, ReadPosition()); PlsrTestDeferFinalArmJob(0U); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_ERROR, ReadStatus()); EXPECT_U(PLSR_ERROR_TIMER, ReadError()); EXPECT_I(-1L, ReadPosition()); ExpectDiagnosticInterrupted(2UL, 1UL); } static void TestAbStopMailboxAtPendingBoundary(void) { ResetCore(); ConfigureAbMotion(0U, 1L, 100000UL, 100000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitAbQuarters(4UL); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_U(1UL, PlsrTestAbFastGateCount()); EXPECT_U(0UL, PlsrTestAbCleanupCount()); EXPECT_I(1L, ReadPosition()); EXPECT_U(1UL, ReadU32(PLSR_DIAG_OBSERVED_COUNT_ADDRESS)); EXPECT_U(PLSR_MB_DEVICE_BUSY, QueueCommand(PLSR_COMMAND_START)); EXPECT_U(PLSR_MB_DEVICE_BUSY, QueueCommand(PLSR_COMMAND_CLEAR)); EXPECT_U(PLSR_MB_OK, QueueCommand(PLSR_COMMAND_STOP)); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_RUNNING, ReadStatus()); EXPECT_U(0UL, PlsrTestAbCleanupCount()); EXPECT_I(1L, ReadPosition()); EXPECT_U(1UL, ReadU32(PLSR_DIAG_OBSERVED_COUNT_ADDRESS)); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_STOPPED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_U(0U, ReadCurrentSegment()); EXPECT_U(1UL, PlsrTestAbCleanupCount()); EXPECT_I(1L, ReadPosition()); EXPECT_U(1UL, ReadU32(PLSR_DIAG_EXPECTED_COUNT_ADDRESS)); EXPECT_U(1UL, ReadU32(PLSR_DIAG_OBSERVED_COUNT_ADDRESS)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_CLEAR)); EXPECT_U(PLSR_STATUS_IDLE, ReadStatus()); EXPECT_I(0L, ReadPosition()); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(1U, PlsrTestPulseIsActive()); PlsrTestEmitAbQuarters(4UL); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_U(2UL, PlsrTestAbCleanupCount()); EXPECT_I(1L, ReadPosition()); EXPECT_U(1UL, ReadU32(PLSR_DIAG_OBSERVED_COUNT_ADDRESS)); } static void TestAbActAndExtCutsFinishAtZero(void) { uint32_t transitionsBefore; ResetCore(); ConfigureAbMotion(0U, 100L, 1000UL, 1000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 100L, PLSR_ACT_TIME, 0U, 1U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitAbQuarters(2UL); EXPECT_U(3U, PlsrTestAbPhase()); PlsrPoll1ms(); PlsrTestEmitAbQuarters(2UL); EXPECT_U(0U, PlsrTestAbPhase()); EXPECT_U(4UL, PlsrTestAbTransitionCount()); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_I(1L, ReadPosition()); transitionsBefore = PlsrTestAbTransitionCount(); PlsrTestEmitAbQuarters(4UL); EXPECT_U(transitionsBefore, PlsrTestAbTransitionCount()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(0U, ReadWord(PLSR_DIAG_FLAGS_ADDRESS) & PLSR_DIAG_FAULT_LATCHED); ExpectDiagnosticInterrupted(100UL, 1UL); ResetCore(); ConfigureAbMotion(2U, -100L, 1000UL, 1000UL, 0U, 0U); PlsrTestSetInput(0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, -100L, PLSR_EXT_SIGNAL, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitAbQuarters(3UL); EXPECT_U(2U, PlsrTestAbPhase()); PlsrTestSetInput(0U, 1U); PlsrPoll1ms(); PlsrTestEmitAbQuarters(1UL); EXPECT_U(0U, PlsrTestAbPhase()); EXPECT_U(4UL, PlsrTestAbTransitionCount()); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_I(-1L, ReadPosition()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(0U, ReadWord(PLSR_DIAG_FLAGS_ADDRESS) & PLSR_DIAG_FAULT_LATCHED); ExpectDiagnosticInterrupted(100UL, 1UL); } static void TestAbSubsequentSinglePulsesStayContinuous(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 2U, PLSR_SEND_SUBSEQUENT, 100000UL, 100000UL, 100000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, WriteWord(0x1000U, 0U)); EXPECT_U(PLSR_MB_OK, WriteWord(PLSR_OUTPUT_MODE_ADDRESS, PLSR_OUTPUT_MODE_AB)); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 100000UL, 1L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(2U, 100000UL, 1L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitAbQuarters(4UL); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_U(2U, ReadCurrentSegment()); EXPECT_U(4UL, PlsrTestAbTransitionCount()); EXPECT_U(0UL, PlsrTestAbFastGateCount()); EXPECT_I(1L, ReadPosition()); PlsrTestEmitAbQuarters(4UL); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_U(0U, PlsrTestAbPhase()); EXPECT_U(8UL, PlsrTestAbTransitionCount()); EXPECT_U(1UL, PlsrTestAbFastGateCount()); EXPECT_I(2L, ReadPosition()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_U(0U, ReadWord(PLSR_DIAG_FLAGS_ADDRESS) & PLSR_DIAG_FAULT_LATCHED); } static void TestAbArmedFrequencyWriteDoesNotReopenOutput(void) { ResetCore(); ConfigureAbMotion(0U, 1L, 1000UL, 1000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitAbQuarters(1UL); EXPECT_U(2U, PlsrTestAbPhase()); EXPECT_U(PLSR_MB_OK, WriteU32(0x1100U, 2000UL)); PlsrPoll1ms(); EXPECT_U(1000UL, PlsrTestOutputFrequency()); EXPECT_U(1000UL, PlsrTestQueuedFrequency()); PlsrTestEmitAbQuarters(3UL); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_U(0U, PlsrTestAbPhase()); EXPECT_U(4UL, PlsrTestAbTransitionCount()); EXPECT_I(1L, ReadPosition()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_U(0U, ReadWord(PLSR_DIAG_FLAGS_ADDRESS) & PLSR_DIAG_FAULT_LATCHED); } static void TestAbStopRequestForcedFault(void) { ResetCore(); ConfigureAbMotion(0U, 1L, 1000UL, 1000UL, 0U, 0U); PlsrTestFailNextStopRequest(); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_I(0L, ReadPosition()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_ERROR, ReadStatus()); EXPECT_U(PLSR_ERROR_TIMER, ReadError()); EXPECT_I(0L, ReadPosition()); ExpectDiagnosticInterrupted(1UL, 0UL); ResetCore(); ConfigureAbMotion(2U, -100L, 1000UL, 1000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitAbQuarters(2UL); PlsrTestFailNextStopRequest(); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_STOP)); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_I(0L, ReadPosition()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_ERROR, ReadStatus()); EXPECT_U(PLSR_ERROR_TIMER, ReadError()); EXPECT_I(0L, ReadPosition()); ExpectDiagnosticInterrupted(100UL, 0UL); } static void TestAbStopAfterFinalBoundaryIsArmed(void) { ResetCore(); ConfigureAbMotion(0U, 1L, 1000UL, 1000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitAbQuarters(1UL); EXPECT_U(2U, PlsrTestAbPhase()); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_STOP)); EXPECT_U(PLSR_STATUS_DECELERATING, ReadStatus()); EXPECT_U(1U, PlsrTestPulseIsActive()); PlsrTestEmitAbQuarters(3UL); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_U(0U, PlsrTestAbPhase()); EXPECT_U(4UL, PlsrTestAbTransitionCount()); EXPECT_U(1UL, PlsrTestAbFastGateCount()); EXPECT_I(1L, ReadPosition()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_STOPPED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_U(0U, ReadWord(PLSR_DIAG_FLAGS_ADDRESS) & PLSR_DIAG_FAULT_LATCHED); } static void TestAbStopArmConsumesLatchedFinalQuarterOnce(void) { ResetCore(); ConfigureAbMotion(0U, 100L, 1000UL, 1000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitAbQuarters(3UL); EXPECT_U(1U, PlsrTestAbPhase()); EXPECT_U(3UL, PlsrTestAbTransitionCount()); EXPECT_I(0L, ReadPosition()); PlsrTestLatchAbFinalQuarterOnNextStopArm(); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_STOP)); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_U(0U, PlsrTestAbPhase()); EXPECT_U(4UL, PlsrTestAbTransitionCount()); EXPECT_U(1UL, PlsrTestAbFastGateCount()); EXPECT_I(1L, ReadPosition()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_STOPPED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_U(0U, ReadWord(PLSR_DIAG_FLAGS_ADDRESS) & PLSR_DIAG_FAULT_LATCHED); } static void TestAbRejectsUnpairedOutputs(void) { ResetCore(); EXPECT_U(PLSR_MB_OK, WriteWord(0x1000U, 1U)); EXPECT_U(PLSR_MB_ILLEGAL_VALUE, WriteWord(PLSR_OUTPUT_MODE_ADDRESS, PLSR_OUTPUT_MODE_AB)); EXPECT_U(PLSR_OUTPUT_MODE_PULSE_DIR, ReadWord(PLSR_OUTPUT_MODE_ADDRESS)); EXPECT_U(1U, ReadWord(0x1000U)); ResetCore(); EXPECT_U(PLSR_MB_OK, WriteWord(0x1000U, 3U)); EXPECT_U(PLSR_MB_ILLEGAL_VALUE, WriteWord(PLSR_OUTPUT_MODE_ADDRESS, PLSR_OUTPUT_MODE_AB)); EXPECT_U(PLSR_OUTPUT_MODE_PULSE_DIR, ReadWord(PLSR_OUTPUT_MODE_ADDRESS)); ResetCore(); EXPECT_U(PLSR_MB_OK, WriteWord(0x1000U, 2U)); EXPECT_U(PLSR_MB_OK, WriteWord(PLSR_OUTPUT_MODE_ADDRESS, PLSR_OUTPUT_MODE_AB)); EXPECT_U(PLSR_MB_ILLEGAL_VALUE, WriteWord(0x1000U, 1U)); EXPECT_U(2U, ReadWord(0x1000U)); EXPECT_U(PLSR_MB_ILLEGAL_VALUE, WriteWord(0x1000U, 3U)); EXPECT_U(2U, ReadWord(0x1000U)); EXPECT_U(PLSR_MB_OK, WriteWord(0x1000U, 0U)); EXPECT_U(0U, ReadWord(0x1000U)); } static void TestAbStopAtCompleteCycleBoundary(void) { ResetCore(); ConfigureAbMotion(0U, 100L, 1000UL, 1000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitAbQuarters(1UL); EXPECT_U(2U, PlsrTestAbPhase()); EXPECT_U(1U, PlsrTestAbTransitionCount()); EXPECT_I(0L, ReadPosition()); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_STOP)); EXPECT_U(PLSR_STATUS_DECELERATING, ReadStatus()); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_U(0UL, PlsrTestAbFastGateCount()); PlsrTestEmitAbQuarters(2UL); EXPECT_U(1U, PlsrTestAbPhase()); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_I(0L, ReadPosition()); PlsrTestEmitAbQuarters(1UL); EXPECT_U(0U, PlsrTestAbPhase()); EXPECT_U(4U, PlsrTestAbTransitionCount()); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_I(1L, ReadPosition()); EXPECT_U(1UL, PlsrTestAbFastGateCount()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_STOPPED, ReadStatus()); } static void TestAbDynamicFrequencyChangesOnlyAtZeroPhase(void) { uint32_t previousFrequency; uint32_t currentFrequency; uint16_t quarter; uint8_t frequencyChanged = 0U; ResetCore(); ConfigureAbMotion(0U, 20L, 1000UL, 1000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitAbQuarters(1UL); EXPECT_U(2U, PlsrTestAbPhase()); EXPECT_U(1000UL, PlsrTestOutputFrequency()); EXPECT_U(PLSR_MB_OK, WriteU32(0x1100U, 2000UL)); PlsrPoll1ms(); previousFrequency = PlsrTestOutputFrequency(); EXPECT_U(1000UL, previousFrequency); for (quarter = 0U; quarter < 12U; quarter++) { PlsrTestEmitAbQuarters(1UL); currentFrequency = PlsrTestOutputFrequency(); if (currentFrequency != previousFrequency) { EXPECT_U(0U, PlsrTestAbPhase()); EXPECT_U(0U, PlsrTestAbTransitionCount() & 3UL); EXPECT_U(1000UL, previousFrequency); EXPECT_U(2000UL, currentFrequency); frequencyChanged = 1U; break; } EXPECT_U(1000UL, currentFrequency); previousFrequency = currentFrequency; } EXPECT_U(1U, frequencyChanged); EXPECT_U(1U, PlsrTestPulseIsActive()); StopAndSettle(); } static void TestAbStaleFrequencyCommitAfterNaturalCompletion(void) { uint16_t flags; ResetCore(); ConfigureAbMotion(0U, 2L, 1000UL, 1000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(PLSR_MB_OK, WriteU32(0x1100U, 2000UL)); PlsrPoll1ms(); EXPECT_U(1000UL, PlsrTestOutputFrequency()); EXPECT_U(1000UL, PlsrTestQueuedFrequency()); PlsrTestCompleteAbCycleOnNextQueueCommit(); PlsrTestEmitAbQuarters(4UL); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_U(0U, PlsrTestAbPhase()); EXPECT_U(8UL, PlsrTestAbTransitionCount()); EXPECT_I(2L, ReadPosition()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); flags = ReadWord(PLSR_DIAG_FLAGS_ADDRESS); EXPECT_U(PLSR_DIAG_COUNT_CHECKED | PLSR_DIAG_COUNT_PASS, flags & (PLSR_DIAG_COUNT_CHECKED | PLSR_DIAG_COUNT_PASS)); EXPECT_U(0U, flags & PLSR_DIAG_FAULT_LATCHED); EXPECT_U(2UL, ReadU32(PLSR_DIAG_EXPECTED_COUNT_ADDRESS)); EXPECT_U(2UL, ReadU32(PLSR_DIAG_OBSERVED_COUNT_ADDRESS)); EXPECT_I(0L, ReadI32(PLSR_DIAG_COUNT_ERROR_ADDRESS)); EXPECT_U(1000UL, ReadU32(PLSR_DIAG_REQUESTED_FREQUENCY_ADDRESS)); EXPECT_U(1000UL, ReadU32(PLSR_DIAG_EXPECTED_TIMER_ADDRESS)); EXPECT_U(1000UL, ReadU32(PLSR_DIAG_ACTIVE_TIMER_ADDRESS)); } static void TestAbDirectionReversalRestartsFromZeroPhase(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 2U, PLSR_SEND_SUBSEQUENT, 1000UL, 1000UL, 1000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, WriteWord(0x1000U, 0U)); EXPECT_U(PLSR_MB_OK, WriteWord(PLSR_OUTPUT_MODE_ADDRESS, PLSR_OUTPUT_MODE_AB)); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 1L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(2U, 1000UL, -1L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitAbQuarters(4UL); EXPECT_U(0U, PlsrTestAbPhase()); EXPECT_U(4U, PlsrTestAbTransitionCount()); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_U(1U, ReadCurrentSegment()); EXPECT_I(1L, ReadPosition()); PlsrPoll1ms(); EXPECT_U(2U, ReadCurrentSegment()); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_U(0U, PlsrTestAbPhase()); EXPECT_U(0x0001U, ReadWord(PLSR_DIAG_MODE_DIRECTION_ADDRESS)); PlsrTestEmitAbQuarters(1UL); EXPECT_U(1U, PlsrTestAbPhase()); EXPECT_U(5U, PlsrTestAbTransitionCount()); EXPECT_I(1L, ReadPosition()); PlsrTestEmitAbQuarters(3UL); EXPECT_U(0U, PlsrTestAbPhase()); EXPECT_U(8U, PlsrTestAbTransitionCount()); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_I(0L, ReadPosition()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); } static void TestAbModePersistence(void) { ResetCore(); ConfigureAbMotion(2U, 4L, 2345UL, 2345UL, 0U, 0U); EXPECT_U(1U, PlsrInit()); EXPECT_U(PLSR_STATUS_IDLE, ReadStatus()); EXPECT_U(2U, ReadWord(0x1000U)); EXPECT_U(PLSR_OUTPUT_MODE_AB, ReadWord(PLSR_OUTPUT_MODE_ADDRESS)); EXPECT_U(2345UL, ReadU32(0x1100U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitPulses(4UL); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_I(4L, ReadPosition()); } static void TestDiagnosticPass(void) { uint16_t flags; ResetCore(); ClearDiagnostic(); ConfigureAbMotion(0U, 8L, 1000UL, 1000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(PLSR_MB_DEVICE_BUSY, WriteWord(PLSR_OUTPUT_MODE_ADDRESS, PLSR_OUTPUT_MODE_PULSE_DIR)); EXPECT_U(PLSR_MB_DEVICE_BUSY, WriteWord(PLSR_DIAGNOSTIC_CONTROL_ADDRESS, 1U)); flags = ReadWord(PLSR_DIAG_FLAGS_ADDRESS); EXPECT_TRUE((flags & PLSR_DIAG_MONITORING_ACTIVE) != 0U); EXPECT_U(1U, ReadWord(PLSR_DIAG_SEGMENT_ADDRESS)); EXPECT_U(0x0101U, ReadWord(PLSR_DIAG_MODE_DIRECTION_ADDRESS)); EXPECT_U(8UL, ReadU32(PLSR_DIAG_EXPECTED_COUNT_ADDRESS)); EXPECT_U(0UL, ReadU32(PLSR_DIAG_OBSERVED_COUNT_ADDRESS)); EXPECT_U(1000UL, ReadU32(PLSR_DIAG_REQUESTED_FREQUENCY_ADDRESS)); EXPECT_U(1000UL, ReadU32(PLSR_DIAG_EXPECTED_TIMER_ADDRESS)); EXPECT_U(1000UL, ReadU32(PLSR_DIAG_ACTIVE_TIMER_ADDRESS)); EXPECT_I(0L, ReadI32(PLSR_DIAG_REQUEST_ERROR_ADDRESS)); PlsrTestEmitPulses(8UL); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); flags = ReadWord(PLSR_DIAG_FLAGS_ADDRESS); EXPECT_U(0U, flags & PLSR_DIAG_MONITORING_ACTIVE); EXPECT_U(PLSR_DIAG_COUNT_CHECKED | PLSR_DIAG_COUNT_PASS, flags & (PLSR_DIAG_COUNT_CHECKED | PLSR_DIAG_COUNT_PASS)); EXPECT_U(PLSR_DIAG_FREQUENCY_CHECKED | PLSR_DIAG_FREQUENCY_PASS, flags & (PLSR_DIAG_FREQUENCY_CHECKED | PLSR_DIAG_FREQUENCY_PASS)); EXPECT_U(PLSR_DIAG_CURVE_CHECKED | PLSR_DIAG_CURVE_PASS, flags & (PLSR_DIAG_CURVE_CHECKED | PLSR_DIAG_CURVE_PASS)); EXPECT_U(0U, flags & PLSR_DIAG_FAULT_LATCHED); EXPECT_U(PLSR_DIAG_REASON_NONE, ReadWord(PLSR_DIAG_REASON_ADDRESS)); EXPECT_U(8UL, ReadU32(PLSR_DIAG_EXPECTED_COUNT_ADDRESS)); EXPECT_U(8UL, ReadU32(PLSR_DIAG_OBSERVED_COUNT_ADDRESS)); EXPECT_I(0L, ReadI32(PLSR_DIAG_COUNT_ERROR_ADDRESS)); EXPECT_U(1000UL, ReadU32(PLSR_DIAG_REQUESTED_FREQUENCY_ADDRESS)); EXPECT_U(1000UL, ReadU32(PLSR_DIAG_EXPECTED_TIMER_ADDRESS)); EXPECT_U(1000UL, ReadU32(PLSR_DIAG_ACTIVE_TIMER_ADDRESS)); EXPECT_I(0L, ReadI32(PLSR_DIAG_REQUEST_ERROR_ADDRESS)); EXPECT_TRUE(ReadU32(PLSR_DIAG_SAMPLE_COUNT_ADDRESS) > 0UL); EXPECT_U(0UL, ReadU32(PLSR_DIAG_MISMATCH_COUNT_ADDRESS)); EXPECT_U(0UL, ReadU32(PLSR_DIAG_MAX_ERROR_ADDRESS)); EXPECT_U(0xFFFFFFFFUL, ReadU32(PLSR_DIAG_FIRST_MISMATCH_ADDRESS)); } static void TestDiagnosticCountFaultAndClear(void) { uint16_t flags; ResetCore(); ConfigureAbMotion(0U, 4L, 1000UL, 1000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestInjectCountOffset(1L); PlsrTestEmitPulses(4UL); PlsrPoll1ms(); flags = ReadWord(PLSR_DIAG_FLAGS_ADDRESS); EXPECT_U(PLSR_DIAG_COUNT_CHECKED, flags & PLSR_DIAG_COUNT_CHECKED); EXPECT_U(0U, flags & PLSR_DIAG_COUNT_PASS); EXPECT_U(PLSR_DIAG_FAULT_LATCHED, flags & PLSR_DIAG_FAULT_LATCHED); EXPECT_U(PLSR_DIAG_REASON_COUNT, ReadWord(PLSR_DIAG_REASON_ADDRESS)); EXPECT_U(4UL, ReadU32(PLSR_DIAG_EXPECTED_COUNT_ADDRESS)); EXPECT_U(5UL, ReadU32(PLSR_DIAG_OBSERVED_COUNT_ADDRESS)); EXPECT_I(1L, ReadI32(PLSR_DIAG_COUNT_ERROR_ADDRESS)); ClearDiagnostic(); } static void TestDiagnosticFrequencyFaultAndClear(void) { uint16_t flags; ResetCore(); ConfigureAbMotion(0U, 8L, 1000UL, 1000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestInjectActiveFrequencyOffset(25L); PlsrTestEmitPulses(8UL); PlsrPoll1ms(); flags = ReadWord(PLSR_DIAG_FLAGS_ADDRESS); EXPECT_U(PLSR_DIAG_FREQUENCY_CHECKED, flags & PLSR_DIAG_FREQUENCY_CHECKED); EXPECT_U(0U, flags & PLSR_DIAG_FREQUENCY_PASS); EXPECT_U(PLSR_DIAG_FAULT_LATCHED, flags & PLSR_DIAG_FAULT_LATCHED); EXPECT_U(PLSR_DIAG_REASON_FREQUENCY, ReadWord(PLSR_DIAG_REASON_ADDRESS)); EXPECT_U(1000UL, ReadU32(PLSR_DIAG_EXPECTED_TIMER_ADDRESS)); EXPECT_U(1025UL, ReadU32(PLSR_DIAG_ACTIVE_TIMER_ADDRESS)); EXPECT_TRUE(ReadU32(PLSR_DIAG_MISMATCH_COUNT_ADDRESS) > 0UL); EXPECT_U(25UL, ReadU32(PLSR_DIAG_MAX_ERROR_ADDRESS)); EXPECT_TRUE(ReadU32(PLSR_DIAG_FIRST_MISMATCH_ADDRESS) != 0xFFFFFFFFUL); ClearDiagnostic(); } static void TestDiagnosticCurveFaultAndClear(void) { uint16_t flags; ResetCore(); ConfigureAbMotion(0U, 50L, 1000UL, 100UL, 1000U, 1000U); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestInjectCurveMismatch(); PlsrTestEmitPulses(50UL); PlsrPoll1ms(); flags = ReadWord(PLSR_DIAG_FLAGS_ADDRESS); EXPECT_U(PLSR_DIAG_CURVE_CHECKED, flags & PLSR_DIAG_CURVE_CHECKED); EXPECT_U(0U, flags & PLSR_DIAG_CURVE_PASS); EXPECT_U(PLSR_DIAG_FAULT_LATCHED, flags & PLSR_DIAG_FAULT_LATCHED); EXPECT_U(PLSR_DIAG_REASON_CURVE, ReadWord(PLSR_DIAG_REASON_ADDRESS)); EXPECT_TRUE(ReadU32(PLSR_DIAG_MISMATCH_COUNT_ADDRESS) > 0UL); EXPECT_TRUE(ReadU32(PLSR_DIAG_FIRST_MISMATCH_ADDRESS) != 0xFFFFFFFFUL); ClearDiagnostic(); } static void TestDiagnosticInterruptedSegments(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 1000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 100L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitPulses(2UL); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_STOP)); PlsrTestEmitPulses(1UL); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_STOPPED, ReadStatus()); ExpectDiagnosticInterrupted(100UL, 3UL); ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 1000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, WriteWord(0x1005U, 10U)); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 100L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_STOP)); EXPECT_U(PLSR_STATUS_STOPPED, ReadStatus()); ExpectDiagnosticInterrupted(100UL, 0UL); ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 1000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 100L, PLSR_ACT_TIME, 0U, 1U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitPulses(3UL); PlsrPoll1ms(); PlsrTestEmitPulses(1UL); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); ExpectDiagnosticInterrupted(100UL, 4UL); ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 1000UL, 0U, 0U); PlsrTestSetInput(0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 100L, PLSR_EXT_SIGNAL, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitPulses(2UL); PlsrTestSetInput(0U, 1U); PlsrPoll1ms(); PlsrTestEmitPulses(1UL); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); ExpectDiagnosticInterrupted(100UL, 3UL); } static void TestDiagnosticFaultLatchNeedsExplicitClear(void) { uint16_t flags; ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 1000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 4L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestInjectCountOffset(1L); PlsrTestEmitPulses(4UL); PlsrPoll1ms(); EXPECT_U(PLSR_DIAG_REASON_COUNT, ReadWord(PLSR_DIAG_REASON_ADDRESS)); PlsrTestInjectCountOffset(0L); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_CLEAR)); flags = ReadWord(PLSR_DIAG_FLAGS_ADDRESS); EXPECT_U(PLSR_DIAG_FAULT_LATCHED, flags & PLSR_DIAG_FAULT_LATCHED); EXPECT_U(0U, flags & PLSR_DIAG_COUNT_PASS); EXPECT_U(PLSR_DIAG_REASON_COUNT, ReadWord(PLSR_DIAG_REASON_ADDRESS)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitPulses(4UL); PlsrPoll1ms(); flags = ReadWord(PLSR_DIAG_FLAGS_ADDRESS); EXPECT_U(PLSR_DIAG_COUNT_CHECKED, flags & PLSR_DIAG_COUNT_CHECKED); EXPECT_U(0U, flags & PLSR_DIAG_COUNT_PASS); EXPECT_U(PLSR_DIAG_FAULT_LATCHED, flags & PLSR_DIAG_FAULT_LATCHED); EXPECT_U(PLSR_DIAG_REASON_COUNT, ReadWord(PLSR_DIAG_REASON_ADDRESS)); EXPECT_U(4UL, ReadU32(PLSR_DIAG_OBSERVED_COUNT_ADDRESS)); EXPECT_I(0L, ReadI32(PLSR_DIAG_COUNT_ERROR_ADDRESS)); ClearDiagnostic(); } static void TestDiagnosticFrequencyPassStaysFailed(void) { uint16_t flags; ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 1000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 4L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestInjectActiveFrequencyOffset(25L); PlsrTestEmitPulses(4UL); PlsrPoll1ms(); flags = ReadWord(PLSR_DIAG_FLAGS_ADDRESS); EXPECT_U(0U, flags & PLSR_DIAG_FREQUENCY_PASS); EXPECT_U(PLSR_DIAG_REASON_FREQUENCY, ReadWord(PLSR_DIAG_REASON_ADDRESS)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitPulses(4UL); PlsrPoll1ms(); flags = ReadWord(PLSR_DIAG_FLAGS_ADDRESS); EXPECT_U(PLSR_DIAG_FREQUENCY_CHECKED, flags & PLSR_DIAG_FREQUENCY_CHECKED); EXPECT_U(0U, flags & PLSR_DIAG_FREQUENCY_PASS); EXPECT_U(PLSR_DIAG_FAULT_LATCHED, flags & PLSR_DIAG_FAULT_LATCHED); EXPECT_U(PLSR_DIAG_REASON_FREQUENCY, ReadWord(PLSR_DIAG_REASON_ADDRESS)); ClearDiagnostic(); } static void TestDiagnosticCurveCountersSaturate(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 1000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 2L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestSetDiagnosticCurveCounts(0xFFFFFFFFUL, 0xFFFFFFFFUL); PlsrTestInjectCurveMismatch(); PlsrTestEmitPulses(2UL); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(0xFFFFFFFFUL, ReadU32(PLSR_DIAG_SAMPLE_COUNT_ADDRESS)); EXPECT_U(0xFFFFFFFFUL, ReadU32(PLSR_DIAG_MISMATCH_COUNT_ADDRESS)); EXPECT_U(PLSR_DIAG_REASON_CURVE, ReadWord(PLSR_DIAG_REASON_ADDRESS)); } static void TestWaitZeroUsesOneMillisecond(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 2U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 100UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 1L, PLSR_WAIT_TIME, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(2U, 1000UL, 1L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitPulses(1UL); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_WAITING, ReadStatus()); EXPECT_U(1U, ReadCurrentSegment()); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(2U, ReadCurrentSegment()); EXPECT_U(1U, PlsrTestPulseIsActive()); PlsrTestEmitPulses(1UL); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_I(2L, ReadPosition()); } static void TestActZeroSkipsWithoutPulse(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 2U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 100UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 100L, PLSR_ACT_TIME, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(2U, 1000UL, 1L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_U(1U, ReadCurrentSegment()); EXPECT_I(0L, ReadPosition()); PlsrPoll1ms(); EXPECT_U(2U, ReadCurrentSegment()); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_I(0L, ReadPosition()); PlsrTestEmitPulses(1UL); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_I(1L, ReadPosition()); } static void TestRelativeAndAbsoluteZeroDisplacement(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 100UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 0L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(PLSR_STATUS_RUNNING, ReadStatus()); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_I(0L, ReadPosition()); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 5L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitPulses(5UL); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_I(5L, ReadPosition()); EXPECT_U(PLSR_MB_OK, WriteWord(0x1008U, PLSR_POSITION_ABSOLUTE)); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 5L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_I(5L, ReadPosition()); } static void ConfigureTenSegmentMove(const uint8_t *jumpSegments) { uint16_t segment; ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 10U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 1000UL, 0U, 0U); for (segment = 1U; segment <= 10U; segment++) { EXPECT_U(PLSR_MB_OK, SetSegment((uint8_t)segment, 1000UL, (int32_t)segment, PLSR_EXT_OR_COMPLETE, 0U, 0U, (jumpSegments != NULL) ? jumpSegments[segment - 1U] : 0U)); } } static void TestAllTenSegmentsRunInSequence(void) { int32_t expectedPosition = 0L; uint16_t segment; ResetCore(); ConfigureTenSegmentMove(NULL); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); for (segment = 1U; segment <= 10U; segment++) { EXPECT_U(segment, ReadCurrentSegment()); EXPECT_U(1U, PlsrTestPulseIsActive()); PlsrTestEmitPulses((uint32_t)segment); expectedPosition += (int32_t)segment; EXPECT_I(expectedPosition, ReadPosition()); PlsrPoll1ms(); if (segment < 10U) { EXPECT_U(segment + 1U, ReadCurrentSegment()); EXPECT_U(PLSR_STATUS_RUNNING, ReadStatus()); } } EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(0U, ReadCurrentSegment()); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_I(55L, ReadPosition()); } static void TestCompleteTenSegmentFrequencyStaircase(void) { uint64_t elapsedNs = 0ULL; uint64_t nextPollNs = 1000000ULL; uint16_t segment; ResetCore(); PlsrTestEnableFinitePulseTrain(1U); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 10U, PLSR_SEND_COMPLETE, 10000UL, 100UL, 100UL, 10U, 10U); for (segment = 1U; segment <= 10U; segment++) { EXPECT_U(PLSR_MB_OK, SetSegment((uint8_t)segment, (uint32_t)segment * 1000UL, 100L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); } EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); for (segment = 1U; segment <= 10U; segment++) { uint32_t maximumFrequencyHz = 0UL; uint16_t trailingLowSpeedPulses = 0U; uint16_t pulse; while ((ReadCurrentSegment() != segment) && (ReadStatus() != PLSR_STATUS_ERROR)) { PlsrPoll1ms(); elapsedNs += 1000000ULL; nextPollNs = elapsedNs + 1000000ULL; } EXPECT_U(segment, ReadCurrentSegment()); for (pulse = 0U; pulse < 100U; pulse++) { uint32_t frequencyHz = PlsrTestOutputFrequency(); EXPECT_U(1U, PlsrTestPulseIsActive()); if (frequencyHz > maximumFrequencyHz) { maximumFrequencyHz = frequencyHz; } if (frequencyHz <= 200UL) { trailingLowSpeedPulses++; } else { trailingLowSpeedPulses = 0U; } elapsedNs += PulsePeriodNs(frequencyHz); PlsrTestEmitPulses(1UL); while ((pulse + 1U < 100U) && (elapsedNs >= nextPollNs)) { PlsrPoll1ms(); nextPollNs += 1000000ULL; } } if (segment < 10U) { EXPECT_U(1U, PlsrTestFinitePulseTrainActive()); EXPECT_U(1U, PlsrTestPulseIsActive()); } EXPECT_TRUE(maximumFrequencyHz >= ((uint32_t)segment * 1000UL * 99UL) / 100UL); EXPECT_TRUE(trailingLowSpeedPulses <= 2U); } while ((ReadStatus() != PLSR_STATUS_COMPLETED) && (ReadStatus() != PLSR_STATUS_ERROR)) { PlsrPoll1ms(); } EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_I(1000L, ReadPosition()); } static void TestCompleteCarriesSpeedAcrossNaturalBoundaries(void) { uint64_t elapsedNs = 0ULL; uint64_t nextPollNs = 1000000ULL; uint32_t firstFrequencyHz[3]; uint32_t lastFrequencyHz[3] = {0UL, 0UL, 0UL}; uint32_t minimumFrequencyHz[3] = { 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL }; uint8_t segment; ResetCore(); PlsrTestEnableFinitePulseTrain(1U); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 3U, PLSR_SEND_COMPLETE, 3000UL, 100UL, 200UL, 10U, 10U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 100L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(2U, 2000UL, 100L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(3U, 3000UL, 100L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); for (segment = 0U; segment < 3U; segment++) { uint16_t pulse; while (((ReadCurrentSegment() != (uint32_t)segment + 1UL) || (PlsrTestPulseIsActive() == 0U)) && (ReadStatus() != PLSR_STATUS_ERROR) && (ReadStatus() != PLSR_STATUS_COMPLETED)) { PlsrPoll1ms(); nextPollNs = elapsedNs + 1000000ULL; } EXPECT_U((uint32_t)segment + 1UL, ReadCurrentSegment()); EXPECT_U(1U, PlsrTestPulseIsActive()); firstFrequencyHz[segment] = PlsrTestOutputFrequency(); for (pulse = 0U; pulse < 100U; pulse++) { uint32_t frequencyHz = PlsrTestOutputFrequency(); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_TRUE(frequencyHz != 0UL); if (frequencyHz == 0UL) { break; } if (frequencyHz < minimumFrequencyHz[segment]) { minimumFrequencyHz[segment] = frequencyHz; } lastFrequencyHz[segment] = frequencyHz; elapsedNs += PulsePeriodNs(frequencyHz); PlsrTestEmitPulses(1UL); while ((pulse + 1U < 100U) && (elapsedNs >= nextPollNs)) { PlsrPoll1ms(); nextPollNs += 1000000ULL; } } } EXPECT_TRUE(firstFrequencyHz[0] >= 400UL); EXPECT_TRUE(firstFrequencyHz[0] <= 410UL); EXPECT_U(2000UL, firstFrequencyHz[1]); EXPECT_U(3000UL, firstFrequencyHz[2]); EXPECT_U(1000UL, lastFrequencyHz[0]); EXPECT_U(2000UL, lastFrequencyHz[1]); EXPECT_TRUE(minimumFrequencyHz[1] >= 1900UL); EXPECT_TRUE(lastFrequencyHz[2] <= 1500UL); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_I(300L, ReadPosition()); } static void TestCompleteJumpCarriesSpeedToTargetSegment(void) { uint64_t elapsedNs = 0ULL; uint64_t nextPollNs = 1000000ULL; uint16_t pulse; ResetCore(); PlsrTestEnableFinitePulseTrain(1U); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 3U, PLSR_SEND_COMPLETE, 3000UL, 100UL, 200UL, 10U, 10U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 100L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 3U)); EXPECT_U(PLSR_MB_OK, SetSegment(2U, 2000UL, 100L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(3U, 3000UL, 100L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_TRUE(PlsrTestOutputFrequency() >= 400UL); EXPECT_TRUE(PlsrTestOutputFrequency() <= 410UL); for (pulse = 0U; pulse < 100U; pulse++) { uint32_t frequencyHz = PlsrTestOutputFrequency(); elapsedNs += PulsePeriodNs(frequencyHz); PlsrTestEmitPulses(1UL); while ((pulse + 1U < 100U) && (elapsedNs >= nextPollNs)) { PlsrPoll1ms(); nextPollNs += 1000000ULL; } } while ((ReadCurrentSegment() != 3U) && (ReadStatus() != PLSR_STATUS_ERROR)) { PlsrPoll1ms(); nextPollNs = elapsedNs + 1000000ULL; } EXPECT_U(3U, ReadCurrentSegment()); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_TRUE(PlsrTestOutputFrequency() >= 2900UL); for (pulse = 0U; pulse < 100U; pulse++) { uint32_t frequencyHz = PlsrTestOutputFrequency(); elapsedNs += PulsePeriodNs(frequencyHz); PlsrTestEmitPulses(1UL); while ((pulse + 1U < 100U) && (elapsedNs >= nextPollNs)) { PlsrPoll1ms(); nextPollNs += 1000000ULL; } } PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_I(200L, ReadPosition()); } static void TestTenMillisecondBoundaryRampHasNoSlowTail(void) { uint64_t elapsedNs = 0ULL; uint64_t nextPollNs = 1000000ULL; uint32_t maximumFrequencyHz = 0UL; uint16_t trailingLowSpeedPulses = 0U; uint16_t pulse; ResetCore(); PlsrTestEnableFinitePulseTrain(1U); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 10000UL, 100UL, 100UL, 10U, 10U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 10000UL, 1000L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); for (pulse = 0U; pulse < 1000U; pulse++) { uint32_t frequencyHz = PlsrTestOutputFrequency(); EXPECT_U(1U, PlsrTestPulseIsActive()); if (frequencyHz > maximumFrequencyHz) { maximumFrequencyHz = frequencyHz; } if (frequencyHz <= 200UL) { trailingLowSpeedPulses++; } else { trailingLowSpeedPulses = 0U; } elapsedNs += PulsePeriodNs(frequencyHz); PlsrTestEmitPulses(1UL); while ((pulse + 1U < 1000U) && (elapsedNs >= nextPollNs)) { PlsrPoll1ms(); nextPollNs += 1000000ULL; } } EXPECT_TRUE(maximumFrequencyHz >= 9900UL); EXPECT_TRUE(trailingLowSpeedPulses <= 2U); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_I(1000L, ReadPosition()); } static void TestFiniteShortSingleSegmentUsesPulseProfile(void) { uint32_t samples[100]; uint64_t durationNs = 0ULL; uint16_t pulse; ResetCore(); PlsrTestEnableFinitePulseTrain(1U); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 10000UL, 100UL, 100UL, 10U, 10U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 100L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(0U, PlsrTestProfileQueueCount()); EXPECT_U(1U, PlsrTestFinitePulseTrainActive()); for (pulse = 0U; pulse < 100U; pulse++) { samples[pulse] = PlsrTestOutputFrequency(); durationNs += PulsePeriodNs(samples[pulse]); EXPECT_U(1U, PlsrTestPulseIsActive()); PlsrTestEmitPulses(1UL); } EXPECT_TRUE((samples[0] >= 549UL) && (samples[0] <= 551UL)); EXPECT_TRUE((samples[99] >= 549UL) && (samples[99] <= 551UL)); for (pulse = 1U; pulse < 99U; pulse++) { EXPECT_U(1000UL, samples[pulse]); } EXPECT_TRUE(durationNs >= 101600000ULL); EXPECT_TRUE(durationNs <= 101700000ULL); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_I(100L, ReadPosition()); } static void TestFiniteProfileThreeSegmentsRunsWithoutPollGap(void) { uint32_t samples[300]; uint16_t pulse; ResetCore(); PlsrTestEnableFinitePulseTrain(1U); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 3U, PLSR_SEND_COMPLETE, 10000UL, 100UL, 100UL, 10U, 10U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 100L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(2U, 2000UL, 100L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(3U, 3000UL, 100L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); for (pulse = 0U; pulse < 300U; pulse++) { samples[pulse] = PlsrTestOutputFrequency(); EXPECT_U(1U, PlsrTestFinitePulseTrainActive()); PlsrTestEmitPulses(1UL); } EXPECT_TRUE((samples[0] >= 549UL) && (samples[0] <= 551UL)); EXPECT_U(1000UL, samples[1]); EXPECT_U(1000UL, samples[99]); EXPECT_U(2000UL, samples[100]); EXPECT_U(2000UL, samples[199]); EXPECT_U(3000UL, samples[200]); EXPECT_TRUE(samples[299] < samples[298]); EXPECT_TRUE(samples[298] < samples[297]); EXPECT_U(0U, PlsrTestFinitePulseTrainActive()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_I(300L, ReadPosition()); } static void TestAllTenSegmentsRunThroughJumpChain(void) { static const uint8_t jumps[10] = { 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 2U, 0U }; static const uint8_t order[10] = { 1U, 3U, 5U, 7U, 9U, 2U, 4U, 6U, 8U, 10U }; int32_t expectedPosition = 0L; uint16_t index; ResetCore(); ConfigureTenSegmentMove(jumps); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); for (index = 0U; index < 10U; index++) { uint8_t segment = order[index]; EXPECT_U(segment, ReadCurrentSegment()); EXPECT_U(1U, PlsrTestPulseIsActive()); PlsrTestEmitPulses((uint32_t)segment); expectedPosition += (int32_t)segment; EXPECT_I(expectedPosition, ReadPosition()); PlsrPoll1ms(); if (index + 1U < 10U) { EXPECT_U(order[index + 1U], ReadCurrentSegment()); EXPECT_U(PLSR_STATUS_RUNNING, ReadStatus()); } } EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(0U, ReadCurrentSegment()); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_I(55L, ReadPosition()); } static void TestStartSegmentTenRunsNormally(void) { ResetCore(); ConfigureTenSegmentMove(NULL); EXPECT_U(PLSR_MB_OK, WriteWord(0x100AU, 10U)); EXPECT_U(10U, ReadWord(0x100AU)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(10U, ReadCurrentSegment()); EXPECT_U(1U, PlsrTestPulseIsActive()); PlsrTestEmitPulses(10UL); EXPECT_I(10L, ReadPosition()); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(0U, ReadCurrentSegment()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_I(10L, ReadPosition()); } static void TestSelfJumpCanStop(void) { unsigned int loop; ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 100UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 2L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 1U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); for (loop = 0U; loop < 3U; loop++) { PlsrTestEmitPulses(2UL); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_RUNNING, ReadStatus()); EXPECT_U(1U, ReadCurrentSegment()); EXPECT_U(1U, PlsrTestPulseIsActive()); } StopAndSettle(); } static void TestStopDeceleratesBeforeCut(void) { unsigned int tick; uint32_t middleFrequency; ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 100UL, 0U, 1000U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 10000L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(1000UL, PlsrTestOutputFrequency()); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_STOP)); EXPECT_U(PLSR_STATUS_DECELERATING, ReadStatus()); EXPECT_U(1U, PlsrTestPulseIsActive()); for (tick = 0U; tick < 450U; tick++) { PlsrPoll1ms(); PlsrTestEmitPulses(1UL); } middleFrequency = PlsrTestOutputFrequency(); EXPECT_TRUE((middleFrequency > 100UL) && (middleFrequency < 1000UL)); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_U(PLSR_MB_OK, QueueCommand(PLSR_COMMAND_STOP)); for (tick = 450U; tick < 900U; tick++) { PlsrPoll1ms(); PlsrTestEmitPulses(1UL); } EXPECT_TRUE(PlsrTestOutputFrequency() > 100UL); EXPECT_TRUE(PlsrTestOutputFrequency() <= 103UL); EXPECT_U(PLSR_STATUS_DECELERATING, ReadStatus()); EXPECT_U(1U, PlsrTestPulseIsActive()); PlsrTestEmitPulses(1UL); EXPECT_U(100UL, PlsrTestOutputFrequency()); EXPECT_U(1U, PlsrTestPulseIsActive()); PlsrTestEmitPulses(1UL); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_STOPPED, ReadStatus()); EXPECT_I(902L, ReadPosition()); } static void TestStopAtPendingBoundary(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 100UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 1L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitPulses(1UL); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_STOP)); EXPECT_U(PLSR_STATUS_RUNNING, ReadStatus()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_STOPPED, ReadStatus()); EXPECT_U(0U, ReadCurrentSegment()); EXPECT_I(1L, ReadPosition()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_STOPPED, ReadStatus()); EXPECT_U(0U, PlsrTestPulseIsActive()); } static void TestOneMillisecondDirectionDelay(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 100UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, WriteWord(0x1005U, 1U)); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 10L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_U(1000UL, PlsrTestOutputFrequency()); StopAndSettle(); } static void ExpectDirectionPinLevels(uint8_t selectedOutput, uint8_t selectedPinLevel) { uint8_t output; for (output = 0U; output < 4U; output++) { EXPECT_U((output == selectedOutput) ? selectedPinLevel : 1U, PlsrTestDirectionPinLevel(output)); } } static void TestDirectionOutputPolarityMatrix(void) { uint8_t directionOutput; uint8_t negativeLogic; uint8_t positive; for (directionOutput = 0U; directionOutput < 4U; directionOutput++) { for (negativeLogic = 0U; negativeLogic < 2U; negativeLogic++) { for (positive = 0U; positive < 2U; positive++) { uint8_t logicalLevel = positive ^ negativeLogic; uint8_t pinLevel = logicalLevel ^ 1U; uint8_t output; ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 1000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, WriteWord(0x1001U, directionOutput)); EXPECT_U(PLSR_MB_OK, WriteWord(0x1005U, 2U)); EXPECT_U(PLSR_MB_OK, WriteWord(0x1006U, negativeLogic)); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, (positive != 0U) ? 1L : -1L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(directionOutput, ReadWord(0x1001U)); EXPECT_U(negativeLogic, ReadWord(0x1006U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(logicalLevel, PlsrTestDirectionLevel()); ExpectDirectionPinLevels(directionOutput, pinLevel); EXPECT_U(0U, PlsrTestPulseIsActive()); for (output = 0U; output < 4U; output++) { EXPECT_U(1UL, PlsrTestDirectionWriteCount(output)); EXPECT_U(((output == directionOutput) && (pinLevel == 0U)) ? 1UL : 0UL, PlsrTestDirectionTransitionCount(output)); } PlsrPoll1ms(); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(1U, PlsrTestPulseIsActive()); PlsrTestEmitPulses(1UL); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_I((positive != 0U) ? 1L : -1L, ReadPosition()); } } } } static void TestDirectionSameAndReverseSegments(void) { uint8_t output; ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 3U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 1000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, WriteWord(0x1001U, 2U)); EXPECT_U(PLSR_MB_OK, WriteWord(0x1005U, 2U)); EXPECT_U(PLSR_MB_OK, WriteWord(0x1006U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 1L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(2U, 1000UL, 1L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(3U, 1000UL, -1L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(1U, PlsrTestDirectionLevel()); ExpectDirectionPinLevels(2U, 0U); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(1U, PlsrTestPulseIsActive()); PlsrTestEmitPulses(1UL); PlsrPoll1ms(); EXPECT_U(2U, ReadCurrentSegment()); EXPECT_U(1U, PlsrTestPulseIsActive()); ExpectDirectionPinLevels(2U, 0U); EXPECT_U(1UL, PlsrTestDirectionTransitionCount(2U)); PlsrTestEmitPulses(1UL); PlsrPoll1ms(); EXPECT_U(3U, ReadCurrentSegment()); EXPECT_U(0U, PlsrTestDirectionLevel()); ExpectDirectionPinLevels(2U, 1U); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_U(2UL, PlsrTestDirectionTransitionCount(2U)); for (output = 0U; output < 4U; output++) { EXPECT_U(3UL, PlsrTestDirectionWriteCount(output)); if (output != 2U) { EXPECT_U(0UL, PlsrTestDirectionTransitionCount(output)); } } PlsrPoll1ms(); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(1U, PlsrTestPulseIsActive()); PlsrTestEmitPulses(1UL); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_I(1L, ReadPosition()); } static void TestDirectionOutputCanChangeBetweenCommands(void) { uint8_t output; ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 1000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, WriteWord(0x1001U, 0U)); EXPECT_U(PLSR_MB_OK, WriteWord(0x1005U, 1U)); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 1L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); ExpectDirectionPinLevels(0U, 0U); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(1U, PlsrTestPulseIsActive()); PlsrTestEmitPulses(1UL); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_MB_OK, WriteWord(0x1001U, 3U)); EXPECT_U(3U, ReadWord(0x1001U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); ExpectDirectionPinLevels(3U, 0U); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_U(2UL, PlsrTestDirectionTransitionCount(0U)); EXPECT_U(1UL, PlsrTestDirectionTransitionCount(3U)); for (output = 0U; output < 4U; output++) { EXPECT_U(2UL, PlsrTestDirectionWriteCount(output)); } PlsrPoll1ms(); EXPECT_U(1U, PlsrTestPulseIsActive()); PlsrTestEmitPulses(1UL); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_I(2L, ReadPosition()); } static void TestExtEdgeAtNaturalBoundary(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 100UL, 0U, 0U); PlsrTestSetInput(0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 1L, PLSR_EXT_SIGNAL, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitPulseOnCriticalEntry(); PlsrTestSetInput(0U, 1U); PlsrPoll1ms(); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(0U, ReadCurrentSegment()); EXPECT_I(1L, ReadPosition()); } static void ConfigureExtBoundaryCarryRace(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 2U, PLSR_SEND_SUBSEQUENT, 2000UL, 500UL, 1000UL, 0U, 1000U); PlsrTestSetInput(0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 2000UL, 1L, PLSR_EXT_SIGNAL, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(2U, 1000UL, 70000L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(2000UL, PlsrTestOutputFrequency()); PlsrTestSetInput(0U, 1U); } static void ExpectExtBoundaryCarry(void) { EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_U(1U, ReadCurrentSegment()); PlsrPoll1ms(); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_U(2U, ReadCurrentSegment()); EXPECT_TRUE(PlsrTestOutputFrequency() >= 1999UL); EXPECT_TRUE(PlsrTestOutputFrequency() <= 2001UL); EXPECT_I(1L, ReadPosition()); } static void TestExtCutAndNaturalBoundaryInterleavings(void) { ConfigureExtBoundaryCarryRace(); PlsrTestEmitPulseAfterCriticalEntries(3U); PlsrPoll1ms(); ExpectExtBoundaryCarry(); ConfigureExtBoundaryCarryRace(); PlsrPoll1ms(); EXPECT_U(1U, PlsrTestPulseIsActive()); PlsrTestEmitPulses(1UL); ExpectExtBoundaryCarry(); } static void TestExtEdgeDuringDirectionDelay(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 100UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, WriteWord(0x1005U, 2U)); PlsrTestSetInput(0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 1L, PLSR_EXT_SIGNAL, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestSetInput(0U, 1U); PlsrPoll1ms(); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(1U, PlsrTestPulseIsActive()); PlsrTestEmitPulses(1UL); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_I(1L, ReadPosition()); } static void TestStoppedTaskClearsPendingExtEdge(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 100UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, WriteWord(0x1005U, 2U)); PlsrTestSetInput(0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 100L, PLSR_EXT_SIGNAL, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrTestSetInput(0U, 1U); PlsrPoll1ms(); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_STOP)); EXPECT_U(PLSR_STATUS_STOPPED, ReadStatus()); PlsrTestSetInput(0U, 0U); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(1U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_I(0L, ReadPosition()); StopAndSettle(); } static void TestExtEdgeDoesNotCutSeamlessNextSegment(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 2U, PLSR_SEND_SUBSEQUENT, 1000UL, 1000UL, 100UL, 0U, 0U); PlsrTestSetInput(0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 1L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(2U, 2000UL, 4L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestSetInput(0U, 1U); PlsrTestEmitPulseAfterCriticalEntries(3U); PlsrPoll1ms(); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_U(2U, ReadCurrentSegment()); EXPECT_U(2000UL, PlsrTestOutputFrequency()); EXPECT_I(1L, ReadPosition()); PlsrTestEmitPulses(4UL); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_I(5L, ReadPosition()); } static void TestOldRampDoesNotRetargetSeamlessNextSegment(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 2U, PLSR_SEND_SUBSEQUENT, 2000UL, 1000UL, 100UL, 100U, 0U); PlsrTestSetInput(0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 2000UL, 1L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(2U, 3000UL, 4L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitPulseAfterCriticalEntries(3U); PlsrPoll1ms(); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_U(2U, ReadCurrentSegment()); EXPECT_U(3000UL, PlsrTestOutputFrequency()); EXPECT_I(1L, ReadPosition()); PlsrTestEmitPulses(4UL); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_I(5L, ReadPosition()); } static void TestShortProfileBoundaryMatrix(void) { static const uint16_t pulseCounts[] = { 1U, 2U, 10U, 99U, 100U, 101U, 258U }; uint32_t samples[3][258]; uint64_t previousDurationNs[3] = {0ULL, 0ULL, 0ULL}; uint64_t durationNs[3]; unsigned int countIndex; uint16_t curveMode; unsigned int pulse; unsigned int firstPeak; unsigned int lastPeak; uint32_t peakFrequencyHz; uint32_t expectedPeakHz; uint64_t expectedDurationNs; uint64_t toleranceNs; uint8_t linearDiffersFromSmooth; uint8_t smoothDiffersFromSine; uint8_t anyLinearDiffersFromSmooth = 0U; uint8_t anySmoothDiffersFromSine = 0U; for (countIndex = 0U; countIndex < sizeof(pulseCounts) / sizeof(pulseCounts[0]); countIndex++) { for (curveMode = 0U; curveMode <= 2U; curveMode++) { ResetCore(); ConfigureCommon(curveMode, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 100UL, 100UL, 1000U, 1000U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, pulseCounts[countIndex], PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(1U, PlsrTestPulseIsActive()); durationNs[curveMode] = 0ULL; for (pulse = 0U; pulse < pulseCounts[countIndex]; pulse++) { samples[curveMode][pulse] = PlsrTestOutputFrequency(); EXPECT_TRUE(samples[curveMode][pulse] >= 100UL); EXPECT_TRUE(samples[curveMode][pulse] <= 1000UL); durationNs[curveMode] += PulsePeriodNs(samples[curveMode][pulse]); PlsrTestEmitPulses(1UL); if (((pulse + 1U) % 100U) == 0U) { PlsrPoll1ms(); } if ((pulse + 1U) < pulseCounts[countIndex]) { EXPECT_U(1U, PlsrTestPulseIsActive()); } } peakFrequencyHz = samples[curveMode][0]; firstPeak = 0U; lastPeak = 0U; for (pulse = 1U; pulse < pulseCounts[countIndex]; pulse++) { if (samples[curveMode][pulse] > peakFrequencyHz) { peakFrequencyHz = samples[curveMode][pulse]; firstPeak = pulse; lastPeak = pulse; } else if (samples[curveMode][pulse] == peakFrequencyHz) { lastPeak = pulse; } } for (pulse = 1U; pulse <= firstPeak; pulse++) { EXPECT_TRUE(samples[curveMode][pulse] >= samples[curveMode][pulse - 1U]); } for (pulse = firstPeak + 1U; pulse <= lastPeak; pulse++) { EXPECT_U(peakFrequencyHz, samples[curveMode][pulse]); } for (pulse = lastPeak + 1U; pulse < pulseCounts[countIndex]; pulse++) { EXPECT_TRUE(samples[curveMode][pulse] <= samples[curveMode][pulse - 1U]); } EXPECT_TRUE((samples[curveMode][0] > samples[curveMode][pulseCounts[countIndex] - 1U] ? samples[curveMode][0] - samples[curveMode][pulseCounts[countIndex] - 1U] : samples[curveMode][pulseCounts[countIndex] - 1U] - samples[curveMode][0]) <= 2UL); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_I((long)pulseCounts[countIndex], ReadPosition()); EXPECT_TRUE(durationNs[curveMode] > previousDurationNs[curveMode]); previousDurationNs[curveMode] = durationNs[curveMode]; expectedPeakHz = IntegerSquareRoot64( 10000ULL + (uint64_t)pulseCounts[countIndex] * 1000ULL); expectedDurationNs = (uint64_t)2U * (expectedPeakHz - 100UL) * 1000000ULL; toleranceNs = expectedDurationNs / 8ULL + 2000000ULL; EXPECT_TRUE(UnsignedDifference64(durationNs[curveMode], expectedDurationNs) <= toleranceNs); } toleranceNs = durationNs[0] / 50ULL + 1000000ULL; EXPECT_TRUE(UnsignedDifference64(durationNs[0], durationNs[1]) <= toleranceNs); EXPECT_TRUE(UnsignedDifference64(durationNs[1], durationNs[2]) <= toleranceNs); if (pulseCounts[countIndex] >= 10U) { linearDiffersFromSmooth = 0U; smoothDiffersFromSine = 0U; for (pulse = 0U; pulse < pulseCounts[countIndex]; pulse++) { if (samples[0][pulse] != samples[1][pulse]) { linearDiffersFromSmooth = 1U; } if (samples[1][pulse] != samples[2][pulse]) { smoothDiffersFromSine = 1U; } } EXPECT_U(1U, linearDiffersFromSmooth); if (linearDiffersFromSmooth != 0U) { anyLinearDiffersFromSmooth = 1U; } if (smoothDiffersFromSine != 0U) { anySmoothDiffersFromSine = 1U; } } } EXPECT_U(1U, anyLinearDiffersFromSmooth); EXPECT_U(1U, anySmoothDiffersFromSine); } static void CaptureShortProfileFrequencies(uint16_t curveMode, uint16_t pulseCount, uint32_t startSpeedHz, uint32_t stopSpeedHz, uint16_t accelerationTimeMs, uint16_t decelerationTimeMs, uint32_t *samples) { uint16_t pulse; ResetCore(); ConfigureCommon(curveMode, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 100000UL, startSpeedHz, stopSpeedHz, accelerationTimeMs, decelerationTimeMs); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 100000UL, pulseCount, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); for (pulse = 0U; pulse < pulseCount; pulse++) { EXPECT_U(1U, PlsrTestPulseIsActive()); samples[pulse] = PlsrTestOutputFrequency(); PlsrTestEmitPulses(1UL); } EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_I((long)pulseCount, ReadPosition()); ExpectCompletedDiagnostic(pulseCount); } static void TestZeroRampTimesIgnoreStartAndStopSpeeds(void) { static const uint16_t pulseCounts[] = {1U, 2U, 10U}; uint32_t firstSamples[10]; uint32_t secondSamples[10]; uint16_t curveMode; uint16_t countIndex; uint16_t pulse; for (curveMode = 0U; curveMode <= 2U; curveMode++) { for (countIndex = 0U; countIndex < sizeof(pulseCounts) / sizeof(pulseCounts[0]); countIndex++) { uint16_t pulseCount = pulseCounts[countIndex]; CaptureShortProfileFrequencies(curveMode, pulseCount, 100UL, 100UL, 0U, 0U, firstSamples); for (pulse = 0U; pulse < pulseCount; pulse++) { EXPECT_U(100000UL, firstSamples[pulse]); } CaptureShortProfileFrequencies(curveMode, pulseCount, 100UL, 100UL, 0U, 1000U, firstSamples); CaptureShortProfileFrequencies(curveMode, pulseCount, 50000UL, 100UL, 0U, 1000U, secondSamples); for (pulse = 0U; pulse < pulseCount; pulse++) { EXPECT_U(firstSamples[pulse], secondSamples[pulse]); } CaptureShortProfileFrequencies(curveMode, pulseCount, 100UL, 100UL, 1000U, 0U, firstSamples); CaptureShortProfileFrequencies(curveMode, pulseCount, 100UL, 50000UL, 1000U, 0U, secondSamples); for (pulse = 0U; pulse < pulseCount; pulse++) { EXPECT_U(firstSamples[pulse], secondSamples[pulse]); } } } } static void TestZeroSegmentFrequencyUsesDefaultSpeed(void) { uint32_t explicitSamples[1000]; uint32_t defaultSamples[1000]; uint16_t pulse; CaptureShortProfileFrequencies(0U, 1000U, 100UL, 100UL, 100U, 100U, explicitSamples); ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 100000UL, 100UL, 100UL, 100U, 100U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 0UL, 1000L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(0UL, ReadU32(0x1100U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); for (pulse = 0U; pulse < 1000U; pulse++) { defaultSamples[pulse] = PlsrTestOutputFrequency(); PlsrTestEmitPulses(1UL); } PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_I(1000L, ReadPosition()); for (pulse = 0U; pulse < 1000U; pulse++) { EXPECT_U(explicitSamples[pulse], defaultSamples[pulse]); } } static void TestShortProfile258IsFullyPrecomputed(void) { uint16_t curveMode; for (curveMode = 0U; curveMode <= 2U; curveMode++) { ResetCore(); ConfigureCommon(curveMode, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 100000UL, 1000UL, 1000UL, 100U, 100U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 100000UL, 258L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(256U, PlsrTestProfileQueueCount()); EXPECT_U(0UL, PlsrTestProfileQueueReadIndex()); EXPECT_U(256UL, PlsrTestProfileQueueWriteIndex()); EXPECT_U(258U, PlsrTestProfileProducerNextPeriod()); PlsrTestEmitPulses(258UL); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_U(0U, PlsrTestProfileQueueCount()); EXPECT_U(256UL, PlsrTestProfileQueueReadIndex()); EXPECT_U(256UL, PlsrTestProfileQueueWriteIndex()); EXPECT_I(258L, ReadPosition()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); } } static void TestShortFinalDeceleratesWithoutPoll(void) { uint16_t curveMode; unsigned int pulse; uint32_t previousFrequencyHz; uint32_t currentFrequencyHz; uint64_t durationNs; for (curveMode = 0U; curveMode <= 2U; curveMode++) { ResetCore(); ConfigureCommon(curveMode, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 100000UL, 100000UL, 100UL, 0U, 1000U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 100000UL, 10L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); previousFrequencyHz = PlsrTestOutputFrequency(); EXPECT_TRUE(previousFrequencyHz >= 99990UL); EXPECT_TRUE(previousFrequencyHz <= 100000UL); durationNs = PulsePeriodNs(previousFrequencyHz); for (pulse = 1U; pulse < 10U; pulse++) { PlsrTestEmitPulses(1UL); EXPECT_U(1U, PlsrTestPulseIsActive()); currentFrequencyHz = PlsrTestOutputFrequency(); EXPECT_TRUE(currentFrequencyHz <= previousFrequencyHz); EXPECT_TRUE(currentFrequencyHz >= 99990UL); durationNs += PulsePeriodNs(currentFrequencyHz); previousFrequencyHz = currentFrequencyHz; if (((pulse + 1UL) % 100UL) == 0UL) { PlsrPoll1ms(); } } EXPECT_TRUE(durationNs >= 99990ULL); EXPECT_TRUE(durationNs <= 100010ULL); PlsrTestEmitPulses(1UL); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_I(10L, ReadPosition()); } } static void ExpectCompletedDiagnostic(uint32_t pulseCount) { uint16_t flags = ReadWord(PLSR_DIAG_FLAGS_ADDRESS); EXPECT_U(pulseCount, ReadU32(PLSR_DIAG_EXPECTED_COUNT_ADDRESS)); EXPECT_U(pulseCount, ReadU32(PLSR_DIAG_OBSERVED_COUNT_ADDRESS)); EXPECT_I(0L, ReadI32(PLSR_DIAG_COUNT_ERROR_ADDRESS)); EXPECT_U(PLSR_DIAG_COUNT_CHECKED | PLSR_DIAG_COUNT_PASS | PLSR_DIAG_FREQUENCY_CHECKED | PLSR_DIAG_FREQUENCY_PASS | PLSR_DIAG_CURVE_CHECKED | PLSR_DIAG_CURVE_PASS, flags & (PLSR_DIAG_COUNT_CHECKED | PLSR_DIAG_COUNT_PASS | PLSR_DIAG_FREQUENCY_CHECKED | PLSR_DIAG_FREQUENCY_PASS | PLSR_DIAG_CURVE_CHECKED | PLSR_DIAG_CURVE_PASS)); EXPECT_U(0U, flags & PLSR_DIAG_FAULT_LATCHED); EXPECT_U(PLSR_DIAG_REASON_NONE, ReadWord(PLSR_DIAG_REASON_ADDRESS)); } typedef struct { uint64_t durationNs; uint32_t peakFrequencyHz; uint16_t peakIndex; uint16_t slowTailPulses; } BUG_REPORT_PROFILE_STATS; static void RunBugReportProfile(uint32_t startSpeedHz, uint32_t stopSpeedHz, uint16_t accelerationTimeMs, uint16_t decelerationTimeMs, BUG_REPORT_PROFILE_STATS *stats) { uint64_t nextPollNs = 1000000ULL; uint32_t frequencyHz; uint16_t pulse; ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 100000UL, startSpeedHz, stopSpeedHz, accelerationTimeMs, decelerationTimeMs); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 100000UL, 1000L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(998U, PlsrTestProfileQueueCount()); stats->durationNs = 0ULL; stats->peakFrequencyHz = 0UL; stats->peakIndex = 0U; stats->slowTailPulses = 0U; for (pulse = 0U; pulse < 1000U; pulse++) { EXPECT_U(1U, PlsrTestPulseIsActive()); frequencyHz = PlsrTestOutputFrequency(); EXPECT_TRUE(frequencyHz != 0UL); if (frequencyHz > stats->peakFrequencyHz) { stats->peakFrequencyHz = frequencyHz; stats->peakIndex = pulse; } if ((pulse >= 900U) && (frequencyHz <= stopSpeedHz * 2UL)) { stats->slowTailPulses++; } stats->durationNs += PulsePeriodNs(frequencyHz); PlsrTestEmitPulses(1UL); while (((pulse + 1U) < 1000U) && (stats->durationNs >= nextPollNs)) { PlsrPoll1ms(); nextPollNs += 1000000ULL; } } EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_I(1000L, ReadPosition()); ExpectCompletedDiagnostic(1000UL); } static void TestBugReportShortProfiles(void) { BUG_REPORT_PROFILE_STATS stats; RunBugReportProfile(100UL, 100UL, 100U, 100U, &stats); EXPECT_TRUE(stats.peakFrequencyHz >= 30000UL); EXPECT_TRUE(stats.peakFrequencyHz <= 34000UL); EXPECT_TRUE(stats.peakIndex >= 400U); EXPECT_TRUE(stats.peakIndex <= 600U); EXPECT_TRUE(stats.slowTailPulses <= 2U); EXPECT_TRUE(stats.durationNs >= 50000000ULL); EXPECT_TRUE(stats.durationNs <= 80000000ULL); RunBugReportProfile(100UL, 100UL, 10U, 10U, &stats); EXPECT_TRUE(stats.peakFrequencyHz >= 99000UL); EXPECT_TRUE(stats.peakIndex >= 400U); EXPECT_TRUE(stats.peakIndex <= 600U); EXPECT_TRUE(stats.slowTailPulses <= 2U); EXPECT_TRUE(stats.durationNs >= 15000000ULL); EXPECT_TRUE(stats.durationNs <= 30000000ULL); RunBugReportProfile(10UL, 10UL, 10U, 100U, &stats); EXPECT_TRUE(stats.peakFrequencyHz >= 30000UL); EXPECT_TRUE(stats.slowTailPulses <= 2U); EXPECT_TRUE(stats.durationNs < 100000000ULL); } static void TestFiniteCompleteTenSegmentsWithoutPoll(void) { uint16_t segment; ResetCore(); PlsrTestEnableFinitePulseTrain(1U); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 10U, PLSR_SEND_COMPLETE, 10000UL, 100UL, 100UL, 10U, 10U); for (segment = 1U; segment <= 10U; segment++) { EXPECT_U(PLSR_MB_OK, SetSegment((uint8_t)segment, 1000UL, (int32_t)(99U + segment), PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); } EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); for (segment = 1U; segment <= 10U; segment++) { EXPECT_U(1U, PlsrTestFinitePulseTrainActive()); PlsrTestEmitPulses(99UL + segment); } EXPECT_U(0U, PlsrTestFinitePulseTrainActive()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_I(1045L, ReadPosition()); } static void TestShortProfileTimerFailure(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 100UL, 100UL, 1000U, 1000U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 10L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestFailNextFrequencyAtUpdate(); PlsrTestEmitPulses(1UL); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_ERROR, ReadStatus()); EXPECT_U(PLSR_ERROR_TIMER, ReadError()); EXPECT_I(1L, ReadPosition()); ExpectDiagnosticInterrupted(10UL, 1UL); } static void TestStopImmediatelyAfterSubsequentHandoff(void) { unsigned int tick; ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 2U, PLSR_SEND_SUBSEQUENT, 1000UL, 1000UL, 100UL, 0U, 100U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 3L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(2U, 2000UL, 20L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitPulses(3UL); EXPECT_U(2U, ReadCurrentSegment()); EXPECT_TRUE(PlsrTestOutputFrequency() <= 2000UL); EXPECT_TRUE(PlsrTestOutputFrequency() > 100UL); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_STOP)); PlsrPoll1ms(); PlsrTestEmitPulses(1UL); EXPECT_U(PLSR_STATUS_DECELERATING, ReadStatus()); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_TRUE(PlsrTestOutputFrequency() < 2000UL); EXPECT_TRUE(PlsrTestOutputFrequency() > 100UL); for (tick = 1U; tick < 190U; tick++) { PlsrPoll1ms(); } while (PlsrTestPulseIsActive() != 0U) { PlsrTestEmitPulses(1UL); } PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_STOPPED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_I(7L, ReadPosition()); } static void TestShortProfileZeroSpeedEdges(void) { unsigned int tick; ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 0UL, 0UL, 1000U, 1000U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 2L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_TRUE(PlsrTestOutputFrequency() > 0UL); PlsrTestEmitPulses(1UL); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_TRUE(PlsrTestOutputFrequency() > 0UL); PlsrTestEmitPulses(1UL); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_I(2L, ReadPosition()); ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 0UL, 0UL, 1000U, 1000U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 1L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); for (tick = 0U; (tick < 10U) && (PlsrTestPulseIsActive() == 0U); tick++) { PlsrPoll1ms(); } EXPECT_U(1U, PlsrTestPulseIsActive()); PlsrTestEmitPulses(1UL); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_I(1L, ReadPosition()); } static void TestShortProfileDynamicRetarget(void) { unsigned int tick; uint32_t frequencyAfterRetarget; int32_t positionBeforeStop; int32_t positionAfterStop; ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 100UL, 100UL, 1000U, 1000U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 50L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitPulses(3UL); EXPECT_U(PLSR_MB_OK, WriteU32(0x1100U, 2000UL)); PlsrPoll1ms(); PlsrTestEmitPulses(1UL); frequencyAfterRetarget = PlsrTestOutputFrequency(); PlsrTestEmitPulses(1UL); EXPECT_TRUE(PlsrTestOutputFrequency() > 0UL); for (tick = 0U; tick < 10U; tick++) { PlsrPoll1ms(); PlsrTestEmitPulses(1UL); } EXPECT_TRUE(PlsrTestOutputFrequency() > frequencyAfterRetarget); positionBeforeStop = ReadPosition(); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_STOP)); for (tick = 0U; tick < 2000U; tick++) { PlsrPoll1ms(); } while (PlsrTestPulseIsActive() != 0U) { PlsrTestEmitPulses(1UL); } PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_STOPPED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); positionAfterStop = ReadPosition(); EXPECT_TRUE(positionAfterStop > positionBeforeStop); EXPECT_TRUE(positionAfterStop <= positionBeforeStop + 3L); } static void TestShortProfileExtCut(void) { uint32_t frequencyBeforeCut; ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 100UL, 100UL, 1000U, 1000U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 50L, PLSR_EXT_SIGNAL, 0U, 0U, 0U)); PlsrTestSetInput(0U, 0U); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitPulses(3UL); frequencyBeforeCut = PlsrTestOutputFrequency(); PlsrTestSetInput(0U, 1U); PlsrPoll1ms(); PlsrTestEmitPulses(1UL); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_U(0UL, PlsrTestOutputFrequency()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_I(4L, ReadPosition()); EXPECT_TRUE(frequencyBeforeCut > 100UL); } static void TestFiniteProfileExtCut(void) { ResetCore(); PlsrTestEnableFinitePulseTrain(1U); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 5000UL, 500UL, 100UL, 100U, 100U); PlsrTestSetInput(0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 5000UL, 1000L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(1U, PlsrTestFinitePulseTrainActive()); PlsrTestEmitPulses(10UL); PlsrPoll1ms(); EXPECT_I(10L, ReadPosition()); PlsrTestSetInput(0U, 1U); PlsrPoll1ms(); /* The already committed terminal pulse is allowed to drain. */ PlsrTestEmitPulses(1UL); EXPECT_U(0U, PlsrTestFinitePulseTrainActive()); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_I(11L, ReadPosition()); } static void TestFiniteProfileStopOwnsTimer(void) { unsigned int pulse; uint32_t previousFrequency; ResetCore(); PlsrTestEnableFinitePulseTrain(1U); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 5000UL, 500UL, 100UL, 100U, 100U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 5000UL, 1000L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(1U, PlsrTestFinitePulseTrainActive()); PlsrTestEmitPulses(20UL); PlsrPoll1ms(); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_STOP)); EXPECT_U(PLSR_STATUS_DECELERATING, ReadStatus()); /* Allow the active and shadow settings to drain at the cutover. */ PlsrTestEmitPulses(2UL); PlsrPoll1ms(); previousFrequency = PlsrTestOutputFrequency(); for (pulse = 0U; (pulse < 200U) && (PlsrTestPulseIsActive() != 0U); pulse++) { uint32_t currentFrequency; PlsrPoll1ms(); PlsrTestEmitPulses(1UL); currentFrequency = PlsrTestOutputFrequency(); if (currentFrequency != 0UL) { EXPECT_TRUE(currentFrequency <= previousFrequency); previousFrequency = currentFrequency; } } PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_STOPPED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_TRUE(ReadPosition() < 1000L); } static void TestFiniteProfileDynamicRetargetOwnsTimer(void) { unsigned int pulse; uint32_t previousFrequency; ResetCore(); PlsrTestEnableFinitePulseTrain(1U); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 5000UL, 500UL, 100UL, 100U, 100U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 5000UL, 1000L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(1U, PlsrTestFinitePulseTrainActive()); PlsrTestEmitPulses(20UL); PlsrPoll1ms(); EXPECT_U(PLSR_MB_OK, WriteU32(0x1100U, 1000UL)); PlsrPoll1ms(); PlsrTestEmitPulses(2UL); PlsrPoll1ms(); previousFrequency = PlsrTestOutputFrequency(); for (pulse = 0U; pulse < 40U; pulse++) { uint32_t currentFrequency; PlsrPoll1ms(); PlsrTestEmitPulses(1UL); currentFrequency = PlsrTestOutputFrequency(); EXPECT_TRUE(currentFrequency <= previousFrequency); previousFrequency = currentFrequency; } EXPECT_TRUE(previousFrequency >= 1000UL); EXPECT_TRUE(previousFrequency < 5000UL); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_STOP)); for (pulse = 0U; (pulse < 300U) && (PlsrTestPulseIsActive() != 0U); pulse++) { PlsrPoll1ms(); PlsrTestEmitPulses(1UL); } PlsrPoll1ms(); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_U(PLSR_STATUS_STOPPED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); } static void TestCurrentFrequencyIsDynamic(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 100UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 100L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(1000UL, PlsrTestOutputFrequency()); EXPECT_U(PLSR_MB_OK, WriteU32(0x1100U, 2000UL)); PlsrPoll1ms(); EXPECT_U(1000UL, PlsrTestOutputFrequency()); PlsrTestEmitPulses(1UL); EXPECT_U(1000UL, PlsrTestOutputFrequency()); EXPECT_U(1000UL, ReadFrequency()); PlsrTestEmitPulses(1UL); EXPECT_U(2000UL, PlsrTestOutputFrequency()); EXPECT_U(2000UL, ReadFrequency()); EXPECT_U(PLSR_MB_OK, WriteI32(0x1102U, 1L)); PlsrTestEmitPulses(2UL); EXPECT_U(1U, PlsrTestPulseIsActive()); StopAndSettle(); } static void TestDynamicZeroFrequencyUsesDefaultSpeed(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 4321UL, 1000UL, 100UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 100L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(1000UL, PlsrTestOutputFrequency()); EXPECT_U(PLSR_MB_OK, WriteU32(0x1100U, 0UL)); EXPECT_U(0UL, ReadU32(0x1100U)); PlsrPoll1ms(); PlsrTestEmitPulses(2UL); EXPECT_U(4321UL, PlsrTestOutputFrequency()); EXPECT_U(4321UL, ReadFrequency()); StopAndSettle(); } static void StartMaximumShortProfile(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 100000UL, 1000UL, 1000UL, 100U, 100U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 100000UL, 258L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(256U, PlsrTestProfileQueueCount()); } static void TestProfileQueueStaleDoesNotAdvance(void) { uint32_t readIndex; uint32_t headFrequencyHz; uint16_t producerPeriod; uint16_t activePeriod; StartMaximumShortProfile(); readIndex = PlsrTestProfileQueueReadIndex(); headFrequencyHz = PlsrTestProfileQueueHeadFrequency(); producerPeriod = PlsrTestProfileProducerNextPeriod(); activePeriod = PlsrTestActiveProfileNextPeriod(); EXPECT_TRUE(headFrequencyHz != 0UL); PlsrTestStaleNextFrequencyAtUpdate(); PlsrTestEmitPulses(1UL); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_U(readIndex, PlsrTestProfileQueueReadIndex()); EXPECT_U(256U, PlsrTestProfileQueueCount()); EXPECT_U(headFrequencyHz, PlsrTestProfileQueueHeadFrequency()); EXPECT_U(producerPeriod, PlsrTestProfileProducerNextPeriod()); EXPECT_U(activePeriod, PlsrTestActiveProfileNextPeriod()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); PlsrTestEmitPulses(1UL); EXPECT_U(readIndex + 1UL, PlsrTestProfileQueueReadIndex()); EXPECT_U(255U, PlsrTestProfileQueueCount()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); } static void TestProfileQueueRetargetInvalidatesGeneration(void) { uint32_t generationBefore; uint32_t generationAfterWrite; StartMaximumShortProfile(); generationBefore = PlsrTestProfileQueueGeneration(); EXPECT_U(PLSR_MB_OK, WriteU32(0x1100U, 2000UL)); generationAfterWrite = PlsrTestProfileQueueGeneration(); EXPECT_TRUE(generationAfterWrite != generationBefore); EXPECT_U(0U, PlsrTestProfileQueueCount()); EXPECT_U(0UL, PlsrTestProfileQueueReadIndex()); EXPECT_U(0UL, PlsrTestProfileQueueWriteIndex()); PlsrPoll1ms(); EXPECT_TRUE(PlsrTestProfileQueueGeneration() != generationAfterWrite); EXPECT_U(0U, PlsrTestProfileQueueCount()); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); } static void TestFinalPulseGatesBeforeDiagnosticFinish(void) { uint32_t gateEvent; uint32_t diagnosticEvent; ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 1000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 1L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitPulses(1UL); gateEvent = PlsrTestLastGateEvent(); diagnosticEvent = PlsrTestLastDiagnosticFinishEvent(); EXPECT_TRUE(gateEvent != 0UL); EXPECT_U(gateEvent + 1UL, diagnosticEvent); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_U(PLSR_DIAG_COUNT_PASS, ReadWord(PLSR_DIAG_FLAGS_ADDRESS) & PLSR_DIAG_COUNT_PASS); } static void TestDeferredFrequencyRetriesAfterStale(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 100UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 100L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(PLSR_MB_OK, WriteU32(0x1100U, 2000UL)); PlsrPoll1ms(); EXPECT_U(1000UL, PlsrTestOutputFrequency()); EXPECT_U(1000UL, PlsrTestQueuedFrequency()); PlsrTestStaleNextFrequencyAtUpdate(); PlsrTestEmitPulses(1UL); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_U(1000UL, PlsrTestOutputFrequency()); EXPECT_U(1000UL, PlsrTestQueuedFrequency()); EXPECT_I(1L, ReadPosition()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); PlsrTestEmitPulses(1UL); EXPECT_U(1000UL, PlsrTestOutputFrequency()); EXPECT_U(2000UL, PlsrTestQueuedFrequency()); EXPECT_I(2L, ReadPosition()); PlsrTestEmitPulses(1UL); EXPECT_U(2000UL, PlsrTestOutputFrequency()); EXPECT_U(2000UL, PlsrTestQueuedFrequency()); EXPECT_I(3L, ReadPosition()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); StopAndSettle(); } static void TestShortProfileRetriesSameSampleAfterStale(void) { uint32_t expectedThirdFrequencyHz; uint32_t expectedFourthFrequencyHz; ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 100UL, 100UL, 1000U, 1000U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 10L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitPulses(1UL); expectedThirdFrequencyHz = PlsrTestQueuedFrequency(); PlsrTestEmitPulses(1UL); expectedFourthFrequencyHz = PlsrTestQueuedFrequency(); EXPECT_TRUE(expectedThirdFrequencyHz != expectedFourthFrequencyHz); ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 100UL, 100UL, 1000U, 1000U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 10L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestStaleNextFrequencyAtUpdate(); PlsrTestEmitPulses(1UL); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_U(PlsrTestOutputFrequency(), PlsrTestQueuedFrequency()); EXPECT_I(1L, ReadPosition()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); PlsrTestEmitPulses(1UL); EXPECT_U(expectedThirdFrequencyHz, PlsrTestQueuedFrequency()); EXPECT_I(2L, ReadPosition()); PlsrTestEmitPulses(1UL); EXPECT_U(expectedThirdFrequencyHz, PlsrTestOutputFrequency()); EXPECT_U(expectedFourthFrequencyHz, PlsrTestQueuedFrequency()); EXPECT_I(3L, ReadPosition()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); PlsrTestEmitPulses(7UL); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_I(10L, ReadPosition()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); } static void TestPollMailboxDefersPlatformFailure(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 100UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 100L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestFailNextFrequencyAtUpdate(); EXPECT_U(PLSR_MB_OK, WriteU32(0x1100U, 2000UL)); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_RUNNING, ReadStatus()); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_U(1000UL, PlsrTestOutputFrequency()); PlsrTestEmitPulses(1UL); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_ERROR, ReadStatus()); EXPECT_U(PLSR_ERROR_TIMER, ReadError()); EXPECT_I(1L, ReadPosition()); } static void TestFutureSegmentFrequencyAppliesOnArrival(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 2U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 100UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 1L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(2U, 3000UL, 10L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(PLSR_MB_OK, WriteU32(0x1110U, 5000UL)); EXPECT_U(1000UL, PlsrTestOutputFrequency()); PlsrTestEmitPulses(1UL); PlsrPoll1ms(); EXPECT_U(2U, ReadCurrentSegment()); EXPECT_U(5000UL, PlsrTestOutputFrequency()); EXPECT_U(5000UL, ReadFrequency()); StopAndSettle(); } static void TestSubsequentFutureFrequencyRebuildsHandoff(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 2U, PLSR_SEND_SUBSEQUENT, 1000UL, 1000UL, 100UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 3L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(2U, 2000UL, 4L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(PLSR_MB_OK, WriteU32(0x1110U, 5000UL)); EXPECT_U(1000UL, PlsrTestOutputFrequency()); PlsrTestEmitPulses(3UL); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_U(2U, ReadCurrentSegment()); EXPECT_U(5000UL, PlsrTestOutputFrequency()); EXPECT_U(5000UL, ReadFrequency()); PlsrTestEmitPulses(4UL); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_I(7L, ReadPosition()); } static void TestFutureFrequencyRaceAtLastPulse(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 2U, PLSR_SEND_SUBSEQUENT, 1000UL, 1000UL, 100UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 1L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(2U, 2000UL, 4L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitPulseOnCriticalExit(); EXPECT_U(PLSR_MB_OK, WriteU32(0x1110U, 5000UL)); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_U(2U, ReadCurrentSegment()); EXPECT_U(5000UL, PlsrTestOutputFrequency()); EXPECT_I(1L, ReadPosition()); PlsrTestEmitPulses(4UL); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_I(5L, ReadPosition()); } static void TestLatchedUpdateDrainsBeforeFutureFrequencyCommit(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 2U, PLSR_SEND_SUBSEQUENT, 1000UL, 1000UL, 100UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 1L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(2U, 2000UL, 4L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(1000UL, PlsrTestOutputFrequency()); EXPECT_U(2000UL, PlsrTestQueuedFrequency()); /* The physical edge latches 2000 Hz while interrupts are masked by the configuration commit. The ISR must consume that old handoff before the new 5000 Hz preload replaces it. */ PlsrTestLatchPulseOnCriticalEntry(); EXPECT_U(PLSR_MB_OK, WriteU32(0x1110U, 5000UL)); EXPECT_U(2U, ReadCurrentSegment()); EXPECT_I(1L, ReadPosition()); EXPECT_U(2000UL, ReadFrequency()); EXPECT_U(2000UL, PlsrTestOutputFrequency()); PlsrPoll1ms(); EXPECT_U(5000UL, PlsrTestQueuedFrequency()); PlsrTestEmitPulses(1UL); EXPECT_U(2U, ReadCurrentSegment()); EXPECT_I(2L, ReadPosition()); EXPECT_U(5000UL, ReadFrequency()); EXPECT_U(5000UL, PlsrTestOutputFrequency()); PlsrTestEmitPulses(3UL); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_I(5L, ReadPosition()); } static void TestSubsequentHandoffHasNoPollGap(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 2U, PLSR_SEND_SUBSEQUENT, 1000UL, 1000UL, 100UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 3L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(2U, 2000UL, 4L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitPulses(3UL); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_U(2U, ReadCurrentSegment()); EXPECT_U(2000UL, PlsrTestOutputFrequency()); EXPECT_I(3L, ReadPosition()); PlsrTestEmitPulses(4UL); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_I(7L, ReadPosition()); } static void TestThreeSinglePulseSubsequentWithoutPoll(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 3U, PLSR_SEND_SUBSEQUENT, 3000UL, 1000UL, 3000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 1L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(2U, 2000UL, 1L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(3U, 3000UL, 1L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(1000UL, PlsrTestOutputFrequency()); PlsrTestEmitPulses(1UL); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_U(2U, ReadCurrentSegment()); EXPECT_U(2000UL, PlsrTestOutputFrequency()); EXPECT_I(1L, ReadPosition()); PlsrTestEmitPulses(1UL); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_U(3U, ReadCurrentSegment()); EXPECT_U(3000UL, PlsrTestOutputFrequency()); EXPECT_I(2L, ReadPosition()); PlsrTestEmitPulses(1UL); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_I(3L, ReadPosition()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); } static void ConfigureHandoffFailureCase(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 2U, PLSR_SEND_SUBSEQUENT, 2000UL, 1000UL, 2000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 3L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SetSegment(2U, 2000UL, 2L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); } static void ExpectHandoffTimerError(void) { EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_ERROR, ReadStatus()); EXPECT_U(PLSR_ERROR_TIMER, ReadError()); EXPECT_U(0U, ReadCurrentSegment()); EXPECT_I(3L, ReadPosition()); } static void TestHandoffQueueFailuresBecomeTimerError(void) { ConfigureHandoffFailureCase(); PlsrTestEmitPulses(1UL); PlsrTestFailNextFrequencyAtUpdate(); PlsrTestEmitPulses(1UL); EXPECT_U(1U, PlsrTestPulseIsActive()); PlsrTestEmitPulses(1UL); ExpectHandoffTimerError(); ConfigureHandoffFailureCase(); PlsrTestEmitPulses(2UL); PlsrTestFailNextFrequencyAtUpdate(); PlsrTestEmitPulses(1UL); ExpectHandoffTimerError(); } static void TestCommandStateRestrictions(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 100UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 100L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_STOP)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_CLEAR)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(PLSR_MB_DEVICE_BUSY, SendCommand(PLSR_COMMAND_START)); EXPECT_U(PLSR_MB_DEVICE_BUSY, SendCommand(PLSR_COMMAND_CLEAR)); EXPECT_U(PLSR_MB_DEVICE_BUSY, WriteWord(0x1000U, 1U)); EXPECT_U(PLSR_MB_DEVICE_BUSY, WriteWord(0x1001U, 1U)); EXPECT_U(PLSR_MB_OK, WriteWord(0x1002U, 1U)); EXPECT_U(PLSR_MB_ILLEGAL_VALUE, SendCommand(3U)); StopAndSettle(); } static void TestCommandMailboxStartSnapshotAndConflicts(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 1000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 20L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, QueueCommand(PLSR_COMMAND_START)); EXPECT_U(PLSR_STATUS_IDLE, ReadStatus()); EXPECT_U(0U, ReadCurrentSegment()); EXPECT_U(0UL, ReadFrequency()); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_I(0L, ReadPosition()); EXPECT_U(PLSR_MB_OK, WriteI32(0x1102U, 1L)); EXPECT_U(PLSR_MB_OK, QueueCommand(PLSR_COMMAND_START)); EXPECT_U(PLSR_MB_DEVICE_BUSY, QueueCommand(PLSR_COMMAND_STOP)); EXPECT_U(PLSR_MB_DEVICE_BUSY, QueueCommand(PLSR_COMMAND_CLEAR)); EXPECT_U(PLSR_MB_ILLEGAL_VALUE, QueueCommand(3U)); EXPECT_U(PLSR_STATUS_IDLE, ReadStatus()); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_RUNNING, ReadStatus()); EXPECT_U(1U, ReadCurrentSegment()); EXPECT_U(1U, PlsrTestPulseIsActive()); PlsrTestEmitPulses(1UL); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_I(1L, ReadPosition()); StopAndSettle(); } static void TestCommandMailboxStopAndClearAreDeferred(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 1000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 100L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitPulses(2UL); EXPECT_U(PLSR_MB_OK, QueueCommand(PLSR_COMMAND_STOP)); EXPECT_U(PLSR_MB_OK, QueueCommand(PLSR_COMMAND_STOP)); EXPECT_U(PLSR_MB_DEVICE_BUSY, QueueCommand(PLSR_COMMAND_CLEAR)); EXPECT_U(PLSR_MB_DEVICE_BUSY, QueueCommand(PLSR_COMMAND_START)); EXPECT_U(PLSR_STATUS_RUNNING, ReadStatus()); EXPECT_U(1U, PlsrTestPulseIsActive()); EXPECT_I(2L, ReadPosition()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_DECELERATING, ReadStatus()); EXPECT_U(1U, PlsrTestPulseIsActive()); PlsrTestEmitPulses(1UL); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_STOPPED, ReadStatus()); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrTestSetPosition(17L, 1U); EXPECT_U(PLSR_MB_OK, QueueCommand(PLSR_COMMAND_CLEAR)); EXPECT_U(PLSR_MB_OK, QueueCommand(PLSR_COMMAND_CLEAR)); EXPECT_U(PLSR_MB_DEVICE_BUSY, QueueCommand(PLSR_COMMAND_START)); EXPECT_U(PLSR_STATUS_STOPPED, ReadStatus()); EXPECT_I(17L, ReadPosition()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_IDLE, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_I(0L, ReadPosition()); } static void TestCommandMailboxValidatesBeforeQueue(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 1000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 10L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, WriteWord(0x100AU, 2U)); EXPECT_U(PLSR_MB_ILLEGAL_VALUE, QueueCommand(PLSR_COMMAND_START)); EXPECT_U(PLSR_STATUS_IDLE, ReadStatus()); EXPECT_U(0U, PlsrTestPulseIsActive()); EXPECT_U(PLSR_MB_OK, QueueCommand(PLSR_COMMAND_STOP)); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_IDLE, ReadStatus()); EXPECT_U(PLSR_MB_OK, WriteWord(0x100AU, 1U)); EXPECT_U(PLSR_MB_OK, WriteWord(0x1008U, PLSR_POSITION_ABSOLUTE)); PlsrTestSetPosition(3L, 0U); EXPECT_U(PLSR_MB_ILLEGAL_VALUE, QueueCommand(PLSR_COMMAND_START)); EXPECT_U(PLSR_STATUS_IDLE, ReadStatus()); EXPECT_U(0U, PlsrTestPulseIsActive()); } static void TestCommandMailboxStartFailureBecomesError(void) { uint16_t flags; ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 1000UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 10L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); PlsrTestFailNextStart(); EXPECT_U(PLSR_MB_OK, QueueCommand(PLSR_COMMAND_START)); EXPECT_U(PLSR_STATUS_IDLE, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_ERROR, ReadStatus()); EXPECT_U(PLSR_ERROR_INVALID_RESOURCE, ReadError()); EXPECT_U(0U, ReadCurrentSegment()); EXPECT_U(0U, PlsrTestPulseIsActive()); flags = ReadWord(PLSR_DIAG_FLAGS_ADDRESS); EXPECT_U(0U, flags & PLSR_DIAG_MONITORING_ACTIVE); EXPECT_U(0U, flags & PLSR_DIAG_FAULT_LATCHED); EXPECT_U(PLSR_MB_DEVICE_BUSY, QueueCommand(PLSR_COMMAND_START)); EXPECT_U(PLSR_MB_OK, QueueCommand(PLSR_COMMAND_CLEAR)); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_IDLE, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); } static void TestWaitSignalPositivePath(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 100UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 2L, PLSR_WAIT_SIGNAL, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitPulses(2UL); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_WAITING, ReadStatus()); PlsrTestSetInput(0U, 1U); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); } static void TestPersistenceAcrossReinit(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 2345UL, 2345UL, 100UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, WriteWord(0x1000U, 2U)); EXPECT_U(PLSR_MB_OK, WriteWord(0x1001U, 3U)); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 2345UL, 4L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitPulses(4UL); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_I(4L, ReadPosition()); EXPECT_U(1U, PlsrInit()); EXPECT_U(PLSR_STATUS_IDLE, ReadStatus()); EXPECT_U(2U, ReadWord(0x1000U)); EXPECT_U(3U, ReadWord(0x1001U)); EXPECT_U(2345UL, ReadU32(0x1100U)); EXPECT_I(4L, ReadPosition()); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_CLEAR)); PlsrPoll1ms(); EXPECT_U(1U, PlsrInit()); EXPECT_U(PLSR_STATUS_IDLE, ReadStatus()); EXPECT_I(0L, ReadPosition()); } static void TestFlashStartupRecoveryDecision(void) { EXPECT_U(1U, PlsrTestFlashNeedsStartupRecovery(0U, 1U, 0UL, 1U, 0UL)); EXPECT_U(0U, PlsrTestFlashNeedsStartupRecovery(1U, 1U, 0UL, 1U, 0UL)); EXPECT_U(0U, PlsrTestFlashNeedsStartupRecovery(0U, 1U, 0x080C0000UL, 1U, 0UL)); EXPECT_U(0U, PlsrTestFlashNeedsStartupRecovery(0U, 1U, 0UL, 1U, 0x080E0000UL)); EXPECT_U(0U, PlsrTestFlashNeedsStartupRecovery(0U, 0U, 0UL, 1U, 0UL)); EXPECT_U(0U, PlsrTestFlashNeedsStartupRecovery(0U, 1U, 0UL, 0U, 0UL)); } static void TestPositionSchedulesFlashSave(void) { unsigned int tick; ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 100UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 1L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); for (tick = 0U; tick < 1001U; tick++) { PlsrPoll1ms(); PlsrServicePersistence(); } PlsrTestResetSaveCount(); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitPulses(1UL); PlsrPoll1ms(); PlsrServicePersistence(); EXPECT_U(0UL, PlsrTestSaveCount()); for (tick = 0U; tick < 1001U; tick++) { PlsrPoll1ms(); PlsrServicePersistence(); } EXPECT_U(1UL, PlsrTestSaveCount()); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_CLEAR)); for (tick = 0U; tick < 1001U; tick++) { PlsrPoll1ms(); PlsrServicePersistence(); } EXPECT_U(2UL, PlsrTestSaveCount()); } static void TestBusyResetInvalidatesAbsolutePosition(void) { unsigned int tick; ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 100UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 100L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitPulses(5UL); for (tick = 0U; tick < 10U; tick++) { PlsrPoll1ms(); } EXPECT_I(5L, ReadPosition()); EXPECT_U(1U, PlsrInit()); EXPECT_U(PLSR_STATUS_IDLE, ReadStatus()); EXPECT_I(5L, ReadPosition()); EXPECT_U(PLSR_MB_OK, WriteWord(0x1008U, PLSR_POSITION_ABSOLUTE)); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 5L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_ILLEGAL_VALUE, SendCommand(PLSR_COMMAND_START)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_CLEAR)); EXPECT_I(0L, ReadPosition()); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 0L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); } static void TestPositionOverflowStopsWithError(void) { ResetCore(); ConfigureCommon(0U, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 1000UL, 100UL, 0U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 1000UL, 2L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); PlsrTestSetPosition(INT32_MAX, 1U); EXPECT_I(INT32_MAX, ReadPosition()); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitPulses(1UL); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_ERROR, ReadStatus()); EXPECT_U(PLSR_ERROR_COUNT, ReadError()); EXPECT_I(INT32_MIN, ReadPosition()); } typedef void (*TEST_FUNCTION)(void); typedef struct { const char *name; TEST_FUNCTION function; } TEST_CASE; static const TEST_CASE TestCases[] = { {"finite_profile_curves_hardware_counting", TestFiniteProfileCurvesUseHardwareCounting}, {"finite_complete_multisegment_hardware_counting", TestFiniteCompleteMultiSegmentUsesHardwareCounting}, {"finite_complete_start_segment", TestFiniteCompleteStartsAtConfiguredSegment}, {"finite_zero_duration_ramp_target", TestFiniteZeroDurationRampAppliesTargetImmediately}, {"finite_ramp_uses_pulse_boundary_profile", TestFiniteRampUsesPulseBoundaryProfile}, {"finite_subsequent_three_segments_no_poll", TestFiniteSubsequentThreeSegmentsWithoutPoll}, {"finite_subsequent_ten_segment_jump_chain", TestFiniteSubsequentTenSegmentJumpChain}, {"finite_subsequent_counter_blocks", TestFiniteSubsequentCrossesCounterBlocks}, {"finite_subsequent_direction_reversal", TestFiniteSubsequentDirectionReversalRestarts}, {"finite_constant_pulse_train_boundaries", TestFiniteConstantPulseTrainBoundaries}, {"protocol_boundaries", TestProtocolBoundaries}, {"ab_output_pairs_phase_sequence", TestAbOutputPairsAndPhaseSequence}, {"ab_single_pulse_100khz_matrix", TestAbSinglePulseMaximumFrequencyMatrix}, {"ab_fast_gate_cleanup_deferred_to_poll", TestAbFastGateCleanupIsDeferredToPoll}, {"ab_final_arm_job_tail_chain_once", TestAbFinalArmJobTailChainsOnce}, {"ab_final_boundary_before_arm_job_noop", TestAbFinalBoundaryBeforeArmJobIsNoOp}, {"ab_final_arm_job_failure_no_final_count", TestAbFinalArmJobFailureDoesNotCountFinalPulse}, {"ab_stop_mailbox_pending_boundary", TestAbStopMailboxAtPendingBoundary}, {"ab_act_ext_cut_zero_boundary", TestAbActAndExtCutsFinishAtZero}, {"ab_subsequent_single_pulse_continuous", TestAbSubsequentSinglePulsesStayContinuous}, {"ab_armed_frequency_write", TestAbArmedFrequencyWriteDoesNotReopenOutput}, {"ab_stop_request_forced_fault", TestAbStopRequestForcedFault}, {"ab_stop_after_final_boundary_armed", TestAbStopAfterFinalBoundaryIsArmed}, {"ab_stop_arm_latched_final_quarter_once", TestAbStopArmConsumesLatchedFinalQuarterOnce}, {"ab_rejects_unpaired_outputs", TestAbRejectsUnpairedOutputs}, {"ab_stop_complete_cycle_boundary", TestAbStopAtCompleteCycleBoundary}, {"ab_dynamic_frequency_zero_boundary", TestAbDynamicFrequencyChangesOnlyAtZeroPhase}, {"ab_stale_frequency_commit_after_completion", TestAbStaleFrequencyCommitAfterNaturalCompletion}, {"ab_direction_reversal_zero_restart", TestAbDirectionReversalRestartsFromZeroPhase}, {"ab_mode_persistence", TestAbModePersistence}, {"diagnostic_pass", TestDiagnosticPass}, {"diagnostic_count_fault_clear", TestDiagnosticCountFaultAndClear}, {"diagnostic_frequency_fault_clear", TestDiagnosticFrequencyFaultAndClear}, {"diagnostic_curve_fault_clear", TestDiagnosticCurveFaultAndClear}, {"diagnostic_interrupted_segments", TestDiagnosticInterruptedSegments}, {"diagnostic_fault_latch_explicit_clear", TestDiagnosticFaultLatchNeedsExplicitClear}, {"diagnostic_frequency_pass_latched", TestDiagnosticFrequencyPassStaysFailed}, {"diagnostic_curve_counter_saturation", TestDiagnosticCurveCountersSaturate}, {"wait_zero_one_ms", TestWaitZeroUsesOneMillisecond}, {"act_zero_no_pulse", TestActZeroSkipsWithoutPulse}, {"relative_absolute_zero", TestRelativeAndAbsoluteZeroDisplacement}, {"ten_segments_sequence", TestAllTenSegmentsRunInSequence}, {"complete_ten_segment_frequency_staircase", TestCompleteTenSegmentFrequencyStaircase}, {"complete_natural_boundaries_carry_speed", TestCompleteCarriesSpeedAcrossNaturalBoundaries}, {"complete_jump_carries_speed", TestCompleteJumpCarriesSpeedToTargetSegment}, {"ten_ms_boundary_ramp_no_slow_tail", TestTenMillisecondBoundaryRampHasNoSlowTail}, {"finite_short_single_segment_pulse_profile", TestFiniteShortSingleSegmentUsesPulseProfile}, {"finite_profile_three_segments_no_poll_gap", TestFiniteProfileThreeSegmentsRunsWithoutPollGap}, {"ten_segments_jump_chain", TestAllTenSegmentsRunThroughJumpChain}, {"start_segment_ten", TestStartSegmentTenRunsNormally}, {"self_jump_stop", TestSelfJumpCanStop}, {"stop_deceleration", TestStopDeceleratesBeforeCut}, {"stop_pending_boundary", TestStopAtPendingBoundary}, {"direction_delay_one_ms", TestOneMillisecondDirectionDelay}, {"direction_output_polarity_matrix", TestDirectionOutputPolarityMatrix}, {"direction_same_reverse_segments", TestDirectionSameAndReverseSegments}, {"direction_output_change", TestDirectionOutputCanChangeBetweenCommands}, {"ext_edge_at_natural_boundary", TestExtEdgeAtNaturalBoundary}, {"ext_cut_natural_boundary_interleavings", TestExtCutAndNaturalBoundaryInterleavings}, {"ext_edge_during_direction_delay", TestExtEdgeDuringDirectionDelay}, {"stopped_clears_pending_ext", TestStoppedTaskClearsPendingExtEdge}, {"ext_edge_seamless_epoch", TestExtEdgeDoesNotCutSeamlessNextSegment}, {"ramp_seamless_epoch", TestOldRampDoesNotRetargetSeamlessNextSegment}, {"short_profile_boundary_matrix", TestShortProfileBoundaryMatrix}, {"zero_ramp_times_ignore_edge_speeds", TestZeroRampTimesIgnoreStartAndStopSpeeds}, {"zero_segment_frequency_uses_default_speed", TestZeroSegmentFrequencyUsesDefaultSpeed}, {"short_profile_258_fully_precomputed", TestShortProfile258IsFullyPrecomputed}, {"short_final_no_poll", TestShortFinalDeceleratesWithoutPoll}, {"bug_report_short_profiles", TestBugReportShortProfiles}, {"finite_complete_ten_segments_no_poll", TestFiniteCompleteTenSegmentsWithoutPoll}, {"profile_queue_stale_no_advance", TestProfileQueueStaleDoesNotAdvance}, {"profile_queue_retarget_generation", TestProfileQueueRetargetInvalidatesGeneration}, {"final_pulse_gate_before_diagnostic", TestFinalPulseGatesBeforeDiagnosticFinish}, {"short_timer_failure", TestShortProfileTimerFailure}, {"stop_after_subsequent_handoff", TestStopImmediatelyAfterSubsequentHandoff}, {"short_zero_speed_edges", TestShortProfileZeroSpeedEdges}, {"short_dynamic_retarget", TestShortProfileDynamicRetarget}, {"short_ext_cut", TestShortProfileExtCut}, {"finite_ext_cut", TestFiniteProfileExtCut}, {"finite_stop_single_timer_owner", TestFiniteProfileStopOwnsTimer}, {"finite_dynamic_single_timer_owner", TestFiniteProfileDynamicRetargetOwnsTimer}, {"current_frequency_dynamic", TestCurrentFrequencyIsDynamic}, {"dynamic_zero_frequency_uses_default_speed", TestDynamicZeroFrequencyUsesDefaultSpeed}, {"deferred_frequency_retries_after_stale", TestDeferredFrequencyRetriesAfterStale}, {"short_profile_retries_same_sample_after_stale", TestShortProfileRetriesSameSampleAfterStale}, {"poll_mailbox_failure", TestPollMailboxDefersPlatformFailure}, {"future_frequency_on_arrival", TestFutureSegmentFrequencyAppliesOnArrival}, {"subsequent_future_frequency_handoff", TestSubsequentFutureFrequencyRebuildsHandoff}, {"future_frequency_last_pulse_race", TestFutureFrequencyRaceAtLastPulse}, {"latched_update_before_future_frequency_commit", TestLatchedUpdateDrainsBeforeFutureFrequencyCommit}, {"subsequent_no_poll_gap", TestSubsequentHandoffHasNoPollGap}, {"three_single_pulse_no_poll", TestThreeSinglePulseSubsequentWithoutPoll}, {"handoff_queue_failures", TestHandoffQueueFailuresBecomeTimerError}, {"command_state_restrictions", TestCommandStateRestrictions}, {"command_mailbox_start_snapshot", TestCommandMailboxStartSnapshotAndConflicts}, {"command_mailbox_stop_clear_deferred", TestCommandMailboxStopAndClearAreDeferred}, {"command_mailbox_validation", TestCommandMailboxValidatesBeforeQueue}, {"command_mailbox_start_failure", TestCommandMailboxStartFailureBecomesError}, {"wait_signal_positive", TestWaitSignalPositivePath}, {"persistence_reinit", TestPersistenceAcrossReinit}, {"flash_startup_recovery_decision", TestFlashStartupRecoveryDecision}, {"position_flash_save", TestPositionSchedulesFlashSave}, {"busy_reset_absolute_gate", TestBusyResetInvalidatesAbsolutePosition}, {"position_overflow", TestPositionOverflowStopsWithError} }; int main(void) { unsigned int index; for (index = 0U; index < (unsigned int)(sizeof(TestCases) / sizeof(TestCases[0])); index++) { unsigned int failuresBefore = FailureCount; CurrentTest = TestCases[index].name; (void)printf("RUN %s\n", CurrentTest); (void)fflush(stdout); TestCases[index].function(); if (FailureCount == failuresBefore) { (void)printf("PASS %s\n", CurrentTest); } else { (void)printf("FAIL %s (%u new failure(s))\n", CurrentTest, FailureCount - failuresBefore); } } (void)printf("SUMMARY tests=%u assertions=%u failures=%u\n", (unsigned int)(sizeof(TestCases) / sizeof(TestCases[0])), AssertionCount, FailureCount); return (FailureCount == 0U) ? 0 : 1; }