#include "plsr_core.h" #include "plc_device.h" #include "plsr_address_map.h" #include "plsr_hal_f407.h" #include "plsr_path.h" #include "plsr_profile.h" #include "plsr_resource.h" #include #ifndef PLSR_HOST_TEST #include "stm32f4xx.h" #include "ucos_ii.h" #endif typedef struct { PLSR_STATE state; PLSR_OUTPUT_MODE outputMode; PLSR_ERROR error; PLSR_STOP_REASON stopReason; PLSR_STATE pendingTerminal; PLSR_RESOURCE_LEASE lease; PLSR_JOB_SNAPSHOT job; PLSR_PARSE_DETAIL parseDetail; volatile uint32_t pendingEvents; uint32_t lastCommandSequence; PLSR_RESULT lastCommandResult; uint32_t illegalTransitionCount; int64_t logicalPosition; int64_t totalPulses; PLSR_PATH_CONTEXT path; PLSR_PROFILE_STATE profile; uint8_t profileActive; uint8_t profileWasAccel; uint8_t hasLastCommand; uint8_t done; uint8_t directionPositive; uint8_t immediateStopPending; uint8_t positionValid; uint8_t jobValid; uint8_t positionOverflow; } PLSR_AXIS; typedef struct { PLSR_COMMAND command; PLSR_START_REQUEST start; PLSR_CALL call; uint32_t ticket; uint8_t hasStart; uint8_t hasCall; uint8_t occupied; } PLSR_COMMAND_SLOT; static PLSR_AXIS PlsrAxes[PLSR_AXIS_COUNT]; static PLSR_COMMAND_SLOT PlsrCommandQueue[PLSR_COMMAND_QUEUE_DEPTH]; static uint32_t PlsrNextTicket; static uint8_t PlsrInitialized; static PLSR_JOB_SNAPSHOT PlsrJobScratch; static void PlsrStopSegmentHardware(uint8_t axis, PLSR_AXIS *axisObject); static void PlsrStartSegmentHardware(uint8_t axis, PLSR_AXIS *axisObject); static uint32_t PlsrCoreEnterCritical(void) { #ifdef PLSR_HOST_TEST return 0UL; #else uint32_t interruptState = __get_PRIMASK(); __disable_irq(); __DMB(); return interruptState; #endif } static void PlsrCoreExitCritical(uint32_t interruptState) { #ifdef PLSR_HOST_TEST (void)interruptState; #else __DMB(); if (interruptState == 0UL) { __enable_irq(); } #endif } static uint8_t PlsrStateIsBusy(PLSR_STATE state) { return ((state == PLSR_STATE_ACCEL) || (state == PLSR_STATE_RUN) || (state == PLSR_STATE_DECEL) || (state == PLSR_STATE_WAIT) || (state == PLSR_STATE_PAUSED)) ? 1U : 0U; } static uint8_t PlsrStateIsPulseActive(PLSR_STATE state) { return ((state == PLSR_STATE_ACCEL) || (state == PLSR_STATE_RUN) || (state == PLSR_STATE_DECEL)) ? 1U : 0U; } static void PlsrPublishAxis(uint8_t axis) { PLSR_AXIS *axisObject = &PlsrAxes[axis]; uint8_t compatibleRun; compatibleRun = (uint8_t)((PlsrStateIsPulseActive(axisObject->state) != 0U) || (axisObject->state == PLSR_STATE_WAIT)); (void)PlcDevicePublishSm(axis, compatibleRun, axisObject->directionPositive); } static void PlsrSetStopReason(PLSR_AXIS *axis, PLSR_STOP_REASON stopReason) { if (stopReason > axis->stopReason) { axis->stopReason = stopReason; } } /* 将 64 位逻辑位置发布为 HSD 的 32 位兼容值: * 超出 INT32 范围时回绕(与信捷 32 位寄存器一致)并置溢出诊断标志。 */ static void PlsrPublishPosition(uint8_t axis, PLSR_AXIS *axisObject) { int32_t compatValue; if ((axisObject->logicalPosition > INT32_MAX) || (axisObject->logicalPosition < INT32_MIN)) { axisObject->positionOverflow = 1U; } compatValue = (int32_t)(uint32_t)axisObject->logicalPosition; (void)PlcDevicePublishHsdDword( (uint16_t)((uint16_t)axis * PLSR_HSD_RUNTIME_AXIS_COUNT), compatValue); } static uint8_t PlsrTransitionIsAllowed(PLSR_STATE current, PLSR_STATE target) { if (current == target) { return 1U; } if (target == PLSR_STATE_ERROR) { return 1U; } switch (current) { case PLSR_STATE_UNINITIALIZED: return (target == PLSR_STATE_IDLE) ? 1U : 0U; case PLSR_STATE_IDLE: case PLSR_STATE_COMPLETED: case PLSR_STATE_STOPPED: return ((target == PLSR_STATE_ACCEL) || (target == PLSR_STATE_WAIT) || (target == PLSR_STATE_COMPLETED)) ? 1U : 0U; case PLSR_STATE_ACCEL: case PLSR_STATE_RUN: return ((target == PLSR_STATE_ACCEL) || (target == PLSR_STATE_RUN) || (target == PLSR_STATE_DECEL) || (target == PLSR_STATE_WAIT) || (target == PLSR_STATE_COMPLETED) || (target == PLSR_STATE_STOPPED)) ? 1U : 0U; case PLSR_STATE_DECEL: return ((target == PLSR_STATE_ACCEL) || (target == PLSR_STATE_RUN) || (target == PLSR_STATE_WAIT) || (target == PLSR_STATE_PAUSED) || (target == PLSR_STATE_COMPLETED) || (target == PLSR_STATE_STOPPED)) ? 1U : 0U; case PLSR_STATE_WAIT: return ((target == PLSR_STATE_ACCEL) || (target == PLSR_STATE_RUN) || (target == PLSR_STATE_PAUSED) || (target == PLSR_STATE_COMPLETED) || (target == PLSR_STATE_STOPPED)) ? 1U : 0U; case PLSR_STATE_PAUSED: return ((target == PLSR_STATE_ACCEL) || (target == PLSR_STATE_RUN) || (target == PLSR_STATE_STOPPED)) ? 1U : 0U; case PLSR_STATE_ERROR: return (target == PLSR_STATE_IDLE) ? 1U : 0U; default: return 0U; } } PLSR_RESULT PlsrStateTransition(uint8_t axis, PLSR_STATE target, PLSR_TRANSITION_REASON reason) { PLSR_AXIS *axisObject; (void)reason; if (axis >= PLSR_AXIS_COUNT) { return PLSR_RESULT_INVALID_AXIS; } if ((uint32_t)target > (uint32_t)PLSR_STATE_ERROR) { return PLSR_RESULT_INVALID_ARGUMENT; } axisObject = &PlsrAxes[axis]; if (PlsrTransitionIsAllowed(axisObject->state, target) == 0U) { axisObject->illegalTransitionCount++; axisObject->error = PLSR_ERROR_ILLEGAL_TRANSITION; axisObject->stopReason = PLSR_STOP_REASON_FAULT; axisObject->done = 0U; axisObject->state = PLSR_STATE_ERROR; axisObject->pendingTerminal = PLSR_STATE_UNINITIALIZED; axisObject->immediateStopPending = 0U; PlsrStopSegmentHardware(axis, axisObject); PlsrResourceRelease(&axisObject->lease); PlsrPublishAxis(axis); return PLSR_RESULT_INVALID_STATE; } axisObject->state = target; if (target == PLSR_STATE_COMPLETED) { axisObject->done = 1U; } if ((target == PLSR_STATE_COMPLETED) || (target == PLSR_STATE_STOPPED) || (target == PLSR_STATE_ERROR)) { axisObject->pendingTerminal = PLSR_STATE_UNINITIALIZED; axisObject->immediateStopPending = 0U; PlsrPathTerminate(&axisObject->path); PlsrStopSegmentHardware(axis, axisObject); PlsrResourceRelease(&axisObject->lease); /* 运动已结束:记录 lastBusy=0,保证掉电后恢复时位置仍可信。 */ (void)PlcDeviceSetHsdCheckpointMeta(axisObject->positionValid, 0U); (void)PlcDeviceCheckpointHsd(); } PlsrPublishAxis(axis); return PLSR_RESULT_OK; } static uint8_t PlsrCommandPriority(PLSR_COMMAND_OPCODE opcode) { switch (opcode) { case PLSR_CMD_STOP_IMMEDIATE: return 0U; case PLSR_CMD_STOP_DECEL: return 1U; case PLSR_CMD_PAUSE: return 2U; case PLSR_CMD_RESUME: return 3U; default: return 4U; } } static PLSR_RESULT PlsrQueueCommand(const PLSR_COMMAND *command, const PLSR_START_REQUEST *start, const PLSR_CALL *call) { uint32_t interruptState; uint8_t freeSlot = PLSR_COMMAND_QUEUE_DEPTH; uint8_t index; interruptState = PlsrCoreEnterCritical(); if ((PlsrAxes[command->axis].hasLastCommand != 0U) && (PlsrAxes[command->axis].lastCommandSequence == command->sequence)) { PLSR_RESULT result = PlsrAxes[command->axis].lastCommandResult; PlsrCoreExitCritical(interruptState); return result; } for (index = 0U; index < PLSR_COMMAND_QUEUE_DEPTH; index++) { if (PlsrCommandQueue[index].occupied != 0U) { if ((PlsrCommandQueue[index].command.axis == command->axis) && (PlsrCommandQueue[index].command.sequence == command->sequence)) { PlsrCoreExitCritical(interruptState); return PLSR_RESULT_QUEUED; } } else if (freeSlot == PLSR_COMMAND_QUEUE_DEPTH) { freeSlot = index; } } if (freeSlot == PLSR_COMMAND_QUEUE_DEPTH) { PlsrCoreExitCritical(interruptState); return PLSR_RESULT_QUEUE_FULL; } PlsrCommandQueue[freeSlot].command = *command; if (start != NULL) { PlsrCommandQueue[freeSlot].start = *start; PlsrCommandQueue[freeSlot].hasStart = 1U; } else { (void)memset(&PlsrCommandQueue[freeSlot].start, 0, sizeof(PlsrCommandQueue[freeSlot].start)); PlsrCommandQueue[freeSlot].hasStart = 0U; } if (call != NULL) { PlsrCommandQueue[freeSlot].call = *call; PlsrCommandQueue[freeSlot].hasCall = 1U; } else { (void)memset(&PlsrCommandQueue[freeSlot].call, 0, sizeof(PlsrCommandQueue[freeSlot].call)); PlsrCommandQueue[freeSlot].hasCall = 0U; } PlsrCommandQueue[freeSlot].ticket = PlsrNextTicket++; PlsrCommandQueue[freeSlot].occupied = 1U; PlsrCoreExitCritical(interruptState); return PLSR_RESULT_QUEUED; } static uint8_t PlsrPopHighestPriorityCommand(PLSR_COMMAND_SLOT *slot) { uint32_t interruptState; uint32_t selectedTicket = 0UL; uint8_t selectedPriority = 0xFFU; uint8_t selected = PLSR_COMMAND_QUEUE_DEPTH; uint8_t index; uint8_t priority; interruptState = PlsrCoreEnterCritical(); for (index = 0U; index < PLSR_COMMAND_QUEUE_DEPTH; index++) { if (PlsrCommandQueue[index].occupied == 0U) { continue; } priority = PlsrCommandPriority(PlsrCommandQueue[index].command.opcode); if ((selected == PLSR_COMMAND_QUEUE_DEPTH) || (priority < selectedPriority) || ((priority == selectedPriority) && ((int32_t)(PlsrCommandQueue[index].ticket - selectedTicket) < 0))) { selected = index; selectedPriority = priority; selectedTicket = PlsrCommandQueue[index].ticket; } } if (selected == PLSR_COMMAND_QUEUE_DEPTH) { PlsrCoreExitCritical(interruptState); return 0U; } *slot = PlsrCommandQueue[selected]; PlsrCommandQueue[selected].occupied = 0U; PlsrCoreExitCritical(interruptState); return 1U; } #ifdef PLSR_HOST_TEST PLSR_RESULT PlsrPostStart(const PLSR_START_REQUEST *request) { PLSR_COMMAND command; if (request == NULL) { return PLSR_RESULT_INVALID_ARGUMENT; } if (request->axis >= PLSR_AXIS_COUNT) { return PLSR_RESULT_INVALID_AXIS; } if (PlsrInitialized == 0U) { return PLSR_RESULT_INVALID_STATE; } command.sequence = request->sequence; command.axis = request->axis; command.opcode = PLSR_CMD_START; command.argument = 0; return PlsrQueueCommand(&command, request, NULL); } #endif /* PLSR_HOST_TEST */ PLSR_RESULT PlsrPostCall(const PLSR_CALL *call) { PLSR_COMMAND command; if (call == NULL) { return PLSR_RESULT_INVALID_ARGUMENT; } if (call->dAxis >= PLSR_AXIS_COUNT) { return PLSR_RESULT_INVALID_AXIS; } if (PlsrInitialized == 0U) { return PLSR_RESULT_INVALID_STATE; } command.sequence = call->sequence; command.axis = call->dAxis; command.opcode = PLSR_CMD_START; command.argument = 0; return PlsrQueueCommand(&command, NULL, call); } PLSR_RESULT PlsrPostCommand(const PLSR_COMMAND *command) { if (command == NULL) { return PLSR_RESULT_INVALID_ARGUMENT; } if (command->axis >= PLSR_AXIS_COUNT) { return PLSR_RESULT_INVALID_AXIS; } if (((uint32_t)command->opcode > (uint32_t)PLSR_CMD_SELF_TEST) || (command->opcode == PLSR_CMD_START)) { return PLSR_RESULT_INVALID_ARGUMENT; } if (PlsrInitialized == 0U) { return PLSR_RESULT_INVALID_STATE; } return PlsrQueueCommand(command, NULL, NULL); } PLSR_RESULT PlsrPostEvent(uint8_t axis, uint32_t eventMask) { uint32_t interruptState; if (axis >= PLSR_AXIS_COUNT) { return PLSR_RESULT_INVALID_AXIS; } if ((eventMask == 0UL) || ((eventMask & ~PLSR_EVENT_ALL_MASK) != 0UL)) { return PLSR_RESULT_INVALID_ARGUMENT; } interruptState = PlsrCoreEnterCritical(); PlsrAxes[axis].pendingEvents |= eventMask; PlsrCoreExitCritical(interruptState); return PLSR_RESULT_OK; } static uint32_t PlsrTakeEvents(uint8_t axis, uint32_t mask) { uint32_t interruptState; uint32_t events; interruptState = PlsrCoreEnterCritical(); events = PlsrAxes[axis].pendingEvents & mask; PlsrAxes[axis].pendingEvents &= ~events; PlsrCoreExitCritical(interruptState); return events; } static uint8_t PlsrAnyAxisBusy(void) { uint8_t axis; for (axis = 0U; axis < PLSR_AXIS_COUNT; axis++) { if (PlsrStateIsBusy(PlsrAxes[axis].state) != 0U) { return 1U; } } return 0U; } static PLSR_RESULT PlsrStartAxis(PLSR_AXIS *axisObject, const PLSR_START_REQUEST *start) { PLSR_RESOURCE_REQUEST resourceRequest; PLSR_RESULT result; if ((axisObject->state != PLSR_STATE_IDLE) && (axisObject->state != PLSR_STATE_COMPLETED) && (axisObject->state != PLSR_STATE_STOPPED)) { return PLSR_RESULT_INVALID_STATE; } resourceRequest.ownerAxis = start->axis; resourceRequest.outputMode = start->outputMode; resourceRequest.dAxis = start->axis; resourceRequest.directionPoint = start->directionPoint; result = PlsrResourceReserve(&resourceRequest, &axisObject->lease); if (result != PLSR_RESULT_OK) { axisObject->error = (result == PLSR_RESULT_RESOURCE_CONFLICT) ? PLSR_ERROR_RESOURCE_CONFLICT : PLSR_ERROR_INVALID_RESOURCE; return result; } axisObject->outputMode = start->outputMode; axisObject->directionPositive = (start->directionPositive != 0U) ? 1U : 0U; axisObject->error = PLSR_ERROR_NONE; axisObject->stopReason = PLSR_STOP_REASON_NONE; axisObject->pendingTerminal = PLSR_STATE_UNINITIALIZED; axisObject->immediateStopPending = 0U; axisObject->done = 0U; axisObject->jobValid = 0U; result = PlsrStateTransition(start->axis, PLSR_STATE_ACCEL, PLSR_TRANSITION_START); if (result != PLSR_RESULT_OK) { PlsrResourceRelease(&axisObject->lease); } else { /* 运动开始:掉电恢复时据此判定"断电时在运动中"。 */ (void)PlcDeviceSetHsdCheckpointMeta(axisObject->positionValid, 1U); (void)PlcDeviceCheckpointHsd(); } return result; } static PLSR_RESULT PlsrStartCall(PLSR_AXIS *axisObject, const PLSR_CALL *call) { PLSR_RESOURCE_REQUEST resourceRequest; PLSR_PARSE_CONTEXT parseContext; PLSR_RESULT result; if ((axisObject->state != PLSR_STATE_IDLE) && (axisObject->state != PLSR_STATE_COMPLETED) && (axisObject->state != PLSR_STATE_STOPPED)) { return PLSR_RESULT_INVALID_STATE; } parseContext.logicalPosition = axisObject->logicalPosition; parseContext.positionValid = axisObject->positionValid; result = PlsrBuildJobSnapshot(call, &parseContext, &PlsrJobScratch, &axisObject->parseDetail); if (result != PLSR_RESULT_OK) { return result; } resourceRequest.ownerAxis = call->dAxis; resourceRequest.outputMode = (PLSR_OUTPUT_MODE)PlsrJobScratch.outputMode; resourceRequest.dAxis = call->dAxis; resourceRequest.directionPoint = PlsrJobScratch.directionPoint; result = PlsrResourceReserve(&resourceRequest, &axisObject->lease); if (result != PLSR_RESULT_OK) { axisObject->error = (result == PLSR_RESULT_RESOURCE_CONFLICT) ? PLSR_ERROR_RESOURCE_CONFLICT : PLSR_ERROR_INVALID_RESOURCE; axisObject->parseDetail.result = result; axisObject->parseDetail.block = PLSR_PARSE_BLOCK_OUTPUT; return result; } axisObject->job = PlsrJobScratch; axisObject->jobValid = 1U; axisObject->outputMode = (PLSR_OUTPUT_MODE)axisObject->job.outputMode; axisObject->directionPositive = axisObject->job.initialDirectionPositive; axisObject->error = PLSR_ERROR_NONE; axisObject->stopReason = PLSR_STOP_REASON_NONE; axisObject->pendingTerminal = PLSR_STATE_UNINITIALIZED; axisObject->immediateStopPending = 0U; axisObject->done = 0U; PlsrPathBegin(&axisObject->path, &axisObject->job, axisObject->logicalPosition); if (axisObject->path.jobEnded != 0U) { /* 起点就是零脉冲且跳转链已结束(任务无实际脉冲)。 */ axisObject->stopReason = PLSR_STOP_REASON_NORMAL_COMPLETE; (void)PlsrStateTransition(call->dAxis, PLSR_STATE_COMPLETED, PLSR_TRANSITION_JOB_COMPLETE); axisObject->jobValid = 0U; return PLSR_RESULT_OK; } result = PlsrStateTransition(call->dAxis, PLSR_STATE_ACCEL, PLSR_TRANSITION_START); if (result != PLSR_RESULT_OK) { axisObject->jobValid = 0U; PlsrResourceRelease(&axisObject->lease); } else { /* 启动当前段硬件输出与速度曲线。 */ PlsrStartSegmentHardware(call->dAxis, axisObject); /* 运动开始:掉电恢复时据此判定"断电时在运动中"。 */ (void)PlcDeviceSetHsdCheckpointMeta(axisObject->positionValid, 1U); (void)PlcDeviceCheckpointHsd(); } return result; } static PLSR_RESULT PlsrStopImmediate(uint8_t axis) { PLSR_AXIS *axisObject = &PlsrAxes[axis]; if ((axisObject->state == PLSR_STATE_IDLE) || (axisObject->state == PLSR_STATE_COMPLETED) || (axisObject->state == PLSR_STATE_STOPPED)) { return PLSR_RESULT_OK; } if (axisObject->state == PLSR_STATE_ERROR) { return PLSR_RESULT_INVALID_STATE; } if (axisObject->immediateStopPending != 0U) { return PLSR_RESULT_OK; } PlsrSetStopReason(axisObject, PLSR_STOP_REASON_STOP_IMMEDIATE); axisObject->pendingTerminal = PLSR_STATE_STOPPED; PlsrPathTerminate(&axisObject->path); PlsrStopSegmentHardware(axis, axisObject); if ((axisObject->state == PLSR_STATE_WAIT) || (axisObject->state == PLSR_STATE_PAUSED)) { return PlsrStateTransition(axis, PLSR_STATE_STOPPED, PLSR_TRANSITION_STOP); } axisObject->immediateStopPending = 1U; return PLSR_RESULT_OK; } static PLSR_RESULT PlsrStopDecel(uint8_t axis) { PLSR_AXIS *axisObject = &PlsrAxes[axis]; if ((axisObject->state == PLSR_STATE_IDLE) || (axisObject->state == PLSR_STATE_COMPLETED) || (axisObject->state == PLSR_STATE_STOPPED)) { return PLSR_RESULT_OK; } if (axisObject->state == PLSR_STATE_ERROR) { return PLSR_RESULT_INVALID_STATE; } if (axisObject->stopReason >= PLSR_STOP_REASON_STOP_IMMEDIATE) { return PLSR_RESULT_OK; } PlsrSetStopReason(axisObject, PLSR_STOP_REASON_STOP_DECEL); axisObject->pendingTerminal = PLSR_STATE_STOPPED; PlsrPathTerminate(&axisObject->path); PlsrStopSegmentHardware(axis, axisObject); if ((axisObject->state == PLSR_STATE_WAIT) || (axisObject->state == PLSR_STATE_PAUSED)) { return PlsrStateTransition(axis, PLSR_STATE_STOPPED, PLSR_TRANSITION_STOP); } if (axisObject->state == PLSR_STATE_DECEL) { return PLSR_RESULT_OK; } return PlsrStateTransition(axis, PLSR_STATE_DECEL, PLSR_TRANSITION_DECEL_REQUEST); } static PLSR_RESULT PlsrPause(uint8_t axis) { PLSR_AXIS *axisObject = &PlsrAxes[axis]; if (axisObject->state == PLSR_STATE_PAUSED) { return PLSR_RESULT_OK; } if (axisObject->stopReason >= PLSR_STOP_REASON_STOP_DECEL) { return PLSR_RESULT_BUSY; } if (axisObject->state == PLSR_STATE_WAIT) { PlsrSetStopReason(axisObject, PLSR_STOP_REASON_PAUSE); PlsrPathTerminate(&axisObject->path); PlsrStopSegmentHardware(axis, axisObject); return PlsrStateTransition(axis, PLSR_STATE_PAUSED, PLSR_TRANSITION_DECEL_COMPLETE); } if ((axisObject->state != PLSR_STATE_ACCEL) && (axisObject->state != PLSR_STATE_RUN) && (axisObject->state != PLSR_STATE_DECEL)) { return PLSR_RESULT_INVALID_STATE; } PlsrSetStopReason(axisObject, PLSR_STOP_REASON_PAUSE); axisObject->pendingTerminal = PLSR_STATE_PAUSED; PlsrPathTerminate(&axisObject->path); if (axisObject->state == PLSR_STATE_DECEL) { return PLSR_RESULT_OK; } return PlsrStateTransition(axis, PLSR_STATE_DECEL, PLSR_TRANSITION_DECEL_REQUEST); } static PLSR_RESULT PlsrExecuteCommand(const PLSR_COMMAND_SLOT *slot) { PLSR_AXIS *axisObject = &PlsrAxes[slot->command.axis]; PLC_DEVICE_RESULT deviceResult; PLSR_RESULT result; switch (slot->command.opcode) { case PLSR_CMD_START: if (slot->hasCall != 0U) { result = PlsrStartCall(axisObject, &slot->call); } else { result = (slot->hasStart != 0U) ? PlsrStartAxis(axisObject, &slot->start) : PLSR_RESULT_INVALID_ARGUMENT; } break; case PLSR_CMD_STOP_DECEL: result = PlsrStopDecel(slot->command.axis); break; case PLSR_CMD_STOP_IMMEDIATE: result = PlsrStopImmediate(slot->command.axis); break; case PLSR_CMD_PAUSE: result = PlsrPause(slot->command.axis); break; case PLSR_CMD_RESUME: if (axisObject->state != PLSR_STATE_PAUSED) { result = PLSR_RESULT_INVALID_STATE; } else { axisObject->stopReason = PLSR_STOP_REASON_NONE; axisObject->pendingTerminal = PLSR_STATE_UNINITIALIZED; result = PlsrStateTransition(slot->command.axis, PLSR_STATE_ACCEL, PLSR_TRANSITION_WAIT_COMPLETE); } break; case PLSR_CMD_SET_POSITION: if (PlsrStateIsBusy(axisObject->state) != 0U) { result = PLSR_RESULT_BUSY; } else { axisObject->logicalPosition = slot->command.argument; axisObject->positionValid = 1U; axisObject->positionOverflow = 0U; PlsrPublishPosition(slot->command.axis, axisObject); (void)PlcDeviceSetHsdCheckpointMeta(1U, 0U); (void)PlcDeviceCheckpointHsd(); result = PLSR_RESULT_OK; } break; case PLSR_CMD_CLEAR_POSITION: if (PlsrStateIsBusy(axisObject->state) != 0U) { result = PLSR_RESULT_BUSY; } else { axisObject->logicalPosition = 0; axisObject->positionValid = 1U; axisObject->positionOverflow = 0U; PlsrPublishPosition(slot->command.axis, axisObject); (void)PlcDeviceSetHsdCheckpointMeta(1U, 0U); (void)PlcDeviceCheckpointHsd(); result = PLSR_RESULT_OK; } break; case PLSR_CMD_CLEAR_TOTAL: if (PlsrStateIsBusy(axisObject->state) != 0U) { result = PLSR_RESULT_BUSY; } else { axisObject->totalPulses = 0; result = PLSR_RESULT_OK; } break; case PLSR_CMD_SAVE_CONFIG: if (PlsrAnyAxisBusy() != 0U) { result = PLSR_RESULT_BUSY; } else { deviceResult = PlcDeviceSaveSfd(); result = (deviceResult == PLC_DEVICE_OK) ? PLSR_RESULT_OK : PLSR_RESULT_PERSISTENCE_ERROR; } break; case PLSR_CMD_LOAD_CONFIG: if (PlsrAnyAxisBusy() != 0U) { result = PLSR_RESULT_BUSY; } else { deviceResult = PlcDeviceLoadSfd(); result = (deviceResult == PLC_DEVICE_OK) ? PLSR_RESULT_OK : PLSR_RESULT_PERSISTENCE_ERROR; } break; case PLSR_CMD_RESET_ERROR: if (axisObject->state != PLSR_STATE_ERROR) { result = PLSR_RESULT_INVALID_STATE; } else { axisObject->error = PLSR_ERROR_NONE; axisObject->stopReason = PLSR_STOP_REASON_NONE; axisObject->done = 0U; result = PlsrStateTransition(slot->command.axis, PLSR_STATE_IDLE, PLSR_TRANSITION_RESET_ERROR); } break; case PLSR_CMD_SELF_TEST: result = ((PlsrAnyAxisBusy() == 0U) && (PlsrResourceCheckInvariant() != 0U)) ? PLSR_RESULT_OK : PLSR_RESULT_BUSY; break; default: result = PLSR_RESULT_INVALID_ARGUMENT; break; } axisObject->lastCommandSequence = slot->command.sequence; axisObject->lastCommandResult = result; axisObject->hasLastCommand = 1U; PlsrPublishAxis(slot->command.axis); return result; } static void PlsrProcessCriticalEvents(uint8_t axis, uint32_t events) { PLSR_AXIS *axisObject = &PlsrAxes[axis]; if ((events & PLSR_EVENT_SOFTWARE_EMERGENCY) != 0UL) { if (PlsrStateIsBusy(axisObject->state) != 0U) { PlsrSetStopReason(axisObject, PLSR_STOP_REASON_SOFTWARE_EMERGENCY); axisObject->done = 0U; PlsrPathTerminate(&axisObject->path); PlsrStopSegmentHardware(axis, axisObject); (void)PlsrStateTransition(axis, PLSR_STATE_STOPPED, PLSR_TRANSITION_STOP); } return; } if ((events & PLSR_EVENT_LIMIT_POSITIVE) != 0UL) { if ((axisObject->directionPositive != 0U) && (PlsrStateIsBusy(axisObject->state) != 0U)) { axisObject->error = PLSR_ERROR_LIMIT_POSITIVE; PlsrSetStopReason(axisObject, PLSR_STOP_REASON_LIMIT_POSITIVE); axisObject->pendingTerminal = PLSR_STATE_STOPPED; PlsrPathTerminate(&axisObject->path); PlsrStopSegmentHardware(axis, axisObject); if ((axisObject->state == PLSR_STATE_WAIT) || (axisObject->state == PLSR_STATE_PAUSED)) { (void)PlsrStateTransition(axis, PLSR_STATE_STOPPED, PLSR_TRANSITION_STOP); } else if (axisObject->state != PLSR_STATE_DECEL) { (void)PlsrStateTransition(axis, PLSR_STATE_DECEL, PLSR_TRANSITION_DECEL_REQUEST); } } return; } if ((events & PLSR_EVENT_LIMIT_NEGATIVE) != 0UL) { if ((axisObject->directionPositive == 0U) && (PlsrStateIsBusy(axisObject->state) != 0U)) { axisObject->error = PLSR_ERROR_LIMIT_NEGATIVE; PlsrSetStopReason(axisObject, PLSR_STOP_REASON_LIMIT_NEGATIVE); axisObject->pendingTerminal = PLSR_STATE_STOPPED; PlsrPathTerminate(&axisObject->path); PlsrStopSegmentHardware(axis, axisObject); if ((axisObject->state == PLSR_STATE_WAIT) || (axisObject->state == PLSR_STATE_PAUSED)) { (void)PlsrStateTransition(axis, PLSR_STATE_STOPPED, PLSR_TRANSITION_STOP); } else if (axisObject->state != PLSR_STATE_DECEL) { (void)PlsrStateTransition(axis, PLSR_STATE_DECEL, PLSR_TRANSITION_DECEL_REQUEST); } } return; } if ((events & (PLSR_EVENT_TIMER_FAULT | PLSR_EVENT_COUNTER_FAULT)) != 0UL) { axisObject->error = ((events & PLSR_EVENT_TIMER_FAULT) != 0UL) ? PLSR_ERROR_TIMER_FAULT : PLSR_ERROR_COUNTER_FAULT; PlsrSetStopReason(axisObject, PLSR_STOP_REASON_FAULT); axisObject->done = 0U; PlsrPathTerminate(&axisObject->path); PlsrStopSegmentHardware(axis, axisObject); (void)PlsrStateTransition(axis, PLSR_STATE_ERROR, PLSR_TRANSITION_FAULT); } } /* 启动当前段的硬件输出与速度曲线(P3a:单轴 PULSE/DIR)。 * 由段进入 ACCEL 时调用(任务启动 + 段间推进)。 */ static void PlsrStartSegmentHardware(uint8_t axis, PLSR_AXIS *axisObject) { const PLSR_JOB_SNAPSHOT *job = &axisObject->job; const PLSR_SEGMENT_SNAPSHOT *segment = &job->segments[axisObject->path.currentSegment - 1U]; PLSR_PROFILE_REQUEST profileRequest; PLSR_HW_START_PARAMS params; int64_t pulses; uint8_t positive; if (job->positioningMode == 0U) { pulses = (segment->pulseOrTarget < 0) ? -(int64_t)segment->pulseOrTarget : (int64_t)segment->pulseOrTarget; positive = (segment->pulseOrTarget >= 0) ? 1U : 0U; } else { /* 绝对模式:P4 位置闭环后完善;P3a 按当前位置计算。 */ int64_t delta = (int64_t)segment->pulseOrTarget - axisObject->logicalPosition; pulses = (delta < 0) ? -delta : delta; positive = (delta >= 0) ? 1U : 0U; } (void)memset(&profileRequest, 0, sizeof(profileRequest)); profileRequest.targetFrequencyHz = segment->targetFrequency; profileRequest.startFrequencyHz = job->s2.startSpeed; profileRequest.stopFrequencyHz = job->s2.stopSpeed; profileRequest.maxFrequencyHz = job->s2.maximumSpeed; profileRequest.accelSlopeHzPerMs = (job->s2.accelerationMs != 0U) ? job->s2.defaultSpeed / job->s2.accelerationMs : 0UL; profileRequest.decelSlopeHzPerMs = (job->s2.decelerationMs != 0U) ? job->s2.defaultSpeed / job->s2.decelerationMs : 0UL; profileRequest.curveMode = job->s2.curveMode; if (PlsrProfileStart(&axisObject->profile, &profileRequest, pulses, 1000U) == PLSR_RESULT_OK) { axisObject->profileActive = 1U; axisObject->profileWasAccel = (axisObject->profile.phase == PLSR_PROFILE_PHASE_ACCEL) ? 1U : 0U; } params.frequencyHz = job->s2.startSpeed; params.targetPulses = pulses; params.directionPoint = job->directionPoint; params.directionPositive = positive; params.directionDelayMs = job->s2.directionDelayMs; (void)PlsrHwStartPulse(axis, ¶ms); } /* 停止当前段的硬件输出与速度曲线。 */ static void PlsrStopSegmentHardware(uint8_t axis, PLSR_AXIS *axisObject) { axisObject->profileActive = 0U; axisObject->profileWasAccel = 0U; (void)PlsrHwStopPulse(axis); } /* 应用路径执行器的动作:段间推进、进入等待、结束、让出、错误。 */ static void PlsrApplyPathAction(uint8_t axis, PLSR_PATH_ACTION action) { PLSR_AXIS *axisObject = &PlsrAxes[axis]; switch (action) { case PLSR_PATH_ACTION_NEXT_SEGMENT: if (axisObject->state == PLSR_STATE_WAIT) { (void)PlsrStateTransition(axis, PLSR_STATE_ACCEL, PLSR_TRANSITION_WAIT_COMPLETE); } else if ((axisObject->state == PLSR_STATE_ACCEL) || (axisObject->state == PLSR_STATE_RUN) || (axisObject->state == PLSR_STATE_DECEL)) { (void)PlsrStateTransition(axis, PLSR_STATE_ACCEL, PLSR_TRANSITION_START); } /* 进入新段:重新启动硬件输出与速度曲线。 */ if (axisObject->state == PLSR_STATE_ACCEL) { PlsrStartSegmentHardware(axis, axisObject); } break; case PLSR_PATH_ACTION_ENTER_WAIT: if ((axisObject->state == PLSR_STATE_ACCEL) || (axisObject->state == PLSR_STATE_RUN)) { (void)PlsrStateTransition(axis, PLSR_STATE_WAIT, PLSR_TRANSITION_WAIT_BEGIN); } break; case PLSR_PATH_ACTION_JOB_COMPLETE: if (PlsrStateIsBusy(axisObject->state) != 0U) { axisObject->stopReason = PLSR_STOP_REASON_NORMAL_COMPLETE; (void)PlsrStateTransition(axis, PLSR_STATE_COMPLETED, PLSR_TRANSITION_JOB_COMPLETE); } break; case PLSR_PATH_ACTION_YIELD: /* 预算耗尽:本轮不再推进,下个 tick 由 PlsrPathTick 恢复。 */ break; case PLSR_PATH_ACTION_ERROR: axisObject->error = PLSR_ERROR_INTERNAL; PlsrSetStopReason(axisObject, PLSR_STOP_REASON_FAULT); axisObject->done = 0U; (void)PlsrStateTransition(axis, PLSR_STATE_ERROR, PLSR_TRANSITION_FAULT); break; default: break; } } static void PlsrProcessNormalEvents(uint8_t axis, uint32_t events) { PLSR_AXIS *axisObject = &PlsrAxes[axis]; if (((events & PLSR_EVENT_STOP_IMMEDIATE_DONE) != 0UL) && (axisObject->immediateStopPending != 0U)) { (void)PlsrStateTransition(axis, PLSR_STATE_STOPPED, PLSR_TRANSITION_STOP); return; } if (((events & PLSR_EVENT_ACCEL_COMPLETE) != 0UL) && (axisObject->state == PLSR_STATE_ACCEL) && (axisObject->immediateStopPending == 0U)) { (void)PlsrStateTransition(axis, PLSR_STATE_RUN, PLSR_TRANSITION_ACCEL_COMPLETE); } if (((events & PLSR_EVENT_DECEL_COMPLETE) != 0UL) && (axisObject->state == PLSR_STATE_DECEL)) { if (axisObject->pendingTerminal == PLSR_STATE_PAUSED) { (void)PlsrStateTransition(axis, PLSR_STATE_PAUSED, PLSR_TRANSITION_DECEL_COMPLETE); } else if (axisObject->pendingTerminal == PLSR_STATE_STOPPED) { (void)PlsrStateTransition(axis, PLSR_STATE_STOPPED, PLSR_TRANSITION_DECEL_COMPLETE); } else { (void)PlsrStateTransition(axis, PLSR_STATE_RUN, PLSR_TRANSITION_DECEL_COMPLETE); } } if (((events & PLSR_EVENT_WAIT_BEGIN) != 0UL) && ((axisObject->state == PLSR_STATE_ACCEL) || (axisObject->state == PLSR_STATE_RUN))) { (void)PlsrStateTransition(axis, PLSR_STATE_WAIT, PLSR_TRANSITION_WAIT_BEGIN); } if (((events & PLSR_EVENT_WAIT_COMPLETE) != 0UL) && (axisObject->state == PLSR_STATE_WAIT)) { (void)PlsrStateTransition(axis, PLSR_STATE_ACCEL, PLSR_TRANSITION_WAIT_COMPLETE); } if (((events & PLSR_EVENT_SEGMENT_COMPLETE) != 0UL) && (axisObject->state == PLSR_STATE_RUN) && (axisObject->pendingTerminal == PLSR_STATE_UNINITIALIZED) && (axisObject->immediateStopPending == 0U)) { PLSR_PATH_ACTION action = PlsrPathOnSegmentDone( &axisObject->path, &axisObject->job, axisObject->logicalPosition); PlsrApplyPathAction(axis, action); } if (((events & PLSR_EVENT_JOB_COMPLETE) != 0UL) && (PlsrStateIsBusy(axisObject->state) != 0U) && (axisObject->pendingTerminal == PLSR_STATE_UNINITIALIZED) && (axisObject->immediateStopPending == 0U)) { axisObject->stopReason = PLSR_STOP_REASON_NORMAL_COMPLETE; (void)PlsrStateTransition(axis, PLSR_STATE_COMPLETED, PLSR_TRANSITION_JOB_COMPLETE); } } PLSR_RESULT PlsrInit(void) { int32_t restoredPosition; uint8_t restoredPositionValid; uint8_t restoredLastBusy; uint8_t axis; (void)memset(PlsrAxes, 0, sizeof(PlsrAxes)); (void)memset(PlsrCommandQueue, 0, sizeof(PlsrCommandQueue)); PlsrNextTicket = 0UL; PlsrResourceInit(); (void)PlsrHwInit(); PlsrInitialized = 1U; restoredPositionValid = PlcDeviceGetRestoredHsdPositionValid(); restoredLastBusy = PlcDeviceGetRestoredHsdLastBusy(); for (axis = 0U; axis < PLSR_AXIS_COUNT; axis++) { PlsrAxes[axis].state = PLSR_STATE_UNINITIALIZED; PlsrAxes[axis].pendingTerminal = PLSR_STATE_UNINITIALIZED; PlsrAxes[axis].lease.directionPoint = PLSR_DIRECTION_POINT_NONE; if (PlcDeviceReadHsdDword( (uint16_t)(axis * PLSR_HSD_RUNTIME_AXIS_COUNT), &restoredPosition) == PLC_DEVICE_OK) { PlsrAxes[axis].logicalPosition = restoredPosition; } /* 只有上次正常停机且保存了位置有效标志,才允许绝对定位; * 运动中掉电(lastBusy=1)时位置不可信。 */ if ((restoredPositionValid != 0U) && (restoredLastBusy == 0U)) { PlsrAxes[axis].positionValid = 1U; } if (PlsrStateTransition(axis, PLSR_STATE_IDLE, PLSR_TRANSITION_INITIALIZED) != PLSR_RESULT_OK) { return PLSR_RESULT_INTERNAL_ERROR; } } return PLSR_RESULT_OK; } void PlsrProcess(void) { PLSR_COMMAND_SLOT slot; uint32_t events; uint8_t processedCommands = 0U; uint8_t axis; if (PlsrInitialized == 0U) { return; } for (axis = 0U; axis < PLSR_AXIS_COUNT; axis++) { events = PlsrTakeEvents(axis, PLSR_EVENT_CRITICAL_MASK); if (events != 0UL) { PlsrProcessCriticalEvents(axis, events); } } while ((processedCommands < PLSR_COMMAND_QUEUE_DEPTH) && (PlsrPopHighestPriorityCommand(&slot) != 0U)) { (void)PlsrExecuteCommand(&slot); processedCommands++; } for (axis = 0U; axis < PLSR_AXIS_COUNT; axis++) { events = PlsrTakeEvents(axis, PLSR_EVENT_ALL_MASK & ~PLSR_EVENT_CRITICAL_MASK); if (events != 0UL) { PlsrProcessNormalEvents(axis, events); } } /* 1ms tick:路径执行器推进(WAIT/ACT 计时、信号/EXT 轮询、跳转链) * + 速度曲线推进(P2) + HAL 状态机(DIR 延时)。 */ for (axis = 0U; axis < PLSR_AXIS_COUNT; axis++) { PLSR_AXIS *axisObject = &PlsrAxes[axis]; PLSR_PATH_ACTION action; uint32_t frequencyHz; uint8_t profileDone; uint8_t wasAccel; PlsrHwTick(axis); if (PlsrStateIsBusy(axisObject->state) == 0U) { continue; } action = PlsrPathTick(&axisObject->path, &axisObject->job, axisObject->logicalPosition); if (action != PLSR_PATH_ACTION_NONE) { PlsrApplyPathAction(axis, action); } if (axisObject->profileActive != 0U) { wasAccel = axisObject->profileWasAccel; (void)PlsrProfileStep(&axisObject->profile, &frequencyHz, &profileDone); if (profileDone == 0U) { (void)PlsrHwSetFrequency(axis, frequencyHz); } axisObject->profileWasAccel = (axisObject->profile.phase == PLSR_PROFILE_PHASE_ACCEL) ? 1U : 0U; if ((wasAccel != 0U) && (axisObject->profileWasAccel == 0U) && (axisObject->state == PLSR_STATE_ACCEL)) { /* 加速完成(曲线进入匀速/减速)→ 状态机推进到 RUN。 */ (void)PlsrPostEvent(axis, PLSR_EVENT_ACCEL_COMPLETE); } } } } void PlsrTask(void *argument) { (void)argument; #ifdef PLSR_HOST_TEST PlsrProcess(); #else while (1) { PlsrProcess(); OSTimeDly(1U); } #endif } PLSR_RESULT PlsrGetStatus(uint8_t axis, PLSR_STATUS *status) { PLSR_AXIS *axisObject; uint32_t interruptState; if (axis >= PLSR_AXIS_COUNT) { return PLSR_RESULT_INVALID_AXIS; } if (status == NULL) { return PLSR_RESULT_INVALID_ARGUMENT; } interruptState = PlsrCoreEnterCritical(); axisObject = &PlsrAxes[axis]; status->state = axisObject->state; status->outputMode = axisObject->outputMode; status->error = axisObject->error; status->stopReason = axisObject->stopReason; status->lastCommandResult = axisObject->lastCommandResult; status->lastCommandSequence = axisObject->lastCommandSequence; status->illegalTransitionCount = axisObject->illegalTransitionCount; status->pendingEvents = axisObject->pendingEvents; status->logicalPosition = axisObject->logicalPosition; status->totalPulses = axisObject->totalPulses; status->busy = PlsrStateIsBusy(axisObject->state); status->pulseActive = PlsrStateIsPulseActive(axisObject->state); status->done = axisObject->done; status->wait = (axisObject->state == PLSR_STATE_WAIT) ? 1U : 0U; status->directionPositive = axisObject->directionPositive; status->highResourceMask = axisObject->lease.highMask; status->directionPoint = (axisObject->lease.valid != 0U) ? axisObject->lease.directionPoint : PLSR_DIRECTION_POINT_NONE; status->positionValid = axisObject->positionValid; status->jobValid = axisObject->jobValid; status->positionOverflow = axisObject->positionOverflow; status->s2Set = (axisObject->jobValid != 0U) ? axisObject->job.s2Set : 0U; status->speedClamped = (axisObject->jobValid != 0U) ? axisObject->job.speedClamped : 0U; status->segmentCount = (axisObject->jobValid != 0U) ? axisObject->job.segmentCount : 0U; status->startSegment = (axisObject->jobValid != 0U) ? axisObject->job.startSegment : 0U; status->currentSegment = (axisObject->jobValid != 0U) ? PlsrPathGetCurrentSegment( &axisObject->path) : 0U; PlsrCoreExitCritical(interruptState); return PLSR_RESULT_OK; } PLSR_RESULT PlsrGetLastParseDetail(uint8_t axis, PLSR_PARSE_DETAIL *detail) { uint32_t interruptState; if (axis >= PLSR_AXIS_COUNT) { return PLSR_RESULT_INVALID_AXIS; } if (detail == NULL) { return PLSR_RESULT_INVALID_ARGUMENT; } interruptState = PlsrCoreEnterCritical(); *detail = PlsrAxes[axis].parseDetail; PlsrCoreExitCritical(interruptState); return PLSR_RESULT_OK; }