当前位置:   article > 正文

C++上位软件通过LibModbus开源库和西门子S7-1200/S7-1500/S7-200 PLC进行ModbusTcp 和ModbusRTU 通信

libmodbus

前言

        一直以来上位软件比如C++等和西门子等其他品牌PLC之间的数据交换都是大家比较头疼的问题,尤其是C++上位软件程序员。传统的方法一般有OPC、Socket 等,直到LibModbus 开源库出现后这种途径对程序袁来说又有了新的选择。

Modbus简介

Modbus特点

        1 )使用简单,利用MUDBUS库文件简单的几条指令就能实现与智能仪表,变频器,打印机等设备进行通讯,且无需加其他硬件上的成本MODBUS总线广泛应用于仪器仪表、智能高低压电器、变送器、可编程控制器、人机界面、变频器、现场智能设备等诸多领域。MODBUS与其他的现场总线和工业网络相比有以下几个显著特点。

        2)标准、开放:用户可以免费放心的使用

        MODBUS协议,不用缴纳许可费用,不会涉及侵犯知识产权。目前支持MODBUS的厂一家超过400家,支持MODBUS的产品超过600种。在中国,MODBUS已经成为国家标准GB/T19582-2008。据不完全统 计:截止到2007年MODBUS的节点安装数量已经超过了1000万个。

        3)应用广泛:凡MODBUS协议设备具有RS232/485接口的都可以使用本产品实现与现场总线PROFIBUS的互连。如:具有MODBUS协议接口的变频器、智能高低压电器、电机启动保护装置、电量测量装置、智能现场测量设备、各种变送器及仪表等。

        4)MODBUS可以支持较多类型的电气接口:MODBUS 总线协议采用主站查询从站的方式,物理接口可以是RS232、RS485、RS422、RJ45,还可以在各种介质上传送,如双绞线、光纤、无线射频等。

        5)MODBUS的帧格式较为简单、紧凑,格式规范,易于传输,通俗易懂。用户使用容易,厂商开发简单。用户不必了解PROFIBUS和MODBUS技术细节,只需参考说明手册及提供的应用实例,按要求完成配置,不需要复杂的编程,即可在短时间内实现设备间的连接通信。

        6)透明通信:用户可以依照PROFIBUS通信数据区和MODBUS通信数据区的映射关系,实现PROFIBUS到MODBUS之间的数据透明通信。

LibModbus库下载

https://libmodbus.org/icon-default.png?t=N7T8https://libmodbus.org/

https://gitcode.com/stephane/libmodbus/overview?utm_source=csdn_github_accelerator&isLogin=1icon-default.png?t=N7T8https://gitcode.com/stephane/libmodbus/overview?utm_source=csdn_github_accelerator&isLogin=1https://github.com/stephane/libmodbusicon-default.png?t=N7T8https://github.com/stephane/libmodbushttps://download.csdn.net/download/lzc881012/88695801icon-default.png?t=N7T8https://download.csdn.net/download/lzc881012/88695801

LibModbus库Windows版本的编译


1、进入到libmodbus\src\win32文件夹下。
2、双击configure.js文件进行编译,成功后会弹出编译完成窗口,点击关闭。
3、然后在双击modbus-9.sln通过VS打开项目,打开项目完成后编译即可。
4、编译完成后libmodbus\src\win32文件夹下就会出现modbus.dll和modbus.lib两个文件。

  1. 将上述步骤中生成的modbus.lib文件和libmodbus\src中所有的.h文件通过VS包含到自己的项目中即可。
  2. 在程序中包含libModbus/modbus.h一个头文件即可。
  3. 将上述步骤在生成的modbus.dll放到你的项目生成目录下,例如Debug/Release目录下。

LibModbus库modbus.h头文件

  1. /*
  2. * Copyright © 2001-2013 Stéphane Raimbault <stephane.raimbault@gmail.com>
  3. *
  4. * SPDX-License-Identifier: LGPL-2.1+
  5. */
  6. #ifndef MODBUS_H
  7. #define MODBUS_H
  8. /* Add this for macros that defined unix flavor */
  9. #if (defined(__unix__) || defined(unix)) && !defined(USG)
  10. #include <sys/param.h>
  11. #endif
  12. #ifndef _MSC_VER
  13. #include <stdint.h>
  14. #else
  15. #include "stdint.h"
  16. #endif
  17. #include "modbus-version.h"
  18. #if defined(_MSC_VER)
  19. # if defined(DLLBUILD)
  20. /* define DLLBUILD when building the DLL */
  21. # define MODBUS_API __declspec(dllexport)
  22. # else
  23. # define MODBUS_API __declspec(dllimport)
  24. # endif
  25. #else
  26. # define MODBUS_API
  27. #endif
  28. #ifdef __cplusplus
  29. # define MODBUS_BEGIN_DECLS extern "C" {
  30. # define MODBUS_END_DECLS }
  31. #else
  32. # define MODBUS_BEGIN_DECLS
  33. # define MODBUS_END_DECLS
  34. #endif
  35. MODBUS_BEGIN_DECLS
  36. #ifndef FALSE
  37. #define FALSE 0
  38. #endif
  39. #ifndef TRUE
  40. #define TRUE 1
  41. #endif
  42. #ifndef OFF
  43. #define OFF 0
  44. #endif
  45. #ifndef ON
  46. #define ON 1
  47. #endif
  48. /* Modbus function codes */
  49. #define MODBUS_FC_READ_COILS 0x01
  50. #define MODBUS_FC_READ_DISCRETE_INPUTS 0x02
  51. #define MODBUS_FC_READ_HOLDING_REGISTERS 0x03
  52. #define MODBUS_FC_READ_INPUT_REGISTERS 0x04
  53. #define MODBUS_FC_WRITE_SINGLE_COIL 0x05
  54. #define MODBUS_FC_WRITE_SINGLE_REGISTER 0x06
  55. #define MODBUS_FC_READ_EXCEPTION_STATUS 0x07
  56. #define MODBUS_FC_WRITE_MULTIPLE_COILS 0x0F
  57. #define MODBUS_FC_WRITE_MULTIPLE_REGISTERS 0x10
  58. #define MODBUS_FC_REPORT_SLAVE_ID 0x11
  59. #define MODBUS_FC_MASK_WRITE_REGISTER 0x16
  60. #define MODBUS_FC_WRITE_AND_READ_REGISTERS 0x17
  61. #define MODBUS_BROADCAST_ADDRESS 0
  62. /* Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 1 page 12)
  63. * Quantity of Coils to read (2 bytes): 1 to 2000 (0x7D0)
  64. * (chapter 6 section 11 page 29)
  65. * Quantity of Coils to write (2 bytes): 1 to 1968 (0x7B0)
  66. */
  67. #define MODBUS_MAX_READ_BITS 2000
  68. #define MODBUS_MAX_WRITE_BITS 1968
  69. /* Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 3 page 15)
  70. * Quantity of Registers to read (2 bytes): 1 to 125 (0x7D)
  71. * (chapter 6 section 12 page 31)
  72. * Quantity of Registers to write (2 bytes) 1 to 123 (0x7B)
  73. * (chapter 6 section 17 page 38)
  74. * Quantity of Registers to write in R/W registers (2 bytes) 1 to 121 (0x79)
  75. */
  76. #define MODBUS_MAX_READ_REGISTERS 125
  77. #define MODBUS_MAX_WRITE_REGISTERS 123
  78. #define MODBUS_MAX_WR_WRITE_REGISTERS 121
  79. #define MODBUS_MAX_WR_READ_REGISTERS 125
  80. /* The size of the MODBUS PDU is limited by the size constraint inherited from
  81. * the first MODBUS implementation on Serial Line network (max. RS485 ADU = 256
  82. * bytes). Therefore, MODBUS PDU for serial line communication = 256 - Server
  83. * address (1 byte) - CRC (2 bytes) = 253 bytes.
  84. */
  85. #define MODBUS_MAX_PDU_LENGTH 253
  86. /* Consequently:
  87. * - RTU MODBUS ADU = 253 bytes + Server address (1 byte) + CRC (2 bytes) = 256
  88. * bytes.
  89. * - TCP MODBUS ADU = 253 bytes + MBAP (7 bytes) = 260 bytes.
  90. * so the maximum of both backend in 260 bytes. This size can used to allocate
  91. * an array of bytes to store responses and it will be compatible with the two
  92. * backends.
  93. */
  94. #define MODBUS_MAX_ADU_LENGTH 260
  95. /* Random number to avoid errno conflicts */
  96. #define MODBUS_ENOBASE 112345678
  97. /* Protocol exceptions */
  98. enum {
  99. MODBUS_EXCEPTION_ILLEGAL_FUNCTION = 0x01,
  100. MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS,
  101. MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,
  102. MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE,
  103. MODBUS_EXCEPTION_ACKNOWLEDGE,
  104. MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY,
  105. MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE,
  106. MODBUS_EXCEPTION_MEMORY_PARITY,
  107. MODBUS_EXCEPTION_NOT_DEFINED,
  108. MODBUS_EXCEPTION_GATEWAY_PATH,
  109. MODBUS_EXCEPTION_GATEWAY_TARGET,
  110. MODBUS_EXCEPTION_MAX
  111. };
  112. #define EMBXILFUN (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_FUNCTION)
  113. #define EMBXILADD (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS)
  114. #define EMBXILVAL (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE)
  115. #define EMBXSFAIL (MODBUS_ENOBASE + MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE)
  116. #define EMBXACK (MODBUS_ENOBASE + MODBUS_EXCEPTION_ACKNOWLEDGE)
  117. #define EMBXSBUSY (MODBUS_ENOBASE + MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY)
  118. #define EMBXNACK (MODBUS_ENOBASE + MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE)
  119. #define EMBXMEMPAR (MODBUS_ENOBASE + MODBUS_EXCEPTION_MEMORY_PARITY)
  120. #define EMBXGPATH (MODBUS_ENOBASE + MODBUS_EXCEPTION_GATEWAY_PATH)
  121. #define EMBXGTAR (MODBUS_ENOBASE + MODBUS_EXCEPTION_GATEWAY_TARGET)
  122. /* Native libmodbus error codes */
  123. #define EMBBADCRC (EMBXGTAR + 1)
  124. #define EMBBADDATA (EMBXGTAR + 2)
  125. #define EMBBADEXC (EMBXGTAR + 3)
  126. #define EMBUNKEXC (EMBXGTAR + 4)
  127. #define EMBMDATA (EMBXGTAR + 5)
  128. #define EMBBADSLAVE (EMBXGTAR + 6)
  129. extern const unsigned int libmodbus_version_major;
  130. extern const unsigned int libmodbus_version_minor;
  131. extern const unsigned int libmodbus_version_micro;
  132. typedef struct _modbus modbus_t;
  133. typedef struct _modbus_mapping_t {
  134. int nb_bits;
  135. int start_bits;
  136. int nb_input_bits;
  137. int start_input_bits;
  138. int nb_input_registers;
  139. int start_input_registers;
  140. int nb_registers;
  141. int start_registers;
  142. uint8_t *tab_bits;
  143. uint8_t *tab_input_bits;
  144. uint16_t *tab_input_registers;
  145. uint16_t *tab_registers;
  146. } modbus_mapping_t;
  147. typedef enum
  148. {
  149. MODBUS_ERROR_RECOVERY_NONE = 0,
  150. MODBUS_ERROR_RECOVERY_LINK = (1<<1),
  151. MODBUS_ERROR_RECOVERY_PROTOCOL = (1<<2)
  152. } modbus_error_recovery_mode;
  153. MODBUS_API int modbus_set_slave(modbus_t* ctx, int slave);
  154. MODBUS_API int modbus_get_slave(modbus_t* ctx);
  155. MODBUS_API int modbus_set_error_recovery(modbus_t *ctx, modbus_error_recovery_mode error_recovery);
  156. MODBUS_API int modbus_set_socket(modbus_t *ctx, int s);
  157. MODBUS_API int modbus_get_socket(modbus_t *ctx);
  158. MODBUS_API int modbus_get_response_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec);
  159. MODBUS_API int modbus_set_response_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec);
  160. MODBUS_API int modbus_get_byte_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec);
  161. MODBUS_API int modbus_set_byte_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec);
  162. MODBUS_API int modbus_get_indication_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec);
  163. MODBUS_API int modbus_set_indication_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec);
  164. MODBUS_API int modbus_get_header_length(modbus_t *ctx);
  165. MODBUS_API int modbus_connect(modbus_t *ctx);
  166. MODBUS_API void modbus_close(modbus_t *ctx);
  167. MODBUS_API void modbus_free(modbus_t *ctx);
  168. MODBUS_API int modbus_flush(modbus_t *ctx);
  169. MODBUS_API int modbus_set_debug(modbus_t *ctx, int flag);
  170. MODBUS_API const char *modbus_strerror(int errnum);
  171. MODBUS_API int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
  172. MODBUS_API int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
  173. MODBUS_API int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
  174. MODBUS_API int modbus_read_input_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
  175. MODBUS_API int modbus_write_bit(modbus_t *ctx, int coil_addr, int status);
  176. MODBUS_API int modbus_write_register(modbus_t *ctx, int reg_addr, const uint16_t value);
  177. MODBUS_API int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *data);
  178. MODBUS_API int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *data);
  179. MODBUS_API int modbus_mask_write_register(modbus_t *ctx, int addr, uint16_t and_mask, uint16_t or_mask);
  180. MODBUS_API int modbus_write_and_read_registers(modbus_t *ctx, int write_addr, int write_nb,
  181. const uint16_t *src, int read_addr, int read_nb,
  182. uint16_t *dest);
  183. MODBUS_API int modbus_report_slave_id(modbus_t *ctx, int max_dest, uint8_t *dest);
  184. MODBUS_API modbus_mapping_t* modbus_mapping_new_start_address(
  185. unsigned int start_bits, unsigned int nb_bits,
  186. unsigned int start_input_bits, unsigned int nb_input_bits,
  187. unsigned int start_registers, unsigned int nb_registers,
  188. unsigned int start_input_registers, unsigned int nb_input_registers);
  189. MODBUS_API modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits,
  190. int nb_registers, int nb_input_registers);
  191. MODBUS_API void modbus_mapping_free(modbus_mapping_t *mb_mapping);
  192. MODBUS_API int modbus_send_raw_request(modbus_t *ctx, const uint8_t *raw_req, int raw_req_length);
  193. MODBUS_API int modbus_receive(modbus_t *ctx, uint8_t *req);
  194. MODBUS_API int modbus_receive_confirmation(modbus_t *ctx, uint8_t *rsp);
  195. MODBUS_API int modbus_reply(modbus_t *ctx, const uint8_t *req,
  196. int req_length, modbus_mapping_t *mb_mapping);
  197. MODBUS_API int modbus_reply_exception(modbus_t *ctx, const uint8_t *req,
  198. unsigned int exception_code);
  199. /**
  200. * UTILS FUNCTIONS
  201. **/
  202. #define MODBUS_GET_HIGH_BYTE(data) (((data) >> 8) & 0xFF)
  203. #define MODBUS_GET_LOW_BYTE(data) ((data) & 0xFF)
  204. #define MODBUS_GET_INT64_FROM_INT16(tab_int16, index) \
  205. (((int64_t)tab_int16[(index) ] << 48) + \
  206. ((int64_t)tab_int16[(index) + 1] << 32) + \
  207. ((int64_t)tab_int16[(index) + 2] << 16) + \
  208. (int64_t)tab_int16[(index) + 3])
  209. #define MODBUS_GET_INT32_FROM_INT16(tab_int16, index) ((tab_int16[(index)] << 16) + tab_int16[(index) + 1])
  210. #define MODBUS_GET_INT16_FROM_INT8(tab_int8, index) ((tab_int8[(index)] << 8) + tab_int8[(index) + 1])
  211. #define MODBUS_SET_INT16_TO_INT8(tab_int8, index, value) \
  212. do { \
  213. tab_int8[(index)] = (value) >> 8; \
  214. tab_int8[(index) + 1] = (value) & 0xFF; \
  215. } while (0)
  216. #define MODBUS_SET_INT32_TO_INT16(tab_int16, index, value) \
  217. do { \
  218. tab_int16[(index) ] = (value) >> 16; \
  219. tab_int16[(index) + 1] = (value); \
  220. } while (0)
  221. #define MODBUS_SET_INT64_TO_INT16(tab_int16, index, value) \
  222. do { \
  223. tab_int16[(index) ] = (value) >> 48; \
  224. tab_int16[(index) + 1] = (value) >> 32; \
  225. tab_int16[(index) + 2] = (value) >> 16; \
  226. tab_int16[(index) + 3] = (value); \
  227. } while (0)
  228. MODBUS_API void modbus_set_bits_from_byte(uint8_t *dest, int idx, const uint8_t value);
  229. MODBUS_API void modbus_set_bits_from_bytes(uint8_t *dest, int idx, unsigned int nb_bits,
  230. const uint8_t *tab_byte);
  231. MODBUS_API uint8_t modbus_get_byte_from_bits(const uint8_t *src, int idx, unsigned int nb_bits);
  232. MODBUS_API float modbus_get_float(const uint16_t *src);
  233. MODBUS_API float modbus_get_float_abcd(const uint16_t *src);
  234. MODBUS_API float modbus_get_float_dcba(const uint16_t *src);
  235. MODBUS_API float modbus_get_float_badc(const uint16_t *src);
  236. MODBUS_API float modbus_get_float_cdab(const uint16_t *src);
  237. MODBUS_API void modbus_set_float(float f, uint16_t *dest);
  238. MODBUS_API void modbus_set_float_abcd(float f, uint16_t *dest);
  239. MODBUS_API void modbus_set_float_dcba(float f, uint16_t *dest);
  240. MODBUS_API void modbus_set_float_badc(float f, uint16_t *dest);
  241. MODBUS_API void modbus_set_float_cdab(float f, uint16_t *dest);
  242. #include "modbus-tcp.h"
  243. #include "modbus-rtu.h"
  244. MODBUS_END_DECLS
  245. #endif /* MODBUS_H */

 

