|
- #include "plc_device.h"
- #include "plsr_core.h"
- #include "plsr_hal_f407.h"
- #include "plsr_job.h"
- #include "plsr_persistence.h"
- #include <stdio.h>
- #include <string.h>
-
- #define TEST_WORD_CAPACITY (3000U)
- #define TEST_S0_BASE (100U)
- #define TEST_S1_BASE (200U)
-
- typedef struct
- {
- uint16_t words[3][TEST_WORD_CAPACITY];
- } TEST_MEMORY;
-
- static int TestFailures;
- static int TestChecks;
-
- #define CHECK(condition) \
- do \
- { \
- TestChecks++; \
- if (!(condition)) \
- { \
- TestFailures++; \
- (void)printf("FAIL line %d: %s\n", __LINE__, #condition); \
- } \
- } while (0)
-
- static uint8_t TestValidateWords(void *context,
- PLSR_DEVICE_TYPE device,
- uint32_t firstAddress,
- uint32_t wordCount)
- {
- (void)context;
- (void)device;
- return (((uint64_t)firstAddress + wordCount) <= TEST_WORD_CAPACITY)
- ? 1U
- : 0U;
- }
-
- static uint8_t TestReadWord(void *context,
- PLSR_DEVICE_TYPE device,
- uint32_t address,
- uint16_t *value)
- {
- TEST_MEMORY *memory = (TEST_MEMORY *)context;
-
- if ((memory == NULL) || (value == NULL) || (device > PLSR_DEVICE_FD)
- || (address >= TEST_WORD_CAPACITY))
- {
- return 0U;
- }
- *value = memory->words[device][address];
- return 1U;
- }
-
- static uint8_t TestReadBit(void *context,
- PLSR_DEVICE_TYPE device,
- uint32_t address,
- uint8_t *value)
- {
- (void)context;
- (void)device;
- (void)address;
- *value = 0U;
- return 1U;
- }
-
- static void TestWriteDword(TEST_MEMORY *memory,
- PLSR_DEVICE_TYPE device,
- uint32_t address,
- int32_t value)
- {
- uint32_t raw = (uint32_t)value;
-
- memory->words[device][address] = (uint16_t)(raw & 0xFFFFUL);
- memory->words[device][address + 1UL] = (uint16_t)(raw >> 16U);
- }
-
- static void TestSetSegment(TEST_MEMORY *memory,
- uint16_t number,
- uint32_t frequency,
- int32_t pulses)
- {
- uint32_t base = TEST_S0_BASE + (uint32_t)number * 10UL;
-
- TestWriteDword(memory, PLSR_DEVICE_D, base, (int32_t)frequency);
- TestWriteDword(memory, PLSR_DEVICE_D, base + 2UL, pulses);
- memory->words[PLSR_DEVICE_D][base + 4UL] = 0U;
- TestWriteDword(memory, PLSR_DEVICE_D, base + 5UL, 0);
- memory->words[PLSR_DEVICE_D][base + 7UL] = 0U;
- TestWriteDword(memory, PLSR_DEVICE_D, base + 8UL, 0);
- }
-
- static void TestResetEnvironment(void)
- {
- PlsrPersistenceTestResetStorage();
- CHECK(PlcDeviceInit() == PLC_DEVICE_OK);
- CHECK(PlcDeviceWriteSfd(906U, 4) == PLC_DEVICE_OK);
- CHECK(PlsrInit() == PLSR_RESULT_OK);
- }
-
- static PLSR_CALL TestMakeCall(TEST_MEMORY *memory)
- {
- PLSR_CALL call;
-
- (void)memset(&call, 0, sizeof(call));
- call.sequence = 10UL;
- call.source.context = memory;
- call.source.validateWords = TestValidateWords;
- call.source.readWord = TestReadWord;
- call.source.readBit = TestReadBit;
- call.s0.device = PLSR_DEVICE_D;
- call.s0.address = TEST_S0_BASE;
- call.s1.device = PLSR_DEVICE_D;
- call.s1.address = TEST_S1_BASE;
- call.s2.type = PLSR_OPERAND_CONSTANT;
- call.s2.constant = 1;
- call.dAxis = 0U;
- call.outputModeOverride = PLSR_OUTPUT_MODE_FROM_SFD;
- return call;
- }
-
- static PLSR_STATUS TestGetStatus(void)
- {
- PLSR_STATUS status;
-
- (void)memset(&status, 0, sizeof(status));
- CHECK(PlsrGetStatus(0U, &status) == PLSR_RESULT_OK);
- return status;
- }
-
- /* ---- HAL 单测 ---- */
-
- static void TestMapping(void)
- {
- (void)PlsrHwInit();
- CHECK(PlsrHwGetTimerClockHz(0U) == 168000000UL);
- CHECK(PlsrHwGetTimerClockHz(1U) == 168000000UL);
- CHECK(PlsrHwGetTimerClockHz(2U) == 168000000UL);
- CHECK(PlsrHwGetTimerClockHz(3U) == 168000000UL);
- CHECK(PlsrHwGetTimerClockHz(4U) == 0UL);
- CHECK(PlsrHwResolveDirectionPoint(4U) != 0U);
- CHECK(PlsrHwResolveDirectionPoint(8U) == 0U);
- CHECK(PlsrHwResolveDirectionPoint(20U) != 0U);
- CHECK(PlsrHwResolveDirectionPoint(21U) == 0U);
- }
-
- static void TestDirDelaySequence(void)
- {
- (void)PlsrHwInit();
- PLSR_HW_START_PARAMS params;
- uint16_t psc;
- uint16_t arr;
- int ticks;
-
- (void)memset(¶ms, 0, sizeof(params));
- params.frequencyHz = 1000UL;
- params.targetPulses = 100;
- params.directionPoint = 4U;
- params.directionPositive = 1U;
- params.directionDelayMs = 10U;
-
- CHECK(PlsrHwStartPulse(0U, ¶ms) == PLSR_RESULT_OK);
- CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_DIR_SETTLING);
- CHECK(PlsrHwTestGetDirLevel(0U) == 1U);
- CHECK(PlsrHwTestGetPwmEnabled(0U) == 0U);
- CHECK(PlsrHwIsPulseActive(0U) == 0U);
-
- for (ticks = 0; ticks < 9; ticks++)
- {
- PlsrHwTick(0U);
- }
- CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_DIR_SETTLING);
-
- PlsrHwTick(0U);
- CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_PWM_PENDING);
-
- /* 首个非零频率启动 PWM,ARR/CCR 与分频计算一致。 */
- CHECK(PlsrHwSetFrequency(0U, 1000UL) == PLSR_RESULT_OK);
- CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_RUNNING);
- CHECK(PlsrHwTestGetPwmEnabled(0U) == 1U);
- CHECK(PlsrHwIsPulseActive(0U) == 1U);
- CHECK(PlsrCalculateTimerDivider(168000000UL, 1000UL, &psc, &arr)
- == PLSR_RESULT_OK);
- CHECK(PlsrHwTestGetArr(0U) == arr);
- CHECK(PlsrHwTestGetPsc(0U) == psc);
- CHECK(PlsrHwTestGetCcr(0U) == arr / 2UL);
- /* PWM 模式 1(OC1M=110):复位后 CCMR1=0 冻结,无此配置输出恒定电平。 */
- CHECK((PlsrHwTestGetCcmr1(0U) & 0x70UL) == 0x60UL);
- /* ARR/CCR 预装载(ARPE=CR1 bit7,OC1PE=CCMR1 bit3):
- * 运行中调频不产生提前回绕,否则加速段多出 ~ln(f1/f0) 个假脉冲。 */
- CHECK((PlsrHwTestGetCr1(0U) & 0x80UL) == 0x80UL);
- CHECK((PlsrHwTestGetCcmr1(0U) & 0x08UL) == 0x08UL);
-
- /* 段间同向衔接:方向不变时跳过方向延时,直接进入 PWM 待启动。 */
- CHECK(PlsrHwStopPulse(0U) == PLSR_RESULT_OK);
- params.targetPulses = 50;
- CHECK(PlsrHwStartPulse(0U, ¶ms) == PLSR_RESULT_OK);
- CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_PWM_PENDING);
- CHECK(PlsrHwTestGetDirLevel(0U) == 1U);
-
- /* 反向时方向延时仍生效。 */
- params.directionPositive = 0U;
- CHECK(PlsrHwStartPulse(0U, ¶ms) == PLSR_RESULT_OK);
- CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_DIR_SETTLING);
- CHECK(PlsrHwTestGetDirLevel(0U) == 0U);
- }
-
- static void TestZeroFrequencyWaits(void)
- {
- (void)PlsrHwInit();
- PLSR_HW_START_PARAMS params;
-
- (void)memset(¶ms, 0, sizeof(params));
- params.frequencyHz = 0UL;
- params.targetPulses = 50;
- params.directionPoint = PLSR_HW_DIR_POINT_NONE;
- params.directionPositive = 1U;
- params.directionDelayMs = 0U;
-
- CHECK(PlsrHwStartPulse(0U, ¶ms) == PLSR_RESULT_OK);
- CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_PWM_PENDING);
- PlsrHwTick(0U);
- CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_PWM_PENDING);
- CHECK(PlsrHwTestGetPwmEnabled(0U) == 0U);
-
- /* 起始速度为 0:profile 升频后首个非零频率才启动 PWM。 */
- CHECK(PlsrHwSetFrequency(0U, 10UL) == PLSR_RESULT_OK);
- CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_RUNNING);
- CHECK(PlsrHwTestGetPwmEnabled(0U) == 1U);
- }
-
- static void TestPulseCounting(void)
- {
- (void)PlsrHwInit();
- PLSR_HW_START_PARAMS params;
- int pulse;
-
- (void)memset(¶ms, 0, sizeof(params));
- params.frequencyHz = 1000UL;
- params.targetPulses = 5;
- params.directionPoint = PLSR_HW_DIR_POINT_NONE;
- params.directionPositive = 1U;
- params.directionDelayMs = 0U;
-
- CHECK(PlsrHwStartPulse(0U, ¶ms) == PLSR_RESULT_OK);
- CHECK(PlsrHwSetFrequency(0U, 1000UL) == PLSR_RESULT_OK);
- CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_RUNNING);
-
- for (pulse = 0; pulse < 4; pulse++)
- {
- PlsrHwTestTriggerUpdate(0U);
- CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_RUNNING);
- }
- /* 第 5 个脉冲:到目标,停止 + 段完成事件。 */
- PlsrHwTestTriggerUpdate(0U);
- CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_DONE);
- CHECK(PlsrHwTestGetPwmEnabled(0U) == 0U);
- CHECK(PlsrHwIsPulseActive(0U) == 0U);
-
- /* 停止后再触发更新中断无动作。 */
- PlsrHwTestTriggerUpdate(0U);
- CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_DONE);
- }
-
- static void TestStopAndInvalidArgs(void)
- {
- (void)PlsrHwInit();
- PLSR_HW_START_PARAMS params;
-
- (void)memset(¶ms, 0, sizeof(params));
- params.frequencyHz = 1000UL;
- params.targetPulses = 100;
- params.directionPoint = PLSR_HW_DIR_POINT_NONE;
- params.directionPositive = 1U;
- params.directionDelayMs = 0U;
-
- CHECK(PlsrHwStartPulse(0U, ¶ms) == PLSR_RESULT_OK);
- CHECK(PlsrHwSetFrequency(0U, 1000UL) == PLSR_RESULT_OK);
- CHECK(PlsrHwIsPulseActive(0U) == 1U);
- CHECK(PlsrHwStopPulse(0U) == PLSR_RESULT_OK);
- CHECK(PlsrHwIsPulseActive(0U) == 0U);
- CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_IDLE);
- CHECK(PlsrHwTestGetPwmEnabled(0U) == 0U);
-
- CHECK(PlsrHwStartPulse(4U, ¶ms) == PLSR_RESULT_INVALID_ARGUMENT);
- CHECK(PlsrHwStartPulse(0U, NULL) == PLSR_RESULT_INVALID_ARGUMENT);
- params.targetPulses = 0;
- CHECK(PlsrHwStartPulse(0U, ¶ms) == PLSR_RESULT_INVALID_ARGUMENT);
- CHECK(PlsrHwSetFrequency(4U, 1000UL) == PLSR_RESULT_INVALID_ARGUMENT);
- CHECK(PlsrHwStopPulse(4U) == PLSR_RESULT_INVALID_ARGUMENT);
- }
-
- /* ---- 端到端集成:START → 硬件 → 计数 → 事件 → 段间 → 完成 ---- */
-
- static void TestEndToEndTwoSegments(void)
- {
- TEST_MEMORY memory;
- PLSR_CALL call;
- PLSR_STATUS status;
- int ticks;
- int pulse;
-
- TestResetEnvironment();
- (void)memset(&memory, 0, sizeof(memory));
- TestWriteDword(&memory, PLSR_DEVICE_D, TEST_S0_BASE, 2);
- TestSetSegment(&memory, 1U, 1000U, 100);
- TestSetSegment(&memory, 2U, 2000U, 200);
-
- call = TestMakeCall(&memory);
- CHECK(PlsrPostCall(&call) == PLSR_RESULT_QUEUED);
- PlsrProcess();
- status = TestGetStatus();
- CHECK(status.state == PLSR_STATE_ACCEL);
- CHECK(status.currentSegment == 1U);
- CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_DIR_SETTLING);
-
- /* DIR 延时 10ms → PWM 启动(段1 起始速度 0,profile 升频后启动)。 */
- for (ticks = 0; ticks < 10; ticks++)
- {
- PlsrProcess();
- }
- CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_RUNNING);
- CHECK(PlsrHwTestGetPwmEnabled(0U) == 1U);
-
- /* 加速完成 → 状态机进入 RUN。 */
- for (ticks = 0; ticks < 500; ticks++)
- {
- PlsrProcess();
- if (TestGetStatus().state == PLSR_STATE_RUN)
- {
- break;
- }
- }
- status = TestGetStatus();
- CHECK(status.state == PLSR_STATE_RUN);
- CHECK(status.currentSegment == 1U);
-
- /* 段1 脉冲完成:100 次更新中断 → SEGMENT_COMPLETE → 段2 启动。 */
- for (pulse = 0; pulse < 100; pulse++)
- {
- PlsrHwTestTriggerUpdate(0U);
- }
- CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_DONE);
- PlsrProcess();
- status = TestGetStatus();
- CHECK(status.state == PLSR_STATE_ACCEL);
- CHECK(status.currentSegment == 2U);
-
- /* 段2:DIR 延时 → PWM → 加速 → RUN。 */
- for (ticks = 0; ticks < 600; ticks++)
- {
- PlsrProcess();
- if (TestGetStatus().state == PLSR_STATE_RUN)
- {
- break;
- }
- }
- status = TestGetStatus();
- CHECK(status.state == PLSR_STATE_RUN);
- CHECK(status.currentSegment == 2U);
-
- /* 段2 脉冲完成 → 任务结束。 */
- for (pulse = 0; pulse < 200; pulse++)
- {
- PlsrHwTestTriggerUpdate(0U);
- }
- PlsrProcess();
- status = TestGetStatus();
- CHECK(status.state == PLSR_STATE_COMPLETED);
- CHECK(status.done != 0U);
- /* 终态转换后 HAL 回 IDLE(允许重新启动),脉冲已停止。 */
- CHECK(PlsrHwIsPulseActive(0U) == 0U);
- CHECK(PlsrHwTestGetPwmEnabled(0U) == 0U);
- }
-
- static void TestStopStopsHardware(void)
- {
- TEST_MEMORY memory;
- PLSR_CALL call;
- PLSR_COMMAND command;
- PLSR_STATUS status;
- int ticks;
-
- TestResetEnvironment();
- (void)memset(&memory, 0, sizeof(memory));
- TestWriteDword(&memory, PLSR_DEVICE_D, TEST_S0_BASE, 1);
- TestSetSegment(&memory, 1U, 1000U, 10000);
-
- call = TestMakeCall(&memory);
- call.sequence = 20UL;
- CHECK(PlsrPostCall(&call) == PLSR_RESULT_QUEUED);
- PlsrProcess();
- for (ticks = 0; ticks < 10; ticks++)
- {
- PlsrProcess();
- }
- CHECK(PlsrHwIsPulseActive(0U) == 1U);
-
- /* STOP_IMMEDIATE:硬件立即停止。 */
- command.sequence = 21UL;
- command.axis = 0U;
- command.opcode = PLSR_CMD_STOP_IMMEDIATE;
- command.argument = 0;
- CHECK(PlsrPostCommand(&command) == PLSR_RESULT_QUEUED);
- PlsrProcess();
- CHECK(PlsrHwIsPulseActive(0U) == 0U);
- CHECK(PlsrHwGetState(0U) == PLSR_HW_STATE_IDLE);
-
- CHECK(PlsrPostEvent(0U, PLSR_EVENT_STOP_IMMEDIATE_DONE)
- == PLSR_RESULT_OK);
- PlsrProcess();
- status = TestGetStatus();
- CHECK(status.state == PLSR_STATE_STOPPED);
- }
-
- int main(void)
- {
- TestMapping();
- TestDirDelaySequence();
- TestZeroFrequencyWaits();
- TestPulseCounting();
- TestStopAndInvalidArgs();
- TestEndToEndTwoSegments();
- TestStopStopsHardware();
-
- if (TestFailures != 0)
- {
- (void)printf("FAIL: %d of %d PLSR HAL checks failed\n",
- TestFailures,
- TestChecks);
- return 1;
- }
- (void)printf("PASS: %d PLSR HAL checks\n", TestChecks);
- return 0;
- }
|