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.
 
 
 
 
 
 

2288 lines
76 KiB

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