LibModbus库Modbus.h头文件

  1. /*
  2. * Copyright © 2001-2011 Stéphane Raimbault <stephane.raimbault@gmail.com>
  3. *
  4. * SPDX-License-Identifier: LGPL-2.1+
  5. *
  6. * This library implements the Modbus protocol.
  7. * http://libmodbus.org/
  8. */
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <stdlib.h>
  12. #include <stdarg.h>
  13. #include <errno.h>
  14. #include <limits.h>
  15. #include <time.h>
  16. #ifndef _MSC_VER
  17. #include <unistd.h>
  18. #endif
  19. #include <config.h>
  20. #include "modbus.h"
  21. #include "modbus-private.h"
  22. /* Internal use */
  23. #define MSG_LENGTH_UNDEFINED -1
  24. /* Exported version */
  25. const unsigned int libmodbus_version_major = LIBMODBUS_VERSION_MAJOR;
  26. const unsigned int libmodbus_version_minor = LIBMODBUS_VERSION_MINOR;
  27. const unsigned int libmodbus_version_micro = LIBMODBUS_VERSION_MICRO;
  28. /* Max between RTU and TCP max adu length (so TCP) */
  29. #define MAX_MESSAGE_LENGTH 260
  30. /* 3 steps are used to parse the query */
  31. typedef enum {
  32. _STEP_FUNCTION,
  33. _STEP_META,
  34. _STEP_DATA
  35. } _step_t;
  36. const char *modbus_strerror(int errnum) {
  37. switch (errnum) {
  38. case EMBXILFUN:
  39. return "Illegal function";
  40. case EMBXILADD:
  41. return "Illegal data address";
  42. case EMBXILVAL:
  43. return "Illegal data value";
  44. case EMBXSFAIL:
  45. return "Slave device or server failure";
  46. case EMBXACK:
  47. return "Acknowledge";
  48. case EMBXSBUSY:
  49. return "Slave device or server is busy";
  50. case EMBXNACK:
  51. return "Negative acknowledge";
  52. case EMBXMEMPAR:
  53. return "Memory parity error";
  54. case EMBXGPATH:
  55. return "Gateway path unavailable";
  56. case EMBXGTAR:
  57. return "Target device failed to respond";
  58. case EMBBADCRC:
  59. return "Invalid CRC";
  60. case EMBBADDATA:
  61. return "Invalid data";
  62. case EMBBADEXC:
  63. return "Invalid exception code";
  64. case EMBMDATA:
  65. return "Too many data";
  66. case EMBBADSLAVE:
  67. return "Response not from requested slave";
  68. default:
  69. return strerror(errnum);
  70. }
  71. }
  72. void _error_print(modbus_t *ctx, const char *context)
  73. {
  74. if (ctx->debug) {
  75. fprintf(stderr, "ERROR %s", modbus_strerror(errno));
  76. if (context != NULL) {
  77. fprintf(stderr, ": %s\n", context);
  78. } else {
  79. fprintf(stderr, "\n");
  80. }
  81. }
  82. }
  83. static void _sleep_response_timeout(modbus_t *ctx)
  84. {
  85. /* Response timeout is always positive */
  86. #ifdef _WIN32
  87. /* usleep doesn't exist on Windows */
  88. Sleep((ctx->response_timeout.tv_sec * 1000) +
  89. (ctx->response_timeout.tv_usec / 1000));
  90. #else
  91. /* usleep source code */
  92. struct timespec request, remaining;
  93. request.tv_sec = ctx->response_timeout.tv_sec;
  94. request.tv_nsec = ((long int)ctx->response_timeout.tv_usec) * 1000;
  95. while (nanosleep(&request, &remaining) == -1 && errno == EINTR) {
  96. request = remaining;
  97. }
  98. #endif
  99. }
  100. int modbus_flush(modbus_t *ctx)
  101. {
  102. int rc;
  103. if (ctx == NULL) {
  104. errno = EINVAL;
  105. return -1;
  106. }
  107. rc = ctx->backend->flush(ctx);
  108. if (rc != -1 && ctx->debug) {
  109. /* Not all backends are able to return the number of bytes flushed */
  110. printf("Bytes flushed (%d)\n", rc);
  111. }
  112. return rc;
  113. }
  114. /* Computes the length of the expected response */
  115. static unsigned int compute_response_length_from_request(modbus_t *ctx, uint8_t *req)
  116. {
  117. int length;
  118. const int offset = ctx->backend->header_length;
  119. switch (req[offset]) {
  120. case MODBUS_FC_READ_COILS:
  121. case MODBUS_FC_READ_DISCRETE_INPUTS: {
  122. /* Header + nb values (code from write_bits) */
  123. int nb = (req[offset + 3] << 8) | req[offset + 4];
  124. length = 2 + (nb / 8) + ((nb % 8) ? 1 : 0);
  125. }
  126. break;
  127. case MODBUS_FC_WRITE_AND_READ_REGISTERS:
  128. case MODBUS_FC_READ_HOLDING_REGISTERS:
  129. case MODBUS_FC_READ_INPUT_REGISTERS:
  130. /* Header + 2 * nb values */
  131. length = 2 + 2 * (req[offset + 3] << 8 | req[offset + 4]);
  132. break;
  133. case MODBUS_FC_READ_EXCEPTION_STATUS:
  134. length = 3;
  135. break;
  136. case MODBUS_FC_REPORT_SLAVE_ID:
  137. /* The response is device specific (the header provides the
  138. length) */
  139. return MSG_LENGTH_UNDEFINED;
  140. case MODBUS_FC_MASK_WRITE_REGISTER:
  141. length = 7;
  142. break;
  143. default:
  144. length = 5;
  145. }
  146. return offset + length + ctx->backend->checksum_length;
  147. }
  148. /* Sends a request/response */
  149. static int send_msg(modbus_t *ctx, uint8_t *msg, int msg_length)
  150. {
  151. int rc;
  152. int i;
  153. msg_length = ctx->backend->send_msg_pre(msg, msg_length);
  154. if (ctx->debug) {
  155. for (i = 0; i < msg_length; i++)
  156. printf("[%.2X]", msg[i]);
  157. printf("\n");
  158. }
  159. /* In recovery mode, the write command will be issued until to be
  160. successful! Disabled by default. */
  161. do {
  162. rc = ctx->backend->send(ctx, msg, msg_length);
  163. if (rc == -1) {
  164. _error_print(ctx, NULL);
  165. if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) {
  166. int saved_errno = errno;
  167. if ((errno == EBADF || errno == ECONNRESET || errno == EPIPE)) {
  168. modbus_close(ctx);
  169. _sleep_response_timeout(ctx);
  170. modbus_connect(ctx);
  171. } else {
  172. _sleep_response_timeout(ctx);
  173. modbus_flush(ctx);
  174. }
  175. errno = saved_errno;
  176. }
  177. }
  178. } while ((ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) &&
  179. rc == -1);
  180. if (rc > 0 && rc != msg_length) {
  181. errno = EMBBADDATA;
  182. return -1;
  183. }
  184. return rc;
  185. }
  186. int modbus_send_raw_request(modbus_t *ctx, const uint8_t *raw_req, int raw_req_length)
  187. {
  188. sft_t sft;
  189. uint8_t req[MAX_MESSAGE_LENGTH];
  190. int req_length;
  191. if (ctx == NULL) {
  192. errno = EINVAL;
  193. return -1;
  194. }
  195. if (raw_req_length < 2 || raw_req_length > (MODBUS_MAX_PDU_LENGTH + 1)) {
  196. /* The raw request must contain function and slave at least and
  197. must not be longer than the maximum pdu length plus the slave
  198. address. */
  199. errno = EINVAL;
  200. return -1;
  201. }
  202. sft.slave = raw_req[0];
  203. sft.function = raw_req[1];
  204. /* The t_id is left to zero */
  205. sft.t_id = 0;
  206. /* This response function only set the header so it's convenient here */
  207. req_length = ctx->backend->build_response_basis(&sft, req);
  208. if (raw_req_length > 2) {
  209. /* Copy data after function code */
  210. memcpy(req + req_length, raw_req + 2, raw_req_length - 2);
  211. req_length += raw_req_length - 2;
  212. }
  213. return send_msg(ctx, req, req_length);
  214. }
  215. /*
  216. * ---------- Request Indication ----------
  217. * | Client | ---------------------->| Server |
  218. * ---------- Confirmation Response ----------
  219. */
  220. /* Computes the length to read after the function received */
  221. static uint8_t compute_meta_length_after_function(int function,
  222. msg_type_t msg_type)
  223. {
  224. int length;
  225. if (msg_type == MSG_INDICATION) {
  226. if (function <= MODBUS_FC_WRITE_SINGLE_REGISTER) {
  227. length = 4;
  228. } else if (function == MODBUS_FC_WRITE_MULTIPLE_COILS ||
  229. function == MODBUS_FC_WRITE_MULTIPLE_REGISTERS) {
  230. length = 5;
  231. } else if (function == MODBUS_FC_MASK_WRITE_REGISTER) {
  232. length = 6;
  233. } else if (function == MODBUS_FC_WRITE_AND_READ_REGISTERS) {
  234. length = 9;
  235. } else {
  236. /* MODBUS_FC_READ_EXCEPTION_STATUS, MODBUS_FC_REPORT_SLAVE_ID */
  237. length = 0;
  238. }
  239. } else {
  240. /* MSG_CONFIRMATION */
  241. switch (function) {
  242. case MODBUS_FC_WRITE_SINGLE_COIL:
  243. case MODBUS_FC_WRITE_SINGLE_REGISTER:
  244. case MODBUS_FC_WRITE_MULTIPLE_COILS:
  245. case MODBUS_FC_WRITE_MULTIPLE_REGISTERS:
  246. length = 4;
  247. break;
  248. case MODBUS_FC_MASK_WRITE_REGISTER:
  249. length = 6;
  250. break;
  251. default:
  252. length = 1;
  253. }
  254. }
  255. return length;
  256. }
  257. /* Computes the length to read after the meta information (address, count, etc) */
  258. static int compute_data_length_after_meta(modbus_t *ctx, uint8_t *msg,
  259. msg_type_t msg_type)
  260. {
  261. int function = msg[ctx->backend->header_length];
  262. int length;
  263. if (msg_type == MSG_INDICATION) {
  264. switch (function) {
  265. case MODBUS_FC_WRITE_MULTIPLE_COILS:
  266. case MODBUS_FC_WRITE_MULTIPLE_REGISTERS:
  267. length = msg[ctx->backend->header_length + 5];
  268. break;
  269. case MODBUS_FC_WRITE_AND_READ_REGISTERS:
  270. length = msg[ctx->backend->header_length + 9];
  271. break;
  272. default:
  273. length = 0;
  274. }
  275. } else {
  276. /* MSG_CONFIRMATION */
  277. if (function <= MODBUS_FC_READ_INPUT_REGISTERS ||
  278. function == MODBUS_FC_REPORT_SLAVE_ID ||
  279. function == MODBUS_FC_WRITE_AND_READ_REGISTERS) {
  280. length = msg[ctx->backend->header_length + 1];
  281. } else {
  282. length = 0;
  283. }
  284. }
  285. length += ctx->backend->checksum_length;
  286. return length;
  287. }
  288. /* Waits a response from a modbus server or a request from a modbus client.
  289. This function blocks if there is no replies (3 timeouts).
  290. The function shall return the number of received characters and the received
  291. message in an array of uint8_t if successful. Otherwise it shall return -1
  292. and errno is set to one of the values defined below:
  293. - ECONNRESET
  294. - EMBBADDATA
  295. - EMBUNKEXC
  296. - ETIMEDOUT
  297. - read() or recv() error codes
  298. */
  299. int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type)
  300. {
  301. int rc;
  302. fd_set rset;
  303. struct timeval tv;
  304. struct timeval *p_tv;
  305. int length_to_read;
  306. int msg_length = 0;
  307. _step_t step;
  308. if (ctx->debug) {
  309. if (msg_type == MSG_INDICATION) {
  310. printf("Waiting for an indication...\n");
  311. } else {
  312. printf("Waiting for a confirmation...\n");
  313. }
  314. }
  315. /* Add a file descriptor to the set */
  316. FD_ZERO(&rset);
  317. FD_SET(ctx->s, &rset);
  318. /* We need to analyse the message step by step. At the first step, we want
  319. * to reach the function code because all packets contain this
  320. * information. */
  321. step = _STEP_FUNCTION;
  322. length_to_read = ctx->backend->header_length + 1;
  323. if (msg_type == MSG_INDICATION) {
  324. /* Wait for a message, we don't know when the message will be
  325. * received */
  326. if (ctx->indication_timeout.tv_sec == 0 && ctx->indication_timeout.tv_usec == 0) {
  327. /* By default, the indication timeout isn't set */
  328. p_tv = NULL;
  329. } else {
  330. /* Wait for an indication (name of a received request by a server, see schema) */
  331. tv.tv_sec = ctx->indication_timeout.tv_sec;
  332. tv.tv_usec = ctx->indication_timeout.tv_usec;
  333. p_tv = &tv;
  334. }
  335. } else {
  336. tv.tv_sec = ctx->response_timeout.tv_sec;
  337. tv.tv_usec = ctx->response_timeout.tv_usec;
  338. p_tv = &tv;
  339. }
  340. while (length_to_read != 0) {
  341. rc = ctx->backend->select(ctx, &rset, p_tv, length_to_read);
  342. if (rc == -1) {
  343. _error_print(ctx, "select");
  344. if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) {
  345. int saved_errno = errno;
  346. if (errno == ETIMEDOUT) {
  347. _sleep_response_timeout(ctx);
  348. modbus_flush(ctx);
  349. } else if (errno == EBADF) {
  350. modbus_close(ctx);
  351. modbus_connect(ctx);
  352. }
  353. errno = saved_errno;
  354. }
  355. return -1;
  356. }
  357. rc = ctx->backend->recv(ctx, msg + msg_length, length_to_read);
  358. if (rc == 0) {
  359. errno = ECONNRESET;
  360. rc = -1;
  361. }
  362. if (rc == -1) {
  363. _error_print(ctx, "read");
  364. if ((ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) &&
  365. (errno == ECONNRESET || errno == ECONNREFUSED ||
  366. errno == EBADF)) {
  367. int saved_errno = errno;
  368. modbus_close(ctx);
  369. modbus_connect(ctx);
  370. /* Could be removed by previous calls */
  371. errno = saved_errno;
  372. }
  373. return -1;
  374. }
  375. /* Display the hex code of each character received */
  376. if (ctx->debug) {
  377. int i;
  378. for (i=0; i < rc; i++)
  379. printf("<%.2X>", msg[msg_length + i]);
  380. }
  381. /* Sums bytes received */
  382. msg_length += rc;
  383. /* Computes remaining bytes */
  384. length_to_read -= rc;
  385. if (length_to_read == 0) {
  386. switch (step) {
  387. case _STEP_FUNCTION:
  388. /* Function code position */
  389. length_to_read = compute_meta_length_after_function(
  390. msg[ctx->backend->header_length],
  391. msg_type);
  392. if (length_to_read != 0) {
  393. step = _STEP_META;
  394. break;
  395. } /* else switches straight to the next step */
  396. case _STEP_META:
  397. length_to_read = compute_data_length_after_meta(
  398. ctx, msg, msg_type);
  399. if ((msg_length + length_to_read) > (int)ctx->backend->max_adu_length) {
  400. errno = EMBBADDATA;
  401. _error_print(ctx, "too many data");
  402. return -1;
  403. }
  404. step = _STEP_DATA;
  405. break;
  406. default:
  407. break;
  408. }
  409. }
  410. if (length_to_read > 0 &&
  411. (ctx->byte_timeout.tv_sec > 0 || ctx->byte_timeout.tv_usec > 0)) {
  412. /* If there is no character in the buffer, the allowed timeout
  413. interval between two consecutive bytes is defined by
  414. byte_timeout */
  415. tv.tv_sec = ctx->byte_timeout.tv_sec;
  416. tv.tv_usec = ctx->byte_timeout.tv_usec;
  417. p_tv = &tv;
  418. }
  419. /* else timeout isn't set again, the full response must be read before
  420. expiration of response timeout (for CONFIRMATION only) */
  421. }
  422. if (ctx->debug)
  423. printf("\n");
  424. return ctx->backend->check_integrity(ctx, msg, msg_length);
  425. }
  426. /* Receive the request from a modbus master */
  427. int modbus_receive(modbus_t *ctx, uint8_t *req)
  428. {
  429. if (ctx == NULL) {
  430. errno = EINVAL;
  431. return -1;
  432. }
  433. return ctx->backend->receive(ctx, req);
  434. }
  435. /* Receives the confirmation.
  436. The function shall store the read response in rsp and return the number of
  437. values (bits or words). Otherwise, its shall return -1 and errno is set.
  438. The function doesn't check the confirmation is the expected response to the
  439. initial request.
  440. */
  441. int modbus_receive_confirmation(modbus_t *ctx, uint8_t *rsp)
  442. {
  443. if (ctx == NULL) {
  444. errno = EINVAL;
  445. return -1;
  446. }
  447. return _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);
  448. }
  449. static int check_confirmation(modbus_t *ctx, uint8_t *req,
  450. uint8_t *rsp, int rsp_length)
  451. {
  452. int rc;
  453. int rsp_length_computed;
  454. const int offset = ctx->backend->header_length;
  455. const int function = rsp[offset];
  456. if (ctx->backend->pre_check_confirmation) {
  457. rc = ctx->backend->pre_check_confirmation(ctx, req, rsp, rsp_length);
  458. if (rc == -1) {
  459. if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_PROTOCOL) {
  460. _sleep_response_timeout(ctx);
  461. modbus_flush(ctx);
  462. }
  463. return -1;
  464. }
  465. }
  466. rsp_length_computed = compute_response_length_from_request(ctx, req);
  467. /* Exception code */
  468. if (function >= 0x80) {
  469. if (rsp_length == (offset + 2 + (int)ctx->backend->checksum_length) &&
  470. req[offset] == (rsp[offset] - 0x80)) {
  471. /* Valid exception code received */
  472. int exception_code = rsp[offset + 1];
  473. if (exception_code < MODBUS_EXCEPTION_MAX) {
  474. errno = MODBUS_ENOBASE + exception_code;
  475. } else {
  476. errno = EMBBADEXC;
  477. }
  478. _error_print(ctx, NULL);
  479. return -1;
  480. } else {
  481. errno = EMBBADEXC;
  482. _error_print(ctx, NULL);
  483. return -1;
  484. }
  485. }
  486. /* Check length */
  487. if ((rsp_length == rsp_length_computed ||
  488. rsp_length_computed == MSG_LENGTH_UNDEFINED) &&
  489. function < 0x80) {
  490. int req_nb_value;
  491. int rsp_nb_value;
  492. /* Check function code */
  493. if (function != req[offset]) {
  494. if (ctx->debug) {
  495. fprintf(stderr,
  496. "Received function not corresponding to the request (0x%X != 0x%X)\n",
  497. function, req[offset]);
  498. }
  499. if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_PROTOCOL) {
  500. _sleep_response_timeout(ctx);
  501. modbus_flush(ctx);
  502. }
  503. errno = EMBBADDATA;
  504. return -1;
  505. }
  506. /* Check the number of values is corresponding to the request */
  507. switch (function) {
  508. case MODBUS_FC_READ_COILS:
  509. case MODBUS_FC_READ_DISCRETE_INPUTS:
  510. /* Read functions, 8 values in a byte (nb
  511. * of values in the request and byte count in
  512. * the response. */
  513. req_nb_value = (req[offset + 3] << 8) + req[offset + 4];
  514. req_nb_value = (req_nb_value / 8) + ((req_nb_value % 8) ? 1 : 0);
  515. rsp_nb_value = rsp[offset + 1];
  516. break;
  517. case MODBUS_FC_WRITE_AND_READ_REGISTERS:
  518. case MODBUS_FC_READ_HOLDING_REGISTERS:
  519. case MODBUS_FC_READ_INPUT_REGISTERS:
  520. /* Read functions 1 value = 2 bytes */
  521. req_nb_value = (req[offset + 3] << 8) + req[offset + 4];
  522. rsp_nb_value = (rsp[offset + 1] / 2);
  523. break;
  524. case MODBUS_FC_WRITE_MULTIPLE_COILS:
  525. case MODBUS_FC_WRITE_MULTIPLE_REGISTERS:
  526. /* N Write functions */
  527. req_nb_value = (req[offset + 3] << 8) + req[offset + 4];
  528. rsp_nb_value = (rsp[offset + 3] << 8) | rsp[offset + 4];
  529. break;
  530. case MODBUS_FC_REPORT_SLAVE_ID:
  531. /* Report slave ID (bytes received) */
  532. req_nb_value = rsp_nb_value = rsp[offset + 1];
  533. break;
  534. default:
  535. /* 1 Write functions & others */
  536. req_nb_value = rsp_nb_value = 1;
  537. }
  538. if (req_nb_value == rsp_nb_value) {
  539. rc = rsp_nb_value;
  540. } else {
  541. if (ctx->debug) {
  542. fprintf(stderr,
  543. "Quantity not corresponding to the request (%d != %d)\n",
  544. rsp_nb_value, req_nb_value);
  545. }
  546. if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_PROTOCOL) {
  547. _sleep_response_timeout(ctx);
  548. modbus_flush(ctx);
  549. }
  550. errno = EMBBADDATA;
  551. rc = -1;
  552. }
  553. } else {
  554. if (ctx->debug) {
  555. fprintf(stderr,
  556. "Message length not corresponding to the computed length (%d != %d)\n",
  557. rsp_length, rsp_length_computed);
  558. }
  559. if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_PROTOCOL) {
  560. _sleep_response_timeout(ctx);
  561. modbus_flush(ctx);
  562. }
  563. errno = EMBBADDATA;
  564. rc = -1;
  565. }
  566. return rc;
  567. }
  568. static int response_io_status(uint8_t *tab_io_status,
  569. int address, int nb,
  570. uint8_t *rsp, int offset)
  571. {
  572. int shift = 0;
  573. /* Instead of byte (not allowed in Win32) */
  574. int one_byte = 0;
  575. int i;
  576. for (i = address; i < address + nb; i++) {
  577. one_byte |= tab_io_status[i] << shift;
  578. if (shift == 7) {
  579. /* Byte is full */
  580. rsp[offset++] = one_byte;
  581. one_byte = shift = 0;
  582. } else {
  583. shift++;
  584. }
  585. }
  586. if (shift != 0)
  587. rsp[offset++] = one_byte;
  588. return offset;
  589. }
  590. /* Build the exception response */
  591. static int response_exception(modbus_t *ctx, sft_t *sft,
  592. int exception_code, uint8_t *rsp,
  593. unsigned int to_flush,
  594. const char* template, ...)
  595. {
  596. int rsp_length;
  597. /* Print debug message */
  598. if (ctx->debug) {
  599. va_list ap;
  600. va_start(ap, template);
  601. vfprintf(stderr, template, ap);
  602. va_end(ap);
  603. }
  604. /* Flush if required */
  605. if (to_flush) {
  606. _sleep_response_timeout(ctx);
  607. modbus_flush(ctx);
  608. }
  609. /* Build exception response */
  610. sft->function = sft->function + 0x80;
  611. rsp_length = ctx->backend->build_response_basis(sft, rsp);
  612. rsp[rsp_length++] = exception_code;
  613. return rsp_length;
  614. }
  615. /* Send a response to the received request.
  616. Analyses the request and constructs a response.
  617. If an error occurs, this function construct the response
  618. accordingly.
  619. */
  620. int modbus_reply(modbus_t *ctx, const uint8_t *req,
  621. int req_length, modbus_mapping_t *mb_mapping)
  622. {
  623. int offset;
  624. int slave;
  625. int function;
  626. uint16_t address;
  627. uint8_t rsp[MAX_MESSAGE_LENGTH];
  628. int rsp_length = 0;
  629. sft_t sft;
  630. if (ctx == NULL) {
  631. errno = EINVAL;
  632. return -1;
  633. }
  634. offset = ctx->backend->header_length;
  635. slave = req[offset - 1];
  636. function = req[offset];
  637. address = (req[offset + 1] << 8) + req[offset + 2];
  638. sft.slave = slave;
  639. sft.function = function;
  640. sft.t_id = ctx->backend->prepare_response_tid(req, &req_length);
  641. /* Data are flushed on illegal number of values errors. */
  642. switch (function) {
  643. case MODBUS_FC_READ_COILS:
  644. case MODBUS_FC_READ_DISCRETE_INPUTS: {
  645. unsigned int is_input = (function == MODBUS_FC_READ_DISCRETE_INPUTS);
  646. int start_bits = is_input ? mb_mapping->start_input_bits : mb_mapping->start_bits;
  647. int nb_bits = is_input ? mb_mapping->nb_input_bits : mb_mapping->nb_bits;
  648. uint8_t *tab_bits = is_input ? mb_mapping->tab_input_bits : mb_mapping->tab_bits;
  649. const char * const name = is_input ? "read_input_bits" : "read_bits";
  650. int nb = (req[offset + 3] << 8) + req[offset + 4];
  651. /* The mapping can be shifted to reduce memory consumption and it
  652. doesn't always start at address zero. */
  653. int mapping_address = address - start_bits;
  654. if (nb < 1 || MODBUS_MAX_READ_BITS < nb) {
  655. rsp_length = response_exception(
  656. ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE,
  657. "Illegal nb of values %d in %s (max %d)\n",
  658. nb, name, MODBUS_MAX_READ_BITS);
  659. } else if (mapping_address < 0 || (mapping_address + nb) > nb_bits) {
  660. rsp_length = response_exception(
  661. ctx, &sft,
  662. MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp, FALSE,
  663. "Illegal data address 0x%0X in %s\n",
  664. mapping_address < 0 ? address : address + nb, name);
  665. } else {
  666. rsp_length = ctx->backend->build_response_basis(&sft, rsp);
  667. rsp[rsp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0);
  668. rsp_length = response_io_status(tab_bits, mapping_address, nb,
  669. rsp, rsp_length);
  670. }
  671. }
  672. break;
  673. case MODBUS_FC_READ_HOLDING_REGISTERS:
  674. case MODBUS_FC_READ_INPUT_REGISTERS: {
  675. unsigned int is_input = (function == MODBUS_FC_READ_INPUT_REGISTERS);
  676. int start_registers = is_input ? mb_mapping->start_input_registers : mb_mapping->start_registers;
  677. int nb_registers = is_input ? mb_mapping->nb_input_registers : mb_mapping->nb_registers;
  678. uint16_t *tab_registers = is_input ? mb_mapping->tab_input_registers : mb_mapping->tab_registers;
  679. const char * const name = is_input ? "read_input_registers" : "read_registers";
  680. int nb = (req[offset + 3] << 8) + req[offset + 4];
  681. /* The mapping can be shifted to reduce memory consumption and it
  682. doesn't always start at address zero. */
  683. int mapping_address = address - start_registers;
  684. if (nb < 1 || MODBUS_MAX_READ_REGISTERS < nb) {
  685. rsp_length = response_exception(
  686. ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE,
  687. "Illegal nb of values %d in %s (max %d)\n",
  688. nb, name, MODBUS_MAX_READ_REGISTERS);
  689. } else if (mapping_address < 0 || (mapping_address + nb) > nb_registers) {
  690. rsp_length = response_exception(
  691. ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp, FALSE,
  692. "Illegal data address 0x%0X in %s\n",
  693. mapping_address < 0 ? address : address + nb, name);
  694. } else {
  695. int i;
  696. rsp_length = ctx->backend->build_response_basis(&sft, rsp);
  697. rsp[rsp_length++] = nb << 1;
  698. for (i = mapping_address; i < mapping_address + nb; i++) {
  699. rsp[rsp_length++] = tab_registers[i] >> 8;
  700. rsp[rsp_length++] = tab_registers[i] & 0xFF;
  701. }
  702. }
  703. }
  704. break;
  705. case MODBUS_FC_WRITE_SINGLE_COIL: {
  706. int mapping_address = address - mb_mapping->start_bits;
  707. if (mapping_address < 0 || mapping_address >= mb_mapping->nb_bits) {
  708. rsp_length = response_exception(
  709. ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp, FALSE,
  710. "Illegal data address 0x%0X in write_bit\n",
  711. address);
  712. } else {
  713. int data = (req[offset + 3] << 8) + req[offset + 4];
  714. if (data == 0xFF00 || data == 0x0) {
  715. mb_mapping->tab_bits[mapping_address] = data ? ON : OFF;
  716. memcpy(rsp, req, req_length);
  717. rsp_length = req_length;
  718. } else {
  719. rsp_length = response_exception(
  720. ctx, &sft,
  721. MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, FALSE,
  722. "Illegal data value 0x%0X in write_bit request at address %0X\n",
  723. data, address);
  724. }
  725. }
  726. }
  727. break;
  728. case MODBUS_FC_WRITE_SINGLE_REGISTER: {
  729. int mapping_address = address - mb_mapping->start_registers;
  730. if (mapping_address < 0 || mapping_address >= mb_mapping->nb_registers) {
  731. rsp_length = response_exception(
  732. ctx, &sft,
  733. MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp, FALSE,
  734. "Illegal data address 0x%0X in write_register\n",
  735. address);
  736. } else {
  737. int data = (req[offset + 3] << 8) + req[offset + 4];
  738. mb_mapping->tab_registers[mapping_address] = data;
  739. memcpy(rsp, req, req_length);
  740. rsp_length = req_length;
  741. }
  742. }
  743. break;
  744. case MODBUS_FC_WRITE_MULTIPLE_COILS: {
  745. int nb = (req[offset + 3] << 8) + req[offset + 4];
  746. int nb_bits = req[offset + 5];
  747. int mapping_address = address - mb_mapping->start_bits;
  748. if (nb < 1 || MODBUS_MAX_WRITE_BITS < nb || nb_bits * 8 < nb) {
  749. /* May be the indication has been truncated on reading because of
  750. * invalid address (eg. nb is 0 but the request contains values to
  751. * write) so it's necessary to flush. */
  752. rsp_length = response_exception(
  753. ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE,
  754. "Illegal number of values %d in write_bits (max %d)\n",
  755. nb, MODBUS_MAX_WRITE_BITS);
  756. } else if (mapping_address < 0 ||
  757. (mapping_address + nb) > mb_mapping->nb_bits) {
  758. rsp_length = response_exception(
  759. ctx, &sft,
  760. MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp, FALSE,
  761. "Illegal data address 0x%0X in write_bits\n",
  762. mapping_address < 0 ? address : address + nb);
  763. } else {
  764. /* 6 = byte count */
  765. modbus_set_bits_from_bytes(mb_mapping->tab_bits, mapping_address, nb,
  766. &req[offset + 6]);
  767. rsp_length = ctx->backend->build_response_basis(&sft, rsp);
  768. /* 4 to copy the bit address (2) and the quantity of bits */
  769. memcpy(rsp + rsp_length, req + rsp_length, 4);
  770. rsp_length += 4;
  771. }
  772. }
  773. break;
  774. case MODBUS_FC_WRITE_MULTIPLE_REGISTERS: {
  775. int nb = (req[offset + 3] << 8) + req[offset + 4];
  776. int nb_bytes = req[offset + 5];
  777. int mapping_address = address - mb_mapping->start_registers;
  778. if (nb < 1 || MODBUS_MAX_WRITE_REGISTERS < nb || nb_bytes != nb * 2) {
  779. rsp_length = response_exception(
  780. ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE,
  781. "Illegal number of values %d in write_registers (max %d)\n",
  782. nb, MODBUS_MAX_WRITE_REGISTERS);
  783. } else if (mapping_address < 0 ||
  784. (mapping_address + nb) > mb_mapping->nb_registers) {
  785. rsp_length = response_exception(
  786. ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp, FALSE,
  787. "Illegal data address 0x%0X in write_registers\n",
  788. mapping_address < 0 ? address : address + nb);
  789. } else {
  790. int i, j;
  791. for (i = mapping_address, j = 6; i < mapping_address + nb; i++, j += 2) {
  792. /* 6 and 7 = first value */
  793. mb_mapping->tab_registers[i] =
  794. (req[offset + j] << 8) + req[offset + j + 1];
  795. }
  796. rsp_length = ctx->backend->build_response_basis(&sft, rsp);
  797. /* 4 to copy the address (2) and the no. of registers */
  798. memcpy(rsp + rsp_length, req + rsp_length, 4);
  799. rsp_length += 4;
  800. }
  801. }
  802. break;
  803. case MODBUS_FC_REPORT_SLAVE_ID: {
  804. int str_len;
  805. int byte_count_pos;
  806. rsp_length = ctx->backend->build_response_basis(&sft, rsp);
  807. /* Skip byte count for now */
  808. byte_count_pos = rsp_length++;
  809. rsp[rsp_length++] = _REPORT_SLAVE_ID;
  810. /* Run indicator status to ON */
  811. rsp[rsp_length++] = 0xFF;
  812. /* LMB + length of LIBMODBUS_VERSION_STRING */
  813. str_len = 3 + strlen(LIBMODBUS_VERSION_STRING);
  814. memcpy(rsp + rsp_length, "LMB" LIBMODBUS_VERSION_STRING, str_len);
  815. rsp_length += str_len;
  816. rsp[byte_count_pos] = rsp_length - byte_count_pos - 1;
  817. }
  818. break;
  819. case MODBUS_FC_READ_EXCEPTION_STATUS:
  820. if (ctx->debug) {
  821. fprintf(stderr, "FIXME Not implemented\n");
  822. }
  823. errno = ENOPROTOOPT;
  824. return -1;
  825. break;
  826. case MODBUS_FC_MASK_WRITE_REGISTER: {
  827. int mapping_address = address - mb_mapping->start_registers;
  828. if (mapping_address < 0 || mapping_address >= mb_mapping->nb_registers) {
  829. rsp_length = response_exception(
  830. ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp, FALSE,
  831. "Illegal data address 0x%0X in write_register\n",
  832. address);
  833. } else {
  834. uint16_t data = mb_mapping->tab_registers[mapping_address];
  835. uint16_t and = (req[offset + 3] << 8) + req[offset + 4];
  836. uint16_t or = (req[offset + 5] << 8) + req[offset + 6];
  837. data = (data & and) | (or & (~and));
  838. mb_mapping->tab_registers[mapping_address] = data;
  839. memcpy(rsp, req, req_length);
  840. rsp_length = req_length;
  841. }
  842. }
  843. break;
  844. case MODBUS_FC_WRITE_AND_READ_REGISTERS: {
  845. int nb = (req[offset + 3] << 8) + req[offset + 4];
  846. uint16_t address_write = (req[offset + 5] << 8) + req[offset + 6];
  847. int nb_write = (req[offset + 7] << 8) + req[offset + 8];
  848. int nb_write_bytes = req[offset + 9];
  849. int mapping_address = address - mb_mapping->start_registers;
  850. int mapping_address_write = address_write - mb_mapping->start_registers;
  851. if (nb_write < 1 || MODBUS_MAX_WR_WRITE_REGISTERS < nb_write ||
  852. nb < 1 || MODBUS_MAX_WR_READ_REGISTERS < nb ||
  853. nb_write_bytes != nb_write * 2) {
  854. rsp_length = response_exception(
  855. ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE,
  856. "Illegal nb of values (W%d, R%d) in write_and_read_registers (max W%d, R%d)\n",
  857. nb_write, nb, MODBUS_MAX_WR_WRITE_REGISTERS, MODBUS_MAX_WR_READ_REGISTERS);
  858. } else if (mapping_address < 0 ||
  859. (mapping_address + nb) > mb_mapping->nb_registers ||
  860. mapping_address < 0 ||
  861. (mapping_address_write + nb_write) > mb_mapping->nb_registers) {
  862. rsp_length = response_exception(
  863. ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp, FALSE,
  864. "Illegal data read address 0x%0X or write address 0x%0X write_and_read_registers\n",
  865. mapping_address < 0 ? address : address + nb,
  866. mapping_address_write < 0 ? address_write : address_write + nb_write);
  867. } else {
  868. int i, j;
  869. rsp_length = ctx->backend->build_response_basis(&sft, rsp);
  870. rsp[rsp_length++] = nb << 1;
  871. /* Write first.
  872. 10 and 11 are the offset of the first values to write */
  873. for (i = mapping_address_write, j = 10;
  874. i < mapping_address_write + nb_write; i++, j += 2) {
  875. mb_mapping->tab_registers[i] =
  876. (req[offset + j] << 8) + req[offset + j + 1];
  877. }
  878. /* and read the data for the response */
  879. for (i = mapping_address; i < mapping_address + nb; i++) {
  880. rsp[rsp_length++] = mb_mapping->tab_registers[i] >> 8;
  881. rsp[rsp_length++] = mb_mapping->tab_registers[i] & 0xFF;
  882. }
  883. }
  884. }
  885. break;
  886. default:
  887. rsp_length = response_exception(
  888. ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_FUNCTION, rsp, TRUE,
  889. "Unknown Modbus function code: 0x%0X\n", function);
  890. break;
  891. }
  892. /* Suppress any responses when the request was a broadcast */
  893. return (ctx->backend->backend_type == _MODBUS_BACKEND_TYPE_RTU &&
  894. slave == MODBUS_BROADCAST_ADDRESS) ? 0 : send_msg(ctx, rsp, rsp_length);
  895. }
  896. int modbus_reply_exception(modbus_t *ctx, const uint8_t *req,
  897. unsigned int exception_code)
  898. {
  899. int offset;
  900. int slave;
  901. int function;
  902. uint8_t rsp[MAX_MESSAGE_LENGTH];
  903. int rsp_length;
  904. int dummy_length = 99;
  905. sft_t sft;
  906. if (ctx == NULL) {
  907. errno = EINVAL;
  908. return -1;
  909. }
  910. offset = ctx->backend->header_length;
  911. slave = req[offset - 1];
  912. function = req[offset];
  913. sft.slave = slave;
  914. sft.function = function + 0x80;
  915. sft.t_id = ctx->backend->prepare_response_tid(req, &dummy_length);
  916. rsp_length = ctx->backend->build_response_basis(&sft, rsp);
  917. /* Positive exception code */
  918. if (exception_code < MODBUS_EXCEPTION_MAX) {
  919. rsp[rsp_length++] = exception_code;
  920. return send_msg(ctx, rsp, rsp_length);
  921. } else {
  922. errno = EINVAL;
  923. return -1;
  924. }
  925. }
  926. /* Reads IO status */
  927. static int read_io_status(modbus_t *ctx, int function,
  928. int addr, int nb, uint8_t *dest)
  929. {
  930. int rc;
  931. int req_length;
  932. uint8_t req[_MIN_REQ_LENGTH];
  933. uint8_t rsp[MAX_MESSAGE_LENGTH];
  934. req_length = ctx->backend->build_request_basis(ctx, function, addr, nb, req);
  935. rc = send_msg(ctx, req, req_length);
  936. if (rc > 0) {
  937. int i, temp, bit;
  938. int pos = 0;
  939. int offset;
  940. int offset_end;
  941. rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);
  942. if (rc == -1)
  943. return -1;
  944. rc = check_confirmation(ctx, req, rsp, rc);
  945. if (rc == -1)
  946. return -1;
  947. offset = ctx->backend->header_length + 2;
  948. offset_end = offset + rc;
  949. for (i = offset; i < offset_end; i++) {
  950. /* Shift reg hi_byte to temp */
  951. temp = rsp[i];
  952. for (bit = 0x01; (bit & 0xff) && (pos < nb);) {
  953. dest[pos++] = (temp & bit) ? TRUE : FALSE;
  954. bit = bit << 1;
  955. }
  956. }
  957. }
  958. return rc;
  959. }
  960. /* Reads the boolean status of bits and sets the array elements
  961. in the destination to TRUE or FALSE (single bits). */
  962. int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest)
  963. {
  964. int rc;
  965. if (ctx == NULL) {
  966. errno = EINVAL;
  967. return -1;
  968. }
  969. if (nb > MODBUS_MAX_READ_BITS) {
  970. if (ctx->debug) {
  971. fprintf(stderr,
  972. "ERROR Too many bits requested (%d > %d)\n",
  973. nb, MODBUS_MAX_READ_BITS);
  974. }
  975. errno = EMBMDATA;
  976. return -1;
  977. }
  978. rc = read_io_status(ctx, MODBUS_FC_READ_COILS, addr, nb, dest);
  979. if (rc == -1)
  980. return -1;
  981. else
  982. return nb;
  983. }
  984. /* Same as modbus_read_bits but reads the remote device input table */
  985. int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest)
  986. {
  987. int rc;
  988. if (ctx == NULL) {
  989. errno = EINVAL;
  990. return -1;
  991. }
  992. if (nb > MODBUS_MAX_READ_BITS) {
  993. if (ctx->debug) {
  994. fprintf(stderr,
  995. "ERROR Too many discrete inputs requested (%d > %d)\n",
  996. nb, MODBUS_MAX_READ_BITS);
  997. }
  998. errno = EMBMDATA;
  999. return -1;
  1000. }
  1001. rc = read_io_status(ctx, MODBUS_FC_READ_DISCRETE_INPUTS, addr, nb, dest);
  1002. if (rc == -1)
  1003. return -1;
  1004. else
  1005. return nb;
  1006. }
  1007. /* Reads the data from a remove device and put that data into an array */
  1008. static int read_registers(modbus_t *ctx, int function, int addr, int nb,
  1009. uint16_t *dest)
  1010. {
  1011. int rc;
  1012. int req_length;
  1013. uint8_t req[_MIN_REQ_LENGTH];
  1014. uint8_t rsp[MAX_MESSAGE_LENGTH];
  1015. if (nb > MODBUS_MAX_READ_REGISTERS) {
  1016. if (ctx->debug) {
  1017. fprintf(stderr,
  1018. "ERROR Too many registers requested (%d > %d)\n",
  1019. nb, MODBUS_MAX_READ_REGISTERS);
  1020. }
  1021. errno = EMBMDATA;
  1022. return -1;
  1023. }
  1024. req_length = ctx->backend->build_request_basis(ctx, function, addr, nb, req);
  1025. rc = send_msg(ctx, req, req_length);
  1026. if (rc > 0) {
  1027. int offset;
  1028. int i;
  1029. rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);
  1030. if (rc == -1)
  1031. return -1;
  1032. rc = check_confirmation(ctx, req, rsp, rc);
  1033. if (rc == -1)
  1034. return -1;
  1035. offset = ctx->backend->header_length;
  1036. for (i = 0; i < rc; i++) {
  1037. /* shift reg hi_byte to temp OR with lo_byte */
  1038. dest[i] = (rsp[offset + 2 + (i << 1)] << 8) |
  1039. rsp[offset + 3 + (i << 1)];
  1040. }
  1041. }
  1042. return rc;
  1043. }
  1044. /* Reads the holding registers of remote device and put the data into an
  1045. array */
  1046. int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest)
  1047. {
  1048. int status;
  1049. if (ctx == NULL) {
  1050. errno = EINVAL;
  1051. return -1;
  1052. }
  1053. if (nb > MODBUS_MAX_READ_REGISTERS) {
  1054. if (ctx->debug) {
  1055. fprintf(stderr,
  1056. "ERROR Too many registers requested (%d > %d)\n",
  1057. nb, MODBUS_MAX_READ_REGISTERS);
  1058. }
  1059. errno = EMBMDATA;
  1060. return -1;
  1061. }
  1062. status = read_registers(ctx, MODBUS_FC_READ_HOLDING_REGISTERS,
  1063. addr, nb, dest);
  1064. return status;
  1065. }
  1066. /* Reads the input registers of remote device and put the data into an array */
  1067. int modbus_read_input_registers(modbus_t *ctx, int addr, int nb,
  1068. uint16_t *dest)
  1069. {
  1070. int status;
  1071. if (ctx == NULL) {
  1072. errno = EINVAL;
  1073. return -1;
  1074. }
  1075. if (nb > MODBUS_MAX_READ_REGISTERS) {
  1076. fprintf(stderr,
  1077. "ERROR Too many input registers requested (%d > %d)\n",
  1078. nb, MODBUS_MAX_READ_REGISTERS);
  1079. errno = EMBMDATA;
  1080. return -1;
  1081. }
  1082. status = read_registers(ctx, MODBUS_FC_READ_INPUT_REGISTERS,
  1083. addr, nb, dest);
  1084. return status;
  1085. }
  1086. /* Write a value to the specified register of the remote device.
  1087. Used by write_bit and write_register */
  1088. static int write_single(modbus_t *ctx, int function, int addr, const uint16_t value)
  1089. {
  1090. int rc;
  1091. int req_length;
  1092. uint8_t req[_MIN_REQ_LENGTH];
  1093. if (ctx == NULL) {
  1094. errno = EINVAL;
  1095. return -1;
  1096. }
  1097. req_length = ctx->backend->build_request_basis(ctx, function, addr, (int) value, req);
  1098. rc = send_msg(ctx, req, req_length);
  1099. if (rc > 0) {
  1100. /* Used by write_bit and write_register */
  1101. uint8_t rsp[MAX_MESSAGE_LENGTH];
  1102. rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);
  1103. if (rc == -1)
  1104. return -1;
  1105. rc = check_confirmation(ctx, req, rsp, rc);
  1106. }
  1107. return rc;
  1108. }
  1109. /* Turns ON or OFF a single bit of the remote device */
  1110. int modbus_write_bit(modbus_t *ctx, int addr, int status)
  1111. {
  1112. if (ctx == NULL) {
  1113. errno = EINVAL;
  1114. return -1;
  1115. }
  1116. return write_single(ctx, MODBUS_FC_WRITE_SINGLE_COIL, addr,
  1117. status ? 0xFF00 : 0);
  1118. }
  1119. /* Writes a value in one register of the remote device */
  1120. int modbus_write_register(modbus_t *ctx, int addr, const uint16_t value)
  1121. {
  1122. if (ctx == NULL) {
  1123. errno = EINVAL;
  1124. return -1;
  1125. }
  1126. return write_single(ctx, MODBUS_FC_WRITE_SINGLE_REGISTER, addr, value);
  1127. }
  1128. /* Write the bits of the array in the remote device */
  1129. int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *src)
  1130. {
  1131. int rc;
  1132. int i;
  1133. int byte_count;
  1134. int req_length;
  1135. int bit_check = 0;
  1136. int pos = 0;
  1137. uint8_t req[MAX_MESSAGE_LENGTH];
  1138. if (ctx == NULL) {
  1139. errno = EINVAL;
  1140. return -1;
  1141. }
  1142. if (nb > MODBUS_MAX_WRITE_BITS) {
  1143. if (ctx->debug) {
  1144. fprintf(stderr, "ERROR Writing too many bits (%d > %d)\n",
  1145. nb, MODBUS_MAX_WRITE_BITS);
  1146. }
  1147. errno = EMBMDATA;
  1148. return -1;
  1149. }
  1150. req_length = ctx->backend->build_request_basis(ctx,
  1151. MODBUS_FC_WRITE_MULTIPLE_COILS,
  1152. addr, nb, req);
  1153. byte_count = (nb / 8) + ((nb % 8) ? 1 : 0);
  1154. req[req_length++] = byte_count;
  1155. for (i = 0; i < byte_count; i++) {
  1156. int bit;
  1157. bit = 0x01;
  1158. req[req_length] = 0;
  1159. while ((bit & 0xFF) && (bit_check++ < nb)) {
  1160. if (src[pos++])
  1161. req[req_length] |= bit;
  1162. else
  1163. req[req_length] &=~ bit;
  1164. bit = bit << 1;
  1165. }
  1166. req_length++;
  1167. }
  1168. rc = send_msg(ctx, req, req_length);
  1169. if (rc > 0) {
  1170. uint8_t rsp[MAX_MESSAGE_LENGTH];
  1171. rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);
  1172. if (rc == -1)
  1173. return -1;
  1174. rc = check_confirmation(ctx, req, rsp, rc);
  1175. }
  1176. return rc;
  1177. }
  1178. /* Write the values from the array to the registers of the remote device */
  1179. int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src)
  1180. {
  1181. int rc;
  1182. int i;
  1183. int req_length;
  1184. int byte_count;
  1185. uint8_t req[MAX_MESSAGE_LENGTH];
  1186. if (ctx == NULL) {
  1187. errno = EINVAL;
  1188. return -1;
  1189. }
  1190. if (nb > MODBUS_MAX_WRITE_REGISTERS) {
  1191. if (ctx->debug) {
  1192. fprintf(stderr,
  1193. "ERROR Trying to write to too many registers (%d > %d)\n",
  1194. nb, MODBUS_MAX_WRITE_REGISTERS);
  1195. }
  1196. errno = EMBMDATA;
  1197. return -1;
  1198. }
  1199. req_length = ctx->backend->build_request_basis(ctx,
  1200. MODBUS_FC_WRITE_MULTIPLE_REGISTERS,
  1201. addr, nb, req);
  1202. byte_count = nb * 2;
  1203. req[req_length++] = byte_count;
  1204. for (i = 0; i < nb; i++) {
  1205. req[req_length++] = src[i] >> 8;
  1206. req[req_length++] = src[i] & 0x00FF;
  1207. }
  1208. rc = send_msg(ctx, req, req_length);
  1209. if (rc > 0) {
  1210. uint8_t rsp[MAX_MESSAGE_LENGTH];
  1211. rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);
  1212. if (rc == -1)
  1213. return -1;
  1214. rc = check_confirmation(ctx, req, rsp, rc);
  1215. }
  1216. return rc;
  1217. }
  1218. int modbus_mask_write_register(modbus_t *ctx, int addr, uint16_t and_mask, uint16_t or_mask)
  1219. {
  1220. int rc;
  1221. int req_length;
  1222. /* The request length can not exceed _MIN_REQ_LENGTH - 2 and 4 bytes to
  1223. * store the masks. The ugly substraction is there to remove the 'nb' value
  1224. * (2 bytes) which is not used. */
  1225. uint8_t req[_MIN_REQ_LENGTH + 2];
  1226. req_length = ctx->backend->build_request_basis(ctx,
  1227. MODBUS_FC_MASK_WRITE_REGISTER,
  1228. addr, 0, req);
  1229. /* HACKISH, count is not used */
  1230. req_length -= 2;
  1231. req[req_length++] = and_mask >> 8;
  1232. req[req_length++] = and_mask & 0x00ff;
  1233. req[req_length++] = or_mask >> 8;
  1234. req[req_length++] = or_mask & 0x00ff;
  1235. rc = send_msg(ctx, req, req_length);
  1236. if (rc > 0) {
  1237. /* Used by write_bit and write_register */
  1238. uint8_t rsp[MAX_MESSAGE_LENGTH];
  1239. rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);
  1240. if (rc == -1)
  1241. return -1;
  1242. rc = check_confirmation(ctx, req, rsp, rc);
  1243. }
  1244. return rc;
  1245. }
  1246. /* Write multiple registers from src array to remote device and read multiple
  1247. registers from remote device to dest array. */
  1248. int modbus_write_and_read_registers(modbus_t *ctx,
  1249. int write_addr, int write_nb,
  1250. const uint16_t *src,
  1251. int read_addr, int read_nb,
  1252. uint16_t *dest)
  1253. {
  1254. int rc;
  1255. int req_length;
  1256. int i;
  1257. int byte_count;
  1258. uint8_t req[MAX_MESSAGE_LENGTH];
  1259. uint8_t rsp[MAX_MESSAGE_LENGTH];
  1260. if (ctx == NULL) {
  1261. errno = EINVAL;
  1262. return -1;
  1263. }
  1264. if (write_nb > MODBUS_MAX_WR_WRITE_REGISTERS) {
  1265. if (ctx->debug) {
  1266. fprintf(stderr,
  1267. "ERROR Too many registers to write (%d > %d)\n",
  1268. write_nb, MODBUS_MAX_WR_WRITE_REGISTERS);
  1269. }
  1270. errno = EMBMDATA;
  1271. return -1;
  1272. }
  1273. if (read_nb > MODBUS_MAX_WR_READ_REGISTERS) {
  1274. if (ctx->debug) {
  1275. fprintf(stderr,
  1276. "ERROR Too many registers requested (%d > %d)\n",
  1277. read_nb, MODBUS_MAX_WR_READ_REGISTERS);
  1278. }
  1279. errno = EMBMDATA;
  1280. return -1;
  1281. }
  1282. req_length = ctx->backend->build_request_basis(ctx,
  1283. MODBUS_FC_WRITE_AND_READ_REGISTERS,
  1284. read_addr, read_nb, req);
  1285. req[req_length++] = write_addr >> 8;
  1286. req[req_length++] = write_addr & 0x00ff;
  1287. req[req_length++] = write_nb >> 8;
  1288. req[req_length++] = write_nb & 0x00ff;
  1289. byte_count = write_nb * 2;
  1290. req[req_length++] = byte_count;
  1291. for (i = 0; i < write_nb; i++) {
  1292. req[req_length++] = src[i] >> 8;
  1293. req[req_length++] = src[i] & 0x00FF;
  1294. }
  1295. rc = send_msg(ctx, req, req_length);
  1296. if (rc > 0) {
  1297. int offset;
  1298. rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);
  1299. if (rc == -1)
  1300. return -1;
  1301. rc = check_confirmation(ctx, req, rsp, rc);
  1302. if (rc == -1)
  1303. return -1;
  1304. offset = ctx->backend->header_length;
  1305. for (i = 0; i < rc; i++) {
  1306. /* shift reg hi_byte to temp OR with lo_byte */
  1307. dest[i] = (rsp[offset + 2 + (i << 1)] << 8) |
  1308. rsp[offset + 3 + (i << 1)];
  1309. }
  1310. }
  1311. return rc;
  1312. }
  1313. /* Send a request to get the slave ID of the device (only available in serial
  1314. communication). */
  1315. int modbus_report_slave_id(modbus_t *ctx, int max_dest, uint8_t *dest)
  1316. {
  1317. int rc;
  1318. int req_length;
  1319. uint8_t req[_MIN_REQ_LENGTH];
  1320. if (ctx == NULL || max_dest <= 0) {
  1321. errno = EINVAL;
  1322. return -1;
  1323. }
  1324. req_length = ctx->backend->build_request_basis(ctx, MODBUS_FC_REPORT_SLAVE_ID,
  1325. 0, 0, req);
  1326. /* HACKISH, addr and count are not used */
  1327. req_length -= 4;
  1328. rc = send_msg(ctx, req, req_length);
  1329. if (rc > 0) {
  1330. int i;
  1331. int offset;
  1332. uint8_t rsp[MAX_MESSAGE_LENGTH];
  1333. rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);
  1334. if (rc == -1)
  1335. return -1;
  1336. rc = check_confirmation(ctx, req, rsp, rc);
  1337. if (rc == -1)
  1338. return -1;
  1339. offset = ctx->backend->header_length + 2;
  1340. /* Byte count, slave id, run indicator status and
  1341. additional data. Truncate copy to max_dest. */
  1342. for (i=0; i < rc && i < max_dest; i++) {
  1343. dest[i] = rsp[offset + i];
  1344. }
  1345. }
  1346. return rc;
  1347. }
  1348. void _modbus_init_common(modbus_t *ctx)
  1349. {
  1350. /* Slave and socket are initialized to -1 */
  1351. ctx->slave = -1;
  1352. ctx->s = -1;
  1353. ctx->debug = FALSE;
  1354. ctx->error_recovery = MODBUS_ERROR_RECOVERY_NONE;
  1355. ctx->response_timeout.tv_sec = 0;
  1356. ctx->response_timeout.tv_usec = _RESPONSE_TIMEOUT;
  1357. ctx->byte_timeout.tv_sec = 0;
  1358. ctx->byte_timeout.tv_usec = _BYTE_TIMEOUT;
  1359. ctx->indication_timeout.tv_sec = 0;
  1360. ctx->indication_timeout.tv_usec = 0;
  1361. }
  1362. /* Define the slave number */
  1363. int modbus_set_slave(modbus_t *ctx, int slave)
  1364. {
  1365. if (ctx == NULL) {
  1366. errno = EINVAL;
  1367. return -1;
  1368. }
  1369. return ctx->backend->set_slave(ctx, slave);
  1370. }
  1371. int modbus_get_slave(modbus_t *ctx)
  1372. {
  1373. if (ctx == NULL) {
  1374. errno = EINVAL;
  1375. return -1;
  1376. }
  1377. return ctx->slave;
  1378. }
  1379. int modbus_set_error_recovery(modbus_t *ctx,
  1380. modbus_error_recovery_mode error_recovery)
  1381. {
  1382. if (ctx == NULL) {
  1383. errno = EINVAL;
  1384. return -1;
  1385. }
  1386. /* The type of modbus_error_recovery_mode is unsigned enum */
  1387. ctx->error_recovery = (uint8_t) error_recovery;
  1388. return 0;
  1389. }
  1390. int modbus_set_socket(modbus_t *ctx, int s)
  1391. {
  1392. if (ctx == NULL) {
  1393. errno = EINVAL;
  1394. return -1;
  1395. }
  1396. ctx->s = s;
  1397. return 0;
  1398. }
  1399. int modbus_get_socket(modbus_t *ctx)
  1400. {
  1401. if (ctx == NULL) {
  1402. errno = EINVAL;
  1403. return -1;
  1404. }
  1405. return ctx->s;
  1406. }
  1407. /* Get the timeout interval used to wait for a response */
  1408. int modbus_get_response_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec)
  1409. {
  1410. if (ctx == NULL) {
  1411. errno = EINVAL;
  1412. return -1;
  1413. }
  1414. *to_sec = ctx->response_timeout.tv_sec;
  1415. *to_usec = ctx->response_timeout.tv_usec;
  1416. return 0;
  1417. }
  1418. int modbus_set_response_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec)
  1419. {
  1420. if (ctx == NULL ||
  1421. (to_sec == 0 && to_usec == 0) || to_usec > 999999) {
  1422. errno = EINVAL;
  1423. return -1;
  1424. }
  1425. ctx->response_timeout.tv_sec = to_sec;
  1426. ctx->response_timeout.tv_usec = to_usec;
  1427. return 0;
  1428. }
  1429. /* Get the timeout interval between two consecutive bytes of a message */
  1430. int modbus_get_byte_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec)
  1431. {
  1432. if (ctx == NULL) {
  1433. errno = EINVAL;
  1434. return -1;
  1435. }
  1436. *to_sec = ctx->byte_timeout.tv_sec;
  1437. *to_usec = ctx->byte_timeout.tv_usec;
  1438. return 0;
  1439. }
  1440. int modbus_set_byte_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec)
  1441. {
  1442. /* Byte timeout can be disabled when both values are zero */
  1443. if (ctx == NULL || to_usec > 999999) {
  1444. errno = EINVAL;
  1445. return -1;
  1446. }
  1447. ctx->byte_timeout.tv_sec = to_sec;
  1448. ctx->byte_timeout.tv_usec = to_usec;
  1449. return 0;
  1450. }
  1451. /* Get the timeout interval used by the server to wait for an indication from a client */
  1452. int modbus_get_indication_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec)
  1453. {
  1454. if (ctx == NULL) {
  1455. errno = EINVAL;
  1456. return -1;
  1457. }
  1458. *to_sec = ctx->indication_timeout.tv_sec;
  1459. *to_usec = ctx->indication_timeout.tv_usec;
  1460. return 0;
  1461. }
  1462. int modbus_set_indication_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec)
  1463. {
  1464. /* Indication timeout can be disabled when both values are zero */
  1465. if (ctx == NULL || to_usec > 999999) {
  1466. errno = EINVAL;
  1467. return -1;
  1468. }
  1469. ctx->indication_timeout.tv_sec = to_sec;
  1470. ctx->indication_timeout.tv_usec = to_usec;
  1471. return 0;
  1472. }
  1473. int modbus_get_header_length(modbus_t *ctx)
  1474. {
  1475. if (ctx == NULL) {
  1476. errno = EINVAL;
  1477. return -1;
  1478. }
  1479. return ctx->backend->header_length;
  1480. }
  1481. int modbus_connect(modbus_t *ctx)
  1482. {
  1483. if (ctx == NULL) {
  1484. errno = EINVAL;
  1485. return -1;
  1486. }
  1487. return ctx->backend->connect(ctx);
  1488. }
  1489. void modbus_close(modbus_t *ctx)
  1490. {
  1491. if (ctx == NULL)
  1492. return;
  1493. ctx->backend->close(ctx);
  1494. }
  1495. void modbus_free(modbus_t *ctx)
  1496. {
  1497. if (ctx == NULL)
  1498. return;
  1499. ctx->backend->free(ctx);
  1500. }
  1501. int modbus_set_debug(modbus_t *ctx, int flag)
  1502. {
  1503. if (ctx == NULL) {
  1504. errno = EINVAL;
  1505. return -1;
  1506. }
  1507. ctx->debug = flag;
  1508. return 0;
  1509. }
  1510. /* Allocates 4 arrays to store bits, input bits, registers and inputs
  1511. registers. The pointers are stored in modbus_mapping structure.
  1512. The modbus_mapping_new_start_address() function shall return the new allocated
  1513. structure if successful. Otherwise it shall return NULL and set errno to
  1514. ENOMEM. */
  1515. modbus_mapping_t* modbus_mapping_new_start_address(
  1516. unsigned int start_bits, unsigned int nb_bits,
  1517. unsigned int start_input_bits, unsigned int nb_input_bits,
  1518. unsigned int start_registers, unsigned int nb_registers,
  1519. unsigned int start_input_registers, unsigned int nb_input_registers)
  1520. {
  1521. modbus_mapping_t *mb_mapping;
  1522. mb_mapping = (modbus_mapping_t *)malloc(sizeof(modbus_mapping_t));
  1523. if (mb_mapping == NULL) {
  1524. return NULL;
  1525. }
  1526. /* 0X */
  1527. mb_mapping->nb_bits = nb_bits;
  1528. mb_mapping->start_bits = start_bits;
  1529. if (nb_bits == 0) {
  1530. mb_mapping->tab_bits = NULL;
  1531. } else {
  1532. /* Negative number raises a POSIX error */
  1533. mb_mapping->tab_bits =
  1534. (uint8_t *) malloc(nb_bits * sizeof(uint8_t));
  1535. if (mb_mapping->tab_bits == NULL) {
  1536. free(mb_mapping);
  1537. return NULL;
  1538. }
  1539. memset(mb_mapping->tab_bits, 0, nb_bits * sizeof(uint8_t));
  1540. }
  1541. /* 1X */
  1542. mb_mapping->nb_input_bits = nb_input_bits;
  1543. mb_mapping->start_input_bits = start_input_bits;
  1544. if (nb_input_bits == 0) {
  1545. mb_mapping->tab_input_bits = NULL;
  1546. } else {
  1547. mb_mapping->tab_input_bits =
  1548. (uint8_t *) malloc(nb_input_bits * sizeof(uint8_t));
  1549. if (mb_mapping->tab_input_bits == NULL) {
  1550. free(mb_mapping->tab_bits);
  1551. free(mb_mapping);
  1552. return NULL;
  1553. }
  1554. memset(mb_mapping->tab_input_bits, 0, nb_input_bits * sizeof(uint8_t));
  1555. }
  1556. /* 4X */
  1557. mb_mapping->nb_registers = nb_registers;
  1558. mb_mapping->start_registers = start_registers;
  1559. if (nb_registers == 0) {
  1560. mb_mapping->tab_registers = NULL;
  1561. } else {
  1562. mb_mapping->tab_registers =
  1563. (uint16_t *) malloc(nb_registers * sizeof(uint16_t));
  1564. if (mb_mapping->tab_registers == NULL) {
  1565. free(mb_mapping->tab_input_bits);
  1566. free(mb_mapping->tab_bits);
  1567. free(mb_mapping);
  1568. return NULL;
  1569. }
  1570. memset(mb_mapping->tab_registers, 0, nb_registers * sizeof(uint16_t));
  1571. }
  1572. /* 3X */
  1573. mb_mapping->nb_input_registers = nb_input_registers;
  1574. mb_mapping->start_input_registers = start_input_registers;
  1575. if (nb_input_registers == 0) {
  1576. mb_mapping->tab_input_registers = NULL;
  1577. } else {
  1578. mb_mapping->tab_input_registers =
  1579. (uint16_t *) malloc(nb_input_registers * sizeof(uint16_t));
  1580. if (mb_mapping->tab_input_registers == NULL) {
  1581. free(mb_mapping->tab_registers);
  1582. free(mb_mapping->tab_input_bits);
  1583. free(mb_mapping->tab_bits);
  1584. free(mb_mapping);
  1585. return NULL;
  1586. }
  1587. memset(mb_mapping->tab_input_registers, 0,
  1588. nb_input_registers * sizeof(uint16_t));
  1589. }
  1590. return mb_mapping;
  1591. }
  1592. modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits,
  1593. int nb_registers, int nb_input_registers)
  1594. {
  1595. return modbus_mapping_new_start_address(
  1596. 0, nb_bits, 0, nb_input_bits, 0, nb_registers, 0, nb_input_registers);
  1597. }
  1598. /* Frees the 4 arrays */
  1599. void modbus_mapping_free(modbus_mapping_t *mb_mapping)
  1600. {
  1601. if (mb_mapping == NULL) {
  1602. return;
  1603. }
  1604. free(mb_mapping->tab_input_registers);
  1605. free(mb_mapping->tab_registers);
  1606. free(mb_mapping->tab_input_bits);
  1607. free(mb_mapping->tab_bits);
  1608. free(mb_mapping);
  1609. }
  1610. #ifndef HAVE_STRLCPY
  1611. /*
  1612. * Function strlcpy was originally developed by
  1613. * Todd C. Miller <Todd.Miller@courtesan.com> to simplify writing secure code.
  1614. * See ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/strlcpy.3
  1615. * for more information.
  1616. *
  1617. * Thank you Ulrich Drepper... not!
  1618. *
  1619. * Copy src to string dest of size dest_size. At most dest_size-1 characters
  1620. * will be copied. Always NUL terminates (unless dest_size == 0). Returns
  1621. * strlen(src); if retval >= dest_size, truncation occurred.
  1622. */
  1623. size_t strlcpy(char *dest, const char *src, size_t dest_size)
  1624. {
  1625. register char *d = dest;
  1626. register const char *s = src;
  1627. register size_t n = dest_size;
  1628. /* Copy as many bytes as will fit */
  1629. if (n != 0 && --n != 0) {
  1630. do {
  1631. if ((*d++ = *s++) == 0)
  1632. break;
  1633. } while (--n != 0);
  1634. }
  1635. /* Not enough room in dest, add NUL and traverse rest of src */
  1636. if (n == 0) {
  1637. if (dest_size != 0)
  1638. *d = '\0'; /* NUL-terminate dest */
  1639. while (*s++)
  1640. ;
  1641. }
  1642. return (s - src - 1); /* count does not include NUL */
  1643. }
  1644. #endif

