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.
 
 
 
 
 
 

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