"# \u4f7f\u7528 libmodbus \u8fdb\u884c Modbus \u534f\u8bae\u7684\u5355\u5143\u6d4b\u8bd5\u548c\u5f02\u5e38\u5904\u7406\n\n> 2024-04-21 | 2024-04-21\n> https:\/\/www.modbus.cn\/en\/27719.html\n\n**Modbus\u7f16\u7a0b\u5f00\u53d1**\n\n---\n\n\u5728\u73b0\u4ee3\u5de5\u4e1a\u81ea\u52a8\u5316\u4e2d\uff0c\u786e\u4fdd\u901a\u4fe1\u534f\u8bae\u7684\u7a33\u5b9a\u6027\u548c\u51c6\u786e\u6027\u662f\u975e\u5e38\u91cd\u8981\u7684\u3002Modbus \u534f\u8bae\u4f5c\u4e3a\u5de5\u4e1a\u754c\u5e7f\u6cdb\u5e94\u7528\u7684\u901a\u4fe1\u534f\u8bae\u4e4b\u4e00\uff0c\u5176\u7a33\u5b9a\u548c\u53ef\u9760\u7684\u8fd0\u884c\u5bf9\u7cfb\u7edf\u7684\u6b63\u5e38\u8fd0\u884c\u81f3\u5173\u91cd\u8981\u3002\u8fd9\u5c31\u9700\u8981\u901a\u8fc7\u4e00\u7cfb\u5217\u7684\u5355\u5143\u6d4b\u8bd5\u6765\u9a8c\u8bc1\u548c\u786e\u4fddModbus\u901a\u4fe1\u5e93\u7684\u6bcf\u4e2a\u529f\u80fd\u90fd\u6309\u9884\u671f\u5de5\u4f5c\uff0c\u540c\u65f6\u4e5f\u8981\u80fd\u59a5\u5584\u5904\u7406\u5f02\u5e38\u60c5\u51b5\u3002\u672c\u6587\u901a\u8fc7\u4e00\u6bb5\u8be6\u7ec6\u7684\u4ee3\u7801\u89e3\u6790\uff0c\u5c55\u793a\u4e86\u5982\u4f55\u4f7f\u7528 libmodbus \u5e93\u8fdb\u884c\u5168\u9762\u7684\u5355\u5143\u6d4b\u8bd5\u3002\n\n### \u80cc\u666f\n\nModbus \u534f\u8bae\u652f\u6301\u591a\u79cd\u6570\u636e\u64cd\u4f5c\uff0c\u5982\u8bfb\u5199\u7ebf\u5708\u3001\u79bb\u6563\u8f93\u5165\u3001\u4fdd\u6301\u5bc4\u5b58\u5668\u548c\u8f93\u5165\u5bc4\u5b58\u5668\u3002\u6d4b\u8bd5\u8fd9\u4e9b\u529f\u80fd\u7684\u6709\u6548\u6027\u548c\u5f02\u5e38\u5904\u7406\u80fd\u529b\u5bf9\u4e8e\u7ef4\u62a4\u901a\u4fe1\u94fe\u8def\u7684\u5065\u58ee\u6027\u81f3\u5173\u91cd\u8981\u3002\n\n\u5b8c\u6574\u4ee3\u7801\uff08\u4e2d\u6587\u6ce8\u91ca\uff09\uff1a\n\n```\n#include &lt;errno.h>\n#include &lt;modbus.h>\n#include &lt;stdio.h>\n#include &lt;stdlib.h>\n#include &lt;string.h>\n#include &lt;unistd.h>\n\n#include \"unit-test.h\"\n\nconst int EXCEPTION_RC = 2; \/\/ \u5b9a\u4e49\u5f02\u5e38\u8fd4\u56de\u7801\n\nenum { \/\/ \u5b9a\u4e49\u4e0d\u540c\u7684\u540e\u7aef\u7c7b\u578b\n    TCP,\n    TCP_PI,\n    RTU\n};\n\nint test_server(modbus_t *ctx, int use_backend); \/\/ \u58f0\u660e\u6d4b\u8bd5\u670d\u52a1\u5668\u7684\u51fd\u6570\nint send_crafted_request(modbus_t *ctx, int function, uint8_t *req, int req_size, uint16_t max_value, uint16_t bytes, int backend_length, int backend_offset); \/\/ \u58f0\u660e\u53d1\u9001\u5b9a\u5236\u8bf7\u6c42\u7684\u51fd\u6570\nint equal_dword(uint16_t *tab_reg, const uint32_t value); \/\/ \u58f0\u660e\u6bd4\u8f83\u53cc\u5b57\u8282\u7684\u51fd\u6570\nint is_memory_equal(const void *s1, const void *s2, size_t size); \/\/ \u58f0\u660e\u5185\u5b58\u6bd4\u8f83\u51fd\u6570\n\n#define BUG_REPORT(_cond, _format, _args...) \\\n  printf(\"\\nLine %d: assertion error for '%s': \" _format \"\\n\", __LINE__, #_cond, ##_args)\n\n#define ASSERT_TRUE(_cond, _format, __args...) \\\n  {                                            \\\n    if (_cond) {                               \\\n      printf(\"OK\\n\");                          \\\n    } else {                                   \\\n      BUG_REPORT(_cond, _format, ##__args);    \\\n      goto close;                              \\\n    }                                          \\\n  };\n\nint is_memory_equal(const void *s1, const void *s2, size_t size)\n{\n    return (memcmp(s1, s2, size) == 0);\n}\n\nint equal_dword(uint16_t *tab_reg, const uint32_t value)\n{\n    return ((tab_reg[0] == (value >> 16)) &amp;&amp; (tab_reg[1] == (value &amp; 0xFFFF)));\n}\n\nint main(int argc, char *argv[])\n{\n    const int NB_REPORT_SLAVE_ID = 2 + 3 + strlen(LIBMODBUS_VERSION_STRING); \/\/ \u8ba1\u7b97 Slave ID \u62a5\u544a\u7684\u957f\u5ea6\n    uint8_t *tab_rp_bits = NULL;\n    uint16_t *tab_rp_registers = NULL;\n    uint16_t *tab_rp_registers_bad = NULL;\n    modbus_t *ctx = NULL;\n    int i;\n    uint8_t value;\n    int nb_points;\n    int rc;\n    float real;\n    uint32_t old_response_to_sec;\n    uint32_t old_response_to_usec;\n    uint32_t new_response_to_sec;\n    uint32_t new_response_to_usec;\n    uint32_t old_byte_to_sec;\n    uint32_t old_byte_to_usec;\n    int use_backend;\n    int success = FALSE;\n    int old_slave;\n    char *ip_or_device;\n\n    if (argc > 1) {\n        if (strcmp(argv[1], \"tcp\") == 0) {\n            use_backend = TCP;\n        } else if (strcmp(argv[1], \"tcppi\") == 0) {\n            use_backend = TCP_PI;\n        } else if (strcmp(argv[1], \"rtu\") == 0) {\n            use_backend = RTU;\n        } else {\n            printf(\"Modbus client for unit testing\\n\");\n            printf(\"Usage:\\n  %s [tcp|tcppi|rtu]\\n\", argv[0]);\n            printf(\"Eg. tcp 127.0.0.1 or rtu \/dev\/ttyUSB1\\n\\n\");\n            exit(1);\n        }\n    } else {\n        \/* \u9ed8\u8ba4\u4f7f\u7528 TCP *\/\n        use_backend = TCP;\n    }\n\n    if (argc > 2) {\n        ip_or_device = argv[2];\n    } else {\n        switch (use_backend) {\n        case TCP:\n            ip_or_device = \"127.0.0.1\";\n            break;\n        case TCP_PI:\n            ip_or_device = \"::1\";\n            break;\n        case RTU:\n            ip_or_device = \"\/dev\/ttyUSB1\";\n            break;\n        default:\n            break;\n        }\n    }\n\n    if (use_backend == TCP) {\n        ctx = modbus_new_tcp(ip_or_device, 1502);\n    } else if (use_backend == TCP_PI) {\n        ctx = modbus_new_tcp_pi(ip_or_device, \"1502\");\n    } else {\n        ctx = modbus_new_rtu(ip_or_device, 115200, 'N', 8, 1);\n    }\n    if (ctx == NULL) {\n        fprintf(stderr, \"\u65e0\u6cd5\u5206\u914d libmodbus \u4e0a\u4e0b\u6587\\n\");\n        return -1;\n    }\n\n    modbus_set_debug(ctx, TRUE);\n    modbus_set_error_recovery(\n        ctx, MODBUS_ERROR_RECOVERY_LINK | MODBUS_ERROR_RECOVERY_PROTOCOL);\n\n    if (use_backend == RTU) {\n        modbus_set_slave(ctx, SERVER_ID);\n    }\n\n    modbus_get_response_timeout(ctx, &amp;old_response_to_sec, &amp;old_response_to_usec);\n    if (modbus_connect(ctx) == -1) {\n        fprintf(stderr, \"\u8fde\u63a5\u5931\u8d25: %s\\n\", modbus_strerror(errno));\n        modbus_free(ctx);\n        return -1;\n    }\n\n    \/\/ \u5206\u914d\u5e76\u521d\u59cb\u5316\u5b58\u50a8\u4f4d\u7684\u5185\u5b58\n    nb_points = (UT_BITS_NB > UT_INPUT_BITS_NB) ? UT_BITS_NB : UT_INPUT_BITS_NB;\n    tab_rp_bits = (uint8_t *) malloc(nb_points * sizeof(uint8_t));\n    memset(tab_rp_bits, 0, nb_points * sizeof(uint8_t));\n\n    \/\/ \u5206\u914d\u5e76\u521d\u59cb\u5316\u5b58\u50a8\u5bc4\u5b58\u5668\u7684\u5185\u5b58\n    nb_points = (UT_REGISTERS_NB > UT_INPUT_REGISTERS_NB) ? UT_REGISTERS_NB\n                                                          : UT_INPUT_REGISTERS_NB;\n    tab_rp_registers = (uint16_t *) malloc(nb_points * sizeof(uint16_t));\n    memset(tab_rp_registers, 0, nb_points * sizeof(uint16_t));\n\n    printf(\"** \u5355\u5143\u6d4b\u8bd5 **\\n\");\n\n    printf(\"1\/1 \u8fde\u63a5\u65f6\u4e0d\u4fee\u6539\u54cd\u5e94\u8d85\u65f6: \");\n    modbus_get_response_timeout(ctx, &amp;new_response_to_sec, &amp;new_response_to_usec);\n    ASSERT_TRUE(old_response_to_sec == new_response_to_sec &amp;&amp;\n                    old_response_to_usec == new_response_to_usec,\n                \"\");\n\n    printf(\"\\n\u6d4b\u8bd5\u8bfb\/\u5199:\\n\");\n\n    \/** \u7ebf\u5708\u4f4d **\/\n\n    \/\/ \u5355\u4e2a\n    rc = modbus_write_bit(ctx, UT_BITS_ADDRESS, ON);\n    printf(\"1\/2 modbus_write_bit: \");\n    ASSERT_TRUE(rc == 1, \"\");\n\n    rc = modbus_read_bits(ctx, UT_BITS_ADDRESS, 1, tab_rp_bits);\n    printf(\"2\/2 modbus_read_bits: \");\n    ASSERT_TRUE(rc == 1, \"\u5931\u8d25 (nb points %d)\\n\", rc);\n    ASSERT_TRUE(tab_rp_bits[0] == ON, \"\u5931\u8d25 (%0X != %0X)\\n\", tab_rp_bits[0], ON);\n\n    \/\/ \u7ed3\u675f\u5355\u4e2a\n\n    \/\/ \u591a\u4e2a\u4f4d\n    {\n        uint8_t tab_value[UT_BITS_NB];\n\n        modbus_set_bits_from_bytes(tab_value, 0, UT_BITS_NB, UT_BITS_TAB);\n        rc = modbus_write_bits(ctx, UT_BITS_ADDRESS, UT_BITS_NB, tab_value);\n        printf(\"1\/2 modbus_write_bits: \");\n        ASSERT_TRUE(rc == UT_BITS_NB, \"\");\n    }\n\n    rc = modbus_read_bits(ctx, UT_BITS_ADDRESS, UT_BITS_NB, tab_rp_bits);\n    printf(\"2\/2 modbus_read_bits: \");\n    ASSERT_TRUE(rc == UT_BITS_NB, \"\u5931\u8d25 (nb points %d)\\n\", rc);\n\n    i = 0;\n    nb_points = UT_BITS_NB;\n    while (nb_points > 0) {\n        int nb_bits = (nb_points > 8) ? 8 : nb_points;\n\n        value = modbus_get_byte_from_bits(tab_rp_bits, i * 8, nb_bits);\n        ASSERT_TRUE(\n            value == UT_BITS_TAB[i], \"\u5931\u8d25 (%0X != %0X)\\n\", value, UT_BITS_TAB[i]);\n\n        nb_points -= nb_bits;\n        i++;\n    }\n    printf(\"OK\\n\");\n    \/\/ \u7ed3\u675f\u591a\u4e2a\u4f4d\n\n    \/** \u79bb\u6563\u8f93\u5165 **\/\n    rc =\n        modbus_read_input_bits(ctx, UT_INPUT_BITS_ADDRESS, UT_INPUT_BITS_NB, tab_rp_bits);\n    printf(\"1\/1 modbus_read_input_bits: \");\n    ASSERT_TRUE(rc == UT_INPUT_BITS_NB, \"\u5931\u8d25 (nb points %d)\\n\", rc);\n\n    i = 0;\n    nb_points = UT_INPUT_BITS_NB;\n    while (nb_points > 0) {\n        int nb_bits = (nb_points > 8) ? 8 : nb_points;\n        value = modbus_get_byte_from_bits(tab_rp_bits, i * 8, nb_bits);\n        ASSERT_TRUE(value == UT_INPUT_BITS_TAB[i],\n                    \"\u5931\u8d25 (%0X != %0X)\\n\",\n                    value,\n                    UT_INPUT_BITS_TAB[i]);\n\n        nb_points -= nb_bits;\n        i++;\n    }\n    printf(\"OK\\n\");\n\n    \/** \u4fdd\u6301\u5bc4\u5b58\u5668 **\/\n\n    \/\/ \u5355\u4e2a\u5bc4\u5b58\u5668\n    rc = modbus_write_register(ctx, UT_REGISTERS_ADDRESS, 0x1234);\n    printf(\"1\/2 modbus_write_register: \");\n    ASSERT_TRUE(rc == 1, \"\");\n\n    rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS, 1, tab_rp_registers);\n    printf(\"2\/2 modbus_read_registers: \");\n    ASSERT_TRUE(rc == 1, \"\u5931\u8d25 (nb points %d)\\n\", rc);\n    ASSERT_TRUE(tab_rp_registers[0] == 0x1234,\n                \"\u5931\u8d25 (%0X != %0X)\\n\",\n                tab_rp_registers[0],\n                0x1234);\n    \/\/ \u7ed3\u675f\u5355\u4e2a\u5bc4\u5b58\u5668\n\n    \/\/ \u591a\u4e2a\u5bc4\u5b58\u5668\n    rc = modbus_write_registers(\n        ctx, UT_REGISTERS_ADDRESS, UT_REGISTERS_NB, UT_REGISTERS_TAB);\n    printf(\"1\/5 modbus_write_registers: \");\n    ASSERT_TRUE(rc == UT_REGISTERS_NB, \"\");\n\n    rc = modbus_read_registers(\n        ctx, UT_REGISTERS_ADDRESS, UT_REGISTERS_NB, tab_rp_registers);\n    printf(\"2\/5 modbus_read_registers: \");\n    ASSERT_TRUE(rc == UT_REGISTERS_NB, \"\u5931\u8d25 (nb points %d)\\n\", rc);\n\n    for (i = 0; i &lt; UT_REGISTERS_NB; i++) {\n        ASSERT_TRUE(tab_rp_registers[i] == UT_REGISTERS_TAB[i],\n                    \"\u5931\u8d25 (%0X != %0X)\\n\",\n                    tab_rp_registers[i],\n                    UT_REGISTERS_TAB[i]);\n    }\n\n    rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS, 0, tab_rp_registers);\n    printf(\"3\/5 modbus_read_registers (0): \");\n    ASSERT_TRUE(rc == -1, \"\u5931\u8d25 (nb_points %d)\\n\", rc);\n\n    nb_points = (UT_REGISTERS_NB > UT_INPUT_REGISTERS_NB) ? UT_REGISTERS_NB\n                                                          : UT_INPUT_REGISTERS_NB;\n    memset(tab_rp_registers, 0, nb_points * sizeof(uint16_t));\n\n    \/\/ \u4ece tab_rp_registers \u5199\u5bc4\u5b58\u5668\u4e3a\u96f6\u5e76\u5c06\u8bfb\u53d6\u7684\u5bc4\u5b58\u5668\u5b58\u50a8\u5230 tab_rp_registers \u4e2d\u3002\u56e0\u6b64\u8bfb\u53d6\u7684\u5bc4\u5b58\u5668\u5fc5\u987b\u8bbe\u7f6e\u4e3a 0\uff0c\u7b2c\u4e00\u4e2a\u9664\u5916\uff0c\u56e0\u4e3a\u5199\u5165\u65f6\u6709 1 \u5bc4\u5b58\u5668\u7684\u504f\u79fb\u91cf\u3002\n    rc = modbus_write_and_read_registers(ctx,\n                                         UT_REGISTERS_ADDRESS + 1,\n                                         UT_REGISTERS_NB - 1,\n                                         tab_rp_registers,\n                                         UT_REGISTERS_ADDRESS,\n                                         UT_REGISTERS_NB,\n                                         tab_rp_registers);\n    printf(\"4\/5 modbus_write_and_read_registers: \");\n    ASSERT_TRUE(\n        rc == UT_REGISTERS_NB, \"\u5931\u8d25 (nb points %d != %d)\\n\", rc, UT_REGISTERS_NB);\n\n    ASSERT_TRUE(tab_rp_registers[0] == UT_REGISTERS_TAB[0],\n                \"\u5931\u8d25 (%0X != %0X)\\n\",\n                tab_rp_registers[0],\n                UT_REGISTERS_TAB[0]);\n\n    for (i = 1; i &lt; UT_REGISTERS_NB; i++) {\n        ASSERT_TRUE(\n            tab_rp_registers[i] == 0, \"\u5931\u8d25 (%0X != %0X)\\n\", tab_rp_registers[i], 0);\n    }\n\n    \/\/ \u7ed3\u675f\u591a\u4e2a\u5bc4\u5b58\u5668\n\n    \/** \u8f93\u5165\u5bc4\u5b58\u5668 **\/\n    rc = modbus_read_input_registers(\n        ctx, UT_INPUT_REGISTERS_ADDRESS, UT_INPUT_REGISTERS_NB, tab_rp_registers);\n    printf(\"1\/1 modbus_read_input_registers: \");\n    ASSERT_TRUE(rc == UT_INPUT_REGISTERS_NB, \"\u5931\u8d25 (nb points %d)\\n\", rc);\n\n    for (i = 0; i &lt; UT_INPUT_REGISTERS_NB; i++) {\n        ASSERT_TRUE(tab_rp_registers[i] == UT_INPUT_REGISTERS_TAB[i],\n                    \"\u5931\u8d25 (%0X != %0X)\\n\",\n                    tab_rp_registers[i],\n                    UT_INPUT_REGISTERS_TAB[i]);\n    }\n\n    \/\/ \u906e\u7f69\n    printf(\"1\/1 Write mask: \");\n    rc = modbus_write_register(ctx, UT_REGISTERS_ADDRESS, 0x12);\n    rc = modbus_mask_write_register(ctx, UT_REGISTERS_ADDRESS, 0xF2, 0x25);\n    ASSERT_TRUE(rc != -1, \"\u5931\u8d25 (%x == -1)\\n\", rc);\n    rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS, 1, tab_rp_registers);\n    ASSERT_TRUE(\n        tab_rp_registers[0] == 0x17, \"\u5931\u8d25 (%0X != %0X)\\n\", tab_rp_registers[0], 0x17);\n\n    printf(\"\\n\u6d4b\u8bd5\u6d6e\u70b9\u6570\\n\");\n    \/** \u6d6e\u70b9\u6570 **\/\n    printf(\"1\/4 Set\/get float ABCD: \");\n    modbus_set_float_abcd(UT_REAL, tab_rp_registers);\n    ASSERT_TRUE(is_memory_equal(tab_rp_registers, UT_IREAL_ABCD_SET, 4),\n                \"\u8bbe\u7f6e\u6d6e\u70b9\u6570 ABCD \u5931\u8d25\");\n    real = modbus_get_float_abcd(UT_IREAL_ABCD_GET);\n    ASSERT_TRUE(real == UT_REAL, \"\u5931\u8d25 (%f != %f)\\n\", real, UT_REAL);\n\n    printf(\"2\/4 Set\/get float DCBA: \");\n    modbus_set_float_dcba(UT_REAL, tab_rp_registers);\n    ASSERT_TRUE(is_memory_equal(tab_rp_registers, UT_IREAL_DCBA_SET, 4),\n                \"\u8bbe\u7f6e\u6d6e\u70b9\u6570 DCBA \u5931\u8d25\");\n    real = modbus_get_float_dcba(UT_IREAL_DCBA_GET);\n    ASSERT_TRUE(real == UT_REAL, \"\u5931\u8d25 (%f != %f)\\n\", real, UT_REAL);\n\n    printf(\"3\/4 Set\/get float BADC: \");\n    modbus_set_float_badc(UT_REAL, tab_rp_registers);\n    ASSERT_TRUE(is_memory_equal(tab_rp_registers, UT_IREAL_BADC_SET, 4),\n                \"\u8bbe\u7f6e\u6d6e\u70b9\u6570 BADC \u5931\u8d25\");\n    real = modbus_get_float_badc(UT_IREAL_BADC_GET);\n    ASSERT_TRUE(real == UT_REAL, \"\u5931\u8d25 (%f != %f)\\n\", real, UT_REAL);\n\n    printf(\"4\/4 Set\/get float CDAB: \");\n    modbus_set_float_cdab(UT_REAL, tab_rp_registers);\n    ASSERT_TRUE(is_memory_equal(tab_rp_registers, UT_IREAL_CDAB_SET, 4),\n                \"\u8bbe\u7f6e\u6d6e\u70b9\u6570 CDAB \u5931\u8d25\");\n    real = modbus_get_float_cdab(UT_IREAL_CDAB_GET);\n    ASSERT_TRUE(real == UT_REAL, \"\u5931\u8d25 (%f != %f)\\n\", real, UT_REAL);\n\n    printf(\"\\n\u6b64\u65f6\uff0c\u9519\u8bef\u6d88\u606f\u4e0d\u8868\u793a\u6d4b\u8bd5\u5931\u8d25\\n\");\n\n    \/** \u975e\u6cd5\u6570\u636e\u5730\u5740 **\/\n    printf(\"\\n\u6d4b\u8bd5\u975e\u6cd5\u6570\u636e\u5730\u5740:\\n\");\n\n    \/\/ \u6620\u5c04\u5f00\u59cb\u4e8e\u5b9a\u4e49\u7684\u5730\u5740\uff0c\u7ed3\u675f\u4e8e\u5730\u5740 + nb_points\uff0c\u56e0\u6b64\u8fd9\u4e9b\u5730\u5740\u65e0\u6548\u3002\n\n    rc = modbus_read_bits(ctx, 0, 1, tab_rp_bits);\n    printf(\"* modbus_read_bits (0): \");\n    ASSERT_TRUE(rc == -1 &amp;&amp; errno == EMBXILADD, \"\");\n\n    rc = modbus_read_bits(ctx, UT_BITS_ADDRESS, UT_BITS_NB + 1, tab_rp_bits);\n    printf(\"* modbus_read_bits (max): \");\n    ASSERT_TRUE(rc == -1 &amp;&amp; errno == EMBXILADD, \"\");\n\n    rc = modbus_read_input_bits(ctx, 0, 1, tab_rp_bits);\n    printf(\"* modbus_read_input_bits (0): \");\n    ASSERT_TRUE(rc == -1 &amp;&amp; errno == EMBXILADD, \"\");\n\n    rc = modbus_read_input_bits(\n        ctx, UT_INPUT_BITS_ADDRESS, UT_INPUT_BITS_NB + 1, tab_rp_bits);\n    printf(\"* modbus_read_input_bits (max): \");\n    ASSERT_TRUE(rc == -1 &amp;&amp; errno == EMBXILADD, \"\");\n\n    rc = modbus_read_registers(ctx, 0, 1, tab_rp_registers);\n    printf(\"* modbus_read_registers (0): \");\n    ASSERT_TRUE(rc == -1 &amp;&amp; errno == EMBXILADD, \"\");\n\n    rc = modbus_read_registers(\n        ctx, UT_REGISTERS_ADDRESS, UT_REGISTERS_NB_MAX + 1, tab_rp_registers);\n    printf(\"* modbus_read_registers (max): \");\n    ASSERT_TRUE(rc == -1 &amp;&amp; errno is EMBXILADD, \"\");\n\n    rc = modbus_read_input_registers(ctx, 0, 1, tab_rp_registers);\n    printf(\"* modbus_read_input_registers (0): \");\n    ASSERT_TRUE(rc == -1 &amp;&amp; errno == EMBXILADD, \"\");\n\n    rc = modbus_read_input_registers(\n        ctx, UT_INPUT_REGISTERS_ADDRESS, UT_INPUT_REGISTERS_NB + 1, tab_rp_registers);\n    printf(\"* modbus_read_input_registers (max): \");\n    ASSERT_TRUE(rc == -1 &amp;&amp; errno == EMBXILADD, \"\");\n\n    rc = modbus_write_bit(ctx, 0, ON);\n    printf(\"* modbus_write_bit (0): \");\n    ASSERT_TRUE(rc == -1 &amp;&amp; errno == EMBXILADD, \"\");\n\n    rc = modbus_write_bit(ctx, UT_BITS_ADDRESS + UT_BITS_NB, ON);\n    printf(\"* modbus_write_bit (max): \");\n    ASSERT_TRUE(rc == -1 and errno == EMBXILADD, \"\");\n\n    rc = modbus_write_bits(ctx, 0, 1, tab_rp_bits);\n    printf(\"* modbus_write_coils (0): \");\n    ASSERT_TRUE(rc == -1 and errno == EMBXILADD, \"\");\n\n    rc = modbus_write_bits(ctx, UT_BITS_ADDRESS + UT_BITS_NB, UT_BITS_NB, tab_rp_bits);\n    printf(\"* modbus_write_coils (max): \");\n    ASSERT_TRUE(rc == -1 and errno == EMBXILADD, \"\");\n\n    rc = modbus_write_register(ctx, 0, tab_rp_registers[0]);\n    printf(\"* modbus_write_register (0): \");\n    ASSERT_TRUE(rc == -1 and errno == EMBXILADD, \"\");\n\n    rc = modbus_write_register(\n        ctx, UT_REGISTERS_ADDRESS + UT_REGISTERS_NB_MAX, tab_rp_registers[0]);\n    printf(\"* modbus_write_register (max): \");\n    ASSERT_TRUE(rc == -1 &amp;&amp; errno == EMBXILADD, \"\");\n\n    rc = modbus_write_registers(ctx, 0, 1, tab_rp_registers);\n    printf(\"* modbus_write_registers (0): \");\n    ASSERT_TRUE(rc == -1 &amp;&amp; errno == EMBXILADD, \"\");\n\n    rc = modbus_write_registers(ctx,\n                                UT_REGISTERS_ADDRESS + UT_REGISTERS_NB_MAX,\n                                UT_REGISTERS_NB,\n                                tab_rp_registers);\n    printf(\"* modbus_write_registers (max): \");\n    ASSERT_TRUE(rc == -1 &amp;&amp; errno == EMBXILADD, \"\");\n\n    rc = modbus_mask_write_register(ctx, 0, 0xF2, 0x25);\n    printf(\"* modbus_mask_write_registers (0): \");\n    ASSERT_TRUE(rc == -1 &amp;&amp; errno == EMBXILADD, \"\");\n\n    rc = modbus_mask_write_register(\n        ctx, UT_REGISTERS_ADDRESS + UT_REGISTERS_NB_MAX, 0xF2, 0x25);\n    printf(\"* modbus_mask_write_registers (max): \");\n    ASSERT_TRUE(rc == -1 &amp;&amp; errno == EMBXILADD, \"\");\n\n    rc = modbus_write_and_read_registers(\n        ctx, 0, 1, tab_rp_registers, 0, 1, tab_rp_registers);\n    printf(\"* modbus_write_and_read_registers (0): \");\n    ASSERT_TRUE(rc == -1 &amp;&amp; errno == EMBXILADD, \"\");\n\n    rc = modbus_write_and_read_registers(ctx,\n                                         UT_REGISTERS_ADDRESS + UT_REGISTERS_NB_MAX,\n                                         UT_REGISTERS_NB,\n                                         tab_rp_registers,\n                                         UT_REGISTERS_ADDRESS + UT_REGISTERS_NB_MAX,\n                                         UT_REGISTERS_NB,\n                                         tab_rp_registers);\n    printf(\"* modbus_write_and_read_registers (max): \");\n    ASSERT_TRUE(rc == -1 &amp;&amp; errno == EMBXILADD, \"\");\n\n    \/** \u592a\u591a\u6570\u636e **\/\n    printf(\"\\n\u6d4b\u8bd5\u592a\u591a\u6570\u636e\u9519\u8bef:\\n\");\n\n    rc = modbus_read_bits(ctx, UT_BITS_ADDRESS, MODBUS_MAX_READ_BITS + 1, tab_rp_bits);\n    printf(\"* modbus_read_bits: \");\n    ASSERT_TRUE(rc == -1 &amp;&amp; errno == EMBMDATA, \"\");\n\n    rc = modbus_read_input_bits(\n        ctx, UT_INPUT_BITS_ADDRESS, MODBUS_MAX_READ_BITS + 1, tab_rp_bits);\n    printf(\"* modbus_read_input_bits: \");\n    ASSERT_TRUE(rc == -1 &amp;&amp; errno == EMBMDATA, \"\");\n\n    rc = modbus_read_registers(\n        ctx, UT_REGISTERS_ADDRESS, MODBUS_MAX_READ_REGISTERS + 1, tab_rp_registers);\n    printf(\"* modbus_read_registers: \");\n    ASSERT_TRUE(rc == -1 &amp;&amp; errno == EMBMDATA, \"\");\n\n    rc = modbus_read_input_registers(\n        ctx, UT_INPUT_REGISTERS_ADDRESS, MODBUS_MAX_READ_REGISTERS + 1, tab_rp_registers);\n    printf(\"* modbus_read_input_registers: \");\n    ASSERT_TRUE(rc == -1 &amp;&amp; errno == EMBMDATA, \"\");\n\n    rc = modbus_write_bits(ctx, UT_BITS_ADDRESS, MODBUS_MAX_WRITE_BITS + 1, tab_rp_bits);\n    printf(\"* modbus_write_bits: \");\n    ASSERT_TRUE(rc == -1 &amp;&amp; errno == EMBMDATA, \"\");\n\n    rc = modbus_write_registers(\n        ctx, UT_REGISTERS_ADDRESS, MODBUS_MAX_WRITE_REGISTERS + 1, tab_rp_registers);\n    printf(\"* modbus_write_registers: \");\n    ASSERT_TRUE(rc == -1 &amp;&amp; errno == EMBMDATA, \"\");\n\n    \/** \u4ece\u5730\u5740 **\/\n    old_slave = modbus_get_slave(ctx);\n\n    printf(\"\\n\u6d4b\u8bd5\u4ece\u5730\u5740:\\n\");\n\n    printf(\"1\/2 \u4e0d\u5408\u89c4\u7684\u4ece\u5730\u5740\u88ab\u62d2\u7edd: \");\n    rc = modbus_set_slave(ctx, 248);\n    ASSERT_TRUE(rc == -1, \"\u4ece\u5730\u5740 248 \u4e0d\u5e94\u88ab\u5141\u8bb8\");\n\n    printf(\"2\/2 \u4e0d\u5408\u89c4\u7684\u4ece\u5730\u5740\u88ab\u5141\u8bb8: \");\n    modbus_enable_quirks(ctx, MODBUS_QUIRK_MAX_SLAVE);\n    rc = modbus_set_slave(ctx, 248);\n    ASSERT_TRUE(rc == 0, \"\u4e0d\u5408\u89c4\u7684\u4ece\u5730\u5740\u5e94\u8be5\u88ab\u63a5\u53d7\");\n\n    modbus_disable_quirks(ctx, MODBUS_QUIRK_MAX_SLAVE);\n    rc = modbus_set_slave(ctx, old_slave);\n    ASSERT_TRUE(rc == 0, \"\u65e0\u6cd5\u6062\u590d\u4ece\u503c\")\n\n    \/** \u4ece\u56de\u590d **\/\n\n    printf(\"\\n\u6d4b\u8bd5\u4ece\u56de\u590d:\\n\");\n    modbus_set_slave(ctx, INVALID_SERVER_ID);\n    rc = modbus_read_registers(\n        ctx, UT_REGISTERS_ADDRESS, UT_REGISTERS_NB, tab_rp_registers);\n    if (use_backend == RTU) {\n        const int RAW_REQ_LENGTH = 6;\n        uint8_t raw_req[] = {INVALID_SERVER_ID, 0x03, 0x00, 0x01, 0x01, 0x01};\n        \/\/ \u592a\u591a\u70b9\u6570\n        uint8_t raw_invalid_req[] = {INVALID_SERVER_ID, 0x03, 0x00, 0x01, 0xFF, 0xFF};\n        const int RAW_RSP_LENGTH = 7;\n        uint8_t raw_rsp[] = {INVALID_SERVER_ID, 0x03, 0x04, 0, 0, 0, 0};\n        uint8_t rsp[MODBUS_RTU_MAX_ADU_LENGTH];\n\n        \/\/ RTU \u6a21\u5f0f\u4e0b\u65e0\u54cd\u5e94\n        printf(\"1-A\/3 \u4ece\u8bbe\u5907 %d \u65e0\u54cd\u5e94: \", INVALID_SERVER_ID);\n        ASSERT_TRUE(rc == -1 &amp;&amp; errno == ETIMEDOUT, \"\");\n\n        \/\/ \u4ece\u8bbe\u5907\u5728\u786e\u8ba4\u4e2d\u5f15\u53d1\u8d85\u65f6\u4ee5\u5ffd\u7565\uff0c\u56e0\u4e3a\u5982\u679c\u63a5\u6536\u5230\u5176\u4ed6\u4ece\u8bbe\u5907\u7684\u6307\u793a\uff0c\u5219\u5fc5\u987b\u9075\u5faa\u786e\u8ba4\n\n        \/\/ \u53d1\u9001\u6307\u793a\/\u786e\u8ba4\u5bf9\u5230\u5177\u6709\u4e0d\u540c\u4ece\u8bbe\u5907 ID \u7684\u4ece\u8bbe\u5907\u4ee5\u6a21\u62df RS485 \u603b\u7ebf\u4e0a\u7684\u901a\u4fe1\u3002\u9996\u5148\uff0c\u4ece\u8bbe\u5907\u5c06\u770b\u5230\u6307\u793a\u6d88\u606f\u7136\u540e\u662f\u786e\u8ba4\uff0c\u5b83\u5fc5\u987b\u5ffd\u7565\u8fd9\u4e24\u4e2a\u3002\n        modbus_send_raw_request(ctx, raw_req, RAW_REQ_LENGTH * sizeof(uint8_t));\n        modbus_send_raw_request(ctx, raw_rsp, RAW_RSP_LENGTH * sizeof(uint8_t));\n        rc = modbus_receive_confirmation(ctx, rsp);\n\n        printf(\"1-B\/3 \u4ece\u8bbe\u5907 %d \u5728\u6307\u793a\/\u786e\u8ba4\u6d88\u606f\u4e0a\u65e0\u54cd\u5e94: \",\n               INVALID_SERVER_ID);\n        ASSERT_TRUE(rc == -1 &amp;&amp; errno == ETIMEDOUT, \"\");\n\n        \/\/ \u53d1\u9001\u53e6\u4e00\u4e2a\u4ece\u8bbe\u5907\u7684\u65e0\u6548\u8bf7\u6c42\n        modbus_send_raw_request(ctx, raw_invalid_req, RAW_REQ_LENGTH * sizeof(uint8_t));\n        rc = modbus_receive_confirmation(ctx, rsp);\n\n        printf(\"1-C\/3 \u4ece\u8bbe\u5907 %d \u6709\u65e0\u6548\u8bf7\u6c42\u65e0\u54cd\u5e94: \",\n               INVALID_SERVER_ID);\n        ASSERT_TRUE(rc == -1 &amp;&amp; errno == ETIMEDOUT, \"\");\n\n        rc = modbus_set_slave(ctx, MODBUS_BROADCAST_ADDRESS);\n        ASSERT_TRUE(rc == 0, \"\u65e0\u6548\u7684\u5e7f\u64ad\u5730\u5740\");\n\n        rc = modbus_read_registers(\n            ctx, UT_REGISTERS_ADDRESS, UT_REGISTERS_NB, tab_rp_registers);\n        printf(\"2\/3 \u5e7f\u64ad\u67e5\u8be2\u540e\u65e0\u56de\u590d: \");\n        ASSERT_TRUE(rc == -1 &amp;&amp; errno == ETIMEDOUT, \"\");\n    } else {\n        \/\/ TCP \u6a21\u5f0f\u54cd\u5e94\n        printf(\"1\/3 \u4ece\u8bbe\u5907 %d \u54cd\u5e94: \", INVALID_SERVER_ID);\n        ASSERT_TRUE(rc == UT_REGISTERS_NB, \"\");\n\n        rc = modbus_set_slave(ctx, MODBUS_BROADCAST_ADDRESS);\n        ASSERT_TRUE(rc == 0, \"\u65e0\u6548\u7684\u5e7f\u64ad\u5730\u5740\");\n\n        rc = modbus_read_registers(\n            ctx, UT_REGISTERS_ADDRESS, UT_REGISTERS_NB, tab_rp_registers);\n        printf(\"2\/3 \u4f7f\u7528 unit id == 0 \u7684\u67e5\u8be2\u56de\u590d: \");\n        ASSERT_TRUE(rc == UT_REGISTERS_NB, \"\");\n    }\n\n    \/\/ \u6062\u590d\u4ece\u8bbe\u5907\n    modbus_set_slave(ctx, old_slave);\n\n    printf(\"3\/3 \u54cd\u5e94\u5177\u6709\u65e0\u6548 TID \u6216\u4ece\u8bbe\u5907\u7684: \");\n    rc = modbus_read_registers(\n        ctx, UT_REGISTERS_ADDRESS_INVALID_TID_OR_SLAVE, 1, tab_rp_registers);\n    ASSERT_TRUE(rc == -1, \"\");\n\n    printf(\"1\/2 \u62a5\u544a\u4ece\u8bbe\u5907 ID \u622a\u65ad: \\n\");\n    \/\/ \u8bbe\u7f6e\u6807\u8bb0\u4ee5\u786e\u4fdd\u9650\u5236\u5f97\u5230\u5c0a\u91cd\n    tab_rp_bits[NB_REPORT_SLAVE_ID - 1] = 42;\n    rc = modbus_report_slave_id(ctx, NB_REPORT_SLAVE_ID - 1, tab_rp_bits);\n    \/\/ \u8fd4\u56de\u6240\u9700\u7684\u5927\u5c0f (\u54cd\u5e94\u5927\u5c0f) \u4f46\u5c0a\u91cd\u5b9a\u4e49\u7684\u9650\u5236\n    ASSERT_TRUE(rc == NB_REPORT_SLAVE_ID &amp;&amp; tab_rp_bits[NB_REPORT_SLAVE_ID - 1] == 42,\n                \"\u8fd4\u56de\u662f rc %d (%d) \u548c\u6807\u8bb0\u662f %d (42)\",\n                rc,\n                NB_REPORT_SLAVE_ID,\n                tab_rp_bits[NB_REPORT_SLAVE_ID - 1]);\n\n    printf(\"2\/2 \u62a5\u544a\u4ece\u8bbe\u5907 ID: \\n\");\n    \/\/ tab_rp_bits \u7528\u4e8e\u5b58\u50a8\u5b57\u8282\n    rc = modbus_report_slave_id(ctx, NB_REPORT_SLAVE_ID, tab_rp_bits);\n    ASSERT_TRUE(rc == NB_REPORT_SLAVE_ID, \"\");\n\n    \/\/ \u4ece\u8bbe\u5907 ID \u662f libmodbus \u7684\u4efb\u610f\u6570\u5b57\n    ASSERT_TRUE(rc > 0, \"\");\n\n    \/\/ \u8fd0\u884c\u72b6\u6001\u6307\u793a\u5668\u4e3a ON\n    ASSERT_TRUE(rc > 1 &amp;&amp; tab_rp_bits[1] == 0xFF, \"\");\n\n    \/\/ \u6253\u5370\u989d\u5916\u6570\u636e\u4f5c\u4e3a\u5b57\u7b26\u4e32\n    if (rc > 2) {\n        printf(\"\u989d\u5916\u6570\u636e: \");\n        for (i = 2; i &lt; rc; i++) {\n            printf(\"%c\", tab_rp_bits[i]);\n        }\n        printf(\"\\n\");\n    }\n\n    \/\/ \u4fdd\u5b58\u539f\u59cb\u8d85\u65f6\n    modbus_get_response_timeout(ctx, &amp;old_response_to_sec, &amp;old_response_to_usec);\n    modbus_get_byte_timeout(ctx, &amp;old_byte_to_sec, &amp;old_byte_to_usec);\n\n    rc = modbus_set_response_timeout(ctx, 0, 0);\n    printf(\"1\/6 \u65e0\u6548\u54cd\u5e94\u8d85\u65f6 (\u96f6): \");\n    ASSERT_TRUE(rc == -1 &amp;&amp; errno == EINVAL, \"\");\n\n    rc = modbus_set_response_timeout(ctx, 0, 1000000);\n    printf(\"2\/6 \u54cd\u5e94\u8d85\u65f6\u8fc7\u5927 (us \u8fc7\u5927): \");\n    ASSERT_TRUE(rc == -1 &amp;&amp; errno == EINVAL, \"\");\n\n    rc = modbus_set_byte_timeout(ctx, 0, 1000000);\n    printf(\"3\/6 \u5b57\u8282\u8d85\u65f6\u8fc7\u5927 (us \u8fc7\u5927): \");\n    ASSERT_TRUE(rc == -1 &amp;&amp; errno == EINVAL, \"\");\n\n    modbus_set_response_timeout(ctx, 0, 1);\n    rc = modbus_read_registers(\n        ctx, UT_REGISTERS_ADDRESS, UT_REGISTERS_NB, tab_rp_registers);\n    printf(\"4\/6 1us \u54cd\u5e94\u8d85\u65f6: \");\n    if (rc == -1 &amp;&amp; errno == ETIMEDOUT) {\n        printf(\"OK\\n\");\n    } else {\n        printf(\"\u5931\u8d25 (\u53ef\u80fd\u5728\u67d0\u4e9b\u5e73\u53f0\u4e0a\u5931\u8d25)\\n\");\n    }\n\n    \/\/ \u7531 libmodbus \u7684\u9519\u8bef\u6062\u590d\u4ee3\u7801\u6267\u884c\u7b49\u5f85\u548c\u5237\u65b0\u64cd\u4f5c\uff0c\u4f46\u5728\u5f53\u524d\u54cd\u5e94\u8d85\u65f6\u4e4b\u540e\u4f11\u7720\n    \/\/ \u56e0\u6b64 0 \u53ef\u80fd\u592a\u77ed\uff01\n    usleep(old_response_to_sec * 1000000 + old_response_to_usec);\n    modbus_flush(ctx);\n\n    \/\/ \u89e6\u53d1\u670d\u52a1\u5668\u4ee3\u7801\u4e0a\u7684\u7279\u6b8a\u884c\u4e3a\uff0c\u7b49\u5f85 0.5 \u79d2\u624d\u56de\u590d\uff0c\u800c\u5141\u8bb8\u7684\u8d85\u65f6\u4e3a 0.2 \u79d2\n    modbus_set_response_timeout(ctx, 0, 200000);\n    rc = modbus_read_registers(\n        ctx, UT_REGISTERS_ADDRESS_SLEEP_500_MS, 1, tab_rp_registers);\n    printf(\"5\/6 \u54cd\u5e94\u8d85\u65f6\u592a\u77ed (0.2s &lt; 0.5s): \");\n    ASSERT_TRUE(rc == -1 &amp;&amp; errno == ETIMEDOUT, \"\");\n\n    \/\/ \u7b49\u5f85\u56de\u590d (0.2 + 0.4 > 0.5 s) \u5e76\u5728\u7ee7\u7eed\u524d\u5237\u65b0\n    usleep(400000);\n    modbus_flush(ctx);\n\n    modbus_set_response_timeout(ctx, 0, 600000);\n    rc = modbus_read_registers(\n        ctx, UT_REGISTERS_ADDRESS_SLEEP_500_MS, 1, tab_rp_registers);\n    printf(\"6\/6 \u9002\u5f53\u7684\u54cd\u5e94\u8d85\u65f6 (0.6s > 0.5s): \");\n    ASSERT_TRUE(rc == 1, \"\");\n\n    \/\/ \u7981\u7528\u5b57\u8282\u8d85\u65f6\u3002\n    \/\/ \u5b8c\u6574\u54cd\u5e94\u5fc5\u987b\u5728 600ms \u5185\u53ef\u7528\n    modbus_set_byte_timeout(ctx, 0, 0);\n    rc = modbus_read_registers(\n        ctx, UT_REGISTERS_ADDRESS_SLEEP_500_MS, 1, tab_rp_registers);\n    printf(\"7\/7 \u7981\u7528\u5b57\u8282\u8d85\u65f6: \");\n    ASSERT_TRUE(rc == 1, \"\");\n\n    \/\/ \u6062\u590d\u539f\u59cb\u54cd\u5e94\u8d85\u65f6\n    modbus_set_response_timeout(ctx, old_response_to_sec, old_response_to_usec);\n\n    if (use_backend == TCP) {\n        \/\/ \u6d4b\u8bd5\u670d\u52a1\u5668\u53ea\u80fd\u4f7f\u7528 TCP \u540e\u7aef\u6d4b\u8bd5\u5b57\u8282\u8d85\u65f6\n\n        \/\/ \u5b57\u8282\u4e4b\u95f4\u7684\u8d85\u65f6\u4e3a 3ms\n        modbus_set_byte_timeout(ctx, 0, 3000);\n        rc = modbus_read_registers(\n            ctx, UT_REGISTERS_ADDRESS_BYTE_SLEEP_5_MS, 1, tab_rp_registers);\n        printf(\"1\/2 \u5b57\u8282\u8d85\u65f6\u592a\u5c0f (3ms &lt; 5ms): \");\n        ASSERT_TRUE(rc == -1 &amp;&amp; errno == ETIMEDOUT, \"\");\n\n        \/\/ \u7b49\u5f85\u5269\u4f59\u5b57\u8282\u524d\u5237\u65b0\n        usleep(11 * 5000);\n        modbus_flush(ctx);\n\n        \/\/ \u5b57\u8282\u4e4b\u95f4\u7684\u8d85\u65f6\u4e3a 7ms\n        modbus_set_byte_timeout(ctx, 0, 7000);\n        rc = modbus_read_registers(\n            ctx, UT_REGISTERS_ADDRESS_BYTE_SLEEP_5_MS, 1, tab_rp_registers);\n        printf(\"2\/2 \u9002\u5e94\u7684\u5b57\u8282\u8d85\u65f6 (7ms > 5ms): \");\n        ASSERT_TRUE(rc == 1, \"\");\n    }\n\n    \/\/ \u6062\u590d\u539f\u59cb\u5b57\u8282\u8d85\u65f6\n    modbus_set_byte_timeout(ctx, old_byte_to_sec, old_byte_to_usec);\n\n    \/** \u9519\u8bef\u54cd\u5e94 **\/\n    printf(\"\\n\u6d4b\u8bd5\u9519\u8bef\u54cd\u5e94\u9519\u8bef:\\n\");\n\n    \/\/ \u4ec5\u5206\u914d\u6240\u9700\u7a7a\u95f4\n    tab_rp_registers_bad =\n        (uint16_t *) malloc(UT_REGISTERS_NB_SPECIAL * sizeof(uint16_t));\n\n    rc = modbus_read_registers(\n        ctx, UT_REGISTERS_ADDRESS, UT_REGISTERS_NB_SPECIAL, tab_rp_registers_bad);\n    printf(\"* modbus_read_registers: \");\n    ASSERT_TRUE(rc == -1 &amp;&amp; errno == EMBBADDATA, \"\");\n    free(tab_rp_registers_bad);\n\n    \/** \u624b\u52a8\u5f02\u5e38 **\/\n    printf(\"\\n\u6d4b\u8bd5\u624b\u52a8\u5f02\u5e38:\\n\");\n    rc = modbus_read_registers(\n        ctx, UT_REGISTERS_ADDRESS_SPECIAL, UT_REGISTERS_NB, tab_rp_registers);\n\n    printf(\"* modbus_read_registers \u5728\u7279\u6b8a\u5730\u5740: \");\n    ASSERT_TRUE(rc == -1 &amp;&amp; errno == EMBXSBUSY, \"\");\n\n    \/** \u8fd0\u884c\u4e00\u4e9b\u6d4b\u8bd5\u6765\u6311\u6218\u670d\u52a1\u5668\u4ee3\u7801 **\/\n    if (test_server(ctx, use_backend) == -1) {\n        goto close;\n    }\n\n    modbus_close(ctx);\n    modbus_free(ctx);\n    ctx = NULL;\n\n    \/\/ \u6d4b\u8bd5\u521d\u59cb\u5316\u51fd\u6570\n    printf(\"\\n\u6d4b\u8bd5\u65e0\u6548\u521d\u59cb\u5316:\\n\");\n    ctx = modbus_new_rtu(NULL, 1, 'A', 0, 0);\n    ASSERT_TRUE(ctx == NULL &amp;&amp; errno == EINVAL, \"\");\n\n    ctx = modbus_new_rtu(\"\/dev\/dummy\", 0, 'A', 0, 0);\n    ASSERT_TRUE(ctx == NULL &amp;&amp; errno == EINVAL, \"\");\n\n    printf(\"\\n\u6240\u6709\u6d4b\u8bd5\u5747\u6210\u529f\u901a\u8fc7\u3002\\n\");\n    success = TRUE;\n\nclose:\n    \/\/ \u91ca\u653e\u5185\u5b58\n    free(tab_rp_bits);\n    free(tab_rp_registers);\n\n    \/\/ \u5173\u95ed\u8fde\u63a5\n    modbus_close(ctx);\n    modbus_free(ctx);\n\n    return (success) ? 0 : -1;\n}\n\n\/* \u53d1\u9001\u5b9a\u5236\u8bf7\u6c42\u4ee5\u6d4b\u8bd5\u670d\u52a1\u5668\u7684\u5f39\u6027\n   \u5e76\u786e\u4fdd\u8fd4\u56de\u9002\u5f53\u7684\u5f02\u5e38\u3002 *\/\nint test_server(modbus_t *ctx, int use_backend)\n{\n    int rc;\n    int i;\n    \/\/ \u8bfb\u53d6\u8bf7\u6c42\n    const int READ_RAW_REQ_LEN = 6;\n    const int slave = (use_backend == RTU) ? SERVER_ID : MODBUS_TCP_SLAVE;\n    uint8_t read_raw_req[] = {slave,\n                              \/* function, address, 5 values *\/\n                              MODBUS_FC_READ_HOLDING_REGISTERS,\n                              UT_REGISTERS_ADDRESS >> 8,\n                              UT_REGISTERS_ADDRESS &amp; 0xFF,\n                              0x0,\n                              0x05};\n    \/\/ \u5199\u5165\u548c\u8bfb\u53d6\u5bc4\u5b58\u5668\u8bf7\u6c42\n    const int RW_RAW_REQ_LEN = 13;\n    uint8_t rw_raw_req[] = {slave,\n                            \/* function, addr to read, nb to read *\/\n                            MODBUS_FC_WRITE_AND_READ_REGISTERS,\n                            \/* Read *\/\n                            UT_REGISTERS_ADDRESS >> 8,\n                            UT_REGISTERS_ADDRESS &amp; 0xFF,\n                            (MODBUS_MAX_WR_READ_REGISTERS + 1) >> 8,\n                            (MODBUS_MAX_WR_READ_REGISTERS + 1) &amp; 0xFF,\n                            \/* Write *\/\n                            0,\n                            0,\n                            0,\n                            1,\n                            \/* Write byte count *\/\n                            1 * 2,\n                            \/* One data to write... *\/\n                            0x12,\n                            0x34};\n    const int WRITE_RAW_REQ_LEN = 13;\n    uint8_t write_raw_req[] = {slave,\n                               \/* function will be set in the loop *\/\n                               MODBUS_FC_WRITE_MULTIPLE_REGISTERS,\n                               \/* Address *\/\n                               UT_REGISTERS_ADDRESS >> 8,\n                               UT_REGISTERS_ADDRESS &amp; 0xFF,\n                               \/* 3 values, 6 bytes *\/\n                               0x00,\n                               0x03,\n                               0x06,\n                               \/* Dummy data to write *\/\n                               0x02,\n                               0x2B,\n                               0x00,\n                               0x01,\n                               0x00,\n                               0x64};\n    const int INVALID_FC = 0x42;\n    const int INVALID_FC_REQ_LEN = 6;\n    uint8_t invalid_fc_raw_req[] = {slave, 0x42, 0x00, 0x00, 0x00, 0x00};\n\n    int req_length;\n    uint8_t rsp[MODBUS_TCP_MAX_ADU_LENGTH];\n    int tab_read_function[] = {MODBUS_FC_READ_COILS,\n                               MODBUS_FC_READ_DISCRETE_INPUTS,\n                               MODBUS_FC_READ_HOLDING_REGISTERS,\n                               MODBUS_FC_READ_INPUT_REGISTERS};\n    int tab_read_nb_max[] = {MODBUS_MAX_READ_BITS + 1,\n                             MODBUS_MAX_READ_BITS + 1,\n                             MODBUS_MAX_READ_REGISTERS + 1,\n                             MODBUS_MAX_READ_REGISTERS + 1};\n    int backend_length;\n    int backend_offset;\n\n    if (use_backend == RTU) {\n        backend_length = 3;\n        backend_offset = 1;\n    } else {\n        backend_length = 7;\n        backend_offset = 7;\n    }\n\n    printf(\"\\n\u6d4b\u8bd5\u539f\u59cb\u8bf7\u6c42:\\n\");\n\n    uint32_t old_response_to_sec;\n    uint32_t old_response_to_usec;\n\n    \/\/ \u8fd9\u4e9b\u8bf7\u6c42\u53ef\u4ee5\u751f\u6210\u670d\u52a1\u5668\u7aef\u7684\u5237\u65b0\uff0c\u56e0\u6b64\u6211\u4eec\u9700\u8981\u6bd4\u670d\u52a1\u5668\u66f4\u9ad8\u7684\u54cd\u5e94\u8d85\u65f6\u3002\u670d\u52a1\u5668\u4f7f\u7528\u5b9a\u4e49\u7684\u54cd\u5e94\u8d85\u65f6\u5728\u5237\u65b0\u524d\u4f11\u7720\u3002\n    \/\/ \u7ed3\u675f\u65f6\u6062\u590d\u65e7\u7684\u8d85\u65f6\u3002\n    modbus_get_response_timeout(ctx, &amp;old_response_to_sec, &amp;old_response_to_usec);\n    modbus_set_response_timeout(ctx, 0, 600000);\n\n    int old_s = modbus_get_socket(ctx);\n    modbus_set_socket(ctx, -1);\n    rc = modbus_receive(ctx, rsp);\n    modbus_set_socket(ctx, old_s);\n    printf(\"* modbus_receive with invalid socket: \");\n    ASSERT_TRUE(rc == -1, \"FAILED (%d)\\n\", rc);\n\n    req_length = modbus_send_raw_request(ctx, read_raw_req, READ_RAW_REQ_LEN);\n    printf(\"* modbus_send_raw_request: \");\n    ASSERT_TRUE(req_length == (backend_length + 5), \"FAILED (%d)\\n\", req_length);\n\n    printf(\"* modbus_receive_confirmation: \");\n    rc = modbus_receive_confirmation(ctx, rsp);\n    ASSERT_TRUE(rc == (backend_length + 12), \"FAILED (%d)\\n\", rc);\n\n    \/\/ \u5c1d\u8bd5\u4e3a\u6240\u6709\u6570\u636e\u7c7b\u578b\u8bfb\u53d6\u6bd4\u54cd\u5e94\u53ef\u4ee5\u5bb9\u7eb3\u7684\u66f4\u591a\u503c\u3002\n    for (i = 0; i &lt; 4; i++) {\n        rc = send_crafted_request(ctx,\n                                  tab_read_function[i],\n                                  read_raw_req,\n                                  READ_RAW_REQ_LEN,\n                                  tab_read_nb_max[i],\n                                  0,\n                                  backend_length,\n                                  backend_offset);\n        if (rc == -1)\n            goto close;\n    }\n\n    rc = send_crafted_request(ctx,\n                              MODBUS_FC_WRITE_AND_READ_REGISTERS,\n                              rw_raw_req,\n                              RW_RAW_REQ_LEN,\n                              MODBUS_MAX_WR_READ_REGISTERS + 1,\n                              0,\n                              backend_length,\n                              backend_offset);\n    if (rc == -1)\n        goto close;\n\n    rc = send_crafted_request(ctx,\n                              MODBUS_FC_WRITE_MULTIPLE_REGISTERS,\n                              write_raw_req,\n                              WRITE_RAW_REQ_LEN,\n                              MODBUS_MAX_WRITE_REGISTERS + 1,\n                              6,\n                              backend_length,\n                              backend_offset);\n    if (rc == -1)\n        goto close;\n\n    rc = send_crafted_request(ctx,\n                              MODBUS_FC_WRITE_MULTIPLE_COILS,\n                              write_raw_req,\n                              WRITE_RAW_REQ_LEN,\n                              MODBUS_MAX_WRITE_BITS + 1,\n                              6,\n                              backend_length,\n                              backend_offset);\n    if (rc == -1)\n        goto close;\n\n    \/\/ \u6d4b\u8bd5 Modbus \u5199\u591a\u4e2a\u5bc4\u5b58\u5668\uff0c\u5bc4\u5b58\u5668\u503c\u6570\u91cf\u5927\uff0c\u4f46\u5728\u8bf7\u6c42\u4e2d\u8bbe\u7f6e\u7684\u5b57\u8282\u6570\u8f83\u5c11\uff08\u901a\u5e38\u4e0d\u662f nb * 2\uff09\u3002\n    rc = send_crafted_request(ctx,\n                              MODBUS_FC_WRITE_MULTIPLE_REGISTERS,\n                              write_raw_req,\n                              WRITE_RAW_REQ_LEN,\n                              MODBUS_MAX_WRITE_REGISTERS,\n                              6,\n                              backend_length,\n                              backend_offset);\n    if (rc == -1)\n        goto close;\n\n    rc = send_crafted_request(ctx,\n                              MODBUS_FC_WRITE_MULTIPLE_COILS,\n                              write_raw_req,\n                              WRITE_RAW_REQ_LEN,\n                              MODBUS_MAX_WRITE_BITS,\n                              6,\n                              backend_length,\n                              backend_offset);\n    if (rc == -1)\n        goto close;\n\n    \/\/ \u6d4b\u8bd5\u65e0\u6548\u529f\u80fd\u7801\n    modbus_send_raw_request(\n        ctx, invalid_fc_raw_req, INVALID_FC_REQ_LEN * sizeof(uint8_t));\n    rc = modbus_receive_confirmation(ctx, rsp);\n    printf(\"Return an exception on unknown function code: \");\n    ASSERT_TRUE(rc == (backend_length + EXCEPTION_RC) &amp;&amp;\n                    rsp[backend_offset] == (0x80 + INVALID_FC),\n                \"\")\n\n    modbus_set_response_timeout(ctx, old_response_to_sec, old_response_to_usec);\n    return 0;\nclose:\n    modbus_set_response_timeout(ctx, old_response_to_sec, old_response_to_usec);\n    return -1;\n}\n\nint send_crafted_request(modbus_t *ctx,\n                         int function,\n                         uint8_t *req,\n                         int req_len,\n                         uint16_t max_value,\n                         uint16_t bytes,\n                         int backend_length,\n                         int backend_offset)\n{\n    uint8_t rsp[MODBUS_TCP_MAX_ADU_LENGTH];\n    int j;\n\n    for (j = 0; j &lt; 2; j++) {\n        int rc;\n\n        req[1] = function;\n        if (j == 0) {\n            \/\/ \u5728\u7b2c\u4e00\u6b21\u8fed\u4ee3\u4e2d\u5c1d\u8bd5\u8bfb\u53d6\u6216\u5199\u5165\u96f6\u503c\n            req[4] = 0x00;\n            req[5] = 0x00;\n            if (bytes) {\n                \/\/ \u5199\u5165\u67e5\u8be2\n                req[6] = 0x00;\n            }\n        } else {\n            \/\/ \u5728\u7b2c\u4e8c\u6b21\u8fed\u4ee3\u4e2d\u5c1d\u8bd5\u8bfb\u53d6\u6216\u5199\u5165\u6700\u5927\u503c +1\n            req[4] = (max_value >> 8) &amp; 0xFF;\n            req[5] = max_value &amp; 0xFF;\n            if (bytes) {\n                \/\/ \u5199\u5165\u67e5\u8be2 (nb values * 2 \u8f6c\u6362\u4e3a\u5bc4\u5b58\u5668\u7684\u5b57\u8282\u6570)\n                req[6] = bytes;\n            }\n        }\n\n        modbus_send_raw_request(ctx, req, req_len * sizeof(uint8_t));\n        if (j == 0) {\n            printf(\n                \"* \u5c1d\u8bd5\u51fd\u6570 0x%X: %s 0 \u503c: \", function, bytes ? \"\u5199\" : \"\u8bfb\");\n        } else {\n            printf(\"* \u5c1d\u8bd5\u51fd\u6570 0x%X: %s %d \u503c: \",\n                   function,\n                   bytes ? \"\u5199\" : \"\u8bfb\",\n                   max_value);\n        }\n        rc = modbus_receive_confirmation(ctx, rsp);\n        ASSERT_TRUE(rc == (backend_length + EXCEPTION_RC) &amp;&amp;\n                        rsp[backend_offset] == (0x80 + function) &amp;&amp;\n                        rsp[backend_offset + 1] == MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,\n                    \"\");\n    }\n    return 0;\nclose:\n    return -1;\n}\n\n```\n\n### \u4ee3\u7801\u6982\u89c8\n\n\u63d0\u4f9b\u7684\u4ee3\u7801\u4f7f\u7528 C \u8bed\u8a00\u7f16\u5199\uff0c\u57fa\u4e8e libmodbus \u5e93\uff0c\u8fd9\u662f\u4e00\u4e2a\u5f00\u6e90\u7684 Modbus \u5e93\uff0c\u652f\u6301RTU\uff08\u4e32\u884c\u7248\u672c\uff09\u548cTCP\/IP\u3002\u6b64\u4ee3\u7801\u5c55\u793a\u4e86\u5982\u4f55\u521d\u59cb\u5316\u8fde\u63a5\u3001\u53d1\u9001\u8bf7\u6c42\u4ee5\u53ca\u5904\u7406\u54cd\u5e94\u548c\u9519\u8bef\u3002\n\n### \u5173\u952e\u529f\u80fd\u7684\u6d4b\u8bd5\n\n#### \u521d\u59cb\u5316\u548c\u8fde\u63a5\n\n\u4ee3\u7801\u9996\u5148\u8bbe\u7f6e Modbus \u4e0a\u4e0b\u6587\uff0c\u6839\u636e\u547d\u4ee4\u884c\u53c2\u6570\u9009\u62e9\u4f7f\u7528 TCP \u6216 RTU \u6a21\u5f0f\u3002\u6b64\u5916\uff0c\u8fd8\u53ef\u4ee5\u8bbe\u7f6e\u8c03\u8bd5\u6a21\u5f0f\u6765\u8ffd\u8e2a\u901a\u4fe1\u8fc7\u7a0b\u4e2d\u7684\u8be6\u7ec6\u4fe1\u606f\u3002\n\n#### \u8bfb\u5199\u6d4b\u8bd5\n\n- **\u5355\u4e2a\u548c\u591a\u4e2a\u4f4d\u7684\u8bfb\u5199**\uff1a\u901a\u8fc7 `modbus_write_bit` \u548c `modbus_read_bits` \u51fd\u6570\u6d4b\u8bd5\u5355\u4e2a\u7ebf\u5708\u7684\u8bfb\u5199\u64cd\u4f5c\u3002\u5bf9\u4e8e\u591a\u4e2a\u7ebf\u5708\uff0c\u4f7f\u7528 `modbus_write_bits` \u548c\u76f8\u5e94\u7684\u8bfb\u53d6\u51fd\u6570\u3002\n\n- **\u5bc4\u5b58\u5668\u64cd\u4f5c**\uff1a\u4f7f\u7528 `modbus_write_register` \u548c `modbus_read_registers` \u6d4b\u8bd5\u5355\u4e2a\u4fdd\u6301\u5bc4\u5b58\u5668\u7684\u8bfb\u5199\u3002\u591a\u5bc4\u5b58\u5668\u7684\u8bfb\u5199\u5219\u901a\u8fc7 `modbus_write_registers` \u548c `modbus_read_registers` \u6d4b\u8bd5\u3002\n\n#### \u5f02\u5e38\u5904\u7406\n\n\u6d4b\u8bd5\u4e86\u5982\u5730\u5740\u975e\u6cd5\u3001\u6570\u636e\u91cf\u8fc7\u591a\u7b49\u5f02\u5e38\u60c5\u51b5\u3002\u8fd9\u662f\u901a\u8fc7\u6784\u9020\u975e\u6cd5\u8bf7\u6c42\u5e76\u9884\u671f\u5e93\u80fd\u8fd4\u56de\u6b63\u786e\u7684\u5f02\u5e38\u54cd\u5e94\u7801\u6765\u5b8c\u6210\u7684\u3002\n\n#### \u6027\u80fd\u8003\u8651\n\n\u4e3a\u4e86\u6d4b\u8bd5\u5e93\u5728\u4e0d\u540c\u7f51\u7edc\u5ef6\u8fdf\u548c\u6570\u636e\u5904\u7406\u901f\u5ea6\u4e0b\u7684\u8868\u73b0\uff0c\u4ee3\u7801\u4e2d\u8c03\u6574\u4e86\u54cd\u5e94\u8d85\u65f6\u548c\u5b57\u8282\u8d85\u65f6\u7684\u8bbe\u7f6e\u3002\n\n### \u7ed3\u8bba\n\n\u901a\u8fc7\u8fd9\u6837\u7684\u5355\u5143\u6d4b\u8bd5\uff0c\u53ef\u4ee5\u7cfb\u7edf\u5730\u9a8c\u8bc1 Modbus \u5e93\u7684\u6bcf\u4e00\u4e2a\u529f\u80fd\u70b9\uff0c\u786e\u4fdd\u5728\u5b9e\u9645\u90e8\u7f72\u524d\uff0c\u6240\u6709\u7684\u529f\u80fd\u90fd\u80fd\u5728\u9884\u5b9a\u7684\u6761\u4ef6\u4e0b\u6b63\u5e38\u5de5\u4f5c\u3002\u8fd9\u4e0d\u4ec5\u5e2e\u52a9\u5f00\u53d1\u8005\u53d1\u73b0\u5e76\u4fee\u590d\u6f5c\u5728\u7684\u9519\u8bef\uff0c\u4e5f\u4e3a\u6700\u7ec8\u7528\u6237\u63d0\u4f9b\u4e86\u989d\u5916\u7684\u4fe1\u5fc3\uff0c\u786e\u4fdd\u4ed6\u4eec\u7684\u5de5\u4e1a\u7cfb\u7edf\u80fd\u591f\u7a33\u5b9a\u53ef\u9760\u5730\u8fd0\u884c\u3002\n\n\u8fd9\u6bb5\u4ee3\u7801\u53ca\u5176\u89e3\u6790\u5c55\u793a\u4e86\u5de5\u4e1a\u901a\u4fe1\u534f\u8bae\u6d4b\u8bd5\u7684\u91cd\u8981\u6027\u548c\u590d\u6742\u6027\uff0c\u4e3aModbus\u901a\u4fe1\u5e93\u7684\u5f00\u53d1\u548c\u7ef4\u62a4\u63d0\u4f9b\u4e86\u5b9d\u8d35\u7684\u53c2\u8003\u3002\n\n---\n*modbus.cn*\n"