LibModbus库实际工程应用

首先要下载安装VisualStudio2019或者VisualStudio2022,下载连接如下:

https://visualstudio.microsoft.com/zh-hans/downloads/icon-default.png?t=N7T8https://visualstudio.microsoft.com/zh-hans/downloads/

1、TIA中新建项目插入PLC 1214C,PLC属性设置如上所示IP地址为192.168.1.214。DB块中数据如下图所示,远程连接地址设置为192.168.1.106,不设置代表任何客户端都可连接。

2、编写ModbusTCP Server端程序,程序如下图所示。

3、Modbus通信数据地址隐射为M100,如下图所示数据长度映射600个字。

4、监控表中添加M100开始的数据监控表。如下图所示。

5、打开VisualStudio2019新建名为“MFCApplicationMultiLineTest”的MFC项目。将modbus.h头文件增加到项目MFCApplicationMultiLineTest.CPP文件中,如下图所示。

6、新建如下全局变量用于通信和线程管理。

  1. #define LOOP 1
  2. #define CLIENT_ID 20
  3. #define ADDRESS_START 40001
  4. #define ADDRESS_END 40101
  5. #define ADDRESS_MAX 40201
  6. #define ADDRESS_SUPERMAX 40301
  7. #define PI 3.1415926
  8. threadInfo Info;
  9. CMutex cmtex;
  10. BOOL ThreadKiller = FALSE;
  11. BOOL ForKiller = FALSE;
  12. HANDLE hMyThread;
  13. BOOL ModbusThreadKiller = FALSE;
  14. BOOL ModbusLoop = FALSE;
  15. BOOL ServerConnectFailedFlag = FALSE;
  16. int nb_fail;
  17. int nb_loop;
  18. int addr;
  19. int addr_float = 100;
  20. int addr_float_supermax = 200;
  21. int nb;
  22. int sel;
  23. int flnb;
  24. int spnb;
  25. int nCount;
  26. CString strfloat;
  27. modbus_t* ctx;
  28. uint8_t * tab_rq_bits;
  29. uint8_t * tab_rp_bits;
  30. uint16_t* tab_rq_registers;
  31. uint16_t* tab_rp_registers;
  32. uint16_t* tab_rw_registers;
  33. uint16_t* tab_float_registers;
  34. uint16_t* tab_float_write_registers;
  35. float * read_float_registers;
  36. float * write_float_registers;
  37. CRect rcClientOld;
  38. CRect rcClientNew;

