Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 
 

634 строки
17 KiB

  1. #include "modbus_rtu_slave.h"
  2. #include "plsr.h"
  3. #include <string.h>
  4. #define MODBUS_RTU_ADU_SIZE_MAX (256U)
  5. #define MODBUS_RTU_BITS_PER_CHAR (11UL)
  6. #define MODBUS_RTU_HIGH_BAUD_LIMIT (19200UL)
  7. #define MODBUS_RTU_T15_US (750UL)
  8. #define MODBUS_RTU_T35_US (1750UL)
  9. #define MODBUS_BROADCAST_ADDRESS (0U)
  10. #define MODBUS_SLAVE_ADDRESS_MAX (247U)
  11. #define MODBUS_FC_READ_HOLDING (0x03U)
  12. #define MODBUS_FC_WRITE_SINGLE (0x06U)
  13. #define MODBUS_FC_WRITE_MULTIPLE (0x10U)
  14. #define MODBUS_EX_ILLEGAL_FUNCTION (0x01U)
  15. #define MODBUS_EX_ILLEGAL_ADDRESS (0x02U)
  16. #define MODBUS_EX_ILLEGAL_VALUE (0x03U)
  17. #define MODBUS_EX_SERVER_FAILURE (0x04U)
  18. #define MODBUS_EX_SERVER_BUSY (0x06U)
  19. #define MODBUS_READ_REGISTERS_MAX (125U)
  20. #define MODBUS_WRITE_REGISTERS_MAX (123U)
  21. static UART_HandleTypeDef *ModbusUart;
  22. static uint8_t ModbusSlaveAddress;
  23. static uint8_t ModbusRxDmaBuffer[MODBUS_RTU_ADU_SIZE_MAX];
  24. static uint8_t ModbusRxAssemblyBuffer[MODBUS_RTU_ADU_SIZE_MAX];
  25. static uint8_t ModbusRxFrame[MODBUS_RTU_ADU_SIZE_MAX];
  26. static uint8_t ModbusTxFrame[MODBUS_RTU_ADU_SIZE_MAX];
  27. static uint16_t ModbusRegisterScratch[MODBUS_READ_REGISTERS_MAX];
  28. static volatile uint16_t ModbusRxAssemblyLength;
  29. static volatile uint8_t ModbusRxAssemblyInvalid;
  30. static volatile uint32_t ModbusRxLastByteCycle;
  31. static volatile uint16_t ModbusRxFrameLength;
  32. static volatile uint8_t ModbusRxFrameReady;
  33. static volatile uint8_t ModbusTxBusy;
  34. static volatile uint32_t ModbusLastActivityCycle;
  35. static uint32_t ModbusRtuCharCycles;
  36. static uint32_t ModbusRtuT15Cycles;
  37. static uint32_t ModbusRtuT35Cycles;
  38. static HAL_StatusTypeDef ModbusStartReceive(void);
  39. static uint32_t ModbusEnterCritical(void)
  40. {
  41. uint32_t primask = __get_PRIMASK();
  42. __disable_irq();
  43. __DMB();
  44. return primask;
  45. }
  46. static void ModbusExitCritical(uint32_t primask)
  47. {
  48. __DMB();
  49. __set_PRIMASK(primask);
  50. }
  51. static uint16_t ModbusCrc16(const uint8_t *data, uint16_t length)
  52. {
  53. uint16_t crc = 0xFFFFU;
  54. uint16_t index;
  55. uint8_t bit;
  56. for (index = 0U; index < length; index++)
  57. {
  58. crc ^= data[index];
  59. for (bit = 0U; bit < 8U; bit++)
  60. {
  61. if ((crc & 1U) != 0U)
  62. {
  63. crc = (uint16_t)((crc >> 1U) ^ 0xA001U);
  64. }
  65. else
  66. {
  67. crc >>= 1U;
  68. }
  69. }
  70. }
  71. return crc;
  72. }
  73. static uint16_t ModbusGetU16Be(const uint8_t *data)
  74. {
  75. return (uint16_t)(((uint16_t)data[0] << 8U) | data[1]);
  76. }
  77. static void ModbusRtuTimingInit(uint32_t baudRate)
  78. {
  79. uint64_t coreClock = SystemCoreClock;
  80. uint64_t charCycleNumerator = coreClock * MODBUS_RTU_BITS_PER_CHAR;
  81. CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
  82. DWT->CYCCNT = 0U;
  83. DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
  84. ModbusRtuCharCycles =
  85. (uint32_t)((charCycleNumerator + baudRate - 1UL) / baudRate);
  86. if (ModbusRtuCharCycles == 0UL)
  87. {
  88. ModbusRtuCharCycles = 1UL;
  89. }
  90. if (baudRate > MODBUS_RTU_HIGH_BAUD_LIMIT)
  91. {
  92. ModbusRtuT15Cycles = (uint32_t)(
  93. (coreClock * MODBUS_RTU_T15_US + 999999UL) / 1000000UL);
  94. ModbusRtuT35Cycles = (uint32_t)(
  95. (coreClock * MODBUS_RTU_T35_US + 999999UL) / 1000000UL);
  96. }
  97. else
  98. {
  99. ModbusRtuT15Cycles =
  100. (uint32_t)(((uint64_t)ModbusRtuCharCycles * 3UL + 1UL) / 2UL);
  101. ModbusRtuT35Cycles =
  102. (uint32_t)(((uint64_t)ModbusRtuCharCycles * 7UL + 1UL) / 2UL);
  103. }
  104. }
  105. static void ModbusRxAssemblyFinalize(void)
  106. {
  107. uint16_t length = ModbusRxAssemblyLength;
  108. if (length == 0U)
  109. {
  110. return;
  111. }
  112. if ((ModbusRxAssemblyInvalid == 0U) && (ModbusRxFrameReady == 0U))
  113. {
  114. (void)memcpy(ModbusRxFrame, ModbusRxAssemblyBuffer, length);
  115. ModbusRxFrameLength = length;
  116. ModbusRxFrameReady = 1U;
  117. }
  118. ModbusRxAssemblyLength = 0U;
  119. ModbusRxAssemblyInvalid = 0U;
  120. }
  121. static HAL_StatusTypeDef ModbusStartReceive(void)
  122. {
  123. HAL_StatusTypeDef status;
  124. if ((ModbusUart == NULL) || (ModbusTxBusy != 0U))
  125. {
  126. return HAL_BUSY;
  127. }
  128. status = HAL_UARTEx_ReceiveToIdle_DMA(ModbusUart,
  129. ModbusRxDmaBuffer,
  130. sizeof(ModbusRxDmaBuffer));
  131. if (status == HAL_OK)
  132. {
  133. __HAL_DMA_DISABLE_IT(ModbusUart->hdmarx, DMA_IT_HT);
  134. }
  135. return status;
  136. }
  137. static void ModbusTryFinalizeReceive(void)
  138. {
  139. uint32_t now;
  140. uint32_t primask;
  141. uint8_t restartReceive;
  142. if ((ModbusUart == NULL) || (ModbusRxAssemblyLength == 0U))
  143. {
  144. return;
  145. }
  146. if (((ModbusUart->Instance->CR3 & USART_CR3_DMAR) != 0U)
  147. && (__HAL_DMA_GET_COUNTER(ModbusUart->hdmarx)
  148. < MODBUS_RTU_ADU_SIZE_MAX))
  149. {
  150. return;
  151. }
  152. now = DWT->CYCCNT;
  153. if ((uint32_t)(now - ModbusRxLastByteCycle) < ModbusRtuT35Cycles)
  154. {
  155. return;
  156. }
  157. if (HAL_UART_AbortReceive(ModbusUart) != HAL_OK)
  158. {
  159. primask = ModbusEnterCritical();
  160. ModbusRxAssemblyLength = 0U;
  161. ModbusRxAssemblyInvalid = 0U;
  162. ModbusExitCritical(primask);
  163. (void)HAL_UART_Abort(ModbusUart);
  164. (void)ModbusStartReceive();
  165. return;
  166. }
  167. primask = ModbusEnterCritical();
  168. ModbusRxAssemblyFinalize();
  169. restartReceive = (ModbusRxFrameReady == 0U) ? 1U : 0U;
  170. ModbusExitCritical(primask);
  171. if (restartReceive != 0U)
  172. {
  173. (void)ModbusStartReceive();
  174. }
  175. }
  176. static void ModbusAppendCrc(uint8_t *frame, uint16_t payloadLength)
  177. {
  178. uint16_t crc = ModbusCrc16(frame, payloadLength);
  179. frame[payloadLength] = (uint8_t)(crc & 0x00FFU);
  180. frame[payloadLength + 1U] = (uint8_t)(crc >> 8U);
  181. }
  182. static uint16_t ModbusBuildException(uint8_t function, uint8_t exception)
  183. {
  184. ModbusTxFrame[0] = ModbusSlaveAddress;
  185. ModbusTxFrame[1] = (uint8_t)(function | 0x80U);
  186. ModbusTxFrame[2] = exception;
  187. ModbusAppendCrc(ModbusTxFrame, 3U);
  188. return 5U;
  189. }
  190. static uint16_t ModbusBuildPlsrException(uint8_t function,
  191. PLSR_MB_RESULT result,
  192. uint8_t isBroadcast)
  193. {
  194. uint8_t exception;
  195. if (isBroadcast != 0U)
  196. {
  197. return 0U;
  198. }
  199. switch (result)
  200. {
  201. case PLSR_MB_NOT_HANDLED:
  202. case PLSR_MB_ILLEGAL_ADDRESS:
  203. exception = MODBUS_EX_ILLEGAL_ADDRESS;
  204. break;
  205. case PLSR_MB_ILLEGAL_VALUE:
  206. exception = MODBUS_EX_ILLEGAL_VALUE;
  207. break;
  208. case PLSR_MB_DEVICE_BUSY:
  209. exception = MODBUS_EX_SERVER_BUSY;
  210. break;
  211. case PLSR_MB_SERVER_FAILURE:
  212. default:
  213. exception = MODBUS_EX_SERVER_FAILURE;
  214. break;
  215. }
  216. return ModbusBuildException(function, exception);
  217. }
  218. static uint16_t ModbusProcessReadHolding(const uint8_t *request,
  219. uint16_t requestLength)
  220. {
  221. uint16_t start;
  222. uint16_t quantity;
  223. uint16_t index;
  224. PLSR_MB_RESULT result;
  225. if (requestLength != 8U)
  226. {
  227. return ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE);
  228. }
  229. start = ModbusGetU16Be(&request[2]);
  230. quantity = ModbusGetU16Be(&request[4]);
  231. if ((quantity == 0U) || (quantity > MODBUS_READ_REGISTERS_MAX))
  232. {
  233. return ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE);
  234. }
  235. result = PlsrModbusReadHolding(start, quantity, ModbusRegisterScratch);
  236. if (result != PLSR_MB_OK)
  237. {
  238. return ModbusBuildPlsrException(request[1], result, 0U);
  239. }
  240. ModbusTxFrame[0] = ModbusSlaveAddress;
  241. ModbusTxFrame[1] = MODBUS_FC_READ_HOLDING;
  242. ModbusTxFrame[2] = (uint8_t)(quantity * 2U);
  243. for (index = 0U; index < quantity; index++)
  244. {
  245. ModbusTxFrame[3U + index * 2U] =
  246. (uint8_t)(ModbusRegisterScratch[index] >> 8U);
  247. ModbusTxFrame[4U + index * 2U] =
  248. (uint8_t)(ModbusRegisterScratch[index] & 0x00FFU);
  249. }
  250. ModbusAppendCrc(ModbusTxFrame, (uint16_t)(3U + quantity * 2U));
  251. return (uint16_t)(5U + quantity * 2U);
  252. }
  253. static uint16_t ModbusProcessWriteSingle(const uint8_t *request,
  254. uint16_t requestLength,
  255. uint8_t isBroadcast)
  256. {
  257. uint16_t address;
  258. uint16_t value;
  259. PLSR_MB_RESULT result;
  260. if (requestLength != 8U)
  261. {
  262. return (isBroadcast != 0U)
  263. ? 0U
  264. : ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE);
  265. }
  266. address = ModbusGetU16Be(&request[2]);
  267. value = ModbusGetU16Be(&request[4]);
  268. result = PlsrModbusWriteHolding(address, 1U, &value);
  269. if (result != PLSR_MB_OK)
  270. {
  271. return ModbusBuildPlsrException(request[1], result, isBroadcast);
  272. }
  273. if (isBroadcast != 0U)
  274. {
  275. return 0U;
  276. }
  277. (void)memcpy(ModbusTxFrame, request, 6U);
  278. ModbusAppendCrc(ModbusTxFrame, 6U);
  279. return 8U;
  280. }
  281. static uint16_t ModbusProcessWriteMultiple(const uint8_t *request,
  282. uint16_t requestLength,
  283. uint8_t isBroadcast)
  284. {
  285. uint16_t start;
  286. uint16_t quantity;
  287. uint16_t byteCount;
  288. uint16_t index;
  289. PLSR_MB_RESULT result;
  290. if (requestLength < 9U)
  291. {
  292. return (isBroadcast != 0U)
  293. ? 0U
  294. : ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE);
  295. }
  296. start = ModbusGetU16Be(&request[2]);
  297. quantity = ModbusGetU16Be(&request[4]);
  298. byteCount = request[6];
  299. if ((quantity == 0U)
  300. || (quantity > MODBUS_WRITE_REGISTERS_MAX)
  301. || (byteCount != (uint16_t)(quantity * 2U))
  302. || (requestLength != (uint16_t)(9U + byteCount)))
  303. {
  304. return (isBroadcast != 0U)
  305. ? 0U
  306. : ModbusBuildException(request[1], MODBUS_EX_ILLEGAL_VALUE);
  307. }
  308. for (index = 0U; index < quantity; index++)
  309. {
  310. ModbusRegisterScratch[index] =
  311. ModbusGetU16Be(&request[7U + index * 2U]);
  312. }
  313. result = PlsrModbusWriteHolding(start, quantity, ModbusRegisterScratch);
  314. if (result != PLSR_MB_OK)
  315. {
  316. return ModbusBuildPlsrException(request[1], result, isBroadcast);
  317. }
  318. if (isBroadcast != 0U)
  319. {
  320. return 0U;
  321. }
  322. ModbusTxFrame[0] = ModbusSlaveAddress;
  323. ModbusTxFrame[1] = MODBUS_FC_WRITE_MULTIPLE;
  324. (void)memcpy(&ModbusTxFrame[2], &request[2], 4U);
  325. ModbusAppendCrc(ModbusTxFrame, 6U);
  326. return 8U;
  327. }
  328. static uint16_t ModbusProcessRequest(const uint8_t *request,
  329. uint16_t requestLength)
  330. {
  331. uint16_t receivedCrc;
  332. uint8_t isBroadcast;
  333. if (requestLength < 4U)
  334. {
  335. return 0U;
  336. }
  337. receivedCrc = (uint16_t)(request[requestLength - 2U]
  338. | ((uint16_t)request[requestLength - 1U] << 8U));
  339. if (ModbusCrc16(request, (uint16_t)(requestLength - 2U)) != receivedCrc)
  340. {
  341. return 0U;
  342. }
  343. if ((request[0] != ModbusSlaveAddress)
  344. && (request[0] != MODBUS_BROADCAST_ADDRESS))
  345. {
  346. return 0U;
  347. }
  348. isBroadcast = (request[0] == MODBUS_BROADCAST_ADDRESS) ? 1U : 0U;
  349. switch (request[1])
  350. {
  351. case MODBUS_FC_READ_HOLDING:
  352. return (isBroadcast != 0U)
  353. ? 0U
  354. : ModbusProcessReadHolding(request, requestLength);
  355. case MODBUS_FC_WRITE_SINGLE:
  356. return ModbusProcessWriteSingle(request,
  357. requestLength,
  358. isBroadcast);
  359. case MODBUS_FC_WRITE_MULTIPLE:
  360. return ModbusProcessWriteMultiple(request,
  361. requestLength,
  362. isBroadcast);
  363. default:
  364. return (isBroadcast != 0U)
  365. ? 0U
  366. : ModbusBuildException(request[1],
  367. MODBUS_EX_ILLEGAL_FUNCTION);
  368. }
  369. }
  370. HAL_StatusTypeDef ModbusSlaveInit(UART_HandleTypeDef *huart,
  371. uint8_t slaveAddress)
  372. {
  373. if ((huart == NULL)
  374. || (huart->Instance == NULL)
  375. || (huart->hdmarx == NULL)
  376. || (huart->hdmatx == NULL)
  377. || (huart->Init.BaudRate == 0UL)
  378. || (slaveAddress == MODBUS_BROADCAST_ADDRESS)
  379. || (slaveAddress > MODBUS_SLAVE_ADDRESS_MAX))
  380. {
  381. return HAL_ERROR;
  382. }
  383. ModbusUart = huart;
  384. ModbusSlaveAddress = slaveAddress;
  385. ModbusRxAssemblyLength = 0U;
  386. ModbusRxAssemblyInvalid = 0U;
  387. ModbusRxLastByteCycle = 0UL;
  388. ModbusRxFrameLength = 0U;
  389. ModbusRxFrameReady = 0U;
  390. ModbusTxBusy = 0U;
  391. ModbusRtuTimingInit(huart->Init.BaudRate);
  392. ModbusLastActivityCycle = DWT->CYCCNT;
  393. return ModbusStartReceive();
  394. }
  395. void ModbusSlavePoll(void)
  396. {
  397. uint16_t responseLength;
  398. uint32_t primask;
  399. HAL_StatusTypeDef txStatus = HAL_OK;
  400. if (ModbusUart == NULL)
  401. {
  402. return;
  403. }
  404. ModbusTryFinalizeReceive();
  405. if ((ModbusRxFrameReady == 0U) || (ModbusTxBusy != 0U))
  406. {
  407. return;
  408. }
  409. responseLength = ModbusProcessRequest(ModbusRxFrame,
  410. ModbusRxFrameLength);
  411. primask = ModbusEnterCritical();
  412. ModbusRxFrameReady = 0U;
  413. if (responseLength > 0U)
  414. {
  415. ModbusTxBusy = 1U;
  416. txStatus = HAL_UART_Transmit_DMA(ModbusUart,
  417. ModbusTxFrame,
  418. responseLength);
  419. if (txStatus != HAL_OK)
  420. {
  421. ModbusTxBusy = 0U;
  422. }
  423. }
  424. ModbusExitCritical(primask);
  425. if ((responseLength == 0U) || (txStatus != HAL_OK))
  426. {
  427. (void)ModbusStartReceive();
  428. }
  429. }
  430. uint8_t ModbusSlaveIsIdle(void)
  431. {
  432. uint32_t primask;
  433. uint32_t now;
  434. uint8_t isIdle = 0U;
  435. if ((ModbusUart == NULL) || (ModbusUart->hdmarx == NULL))
  436. {
  437. return 0U;
  438. }
  439. primask = ModbusEnterCritical();
  440. if ((ModbusRxAssemblyLength == 0U)
  441. && (ModbusRxAssemblyInvalid == 0U)
  442. && (ModbusRxFrameReady == 0U)
  443. && (ModbusTxBusy == 0U)
  444. && (ModbusUart->RxState == HAL_UART_STATE_BUSY_RX)
  445. && ((ModbusUart->Instance->CR3 & USART_CR3_DMAR) != 0U)
  446. && ((ModbusUart->hdmarx->Instance->CR & DMA_SxCR_EN) != 0U)
  447. && (__HAL_DMA_GET_COUNTER(ModbusUart->hdmarx)
  448. == MODBUS_RTU_ADU_SIZE_MAX)
  449. && ((ModbusUart->Instance->SR
  450. & (USART_SR_PE | USART_SR_FE | USART_SR_NE | USART_SR_ORE
  451. | USART_SR_IDLE | USART_SR_RXNE)) == 0U))
  452. {
  453. now = DWT->CYCCNT;
  454. if ((uint32_t)(now - ModbusLastActivityCycle)
  455. >= ModbusRtuT35Cycles)
  456. {
  457. isIdle = 1U;
  458. }
  459. }
  460. ModbusExitCritical(primask);
  461. return isIdle;
  462. }
  463. void ModbusSlaveOnRxEvent(UART_HandleTypeDef *huart, uint16_t size)
  464. {
  465. HAL_UART_RxEventTypeTypeDef eventType;
  466. uint32_t now;
  467. uint32_t lastByteCycle;
  468. uint32_t firstByteCycle;
  469. uint32_t chunkCycles;
  470. uint32_t interChunkGap;
  471. if ((ModbusUart == NULL) || (huart != ModbusUart))
  472. {
  473. return;
  474. }
  475. now = DWT->CYCCNT;
  476. ModbusLastActivityCycle = now;
  477. eventType = HAL_UARTEx_GetRxEventType(huart);
  478. if (eventType == HAL_UART_RXEVENT_HT)
  479. {
  480. return;
  481. }
  482. if ((size == 0U) || (size > MODBUS_RTU_ADU_SIZE_MAX))
  483. {
  484. ModbusRxAssemblyLength = 0U;
  485. ModbusRxAssemblyInvalid = 0U;
  486. (void)ModbusStartReceive();
  487. return;
  488. }
  489. lastByteCycle = now;
  490. if (eventType == HAL_UART_RXEVENT_IDLE)
  491. {
  492. lastByteCycle -= ModbusRtuCharCycles;
  493. }
  494. chunkCycles = (uint32_t)((uint64_t)size * ModbusRtuCharCycles);
  495. firstByteCycle = lastByteCycle - chunkCycles;
  496. if (ModbusRxAssemblyLength > 0U)
  497. {
  498. interChunkGap = (uint32_t)(firstByteCycle
  499. - ModbusRxLastByteCycle);
  500. if (interChunkGap >= ModbusRtuT35Cycles)
  501. {
  502. ModbusRxAssemblyFinalize();
  503. }
  504. else if (interChunkGap > ModbusRtuT15Cycles)
  505. {
  506. ModbusRxAssemblyInvalid = 1U;
  507. }
  508. }
  509. if (size <= (uint16_t)(MODBUS_RTU_ADU_SIZE_MAX
  510. - ModbusRxAssemblyLength))
  511. {
  512. (void)memcpy(&ModbusRxAssemblyBuffer[ModbusRxAssemblyLength],
  513. ModbusRxDmaBuffer,
  514. size);
  515. ModbusRxAssemblyLength += size;
  516. }
  517. else
  518. {
  519. ModbusRxAssemblyInvalid = 1U;
  520. }
  521. ModbusRxLastByteCycle = lastByteCycle;
  522. (void)ModbusStartReceive();
  523. }
  524. void ModbusSlaveOnTxComplete(UART_HandleTypeDef *huart)
  525. {
  526. if ((ModbusUart == NULL) || (huart != ModbusUart))
  527. {
  528. return;
  529. }
  530. ModbusLastActivityCycle = DWT->CYCCNT;
  531. ModbusTxBusy = 0U;
  532. (void)ModbusStartReceive();
  533. }
  534. void ModbusSlaveOnUartError(UART_HandleTypeDef *huart)
  535. {
  536. if ((ModbusUart == NULL) || (huart != ModbusUart))
  537. {
  538. return;
  539. }
  540. ModbusLastActivityCycle = DWT->CYCCNT;
  541. ModbusTxBusy = 0U;
  542. ModbusRxAssemblyLength = 0U;
  543. ModbusRxAssemblyInvalid = 0U;
  544. ModbusRxFrameLength = 0U;
  545. ModbusRxFrameReady = 0U;
  546. (void)HAL_UART_Abort(huart);
  547. (void)ModbusStartReceive();
  548. }