Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 
 
 

2732 rader
92 KiB

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