7、在OnInitDialog()初始化函数中加入如下代码。窗口打开后即可连接ModbusTCP服务器端。

  1. ctx = modbus_new_tcp("192.168.1.214", 502);
  2. modbus_set_debug(ctx, TRUE);
  3. modbus_set_slave(ctx, CLIENT_ID);
  4. modbus_set_response_timeout(ctx, 10, 1000000);
  5. if (modbus_connect(ctx) == -1)
  6. {
  7. fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
  8. printf("Connection failed: %s\n", modbus_strerror(errno));
  9. OutputDebugString(_T("Connection failed : % s\n"));
  10. AfxMessageBox(_T("Modbus Server Conneect Failed!"), MB_ICONINFORMATION);
  11. modbus_close(ctx);
  12. modbus_free(ctx);
  13. ServerConnectFailedFlag = TRUE;
  14. return -1;
  15. }
  16. else
  17. {
  18. AfxMessageBox(_T("Modbus Server Conneect Success!"), MB_ICONINFORMATION);
  19. ServerConnectFailedFlag = FALSE;
  20. }
  21. SetTimer(1, 1000, NULL);
  22. /*ModbusTCP通讯寄存器内存分配和内存空间初始化*/
  23. nb = ADDRESS_END - ADDRESS_START;//40001-4101为int
  24. flnb = ADDRESS_MAX - ADDRESS_END;//40101-40201为float
  25. spnb = ADDRESS_SUPERMAX - ADDRESS_MAX;//40201-40301为float
  26. tab_rq_bits = (uint8_t*)malloc(nb * sizeof(uint8_t));
  27. memset(tab_rq_bits,0, nb * sizeof(uint8_t));
  28. tab_rp_bits = (uint8_t*)malloc(nb * sizeof(uint8_t));
  29. memset(tab_rp_bits,0, nb * sizeof(uint8_t));
  30. tab_rq_registers = (uint16_t*)malloc(nb * sizeof(uint16_t));
  31. memset(tab_rq_registers,0, nb * sizeof(uint16_t));
  32. tab_rp_registers = (uint16_t*)malloc(nb * sizeof(uint16_t));
  33. memset(tab_rp_registers,0, nb * sizeof(uint16_t));
  34. tab_rw_registers = (uint16_t*)malloc(nb * sizeof(uint16_t));
  35. memset(tab_rw_registers,0, nb * sizeof(uint16_t));
  36. tab_float_registers = (uint16_t*)malloc(2 * flnb * sizeof(uint16_t));
  37. memset(tab_float_registers,0, 2 * flnb * sizeof(uint16_t));
  38. read_float_registers = (float*)malloc(flnb * sizeof(float));
  39. memset(read_float_registers,0, flnb * sizeof(float));
  40. write_float_registers = (float*)malloc((flnb) * sizeof(float));
  41. memset(write_float_registers,0, (flnb) * sizeof(float));
  42. tab_float_write_registers = (uint16_t*)malloc(2 * flnb * sizeof(uint16_t));
  43. memset(tab_float_write_registers,0, 2 * flnb * sizeof(uint16_t));
  44. //**********************************************************************
  45. GetClientRect(&rcGetold);
  46. OldClientPoint.x = rcGetold.right - rcGetold.left;
  47. OldClientPoint.y = rcGetold.bottom - rcGetold.top;

