Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 
 
 

893 řádky
31 KiB

  1. #include "plsr_modbus_control.h"
  2. #include "modbus_data_store.h"
  3. #include "plc_device.h"
  4. #include "plsr_address_map.h"
  5. #include "plsr_core.h"
  6. #include "plsr_hal_f407.h"
  7. #include "plsr_job.h"
  8. #include "plsr_modbus_data.h"
  9. #include "plsr_persistence.h"
  10. #include <stddef.h>
  11. #include <string.h>
  12. #ifndef PLSR_HOST_TEST
  13. #include "stm32f4xx.h"
  14. #include "usbd_cdc_if.h"
  15. #endif
  16. #define PLSR_MODBUS_MAGIC_LOW (0x504CU)
  17. #define PLSR_MODBUS_MAGIC_HIGH (0x5352U)
  18. #define PLSR_MODBUS_CAPABILITIES (0x0007U)
  19. #define PLSR_MODBUS_CALL_REQUEST_WORDS (16UL)
  20. #define PLSR_MODBUS_CALL_RESPONSE_WORDS (12UL)
  21. #define PLSR_MODBUS_COMMAND_REQUEST_WORDS (8UL)
  22. #define PLSR_MODBUS_COMMAND_RESPONSE_WORDS (8UL)
  23. #define PLSR_MODBUS_S0_HEADER_WORDS (10UL)
  24. #define PLSR_MODBUS_S0_SEGMENT_WORDS (10UL)
  25. #define PLSR_MODBUS_S1_WORDS (4UL)
  26. #define PLSR_MODBUS_HASH_OFFSET (2166136261UL)
  27. #define PLSR_MODBUS_HASH_PRIME (16777619UL)
  28. #define PLSR_MODBUS_PERSIST_MAGIC_A (0xDA7AU)
  29. #define PLSR_MODBUS_PERSIST_MAGIC_B (0x51F0U)
  30. #define PLSR_MODBUS_PERSIST_ARM (0xA55AU)
  31. #define PLSR_MODBUS_PERSIST_INVALIDATE_HSD (1U)
  32. #define PLSR_MODBUS_PERSIST_INVALIDATE_SFD (2U)
  33. typedef struct
  34. {
  35. PLSR_CALL call;
  36. uint32_t fingerprint;
  37. uint8_t valid;
  38. } PLSR_MODBUS_COMMITTED_CALL;
  39. static uint16_t PlsrModbusBaseAddress;
  40. static uint8_t PlsrModbusEnabled;
  41. static uint32_t PlsrModbusLastCallRequestSequence;
  42. static uint32_t PlsrModbusLastCommandRequestSequence;
  43. static uint32_t PlsrModbusStatusGeneration[PLSR_AXIS_COUNT];
  44. static uint32_t PlsrModbusPersistenceGeneration;
  45. static uint32_t PlsrModbusUsbDiagnosticsGeneration;
  46. static uint32_t PlsrModbusLastPersistenceRequestSequence;
  47. static PLSR_MODBUS_COMMITTED_CALL PlsrModbusCommitted[PLSR_AXIS_COUNT];
  48. static uint16_t PlsrModbusStatusWords[PLSR_AXIS_COUNT]
  49. [PLSR_MODBUS_AXIS_STATUS_WORDS];
  50. static const uint16_t PlsrModbusZeroWindow[PLSR_MODBUS_WINDOW_WORDS] = {0U};
  51. static void PlsrModbusPutU32(uint16_t *words,
  52. uint32_t offset,
  53. uint32_t value)
  54. {
  55. words[offset] = (uint16_t)(value & 0xFFFFUL);
  56. words[offset + 1UL] = (uint16_t)(value >> 16U);
  57. }
  58. static void PlsrModbusPutU64(uint16_t *words,
  59. uint32_t offset,
  60. uint64_t value)
  61. {
  62. words[offset] = (uint16_t)(value & 0xFFFFULL);
  63. words[offset + 1UL] = (uint16_t)((value >> 16U) & 0xFFFFULL);
  64. words[offset + 2UL] = (uint16_t)((value >> 32U) & 0xFFFFULL);
  65. words[offset + 3UL] = (uint16_t)(value >> 48U);
  66. }
  67. static uint32_t PlsrModbusGetU32(const uint16_t *words, uint32_t offset)
  68. {
  69. return ((uint32_t)words[offset + 1UL] << 16U) | words[offset];
  70. }
  71. static uint64_t PlsrModbusGetU64(const uint16_t *words, uint32_t offset)
  72. {
  73. return ((uint64_t)words[offset + 3UL] << 48U)
  74. | ((uint64_t)words[offset + 2UL] << 32U)
  75. | ((uint64_t)words[offset + 1UL] << 16U)
  76. | words[offset];
  77. }
  78. static uint8_t PlsrModbusReadWords(uint32_t offset,
  79. uint16_t *words,
  80. uint32_t wordCount)
  81. {
  82. uint32_t index;
  83. if (words == NULL)
  84. {
  85. return 0U;
  86. }
  87. for (index = 0UL; index < wordCount; index++)
  88. {
  89. if (ModbusDataReadWord(MODBUS_DATA_DEVICE_D,
  90. (uint32_t)PlsrModbusBaseAddress + offset + index,
  91. &words[index]) == 0U)
  92. {
  93. return 0U;
  94. }
  95. }
  96. return 1U;
  97. }
  98. static uint8_t PlsrModbusRangesOverlap(uint32_t firstA,
  99. uint32_t countA,
  100. uint32_t firstB,
  101. uint32_t countB)
  102. {
  103. return ((firstA < (firstB + countB)) && (firstB < (firstA + countA)))
  104. ? 1U
  105. : 0U;
  106. }
  107. static uint32_t PlsrModbusHashWord(uint32_t hash, uint16_t value)
  108. {
  109. hash ^= (uint8_t)(value & 0x00FFU);
  110. hash *= PLSR_MODBUS_HASH_PRIME;
  111. hash ^= (uint8_t)(value >> 8U);
  112. hash *= PLSR_MODBUS_HASH_PRIME;
  113. return hash;
  114. }
  115. static uint32_t PlsrModbusHashU32(uint32_t hash, uint32_t value)
  116. {
  117. hash = PlsrModbusHashWord(hash, (uint16_t)(value & 0xFFFFUL));
  118. return PlsrModbusHashWord(hash, (uint16_t)(value >> 16U));
  119. }
  120. static PLSR_RESULT PlsrModbusFingerprintCall(const PLSR_CALL *call,
  121. uint32_t *fingerprint)
  122. {
  123. uint16_t word;
  124. int32_t segmentCount;
  125. uint32_t s0Words;
  126. uint32_t index;
  127. uint32_t hash = PLSR_MODBUS_HASH_OFFSET;
  128. if ((call == NULL) || (fingerprint == NULL)
  129. || (call->source.readDword == NULL)
  130. || (call->source.readWord == NULL)
  131. || (call->source.validateWords == NULL))
  132. {
  133. return PLSR_RESULT_INVALID_ARGUMENT;
  134. }
  135. if (call->source.readDword(call->source.context,
  136. call->s0.device,
  137. call->s0.address,
  138. &segmentCount) == 0U)
  139. {
  140. return PLSR_RESULT_DATA_ACCESS;
  141. }
  142. if ((segmentCount < 1) || (segmentCount > (int32_t)PLSR_MAX_SEGMENTS))
  143. {
  144. return PLSR_RESULT_SEGMENT_OVERFLOW;
  145. }
  146. s0Words = PLSR_MODBUS_S0_HEADER_WORDS
  147. + (uint32_t)segmentCount * PLSR_MODBUS_S0_SEGMENT_WORDS;
  148. if ((call->source.validateWords(call->source.context,
  149. call->s0.device,
  150. call->s0.address,
  151. s0Words) == 0U)
  152. || (call->source.validateWords(call->source.context,
  153. call->s1.device,
  154. call->s1.address,
  155. PLSR_MODBUS_S1_WORDS) == 0U))
  156. {
  157. return PLSR_RESULT_DATA_ACCESS;
  158. }
  159. if (((call->s0.device == PLSR_DEVICE_D)
  160. && (PlsrModbusRangesOverlap(call->s0.address,
  161. s0Words,
  162. PlsrModbusBaseAddress,
  163. PLSR_MODBUS_WINDOW_WORDS) != 0U))
  164. || ((call->s1.device == PLSR_DEVICE_D)
  165. && (PlsrModbusRangesOverlap(call->s1.address,
  166. PLSR_MODBUS_S1_WORDS,
  167. PlsrModbusBaseAddress,
  168. PLSR_MODBUS_WINDOW_WORDS) != 0U)))
  169. {
  170. return PLSR_RESULT_BLOCK_OVERLAP;
  171. }
  172. hash = PlsrModbusHashWord(hash, (uint16_t)call->s0.device);
  173. hash = PlsrModbusHashU32(hash, call->s0.address);
  174. for (index = 0UL; index < s0Words; index++)
  175. {
  176. if (call->source.readWord(call->source.context,
  177. call->s0.device,
  178. call->s0.address + index,
  179. &word) == 0U)
  180. {
  181. return PLSR_RESULT_DATA_ACCESS;
  182. }
  183. hash = PlsrModbusHashWord(hash, word);
  184. }
  185. hash = PlsrModbusHashWord(hash, (uint16_t)call->s1.device);
  186. hash = PlsrModbusHashU32(hash, call->s1.address);
  187. for (index = 0UL; index < PLSR_MODBUS_S1_WORDS; index++)
  188. {
  189. if (call->source.readWord(call->source.context,
  190. call->s1.device,
  191. call->s1.address + index,
  192. &word) == 0U)
  193. {
  194. return PLSR_RESULT_DATA_ACCESS;
  195. }
  196. hash = PlsrModbusHashWord(hash, word);
  197. }
  198. hash = PlsrModbusHashWord(hash, (uint16_t)call->s2.type);
  199. hash = PlsrModbusHashWord(hash, (uint16_t)call->s2.data.device);
  200. hash = PlsrModbusHashU32(hash, call->s2.data.address);
  201. hash = PlsrModbusHashU32(hash, (uint32_t)call->s2.constant);
  202. if (call->s2.type == PLSR_OPERAND_DATA)
  203. {
  204. for (index = 0UL; index < 2UL; index++)
  205. {
  206. if (call->source.readWord(call->source.context,
  207. call->s2.data.device,
  208. call->s2.data.address + index,
  209. &word) == 0U)
  210. {
  211. return PLSR_RESULT_DATA_ACCESS;
  212. }
  213. hash = PlsrModbusHashWord(hash, word);
  214. }
  215. }
  216. hash = PlsrModbusHashWord(hash, call->dAxis);
  217. hash = PlsrModbusHashWord(hash, call->outputModeOverride);
  218. *fingerprint = hash;
  219. return PLSR_RESULT_OK;
  220. }
  221. static PLSR_RESULT PlsrModbusBuildCall(const uint16_t *request,
  222. PLSR_CALL *call)
  223. {
  224. uint16_t s2Type;
  225. uint16_t outputMode;
  226. if ((request == NULL) || (call == NULL))
  227. {
  228. return PLSR_RESULT_INVALID_ARGUMENT;
  229. }
  230. s2Type = request[8UL];
  231. outputMode = request[13UL];
  232. if ((request[2UL] > (uint16_t)PLSR_DEVICE_FD)
  233. || (request[5UL] > (uint16_t)PLSR_DEVICE_FD)
  234. || (s2Type > (uint16_t)PLSR_OPERAND_DATA)
  235. || ((s2Type == (uint16_t)PLSR_OPERAND_DATA)
  236. && (request[9UL] > (uint16_t)PLSR_DEVICE_FD))
  237. || (request[12UL] >= PLSR_AXIS_COUNT)
  238. || ((outputMode > (uint16_t)PLSR_OUTPUT_CW_CCW)
  239. && (outputMode != PLSR_OUTPUT_MODE_FROM_SFD)))
  240. {
  241. return PLSR_RESULT_INVALID_ARGUMENT;
  242. }
  243. (void)memset(call, 0, sizeof(*call));
  244. call->sequence = PlsrModbusGetU32(request, 0UL);
  245. call->s0.device = (PLSR_DEVICE_TYPE)request[2UL];
  246. call->s0.address = PlsrModbusGetU32(request, 3UL);
  247. call->s1.device = (PLSR_DEVICE_TYPE)request[5UL];
  248. call->s1.address = PlsrModbusGetU32(request, 6UL);
  249. call->s2.type = (PLSR_OPERAND_TYPE)s2Type;
  250. call->s2.data.device = (PLSR_DEVICE_TYPE)request[9UL];
  251. call->s2.data.address = PlsrModbusGetU32(request, 10UL);
  252. call->s2.constant = (int32_t)PlsrModbusGetU32(request, 10UL);
  253. call->dAxis = (uint8_t)request[12UL];
  254. call->outputModeOverride = (uint8_t)outputMode;
  255. PlsrModbusDataSourceInit(&call->source);
  256. return PLSR_RESULT_OK;
  257. }
  258. static void PlsrModbusPublishCallResponse(uint32_t sequence,
  259. uint16_t operation,
  260. PLSR_RESULT result,
  261. const PLSR_PARSE_DETAIL *detail,
  262. uint8_t committed)
  263. {
  264. uint16_t response[PLSR_MODBUS_CALL_RESPONSE_WORDS] = {0U};
  265. PlsrModbusPutU32(response, 0UL, sequence);
  266. response[2UL] = operation;
  267. response[3UL] = (uint16_t)result;
  268. if (detail != NULL)
  269. {
  270. response[4UL] = (uint16_t)detail->result;
  271. response[5UL] = (uint16_t)detail->block;
  272. PlsrModbusPutU32(response, 6UL, detail->address);
  273. PlsrModbusPutU32(response, 8UL, (uint32_t)detail->value);
  274. response[10UL] = detail->segment;
  275. }
  276. response[11UL] = committed;
  277. (void)ModbusDataWriteWords(MODBUS_DATA_DEVICE_D,
  278. (uint32_t)PlsrModbusBaseAddress
  279. + PLSR_MODBUS_CALL_RESPONSE_OFFSET,
  280. response,
  281. PLSR_MODBUS_CALL_RESPONSE_WORDS);
  282. }
  283. static void PlsrModbusHandleCallRequest(void)
  284. {
  285. uint16_t request[PLSR_MODBUS_CALL_REQUEST_WORDS];
  286. PLSR_CALL call;
  287. PLSR_PARSE_DETAIL detail;
  288. PLSR_RESULT result;
  289. uint32_t sequence;
  290. uint32_t fingerprint;
  291. uint16_t operation;
  292. uint8_t axis = 0U;
  293. if (PlsrModbusReadWords(PLSR_MODBUS_CALL_REQUEST_OFFSET,
  294. request,
  295. PLSR_MODBUS_CALL_REQUEST_WORDS) == 0U)
  296. {
  297. return;
  298. }
  299. sequence = PlsrModbusGetU32(request, 0UL);
  300. if ((sequence == 0UL) || (sequence == PlsrModbusLastCallRequestSequence))
  301. {
  302. return;
  303. }
  304. PlsrModbusLastCallRequestSequence = sequence;
  305. operation = request[14UL];
  306. (void)memset(&detail, 0, sizeof(detail));
  307. result = PlsrModbusBuildCall(request, &call);
  308. if (result == PLSR_RESULT_OK)
  309. {
  310. axis = call.dAxis;
  311. }
  312. if ((result == PLSR_RESULT_OK) && (operation == PLSR_MODBUS_CALL_COMMIT))
  313. {
  314. result = PlsrValidateCall(&call, &detail);
  315. if (result == PLSR_RESULT_OK)
  316. {
  317. result = PlsrModbusFingerprintCall(&call, &fingerprint);
  318. }
  319. if (result == PLSR_RESULT_OK)
  320. {
  321. PlsrModbusCommitted[axis].call = call;
  322. PlsrModbusCommitted[axis].fingerprint = fingerprint;
  323. PlsrModbusCommitted[axis].valid = 1U;
  324. }
  325. else
  326. {
  327. PlsrModbusCommitted[axis].valid = 0U;
  328. }
  329. }
  330. else if ((result == PLSR_RESULT_OK)
  331. && (operation == PLSR_MODBUS_CALL_START))
  332. {
  333. if (PlsrModbusCommitted[axis].valid == 0U)
  334. {
  335. result = PLSR_RESULT_INVALID_STATE;
  336. }
  337. else
  338. {
  339. result = PlsrModbusFingerprintCall(
  340. &PlsrModbusCommitted[axis].call,
  341. &fingerprint);
  342. if ((result == PLSR_RESULT_OK)
  343. && (fingerprint != PlsrModbusCommitted[axis].fingerprint))
  344. {
  345. result = PLSR_RESULT_BUSY;
  346. }
  347. if (result == PLSR_RESULT_OK)
  348. {
  349. result = PlsrValidateCall(&PlsrModbusCommitted[axis].call,
  350. &detail);
  351. }
  352. if (result == PLSR_RESULT_OK)
  353. {
  354. PlsrModbusCommitted[axis].call.sequence = sequence;
  355. result = PlsrPostCall(&PlsrModbusCommitted[axis].call);
  356. }
  357. }
  358. }
  359. else if (result == PLSR_RESULT_OK)
  360. {
  361. result = PLSR_RESULT_INVALID_ARGUMENT;
  362. }
  363. PlsrModbusPublishCallResponse(
  364. sequence,
  365. operation,
  366. result,
  367. &detail,
  368. (axis < PLSR_AXIS_COUNT) ? PlsrModbusCommitted[axis].valid : 0U);
  369. }
  370. static void PlsrModbusPublishCommandResponse(uint32_t sequence,
  371. uint16_t opcode,
  372. uint16_t axis,
  373. PLSR_RESULT result)
  374. {
  375. uint16_t response[PLSR_MODBUS_COMMAND_RESPONSE_WORDS] = {0U};
  376. PlsrModbusPutU32(response, 0UL, sequence);
  377. response[2UL] = opcode;
  378. response[3UL] = axis;
  379. response[4UL] = (uint16_t)result;
  380. (void)ModbusDataWriteWords(MODBUS_DATA_DEVICE_D,
  381. (uint32_t)PlsrModbusBaseAddress
  382. + PLSR_MODBUS_COMMAND_RESPONSE_OFFSET,
  383. response,
  384. PLSR_MODBUS_COMMAND_RESPONSE_WORDS);
  385. }
  386. static void PlsrModbusHandleCommandRequest(void)
  387. {
  388. uint16_t request[PLSR_MODBUS_COMMAND_REQUEST_WORDS];
  389. PLSR_COMMAND command;
  390. PLSR_RESULT result;
  391. uint32_t sequence;
  392. if (PlsrModbusReadWords(PLSR_MODBUS_COMMAND_REQUEST_OFFSET,
  393. request,
  394. PLSR_MODBUS_COMMAND_REQUEST_WORDS) == 0U)
  395. {
  396. return;
  397. }
  398. sequence = PlsrModbusGetU32(request, 0UL);
  399. if ((sequence == 0UL)
  400. || (sequence == PlsrModbusLastCommandRequestSequence))
  401. {
  402. return;
  403. }
  404. PlsrModbusLastCommandRequestSequence = sequence;
  405. (void)memset(&command, 0, sizeof(command));
  406. if ((request[2UL] > (uint16_t)PLSR_CMD_SELF_TEST)
  407. || (request[2UL] == (uint16_t)PLSR_CMD_START)
  408. || (request[3UL] >= PLSR_AXIS_COUNT))
  409. {
  410. result = PLSR_RESULT_INVALID_ARGUMENT;
  411. }
  412. else
  413. {
  414. command.sequence = sequence;
  415. command.opcode = (PLSR_COMMAND_OPCODE)request[2UL];
  416. command.axis = (uint8_t)request[3UL];
  417. command.argument = (int64_t)PlsrModbusGetU64(request, 4UL);
  418. result = PlsrPostCommand(&command);
  419. }
  420. PlsrModbusPublishCommandResponse(sequence,
  421. request[2UL],
  422. request[3UL],
  423. result);
  424. }
  425. static uint8_t PlsrModbusPersistenceAllAxesIdle(void)
  426. {
  427. PLSR_STATUS status;
  428. uint8_t axis;
  429. for (axis = 0U; axis < PLSR_AXIS_COUNT; axis++)
  430. {
  431. if ((PlsrGetStatus(axis, &status) != PLSR_RESULT_OK)
  432. || (status.busy != 0U)
  433. || (status.pulseActive != 0U))
  434. {
  435. return 0U;
  436. }
  437. }
  438. return 1U;
  439. }
  440. static uint32_t PlsrModbusEnterPersistenceDiagnosticCritical(void)
  441. {
  442. #ifdef PLSR_HOST_TEST
  443. return 0UL;
  444. #else
  445. uint32_t interruptState = __get_PRIMASK();
  446. __disable_irq();
  447. __DMB();
  448. return interruptState;
  449. #endif
  450. }
  451. static void PlsrModbusExitPersistenceDiagnosticCritical(
  452. uint32_t interruptState)
  453. {
  454. #ifdef PLSR_HOST_TEST
  455. (void)interruptState;
  456. #else
  457. __DMB();
  458. if (interruptState == 0UL)
  459. {
  460. __enable_irq();
  461. }
  462. #endif
  463. }
  464. static PLSR_RESULT PlsrModbusMapPersistenceResult(
  465. PLSR_PERSISTENCE_RESULT persistenceResult)
  466. {
  467. if (persistenceResult == PLSR_PERSISTENCE_OK)
  468. {
  469. return PLSR_RESULT_OK;
  470. }
  471. if (persistenceResult == PLSR_PERSISTENCE_NOT_IMPLEMENTED)
  472. {
  473. return PLSR_RESULT_NOT_SUPPORTED;
  474. }
  475. if (persistenceResult == PLSR_PERSISTENCE_INVALID_ARGUMENT)
  476. {
  477. return PLSR_RESULT_INVALID_ARGUMENT;
  478. }
  479. return PLSR_RESULT_PERSISTENCE_ERROR;
  480. }
  481. static void PlsrModbusPublishPersistenceResponse(uint32_t sequence,
  482. uint16_t operation,
  483. PLSR_RESULT result)
  484. {
  485. PLSR_PERSISTENCE_DIAGNOSTICS diagnostics;
  486. uint16_t response[PLSR_MODBUS_PERSISTENCE_RESPONSE_WORDS] = {0U};
  487. PlsrPersistenceGetDiagnostics(&diagnostics);
  488. PlsrModbusPutU32(response, 0UL, sequence);
  489. response[2UL] = operation;
  490. response[3UL] = (uint16_t)result;
  491. response[4UL] = (uint16_t)diagnostics.hsdValidMask
  492. | ((uint16_t)diagnostics.sfdValidMask << 8U);
  493. response[5UL] = (uint16_t)diagnostics.hsdNewestMask
  494. | ((uint16_t)diagnostics.sfdNewestMask << 8U);
  495. response[6UL] = diagnostics.destructiveDiagnosticEnabled;
  496. (void)ModbusDataWriteWords(
  497. MODBUS_DATA_DEVICE_D,
  498. (uint32_t)PlsrModbusBaseAddress
  499. + PLSR_MODBUS_PERSISTENCE_RESPONSE_OFFSET,
  500. response,
  501. PLSR_MODBUS_PERSISTENCE_RESPONSE_WORDS);
  502. }
  503. static void PlsrModbusHandlePersistenceRequest(void)
  504. {
  505. uint16_t request[PLSR_MODBUS_PERSISTENCE_REQUEST_WORDS];
  506. const uint16_t clearRequest[PLSR_MODBUS_PERSISTENCE_REQUEST_WORDS] =
  507. {0U};
  508. PLSR_PERSISTENCE_RESULT persistenceResult;
  509. PLSR_PERSISTENCE_DIAG_TARGET target;
  510. PLSR_RESULT result;
  511. uint32_t sequence;
  512. uint32_t inverseSequence;
  513. uint32_t interruptState;
  514. uint16_t operation;
  515. if (PlsrModbusReadWords(PLSR_MODBUS_PERSISTENCE_REQUEST_OFFSET,
  516. request,
  517. PLSR_MODBUS_PERSISTENCE_REQUEST_WORDS) == 0U)
  518. {
  519. return;
  520. }
  521. if ((request[0UL] != PLSR_MODBUS_PERSIST_MAGIC_A)
  522. || (request[1UL] != PLSR_MODBUS_PERSIST_MAGIC_B))
  523. {
  524. return;
  525. }
  526. sequence = PlsrModbusGetU32(request, 2UL);
  527. inverseSequence = PlsrModbusGetU32(request, 4UL);
  528. operation = request[6UL];
  529. if ((sequence != 0UL)
  530. && (sequence == PlsrModbusLastPersistenceRequestSequence))
  531. {
  532. return;
  533. }
  534. if (sequence != 0UL)
  535. {
  536. PlsrModbusLastPersistenceRequestSequence = sequence;
  537. }
  538. result = PLSR_RESULT_INVALID_ARGUMENT;
  539. if ((sequence != 0UL)
  540. && (inverseSequence == ~sequence)
  541. && (request[7UL] == PLSR_MODBUS_PERSIST_ARM)
  542. && ((operation == PLSR_MODBUS_PERSIST_INVALIDATE_HSD)
  543. || (operation == PLSR_MODBUS_PERSIST_INVALIDATE_SFD)))
  544. {
  545. /* Keep the idle check and the optional one-word invalidation in one
  546. * scheduling exclusion window. This diagnostic is disabled in
  547. * normal builds; when enabled, no START can race the Flash write. */
  548. interruptState = PlsrModbusEnterPersistenceDiagnosticCritical();
  549. if (PlsrModbusPersistenceAllAxesIdle() == 0U)
  550. {
  551. result = PLSR_RESULT_BUSY;
  552. }
  553. else
  554. {
  555. target = (operation == PLSR_MODBUS_PERSIST_INVALIDATE_HSD)
  556. ? PLSR_PERSISTENCE_DIAG_TARGET_HSD
  557. : PLSR_PERSISTENCE_DIAG_TARGET_SFD;
  558. persistenceResult =
  559. PlsrPersistenceDiagnosticInvalidateNewest(target);
  560. result = PlsrModbusMapPersistenceResult(persistenceResult);
  561. }
  562. PlsrModbusExitPersistenceDiagnosticCritical(interruptState);
  563. }
  564. PlsrModbusPublishPersistenceResponse(sequence, operation, result);
  565. (void)ModbusDataWriteWords(
  566. MODBUS_DATA_DEVICE_D,
  567. (uint32_t)PlsrModbusBaseAddress
  568. + PLSR_MODBUS_PERSISTENCE_REQUEST_OFFSET,
  569. clearRequest,
  570. PLSR_MODBUS_PERSISTENCE_REQUEST_WORDS);
  571. }
  572. static void PlsrModbusPublishAxisStatus(uint8_t axis)
  573. {
  574. PLSR_STATUS status;
  575. uint16_t *words = PlsrModbusStatusWords[axis];
  576. uint32_t flags = 0UL;
  577. uint32_t generation;
  578. if (PlsrGetStatus(axis, &status) != PLSR_RESULT_OK)
  579. {
  580. return;
  581. }
  582. generation = PlsrModbusStatusGeneration[axis] + 2UL;
  583. if (generation == 0UL)
  584. {
  585. generation = 2UL;
  586. }
  587. PlsrModbusStatusGeneration[axis] = generation;
  588. (void)memset(words, 0, sizeof(PlsrModbusStatusWords[axis]));
  589. if (status.busy != 0U) flags |= (1UL << 0U);
  590. if (status.pulseActive != 0U) flags |= (1UL << 1U);
  591. if (status.done != 0U) flags |= (1UL << 2U);
  592. if (status.wait != 0U) flags |= (1UL << 3U);
  593. if (status.directionPositive != 0U) flags |= (1UL << 4U);
  594. if (status.positionValid != 0U) flags |= (1UL << 5U);
  595. if (status.jobValid != 0U) flags |= (1UL << 6U);
  596. if (status.speedClamped != 0U) flags |= (1UL << 7U);
  597. if (status.positionOverflow != 0U) flags |= (1UL << 8U);
  598. if (status.positiveLimitActive != 0U) flags |= (1UL << 9U);
  599. if (status.negativeLimitActive != 0U) flags |= (1UL << 10U);
  600. if (status.emergencyLatched != 0U) flags |= (1UL << 11U);
  601. if (status.backlashActive != 0U) flags |= (1UL << 12U);
  602. PlsrModbusPutU32(words, 0UL, generation);
  603. words[2UL] = (uint16_t)status.state;
  604. PlsrModbusPutU32(words, 3UL, flags);
  605. words[5UL] = (uint16_t)status.outputMode;
  606. words[6UL] = (uint16_t)status.error;
  607. words[7UL] = (uint16_t)status.stopReason;
  608. words[8UL] = (uint16_t)status.lastCommandResult;
  609. words[9UL] = status.s2Set;
  610. PlsrModbusPutU32(words, 10UL, status.lastCommandSequence);
  611. PlsrModbusPutU32(words, 12UL, status.illegalTransitionCount);
  612. PlsrModbusPutU32(words, 14UL, status.pendingEvents);
  613. PlsrModbusPutU64(words, 16UL, (uint64_t)status.logicalPosition);
  614. PlsrModbusPutU64(words, 20UL, (uint64_t)status.taskPulses);
  615. PlsrModbusPutU64(words, 24UL, (uint64_t)status.totalPulses);
  616. PlsrModbusPutU64(words, 28UL, status.physicalPulses);
  617. words[32UL] = status.segmentCount;
  618. words[33UL] = status.startSegment;
  619. words[34UL] = status.currentSegment;
  620. words[35UL] = status.directionPoint;
  621. words[36UL] = status.highResourceMask;
  622. words[37UL] = status.hardwareCounter;
  623. PlsrModbusPutU32(words, 38UL, status.currentFrequencyHz);
  624. PlsrModbusPutU32(words, 40UL, status.targetFrequencyHz);
  625. PlsrModbusPutU32(words, 42UL, status.liveFrequencyRejectCount);
  626. words[44UL] = (uint16_t)status.lastLiveFrequencyResult;
  627. PlsrModbusPutU32(words, 46UL, generation);
  628. (void)ModbusDataWriteWords(
  629. MODBUS_DATA_DEVICE_D,
  630. (uint32_t)PlsrModbusBaseAddress + PLSR_MODBUS_AXIS_STATUS_OFFSET
  631. + (uint32_t)axis * PLSR_MODBUS_AXIS_STATUS_WORDS,
  632. words,
  633. PLSR_MODBUS_AXIS_STATUS_WORDS);
  634. }
  635. static void PlsrModbusPublishPerformance(void)
  636. {
  637. uint16_t words[PLSR_MODBUS_PERFORMANCE_WORDS];
  638. uint16_t stageWords[PLSR_MODBUS_STAGE_PERFORMANCE_WORDS];
  639. uint16_t abGateWords[PLSR_MODBUS_AB_GATE_PERFORMANCE_WORDS];
  640. uint32_t outputCycles = PlsrHwGetMaxOutputIsrCycles();
  641. uint32_t counterCycles = PlsrHwGetMaxCounterIsrCycles();
  642. uint8_t stage;
  643. PlsrModbusPutU32(words, 0UL, PlsrGetMaxProcessCycles());
  644. PlsrModbusPutU32(words, 2UL, PlsrGetMaxProcessResponseCycles());
  645. PlsrModbusPutU32(words, 4UL, PlsrHwGetMaxControlIsrCycles());
  646. words[6UL] = (uint16_t)((outputCycles > UINT16_MAX)
  647. ? UINT16_MAX
  648. : outputCycles);
  649. words[7UL] = (uint16_t)((counterCycles > UINT16_MAX)
  650. ? UINT16_MAX
  651. : counterCycles);
  652. (void)ModbusDataWriteWords(
  653. MODBUS_DATA_DEVICE_D,
  654. (uint32_t)PlsrModbusBaseAddress + PLSR_MODBUS_PERFORMANCE_OFFSET,
  655. words,
  656. PLSR_MODBUS_PERFORMANCE_WORDS);
  657. for (stage = 0U; stage < PLSR_PROCESS_STAGE_COUNT; stage++)
  658. {
  659. PlsrModbusPutU32(stageWords,
  660. (uint32_t)stage * 2UL,
  661. PlsrGetMaxProcessStageCycles(stage));
  662. }
  663. (void)ModbusDataWriteWords(
  664. MODBUS_DATA_DEVICE_D,
  665. (uint32_t)PlsrModbusBaseAddress
  666. + PLSR_MODBUS_STAGE_PERFORMANCE_OFFSET,
  667. stageWords,
  668. PLSR_MODBUS_STAGE_PERFORMANCE_WORDS);
  669. PlsrModbusPutU32(abGateWords, 0UL, PlsrHwGetMaxAbGateCycles());
  670. (void)ModbusDataWriteWords(
  671. MODBUS_DATA_DEVICE_D,
  672. (uint32_t)PlsrModbusBaseAddress
  673. + PLSR_MODBUS_AB_GATE_PERFORMANCE_OFFSET,
  674. abGateWords,
  675. PLSR_MODBUS_AB_GATE_PERFORMANCE_WORDS);
  676. }
  677. static void PlsrModbusPublishPersistence(void)
  678. {
  679. PLSR_PERSISTENCE_DIAGNOSTICS diagnostics;
  680. uint16_t words[PLSR_MODBUS_PERSISTENCE_WORDS] = {0U};
  681. uint32_t flags = 0UL;
  682. uint32_t generation = PlsrModbusPersistenceGeneration + 2UL;
  683. if (generation == 0UL)
  684. {
  685. generation = 2UL;
  686. }
  687. PlsrModbusPersistenceGeneration = generation;
  688. PlsrPersistenceGetDiagnostics(&diagnostics);
  689. if (PlcDeviceIsHsdDirty() != 0U) flags |= (1UL << 0U);
  690. if (PlcDeviceIsSfdDirty() != 0U) flags |= (1UL << 1U);
  691. if (PlcDeviceGetRestoredHsdPositionValid() != 0U)
  692. {
  693. flags |= (1UL << 2U);
  694. }
  695. if (PlcDeviceGetRestoredHsdLastBusy() != 0U)
  696. {
  697. flags |= (1UL << 3U);
  698. }
  699. if (diagnostics.destructiveDiagnosticEnabled != 0U)
  700. {
  701. flags |= (1UL << 4U);
  702. }
  703. PlsrModbusPutU32(words, 0UL, generation);
  704. words[2UL] = PLSR_MODBUS_PERSISTENCE_VERSION;
  705. words[3UL] = (uint16_t)diagnostics.hsdValidMask
  706. | ((uint16_t)diagnostics.sfdValidMask << 8U);
  707. words[4UL] = (uint16_t)diagnostics.hsdNewestMask
  708. | ((uint16_t)diagnostics.sfdNewestMask << 8U);
  709. words[5UL] = (uint16_t)flags;
  710. words[6UL] = (uint16_t)diagnostics.lastHsdLoadResult;
  711. words[7UL] = (uint16_t)diagnostics.lastSfdLoadResult;
  712. words[8UL] = (uint16_t)diagnostics.lastHsdSaveResult;
  713. words[9UL] = (uint16_t)diagnostics.lastSfdSaveResult;
  714. words[10UL] = (uint16_t)diagnostics.lastSfdEraseResult;
  715. PlsrModbusPutU32(words, 12UL, diagnostics.hsdGeneration[0]);
  716. PlsrModbusPutU32(words, 14UL, diagnostics.hsdGeneration[1]);
  717. PlsrModbusPutU32(words, 16UL, diagnostics.sfdGeneration[0]);
  718. PlsrModbusPutU32(words, 18UL, diagnostics.sfdGeneration[1]);
  719. PlsrModbusPutU32(words, 20UL, diagnostics.hsdSaveCount);
  720. PlsrModbusPutU32(words, 22UL, diagnostics.sfdSaveCount);
  721. PlsrModbusPutU32(words, 24UL, diagnostics.selectedHsdCrc32);
  722. PlsrModbusPutU32(words, 26UL, diagnostics.selectedSfdCrc32);
  723. PlsrModbusPutU32(words, 28UL, generation);
  724. (void)ModbusDataWriteWords(
  725. MODBUS_DATA_DEVICE_D,
  726. (uint32_t)PlsrModbusBaseAddress + PLSR_MODBUS_PERSISTENCE_OFFSET,
  727. words,
  728. PLSR_MODBUS_PERSISTENCE_WORDS);
  729. }
  730. static void PlsrModbusPublishUsbDiagnostics(void)
  731. {
  732. uint16_t words[PLSR_MODBUS_USB_DIAGNOSTICS_WORDS] = {0U};
  733. uint32_t generation = PlsrModbusUsbDiagnosticsGeneration + 2UL;
  734. #ifndef PLSR_HOST_TEST
  735. USB_CDC_RUNTIME_DIAGNOSTICS diagnostics;
  736. (void)memset(&diagnostics, 0, sizeof(diagnostics));
  737. (void)CDC_GetRuntimeDiagnostics(&diagnostics);
  738. #endif
  739. if (generation == 0UL)
  740. {
  741. generation = 2UL;
  742. }
  743. PlsrModbusUsbDiagnosticsGeneration = generation;
  744. PlsrModbusPutU32(words, 0UL, generation);
  745. words[2UL] = PLSR_MODBUS_USB_DIAGNOSTICS_VERSION;
  746. #ifndef PLSR_HOST_TEST
  747. words[3UL] = diagnostics.initialized;
  748. PlsrModbusPutU32(words, 4UL, diagnostics.rxPacketCount);
  749. PlsrModbusPutU32(words, 6UL, diagnostics.rxByteCount);
  750. PlsrModbusPutU32(words, 8UL, diagnostics.rxRearmFailureCount);
  751. PlsrModbusPutU32(words, 10UL, diagnostics.txRequestCount);
  752. PlsrModbusPutU32(words, 12UL, diagnostics.txByteCount);
  753. PlsrModbusPutU32(words, 14UL, diagnostics.txBusyCount);
  754. PlsrModbusPutU32(words, 16UL, diagnostics.txFailureCount);
  755. PlsrModbusPutU32(words, 18UL, diagnostics.txCompleteCount);
  756. #endif
  757. PlsrModbusPutU32(words, 20UL, generation);
  758. (void)ModbusDataWriteWords(
  759. MODBUS_DATA_DEVICE_D,
  760. (uint32_t)PlsrModbusBaseAddress
  761. + PLSR_MODBUS_USB_DIAGNOSTICS_OFFSET,
  762. words,
  763. PLSR_MODBUS_USB_DIAGNOSTICS_WORDS);
  764. }
  765. PLSR_RESULT PlsrModbusControlInit(uint16_t baseAddress)
  766. {
  767. uint16_t header[8] = {0U};
  768. if (ModbusDataValidateWords(MODBUS_DATA_DEVICE_D,
  769. baseAddress,
  770. PLSR_MODBUS_WINDOW_WORDS) == 0U)
  771. {
  772. return PLSR_RESULT_DATA_ACCESS;
  773. }
  774. PlsrModbusBaseAddress = baseAddress;
  775. PlsrModbusEnabled = 0U;
  776. PlsrModbusLastCallRequestSequence = 0UL;
  777. PlsrModbusLastCommandRequestSequence = 0UL;
  778. PlsrModbusLastPersistenceRequestSequence = 0UL;
  779. PlsrModbusPersistenceGeneration = 0UL;
  780. PlsrModbusUsbDiagnosticsGeneration = 0UL;
  781. (void)memset(PlsrModbusCommitted, 0, sizeof(PlsrModbusCommitted));
  782. (void)memset(PlsrModbusStatusGeneration,
  783. 0,
  784. sizeof(PlsrModbusStatusGeneration));
  785. if (ModbusDataWriteWords(MODBUS_DATA_DEVICE_D,
  786. baseAddress,
  787. PlsrModbusZeroWindow,
  788. PLSR_MODBUS_WINDOW_WORDS) == 0U)
  789. {
  790. return PLSR_RESULT_DATA_ACCESS;
  791. }
  792. header[0UL] = PLSR_MODBUS_MAGIC_LOW;
  793. header[1UL] = PLSR_MODBUS_MAGIC_HIGH;
  794. header[2UL] = PLSR_MODBUS_PROTOCOL_VERSION;
  795. header[3UL] = (uint16_t)PLSR_MODBUS_WINDOW_WORDS;
  796. header[4UL] = PLSR_MODBUS_CAPABILITIES;
  797. PlsrModbusPutU32(header, 5UL, PlsrHwGetTimerClockHz(0U));
  798. header[7UL] = PLSR_MODBUS_PERFORMANCE_VERSION;
  799. if (ModbusDataWriteWords(MODBUS_DATA_DEVICE_D,
  800. baseAddress,
  801. header,
  802. 8UL) == 0U)
  803. {
  804. return PLSR_RESULT_DATA_ACCESS;
  805. }
  806. PlsrModbusEnabled = 1U;
  807. PlsrModbusControlPoll();
  808. return PLSR_RESULT_OK;
  809. }
  810. void PlsrModbusControlPoll(void)
  811. {
  812. uint8_t axis;
  813. if (PlsrModbusEnabled == 0U)
  814. {
  815. return;
  816. }
  817. PlsrModbusHandleCallRequest();
  818. PlsrModbusHandleCommandRequest();
  819. PlsrModbusHandlePersistenceRequest();
  820. for (axis = 0U; axis < PLSR_AXIS_COUNT; axis++)
  821. {
  822. PlsrModbusPublishAxisStatus(axis);
  823. }
  824. PlsrModbusPublishPerformance();
  825. PlsrModbusPublishPersistence();
  826. PlsrModbusPublishUsbDiagnostics();
  827. }
  828. uint8_t PlsrModbusControlIsEnabled(void)
  829. {
  830. return PlsrModbusEnabled;
  831. }
  832. uint16_t PlsrModbusControlGetBaseAddress(void)
  833. {
  834. return PlsrModbusBaseAddress;
  835. }