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.
 
 
 
 

426 lines
17 KiB

  1. #include "Modbus.h"
  2. bitset<MAX_Address> Coil_date; //0-9999
  3. UINT16 Register[MAX_Address]; // 0-9999
  4. unsigned int Response_Message_Len;
  5. unsigned int RTU_Enable = 1;
  6. /*********************************************************************************************
  7. * 功能    : 计算写入数据的字节数
  8. * 描述   : 通过对应的功能码和操作数量计算对应的数据字节数
  9. * 输入 : Function_code 选择的功能码类型 Operations_Number对应功能码类型的操作数量
  10. * 输出 : Read_date_number 写入数据的字节数
  11. *********************************************************************************************/
  12. unsigned int Count_Read_date_number(int function_code, unsigned int operations_number)
  13. {
  14. unsigned int read_date_number = 0;
  15. if (function_code == 0x01 || function_code == 0x0F) //读线圈
  16. {
  17. read_date_number = operations_number / 8;
  18. if (operations_number % 8)
  19. read_date_number++;
  20. }
  21. if (function_code == 0x03 || function_code == 0x10)//读寄存器
  22. read_date_number = operations_number * 2;
  23. return read_date_number;
  24. }
  25. /*********************************************************************************************
  26. * 功能     :  计算CRC校验
  27. * 描述    : 获取Modbus—CRC-16的校验数据
  28. * 输入 : *Data 计算校验数据 CRC_Len 数据长度
  29. * 返回值 : Ret_CRC_date CRC校验结果
  30. **********************************************************************************************/
  31. UINT16 CRC_16(UINT8 *data, unsigned int crc_len)
  32. {
  33. UINT16 crc_date = 0XFFFF;//16位crc寄存器预置
  34. UINT16 temp;
  35. unsigned int i = 0, j = 0;
  36. for (i = 0; i < crc_len; i++)
  37. {
  38. temp = *data & 0X00FF;//将八位数据与CRC寄存器亦或
  39. data++;
  40. crc_date ^= temp;
  41. for (j = 0; j < 8; j++)
  42. {
  43. if (crc_date & 0X0001)//判断右移出的是不是1,如果是1则与多项式进行异或。
  44. {
  45. crc_date >>= 1;
  46. crc_date ^= 0XA001;
  47. }
  48. else
  49. {
  50. crc_date >>= 1;
  51. }
  52. }
  53. }
  54. UINT16 ret_crc_date = crc_date >> 8;
  55. ret_crc_date = ret_crc_date | crc_date << 8;
  56. return ret_crc_date;
  57. }
  58. /*********************************************************************************************
  59. * 功能     :  初始化线圈和寄存器
  60. * 描述    : 对线圈和寄存器数组赋值为全1
  61. * 输入 : 无
  62. * 返回值 : 无
  63. **********************************************************************************************/
  64. void Init_Coil_Register(void)
  65. {
  66. for (int i = 0; i < MAX_Address; i++)
  67. {
  68. Coil_date[i] = 1;
  69. Register[i] = 0xFFFF;
  70. }
  71. }
  72. /*********************************************************************************************
  73. * 功能     :  Bitset转UINT8类型
  74. * 描述    : Bitset ==》UINT8
  75. * 输入 : Bitset_Address Bitset的起始地址 Read_Number 要读取的位数
  76. * 返回值 : Date 转换后的UNIT8数据
  77. **********************************************************************************************/
  78. UINT8 Bitset_to_Uint8(unsigned int bitset_address, unsigned int read_number)
  79. {
  80. UINT8 date = 0x00;
  81. if (read_number >= 8)
  82. {
  83. unsigned int len = bitset_address + 7;
  84. for (unsigned int i = 0; i < 8; i++)
  85. {
  86. date = date << 1;
  87. date = date | (int)Coil_date[len--];
  88. }
  89. }
  90. else
  91. {
  92. unsigned int len = bitset_address + read_number - 1;
  93. for (unsigned int i = 0; i < read_number; i++)
  94. {
  95. date = date << 1;
  96. date = date | (int)Coil_date[len--];
  97. }
  98. }
  99. return date;
  100. }
  101. /*********************************************************************************************
  102. * 功能     :  生成异常码响应报文
  103. * 描述    : 对不支持的功能码生成对应的异常响应报文
  104. * 输入 : *Requst_Message 请求报文 *Response_Message响应报文
  105. * 返回值 : 无
  106. **********************************************************************************************/
  107. void Create_Abnormal_Code_Response_Message(UINT8 *Requst_Message, UINT8 *Response_Message, UINT8 abnormal_code)
  108. {
  109. Response_Message[0] = Device_ID;
  110. Response_Message[1] = Requst_Message[1] + 0x80;
  111. Response_Message[2] = abnormal_code;
  112. Response_Message_Len = 3;
  113. UINT16 crc_date = CRC_16(Response_Message, 3);
  114. Response_Message[3] = crc_date >> 8;//CRC_H
  115. Response_Message[4] = (UINT8)crc_date; //CRC_L
  116. Response_Message_Len = 5;
  117. }
  118. /*********************************************************************************************
  119. * 功能     :  生成0x01功能码响应报文
  120. * 描述    : 通过判断地址范围生成0x01对应的响应报文
  121. * 输入 : *Requst_Message 请求报文 *Response_Message响应报文
  122. * 返回值 : 无
  123. **********************************************************************************************/
  124. void Create_0x01_Response_Message(UINT8 *Requst_Message, UINT8 *Response_Message)
  125. {
  126. unsigned int start_Address = Requst_Message[2] << 8 | Requst_Message[3];
  127. unsigned int address_range = start_Address + (Requst_Message[4] << 8 | Requst_Message[5]);
  128. if (address_range < MAX_Address)//判断地址是否超限
  129. {
  130. unsigned int read_number = Requst_Message[4] << 8 | Requst_Message[5];//要读取的位数
  131. unsigned int read_len = Count_Read_date_number(Requst_Message[1], read_number); //要读取的字节数
  132. for (unsigned int i = 3; i < read_len + 3; i++)
  133. {
  134. Response_Message[i] = Bitset_to_Uint8(start_Address, read_number);
  135. start_Address += 8;
  136. read_number -= 8;
  137. }
  138. Response_Message[0] = Device_ID;
  139. Response_Message[1] = Requst_Message[1];
  140. Response_Message[2] = read_len; //响应报文中的后续字节数
  141. UINT16 crc_date = CRC_16(Response_Message, read_len + 3);
  142. Response_Message_Len = read_len + 2 + 3;
  143. Response_Message[Response_Message_Len - 2] = crc_date >> 8;//CRC_H
  144. Response_Message[Response_Message_Len - 1] = (UINT8)crc_date; //CRC_L
  145. }
  146. else
  147. {
  148. Create_Abnormal_Code_Response_Message(Requst_Message, Response_Message, 0x02);
  149. }
  150. }
  151. /*********************************************************************************************
  152. * 功能     :  生成0x03功能码响应报文
  153. * 描述    : 通过判断地址范围生成0x03对应的响应报文
  154. * 输入 : *Requst_Message 请求报文 *Response_Message响应报文
  155. * 返回值 : 无
  156. **********************************************************************************************/
  157. void Create_0x03_Response_Message(UINT8 *Requst_Message, UINT8 *Response_Message)
  158. {
  159. unsigned int start_Address = Requst_Message[2] << 8 | Requst_Message[3];
  160. unsigned int address_range = start_Address + (Requst_Message[4] << 8 | Requst_Message[5]);
  161. if (address_range < MAX_Address) //判断地址是否超限
  162. {
  163. unsigned int read_number = Requst_Message[4] << 8 | Requst_Message[5];//要读取的寄存器数量
  164. unsigned int read_len = Count_Read_date_number(Requst_Message[1], read_number); //要读取的字节数
  165. for (unsigned int i = 3; i < read_len + 3; i = i + 2)
  166. {
  167. Response_Message[i] = Register[start_Address] >> 8;
  168. Response_Message[i + 1] = (UINT8)Register[start_Address];
  169. start_Address += 1;
  170. }
  171. Response_Message[0] = Device_ID;
  172. Response_Message[1] = Requst_Message[1];
  173. Response_Message[2] = read_len; //响应报文中的后续字节数
  174. UINT16 crc_date = CRC_16(Response_Message, read_len + 3);
  175. Response_Message_Len = read_len + 2 + 3;
  176. Response_Message[Response_Message_Len - 2] = crc_date >> 8;//CRC_H
  177. Response_Message[Response_Message_Len - 1] = (UINT8)crc_date; //CRC_L
  178. }
  179. else //地址超限
  180. {
  181. Create_Abnormal_Code_Response_Message(Requst_Message, Response_Message, 0x02);
  182. }
  183. }
  184. /*********************************************************************************************
  185. * 功能     :  写入线圈
  186. * 描述    : 将数据写入线圈中
  187. * 输入 : Write_date_Message 要写入的数据 Write_Number要写入的位数 Start_Address起始地址
  188. * 返回值 : 无
  189. **********************************************************************************************/
  190. void Write_Coil_date(UINT8 write_date_message, unsigned int write_number, unsigned int start_address)
  191. {
  192. if (write_number >= 8)
  193. {
  194. for (unsigned int i = start_address; i < start_address + 8; i++)
  195. {
  196. Coil_date[i] = write_date_message & 1;
  197. write_date_message = write_date_message >> 1;
  198. }
  199. }
  200. else
  201. {
  202. for (unsigned int i = start_address; i < start_address + write_number; i++)
  203. {
  204. Coil_date[i] = write_date_message & 1;
  205. write_date_message = write_date_message >> 1;
  206. }
  207. }
  208. }
  209. /*********************************************************************************************
  210. * 功能     :  生成0x0F功能码响应报文
  211. * 描述    : 通过判断地址范围生成0x0F对应的响应报文
  212. * 输入 : *Requst_Message 请求报文 *Response_Message响应报文
  213. * 返回值 : 无
  214. **********************************************************************************************/
  215. void Create_0x0F_Response_Message(UINT8 *Requst_Message, UINT8 *Response_Message)
  216. {
  217. unsigned int start_Address = Requst_Message[2] << 8 | Requst_Message[3];
  218. unsigned int address_range = start_Address + (Requst_Message[4] << 8 | Requst_Message[5]);
  219. if (address_range < MAX_Address)//判断地址是否超限
  220. {
  221. unsigned int write_Number = Requst_Message[4] << 8 | Requst_Message[5];//要写入的位数
  222. for (int i = 7; i < Requst_Message[6] + 7; i++)//执行写入线圈操作
  223. {
  224. Write_Coil_date(Requst_Message[i], write_Number, start_Address);
  225. write_Number -= 8;
  226. start_Address += 8;
  227. }
  228. Response_Message[0] = Device_ID;
  229. Response_Message[1] = Requst_Message[1];
  230. Response_Message[2] = Requst_Message[2];
  231. Response_Message[3] = Requst_Message[3];
  232. Response_Message[4] = Requst_Message[4];
  233. Response_Message[5] = Requst_Message[5];
  234. UINT16 crc_date = CRC_16(Response_Message, 6);
  235. Response_Message[6] = crc_date >> 8;//CRC_H
  236. Response_Message[7] = (UINT8)crc_date; //CRC_L
  237. Response_Message_Len = 8;
  238. }
  239. else //地址超限
  240. {
  241. Create_Abnormal_Code_Response_Message(Requst_Message, Response_Message, 0x02);
  242. }
  243. }
  244. /*********************************************************************************************
  245. * 功能     :  生成0x10功能码响应报文
  246. * 描述    : 通过判断地址范围生成0x10对应的响应报文
  247. * 输入 : *Requst_Message 请求报文 *Response_Message响应报文
  248. * 返回值 : 无
  249. **********************************************************************************************/
  250. void Create_0x10_Response_Message(UINT8 *Requst_Message, UINT8 *Response_Message)
  251. {
  252. unsigned int start_Address = Requst_Message[2] << 8 | Requst_Message[3];
  253. unsigned int address_range = start_Address + (Requst_Message[4] << 8 | Requst_Message[5]);
  254. if (address_range < MAX_Address)//判断地址是否超限
  255. {
  256. for (int i = 7; i < Requst_Message[6] + 7; i = i + 2)//执行写入寄存器操作
  257. {
  258. Register[start_Address] = Requst_Message[i] << 8 | Requst_Message[i + 1];
  259. start_Address++;
  260. }
  261. Response_Message[0] = Device_ID;
  262. Response_Message[1] = Requst_Message[1];
  263. Response_Message[2] = Requst_Message[2];
  264. Response_Message[3] = Requst_Message[3];
  265. Response_Message[4] = Requst_Message[4];
  266. Response_Message[5] = Requst_Message[5];
  267. UINT16 crc_date = CRC_16(Response_Message, 6);
  268. Response_Message[6] = crc_date >> 8;//CRC_H
  269. Response_Message[7] = (UINT8)crc_date; //CRC_L
  270. Response_Message_Len = 8;
  271. }
  272. else //地址超限
  273. {
  274. Create_Abnormal_Code_Response_Message(Requst_Message, Response_Message, 0x02);
  275. }
  276. }
  277. /*********************************************************************************************
  278. * 功能     :  CRC校验
  279. * 描述    : 对请求报文中的数据进行CRC校验
  280. * 输入 : *Requst_Message 请求报文 Read_len 接收到到的字节数
  281. * 返回值 : true CRC校验通过
  282. * false CRC校验不通过
  283. **********************************************************************************************/
  284. bool Check_Requst_Message_CRC(UINT8 *Requst_Message, DWORD read_len)
  285. {
  286. UINT16 crc_data = CRC_16(Requst_Message, read_len - 2);
  287. UINT16 message_crc = Requst_Message[read_len - 2] << 8 | Requst_Message[read_len - 1];
  288. if (crc_data != message_crc)
  289. return false;
  290. return true;
  291. }
  292. /*********************************************************************************************
  293. * 功能     :  异常码03判定--请求报文长度校验
  294. * 描述    : 对请求报文的字节长度进行计算校验
  295. * 输入 : *Requst_Message 请求报文 Read_len 接收到到的字节数
  296. * 返回值 : true 长度校验通过
  297. * false 长度校验不通过
  298. **********************************************************************************************/
  299. bool Check_Requst_Message_Len(UINT8 *Requst_Message, DWORD read_len)
  300. {
  301. if (Requst_Message[1] == 0x01 || Requst_Message[1] == 0x03)
  302. {
  303. if (read_len != 8)
  304. return false;
  305. }
  306. if (Requst_Message[1] == 0x0F || Requst_Message[1] == 0x10)
  307. {
  308. unsigned int number = Requst_Message[4] << 8 | Requst_Message[5];
  309. unsigned int count_len = Count_Read_date_number(Requst_Message[1], number);
  310. if (Requst_Message[6] != count_len || read_len != count_len + 9)
  311. return false;
  312. }
  313. return true;
  314. }
  315. /*********************************************************************************************
  316. * 功能     :  异常码03判定--请求报文中的操作数量判定
  317. * 描述    : 对请求报文中的操作数量进行判定
  318. * 输入 : *Requst_Message 请求报文 Read_len 接收到到的字节数
  319. * 返回值 : true 校验通过
  320. * false 校验不通过
  321. **********************************************************************************************/
  322. bool Check_Operation_Number_Requst_Message(UINT8 *Requst_Message)
  323. {
  324. unsigned int operation_number = Requst_Message[4] << 8 | Requst_Message[5];
  325. if (Requst_Message[1] == 0x01)
  326. {
  327. if (operation_number == 0 || operation_number > 2000)
  328. return false;
  329. }
  330. if (Requst_Message[1] == 0x03)
  331. {
  332. if (operation_number == 0 || operation_number > 125)
  333. return false;
  334. }
  335. if (Requst_Message[1] == 0x0F)
  336. {
  337. if (operation_number < 1 || operation_number > 1968)
  338. return false;
  339. }
  340. if (Requst_Message[1] == 0x10)
  341. {
  342. if (operation_number < 1 || operation_number > 123)
  343. return false;
  344. }
  345. return true;
  346. }
  347. /*********************************************************************************************
  348. * 功能     :  解析请求报文
  349. * 描述    : 判断该请求报文的返回类型
  350. * 输入 : *Requst_Message 请求报文 *Response_Message 响应报文 Read_len 接收到到的字节数
  351. * 返回值 : 响应类型
  352. **********************************************************************************************/
  353. int Analysis_Response_Msg(UINT8 *Requst_Message, UINT8 *Response_Message, DWORD read_len)
  354. {
  355. if (read_len < 8)
  356. return NO_RESPONSE;
  357. if (!Check_Requst_Message_CRC(Requst_Message, read_len))//CRC校验报文是否正确
  358. return NO_RESPONSE;
  359. if (Requst_Message[0] != Device_ID) //检查设备ID一致
  360. return NO_RESPONSE;
  361. if (RTU_Enable == 0)
  362. {
  363. return EXCEPTION_CODE_04;
  364. }
  365. if (!Check_Requst_Message_Len(Requst_Message, read_len) || !Check_Operation_Number_Requst_Message(Requst_Message))//检查请求报文长度是否正确
  366. {
  367. return EXCEPTION_CODE_03;
  368. }
  369. if (Requst_Message[1] != 0x01 && Requst_Message[1] != 0x03 && Requst_Message[1] != 0x0F && Requst_Message[1] != 0x10)
  370. return EXCEPTION_CODE_01;
  371. return NORMAL_REQUEST;
  372. }
  373. /*********************************************************************************************
  374. * 功能     :  生成正常读写响应报文和02异常码响应
  375. * 描述    : 通过对功能码进行判断,进行相应的读写操作后,生成对应的相应报文
  376. * 输入 : *Requst_Message 请求报文 *Response_Message 响应报文
  377. * 返回值 : 无
  378. **********************************************************************************************/
  379. void Create_Normal_Message(UINT8 *Requst_Message, UINT8 *Response_Message)
  380. {
  381. switch (Requst_Message[1])
  382. {
  383. case 0x01:Create_0x01_Response_Message(Requst_Message, Response_Message); break;
  384. case 0x03:Create_0x03_Response_Message(Requst_Message, Response_Message); break;
  385. case 0x0F:Create_0x0F_Response_Message(Requst_Message, Response_Message); break;
  386. case 0x10:Create_0x10_Response_Message(Requst_Message, Response_Message); break;
  387. default: Create_Abnormal_Code_Response_Message(Requst_Message, Response_Message, 0x04);
  388. }
  389. }
  390. /*********************************************************************************************
  391. * 功能     :  生成响应报文
  392. * 描述    : 检查设备请求报文来生成对应功能的响应报文
  393. * 输入 : *Requst_Message 请求报文 *Response_Message响应报文
  394. * 返回值 : true 生成响应报文
  395. * false 不生成响应报文
  396. **********************************************************************************************/
  397. bool Create_Response_Message(UINT8 *Requst_Message, UINT8 *Response_Message, int flage)
  398. {
  399. switch (flage)
  400. {
  401. case NO_RESPONSE:return false;
  402. case NORMAL_REQUEST: Create_Normal_Message(Requst_Message, Response_Message); break;
  403. case EXCEPTION_CODE_01:Create_Abnormal_Code_Response_Message(Requst_Message, Response_Message, 0x01); break;
  404. case EXCEPTION_CODE_03:Create_Abnormal_Code_Response_Message(Requst_Message, Response_Message, 0x03); break;
  405. case EXCEPTION_CODE_04:Create_Abnormal_Code_Response_Message(Requst_Message, Response_Message, 0x04); break;
  406. }
  407. return true;
  408. }