mb_util.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. /*
  2. *********************************************************************************************************
  3. * uC/Modbus
  4. * The Embedded Modbus Stack
  5. *
  6. * Copyright 2003-2020 Silicon Laboratories Inc. www.silabs.com
  7. *
  8. * SPDX-License-Identifier: APACHE-2.0
  9. *
  10. * This software is subject to an open source license and is distributed by
  11. * Silicon Laboratories Inc. pursuant to the terms of the Apache License,
  12. * Version 2.0 available at www.apache.org/licenses/LICENSE-2.0.
  13. *
  14. *********************************************************************************************************
  15. */
  16. /*
  17. *********************************************************************************************************
  18. * uC/MODBUS Utilities
  19. *
  20. * Filename : mb_util.h
  21. * Version : V2.14.00
  22. *********************************************************************************************************
  23. */
  24. /*
  25. *********************************************************************************************************
  26. * INCLUDE FILES
  27. *********************************************************************************************************
  28. */
  29. #define MB_UTIL_MODULE
  30. #include "mb.h"
  31. /*
  32. *********************************************************************************************************
  33. * LOCAL DEFINES
  34. *********************************************************************************************************
  35. */
  36. /*
  37. *********************************************************************************************************
  38. * LOCAL CONSTANTS
  39. *********************************************************************************************************
  40. */
  41. /*
  42. *********************************************************************************************************
  43. * LOCAL DATA TYPES
  44. *********************************************************************************************************
  45. */
  46. /*
  47. *********************************************************************************************************
  48. * LOCAL TABLES
  49. *********************************************************************************************************
  50. */
  51. /*
  52. *********************************************************************************************************
  53. * LOCAL GLOBAL VARIABLES
  54. *********************************************************************************************************
  55. */
  56. /*
  57. *********************************************************************************************************
  58. * LOCAL FUNCTION PROTOTYPES
  59. *********************************************************************************************************
  60. */
  61. /*
  62. *********************************************************************************************************
  63. * LOCAL CONFIGURATION ERRORS
  64. *********************************************************************************************************
  65. */
  66. /*
  67. *********************************************************************************************************
  68. * MB_ASCII_BinToHex()
  69. *
  70. * Description : Converts a byte into two ASCII characters into the given buffer.
  71. *
  72. * Argument(s) : value The byte of data to be converted.
  73. * pbuf A pointer to the buffer to store the ASCII chars.
  74. *
  75. * Return(s) : The buffer pointer which has been updated to point to the next char in the buffer.
  76. *
  77. * Caller(s) : MB_ASCII_Tx().
  78. *
  79. * Note(s) : (1) The function ONLY converts the byte to ASCII and DOES NOT null terminate the string.
  80. *********************************************************************************************************
  81. */
  82. #if (MODBUS_CFG_ASCII_EN == DEF_ENABLED)
  83. CPU_INT08U *MB_ASCII_BinToHex (CPU_INT08U value,
  84. CPU_INT08U *pbuf)
  85. {
  86. CPU_INT08U nibble;
  87. nibble = (value >> 4) & 0x0F; /* Upper Nibble */
  88. if (nibble <= 9) {
  89. *pbuf++ = (CPU_INT08U)(nibble + '0');
  90. } else {
  91. *pbuf++ = (CPU_INT08U)(nibble - 10 + 'A');
  92. }
  93. nibble = value & 0x0F; /* Lower Nibble */
  94. if (nibble <= 9) {
  95. *pbuf++ = (CPU_INT08U)(nibble + '0');
  96. } else {
  97. *pbuf++ = (CPU_INT08U)(nibble - 10 + 'A');
  98. }
  99. return (pbuf);
  100. }
  101. #endif
  102. /*
  103. *********************************************************************************************************
  104. * MB_ASCII_HexToBin()
  105. *
  106. * Description : Converts the first two ASCII hex characters in the buffer into one byte.
  107. *
  108. * Argument(s) : phex Pointer to the buffer that contains the two ascii chars.
  109. *
  110. * Return(s) : value of the two ASCII HEX digits pointed to by 'phex'.
  111. *
  112. * Caller(s) : MB_ASCII_RxByte(),
  113. * MB_ASCII_Rx(),
  114. * MB_ASCII_RxCalcLRC(),
  115. * MB_ASCII_TxCalcLRC().
  116. *
  117. * Note(s) : none.
  118. *********************************************************************************************************
  119. */
  120. #if (MODBUS_CFG_ASCII_EN == DEF_ENABLED)
  121. CPU_INT08U MB_ASCII_HexToBin (CPU_INT08U *phex)
  122. {
  123. CPU_INT08U value;
  124. CPU_INT08U high;
  125. CPU_INT08U low;
  126. high = *phex; /* Get upper nibble */
  127. phex++;
  128. low = *phex; /* Get lower nibble */
  129. if (high <= '9') { /* Upper Nibble */
  130. value = (CPU_INT08U)(high - '0');
  131. } else if (high <= 'F') {
  132. value = (CPU_INT08U)(high - 'A' + 10);
  133. } else {
  134. value = (CPU_INT08U)(high - 'a' + 10);
  135. }
  136. value <<= 4;
  137. if (low <= '9') { /* Lower Nibble */
  138. value += (CPU_INT08U)(low - '0');
  139. } else if (low <= 'F') {
  140. value += (CPU_INT08U)(low - 'A' + 10);
  141. } else {
  142. value += (CPU_INT08U)(low - 'a' + 10);
  143. }
  144. return (value);
  145. }
  146. #endif
  147. /*
  148. *********************************************************************************************************
  149. * MB_ASCII_RxCalcLRC()
  150. *
  151. * Description : The function calculates an 8-bit Longitudinal Redundancy Check on a MODBUS_FRAME
  152. * structure.
  153. *
  154. * Argument(s) : none.
  155. *
  156. * Return(s) : The calculated LRC value.
  157. *
  158. * Caller(s) : MBS_ASCII_Task().
  159. *
  160. * Note(s) : (1) The LRC is calculated on the ADDR, FC and Data fields, not the ':', CR/LF and LRC
  161. * placed in the message by the sender. We thus need to subtract 5 'ASCII' characters
  162. * from the received message to exclude these.
  163. *********************************************************************************************************
  164. */
  165. #if (MODBUS_CFG_ASCII_EN == DEF_ENABLED)
  166. CPU_INT08U MB_ASCII_RxCalcLRC (MODBUS_CH *pch)
  167. {
  168. CPU_INT08U lrc;
  169. CPU_INT16U len;
  170. CPU_INT08U *pblock;
  171. len = (pch->RxBufByteCtr - 5) / 2 ; /* LRC to include Addr + FC + Data */
  172. pblock = (CPU_INT08U *)&pch->RxBuf[1];
  173. lrc = 0;
  174. while (len-- > 0) { /* For each byte of data in the data block... */
  175. lrc += MB_ASCII_HexToBin(pblock); /* Add the data byte to LRC, increment data pointer. */
  176. pblock += 2;
  177. }
  178. lrc = ~lrc + 1; /* Two complement the binary sum */
  179. return (lrc); /* Return LRC for all data in block. */
  180. }
  181. #endif
  182. /*
  183. *********************************************************************************************************
  184. * MB_ASCII_TxCalcLRC()
  185. *
  186. * Description : The function calculates an 8-bit Longitudinal Redundancy Check on a MODBUS_FRAME
  187. * structure.
  188. *
  189. * Argument(s) : none.
  190. *
  191. * Return(s) : The calculated LRC value.
  192. *
  193. * Caller(s) : MB_ASCII_Tx().
  194. *
  195. * Note(s) : (1) The LRC is calculated on the ADDR, FC and Data fields, not the ':' which was inserted
  196. * in the TxBuf[]. Thus we subtract 1 ASCII character from the LRC.
  197. *
  198. * (2) The LRC and CR/LF bytes are not YET in the .RxBuf[].
  199. *********************************************************************************************************
  200. */
  201. #if (MODBUS_CFG_ASCII_EN == DEF_ENABLED)
  202. CPU_INT08U MB_ASCII_TxCalcLRC (MODBUS_CH *pch, CPU_INT16U tx_bytes)
  203. {
  204. CPU_INT08U lrc;
  205. CPU_INT16U len;
  206. CPU_INT08U *pblock;
  207. len = (tx_bytes - 1) / 2; /* LRC to include Addr + FC + Data (exclude ':') */
  208. pblock = (CPU_INT08U *)&pch->TxBuf[1];
  209. lrc = 0;
  210. while (len-- > 0) { /* For each byte of data in the data block... */
  211. lrc += MB_ASCII_HexToBin(pblock); /* Add the data byte to LRC, increment data pointer. */
  212. pblock += 2;
  213. }
  214. lrc = ~lrc + 1; /* Two complement the binary sum */
  215. return (lrc); /* Return LRC for all data in block. */
  216. }
  217. #endif
  218. /*
  219. *********************************************************************************************************
  220. * MB_RTU_RxCalcCRC()
  221. *
  222. * Description : The polynomial is a CRC-16 found for 'MBS_RxFrameNDataBytes' number of characters
  223. * starting at 'MBS_RxFrameAddr'.
  224. *
  225. * Argument(s) : none.
  226. *
  227. * Return(s) : An unsigned 16-bit value representing the CRC-16 of the data.
  228. *
  229. * Caller(s) : MBS_RTU_Task().
  230. *
  231. * Note(s) : none.
  232. *********************************************************************************************************
  233. */
  234. #if (MODBUS_CFG_RTU_EN == DEF_ENABLED)
  235. CPU_INT16U MB_RTU_RxCalcCRC (MODBUS_CH *pch)
  236. {
  237. CPU_INT16U crc;
  238. CPU_INT08U shiftctr;
  239. CPU_BOOLEAN flag;
  240. CPU_INT16U length;
  241. CPU_INT08U *pblock;
  242. pblock = (CPU_INT08U *)&pch->RxFrameData[0]; /* Starting address of where the CRC data starts */
  243. length = pch->RxFrameNDataBytes + 2; /* Include the address and function code in the CRC */
  244. crc = 0xFFFF; /* Initialize CRC to all ones. */
  245. while (length > 0) { /* Account for each byte of data */
  246. length--;
  247. crc ^= (CPU_INT16U)*pblock++;
  248. shiftctr = 8;
  249. do {
  250. flag = (crc & 0x0001) ? DEF_TRUE : DEF_FALSE; /* Determine if the shift out of rightmost bit is 1 */
  251. crc >>= 1; /* Shift CRC to the right one bit. */
  252. if (flag == DEF_TRUE) { /* If (bit shifted out of rightmost bit was a 1) */
  253. crc ^= MODBUS_CRC16_POLY; /* Exclusive OR the CRC with the generating polynomial. */
  254. }
  255. shiftctr--;
  256. } while (shiftctr > 0);
  257. }
  258. pch->RxFrameCRC_Calc = crc;
  259. return (crc);
  260. }
  261. #endif
  262. /*
  263. *********************************************************************************************************
  264. * MB_RTU_TxCalcCRC()
  265. *
  266. * Description : The polynomial is a CRC-16 found for 'MBS_TxFrameNDataBytes' number of characters
  267. * starting at 'MBS_TxFrameAddr'.
  268. *
  269. * Argument(s) : none.
  270. *
  271. * Return(s) : An unsigned 16-bit value representing the CRC-16 of the data.
  272. *
  273. * Caller(s) : MB_RTU_Tx().
  274. *
  275. * Note*(s) : none.
  276. *********************************************************************************************************
  277. */
  278. #if (MODBUS_CFG_RTU_EN == DEF_ENABLED)
  279. CPU_INT16U MB_RTU_TxCalcCRC (MODBUS_CH *pch)
  280. {
  281. CPU_INT16U crc;
  282. CPU_INT08U shiftctr;
  283. CPU_BOOLEAN flag;
  284. CPU_INT16U length;
  285. CPU_INT08U *pblock;
  286. pblock = (CPU_INT08U *)&pch->TxFrameData[0]; /* Starting address of where the CRC data starts */
  287. length = pch->TxFrameNDataBytes + 2; /* Include the address and function code in the CRC */
  288. crc = 0xFFFF; /* Initialize CRC to all ones. */
  289. while (length > 0) { /* Account for each byte of data */
  290. length--;
  291. crc ^= (CPU_INT16U)*pblock++;
  292. shiftctr = 8;
  293. do {
  294. flag = (crc & 0x0001) ? DEF_TRUE : DEF_FALSE; /* Determine if the shift out of rightmost bit is 1. */
  295. crc >>= 1; /* Shift CRC to the right one bit. */
  296. if (flag == DEF_TRUE) { /* If (bit shifted out of rightmost bit was a 1) */
  297. crc ^= MODBUS_CRC16_POLY; /* Exclusive OR the CRC with the generating polynomial */
  298. }
  299. shiftctr--;
  300. } while (shiftctr > 0);
  301. }
  302. return (crc); /* Return CRC for all data in block. */
  303. }
  304. #endif