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.
 
 
 
 
 
 

405 lines
14 KiB

  1. #include "plc_device.h"
  2. #include "plsr_core.h"
  3. #include "plsr_persistence.h"
  4. #include "plsr_resource.h"
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. static unsigned int TestCount;
  9. #define TEST_CHECK(condition) \
  10. do \
  11. { \
  12. TestCount++; \
  13. if (!(condition)) \
  14. { \
  15. (void)fprintf(stderr, "FAIL line %d: %s\n", __LINE__, #condition); \
  16. exit(EXIT_FAILURE); \
  17. } \
  18. } while (0)
  19. static void TestReset(void)
  20. {
  21. PlsrPersistenceTestResetStorage();
  22. TEST_CHECK(PlcDeviceInit() == PLC_DEVICE_OK);
  23. TEST_CHECK(PlsrInit() == PLSR_RESULT_OK);
  24. }
  25. static PLSR_RESULT TestPostCommand(uint32_t sequence,
  26. uint8_t axis,
  27. PLSR_COMMAND_OPCODE opcode,
  28. int64_t argument)
  29. {
  30. PLSR_COMMAND command;
  31. command.sequence = sequence;
  32. command.axis = axis;
  33. command.opcode = opcode;
  34. command.argument = argument;
  35. return PlsrPostCommand(&command);
  36. }
  37. static PLSR_RESULT TestPostStart(uint32_t sequence,
  38. uint8_t axis,
  39. PLSR_OUTPUT_MODE mode,
  40. uint8_t directionPoint,
  41. uint8_t directionPositive)
  42. {
  43. PLSR_START_REQUEST request;
  44. request.sequence = sequence;
  45. request.axis = axis;
  46. request.outputMode = mode;
  47. request.directionPoint = directionPoint;
  48. request.directionPositive = directionPositive;
  49. return PlsrPostStart(&request);
  50. }
  51. static PLSR_STATUS TestGetStatus(uint8_t axis)
  52. {
  53. PLSR_STATUS status;
  54. (void)memset(&status, 0, sizeof(status));
  55. TEST_CHECK(PlsrGetStatus(axis, &status) == PLSR_RESULT_OK);
  56. return status;
  57. }
  58. static void TestResourceManager(void)
  59. {
  60. PLSR_RESOURCE_REQUEST request;
  61. PLSR_RESOURCE_LEASE first;
  62. PLSR_RESOURCE_LEASE second;
  63. PLSR_RESOURCE_STATUS status;
  64. (void)memset(&first, 0, sizeof(first));
  65. (void)memset(&second, 0, sizeof(second));
  66. PlsrResourceInit();
  67. request.ownerAxis = 0U;
  68. request.outputMode = PLSR_OUTPUT_PULSE_DIR;
  69. request.dAxis = 0U;
  70. request.directionPoint = 4U;
  71. TEST_CHECK(PlsrResourceReserve(&request, &first) == PLSR_RESULT_OK);
  72. TEST_CHECK(first.highMask == 0x01U);
  73. TEST_CHECK(first.outputMask == ((1UL << 0U) | (1UL << 4U)));
  74. request.ownerAxis = 1U;
  75. request.dAxis = 1U;
  76. request.directionPoint = 4U;
  77. TEST_CHECK(PlsrResourceReserve(&request, &second)
  78. == PLSR_RESULT_RESOURCE_CONFLICT);
  79. TEST_CHECK(second.valid == 0U);
  80. request.directionPoint = 8U;
  81. TEST_CHECK(PlsrResourceReserve(&request, &second)
  82. == PLSR_RESULT_INVALID_RESOURCE);
  83. request.directionPoint = 1U;
  84. TEST_CHECK(PlsrResourceReserve(&request, &second)
  85. == PLSR_RESULT_INVALID_RESOURCE);
  86. PlsrResourceRelease(&first);
  87. PlsrResourceRelease(&first);
  88. request.ownerAxis = 0U;
  89. request.outputMode = PLSR_OUTPUT_AB;
  90. request.dAxis = 0U;
  91. request.directionPoint = PLSR_DIRECTION_POINT_NONE;
  92. TEST_CHECK(PlsrResourceReserve(&request, &first) == PLSR_RESULT_OK);
  93. TEST_CHECK(first.highMask == 0x03U);
  94. request.ownerAxis = 2U;
  95. request.outputMode = PLSR_OUTPUT_PULSE_DIR;
  96. request.dAxis = 2U;
  97. request.directionPoint = 4U;
  98. TEST_CHECK(PlsrResourceReserve(&request, &second) == PLSR_RESULT_OK);
  99. TEST_CHECK(second.highMask == 0x04U);
  100. request.ownerAxis = 1U;
  101. request.outputMode = PLSR_OUTPUT_CW_CCW;
  102. request.dAxis = 1U;
  103. request.directionPoint = PLSR_DIRECTION_POINT_NONE;
  104. PlsrResourceRelease(&second);
  105. TEST_CHECK(PlsrResourceReserve(&request, &second)
  106. == PLSR_RESULT_INVALID_RESOURCE);
  107. PlsrResourceGetStatus(&status);
  108. TEST_CHECK(status.highMask == 0x03U);
  109. TEST_CHECK(PlsrResourceCheckInvariant() != 0U);
  110. PlsrResourceRelease(&first);
  111. PlsrResourceGetStatus(&status);
  112. TEST_CHECK(status.outputMask == 0UL);
  113. }
  114. static void TestStateMachineAndCommands(void)
  115. {
  116. PLSR_RESOURCE_STATUS resources;
  117. PLSR_STATUS status;
  118. TestReset();
  119. status = TestGetStatus(0U);
  120. TEST_CHECK(status.state == PLSR_STATE_IDLE);
  121. TEST_CHECK(status.directionPoint == PLSR_DIRECTION_POINT_NONE);
  122. TEST_CHECK(TestPostStart(1U, 0U, PLSR_OUTPUT_PULSE_DIR, 4U, 1U)
  123. == PLSR_RESULT_QUEUED);
  124. PlsrProcess();
  125. status = TestGetStatus(0U);
  126. TEST_CHECK(status.state == PLSR_STATE_ACCEL);
  127. TEST_CHECK(status.busy != 0U);
  128. TEST_CHECK(status.pulseActive != 0U);
  129. TEST_CHECK(status.done == 0U);
  130. TEST_CHECK(status.highResourceMask == 0x01U);
  131. TEST_CHECK(status.directionPoint == 4U);
  132. TEST_CHECK(status.lastCommandSequence == 1U);
  133. TEST_CHECK(status.lastCommandResult == PLSR_RESULT_OK);
  134. TEST_CHECK(TestPostStart(1U, 0U, PLSR_OUTPUT_PULSE_DIR, 4U, 1U)
  135. == PLSR_RESULT_OK);
  136. TEST_CHECK(TestPostStart(1U, 1U, PLSR_OUTPUT_PULSE_DIR, 4U, 1U)
  137. == PLSR_RESULT_QUEUED);
  138. PlsrProcess();
  139. status = TestGetStatus(1U);
  140. TEST_CHECK(status.state == PLSR_STATE_IDLE);
  141. TEST_CHECK(status.lastCommandResult == PLSR_RESULT_RESOURCE_CONFLICT);
  142. TEST_CHECK(status.error == PLSR_ERROR_RESOURCE_CONFLICT);
  143. TEST_CHECK(PlsrPostEvent(0U, PLSR_EVENT_ACCEL_COMPLETE)
  144. == PLSR_RESULT_OK);
  145. PlsrProcess();
  146. TEST_CHECK(TestGetStatus(0U).state == PLSR_STATE_RUN);
  147. TEST_CHECK(TestPostCommand(2U, 0U, PLSR_CMD_SET_POSITION, 500)
  148. == PLSR_RESULT_QUEUED);
  149. PlsrProcess();
  150. TEST_CHECK(TestGetStatus(0U).lastCommandResult == PLSR_RESULT_BUSY);
  151. TEST_CHECK(TestPostCommand(3U, 0U, PLSR_CMD_PAUSE, 0)
  152. == PLSR_RESULT_QUEUED);
  153. PlsrProcess();
  154. TEST_CHECK(TestGetStatus(0U).state == PLSR_STATE_DECEL);
  155. TEST_CHECK(PlsrPostEvent(0U, PLSR_EVENT_DECEL_COMPLETE)
  156. == PLSR_RESULT_OK);
  157. PlsrProcess();
  158. status = TestGetStatus(0U);
  159. TEST_CHECK(status.state == PLSR_STATE_PAUSED);
  160. TEST_CHECK(status.busy != 0U);
  161. TEST_CHECK(status.pulseActive == 0U);
  162. TEST_CHECK(status.highResourceMask == 0x01U);
  163. TEST_CHECK(TestPostCommand(4U, 0U, PLSR_CMD_RESUME, 0)
  164. == PLSR_RESULT_QUEUED);
  165. PlsrProcess();
  166. TEST_CHECK(TestGetStatus(0U).state == PLSR_STATE_ACCEL);
  167. TEST_CHECK(TestPostCommand(5U, 0U, PLSR_CMD_STOP_IMMEDIATE, 0)
  168. == PLSR_RESULT_QUEUED);
  169. PlsrProcess();
  170. status = TestGetStatus(0U);
  171. TEST_CHECK(status.state == PLSR_STATE_ACCEL);
  172. TEST_CHECK(status.stopReason == PLSR_STOP_REASON_STOP_IMMEDIATE);
  173. TEST_CHECK(status.highResourceMask == 0x01U);
  174. TEST_CHECK(TestPostCommand(5U, 0U, PLSR_CMD_STOP_IMMEDIATE, 0)
  175. == PLSR_RESULT_OK);
  176. TEST_CHECK(PlsrPostEvent(0U, PLSR_EVENT_STOP_IMMEDIATE_DONE)
  177. == PLSR_RESULT_OK);
  178. PlsrProcess();
  179. status = TestGetStatus(0U);
  180. TEST_CHECK(status.state == PLSR_STATE_STOPPED);
  181. TEST_CHECK(status.busy == 0U);
  182. TEST_CHECK(status.done == 0U);
  183. TEST_CHECK(status.highResourceMask == 0U);
  184. PlsrResourceGetStatus(&resources);
  185. TEST_CHECK(resources.outputMask == 0UL);
  186. TEST_CHECK(TestPostStart(6U, 0U, PLSR_OUTPUT_PULSE_DIR, 4U, 0U)
  187. == PLSR_RESULT_QUEUED);
  188. PlsrProcess();
  189. TEST_CHECK(PlsrPostEvent(0U, PLSR_EVENT_JOB_COMPLETE)
  190. == PLSR_RESULT_OK);
  191. PlsrProcess();
  192. status = TestGetStatus(0U);
  193. TEST_CHECK(status.state == PLSR_STATE_COMPLETED);
  194. TEST_CHECK(status.done != 0U);
  195. TEST_CHECK(status.stopReason == PLSR_STOP_REASON_NORMAL_COMPLETE);
  196. TEST_CHECK(TestPostStart(7U, 0U, PLSR_OUTPUT_PULSE_DIR, 4U, 1U)
  197. == PLSR_RESULT_QUEUED);
  198. PlsrProcess();
  199. TEST_CHECK(TestGetStatus(0U).done == 0U);
  200. TEST_CHECK(PlsrPostEvent(0U,
  201. PLSR_EVENT_JOB_COMPLETE
  202. | PLSR_EVENT_SOFTWARE_EMERGENCY)
  203. == PLSR_RESULT_OK);
  204. PlsrProcess();
  205. status = TestGetStatus(0U);
  206. TEST_CHECK(status.state == PLSR_STATE_STOPPED);
  207. TEST_CHECK(status.done == 0U);
  208. TEST_CHECK(status.stopReason == PLSR_STOP_REASON_SOFTWARE_EMERGENCY);
  209. TEST_CHECK(PlsrStateTransition(0U,
  210. PLSR_STATE_RUN,
  211. PLSR_TRANSITION_ACCEL_COMPLETE)
  212. == PLSR_RESULT_INVALID_STATE);
  213. status = TestGetStatus(0U);
  214. TEST_CHECK(status.state == PLSR_STATE_ERROR);
  215. TEST_CHECK(status.error == PLSR_ERROR_ILLEGAL_TRANSITION);
  216. TEST_CHECK(status.illegalTransitionCount == 1UL);
  217. TEST_CHECK(TestPostCommand(8U, 0U, PLSR_CMD_RESET_ERROR, 0)
  218. == PLSR_RESULT_QUEUED);
  219. PlsrProcess();
  220. TEST_CHECK(TestGetStatus(0U).state == PLSR_STATE_IDLE);
  221. }
  222. static void TestLimitWaitAndPairs(void)
  223. {
  224. PLSR_STATUS status;
  225. TestReset();
  226. TEST_CHECK(TestPostStart(10U, 0U, PLSR_OUTPUT_PULSE_DIR, 4U, 1U)
  227. == PLSR_RESULT_QUEUED);
  228. PlsrProcess();
  229. TEST_CHECK(PlsrPostEvent(0U,
  230. PLSR_EVENT_LIMIT_POSITIVE
  231. | PLSR_EVENT_DECEL_COMPLETE)
  232. == PLSR_RESULT_OK);
  233. PlsrProcess();
  234. status = TestGetStatus(0U);
  235. TEST_CHECK(status.state == PLSR_STATE_STOPPED);
  236. TEST_CHECK(status.stopReason == PLSR_STOP_REASON_LIMIT_POSITIVE);
  237. TEST_CHECK(status.error == PLSR_ERROR_LIMIT_POSITIVE);
  238. TEST_CHECK(TestPostStart(11U,
  239. 2U,
  240. PLSR_OUTPUT_AB,
  241. PLSR_DIRECTION_POINT_NONE,
  242. 0U)
  243. == PLSR_RESULT_QUEUED);
  244. PlsrProcess();
  245. status = TestGetStatus(2U);
  246. TEST_CHECK(status.highResourceMask == 0x0CU);
  247. TEST_CHECK(status.outputMode == PLSR_OUTPUT_AB);
  248. TEST_CHECK(PlsrPostEvent(2U, PLSR_EVENT_WAIT_BEGIN) == PLSR_RESULT_OK);
  249. PlsrProcess();
  250. status = TestGetStatus(2U);
  251. TEST_CHECK(status.state == PLSR_STATE_WAIT);
  252. TEST_CHECK(status.busy != 0U);
  253. TEST_CHECK(status.pulseActive == 0U);
  254. TEST_CHECK(status.highResourceMask == 0x0CU);
  255. TEST_CHECK(TestPostCommand(12U, 2U, PLSR_CMD_PAUSE, 0)
  256. == PLSR_RESULT_QUEUED);
  257. PlsrProcess();
  258. TEST_CHECK(TestGetStatus(2U).state == PLSR_STATE_PAUSED);
  259. TEST_CHECK(TestPostCommand(13U, 2U, PLSR_CMD_STOP_DECEL, 0)
  260. == PLSR_RESULT_QUEUED);
  261. PlsrProcess();
  262. status = TestGetStatus(2U);
  263. TEST_CHECK(status.state == PLSR_STATE_STOPPED);
  264. TEST_CHECK(status.highResourceMask == 0U);
  265. TEST_CHECK(TestPostStart(14U,
  266. 1U,
  267. PLSR_OUTPUT_CW_CCW,
  268. PLSR_DIRECTION_POINT_NONE,
  269. 1U)
  270. == PLSR_RESULT_QUEUED);
  271. PlsrProcess();
  272. status = TestGetStatus(1U);
  273. TEST_CHECK(status.state == PLSR_STATE_IDLE);
  274. TEST_CHECK(status.lastCommandResult == PLSR_RESULT_INVALID_RESOURCE);
  275. }
  276. static void TestQueueAndInputValidation(void)
  277. {
  278. PLSR_COMMAND command;
  279. uint32_t sequence;
  280. TestReset();
  281. TEST_CHECK(PlsrPostEvent(4U, PLSR_EVENT_JOB_COMPLETE)
  282. == PLSR_RESULT_INVALID_AXIS);
  283. TEST_CHECK(PlsrPostEvent(0U, 0UL) == PLSR_RESULT_INVALID_ARGUMENT);
  284. TEST_CHECK(PlsrPostEvent(0U, 0x80000000UL)
  285. == PLSR_RESULT_INVALID_ARGUMENT);
  286. TEST_CHECK(PlsrGetStatus(0U, NULL) == PLSR_RESULT_INVALID_ARGUMENT);
  287. TEST_CHECK(PlsrGetStatus(4U, NULL) == PLSR_RESULT_INVALID_AXIS);
  288. command.axis = 1U;
  289. command.opcode = PLSR_CMD_CLEAR_POSITION;
  290. command.argument = 0;
  291. for (sequence = 100U;
  292. sequence < 100U + PLSR_COMMAND_QUEUE_DEPTH;
  293. sequence++)
  294. {
  295. command.sequence = sequence;
  296. TEST_CHECK(PlsrPostCommand(&command) == PLSR_RESULT_QUEUED);
  297. }
  298. command.sequence = 1000U;
  299. TEST_CHECK(PlsrPostCommand(&command) == PLSR_RESULT_QUEUE_FULL);
  300. PlsrProcess();
  301. TEST_CHECK(TestGetStatus(1U).lastCommandResult == PLSR_RESULT_OK);
  302. TEST_CHECK(TestPostCommand(2000U, 0U, PLSR_CMD_SELF_TEST, 0)
  303. == PLSR_RESULT_QUEUED);
  304. PlsrProcess();
  305. TEST_CHECK(TestGetStatus(0U).lastCommandResult == PLSR_RESULT_OK);
  306. }
  307. static void TestPositionCheckpointing(void)
  308. {
  309. PLSR_STATUS status;
  310. int32_t hsdPosition;
  311. /* 1. SET_POSITION 后立即写入 HSD 检查点。 */
  312. TestReset();
  313. TEST_CHECK(TestPostCommand(1U, 0U, PLSR_CMD_SET_POSITION, 500)
  314. == PLSR_RESULT_QUEUED);
  315. PlsrProcess();
  316. status = TestGetStatus(0U);
  317. TEST_CHECK(status.lastCommandResult == PLSR_RESULT_OK);
  318. TEST_CHECK(status.positionValid != 0U);
  319. TEST_CHECK(PlcDeviceIsHsdDirty() == 0U);
  320. TEST_CHECK(PlcDeviceReadHsdDword(0U, &hsdPosition) == PLC_DEVICE_OK);
  321. TEST_CHECK(hsdPosition == 500);
  322. /* 2. 模拟重启:位置与 positionValid 应恢复到上次正常停机的检查点。 */
  323. TEST_CHECK(PlcDeviceInit() == PLC_DEVICE_OK);
  324. TEST_CHECK(PlsrInit() == PLSR_RESULT_OK);
  325. status = TestGetStatus(0U);
  326. TEST_CHECK(status.positionValid != 0U);
  327. TEST_CHECK(status.logicalPosition == 500);
  328. /* 3. 运动中掉电(lastBusy=1):恢复后位置不可信。 */
  329. TEST_CHECK(PlcDeviceSetHsdCheckpointMeta(1U, 1U) == PLC_DEVICE_OK);
  330. TEST_CHECK(PlcDeviceCheckpointHsd() == PLC_DEVICE_OK);
  331. TEST_CHECK(PlcDeviceInit() == PLC_DEVICE_OK);
  332. TEST_CHECK(PlsrInit() == PLSR_RESULT_OK);
  333. status = TestGetStatus(0U);
  334. TEST_CHECK(status.positionValid == 0U);
  335. TEST_CHECK(status.logicalPosition == 500);
  336. /* 4. 64位位置超出 INT32 范围:对外回绕并置溢出诊断。 */
  337. TEST_CHECK(TestPostCommand(2U,
  338. 0U,
  339. PLSR_CMD_SET_POSITION,
  340. INT64_C(0x100000000))
  341. == PLSR_RESULT_QUEUED);
  342. PlsrProcess();
  343. status = TestGetStatus(0U);
  344. TEST_CHECK(status.lastCommandResult == PLSR_RESULT_OK);
  345. TEST_CHECK(status.positionOverflow != 0U);
  346. TEST_CHECK(PlcDeviceReadHsdDword(0U, &hsdPosition) == PLC_DEVICE_OK);
  347. TEST_CHECK(hsdPosition == 0);
  348. }
  349. int main(void)
  350. {
  351. TestResourceManager();
  352. TestStateMachineAndCommands();
  353. TestLimitWaitAndPairs();
  354. TestQueueAndInputValidation();
  355. TestPositionCheckpointing();
  356. (void)printf("PASS: %u PLSR core checks\n", TestCount);
  357. return EXIT_SUCCESS;
  358. }