libmodbus源码分析
主机发起请求,从机回应请求。
unit-test-client.c (主机)
if (argc > 1) {if (strcmp(argv[1], "tcp") == 0) {use_backend = TCP;} else if (strcmp(argv[1], "tcppi") == 0) {use_backend = TCP_PI;} else if (strcmp(argv[1], "rtu") == 0) {use_backend = RTU; //1. 设置use_backend } else {printf("Modbus client for unit testing\n");printf("Usage:\n %s [tcp|tcppi|rtu]\n", argv[0]);printf("Eg. tcp 127.0.0.1 or rtu /dev/ttyUSB1\n\n");exit(1);}} else {/* By default */use_backend = TCP;}if (argc > 2) {ip_or_device = argv[2];} else {switch (use_backend) {case TCP:ip_or_device = "127.0.0.1";break;case TCP_PI:ip_or_device = "::1";break;case RTU:ip_or_device = "/dev/ttyUSB1"; //2.设备名 break;default:break;}}if (use_backend == TCP) {ctx = modbus_new_tcp(ip_or_device, 1502);} else if (use_backend == TCP_PI) {ctx = modbus_new_tcp_pi(ip_or_device, "1502");} else {ctx = modbus_new_rtu(ip_or_device, 115200, 'N', 8, 1); //3. 生成modbus_t结构体ctx }if (ctx == NULL) {fprintf(stderr, "Unable to allocate libmodbus context\n");return -1;}modbus_set_debug(ctx, TRUE);modbus_set_error_recovery(ctx, MODBUS_ERROR_RECOVERY_LINK | MODBUS_ERROR_RECOVERY_PROTOCOL);if (use_backend == RTU) {modbus_set_slave(ctx, SERVER_ID); //4. 设置要访问的从机 }modbus_get_response_timeout(ctx, &old_response_to_sec, &old_response_to_usec);if (modbus_connect(ctx) == -1) { //5. 连接 fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));modbus_free(ctx);return -1;}....../* Single :写位寄存器*/ /*函数内部:1)构造请求2)发送消息3)接收回应 该函数内部调用write_single, 其modbus.c中 */ rc = modbus_write_bit(ctx, UT_BITS_ADDRESS, ON);printf("1/2 modbus_write_bit: ");ASSERT_TRUE(rc == 1, "");rc = modbus_read_bits(ctx, UT_BITS_ADDRESS, 1, tab_rp_bits);printf("2/2 modbus_read_bits: ");ASSERT_TRUE(rc == 1, "FAILED (nb points %d)\n", rc);ASSERT_TRUE(tab_rp_bits[0] == ON, "FAILED (%0X != %0X)\n", tab_rp_bits[0], ON);/* End single */
modbus.c/* Write a value to the specified register of the remote device.Used by write_bit and write_register */ static int write_single(modbus_t *ctx, int function, int addr, const uint16_t value) {int rc;int req_length;uint8_t req[_MIN_REQ_LENGTH];if (ctx == NULL) {errno = EINVAL;return -1;}// 1)构造请求 req_length = ctx->backend->build_request_basis(ctx, function, addr, (int) value, req);// 2)发送消息 rc = send_msg(ctx, req, req_length);if (rc > 0) {/* Used by write_bit and write_register */uint8_t rsp[MAX_MESSAGE_LENGTH];// 3)接收回应 rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);if (rc == -1)return -1;// 4)检查回应 rc = check_confirmation(ctx, req, rsp, rc);}return rc; }
unit-test-server.c (从机)
if (argc > 1) {if (strcmp(argv[1], "tcp") == 0) {use_backend = TCP;} else if (strcmp(argv[1], "tcppi") == 0) {use_backend = TCP_PI;} else if (strcmp(argv[1], "rtu") == 0) {use_backend = RTU; //1. RTU} else {printf("Modbus server for unit testing.\n");printf("Usage:\n %s [tcp|tcppi|rtu] [<ip or device>]\n", argv[0]);printf("Eg. tcp 127.0.0.1 or rtu /dev/ttyUSB0\n\n");return -1;}} else {/* By default */use_backend = TCP;}if (argc > 2) {ip_or_device = argv[2];} else {switch (use_backend) {case TCP:ip_or_device = "127.0.0.1";break;case TCP_PI:ip_or_device = "::1";break;case RTU:ip_or_device = "/dev/ttyUSB0"; //2.主机是/dev/ttyUSB001 break;default:break;}}if (use_backend == TCP) {ctx = modbus_new_tcp(ip_or_device, 1502);query = malloc(MODBUS_TCP_MAX_ADU_LENGTH);} else if (use_backend == TCP_PI) {ctx = modbus_new_tcp_pi(ip_or_device, "1502");query = malloc(MODBUS_TCP_MAX_ADU_LENGTH);} else {ctx = modbus_new_rtu(ip_or_device, 115200, 'N', 8, 1); //3. 将信息放入结构体 modbus_set_slave(ctx, SERVER_ID); //4. 设置的是自己的设备地址 query = malloc(MODBUS_RTU_MAX_ADU_LENGTH);}header_length = modbus_get_header_length(ctx);modbus_set_debug(ctx, TRUE);mb_mapping = modbus_mapping_new_start_address(UT_BITS_ADDRESS,UT_BITS_NB,UT_INPUT_BITS_ADDRESS,UT_INPUT_BITS_NB,UT_REGISTERS_ADDRESS,UT_REGISTERS_NB_MAX,UT_INPUT_REGISTERS_ADDRESS,UT_INPUT_REGISTERS_NB);if (mb_mapping == NULL) {fprintf(stderr, "Failed to allocate the mapping: %s\n", modbus_strerror(errno));modbus_free(ctx);return -1;}/* Examples from PI_MODBUS_300.pdf.Only the read-only input values are assigned. *//* Initialize input values that's can be only done server side. */modbus_set_bits_from_bytes(mb_mapping->tab_input_bits, 0, UT_INPUT_BITS_NB, UT_INPUT_BITS_TAB);/* Initialize values of INPUT REGISTERS */for (i = 0; i < UT_INPUT_REGISTERS_NB; i++) {mb_mapping->tab_input_registers[i] = UT_INPUT_REGISTERS_TAB[i];}if (use_backend == TCP) {s = modbus_tcp_listen(ctx, 1);modbus_tcp_accept(ctx, &s);} else if (use_backend == TCP_PI) {s = modbus_tcp_pi_listen(ctx, 1);modbus_tcp_pi_accept(ctx, &s);} else {rc = modbus_connect(ctx); //5. 连接 if (rc == -1) {fprintf(stderr, "Unable to connect %s\n", modbus_strerror(errno));modbus_free(ctx);return -1;}}