#include "plsr_path.h" #include /* 等待寄存器类型编码(PLSR_VALUE_SOURCE)与软元件类型(PLSR_DEVICE_TYPE) * 相差 1:D=1→D、HD=2→HD、FD=3→FD、X=4→X、M=5→M、HM=6→HM。 */ static uint8_t PlsrPathDeviceFromSource(uint8_t sourceCode) { return (uint8_t)(sourceCode - 1U); } static uint8_t PlsrPathReadDword(const PLSR_DATA_SOURCE *source, PLSR_DEVICE_TYPE device, uint32_t address, int32_t *value) { uint16_t lowWord; uint16_t highWord; if ((source->readWord == NULL) || (source->readWord(source->context, device, address, &lowWord) == 0U) || (source->readWord(source->context, device, address + 1U, &highWord) == 0U)) { return 0U; } *value = (int32_t)(((uint32_t)highWord << 16U) | (uint32_t)lowWord); return 1U; } static uint8_t PlsrPathReadBit(const PLSR_DATA_SOURCE *source, PLSR_DEVICE_TYPE device, uint32_t address, uint8_t *value) { if ((source->readBit == NULL) || (source->readBit(source->context, device, address, value) == 0U)) { return 0U; } return 1U; } /* 求值当前段的跳转目标。 * 返回:0=顺序下一段,1~segmentCount=指定段。 * 动态来源在跳转发生时重新读取;非法值置 error。 */ static int32_t PlsrPathResolveJumpTarget(const PLSR_JOB_SNAPSHOT *job, uint16_t segment, uint8_t *error) { const PLSR_SEGMENT_SNAPSHOT *segmentSnapshot = &job->segments[segment - 1U]; int32_t target; *error = 0U; if (segmentSnapshot->jumpSource == PLSR_VALUE_CONSTANT) { target = segmentSnapshot->jumpValueOrAddress; } else { if (PlsrPathReadDword(&job->source, (PLSR_DEVICE_TYPE)PlsrPathDeviceFromSource( segmentSnapshot->jumpSource), (uint32_t)segmentSnapshot->jumpValueOrAddress, &target) == 0U) { *error = 1U; return 0; } } if ((target < 0) || (target > (int32_t)job->segmentCount)) { *error = 1U; return 0; } return target; } /* 段是否零脉冲:相对模式脉冲数为 0,或绝对模式目标等于进入段时的位置。 */ static uint8_t PlsrPathSegmentIsZeroPulse(const PLSR_JOB_SNAPSHOT *job, uint16_t segment, int64_t logicalPosition) { const PLSR_SEGMENT_SNAPSHOT *segmentSnapshot = &job->segments[segment - 1U]; int64_t targetPosition; if ((segmentSnapshot->flags & PLSR_SEGMENT_FLAG_ZERO_PULSE) != 0U) { return 1U; } if ((job->positioningMode == 1U) && (PlsrPositionAbsoluteUnitsToPulses( &job->equivalent, segmentSnapshot->pulseOrTarget, &targetPosition) == PLSR_RESULT_OK) && (targetPosition == logicalPosition)) { return 1U; } return 0U; } /* 进入新段时的初始化:求值 ACT 时间、EXT/等待信号地址与当前电平。 */ static void PlsrPathEnterSegment(PLSR_PATH_CONTEXT *context, const PLSR_JOB_SNAPSHOT *job) { const PLSR_SEGMENT_SNAPSHOT *segmentSnapshot = &job->segments[context->currentSegment - 1U]; int32_t actValue; context->segmentEnded = 0U; context->extActive = 0U; context->actActive = 0U; context->waitCondition = (uint8_t)segmentSnapshot->waitCondition; switch (context->waitCondition) { case PLSR_WAIT_ACT_TIME: context->actActive = 1U; if (segmentSnapshot->waitSource == PLSR_VALUE_CONSTANT) { actValue = segmentSnapshot->waitValueOrAddress; } else { actValue = 0; (void)PlsrPathReadDword(&job->source, (PLSR_DEVICE_TYPE) PlsrPathDeviceFromSource( segmentSnapshot->waitSource), (uint32_t) segmentSnapshot->waitValueOrAddress, &actValue); } context->waitRemainingMs = (actValue > 0) ? (uint32_t)actValue : 0U; break; case PLSR_WAIT_SIGNAL: case PLSR_WAIT_EXT: case PLSR_WAIT_EXT_OR_COMPLETE: context->waitSignalDevice = PlsrPathDeviceFromSource(segmentSnapshot->waitSource); context->waitSignalAddress = (uint32_t)segmentSnapshot->waitValueOrAddress; if (context->waitCondition != PLSR_WAIT_SIGNAL) { /* EXT:记录段开始时的电平,已有的有效电平不算新边沿。 */ uint8_t level = 0U; (void)PlsrPathReadBit(&job->source, (PLSR_DEVICE_TYPE) context->waitSignalDevice, context->waitSignalAddress, &level); context->lastExtLevel = level; context->extActive = 1U; } break; default: break; } } /* EXT 边沿检测:电平 0→1 才算新边沿。 */ static uint8_t PlsrPathPollExt(PLSR_PATH_CONTEXT *context, const PLSR_JOB_SNAPSHOT *job) { uint8_t level = 0U; uint8_t triggered = 0U; if (PlsrPathReadBit(&job->source, (PLSR_DEVICE_TYPE)context->waitSignalDevice, context->waitSignalAddress, &level) != 0U) { if ((level != 0U) && (context->lastExtLevel == 0U)) { triggered = 1U; } context->lastExtLevel = level; } return triggered; } /* 推进跳转链:零脉冲段连续跳转(预算内),直到有脉冲段、结束或预算耗尽。 */ static PLSR_PATH_ACTION PlsrPathAdvance(PLSR_PATH_CONTEXT *context, const PLSR_JOB_SNAPSHOT *job, int64_t logicalPosition) { uint8_t error; int32_t target; uint16_t next; while (context->zeroJumpBudget > 0U) { target = PlsrPathResolveJumpTarget(job, context->currentSegment, &error); if (error != 0U) { context->jobEnded = 1U; context->phase = PLSR_PATH_ENDED; return PLSR_PATH_ACTION_ERROR; } if (target == 0) { if (context->currentSegment >= job->segmentCount) { context->jobEnded = 1U; context->phase = PLSR_PATH_ENDED; return PLSR_PATH_ACTION_JOB_COMPLETE; } next = (uint16_t)(context->currentSegment + 1U); } else { next = (uint16_t)target; } if (PlsrPathSegmentIsZeroPulse(job, next, logicalPosition) != 0U) { context->zeroJumpBudget--; context->currentSegment = next; context->nextSegment = next; PlsrPathEnterSegment(context, job); continue; } context->currentSegment = next; context->nextSegment = next; context->phase = PLSR_PATH_SEGMENT_RUNNING; PlsrPathEnterSegment(context, job); return PLSR_PATH_ACTION_NEXT_SEGMENT; } context->jumpChainPending = 1U; return PLSR_PATH_ACTION_YIELD; } void PlsrPathBegin(PLSR_PATH_CONTEXT *context, const PLSR_JOB_SNAPSHOT *job, int64_t logicalPosition) { (void)memset(context, 0, sizeof(*context)); context->currentSegment = job->startSegment; context->nextSegment = context->currentSegment; context->zeroJumpBudget = PLSR_PATH_ZERO_JUMP_BUDGET; context->phase = PLSR_PATH_SEGMENT_RUNNING; PlsrPathEnterSegment(context, job); if (PlsrPathSegmentIsZeroPulse(job, context->currentSegment, logicalPosition) != 0U) { /* 起点段就是零脉冲:直接走跳转链。 */ (void)PlsrPathAdvance(context, job, logicalPosition); } } PLSR_PATH_ACTION PlsrPathOnSegmentDone(PLSR_PATH_CONTEXT *context, const PLSR_JOB_SNAPSHOT *job, int64_t logicalPosition) { const PLSR_SEGMENT_SNAPSHOT *segmentSnapshot; int32_t waitValue; uint8_t level; if ((context->jobEnded != 0U) || (context->phase == PLSR_PATH_ENDED)) { return PLSR_PATH_ACTION_NONE; } context->segmentEnded = 1U; context->zeroJumpBudget = PLSR_PATH_ZERO_JUMP_BUDGET; context->jumpChainPending = 0U; segmentSnapshot = &job->segments[context->currentSegment - 1U]; switch (context->waitCondition) { case PLSR_WAIT_PULSE_COMPLETE: case PLSR_WAIT_EXT_OR_COMPLETE: return PlsrPathAdvance(context, job, logicalPosition); case PLSR_WAIT_TIME: /* 等待时间在段完成时求值一次。 */ if (segmentSnapshot->waitSource == PLSR_VALUE_CONSTANT) { waitValue = segmentSnapshot->waitValueOrAddress; } else { waitValue = 0; (void)PlsrPathReadDword( &job->source, (PLSR_DEVICE_TYPE)PlsrPathDeviceFromSource( segmentSnapshot->waitSource), (uint32_t)segmentSnapshot->waitValueOrAddress, &waitValue); } context->waitRemainingMs = (waitValue > 0) ? (uint32_t)waitValue : 0U; if (context->waitRemainingMs == 0U) { return PlsrPathAdvance(context, job, logicalPosition); } context->phase = PLSR_PATH_WAIT_TIME; return PLSR_PATH_ACTION_ENTER_WAIT; case PLSR_WAIT_SIGNAL: /* 信号地址已在进入段时求值;先立即检查一次,已有效则直接跳。 */ if (PlsrPathReadBit(&job->source, (PLSR_DEVICE_TYPE)context->waitSignalDevice, context->waitSignalAddress, &level) != 0U) { if (level != 0U) { return PlsrPathAdvance(context, job, logicalPosition); } } context->phase = PLSR_PATH_WAIT_SIGNAL; return PLSR_PATH_ACTION_ENTER_WAIT; case PLSR_WAIT_ACT_TIME: if (context->waitRemainingMs == 0U) { return PlsrPathAdvance(context, job, logicalPosition); } /* 段已完成但 ACT 未到:停在 ACT_PENDING(core 处于 WAIT)。 */ context->phase = PLSR_PATH_ACT_PENDING; return PLSR_PATH_ACTION_ENTER_WAIT; case PLSR_WAIT_EXT: /* 段已完成但 EXT 未触发:继续等新边沿。 */ context->phase = PLSR_PATH_WAIT_SIGNAL; return PLSR_PATH_ACTION_ENTER_WAIT; default: return PlsrPathAdvance(context, job, logicalPosition); } } PLSR_PATH_ACTION PlsrPathTick(PLSR_PATH_CONTEXT *context, const PLSR_JOB_SNAPSHOT *job, int64_t logicalPosition) { uint8_t level; if ((context->jobEnded != 0U) || (context->phase == PLSR_PATH_ENDED)) { return PLSR_PATH_ACTION_NONE; } if (context->jumpChainPending != 0U) { /* 上轮预算耗尽让出:本轮重置预算继续跳转链。 */ context->zeroJumpBudget = PLSR_PATH_ZERO_JUMP_BUDGET; context->jumpChainPending = 0U; return PlsrPathAdvance(context, job, logicalPosition); } switch (context->phase) { case PLSR_PATH_SEGMENT_RUNNING: if ((context->actActive != 0U) && (context->waitRemainingMs > 0U)) { context->waitRemainingMs--; if (context->waitRemainingMs == 0U) { /* ACT 到时:截断当前段,立即跳转。 */ return PlsrPathAdvance(context, job, logicalPosition); } } if ((context->extActive != 0U) && (PlsrPathPollExt(context, job) != 0U)) { return PlsrPathAdvance(context, job, logicalPosition); } break; case PLSR_PATH_WAIT_TIME: if (context->waitRemainingMs > 0U) { context->waitRemainingMs--; } if (context->waitRemainingMs == 0U) { return PlsrPathAdvance(context, job, logicalPosition); } break; case PLSR_PATH_WAIT_SIGNAL: if (context->waitCondition == PLSR_WAIT_SIGNAL) { /* H02:电平有效即触发。 */ if (PlsrPathReadBit(&job->source, (PLSR_DEVICE_TYPE) context->waitSignalDevice, context->waitSignalAddress, &level) != 0U) { if (level != 0U) { return PlsrPathAdvance(context, job, logicalPosition); } } } else { /* H04 段完成后的 EXT 等待:新边沿触发。 */ if (PlsrPathPollExt(context, job) != 0U) { return PlsrPathAdvance(context, job, logicalPosition); } } break; case PLSR_PATH_ACT_PENDING: if (context->waitRemainingMs > 0U) { context->waitRemainingMs--; } if (context->waitRemainingMs == 0U) { return PlsrPathAdvance(context, job, logicalPosition); } break; default: break; } return PLSR_PATH_ACTION_NONE; } uint16_t PlsrPathGetCurrentSegment(const PLSR_PATH_CONTEXT *context) { if (context == NULL) { return 0U; } return context->currentSegment; } void PlsrPathTerminate(PLSR_PATH_CONTEXT *context) { if (context == NULL) { return; } context->phase = PLSR_PATH_ENDED; context->jobEnded = 1U; context->jumpChainPending = 0U; context->zeroJumpBudget = 0U; }