You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1527 lines
50 KiB

  1. #include "plsr_core.h"
  2. #include "plc_device.h"
  3. #include "plsr_address_map.h"
  4. #include "plsr_hal_f407.h"
  5. #include "plsr_path.h"
  6. #include "plsr_profile.h"
  7. #include "plsr_resource.h"
  8. #include <string.h>
  9. #ifndef PLSR_HOST_TEST
  10. #include "stm32f4xx.h"
  11. #include "ucos_ii.h"
  12. #endif
  13. typedef struct
  14. {
  15. PLSR_STATE state;
  16. PLSR_OUTPUT_MODE outputMode;
  17. PLSR_ERROR error;
  18. PLSR_STOP_REASON stopReason;
  19. PLSR_STATE pendingTerminal;
  20. PLSR_RESOURCE_LEASE lease;
  21. PLSR_JOB_SNAPSHOT job;
  22. PLSR_PARSE_DETAIL parseDetail;
  23. volatile uint32_t pendingEvents;
  24. uint32_t lastCommandSequence;
  25. PLSR_RESULT lastCommandResult;
  26. uint32_t illegalTransitionCount;
  27. int64_t logicalPosition;
  28. int64_t totalPulses;
  29. PLSR_PATH_CONTEXT path;
  30. PLSR_PROFILE_STATE profile;
  31. uint8_t profileActive;
  32. uint8_t profileWasAccel;
  33. uint8_t hasLastCommand;
  34. uint8_t done;
  35. uint8_t directionPositive;
  36. uint8_t immediateStopPending;
  37. uint8_t positionValid;
  38. uint8_t jobValid;
  39. uint8_t positionOverflow;
  40. } PLSR_AXIS;
  41. typedef struct
  42. {
  43. PLSR_COMMAND command;
  44. PLSR_START_REQUEST start;
  45. PLSR_CALL call;
  46. uint32_t ticket;
  47. uint8_t hasStart;
  48. uint8_t hasCall;
  49. uint8_t occupied;
  50. } PLSR_COMMAND_SLOT;
  51. static PLSR_AXIS PlsrAxes[PLSR_AXIS_COUNT];
  52. static PLSR_COMMAND_SLOT PlsrCommandQueue[PLSR_COMMAND_QUEUE_DEPTH];
  53. static uint32_t PlsrNextTicket;
  54. static uint8_t PlsrInitialized;
  55. static PLSR_JOB_SNAPSHOT PlsrJobScratch;
  56. static void PlsrStopSegmentHardware(uint8_t axis, PLSR_AXIS *axisObject);
  57. static PLSR_RESULT PlsrStartSegmentHardware(uint8_t axis,
  58. PLSR_AXIS *axisObject);
  59. static uint32_t PlsrCoreEnterCritical(void)
  60. {
  61. #ifdef PLSR_HOST_TEST
  62. return 0UL;
  63. #else
  64. uint32_t interruptState = __get_PRIMASK();
  65. __disable_irq();
  66. __DMB();
  67. return interruptState;
  68. #endif
  69. }
  70. static void PlsrCoreExitCritical(uint32_t interruptState)
  71. {
  72. #ifdef PLSR_HOST_TEST
  73. (void)interruptState;
  74. #else
  75. __DMB();
  76. if (interruptState == 0UL)
  77. {
  78. __enable_irq();
  79. }
  80. #endif
  81. }
  82. static uint8_t PlsrStateIsBusy(PLSR_STATE state)
  83. {
  84. return ((state == PLSR_STATE_ACCEL) || (state == PLSR_STATE_RUN)
  85. || (state == PLSR_STATE_DECEL) || (state == PLSR_STATE_WAIT)
  86. || (state == PLSR_STATE_PAUSED))
  87. ? 1U
  88. : 0U;
  89. }
  90. static uint8_t PlsrStateIsPulseActive(PLSR_STATE state)
  91. {
  92. return ((state == PLSR_STATE_ACCEL) || (state == PLSR_STATE_RUN)
  93. || (state == PLSR_STATE_DECEL))
  94. ? 1U
  95. : 0U;
  96. }
  97. static void PlsrPublishAxis(uint8_t axis)
  98. {
  99. PLSR_AXIS *axisObject = &PlsrAxes[axis];
  100. uint8_t compatibleRun;
  101. compatibleRun = (uint8_t)((PlsrStateIsPulseActive(axisObject->state) != 0U)
  102. || (axisObject->state == PLSR_STATE_WAIT));
  103. (void)PlcDevicePublishSm(axis,
  104. compatibleRun,
  105. axisObject->directionPositive);
  106. }
  107. static void PlsrSetStopReason(PLSR_AXIS *axis,
  108. PLSR_STOP_REASON stopReason)
  109. {
  110. if (stopReason > axis->stopReason)
  111. {
  112. axis->stopReason = stopReason;
  113. }
  114. }
  115. /* 将 64 位逻辑位置发布为 HSD 的 32 位兼容值:
  116. * 超出 INT32 范围时回绕(与信捷 32 位寄存器一致)并置溢出诊断标志。 */
  117. static void PlsrPublishPosition(uint8_t axis, PLSR_AXIS *axisObject)
  118. {
  119. int32_t compatValue;
  120. if ((axisObject->logicalPosition > INT32_MAX)
  121. || (axisObject->logicalPosition < INT32_MIN))
  122. {
  123. axisObject->positionOverflow = 1U;
  124. }
  125. compatValue = (int32_t)(uint32_t)axisObject->logicalPosition;
  126. (void)PlcDevicePublishHsdDword(
  127. (uint16_t)((uint16_t)axis * PLSR_HSD_RUNTIME_AXIS_COUNT),
  128. compatValue);
  129. }
  130. static uint8_t PlsrTransitionIsAllowed(PLSR_STATE current,
  131. PLSR_STATE target)
  132. {
  133. if (current == target)
  134. {
  135. return 1U;
  136. }
  137. if (target == PLSR_STATE_ERROR)
  138. {
  139. return 1U;
  140. }
  141. switch (current)
  142. {
  143. case PLSR_STATE_UNINITIALIZED:
  144. return (target == PLSR_STATE_IDLE) ? 1U : 0U;
  145. case PLSR_STATE_IDLE:
  146. case PLSR_STATE_COMPLETED:
  147. case PLSR_STATE_STOPPED:
  148. return ((target == PLSR_STATE_ACCEL)
  149. || (target == PLSR_STATE_WAIT)
  150. || (target == PLSR_STATE_COMPLETED))
  151. ? 1U
  152. : 0U;
  153. case PLSR_STATE_ACCEL:
  154. case PLSR_STATE_RUN:
  155. return ((target == PLSR_STATE_ACCEL)
  156. || (target == PLSR_STATE_RUN)
  157. || (target == PLSR_STATE_DECEL)
  158. || (target == PLSR_STATE_WAIT)
  159. || (target == PLSR_STATE_COMPLETED)
  160. || (target == PLSR_STATE_STOPPED))
  161. ? 1U
  162. : 0U;
  163. case PLSR_STATE_DECEL:
  164. return ((target == PLSR_STATE_ACCEL)
  165. || (target == PLSR_STATE_RUN)
  166. || (target == PLSR_STATE_WAIT)
  167. || (target == PLSR_STATE_PAUSED)
  168. || (target == PLSR_STATE_COMPLETED)
  169. || (target == PLSR_STATE_STOPPED))
  170. ? 1U
  171. : 0U;
  172. case PLSR_STATE_WAIT:
  173. return ((target == PLSR_STATE_ACCEL)
  174. || (target == PLSR_STATE_RUN)
  175. || (target == PLSR_STATE_PAUSED)
  176. || (target == PLSR_STATE_COMPLETED)
  177. || (target == PLSR_STATE_STOPPED))
  178. ? 1U
  179. : 0U;
  180. case PLSR_STATE_PAUSED:
  181. return ((target == PLSR_STATE_ACCEL)
  182. || (target == PLSR_STATE_RUN)
  183. || (target == PLSR_STATE_STOPPED))
  184. ? 1U
  185. : 0U;
  186. case PLSR_STATE_ERROR:
  187. return (target == PLSR_STATE_IDLE) ? 1U : 0U;
  188. default:
  189. return 0U;
  190. }
  191. }
  192. PLSR_RESULT PlsrStateTransition(uint8_t axis,
  193. PLSR_STATE target,
  194. PLSR_TRANSITION_REASON reason)
  195. {
  196. PLSR_AXIS *axisObject;
  197. (void)reason;
  198. if (axis >= PLSR_AXIS_COUNT)
  199. {
  200. return PLSR_RESULT_INVALID_AXIS;
  201. }
  202. if ((uint32_t)target > (uint32_t)PLSR_STATE_ERROR)
  203. {
  204. return PLSR_RESULT_INVALID_ARGUMENT;
  205. }
  206. axisObject = &PlsrAxes[axis];
  207. if (PlsrTransitionIsAllowed(axisObject->state, target) == 0U)
  208. {
  209. axisObject->illegalTransitionCount++;
  210. axisObject->error = PLSR_ERROR_ILLEGAL_TRANSITION;
  211. axisObject->stopReason = PLSR_STOP_REASON_FAULT;
  212. axisObject->done = 0U;
  213. axisObject->state = PLSR_STATE_ERROR;
  214. axisObject->pendingTerminal = PLSR_STATE_UNINITIALIZED;
  215. axisObject->immediateStopPending = 0U;
  216. PlsrStopSegmentHardware(axis, axisObject);
  217. PlsrResourceRelease(&axisObject->lease);
  218. PlsrPublishAxis(axis);
  219. return PLSR_RESULT_INVALID_STATE;
  220. }
  221. axisObject->state = target;
  222. if (target == PLSR_STATE_COMPLETED)
  223. {
  224. axisObject->done = 1U;
  225. }
  226. if ((target == PLSR_STATE_COMPLETED) || (target == PLSR_STATE_STOPPED)
  227. || (target == PLSR_STATE_ERROR))
  228. {
  229. axisObject->pendingTerminal = PLSR_STATE_UNINITIALIZED;
  230. axisObject->immediateStopPending = 0U;
  231. PlsrPathTerminate(&axisObject->path);
  232. PlsrStopSegmentHardware(axis, axisObject);
  233. PlsrResourceRelease(&axisObject->lease);
  234. /* 运动已结束:记录 lastBusy=0,保证掉电后恢复时位置仍可信。 */
  235. (void)PlcDeviceSetHsdCheckpointMeta(axisObject->positionValid, 0U);
  236. (void)PlcDeviceCheckpointHsd();
  237. }
  238. PlsrPublishAxis(axis);
  239. return PLSR_RESULT_OK;
  240. }
  241. static uint8_t PlsrCommandPriority(PLSR_COMMAND_OPCODE opcode)
  242. {
  243. switch (opcode)
  244. {
  245. case PLSR_CMD_STOP_IMMEDIATE:
  246. return 0U;
  247. case PLSR_CMD_STOP_DECEL:
  248. return 1U;
  249. case PLSR_CMD_PAUSE:
  250. return 2U;
  251. case PLSR_CMD_RESUME:
  252. return 3U;
  253. default:
  254. return 4U;
  255. }
  256. }
  257. static PLSR_RESULT PlsrQueueCommand(const PLSR_COMMAND *command,
  258. const PLSR_START_REQUEST *start,
  259. const PLSR_CALL *call)
  260. {
  261. uint32_t interruptState;
  262. uint8_t freeSlot = PLSR_COMMAND_QUEUE_DEPTH;
  263. uint8_t index;
  264. interruptState = PlsrCoreEnterCritical();
  265. if ((PlsrAxes[command->axis].hasLastCommand != 0U)
  266. && (PlsrAxes[command->axis].lastCommandSequence == command->sequence))
  267. {
  268. PLSR_RESULT result = PlsrAxes[command->axis].lastCommandResult;
  269. PlsrCoreExitCritical(interruptState);
  270. return result;
  271. }
  272. for (index = 0U; index < PLSR_COMMAND_QUEUE_DEPTH; index++)
  273. {
  274. if (PlsrCommandQueue[index].occupied != 0U)
  275. {
  276. if ((PlsrCommandQueue[index].command.axis == command->axis)
  277. && (PlsrCommandQueue[index].command.sequence
  278. == command->sequence))
  279. {
  280. PlsrCoreExitCritical(interruptState);
  281. return PLSR_RESULT_QUEUED;
  282. }
  283. }
  284. else if (freeSlot == PLSR_COMMAND_QUEUE_DEPTH)
  285. {
  286. freeSlot = index;
  287. }
  288. }
  289. if (freeSlot == PLSR_COMMAND_QUEUE_DEPTH)
  290. {
  291. PlsrCoreExitCritical(interruptState);
  292. return PLSR_RESULT_QUEUE_FULL;
  293. }
  294. PlsrCommandQueue[freeSlot].command = *command;
  295. if (start != NULL)
  296. {
  297. PlsrCommandQueue[freeSlot].start = *start;
  298. PlsrCommandQueue[freeSlot].hasStart = 1U;
  299. }
  300. else
  301. {
  302. (void)memset(&PlsrCommandQueue[freeSlot].start,
  303. 0,
  304. sizeof(PlsrCommandQueue[freeSlot].start));
  305. PlsrCommandQueue[freeSlot].hasStart = 0U;
  306. }
  307. if (call != NULL)
  308. {
  309. PlsrCommandQueue[freeSlot].call = *call;
  310. PlsrCommandQueue[freeSlot].hasCall = 1U;
  311. }
  312. else
  313. {
  314. (void)memset(&PlsrCommandQueue[freeSlot].call,
  315. 0,
  316. sizeof(PlsrCommandQueue[freeSlot].call));
  317. PlsrCommandQueue[freeSlot].hasCall = 0U;
  318. }
  319. PlsrCommandQueue[freeSlot].ticket = PlsrNextTicket++;
  320. PlsrCommandQueue[freeSlot].occupied = 1U;
  321. PlsrCoreExitCritical(interruptState);
  322. return PLSR_RESULT_QUEUED;
  323. }
  324. static uint8_t PlsrPopHighestPriorityCommand(PLSR_COMMAND_SLOT *slot)
  325. {
  326. uint32_t interruptState;
  327. uint32_t selectedTicket = 0UL;
  328. uint8_t selectedPriority = 0xFFU;
  329. uint8_t selected = PLSR_COMMAND_QUEUE_DEPTH;
  330. uint8_t index;
  331. uint8_t priority;
  332. interruptState = PlsrCoreEnterCritical();
  333. for (index = 0U; index < PLSR_COMMAND_QUEUE_DEPTH; index++)
  334. {
  335. if (PlsrCommandQueue[index].occupied == 0U)
  336. {
  337. continue;
  338. }
  339. priority = PlsrCommandPriority(PlsrCommandQueue[index].command.opcode);
  340. if ((selected == PLSR_COMMAND_QUEUE_DEPTH)
  341. || (priority < selectedPriority)
  342. || ((priority == selectedPriority)
  343. && ((int32_t)(PlsrCommandQueue[index].ticket
  344. - selectedTicket)
  345. < 0)))
  346. {
  347. selected = index;
  348. selectedPriority = priority;
  349. selectedTicket = PlsrCommandQueue[index].ticket;
  350. }
  351. }
  352. if (selected == PLSR_COMMAND_QUEUE_DEPTH)
  353. {
  354. PlsrCoreExitCritical(interruptState);
  355. return 0U;
  356. }
  357. *slot = PlsrCommandQueue[selected];
  358. PlsrCommandQueue[selected].occupied = 0U;
  359. PlsrCoreExitCritical(interruptState);
  360. return 1U;
  361. }
  362. #ifdef PLSR_HOST_TEST
  363. PLSR_RESULT PlsrPostStart(const PLSR_START_REQUEST *request)
  364. {
  365. PLSR_COMMAND command;
  366. if (request == NULL)
  367. {
  368. return PLSR_RESULT_INVALID_ARGUMENT;
  369. }
  370. if (request->axis >= PLSR_AXIS_COUNT)
  371. {
  372. return PLSR_RESULT_INVALID_AXIS;
  373. }
  374. if (PlsrInitialized == 0U)
  375. {
  376. return PLSR_RESULT_INVALID_STATE;
  377. }
  378. command.sequence = request->sequence;
  379. command.axis = request->axis;
  380. command.opcode = PLSR_CMD_START;
  381. command.argument = 0;
  382. return PlsrQueueCommand(&command, request, NULL);
  383. }
  384. #endif /* PLSR_HOST_TEST */
  385. PLSR_RESULT PlsrPostCall(const PLSR_CALL *call)
  386. {
  387. PLSR_COMMAND command;
  388. if (call == NULL)
  389. {
  390. return PLSR_RESULT_INVALID_ARGUMENT;
  391. }
  392. if (call->dAxis >= PLSR_AXIS_COUNT)
  393. {
  394. return PLSR_RESULT_INVALID_AXIS;
  395. }
  396. if (PlsrInitialized == 0U)
  397. {
  398. return PLSR_RESULT_INVALID_STATE;
  399. }
  400. command.sequence = call->sequence;
  401. command.axis = call->dAxis;
  402. command.opcode = PLSR_CMD_START;
  403. command.argument = 0;
  404. return PlsrQueueCommand(&command, NULL, call);
  405. }
  406. PLSR_RESULT PlsrPostCommand(const PLSR_COMMAND *command)
  407. {
  408. if (command == NULL)
  409. {
  410. return PLSR_RESULT_INVALID_ARGUMENT;
  411. }
  412. if (command->axis >= PLSR_AXIS_COUNT)
  413. {
  414. return PLSR_RESULT_INVALID_AXIS;
  415. }
  416. if (((uint32_t)command->opcode > (uint32_t)PLSR_CMD_SELF_TEST)
  417. || (command->opcode == PLSR_CMD_START))
  418. {
  419. return PLSR_RESULT_INVALID_ARGUMENT;
  420. }
  421. if (PlsrInitialized == 0U)
  422. {
  423. return PLSR_RESULT_INVALID_STATE;
  424. }
  425. return PlsrQueueCommand(command, NULL, NULL);
  426. }
  427. PLSR_RESULT PlsrPostEvent(uint8_t axis, uint32_t eventMask)
  428. {
  429. uint32_t interruptState;
  430. if (axis >= PLSR_AXIS_COUNT)
  431. {
  432. return PLSR_RESULT_INVALID_AXIS;
  433. }
  434. if ((eventMask == 0UL) || ((eventMask & ~PLSR_EVENT_ALL_MASK) != 0UL))
  435. {
  436. return PLSR_RESULT_INVALID_ARGUMENT;
  437. }
  438. interruptState = PlsrCoreEnterCritical();
  439. PlsrAxes[axis].pendingEvents |= eventMask;
  440. PlsrCoreExitCritical(interruptState);
  441. return PLSR_RESULT_OK;
  442. }
  443. static uint32_t PlsrTakeEvents(uint8_t axis, uint32_t mask)
  444. {
  445. uint32_t interruptState;
  446. uint32_t events;
  447. interruptState = PlsrCoreEnterCritical();
  448. events = PlsrAxes[axis].pendingEvents & mask;
  449. PlsrAxes[axis].pendingEvents &= ~events;
  450. PlsrCoreExitCritical(interruptState);
  451. return events;
  452. }
  453. static uint8_t PlsrAnyAxisBusy(void)
  454. {
  455. uint8_t axis;
  456. for (axis = 0U; axis < PLSR_AXIS_COUNT; axis++)
  457. {
  458. if (PlsrStateIsBusy(PlsrAxes[axis].state) != 0U)
  459. {
  460. return 1U;
  461. }
  462. }
  463. return 0U;
  464. }
  465. static PLSR_RESULT PlsrStartAxis(PLSR_AXIS *axisObject,
  466. const PLSR_START_REQUEST *start)
  467. {
  468. PLSR_RESOURCE_REQUEST resourceRequest;
  469. PLSR_RESULT result;
  470. if ((axisObject->state != PLSR_STATE_IDLE)
  471. && (axisObject->state != PLSR_STATE_COMPLETED)
  472. && (axisObject->state != PLSR_STATE_STOPPED))
  473. {
  474. return PLSR_RESULT_INVALID_STATE;
  475. }
  476. resourceRequest.ownerAxis = start->axis;
  477. resourceRequest.outputMode = start->outputMode;
  478. resourceRequest.dAxis = start->axis;
  479. resourceRequest.directionPoint = start->directionPoint;
  480. result = PlsrResourceReserve(&resourceRequest, &axisObject->lease);
  481. if (result != PLSR_RESULT_OK)
  482. {
  483. axisObject->error = (result == PLSR_RESULT_RESOURCE_CONFLICT)
  484. ? PLSR_ERROR_RESOURCE_CONFLICT
  485. : PLSR_ERROR_INVALID_RESOURCE;
  486. return result;
  487. }
  488. axisObject->outputMode = start->outputMode;
  489. axisObject->directionPositive = (start->directionPositive != 0U) ? 1U : 0U;
  490. axisObject->error = PLSR_ERROR_NONE;
  491. axisObject->stopReason = PLSR_STOP_REASON_NONE;
  492. axisObject->pendingTerminal = PLSR_STATE_UNINITIALIZED;
  493. axisObject->immediateStopPending = 0U;
  494. axisObject->done = 0U;
  495. axisObject->jobValid = 0U;
  496. result = PlsrStateTransition(start->axis,
  497. PLSR_STATE_ACCEL,
  498. PLSR_TRANSITION_START);
  499. if (result != PLSR_RESULT_OK)
  500. {
  501. PlsrResourceRelease(&axisObject->lease);
  502. }
  503. else
  504. {
  505. /* 运动开始:掉电恢复时据此判定"断电时在运动中"。 */
  506. (void)PlcDeviceSetHsdCheckpointMeta(axisObject->positionValid, 1U);
  507. (void)PlcDeviceCheckpointHsd();
  508. }
  509. return result;
  510. }
  511. static PLSR_RESULT PlsrStartCall(PLSR_AXIS *axisObject,
  512. const PLSR_CALL *call)
  513. {
  514. PLSR_RESOURCE_REQUEST resourceRequest;
  515. PLSR_PARSE_CONTEXT parseContext;
  516. PLSR_RESULT result;
  517. if ((axisObject->state != PLSR_STATE_IDLE)
  518. && (axisObject->state != PLSR_STATE_COMPLETED)
  519. && (axisObject->state != PLSR_STATE_STOPPED))
  520. {
  521. return PLSR_RESULT_INVALID_STATE;
  522. }
  523. parseContext.logicalPosition = axisObject->logicalPosition;
  524. parseContext.positionValid = axisObject->positionValid;
  525. result = PlsrBuildJobSnapshot(call,
  526. &parseContext,
  527. &PlsrJobScratch,
  528. &axisObject->parseDetail);
  529. if (result != PLSR_RESULT_OK)
  530. {
  531. return result;
  532. }
  533. resourceRequest.ownerAxis = call->dAxis;
  534. resourceRequest.outputMode =
  535. (PLSR_OUTPUT_MODE)PlsrJobScratch.outputMode;
  536. resourceRequest.dAxis = call->dAxis;
  537. resourceRequest.directionPoint = PlsrJobScratch.directionPoint;
  538. result = PlsrResourceReserve(&resourceRequest, &axisObject->lease);
  539. if (result != PLSR_RESULT_OK)
  540. {
  541. axisObject->error = (result == PLSR_RESULT_RESOURCE_CONFLICT)
  542. ? PLSR_ERROR_RESOURCE_CONFLICT
  543. : PLSR_ERROR_INVALID_RESOURCE;
  544. axisObject->parseDetail.result = result;
  545. axisObject->parseDetail.block = PLSR_PARSE_BLOCK_OUTPUT;
  546. return result;
  547. }
  548. axisObject->job = PlsrJobScratch;
  549. axisObject->jobValid = 1U;
  550. axisObject->outputMode = (PLSR_OUTPUT_MODE)axisObject->job.outputMode;
  551. axisObject->directionPositive = axisObject->job.initialDirectionPositive;
  552. axisObject->error = PLSR_ERROR_NONE;
  553. axisObject->stopReason = PLSR_STOP_REASON_NONE;
  554. axisObject->pendingTerminal = PLSR_STATE_UNINITIALIZED;
  555. axisObject->immediateStopPending = 0U;
  556. axisObject->done = 0U;
  557. PlsrPathBegin(&axisObject->path,
  558. &axisObject->job,
  559. axisObject->logicalPosition);
  560. if (axisObject->path.jobEnded != 0U)
  561. {
  562. /* 起点就是零脉冲且跳转链已结束(任务无实际脉冲)。 */
  563. axisObject->stopReason = PLSR_STOP_REASON_NORMAL_COMPLETE;
  564. (void)PlsrStateTransition(call->dAxis,
  565. PLSR_STATE_COMPLETED,
  566. PLSR_TRANSITION_JOB_COMPLETE);
  567. axisObject->jobValid = 0U;
  568. return PLSR_RESULT_OK;
  569. }
  570. result = PlsrStateTransition(call->dAxis,
  571. PLSR_STATE_ACCEL,
  572. PLSR_TRANSITION_START);
  573. if (result != PLSR_RESULT_OK)
  574. {
  575. axisObject->jobValid = 0U;
  576. PlsrResourceRelease(&axisObject->lease);
  577. }
  578. else
  579. {
  580. /* 启动当前段硬件输出与速度曲线。 */
  581. /* 零脉冲跳转链耗尽本轮预算时没有实际运动段,等待下一次
  582. * PlsrPathTick 找到非零段后再启动硬件。 */
  583. if (axisObject->path.jumpChainPending == 0U)
  584. {
  585. result = PlsrStartSegmentHardware(call->dAxis, axisObject);
  586. }
  587. if (result != PLSR_RESULT_OK)
  588. {
  589. axisObject->error = PLSR_ERROR_TIMER_FAULT;
  590. PlsrSetStopReason(axisObject, PLSR_STOP_REASON_FAULT);
  591. axisObject->done = 0U;
  592. (void)PlsrStateTransition(call->dAxis,
  593. PLSR_STATE_ERROR,
  594. PLSR_TRANSITION_FAULT);
  595. return result;
  596. }
  597. /* 运动开始:掉电恢复时据此判定"断电时在运动中"。 */
  598. (void)PlcDeviceSetHsdCheckpointMeta(axisObject->positionValid, 1U);
  599. (void)PlcDeviceCheckpointHsd();
  600. }
  601. return result;
  602. }
  603. static PLSR_RESULT PlsrStopImmediate(uint8_t axis)
  604. {
  605. PLSR_AXIS *axisObject = &PlsrAxes[axis];
  606. if ((axisObject->state == PLSR_STATE_IDLE)
  607. || (axisObject->state == PLSR_STATE_COMPLETED)
  608. || (axisObject->state == PLSR_STATE_STOPPED))
  609. {
  610. return PLSR_RESULT_OK;
  611. }
  612. if (axisObject->state == PLSR_STATE_ERROR)
  613. {
  614. return PLSR_RESULT_INVALID_STATE;
  615. }
  616. if (axisObject->immediateStopPending != 0U)
  617. {
  618. return PLSR_RESULT_OK;
  619. }
  620. PlsrSetStopReason(axisObject, PLSR_STOP_REASON_STOP_IMMEDIATE);
  621. axisObject->pendingTerminal = PLSR_STATE_STOPPED;
  622. PlsrPathTerminate(&axisObject->path);
  623. PlsrStopSegmentHardware(axis, axisObject);
  624. if ((axisObject->state == PLSR_STATE_WAIT)
  625. || (axisObject->state == PLSR_STATE_PAUSED))
  626. {
  627. return PlsrStateTransition(axis,
  628. PLSR_STATE_STOPPED,
  629. PLSR_TRANSITION_STOP);
  630. }
  631. axisObject->immediateStopPending = 1U;
  632. return PLSR_RESULT_OK;
  633. }
  634. static PLSR_RESULT PlsrStopDecel(uint8_t axis)
  635. {
  636. PLSR_AXIS *axisObject = &PlsrAxes[axis];
  637. if ((axisObject->state == PLSR_STATE_IDLE)
  638. || (axisObject->state == PLSR_STATE_COMPLETED)
  639. || (axisObject->state == PLSR_STATE_STOPPED))
  640. {
  641. return PLSR_RESULT_OK;
  642. }
  643. if (axisObject->state == PLSR_STATE_ERROR)
  644. {
  645. return PLSR_RESULT_INVALID_STATE;
  646. }
  647. if (axisObject->stopReason >= PLSR_STOP_REASON_STOP_IMMEDIATE)
  648. {
  649. return PLSR_RESULT_OK;
  650. }
  651. PlsrSetStopReason(axisObject, PLSR_STOP_REASON_STOP_DECEL);
  652. axisObject->pendingTerminal = PLSR_STATE_STOPPED;
  653. PlsrPathTerminate(&axisObject->path);
  654. PlsrStopSegmentHardware(axis, axisObject);
  655. if ((axisObject->state == PLSR_STATE_WAIT)
  656. || (axisObject->state == PLSR_STATE_PAUSED))
  657. {
  658. return PlsrStateTransition(axis,
  659. PLSR_STATE_STOPPED,
  660. PLSR_TRANSITION_STOP);
  661. }
  662. if (axisObject->state == PLSR_STATE_DECEL)
  663. {
  664. return PLSR_RESULT_OK;
  665. }
  666. return PlsrStateTransition(axis,
  667. PLSR_STATE_DECEL,
  668. PLSR_TRANSITION_DECEL_REQUEST);
  669. }
  670. static PLSR_RESULT PlsrPause(uint8_t axis)
  671. {
  672. PLSR_AXIS *axisObject = &PlsrAxes[axis];
  673. if (axisObject->state == PLSR_STATE_PAUSED)
  674. {
  675. return PLSR_RESULT_OK;
  676. }
  677. if (axisObject->stopReason >= PLSR_STOP_REASON_STOP_DECEL)
  678. {
  679. return PLSR_RESULT_BUSY;
  680. }
  681. if (axisObject->state == PLSR_STATE_WAIT)
  682. {
  683. PlsrSetStopReason(axisObject, PLSR_STOP_REASON_PAUSE);
  684. PlsrPathTerminate(&axisObject->path);
  685. PlsrStopSegmentHardware(axis, axisObject);
  686. return PlsrStateTransition(axis,
  687. PLSR_STATE_PAUSED,
  688. PLSR_TRANSITION_DECEL_COMPLETE);
  689. }
  690. if ((axisObject->state != PLSR_STATE_ACCEL)
  691. && (axisObject->state != PLSR_STATE_RUN)
  692. && (axisObject->state != PLSR_STATE_DECEL))
  693. {
  694. return PLSR_RESULT_INVALID_STATE;
  695. }
  696. PlsrSetStopReason(axisObject, PLSR_STOP_REASON_PAUSE);
  697. axisObject->pendingTerminal = PLSR_STATE_PAUSED;
  698. PlsrPathTerminate(&axisObject->path);
  699. if (axisObject->state == PLSR_STATE_DECEL)
  700. {
  701. return PLSR_RESULT_OK;
  702. }
  703. return PlsrStateTransition(axis,
  704. PLSR_STATE_DECEL,
  705. PLSR_TRANSITION_DECEL_REQUEST);
  706. }
  707. static PLSR_RESULT PlsrExecuteCommand(const PLSR_COMMAND_SLOT *slot)
  708. {
  709. PLSR_AXIS *axisObject = &PlsrAxes[slot->command.axis];
  710. PLC_DEVICE_RESULT deviceResult;
  711. PLSR_RESULT result;
  712. switch (slot->command.opcode)
  713. {
  714. case PLSR_CMD_START:
  715. if (slot->hasCall != 0U)
  716. {
  717. result = PlsrStartCall(axisObject, &slot->call);
  718. }
  719. else
  720. {
  721. result = (slot->hasStart != 0U)
  722. ? PlsrStartAxis(axisObject, &slot->start)
  723. : PLSR_RESULT_INVALID_ARGUMENT;
  724. }
  725. break;
  726. case PLSR_CMD_STOP_DECEL:
  727. result = PlsrStopDecel(slot->command.axis);
  728. break;
  729. case PLSR_CMD_STOP_IMMEDIATE:
  730. result = PlsrStopImmediate(slot->command.axis);
  731. break;
  732. case PLSR_CMD_PAUSE:
  733. result = PlsrPause(slot->command.axis);
  734. break;
  735. case PLSR_CMD_RESUME:
  736. if (axisObject->state != PLSR_STATE_PAUSED)
  737. {
  738. result = PLSR_RESULT_INVALID_STATE;
  739. }
  740. else
  741. {
  742. axisObject->stopReason = PLSR_STOP_REASON_NONE;
  743. axisObject->pendingTerminal = PLSR_STATE_UNINITIALIZED;
  744. result = PlsrStateTransition(slot->command.axis,
  745. PLSR_STATE_ACCEL,
  746. PLSR_TRANSITION_WAIT_COMPLETE);
  747. }
  748. break;
  749. case PLSR_CMD_SET_POSITION:
  750. if (PlsrStateIsBusy(axisObject->state) != 0U)
  751. {
  752. result = PLSR_RESULT_BUSY;
  753. }
  754. else
  755. {
  756. axisObject->logicalPosition = slot->command.argument;
  757. axisObject->positionValid = 1U;
  758. axisObject->positionOverflow = 0U;
  759. PlsrPublishPosition(slot->command.axis, axisObject);
  760. (void)PlcDeviceSetHsdCheckpointMeta(1U, 0U);
  761. (void)PlcDeviceCheckpointHsd();
  762. result = PLSR_RESULT_OK;
  763. }
  764. break;
  765. case PLSR_CMD_CLEAR_POSITION:
  766. if (PlsrStateIsBusy(axisObject->state) != 0U)
  767. {
  768. result = PLSR_RESULT_BUSY;
  769. }
  770. else
  771. {
  772. axisObject->logicalPosition = 0;
  773. axisObject->positionValid = 1U;
  774. axisObject->positionOverflow = 0U;
  775. PlsrPublishPosition(slot->command.axis, axisObject);
  776. (void)PlcDeviceSetHsdCheckpointMeta(1U, 0U);
  777. (void)PlcDeviceCheckpointHsd();
  778. result = PLSR_RESULT_OK;
  779. }
  780. break;
  781. case PLSR_CMD_CLEAR_TOTAL:
  782. if (PlsrStateIsBusy(axisObject->state) != 0U)
  783. {
  784. result = PLSR_RESULT_BUSY;
  785. }
  786. else
  787. {
  788. axisObject->totalPulses = 0;
  789. result = PLSR_RESULT_OK;
  790. }
  791. break;
  792. case PLSR_CMD_SAVE_CONFIG:
  793. if (PlsrAnyAxisBusy() != 0U)
  794. {
  795. result = PLSR_RESULT_BUSY;
  796. }
  797. else
  798. {
  799. deviceResult = PlcDeviceSaveSfd();
  800. result = (deviceResult == PLC_DEVICE_OK)
  801. ? PLSR_RESULT_OK
  802. : PLSR_RESULT_PERSISTENCE_ERROR;
  803. }
  804. break;
  805. case PLSR_CMD_LOAD_CONFIG:
  806. if (PlsrAnyAxisBusy() != 0U)
  807. {
  808. result = PLSR_RESULT_BUSY;
  809. }
  810. else
  811. {
  812. deviceResult = PlcDeviceLoadSfd();
  813. result = (deviceResult == PLC_DEVICE_OK)
  814. ? PLSR_RESULT_OK
  815. : PLSR_RESULT_PERSISTENCE_ERROR;
  816. }
  817. break;
  818. case PLSR_CMD_RESET_ERROR:
  819. if (axisObject->state != PLSR_STATE_ERROR)
  820. {
  821. result = PLSR_RESULT_INVALID_STATE;
  822. }
  823. else
  824. {
  825. axisObject->error = PLSR_ERROR_NONE;
  826. axisObject->stopReason = PLSR_STOP_REASON_NONE;
  827. axisObject->done = 0U;
  828. result = PlsrStateTransition(slot->command.axis,
  829. PLSR_STATE_IDLE,
  830. PLSR_TRANSITION_RESET_ERROR);
  831. }
  832. break;
  833. case PLSR_CMD_SELF_TEST:
  834. result = ((PlsrAnyAxisBusy() == 0U)
  835. && (PlsrResourceCheckInvariant() != 0U))
  836. ? PLSR_RESULT_OK
  837. : PLSR_RESULT_BUSY;
  838. break;
  839. default:
  840. result = PLSR_RESULT_INVALID_ARGUMENT;
  841. break;
  842. }
  843. axisObject->lastCommandSequence = slot->command.sequence;
  844. axisObject->lastCommandResult = result;
  845. axisObject->hasLastCommand = 1U;
  846. PlsrPublishAxis(slot->command.axis);
  847. return result;
  848. }
  849. static void PlsrProcessCriticalEvents(uint8_t axis, uint32_t events)
  850. {
  851. PLSR_AXIS *axisObject = &PlsrAxes[axis];
  852. if ((events & PLSR_EVENT_SOFTWARE_EMERGENCY) != 0UL)
  853. {
  854. if (PlsrStateIsBusy(axisObject->state) != 0U)
  855. {
  856. PlsrSetStopReason(axisObject,
  857. PLSR_STOP_REASON_SOFTWARE_EMERGENCY);
  858. axisObject->done = 0U;
  859. PlsrPathTerminate(&axisObject->path);
  860. PlsrStopSegmentHardware(axis, axisObject);
  861. (void)PlsrStateTransition(axis,
  862. PLSR_STATE_STOPPED,
  863. PLSR_TRANSITION_STOP);
  864. }
  865. return;
  866. }
  867. if ((events & PLSR_EVENT_LIMIT_POSITIVE) != 0UL)
  868. {
  869. if ((axisObject->directionPositive != 0U)
  870. && (PlsrStateIsBusy(axisObject->state) != 0U))
  871. {
  872. axisObject->error = PLSR_ERROR_LIMIT_POSITIVE;
  873. PlsrSetStopReason(axisObject,
  874. PLSR_STOP_REASON_LIMIT_POSITIVE);
  875. axisObject->pendingTerminal = PLSR_STATE_STOPPED;
  876. PlsrPathTerminate(&axisObject->path);
  877. PlsrStopSegmentHardware(axis, axisObject);
  878. if ((axisObject->state == PLSR_STATE_WAIT)
  879. || (axisObject->state == PLSR_STATE_PAUSED))
  880. {
  881. (void)PlsrStateTransition(axis,
  882. PLSR_STATE_STOPPED,
  883. PLSR_TRANSITION_STOP);
  884. }
  885. else if (axisObject->state != PLSR_STATE_DECEL)
  886. {
  887. (void)PlsrStateTransition(axis,
  888. PLSR_STATE_DECEL,
  889. PLSR_TRANSITION_DECEL_REQUEST);
  890. }
  891. }
  892. return;
  893. }
  894. if ((events & PLSR_EVENT_LIMIT_NEGATIVE) != 0UL)
  895. {
  896. if ((axisObject->directionPositive == 0U)
  897. && (PlsrStateIsBusy(axisObject->state) != 0U))
  898. {
  899. axisObject->error = PLSR_ERROR_LIMIT_NEGATIVE;
  900. PlsrSetStopReason(axisObject,
  901. PLSR_STOP_REASON_LIMIT_NEGATIVE);
  902. axisObject->pendingTerminal = PLSR_STATE_STOPPED;
  903. PlsrPathTerminate(&axisObject->path);
  904. PlsrStopSegmentHardware(axis, axisObject);
  905. if ((axisObject->state == PLSR_STATE_WAIT)
  906. || (axisObject->state == PLSR_STATE_PAUSED))
  907. {
  908. (void)PlsrStateTransition(axis,
  909. PLSR_STATE_STOPPED,
  910. PLSR_TRANSITION_STOP);
  911. }
  912. else if (axisObject->state != PLSR_STATE_DECEL)
  913. {
  914. (void)PlsrStateTransition(axis,
  915. PLSR_STATE_DECEL,
  916. PLSR_TRANSITION_DECEL_REQUEST);
  917. }
  918. }
  919. return;
  920. }
  921. if ((events & (PLSR_EVENT_TIMER_FAULT | PLSR_EVENT_COUNTER_FAULT)) != 0UL)
  922. {
  923. axisObject->error = ((events & PLSR_EVENT_TIMER_FAULT) != 0UL)
  924. ? PLSR_ERROR_TIMER_FAULT
  925. : PLSR_ERROR_COUNTER_FAULT;
  926. PlsrSetStopReason(axisObject, PLSR_STOP_REASON_FAULT);
  927. axisObject->done = 0U;
  928. PlsrPathTerminate(&axisObject->path);
  929. PlsrStopSegmentHardware(axis, axisObject);
  930. (void)PlsrStateTransition(axis,
  931. PLSR_STATE_ERROR,
  932. PLSR_TRANSITION_FAULT);
  933. }
  934. }
  935. /* 启动当前段的硬件输出与速度曲线(P3a:单轴 PULSE/DIR)。
  936. * 由段进入 ACCEL 时调用(任务启动 + 段间推进)。 */
  937. static PLSR_RESULT PlsrStartSegmentHardware(uint8_t axis,
  938. PLSR_AXIS *axisObject)
  939. {
  940. const PLSR_JOB_SNAPSHOT *job = &axisObject->job;
  941. const PLSR_SEGMENT_SNAPSHOT *segment =
  942. &job->segments[axisObject->path.currentSegment - 1U];
  943. PLSR_PROFILE_REQUEST profileRequest;
  944. PLSR_HW_START_PARAMS params;
  945. PLSR_RESULT result;
  946. int64_t pulses;
  947. uint8_t positive;
  948. if (job->positioningMode == 0U)
  949. {
  950. pulses = (segment->pulseOrTarget < 0)
  951. ? -(int64_t)segment->pulseOrTarget
  952. : (int64_t)segment->pulseOrTarget;
  953. positive = (segment->pulseOrTarget >= 0) ? 1U : 0U;
  954. }
  955. else
  956. {
  957. /* 绝对模式:P4 位置闭环后完善;P3a 按当前位置计算。 */
  958. int64_t delta = (int64_t)segment->pulseOrTarget
  959. - axisObject->logicalPosition;
  960. pulses = (delta < 0) ? -delta : delta;
  961. positive = (delta >= 0) ? 1U : 0U;
  962. }
  963. (void)memset(&profileRequest, 0, sizeof(profileRequest));
  964. profileRequest.targetFrequencyHz = segment->targetFrequency;
  965. profileRequest.startFrequencyHz = job->s2.startSpeed;
  966. profileRequest.stopFrequencyHz = job->s2.stopSpeed;
  967. profileRequest.maxFrequencyHz = job->s2.maximumSpeed;
  968. profileRequest.accelSlopeHzPerMs =
  969. (job->s2.accelerationMs != 0U)
  970. ? job->s2.defaultSpeed / job->s2.accelerationMs
  971. : 0UL;
  972. profileRequest.decelSlopeHzPerMs =
  973. (job->s2.decelerationMs != 0U)
  974. ? job->s2.defaultSpeed / job->s2.decelerationMs
  975. : 0UL;
  976. profileRequest.curveMode = job->s2.curveMode;
  977. result = PlsrProfileStart(&axisObject->profile,
  978. &profileRequest,
  979. pulses,
  980. 1000U);
  981. if (result != PLSR_RESULT_OK)
  982. {
  983. return result;
  984. }
  985. params.frequencyHz = job->s2.startSpeed;
  986. params.targetPulses = pulses;
  987. params.outputMode = (PLSR_OUTPUT_MODE)job->outputMode;
  988. params.directionPoint = job->directionPoint;
  989. params.directionPositive = positive;
  990. params.directionDelayMs = job->s2.directionDelayMs;
  991. result = PlsrHwStartPulse(axis, &params);
  992. if (result != PLSR_RESULT_OK)
  993. {
  994. axisObject->profileActive = 0U;
  995. axisObject->profileWasAccel = 0U;
  996. return result;
  997. }
  998. axisObject->profileActive = 1U;
  999. axisObject->profileWasAccel =
  1000. (axisObject->profile.phase == PLSR_PROFILE_PHASE_ACCEL) ? 1U : 0U;
  1001. return PLSR_RESULT_OK;
  1002. }
  1003. /* 停止当前段的硬件输出与速度曲线。 */
  1004. static void PlsrStopSegmentHardware(uint8_t axis, PLSR_AXIS *axisObject)
  1005. {
  1006. axisObject->profileActive = 0U;
  1007. axisObject->profileWasAccel = 0U;
  1008. (void)PlsrHwStopPulse(axis);
  1009. }
  1010. /* 应用路径执行器的动作:段间推进、进入等待、结束、让出、错误。 */
  1011. static void PlsrApplyPathAction(uint8_t axis, PLSR_PATH_ACTION action)
  1012. {
  1013. PLSR_AXIS *axisObject = &PlsrAxes[axis];
  1014. switch (action)
  1015. {
  1016. case PLSR_PATH_ACTION_NEXT_SEGMENT:
  1017. /* SEGMENT_COMPLETE 表示上一段输出边界已经结束。统一收口旧段
  1018. * profile/HAL 后再启动新段;真实 IRQ 与测试注入事件均一致。 */
  1019. PlsrStopSegmentHardware(axis, axisObject);
  1020. if (axisObject->state == PLSR_STATE_WAIT)
  1021. {
  1022. (void)PlsrStateTransition(axis,
  1023. PLSR_STATE_ACCEL,
  1024. PLSR_TRANSITION_WAIT_COMPLETE);
  1025. }
  1026. else if ((axisObject->state == PLSR_STATE_ACCEL)
  1027. || (axisObject->state == PLSR_STATE_RUN)
  1028. || (axisObject->state == PLSR_STATE_DECEL))
  1029. {
  1030. (void)PlsrStateTransition(axis,
  1031. PLSR_STATE_ACCEL,
  1032. PLSR_TRANSITION_START);
  1033. }
  1034. /* 进入新段:重新启动硬件输出与速度曲线。 */
  1035. if (axisObject->state == PLSR_STATE_ACCEL)
  1036. {
  1037. if (PlsrStartSegmentHardware(axis, axisObject)
  1038. != PLSR_RESULT_OK)
  1039. {
  1040. axisObject->error = PLSR_ERROR_TIMER_FAULT;
  1041. PlsrSetStopReason(axisObject, PLSR_STOP_REASON_FAULT);
  1042. axisObject->done = 0U;
  1043. (void)PlsrStateTransition(axis,
  1044. PLSR_STATE_ERROR,
  1045. PLSR_TRANSITION_FAULT);
  1046. }
  1047. }
  1048. break;
  1049. case PLSR_PATH_ACTION_ENTER_WAIT:
  1050. if ((axisObject->state == PLSR_STATE_ACCEL)
  1051. || (axisObject->state == PLSR_STATE_RUN))
  1052. {
  1053. (void)PlsrStateTransition(axis,
  1054. PLSR_STATE_WAIT,
  1055. PLSR_TRANSITION_WAIT_BEGIN);
  1056. }
  1057. break;
  1058. case PLSR_PATH_ACTION_JOB_COMPLETE:
  1059. if (PlsrStateIsBusy(axisObject->state) != 0U)
  1060. {
  1061. axisObject->stopReason = PLSR_STOP_REASON_NORMAL_COMPLETE;
  1062. (void)PlsrStateTransition(axis,
  1063. PLSR_STATE_COMPLETED,
  1064. PLSR_TRANSITION_JOB_COMPLETE);
  1065. }
  1066. break;
  1067. case PLSR_PATH_ACTION_YIELD:
  1068. /* 预算耗尽:本轮不再推进,下个 tick 由 PlsrPathTick 恢复。 */
  1069. break;
  1070. case PLSR_PATH_ACTION_ERROR:
  1071. axisObject->error = PLSR_ERROR_INTERNAL;
  1072. PlsrSetStopReason(axisObject, PLSR_STOP_REASON_FAULT);
  1073. axisObject->done = 0U;
  1074. (void)PlsrStateTransition(axis,
  1075. PLSR_STATE_ERROR,
  1076. PLSR_TRANSITION_FAULT);
  1077. break;
  1078. default:
  1079. break;
  1080. }
  1081. }
  1082. static void PlsrProcessNormalEvents(uint8_t axis, uint32_t events)
  1083. {
  1084. PLSR_AXIS *axisObject = &PlsrAxes[axis];
  1085. if (((events & PLSR_EVENT_STOP_IMMEDIATE_DONE) != 0UL)
  1086. && (axisObject->immediateStopPending != 0U))
  1087. {
  1088. (void)PlsrStateTransition(axis,
  1089. PLSR_STATE_STOPPED,
  1090. PLSR_TRANSITION_STOP);
  1091. return;
  1092. }
  1093. if (((events & PLSR_EVENT_ACCEL_COMPLETE) != 0UL)
  1094. && (axisObject->state == PLSR_STATE_ACCEL)
  1095. && (axisObject->immediateStopPending == 0U))
  1096. {
  1097. (void)PlsrStateTransition(axis,
  1098. PLSR_STATE_RUN,
  1099. PLSR_TRANSITION_ACCEL_COMPLETE);
  1100. }
  1101. if (((events & PLSR_EVENT_DECEL_COMPLETE) != 0UL)
  1102. && (axisObject->state == PLSR_STATE_DECEL))
  1103. {
  1104. if (axisObject->pendingTerminal == PLSR_STATE_PAUSED)
  1105. {
  1106. (void)PlsrStateTransition(axis,
  1107. PLSR_STATE_PAUSED,
  1108. PLSR_TRANSITION_DECEL_COMPLETE);
  1109. }
  1110. else if (axisObject->pendingTerminal == PLSR_STATE_STOPPED)
  1111. {
  1112. (void)PlsrStateTransition(axis,
  1113. PLSR_STATE_STOPPED,
  1114. PLSR_TRANSITION_DECEL_COMPLETE);
  1115. }
  1116. else
  1117. {
  1118. (void)PlsrStateTransition(axis,
  1119. PLSR_STATE_RUN,
  1120. PLSR_TRANSITION_DECEL_COMPLETE);
  1121. }
  1122. }
  1123. if (((events & PLSR_EVENT_WAIT_BEGIN) != 0UL)
  1124. && ((axisObject->state == PLSR_STATE_ACCEL)
  1125. || (axisObject->state == PLSR_STATE_RUN)))
  1126. {
  1127. (void)PlsrStateTransition(axis,
  1128. PLSR_STATE_WAIT,
  1129. PLSR_TRANSITION_WAIT_BEGIN);
  1130. }
  1131. if (((events & PLSR_EVENT_WAIT_COMPLETE) != 0UL)
  1132. && (axisObject->state == PLSR_STATE_WAIT))
  1133. {
  1134. (void)PlsrStateTransition(axis,
  1135. PLSR_STATE_ACCEL,
  1136. PLSR_TRANSITION_WAIT_COMPLETE);
  1137. }
  1138. if (((events & PLSR_EVENT_SEGMENT_COMPLETE) != 0UL)
  1139. && ((axisObject->state == PLSR_STATE_ACCEL)
  1140. || (axisObject->state == PLSR_STATE_RUN)
  1141. || (axisObject->state == PLSR_STATE_DECEL))
  1142. && (axisObject->pendingTerminal == PLSR_STATE_UNINITIALIZED)
  1143. && (axisObject->immediateStopPending == 0U))
  1144. {
  1145. PLSR_PATH_ACTION action = PlsrPathOnSegmentDone(
  1146. &axisObject->path,
  1147. &axisObject->job,
  1148. axisObject->logicalPosition);
  1149. PlsrApplyPathAction(axis, action);
  1150. }
  1151. if (((events & PLSR_EVENT_JOB_COMPLETE) != 0UL)
  1152. && (PlsrStateIsBusy(axisObject->state) != 0U)
  1153. && (axisObject->pendingTerminal == PLSR_STATE_UNINITIALIZED)
  1154. && (axisObject->immediateStopPending == 0U))
  1155. {
  1156. axisObject->stopReason = PLSR_STOP_REASON_NORMAL_COMPLETE;
  1157. (void)PlsrStateTransition(axis,
  1158. PLSR_STATE_COMPLETED,
  1159. PLSR_TRANSITION_JOB_COMPLETE);
  1160. }
  1161. }
  1162. PLSR_RESULT PlsrInit(void)
  1163. {
  1164. int32_t restoredPosition;
  1165. uint8_t restoredPositionValid;
  1166. uint8_t restoredLastBusy;
  1167. uint8_t axis;
  1168. (void)memset(PlsrAxes, 0, sizeof(PlsrAxes));
  1169. (void)memset(PlsrCommandQueue, 0, sizeof(PlsrCommandQueue));
  1170. PlsrNextTicket = 0UL;
  1171. PlsrResourceInit();
  1172. (void)PlsrHwInit();
  1173. PlsrInitialized = 1U;
  1174. restoredPositionValid = PlcDeviceGetRestoredHsdPositionValid();
  1175. restoredLastBusy = PlcDeviceGetRestoredHsdLastBusy();
  1176. for (axis = 0U; axis < PLSR_AXIS_COUNT; axis++)
  1177. {
  1178. PlsrAxes[axis].state = PLSR_STATE_UNINITIALIZED;
  1179. PlsrAxes[axis].pendingTerminal = PLSR_STATE_UNINITIALIZED;
  1180. PlsrAxes[axis].lease.directionPoint = PLSR_DIRECTION_POINT_NONE;
  1181. if (PlcDeviceReadHsdDword(
  1182. (uint16_t)(axis * PLSR_HSD_RUNTIME_AXIS_COUNT),
  1183. &restoredPosition) == PLC_DEVICE_OK)
  1184. {
  1185. PlsrAxes[axis].logicalPosition = restoredPosition;
  1186. }
  1187. /* 只有上次正常停机且保存了位置有效标志,才允许绝对定位;
  1188. * 运动中掉电(lastBusy=1)时位置不可信。 */
  1189. if ((restoredPositionValid != 0U) && (restoredLastBusy == 0U))
  1190. {
  1191. PlsrAxes[axis].positionValid = 1U;
  1192. }
  1193. if (PlsrStateTransition(axis,
  1194. PLSR_STATE_IDLE,
  1195. PLSR_TRANSITION_INITIALIZED)
  1196. != PLSR_RESULT_OK)
  1197. {
  1198. return PLSR_RESULT_INTERNAL_ERROR;
  1199. }
  1200. }
  1201. return PLSR_RESULT_OK;
  1202. }
  1203. void PlsrProcess(void)
  1204. {
  1205. PLSR_COMMAND_SLOT slot;
  1206. uint32_t events;
  1207. uint8_t processedCommands = 0U;
  1208. uint8_t axis;
  1209. if (PlsrInitialized == 0U)
  1210. {
  1211. return;
  1212. }
  1213. for (axis = 0U; axis < PLSR_AXIS_COUNT; axis++)
  1214. {
  1215. events = PlsrTakeEvents(axis, PLSR_EVENT_CRITICAL_MASK);
  1216. if (events != 0UL)
  1217. {
  1218. PlsrProcessCriticalEvents(axis, events);
  1219. }
  1220. }
  1221. while ((processedCommands < PLSR_COMMAND_QUEUE_DEPTH)
  1222. && (PlsrPopHighestPriorityCommand(&slot) != 0U))
  1223. {
  1224. (void)PlsrExecuteCommand(&slot);
  1225. processedCommands++;
  1226. }
  1227. for (axis = 0U; axis < PLSR_AXIS_COUNT; axis++)
  1228. {
  1229. events = PlsrTakeEvents(axis,
  1230. PLSR_EVENT_ALL_MASK
  1231. & ~PLSR_EVENT_CRITICAL_MASK);
  1232. if (events != 0UL)
  1233. {
  1234. PlsrProcessNormalEvents(axis, events);
  1235. }
  1236. }
  1237. /* 1ms tick:路径执行器推进(WAIT/ACT 计时、信号/EXT 轮询、跳转链)
  1238. * + 速度曲线推进(P2) + HAL 状态机(DIR 延时)。 */
  1239. for (axis = 0U; axis < PLSR_AXIS_COUNT; axis++)
  1240. {
  1241. PLSR_AXIS *axisObject = &PlsrAxes[axis];
  1242. PLSR_PATH_ACTION action;
  1243. uint32_t frequencyHz;
  1244. uint32_t outputFrequencyHz;
  1245. uint64_t hardwarePulses;
  1246. uint64_t remainingPulses;
  1247. uint8_t profileDone;
  1248. uint8_t wasAccel;
  1249. PlsrHwTick(axis);
  1250. if (PlsrStateIsBusy(axisObject->state) == 0U)
  1251. {
  1252. continue;
  1253. }
  1254. action = PlsrPathTick(&axisObject->path,
  1255. &axisObject->job,
  1256. axisObject->logicalPosition);
  1257. if (action != PLSR_PATH_ACTION_NONE)
  1258. {
  1259. PlsrApplyPathAction(axis, action);
  1260. }
  1261. if ((axisObject->profileActive != 0U)
  1262. && (PlsrHwGetState(axis) != PLSR_HW_STATE_DIR_SETTLING))
  1263. {
  1264. /* 虚拟计数校准到硬件实际计数:ARPE 预装载滞后的偏差不累积,
  1265. * 保证 profile DONE 与硬件计数同步(消除段尾冻结频率收尾)。 */
  1266. hardwarePulses = (uint64_t)PlsrHwGetEmittedPulses(axis);
  1267. PlsrProfileSyncPulses(&axisObject->profile, hardwarePulses);
  1268. wasAccel = axisObject->profileWasAccel;
  1269. (void)PlsrProfileStep(&axisObject->profile,
  1270. &frequencyHz,
  1271. &profileDone);
  1272. outputFrequencyHz = frequencyHz;
  1273. if ((PlsrHwGetState(axis) == PLSR_HW_STATE_RUNNING)
  1274. && (wasAccel == 0U)
  1275. && ((uint64_t)axisObject->profile.totalPulses
  1276. > hardwarePulses + 1UL))
  1277. {
  1278. /* ARR 预装载在当前脉冲结束后生效,因此计算的是
  1279. * “当前脉冲之后”剩余的脉冲。用位置反推减速频率,
  1280. * 避免 1 ms 时间曲线与预装载滞后造成段尾突停。 */
  1281. remainingPulses =
  1282. (uint64_t)axisObject->profile.totalPulses
  1283. - hardwarePulses - 1UL;
  1284. outputFrequencyHz =
  1285. PlsrProfileGetBrakingOutputFrequency(
  1286. &axisObject->profile,
  1287. remainingPulses);
  1288. }
  1289. if ((PlsrHwGetState(axis) == PLSR_HW_STATE_PWM_PENDING)
  1290. && (axisObject->profile.phase
  1291. == PLSR_PROFILE_PHASE_ACCEL))
  1292. {
  1293. outputFrequencyHz =
  1294. PlsrProfileGetInitialOutputFrequency(
  1295. &axisObject->profile);
  1296. }
  1297. if ((profileDone == 0U) || (outputFrequencyHz != 0UL))
  1298. {
  1299. (void)PlsrHwSetFrequency(axis, outputFrequencyHz);
  1300. }
  1301. axisObject->profileWasAccel =
  1302. (axisObject->profile.phase == PLSR_PROFILE_PHASE_ACCEL)
  1303. ? 1U
  1304. : 0U;
  1305. if ((wasAccel != 0U)
  1306. && (axisObject->profileWasAccel == 0U)
  1307. && (axisObject->state == PLSR_STATE_ACCEL))
  1308. {
  1309. /* 加速完成(曲线进入匀速/减速)→ 状态机推进到 RUN。 */
  1310. (void)PlsrPostEvent(axis, PLSR_EVENT_ACCEL_COMPLETE);
  1311. }
  1312. }
  1313. }
  1314. }
  1315. void PlsrTask(void *argument)
  1316. {
  1317. (void)argument;
  1318. #ifdef PLSR_HOST_TEST
  1319. PlsrProcess();
  1320. #else
  1321. while (1)
  1322. {
  1323. PlsrProcess();
  1324. OSTimeDly(1U);
  1325. }
  1326. #endif
  1327. }
  1328. PLSR_RESULT PlsrGetStatus(uint8_t axis, PLSR_STATUS *status)
  1329. {
  1330. PLSR_AXIS *axisObject;
  1331. uint32_t interruptState;
  1332. if (axis >= PLSR_AXIS_COUNT)
  1333. {
  1334. return PLSR_RESULT_INVALID_AXIS;
  1335. }
  1336. if (status == NULL)
  1337. {
  1338. return PLSR_RESULT_INVALID_ARGUMENT;
  1339. }
  1340. interruptState = PlsrCoreEnterCritical();
  1341. axisObject = &PlsrAxes[axis];
  1342. status->state = axisObject->state;
  1343. status->outputMode = axisObject->outputMode;
  1344. status->error = axisObject->error;
  1345. status->stopReason = axisObject->stopReason;
  1346. status->lastCommandResult = axisObject->lastCommandResult;
  1347. status->lastCommandSequence = axisObject->lastCommandSequence;
  1348. status->illegalTransitionCount = axisObject->illegalTransitionCount;
  1349. status->pendingEvents = axisObject->pendingEvents;
  1350. status->logicalPosition = axisObject->logicalPosition;
  1351. status->totalPulses = axisObject->totalPulses;
  1352. status->busy = PlsrStateIsBusy(axisObject->state);
  1353. status->pulseActive = PlsrStateIsPulseActive(axisObject->state);
  1354. status->done = axisObject->done;
  1355. status->wait = (axisObject->state == PLSR_STATE_WAIT) ? 1U : 0U;
  1356. status->directionPositive = axisObject->directionPositive;
  1357. status->highResourceMask = axisObject->lease.highMask;
  1358. status->directionPoint = (axisObject->lease.valid != 0U)
  1359. ? axisObject->lease.directionPoint
  1360. : PLSR_DIRECTION_POINT_NONE;
  1361. status->positionValid = axisObject->positionValid;
  1362. status->jobValid = axisObject->jobValid;
  1363. status->positionOverflow = axisObject->positionOverflow;
  1364. status->s2Set = (axisObject->jobValid != 0U) ? axisObject->job.s2Set : 0U;
  1365. status->speedClamped = (axisObject->jobValid != 0U)
  1366. ? axisObject->job.speedClamped
  1367. : 0U;
  1368. status->segmentCount = (axisObject->jobValid != 0U)
  1369. ? axisObject->job.segmentCount
  1370. : 0U;
  1371. status->startSegment = (axisObject->jobValid != 0U)
  1372. ? axisObject->job.startSegment
  1373. : 0U;
  1374. status->currentSegment = (axisObject->jobValid != 0U)
  1375. ? PlsrPathGetCurrentSegment(
  1376. &axisObject->path)
  1377. : 0U;
  1378. PlsrCoreExitCritical(interruptState);
  1379. return PLSR_RESULT_OK;
  1380. }
  1381. PLSR_RESULT PlsrGetLastParseDetail(uint8_t axis,
  1382. PLSR_PARSE_DETAIL *detail)
  1383. {
  1384. uint32_t interruptState;
  1385. if (axis >= PLSR_AXIS_COUNT)
  1386. {
  1387. return PLSR_RESULT_INVALID_AXIS;
  1388. }
  1389. if (detail == NULL)
  1390. {
  1391. return PLSR_RESULT_INVALID_ARGUMENT;
  1392. }
  1393. interruptState = PlsrCoreEnterCritical();
  1394. *detail = PlsrAxes[axis].parseDetail;
  1395. PlsrCoreExitCritical(interruptState);
  1396. return PLSR_RESULT_OK;
  1397. }