|
- #include "plsr_path.h"
- #include <string.h>
-
- /* 等待寄存器类型编码(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];
-
- if ((segmentSnapshot->flags & PLSR_SEGMENT_FLAG_ZERO_PULSE) != 0U)
- {
- return 1U;
- }
- if ((job->positioningMode == 1U)
- && (segmentSnapshot->pulseOrTarget == (int32_t)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;
- }
|