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.
 
 
 
 
 
 

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