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.
 
 
 
 
 
 

457 line
15 KiB

  1. #include "plsr_path.h"
  2. #include <string.h>
  3. /* 等待寄存器类型编码(PLSR_VALUE_SOURCE)与软元件类型(PLSR_DEVICE_TYPE)
  4. * 相差 1:D=1→D、HD=2→HD、FD=3→FD、X=4→X、M=5→M、HM=6→HM。 */
  5. static uint8_t PlsrPathDeviceFromSource(uint8_t sourceCode)
  6. {
  7. return (uint8_t)(sourceCode - 1U);
  8. }
  9. static uint8_t PlsrPathReadDword(const PLSR_DATA_SOURCE *source,
  10. PLSR_DEVICE_TYPE device,
  11. uint32_t address,
  12. int32_t *value)
  13. {
  14. uint16_t lowWord;
  15. uint16_t highWord;
  16. if ((source->readWord == NULL)
  17. || (source->readWord(source->context,
  18. device,
  19. address,
  20. &lowWord) == 0U)
  21. || (source->readWord(source->context,
  22. device,
  23. address + 1U,
  24. &highWord) == 0U))
  25. {
  26. return 0U;
  27. }
  28. *value = (int32_t)(((uint32_t)highWord << 16U) | (uint32_t)lowWord);
  29. return 1U;
  30. }
  31. static uint8_t PlsrPathReadBit(const PLSR_DATA_SOURCE *source,
  32. PLSR_DEVICE_TYPE device,
  33. uint32_t address,
  34. uint8_t *value)
  35. {
  36. if ((source->readBit == NULL)
  37. || (source->readBit(source->context, device, address, value) == 0U))
  38. {
  39. return 0U;
  40. }
  41. return 1U;
  42. }
  43. /* 求值当前段的跳转目标。
  44. * 返回:0=顺序下一段,1~segmentCount=指定段。
  45. * 动态来源在跳转发生时重新读取;非法值置 error。 */
  46. static int32_t PlsrPathResolveJumpTarget(const PLSR_JOB_SNAPSHOT *job,
  47. uint16_t segment,
  48. uint8_t *error)
  49. {
  50. const PLSR_SEGMENT_SNAPSHOT *segmentSnapshot =
  51. &job->segments[segment - 1U];
  52. int32_t target;
  53. *error = 0U;
  54. if (segmentSnapshot->jumpSource == PLSR_VALUE_CONSTANT)
  55. {
  56. target = segmentSnapshot->jumpValueOrAddress;
  57. }
  58. else
  59. {
  60. if (PlsrPathReadDword(&job->source,
  61. (PLSR_DEVICE_TYPE)PlsrPathDeviceFromSource(
  62. segmentSnapshot->jumpSource),
  63. (uint32_t)segmentSnapshot->jumpValueOrAddress,
  64. &target) == 0U)
  65. {
  66. *error = 1U;
  67. return 0;
  68. }
  69. }
  70. if ((target < 0) || (target > (int32_t)job->segmentCount))
  71. {
  72. *error = 1U;
  73. return 0;
  74. }
  75. return target;
  76. }
  77. /* 段是否零脉冲:相对模式脉冲数为 0,或绝对模式目标等于进入段时的位置。 */
  78. static uint8_t PlsrPathSegmentIsZeroPulse(const PLSR_JOB_SNAPSHOT *job,
  79. uint16_t segment,
  80. int64_t logicalPosition)
  81. {
  82. const PLSR_SEGMENT_SNAPSHOT *segmentSnapshot =
  83. &job->segments[segment - 1U];
  84. if ((segmentSnapshot->flags & PLSR_SEGMENT_FLAG_ZERO_PULSE) != 0U)
  85. {
  86. return 1U;
  87. }
  88. if ((job->positioningMode == 1U)
  89. && (segmentSnapshot->pulseOrTarget == (int32_t)logicalPosition))
  90. {
  91. return 1U;
  92. }
  93. return 0U;
  94. }
  95. /* 进入新段时的初始化:求值 ACT 时间、EXT/等待信号地址与当前电平。 */
  96. static void PlsrPathEnterSegment(PLSR_PATH_CONTEXT *context,
  97. const PLSR_JOB_SNAPSHOT *job)
  98. {
  99. const PLSR_SEGMENT_SNAPSHOT *segmentSnapshot =
  100. &job->segments[context->currentSegment - 1U];
  101. int32_t actValue;
  102. context->segmentEnded = 0U;
  103. context->extActive = 0U;
  104. context->actActive = 0U;
  105. context->waitCondition = (uint8_t)segmentSnapshot->waitCondition;
  106. switch (context->waitCondition)
  107. {
  108. case PLSR_WAIT_ACT_TIME:
  109. context->actActive = 1U;
  110. if (segmentSnapshot->waitSource == PLSR_VALUE_CONSTANT)
  111. {
  112. actValue = segmentSnapshot->waitValueOrAddress;
  113. }
  114. else
  115. {
  116. actValue = 0;
  117. (void)PlsrPathReadDword(&job->source,
  118. (PLSR_DEVICE_TYPE)
  119. PlsrPathDeviceFromSource(
  120. segmentSnapshot->waitSource),
  121. (uint32_t)
  122. segmentSnapshot->waitValueOrAddress,
  123. &actValue);
  124. }
  125. context->waitRemainingMs =
  126. (actValue > 0) ? (uint32_t)actValue : 0U;
  127. break;
  128. case PLSR_WAIT_SIGNAL:
  129. case PLSR_WAIT_EXT:
  130. case PLSR_WAIT_EXT_OR_COMPLETE:
  131. context->waitSignalDevice =
  132. PlsrPathDeviceFromSource(segmentSnapshot->waitSource);
  133. context->waitSignalAddress =
  134. (uint32_t)segmentSnapshot->waitValueOrAddress;
  135. if (context->waitCondition != PLSR_WAIT_SIGNAL)
  136. {
  137. /* EXT:记录段开始时的电平,已有的有效电平不算新边沿。 */
  138. uint8_t level = 0U;
  139. (void)PlsrPathReadBit(&job->source,
  140. (PLSR_DEVICE_TYPE)
  141. context->waitSignalDevice,
  142. context->waitSignalAddress,
  143. &level);
  144. context->lastExtLevel = level;
  145. context->extActive = 1U;
  146. }
  147. break;
  148. default:
  149. break;
  150. }
  151. }
  152. /* EXT 边沿检测:电平 0→1 才算新边沿。 */
  153. static uint8_t PlsrPathPollExt(PLSR_PATH_CONTEXT *context,
  154. const PLSR_JOB_SNAPSHOT *job)
  155. {
  156. uint8_t level = 0U;
  157. uint8_t triggered = 0U;
  158. if (PlsrPathReadBit(&job->source,
  159. (PLSR_DEVICE_TYPE)context->waitSignalDevice,
  160. context->waitSignalAddress,
  161. &level) != 0U)
  162. {
  163. if ((level != 0U) && (context->lastExtLevel == 0U))
  164. {
  165. triggered = 1U;
  166. }
  167. context->lastExtLevel = level;
  168. }
  169. return triggered;
  170. }
  171. /* 推进跳转链:零脉冲段连续跳转(预算内),直到有脉冲段、结束或预算耗尽。 */
  172. static PLSR_PATH_ACTION PlsrPathAdvance(PLSR_PATH_CONTEXT *context,
  173. const PLSR_JOB_SNAPSHOT *job,
  174. int64_t logicalPosition)
  175. {
  176. uint8_t error;
  177. int32_t target;
  178. uint16_t next;
  179. while (context->zeroJumpBudget > 0U)
  180. {
  181. target = PlsrPathResolveJumpTarget(job,
  182. context->currentSegment,
  183. &error);
  184. if (error != 0U)
  185. {
  186. context->jobEnded = 1U;
  187. context->phase = PLSR_PATH_ENDED;
  188. return PLSR_PATH_ACTION_ERROR;
  189. }
  190. if (target == 0)
  191. {
  192. if (context->currentSegment >= job->segmentCount)
  193. {
  194. context->jobEnded = 1U;
  195. context->phase = PLSR_PATH_ENDED;
  196. return PLSR_PATH_ACTION_JOB_COMPLETE;
  197. }
  198. next = (uint16_t)(context->currentSegment + 1U);
  199. }
  200. else
  201. {
  202. next = (uint16_t)target;
  203. }
  204. if (PlsrPathSegmentIsZeroPulse(job, next, logicalPosition) != 0U)
  205. {
  206. context->zeroJumpBudget--;
  207. context->currentSegment = next;
  208. context->nextSegment = next;
  209. PlsrPathEnterSegment(context, job);
  210. continue;
  211. }
  212. context->currentSegment = next;
  213. context->nextSegment = next;
  214. context->phase = PLSR_PATH_SEGMENT_RUNNING;
  215. PlsrPathEnterSegment(context, job);
  216. return PLSR_PATH_ACTION_NEXT_SEGMENT;
  217. }
  218. context->jumpChainPending = 1U;
  219. return PLSR_PATH_ACTION_YIELD;
  220. }
  221. void PlsrPathBegin(PLSR_PATH_CONTEXT *context,
  222. const PLSR_JOB_SNAPSHOT *job,
  223. int64_t logicalPosition)
  224. {
  225. (void)memset(context, 0, sizeof(*context));
  226. context->currentSegment = job->startSegment;
  227. context->nextSegment = context->currentSegment;
  228. context->zeroJumpBudget = PLSR_PATH_ZERO_JUMP_BUDGET;
  229. context->phase = PLSR_PATH_SEGMENT_RUNNING;
  230. PlsrPathEnterSegment(context, job);
  231. if (PlsrPathSegmentIsZeroPulse(job,
  232. context->currentSegment,
  233. logicalPosition) != 0U)
  234. {
  235. /* 起点段就是零脉冲:直接走跳转链。 */
  236. (void)PlsrPathAdvance(context, job, logicalPosition);
  237. }
  238. }
  239. PLSR_PATH_ACTION PlsrPathOnSegmentDone(PLSR_PATH_CONTEXT *context,
  240. const PLSR_JOB_SNAPSHOT *job,
  241. int64_t logicalPosition)
  242. {
  243. const PLSR_SEGMENT_SNAPSHOT *segmentSnapshot;
  244. int32_t waitValue;
  245. uint8_t level;
  246. if ((context->jobEnded != 0U) || (context->phase == PLSR_PATH_ENDED))
  247. {
  248. return PLSR_PATH_ACTION_NONE;
  249. }
  250. context->segmentEnded = 1U;
  251. context->zeroJumpBudget = PLSR_PATH_ZERO_JUMP_BUDGET;
  252. context->jumpChainPending = 0U;
  253. segmentSnapshot = &job->segments[context->currentSegment - 1U];
  254. switch (context->waitCondition)
  255. {
  256. case PLSR_WAIT_PULSE_COMPLETE:
  257. case PLSR_WAIT_EXT_OR_COMPLETE:
  258. return PlsrPathAdvance(context, job, logicalPosition);
  259. case PLSR_WAIT_TIME:
  260. /* 等待时间在段完成时求值一次。 */
  261. if (segmentSnapshot->waitSource == PLSR_VALUE_CONSTANT)
  262. {
  263. waitValue = segmentSnapshot->waitValueOrAddress;
  264. }
  265. else
  266. {
  267. waitValue = 0;
  268. (void)PlsrPathReadDword(
  269. &job->source,
  270. (PLSR_DEVICE_TYPE)PlsrPathDeviceFromSource(
  271. segmentSnapshot->waitSource),
  272. (uint32_t)segmentSnapshot->waitValueOrAddress,
  273. &waitValue);
  274. }
  275. context->waitRemainingMs =
  276. (waitValue > 0) ? (uint32_t)waitValue : 0U;
  277. if (context->waitRemainingMs == 0U)
  278. {
  279. return PlsrPathAdvance(context, job, logicalPosition);
  280. }
  281. context->phase = PLSR_PATH_WAIT_TIME;
  282. return PLSR_PATH_ACTION_ENTER_WAIT;
  283. case PLSR_WAIT_SIGNAL:
  284. /* 信号地址已在进入段时求值;先立即检查一次,已有效则直接跳。 */
  285. if (PlsrPathReadBit(&job->source,
  286. (PLSR_DEVICE_TYPE)context->waitSignalDevice,
  287. context->waitSignalAddress,
  288. &level) != 0U)
  289. {
  290. if (level != 0U)
  291. {
  292. return PlsrPathAdvance(context, job, logicalPosition);
  293. }
  294. }
  295. context->phase = PLSR_PATH_WAIT_SIGNAL;
  296. return PLSR_PATH_ACTION_ENTER_WAIT;
  297. case PLSR_WAIT_ACT_TIME:
  298. if (context->waitRemainingMs == 0U)
  299. {
  300. return PlsrPathAdvance(context, job, logicalPosition);
  301. }
  302. /* 段已完成但 ACT 未到:停在 ACT_PENDING(core 处于 WAIT)。 */
  303. context->phase = PLSR_PATH_ACT_PENDING;
  304. return PLSR_PATH_ACTION_ENTER_WAIT;
  305. case PLSR_WAIT_EXT:
  306. /* 段已完成但 EXT 未触发:继续等新边沿。 */
  307. context->phase = PLSR_PATH_WAIT_SIGNAL;
  308. return PLSR_PATH_ACTION_ENTER_WAIT;
  309. default:
  310. return PlsrPathAdvance(context, job, logicalPosition);
  311. }
  312. }
  313. PLSR_PATH_ACTION PlsrPathTick(PLSR_PATH_CONTEXT *context,
  314. const PLSR_JOB_SNAPSHOT *job,
  315. int64_t logicalPosition)
  316. {
  317. uint8_t level;
  318. if ((context->jobEnded != 0U) || (context->phase == PLSR_PATH_ENDED))
  319. {
  320. return PLSR_PATH_ACTION_NONE;
  321. }
  322. if (context->jumpChainPending != 0U)
  323. {
  324. /* 上轮预算耗尽让出:本轮重置预算继续跳转链。 */
  325. context->zeroJumpBudget = PLSR_PATH_ZERO_JUMP_BUDGET;
  326. context->jumpChainPending = 0U;
  327. return PlsrPathAdvance(context, job, logicalPosition);
  328. }
  329. switch (context->phase)
  330. {
  331. case PLSR_PATH_SEGMENT_RUNNING:
  332. if ((context->actActive != 0U)
  333. && (context->waitRemainingMs > 0U))
  334. {
  335. context->waitRemainingMs--;
  336. if (context->waitRemainingMs == 0U)
  337. {
  338. /* ACT 到时:截断当前段,立即跳转。 */
  339. return PlsrPathAdvance(context, job, logicalPosition);
  340. }
  341. }
  342. if ((context->extActive != 0U)
  343. && (PlsrPathPollExt(context, job) != 0U))
  344. {
  345. return PlsrPathAdvance(context, job, logicalPosition);
  346. }
  347. break;
  348. case PLSR_PATH_WAIT_TIME:
  349. if (context->waitRemainingMs > 0U)
  350. {
  351. context->waitRemainingMs--;
  352. }
  353. if (context->waitRemainingMs == 0U)
  354. {
  355. return PlsrPathAdvance(context, job, logicalPosition);
  356. }
  357. break;
  358. case PLSR_PATH_WAIT_SIGNAL:
  359. if (context->waitCondition == PLSR_WAIT_SIGNAL)
  360. {
  361. /* H02:电平有效即触发。 */
  362. if (PlsrPathReadBit(&job->source,
  363. (PLSR_DEVICE_TYPE)
  364. context->waitSignalDevice,
  365. context->waitSignalAddress,
  366. &level) != 0U)
  367. {
  368. if (level != 0U)
  369. {
  370. return PlsrPathAdvance(context, job, logicalPosition);
  371. }
  372. }
  373. }
  374. else
  375. {
  376. /* H04 段完成后的 EXT 等待:新边沿触发。 */
  377. if (PlsrPathPollExt(context, job) != 0U)
  378. {
  379. return PlsrPathAdvance(context, job, logicalPosition);
  380. }
  381. }
  382. break;
  383. case PLSR_PATH_ACT_PENDING:
  384. if (context->waitRemainingMs > 0U)
  385. {
  386. context->waitRemainingMs--;
  387. }
  388. if (context->waitRemainingMs == 0U)
  389. {
  390. return PlsrPathAdvance(context, job, logicalPosition);
  391. }
  392. break;
  393. default:
  394. break;
  395. }
  396. return PLSR_PATH_ACTION_NONE;
  397. }
  398. uint16_t PlsrPathGetCurrentSegment(const PLSR_PATH_CONTEXT *context)
  399. {
  400. if (context == NULL)
  401. {
  402. return 0U;
  403. }
  404. return context->currentSegment;
  405. }
  406. void PlsrPathTerminate(PLSR_PATH_CONTEXT *context)
  407. {
  408. if (context == NULL)
  409. {
  410. return;
  411. }
  412. context->phase = PLSR_PATH_ENDED;
  413. context->jobEnded = 1U;
  414. context->jumpChainPending = 0U;
  415. context->zeroJumpBudget = 0U;
  416. }