8、编写相关的通信线程函数ModBusCommunication(LPVOID* pParam)。Libmodbus库函数说明在Libmodbus官网有详细的说明。

  1. UINT CMFCApplicationMultiLineTestDlg::ModBusCommunication(LPVOID* pParam)
  2. {
  3. CMFCApplicationMultiLineTestDlg* modbustcp = (CMFCApplicationMultiLineTestDlg*)pParam;
  4. int rc=0;
  5. int n=0;
  6. int qw=0;
  7. int rq=0;
  8. int wf = 0;
  9. float rfloat = 0;
  10. //COLORREF RGB;
  11. BOOL sendmsg = FALSE;
  12. BOOL dspmsg = FALSE;
  13. CWnd* thHwnd = AfxGetApp()->GetMainWnd();
  14. CSingleLock modbuslock(&cmtex);
  15. modbuslock.Lock();
  16. if (ServerConnectFailedFlag == FALSE)
  17. {
  18. while (ModbusLoop==FALSE)
  19. {
  20. if(ServerConnectFailedFlag==FALSE)
  21. {
  22. if (ModbusThreadKiller)//最好让线程自行退出。
  23. {
  24. DWORD dwExitCode;
  25. GetExitCodeThread(modbustcp->ModbusTcpThread,&dwExitCode);
  26. AfxEndThread(dwExitCode,TRUE);
  27. }
  28. else
  29. {
  30. for (int q = 0; q <= 9; q++)
  31. {
  32. rc = modbus_write_bit(ctx, q, 0);
  33. if (rc != 1)
  34. {
  35. printf("Error modbus_write_bit(%d)\n", rc);
  36. printf("Address=%d,value=%d\n", q, 0);
  37. nb_fail++;
  38. }
  39. else
  40. {
  41. rc = modbus_read_bits(ctx, q, 1, tab_rq_bits);
  42. if (rc != 1 || tab_rq_bits[0] != 0)
  43. {
  44. printf("Error modbus_read_bit single(%d)\n", rc);
  45. printf("Address=%d", q);
  46. nb_fail++;
  47. }
  48. }
  49. Sleep(10);
  50. }
  51. for (qw = 0; qw <= 9; qw++)
  52. {
  53. rc = modbus_write_bit(ctx, qw, 1);//西门子S7-1200 I/O地址对应:0对应Q0.0,1对应Q0.1,8对应Q1.0
  54. if (rc != 1)
  55. {
  56. printf("Error modbus_write_bit(%d)\n", rc);
  57. printf("Address=%d,value=%d\n", qw, 1);
  58. nb_fail++;
  59. }
  60. else
  61. {
  62. rc = modbus_read_bits(ctx, qw, 1, tab_rq_bits);
  63. if (rc != 1 || tab_rq_bits[0] != 1)
  64. {
  65. printf("Error modbus_read_bit single(%d)\n", rc);
  66. printf("Address=%d", qw);
  67. nb_fail++;
  68. }
  69. }
  70. Sleep(10);
  71. }
  72. addr = 0;
  73. //addr=0对应西门子S7-1200 modbus寄存器40001,1对应40002、40001映射S7-1200 MW100,40002映射S7-1200 MW102,
  74. for (rq = 0; rq < nb; rq++)
  75. {
  76. tab_rq_registers[rq] = rq + 820 * sel;
  77. }
  78. //向S7-1200 MD300-MD696寄存器写入100个浮点数据,MD300对应modbus寄存器40201(200),MD696对应寄存器40301
  79. for (wf= 0;wf<flnb; wf++)
  80. {
  81. write_float_registers[wf] = (wf+sel)*(float)PI;
  82. modbus_set_float_dcba(write_float_registers[wf], tab_float_write_registers + 2 * wf);
  83. }
  84. rc = modbus_write_registers(ctx, addr,nb,tab_rq_registers);
  85. if (rc != nb)
  86. {
  87. printf("Error modbus_write_registers(%d)\n", rc);
  88. printf("Address=%d,nb=%d\n", addr,nb);
  89. nb_fail++;
  90. if (sendmsg == FALSE)
  91. {
  92. sendmsg = TRUE;
  93. ::PostMessage(thHwnd->GetSafeHwnd(), WM_THREAD_MONITOR, WPARAM(sendmsg), 0);
  94. }
  95. }
  96. else
  97. {
  98. rc = modbus_read_registers(ctx,addr,nb,tab_rp_registers);
  99. if (rc != nb)
  100. {
  101. printf("Error modbus_read_registers(%d)\n", rc);
  102. printf("Address=%d,nb=%d\n", addr, nb);
  103. nb_fail++;
  104. }
  105. else
  106. {
  107. for (int k = 0; k < nb; k++)
  108. {
  109. if (tab_rq_registers[k] != tab_rp_registers[k])
  110. {
  111. printf("Error modbus_read_registers(%d)\n",nb);
  112. printf("Address=%d,Value %d(0x%X!=%d (0x%X))\n",addr,tab_rq_registers[k],tab_rq_registers[k],tab_rp_registers[k],tab_rp_registers[k]);
  113. nb_fail++;
  114. }
  115. }
  116. }
  117. }
  118. /*S7-1200浮点数据写入格式为dcba(100-200定义为float数据对应MD300-MD496,float数据需要分配2*flnb的存储空间)最大写入123个字
  119. 写入前50个浮点数据(写入100个浮点数据必须分两次写入)*/
  120. rc = modbus_write_registers(ctx,addr_float,flnb,tab_float_write_registers);
  121. if (rc!=flnb)
  122. {
  123. printf("Error modbus_write_registers(%d)\n",flnb);
  124. printf("Address=%d,flnb=%d\n",addr_float,flnb);
  125. nb_fail++;
  126. }
  127. /*S7-1200浮点数据读取格式为dcba(100-200定义为float数据对应MD300-MD496,float数据需要分配2*flnb的存储空间)最大写入123个字
  128. 写入后50个浮点数据(写入100个浮点数据必须分两次写入)*/
  129. rc = modbus_write_registers(ctx, addr_float_supermax, spnb, tab_float_write_registers+spnb);
  130. if (rc != spnb)
  131. {
  132. printf("Error modbus_write_registers(%d)\n", spnb);
  133. printf("Address=%d,flnb=%d\n", addr_float_supermax, spnb);
  134. nb_fail++;
  135. }
  136. /*S7-1200浮点数据读取格式为dcba(100-200定义为float数据对应MD300-MD496,float数据需要分配2*flnb的存储空间)最大读取125个字
  137. 读取前50个浮点数据(读取数据必须分两次读取)*/
  138. rc = modbus_read_registers(ctx,addr_float,flnb,tab_float_registers);//读取前50个浮点
  139. if (rc!=flnb)
  140. {
  141. printf("Error modbus_read_registersF(%d)\n", rc);
  142. printf("Address=%d,nb=%d\n", addr_float, flnb);
  143. nb_fail++;
  144. }
  145. rc = modbus_read_registers(ctx, addr_float_supermax, spnb, tab_float_registers+spnb);//读取后50个浮点
  146. if (rc != spnb)
  147. {
  148. printf("error modbus_read_registersb(%d)\n", rc);
  149. printf("address=%d,nb=%d\n", addr_float_supermax, spnb);
  150. nb_fail++;
  151. }
  152. else
  153. {
  154. for (int lst = 0; lst < flnb; lst++)
  155. {
  156. dspmsg = TRUE;
  157. read_float_registers[lst] = modbus_get_float_dcba(tab_float_registers+lst*2);
  158. rfloat = read_float_registers[lst];
  159. //Sleep(1);
  160. ::PostMessage(thHwnd->GetSafeHwnd(), WM_SHOUWDATAFROMSIEMENS,WPARAM(dspmsg),LPARAM(lst));
  161. dspmsg = FALSE;
  162. }
  163. rfloat = read_float_registers[0];
  164. strfloat.Format(_T("%.4f"), rfloat);
  165. modbustcp->SetDlgItemText(IDC_EDITREADFLOAT,strfloat);
  166. strfloat.Format(_T("%.4f"), read_float_registers[1]);
  167. modbustcp->SetDlgItemText(IDC_EDITFREADLOAT4, strfloat);
  168. strfloat.Format(_T("%.4f"), read_float_registers[2]);
  169. modbustcp->SetDlgItemText(IDC_EDITREADFLOAT8, strfloat);
  170. }
  171. n++;
  172. modbustcp->SetDlgItemInt(IDC_EDITCACULATE, n);
  173. }
  174. }
  175. }
  176. }
  177. else
  178. {
  179. printf("Connection Failed: %s\n", modbus_strerror(errno));
  180. AfxMessageBox(_T("ModbusServer Connect Failed!"), MB_ICONINFORMATION);
  181. }
  182. n = 0;
  183. modbustcp->SetDlgItemInt(IDC_EDITCACULATE, n);
  184. modbustcp->ModbusTcpThread = NULL;
  185. sendmsg = FALSE;
  186. dspmsg = FALSE;
  187. modbuslock.Unlock();
  188. return 0;
  189. }

