#include "plc_device.h" #include "plsr_core.h" #include "plsr_job.h" #include "plsr_path.h" #include "plsr_persistence.h" #include #include #define TEST_WORD_CAPACITY (3000U) #define TEST_BIT_CAPACITY (128U) #define TEST_S0_BASE (100U) #define TEST_S1_BASE (200U) #define TEST_SEGMENT_STRIDE (10U) /* 等待条件编码(信捷):高8位条件、低8位来源。 */ #define TEST_WAIT_CODE(condition, source) \ ((uint16_t)(((uint16_t)(condition) << 8U) | (uint16_t)(source))) typedef struct { uint16_t words[3][TEST_WORD_CAPACITY]; uint8_t bits[3][TEST_BIT_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; if ((device > PLSR_DEVICE_FD) || (wordCount == 0UL)) { return 0U; } 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) { TEST_MEMORY *memory = (TEST_MEMORY *)context; uint8_t index; if ((memory == NULL) || (value == NULL) || (device < PLSR_DEVICE_X) || (device > PLSR_DEVICE_HM) || (address >= TEST_BIT_CAPACITY)) { return 0U; } index = (uint8_t)(device - PLSR_DEVICE_X); *value = memory->bits[index][address]; 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); } /* 写入一个段的数据块(S0 布局,每段 10 字)。 */ static void TestSetSegment(TEST_MEMORY *memory, uint16_t number, uint32_t frequency, int32_t pulses, uint16_t waitCode, int32_t waitValue, uint16_t jumpSource, int32_t jumpValue) { uint32_t base = TEST_S0_BASE + (uint32_t)number * TEST_SEGMENT_STRIDE; TestWriteDword(memory, PLSR_DEVICE_D, base, (int32_t)frequency); TestWriteDword(memory, PLSR_DEVICE_D, base + 2UL, pulses); memory->words[PLSR_DEVICE_D][base + 4UL] = waitCode; TestWriteDword(memory, PLSR_DEVICE_D, base + 5UL, waitValue); memory->words[PLSR_DEVICE_D][base + 7UL] = (uint16_t)jumpSource; TestWriteDword(memory, PLSR_DEVICE_D, base + 8UL, jumpValue); } static void TestResetEnvironment(void) { PlsrPersistenceTestResetStorage(); CHECK(PlcDeviceInit() == PLC_DEVICE_OK); /* 默认 SFD + 配置方向端子(接线参数,测试用 Y4)。 */ 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; } /* 当前段加速完成进入 RUN。 */ static void TestAccelToRun(void) { CHECK(PlsrPostEvent(0U, PLSR_EVENT_ACCEL_COMPLETE) == PLSR_RESULT_OK); PlsrProcess(); CHECK(TestGetStatus().state == PLSR_STATE_RUN); } /* 启动一个 N 段任务(全部 H00 完成条件、顺序跳转)。 */ static void TestStartSequentialJob(TEST_MEMORY *memory, uint16_t segmentCount, uint32_t sequence) { uint16_t segment; (void)memset(memory, 0, sizeof(*memory)); TestWriteDword(memory, PLSR_DEVICE_D, TEST_S0_BASE, segmentCount); for (segment = 1U; segment <= segmentCount; segment++) { TestSetSegment(memory, segment, 1000U + (uint32_t)segment * 1000U, (int32_t)(segment * 100), TEST_WAIT_CODE(0U, 0U), 0, 0U, 0); } { PLSR_CALL call = TestMakeCall(memory); call.sequence = sequence; CHECK(PlsrPostCall(&call) == PLSR_RESULT_QUEUED); } PlsrProcess(); CHECK(TestGetStatus().lastCommandResult == PLSR_RESULT_OK); } static void TestSequentialSegments(void) { TEST_MEMORY memory; TestResetEnvironment(); TestStartSequentialJob(&memory, 3U, 10UL); CHECK(TestGetStatus().state == PLSR_STATE_ACCEL); CHECK(TestGetStatus().currentSegment == 1U); TestAccelToRun(); CHECK(PlsrPostEvent(0U, PLSR_EVENT_SEGMENT_COMPLETE) == PLSR_RESULT_OK); PlsrProcess(); CHECK(TestGetStatus().state == PLSR_STATE_ACCEL); CHECK(TestGetStatus().currentSegment == 2U); TestAccelToRun(); CHECK(PlsrPostEvent(0U, PLSR_EVENT_SEGMENT_COMPLETE) == PLSR_RESULT_OK); PlsrProcess(); CHECK(TestGetStatus().state == PLSR_STATE_ACCEL); CHECK(TestGetStatus().currentSegment == 3U); TestAccelToRun(); CHECK(PlsrPostEvent(0U, PLSR_EVENT_SEGMENT_COMPLETE) == PLSR_RESULT_OK); PlsrProcess(); CHECK(TestGetStatus().state == PLSR_STATE_COMPLETED); CHECK(TestGetStatus().done != 0U); } static void TestJumpToSpecifiedSegment(void) { TEST_MEMORY memory; TestResetEnvironment(); (void)memset(&memory, 0, sizeof(memory)); TestWriteDword(&memory, PLSR_DEVICE_D, TEST_S0_BASE, 3); TestSetSegment(&memory, 1U, 1000U, 100, TEST_WAIT_CODE(0U, 0U), 0, 0U, 3); TestSetSegment(&memory, 2U, 2000U, 200, TEST_WAIT_CODE(0U, 0U), 0, 0U, 0); TestSetSegment(&memory, 3U, 3000U, 300, TEST_WAIT_CODE(0U, 0U), 0, 0U, 0); { PLSR_CALL call = TestMakeCall(&memory); call.sequence = 20UL; CHECK(PlsrPostCall(&call) == PLSR_RESULT_QUEUED); } PlsrProcess(); CHECK(TestGetStatus().currentSegment == 1U); /* 段1 完成 → 跳到段3(跳过段2)。 */ TestAccelToRun(); CHECK(PlsrPostEvent(0U, PLSR_EVENT_SEGMENT_COMPLETE) == PLSR_RESULT_OK); PlsrProcess(); CHECK(TestGetStatus().state == PLSR_STATE_ACCEL); CHECK(TestGetStatus().currentSegment == 3U); /* 段3 完成 → 顺序下一段超出 → 任务结束。 */ TestAccelToRun(); CHECK(PlsrPostEvent(0U, PLSR_EVENT_SEGMENT_COMPLETE) == PLSR_RESULT_OK); PlsrProcess(); CHECK(TestGetStatus().state == PLSR_STATE_COMPLETED); } static void TestWaitTime(void) { TEST_MEMORY memory; int ticks; TestResetEnvironment(); (void)memset(&memory, 0, sizeof(memory)); TestWriteDword(&memory, PLSR_DEVICE_D, TEST_S0_BASE, 2); TestSetSegment(&memory, 1U, 1000U, 100, TEST_WAIT_CODE(1U, 0U), 200, 0U, 0); TestSetSegment(&memory, 2U, 2000U, 200, TEST_WAIT_CODE(0U, 0U), 0, 0U, 0); { PLSR_CALL call = TestMakeCall(&memory); call.sequence = 30UL; CHECK(PlsrPostCall(&call) == PLSR_RESULT_QUEUED); } PlsrProcess(); TestAccelToRun(); /* 段1 完成 → 进入 WAIT(等 200ms)。 */ CHECK(PlsrPostEvent(0U, PLSR_EVENT_SEGMENT_COMPLETE) == PLSR_RESULT_OK); PlsrProcess(); CHECK(TestGetStatus().state == PLSR_STATE_WAIT); /* 事件处理同轮已递减 1ms:198 个 tick 后仍在等待。 */ for (ticks = 0; ticks < 198; ticks++) { PlsrProcess(); } CHECK(TestGetStatus().state == PLSR_STATE_WAIT); CHECK(TestGetStatus().currentSegment == 1U); /* 第 200 个 tick:计时到,跳到段2。 */ PlsrProcess(); CHECK(TestGetStatus().state == PLSR_STATE_ACCEL); CHECK(TestGetStatus().currentSegment == 2U); } static void TestWaitSignal(void) { TEST_MEMORY memory; TestResetEnvironment(); (void)memset(&memory, 0, sizeof(memory)); TestWriteDword(&memory, PLSR_DEVICE_D, TEST_S0_BASE, 2); TestSetSegment(&memory, 1U, 1000U, 100, TEST_WAIT_CODE(2U, 5U), 10, 0U, 0); TestSetSegment(&memory, 2U, 2000U, 200, TEST_WAIT_CODE(0U, 0U), 0, 0U, 0); { PLSR_CALL call = TestMakeCall(&memory); call.sequence = 40UL; CHECK(PlsrPostCall(&call) == PLSR_RESULT_QUEUED); } PlsrProcess(); TestAccelToRun(); /* 段1 完成 → 等 M10(当前 OFF)。 */ CHECK(PlsrPostEvent(0U, PLSR_EVENT_SEGMENT_COMPLETE) == PLSR_RESULT_OK); PlsrProcess(); CHECK(TestGetStatus().state == PLSR_STATE_WAIT); /* 信号仍 OFF:不跳转。 */ PlsrProcess(); PlsrProcess(); CHECK(TestGetStatus().state == PLSR_STATE_WAIT); /* 信号置 ON:tick 轮询到后跳段。 */ memory.bits[1U][10U] = 1U; /* M10 */ PlsrProcess(); CHECK(TestGetStatus().state == PLSR_STATE_ACCEL); CHECK(TestGetStatus().currentSegment == 2U); } static void TestActTruncatesSegment(void) { TEST_MEMORY memory; int ticks; TestResetEnvironment(); (void)memset(&memory, 0, sizeof(memory)); TestWriteDword(&memory, PLSR_DEVICE_D, TEST_S0_BASE, 2); TestSetSegment(&memory, 1U, 1000U, 100, TEST_WAIT_CODE(3U, 0U), 200, 0U, 0); TestSetSegment(&memory, 2U, 2000U, 200, TEST_WAIT_CODE(0U, 0U), 0, 0U, 0); { PLSR_CALL call = TestMakeCall(&memory); call.sequence = 50UL; CHECK(PlsrPostCall(&call) == PLSR_RESULT_QUEUED); } PlsrProcess(); TestAccelToRun(); /* 不注入 SEGMENT_COMPLETE:ACT 200ms 到时截断当前段。 */ for (ticks = 0; ticks < 200; ticks++) { PlsrProcess(); } CHECK(TestGetStatus().state == PLSR_STATE_ACCEL); CHECK(TestGetStatus().currentSegment == 2U); } static void TestActPendingAfterSegmentDone(void) { TEST_MEMORY memory; int ticks; TestResetEnvironment(); (void)memset(&memory, 0, sizeof(memory)); TestWriteDword(&memory, PLSR_DEVICE_D, TEST_S0_BASE, 2); TestSetSegment(&memory, 1U, 1000U, 100, TEST_WAIT_CODE(3U, 0U), 200, 0U, 0); TestSetSegment(&memory, 2U, 2000U, 200, TEST_WAIT_CODE(0U, 0U), 0, 0U, 0); { PLSR_CALL call = TestMakeCall(&memory); call.sequence = 60UL; CHECK(PlsrPostCall(&call) == PLSR_RESULT_QUEUED); } PlsrProcess(); TestAccelToRun(); /* 段脉冲先完成(ACT 还剩 199ms)→ 停在 ACT_PENDING(WAIT 状态)。 */ CHECK(PlsrPostEvent(0U, PLSR_EVENT_SEGMENT_COMPLETE) == PLSR_RESULT_OK); PlsrProcess(); CHECK(TestGetStatus().state == PLSR_STATE_WAIT); /* ACT 到时 → 跳段2。 */ for (ticks = 0; ticks < 199; ticks++) { PlsrProcess(); } CHECK(TestGetStatus().state == PLSR_STATE_ACCEL); CHECK(TestGetStatus().currentSegment == 2U); } static void TestExtEdgeTruncates(void) { TEST_MEMORY memory; int ticks; TestResetEnvironment(); (void)memset(&memory, 0, sizeof(memory)); TestWriteDword(&memory, PLSR_DEVICE_D, TEST_S0_BASE, 2); TestSetSegment(&memory, 1U, 1000U, 100, TEST_WAIT_CODE(4U, 4U), 0, 0U, 0); TestSetSegment(&memory, 2U, 2000U, 200, TEST_WAIT_CODE(0U, 0U), 0, 0U, 0); /* X0 在任务开始前就有效:进入段时记录为已有电平,不算新边沿。 */ memory.bits[0U][0U] = 1U; { PLSR_CALL call = TestMakeCall(&memory); call.sequence = 70UL; CHECK(PlsrPostCall(&call) == PLSR_RESULT_QUEUED); } PlsrProcess(); TestAccelToRun(); /* X0 持续 ON:没有新边沿,不应触发。 */ for (ticks = 0; ticks < 5; ticks++) { PlsrProcess(); } CHECK(TestGetStatus().state == PLSR_STATE_RUN); CHECK(TestGetStatus().currentSegment == 1U); /* 先拉低再拉高:新上升沿,截断当前段。 */ memory.bits[0U][0U] = 0U; PlsrProcess(); memory.bits[0U][0U] = 1U; PlsrProcess(); CHECK(TestGetStatus().state == PLSR_STATE_ACCEL); CHECK(TestGetStatus().currentSegment == 2U); } static void TestExtOrComplete(void) { TEST_MEMORY memory; TestResetEnvironment(); (void)memset(&memory, 0, sizeof(memory)); TestWriteDword(&memory, PLSR_DEVICE_D, TEST_S0_BASE, 2); TestSetSegment(&memory, 1U, 1000U, 100, TEST_WAIT_CODE(5U, 4U), 0, 0U, 0); TestSetSegment(&memory, 2U, 2000U, 200, TEST_WAIT_CODE(0U, 0U), 0, 0U, 0); { PLSR_CALL call = TestMakeCall(&memory); call.sequence = 80UL; CHECK(PlsrPostCall(&call) == PLSR_RESULT_QUEUED); } PlsrProcess(); TestAccelToRun(); /* 段脉冲先完成 → 正常跳段(EXT 或完成)。 */ CHECK(PlsrPostEvent(0U, PLSR_EVENT_SEGMENT_COMPLETE) == PLSR_RESULT_OK); PlsrProcess(); CHECK(TestGetStatus().state == PLSR_STATE_ACCEL); CHECK(TestGetStatus().currentSegment == 2U); } static void TestDynamicJump(void) { TEST_MEMORY memory; TestResetEnvironment(); (void)memset(&memory, 0, sizeof(memory)); TestWriteDword(&memory, PLSR_DEVICE_D, TEST_S0_BASE, 3); TestSetSegment(&memory, 1U, 1000U, 100, TEST_WAIT_CODE(0U, 0U), 0, 0U, 3); TestSetSegment(&memory, 2U, 2000U, 200, TEST_WAIT_CODE(0U, 0U), 0, 0U, 0); /* 段3 跳转也来自 D300(初始 3 = 自跳转,运行期改非法值验证越界)。 */ TestSetSegment(&memory, 3U, 3000U, 300, TEST_WAIT_CODE(0U, 0U), 0, 1U, 300); TestWriteDword(&memory, PLSR_DEVICE_D, 300U, 3); { PLSR_CALL call = TestMakeCall(&memory); call.sequence = 90UL; CHECK(PlsrPostCall(&call) == PLSR_RESULT_QUEUED); } PlsrProcess(); TestAccelToRun(); /* 段1 完成:跳到段3。 */ CHECK(PlsrPostEvent(0U, PLSR_EVENT_SEGMENT_COMPLETE) == PLSR_RESULT_OK); PlsrProcess(); CHECK(TestGetStatus().currentSegment == 3U); /* 段3 完成前把 D300 改成非法值 → 运行期错误 → ERROR。 */ TestAccelToRun(); TestWriteDword(&memory, PLSR_DEVICE_D, 300U, 99); CHECK(PlsrPostEvent(0U, PLSR_EVENT_SEGMENT_COMPLETE) == PLSR_RESULT_OK); PlsrProcess(); CHECK(TestGetStatus().state == PLSR_STATE_ERROR); } static void TestAbsoluteZeroDisplacement(void) { TEST_MEMORY memory; PLSR_COMMAND command; TestResetEnvironment(); (void)memset(&memory, 0, sizeof(memory)); TestWriteDword(&memory, PLSR_DEVICE_D, TEST_S0_BASE, 2); /* S1+0 = 1:绝对模式。 */ TestWriteDword(&memory, PLSR_DEVICE_D, TEST_S1_BASE, 1); /* 段1 目标 0(=当前位置 0,零位移);段2 目标 5000。 */ TestSetSegment(&memory, 1U, 1000U, 0, TEST_WAIT_CODE(0U, 0U), 0, 0U, 0); TestSetSegment(&memory, 2U, 2000U, 5000, TEST_WAIT_CODE(0U, 0U), 0, 0U, 0); /* 绝对定位需要 positionValid:先 SET_POSITION(0)。 */ command.sequence = 91UL; command.axis = 0U; command.opcode = PLSR_CMD_SET_POSITION; command.argument = 0; CHECK(PlsrPostCommand(&command) == PLSR_RESULT_QUEUED); PlsrProcess(); { PLSR_CALL call = TestMakeCall(&memory); call.sequence = 92UL; CHECK(PlsrPostCall(&call) == PLSR_RESULT_QUEUED); } PlsrProcess(); /* 起点段1 零位移:直接跳过,从段2 开始发脉冲。 */ CHECK(TestGetStatus().state == PLSR_STATE_ACCEL); CHECK(TestGetStatus().currentSegment == 2U); } static void TestZeroJumpBudgetYields(void) { TEST_MEMORY memory; int rounds; TestResetEnvironment(); (void)memset(&memory, 0, sizeof(memory)); TestWriteDword(&memory, PLSR_DEVICE_D, TEST_S0_BASE, 3); /* 段1:零脉冲,跳到段2;段2:零脉冲,动态跳转(初始自跳转);段3:正常段。 */ TestSetSegment(&memory, 1U, 1000U, 0, TEST_WAIT_CODE(0U, 0U), 0, 0U, 2); TestSetSegment(&memory, 2U, 1000U, 0, TEST_WAIT_CODE(0U, 0U), 0, 1U, 300); TestSetSegment(&memory, 3U, 1000U, 100, TEST_WAIT_CODE(0U, 0U), 0, 0U, 0); TestWriteDword(&memory, PLSR_DEVICE_D, 300U, 2); { PLSR_CALL call = TestMakeCall(&memory); call.sequence = 100UL; CHECK(PlsrPostCall(&call) == PLSR_RESULT_QUEUED); } PlsrProcess(); /* 每轮 100 次预算:零脉冲自循环链停在段2 并让出,任务不结束。 */ CHECK(TestGetStatus().state == PLSR_STATE_ACCEL); CHECK(TestGetStatus().currentSegment == 2U); CHECK(TestGetStatus().done == 0U); for (rounds = 0; rounds < 3; rounds++) { PlsrProcess(); } CHECK(TestGetStatus().state == PLSR_STATE_ACCEL); CHECK(TestGetStatus().currentSegment == 2U); CHECK(TestGetStatus().done == 0U); /* 运行中改动态跳转目标 → 链走向段3(有脉冲)→ 正常执行并完成。 */ TestWriteDword(&memory, PLSR_DEVICE_D, 300U, 3); PlsrProcess(); CHECK(TestGetStatus().state == PLSR_STATE_ACCEL); CHECK(TestGetStatus().currentSegment == 3U); TestAccelToRun(); CHECK(PlsrPostEvent(0U, PLSR_EVENT_SEGMENT_COMPLETE) == PLSR_RESULT_OK); PlsrProcess(); CHECK(TestGetStatus().state == PLSR_STATE_COMPLETED); } static void TestSelfLoopInterruptedByStop(void) { TEST_MEMORY memory; PLSR_COMMAND command; TestResetEnvironment(); (void)memset(&memory, 0, sizeof(memory)); TestWriteDword(&memory, PLSR_DEVICE_D, TEST_S0_BASE, 1); TestSetSegment(&memory, 1U, 1000U, 100, TEST_WAIT_CODE(0U, 0U), 0, 0U, 1); { PLSR_CALL call = TestMakeCall(&memory); call.sequence = 110UL; CHECK(PlsrPostCall(&call) == PLSR_RESULT_QUEUED); } PlsrProcess(); TestAccelToRun(); /* 段1 完成 → 自跳转回段1。 */ CHECK(PlsrPostEvent(0U, PLSR_EVENT_SEGMENT_COMPLETE) == PLSR_RESULT_OK); PlsrProcess(); CHECK(TestGetStatus().state == PLSR_STATE_ACCEL); CHECK(TestGetStatus().currentSegment == 1U); /* STOP 可打断自循环。 */ command.sequence = 111UL; command.axis = 0U; command.opcode = PLSR_CMD_STOP_IMMEDIATE; command.argument = 0; CHECK(PlsrPostCommand(&command) == PLSR_RESULT_QUEUED); PlsrProcess(); CHECK(PlsrPostEvent(0U, PLSR_EVENT_STOP_IMMEDIATE_DONE) == PLSR_RESULT_OK); PlsrProcess(); CHECK(TestGetStatus().state == PLSR_STATE_STOPPED); CHECK(TestGetStatus().done == 0U); } static void TestLastSegmentWaitTime(void) { TEST_MEMORY memory; int ticks; TestResetEnvironment(); (void)memset(&memory, 0, sizeof(memory)); TestWriteDword(&memory, PLSR_DEVICE_D, TEST_S0_BASE, 2); TestSetSegment(&memory, 1U, 1000U, 100, TEST_WAIT_CODE(0U, 0U), 0, 0U, 0); /* 最后一段用 WAIT 时间(信捷警告场景:验证不会卡死)。 */ TestSetSegment(&memory, 2U, 2000U, 200, TEST_WAIT_CODE(1U, 0U), 100, 0U, 0); { PLSR_CALL call = TestMakeCall(&memory); call.sequence = 120UL; CHECK(PlsrPostCall(&call) == PLSR_RESULT_QUEUED); } PlsrProcess(); TestAccelToRun(); CHECK(PlsrPostEvent(0U, PLSR_EVENT_SEGMENT_COMPLETE) == PLSR_RESULT_OK); PlsrProcess(); TestAccelToRun(); /* 段2(最后一段)完成 → 等待 100ms。 */ CHECK(PlsrPostEvent(0U, PLSR_EVENT_SEGMENT_COMPLETE) == PLSR_RESULT_OK); PlsrProcess(); CHECK(TestGetStatus().state == PLSR_STATE_WAIT); /* 计时到 → 任务正常结束。 */ for (ticks = 0; ticks < 100; ticks++) { PlsrProcess(); } CHECK(TestGetStatus().state == PLSR_STATE_COMPLETED); CHECK(TestGetStatus().done != 0U); } int main(void) { TestSequentialSegments(); TestJumpToSpecifiedSegment(); TestWaitTime(); TestWaitSignal(); TestActTruncatesSegment(); TestActPendingAfterSegmentDone(); TestExtEdgeTruncates(); TestExtOrComplete(); TestDynamicJump(); TestAbsoluteZeroDisplacement(); TestZeroJumpBudgetYields(); TestSelfLoopInterruptedByStop(); TestLastSegmentWaitTime(); if (TestFailures != 0) { (void)printf("FAIL: %d of %d PLSR path checks failed\n", TestFailures, TestChecks); return 1; } (void)printf("PASS: %d PLSR path checks\n", TestChecks); return 0; }