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.
 
 
 
 
 
 

2984 lines
100 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_STATE pauseReturnState;
  24. PLSR_RESOURCE_LEASE lease;
  25. PLSR_JOB_SNAPSHOT job;
  26. PLSR_PARSE_DETAIL parseDetail;
  27. volatile uint32_t pendingEvents;
  28. uint32_t lastCommandSequence;
  29. PLSR_RESULT lastCommandResult;
  30. uint32_t illegalTransitionCount;
  31. int64_t logicalPosition;
  32. int64_t taskPulses;
  33. int64_t totalPulses;
  34. uint64_t physicalPulses;
  35. int64_t segmentAccountedPulses;
  36. int64_t equivalentCommandRemainder;
  37. PLSR_EQUIVALENT_CONFIG equivalent;
  38. PLSR_PATH_CONTEXT path;
  39. PLSR_PROFILE_STATE profile;
  40. int32_t liveFrequencyRaw;
  41. uint32_t liveTargetFrequencyHz;
  42. uint32_t pauseStopFrequencyHz;
  43. uint32_t liveFrequencyRejectCount;
  44. PLSR_RESULT lastLiveFrequencyResult;
  45. /* Publish gate shared by PlsrTask and the TIM6 100us control ISR. */
  46. volatile uint8_t profileActive;
  47. uint8_t profileWasAccel;
  48. uint8_t hasLastCommand;
  49. uint8_t done;
  50. uint8_t directionPositive;
  51. uint8_t immediateStopPending;
  52. uint8_t positionValid;
  53. uint8_t jobValid;
  54. uint8_t positionOverflow;
  55. uint8_t segmentAccountingActive;
  56. uint8_t positiveLimitActive;
  57. uint8_t negativeLimitActive;
  58. uint8_t emergencyLatched;
  59. uint8_t segmentEventPublished;
  60. uint8_t backlashActive;
  61. uint8_t backlashBypassOnce;
  62. uint8_t lastUserDirectionValid;
  63. uint8_t lastUserDirectionPositive;
  64. uint8_t runtimeSpeedClamped;
  65. } PLSR_AXIS;
  66. typedef struct
  67. {
  68. PLSR_COMMAND command;
  69. PLSR_START_REQUEST start;
  70. PLSR_CALL call;
  71. uint32_t ticket;
  72. uint8_t hasStart;
  73. uint8_t hasCall;
  74. uint8_t occupied;
  75. } PLSR_COMMAND_SLOT;
  76. static PLSR_AXIS PlsrAxes[PLSR_AXIS_COUNT];
  77. static PLSR_COMMAND_SLOT PlsrCommandQueue[PLSR_COMMAND_QUEUE_DEPTH];
  78. static uint32_t PlsrNextTicket;
  79. static uint8_t PlsrInitialized;
  80. static PLSR_JOB_SNAPSHOT PlsrJobScratch;
  81. static PLSR_JOB_SNAPSHOT PlsrValidationScratch;
  82. static void (* volatile PlsrControlTickHook)(void);
  83. static volatile uint32_t PlsrMaxProcessCycles;
  84. static volatile uint32_t PlsrMaxProcessResponseCycles;
  85. static volatile uint32_t
  86. PlsrMaxProcessStageCycles[PLSR_PROCESS_STAGE_COUNT];
  87. static uint8_t PlsrDeferHsdCheckpoint;
  88. static uint8_t PlsrHsdCheckpointPending;
  89. static void PlsrStopSegmentHardware(uint8_t axis, PLSR_AXIS *axisObject);
  90. static PLSR_RESULT PlsrStartSegmentHardware(uint8_t axis,
  91. PLSR_AXIS *axisObject);
  92. static void PlsrAccountHardwarePulses(uint8_t axis,
  93. PLSR_AXIS *axisObject);
  94. static void PlsrPublishSegmentEvent(uint8_t axis,
  95. PLSR_AXIS *axisObject,
  96. PLSR_STOP_REASON reason);
  97. static uint8_t PlsrAnyAxisBusy(void);
  98. static uint8_t PlsrAllAxesPositionValid(void);
  99. #ifndef PLSR_HOST_TEST
  100. static void PlsrUpdateProcessStageMax(uint8_t stage,
  101. uint32_t started,
  102. uint64_t startedIsrCycles,
  103. uint32_t finished,
  104. uint64_t finishedIsrCycles)
  105. {
  106. uint32_t responseCycles = finished - started;
  107. uint64_t preemptedCycles = finishedIsrCycles - startedIsrCycles;
  108. uint32_t processCycles =
  109. (preemptedCycles < (uint64_t)responseCycles)
  110. ? responseCycles - (uint32_t)preemptedCycles
  111. : 0UL;
  112. if ((stage < PLSR_PROCESS_STAGE_COUNT)
  113. && (processCycles > PlsrMaxProcessStageCycles[stage]))
  114. {
  115. PlsrMaxProcessStageCycles[stage] = processCycles;
  116. }
  117. }
  118. #endif
  119. static void PlsrFlushHsdCheckpoint(void)
  120. {
  121. if (PlsrHsdCheckpointPending != 0U)
  122. {
  123. (void)PlcDeviceSetHsdCheckpointMeta(
  124. PlsrAllAxesPositionValid(),
  125. PlsrAnyAxisBusy());
  126. if (PlcDeviceCheckpointHsd() == PLC_DEVICE_OK)
  127. {
  128. PlsrHsdCheckpointPending = 0U;
  129. }
  130. }
  131. }
  132. static void PlsrCheckpointHsd(void)
  133. {
  134. PlsrHsdCheckpointPending = 1U;
  135. if (PlsrDeferHsdCheckpoint == 0U)
  136. {
  137. PlsrFlushHsdCheckpoint();
  138. }
  139. }
  140. static void PlsrCheckpointHsdImmediate(void)
  141. {
  142. uint8_t deferHsdCheckpoint = PlsrDeferHsdCheckpoint;
  143. PlsrHsdCheckpointPending = 1U;
  144. PlsrDeferHsdCheckpoint = 0U;
  145. PlsrFlushHsdCheckpoint();
  146. PlsrDeferHsdCheckpoint = deferHsdCheckpoint;
  147. }
  148. static uint32_t PlsrCoreEnterCritical(void)
  149. {
  150. #ifdef PLSR_HOST_TEST
  151. return 0UL;
  152. #else
  153. uint32_t interruptState = __get_PRIMASK();
  154. __disable_irq();
  155. __DMB();
  156. return interruptState;
  157. #endif
  158. }
  159. static void PlsrCoreExitCritical(uint32_t interruptState)
  160. {
  161. #ifdef PLSR_HOST_TEST
  162. (void)interruptState;
  163. #else
  164. __DMB();
  165. if (interruptState == 0UL)
  166. {
  167. __enable_irq();
  168. }
  169. #endif
  170. }
  171. static void PlsrSetProfileActive(PLSR_AXIS *axisObject, uint8_t active)
  172. {
  173. uint32_t interruptState = PlsrCoreEnterCritical();
  174. /* Ownership hand-off between PlsrTask and the TIM6 100us ISR. */
  175. axisObject->profileActive = active;
  176. PlsrCoreExitCritical(interruptState);
  177. }
  178. void PlsrSetControlTickHook(void (*hook)(void))
  179. {
  180. uint32_t interruptState = PlsrCoreEnterCritical();
  181. PlsrControlTickHook = hook;
  182. PlsrCoreExitCritical(interruptState);
  183. }
  184. static uint8_t PlsrStateIsBusy(PLSR_STATE state)
  185. {
  186. return ((state == PLSR_STATE_ACCEL) || (state == PLSR_STATE_RUN)
  187. || (state == PLSR_STATE_DECEL) || (state == PLSR_STATE_WAIT)
  188. || (state == PLSR_STATE_PAUSED))
  189. ? 1U
  190. : 0U;
  191. }
  192. static uint8_t PlsrStateIsPulseActive(PLSR_STATE state)
  193. {
  194. return ((state == PLSR_STATE_ACCEL) || (state == PLSR_STATE_RUN)
  195. || (state == PLSR_STATE_DECEL))
  196. ? 1U
  197. : 0U;
  198. }
  199. static void PlsrLoadAxisEquivalentConfig(uint8_t axis,
  200. PLSR_EQUIVALENT_CONFIG *config)
  201. {
  202. uint16_t base = (uint16_t)(PLSR_SFD_CONFIG_START
  203. + (uint16_t)axis
  204. * PLSR_CORE_SFD_AXIS_STRIDE);
  205. uint16_t word;
  206. uint16_t lowWord;
  207. uint16_t highWord;
  208. config->unitCode = 0U;
  209. config->pulsesPerRevolution = 1UL;
  210. config->movementPerRevolution = 1UL;
  211. if (PlcDeviceReadSfd(base, &word) != PLC_DEVICE_OK)
  212. {
  213. return;
  214. }
  215. config->unitCode = (uint8_t)((word >> 8U) & 0x07U);
  216. if ((PlcDeviceReadSfd((uint16_t)(base + 2U), &lowWord)
  217. != PLC_DEVICE_OK)
  218. || (PlcDeviceReadSfd((uint16_t)(base + 3U), &highWord)
  219. != PLC_DEVICE_OK))
  220. {
  221. config->unitCode = 0U;
  222. return;
  223. }
  224. config->pulsesPerRevolution = (uint32_t)lowWord
  225. | ((uint32_t)highWord << 16U);
  226. if ((PlcDeviceReadSfd((uint16_t)(base + 4U), &lowWord)
  227. != PLC_DEVICE_OK)
  228. || (PlcDeviceReadSfd((uint16_t)(base + 5U), &highWord)
  229. != PLC_DEVICE_OK))
  230. {
  231. config->unitCode = 0U;
  232. return;
  233. }
  234. config->movementPerRevolution = (uint32_t)lowWord
  235. | ((uint32_t)highWord << 16U);
  236. if (PlsrPositionValidateEquivalent(config) != PLSR_RESULT_OK)
  237. {
  238. config->unitCode = 0U;
  239. config->pulsesPerRevolution = 1UL;
  240. config->movementPerRevolution = 1UL;
  241. }
  242. }
  243. static void PlsrPublishSdDword(uint8_t axis,
  244. uint8_t lowItem,
  245. int32_t value)
  246. {
  247. (void)PlcDevicePublishSdDword(axis, lowItem, value);
  248. }
  249. static int32_t PlsrGetCompatibleSegmentPulses(const PLSR_AXIS *axisObject)
  250. {
  251. int64_t signedPulses;
  252. if (axisObject->backlashActive != 0U)
  253. {
  254. return 0;
  255. }
  256. signedPulses = (axisObject->directionPositive != 0U)
  257. ? axisObject->segmentAccountedPulses
  258. : -axisObject->segmentAccountedPulses;
  259. if (signedPulses > INT32_MAX)
  260. {
  261. return INT32_MAX;
  262. }
  263. if (signedPulses < INT32_MIN)
  264. {
  265. return INT32_MIN;
  266. }
  267. return (int32_t)signedPulses;
  268. }
  269. static int32_t PlsrClampCompatibleInt32(int64_t value)
  270. {
  271. if (value > INT32_MAX) return INT32_MAX;
  272. if (value < INT32_MIN) return INT32_MIN;
  273. return (int32_t)value;
  274. }
  275. static void PlsrPublishSegmentEvent(uint8_t axis,
  276. PLSR_AXIS *axisObject,
  277. PLSR_STOP_REASON reason)
  278. {
  279. uint16_t segment;
  280. if ((axisObject->jobValid == 0U)
  281. || (axisObject->segmentEventPublished != 0U))
  282. {
  283. return;
  284. }
  285. segment = PlsrPathGetCurrentSegment(&axisObject->path);
  286. if ((segment == 0U) || (segment > PLSR_MAX_SEGMENTS))
  287. {
  288. return;
  289. }
  290. if (PlcDevicePublishEvent(axis, segment, (uint16_t)reason)
  291. == PLC_DEVICE_OK)
  292. {
  293. axisObject->segmentEventPublished = 1U;
  294. }
  295. }
  296. static void PlsrPublishRuntime(uint8_t axis)
  297. {
  298. PLSR_AXIS *axisObject = &PlsrAxes[axis];
  299. uint16_t currentSegment = (axisObject->jobValid != 0U)
  300. ? PlsrPathGetCurrentSegment(
  301. &axisObject->path)
  302. : 0U;
  303. int32_t segmentPulses = PlsrGetCompatibleSegmentPulses(axisObject);
  304. int32_t frequencyHz = (int32_t)PlsrHwGetCurrentFrequencyHz(axis);
  305. int64_t segmentEquivalent64 = segmentPulses;
  306. uint32_t speed = (uint32_t)frequencyHz;
  307. uint16_t publishedError;
  308. uint16_t publishedBlock;
  309. if (PlsrPositionPulsesToUnits(&axisObject->equivalent,
  310. segmentPulses,
  311. &segmentEquivalent64) != PLSR_RESULT_OK)
  312. {
  313. axisObject->positionOverflow = 1U;
  314. segmentEquivalent64 = (segmentPulses < 0) ? INT32_MIN : INT32_MAX;
  315. }
  316. if (PlsrPositionPulseFrequencyToSpeed(&axisObject->equivalent,
  317. (uint32_t)frequencyHz,
  318. &speed) != PLSR_RESULT_OK)
  319. {
  320. speed = UINT32_MAX;
  321. }
  322. PlsrPublishSdDword(axis,
  323. PLSR_SD_ITEM_SEGMENT,
  324. (int32_t)currentSegment);
  325. PlsrPublishSdDword(axis,
  326. PLSR_SD_ITEM_SEGMENT_PULSES,
  327. segmentPulses);
  328. PlsrPublishSdDword(axis,
  329. PLSR_SD_ITEM_SEGMENT_EQUIV,
  330. PlsrClampCompatibleInt32(segmentEquivalent64));
  331. PlsrPublishSdDword(axis, PLSR_SD_ITEM_FREQUENCY, frequencyHz);
  332. PlsrPublishSdDword(axis,
  333. PLSR_SD_ITEM_SPEED,
  334. (speed > (uint32_t)INT32_MAX) ? INT32_MAX
  335. : (int32_t)speed);
  336. /* SD(B+10/+11)只发布信捷兼容码;项目内部符号错误保留在状态API,
  337. * 不得用枚举数值占用信捷固定错误码。 */
  338. publishedError = axisObject->compatibleErrorCode;
  339. publishedBlock = (publishedError != 0U)
  340. ? axisObject->compatibleErrorBlock
  341. : 0U;
  342. (void)PlcDevicePublishSd(axis,
  343. PLSR_SD_ITEM_ERROR_CODE,
  344. (int32_t)publishedError);
  345. (void)PlcDevicePublishSd(axis,
  346. PLSR_SD_ITEM_ERROR_BLOCK,
  347. (int32_t)publishedBlock);
  348. }
  349. static void PlsrSetCompatibleParseError(uint8_t axis,
  350. PLSR_AXIS *axisObject)
  351. {
  352. uint16_t commonBase = (uint16_t)(PLSR_SFD_CONFIG_START
  353. + (uint16_t)axis
  354. * PLSR_CORE_SFD_AXIS_STRIDE);
  355. uint16_t dynamicBase = (uint16_t)(PLSR_HSD_CONFIG_START
  356. + (uint16_t)axis * 20U);
  357. uint16_t set;
  358. axisObject->compatibleErrorCode = 0U;
  359. axisObject->compatibleErrorBlock = 0U;
  360. if ((axisObject->parseDetail.result == PLSR_RESULT_RESOURCE_CONFLICT)
  361. || (axisObject->parseDetail.result == PLSR_RESULT_INVALID_RESOURCE))
  362. {
  363. axisObject->compatibleErrorCode = 26U;
  364. return;
  365. }
  366. if ((axisObject->parseDetail.block == PLSR_PARSE_BLOCK_S0)
  367. && (axisObject->parseDetail.segment != 0U))
  368. {
  369. axisObject->compatibleErrorCode = 1U;
  370. axisObject->compatibleErrorBlock = axisObject->parseDetail.segment;
  371. return;
  372. }
  373. if ((axisObject->parseDetail.address == (uint32_t)(commonBase + 2U))
  374. || (axisObject->parseDetail.address
  375. == (uint32_t)(commonBase + 4U)))
  376. {
  377. axisObject->compatibleErrorCode = 2U;
  378. return;
  379. }
  380. if ((axisObject->parseDetail.address == (uint32_t)(dynamicBase + 12U))
  381. || (axisObject->parseDetail.address
  382. == (uint32_t)(dynamicBase + 13U)))
  383. {
  384. axisObject->compatibleErrorCode =
  385. (axisObject->parseDetail.address
  386. == (uint32_t)(dynamicBase + 12U)) ? 15U : 16U;
  387. return;
  388. }
  389. for (set = 0U; set < 4U; set++)
  390. {
  391. uint32_t setBase = (uint32_t)commonBase + 50UL
  392. + (uint32_t)set * 20UL;
  393. if (axisObject->parseDetail.address == setBase + 12UL)
  394. {
  395. axisObject->compatibleErrorCode = 15U;
  396. return;
  397. }
  398. if (axisObject->parseDetail.address == setBase + 13UL)
  399. {
  400. axisObject->compatibleErrorCode = 16U;
  401. return;
  402. }
  403. }
  404. if ((axisObject->parseDetail.address == (uint32_t)(commonBase + 30U))
  405. || (axisObject->parseDetail.address
  406. == (uint32_t)(commonBase + 32U))
  407. || (axisObject->parseDetail.result == PLSR_RESULT_SEGMENT_OVERFLOW)
  408. || (axisObject->parseDetail.result == PLSR_RESULT_BLOCK_OVERLAP)
  409. || (axisObject->parseDetail.result == PLSR_RESULT_ADDRESS_OVERFLOW))
  410. {
  411. axisObject->compatibleErrorCode = 4U;
  412. return;
  413. }
  414. if (axisObject->parseDetail.block == PLSR_PARSE_BLOCK_S2)
  415. {
  416. axisObject->compatibleErrorCode = 3U;
  417. }
  418. }
  419. static void PlsrPublishAxis(uint8_t axis)
  420. {
  421. PLSR_AXIS *axisObject = &PlsrAxes[axis];
  422. uint8_t compatibleRun;
  423. compatibleRun = (uint8_t)((PlsrStateIsPulseActive(axisObject->state) != 0U)
  424. || (axisObject->state == PLSR_STATE_WAIT));
  425. (void)PlcDevicePublishSm(axis,
  426. compatibleRun,
  427. axisObject->directionPositive);
  428. PlsrPublishRuntime(axis);
  429. }
  430. static void PlsrSetStopReason(PLSR_AXIS *axis,
  431. PLSR_STOP_REASON stopReason)
  432. {
  433. if (stopReason > axis->stopReason)
  434. {
  435. axis->stopReason = stopReason;
  436. }
  437. }
  438. /* 将 64 位逻辑位置发布为 HSD 的 32 位兼容值。
  439. * 超出范围时保持最近一次合法值,只锁存诊断,禁止回绕或静默截断。 */
  440. static void PlsrPublishPosition(uint8_t axis, PLSR_AXIS *axisObject)
  441. {
  442. int32_t compatValue;
  443. int64_t equivalentPosition;
  444. uint16_t base = (uint16_t)((uint16_t)axis
  445. * PLSR_HSD_RUNTIME_AXIS_COUNT);
  446. if ((axisObject->logicalPosition > INT32_MAX)
  447. || (axisObject->logicalPosition < INT32_MIN))
  448. {
  449. axisObject->positionOverflow = 1U;
  450. return;
  451. }
  452. compatValue = (int32_t)axisObject->logicalPosition;
  453. (void)PlcDevicePublishHsdDword(base, compatValue);
  454. if ((PlsrPositionPulsesToUnits(&axisObject->equivalent,
  455. axisObject->logicalPosition,
  456. &equivalentPosition) != PLSR_RESULT_OK)
  457. || (equivalentPosition > INT32_MAX)
  458. || (equivalentPosition < INT32_MIN))
  459. {
  460. axisObject->positionOverflow = 1U;
  461. return;
  462. }
  463. (void)PlcDevicePublishHsdDword((uint16_t)(base + 2U),
  464. (int32_t)equivalentPosition);
  465. }
  466. static uint8_t PlsrAddInt64Checked(int64_t left,
  467. int64_t right,
  468. int64_t *result)
  469. {
  470. if ((result == NULL)
  471. || ((right > 0) && (left > INT64_MAX - right))
  472. || ((right < 0) && (left < INT64_MIN - right)))
  473. {
  474. return 0U;
  475. }
  476. *result = left + right;
  477. return 1U;
  478. }
  479. static PLSR_RESULT PlsrReadLimitInput(const PLSR_JOB_SNAPSHOT *job,
  480. uint8_t point,
  481. uint8_t activeLow,
  482. uint8_t *active)
  483. {
  484. uint8_t rawLevel;
  485. if ((job == NULL) || (active == NULL))
  486. {
  487. return PLSR_RESULT_INVALID_ARGUMENT;
  488. }
  489. if (point == 0xFFU)
  490. {
  491. *active = 0U;
  492. return PLSR_RESULT_OK;
  493. }
  494. if ((job->source.readBit == NULL)
  495. || (job->source.readBit(job->source.context,
  496. PLSR_DEVICE_X,
  497. point,
  498. &rawLevel) == 0U))
  499. {
  500. return PLSR_RESULT_DATA_ACCESS;
  501. }
  502. *active = (activeLow != 0U)
  503. ? ((rawLevel == 0U) ? 1U : 0U)
  504. : ((rawLevel != 0U) ? 1U : 0U);
  505. return PLSR_RESULT_OK;
  506. }
  507. static int64_t PlsrGetBrakingDistance(uint8_t axis,
  508. const PLSR_AXIS *axisObject)
  509. {
  510. uint64_t frequencyHz;
  511. uint64_t hardwareFrequencyHz;
  512. uint64_t denominator;
  513. uint64_t numerator;
  514. uint64_t brakingPulses;
  515. uint64_t samplingPulses;
  516. uint64_t frequencyQ32;
  517. uint32_t decelSlopeHzPerMs;
  518. uint32_t interruptState;
  519. uint8_t profileActive;
  520. /* frequencyQ32 is 64-bit and may be updated by TIM6. Snapshot it with
  521. * the related fields so the 1ms protection pass cannot observe a torn
  522. * value or a mixture of two control ticks. */
  523. interruptState = PlsrCoreEnterCritical();
  524. profileActive = axisObject->profileActive;
  525. decelSlopeHzPerMs = axisObject->profile.decelSlopeHzPerMs;
  526. frequencyQ32 = axisObject->profile.frequencyQ32;
  527. PlsrCoreExitCritical(interruptState);
  528. if ((profileActive == 0U) || (decelSlopeHzPerMs == 0UL))
  529. {
  530. return 0;
  531. }
  532. frequencyHz = frequencyQ32 >> 32U;
  533. hardwareFrequencyHz = PlsrHwGetCurrentFrequencyHz(axis);
  534. if (hardwareFrequencyHz > frequencyHz)
  535. {
  536. /* Protection must follow the frequency already present at the output,
  537. * not an earlier/lower profile value waiting behind timer preload. */
  538. frequencyHz = hardwareFrequencyHz;
  539. }
  540. numerator = frequencyHz * frequencyHz;
  541. denominator = UINT64_C(2000) * decelSlopeHzPerMs;
  542. brakingPulses = (numerator + denominator - 1UL) / denominator;
  543. /* The 1ms protection task can observe several new pulses per pass. The
  544. * inclusive position comparison already covers one of them; reserve only
  545. * the additional pulses so <=1kHz behavior is unchanged while higher
  546. * frequencies cannot cross the limit by a complete sampling window. */
  547. samplingPulses = (frequencyHz + UINT64_C(999)) / UINT64_C(1000);
  548. if (samplingPulses > 0UL)
  549. {
  550. samplingPulses--;
  551. }
  552. if (brakingPulses > (uint64_t)INT64_MAX - samplingPulses)
  553. {
  554. return INT64_MAX;
  555. }
  556. return (int64_t)(brakingPulses + samplingPulses);
  557. }
  558. static PLSR_RESULT PlsrUpdateLimitState(PLSR_AXIS *axisObject,
  559. const PLSR_JOB_SNAPSHOT *job,
  560. uint8_t includeBrakingDistance)
  561. {
  562. int64_t brakingDistance = 0;
  563. uint8_t positiveHard;
  564. uint8_t negativeHard;
  565. uint8_t positiveSoft = 0U;
  566. uint8_t negativeSoft = 0U;
  567. PLSR_RESULT result;
  568. result = PlsrReadLimitInput(job,
  569. job->limits.positiveInputPoint,
  570. job->limits.positiveInputActiveLow,
  571. &positiveHard);
  572. if (result != PLSR_RESULT_OK) return result;
  573. result = PlsrReadLimitInput(job,
  574. job->limits.negativeInputPoint,
  575. job->limits.negativeInputActiveLow,
  576. &negativeHard);
  577. if (result != PLSR_RESULT_OK) return result;
  578. if ((job->limits.softLimitEnabled != 0U)
  579. && (axisObject->backlashActive == 0U)
  580. && (axisObject->positionValid != 0U))
  581. {
  582. if (includeBrakingDistance != 0U)
  583. {
  584. brakingDistance = PlsrGetBrakingDistance(job->dAxis,
  585. axisObject);
  586. }
  587. if (axisObject->logicalPosition
  588. >= job->limits.positiveSoftLimitPulses)
  589. {
  590. positiveSoft = 1U;
  591. }
  592. else if ((axisObject->directionPositive != 0U)
  593. && (brakingDistance > 0)
  594. && ((axisObject->logicalPosition
  595. > INT64_MAX - brakingDistance)
  596. || (axisObject->logicalPosition + brakingDistance
  597. >= job->limits.positiveSoftLimitPulses)))
  598. {
  599. positiveSoft = 1U;
  600. }
  601. if (axisObject->logicalPosition
  602. <= job->limits.negativeSoftLimitPulses)
  603. {
  604. negativeSoft = 1U;
  605. }
  606. else if ((axisObject->directionPositive == 0U)
  607. && (brakingDistance > 0)
  608. && ((axisObject->logicalPosition
  609. < INT64_MIN + brakingDistance)
  610. || (axisObject->logicalPosition - brakingDistance
  611. <= job->limits.negativeSoftLimitPulses)))
  612. {
  613. negativeSoft = 1U;
  614. }
  615. }
  616. axisObject->positiveLimitActive =
  617. ((positiveHard != 0U) || (positiveSoft != 0U)) ? 1U : 0U;
  618. axisObject->negativeLimitActive =
  619. ((negativeHard != 0U) || (negativeSoft != 0U)) ? 1U : 0U;
  620. return PLSR_RESULT_OK;
  621. }
  622. static PLSR_RESULT PlsrCheckStartProtection(PLSR_AXIS *axisObject,
  623. const PLSR_JOB_SNAPSHOT *job)
  624. {
  625. PLSR_RESULT result;
  626. if (axisObject->emergencyLatched != 0U)
  627. {
  628. return PLSR_RESULT_EMERGENCY_LATCHED;
  629. }
  630. if ((job->limits.softLimitEnabled != 0U)
  631. && (axisObject->positionValid == 0U))
  632. {
  633. return PLSR_RESULT_POSITION_INVALID;
  634. }
  635. result = PlsrUpdateLimitState(axisObject, job, 0U);
  636. if (result != PLSR_RESULT_OK)
  637. {
  638. return result;
  639. }
  640. if ((job->initialDirectionPositive != 0U)
  641. && (axisObject->positiveLimitActive != 0U))
  642. {
  643. return PLSR_RESULT_LIMIT_POSITIVE;
  644. }
  645. if ((job->initialDirectionPositive == 0U)
  646. && (axisObject->negativeLimitActive != 0U))
  647. {
  648. return PLSR_RESULT_LIMIT_NEGATIVE;
  649. }
  650. return PLSR_RESULT_OK;
  651. }
  652. /* 将 HAL 实际完成的完整脉冲/AB周期合并到64位位置。
  653. * emittedPulses 每段从0开始,因此用 segmentAccountedPulses 做差量去重。 */
  654. static void PlsrAccountHardwarePulses(uint8_t axis,
  655. PLSR_AXIS *axisObject)
  656. {
  657. int64_t emittedPulses;
  658. int64_t delta;
  659. int64_t signedDelta;
  660. int64_t newLogicalPosition;
  661. int64_t newTaskPulses;
  662. int64_t newTotalPulses;
  663. if (axisObject->segmentAccountingActive == 0U)
  664. {
  665. return;
  666. }
  667. emittedPulses = PlsrHwGetEmittedPulses(axis);
  668. if ((emittedPulses < 0)
  669. || (emittedPulses < axisObject->segmentAccountedPulses))
  670. {
  671. axisObject->positionOverflow = 1U;
  672. (void)PlsrPostEvent(axis, PLSR_EVENT_COUNTER_FAULT);
  673. return;
  674. }
  675. delta = emittedPulses - axisObject->segmentAccountedPulses;
  676. if (delta == 0)
  677. {
  678. return;
  679. }
  680. if ((uint64_t)delta > UINT64_MAX - axisObject->physicalPulses)
  681. {
  682. axisObject->positionOverflow = 1U;
  683. axisObject->segmentAccountedPulses = emittedPulses;
  684. (void)PlsrPostEvent(axis, PLSR_EVENT_COUNTER_FAULT);
  685. return;
  686. }
  687. axisObject->physicalPulses += (uint64_t)delta;
  688. if (axisObject->backlashActive != 0U)
  689. {
  690. /* Backlash pulses move through mechanical clearance only. */
  691. axisObject->segmentAccountedPulses = emittedPulses;
  692. PlsrPublishRuntime(axis);
  693. return;
  694. }
  695. signedDelta = (axisObject->directionPositive != 0U) ? delta : -delta;
  696. if ((PlsrAddInt64Checked(axisObject->logicalPosition,
  697. signedDelta,
  698. &newLogicalPosition) == 0U)
  699. || (PlsrAddInt64Checked(axisObject->taskPulses,
  700. signedDelta,
  701. &newTaskPulses) == 0U)
  702. || (PlsrAddInt64Checked(axisObject->totalPulses,
  703. delta,
  704. &newTotalPulses) == 0U))
  705. {
  706. axisObject->positionOverflow = 1U;
  707. axisObject->segmentAccountedPulses = emittedPulses;
  708. (void)PlsrPostEvent(axis, PLSR_EVENT_COUNTER_FAULT);
  709. return;
  710. }
  711. axisObject->logicalPosition = newLogicalPosition;
  712. axisObject->taskPulses = newTaskPulses;
  713. axisObject->totalPulses = newTotalPulses;
  714. axisObject->segmentAccountedPulses = emittedPulses;
  715. PlsrPublishPosition(axis, axisObject);
  716. PlsrPublishRuntime(axis);
  717. }
  718. static uint8_t PlsrTransitionIsAllowed(PLSR_STATE current,
  719. PLSR_STATE target)
  720. {
  721. if (current == target)
  722. {
  723. return 1U;
  724. }
  725. if (target == PLSR_STATE_ERROR)
  726. {
  727. return 1U;
  728. }
  729. switch (current)
  730. {
  731. case PLSR_STATE_UNINITIALIZED:
  732. return (target == PLSR_STATE_IDLE) ? 1U : 0U;
  733. case PLSR_STATE_IDLE:
  734. case PLSR_STATE_COMPLETED:
  735. case PLSR_STATE_STOPPED:
  736. return ((target == PLSR_STATE_IDLE)
  737. || (target == PLSR_STATE_ACCEL)
  738. || (target == PLSR_STATE_WAIT)
  739. || (target == PLSR_STATE_COMPLETED))
  740. ? 1U
  741. : 0U;
  742. case PLSR_STATE_ACCEL:
  743. case PLSR_STATE_RUN:
  744. return ((target == PLSR_STATE_ACCEL)
  745. || (target == PLSR_STATE_RUN)
  746. || (target == PLSR_STATE_DECEL)
  747. || (target == PLSR_STATE_WAIT)
  748. || (target == PLSR_STATE_COMPLETED)
  749. || (target == PLSR_STATE_STOPPED))
  750. ? 1U
  751. : 0U;
  752. case PLSR_STATE_DECEL:
  753. return ((target == PLSR_STATE_ACCEL)
  754. || (target == PLSR_STATE_RUN)
  755. || (target == PLSR_STATE_WAIT)
  756. || (target == PLSR_STATE_PAUSED)
  757. || (target == PLSR_STATE_COMPLETED)
  758. || (target == PLSR_STATE_STOPPED))
  759. ? 1U
  760. : 0U;
  761. case PLSR_STATE_WAIT:
  762. return ((target == PLSR_STATE_ACCEL)
  763. || (target == PLSR_STATE_RUN)
  764. || (target == PLSR_STATE_PAUSED)
  765. || (target == PLSR_STATE_COMPLETED)
  766. || (target == PLSR_STATE_STOPPED))
  767. ? 1U
  768. : 0U;
  769. case PLSR_STATE_PAUSED:
  770. return ((target == PLSR_STATE_ACCEL)
  771. || (target == PLSR_STATE_RUN)
  772. || (target == PLSR_STATE_WAIT)
  773. || (target == PLSR_STATE_STOPPED))
  774. ? 1U
  775. : 0U;
  776. case PLSR_STATE_ERROR:
  777. return (target == PLSR_STATE_IDLE) ? 1U : 0U;
  778. default:
  779. return 0U;
  780. }
  781. }
  782. PLSR_RESULT PlsrStateTransition(uint8_t axis,
  783. PLSR_STATE target,
  784. PLSR_TRANSITION_REASON reason)
  785. {
  786. PLSR_AXIS *axisObject;
  787. (void)reason;
  788. if (axis >= PLSR_AXIS_COUNT)
  789. {
  790. return PLSR_RESULT_INVALID_AXIS;
  791. }
  792. if ((uint32_t)target > (uint32_t)PLSR_STATE_ERROR)
  793. {
  794. return PLSR_RESULT_INVALID_ARGUMENT;
  795. }
  796. axisObject = &PlsrAxes[axis];
  797. if (PlsrTransitionIsAllowed(axisObject->state, target) == 0U)
  798. {
  799. axisObject->illegalTransitionCount++;
  800. axisObject->error = PLSR_ERROR_ILLEGAL_TRANSITION;
  801. axisObject->stopReason = PLSR_STOP_REASON_FAULT;
  802. axisObject->done = 0U;
  803. axisObject->state = PLSR_STATE_ERROR;
  804. axisObject->pendingTerminal = PLSR_STATE_UNINITIALIZED;
  805. axisObject->immediateStopPending = 0U;
  806. PlsrStopSegmentHardware(axis, axisObject);
  807. axisObject->backlashActive = 0U;
  808. axisObject->backlashBypassOnce = 0U;
  809. PlsrResourceRelease(&axisObject->lease);
  810. PlsrPublishAxis(axis);
  811. return PLSR_RESULT_INVALID_STATE;
  812. }
  813. axisObject->state = target;
  814. if (target == PLSR_STATE_COMPLETED)
  815. {
  816. axisObject->done = 1U;
  817. }
  818. if ((target == PLSR_STATE_COMPLETED) || (target == PLSR_STATE_STOPPED)
  819. || (target == PLSR_STATE_ERROR))
  820. {
  821. axisObject->pendingTerminal = PLSR_STATE_UNINITIALIZED;
  822. axisObject->immediateStopPending = 0U;
  823. PlsrPathTerminate(&axisObject->path);
  824. PlsrStopSegmentHardware(axis, axisObject);
  825. PlsrResourceRelease(&axisObject->lease);
  826. /* 检查点写入前按全部轴的最终状态统一计算 lastBusy。 */
  827. PlsrCheckpointHsd();
  828. }
  829. PlsrPublishAxis(axis);
  830. return PLSR_RESULT_OK;
  831. }
  832. static uint8_t PlsrCommandPriority(PLSR_COMMAND_OPCODE opcode)
  833. {
  834. switch (opcode)
  835. {
  836. case PLSR_CMD_STOP_IMMEDIATE:
  837. return 0U;
  838. case PLSR_CMD_STOP_DECEL:
  839. return 1U;
  840. case PLSR_CMD_PAUSE:
  841. return 2U;
  842. case PLSR_CMD_RESUME:
  843. return 3U;
  844. default:
  845. return 4U;
  846. }
  847. }
  848. static PLSR_RESULT PlsrQueueCommand(const PLSR_COMMAND *command,
  849. const PLSR_START_REQUEST *start,
  850. const PLSR_CALL *call)
  851. {
  852. uint32_t interruptState;
  853. uint8_t freeSlot = PLSR_COMMAND_QUEUE_DEPTH;
  854. uint8_t index;
  855. interruptState = PlsrCoreEnterCritical();
  856. if ((PlsrAxes[command->axis].hasLastCommand != 0U)
  857. && (PlsrAxes[command->axis].lastCommandSequence == command->sequence))
  858. {
  859. PLSR_RESULT result = PlsrAxes[command->axis].lastCommandResult;
  860. PlsrCoreExitCritical(interruptState);
  861. return result;
  862. }
  863. for (index = 0U; index < PLSR_COMMAND_QUEUE_DEPTH; index++)
  864. {
  865. if (PlsrCommandQueue[index].occupied != 0U)
  866. {
  867. if ((PlsrCommandQueue[index].command.axis == command->axis)
  868. && (PlsrCommandQueue[index].command.sequence
  869. == command->sequence))
  870. {
  871. PlsrCoreExitCritical(interruptState);
  872. return PLSR_RESULT_QUEUED;
  873. }
  874. }
  875. else if (freeSlot == PLSR_COMMAND_QUEUE_DEPTH)
  876. {
  877. freeSlot = index;
  878. }
  879. }
  880. if (freeSlot == PLSR_COMMAND_QUEUE_DEPTH)
  881. {
  882. PlsrCoreExitCritical(interruptState);
  883. return PLSR_RESULT_QUEUE_FULL;
  884. }
  885. PlsrCommandQueue[freeSlot].command = *command;
  886. if (start != NULL)
  887. {
  888. PlsrCommandQueue[freeSlot].start = *start;
  889. PlsrCommandQueue[freeSlot].hasStart = 1U;
  890. }
  891. else
  892. {
  893. (void)memset(&PlsrCommandQueue[freeSlot].start,
  894. 0,
  895. sizeof(PlsrCommandQueue[freeSlot].start));
  896. PlsrCommandQueue[freeSlot].hasStart = 0U;
  897. }
  898. if (call != NULL)
  899. {
  900. PlsrCommandQueue[freeSlot].call = *call;
  901. PlsrCommandQueue[freeSlot].hasCall = 1U;
  902. }
  903. else
  904. {
  905. (void)memset(&PlsrCommandQueue[freeSlot].call,
  906. 0,
  907. sizeof(PlsrCommandQueue[freeSlot].call));
  908. PlsrCommandQueue[freeSlot].hasCall = 0U;
  909. }
  910. PlsrCommandQueue[freeSlot].ticket = PlsrNextTicket++;
  911. PlsrCommandQueue[freeSlot].occupied = 1U;
  912. PlsrCoreExitCritical(interruptState);
  913. return PLSR_RESULT_QUEUED;
  914. }
  915. static uint8_t PlsrPopHighestPriorityCommand(PLSR_COMMAND_SLOT *slot)
  916. {
  917. uint32_t interruptState;
  918. uint32_t selectedTicket = 0UL;
  919. uint8_t selectedPriority = 0xFFU;
  920. uint8_t selected = PLSR_COMMAND_QUEUE_DEPTH;
  921. uint8_t index;
  922. uint8_t priority;
  923. interruptState = PlsrCoreEnterCritical();
  924. for (index = 0U; index < PLSR_COMMAND_QUEUE_DEPTH; index++)
  925. {
  926. if (PlsrCommandQueue[index].occupied == 0U)
  927. {
  928. continue;
  929. }
  930. priority = PlsrCommandPriority(PlsrCommandQueue[index].command.opcode);
  931. if ((selected == PLSR_COMMAND_QUEUE_DEPTH)
  932. || (priority < selectedPriority)
  933. || ((priority == selectedPriority)
  934. && ((int32_t)(PlsrCommandQueue[index].ticket
  935. - selectedTicket)
  936. < 0)))
  937. {
  938. selected = index;
  939. selectedPriority = priority;
  940. selectedTicket = PlsrCommandQueue[index].ticket;
  941. }
  942. }
  943. if (selected == PLSR_COMMAND_QUEUE_DEPTH)
  944. {
  945. PlsrCoreExitCritical(interruptState);
  946. return 0U;
  947. }
  948. *slot = PlsrCommandQueue[selected];
  949. PlsrCommandQueue[selected].occupied = 0U;
  950. PlsrCoreExitCritical(interruptState);
  951. return 1U;
  952. }
  953. #ifdef PLSR_HOST_TEST
  954. uint32_t PlsrTestGetProfileRefreshHz(uint8_t axis)
  955. {
  956. return (axis < PLSR_AXIS_COUNT) ? PlsrAxes[axis].profile.refreshHz : 0UL;
  957. }
  958. uint8_t PlsrTestGetProfileActive(uint8_t axis)
  959. {
  960. return (axis < PLSR_AXIS_COUNT) ? PlsrAxes[axis].profileActive : 0U;
  961. }
  962. uint8_t PlsrTestGetJobRefreshCode(uint8_t axis)
  963. {
  964. return (axis < PLSR_AXIS_COUNT)
  965. ? PlsrAxes[axis].job.s2.refreshCode
  966. : 0U;
  967. }
  968. uint32_t PlsrTestGetProfileFrequencyHz(uint8_t axis)
  969. {
  970. return (axis < PLSR_AXIS_COUNT)
  971. ? (uint32_t)(PlsrAxes[axis].profile.frequencyQ32 >> 32U)
  972. : 0UL;
  973. }
  974. PLSR_RESULT PlsrPostStart(const PLSR_START_REQUEST *request)
  975. {
  976. PLSR_COMMAND command;
  977. if (request == NULL)
  978. {
  979. return PLSR_RESULT_INVALID_ARGUMENT;
  980. }
  981. if (request->axis >= PLSR_AXIS_COUNT)
  982. {
  983. return PLSR_RESULT_INVALID_AXIS;
  984. }
  985. if (PlsrInitialized == 0U)
  986. {
  987. return PLSR_RESULT_INVALID_STATE;
  988. }
  989. command.sequence = request->sequence;
  990. command.axis = request->axis;
  991. command.opcode = PLSR_CMD_START;
  992. command.argument = 0;
  993. return PlsrQueueCommand(&command, request, NULL);
  994. }
  995. #endif /* PLSR_HOST_TEST */
  996. PLSR_RESULT PlsrPostCall(const PLSR_CALL *call)
  997. {
  998. PLSR_COMMAND command;
  999. if (call == NULL)
  1000. {
  1001. return PLSR_RESULT_INVALID_ARGUMENT;
  1002. }
  1003. if (call->dAxis >= PLSR_AXIS_COUNT)
  1004. {
  1005. return PLSR_RESULT_INVALID_AXIS;
  1006. }
  1007. if (PlsrInitialized == 0U)
  1008. {
  1009. return PLSR_RESULT_INVALID_STATE;
  1010. }
  1011. command.sequence = call->sequence;
  1012. command.axis = call->dAxis;
  1013. command.opcode = PLSR_CMD_START;
  1014. command.argument = 0;
  1015. return PlsrQueueCommand(&command, NULL, call);
  1016. }
  1017. PLSR_RESULT PlsrValidateCall(const PLSR_CALL *call,
  1018. PLSR_PARSE_DETAIL *detail)
  1019. {
  1020. PLSR_PARSE_CONTEXT parseContext;
  1021. uint32_t interruptState;
  1022. if ((call == NULL) || (detail == NULL))
  1023. {
  1024. return PLSR_RESULT_INVALID_ARGUMENT;
  1025. }
  1026. if (call->dAxis >= PLSR_AXIS_COUNT)
  1027. {
  1028. return PLSR_RESULT_INVALID_AXIS;
  1029. }
  1030. if (PlsrInitialized == 0U)
  1031. {
  1032. return PLSR_RESULT_INVALID_STATE;
  1033. }
  1034. interruptState = PlsrCoreEnterCritical();
  1035. parseContext.logicalPosition = PlsrAxes[call->dAxis].logicalPosition;
  1036. parseContext.positionValid = PlsrAxes[call->dAxis].positionValid;
  1037. PlsrCoreExitCritical(interruptState);
  1038. return PlsrBuildJobSnapshot(call,
  1039. &parseContext,
  1040. &PlsrValidationScratch,
  1041. detail);
  1042. }
  1043. PLSR_RESULT PlsrPostCommand(const PLSR_COMMAND *command)
  1044. {
  1045. if (command == NULL)
  1046. {
  1047. return PLSR_RESULT_INVALID_ARGUMENT;
  1048. }
  1049. if (command->axis >= PLSR_AXIS_COUNT)
  1050. {
  1051. return PLSR_RESULT_INVALID_AXIS;
  1052. }
  1053. if (((uint32_t)command->opcode > (uint32_t)PLSR_CMD_SELF_TEST)
  1054. || (command->opcode == PLSR_CMD_START))
  1055. {
  1056. return PLSR_RESULT_INVALID_ARGUMENT;
  1057. }
  1058. if (PlsrInitialized == 0U)
  1059. {
  1060. return PLSR_RESULT_INVALID_STATE;
  1061. }
  1062. return PlsrQueueCommand(command, NULL, NULL);
  1063. }
  1064. PLSR_RESULT PlsrPostEvent(uint8_t axis, uint32_t eventMask)
  1065. {
  1066. uint32_t interruptState;
  1067. if (axis >= PLSR_AXIS_COUNT)
  1068. {
  1069. return PLSR_RESULT_INVALID_AXIS;
  1070. }
  1071. if ((eventMask == 0UL) || ((eventMask & ~PLSR_EVENT_ALL_MASK) != 0UL))
  1072. {
  1073. return PLSR_RESULT_INVALID_ARGUMENT;
  1074. }
  1075. interruptState = PlsrCoreEnterCritical();
  1076. PlsrAxes[axis].pendingEvents |= eventMask;
  1077. PlsrCoreExitCritical(interruptState);
  1078. return PLSR_RESULT_OK;
  1079. }
  1080. static uint32_t PlsrTakeEvents(uint8_t axis, uint32_t mask)
  1081. {
  1082. uint32_t interruptState;
  1083. uint32_t events;
  1084. interruptState = PlsrCoreEnterCritical();
  1085. events = PlsrAxes[axis].pendingEvents & mask;
  1086. PlsrAxes[axis].pendingEvents &= ~events;
  1087. PlsrCoreExitCritical(interruptState);
  1088. return events;
  1089. }
  1090. static uint8_t PlsrAnyAxisBusy(void)
  1091. {
  1092. uint8_t axis;
  1093. for (axis = 0U; axis < PLSR_AXIS_COUNT; axis++)
  1094. {
  1095. if (PlsrStateIsBusy(PlsrAxes[axis].state) != 0U)
  1096. {
  1097. return 1U;
  1098. }
  1099. }
  1100. return 0U;
  1101. }
  1102. static uint8_t PlsrAllAxesPositionValid(void)
  1103. {
  1104. uint8_t axis;
  1105. for (axis = 0U; axis < PLSR_AXIS_COUNT; axis++)
  1106. {
  1107. if ((PlsrAxes[axis].positionValid == 0U)
  1108. || (PlsrAxes[axis].positionOverflow != 0U))
  1109. {
  1110. return 0U;
  1111. }
  1112. }
  1113. return 1U;
  1114. }
  1115. static PLSR_RESULT PlsrStartAxis(PLSR_AXIS *axisObject,
  1116. const PLSR_START_REQUEST *start)
  1117. {
  1118. PLSR_RESOURCE_REQUEST resourceRequest;
  1119. PLSR_RESULT result;
  1120. uint8_t axisWasBusy = PlsrAnyAxisBusy();
  1121. if ((axisObject->state != PLSR_STATE_IDLE)
  1122. && (axisObject->state != PLSR_STATE_COMPLETED)
  1123. && (axisObject->state != PLSR_STATE_STOPPED))
  1124. {
  1125. return PLSR_RESULT_INVALID_STATE;
  1126. }
  1127. resourceRequest.ownerAxis = start->axis;
  1128. resourceRequest.outputMode = start->outputMode;
  1129. resourceRequest.dAxis = start->axis;
  1130. resourceRequest.directionPoint = start->directionPoint;
  1131. result = PlsrResourceReserve(&resourceRequest, &axisObject->lease);
  1132. if (result != PLSR_RESULT_OK)
  1133. {
  1134. axisObject->error = (result == PLSR_RESULT_RESOURCE_CONFLICT)
  1135. ? PLSR_ERROR_RESOURCE_CONFLICT
  1136. : PLSR_ERROR_INVALID_RESOURCE;
  1137. return result;
  1138. }
  1139. axisObject->outputMode = start->outputMode;
  1140. axisObject->directionPositive = (start->directionPositive != 0U) ? 1U : 0U;
  1141. axisObject->error = PLSR_ERROR_NONE;
  1142. axisObject->compatibleErrorCode = 0U;
  1143. axisObject->compatibleErrorBlock = 0U;
  1144. axisObject->stopReason = PLSR_STOP_REASON_NONE;
  1145. axisObject->pendingTerminal = PLSR_STATE_UNINITIALIZED;
  1146. axisObject->pauseReturnState = PLSR_STATE_UNINITIALIZED;
  1147. axisObject->immediateStopPending = 0U;
  1148. axisObject->done = 0U;
  1149. axisObject->jobValid = 0U;
  1150. axisObject->taskPulses = 0;
  1151. axisObject->segmentAccountedPulses = 0;
  1152. axisObject->segmentAccountingActive = 0U;
  1153. axisObject->backlashActive = 0U;
  1154. axisObject->backlashBypassOnce = 0U;
  1155. axisObject->liveFrequencyRaw = 0;
  1156. axisObject->liveTargetFrequencyHz = 0UL;
  1157. axisObject->pauseStopFrequencyHz = 0UL;
  1158. axisObject->liveFrequencyRejectCount = 0UL;
  1159. axisObject->lastLiveFrequencyResult = PLSR_RESULT_OK;
  1160. axisObject->runtimeSpeedClamped = 0U;
  1161. result = PlsrStateTransition(start->axis,
  1162. PLSR_STATE_ACCEL,
  1163. PLSR_TRANSITION_START);
  1164. if (result != PLSR_RESULT_OK)
  1165. {
  1166. PlsrResourceRelease(&axisObject->lease);
  1167. }
  1168. else
  1169. {
  1170. /* 全局空闲到运行的边沿立即落盘,保持原有掉电安全窗口;后续
  1171. * 并发轴已由同一个全局 lastBusy=1 检查点覆盖。 */
  1172. if (axisWasBusy == 0U)
  1173. {
  1174. PlsrCheckpointHsdImmediate();
  1175. }
  1176. }
  1177. return result;
  1178. }
  1179. static PLSR_RESULT PlsrStartCall(PLSR_AXIS *axisObject,
  1180. const PLSR_CALL *call)
  1181. {
  1182. PLSR_RESOURCE_REQUEST resourceRequest;
  1183. PLSR_PARSE_CONTEXT parseContext;
  1184. PLSR_RESULT result;
  1185. uint8_t axisWasBusy = PlsrAnyAxisBusy();
  1186. if ((axisObject->state != PLSR_STATE_IDLE)
  1187. && (axisObject->state != PLSR_STATE_COMPLETED)
  1188. && (axisObject->state != PLSR_STATE_STOPPED))
  1189. {
  1190. return PLSR_RESULT_INVALID_STATE;
  1191. }
  1192. if (axisObject->emergencyLatched != 0U)
  1193. {
  1194. return PLSR_RESULT_EMERGENCY_LATCHED;
  1195. }
  1196. axisObject->compatibleErrorCode = 0U;
  1197. axisObject->compatibleErrorBlock = 0U;
  1198. parseContext.logicalPosition = axisObject->logicalPosition;
  1199. parseContext.positionValid = axisObject->positionValid;
  1200. result = PlsrBuildJobSnapshot(call,
  1201. &parseContext,
  1202. &PlsrJobScratch,
  1203. &axisObject->parseDetail);
  1204. if (result != PLSR_RESULT_OK)
  1205. {
  1206. PlsrSetCompatibleParseError(call->dAxis, axisObject);
  1207. return result;
  1208. }
  1209. result = PlsrCheckStartProtection(axisObject, &PlsrJobScratch);
  1210. if (result != PLSR_RESULT_OK)
  1211. {
  1212. if (result == PLSR_RESULT_LIMIT_POSITIVE)
  1213. {
  1214. axisObject->error = PLSR_ERROR_LIMIT_POSITIVE;
  1215. axisObject->compatibleErrorCode = 5U;
  1216. axisObject->stopReason = PLSR_STOP_REASON_LIMIT_POSITIVE;
  1217. }
  1218. else if (result == PLSR_RESULT_LIMIT_NEGATIVE)
  1219. {
  1220. axisObject->error = PLSR_ERROR_LIMIT_NEGATIVE;
  1221. axisObject->compatibleErrorCode = 6U;
  1222. axisObject->stopReason = PLSR_STOP_REASON_LIMIT_NEGATIVE;
  1223. }
  1224. else if (result == PLSR_RESULT_EMERGENCY_LATCHED)
  1225. {
  1226. axisObject->error = PLSR_ERROR_EMERGENCY;
  1227. axisObject->stopReason = PLSR_STOP_REASON_SOFTWARE_EMERGENCY;
  1228. }
  1229. else if (result == PLSR_RESULT_DATA_ACCESS)
  1230. {
  1231. axisObject->error = PLSR_ERROR_INTERNAL;
  1232. axisObject->compatibleErrorCode = 26U;
  1233. axisObject->stopReason = PLSR_STOP_REASON_FAULT;
  1234. }
  1235. return result;
  1236. }
  1237. resourceRequest.ownerAxis = call->dAxis;
  1238. resourceRequest.outputMode =
  1239. (PLSR_OUTPUT_MODE)PlsrJobScratch.outputMode;
  1240. resourceRequest.dAxis = call->dAxis;
  1241. resourceRequest.directionPoint = PlsrJobScratch.directionPoint;
  1242. result = PlsrResourceReserve(&resourceRequest, &axisObject->lease);
  1243. if (result != PLSR_RESULT_OK)
  1244. {
  1245. axisObject->error = (result == PLSR_RESULT_RESOURCE_CONFLICT)
  1246. ? PLSR_ERROR_RESOURCE_CONFLICT
  1247. : PLSR_ERROR_INVALID_RESOURCE;
  1248. axisObject->parseDetail.result = result;
  1249. axisObject->parseDetail.block = PLSR_PARSE_BLOCK_OUTPUT;
  1250. axisObject->compatibleErrorCode = 26U;
  1251. axisObject->compatibleErrorBlock = 0U;
  1252. return result;
  1253. }
  1254. axisObject->job = PlsrJobScratch;
  1255. axisObject->jobValid = 1U;
  1256. if ((axisObject->equivalent.unitCode
  1257. != axisObject->job.equivalent.unitCode)
  1258. || (axisObject->equivalent.pulsesPerRevolution
  1259. != axisObject->job.equivalent.pulsesPerRevolution)
  1260. || (axisObject->equivalent.movementPerRevolution
  1261. != axisObject->job.equivalent.movementPerRevolution))
  1262. {
  1263. axisObject->equivalentCommandRemainder = 0;
  1264. }
  1265. axisObject->equivalent = axisObject->job.equivalent;
  1266. axisObject->outputMode = (PLSR_OUTPUT_MODE)axisObject->job.outputMode;
  1267. axisObject->directionPositive = axisObject->job.initialDirectionPositive;
  1268. axisObject->error = PLSR_ERROR_NONE;
  1269. axisObject->compatibleErrorCode = 0U;
  1270. axisObject->compatibleErrorBlock = 0U;
  1271. axisObject->stopReason = PLSR_STOP_REASON_NONE;
  1272. axisObject->pendingTerminal = PLSR_STATE_UNINITIALIZED;
  1273. axisObject->pauseReturnState = PLSR_STATE_UNINITIALIZED;
  1274. axisObject->immediateStopPending = 0U;
  1275. axisObject->done = 0U;
  1276. axisObject->taskPulses = 0;
  1277. axisObject->segmentAccountedPulses = 0;
  1278. axisObject->segmentAccountingActive = 0U;
  1279. axisObject->segmentEventPublished = 0U;
  1280. axisObject->backlashActive = 0U;
  1281. axisObject->backlashBypassOnce = 0U;
  1282. axisObject->liveFrequencyRaw = 0;
  1283. axisObject->liveTargetFrequencyHz = 0UL;
  1284. axisObject->pauseStopFrequencyHz = 0UL;
  1285. axisObject->liveFrequencyRejectCount = 0UL;
  1286. axisObject->lastLiveFrequencyResult = PLSR_RESULT_OK;
  1287. axisObject->runtimeSpeedClamped = 0U;
  1288. PlsrPathBegin(&axisObject->path,
  1289. &axisObject->job,
  1290. axisObject->logicalPosition);
  1291. if (axisObject->path.jobEnded != 0U)
  1292. {
  1293. /* 起点就是零脉冲且跳转链已结束(任务无实际脉冲)。 */
  1294. axisObject->stopReason = PLSR_STOP_REASON_NORMAL_COMPLETE;
  1295. (void)PlsrStateTransition(call->dAxis,
  1296. PLSR_STATE_COMPLETED,
  1297. PLSR_TRANSITION_JOB_COMPLETE);
  1298. axisObject->jobValid = 0U;
  1299. return PLSR_RESULT_OK;
  1300. }
  1301. result = PlsrStateTransition(call->dAxis,
  1302. PLSR_STATE_ACCEL,
  1303. PLSR_TRANSITION_START);
  1304. if (result != PLSR_RESULT_OK)
  1305. {
  1306. axisObject->jobValid = 0U;
  1307. PlsrResourceRelease(&axisObject->lease);
  1308. }
  1309. else
  1310. {
  1311. /* 先持久化全局 0->1 busy 边沿,再允许硬件输出启动;后续并发
  1312. * 轴由同一个 lastBusy=1 检查点覆盖。 */
  1313. if (axisWasBusy == 0U)
  1314. {
  1315. PlsrCheckpointHsdImmediate();
  1316. }
  1317. /* 启动当前段硬件输出与速度曲线。 */
  1318. /* 零脉冲跳转链耗尽本轮预算时没有实际运动段,等待下一次
  1319. * PlsrPathTick 找到非零段后再启动硬件。 */
  1320. if (axisObject->path.jumpChainPending == 0U)
  1321. {
  1322. result = PlsrStartSegmentHardware(call->dAxis, axisObject);
  1323. }
  1324. if (result != PLSR_RESULT_OK)
  1325. {
  1326. if ((result == PLSR_RESULT_LIMIT_POSITIVE)
  1327. || (result == PLSR_RESULT_LIMIT_NEGATIVE))
  1328. {
  1329. axisObject->error =
  1330. (result == PLSR_RESULT_LIMIT_POSITIVE)
  1331. ? PLSR_ERROR_LIMIT_POSITIVE
  1332. : PLSR_ERROR_LIMIT_NEGATIVE;
  1333. axisObject->compatibleErrorCode =
  1334. (result == PLSR_RESULT_LIMIT_POSITIVE) ? 5U : 6U;
  1335. PlsrSetStopReason(
  1336. axisObject,
  1337. (result == PLSR_RESULT_LIMIT_POSITIVE)
  1338. ? PLSR_STOP_REASON_LIMIT_POSITIVE
  1339. : PLSR_STOP_REASON_LIMIT_NEGATIVE);
  1340. (void)PlsrStateTransition(call->dAxis,
  1341. PLSR_STATE_STOPPED,
  1342. PLSR_TRANSITION_STOP);
  1343. }
  1344. else
  1345. {
  1346. axisObject->error = PLSR_ERROR_TIMER_FAULT;
  1347. PlsrSetStopReason(axisObject, PLSR_STOP_REASON_FAULT);
  1348. axisObject->done = 0U;
  1349. (void)PlsrStateTransition(call->dAxis,
  1350. PLSR_STATE_ERROR,
  1351. PLSR_TRANSITION_FAULT);
  1352. }
  1353. return result;
  1354. }
  1355. }
  1356. return result;
  1357. }
  1358. static PLSR_RESULT PlsrStopImmediate(uint8_t axis)
  1359. {
  1360. PLSR_AXIS *axisObject = &PlsrAxes[axis];
  1361. if ((axisObject->state == PLSR_STATE_IDLE)
  1362. || (axisObject->state == PLSR_STATE_COMPLETED)
  1363. || (axisObject->state == PLSR_STATE_STOPPED))
  1364. {
  1365. return PLSR_RESULT_OK;
  1366. }
  1367. if (axisObject->state == PLSR_STATE_ERROR)
  1368. {
  1369. return PLSR_RESULT_INVALID_STATE;
  1370. }
  1371. if (axisObject->immediateStopPending != 0U)
  1372. {
  1373. return PLSR_RESULT_OK;
  1374. }
  1375. PlsrSetStopReason(axisObject, PLSR_STOP_REASON_STOP_IMMEDIATE);
  1376. axisObject->pendingTerminal = PLSR_STATE_STOPPED;
  1377. PlsrPublishSegmentEvent(axis,
  1378. axisObject,
  1379. PLSR_STOP_REASON_STOP_IMMEDIATE);
  1380. PlsrPathTerminate(&axisObject->path);
  1381. PlsrStopSegmentHardware(axis, axisObject);
  1382. return PlsrStateTransition(axis,
  1383. PLSR_STATE_STOPPED,
  1384. PLSR_TRANSITION_STOP);
  1385. }
  1386. static PLSR_RESULT PlsrRequestControlledStop(uint8_t axis,
  1387. PLSR_STATE terminal,
  1388. PLSR_STOP_REASON reason)
  1389. {
  1390. PLSR_AXIS *axisObject = &PlsrAxes[axis];
  1391. PLSR_RESULT result;
  1392. uint32_t interruptState;
  1393. PlsrSetStopReason(axisObject, reason);
  1394. axisObject->pendingTerminal = terminal;
  1395. if (terminal != PLSR_STATE_PAUSED)
  1396. {
  1397. PlsrPublishSegmentEvent(axis, axisObject, reason);
  1398. PlsrPathTerminate(&axisObject->path);
  1399. }
  1400. if ((axisObject->state == PLSR_STATE_WAIT)
  1401. || (axisObject->state == PLSR_STATE_PAUSED))
  1402. {
  1403. PlsrStopSegmentHardware(axis, axisObject);
  1404. return PlsrStateTransition(axis,
  1405. terminal,
  1406. PLSR_TRANSITION_DECEL_COMPLETE);
  1407. }
  1408. if (axisObject->profileActive == 0U)
  1409. {
  1410. return (axisObject->state == PLSR_STATE_DECEL)
  1411. ? PLSR_RESULT_OK
  1412. : PlsrStateTransition(axis,
  1413. PLSR_STATE_DECEL,
  1414. PLSR_TRANSITION_DECEL_REQUEST);
  1415. }
  1416. interruptState = PlsrCoreEnterCritical();
  1417. result = PlsrProfileRequestStop(&axisObject->profile);
  1418. PlsrCoreExitCritical(interruptState);
  1419. if (result != PLSR_RESULT_OK)
  1420. {
  1421. return result;
  1422. }
  1423. if (axisObject->state == PLSR_STATE_DECEL)
  1424. {
  1425. return PLSR_RESULT_OK;
  1426. }
  1427. return PlsrStateTransition(axis,
  1428. PLSR_STATE_DECEL,
  1429. PLSR_TRANSITION_DECEL_REQUEST);
  1430. }
  1431. static PLSR_RESULT PlsrStopDecel(uint8_t axis)
  1432. {
  1433. PLSR_AXIS *axisObject = &PlsrAxes[axis];
  1434. if ((axisObject->state == PLSR_STATE_IDLE)
  1435. || (axisObject->state == PLSR_STATE_COMPLETED)
  1436. || (axisObject->state == PLSR_STATE_STOPPED))
  1437. {
  1438. return PLSR_RESULT_OK;
  1439. }
  1440. if (axisObject->state == PLSR_STATE_ERROR)
  1441. {
  1442. return PLSR_RESULT_INVALID_STATE;
  1443. }
  1444. if (axisObject->stopReason >= PLSR_STOP_REASON_STOP_IMMEDIATE)
  1445. {
  1446. return PLSR_RESULT_OK;
  1447. }
  1448. return PlsrRequestControlledStop(axis,
  1449. PLSR_STATE_STOPPED,
  1450. PLSR_STOP_REASON_STOP_DECEL);
  1451. }
  1452. static PLSR_RESULT PlsrPause(uint8_t axis)
  1453. {
  1454. PLSR_AXIS *axisObject = &PlsrAxes[axis];
  1455. uint32_t interruptState;
  1456. if (axisObject->state == PLSR_STATE_PAUSED)
  1457. {
  1458. return PLSR_RESULT_OK;
  1459. }
  1460. if (axisObject->stopReason >= PLSR_STOP_REASON_STOP_DECEL)
  1461. {
  1462. return PLSR_RESULT_BUSY;
  1463. }
  1464. if ((axisObject->state != PLSR_STATE_ACCEL)
  1465. && (axisObject->state != PLSR_STATE_RUN)
  1466. && (axisObject->state != PLSR_STATE_DECEL)
  1467. && (axisObject->state != PLSR_STATE_WAIT))
  1468. {
  1469. return PLSR_RESULT_INVALID_STATE;
  1470. }
  1471. axisObject->pauseReturnState = axisObject->state;
  1472. if (axisObject->profileActive != 0U)
  1473. {
  1474. interruptState = PlsrCoreEnterCritical();
  1475. /* RequestStop temporarily replaces stopFrequencyHz with zero. Keep
  1476. * the segment-specific value (including backlash profiles) so RESUME
  1477. * rebuilds the same trajectory rather than assuming the user S2 one. */
  1478. axisObject->pauseStopFrequencyHz =
  1479. axisObject->profile.stopFrequencyHz;
  1480. PlsrCoreExitCritical(interruptState);
  1481. }
  1482. return PlsrRequestControlledStop(axis,
  1483. PLSR_STATE_PAUSED,
  1484. PLSR_STOP_REASON_PAUSE);
  1485. }
  1486. static PLSR_RESULT PlsrResume(uint8_t axis)
  1487. {
  1488. PLSR_AXIS *axisObject = &PlsrAxes[axis];
  1489. PLSR_RESULT result;
  1490. PLSR_STATE targetState;
  1491. uint64_t emittedPulses;
  1492. if (axisObject->state != PLSR_STATE_PAUSED)
  1493. {
  1494. return PLSR_RESULT_INVALID_STATE;
  1495. }
  1496. if (axisObject->pauseReturnState == PLSR_STATE_WAIT)
  1497. {
  1498. axisObject->stopReason = PLSR_STOP_REASON_NONE;
  1499. axisObject->pendingTerminal = PLSR_STATE_UNINITIALIZED;
  1500. axisObject->pauseReturnState = PLSR_STATE_UNINITIALIZED;
  1501. return PlsrStateTransition(axis,
  1502. PLSR_STATE_WAIT,
  1503. PLSR_TRANSITION_WAIT_COMPLETE);
  1504. }
  1505. if (axisObject->jobValid == 0U)
  1506. {
  1507. /* The snapshot-less start entry exists only for host state-machine
  1508. * tests; preserve its historical transition-only resume semantics. */
  1509. axisObject->stopReason = PLSR_STOP_REASON_NONE;
  1510. axisObject->pendingTerminal = PLSR_STATE_UNINITIALIZED;
  1511. axisObject->pauseReturnState = PLSR_STATE_UNINITIALIZED;
  1512. return PlsrStateTransition(axis,
  1513. PLSR_STATE_ACCEL,
  1514. PLSR_TRANSITION_WAIT_COMPLETE);
  1515. }
  1516. emittedPulses = (uint64_t)PlsrHwGetEmittedPulses(axis);
  1517. PlsrProfileSyncPulses(&axisObject->profile, emittedPulses);
  1518. if (emittedPulses >= (uint64_t)axisObject->profile.totalPulses)
  1519. {
  1520. axisObject->stopReason = PLSR_STOP_REASON_NONE;
  1521. axisObject->pendingTerminal = PLSR_STATE_UNINITIALIZED;
  1522. axisObject->pauseReturnState = PLSR_STATE_UNINITIALIZED;
  1523. result = PlsrStateTransition(axis,
  1524. PLSR_STATE_ACCEL,
  1525. PLSR_TRANSITION_WAIT_COMPLETE);
  1526. if (result == PLSR_RESULT_OK)
  1527. {
  1528. (void)PlsrPostEvent(axis, PLSR_EVENT_SEGMENT_COMPLETE);
  1529. }
  1530. return result;
  1531. }
  1532. result = PlsrProfileResume(&axisObject->profile,
  1533. axisObject->profile.startFrequencyHz,
  1534. axisObject->liveTargetFrequencyHz,
  1535. axisObject->pauseStopFrequencyHz);
  1536. if (result != PLSR_RESULT_OK)
  1537. {
  1538. return result;
  1539. }
  1540. result = PlsrHwResumePulse(axis);
  1541. if (result != PLSR_RESULT_OK)
  1542. {
  1543. return result;
  1544. }
  1545. axisObject->stopReason = PLSR_STOP_REASON_NONE;
  1546. axisObject->pendingTerminal = PLSR_STATE_UNINITIALIZED;
  1547. axisObject->pauseReturnState = PLSR_STATE_UNINITIALIZED;
  1548. PlsrSetProfileActive(axisObject, 1U);
  1549. axisObject->profileWasAccel =
  1550. (axisObject->profile.phase == PLSR_PROFILE_PHASE_ACCEL) ? 1U : 0U;
  1551. targetState = (axisObject->profileWasAccel != 0U)
  1552. ? PLSR_STATE_ACCEL
  1553. : PLSR_STATE_RUN;
  1554. return PlsrStateTransition(axis,
  1555. targetState,
  1556. PLSR_TRANSITION_WAIT_COMPLETE);
  1557. }
  1558. static PLSR_RESULT PlsrExecuteCommand(const PLSR_COMMAND_SLOT *slot)
  1559. {
  1560. PLSR_AXIS *axisObject = &PlsrAxes[slot->command.axis];
  1561. PLC_DEVICE_RESULT deviceResult;
  1562. PLSR_RESULT result;
  1563. switch (slot->command.opcode)
  1564. {
  1565. case PLSR_CMD_START:
  1566. if (slot->hasCall != 0U)
  1567. {
  1568. result = PlsrStartCall(axisObject, &slot->call);
  1569. }
  1570. else
  1571. {
  1572. result = (slot->hasStart != 0U)
  1573. ? PlsrStartAxis(axisObject, &slot->start)
  1574. : PLSR_RESULT_INVALID_ARGUMENT;
  1575. }
  1576. break;
  1577. case PLSR_CMD_STOP_DECEL:
  1578. result = PlsrStopDecel(slot->command.axis);
  1579. break;
  1580. case PLSR_CMD_STOP_IMMEDIATE:
  1581. result = PlsrStopImmediate(slot->command.axis);
  1582. break;
  1583. case PLSR_CMD_PAUSE:
  1584. result = PlsrPause(slot->command.axis);
  1585. break;
  1586. case PLSR_CMD_RESUME:
  1587. result = PlsrResume(slot->command.axis);
  1588. break;
  1589. case PLSR_CMD_SET_POSITION:
  1590. if (PlsrStateIsBusy(axisObject->state) != 0U)
  1591. {
  1592. result = PLSR_RESULT_BUSY;
  1593. }
  1594. else
  1595. {
  1596. axisObject->logicalPosition = slot->command.argument;
  1597. axisObject->positionValid = 1U;
  1598. axisObject->positionOverflow = 0U;
  1599. PlsrPublishPosition(slot->command.axis, axisObject);
  1600. PlsrCheckpointHsd();
  1601. result = PLSR_RESULT_OK;
  1602. }
  1603. break;
  1604. case PLSR_CMD_CLEAR_POSITION:
  1605. if (PlsrStateIsBusy(axisObject->state) != 0U)
  1606. {
  1607. result = PLSR_RESULT_BUSY;
  1608. }
  1609. else
  1610. {
  1611. axisObject->logicalPosition = 0;
  1612. axisObject->positionValid = 1U;
  1613. axisObject->positionOverflow = 0U;
  1614. PlsrPublishPosition(slot->command.axis, axisObject);
  1615. PlsrCheckpointHsd();
  1616. result = PLSR_RESULT_OK;
  1617. }
  1618. break;
  1619. case PLSR_CMD_CLEAR_TOTAL:
  1620. if (PlsrStateIsBusy(axisObject->state) != 0U)
  1621. {
  1622. result = PLSR_RESULT_BUSY;
  1623. }
  1624. else
  1625. {
  1626. axisObject->totalPulses = 0;
  1627. PlsrCheckpointHsd();
  1628. result = PLSR_RESULT_OK;
  1629. }
  1630. break;
  1631. case PLSR_CMD_SAVE_CONFIG:
  1632. if (PlsrAnyAxisBusy() != 0U)
  1633. {
  1634. result = PLSR_RESULT_BUSY;
  1635. }
  1636. else
  1637. {
  1638. deviceResult = PlcDeviceSaveSfd();
  1639. result = (deviceResult == PLC_DEVICE_OK)
  1640. ? PLSR_RESULT_OK
  1641. : PLSR_RESULT_PERSISTENCE_ERROR;
  1642. }
  1643. break;
  1644. case PLSR_CMD_LOAD_CONFIG:
  1645. if (PlsrAnyAxisBusy() != 0U)
  1646. {
  1647. result = PLSR_RESULT_BUSY;
  1648. }
  1649. else
  1650. {
  1651. deviceResult = PlcDeviceLoadSfd();
  1652. result = (deviceResult == PLC_DEVICE_OK)
  1653. ? PLSR_RESULT_OK
  1654. : PLSR_RESULT_PERSISTENCE_ERROR;
  1655. }
  1656. break;
  1657. case PLSR_CMD_RESET_ERROR:
  1658. if (PlsrStateIsBusy(axisObject->state) != 0U)
  1659. {
  1660. result = PLSR_RESULT_BUSY;
  1661. }
  1662. else if ((axisObject->state != PLSR_STATE_ERROR)
  1663. && (axisObject->error == PLSR_ERROR_NONE)
  1664. && (axisObject->emergencyLatched == 0U)
  1665. && (axisObject->compatibleErrorCode == 0U))
  1666. {
  1667. result = PLSR_RESULT_INVALID_STATE;
  1668. }
  1669. else
  1670. {
  1671. axisObject->error = PLSR_ERROR_NONE;
  1672. axisObject->compatibleErrorCode = 0U;
  1673. axisObject->compatibleErrorBlock = 0U;
  1674. axisObject->emergencyLatched = 0U;
  1675. axisObject->stopReason = PLSR_STOP_REASON_NONE;
  1676. axisObject->done = 0U;
  1677. result = (axisObject->state == PLSR_STATE_IDLE)
  1678. ? PLSR_RESULT_OK
  1679. : PlsrStateTransition(
  1680. slot->command.axis,
  1681. PLSR_STATE_IDLE,
  1682. PLSR_TRANSITION_RESET_ERROR);
  1683. }
  1684. break;
  1685. case PLSR_CMD_SELF_TEST:
  1686. result = ((PlsrAnyAxisBusy() == 0U)
  1687. && (PlsrResourceCheckInvariant() != 0U))
  1688. ? PLSR_RESULT_OK
  1689. : PLSR_RESULT_BUSY;
  1690. break;
  1691. default:
  1692. result = PLSR_RESULT_INVALID_ARGUMENT;
  1693. break;
  1694. }
  1695. axisObject->lastCommandSequence = slot->command.sequence;
  1696. axisObject->lastCommandResult = result;
  1697. axisObject->hasLastCommand = 1U;
  1698. PlsrPublishAxis(slot->command.axis);
  1699. return result;
  1700. }
  1701. static void PlsrProcessCriticalEvents(uint8_t axis, uint32_t events)
  1702. {
  1703. PLSR_AXIS *axisObject = &PlsrAxes[axis];
  1704. if ((events & PLSR_EVENT_SOFTWARE_EMERGENCY) != 0UL)
  1705. {
  1706. axisObject->emergencyLatched = 1U;
  1707. axisObject->error = PLSR_ERROR_EMERGENCY;
  1708. PlsrSetStopReason(axisObject,
  1709. PLSR_STOP_REASON_SOFTWARE_EMERGENCY);
  1710. axisObject->done = 0U;
  1711. if (PlsrStateIsBusy(axisObject->state) != 0U)
  1712. {
  1713. PlsrPublishSegmentEvent(
  1714. axis,
  1715. axisObject,
  1716. PLSR_STOP_REASON_SOFTWARE_EMERGENCY);
  1717. PlsrPathTerminate(&axisObject->path);
  1718. PlsrStopSegmentHardware(axis, axisObject);
  1719. (void)PlsrStateTransition(axis,
  1720. PLSR_STATE_STOPPED,
  1721. PLSR_TRANSITION_STOP);
  1722. }
  1723. else
  1724. {
  1725. PlsrPublishAxis(axis);
  1726. }
  1727. return;
  1728. }
  1729. if ((events & PLSR_EVENT_LIMIT_POSITIVE) != 0UL)
  1730. {
  1731. axisObject->positiveLimitActive = 1U;
  1732. if ((axisObject->directionPositive != 0U)
  1733. && (PlsrStateIsBusy(axisObject->state) != 0U))
  1734. {
  1735. axisObject->error = PLSR_ERROR_LIMIT_POSITIVE;
  1736. axisObject->compatibleErrorCode = 5U;
  1737. axisObject->compatibleErrorBlock = 0U;
  1738. (void)PlsrRequestControlledStop(
  1739. axis,
  1740. PLSR_STATE_STOPPED,
  1741. PLSR_STOP_REASON_LIMIT_POSITIVE);
  1742. return;
  1743. }
  1744. }
  1745. if ((events & PLSR_EVENT_LIMIT_NEGATIVE) != 0UL)
  1746. {
  1747. axisObject->negativeLimitActive = 1U;
  1748. if ((axisObject->directionPositive == 0U)
  1749. && (PlsrStateIsBusy(axisObject->state) != 0U))
  1750. {
  1751. axisObject->error = PLSR_ERROR_LIMIT_NEGATIVE;
  1752. axisObject->compatibleErrorCode = 6U;
  1753. axisObject->compatibleErrorBlock = 0U;
  1754. (void)PlsrRequestControlledStop(
  1755. axis,
  1756. PLSR_STATE_STOPPED,
  1757. PLSR_STOP_REASON_LIMIT_NEGATIVE);
  1758. return;
  1759. }
  1760. }
  1761. if ((events & (PLSR_EVENT_TIMER_FAULT | PLSR_EVENT_COUNTER_FAULT)) != 0UL)
  1762. {
  1763. axisObject->error = ((events & PLSR_EVENT_TIMER_FAULT) != 0UL)
  1764. ? PLSR_ERROR_TIMER_FAULT
  1765. : PLSR_ERROR_COUNTER_FAULT;
  1766. PlsrSetStopReason(axisObject, PLSR_STOP_REASON_FAULT);
  1767. axisObject->done = 0U;
  1768. PlsrPathTerminate(&axisObject->path);
  1769. PlsrStopSegmentHardware(axis, axisObject);
  1770. (void)PlsrStateTransition(axis,
  1771. PLSR_STATE_ERROR,
  1772. PLSR_TRANSITION_FAULT);
  1773. }
  1774. }
  1775. static void PlsrMonitorAxisProtection(uint8_t axis)
  1776. {
  1777. PLSR_AXIS *axisObject = &PlsrAxes[axis];
  1778. PLSR_RESULT result;
  1779. if ((axisObject->jobValid == 0U)
  1780. || (PlsrStateIsBusy(axisObject->state) == 0U))
  1781. {
  1782. return;
  1783. }
  1784. result = PlsrUpdateLimitState(axisObject, &axisObject->job, 1U);
  1785. if (result != PLSR_RESULT_OK)
  1786. {
  1787. axisObject->error = PLSR_ERROR_INTERNAL;
  1788. axisObject->compatibleErrorCode = 26U;
  1789. axisObject->compatibleErrorBlock = 0U;
  1790. PlsrSetStopReason(axisObject, PLSR_STOP_REASON_FAULT);
  1791. axisObject->done = 0U;
  1792. PlsrPublishSegmentEvent(axis,
  1793. axisObject,
  1794. PLSR_STOP_REASON_FAULT);
  1795. PlsrPathTerminate(&axisObject->path);
  1796. PlsrStopSegmentHardware(axis, axisObject);
  1797. (void)PlsrStateTransition(axis,
  1798. PLSR_STATE_ERROR,
  1799. PLSR_TRANSITION_FAULT);
  1800. return;
  1801. }
  1802. if ((axisObject->directionPositive != 0U)
  1803. && (axisObject->positiveLimitActive != 0U)
  1804. && !((axisObject->pendingTerminal == PLSR_STATE_STOPPED)
  1805. && (axisObject->stopReason
  1806. == PLSR_STOP_REASON_LIMIT_POSITIVE)))
  1807. {
  1808. (void)PlsrPostEvent(axis, PLSR_EVENT_LIMIT_POSITIVE);
  1809. }
  1810. else if ((axisObject->directionPositive == 0U)
  1811. && (axisObject->negativeLimitActive != 0U)
  1812. && !((axisObject->pendingTerminal == PLSR_STATE_STOPPED)
  1813. && (axisObject->stopReason
  1814. == PLSR_STOP_REASON_LIMIT_NEGATIVE)))
  1815. {
  1816. (void)PlsrPostEvent(axis, PLSR_EVENT_LIMIT_NEGATIVE);
  1817. }
  1818. }
  1819. /* 启动当前段的硬件输出与速度曲线(P3a:单轴 PULSE/DIR)。
  1820. * 由段进入 ACCEL 时调用(任务启动 + 段间推进)。 */
  1821. static PLSR_RESULT PlsrStartSegmentHardware(uint8_t axis,
  1822. PLSR_AXIS *axisObject)
  1823. {
  1824. const PLSR_JOB_SNAPSHOT *job = &axisObject->job;
  1825. const PLSR_SEGMENT_SNAPSHOT *segment =
  1826. &job->segments[axisObject->path.currentSegment - 1U];
  1827. PLSR_PROFILE_REQUEST profileRequest;
  1828. PLSR_HW_START_PARAMS params;
  1829. PLSR_RESULT result;
  1830. int64_t pulses;
  1831. int64_t signedPulses;
  1832. int64_t targetPosition;
  1833. int64_t nextEquivalentRemainder =
  1834. axisObject->equivalentCommandRemainder;
  1835. int64_t outputPulses;
  1836. int32_t liveFrequencyRaw;
  1837. uint32_t gapSlopeHzPerMs;
  1838. uint16_t backlashPulses = 0U;
  1839. uint8_t runBacklash = 0U;
  1840. uint8_t positive;
  1841. if (job->positioningMode == 0U)
  1842. {
  1843. result = PlsrPositionUnitsToPulses(
  1844. &axisObject->equivalent,
  1845. segment->pulseOrTarget,
  1846. axisObject->equivalentCommandRemainder,
  1847. &signedPulses,
  1848. &nextEquivalentRemainder);
  1849. if (result != PLSR_RESULT_OK)
  1850. {
  1851. return result;
  1852. }
  1853. if (signedPulses == INT64_MIN)
  1854. {
  1855. return PLSR_RESULT_POSITION_OVERFLOW;
  1856. }
  1857. pulses = (signedPulses < 0) ? -signedPulses : signedPulses;
  1858. positive = (signedPulses >= 0) ? 1U : 0U;
  1859. }
  1860. else
  1861. {
  1862. /* 绝对模式使用实际硬件脉冲闭环更新后的逻辑位置计算位移。 */
  1863. int64_t delta;
  1864. result = PlsrPositionAbsoluteUnitsToPulses(
  1865. &axisObject->equivalent,
  1866. segment->pulseOrTarget,
  1867. &targetPosition);
  1868. if (result != PLSR_RESULT_OK)
  1869. {
  1870. return result;
  1871. }
  1872. if (((axisObject->logicalPosition > 0)
  1873. && (targetPosition
  1874. < INT64_MIN + axisObject->logicalPosition))
  1875. || ((axisObject->logicalPosition < 0)
  1876. && (targetPosition
  1877. > INT64_MAX + axisObject->logicalPosition)))
  1878. {
  1879. return PLSR_RESULT_POSITION_OVERFLOW;
  1880. }
  1881. delta = targetPosition - axisObject->logicalPosition;
  1882. if (delta == INT64_MIN)
  1883. {
  1884. return PLSR_RESULT_POSITION_OVERFLOW;
  1885. }
  1886. pulses = (delta < 0) ? -delta : delta;
  1887. positive = (delta >= 0) ? 1U : 0U;
  1888. }
  1889. result = PlsrUpdateLimitState(axisObject, job, 0U);
  1890. if (result != PLSR_RESULT_OK)
  1891. {
  1892. return result;
  1893. }
  1894. if ((positive != 0U) && (axisObject->positiveLimitActive != 0U))
  1895. {
  1896. return PLSR_RESULT_LIMIT_POSITIVE;
  1897. }
  1898. if ((positive == 0U) && (axisObject->negativeLimitActive != 0U))
  1899. {
  1900. return PLSR_RESULT_LIMIT_NEGATIVE;
  1901. }
  1902. axisObject->segmentEventPublished = 0U;
  1903. if (pulses == 0)
  1904. {
  1905. /* 当量小于一个物理脉冲时保存余数并按零脉冲段推进;不启动PWM。 */
  1906. axisObject->equivalentCommandRemainder = nextEquivalentRemainder;
  1907. axisObject->directionPositive = positive;
  1908. axisObject->segmentAccountedPulses = 0;
  1909. axisObject->segmentAccountingActive = 0U;
  1910. PlsrPublishAxis(axis);
  1911. (void)PlsrPostEvent(axis, PLSR_EVENT_SEGMENT_COMPLETE);
  1912. return PLSR_RESULT_OK;
  1913. }
  1914. /* A future segment edited before it becomes current must still use the
  1915. * COMMIT snapshot. Capture the source value only as a change-detection
  1916. * baseline; a later edit, made while this segment is current, is live. */
  1917. result = PlsrReadLiveFrequencyRaw(job,
  1918. axisObject->path.currentSegment,
  1919. &liveFrequencyRaw);
  1920. if (result == PLSR_RESULT_OK)
  1921. {
  1922. axisObject->liveFrequencyRaw = liveFrequencyRaw;
  1923. axisObject->lastLiveFrequencyResult = PLSR_RESULT_OK;
  1924. }
  1925. else
  1926. {
  1927. axisObject->lastLiveFrequencyResult = result;
  1928. if (axisObject->liveFrequencyRejectCount != UINT32_MAX)
  1929. {
  1930. axisObject->liveFrequencyRejectCount++;
  1931. }
  1932. }
  1933. axisObject->liveTargetFrequencyHz = segment->targetFrequency;
  1934. if (axisObject->backlashBypassOnce != 0U)
  1935. {
  1936. /* The internal block has just completed; start the user segment. */
  1937. axisObject->backlashBypassOnce = 0U;
  1938. }
  1939. else if ((axisObject->lastUserDirectionValid != 0U)
  1940. && (axisObject->lastUserDirectionPositive != positive))
  1941. {
  1942. backlashPulses = (positive != 0U)
  1943. ? job->positiveBacklashPulses
  1944. : job->negativeBacklashPulses;
  1945. runBacklash = (backlashPulses != 0U) ? 1U : 0U;
  1946. }
  1947. (void)memset(&profileRequest, 0, sizeof(profileRequest));
  1948. profileRequest.targetFrequencyHz = segment->targetFrequency;
  1949. profileRequest.maxFrequencyHz = job->s2.maximumSpeed;
  1950. profileRequest.curveMode = job->s2.curveMode;
  1951. outputPulses = pulses;
  1952. if (runBacklash != 0U)
  1953. {
  1954. outputPulses = backlashPulses;
  1955. profileRequest.startFrequencyHz =
  1956. (job->s2.gapAccelerationMs == 0U)
  1957. ? segment->targetFrequency
  1958. : 0UL;
  1959. profileRequest.stopFrequencyHz = 0UL;
  1960. gapSlopeHzPerMs =
  1961. (job->s2.gapAccelerationMs != 0U)
  1962. ? segment->targetFrequency / job->s2.gapAccelerationMs
  1963. : 0UL;
  1964. if ((job->s2.gapAccelerationMs != 0U)
  1965. && (gapSlopeHzPerMs == 0UL))
  1966. {
  1967. gapSlopeHzPerMs = 1UL;
  1968. }
  1969. profileRequest.accelSlopeHzPerMs = gapSlopeHzPerMs;
  1970. profileRequest.decelSlopeHzPerMs = gapSlopeHzPerMs;
  1971. }
  1972. else
  1973. {
  1974. profileRequest.startFrequencyHz = job->s2.startSpeed;
  1975. profileRequest.stopFrequencyHz = job->s2.stopSpeed;
  1976. profileRequest.accelSlopeHzPerMs =
  1977. (job->s2.accelerationMs != 0U)
  1978. ? job->s2.defaultSpeed / job->s2.accelerationMs
  1979. : 0UL;
  1980. profileRequest.decelSlopeHzPerMs =
  1981. (job->s2.decelerationMs != 0U)
  1982. ? job->s2.defaultSpeed / job->s2.decelerationMs
  1983. : 0UL;
  1984. }
  1985. result = PlsrProfileStart(&axisObject->profile,
  1986. &profileRequest,
  1987. outputPulses,
  1988. (job->s2.refreshCode == 2U) ? 10000U : 1000U);
  1989. if (result != PLSR_RESULT_OK)
  1990. {
  1991. return result;
  1992. }
  1993. params.frequencyHz = profileRequest.startFrequencyHz;
  1994. params.targetPulses = outputPulses;
  1995. params.outputMode = (PLSR_OUTPUT_MODE)job->outputMode;
  1996. params.directionPoint = job->directionPoint;
  1997. params.directionPositive = positive;
  1998. params.directionNegativeLogic = job->directionNegativeLogic;
  1999. params.directionDelayMs = job->s2.directionDelayMs;
  2000. result = PlsrHwStartPulse(axis, &params);
  2001. if (result != PLSR_RESULT_OK)
  2002. {
  2003. PlsrSetProfileActive(axisObject, 0U);
  2004. axisObject->profileWasAccel = 0U;
  2005. return result;
  2006. }
  2007. axisObject->directionPositive = positive;
  2008. axisObject->segmentAccountedPulses = 0;
  2009. axisObject->segmentAccountingActive = 1U;
  2010. axisObject->backlashActive = runBacklash;
  2011. if (runBacklash == 0U)
  2012. {
  2013. axisObject->equivalentCommandRemainder = nextEquivalentRemainder;
  2014. axisObject->lastUserDirectionValid = 1U;
  2015. axisObject->lastUserDirectionPositive = positive;
  2016. }
  2017. PlsrSetProfileActive(axisObject, 1U);
  2018. axisObject->profileWasAccel =
  2019. (axisObject->profile.phase == PLSR_PROFILE_PHASE_ACCEL) ? 1U : 0U;
  2020. PlsrPublishAxis(axis);
  2021. if (axisObject->profileWasAccel == 0U)
  2022. {
  2023. /* start==target or zero acceleration enters CRUISE directly. The
  2024. * axis state must not remain stuck in ACCEL for the whole segment. */
  2025. (void)PlsrPostEvent(axis, PLSR_EVENT_ACCEL_COMPLETE);
  2026. }
  2027. return PLSR_RESULT_OK;
  2028. }
  2029. /* 停止当前段的硬件输出与速度曲线。 */
  2030. static void PlsrStopSegmentHardware(uint8_t axis, PLSR_AXIS *axisObject)
  2031. {
  2032. PlsrAccountHardwarePulses(axis, axisObject);
  2033. PlsrSetProfileActive(axisObject, 0U);
  2034. axisObject->profileWasAccel = 0U;
  2035. (void)PlsrHwStopPulse(axis);
  2036. PlsrAccountHardwarePulses(axis, axisObject);
  2037. axisObject->segmentAccountingActive = 0U;
  2038. PlsrPublishRuntime(axis);
  2039. }
  2040. /* 应用路径执行器的动作:段间推进、进入等待、结束、让出、错误。 */
  2041. static void PlsrApplyPathAction(uint8_t axis, PLSR_PATH_ACTION action)
  2042. {
  2043. PLSR_AXIS *axisObject = &PlsrAxes[axis];
  2044. switch (action)
  2045. {
  2046. case PLSR_PATH_ACTION_NEXT_SEGMENT:
  2047. /* SEGMENT_COMPLETE 表示上一段输出边界已经结束。统一收口旧段
  2048. * profile/HAL 后再启动新段;真实 IRQ 与测试注入事件均一致。 */
  2049. PlsrStopSegmentHardware(axis, axisObject);
  2050. if (axisObject->state == PLSR_STATE_WAIT)
  2051. {
  2052. (void)PlsrStateTransition(axis,
  2053. PLSR_STATE_ACCEL,
  2054. PLSR_TRANSITION_WAIT_COMPLETE);
  2055. }
  2056. else if ((axisObject->state == PLSR_STATE_ACCEL)
  2057. || (axisObject->state == PLSR_STATE_RUN)
  2058. || (axisObject->state == PLSR_STATE_DECEL))
  2059. {
  2060. (void)PlsrStateTransition(axis,
  2061. PLSR_STATE_ACCEL,
  2062. PLSR_TRANSITION_START);
  2063. }
  2064. /* 进入新段:重新启动硬件输出与速度曲线。 */
  2065. if (axisObject->state == PLSR_STATE_ACCEL)
  2066. {
  2067. PLSR_RESULT startResult =
  2068. PlsrStartSegmentHardware(axis, axisObject);
  2069. if ((startResult == PLSR_RESULT_LIMIT_POSITIVE)
  2070. || (startResult == PLSR_RESULT_LIMIT_NEGATIVE))
  2071. {
  2072. axisObject->error =
  2073. (startResult == PLSR_RESULT_LIMIT_POSITIVE)
  2074. ? PLSR_ERROR_LIMIT_POSITIVE
  2075. : PLSR_ERROR_LIMIT_NEGATIVE;
  2076. axisObject->compatibleErrorCode =
  2077. (startResult == PLSR_RESULT_LIMIT_POSITIVE) ? 5U : 6U;
  2078. PlsrSetStopReason(
  2079. axisObject,
  2080. (startResult == PLSR_RESULT_LIMIT_POSITIVE)
  2081. ? PLSR_STOP_REASON_LIMIT_POSITIVE
  2082. : PLSR_STOP_REASON_LIMIT_NEGATIVE);
  2083. (void)PlsrStateTransition(axis,
  2084. PLSR_STATE_STOPPED,
  2085. PLSR_TRANSITION_STOP);
  2086. }
  2087. else if (startResult != PLSR_RESULT_OK)
  2088. {
  2089. axisObject->error = PLSR_ERROR_TIMER_FAULT;
  2090. PlsrSetStopReason(axisObject, PLSR_STOP_REASON_FAULT);
  2091. axisObject->done = 0U;
  2092. (void)PlsrStateTransition(axis,
  2093. PLSR_STATE_ERROR,
  2094. PLSR_TRANSITION_FAULT);
  2095. }
  2096. }
  2097. break;
  2098. case PLSR_PATH_ACTION_ENTER_WAIT:
  2099. if ((axisObject->state == PLSR_STATE_ACCEL)
  2100. || (axisObject->state == PLSR_STATE_RUN))
  2101. {
  2102. (void)PlsrStateTransition(axis,
  2103. PLSR_STATE_WAIT,
  2104. PLSR_TRANSITION_WAIT_BEGIN);
  2105. }
  2106. break;
  2107. case PLSR_PATH_ACTION_JOB_COMPLETE:
  2108. if (PlsrStateIsBusy(axisObject->state) != 0U)
  2109. {
  2110. axisObject->stopReason = PLSR_STOP_REASON_NORMAL_COMPLETE;
  2111. (void)PlsrStateTransition(axis,
  2112. PLSR_STATE_COMPLETED,
  2113. PLSR_TRANSITION_JOB_COMPLETE);
  2114. }
  2115. break;
  2116. case PLSR_PATH_ACTION_YIELD:
  2117. /* 预算耗尽:本轮不再推进,下个 tick 由 PlsrPathTick 恢复。 */
  2118. break;
  2119. case PLSR_PATH_ACTION_ERROR:
  2120. axisObject->error = PLSR_ERROR_INTERNAL;
  2121. PlsrSetStopReason(axisObject, PLSR_STOP_REASON_FAULT);
  2122. axisObject->done = 0U;
  2123. (void)PlsrStateTransition(axis,
  2124. PLSR_STATE_ERROR,
  2125. PLSR_TRANSITION_FAULT);
  2126. break;
  2127. default:
  2128. break;
  2129. }
  2130. }
  2131. static void PlsrProcessNormalEvents(uint8_t axis, uint32_t events)
  2132. {
  2133. PLSR_AXIS *axisObject = &PlsrAxes[axis];
  2134. if (((events & PLSR_EVENT_STOP_IMMEDIATE_DONE) != 0UL)
  2135. && (axisObject->immediateStopPending != 0U))
  2136. {
  2137. (void)PlsrStateTransition(axis,
  2138. PLSR_STATE_STOPPED,
  2139. PLSR_TRANSITION_STOP);
  2140. return;
  2141. }
  2142. if (((events & PLSR_EVENT_ACCEL_COMPLETE) != 0UL)
  2143. && (axisObject->state == PLSR_STATE_ACCEL)
  2144. && (axisObject->immediateStopPending == 0U))
  2145. {
  2146. (void)PlsrStateTransition(axis,
  2147. PLSR_STATE_RUN,
  2148. PLSR_TRANSITION_ACCEL_COMPLETE);
  2149. }
  2150. if (((events & PLSR_EVENT_DECEL_COMPLETE) != 0UL)
  2151. && (axisObject->state == PLSR_STATE_DECEL))
  2152. {
  2153. if (axisObject->pendingTerminal == PLSR_STATE_PAUSED)
  2154. {
  2155. (void)PlsrStateTransition(axis,
  2156. PLSR_STATE_PAUSED,
  2157. PLSR_TRANSITION_DECEL_COMPLETE);
  2158. }
  2159. else if (axisObject->pendingTerminal == PLSR_STATE_STOPPED)
  2160. {
  2161. (void)PlsrStateTransition(axis,
  2162. PLSR_STATE_STOPPED,
  2163. PLSR_TRANSITION_DECEL_COMPLETE);
  2164. }
  2165. else
  2166. {
  2167. (void)PlsrStateTransition(axis,
  2168. PLSR_STATE_RUN,
  2169. PLSR_TRANSITION_DECEL_COMPLETE);
  2170. }
  2171. }
  2172. if (((events & PLSR_EVENT_WAIT_BEGIN) != 0UL)
  2173. && ((axisObject->state == PLSR_STATE_ACCEL)
  2174. || (axisObject->state == PLSR_STATE_RUN)))
  2175. {
  2176. (void)PlsrStateTransition(axis,
  2177. PLSR_STATE_WAIT,
  2178. PLSR_TRANSITION_WAIT_BEGIN);
  2179. }
  2180. if (((events & PLSR_EVENT_WAIT_COMPLETE) != 0UL)
  2181. && (axisObject->state == PLSR_STATE_WAIT))
  2182. {
  2183. (void)PlsrStateTransition(axis,
  2184. PLSR_STATE_ACCEL,
  2185. PLSR_TRANSITION_WAIT_COMPLETE);
  2186. }
  2187. if (((events & PLSR_EVENT_SEGMENT_COMPLETE) != 0UL)
  2188. && ((axisObject->state == PLSR_STATE_ACCEL)
  2189. || (axisObject->state == PLSR_STATE_RUN)
  2190. || (axisObject->state == PLSR_STATE_DECEL))
  2191. && (axisObject->pendingTerminal == PLSR_STATE_UNINITIALIZED)
  2192. && (axisObject->immediateStopPending == 0U))
  2193. {
  2194. PLSR_PATH_ACTION action;
  2195. if (axisObject->backlashActive != 0U)
  2196. {
  2197. PLSR_RESULT startResult;
  2198. /* Internal compensation completion is not a user segment
  2199. * completion and therefore must not publish I6000..I6399 or
  2200. * advance the path. */
  2201. PlsrStopSegmentHardware(axis, axisObject);
  2202. axisObject->backlashActive = 0U;
  2203. axisObject->backlashBypassOnce = 1U;
  2204. (void)PlsrStateTransition(axis,
  2205. PLSR_STATE_ACCEL,
  2206. PLSR_TRANSITION_START);
  2207. startResult = PlsrStartSegmentHardware(axis, axisObject);
  2208. if ((startResult == PLSR_RESULT_LIMIT_POSITIVE)
  2209. || (startResult == PLSR_RESULT_LIMIT_NEGATIVE))
  2210. {
  2211. axisObject->error =
  2212. (startResult == PLSR_RESULT_LIMIT_POSITIVE)
  2213. ? PLSR_ERROR_LIMIT_POSITIVE
  2214. : PLSR_ERROR_LIMIT_NEGATIVE;
  2215. axisObject->compatibleErrorCode =
  2216. (startResult == PLSR_RESULT_LIMIT_POSITIVE) ? 5U : 6U;
  2217. PlsrSetStopReason(
  2218. axisObject,
  2219. (startResult == PLSR_RESULT_LIMIT_POSITIVE)
  2220. ? PLSR_STOP_REASON_LIMIT_POSITIVE
  2221. : PLSR_STOP_REASON_LIMIT_NEGATIVE);
  2222. (void)PlsrStateTransition(axis,
  2223. PLSR_STATE_STOPPED,
  2224. PLSR_TRANSITION_STOP);
  2225. }
  2226. else if (startResult != PLSR_RESULT_OK)
  2227. {
  2228. axisObject->error = PLSR_ERROR_TIMER_FAULT;
  2229. PlsrSetStopReason(axisObject, PLSR_STOP_REASON_FAULT);
  2230. axisObject->done = 0U;
  2231. (void)PlsrStateTransition(axis,
  2232. PLSR_STATE_ERROR,
  2233. PLSR_TRANSITION_FAULT);
  2234. }
  2235. return;
  2236. }
  2237. PlsrPublishSegmentEvent(axis,
  2238. axisObject,
  2239. PLSR_STOP_REASON_NORMAL_COMPLETE);
  2240. action = PlsrPathOnSegmentDone(&axisObject->path,
  2241. &axisObject->job,
  2242. axisObject->logicalPosition);
  2243. PlsrApplyPathAction(axis, action);
  2244. }
  2245. if (((events & PLSR_EVENT_JOB_COMPLETE) != 0UL)
  2246. && (PlsrStateIsBusy(axisObject->state) != 0U)
  2247. && (axisObject->pendingTerminal == PLSR_STATE_UNINITIALIZED)
  2248. && (axisObject->immediateStopPending == 0U))
  2249. {
  2250. axisObject->stopReason = PLSR_STOP_REASON_NORMAL_COMPLETE;
  2251. (void)PlsrStateTransition(axis,
  2252. PLSR_STATE_COMPLETED,
  2253. PLSR_TRANSITION_JOB_COMPLETE);
  2254. }
  2255. }
  2256. PLSR_RESULT PlsrInit(void)
  2257. {
  2258. int32_t restoredPosition;
  2259. uint8_t restoredPositionValid;
  2260. uint8_t restoredLastBusy;
  2261. uint8_t axis;
  2262. (void)memset(PlsrAxes, 0, sizeof(PlsrAxes));
  2263. (void)memset(PlsrCommandQueue, 0, sizeof(PlsrCommandQueue));
  2264. PlsrNextTicket = 0UL;
  2265. PlsrMaxProcessCycles = 0UL;
  2266. PlsrMaxProcessResponseCycles = 0UL;
  2267. (void)memset((void *)PlsrMaxProcessStageCycles,
  2268. 0,
  2269. sizeof(PlsrMaxProcessStageCycles));
  2270. PlsrDeferHsdCheckpoint = 0U;
  2271. PlsrHsdCheckpointPending = 0U;
  2272. PlsrResourceInit();
  2273. (void)PlsrHwInit();
  2274. PlsrControlTickHook = NULL;
  2275. PlsrInitialized = 1U;
  2276. restoredPositionValid = PlcDeviceGetRestoredHsdPositionValid();
  2277. restoredLastBusy = PlcDeviceGetRestoredHsdLastBusy();
  2278. for (axis = 0U; axis < PLSR_AXIS_COUNT; axis++)
  2279. {
  2280. PlsrAxes[axis].state = PLSR_STATE_UNINITIALIZED;
  2281. PlsrAxes[axis].pendingTerminal = PLSR_STATE_UNINITIALIZED;
  2282. PlsrAxes[axis].lease.directionPoint = PLSR_DIRECTION_POINT_NONE;
  2283. PlsrLoadAxisEquivalentConfig(axis, &PlsrAxes[axis].equivalent);
  2284. if (PlcDeviceReadHsdDword(
  2285. (uint16_t)(axis * PLSR_HSD_RUNTIME_AXIS_COUNT),
  2286. &restoredPosition) == PLC_DEVICE_OK)
  2287. {
  2288. PlsrAxes[axis].logicalPosition = restoredPosition;
  2289. }
  2290. /* 只有上次正常停机且保存了位置有效标志,才允许绝对定位;
  2291. * 运动中掉电(lastBusy=1)时位置不可信。 */
  2292. if ((restoredPositionValid != 0U) && (restoredLastBusy == 0U))
  2293. {
  2294. PlsrAxes[axis].positionValid = 1U;
  2295. }
  2296. if (PlsrStateTransition(axis,
  2297. PLSR_STATE_IDLE,
  2298. PLSR_TRANSITION_INITIALIZED)
  2299. != PLSR_RESULT_OK)
  2300. {
  2301. return PLSR_RESULT_INTERNAL_ERROR;
  2302. }
  2303. }
  2304. return PLSR_RESULT_OK;
  2305. }
  2306. static void PlsrStepProfileAxis(uint8_t axis)
  2307. {
  2308. PLSR_AXIS *axisObject = &PlsrAxes[axis];
  2309. PLSR_RESULT liveResult;
  2310. int32_t liveRaw;
  2311. uint32_t frequencyHz;
  2312. uint32_t liveFrequencyHz;
  2313. uint32_t outputFrequencyHz;
  2314. uint64_t hardwarePulses;
  2315. uint64_t remainingPulses;
  2316. uint8_t profileDone;
  2317. uint8_t liveClamped;
  2318. uint8_t wasAccel;
  2319. if ((axisObject->profileActive == 0U)
  2320. || (PlsrHwGetState(axis) == PLSR_HW_STATE_DIR_SETTLING))
  2321. {
  2322. return;
  2323. }
  2324. /* Only the current segment frequency remains live after COMMIT. Poll the
  2325. * raw dword every selected control tick; conversion/divider validation is
  2326. * performed only when the raw value actually changes. */
  2327. if ((axisObject->backlashActive == 0U)
  2328. && (axisObject->jobValid != 0U))
  2329. {
  2330. liveResult = PlsrReadLiveFrequencyRaw(
  2331. &axisObject->job,
  2332. axisObject->path.currentSegment,
  2333. &liveRaw);
  2334. if (liveResult != PLSR_RESULT_OK)
  2335. {
  2336. if (axisObject->lastLiveFrequencyResult != liveResult)
  2337. {
  2338. if (axisObject->liveFrequencyRejectCount != UINT32_MAX)
  2339. {
  2340. axisObject->liveFrequencyRejectCount++;
  2341. }
  2342. }
  2343. axisObject->lastLiveFrequencyResult = liveResult;
  2344. }
  2345. else if (liveRaw != axisObject->liveFrequencyRaw)
  2346. {
  2347. axisObject->liveFrequencyRaw = liveRaw;
  2348. liveResult = PlsrResolveLiveFrequency(
  2349. &axisObject->job,
  2350. axisObject->path.currentSegment,
  2351. &liveFrequencyHz,
  2352. &liveClamped);
  2353. if (liveResult == PLSR_RESULT_OK)
  2354. {
  2355. liveResult = PlsrProfileRetarget(&axisObject->profile,
  2356. liveFrequencyHz);
  2357. }
  2358. if (liveResult == PLSR_RESULT_OK)
  2359. {
  2360. axisObject->liveTargetFrequencyHz = liveFrequencyHz;
  2361. axisObject->lastLiveFrequencyResult = PLSR_RESULT_OK;
  2362. if (liveClamped != 0U)
  2363. {
  2364. axisObject->runtimeSpeedClamped = 1U;
  2365. }
  2366. }
  2367. else
  2368. {
  2369. axisObject->lastLiveFrequencyResult = liveResult;
  2370. if (axisObject->liveFrequencyRejectCount != UINT32_MAX)
  2371. {
  2372. axisObject->liveFrequencyRejectCount++;
  2373. }
  2374. }
  2375. }
  2376. else
  2377. {
  2378. axisObject->lastLiveFrequencyResult = PLSR_RESULT_OK;
  2379. }
  2380. }
  2381. hardwarePulses = (uint64_t)PlsrHwGetEmittedPulses(axis);
  2382. PlsrProfileSyncPulses(&axisObject->profile, hardwarePulses);
  2383. wasAccel = axisObject->profileWasAccel;
  2384. (void)PlsrProfileStep(&axisObject->profile,
  2385. &frequencyHz,
  2386. &profileDone);
  2387. outputFrequencyHz = frequencyHz;
  2388. if ((PlsrHwGetState(axis) == PLSR_HW_STATE_RUNNING)
  2389. && (axisObject->profile.phase != PLSR_PROFILE_PHASE_ACCEL)
  2390. && ((axisObject->profile.phase != PLSR_PROFILE_PHASE_DECEL)
  2391. || (axisObject->profile.decelTargetHz
  2392. == axisObject->profile.stopFrequencyHz))
  2393. && (axisObject->pendingTerminal == PLSR_STATE_UNINITIALIZED)
  2394. && ((uint64_t)axisObject->profile.totalPulses
  2395. > hardwarePulses + 1UL))
  2396. {
  2397. remainingPulses = (uint64_t)axisObject->profile.totalPulses
  2398. - hardwarePulses - 1UL;
  2399. outputFrequencyHz =
  2400. PlsrProfileGetBrakingOutputFrequency(&axisObject->profile,
  2401. remainingPulses);
  2402. }
  2403. if ((PlsrHwGetState(axis) == PLSR_HW_STATE_PWM_PENDING)
  2404. && (axisObject->profile.phase == PLSR_PROFILE_PHASE_ACCEL))
  2405. {
  2406. outputFrequencyHz =
  2407. PlsrProfileGetInitialOutputFrequency(&axisObject->profile);
  2408. }
  2409. if ((profileDone == 0U) || (outputFrequencyHz != 0UL))
  2410. {
  2411. (void)PlsrHwSetFrequency(axis, outputFrequencyHz);
  2412. }
  2413. if ((profileDone != 0U)
  2414. && (axisObject->pendingTerminal != PLSR_STATE_UNINITIALIZED))
  2415. {
  2416. (void)PlsrHwSetFrequency(axis, 0UL);
  2417. PlsrSetProfileActive(axisObject, 0U);
  2418. (void)PlsrPostEvent(axis, PLSR_EVENT_DECEL_COMPLETE);
  2419. }
  2420. axisObject->profileWasAccel =
  2421. (axisObject->profile.phase == PLSR_PROFILE_PHASE_ACCEL) ? 1U : 0U;
  2422. if ((wasAccel != 0U)
  2423. && (axisObject->profileWasAccel == 0U)
  2424. && (axisObject->state == PLSR_STATE_ACCEL))
  2425. {
  2426. (void)PlsrPostEvent(axis, PLSR_EVENT_ACCEL_COMPLETE);
  2427. }
  2428. }
  2429. void PlsrControlTick100us(void)
  2430. {
  2431. void (*hook)(void);
  2432. uint8_t axis;
  2433. if (PlsrInitialized == 0U)
  2434. {
  2435. return;
  2436. }
  2437. hook = PlsrControlTickHook;
  2438. if (hook != NULL)
  2439. {
  2440. hook();
  2441. }
  2442. for (axis = 0U; axis < PLSR_AXIS_COUNT; axis++)
  2443. {
  2444. if (PlsrAxes[axis].job.s2.refreshCode == 2U)
  2445. {
  2446. PlsrStepProfileAxis(axis);
  2447. }
  2448. }
  2449. }
  2450. void PlsrProcess(void)
  2451. {
  2452. PLSR_COMMAND_SLOT slot;
  2453. uint32_t events;
  2454. #ifndef PLSR_HOST_TEST
  2455. uint32_t started;
  2456. uint64_t startedIsrCycles;
  2457. uint32_t stageStarted;
  2458. uint64_t stageStartedIsrCycles;
  2459. #endif
  2460. uint8_t processedCommands = 0U;
  2461. uint8_t criticalAxes = 0U;
  2462. uint8_t axis;
  2463. if (PlsrInitialized == 0U)
  2464. {
  2465. return;
  2466. }
  2467. #ifndef PLSR_HOST_TEST
  2468. PlsrHwGetCycleSnapshot(&started, &startedIsrCycles);
  2469. stageStarted = started;
  2470. stageStartedIsrCycles = startedIsrCycles;
  2471. #endif
  2472. PlsrDeferHsdCheckpoint = 1U;
  2473. /* 先合并 ISR 已完成的实际脉冲,确保段完成、STOP或新命令不会在
  2474. * HAL 计数清零前丢失最后一批位置增量。 */
  2475. for (axis = 0U; axis < PLSR_AXIS_COUNT; axis++)
  2476. {
  2477. PlsrAccountHardwarePulses(axis, &PlsrAxes[axis]);
  2478. PlsrMonitorAxisProtection(axis);
  2479. }
  2480. #ifndef PLSR_HOST_TEST
  2481. {
  2482. uint32_t finished;
  2483. uint64_t finishedIsrCycles;
  2484. PlsrHwGetCycleSnapshot(&finished, &finishedIsrCycles);
  2485. PlsrUpdateProcessStageMax(PLSR_PROCESS_STAGE_ACCOUNT_PROTECTION,
  2486. stageStarted,
  2487. stageStartedIsrCycles,
  2488. finished,
  2489. finishedIsrCycles);
  2490. stageStarted = finished;
  2491. stageStartedIsrCycles = finishedIsrCycles;
  2492. }
  2493. #endif
  2494. for (axis = 0U; axis < PLSR_AXIS_COUNT; axis++)
  2495. {
  2496. events = PlsrTakeEvents(axis, PLSR_EVENT_CRITICAL_MASK);
  2497. if (events != 0UL)
  2498. {
  2499. criticalAxes |= (uint8_t)(1U << axis);
  2500. PlsrProcessCriticalEvents(axis, events);
  2501. }
  2502. }
  2503. #ifndef PLSR_HOST_TEST
  2504. {
  2505. uint32_t finished;
  2506. uint64_t finishedIsrCycles;
  2507. PlsrHwGetCycleSnapshot(&finished, &finishedIsrCycles);
  2508. PlsrUpdateProcessStageMax(PLSR_PROCESS_STAGE_CRITICAL_EVENTS,
  2509. stageStarted,
  2510. stageStartedIsrCycles,
  2511. finished,
  2512. finishedIsrCycles);
  2513. stageStarted = finished;
  2514. stageStartedIsrCycles = finishedIsrCycles;
  2515. }
  2516. #endif
  2517. /* Apply related multi-axis DIR changes after all commands and segment
  2518. * events, keeping cross-port GPIO writes in one short commit window. */
  2519. PlsrHwBeginDirectionBatch();
  2520. while ((processedCommands < PLSR_COMMAND_QUEUE_DEPTH)
  2521. && (PlsrPopHighestPriorityCommand(&slot) != 0U))
  2522. {
  2523. if ((slot.command.opcode == PLSR_CMD_RESET_ERROR)
  2524. && ((criticalAxes & (uint8_t)(1U << slot.command.axis)) != 0U))
  2525. {
  2526. PLSR_AXIS *axisObject = &PlsrAxes[slot.command.axis];
  2527. axisObject->lastCommandSequence = slot.command.sequence;
  2528. axisObject->lastCommandResult = PLSR_RESULT_BUSY;
  2529. axisObject->hasLastCommand = 1U;
  2530. PlsrPublishAxis(slot.command.axis);
  2531. }
  2532. else
  2533. {
  2534. (void)PlsrExecuteCommand(&slot);
  2535. }
  2536. processedCommands++;
  2537. }
  2538. #ifndef PLSR_HOST_TEST
  2539. {
  2540. uint32_t finished;
  2541. uint64_t finishedIsrCycles;
  2542. PlsrHwGetCycleSnapshot(&finished, &finishedIsrCycles);
  2543. PlsrUpdateProcessStageMax(PLSR_PROCESS_STAGE_COMMANDS,
  2544. stageStarted,
  2545. stageStartedIsrCycles,
  2546. finished,
  2547. finishedIsrCycles);
  2548. stageStarted = finished;
  2549. stageStartedIsrCycles = finishedIsrCycles;
  2550. }
  2551. #endif
  2552. for (axis = 0U; axis < PLSR_AXIS_COUNT; axis++)
  2553. {
  2554. events = PlsrTakeEvents(axis,
  2555. PLSR_EVENT_ALL_MASK
  2556. & ~PLSR_EVENT_CRITICAL_MASK);
  2557. if (events != 0UL)
  2558. {
  2559. PlsrProcessNormalEvents(axis, events);
  2560. }
  2561. }
  2562. PlsrHwEndDirectionBatch();
  2563. #ifndef PLSR_HOST_TEST
  2564. {
  2565. uint32_t finished;
  2566. uint64_t finishedIsrCycles;
  2567. PlsrHwGetCycleSnapshot(&finished, &finishedIsrCycles);
  2568. PlsrUpdateProcessStageMax(PLSR_PROCESS_STAGE_NORMAL_EVENTS,
  2569. stageStarted,
  2570. stageStartedIsrCycles,
  2571. finished,
  2572. finishedIsrCycles);
  2573. stageStarted = finished;
  2574. stageStartedIsrCycles = finishedIsrCycles;
  2575. }
  2576. #endif
  2577. /* 1ms tick:路径执行器推进(WAIT/ACT 计时、信号/EXT 轮询、跳转链)
  2578. * + 速度曲线推进(P2) + HAL 状态机(DIR 延时)。 */
  2579. for (axis = 0U; axis < PLSR_AXIS_COUNT; axis++)
  2580. {
  2581. PLSR_AXIS *axisObject = &PlsrAxes[axis];
  2582. PLSR_PATH_ACTION action;
  2583. PlsrHwTick(axis);
  2584. /* Pulses were merged at the beginning of this pass. Merging again
  2585. * here republishes HSD/SD runtime data for the few pulses emitted
  2586. * while PlsrProcess itself was running and nearly doubles the
  2587. * four-axis cost. Those pulses are safely merged at the beginning
  2588. * of the next pass or by the terminal event path. */
  2589. /* 首次 AB 内部预热周期不属于用户运动,速度曲线也必须冻结;
  2590. * 否则低速起步时会在隐藏周期内提前爬升十余个刷新步。 */
  2591. if (PlsrHwIsAbStartupPriming(axis) != 0U)
  2592. {
  2593. continue;
  2594. }
  2595. if (PlsrStateIsBusy(axisObject->state) == 0U)
  2596. {
  2597. continue;
  2598. }
  2599. action = (axisObject->backlashActive != 0U)
  2600. ? PLSR_PATH_ACTION_NONE
  2601. : PlsrPathTick(&axisObject->path,
  2602. &axisObject->job,
  2603. axisObject->logicalPosition);
  2604. if (action != PLSR_PATH_ACTION_NONE)
  2605. {
  2606. PlsrApplyPathAction(axis, action);
  2607. }
  2608. if (axisObject->job.s2.refreshCode != 2U)
  2609. {
  2610. PlsrStepProfileAxis(axis);
  2611. }
  2612. }
  2613. #ifndef PLSR_HOST_TEST
  2614. {
  2615. uint32_t tickFinished;
  2616. uint32_t finished;
  2617. uint32_t responseCycles;
  2618. uint32_t processCycles;
  2619. uint64_t tickFinishedIsrCycles;
  2620. uint64_t finishedIsrCycles;
  2621. uint64_t preemptedCycles;
  2622. PlsrHwGetCycleSnapshot(&tickFinished, &tickFinishedIsrCycles);
  2623. PlsrUpdateProcessStageMax(PLSR_PROCESS_STAGE_TICK_PATH_PROFILE,
  2624. stageStarted,
  2625. stageStartedIsrCycles,
  2626. tickFinished,
  2627. tickFinishedIsrCycles);
  2628. PlsrDeferHsdCheckpoint = 0U;
  2629. PlsrFlushHsdCheckpoint();
  2630. PlsrHwGetCycleSnapshot(&finished, &finishedIsrCycles);
  2631. PlsrUpdateProcessStageMax(PLSR_PROCESS_STAGE_HSD_CHECKPOINT,
  2632. tickFinished,
  2633. tickFinishedIsrCycles,
  2634. finished,
  2635. finishedIsrCycles);
  2636. responseCycles = finished - started;
  2637. preemptedCycles = finishedIsrCycles - startedIsrCycles;
  2638. processCycles = (preemptedCycles < (uint64_t)responseCycles)
  2639. ? responseCycles - (uint32_t)preemptedCycles
  2640. : 0UL;
  2641. if (processCycles > PlsrMaxProcessCycles)
  2642. {
  2643. PlsrMaxProcessCycles = processCycles;
  2644. }
  2645. if (responseCycles > PlsrMaxProcessResponseCycles)
  2646. {
  2647. PlsrMaxProcessResponseCycles = responseCycles;
  2648. }
  2649. }
  2650. #else
  2651. PlsrDeferHsdCheckpoint = 0U;
  2652. PlsrFlushHsdCheckpoint();
  2653. #endif
  2654. }
  2655. uint32_t PlsrGetMaxProcessCycles(void)
  2656. {
  2657. return PlsrMaxProcessCycles;
  2658. }
  2659. uint32_t PlsrGetMaxProcessResponseCycles(void)
  2660. {
  2661. return PlsrMaxProcessResponseCycles;
  2662. }
  2663. uint32_t PlsrGetMaxProcessStageCycles(uint8_t stage)
  2664. {
  2665. if (stage >= PLSR_PROCESS_STAGE_COUNT)
  2666. {
  2667. return 0UL;
  2668. }
  2669. return PlsrMaxProcessStageCycles[stage];
  2670. }
  2671. void PlsrTask(void *argument)
  2672. {
  2673. (void)argument;
  2674. #ifdef PLSR_HOST_TEST
  2675. PlsrProcess();
  2676. #else
  2677. while (1)
  2678. {
  2679. PlsrProcess();
  2680. OSTimeDly(1U);
  2681. }
  2682. #endif
  2683. }
  2684. PLSR_RESULT PlsrGetStatus(uint8_t axis, PLSR_STATUS *status)
  2685. {
  2686. PLSR_AXIS *axisObject;
  2687. uint32_t interruptState;
  2688. if (axis >= PLSR_AXIS_COUNT)
  2689. {
  2690. return PLSR_RESULT_INVALID_AXIS;
  2691. }
  2692. if (status == NULL)
  2693. {
  2694. return PLSR_RESULT_INVALID_ARGUMENT;
  2695. }
  2696. interruptState = PlsrCoreEnterCritical();
  2697. axisObject = &PlsrAxes[axis];
  2698. status->state = axisObject->state;
  2699. status->outputMode = axisObject->outputMode;
  2700. status->error = axisObject->error;
  2701. status->stopReason = axisObject->stopReason;
  2702. status->lastCommandResult = axisObject->lastCommandResult;
  2703. status->lastCommandSequence = axisObject->lastCommandSequence;
  2704. status->illegalTransitionCount = axisObject->illegalTransitionCount;
  2705. status->pendingEvents = axisObject->pendingEvents;
  2706. status->logicalPosition = axisObject->logicalPosition;
  2707. status->taskPulses = axisObject->taskPulses;
  2708. status->totalPulses = axisObject->totalPulses;
  2709. status->physicalPulses = axisObject->physicalPulses;
  2710. status->busy = PlsrStateIsBusy(axisObject->state);
  2711. status->pulseActive = PlsrStateIsPulseActive(axisObject->state);
  2712. status->done = axisObject->done;
  2713. status->wait = (axisObject->state == PLSR_STATE_WAIT) ? 1U : 0U;
  2714. status->directionPositive = axisObject->directionPositive;
  2715. status->highResourceMask = axisObject->lease.highMask;
  2716. status->hardwareCounter = PlsrHwUsesHardwareCounter(axis);
  2717. status->directionPoint = (axisObject->lease.valid != 0U)
  2718. ? axisObject->lease.directionPoint
  2719. : PLSR_DIRECTION_POINT_NONE;
  2720. status->positionValid = axisObject->positionValid;
  2721. status->jobValid = axisObject->jobValid;
  2722. status->positionOverflow = axisObject->positionOverflow;
  2723. status->positiveLimitActive = axisObject->positiveLimitActive;
  2724. status->negativeLimitActive = axisObject->negativeLimitActive;
  2725. status->emergencyLatched = axisObject->emergencyLatched;
  2726. status->backlashActive = axisObject->backlashActive;
  2727. status->s2Set = (axisObject->jobValid != 0U) ? axisObject->job.s2Set : 0U;
  2728. status->speedClamped = (axisObject->jobValid != 0U)
  2729. ? (uint8_t)((axisObject->job.speedClamped != 0U)
  2730. || (axisObject->runtimeSpeedClamped
  2731. != 0U))
  2732. : 0U;
  2733. status->segmentCount = (axisObject->jobValid != 0U)
  2734. ? axisObject->job.segmentCount
  2735. : 0U;
  2736. status->startSegment = (axisObject->jobValid != 0U)
  2737. ? axisObject->job.startSegment
  2738. : 0U;
  2739. status->currentSegment = (axisObject->jobValid != 0U)
  2740. ? PlsrPathGetCurrentSegment(
  2741. &axisObject->path)
  2742. : 0U;
  2743. status->currentFrequencyHz = PlsrHwGetCurrentFrequencyHz(axis);
  2744. status->targetFrequencyHz = (axisObject->jobValid != 0U)
  2745. ? axisObject->liveTargetFrequencyHz
  2746. : 0UL;
  2747. status->liveFrequencyRejectCount =
  2748. axisObject->liveFrequencyRejectCount;
  2749. status->lastLiveFrequencyResult =
  2750. axisObject->lastLiveFrequencyResult;
  2751. PlsrCoreExitCritical(interruptState);
  2752. return PLSR_RESULT_OK;
  2753. }
  2754. PLSR_RESULT PlsrGetLastParseDetail(uint8_t axis,
  2755. PLSR_PARSE_DETAIL *detail)
  2756. {
  2757. uint32_t interruptState;
  2758. if (axis >= PLSR_AXIS_COUNT)
  2759. {
  2760. return PLSR_RESULT_INVALID_AXIS;
  2761. }
  2762. if (detail == NULL)
  2763. {
  2764. return PLSR_RESULT_INVALID_ARGUMENT;
  2765. }
  2766. interruptState = PlsrCoreEnterCritical();
  2767. *detail = PlsrAxes[axis].parseDetail;
  2768. PlsrCoreExitCritical(interruptState);
  2769. return PLSR_RESULT_OK;
  2770. }