9、增加线程启动按钮,在按钮中启动通信线程完成通信。此例程为Libmodbus和S7-1200通信测试例程,写的比较早,没有严格封装。S7-200 PLC 的程序做了严格封装,后面在做介绍。

  1. void CMFCApplicationMultiLineTestDlg::OnBnClickedButtonstart()
  2. {
  3. if (ModbusTcpThread == NULL)
  4. {
  5. ModbusThreadKiller = FALSE;
  6. ModbusLoop = FALSE;
  7. UpdateData(TRUE);
  8. sel = m_select;
  9. SetDlgItemInt(IDC_EDITDSP,sel);
  10. UpdateData(FALSE);
  11. Sleep(50);
  12. ModbusTcpThread = AfxBeginThread((AFX_THREADPROC)ModBusCommunication, this);
  13. }
  14. else
  15. {
  16. AfxMessageBox(_T("ModbusTCP通讯线程已启动,无需重启!"), MB_ICONINFORMATION);
  17. }
  18. }

10、启动MFC程序进行仿真。如下图所示。

11、在博图变量监控表中监控变量,如下图所示。对比发现数据准确无误。

12、合信M226ES与LibModbus之间的通信。合信M226ESModbusTCP协议客户端不需要编写程序,设置好IP地址即可,端口默认502。下面是M226ES Modbus地址映射(默认隐射)。

13、下面为测试的相关视频。

C++和S7-1200 Libmodbus 通信

开启你的Libmodbus之旅吧!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/616946
推荐阅读
相关标签
  

闽ICP备14008679号