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.
 
 
 
 
 
 

1407 lines
50 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. PLC_DEVICE_RESULT deviceResult;
  180. deviceResult = (useHsd != 0U) ? PlcDeviceReadHsd(address, value)
  181. : PlcDeviceReadSfd(address, value);
  182. if (deviceResult != PLC_DEVICE_OK)
  183. {
  184. PlsrSetDetail(detail,
  185. PLSR_RESULT_INVALID_S2,
  186. PLSR_PARSE_BLOCK_S2,
  187. address,
  188. 0,
  189. 0U);
  190. return PLSR_RESULT_INVALID_S2;
  191. }
  192. return PLSR_RESULT_OK;
  193. }
  194. static PLSR_RESULT PlsrReadFixedDword(uint8_t useHsd,
  195. uint16_t address,
  196. uint32_t *value,
  197. PLSR_PARSE_DETAIL *detail)
  198. {
  199. uint16_t lowWord;
  200. uint16_t highWord;
  201. PLSR_RESULT result;
  202. result = PlsrReadFixedWord(useHsd, address, &lowWord, detail);
  203. if (result != PLSR_RESULT_OK)
  204. {
  205. return result;
  206. }
  207. result = PlsrReadFixedWord(useHsd,
  208. (uint16_t)(address + 1U),
  209. &highWord,
  210. detail);
  211. if (result != PLSR_RESULT_OK)
  212. {
  213. return result;
  214. }
  215. *value = ((uint32_t)highWord << 16U) | (uint32_t)lowWord;
  216. return PLSR_RESULT_OK;
  217. }
  218. PLSR_RESULT PlsrCalculateTimerDivider(uint32_t timerClockHz,
  219. uint32_t frequencyHz,
  220. uint16_t *psc,
  221. uint16_t *arr)
  222. {
  223. uint64_t minimumDivider;
  224. uint64_t periodTicks;
  225. if ((timerClockHz == 0UL) || (frequencyHz == 0UL) || (psc == NULL)
  226. || (arr == NULL))
  227. {
  228. return PLSR_RESULT_INVALID_ARGUMENT;
  229. }
  230. minimumDivider = ((uint64_t)timerClockHz
  231. + ((uint64_t)frequencyHz * 65536ULL) - 1ULL)
  232. / ((uint64_t)frequencyHz * 65536ULL);
  233. if (minimumDivider == 0ULL)
  234. {
  235. minimumDivider = 1ULL;
  236. }
  237. if (minimumDivider > 65536ULL)
  238. {
  239. return PLSR_RESULT_DIVIDER_UNREPRESENTABLE;
  240. }
  241. periodTicks = ((uint64_t)timerClockHz
  242. + ((uint64_t)frequencyHz * minimumDivider) / 2ULL)
  243. / ((uint64_t)frequencyHz * minimumDivider);
  244. if ((periodTicks < 2ULL) || (periodTicks > 65536ULL))
  245. {
  246. return PLSR_RESULT_DIVIDER_UNREPRESENTABLE;
  247. }
  248. *psc = (uint16_t)(minimumDivider - 1ULL);
  249. *arr = (uint16_t)(periodTicks - 1ULL);
  250. return PLSR_RESULT_OK;
  251. }
  252. static PLSR_RESULT PlsrValidateFrequencyDivider(
  253. const PLSR_JOB_SNAPSHOT *snapshot,
  254. uint32_t frequency,
  255. PLSR_PARSE_DETAIL *detail,
  256. uint16_t segment)
  257. {
  258. uint16_t psc;
  259. uint16_t arr;
  260. PLSR_RESULT result;
  261. result = PlsrCalculateTimerDivider(snapshot->timerClockHz,
  262. frequency,
  263. &psc,
  264. &arr);
  265. if ((result == PLSR_RESULT_OK)
  266. && (snapshot->pairedTimerClockHz != 0UL))
  267. {
  268. result = PlsrCalculateTimerDivider(snapshot->pairedTimerClockHz,
  269. frequency,
  270. &psc,
  271. &arr);
  272. }
  273. if (result != PLSR_RESULT_OK)
  274. {
  275. PlsrSetDetail(detail,
  276. PLSR_RESULT_DIVIDER_UNREPRESENTABLE,
  277. PLSR_PARSE_BLOCK_S0,
  278. snapshot->s0.address
  279. + (uint32_t)segment * PLSR_S0_SEGMENT_WORDS,
  280. (int32_t)frequency,
  281. segment);
  282. return PLSR_RESULT_DIVIDER_UNREPRESENTABLE;
  283. }
  284. return PLSR_RESULT_OK;
  285. }
  286. static PLSR_RESULT PlsrResolveOperand(const PLSR_CALL *call,
  287. const PLSR_VALUE_OPERAND *operand,
  288. int32_t *value,
  289. PLSR_PARSE_DETAIL *detail)
  290. {
  291. PLSR_RESULT result;
  292. if (operand->type == PLSR_OPERAND_CONSTANT)
  293. {
  294. *value = operand->constant;
  295. return PLSR_RESULT_OK;
  296. }
  297. if ((operand->type != PLSR_OPERAND_DATA)
  298. || (PlsrIsWordDevice(operand->data.device) == 0U))
  299. {
  300. PlsrSetDetail(detail,
  301. PLSR_RESULT_INVALID_S2,
  302. PLSR_PARSE_BLOCK_S2,
  303. operand->data.address,
  304. (int32_t)operand->type,
  305. 0U);
  306. return PLSR_RESULT_INVALID_S2;
  307. }
  308. result = PlsrValidateRange(&call->source,
  309. operand->data,
  310. 2UL,
  311. PLSR_PARSE_BLOCK_S2,
  312. detail);
  313. if (result != PLSR_RESULT_OK)
  314. {
  315. return result;
  316. }
  317. return PlsrReadInt32(&call->source,
  318. operand->data.device,
  319. operand->data.address,
  320. value,
  321. PLSR_PARSE_BLOCK_S2,
  322. 0U,
  323. detail);
  324. }
  325. static PLSR_RESULT PlsrLoadS2(const PLSR_CALL *call,
  326. PLSR_JOB_SNAPSHOT *snapshot,
  327. PLSR_PARSE_DETAIL *detail)
  328. {
  329. uint16_t commonBase;
  330. uint16_t setBase;
  331. uint16_t word;
  332. int32_t selectedSet;
  333. uint8_t useHsd;
  334. PLSR_RESULT result;
  335. result = PlsrResolveOperand(call, &call->s2, &selectedSet, detail);
  336. if (result != PLSR_RESULT_OK)
  337. {
  338. return result;
  339. }
  340. if ((selectedSet < 0) || (selectedSet > 4))
  341. {
  342. PlsrSetDetail(detail,
  343. PLSR_RESULT_INVALID_S2,
  344. PLSR_PARSE_BLOCK_S2,
  345. call->s2.data.address,
  346. selectedSet,
  347. 0U);
  348. return PLSR_RESULT_INVALID_S2;
  349. }
  350. snapshot->s2Set = (uint8_t)selectedSet;
  351. commonBase = (uint16_t)(PLSR_SFD_CONFIG_START
  352. + (uint16_t)call->dAxis
  353. * PLSR_SFD_AXIS_STRIDE);
  354. if (snapshot->s2Set == 0U)
  355. {
  356. useHsd = 1U;
  357. setBase = (uint16_t)(PLSR_HSD_SET_BASE
  358. + (uint16_t)call->dAxis * PLSR_S2_SET_WORDS);
  359. }
  360. else
  361. {
  362. useHsd = 0U;
  363. setBase = (uint16_t)(commonBase + PLSR_SFD_SET_OFFSET
  364. + (uint16_t)(snapshot->s2Set - 1U)
  365. * PLSR_S2_SET_WORDS);
  366. }
  367. result = PlsrReadFixedDword(useHsd,
  368. setBase,
  369. &snapshot->s2.defaultSpeed,
  370. detail);
  371. if (result != PLSR_RESULT_OK) return result;
  372. result = PlsrReadFixedWord(useHsd,
  373. (uint16_t)(setBase + 2U),
  374. &snapshot->s2.accelerationMs,
  375. detail);
  376. if (result != PLSR_RESULT_OK) return result;
  377. result = PlsrReadFixedWord(useHsd,
  378. (uint16_t)(setBase + 3U),
  379. &snapshot->s2.decelerationMs,
  380. detail);
  381. if (result != PLSR_RESULT_OK) return result;
  382. result = PlsrReadFixedWord(useHsd,
  383. (uint16_t)(setBase + 4U),
  384. &snapshot->s2.gapAccelerationMs,
  385. detail);
  386. if (result != PLSR_RESULT_OK) return result;
  387. result = PlsrReadFixedWord(useHsd,
  388. (uint16_t)(setBase + 5U),
  389. &word,
  390. detail);
  391. if (result != PLSR_RESULT_OK) return result;
  392. snapshot->s2.curveMode = (uint8_t)(word & 0x03U);
  393. result = PlsrReadFixedDword(useHsd,
  394. (uint16_t)(setBase + 6U),
  395. &snapshot->s2.maximumSpeed,
  396. detail);
  397. if (result != PLSR_RESULT_OK) return result;
  398. result = PlsrReadFixedDword(useHsd,
  399. (uint16_t)(setBase + 8U),
  400. &snapshot->s2.startSpeed,
  401. detail);
  402. if (result != PLSR_RESULT_OK) return result;
  403. result = PlsrReadFixedDword(useHsd,
  404. (uint16_t)(setBase + 10U),
  405. &snapshot->s2.stopSpeed,
  406. detail);
  407. if (result != PLSR_RESULT_OK) return result;
  408. result = PlsrReadFixedWord(useHsd,
  409. (uint16_t)(setBase + 12U),
  410. &word,
  411. detail);
  412. if (result != PLSR_RESULT_OK) return result;
  413. if ((word < 1U) || (word > 100U))
  414. {
  415. PlsrSetDetail(detail,
  416. PLSR_RESULT_INVALID_S2,
  417. PLSR_PARSE_BLOCK_S2,
  418. (uint16_t)(setBase + 12U),
  419. word,
  420. 0U);
  421. return PLSR_RESULT_INVALID_S2;
  422. }
  423. snapshot->s2.follow = (uint8_t)word;
  424. result = PlsrReadFixedWord(useHsd,
  425. (uint16_t)(setBase + 13U),
  426. &word,
  427. detail);
  428. if (result != PLSR_RESULT_OK) return result;
  429. if (word > 100U)
  430. {
  431. PlsrSetDetail(detail,
  432. PLSR_RESULT_INVALID_S2,
  433. PLSR_PARSE_BLOCK_S2,
  434. (uint16_t)(setBase + 13U),
  435. word,
  436. 0U);
  437. return PLSR_RESULT_INVALID_S2;
  438. }
  439. snapshot->s2.feedforwardPercent = (uint8_t)word;
  440. result = PlsrReadFixedWord(useHsd,
  441. (uint16_t)(setBase + 14U),
  442. &word,
  443. detail);
  444. if (result != PLSR_RESULT_OK) return result;
  445. snapshot->s2.refreshCode = (uint8_t)(word & 0x03U);
  446. result = PlsrReadFixedDword(useHsd,
  447. (uint16_t)(setBase + 16U),
  448. &snapshot->s2.zrnHighSpeed,
  449. detail);
  450. if (result != PLSR_RESULT_OK) return result;
  451. result = PlsrReadFixedDword(useHsd,
  452. (uint16_t)(setBase + 18U),
  453. &snapshot->s2.zrnCrawlSpeed,
  454. detail);
  455. if (result != PLSR_RESULT_OK) return result;
  456. result = PlsrReadFixedWord(0U, commonBase, &word, detail);
  457. if (result != PLSR_RESULT_OK) return result;
  458. snapshot->directionActiveHigh = ((word & (1U << 1U)) != 0U) ? 1U : 0U;
  459. snapshot->equivalent.unitCode = (uint8_t)((word >> 8U) & 0x07U);
  460. if (PlsrPositionUnitCodeIsValid(snapshot->equivalent.unitCode) == 0U)
  461. {
  462. PlsrSetDetail(detail,
  463. PLSR_RESULT_INVALID_S2,
  464. PLSR_PARSE_BLOCK_S2,
  465. commonBase,
  466. snapshot->equivalent.unitCode,
  467. 0U);
  468. return PLSR_RESULT_INVALID_S2;
  469. }
  470. result = PlsrReadFixedDword(0U,
  471. (uint16_t)(commonBase + 2U),
  472. &snapshot->equivalent.pulsesPerRevolution,
  473. detail);
  474. if (result != PLSR_RESULT_OK) return result;
  475. result = PlsrReadFixedDword(0U,
  476. (uint16_t)(commonBase + 4U),
  477. &snapshot->equivalent.movementPerRevolution,
  478. detail);
  479. if (result != PLSR_RESULT_OK) return result;
  480. if (PlsrPositionValidateEquivalent(&snapshot->equivalent)
  481. != PLSR_RESULT_OK)
  482. {
  483. uint16_t invalidAddress =
  484. (snapshot->equivalent.pulsesPerRevolution == 0UL)
  485. ? (uint16_t)(commonBase + 2U)
  486. : (uint16_t)(commonBase + 4U);
  487. PlsrSetDetail(detail,
  488. PLSR_RESULT_INVALID_S2,
  489. PLSR_PARSE_BLOCK_S2,
  490. invalidAddress,
  491. 0,
  492. 0U);
  493. return PLSR_RESULT_INVALID_S2;
  494. }
  495. if (call->outputModeOverride == PLSR_OUTPUT_MODE_FROM_SFD)
  496. {
  497. snapshot->outputMode = ((word & (1U << 13U)) != 0U)
  498. ? (uint8_t)PLSR_OUTPUT_AB
  499. : (uint8_t)PLSR_OUTPUT_PULSE_DIR;
  500. }
  501. else if (call->outputModeOverride <= (uint8_t)PLSR_OUTPUT_CW_CCW)
  502. {
  503. snapshot->outputMode = call->outputModeOverride;
  504. }
  505. else
  506. {
  507. PlsrSetDetail(detail,
  508. PLSR_RESULT_INVALID_RESOURCE,
  509. PLSR_PARSE_BLOCK_OUTPUT,
  510. commonBase,
  511. call->outputModeOverride,
  512. 0U);
  513. return PLSR_RESULT_INVALID_RESOURCE;
  514. }
  515. result = PlsrReadFixedWord(0U,
  516. (uint16_t)(commonBase + 6U),
  517. &word,
  518. detail);
  519. if (result != PLSR_RESULT_OK) return result;
  520. if (word > UINT8_MAX)
  521. {
  522. PlsrSetDetail(detail,
  523. PLSR_RESULT_INVALID_RESOURCE,
  524. PLSR_PARSE_BLOCK_OUTPUT,
  525. (uint16_t)(commonBase + 6U),
  526. word,
  527. 0U);
  528. return PLSR_RESULT_INVALID_RESOURCE;
  529. }
  530. snapshot->directionPoint = (uint8_t)word;
  531. result = PlsrReadFixedWord(0U,
  532. (uint16_t)(commonBase + 7U),
  533. &snapshot->s2.directionDelayMs,
  534. detail);
  535. if (result != PLSR_RESULT_OK) return result;
  536. if ((snapshot->s2.maximumSpeed < PLSR_FREQUENCY_MIN_HZ)
  537. || (snapshot->s2.maximumSpeed > PLSR_FREQUENCY_MAX_HZ)
  538. || (snapshot->s2.curveMode > 2U) || (snapshot->s2.follow < 1U)
  539. || (snapshot->s2.follow > 100U)
  540. || (snapshot->s2.feedforwardPercent > 100U)
  541. || ((snapshot->s2.refreshCode != 0U)
  542. && (snapshot->s2.refreshCode != 2U)))
  543. {
  544. PlsrSetDetail(detail,
  545. PLSR_RESULT_INVALID_S2,
  546. PLSR_PARSE_BLOCK_S2,
  547. setBase,
  548. (int32_t)snapshot->s2.maximumSpeed,
  549. 0U);
  550. return PLSR_RESULT_INVALID_S2;
  551. }
  552. if (snapshot->s2.startSpeed > snapshot->s2.maximumSpeed)
  553. {
  554. snapshot->s2.startSpeed = snapshot->s2.maximumSpeed;
  555. snapshot->speedClamped = 1U;
  556. }
  557. if (snapshot->s2.stopSpeed > snapshot->s2.maximumSpeed)
  558. {
  559. snapshot->s2.stopSpeed = snapshot->s2.maximumSpeed;
  560. snapshot->speedClamped = 1U;
  561. }
  562. snapshot->inputDefaultSpeed = snapshot->s2.defaultSpeed;
  563. snapshot->inputMaximumSpeed = snapshot->s2.maximumSpeed;
  564. return PLSR_RESULT_OK;
  565. }
  566. static PLSR_RESULT PlsrValidateVariableReference(
  567. const PLSR_CALL *call,
  568. uint8_t sourceCode,
  569. int32_t addressValue,
  570. uint8_t bitReference,
  571. int32_t *currentValue,
  572. PLSR_PARSE_BLOCK block,
  573. uint16_t segment,
  574. PLSR_PARSE_DETAIL *detail)
  575. {
  576. PLSR_DEVICE_TYPE device;
  577. PLSR_DATA_REF reference;
  578. uint8_t bitValue;
  579. PLSR_RESULT result;
  580. if ((sourceCode == 0U) || (sourceCode > 6U) || (addressValue < 0))
  581. {
  582. PlsrSetDetail(detail,
  583. (block == PLSR_PARSE_BLOCK_S0)
  584. ? PLSR_RESULT_INVALID_WAIT
  585. : PLSR_RESULT_DATA_ACCESS,
  586. block,
  587. (uint32_t)addressValue,
  588. sourceCode,
  589. segment);
  590. return (block == PLSR_PARSE_BLOCK_S0) ? PLSR_RESULT_INVALID_WAIT
  591. : PLSR_RESULT_DATA_ACCESS;
  592. }
  593. device = (PLSR_DEVICE_TYPE)(sourceCode - 1U);
  594. if (bitReference != 0U)
  595. {
  596. if ((device < PLSR_DEVICE_X) || (call->source.readBit == NULL)
  597. || (call->source.readBit(call->source.context,
  598. device,
  599. (uint32_t)addressValue,
  600. &bitValue)
  601. == 0U))
  602. {
  603. PlsrSetDetail(detail,
  604. PLSR_RESULT_INVALID_WAIT,
  605. block,
  606. (uint32_t)addressValue,
  607. sourceCode,
  608. segment);
  609. return PLSR_RESULT_INVALID_WAIT;
  610. }
  611. *currentValue = (int32_t)bitValue;
  612. return PLSR_RESULT_OK;
  613. }
  614. if (PlsrIsWordDevice(device) == 0U)
  615. {
  616. PlsrSetDetail(detail,
  617. PLSR_RESULT_INVALID_WAIT,
  618. block,
  619. (uint32_t)addressValue,
  620. sourceCode,
  621. segment);
  622. return PLSR_RESULT_INVALID_WAIT;
  623. }
  624. reference.device = device;
  625. reference.address = (uint32_t)addressValue;
  626. result = PlsrValidateRange(&call->source,
  627. reference,
  628. 2UL,
  629. block,
  630. detail);
  631. if (result != PLSR_RESULT_OK)
  632. {
  633. return result;
  634. }
  635. return PlsrReadInt32(&call->source,
  636. device,
  637. reference.address,
  638. currentValue,
  639. block,
  640. segment,
  641. detail);
  642. }
  643. static PLSR_RESULT PlsrValidateWait(const PLSR_CALL *call,
  644. PLSR_SEGMENT_SNAPSHOT *segmentData,
  645. uint16_t segment,
  646. PLSR_PARSE_DETAIL *detail)
  647. {
  648. int32_t currentValue;
  649. PLSR_RESULT result;
  650. if ((segmentData->waitCondition > PLSR_WAIT_EXT_OR_COMPLETE)
  651. || (segmentData->waitSource > PLSR_VALUE_HM))
  652. {
  653. goto invalidWait;
  654. }
  655. if (segmentData->waitCondition == PLSR_WAIT_PULSE_COMPLETE)
  656. {
  657. if (segmentData->waitSource != PLSR_VALUE_CONSTANT)
  658. {
  659. goto invalidWait;
  660. }
  661. return PLSR_RESULT_OK;
  662. }
  663. if ((segmentData->waitCondition == PLSR_WAIT_TIME)
  664. || (segmentData->waitCondition == PLSR_WAIT_ACT_TIME))
  665. {
  666. if (segmentData->waitSource == PLSR_VALUE_CONSTANT)
  667. {
  668. currentValue = segmentData->waitValueOrAddress;
  669. }
  670. else
  671. {
  672. if (segmentData->waitSource > PLSR_VALUE_FD)
  673. {
  674. goto invalidWait;
  675. }
  676. result = PlsrValidateVariableReference(call,
  677. segmentData->waitSource,
  678. segmentData->waitValueOrAddress,
  679. 0U,
  680. &currentValue,
  681. PLSR_PARSE_BLOCK_S0,
  682. segment,
  683. detail);
  684. if (result != PLSR_RESULT_OK) return result;
  685. }
  686. if (currentValue < 0) goto invalidWait;
  687. return PLSR_RESULT_OK;
  688. }
  689. if (segmentData->waitCondition == PLSR_WAIT_SIGNAL)
  690. {
  691. if ((segmentData->waitSource < PLSR_VALUE_X)
  692. || (segmentData->waitSource > PLSR_VALUE_HM))
  693. {
  694. goto invalidWait;
  695. }
  696. }
  697. else if ((segmentData->waitCondition == PLSR_WAIT_EXT)
  698. || (segmentData->waitCondition == PLSR_WAIT_EXT_OR_COMPLETE))
  699. {
  700. if (segmentData->waitSource != PLSR_VALUE_X)
  701. {
  702. goto invalidWait;
  703. }
  704. }
  705. result = PlsrValidateVariableReference(call,
  706. segmentData->waitSource,
  707. segmentData->waitValueOrAddress,
  708. 1U,
  709. &currentValue,
  710. PLSR_PARSE_BLOCK_S0,
  711. segment,
  712. detail);
  713. return result;
  714. invalidWait:
  715. PlsrSetDetail(detail,
  716. PLSR_RESULT_INVALID_WAIT,
  717. PLSR_PARSE_BLOCK_S0,
  718. call->s0.address
  719. + (uint32_t)segment * PLSR_S0_SEGMENT_WORDS + 4UL,
  720. ((int32_t)segmentData->waitCondition << 8)
  721. | segmentData->waitSource,
  722. segment);
  723. return PLSR_RESULT_INVALID_WAIT;
  724. }
  725. static PLSR_RESULT PlsrValidateJump(const PLSR_CALL *call,
  726. const PLSR_JOB_SNAPSHOT *snapshot,
  727. PLSR_SEGMENT_SNAPSHOT *segmentData,
  728. uint16_t segment,
  729. int32_t *resolvedJump,
  730. PLSR_PARSE_DETAIL *detail)
  731. {
  732. PLSR_RESULT result;
  733. if (segmentData->jumpSource > PLSR_VALUE_FD)
  734. {
  735. goto invalidJump;
  736. }
  737. if (segmentData->jumpSource == PLSR_VALUE_CONSTANT)
  738. {
  739. *resolvedJump = segmentData->jumpValueOrAddress;
  740. }
  741. else
  742. {
  743. result = PlsrValidateVariableReference(call,
  744. segmentData->jumpSource,
  745. segmentData->jumpValueOrAddress,
  746. 0U,
  747. resolvedJump,
  748. PLSR_PARSE_BLOCK_NONE,
  749. segment,
  750. detail);
  751. if (result != PLSR_RESULT_OK)
  752. {
  753. PlsrSetDetail(detail,
  754. PLSR_RESULT_INVALID_JUMP,
  755. PLSR_PARSE_BLOCK_S0,
  756. (uint32_t)segmentData->jumpValueOrAddress,
  757. segmentData->jumpSource,
  758. segment);
  759. return PLSR_RESULT_INVALID_JUMP;
  760. }
  761. }
  762. if ((*resolvedJump < 0)
  763. || (*resolvedJump > (int32_t)snapshot->segmentCount))
  764. {
  765. goto invalidJump;
  766. }
  767. if (*resolvedJump == (int32_t)segment)
  768. {
  769. segmentData->flags |= PLSR_SEGMENT_FLAG_SELF_LOOP;
  770. }
  771. return PLSR_RESULT_OK;
  772. invalidJump:
  773. PlsrSetDetail(detail,
  774. PLSR_RESULT_INVALID_JUMP,
  775. PLSR_PARSE_BLOCK_S0,
  776. call->s0.address
  777. + (uint32_t)segment * PLSR_S0_SEGMENT_WORDS + 7UL,
  778. *resolvedJump,
  779. segment);
  780. return PLSR_RESULT_INVALID_JUMP;
  781. }
  782. static PLSR_RESULT PlsrCheckConstantPath(PLSR_JOB_SNAPSHOT *snapshot,
  783. PLSR_PARSE_DETAIL *detail)
  784. {
  785. uint8_t visited[PLSR_MAX_SEGMENTS];
  786. uint16_t segment = snapshot->startSegment;
  787. int32_t next;
  788. (void)memset(visited, 0, sizeof(visited));
  789. while ((segment >= 1U) && (segment <= snapshot->segmentCount))
  790. {
  791. if (visited[segment - 1U] != 0U)
  792. {
  793. PlsrSetDetail(detail,
  794. PLSR_RESULT_PATH_CYCLE,
  795. PLSR_PARSE_BLOCK_S0,
  796. snapshot->s0.address
  797. + (uint32_t)segment * PLSR_S0_SEGMENT_WORDS
  798. + 8UL,
  799. segment,
  800. segment);
  801. return PLSR_RESULT_PATH_CYCLE;
  802. }
  803. visited[segment - 1U] = 1U;
  804. if (snapshot->segments[segment - 1U].jumpSource
  805. != PLSR_VALUE_CONSTANT)
  806. {
  807. return PLSR_RESULT_OK;
  808. }
  809. next = snapshot->segments[segment - 1U].jumpValueOrAddress;
  810. if (next == (int32_t)segment)
  811. {
  812. snapshot->hasSelfLoop = 1U;
  813. return PLSR_RESULT_OK;
  814. }
  815. if (next == 0)
  816. {
  817. if (segment == snapshot->segmentCount)
  818. {
  819. return PLSR_RESULT_OK;
  820. }
  821. segment++;
  822. }
  823. else
  824. {
  825. segment = (uint16_t)next;
  826. }
  827. }
  828. return PLSR_RESULT_OK;
  829. }
  830. static PLSR_RESULT PlsrCheckInitialPosition(
  831. PLSR_JOB_SNAPSHOT *snapshot,
  832. const PLSR_PARSE_CONTEXT *context,
  833. PLSR_PARSE_DETAIL *detail)
  834. {
  835. uint8_t visited[PLSR_MAX_SEGMENTS];
  836. int64_t position = context->logicalPosition;
  837. int64_t movement;
  838. int64_t targetPosition;
  839. int64_t remainder = 0;
  840. int32_t next;
  841. uint16_t segment = snapshot->startSegment;
  842. PLSR_RESULT result;
  843. if ((snapshot->positioningMode != 0U) && (context->positionValid == 0U))
  844. {
  845. PlsrSetDetail(detail,
  846. PLSR_RESULT_POSITION_INVALID,
  847. PLSR_PARSE_BLOCK_POSITION,
  848. snapshot->s1.address,
  849. 1,
  850. 0U);
  851. return PLSR_RESULT_POSITION_INVALID;
  852. }
  853. (void)memset(visited, 0, sizeof(visited));
  854. while ((segment >= 1U) && (segment <= snapshot->segmentCount)
  855. && (visited[segment - 1U] == 0U))
  856. {
  857. PLSR_SEGMENT_SNAPSHOT *segmentData = &snapshot->segments[segment - 1U];
  858. visited[segment - 1U] = 1U;
  859. if (snapshot->positioningMode == 0U)
  860. {
  861. result = PlsrPositionUnitsToPulses(&snapshot->equivalent,
  862. segmentData->pulseOrTarget,
  863. remainder,
  864. &movement,
  865. &remainder);
  866. if (result != PLSR_RESULT_OK)
  867. {
  868. PlsrSetDetail(detail,
  869. PLSR_RESULT_POSITION_OVERFLOW,
  870. PLSR_PARSE_BLOCK_POSITION,
  871. snapshot->s0.address
  872. + (uint32_t)segment
  873. * PLSR_S0_SEGMENT_WORDS
  874. + 2UL,
  875. segmentData->pulseOrTarget,
  876. segment);
  877. return PLSR_RESULT_POSITION_OVERFLOW;
  878. }
  879. if (((movement > 0) && (position > INT64_MAX - movement))
  880. || ((movement < 0) && (position < INT64_MIN - movement)))
  881. {
  882. PlsrSetDetail(detail,
  883. PLSR_RESULT_POSITION_OVERFLOW,
  884. PLSR_PARSE_BLOCK_POSITION,
  885. snapshot->s0.address
  886. + (uint32_t)segment
  887. * PLSR_S0_SEGMENT_WORDS
  888. + 2UL,
  889. movement,
  890. segment);
  891. return PLSR_RESULT_POSITION_OVERFLOW;
  892. }
  893. position += movement;
  894. }
  895. else
  896. {
  897. result = PlsrPositionAbsoluteUnitsToPulses(
  898. &snapshot->equivalent,
  899. segmentData->pulseOrTarget,
  900. &targetPosition);
  901. if (result != PLSR_RESULT_OK)
  902. {
  903. return PLSR_RESULT_POSITION_OVERFLOW;
  904. }
  905. movement = (targetPosition > position)
  906. ? 1
  907. : ((targetPosition < position) ? -1 : 0);
  908. position = targetPosition;
  909. }
  910. if ((movement != 0) && (snapshot->initialDirectionPositive == 0U))
  911. {
  912. snapshot->initialDirectionPositive = (movement > 0) ? 2U : 1U;
  913. }
  914. if (segmentData->jumpSource != PLSR_VALUE_CONSTANT)
  915. {
  916. break;
  917. }
  918. next = segmentData->jumpValueOrAddress;
  919. if (next == (int32_t)segment)
  920. {
  921. break;
  922. }
  923. if (next == 0)
  924. {
  925. if (segment == snapshot->segmentCount) break;
  926. segment++;
  927. }
  928. else
  929. {
  930. segment = (uint16_t)next;
  931. }
  932. }
  933. snapshot->initialDirectionPositive =
  934. (snapshot->initialDirectionPositive == 2U) ? 1U : 0U;
  935. return PLSR_RESULT_OK;
  936. }
  937. static PLSR_RESULT PlsrConvertSnapshotSpeeds(
  938. PLSR_JOB_SNAPSHOT *snapshot,
  939. PLSR_PARSE_DETAIL *detail)
  940. {
  941. uint16_t segment;
  942. PLSR_RESULT result;
  943. result = PlsrPositionSpeedToPulseFrequency(&snapshot->equivalent,
  944. snapshot->s2.defaultSpeed,
  945. &snapshot->s2.defaultSpeed);
  946. if (result != PLSR_RESULT_OK) return result;
  947. result = PlsrPositionSpeedToPulseFrequency(&snapshot->equivalent,
  948. snapshot->s2.maximumSpeed,
  949. &snapshot->s2.maximumSpeed);
  950. if (result != PLSR_RESULT_OK) return result;
  951. result = PlsrPositionSpeedToPulseFrequency(&snapshot->equivalent,
  952. snapshot->s2.startSpeed,
  953. &snapshot->s2.startSpeed);
  954. if (result != PLSR_RESULT_OK) return result;
  955. result = PlsrPositionSpeedToPulseFrequency(&snapshot->equivalent,
  956. snapshot->s2.stopSpeed,
  957. &snapshot->s2.stopSpeed);
  958. if (result != PLSR_RESULT_OK) return result;
  959. result = PlsrPositionSpeedToPulseFrequency(&snapshot->equivalent,
  960. snapshot->s2.zrnHighSpeed,
  961. &snapshot->s2.zrnHighSpeed);
  962. if (result != PLSR_RESULT_OK) return result;
  963. result = PlsrPositionSpeedToPulseFrequency(&snapshot->equivalent,
  964. snapshot->s2.zrnCrawlSpeed,
  965. &snapshot->s2.zrnCrawlSpeed);
  966. if (result != PLSR_RESULT_OK) return result;
  967. if ((snapshot->s2.maximumSpeed < PLSR_FREQUENCY_MIN_HZ)
  968. || (snapshot->s2.maximumSpeed > PLSR_FREQUENCY_MAX_HZ))
  969. {
  970. PlsrSetDetail(detail,
  971. PLSR_RESULT_INVALID_FREQUENCY,
  972. PLSR_PARSE_BLOCK_S2,
  973. 0UL,
  974. (int32_t)snapshot->s2.maximumSpeed,
  975. 0U);
  976. return PLSR_RESULT_INVALID_FREQUENCY;
  977. }
  978. for (segment = 1U; segment <= snapshot->segmentCount; segment++)
  979. {
  980. PLSR_SEGMENT_SNAPSHOT *segmentData =
  981. &snapshot->segments[segment - 1U];
  982. if (segmentData->targetFrequency == 0UL)
  983. {
  984. continue;
  985. }
  986. result = PlsrPositionSpeedToPulseFrequency(
  987. &snapshot->equivalent,
  988. segmentData->targetFrequency,
  989. &segmentData->targetFrequency);
  990. if ((result != PLSR_RESULT_OK)
  991. || (segmentData->targetFrequency < PLSR_FREQUENCY_MIN_HZ)
  992. || (segmentData->targetFrequency > PLSR_FREQUENCY_MAX_HZ))
  993. {
  994. PlsrSetDetail(detail,
  995. PLSR_RESULT_INVALID_FREQUENCY,
  996. PLSR_PARSE_BLOCK_S0,
  997. snapshot->s0.address
  998. + (uint32_t)segment * PLSR_S0_SEGMENT_WORDS,
  999. (int32_t)segmentData->targetFrequency,
  1000. segment);
  1001. return PLSR_RESULT_INVALID_FREQUENCY;
  1002. }
  1003. result = PlsrValidateFrequencyDivider(snapshot,
  1004. segmentData->targetFrequency,
  1005. detail,
  1006. segment);
  1007. if (result != PLSR_RESULT_OK) return result;
  1008. }
  1009. return PLSR_RESULT_OK;
  1010. }
  1011. PLSR_RESULT PlsrBuildJobSnapshot(const PLSR_CALL *call,
  1012. const PLSR_PARSE_CONTEXT *context,
  1013. PLSR_JOB_SNAPSHOT *snapshot,
  1014. PLSR_PARSE_DETAIL *detail)
  1015. {
  1016. uint64_t s0Words64;
  1017. uint32_t s0Words;
  1018. uint32_t segmentBase;
  1019. int32_t intValue;
  1020. int32_t resolvedJump;
  1021. uint16_t word;
  1022. uint16_t segment;
  1023. uint8_t index;
  1024. PLSR_RESULT result;
  1025. if ((call == NULL) || (context == NULL) || (snapshot == NULL)
  1026. || (PlsrSourceIsUsable(&call->source) == 0U))
  1027. {
  1028. return PLSR_RESULT_INVALID_ARGUMENT;
  1029. }
  1030. if (call->dAxis >= PLSR_AXIS_COUNT)
  1031. {
  1032. return PLSR_RESULT_INVALID_AXIS;
  1033. }
  1034. (void)memset(snapshot, 0, sizeof(*snapshot));
  1035. if (detail != NULL) (void)memset(detail, 0, sizeof(*detail));
  1036. snapshot->source = call->source;
  1037. snapshot->s0 = call->s0;
  1038. snapshot->s1 = call->s1;
  1039. snapshot->dAxis = call->dAxis;
  1040. snapshot->timerClockHz = ((call->dAxis == 0U) || (call->dAxis == 2U))
  1041. ? PLSR_TIMER_168MHZ
  1042. : PLSR_TIMER_84MHZ;
  1043. result = PlsrValidateRange(&call->source,
  1044. call->s0,
  1045. PLSR_S0_HEADER_WORDS,
  1046. PLSR_PARSE_BLOCK_S0,
  1047. detail);
  1048. if (result != PLSR_RESULT_OK) return result;
  1049. result = PlsrReadInt32(&call->source,
  1050. call->s0.device,
  1051. call->s0.address,
  1052. &intValue,
  1053. PLSR_PARSE_BLOCK_S0,
  1054. 0U,
  1055. detail);
  1056. if ((result != PLSR_RESULT_OK) || (intValue < 1)
  1057. || (intValue > (int32_t)PLSR_MAX_SEGMENTS))
  1058. {
  1059. if (result == PLSR_RESULT_OK)
  1060. {
  1061. PlsrSetDetail(detail,
  1062. PLSR_RESULT_SEGMENT_OVERFLOW,
  1063. PLSR_PARSE_BLOCK_S0,
  1064. call->s0.address,
  1065. intValue,
  1066. 0U);
  1067. result = PLSR_RESULT_SEGMENT_OVERFLOW;
  1068. }
  1069. return result;
  1070. }
  1071. snapshot->segmentCount = (uint16_t)intValue;
  1072. s0Words64 = (uint64_t)snapshot->segmentCount * PLSR_S0_SEGMENT_WORDS
  1073. + PLSR_S0_HEADER_WORDS;
  1074. if (s0Words64 > UINT32_MAX)
  1075. {
  1076. return PLSR_RESULT_ADDRESS_OVERFLOW;
  1077. }
  1078. s0Words = (uint32_t)s0Words64;
  1079. result = PlsrValidateRange(&call->source,
  1080. call->s0,
  1081. s0Words,
  1082. PLSR_PARSE_BLOCK_S0,
  1083. detail);
  1084. if (result != PLSR_RESULT_OK) return result;
  1085. result = PlsrValidateRange(&call->source,
  1086. call->s1,
  1087. PLSR_S1_WORDS,
  1088. PLSR_PARSE_BLOCK_S1,
  1089. detail);
  1090. if (result != PLSR_RESULT_OK) return result;
  1091. if (PlsrBlocksOverlap(call->s0, s0Words, call->s1, PLSR_S1_WORDS) != 0U)
  1092. {
  1093. PlsrSetDetail(detail,
  1094. PLSR_RESULT_BLOCK_OVERLAP,
  1095. PLSR_PARSE_BLOCK_S1,
  1096. call->s1.address,
  1097. (int32_t)s0Words,
  1098. 0U);
  1099. return PLSR_RESULT_BLOCK_OVERLAP;
  1100. }
  1101. for (index = 2U; index < 10U; index++)
  1102. {
  1103. result = PlsrReadWord(&call->source,
  1104. call->s0.device,
  1105. call->s0.address + index,
  1106. &word,
  1107. PLSR_PARSE_BLOCK_S0,
  1108. 0U,
  1109. detail);
  1110. if (result != PLSR_RESULT_OK) return result;
  1111. if (word != 0U)
  1112. {
  1113. PlsrSetDetail(detail,
  1114. PLSR_RESULT_RESERVED_NOT_ZERO,
  1115. PLSR_PARSE_BLOCK_S0,
  1116. call->s0.address + index,
  1117. word,
  1118. 0U);
  1119. return PLSR_RESULT_RESERVED_NOT_ZERO;
  1120. }
  1121. }
  1122. result = PlsrReadInt32(&call->source,
  1123. call->s1.device,
  1124. call->s1.address,
  1125. &intValue,
  1126. PLSR_PARSE_BLOCK_S1,
  1127. 0U,
  1128. detail);
  1129. if (result != PLSR_RESULT_OK) return result;
  1130. if ((intValue < 0) || (intValue > 1))
  1131. {
  1132. PlsrSetDetail(detail,
  1133. PLSR_RESULT_INVALID_POSITION_MODE,
  1134. PLSR_PARSE_BLOCK_S1,
  1135. call->s1.address,
  1136. intValue,
  1137. 0U);
  1138. return PLSR_RESULT_INVALID_POSITION_MODE;
  1139. }
  1140. snapshot->positioningMode = (uint8_t)intValue;
  1141. result = PlsrReadInt32(&call->source,
  1142. call->s1.device,
  1143. call->s1.address + 2UL,
  1144. &intValue,
  1145. PLSR_PARSE_BLOCK_S1,
  1146. 0U,
  1147. detail);
  1148. if (result != PLSR_RESULT_OK) return result;
  1149. if ((intValue < 0) || (intValue > snapshot->segmentCount))
  1150. {
  1151. PlsrSetDetail(detail,
  1152. PLSR_RESULT_INVALID_ARGUMENT,
  1153. PLSR_PARSE_BLOCK_S1,
  1154. call->s1.address + 2UL,
  1155. intValue,
  1156. 0U);
  1157. return PLSR_RESULT_INVALID_ARGUMENT;
  1158. }
  1159. snapshot->startSegment = (intValue <= 1) ? 1U : (uint16_t)intValue;
  1160. result = PlsrLoadS2(call, snapshot, detail);
  1161. if (result != PLSR_RESULT_OK) return result;
  1162. if ((snapshot->outputMode == PLSR_OUTPUT_AB)
  1163. || (snapshot->outputMode == PLSR_OUTPUT_CW_CCW))
  1164. {
  1165. if ((call->dAxis != 0U) && (call->dAxis != 2U))
  1166. {
  1167. PlsrSetDetail(detail,
  1168. PLSR_RESULT_INVALID_RESOURCE,
  1169. PLSR_PARSE_BLOCK_OUTPUT,
  1170. call->dAxis,
  1171. snapshot->outputMode,
  1172. 0U);
  1173. return PLSR_RESULT_INVALID_RESOURCE;
  1174. }
  1175. snapshot->pairedTimerClockHz = PLSR_TIMER_84MHZ;
  1176. }
  1177. for (segment = 1U; segment <= snapshot->segmentCount; segment++)
  1178. {
  1179. PLSR_SEGMENT_SNAPSHOT *segmentData = &snapshot->segments[segment - 1U];
  1180. segmentBase = call->s0.address
  1181. + (uint32_t)segment * PLSR_S0_SEGMENT_WORDS;
  1182. result = PlsrReadInt32(&call->source,
  1183. call->s0.device,
  1184. segmentBase,
  1185. &intValue,
  1186. PLSR_PARSE_BLOCK_S0,
  1187. segment,
  1188. detail);
  1189. if (result != PLSR_RESULT_OK) return result;
  1190. if (intValue < 0)
  1191. {
  1192. PlsrSetDetail(detail,
  1193. PLSR_RESULT_INVALID_FREQUENCY,
  1194. PLSR_PARSE_BLOCK_S0,
  1195. segmentBase,
  1196. intValue,
  1197. segment);
  1198. return PLSR_RESULT_INVALID_FREQUENCY;
  1199. }
  1200. segmentData->targetFrequency = (uint32_t)intValue;
  1201. result = PlsrReadInt32(&call->source,
  1202. call->s0.device,
  1203. segmentBase + 2UL,
  1204. &segmentData->pulseOrTarget,
  1205. PLSR_PARSE_BLOCK_S0,
  1206. segment,
  1207. detail);
  1208. if (result != PLSR_RESULT_OK) return result;
  1209. result = PlsrReadWord(&call->source,
  1210. call->s0.device,
  1211. segmentBase + 4UL,
  1212. &word,
  1213. PLSR_PARSE_BLOCK_S0,
  1214. segment,
  1215. detail);
  1216. if (result != PLSR_RESULT_OK) return result;
  1217. segmentData->waitSource = (uint8_t)(word & 0xFFU);
  1218. segmentData->waitCondition = (uint8_t)(word >> 8U);
  1219. result = PlsrReadInt32(&call->source,
  1220. call->s0.device,
  1221. segmentBase + 5UL,
  1222. &segmentData->waitValueOrAddress,
  1223. PLSR_PARSE_BLOCK_S0,
  1224. segment,
  1225. detail);
  1226. if (result != PLSR_RESULT_OK) return result;
  1227. result = PlsrReadWord(&call->source,
  1228. call->s0.device,
  1229. segmentBase + 7UL,
  1230. &word,
  1231. PLSR_PARSE_BLOCK_S0,
  1232. segment,
  1233. detail);
  1234. if (result != PLSR_RESULT_OK) return result;
  1235. if ((word & 0xFF00U) != 0U)
  1236. {
  1237. PlsrSetDetail(detail,
  1238. PLSR_RESULT_RESERVED_NOT_ZERO,
  1239. PLSR_PARSE_BLOCK_S0,
  1240. segmentBase + 7UL,
  1241. word,
  1242. segment);
  1243. return PLSR_RESULT_RESERVED_NOT_ZERO;
  1244. }
  1245. segmentData->jumpSource = (uint8_t)(word & 0xFFU);
  1246. result = PlsrReadInt32(&call->source,
  1247. call->s0.device,
  1248. segmentBase + 8UL,
  1249. &segmentData->jumpValueOrAddress,
  1250. PLSR_PARSE_BLOCK_S0,
  1251. segment,
  1252. detail);
  1253. if (result != PLSR_RESULT_OK) return result;
  1254. if ((snapshot->positioningMode == 0U)
  1255. && (segmentData->pulseOrTarget == 0))
  1256. {
  1257. segmentData->flags |= PLSR_SEGMENT_FLAG_ZERO_PULSE;
  1258. segmentData->targetFrequency = 0UL;
  1259. }
  1260. else if (segmentData->targetFrequency == 0UL)
  1261. {
  1262. if (snapshot->s2.defaultSpeed == 0UL)
  1263. {
  1264. PlsrSetDetail(detail,
  1265. PLSR_RESULT_INVALID_FREQUENCY,
  1266. PLSR_PARSE_BLOCK_S2,
  1267. 0UL,
  1268. 0,
  1269. segment);
  1270. return PLSR_RESULT_INVALID_FREQUENCY;
  1271. }
  1272. segmentData->targetFrequency = snapshot->s2.defaultSpeed;
  1273. segmentData->flags |= PLSR_SEGMENT_FLAG_DEFAULT_SPEED;
  1274. }
  1275. if (segmentData->targetFrequency > snapshot->s2.maximumSpeed)
  1276. {
  1277. segmentData->targetFrequency = snapshot->s2.maximumSpeed;
  1278. segmentData->flags |= PLSR_SEGMENT_FLAG_SPEED_CLAMPED;
  1279. snapshot->speedClamped = 1U;
  1280. }
  1281. result = PlsrValidateWait(call, segmentData, segment, detail);
  1282. if (result != PLSR_RESULT_OK) return result;
  1283. result = PlsrValidateJump(call,
  1284. snapshot,
  1285. segmentData,
  1286. segment,
  1287. &resolvedJump,
  1288. detail);
  1289. if (result != PLSR_RESULT_OK) return result;
  1290. }
  1291. result = PlsrConvertSnapshotSpeeds(snapshot, detail);
  1292. if (result != PLSR_RESULT_OK) return result;
  1293. result = PlsrCheckConstantPath(snapshot, detail);
  1294. if (result != PLSR_RESULT_OK) return result;
  1295. result = PlsrCheckInitialPosition(snapshot, context, detail);
  1296. if (result != PLSR_RESULT_OK) return result;
  1297. if (detail != NULL) detail->result = PLSR_RESULT_OK;
  1298. return PLSR_RESULT_OK;
  1299. }
  1300. PLSR_RESULT PlsrResolveLiveFrequency(const PLSR_JOB_SNAPSHOT *snapshot,
  1301. uint16_t segment,
  1302. uint32_t *frequency,
  1303. uint8_t *clamped)
  1304. {
  1305. int32_t rawFrequency;
  1306. uint32_t segmentAddress;
  1307. PLSR_RESULT result;
  1308. if ((snapshot == NULL) || (frequency == NULL) || (clamped == NULL)
  1309. || (segment < 1U) || (segment > snapshot->segmentCount))
  1310. {
  1311. return PLSR_RESULT_INVALID_ARGUMENT;
  1312. }
  1313. if ((snapshot->segments[segment - 1U].flags
  1314. & PLSR_SEGMENT_FLAG_ZERO_PULSE)
  1315. != 0U)
  1316. {
  1317. *frequency = 0UL;
  1318. *clamped = 0U;
  1319. return PLSR_RESULT_OK;
  1320. }
  1321. segmentAddress = snapshot->s0.address
  1322. + (uint32_t)segment * PLSR_S0_SEGMENT_WORDS;
  1323. result = PlsrReadInt32(&snapshot->source,
  1324. snapshot->s0.device,
  1325. segmentAddress,
  1326. &rawFrequency,
  1327. PLSR_PARSE_BLOCK_S0,
  1328. segment,
  1329. NULL);
  1330. if (result != PLSR_RESULT_OK) return result;
  1331. if (rawFrequency < 0) return PLSR_RESULT_INVALID_FREQUENCY;
  1332. *frequency = (rawFrequency == 0) ? snapshot->inputDefaultSpeed
  1333. : (uint32_t)rawFrequency;
  1334. *clamped = 0U;
  1335. if (*frequency > snapshot->inputMaximumSpeed)
  1336. {
  1337. *frequency = snapshot->inputMaximumSpeed;
  1338. *clamped = 1U;
  1339. }
  1340. if (*frequency == 0UL) return PLSR_RESULT_INVALID_FREQUENCY;
  1341. result = PlsrPositionSpeedToPulseFrequency(&snapshot->equivalent,
  1342. *frequency,
  1343. frequency);
  1344. if ((result != PLSR_RESULT_OK) || (*frequency == 0UL)
  1345. || (*frequency > PLSR_FREQUENCY_MAX_HZ))
  1346. {
  1347. return PLSR_RESULT_INVALID_FREQUENCY;
  1348. }
  1349. return PlsrValidateFrequencyDivider(snapshot, *frequency, NULL, segment);
  1350. }