#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_COUNT (5U) static const char *CurrentTest; static unsigned int AssertionCount; static unsigned int FailureCount; 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 void TestU64ByU32Division(void) { static const uint64_t dividends[] = { 0ULL, 1ULL, 0xFFFFFFFFULL, 0x100000000ULL, 0x100000001ULL, 0xFFFFFFFFFFFFFFFFULL, 0x8000000000000000ULL, 0x7FFFFFFFFFFFFFFFULL }; static const uint32_t divisors[] = { 1UL, 2UL, 3UL, 0xFFFFUL, 0x10000UL, 100000UL, 0x7FFFFFFFUL, 0x80000000UL, 0xFFFFFFFFUL }; uint32_t state = 0xA5C39E17UL; uint64_t dividend; uint64_t quotient; uint32_t divisor; uint32_t remainder; uint32_t dividendIndex; uint32_t divisorIndex; uint32_t iteration; for (dividendIndex = 0U; dividendIndex < (uint32_t)(sizeof(dividends) / sizeof(dividends[0])); dividendIndex++) { for (divisorIndex = 0U; divisorIndex < (uint32_t)(sizeof(divisors) / sizeof(divisors[0])); divisorIndex++) { dividend = dividends[dividendIndex]; divisor = divisors[divisorIndex]; quotient = PlsrTestDivideU64ByU32(dividend, divisor, &remainder); EXPECT_TRUE(quotient == dividend / divisor); EXPECT_U((uint32_t)(dividend % divisor), remainder); } } for (iteration = 0U; iteration < 250000UL; iteration++) { state = state * 1664525UL + 1013904223UL; dividend = (uint64_t)state << 32U; state = state * 1664525UL + 1013904223UL; dividend |= state; state = state * 1664525UL + 1013904223UL; divisor = state | 1UL; quotient = PlsrTestDivideU64ByU32(dividend, divisor, &remainder); EXPECT_TRUE(quotient == dividend / divisor); EXPECT_U((uint32_t)(dividend % divisor), remainder); } } 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 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 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(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(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(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)); } 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 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 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_U(2000UL, PlsrTestOutputFrequency()); 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}; uint32_t samples[3][101]; 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) < 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 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; } 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 TestZeroToMaximumRampKeepsConfiguredDuration(void) { uint16_t curveMode; uint32_t firstFrequencyHz[3]; uint32_t previousFrequencyHz; uint32_t currentFrequencyHz; uint32_t frequencyStepHz; uint32_t maximumStepHz; uint32_t pulse; uint64_t durationNs; const uint64_t expectedDurationNs = 20000000ULL; const uint64_t toleranceNs = 100000ULL; for (curveMode = 0U; curveMode <= 2U; curveMode++) { ResetCore(); ConfigureCommon(curveMode, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 100000UL, 0UL, 100000UL, 20U, 0U); 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(1U, PlsrTestPulseIsActive()); previousFrequencyHz = PlsrTestOutputFrequency(); firstFrequencyHz[curveMode] = previousFrequencyHz; EXPECT_TRUE(previousFrequencyHz >= 400UL); EXPECT_TRUE(previousFrequencyHz <= 2500UL); maximumStepHz = 0UL; durationNs = PulsePeriodNs(previousFrequencyHz); for (pulse = 1UL; pulse < 1000UL; pulse++) { PlsrTestEmitPulses(1UL); EXPECT_U(1U, PlsrTestPulseIsActive()); currentFrequencyHz = PlsrTestOutputFrequency(); EXPECT_TRUE(currentFrequencyHz >= previousFrequencyHz); EXPECT_TRUE(currentFrequencyHz <= 100000UL); frequencyStepHz = currentFrequencyHz - previousFrequencyHz; if (frequencyStepHz > maximumStepHz) { maximumStepHz = frequencyStepHz; } durationNs += PulsePeriodNs(currentFrequencyHz); previousFrequencyHz = currentFrequencyHz; } EXPECT_TRUE(maximumStepHz <= 10000UL); EXPECT_TRUE(previousFrequencyHz >= 99000UL); EXPECT_TRUE(UnsignedDifference64(durationNs, expectedDurationNs) <= toleranceNs); PlsrTestEmitPulses(1UL); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_I(1000L, ReadPosition()); } EXPECT_TRUE(firstFrequencyHz[0] > firstFrequencyHz[1]); EXPECT_TRUE(firstFrequencyHz[1] > firstFrequencyHz[2]); } static void TestMaximumPulseRampKeepsReachableDuration(void) { uint16_t curveMode; uint32_t previousFrequencyHz; uint32_t currentFrequencyHz; uint32_t frequencyStepHz; uint32_t maximumStepHz; uint32_t pulse; uint32_t reachablePeakHz = IntegerSquareRoot64( (uint64_t)2U * 65535UL * 100000UL * 1000UL / 1311UL); uint64_t durationNs; uint64_t expectedDurationNs = (uint64_t)2U * 65535UL * 1000000000ULL / reachablePeakHz; uint64_t toleranceNs = expectedDurationNs / 500ULL + 1000000ULL; for (curveMode = 0U; curveMode <= 2U; curveMode++) { ResetCore(); ConfigureCommon(curveMode, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 100000UL, 0UL, 100000UL, 1311U, 0U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 100000UL, 65535L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); EXPECT_U(1U, PlsrTestPulseIsActive()); previousFrequencyHz = PlsrTestOutputFrequency(); EXPECT_TRUE(previousFrequencyHz > 1UL); EXPECT_TRUE(previousFrequencyHz < reachablePeakHz); maximumStepHz = 0UL; durationNs = PulsePeriodNs(previousFrequencyHz); for (pulse = 1UL; pulse < 65535UL; pulse++) { PlsrTestEmitPulses(1UL); EXPECT_U(1U, PlsrTestPulseIsActive()); currentFrequencyHz = PlsrTestOutputFrequency(); EXPECT_TRUE(currentFrequencyHz >= previousFrequencyHz); EXPECT_TRUE(currentFrequencyHz <= reachablePeakHz + 5UL); frequencyStepHz = currentFrequencyHz - previousFrequencyHz; if (frequencyStepHz > maximumStepHz) { maximumStepHz = frequencyStepHz; } durationNs += PulsePeriodNs(currentFrequencyHz); previousFrequencyHz = currentFrequencyHz; } EXPECT_TRUE(maximumStepHz <= 5000UL); EXPECT_TRUE(previousFrequencyHz * 100UL >= reachablePeakHz * 99UL); EXPECT_TRUE(UnsignedDifference64(durationNs, expectedDurationNs) <= toleranceNs); PlsrTestEmitPulses(1UL); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_I(65535L, ReadPosition()); } } static void TestMaximumSingleRampWithoutPoll(void) { uint16_t curveMode; uint32_t previousFrequencyHz; uint32_t currentFrequencyHz; uint32_t minimumFrequencyHz; uint32_t maximumFrequencyHz; uint32_t pulse; for (curveMode = 0U; curveMode <= 2U; curveMode++) { ResetCore(); ConfigureCommon(curveMode, PLSR_POSITION_RELATIVE, 1U, PLSR_SEND_COMPLETE, 1000UL, 100000UL, 0UL, 1000U, 1000U); EXPECT_U(PLSR_MB_OK, SetSegment(1U, 100000UL, 65535L, PLSR_EXT_OR_COMPLETE, 0U, 0U, 0U)); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); previousFrequencyHz = PlsrTestOutputFrequency(); minimumFrequencyHz = previousFrequencyHz; maximumFrequencyHz = previousFrequencyHz; EXPECT_TRUE(previousFrequencyHz >= 99000UL); EXPECT_TRUE(previousFrequencyHz <= 100000UL); for (pulse = 1UL; pulse < 65535UL; pulse++) { PlsrTestEmitPulses(1UL); EXPECT_U(1U, PlsrTestPulseIsActive()); currentFrequencyHz = PlsrTestOutputFrequency(); EXPECT_TRUE(currentFrequencyHz <= previousFrequencyHz); EXPECT_TRUE(currentFrequencyHz >= 99000UL); if (currentFrequencyHz < minimumFrequencyHz) { minimumFrequencyHz = currentFrequencyHz; } if (currentFrequencyHz > maximumFrequencyHz) { maximumFrequencyHz = currentFrequencyHz; } previousFrequencyHz = currentFrequencyHz; } EXPECT_TRUE(minimumFrequencyHz > 1UL); EXPECT_TRUE(maximumFrequencyHz <= 100000UL); EXPECT_TRUE(minimumFrequencyHz < maximumFrequencyHz); PlsrTestEmitPulses(1UL); EXPECT_U(0U, PlsrTestPulseIsActive()); PlsrPoll1ms(); EXPECT_U(PLSR_STATUS_COMPLETED, ReadStatus()); EXPECT_U(PLSR_ERROR_NONE, ReadError()); EXPECT_I(65535L, 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()); } 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 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 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) { 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()); 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 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(); } PlsrTestResetSaveCount(); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_START)); PlsrTestEmitPulses(1UL); PlsrPoll1ms(); EXPECT_U(0UL, PlsrTestSaveCount()); for (tick = 0U; tick < 1001U; tick++) { PlsrPoll1ms(); } EXPECT_U(1UL, PlsrTestSaveCount()); EXPECT_U(PLSR_MB_OK, SendCommand(PLSR_COMMAND_CLEAR)); for (tick = 0U; tick < 1001U; tick++) { PlsrPoll1ms(); } 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[] = { {"u64_by_u32_division", TestU64ByU32Division}, {"protocol_boundaries", TestProtocolBoundaries}, {"wait_zero_one_ms", TestWaitZeroUsesOneMillisecond}, {"act_zero_no_pulse", TestActZeroSkipsWithoutPulse}, {"relative_absolute_zero", TestRelativeAndAbsoluteZeroDisplacement}, {"self_jump_stop", TestSelfJumpCanStop}, {"stop_deceleration", TestStopDeceleratesBeforeCut}, {"stop_pending_boundary", TestStopAtPendingBoundary}, {"direction_delay_one_ms", TestOneMillisecondDirectionDelay}, {"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}, {"short_final_no_poll", TestShortFinalDeceleratesWithoutPoll}, {"zero_to_maximum_ramp_duration", TestZeroToMaximumRampKeepsConfiguredDuration}, {"maximum_pulse_ramp_duration", TestMaximumPulseRampKeepsReachableDuration}, {"maximum_single_ramp_no_poll", TestMaximumSingleRampWithoutPoll}, {"short_timer_failure", TestShortProfileTimerFailure}, {"stop_after_subsequent_handoff", TestStopImmediatelyAfterSubsequentHandoff}, {"short_zero_speed_edges", TestShortProfileZeroSpeedEdges}, {"short_dynamic_retarget", TestShortProfileDynamicRetarget}, {"short_ext_cut", TestShortProfileExtCut}, {"current_frequency_dynamic", TestCurrentFrequencyIsDynamic}, {"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}, {"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); 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; }