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.
 
 
 
 
 
 

1263 lines
44 KiB

  1. #include "plsr_job.h"
  2. #include "plc_device.h"
  3. #include "plsr_address_map.h"
  4. #include <limits.h>
  5. #include <string.h>
  6. #define PLSR_S0_HEADER_WORDS (10UL)
  7. #define PLSR_S0_SEGMENT_WORDS (10UL)
  8. #define PLSR_S1_WORDS (4UL)
  9. #define PLSR_SFD_AXIS_STRIDE (130U)
  10. #define PLSR_SFD_SET_OFFSET (50U)
  11. #define PLSR_S2_SET_WORDS (20U)
  12. #define PLSR_HSD_SET_BASE (460U)
  13. #define PLSR_TIMER_168MHZ (168000000UL)
  14. #define PLSR_TIMER_84MHZ (84000000UL)
  15. static void PlsrSetDetail(PLSR_PARSE_DETAIL *detail,
  16. PLSR_RESULT result,
  17. PLSR_PARSE_BLOCK block,
  18. uint32_t address,
  19. int32_t value,
  20. uint16_t segment)
  21. {
  22. if (detail != NULL)
  23. {
  24. detail->result = result;
  25. detail->block = block;
  26. detail->address = address;
  27. detail->value = value;
  28. detail->segment = segment;
  29. }
  30. }
  31. static uint8_t PlsrIsWordDevice(PLSR_DEVICE_TYPE device)
  32. {
  33. return ((device == PLSR_DEVICE_D) || (device == PLSR_DEVICE_HD)
  34. || (device == PLSR_DEVICE_FD))
  35. ? 1U
  36. : 0U;
  37. }
  38. static uint8_t PlsrSourceIsUsable(const PLSR_DATA_SOURCE *source)
  39. {
  40. return ((source != NULL) && (source->validateWords != NULL)
  41. && (source->readWord != NULL))
  42. ? 1U
  43. : 0U;
  44. }
  45. static PLSR_RESULT PlsrValidateRange(const PLSR_DATA_SOURCE *source,
  46. PLSR_DATA_REF reference,
  47. uint32_t wordCount,
  48. PLSR_PARSE_BLOCK block,
  49. PLSR_PARSE_DETAIL *detail)
  50. {
  51. uint64_t endAddress;
  52. if ((PlsrIsWordDevice(reference.device) == 0U) || (wordCount == 0UL))
  53. {
  54. PlsrSetDetail(detail,
  55. PLSR_RESULT_DATA_ACCESS,
  56. block,
  57. reference.address,
  58. (int32_t)reference.device,
  59. 0U);
  60. return PLSR_RESULT_DATA_ACCESS;
  61. }
  62. endAddress = (uint64_t)reference.address + (uint64_t)wordCount - 1ULL;
  63. if (endAddress > UINT32_MAX)
  64. {
  65. PlsrSetDetail(detail,
  66. PLSR_RESULT_ADDRESS_OVERFLOW,
  67. block,
  68. reference.address,
  69. (int32_t)wordCount,
  70. 0U);
  71. return PLSR_RESULT_ADDRESS_OVERFLOW;
  72. }
  73. if (source->validateWords(source->context,
  74. reference.device,
  75. reference.address,
  76. wordCount)
  77. == 0U)
  78. {
  79. PlsrSetDetail(detail,
  80. PLSR_RESULT_DATA_ACCESS,
  81. block,
  82. reference.address,
  83. (int32_t)wordCount,
  84. 0U);
  85. return PLSR_RESULT_DATA_ACCESS;
  86. }
  87. return PLSR_RESULT_OK;
  88. }
  89. static PLSR_RESULT PlsrReadWord(const PLSR_DATA_SOURCE *source,
  90. PLSR_DEVICE_TYPE device,
  91. uint32_t address,
  92. uint16_t *value,
  93. PLSR_PARSE_BLOCK block,
  94. uint16_t segment,
  95. PLSR_PARSE_DETAIL *detail)
  96. {
  97. if ((value == NULL)
  98. || (source->readWord(source->context, device, address, value) == 0U))
  99. {
  100. PlsrSetDetail(detail,
  101. PLSR_RESULT_DATA_ACCESS,
  102. block,
  103. address,
  104. 0,
  105. segment);
  106. return PLSR_RESULT_DATA_ACCESS;
  107. }
  108. return PLSR_RESULT_OK;
  109. }
  110. static PLSR_RESULT PlsrReadInt32(const PLSR_DATA_SOURCE *source,
  111. PLSR_DEVICE_TYPE device,
  112. uint32_t address,
  113. int32_t *value,
  114. PLSR_PARSE_BLOCK block,
  115. uint16_t segment,
  116. PLSR_PARSE_DETAIL *detail)
  117. {
  118. uint16_t lowWord;
  119. uint16_t highWord;
  120. PLSR_RESULT result;
  121. if (address == UINT32_MAX)
  122. {
  123. PlsrSetDetail(detail,
  124. PLSR_RESULT_ADDRESS_OVERFLOW,
  125. block,
  126. address,
  127. 2,
  128. segment);
  129. return PLSR_RESULT_ADDRESS_OVERFLOW;
  130. }
  131. result = PlsrReadWord(source,
  132. device,
  133. address,
  134. &lowWord,
  135. block,
  136. segment,
  137. detail);
  138. if (result != PLSR_RESULT_OK)
  139. {
  140. return result;
  141. }
  142. result = PlsrReadWord(source,
  143. device,
  144. address + 1UL,
  145. &highWord,
  146. block,
  147. segment,
  148. detail);
  149. if (result != PLSR_RESULT_OK)
  150. {
  151. return result;
  152. }
  153. *value = (int32_t)(((uint32_t)highWord << 16U) | (uint32_t)lowWord);
  154. return PLSR_RESULT_OK;
  155. }
  156. static uint8_t PlsrBlocksOverlap(PLSR_DATA_REF first,
  157. uint32_t firstWords,
  158. PLSR_DATA_REF second,
  159. uint32_t secondWords)
  160. {
  161. uint64_t firstEnd;
  162. uint64_t secondEnd;
  163. if (first.device != second.device)
  164. {
  165. return 0U;
  166. }
  167. firstEnd = (uint64_t)first.address + (uint64_t)firstWords - 1ULL;
  168. secondEnd = (uint64_t)second.address + (uint64_t)secondWords - 1ULL;
  169. return (((uint64_t)first.address <= secondEnd)
  170. && ((uint64_t)second.address <= firstEnd))
  171. ? 1U
  172. : 0U;
  173. }
  174. static PLSR_RESULT PlsrReadFixedWord(uint8_t useHsd,
  175. uint16_t address,
  176. uint16_t *value,
  177. PLSR_PARSE_DETAIL *detail)
  178. {
  179. int32_t rawValue = 0;
  180. PLC_DEVICE_RESULT deviceResult;
  181. deviceResult = (useHsd != 0U) ? PlcDeviceReadHsd(address, &rawValue)
  182. : PlcDeviceReadSfd(address, &rawValue);
  183. if ((deviceResult != PLC_DEVICE_OK) || (rawValue < 0)
  184. || (rawValue > (int32_t)UINT16_MAX))
  185. {
  186. PlsrSetDetail(detail,
  187. PLSR_RESULT_INVALID_S2,
  188. PLSR_PARSE_BLOCK_S2,
  189. address,
  190. rawValue,
  191. 0U);
  192. return PLSR_RESULT_INVALID_S2;
  193. }
  194. *value = (uint16_t)rawValue;
  195. return PLSR_RESULT_OK;
  196. }
  197. static PLSR_RESULT PlsrReadFixedDword(uint8_t useHsd,
  198. uint16_t address,
  199. uint32_t *value,
  200. PLSR_PARSE_DETAIL *detail)
  201. {
  202. uint16_t lowWord;
  203. uint16_t highWord;
  204. PLSR_RESULT result;
  205. result = PlsrReadFixedWord(useHsd, address, &lowWord, detail);
  206. if (result != PLSR_RESULT_OK)
  207. {
  208. return result;
  209. }
  210. result = PlsrReadFixedWord(useHsd,
  211. (uint16_t)(address + 1U),
  212. &highWord,
  213. detail);
  214. if (result != PLSR_RESULT_OK)
  215. {
  216. return result;
  217. }
  218. *value = ((uint32_t)highWord << 16U) | (uint32_t)lowWord;
  219. return PLSR_RESULT_OK;
  220. }
  221. PLSR_RESULT PlsrCalculateTimerDivider(uint32_t timerClockHz,
  222. uint32_t frequencyHz,
  223. uint16_t *psc,
  224. uint16_t *arr)
  225. {
  226. uint64_t minimumDivider;
  227. uint64_t periodTicks;
  228. if ((timerClockHz == 0UL) || (frequencyHz == 0UL) || (psc == NULL)
  229. || (arr == NULL))
  230. {
  231. return PLSR_RESULT_INVALID_ARGUMENT;
  232. }
  233. minimumDivider = ((uint64_t)timerClockHz
  234. + ((uint64_t)frequencyHz * 65536ULL) - 1ULL)
  235. / ((uint64_t)frequencyHz * 65536ULL);
  236. if (minimumDivider == 0ULL)
  237. {
  238. minimumDivider = 1ULL;
  239. }
  240. if (minimumDivider > 65536ULL)
  241. {
  242. return PLSR_RESULT_DIVIDER_UNREPRESENTABLE;
  243. }
  244. periodTicks = ((uint64_t)timerClockHz
  245. + ((uint64_t)frequencyHz * minimumDivider) / 2ULL)
  246. / ((uint64_t)frequencyHz * minimumDivider);
  247. if ((periodTicks < 2ULL) || (periodTicks > 65536ULL))
  248. {
  249. return PLSR_RESULT_DIVIDER_UNREPRESENTABLE;
  250. }
  251. *psc = (uint16_t)(minimumDivider - 1ULL);
  252. *arr = (uint16_t)(periodTicks - 1ULL);
  253. return PLSR_RESULT_OK;
  254. }
  255. static PLSR_RESULT PlsrValidateFrequencyDivider(
  256. const PLSR_JOB_SNAPSHOT *snapshot,
  257. uint32_t frequency,
  258. PLSR_PARSE_DETAIL *detail,
  259. uint16_t segment)
  260. {
  261. uint16_t psc;
  262. uint16_t arr;
  263. PLSR_RESULT result;
  264. result = PlsrCalculateTimerDivider(snapshot->timerClockHz,
  265. frequency,
  266. &psc,
  267. &arr);
  268. if ((result == PLSR_RESULT_OK)
  269. && (snapshot->pairedTimerClockHz != 0UL))
  270. {
  271. result = PlsrCalculateTimerDivider(snapshot->pairedTimerClockHz,
  272. frequency,
  273. &psc,
  274. &arr);
  275. }
  276. if (result != PLSR_RESULT_OK)
  277. {
  278. PlsrSetDetail(detail,
  279. PLSR_RESULT_DIVIDER_UNREPRESENTABLE,
  280. PLSR_PARSE_BLOCK_S0,
  281. snapshot->s0.address
  282. + (uint32_t)segment * PLSR_S0_SEGMENT_WORDS,
  283. (int32_t)frequency,
  284. segment);
  285. return PLSR_RESULT_DIVIDER_UNREPRESENTABLE;
  286. }
  287. return PLSR_RESULT_OK;
  288. }
  289. static PLSR_RESULT PlsrResolveOperand(const PLSR_CALL *call,
  290. const PLSR_VALUE_OPERAND *operand,
  291. int32_t *value,
  292. PLSR_PARSE_DETAIL *detail)
  293. {
  294. PLSR_RESULT result;
  295. if (operand->type == PLSR_OPERAND_CONSTANT)
  296. {
  297. *value = operand->constant;
  298. return PLSR_RESULT_OK;
  299. }
  300. if ((operand->type != PLSR_OPERAND_DATA)
  301. || (PlsrIsWordDevice(operand->data.device) == 0U))
  302. {
  303. PlsrSetDetail(detail,
  304. PLSR_RESULT_INVALID_S2,
  305. PLSR_PARSE_BLOCK_S2,
  306. operand->data.address,
  307. (int32_t)operand->type,
  308. 0U);
  309. return PLSR_RESULT_INVALID_S2;
  310. }
  311. result = PlsrValidateRange(&call->source,
  312. operand->data,
  313. 2UL,
  314. PLSR_PARSE_BLOCK_S2,
  315. detail);
  316. if (result != PLSR_RESULT_OK)
  317. {
  318. return result;
  319. }
  320. return PlsrReadInt32(&call->source,
  321. operand->data.device,
  322. operand->data.address,
  323. value,
  324. PLSR_PARSE_BLOCK_S2,
  325. 0U,
  326. detail);
  327. }
  328. static PLSR_RESULT PlsrLoadS2(const PLSR_CALL *call,
  329. PLSR_JOB_SNAPSHOT *snapshot,
  330. PLSR_PARSE_DETAIL *detail)
  331. {
  332. uint16_t commonBase;
  333. uint16_t setBase;
  334. uint16_t word;
  335. int32_t selectedSet;
  336. uint8_t useHsd;
  337. PLSR_RESULT result;
  338. result = PlsrResolveOperand(call, &call->s2, &selectedSet, detail);
  339. if (result != PLSR_RESULT_OK)
  340. {
  341. return result;
  342. }
  343. if ((selectedSet < 0) || (selectedSet > 4))
  344. {
  345. PlsrSetDetail(detail,
  346. PLSR_RESULT_INVALID_S2,
  347. PLSR_PARSE_BLOCK_S2,
  348. call->s2.data.address,
  349. selectedSet,
  350. 0U);
  351. return PLSR_RESULT_INVALID_S2;
  352. }
  353. snapshot->s2Set = (uint8_t)selectedSet;
  354. commonBase = (uint16_t)(PLSR_SFD_CONFIG_START
  355. + (uint16_t)call->dAxis
  356. * PLSR_SFD_AXIS_STRIDE);
  357. if (snapshot->s2Set == 0U)
  358. {
  359. useHsd = 1U;
  360. setBase = (uint16_t)(PLSR_HSD_SET_BASE
  361. + (uint16_t)call->dAxis * PLSR_S2_SET_WORDS);
  362. }
  363. else
  364. {
  365. useHsd = 0U;
  366. setBase = (uint16_t)(commonBase + PLSR_SFD_SET_OFFSET
  367. + (uint16_t)(snapshot->s2Set - 1U)
  368. * PLSR_S2_SET_WORDS);
  369. }
  370. result = PlsrReadFixedDword(useHsd,
  371. setBase,
  372. &snapshot->s2.defaultSpeed,
  373. detail);
  374. if (result != PLSR_RESULT_OK) return result;
  375. result = PlsrReadFixedWord(useHsd,
  376. (uint16_t)(setBase + 2U),
  377. &snapshot->s2.accelerationMs,
  378. detail);
  379. if (result != PLSR_RESULT_OK) return result;
  380. result = PlsrReadFixedWord(useHsd,
  381. (uint16_t)(setBase + 3U),
  382. &snapshot->s2.decelerationMs,
  383. detail);
  384. if (result != PLSR_RESULT_OK) return result;
  385. result = PlsrReadFixedWord(useHsd,
  386. (uint16_t)(setBase + 4U),
  387. &snapshot->s2.gapAccelerationMs,
  388. detail);
  389. if (result != PLSR_RESULT_OK) return result;
  390. result = PlsrReadFixedWord(useHsd,
  391. (uint16_t)(setBase + 5U),
  392. &word,
  393. detail);
  394. if (result != PLSR_RESULT_OK) return result;
  395. snapshot->s2.curveMode = (uint8_t)(word & 0x03U);
  396. result = PlsrReadFixedDword(useHsd,
  397. (uint16_t)(setBase + 6U),
  398. &snapshot->s2.maximumSpeed,
  399. detail);
  400. if (result != PLSR_RESULT_OK) return result;
  401. result = PlsrReadFixedDword(useHsd,
  402. (uint16_t)(setBase + 8U),
  403. &snapshot->s2.startSpeed,
  404. detail);
  405. if (result != PLSR_RESULT_OK) return result;
  406. result = PlsrReadFixedDword(useHsd,
  407. (uint16_t)(setBase + 10U),
  408. &snapshot->s2.stopSpeed,
  409. detail);
  410. if (result != PLSR_RESULT_OK) return result;
  411. result = PlsrReadFixedWord(useHsd,
  412. (uint16_t)(setBase + 12U),
  413. &word,
  414. detail);
  415. if (result != PLSR_RESULT_OK) return result;
  416. if ((word < 1U) || (word > 100U))
  417. {
  418. PlsrSetDetail(detail,
  419. PLSR_RESULT_INVALID_S2,
  420. PLSR_PARSE_BLOCK_S2,
  421. (uint16_t)(setBase + 12U),
  422. word,
  423. 0U);
  424. return PLSR_RESULT_INVALID_S2;
  425. }
  426. snapshot->s2.follow = (uint8_t)word;
  427. result = PlsrReadFixedWord(useHsd,
  428. (uint16_t)(setBase + 13U),
  429. &word,
  430. detail);
  431. if (result != PLSR_RESULT_OK) return result;
  432. if (word > 100U)
  433. {
  434. PlsrSetDetail(detail,
  435. PLSR_RESULT_INVALID_S2,
  436. PLSR_PARSE_BLOCK_S2,
  437. (uint16_t)(setBase + 13U),
  438. word,
  439. 0U);
  440. return PLSR_RESULT_INVALID_S2;
  441. }
  442. snapshot->s2.feedforwardPercent = (uint8_t)word;
  443. result = PlsrReadFixedWord(useHsd,
  444. (uint16_t)(setBase + 14U),
  445. &word,
  446. detail);
  447. if (result != PLSR_RESULT_OK) return result;
  448. snapshot->s2.refreshCode = (uint8_t)(word & 0x03U);
  449. result = PlsrReadFixedDword(useHsd,
  450. (uint16_t)(setBase + 16U),
  451. &snapshot->s2.zrnHighSpeed,
  452. detail);
  453. if (result != PLSR_RESULT_OK) return result;
  454. result = PlsrReadFixedDword(useHsd,
  455. (uint16_t)(setBase + 18U),
  456. &snapshot->s2.zrnCrawlSpeed,
  457. detail);
  458. if (result != PLSR_RESULT_OK) return result;
  459. result = PlsrReadFixedWord(0U, commonBase, &word, detail);
  460. if (result != PLSR_RESULT_OK) return result;
  461. snapshot->directionActiveHigh = ((word & (1U << 1U)) != 0U) ? 1U : 0U;
  462. if (call->outputModeOverride == PLSR_OUTPUT_MODE_FROM_SFD)
  463. {
  464. snapshot->outputMode = ((word & (1U << 13U)) != 0U)
  465. ? (uint8_t)PLSR_OUTPUT_AB
  466. : (uint8_t)PLSR_OUTPUT_PULSE_DIR;
  467. }
  468. else if (call->outputModeOverride <= (uint8_t)PLSR_OUTPUT_CW_CCW)
  469. {
  470. snapshot->outputMode = call->outputModeOverride;
  471. }
  472. else
  473. {
  474. PlsrSetDetail(detail,
  475. PLSR_RESULT_INVALID_RESOURCE,
  476. PLSR_PARSE_BLOCK_OUTPUT,
  477. commonBase,
  478. call->outputModeOverride,
  479. 0U);
  480. return PLSR_RESULT_INVALID_RESOURCE;
  481. }
  482. result = PlsrReadFixedWord(0U,
  483. (uint16_t)(commonBase + 6U),
  484. &word,
  485. detail);
  486. if (result != PLSR_RESULT_OK) return result;
  487. if (word > UINT8_MAX)
  488. {
  489. PlsrSetDetail(detail,
  490. PLSR_RESULT_INVALID_RESOURCE,
  491. PLSR_PARSE_BLOCK_OUTPUT,
  492. (uint16_t)(commonBase + 6U),
  493. word,
  494. 0U);
  495. return PLSR_RESULT_INVALID_RESOURCE;
  496. }
  497. snapshot->directionPoint = (uint8_t)word;
  498. result = PlsrReadFixedWord(0U,
  499. (uint16_t)(commonBase + 7U),
  500. &snapshot->s2.directionDelayUs,
  501. detail);
  502. if (result != PLSR_RESULT_OK) return result;
  503. if ((snapshot->s2.maximumSpeed < PLSR_FREQUENCY_MIN_HZ)
  504. || (snapshot->s2.maximumSpeed > PLSR_FREQUENCY_MAX_HZ)
  505. || (snapshot->s2.curveMode > 2U) || (snapshot->s2.follow < 1U)
  506. || (snapshot->s2.follow > 100U)
  507. || (snapshot->s2.feedforwardPercent > 100U)
  508. || ((snapshot->s2.refreshCode != 0U)
  509. && (snapshot->s2.refreshCode != 2U)))
  510. {
  511. PlsrSetDetail(detail,
  512. PLSR_RESULT_INVALID_S2,
  513. PLSR_PARSE_BLOCK_S2,
  514. setBase,
  515. (int32_t)snapshot->s2.maximumSpeed,
  516. 0U);
  517. return PLSR_RESULT_INVALID_S2;
  518. }
  519. if (snapshot->s2.startSpeed > snapshot->s2.maximumSpeed)
  520. {
  521. snapshot->s2.startSpeed = snapshot->s2.maximumSpeed;
  522. snapshot->speedClamped = 1U;
  523. }
  524. if (snapshot->s2.stopSpeed > snapshot->s2.maximumSpeed)
  525. {
  526. snapshot->s2.stopSpeed = snapshot->s2.maximumSpeed;
  527. snapshot->speedClamped = 1U;
  528. }
  529. return PLSR_RESULT_OK;
  530. }
  531. static PLSR_RESULT PlsrValidateVariableReference(
  532. const PLSR_CALL *call,
  533. uint8_t sourceCode,
  534. int32_t addressValue,
  535. uint8_t bitReference,
  536. int32_t *currentValue,
  537. PLSR_PARSE_BLOCK block,
  538. uint16_t segment,
  539. PLSR_PARSE_DETAIL *detail)
  540. {
  541. PLSR_DEVICE_TYPE device;
  542. PLSR_DATA_REF reference;
  543. uint8_t bitValue;
  544. PLSR_RESULT result;
  545. if ((sourceCode == 0U) || (sourceCode > 6U) || (addressValue < 0))
  546. {
  547. PlsrSetDetail(detail,
  548. (block == PLSR_PARSE_BLOCK_S0)
  549. ? PLSR_RESULT_INVALID_WAIT
  550. : PLSR_RESULT_DATA_ACCESS,
  551. block,
  552. (uint32_t)addressValue,
  553. sourceCode,
  554. segment);
  555. return (block == PLSR_PARSE_BLOCK_S0) ? PLSR_RESULT_INVALID_WAIT
  556. : PLSR_RESULT_DATA_ACCESS;
  557. }
  558. device = (PLSR_DEVICE_TYPE)(sourceCode - 1U);
  559. if (bitReference != 0U)
  560. {
  561. if ((device < PLSR_DEVICE_X) || (call->source.readBit == NULL)
  562. || (call->source.readBit(call->source.context,
  563. device,
  564. (uint32_t)addressValue,
  565. &bitValue)
  566. == 0U))
  567. {
  568. PlsrSetDetail(detail,
  569. PLSR_RESULT_INVALID_WAIT,
  570. block,
  571. (uint32_t)addressValue,
  572. sourceCode,
  573. segment);
  574. return PLSR_RESULT_INVALID_WAIT;
  575. }
  576. *currentValue = (int32_t)bitValue;
  577. return PLSR_RESULT_OK;
  578. }
  579. if (PlsrIsWordDevice(device) == 0U)
  580. {
  581. PlsrSetDetail(detail,
  582. PLSR_RESULT_INVALID_WAIT,
  583. block,
  584. (uint32_t)addressValue,
  585. sourceCode,
  586. segment);
  587. return PLSR_RESULT_INVALID_WAIT;
  588. }
  589. reference.device = device;
  590. reference.address = (uint32_t)addressValue;
  591. result = PlsrValidateRange(&call->source,
  592. reference,
  593. 2UL,
  594. block,
  595. detail);
  596. if (result != PLSR_RESULT_OK)
  597. {
  598. return result;
  599. }
  600. return PlsrReadInt32(&call->source,
  601. device,
  602. reference.address,
  603. currentValue,
  604. block,
  605. segment,
  606. detail);
  607. }
  608. static PLSR_RESULT PlsrValidateWait(const PLSR_CALL *call,
  609. PLSR_SEGMENT_SNAPSHOT *segmentData,
  610. uint16_t segment,
  611. PLSR_PARSE_DETAIL *detail)
  612. {
  613. int32_t currentValue;
  614. PLSR_RESULT result;
  615. if ((segmentData->waitCondition > PLSR_WAIT_EXT_OR_COMPLETE)
  616. || (segmentData->waitSource > PLSR_VALUE_HM))
  617. {
  618. goto invalidWait;
  619. }
  620. if (segmentData->waitCondition == PLSR_WAIT_PULSE_COMPLETE)
  621. {
  622. if (segmentData->waitSource != PLSR_VALUE_CONSTANT)
  623. {
  624. goto invalidWait;
  625. }
  626. return PLSR_RESULT_OK;
  627. }
  628. if ((segmentData->waitCondition == PLSR_WAIT_TIME)
  629. || (segmentData->waitCondition == PLSR_WAIT_ACT_TIME))
  630. {
  631. if (segmentData->waitSource == PLSR_VALUE_CONSTANT)
  632. {
  633. currentValue = segmentData->waitValueOrAddress;
  634. }
  635. else
  636. {
  637. if (segmentData->waitSource > PLSR_VALUE_FD)
  638. {
  639. goto invalidWait;
  640. }
  641. result = PlsrValidateVariableReference(call,
  642. segmentData->waitSource,
  643. segmentData->waitValueOrAddress,
  644. 0U,
  645. &currentValue,
  646. PLSR_PARSE_BLOCK_S0,
  647. segment,
  648. detail);
  649. if (result != PLSR_RESULT_OK) return result;
  650. }
  651. if (currentValue < 0) goto invalidWait;
  652. return PLSR_RESULT_OK;
  653. }
  654. if (segmentData->waitCondition == PLSR_WAIT_SIGNAL)
  655. {
  656. if ((segmentData->waitSource < PLSR_VALUE_X)
  657. || (segmentData->waitSource > PLSR_VALUE_HM))
  658. {
  659. goto invalidWait;
  660. }
  661. }
  662. else if ((segmentData->waitCondition == PLSR_WAIT_EXT)
  663. || (segmentData->waitCondition == PLSR_WAIT_EXT_OR_COMPLETE))
  664. {
  665. if (segmentData->waitSource != PLSR_VALUE_X)
  666. {
  667. goto invalidWait;
  668. }
  669. }
  670. result = PlsrValidateVariableReference(call,
  671. segmentData->waitSource,
  672. segmentData->waitValueOrAddress,
  673. 1U,
  674. &currentValue,
  675. PLSR_PARSE_BLOCK_S0,
  676. segment,
  677. detail);
  678. return result;
  679. invalidWait:
  680. PlsrSetDetail(detail,
  681. PLSR_RESULT_INVALID_WAIT,
  682. PLSR_PARSE_BLOCK_S0,
  683. call->s0.address
  684. + (uint32_t)segment * PLSR_S0_SEGMENT_WORDS + 4UL,
  685. ((int32_t)segmentData->waitCondition << 8)
  686. | segmentData->waitSource,
  687. segment);
  688. return PLSR_RESULT_INVALID_WAIT;
  689. }
  690. static PLSR_RESULT PlsrValidateJump(const PLSR_CALL *call,
  691. const PLSR_JOB_SNAPSHOT *snapshot,
  692. PLSR_SEGMENT_SNAPSHOT *segmentData,
  693. uint16_t segment,
  694. int32_t *resolvedJump,
  695. PLSR_PARSE_DETAIL *detail)
  696. {
  697. PLSR_RESULT result;
  698. if (segmentData->jumpSource > PLSR_VALUE_FD)
  699. {
  700. goto invalidJump;
  701. }
  702. if (segmentData->jumpSource == PLSR_VALUE_CONSTANT)
  703. {
  704. *resolvedJump = segmentData->jumpValueOrAddress;
  705. }
  706. else
  707. {
  708. result = PlsrValidateVariableReference(call,
  709. segmentData->jumpSource,
  710. segmentData->jumpValueOrAddress,
  711. 0U,
  712. resolvedJump,
  713. PLSR_PARSE_BLOCK_NONE,
  714. segment,
  715. detail);
  716. if (result != PLSR_RESULT_OK)
  717. {
  718. PlsrSetDetail(detail,
  719. PLSR_RESULT_INVALID_JUMP,
  720. PLSR_PARSE_BLOCK_S0,
  721. (uint32_t)segmentData->jumpValueOrAddress,
  722. segmentData->jumpSource,
  723. segment);
  724. return PLSR_RESULT_INVALID_JUMP;
  725. }
  726. }
  727. if ((*resolvedJump < 0)
  728. || (*resolvedJump > (int32_t)snapshot->segmentCount))
  729. {
  730. goto invalidJump;
  731. }
  732. if (*resolvedJump == (int32_t)segment)
  733. {
  734. segmentData->flags |= PLSR_SEGMENT_FLAG_SELF_LOOP;
  735. }
  736. return PLSR_RESULT_OK;
  737. invalidJump:
  738. PlsrSetDetail(detail,
  739. PLSR_RESULT_INVALID_JUMP,
  740. PLSR_PARSE_BLOCK_S0,
  741. call->s0.address
  742. + (uint32_t)segment * PLSR_S0_SEGMENT_WORDS + 7UL,
  743. *resolvedJump,
  744. segment);
  745. return PLSR_RESULT_INVALID_JUMP;
  746. }
  747. static PLSR_RESULT PlsrCheckConstantPath(PLSR_JOB_SNAPSHOT *snapshot,
  748. PLSR_PARSE_DETAIL *detail)
  749. {
  750. uint8_t visited[PLSR_MAX_SEGMENTS];
  751. uint16_t segment = snapshot->startSegment;
  752. int32_t next;
  753. (void)memset(visited, 0, sizeof(visited));
  754. while ((segment >= 1U) && (segment <= snapshot->segmentCount))
  755. {
  756. if (visited[segment - 1U] != 0U)
  757. {
  758. PlsrSetDetail(detail,
  759. PLSR_RESULT_PATH_CYCLE,
  760. PLSR_PARSE_BLOCK_S0,
  761. snapshot->s0.address
  762. + (uint32_t)segment * PLSR_S0_SEGMENT_WORDS
  763. + 8UL,
  764. segment,
  765. segment);
  766. return PLSR_RESULT_PATH_CYCLE;
  767. }
  768. visited[segment - 1U] = 1U;
  769. if (snapshot->segments[segment - 1U].jumpSource
  770. != PLSR_VALUE_CONSTANT)
  771. {
  772. return PLSR_RESULT_OK;
  773. }
  774. next = snapshot->segments[segment - 1U].jumpValueOrAddress;
  775. if (next == (int32_t)segment)
  776. {
  777. snapshot->hasSelfLoop = 1U;
  778. return PLSR_RESULT_OK;
  779. }
  780. if (next == 0)
  781. {
  782. if (segment == snapshot->segmentCount)
  783. {
  784. return PLSR_RESULT_OK;
  785. }
  786. segment++;
  787. }
  788. else
  789. {
  790. segment = (uint16_t)next;
  791. }
  792. }
  793. return PLSR_RESULT_OK;
  794. }
  795. static PLSR_RESULT PlsrCheckInitialPosition(
  796. PLSR_JOB_SNAPSHOT *snapshot,
  797. const PLSR_PARSE_CONTEXT *context,
  798. PLSR_PARSE_DETAIL *detail)
  799. {
  800. uint8_t visited[PLSR_MAX_SEGMENTS];
  801. int64_t position = context->logicalPosition;
  802. int32_t movement;
  803. int32_t next;
  804. uint16_t segment = snapshot->startSegment;
  805. if ((snapshot->positioningMode != 0U) && (context->positionValid == 0U))
  806. {
  807. PlsrSetDetail(detail,
  808. PLSR_RESULT_POSITION_INVALID,
  809. PLSR_PARSE_BLOCK_POSITION,
  810. snapshot->s1.address,
  811. 1,
  812. 0U);
  813. return PLSR_RESULT_POSITION_INVALID;
  814. }
  815. (void)memset(visited, 0, sizeof(visited));
  816. while ((segment >= 1U) && (segment <= snapshot->segmentCount)
  817. && (visited[segment - 1U] == 0U))
  818. {
  819. PLSR_SEGMENT_SNAPSHOT *segmentData = &snapshot->segments[segment - 1U];
  820. visited[segment - 1U] = 1U;
  821. if (snapshot->positioningMode == 0U)
  822. {
  823. movement = segmentData->pulseOrTarget;
  824. if (((movement > 0) && (position > INT64_MAX - movement))
  825. || ((movement < 0) && (position < INT64_MIN - movement)))
  826. {
  827. PlsrSetDetail(detail,
  828. PLSR_RESULT_POSITION_OVERFLOW,
  829. PLSR_PARSE_BLOCK_POSITION,
  830. snapshot->s0.address
  831. + (uint32_t)segment
  832. * PLSR_S0_SEGMENT_WORDS
  833. + 2UL,
  834. movement,
  835. segment);
  836. return PLSR_RESULT_POSITION_OVERFLOW;
  837. }
  838. position += movement;
  839. }
  840. else
  841. {
  842. movement = (segmentData->pulseOrTarget > position)
  843. ? 1
  844. : ((segmentData->pulseOrTarget < position) ? -1 : 0);
  845. position = segmentData->pulseOrTarget;
  846. }
  847. if ((movement != 0) && (snapshot->initialDirectionPositive == 0U))
  848. {
  849. snapshot->initialDirectionPositive = (movement > 0) ? 2U : 1U;
  850. }
  851. if (segmentData->jumpSource != PLSR_VALUE_CONSTANT)
  852. {
  853. break;
  854. }
  855. next = segmentData->jumpValueOrAddress;
  856. if (next == (int32_t)segment)
  857. {
  858. break;
  859. }
  860. if (next == 0)
  861. {
  862. if (segment == snapshot->segmentCount) break;
  863. segment++;
  864. }
  865. else
  866. {
  867. segment = (uint16_t)next;
  868. }
  869. }
  870. snapshot->initialDirectionPositive =
  871. (snapshot->initialDirectionPositive == 2U) ? 1U : 0U;
  872. return PLSR_RESULT_OK;
  873. }
  874. PLSR_RESULT PlsrBuildJobSnapshot(const PLSR_CALL *call,
  875. const PLSR_PARSE_CONTEXT *context,
  876. PLSR_JOB_SNAPSHOT *snapshot,
  877. PLSR_PARSE_DETAIL *detail)
  878. {
  879. uint64_t s0Words64;
  880. uint32_t s0Words;
  881. uint32_t segmentBase;
  882. int32_t intValue;
  883. int32_t resolvedJump;
  884. uint16_t word;
  885. uint16_t segment;
  886. uint8_t index;
  887. PLSR_RESULT result;
  888. if ((call == NULL) || (context == NULL) || (snapshot == NULL)
  889. || (PlsrSourceIsUsable(&call->source) == 0U))
  890. {
  891. return PLSR_RESULT_INVALID_ARGUMENT;
  892. }
  893. if (call->dAxis >= PLSR_AXIS_COUNT)
  894. {
  895. return PLSR_RESULT_INVALID_AXIS;
  896. }
  897. (void)memset(snapshot, 0, sizeof(*snapshot));
  898. if (detail != NULL) (void)memset(detail, 0, sizeof(*detail));
  899. snapshot->source = call->source;
  900. snapshot->s0 = call->s0;
  901. snapshot->s1 = call->s1;
  902. snapshot->dAxis = call->dAxis;
  903. snapshot->timerClockHz = ((call->dAxis == 0U) || (call->dAxis == 2U))
  904. ? PLSR_TIMER_168MHZ
  905. : PLSR_TIMER_84MHZ;
  906. result = PlsrValidateRange(&call->source,
  907. call->s0,
  908. PLSR_S0_HEADER_WORDS,
  909. PLSR_PARSE_BLOCK_S0,
  910. detail);
  911. if (result != PLSR_RESULT_OK) return result;
  912. result = PlsrReadInt32(&call->source,
  913. call->s0.device,
  914. call->s0.address,
  915. &intValue,
  916. PLSR_PARSE_BLOCK_S0,
  917. 0U,
  918. detail);
  919. if ((result != PLSR_RESULT_OK) || (intValue < 1)
  920. || (intValue > (int32_t)PLSR_MAX_SEGMENTS))
  921. {
  922. if (result == PLSR_RESULT_OK)
  923. {
  924. PlsrSetDetail(detail,
  925. PLSR_RESULT_SEGMENT_OVERFLOW,
  926. PLSR_PARSE_BLOCK_S0,
  927. call->s0.address,
  928. intValue,
  929. 0U);
  930. result = PLSR_RESULT_SEGMENT_OVERFLOW;
  931. }
  932. return result;
  933. }
  934. snapshot->segmentCount = (uint16_t)intValue;
  935. s0Words64 = (uint64_t)snapshot->segmentCount * PLSR_S0_SEGMENT_WORDS
  936. + PLSR_S0_HEADER_WORDS;
  937. if (s0Words64 > UINT32_MAX)
  938. {
  939. return PLSR_RESULT_ADDRESS_OVERFLOW;
  940. }
  941. s0Words = (uint32_t)s0Words64;
  942. result = PlsrValidateRange(&call->source,
  943. call->s0,
  944. s0Words,
  945. PLSR_PARSE_BLOCK_S0,
  946. detail);
  947. if (result != PLSR_RESULT_OK) return result;
  948. result = PlsrValidateRange(&call->source,
  949. call->s1,
  950. PLSR_S1_WORDS,
  951. PLSR_PARSE_BLOCK_S1,
  952. detail);
  953. if (result != PLSR_RESULT_OK) return result;
  954. if (PlsrBlocksOverlap(call->s0, s0Words, call->s1, PLSR_S1_WORDS) != 0U)
  955. {
  956. PlsrSetDetail(detail,
  957. PLSR_RESULT_BLOCK_OVERLAP,
  958. PLSR_PARSE_BLOCK_S1,
  959. call->s1.address,
  960. (int32_t)s0Words,
  961. 0U);
  962. return PLSR_RESULT_BLOCK_OVERLAP;
  963. }
  964. for (index = 2U; index < 10U; index++)
  965. {
  966. result = PlsrReadWord(&call->source,
  967. call->s0.device,
  968. call->s0.address + index,
  969. &word,
  970. PLSR_PARSE_BLOCK_S0,
  971. 0U,
  972. detail);
  973. if (result != PLSR_RESULT_OK) return result;
  974. if (word != 0U)
  975. {
  976. PlsrSetDetail(detail,
  977. PLSR_RESULT_RESERVED_NOT_ZERO,
  978. PLSR_PARSE_BLOCK_S0,
  979. call->s0.address + index,
  980. word,
  981. 0U);
  982. return PLSR_RESULT_RESERVED_NOT_ZERO;
  983. }
  984. }
  985. result = PlsrReadInt32(&call->source,
  986. call->s1.device,
  987. call->s1.address,
  988. &intValue,
  989. PLSR_PARSE_BLOCK_S1,
  990. 0U,
  991. detail);
  992. if (result != PLSR_RESULT_OK) return result;
  993. if ((intValue < 0) || (intValue > 1))
  994. {
  995. PlsrSetDetail(detail,
  996. PLSR_RESULT_INVALID_POSITION_MODE,
  997. PLSR_PARSE_BLOCK_S1,
  998. call->s1.address,
  999. intValue,
  1000. 0U);
  1001. return PLSR_RESULT_INVALID_POSITION_MODE;
  1002. }
  1003. snapshot->positioningMode = (uint8_t)intValue;
  1004. result = PlsrReadInt32(&call->source,
  1005. call->s1.device,
  1006. call->s1.address + 2UL,
  1007. &intValue,
  1008. PLSR_PARSE_BLOCK_S1,
  1009. 0U,
  1010. detail);
  1011. if (result != PLSR_RESULT_OK) return result;
  1012. if ((intValue < 0) || (intValue > snapshot->segmentCount))
  1013. {
  1014. PlsrSetDetail(detail,
  1015. PLSR_RESULT_INVALID_ARGUMENT,
  1016. PLSR_PARSE_BLOCK_S1,
  1017. call->s1.address + 2UL,
  1018. intValue,
  1019. 0U);
  1020. return PLSR_RESULT_INVALID_ARGUMENT;
  1021. }
  1022. snapshot->startSegment = (intValue <= 1) ? 1U : (uint16_t)intValue;
  1023. result = PlsrLoadS2(call, snapshot, detail);
  1024. if (result != PLSR_RESULT_OK) return result;
  1025. if ((snapshot->outputMode == PLSR_OUTPUT_AB)
  1026. || (snapshot->outputMode == PLSR_OUTPUT_CW_CCW))
  1027. {
  1028. if ((call->dAxis != 0U) && (call->dAxis != 2U))
  1029. {
  1030. PlsrSetDetail(detail,
  1031. PLSR_RESULT_INVALID_RESOURCE,
  1032. PLSR_PARSE_BLOCK_OUTPUT,
  1033. call->dAxis,
  1034. snapshot->outputMode,
  1035. 0U);
  1036. return PLSR_RESULT_INVALID_RESOURCE;
  1037. }
  1038. snapshot->pairedTimerClockHz = PLSR_TIMER_84MHZ;
  1039. }
  1040. for (segment = 1U; segment <= snapshot->segmentCount; segment++)
  1041. {
  1042. PLSR_SEGMENT_SNAPSHOT *segmentData = &snapshot->segments[segment - 1U];
  1043. segmentBase = call->s0.address
  1044. + (uint32_t)segment * PLSR_S0_SEGMENT_WORDS;
  1045. result = PlsrReadInt32(&call->source,
  1046. call->s0.device,
  1047. segmentBase,
  1048. &intValue,
  1049. PLSR_PARSE_BLOCK_S0,
  1050. segment,
  1051. detail);
  1052. if (result != PLSR_RESULT_OK) return result;
  1053. if (intValue < 0)
  1054. {
  1055. PlsrSetDetail(detail,
  1056. PLSR_RESULT_INVALID_FREQUENCY,
  1057. PLSR_PARSE_BLOCK_S0,
  1058. segmentBase,
  1059. intValue,
  1060. segment);
  1061. return PLSR_RESULT_INVALID_FREQUENCY;
  1062. }
  1063. segmentData->targetFrequency = (uint32_t)intValue;
  1064. result = PlsrReadInt32(&call->source,
  1065. call->s0.device,
  1066. segmentBase + 2UL,
  1067. &segmentData->pulseOrTarget,
  1068. PLSR_PARSE_BLOCK_S0,
  1069. segment,
  1070. detail);
  1071. if (result != PLSR_RESULT_OK) return result;
  1072. result = PlsrReadWord(&call->source,
  1073. call->s0.device,
  1074. segmentBase + 4UL,
  1075. &word,
  1076. PLSR_PARSE_BLOCK_S0,
  1077. segment,
  1078. detail);
  1079. if (result != PLSR_RESULT_OK) return result;
  1080. segmentData->waitSource = (uint8_t)(word & 0xFFU);
  1081. segmentData->waitCondition = (uint8_t)(word >> 8U);
  1082. result = PlsrReadInt32(&call->source,
  1083. call->s0.device,
  1084. segmentBase + 5UL,
  1085. &segmentData->waitValueOrAddress,
  1086. PLSR_PARSE_BLOCK_S0,
  1087. segment,
  1088. detail);
  1089. if (result != PLSR_RESULT_OK) return result;
  1090. result = PlsrReadWord(&call->source,
  1091. call->s0.device,
  1092. segmentBase + 7UL,
  1093. &word,
  1094. PLSR_PARSE_BLOCK_S0,
  1095. segment,
  1096. detail);
  1097. if (result != PLSR_RESULT_OK) return result;
  1098. if ((word & 0xFF00U) != 0U)
  1099. {
  1100. PlsrSetDetail(detail,
  1101. PLSR_RESULT_RESERVED_NOT_ZERO,
  1102. PLSR_PARSE_BLOCK_S0,
  1103. segmentBase + 7UL,
  1104. word,
  1105. segment);
  1106. return PLSR_RESULT_RESERVED_NOT_ZERO;
  1107. }
  1108. segmentData->jumpSource = (uint8_t)(word & 0xFFU);
  1109. result = PlsrReadInt32(&call->source,
  1110. call->s0.device,
  1111. segmentBase + 8UL,
  1112. &segmentData->jumpValueOrAddress,
  1113. PLSR_PARSE_BLOCK_S0,
  1114. segment,
  1115. detail);
  1116. if (result != PLSR_RESULT_OK) return result;
  1117. if ((snapshot->positioningMode == 0U)
  1118. && (segmentData->pulseOrTarget == 0))
  1119. {
  1120. segmentData->flags |= PLSR_SEGMENT_FLAG_ZERO_PULSE;
  1121. segmentData->targetFrequency = 0UL;
  1122. }
  1123. else if (segmentData->targetFrequency == 0UL)
  1124. {
  1125. if (snapshot->s2.defaultSpeed == 0UL)
  1126. {
  1127. PlsrSetDetail(detail,
  1128. PLSR_RESULT_INVALID_FREQUENCY,
  1129. PLSR_PARSE_BLOCK_S2,
  1130. 0UL,
  1131. 0,
  1132. segment);
  1133. return PLSR_RESULT_INVALID_FREQUENCY;
  1134. }
  1135. segmentData->targetFrequency = snapshot->s2.defaultSpeed;
  1136. segmentData->flags |= PLSR_SEGMENT_FLAG_DEFAULT_SPEED;
  1137. }
  1138. if (segmentData->targetFrequency > snapshot->s2.maximumSpeed)
  1139. {
  1140. segmentData->targetFrequency = snapshot->s2.maximumSpeed;
  1141. segmentData->flags |= PLSR_SEGMENT_FLAG_SPEED_CLAMPED;
  1142. snapshot->speedClamped = 1U;
  1143. }
  1144. if (segmentData->targetFrequency != 0UL)
  1145. {
  1146. result = PlsrValidateFrequencyDivider(snapshot,
  1147. segmentData->targetFrequency,
  1148. detail,
  1149. segment);
  1150. if (result != PLSR_RESULT_OK) return result;
  1151. }
  1152. result = PlsrValidateWait(call, segmentData, segment, detail);
  1153. if (result != PLSR_RESULT_OK) return result;
  1154. result = PlsrValidateJump(call,
  1155. snapshot,
  1156. segmentData,
  1157. segment,
  1158. &resolvedJump,
  1159. detail);
  1160. if (result != PLSR_RESULT_OK) return result;
  1161. }
  1162. result = PlsrCheckConstantPath(snapshot, detail);
  1163. if (result != PLSR_RESULT_OK) return result;
  1164. result = PlsrCheckInitialPosition(snapshot, context, detail);
  1165. if (result != PLSR_RESULT_OK) return result;
  1166. if (detail != NULL) detail->result = PLSR_RESULT_OK;
  1167. return PLSR_RESULT_OK;
  1168. }
  1169. PLSR_RESULT PlsrResolveLiveFrequency(const PLSR_JOB_SNAPSHOT *snapshot,
  1170. uint16_t segment,
  1171. uint32_t *frequency,
  1172. uint8_t *clamped)
  1173. {
  1174. int32_t rawFrequency;
  1175. uint32_t segmentAddress;
  1176. PLSR_RESULT result;
  1177. if ((snapshot == NULL) || (frequency == NULL) || (clamped == NULL)
  1178. || (segment < 1U) || (segment > snapshot->segmentCount))
  1179. {
  1180. return PLSR_RESULT_INVALID_ARGUMENT;
  1181. }
  1182. if ((snapshot->segments[segment - 1U].flags
  1183. & PLSR_SEGMENT_FLAG_ZERO_PULSE)
  1184. != 0U)
  1185. {
  1186. *frequency = 0UL;
  1187. *clamped = 0U;
  1188. return PLSR_RESULT_OK;
  1189. }
  1190. segmentAddress = snapshot->s0.address
  1191. + (uint32_t)segment * PLSR_S0_SEGMENT_WORDS;
  1192. result = PlsrReadInt32(&snapshot->source,
  1193. snapshot->s0.device,
  1194. segmentAddress,
  1195. &rawFrequency,
  1196. PLSR_PARSE_BLOCK_S0,
  1197. segment,
  1198. NULL);
  1199. if (result != PLSR_RESULT_OK) return result;
  1200. if (rawFrequency < 0) return PLSR_RESULT_INVALID_FREQUENCY;
  1201. *frequency = (rawFrequency == 0) ? snapshot->s2.defaultSpeed
  1202. : (uint32_t)rawFrequency;
  1203. *clamped = 0U;
  1204. if (*frequency > snapshot->s2.maximumSpeed)
  1205. {
  1206. *frequency = snapshot->s2.maximumSpeed;
  1207. *clamped = 1U;
  1208. }
  1209. if (*frequency == 0UL) return PLSR_RESULT_INVALID_FREQUENCY;
  1210. return PlsrValidateFrequencyDivider(snapshot, *frequency, NULL, segment);
  1211. }