Commit 66c59d6f852811900f4b7730d0d5d8f321f2226f
1 parent
5ab6c0e1
Change indent level from 8 to 4
Showing
11 changed files
with
2588 additions
and
2590 deletions
.dir-locals.el
src/modbus.c
| @@ -16,16 +16,16 @@ | @@ -16,16 +16,16 @@ | ||
| 16 | */ | 16 | */ |
| 17 | 17 | ||
| 18 | /* | 18 | /* |
| 19 | - The library is designed to send and receive data from a device that | ||
| 20 | - communicate via the Modbus protocol. | 19 | + The library is designed to send and receive data from a device that |
| 20 | + communicate via the Modbus protocol. | ||
| 21 | 21 | ||
| 22 | - The function names used are inspired by the Modicon Modbus Protocol | ||
| 23 | - Reference Guide which can be obtained from Schneider at | ||
| 24 | - www.schneiderautomation.com. | 22 | + The function names used are inspired by the Modicon Modbus Protocol |
| 23 | + Reference Guide which can be obtained from Schneider at | ||
| 24 | + www.schneiderautomation.com. | ||
| 25 | 25 | ||
| 26 | - Documentation: | ||
| 27 | - http://www.easysw.com/~mike/serial/serial.html | ||
| 28 | - http://copyleft.free.fr/wordpress/index.php/libmodbus/ | 26 | + Documentation: |
| 27 | + http://www.easysw.com/~mike/serial/serial.html | ||
| 28 | + http://copyleft.free.fr/wordpress/index.php/libmodbus/ | ||
| 29 | */ | 29 | */ |
| 30 | 30 | ||
| 31 | #include <stdio.h> | 31 | #include <stdio.h> |
| @@ -72,205 +72,205 @@ const unsigned int libmodbus_version_micro = LIBMODBUS_VERSION_MICRO; | @@ -72,205 +72,205 @@ const unsigned int libmodbus_version_micro = LIBMODBUS_VERSION_MICRO; | ||
| 72 | /* This structure reduces the number of params in functions and so | 72 | /* This structure reduces the number of params in functions and so |
| 73 | * optimizes the speed of execution (~ 37%). */ | 73 | * optimizes the speed of execution (~ 37%). */ |
| 74 | typedef struct { | 74 | typedef struct { |
| 75 | - int slave; | ||
| 76 | - int function; | ||
| 77 | - int t_id; | 75 | + int slave; |
| 76 | + int function; | ||
| 77 | + int t_id; | ||
| 78 | } sft_t; | 78 | } sft_t; |
| 79 | 79 | ||
| 80 | /* Table of CRC values for high-order byte */ | 80 | /* Table of CRC values for high-order byte */ |
| 81 | static uint8_t table_crc_hi[] = { | 81 | static uint8_t table_crc_hi[] = { |
| 82 | - 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, | ||
| 83 | - 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, | ||
| 84 | - 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, | ||
| 85 | - 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, | ||
| 86 | - 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, | ||
| 87 | - 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, | ||
| 88 | - 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, | ||
| 89 | - 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, | ||
| 90 | - 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, | ||
| 91 | - 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, | ||
| 92 | - 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, | ||
| 93 | - 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, | ||
| 94 | - 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, | ||
| 95 | - 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, | ||
| 96 | - 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, | ||
| 97 | - 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, | ||
| 98 | - 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, | ||
| 99 | - 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, | ||
| 100 | - 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, | ||
| 101 | - 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, | ||
| 102 | - 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, | ||
| 103 | - 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, | ||
| 104 | - 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, | ||
| 105 | - 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, | ||
| 106 | - 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, | ||
| 107 | - 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 | 82 | + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, |
| 83 | + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, | ||
| 84 | + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, | ||
| 85 | + 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, | ||
| 86 | + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, | ||
| 87 | + 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, | ||
| 88 | + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, | ||
| 89 | + 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, | ||
| 90 | + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, | ||
| 91 | + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, | ||
| 92 | + 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, | ||
| 93 | + 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, | ||
| 94 | + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, | ||
| 95 | + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, | ||
| 96 | + 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, | ||
| 97 | + 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, | ||
| 98 | + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, | ||
| 99 | + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, | ||
| 100 | + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, | ||
| 101 | + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, | ||
| 102 | + 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, | ||
| 103 | + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, | ||
| 104 | + 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, | ||
| 105 | + 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, | ||
| 106 | + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, | ||
| 107 | + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40 | ||
| 108 | }; | 108 | }; |
| 109 | 109 | ||
| 110 | /* Table of CRC values for low-order byte */ | 110 | /* Table of CRC values for low-order byte */ |
| 111 | static uint8_t table_crc_lo[] = { | 111 | static uint8_t table_crc_lo[] = { |
| 112 | - 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, | ||
| 113 | - 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, | ||
| 114 | - 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, | ||
| 115 | - 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, | ||
| 116 | - 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, | ||
| 117 | - 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, | ||
| 118 | - 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, | ||
| 119 | - 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, | ||
| 120 | - 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, | ||
| 121 | - 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, | ||
| 122 | - 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, | ||
| 123 | - 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, | ||
| 124 | - 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, | ||
| 125 | - 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, | ||
| 126 | - 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, | ||
| 127 | - 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, | ||
| 128 | - 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, | ||
| 129 | - 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, | ||
| 130 | - 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, | ||
| 131 | - 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, | ||
| 132 | - 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, | ||
| 133 | - 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, | ||
| 134 | - 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, | ||
| 135 | - 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, | ||
| 136 | - 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, | ||
| 137 | - 0x43, 0x83, 0x41, 0x81, 0x80, 0x40 | 112 | + 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, |
| 113 | + 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, | ||
| 114 | + 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, | ||
| 115 | + 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, | ||
| 116 | + 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, | ||
| 117 | + 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3, | ||
| 118 | + 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, | ||
| 119 | + 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, | ||
| 120 | + 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, | ||
| 121 | + 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, | ||
| 122 | + 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, | ||
| 123 | + 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, | ||
| 124 | + 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, | ||
| 125 | + 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, | ||
| 126 | + 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, | ||
| 127 | + 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, | ||
| 128 | + 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E, | ||
| 129 | + 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, | ||
| 130 | + 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, | ||
| 131 | + 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, | ||
| 132 | + 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, | ||
| 133 | + 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, | ||
| 134 | + 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, | ||
| 135 | + 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C, | ||
| 136 | + 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, | ||
| 137 | + 0x43, 0x83, 0x41, 0x81, 0x80, 0x40 | ||
| 138 | }; | 138 | }; |
| 139 | 139 | ||
| 140 | static const int TAB_HEADER_LENGTH[2] = { | 140 | static const int TAB_HEADER_LENGTH[2] = { |
| 141 | - HEADER_LENGTH_RTU, | ||
| 142 | - HEADER_LENGTH_TCP | 141 | + HEADER_LENGTH_RTU, |
| 142 | + HEADER_LENGTH_TCP | ||
| 143 | }; | 143 | }; |
| 144 | 144 | ||
| 145 | static const int TAB_CHECKSUM_LENGTH[2] = { | 145 | static const int TAB_CHECKSUM_LENGTH[2] = { |
| 146 | - CHECKSUM_LENGTH_RTU, | ||
| 147 | - CHECKSUM_LENGTH_TCP | 146 | + CHECKSUM_LENGTH_RTU, |
| 147 | + CHECKSUM_LENGTH_TCP | ||
| 148 | }; | 148 | }; |
| 149 | 149 | ||
| 150 | static const int TAB_MAX_ADU_LENGTH[2] = { | 150 | static const int TAB_MAX_ADU_LENGTH[2] = { |
| 151 | - MAX_ADU_LENGTH_RTU, | ||
| 152 | - MAX_ADU_LENGTH_TCP, | 151 | + MAX_ADU_LENGTH_RTU, |
| 152 | + MAX_ADU_LENGTH_TCP, | ||
| 153 | }; | 153 | }; |
| 154 | 154 | ||
| 155 | const char *modbus_strerror(int errnum) { | 155 | const char *modbus_strerror(int errnum) { |
| 156 | - switch (errnum) { | ||
| 157 | - case EMBXILFUN: | ||
| 158 | - return "Illegal function"; | ||
| 159 | - case EMBXILADD: | ||
| 160 | - return "Illegal data address"; | ||
| 161 | - case EMBXILVAL: | ||
| 162 | - return "Illegal data value"; | ||
| 163 | - case EMBXSFAIL: | ||
| 164 | - return "Slave device or server failure"; | ||
| 165 | - case EMBXACK: | ||
| 166 | - return "Acknowledge"; | ||
| 167 | - case EMBXSBUSY: | ||
| 168 | - return "Slave device or server is busy"; | ||
| 169 | - case EMBXNACK: | ||
| 170 | - return "Negative acknowledge"; | ||
| 171 | - case EMBXMEMPAR: | ||
| 172 | - return "Memory parity error"; | ||
| 173 | - case EMBXGPATH: | ||
| 174 | - return "Gateway path unavailable"; | ||
| 175 | - case EMBXGTAR: | ||
| 176 | - return "Target device failed to respond"; | ||
| 177 | - case EMBBADCRC: | ||
| 178 | - return "Invalid CRC"; | ||
| 179 | - case EMBBADDATA: | ||
| 180 | - return "Invalid data"; | ||
| 181 | - case EMBBADEXC: | ||
| 182 | - return "Invalid exception code"; | ||
| 183 | - case EMBMDATA: | ||
| 184 | - return "Too many data"; | ||
| 185 | - default: | ||
| 186 | - return strerror(errnum); | ||
| 187 | - } | 156 | + switch (errnum) { |
| 157 | + case EMBXILFUN: | ||
| 158 | + return "Illegal function"; | ||
| 159 | + case EMBXILADD: | ||
| 160 | + return "Illegal data address"; | ||
| 161 | + case EMBXILVAL: | ||
| 162 | + return "Illegal data value"; | ||
| 163 | + case EMBXSFAIL: | ||
| 164 | + return "Slave device or server failure"; | ||
| 165 | + case EMBXACK: | ||
| 166 | + return "Acknowledge"; | ||
| 167 | + case EMBXSBUSY: | ||
| 168 | + return "Slave device or server is busy"; | ||
| 169 | + case EMBXNACK: | ||
| 170 | + return "Negative acknowledge"; | ||
| 171 | + case EMBXMEMPAR: | ||
| 172 | + return "Memory parity error"; | ||
| 173 | + case EMBXGPATH: | ||
| 174 | + return "Gateway path unavailable"; | ||
| 175 | + case EMBXGTAR: | ||
| 176 | + return "Target device failed to respond"; | ||
| 177 | + case EMBBADCRC: | ||
| 178 | + return "Invalid CRC"; | ||
| 179 | + case EMBBADDATA: | ||
| 180 | + return "Invalid data"; | ||
| 181 | + case EMBBADEXC: | ||
| 182 | + return "Invalid exception code"; | ||
| 183 | + case EMBMDATA: | ||
| 184 | + return "Too many data"; | ||
| 185 | + default: | ||
| 186 | + return strerror(errnum); | ||
| 187 | + } | ||
| 188 | } | 188 | } |
| 189 | 189 | ||
| 190 | static void error_print(modbus_param_t *mb_param, const char *context) | 190 | static void error_print(modbus_param_t *mb_param, const char *context) |
| 191 | { | 191 | { |
| 192 | - if (mb_param->debug) { | ||
| 193 | - fprintf(stderr, "ERROR %s", modbus_strerror(errno)); | ||
| 194 | - if (context != NULL) { | ||
| 195 | - fprintf(stderr, ": %s\n", context); | ||
| 196 | - } else { | ||
| 197 | - fprintf(stderr, "\n"); | ||
| 198 | - } | 192 | + if (mb_param->debug) { |
| 193 | + fprintf(stderr, "ERROR %s", modbus_strerror(errno)); | ||
| 194 | + if (context != NULL) { | ||
| 195 | + fprintf(stderr, ": %s\n", context); | ||
| 196 | + } else { | ||
| 197 | + fprintf(stderr, "\n"); | ||
| 199 | } | 198 | } |
| 199 | + } | ||
| 200 | } | 200 | } |
| 201 | 201 | ||
| 202 | int modbus_flush(modbus_param_t *mb_param) | 202 | int modbus_flush(modbus_param_t *mb_param) |
| 203 | { | 203 | { |
| 204 | - int rc; | 204 | + int rc; |
| 205 | 205 | ||
| 206 | - if (mb_param->type_com == RTU) { | ||
| 207 | - rc = tcflush(mb_param->fd, TCIOFLUSH); | ||
| 208 | - } else { | ||
| 209 | - do { | ||
| 210 | - /* Extract the garbage from the socket */ | ||
| 211 | - char devnull[MAX_ADU_LENGTH_TCP]; | 206 | + if (mb_param->type_com == RTU) { |
| 207 | + rc = tcflush(mb_param->fd, TCIOFLUSH); | ||
| 208 | + } else { | ||
| 209 | + do { | ||
| 210 | + /* Extract the garbage from the socket */ | ||
| 211 | + char devnull[MAX_ADU_LENGTH_TCP]; | ||
| 212 | #if (!HAVE_DECL___CYGWIN__) | 212 | #if (!HAVE_DECL___CYGWIN__) |
| 213 | - rc = recv(mb_param->fd, devnull, MAX_ADU_LENGTH_TCP, MSG_DONTWAIT); | 213 | + rc = recv(mb_param->fd, devnull, MAX_ADU_LENGTH_TCP, MSG_DONTWAIT); |
| 214 | #else | 214 | #else |
| 215 | - /* On Cygwin, it's a bit more complicated to not wait */ | ||
| 216 | - fd_set rfds; | ||
| 217 | - struct timeval tv; | ||
| 218 | - | ||
| 219 | - tv.tv_sec = 0; | ||
| 220 | - tv.tv_usec = 0; | ||
| 221 | - FD_ZERO(&rfds); | ||
| 222 | - FD_SET(mb_param->fd, &rfds); | ||
| 223 | - rc = select(mb_param->fd+1, &rfds, NULL, NULL, &tv); | ||
| 224 | - if (rc == -1) { | ||
| 225 | - return -1; | ||
| 226 | - } | ||
| 227 | - | ||
| 228 | - rc = recv(mb_param->fd, devnull, MAX_ADU_LENGTH_TCP, 0); | 215 | + /* On Cygwin, it's a bit more complicated to not wait */ |
| 216 | + fd_set rfds; | ||
| 217 | + struct timeval tv; | ||
| 218 | + | ||
| 219 | + tv.tv_sec = 0; | ||
| 220 | + tv.tv_usec = 0; | ||
| 221 | + FD_ZERO(&rfds); | ||
| 222 | + FD_SET(mb_param->fd, &rfds); | ||
| 223 | + rc = select(mb_param->fd+1, &rfds, NULL, NULL, &tv); | ||
| 224 | + if (rc == -1) { | ||
| 225 | + return -1; | ||
| 226 | + } | ||
| 227 | + | ||
| 228 | + rc = recv(mb_param->fd, devnull, MAX_ADU_LENGTH_TCP, 0); | ||
| 229 | #endif | 229 | #endif |
| 230 | - if (mb_param->debug && rc != -1) { | ||
| 231 | - printf("\n%d bytes flushed\n", rc); | ||
| 232 | - } | ||
| 233 | - } while (rc > 0); | ||
| 234 | - } | 230 | + if (mb_param->debug && rc != -1) { |
| 231 | + printf("\n%d bytes flushed\n", rc); | ||
| 232 | + } | ||
| 233 | + } while (rc > 0); | ||
| 234 | + } | ||
| 235 | 235 | ||
| 236 | - return rc; | 236 | + return rc; |
| 237 | } | 237 | } |
| 238 | 238 | ||
| 239 | /* Computes the length of the expected response */ | 239 | /* Computes the length of the expected response */ |
| 240 | static unsigned int compute_response_length(modbus_param_t *mb_param, | 240 | static unsigned int compute_response_length(modbus_param_t *mb_param, |
| 241 | uint8_t *query) | 241 | uint8_t *query) |
| 242 | { | 242 | { |
| 243 | - int length; | ||
| 244 | - int offset; | ||
| 245 | - | ||
| 246 | - offset = TAB_HEADER_LENGTH[mb_param->type_com]; | ||
| 247 | - | ||
| 248 | - switch (query[offset]) { | ||
| 249 | - case FC_READ_COIL_STATUS: | ||
| 250 | - case FC_READ_INPUT_STATUS: { | ||
| 251 | - /* Header + nb values (code from force_multiple_coils) */ | ||
| 252 | - int nb = (query[offset + 3] << 8) | query[offset + 4]; | ||
| 253 | - length = 2 + (nb / 8) + ((nb % 8) ? 1 : 0); | ||
| 254 | - } | ||
| 255 | - break; | ||
| 256 | - case FC_READ_HOLDING_REGISTERS: | ||
| 257 | - case FC_READ_INPUT_REGISTERS: | ||
| 258 | - /* Header + 2 * nb values */ | ||
| 259 | - length = 2 + 2 * (query[offset + 3] << 8 | | ||
| 260 | - query[offset + 4]); | ||
| 261 | - break; | ||
| 262 | - case FC_READ_EXCEPTION_STATUS: | ||
| 263 | - length = 3; | ||
| 264 | - break; | ||
| 265 | - case FC_REPORT_SLAVE_ID: | ||
| 266 | - /* The response is device specific (the header provides the | ||
| 267 | - length) */ | ||
| 268 | - return MSG_LENGTH_UNDEFINED; | ||
| 269 | - default: | ||
| 270 | - length = 5; | ||
| 271 | - } | ||
| 272 | - | ||
| 273 | - return length + offset + TAB_CHECKSUM_LENGTH[mb_param->type_com]; | 243 | + int length; |
| 244 | + int offset; | ||
| 245 | + | ||
| 246 | + offset = TAB_HEADER_LENGTH[mb_param->type_com]; | ||
| 247 | + | ||
| 248 | + switch (query[offset]) { | ||
| 249 | + case FC_READ_COIL_STATUS: | ||
| 250 | + case FC_READ_INPUT_STATUS: { | ||
| 251 | + /* Header + nb values (code from force_multiple_coils) */ | ||
| 252 | + int nb = (query[offset + 3] << 8) | query[offset + 4]; | ||
| 253 | + length = 2 + (nb / 8) + ((nb % 8) ? 1 : 0); | ||
| 254 | + } | ||
| 255 | + break; | ||
| 256 | + case FC_READ_HOLDING_REGISTERS: | ||
| 257 | + case FC_READ_INPUT_REGISTERS: | ||
| 258 | + /* Header + 2 * nb values */ | ||
| 259 | + length = 2 + 2 * (query[offset + 3] << 8 | | ||
| 260 | + query[offset + 4]); | ||
| 261 | + break; | ||
| 262 | + case FC_READ_EXCEPTION_STATUS: | ||
| 263 | + length = 3; | ||
| 264 | + break; | ||
| 265 | + case FC_REPORT_SLAVE_ID: | ||
| 266 | + /* The response is device specific (the header provides the | ||
| 267 | + length) */ | ||
| 268 | + return MSG_LENGTH_UNDEFINED; | ||
| 269 | + default: | ||
| 270 | + length = 5; | ||
| 271 | + } | ||
| 272 | + | ||
| 273 | + return length + offset + TAB_CHECKSUM_LENGTH[mb_param->type_com]; | ||
| 274 | } | 274 | } |
| 275 | 275 | ||
| 276 | /* Builds a RTU query header */ | 276 | /* Builds a RTU query header */ |
| @@ -278,14 +278,14 @@ static int build_query_basis_rtu(int slave, int function, | @@ -278,14 +278,14 @@ static int build_query_basis_rtu(int slave, int function, | ||
| 278 | int start_addr, int nb, | 278 | int start_addr, int nb, |
| 279 | uint8_t *query) | 279 | uint8_t *query) |
| 280 | { | 280 | { |
| 281 | - query[0] = slave; | ||
| 282 | - query[1] = function; | ||
| 283 | - query[2] = start_addr >> 8; | ||
| 284 | - query[3] = start_addr & 0x00ff; | ||
| 285 | - query[4] = nb >> 8; | ||
| 286 | - query[5] = nb & 0x00ff; | ||
| 287 | - | ||
| 288 | - return PRESET_QUERY_LENGTH_RTU; | 281 | + query[0] = slave; |
| 282 | + query[1] = function; | ||
| 283 | + query[2] = start_addr >> 8; | ||
| 284 | + query[3] = start_addr & 0x00ff; | ||
| 285 | + query[4] = nb >> 8; | ||
| 286 | + query[5] = nb & 0x00ff; | ||
| 287 | + | ||
| 288 | + return PRESET_QUERY_LENGTH_RTU; | ||
| 289 | } | 289 | } |
| 290 | 290 | ||
| 291 | /* Builds a TCP query header */ | 291 | /* Builds a TCP query header */ |
| @@ -294,105 +294,105 @@ static int build_query_basis_tcp(int slave, int function, | @@ -294,105 +294,105 @@ static int build_query_basis_tcp(int slave, int function, | ||
| 294 | uint8_t *query) | 294 | uint8_t *query) |
| 295 | { | 295 | { |
| 296 | 296 | ||
| 297 | - /* Extract from MODBUS Messaging on TCP/IP Implementation Guide V1.0b | ||
| 298 | - (page 23/46): | ||
| 299 | - The transaction identifier is used to associate the future response | ||
| 300 | - with the request. So, at a time, on a TCP connection, this identifier | ||
| 301 | - must be unique. */ | ||
| 302 | - static uint16_t t_id = 0; | ||
| 303 | - | ||
| 304 | - /* Transaction ID */ | ||
| 305 | - if (t_id < UINT16_MAX) | ||
| 306 | - t_id++; | ||
| 307 | - else | ||
| 308 | - t_id = 0; | ||
| 309 | - query[0] = t_id >> 8; | ||
| 310 | - query[1] = t_id & 0x00ff; | ||
| 311 | - | ||
| 312 | - /* Protocol Modbus */ | ||
| 313 | - query[2] = 0; | ||
| 314 | - query[3] = 0; | ||
| 315 | - | ||
| 316 | - /* Length will be defined later by set_query_length_tcp at offsets 4 | ||
| 317 | - and 5 */ | ||
| 318 | - | ||
| 319 | - query[6] = slave; | ||
| 320 | - query[7] = function; | ||
| 321 | - query[8] = start_addr >> 8; | ||
| 322 | - query[9] = start_addr & 0x00ff; | ||
| 323 | - query[10] = nb >> 8; | ||
| 324 | - query[11] = nb & 0x00ff; | ||
| 325 | - | ||
| 326 | - return PRESET_QUERY_LENGTH_TCP; | 297 | + /* Extract from MODBUS Messaging on TCP/IP Implementation Guide V1.0b |
| 298 | + (page 23/46): | ||
| 299 | + The transaction identifier is used to associate the future response | ||
| 300 | + with the request. So, at a time, on a TCP connection, this identifier | ||
| 301 | + must be unique. */ | ||
| 302 | + static uint16_t t_id = 0; | ||
| 303 | + | ||
| 304 | + /* Transaction ID */ | ||
| 305 | + if (t_id < UINT16_MAX) | ||
| 306 | + t_id++; | ||
| 307 | + else | ||
| 308 | + t_id = 0; | ||
| 309 | + query[0] = t_id >> 8; | ||
| 310 | + query[1] = t_id & 0x00ff; | ||
| 311 | + | ||
| 312 | + /* Protocol Modbus */ | ||
| 313 | + query[2] = 0; | ||
| 314 | + query[3] = 0; | ||
| 315 | + | ||
| 316 | + /* Length will be defined later by set_query_length_tcp at offsets 4 | ||
| 317 | + and 5 */ | ||
| 318 | + | ||
| 319 | + query[6] = slave; | ||
| 320 | + query[7] = function; | ||
| 321 | + query[8] = start_addr >> 8; | ||
| 322 | + query[9] = start_addr & 0x00ff; | ||
| 323 | + query[10] = nb >> 8; | ||
| 324 | + query[11] = nb & 0x00ff; | ||
| 325 | + | ||
| 326 | + return PRESET_QUERY_LENGTH_TCP; | ||
| 327 | } | 327 | } |
| 328 | 328 | ||
| 329 | static int build_query_basis(modbus_param_t *mb_param, int slave, | 329 | static int build_query_basis(modbus_param_t *mb_param, int slave, |
| 330 | int function, int start_addr, | 330 | int function, int start_addr, |
| 331 | int nb, uint8_t *query) | 331 | int nb, uint8_t *query) |
| 332 | { | 332 | { |
| 333 | - if (mb_param->type_com == RTU) | ||
| 334 | - return build_query_basis_rtu(slave, function, | ||
| 335 | - start_addr, nb, query); | ||
| 336 | - else | ||
| 337 | - return build_query_basis_tcp(slave, function, | ||
| 338 | - start_addr, nb, query); | 333 | + if (mb_param->type_com == RTU) |
| 334 | + return build_query_basis_rtu(slave, function, | ||
| 335 | + start_addr, nb, query); | ||
| 336 | + else | ||
| 337 | + return build_query_basis_tcp(slave, function, | ||
| 338 | + start_addr, nb, query); | ||
| 339 | } | 339 | } |
| 340 | 340 | ||
| 341 | /* Builds a RTU response header */ | 341 | /* Builds a RTU response header */ |
| 342 | static int build_response_basis_rtu(sft_t *sft, uint8_t *response) | 342 | static int build_response_basis_rtu(sft_t *sft, uint8_t *response) |
| 343 | { | 343 | { |
| 344 | - response[0] = sft->slave; | ||
| 345 | - response[1] = sft->function; | 344 | + response[0] = sft->slave; |
| 345 | + response[1] = sft->function; | ||
| 346 | 346 | ||
| 347 | - return PRESET_RESPONSE_LENGTH_RTU; | 347 | + return PRESET_RESPONSE_LENGTH_RTU; |
| 348 | } | 348 | } |
| 349 | 349 | ||
| 350 | /* Builds a TCP response header */ | 350 | /* Builds a TCP response header */ |
| 351 | static int build_response_basis_tcp(sft_t *sft, uint8_t *response) | 351 | static int build_response_basis_tcp(sft_t *sft, uint8_t *response) |
| 352 | { | 352 | { |
| 353 | - /* Extract from MODBUS Messaging on TCP/IP Implementation | ||
| 354 | - Guide V1.0b (page 23/46): | ||
| 355 | - The transaction identifier is used to associate the future | ||
| 356 | - response with the request. */ | ||
| 357 | - response[0] = sft->t_id >> 8; | ||
| 358 | - response[1] = sft->t_id & 0x00ff; | 353 | + /* Extract from MODBUS Messaging on TCP/IP Implementation |
| 354 | + Guide V1.0b (page 23/46): | ||
| 355 | + The transaction identifier is used to associate the future | ||
| 356 | + response with the request. */ | ||
| 357 | + response[0] = sft->t_id >> 8; | ||
| 358 | + response[1] = sft->t_id & 0x00ff; | ||
| 359 | 359 | ||
| 360 | - /* Protocol Modbus */ | ||
| 361 | - response[2] = 0; | ||
| 362 | - response[3] = 0; | 360 | + /* Protocol Modbus */ |
| 361 | + response[2] = 0; | ||
| 362 | + response[3] = 0; | ||
| 363 | 363 | ||
| 364 | - /* Length will be set later by modbus_send (4 and 5) */ | 364 | + /* Length will be set later by modbus_send (4 and 5) */ |
| 365 | 365 | ||
| 366 | - response[6] = 0xFF; | ||
| 367 | - response[7] = sft->function; | 366 | + response[6] = 0xFF; |
| 367 | + response[7] = sft->function; | ||
| 368 | 368 | ||
| 369 | - return PRESET_RESPONSE_LENGTH_TCP; | 369 | + return PRESET_RESPONSE_LENGTH_TCP; |
| 370 | } | 370 | } |
| 371 | 371 | ||
| 372 | static int build_response_basis(modbus_param_t *mb_param, sft_t *sft, | 372 | static int build_response_basis(modbus_param_t *mb_param, sft_t *sft, |
| 373 | uint8_t *response) | 373 | uint8_t *response) |
| 374 | { | 374 | { |
| 375 | - if (mb_param->type_com == RTU) | ||
| 376 | - return build_response_basis_rtu(sft, response); | ||
| 377 | - else | ||
| 378 | - return build_response_basis_tcp(sft, response); | 375 | + if (mb_param->type_com == RTU) |
| 376 | + return build_response_basis_rtu(sft, response); | ||
| 377 | + else | ||
| 378 | + return build_response_basis_tcp(sft, response); | ||
| 379 | } | 379 | } |
| 380 | 380 | ||
| 381 | /* Fast CRC */ | 381 | /* Fast CRC */ |
| 382 | static uint16_t crc16(uint8_t *buffer, uint16_t buffer_length) | 382 | static uint16_t crc16(uint8_t *buffer, uint16_t buffer_length) |
| 383 | { | 383 | { |
| 384 | - uint8_t crc_hi = 0xFF; /* high CRC byte initialized */ | ||
| 385 | - uint8_t crc_lo = 0xFF; /* low CRC byte initialized */ | ||
| 386 | - unsigned int i; /* will index into CRC lookup */ | ||
| 387 | - | ||
| 388 | - /* pass through message buffer */ | ||
| 389 | - while (buffer_length--) { | ||
| 390 | - i = crc_hi ^ *buffer++; /* calculate the CRC */ | ||
| 391 | - crc_hi = crc_lo ^ table_crc_hi[i]; | ||
| 392 | - crc_lo = table_crc_lo[i]; | ||
| 393 | - } | ||
| 394 | - | ||
| 395 | - return (crc_hi << 8 | crc_lo); | 384 | + uint8_t crc_hi = 0xFF; /* high CRC byte initialized */ |
| 385 | + uint8_t crc_lo = 0xFF; /* low CRC byte initialized */ | ||
| 386 | + unsigned int i; /* will index into CRC lookup */ | ||
| 387 | + | ||
| 388 | + /* pass through message buffer */ | ||
| 389 | + while (buffer_length--) { | ||
| 390 | + i = crc_hi ^ *buffer++; /* calculate the CRC */ | ||
| 391 | + crc_hi = crc_lo ^ table_crc_hi[i]; | ||
| 392 | + crc_lo = table_crc_lo[i]; | ||
| 393 | + } | ||
| 394 | + | ||
| 395 | + return (crc_hi << 8 | crc_lo); | ||
| 396 | } | 396 | } |
| 397 | 397 | ||
| 398 | /* The check_crc16 function shall return the message length if the CRC is | 398 | /* The check_crc16 function shall return the message length if the CRC is |
| @@ -401,164 +401,163 @@ static int check_crc16(modbus_param_t *mb_param, | @@ -401,164 +401,163 @@ static int check_crc16(modbus_param_t *mb_param, | ||
| 401 | uint8_t *msg, | 401 | uint8_t *msg, |
| 402 | const int msg_length) | 402 | const int msg_length) |
| 403 | { | 403 | { |
| 404 | - uint16_t crc_calculated; | ||
| 405 | - uint16_t crc_received; | 404 | + uint16_t crc_calculated; |
| 405 | + uint16_t crc_received; | ||
| 406 | 406 | ||
| 407 | - crc_calculated = crc16(msg, msg_length - 2); | ||
| 408 | - crc_received = (msg[msg_length - 2] << 8) | msg[msg_length - 1]; | 407 | + crc_calculated = crc16(msg, msg_length - 2); |
| 408 | + crc_received = (msg[msg_length - 2] << 8) | msg[msg_length - 1]; | ||
| 409 | 409 | ||
| 410 | - /* Check CRC of msg */ | ||
| 411 | - if (crc_calculated == crc_received) { | ||
| 412 | - return msg_length; | ||
| 413 | - } else { | ||
| 414 | - if (mb_param->debug) { | ||
| 415 | - fprintf(stderr, "ERROR CRC received %0X != CRC calculated %0X\n", | ||
| 416 | - crc_received, crc_calculated); | ||
| 417 | - } | ||
| 418 | - if (mb_param->error_recovery) { | ||
| 419 | - modbus_flush(mb_param); | ||
| 420 | - } | ||
| 421 | - errno = EMBBADCRC; | ||
| 422 | - return -1; | 410 | + /* Check CRC of msg */ |
| 411 | + if (crc_calculated == crc_received) { | ||
| 412 | + return msg_length; | ||
| 413 | + } else { | ||
| 414 | + if (mb_param->debug) { | ||
| 415 | + fprintf(stderr, "ERROR CRC received %0X != CRC calculated %0X\n", | ||
| 416 | + crc_received, crc_calculated); | ||
| 417 | + } | ||
| 418 | + if (mb_param->error_recovery) { | ||
| 419 | + modbus_flush(mb_param); | ||
| 423 | } | 420 | } |
| 421 | + errno = EMBBADCRC; | ||
| 422 | + return -1; | ||
| 423 | + } | ||
| 424 | } | 424 | } |
| 425 | 425 | ||
| 426 | /* Sends a query/response over a serial or a TCP communication */ | 426 | /* Sends a query/response over a serial or a TCP communication */ |
| 427 | static int modbus_send(modbus_param_t *mb_param, uint8_t *query, | 427 | static int modbus_send(modbus_param_t *mb_param, uint8_t *query, |
| 428 | int query_length) | 428 | int query_length) |
| 429 | { | 429 | { |
| 430 | - int rc; | ||
| 431 | - uint16_t s_crc; | ||
| 432 | - int i; | ||
| 433 | - | ||
| 434 | - if (mb_param->type_com == RTU) { | ||
| 435 | - s_crc = crc16(query, query_length); | ||
| 436 | - query[query_length++] = s_crc >> 8; | ||
| 437 | - query[query_length++] = s_crc & 0x00FF; | ||
| 438 | - } else { | ||
| 439 | - /* Substract the header length to the message length */ | ||
| 440 | - int mbap_length = query_length - 6; | ||
| 441 | - | ||
| 442 | - query[4] = mbap_length >> 8; | ||
| 443 | - query[5] = mbap_length & 0x00FF; | ||
| 444 | - } | 430 | + int rc; |
| 431 | + uint16_t s_crc; | ||
| 432 | + int i; | ||
| 433 | + | ||
| 434 | + if (mb_param->type_com == RTU) { | ||
| 435 | + s_crc = crc16(query, query_length); | ||
| 436 | + query[query_length++] = s_crc >> 8; | ||
| 437 | + query[query_length++] = s_crc & 0x00FF; | ||
| 438 | + } else { | ||
| 439 | + /* Substract the header length to the message length */ | ||
| 440 | + int mbap_length = query_length - 6; | ||
| 441 | + | ||
| 442 | + query[4] = mbap_length >> 8; | ||
| 443 | + query[5] = mbap_length & 0x00FF; | ||
| 444 | + } | ||
| 445 | + | ||
| 446 | + if (mb_param->debug) { | ||
| 447 | + for (i = 0; i < query_length; i++) | ||
| 448 | + printf("[%.2X]", query[i]); | ||
| 449 | + printf("\n"); | ||
| 450 | + } | ||
| 451 | + | ||
| 452 | + /* In recovery mode, the write command will be issued until to be | ||
| 453 | + successful! Disabled by default. | ||
| 454 | + */ | ||
| 455 | + do { | ||
| 456 | + if (mb_param->type_com == RTU) | ||
| 457 | + rc = write(mb_param->fd, query, query_length); | ||
| 458 | + else | ||
| 459 | + /* MSG_NOSIGNAL | ||
| 460 | + Requests not to send SIGPIPE on errors on stream oriented | ||
| 461 | + sockets when the other end breaks the connection. The EPIPE | ||
| 462 | + error is still returned. */ | ||
| 463 | + rc = send(mb_param->fd, query, query_length, MSG_NOSIGNAL); | ||
| 445 | 464 | ||
| 446 | - if (mb_param->debug) { | ||
| 447 | - for (i = 0; i < query_length; i++) | ||
| 448 | - printf("[%.2X]", query[i]); | ||
| 449 | - printf("\n"); | 465 | + if (rc == -1) { |
| 466 | + error_print(mb_param, NULL); | ||
| 467 | + if (mb_param->error_recovery && | ||
| 468 | + (errno == EBADF || errno == ECONNRESET || errno == EPIPE)) { | ||
| 469 | + modbus_close(mb_param); | ||
| 470 | + modbus_connect(mb_param); | ||
| 471 | + } | ||
| 450 | } | 472 | } |
| 473 | + } while (mb_param->error_recovery && rc == -1); | ||
| 451 | 474 | ||
| 452 | - /* In recovery mode, the write command will be issued until to be | ||
| 453 | - successful! Disabled by default. | ||
| 454 | - */ | ||
| 455 | - do { | ||
| 456 | - if (mb_param->type_com == RTU) | ||
| 457 | - rc = write(mb_param->fd, query, query_length); | ||
| 458 | - else | ||
| 459 | - /* MSG_NOSIGNAL | ||
| 460 | - Requests not to send SIGPIPE on errors on stream oriented | ||
| 461 | - sockets when the other end breaks the connection. The EPIPE | ||
| 462 | - error is still returned. */ | ||
| 463 | - rc = send(mb_param->fd, query, query_length, MSG_NOSIGNAL); | ||
| 464 | - | ||
| 465 | - if (rc == -1) { | ||
| 466 | - error_print(mb_param, NULL); | ||
| 467 | - if (mb_param->error_recovery && (errno == EBADF || | ||
| 468 | - errno == ECONNRESET || errno == EPIPE)) { | ||
| 469 | - modbus_close(mb_param); | ||
| 470 | - modbus_connect(mb_param); | ||
| 471 | - } | ||
| 472 | - } | ||
| 473 | - } while (mb_param->error_recovery && rc == -1); | 475 | + if (rc > 0 && rc != query_length) { |
| 476 | + errno = EMBBADDATA; | ||
| 477 | + return -1; | ||
| 478 | + } | ||
| 474 | 479 | ||
| 475 | - if (rc > 0 && rc != query_length) { | ||
| 476 | - errno = EMBBADDATA; | ||
| 477 | - return -1; | ||
| 478 | - } | ||
| 479 | - | ||
| 480 | - return rc; | 480 | + return rc; |
| 481 | } | 481 | } |
| 482 | 482 | ||
| 483 | /* Computes the length of the header following the function code */ | 483 | /* Computes the length of the header following the function code */ |
| 484 | static uint8_t compute_query_length_header(int function) | 484 | static uint8_t compute_query_length_header(int function) |
| 485 | { | 485 | { |
| 486 | - int length; | ||
| 487 | - | ||
| 488 | - if (function <= FC_FORCE_SINGLE_COIL || | ||
| 489 | - function == FC_PRESET_SINGLE_REGISTER) | ||
| 490 | - /* Read and single write */ | ||
| 491 | - length = 4; | ||
| 492 | - else if (function == FC_FORCE_MULTIPLE_COILS || | ||
| 493 | - function == FC_PRESET_MULTIPLE_REGISTERS) | ||
| 494 | - /* Multiple write */ | ||
| 495 | - length = 5; | ||
| 496 | - else if (function == FC_REPORT_SLAVE_ID) | ||
| 497 | - length = 1; | ||
| 498 | - else | ||
| 499 | - length = 0; | ||
| 500 | - | ||
| 501 | - return length; | 486 | + int length; |
| 487 | + | ||
| 488 | + if (function <= FC_FORCE_SINGLE_COIL || | ||
| 489 | + function == FC_PRESET_SINGLE_REGISTER) | ||
| 490 | + /* Read and single write */ | ||
| 491 | + length = 4; | ||
| 492 | + else if (function == FC_FORCE_MULTIPLE_COILS || | ||
| 493 | + function == FC_PRESET_MULTIPLE_REGISTERS) | ||
| 494 | + /* Multiple write */ | ||
| 495 | + length = 5; | ||
| 496 | + else if (function == FC_REPORT_SLAVE_ID) | ||
| 497 | + length = 1; | ||
| 498 | + else | ||
| 499 | + length = 0; | ||
| 500 | + | ||
| 501 | + return length; | ||
| 502 | } | 502 | } |
| 503 | 503 | ||
| 504 | /* Computes the length of the data to write in the query */ | 504 | /* Computes the length of the data to write in the query */ |
| 505 | static int compute_query_length_data(modbus_param_t *mb_param, uint8_t *msg) | 505 | static int compute_query_length_data(modbus_param_t *mb_param, uint8_t *msg) |
| 506 | { | 506 | { |
| 507 | - int function = msg[TAB_HEADER_LENGTH[mb_param->type_com]]; | ||
| 508 | - int length; | ||
| 509 | - | ||
| 510 | - if (function == FC_FORCE_MULTIPLE_COILS || | ||
| 511 | - function == FC_PRESET_MULTIPLE_REGISTERS) | ||
| 512 | - length = msg[TAB_HEADER_LENGTH[mb_param->type_com] + 5]; | ||
| 513 | - else if (function == FC_REPORT_SLAVE_ID) | ||
| 514 | - length = msg[TAB_HEADER_LENGTH[mb_param->type_com] + 1]; | ||
| 515 | - else | ||
| 516 | - length = 0; | 507 | + int function = msg[TAB_HEADER_LENGTH[mb_param->type_com]]; |
| 508 | + int length; | ||
| 517 | 509 | ||
| 518 | - length += TAB_CHECKSUM_LENGTH[mb_param->type_com]; | 510 | + if (function == FC_FORCE_MULTIPLE_COILS || |
| 511 | + function == FC_PRESET_MULTIPLE_REGISTERS) | ||
| 512 | + length = msg[TAB_HEADER_LENGTH[mb_param->type_com] + 5]; | ||
| 513 | + else if (function == FC_REPORT_SLAVE_ID) | ||
| 514 | + length = msg[TAB_HEADER_LENGTH[mb_param->type_com] + 1]; | ||
| 515 | + else | ||
| 516 | + length = 0; | ||
| 519 | 517 | ||
| 520 | - return length; | 518 | + length += TAB_CHECKSUM_LENGTH[mb_param->type_com]; |
| 519 | + | ||
| 520 | + return length; | ||
| 521 | } | 521 | } |
| 522 | 522 | ||
| 523 | -#define WAIT_DATA() \ | ||
| 524 | -{ \ | ||
| 525 | - while ((s_rc = select(mb_param->fd+1, &rfds, NULL, NULL, &tv)) == -1) { \ | ||
| 526 | - if (errno == EINTR) { \ | ||
| 527 | - if (mb_param->debug) { \ | ||
| 528 | - fprintf(stderr, \ | ||
| 529 | - "A non blocked signal was caught\n"); \ | ||
| 530 | - } \ | ||
| 531 | - /* Necessary after an error */ \ | ||
| 532 | - FD_ZERO(&rfds); \ | ||
| 533 | - FD_SET(mb_param->fd, &rfds); \ | ||
| 534 | - } else { \ | ||
| 535 | - error_print(mb_param, "select"); \ | ||
| 536 | - if (mb_param->error_recovery && (errno == EBADF)) { \ | ||
| 537 | - modbus_close(mb_param); \ | ||
| 538 | - modbus_connect(mb_param); \ | ||
| 539 | - errno = EBADF; \ | ||
| 540 | - return -1; \ | ||
| 541 | - } else { \ | ||
| 542 | - return -1; \ | ||
| 543 | - } \ | ||
| 544 | - } \ | ||
| 545 | - } \ | ||
| 546 | - \ | ||
| 547 | - if (s_rc == 0) { \ | ||
| 548 | - /* Timeout */ \ | ||
| 549 | - if (msg_length == (TAB_HEADER_LENGTH[mb_param->type_com] + 2 + \ | ||
| 550 | - TAB_CHECKSUM_LENGTH[mb_param->type_com])) { \ | ||
| 551 | - /* Optimization allowed because exception response is \ | ||
| 552 | - the smallest trame in modbus protocol (3) so always \ | ||
| 553 | - raise a timeout error. \ | ||
| 554 | - Temporary error before exception analyze. */ \ | ||
| 555 | - errno = EMBUNKEXC; \ | ||
| 556 | - } else { \ | ||
| 557 | - errno = ETIMEDOUT; \ | ||
| 558 | - error_print(mb_param, "select"); \ | ||
| 559 | - } \ | ||
| 560 | - return -1; \ | ||
| 561 | - } \ | 523 | +#define WAIT_DATA() { \ |
| 524 | + while ((s_rc = select(mb_param->fd+1, &rfds, NULL, NULL, &tv)) == -1) { \ | ||
| 525 | + if (errno == EINTR) { \ | ||
| 526 | + if (mb_param->debug) { \ | ||
| 527 | + fprintf(stderr, \ | ||
| 528 | + "A non blocked signal was caught\n"); \ | ||
| 529 | + } \ | ||
| 530 | + /* Necessary after an error */ \ | ||
| 531 | + FD_ZERO(&rfds); \ | ||
| 532 | + FD_SET(mb_param->fd, &rfds); \ | ||
| 533 | + } else { \ | ||
| 534 | + error_print(mb_param, "select"); \ | ||
| 535 | + if (mb_param->error_recovery && (errno == EBADF)) { \ | ||
| 536 | + modbus_close(mb_param); \ | ||
| 537 | + modbus_connect(mb_param); \ | ||
| 538 | + errno = EBADF; \ | ||
| 539 | + return -1; \ | ||
| 540 | + } else { \ | ||
| 541 | + return -1; \ | ||
| 542 | + } \ | ||
| 543 | + } \ | ||
| 544 | + } \ | ||
| 545 | + \ | ||
| 546 | + if (s_rc == 0) { \ | ||
| 547 | + /* Timeout */ \ | ||
| 548 | + if (msg_length == (TAB_HEADER_LENGTH[mb_param->type_com] + 2 + \ | ||
| 549 | + TAB_CHECKSUM_LENGTH[mb_param->type_com])) { \ | ||
| 550 | + /* Optimization allowed because exception response is \ | ||
| 551 | + the smallest trame in modbus protocol (3) so always \ | ||
| 552 | + raise a timeout error. \ | ||
| 553 | + Temporary error before exception analyze. */ \ | ||
| 554 | + errno = EMBUNKEXC; \ | ||
| 555 | + } else { \ | ||
| 556 | + errno = ETIMEDOUT; \ | ||
| 557 | + error_print(mb_param, "select"); \ | ||
| 558 | + } \ | ||
| 559 | + return -1; \ | ||
| 560 | + } \ | ||
| 562 | } | 561 | } |
| 563 | 562 | ||
| 564 | /* Waits a reply from a modbus slave or a query from a modbus master. | 563 | /* Waits a reply from a modbus slave or a query from a modbus master. |
| @@ -580,144 +579,144 @@ static int receive_msg(modbus_param_t *mb_param, | @@ -580,144 +579,144 @@ static int receive_msg(modbus_param_t *mb_param, | ||
| 580 | int msg_length_computed, | 579 | int msg_length_computed, |
| 581 | uint8_t *msg) | 580 | uint8_t *msg) |
| 582 | { | 581 | { |
| 583 | - int s_rc; | ||
| 584 | - int read_rc; | ||
| 585 | - fd_set rfds; | ||
| 586 | - struct timeval tv; | ||
| 587 | - int length_to_read; | ||
| 588 | - uint8_t *p_msg; | ||
| 589 | - enum { FUNCTION, BYTE, COMPLETE }; | ||
| 590 | - int state; | ||
| 591 | - | ||
| 592 | - int msg_length = 0; | 582 | + int s_rc; |
| 583 | + int read_rc; | ||
| 584 | + fd_set rfds; | ||
| 585 | + struct timeval tv; | ||
| 586 | + int length_to_read; | ||
| 587 | + uint8_t *p_msg; | ||
| 588 | + enum { FUNCTION, BYTE, COMPLETE }; | ||
| 589 | + int state; | ||
| 590 | + | ||
| 591 | + int msg_length = 0; | ||
| 592 | + | ||
| 593 | + if (mb_param->debug) { | ||
| 594 | + if (msg_length_computed == MSG_LENGTH_UNDEFINED) | ||
| 595 | + printf("Waiting for a message...\n"); | ||
| 596 | + else | ||
| 597 | + printf("Waiting for a message (%d bytes)...\n", | ||
| 598 | + msg_length_computed); | ||
| 599 | + } | ||
| 600 | + | ||
| 601 | + /* Add a file descriptor to the set */ | ||
| 602 | + FD_ZERO(&rfds); | ||
| 603 | + FD_SET(mb_param->fd, &rfds); | ||
| 604 | + | ||
| 605 | + if (msg_length_computed == MSG_LENGTH_UNDEFINED) { | ||
| 606 | + /* Wait for a message */ | ||
| 607 | + tv.tv_sec = 60; | ||
| 608 | + tv.tv_usec = 0; | ||
| 609 | + | ||
| 610 | + /* The message length is undefined (query receiving) so | ||
| 611 | + * we need to analyse the message step by step. | ||
| 612 | + * At the first step, we want to reach the function | ||
| 613 | + * code because all packets have that information. */ | ||
| 614 | + state = FUNCTION; | ||
| 615 | + msg_length_computed = TAB_HEADER_LENGTH[mb_param->type_com] + 1; | ||
| 616 | + } else { | ||
| 617 | + tv.tv_sec = mb_param->timeout_begin.tv_sec; | ||
| 618 | + tv.tv_usec = mb_param->timeout_begin.tv_usec; | ||
| 619 | + state = COMPLETE; | ||
| 620 | + } | ||
| 621 | + | ||
| 622 | + length_to_read = msg_length_computed; | ||
| 623 | + | ||
| 624 | + s_rc = 0; | ||
| 625 | + WAIT_DATA(); | ||
| 626 | + | ||
| 627 | + p_msg = msg; | ||
| 628 | + while (s_rc) { | ||
| 629 | + if (mb_param->type_com == RTU) | ||
| 630 | + read_rc = read(mb_param->fd, p_msg, length_to_read); | ||
| 631 | + else | ||
| 632 | + read_rc = recv(mb_param->fd, p_msg, length_to_read, 0); | ||
| 593 | 633 | ||
| 594 | - if (mb_param->debug) { | ||
| 595 | - if (msg_length_computed == MSG_LENGTH_UNDEFINED) | ||
| 596 | - printf("Waiting for a message...\n"); | ||
| 597 | - else | ||
| 598 | - printf("Waiting for a message (%d bytes)...\n", | ||
| 599 | - msg_length_computed); | 634 | + if (read_rc == 0) { |
| 635 | + errno = ECONNRESET; | ||
| 636 | + read_rc = -1; | ||
| 600 | } | 637 | } |
| 601 | 638 | ||
| 602 | - /* Add a file descriptor to the set */ | ||
| 603 | - FD_ZERO(&rfds); | ||
| 604 | - FD_SET(mb_param->fd, &rfds); | ||
| 605 | - | ||
| 606 | - if (msg_length_computed == MSG_LENGTH_UNDEFINED) { | ||
| 607 | - /* Wait for a message */ | ||
| 608 | - tv.tv_sec = 60; | ||
| 609 | - tv.tv_usec = 0; | ||
| 610 | - | ||
| 611 | - /* The message length is undefined (query receiving) so | ||
| 612 | - * we need to analyse the message step by step. | ||
| 613 | - * At the first step, we want to reach the function | ||
| 614 | - * code because all packets have that information. */ | ||
| 615 | - state = FUNCTION; | ||
| 616 | - msg_length_computed = TAB_HEADER_LENGTH[mb_param->type_com] + 1; | ||
| 617 | - } else { | ||
| 618 | - tv.tv_sec = mb_param->timeout_begin.tv_sec; | ||
| 619 | - tv.tv_usec = mb_param->timeout_begin.tv_usec; | ||
| 620 | - state = COMPLETE; | 639 | + if (read_rc == -1) { |
| 640 | + error_print(mb_param, "read"); | ||
| 641 | + if (mb_param->error_recovery && (errno == ECONNRESET || | ||
| 642 | + errno == ECONNREFUSED)) { | ||
| 643 | + modbus_close(mb_param); | ||
| 644 | + modbus_connect(mb_param); | ||
| 645 | + /* Could be removed by previous calls */ | ||
| 646 | + errno = ECONNRESET; | ||
| 647 | + return -1; | ||
| 648 | + } | ||
| 649 | + return -1; | ||
| 621 | } | 650 | } |
| 622 | 651 | ||
| 623 | - length_to_read = msg_length_computed; | ||
| 624 | - | ||
| 625 | - s_rc = 0; | ||
| 626 | - WAIT_DATA(); | ||
| 627 | - | ||
| 628 | - p_msg = msg; | ||
| 629 | - while (s_rc) { | ||
| 630 | - if (mb_param->type_com == RTU) | ||
| 631 | - read_rc = read(mb_param->fd, p_msg, length_to_read); | ||
| 632 | - else | ||
| 633 | - read_rc = recv(mb_param->fd, p_msg, length_to_read, 0); | ||
| 634 | - | ||
| 635 | - if (read_rc == 0) { | ||
| 636 | - errno = ECONNRESET; | ||
| 637 | - read_rc = -1; | ||
| 638 | - } | ||
| 639 | - | ||
| 640 | - if (read_rc == -1) { | ||
| 641 | - error_print(mb_param, "read"); | ||
| 642 | - if (mb_param->error_recovery && (errno == ECONNRESET || | ||
| 643 | - errno == ECONNREFUSED)) { | ||
| 644 | - modbus_close(mb_param); | ||
| 645 | - modbus_connect(mb_param); | ||
| 646 | - /* Could be removed by previous calls */ | ||
| 647 | - errno = ECONNRESET; | ||
| 648 | - return -1; | ||
| 649 | - } | ||
| 650 | - return -1; | ||
| 651 | - } | ||
| 652 | - | ||
| 653 | - /* Sums bytes received */ | ||
| 654 | - msg_length += read_rc; | 652 | + /* Sums bytes received */ |
| 653 | + msg_length += read_rc; | ||
| 655 | 654 | ||
| 656 | - /* Display the hex code of each character received */ | ||
| 657 | - if (mb_param->debug) { | ||
| 658 | - int i; | ||
| 659 | - for (i=0; i < read_rc; i++) | ||
| 660 | - printf("<%.2X>", p_msg[i]); | ||
| 661 | - } | ||
| 662 | - | ||
| 663 | - if (msg_length < msg_length_computed) { | ||
| 664 | - /* Message incomplete */ | ||
| 665 | - length_to_read = msg_length_computed - msg_length; | ||
| 666 | - } else { | ||
| 667 | - switch (state) { | ||
| 668 | - case FUNCTION: | ||
| 669 | - /* Function code position */ | ||
| 670 | - length_to_read = compute_query_length_header( | ||
| 671 | - msg[TAB_HEADER_LENGTH[mb_param->type_com]]); | ||
| 672 | - msg_length_computed += length_to_read; | ||
| 673 | - /* It's useless to check the value of | ||
| 674 | - msg_length_computed in this case (only | ||
| 675 | - defined values are used). */ | ||
| 676 | - state = BYTE; | ||
| 677 | - break; | ||
| 678 | - case BYTE: | ||
| 679 | - length_to_read = compute_query_length_data(mb_param, msg); | ||
| 680 | - msg_length_computed += length_to_read; | ||
| 681 | - if (msg_length_computed > TAB_MAX_ADU_LENGTH[mb_param->type_com]) { | ||
| 682 | - errno = EMBBADDATA; | ||
| 683 | - error_print(mb_param, "too many data"); | ||
| 684 | - return -1; | ||
| 685 | - } | ||
| 686 | - state = COMPLETE; | ||
| 687 | - break; | ||
| 688 | - case COMPLETE: | ||
| 689 | - length_to_read = 0; | ||
| 690 | - break; | ||
| 691 | - } | ||
| 692 | - } | ||
| 693 | - | ||
| 694 | - /* Moves the pointer to receive other data */ | ||
| 695 | - p_msg = &(p_msg[read_rc]); | ||
| 696 | - | ||
| 697 | - if (length_to_read > 0) { | ||
| 698 | - /* If no character at the buffer wait | ||
| 699 | - TIME_OUT_END_OF_TRAME before to generate an error. */ | ||
| 700 | - tv.tv_sec = mb_param->timeout_end.tv_sec; | ||
| 701 | - tv.tv_usec = mb_param->timeout_end.tv_usec; | 655 | + /* Display the hex code of each character received */ |
| 656 | + if (mb_param->debug) { | ||
| 657 | + int i; | ||
| 658 | + for (i=0; i < read_rc; i++) | ||
| 659 | + printf("<%.2X>", p_msg[i]); | ||
| 660 | + } | ||
| 702 | 661 | ||
| 703 | - WAIT_DATA(); | ||
| 704 | - } else { | ||
| 705 | - /* All chars are received */ | ||
| 706 | - s_rc = FALSE; | 662 | + if (msg_length < msg_length_computed) { |
| 663 | + /* Message incomplete */ | ||
| 664 | + length_to_read = msg_length_computed - msg_length; | ||
| 665 | + } else { | ||
| 666 | + switch (state) { | ||
| 667 | + case FUNCTION: | ||
| 668 | + /* Function code position */ | ||
| 669 | + length_to_read = compute_query_length_header( | ||
| 670 | + msg[TAB_HEADER_LENGTH[mb_param->type_com]]); | ||
| 671 | + msg_length_computed += length_to_read; | ||
| 672 | + /* It's useless to check the value of | ||
| 673 | + msg_length_computed in this case (only | ||
| 674 | + defined values are used). */ | ||
| 675 | + state = BYTE; | ||
| 676 | + break; | ||
| 677 | + case BYTE: | ||
| 678 | + length_to_read = compute_query_length_data(mb_param, msg); | ||
| 679 | + msg_length_computed += length_to_read; | ||
| 680 | + if (msg_length_computed > TAB_MAX_ADU_LENGTH[mb_param->type_com]) { | ||
| 681 | + errno = EMBBADDATA; | ||
| 682 | + error_print(mb_param, "too many data"); | ||
| 683 | + return -1; | ||
| 707 | } | 684 | } |
| 685 | + state = COMPLETE; | ||
| 686 | + break; | ||
| 687 | + case COMPLETE: | ||
| 688 | + length_to_read = 0; | ||
| 689 | + break; | ||
| 690 | + } | ||
| 708 | } | 691 | } |
| 709 | 692 | ||
| 710 | - if (mb_param->debug) | ||
| 711 | - printf("\n"); | 693 | + /* Moves the pointer to receive other data */ |
| 694 | + p_msg = &(p_msg[read_rc]); | ||
| 712 | 695 | ||
| 713 | - if (mb_param->type_com == RTU) { | ||
| 714 | - /* Returns msg_length on success and a negative value on | ||
| 715 | - failure */ | ||
| 716 | - return check_crc16(mb_param, msg, msg_length); | 696 | + if (length_to_read > 0) { |
| 697 | + /* If no character at the buffer wait | ||
| 698 | + TIME_OUT_END_OF_TRAME before to generate an error. */ | ||
| 699 | + tv.tv_sec = mb_param->timeout_end.tv_sec; | ||
| 700 | + tv.tv_usec = mb_param->timeout_end.tv_usec; | ||
| 701 | + | ||
| 702 | + WAIT_DATA(); | ||
| 717 | } else { | 703 | } else { |
| 718 | - /* OK */ | ||
| 719 | - return msg_length; | ||
| 720 | - } | 704 | + /* All chars are received */ |
| 705 | + s_rc = FALSE; | ||
| 706 | + } | ||
| 707 | + } | ||
| 708 | + | ||
| 709 | + if (mb_param->debug) | ||
| 710 | + printf("\n"); | ||
| 711 | + | ||
| 712 | + if (mb_param->type_com == RTU) { | ||
| 713 | + /* Returns msg_length on success and a negative value on | ||
| 714 | + failure */ | ||
| 715 | + return check_crc16(mb_param, msg, msg_length); | ||
| 716 | + } else { | ||
| 717 | + /* OK */ | ||
| 718 | + return msg_length; | ||
| 719 | + } | ||
| 721 | } | 720 | } |
| 722 | 721 | ||
| 723 | /* Listens for any query from a modbus master in TCP, requires the socket file | 722 | /* Listens for any query from a modbus master in TCP, requires the socket file |
| @@ -728,12 +727,12 @@ static int receive_msg(modbus_param_t *mb_param, | @@ -728,12 +727,12 @@ static int receive_msg(modbus_param_t *mb_param, | ||
| 728 | byte length if successul. Otherwise, it shall return -1 and errno is set. */ | 727 | byte length if successul. Otherwise, it shall return -1 and errno is set. */ |
| 729 | int modbus_slave_receive(modbus_param_t *mb_param, int sockfd, uint8_t *query) | 728 | int modbus_slave_receive(modbus_param_t *mb_param, int sockfd, uint8_t *query) |
| 730 | { | 729 | { |
| 731 | - if (sockfd != -1) { | ||
| 732 | - mb_param->fd = sockfd; | ||
| 733 | - } | 730 | + if (sockfd != -1) { |
| 731 | + mb_param->fd = sockfd; | ||
| 732 | + } | ||
| 734 | 733 | ||
| 735 | - /* The length of the query to receive isn't known. */ | ||
| 736 | - return receive_msg(mb_param, MSG_LENGTH_UNDEFINED, query); | 734 | + /* The length of the query to receive isn't known. */ |
| 735 | + return receive_msg(mb_param, MSG_LENGTH_UNDEFINED, query); | ||
| 737 | } | 736 | } |
| 738 | 737 | ||
| 739 | /* Receives the response and checks values (and checksum in RTU). | 738 | /* Receives the response and checks values (and checksum in RTU). |
| @@ -747,127 +746,127 @@ static int modbus_receive(modbus_param_t *mb_param, | @@ -747,127 +746,127 @@ static int modbus_receive(modbus_param_t *mb_param, | ||
| 747 | uint8_t *query, | 746 | uint8_t *query, |
| 748 | uint8_t *response) | 747 | uint8_t *response) |
| 749 | { | 748 | { |
| 750 | - int rc; | ||
| 751 | - int response_length_computed; | ||
| 752 | - int offset = TAB_HEADER_LENGTH[mb_param->type_com]; | ||
| 753 | - | ||
| 754 | - response_length_computed = compute_response_length(mb_param, query); | ||
| 755 | - rc = receive_msg(mb_param, response_length_computed, response); | ||
| 756 | - if (rc != -1) { | ||
| 757 | - /* GOOD RESPONSE */ | ||
| 758 | - int query_nb_value; | ||
| 759 | - int response_nb_value; | ||
| 760 | - | ||
| 761 | - /* The number of values is returned if it's corresponding | ||
| 762 | - * to the query */ | ||
| 763 | - switch (response[offset]) { | ||
| 764 | - case FC_READ_COIL_STATUS: | ||
| 765 | - case FC_READ_INPUT_STATUS: | ||
| 766 | - /* Read functions, 8 values in a byte (nb | ||
| 767 | - * of values in the query and byte count in | ||
| 768 | - * the response. */ | ||
| 769 | - query_nb_value = (query[offset + 3] << 8) + query[offset + 4]; | ||
| 770 | - query_nb_value = (query_nb_value / 8) + ((query_nb_value % 8) ? 1 : 0); | ||
| 771 | - response_nb_value = response[offset + 1]; | ||
| 772 | - break; | ||
| 773 | - case FC_READ_HOLDING_REGISTERS: | ||
| 774 | - case FC_READ_INPUT_REGISTERS: | ||
| 775 | - /* Read functions 1 value = 2 bytes */ | ||
| 776 | - query_nb_value = (query[offset + 3] << 8) + query[offset + 4]; | ||
| 777 | - response_nb_value = (response[offset + 1] / 2); | ||
| 778 | - break; | ||
| 779 | - case FC_FORCE_MULTIPLE_COILS: | ||
| 780 | - case FC_PRESET_MULTIPLE_REGISTERS: | ||
| 781 | - /* N Write functions */ | ||
| 782 | - query_nb_value = (query[offset + 3] << 8) + query[offset + 4]; | ||
| 783 | - response_nb_value = (response[offset + 3] << 8) | response[offset + 4]; | ||
| 784 | - break; | ||
| 785 | - case FC_REPORT_SLAVE_ID: | ||
| 786 | - /* Report slave ID (bytes received) */ | ||
| 787 | - query_nb_value = response_nb_value = rc; | ||
| 788 | - break; | ||
| 789 | - default: | ||
| 790 | - /* 1 Write functions & others */ | ||
| 791 | - query_nb_value = response_nb_value = 1; | ||
| 792 | - } | 749 | + int rc; |
| 750 | + int response_length_computed; | ||
| 751 | + int offset = TAB_HEADER_LENGTH[mb_param->type_com]; | ||
| 752 | + | ||
| 753 | + response_length_computed = compute_response_length(mb_param, query); | ||
| 754 | + rc = receive_msg(mb_param, response_length_computed, response); | ||
| 755 | + if (rc != -1) { | ||
| 756 | + /* GOOD RESPONSE */ | ||
| 757 | + int query_nb_value; | ||
| 758 | + int response_nb_value; | ||
| 759 | + | ||
| 760 | + /* The number of values is returned if it's corresponding | ||
| 761 | + * to the query */ | ||
| 762 | + switch (response[offset]) { | ||
| 763 | + case FC_READ_COIL_STATUS: | ||
| 764 | + case FC_READ_INPUT_STATUS: | ||
| 765 | + /* Read functions, 8 values in a byte (nb | ||
| 766 | + * of values in the query and byte count in | ||
| 767 | + * the response. */ | ||
| 768 | + query_nb_value = (query[offset + 3] << 8) + query[offset + 4]; | ||
| 769 | + query_nb_value = (query_nb_value / 8) + ((query_nb_value % 8) ? 1 : 0); | ||
| 770 | + response_nb_value = response[offset + 1]; | ||
| 771 | + break; | ||
| 772 | + case FC_READ_HOLDING_REGISTERS: | ||
| 773 | + case FC_READ_INPUT_REGISTERS: | ||
| 774 | + /* Read functions 1 value = 2 bytes */ | ||
| 775 | + query_nb_value = (query[offset + 3] << 8) + query[offset + 4]; | ||
| 776 | + response_nb_value = (response[offset + 1] / 2); | ||
| 777 | + break; | ||
| 778 | + case FC_FORCE_MULTIPLE_COILS: | ||
| 779 | + case FC_PRESET_MULTIPLE_REGISTERS: | ||
| 780 | + /* N Write functions */ | ||
| 781 | + query_nb_value = (query[offset + 3] << 8) + query[offset + 4]; | ||
| 782 | + response_nb_value = (response[offset + 3] << 8) | response[offset + 4]; | ||
| 783 | + break; | ||
| 784 | + case FC_REPORT_SLAVE_ID: | ||
| 785 | + /* Report slave ID (bytes received) */ | ||
| 786 | + query_nb_value = response_nb_value = rc; | ||
| 787 | + break; | ||
| 788 | + default: | ||
| 789 | + /* 1 Write functions & others */ | ||
| 790 | + query_nb_value = response_nb_value = 1; | ||
| 791 | + } | ||
| 793 | 792 | ||
| 794 | - if (query_nb_value == response_nb_value) { | ||
| 795 | - rc = response_nb_value; | ||
| 796 | - } else { | ||
| 797 | - if (mb_param->debug) { | ||
| 798 | - fprintf(stderr, | ||
| 799 | - "Quantity not corresponding to the query (%d != %d)\n", | ||
| 800 | - response_nb_value, query_nb_value); | ||
| 801 | - } | ||
| 802 | - errno = EMBBADDATA; | ||
| 803 | - rc = -1; | ||
| 804 | - } | ||
| 805 | - } else if (errno == EMBUNKEXC) { | ||
| 806 | - /* EXCEPTION CODE RECEIVED */ | ||
| 807 | - | ||
| 808 | - /* CRC must be checked here (not done in receive_msg) */ | ||
| 809 | - if (mb_param->type_com == RTU) { | ||
| 810 | - rc = check_crc16(mb_param, response, EXCEPTION_RESPONSE_LENGTH_RTU); | ||
| 811 | - if (rc == -1) | ||
| 812 | - return -1; | ||
| 813 | - } | 793 | + if (query_nb_value == response_nb_value) { |
| 794 | + rc = response_nb_value; | ||
| 795 | + } else { | ||
| 796 | + if (mb_param->debug) { | ||
| 797 | + fprintf(stderr, | ||
| 798 | + "Quantity not corresponding to the query (%d != %d)\n", | ||
| 799 | + response_nb_value, query_nb_value); | ||
| 800 | + } | ||
| 801 | + errno = EMBBADDATA; | ||
| 802 | + rc = -1; | ||
| 803 | + } | ||
| 804 | + } else if (errno == EMBUNKEXC) { | ||
| 805 | + /* EXCEPTION CODE RECEIVED */ | ||
| 814 | 806 | ||
| 815 | - /* Check for exception response. | ||
| 816 | - 0x80 + function is stored in the exception | ||
| 817 | - response. */ | ||
| 818 | - if (0x80 + query[offset] == response[offset]) { | ||
| 819 | - int exception_code = response[offset + 1]; | ||
| 820 | - if (exception_code < MODBUS_EXCEPTION_MAX) { | ||
| 821 | - errno = MODBUS_ENOBASE + exception_code; | ||
| 822 | - } else { | ||
| 823 | - errno = EMBBADEXC; | ||
| 824 | - } | ||
| 825 | - error_print(mb_param, NULL); | ||
| 826 | - return -1; | ||
| 827 | - } | 807 | + /* CRC must be checked here (not done in receive_msg) */ |
| 808 | + if (mb_param->type_com == RTU) { | ||
| 809 | + rc = check_crc16(mb_param, response, EXCEPTION_RESPONSE_LENGTH_RTU); | ||
| 810 | + if (rc == -1) | ||
| 811 | + return -1; | ||
| 812 | + } | ||
| 813 | + | ||
| 814 | + /* Check for exception response. | ||
| 815 | + 0x80 + function is stored in the exception | ||
| 816 | + response. */ | ||
| 817 | + if (0x80 + query[offset] == response[offset]) { | ||
| 818 | + int exception_code = response[offset + 1]; | ||
| 819 | + if (exception_code < MODBUS_EXCEPTION_MAX) { | ||
| 820 | + errno = MODBUS_ENOBASE + exception_code; | ||
| 821 | + } else { | ||
| 822 | + errno = EMBBADEXC; | ||
| 823 | + } | ||
| 824 | + error_print(mb_param, NULL); | ||
| 825 | + return -1; | ||
| 828 | } | 826 | } |
| 827 | + } | ||
| 829 | 828 | ||
| 830 | - return rc; | 829 | + return rc; |
| 831 | } | 830 | } |
| 832 | 831 | ||
| 833 | static int response_io_status(int address, int nb, | 832 | static int response_io_status(int address, int nb, |
| 834 | uint8_t *tab_io_status, | 833 | uint8_t *tab_io_status, |
| 835 | uint8_t *response, int offset) | 834 | uint8_t *response, int offset) |
| 836 | { | 835 | { |
| 837 | - int shift = 0; | ||
| 838 | - int byte = 0; | ||
| 839 | - int i; | ||
| 840 | - | ||
| 841 | - for (i = address; i < address+nb; i++) { | ||
| 842 | - byte |= tab_io_status[i] << shift; | ||
| 843 | - if (shift == 7) { | ||
| 844 | - /* Byte is full */ | ||
| 845 | - response[offset++] = byte; | ||
| 846 | - byte = shift = 0; | ||
| 847 | - } else { | ||
| 848 | - shift++; | ||
| 849 | - } | 836 | + int shift = 0; |
| 837 | + int byte = 0; | ||
| 838 | + int i; | ||
| 839 | + | ||
| 840 | + for (i = address; i < address+nb; i++) { | ||
| 841 | + byte |= tab_io_status[i] << shift; | ||
| 842 | + if (shift == 7) { | ||
| 843 | + /* Byte is full */ | ||
| 844 | + response[offset++] = byte; | ||
| 845 | + byte = shift = 0; | ||
| 846 | + } else { | ||
| 847 | + shift++; | ||
| 850 | } | 848 | } |
| 849 | + } | ||
| 851 | 850 | ||
| 852 | - if (shift != 0) | ||
| 853 | - response[offset++] = byte; | 851 | + if (shift != 0) |
| 852 | + response[offset++] = byte; | ||
| 854 | 853 | ||
| 855 | - return offset; | 854 | + return offset; |
| 856 | } | 855 | } |
| 857 | 856 | ||
| 858 | /* Build the exception response */ | 857 | /* Build the exception response */ |
| 859 | static int response_exception(modbus_param_t *mb_param, sft_t *sft, | 858 | static int response_exception(modbus_param_t *mb_param, sft_t *sft, |
| 860 | int exception_code, uint8_t *response) | 859 | int exception_code, uint8_t *response) |
| 861 | { | 860 | { |
| 862 | - int response_length; | 861 | + int response_length; |
| 863 | 862 | ||
| 864 | - sft->function = sft->function + 0x80; | ||
| 865 | - response_length = build_response_basis(mb_param, sft, response); | 863 | + sft->function = sft->function + 0x80; |
| 864 | + response_length = build_response_basis(mb_param, sft, response); | ||
| 866 | 865 | ||
| 867 | - /* Positive exception code */ | ||
| 868 | - response[response_length++] = exception_code; | 866 | + /* Positive exception code */ |
| 867 | + response[response_length++] = exception_code; | ||
| 869 | 868 | ||
| 870 | - return response_length; | 869 | + return response_length; |
| 871 | } | 870 | } |
| 872 | 871 | ||
| 873 | /* Manages the received query. | 872 | /* Manages the received query. |
| @@ -879,277 +878,277 @@ static int response_exception(modbus_param_t *mb_param, sft_t *sft, | @@ -879,277 +878,277 @@ static int response_exception(modbus_param_t *mb_param, sft_t *sft, | ||
| 879 | int modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query, | 878 | int modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query, |
| 880 | int query_length, modbus_mapping_t *mb_mapping) | 879 | int query_length, modbus_mapping_t *mb_mapping) |
| 881 | { | 880 | { |
| 882 | - int offset = TAB_HEADER_LENGTH[mb_param->type_com]; | ||
| 883 | - int slave = query[offset - 1]; | ||
| 884 | - int function = query[offset]; | ||
| 885 | - uint16_t address = (query[offset + 1] << 8) + query[offset + 2]; | ||
| 886 | - uint8_t response[MAX_MESSAGE_LENGTH]; | ||
| 887 | - int resp_length = 0; | ||
| 888 | - sft_t sft; | ||
| 889 | - | ||
| 890 | - /* Filter on the Modbus unit identifier (slave) in RTU mode */ | ||
| 891 | - if (mb_param->type_com == RTU && | ||
| 892 | - slave != mb_param->slave && slave != MODBUS_BROADCAST_ADDRESS) { | ||
| 893 | - /* Ignores the query (not for me) */ | ||
| 894 | - if (mb_param->debug) { | ||
| 895 | - printf("Request for slave %d ignored (not %d)\n", | ||
| 896 | - slave, mb_param->slave); | ||
| 897 | - } | ||
| 898 | - return 0; | 881 | + int offset = TAB_HEADER_LENGTH[mb_param->type_com]; |
| 882 | + int slave = query[offset - 1]; | ||
| 883 | + int function = query[offset]; | ||
| 884 | + uint16_t address = (query[offset + 1] << 8) + query[offset + 2]; | ||
| 885 | + uint8_t response[MAX_MESSAGE_LENGTH]; | ||
| 886 | + int resp_length = 0; | ||
| 887 | + sft_t sft; | ||
| 888 | + | ||
| 889 | + /* Filter on the Modbus unit identifier (slave) in RTU mode */ | ||
| 890 | + if (mb_param->type_com == RTU && | ||
| 891 | + slave != mb_param->slave && slave != MODBUS_BROADCAST_ADDRESS) { | ||
| 892 | + /* Ignores the query (not for me) */ | ||
| 893 | + if (mb_param->debug) { | ||
| 894 | + printf("Request for slave %d ignored (not %d)\n", | ||
| 895 | + slave, mb_param->slave); | ||
| 899 | } | 896 | } |
| 900 | - | ||
| 901 | - sft.slave = slave; | ||
| 902 | - sft.function = function; | ||
| 903 | - if (mb_param->type_com == TCP) { | ||
| 904 | - sft.t_id = (query[0] << 8) + query[1]; | 897 | + return 0; |
| 898 | + } | ||
| 899 | + | ||
| 900 | + sft.slave = slave; | ||
| 901 | + sft.function = function; | ||
| 902 | + if (mb_param->type_com == TCP) { | ||
| 903 | + sft.t_id = (query[0] << 8) + query[1]; | ||
| 904 | + } else { | ||
| 905 | + sft.t_id = 0; | ||
| 906 | + query_length -= CHECKSUM_LENGTH_RTU; | ||
| 907 | + } | ||
| 908 | + | ||
| 909 | + switch (function) { | ||
| 910 | + case FC_READ_COIL_STATUS: { | ||
| 911 | + int nb = (query[offset + 3] << 8) + query[offset + 4]; | ||
| 912 | + | ||
| 913 | + if ((address + nb) > mb_mapping->nb_coil_status) { | ||
| 914 | + if (mb_param->debug) { | ||
| 915 | + fprintf(stderr, "Illegal data address %0X in read_coil_status\n", | ||
| 916 | + address + nb); | ||
| 917 | + } | ||
| 918 | + resp_length = response_exception( | ||
| 919 | + mb_param, &sft, | ||
| 920 | + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response); | ||
| 905 | } else { | 921 | } else { |
| 906 | - sft.t_id = 0; | ||
| 907 | - query_length -= CHECKSUM_LENGTH_RTU; | ||
| 908 | - } | ||
| 909 | - | ||
| 910 | - switch (function) { | ||
| 911 | - case FC_READ_COIL_STATUS: { | ||
| 912 | - int nb = (query[offset + 3] << 8) + query[offset + 4]; | ||
| 913 | - | ||
| 914 | - if ((address + nb) > mb_mapping->nb_coil_status) { | ||
| 915 | - if (mb_param->debug) { | ||
| 916 | - fprintf(stderr, "Illegal data address %0X in read_coil_status\n", | ||
| 917 | - address + nb); | ||
| 918 | - } | ||
| 919 | - resp_length = response_exception( | ||
| 920 | - mb_param, &sft, | ||
| 921 | - MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response); | ||
| 922 | - } else { | ||
| 923 | - resp_length = build_response_basis(mb_param, &sft, response); | ||
| 924 | - response[resp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0); | ||
| 925 | - resp_length = response_io_status(address, nb, | ||
| 926 | - mb_mapping->tab_coil_status, | ||
| 927 | - response, resp_length); | ||
| 928 | - } | ||
| 929 | - } | ||
| 930 | - break; | ||
| 931 | - case FC_READ_INPUT_STATUS: { | ||
| 932 | - /* Similar to coil status (but too much arguments to use a | ||
| 933 | - * function) */ | ||
| 934 | - int nb = (query[offset + 3] << 8) + query[offset + 4]; | ||
| 935 | - | ||
| 936 | - if ((address + nb) > mb_mapping->nb_input_status) { | ||
| 937 | - if (mb_param->debug) { | ||
| 938 | - fprintf(stderr, "Illegal data address %0X in read_input_status\n", | ||
| 939 | - address + nb); | ||
| 940 | - } | ||
| 941 | - resp_length = response_exception( | ||
| 942 | - mb_param, &sft, | ||
| 943 | - MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response); | ||
| 944 | - } else { | ||
| 945 | - resp_length = build_response_basis(mb_param, &sft, response); | ||
| 946 | - response[resp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0); | ||
| 947 | - resp_length = response_io_status(address, nb, | ||
| 948 | - mb_mapping->tab_input_status, | ||
| 949 | - response, resp_length); | ||
| 950 | - } | ||
| 951 | - } | ||
| 952 | - break; | ||
| 953 | - case FC_READ_HOLDING_REGISTERS: { | ||
| 954 | - int nb = (query[offset + 3] << 8) + query[offset + 4]; | ||
| 955 | - | ||
| 956 | - if ((address + nb) > mb_mapping->nb_holding_registers) { | ||
| 957 | - if (mb_param->debug) { | ||
| 958 | - fprintf(stderr, "Illegal data address %0X in read_holding_registers\n", | ||
| 959 | - address + nb); | ||
| 960 | - } | ||
| 961 | - resp_length = response_exception( | ||
| 962 | - mb_param, &sft, | ||
| 963 | - MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response); | ||
| 964 | - } else { | ||
| 965 | - int i; | ||
| 966 | - | ||
| 967 | - resp_length = build_response_basis(mb_param, &sft, response); | ||
| 968 | - response[resp_length++] = nb << 1; | ||
| 969 | - for (i = address; i < address + nb; i++) { | ||
| 970 | - response[resp_length++] = mb_mapping->tab_holding_registers[i] >> 8; | ||
| 971 | - response[resp_length++] = mb_mapping->tab_holding_registers[i] & 0xFF; | ||
| 972 | - } | ||
| 973 | - } | ||
| 974 | - } | ||
| 975 | - break; | ||
| 976 | - case FC_READ_INPUT_REGISTERS: { | ||
| 977 | - /* Similar to holding registers (but too much arguments to use a | ||
| 978 | - * function) */ | ||
| 979 | - int nb = (query[offset + 3] << 8) + query[offset + 4]; | ||
| 980 | - | ||
| 981 | - if ((address + nb) > mb_mapping->nb_input_registers) { | ||
| 982 | - if (mb_param->debug) { | ||
| 983 | - fprintf(stderr, "Illegal data address %0X in read_input_registers\n", | ||
| 984 | - address + nb); | ||
| 985 | - } | ||
| 986 | - resp_length = response_exception( | ||
| 987 | - mb_param, &sft, | ||
| 988 | - MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response); | ||
| 989 | - } else { | ||
| 990 | - int i; | ||
| 991 | - | ||
| 992 | - resp_length = build_response_basis(mb_param, &sft, response); | ||
| 993 | - response[resp_length++] = nb << 1; | ||
| 994 | - for (i = address; i < address + nb; i++) { | ||
| 995 | - response[resp_length++] = mb_mapping->tab_input_registers[i] >> 8; | ||
| 996 | - response[resp_length++] = mb_mapping->tab_input_registers[i] & 0xFF; | ||
| 997 | - } | ||
| 998 | - } | ||
| 999 | - } | ||
| 1000 | - break; | ||
| 1001 | - case FC_FORCE_SINGLE_COIL: | ||
| 1002 | - if (address >= mb_mapping->nb_coil_status) { | ||
| 1003 | - if (mb_param->debug) { | ||
| 1004 | - fprintf(stderr, "Illegal data address %0X in force_singe_coil\n", | ||
| 1005 | - address); | ||
| 1006 | - } | ||
| 1007 | - resp_length = response_exception( | ||
| 1008 | - mb_param, &sft, | ||
| 1009 | - MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response); | ||
| 1010 | - } else { | ||
| 1011 | - int data = (query[offset + 3] << 8) + query[offset + 4]; | ||
| 1012 | - | ||
| 1013 | - if (data == 0xFF00 || data == 0x0) { | ||
| 1014 | - mb_mapping->tab_coil_status[address] = (data) ? ON : OFF; | ||
| 1015 | - | ||
| 1016 | - /* In RTU mode, the CRC is computed and added | ||
| 1017 | - to the query by modbus_send, the computed | ||
| 1018 | - CRC will be same and optimisation is | ||
| 1019 | - possible here (FIXME). */ | ||
| 1020 | - memcpy(response, query, query_length); | ||
| 1021 | - resp_length = query_length; | ||
| 1022 | - } else { | ||
| 1023 | - if (mb_param->debug) { | ||
| 1024 | - fprintf(stderr, "Illegal data value %0X in force_single_coil request at address %0X\n", | ||
| 1025 | - data, address); | ||
| 1026 | - } | ||
| 1027 | - resp_length = response_exception( | ||
| 1028 | - mb_param, &sft, | ||
| 1029 | - MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, response); | ||
| 1030 | - } | ||
| 1031 | - } | ||
| 1032 | - break; | ||
| 1033 | - case FC_PRESET_SINGLE_REGISTER: | ||
| 1034 | - if (address >= mb_mapping->nb_holding_registers) { | ||
| 1035 | - if (mb_param->debug) { | ||
| 1036 | - fprintf(stderr, "Illegal data address %0X in preset_holding_register\n", | ||
| 1037 | - address); | ||
| 1038 | - } | ||
| 1039 | - resp_length = response_exception( | ||
| 1040 | - mb_param, &sft, | ||
| 1041 | - MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response); | ||
| 1042 | - } else { | ||
| 1043 | - int data = (query[offset + 3] << 8) + query[offset + 4]; | ||
| 1044 | - | ||
| 1045 | - mb_mapping->tab_holding_registers[address] = data; | ||
| 1046 | - memcpy(response, query, query_length); | ||
| 1047 | - resp_length = query_length; | ||
| 1048 | - } | ||
| 1049 | - break; | ||
| 1050 | - case FC_FORCE_MULTIPLE_COILS: { | ||
| 1051 | - int nb = (query[offset + 3] << 8) + query[offset + 4]; | ||
| 1052 | - | ||
| 1053 | - if ((address + nb) > mb_mapping->nb_coil_status) { | ||
| 1054 | - if (mb_param->debug) { | ||
| 1055 | - fprintf(stderr, "Illegal data address %0X in force_multiple_coils\n", | ||
| 1056 | - address + nb); | ||
| 1057 | - } | ||
| 1058 | - resp_length = response_exception( | ||
| 1059 | - mb_param, &sft, | ||
| 1060 | - MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response); | ||
| 1061 | - } else { | ||
| 1062 | - /* 6 = byte count */ | ||
| 1063 | - set_bits_from_bytes(mb_mapping->tab_coil_status, address, nb, &query[offset + 6]); | ||
| 1064 | - | ||
| 1065 | - resp_length = build_response_basis(mb_param, &sft, response); | ||
| 1066 | - /* 4 to copy the coil address (2) and the quantity of coils */ | ||
| 1067 | - memcpy(response + resp_length, query + resp_length, 4); | ||
| 1068 | - resp_length += 4; | ||
| 1069 | - } | ||
| 1070 | - } | ||
| 1071 | - break; | ||
| 1072 | - case FC_PRESET_MULTIPLE_REGISTERS: { | ||
| 1073 | - int nb = (query[offset + 3] << 8) + query[offset + 4]; | ||
| 1074 | - | ||
| 1075 | - if ((address + nb) > mb_mapping->nb_holding_registers) { | ||
| 1076 | - if (mb_param->debug) { | ||
| 1077 | - fprintf(stderr, "Illegal data address %0X in preset_multiple_registers\n", | ||
| 1078 | - address + nb); | ||
| 1079 | - } | ||
| 1080 | - resp_length = response_exception( | ||
| 1081 | - mb_param, &sft, | ||
| 1082 | - MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response); | ||
| 1083 | - } else { | ||
| 1084 | - int i, j; | ||
| 1085 | - for (i = address, j = 6; i < address + nb; i++, j += 2) { | ||
| 1086 | - /* 6 and 7 = first value */ | ||
| 1087 | - mb_mapping->tab_holding_registers[i] = | ||
| 1088 | - (query[offset + j] << 8) + query[offset + j + 1]; | ||
| 1089 | - } | ||
| 1090 | - | ||
| 1091 | - resp_length = build_response_basis(mb_param, &sft, response); | ||
| 1092 | - /* 4 to copy the address (2) and the no. of registers */ | ||
| 1093 | - memcpy(response + resp_length, query + resp_length, 4); | ||
| 1094 | - resp_length += 4; | ||
| 1095 | - } | ||
| 1096 | - } | ||
| 1097 | - break; | ||
| 1098 | - case FC_READ_EXCEPTION_STATUS: | ||
| 1099 | - case FC_REPORT_SLAVE_ID: | 922 | + resp_length = build_response_basis(mb_param, &sft, response); |
| 923 | + response[resp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0); | ||
| 924 | + resp_length = response_io_status(address, nb, | ||
| 925 | + mb_mapping->tab_coil_status, | ||
| 926 | + response, resp_length); | ||
| 927 | + } | ||
| 928 | + } | ||
| 929 | + break; | ||
| 930 | + case FC_READ_INPUT_STATUS: { | ||
| 931 | + /* Similar to coil status (but too much arguments to use a | ||
| 932 | + * function) */ | ||
| 933 | + int nb = (query[offset + 3] << 8) + query[offset + 4]; | ||
| 934 | + | ||
| 935 | + if ((address + nb) > mb_mapping->nb_input_status) { | ||
| 936 | + if (mb_param->debug) { | ||
| 937 | + fprintf(stderr, "Illegal data address %0X in read_input_status\n", | ||
| 938 | + address + nb); | ||
| 939 | + } | ||
| 940 | + resp_length = response_exception( | ||
| 941 | + mb_param, &sft, | ||
| 942 | + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response); | ||
| 943 | + } else { | ||
| 944 | + resp_length = build_response_basis(mb_param, &sft, response); | ||
| 945 | + response[resp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0); | ||
| 946 | + resp_length = response_io_status(address, nb, | ||
| 947 | + mb_mapping->tab_input_status, | ||
| 948 | + response, resp_length); | ||
| 949 | + } | ||
| 950 | + } | ||
| 951 | + break; | ||
| 952 | + case FC_READ_HOLDING_REGISTERS: { | ||
| 953 | + int nb = (query[offset + 3] << 8) + query[offset + 4]; | ||
| 954 | + | ||
| 955 | + if ((address + nb) > mb_mapping->nb_holding_registers) { | ||
| 956 | + if (mb_param->debug) { | ||
| 957 | + fprintf(stderr, "Illegal data address %0X in read_holding_registers\n", | ||
| 958 | + address + nb); | ||
| 959 | + } | ||
| 960 | + resp_length = response_exception( | ||
| 961 | + mb_param, &sft, | ||
| 962 | + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response); | ||
| 963 | + } else { | ||
| 964 | + int i; | ||
| 965 | + | ||
| 966 | + resp_length = build_response_basis(mb_param, &sft, response); | ||
| 967 | + response[resp_length++] = nb << 1; | ||
| 968 | + for (i = address; i < address + nb; i++) { | ||
| 969 | + response[resp_length++] = mb_mapping->tab_holding_registers[i] >> 8; | ||
| 970 | + response[resp_length++] = mb_mapping->tab_holding_registers[i] & 0xFF; | ||
| 971 | + } | ||
| 972 | + } | ||
| 973 | + } | ||
| 974 | + break; | ||
| 975 | + case FC_READ_INPUT_REGISTERS: { | ||
| 976 | + /* Similar to holding registers (but too much arguments to use a | ||
| 977 | + * function) */ | ||
| 978 | + int nb = (query[offset + 3] << 8) + query[offset + 4]; | ||
| 979 | + | ||
| 980 | + if ((address + nb) > mb_mapping->nb_input_registers) { | ||
| 981 | + if (mb_param->debug) { | ||
| 982 | + fprintf(stderr, "Illegal data address %0X in read_input_registers\n", | ||
| 983 | + address + nb); | ||
| 984 | + } | ||
| 985 | + resp_length = response_exception( | ||
| 986 | + mb_param, &sft, | ||
| 987 | + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response); | ||
| 988 | + } else { | ||
| 989 | + int i; | ||
| 990 | + | ||
| 991 | + resp_length = build_response_basis(mb_param, &sft, response); | ||
| 992 | + response[resp_length++] = nb << 1; | ||
| 993 | + for (i = address; i < address + nb; i++) { | ||
| 994 | + response[resp_length++] = mb_mapping->tab_input_registers[i] >> 8; | ||
| 995 | + response[resp_length++] = mb_mapping->tab_input_registers[i] & 0xFF; | ||
| 996 | + } | ||
| 997 | + } | ||
| 998 | + } | ||
| 999 | + break; | ||
| 1000 | + case FC_FORCE_SINGLE_COIL: | ||
| 1001 | + if (address >= mb_mapping->nb_coil_status) { | ||
| 1002 | + if (mb_param->debug) { | ||
| 1003 | + fprintf(stderr, "Illegal data address %0X in force_singe_coil\n", | ||
| 1004 | + address); | ||
| 1005 | + } | ||
| 1006 | + resp_length = response_exception( | ||
| 1007 | + mb_param, &sft, | ||
| 1008 | + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response); | ||
| 1009 | + } else { | ||
| 1010 | + int data = (query[offset + 3] << 8) + query[offset + 4]; | ||
| 1011 | + | ||
| 1012 | + if (data == 0xFF00 || data == 0x0) { | ||
| 1013 | + mb_mapping->tab_coil_status[address] = (data) ? ON : OFF; | ||
| 1014 | + | ||
| 1015 | + /* In RTU mode, the CRC is computed and added | ||
| 1016 | + to the query by modbus_send, the computed | ||
| 1017 | + CRC will be same and optimisation is | ||
| 1018 | + possible here (FIXME). */ | ||
| 1019 | + memcpy(response, query, query_length); | ||
| 1020 | + resp_length = query_length; | ||
| 1021 | + } else { | ||
| 1100 | if (mb_param->debug) { | 1022 | if (mb_param->debug) { |
| 1101 | - fprintf(stderr, "FIXME Not implemented\n"); | 1023 | + fprintf(stderr, "Illegal data value %0X in force_single_coil request at address %0X\n", |
| 1024 | + data, address); | ||
| 1102 | } | 1025 | } |
| 1103 | - errno = ENOPROTOOPT; | ||
| 1104 | - return -1; | ||
| 1105 | - break; | ||
| 1106 | - default: | ||
| 1107 | - /* FIXME Invalid function exception */ | ||
| 1108 | - break; | 1026 | + resp_length = response_exception( |
| 1027 | + mb_param, &sft, | ||
| 1028 | + MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, response); | ||
| 1029 | + } | ||
| 1030 | + } | ||
| 1031 | + break; | ||
| 1032 | + case FC_PRESET_SINGLE_REGISTER: | ||
| 1033 | + if (address >= mb_mapping->nb_holding_registers) { | ||
| 1034 | + if (mb_param->debug) { | ||
| 1035 | + fprintf(stderr, "Illegal data address %0X in preset_holding_register\n", | ||
| 1036 | + address); | ||
| 1037 | + } | ||
| 1038 | + resp_length = response_exception( | ||
| 1039 | + mb_param, &sft, | ||
| 1040 | + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response); | ||
| 1041 | + } else { | ||
| 1042 | + int data = (query[offset + 3] << 8) + query[offset + 4]; | ||
| 1043 | + | ||
| 1044 | + mb_mapping->tab_holding_registers[address] = data; | ||
| 1045 | + memcpy(response, query, query_length); | ||
| 1046 | + resp_length = query_length; | ||
| 1047 | + } | ||
| 1048 | + break; | ||
| 1049 | + case FC_FORCE_MULTIPLE_COILS: { | ||
| 1050 | + int nb = (query[offset + 3] << 8) + query[offset + 4]; | ||
| 1051 | + | ||
| 1052 | + if ((address + nb) > mb_mapping->nb_coil_status) { | ||
| 1053 | + if (mb_param->debug) { | ||
| 1054 | + fprintf(stderr, "Illegal data address %0X in force_multiple_coils\n", | ||
| 1055 | + address + nb); | ||
| 1056 | + } | ||
| 1057 | + resp_length = response_exception( | ||
| 1058 | + mb_param, &sft, | ||
| 1059 | + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response); | ||
| 1060 | + } else { | ||
| 1061 | + /* 6 = byte count */ | ||
| 1062 | + set_bits_from_bytes(mb_mapping->tab_coil_status, address, nb, &query[offset + 6]); | ||
| 1063 | + | ||
| 1064 | + resp_length = build_response_basis(mb_param, &sft, response); | ||
| 1065 | + /* 4 to copy the coil address (2) and the quantity of coils */ | ||
| 1066 | + memcpy(response + resp_length, query + resp_length, 4); | ||
| 1067 | + resp_length += 4; | ||
| 1068 | + } | ||
| 1069 | + } | ||
| 1070 | + break; | ||
| 1071 | + case FC_PRESET_MULTIPLE_REGISTERS: { | ||
| 1072 | + int nb = (query[offset + 3] << 8) + query[offset + 4]; | ||
| 1073 | + | ||
| 1074 | + if ((address + nb) > mb_mapping->nb_holding_registers) { | ||
| 1075 | + if (mb_param->debug) { | ||
| 1076 | + fprintf(stderr, "Illegal data address %0X in preset_multiple_registers\n", | ||
| 1077 | + address + nb); | ||
| 1078 | + } | ||
| 1079 | + resp_length = response_exception( | ||
| 1080 | + mb_param, &sft, | ||
| 1081 | + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response); | ||
| 1082 | + } else { | ||
| 1083 | + int i, j; | ||
| 1084 | + for (i = address, j = 6; i < address + nb; i++, j += 2) { | ||
| 1085 | + /* 6 and 7 = first value */ | ||
| 1086 | + mb_mapping->tab_holding_registers[i] = | ||
| 1087 | + (query[offset + j] << 8) + query[offset + j + 1]; | ||
| 1088 | + } | ||
| 1089 | + | ||
| 1090 | + resp_length = build_response_basis(mb_param, &sft, response); | ||
| 1091 | + /* 4 to copy the address (2) and the no. of registers */ | ||
| 1092 | + memcpy(response + resp_length, query + resp_length, 4); | ||
| 1093 | + resp_length += 4; | ||
| 1094 | + } | ||
| 1095 | + } | ||
| 1096 | + break; | ||
| 1097 | + case FC_READ_EXCEPTION_STATUS: | ||
| 1098 | + case FC_REPORT_SLAVE_ID: | ||
| 1099 | + if (mb_param->debug) { | ||
| 1100 | + fprintf(stderr, "FIXME Not implemented\n"); | ||
| 1109 | } | 1101 | } |
| 1102 | + errno = ENOPROTOOPT; | ||
| 1103 | + return -1; | ||
| 1104 | + break; | ||
| 1105 | + default: | ||
| 1106 | + /* FIXME Invalid function exception */ | ||
| 1107 | + break; | ||
| 1108 | + } | ||
| 1110 | 1109 | ||
| 1111 | - return modbus_send(mb_param, response, resp_length); | 1110 | + return modbus_send(mb_param, response, resp_length); |
| 1112 | } | 1111 | } |
| 1113 | 1112 | ||
| 1114 | /* Reads IO status */ | 1113 | /* Reads IO status */ |
| 1115 | static int read_io_status(modbus_param_t *mb_param, int slave, int function, | 1114 | static int read_io_status(modbus_param_t *mb_param, int slave, int function, |
| 1116 | int start_addr, int nb, uint8_t *data_dest) | 1115 | int start_addr, int nb, uint8_t *data_dest) |
| 1117 | { | 1116 | { |
| 1118 | - int rc; | ||
| 1119 | - int query_length; | 1117 | + int rc; |
| 1118 | + int query_length; | ||
| 1120 | 1119 | ||
| 1121 | - uint8_t query[MIN_QUERY_LENGTH]; | ||
| 1122 | - uint8_t response[MAX_MESSAGE_LENGTH]; | 1120 | + uint8_t query[MIN_QUERY_LENGTH]; |
| 1121 | + uint8_t response[MAX_MESSAGE_LENGTH]; | ||
| 1123 | 1122 | ||
| 1124 | - query_length = build_query_basis(mb_param, slave, function, | ||
| 1125 | - start_addr, nb, query); | 1123 | + query_length = build_query_basis(mb_param, slave, function, |
| 1124 | + start_addr, nb, query); | ||
| 1126 | 1125 | ||
| 1127 | - rc = modbus_send(mb_param, query, query_length); | ||
| 1128 | - if (rc > 0) { | ||
| 1129 | - int i, temp, bit; | ||
| 1130 | - int pos = 0; | ||
| 1131 | - int offset; | ||
| 1132 | - int offset_end; | 1126 | + rc = modbus_send(mb_param, query, query_length); |
| 1127 | + if (rc > 0) { | ||
| 1128 | + int i, temp, bit; | ||
| 1129 | + int pos = 0; | ||
| 1130 | + int offset; | ||
| 1131 | + int offset_end; | ||
| 1133 | 1132 | ||
| 1134 | - rc = modbus_receive(mb_param, query, response); | ||
| 1135 | - if (rc == -1) | ||
| 1136 | - return -1; | 1133 | + rc = modbus_receive(mb_param, query, response); |
| 1134 | + if (rc == -1) | ||
| 1135 | + return -1; | ||
| 1137 | 1136 | ||
| 1138 | - offset = TAB_HEADER_LENGTH[mb_param->type_com]; | ||
| 1139 | - offset_end = offset + rc; | ||
| 1140 | - for (i = offset; i < offset_end; i++) { | ||
| 1141 | - /* Shift reg hi_byte to temp */ | ||
| 1142 | - temp = response[i + 2]; | 1137 | + offset = TAB_HEADER_LENGTH[mb_param->type_com]; |
| 1138 | + offset_end = offset + rc; | ||
| 1139 | + for (i = offset; i < offset_end; i++) { | ||
| 1140 | + /* Shift reg hi_byte to temp */ | ||
| 1141 | + temp = response[i + 2]; | ||
| 1143 | 1142 | ||
| 1144 | - for (bit = 0x01; (bit & 0xff) && (pos < nb);) { | ||
| 1145 | - data_dest[pos++] = (temp & bit) ? TRUE : FALSE; | ||
| 1146 | - bit = bit << 1; | ||
| 1147 | - } | 1143 | + for (bit = 0x01; (bit & 0xff) && (pos < nb);) { |
| 1144 | + data_dest[pos++] = (temp & bit) ? TRUE : FALSE; | ||
| 1145 | + bit = bit << 1; | ||
| 1146 | + } | ||
| 1148 | 1147 | ||
| 1149 | - } | ||
| 1150 | } | 1148 | } |
| 1149 | + } | ||
| 1151 | 1150 | ||
| 1152 | - return rc; | 1151 | + return rc; |
| 1153 | } | 1152 | } |
| 1154 | 1153 | ||
| 1155 | /* Reads the boolean status of coils and sets the array elements | 1154 | /* Reads the boolean status of coils and sets the array elements |
| @@ -1157,25 +1156,25 @@ static int read_io_status(modbus_param_t *mb_param, int slave, int function, | @@ -1157,25 +1156,25 @@ static int read_io_status(modbus_param_t *mb_param, int slave, int function, | ||
| 1157 | int read_coil_status(modbus_param_t *mb_param, int slave, int start_addr, | 1156 | int read_coil_status(modbus_param_t *mb_param, int slave, int start_addr, |
| 1158 | int nb, uint8_t *data_dest) | 1157 | int nb, uint8_t *data_dest) |
| 1159 | { | 1158 | { |
| 1160 | - int rc; | 1159 | + int rc; |
| 1161 | 1160 | ||
| 1162 | - if (nb > MAX_STATUS) { | ||
| 1163 | - if (mb_param->debug) { | ||
| 1164 | - fprintf(stderr, | ||
| 1165 | - "ERROR Too many coils status requested (%d > %d)\n", | ||
| 1166 | - nb, MAX_STATUS); | ||
| 1167 | - } | ||
| 1168 | - errno = EMBMDATA; | ||
| 1169 | - return -1; | 1161 | + if (nb > MAX_STATUS) { |
| 1162 | + if (mb_param->debug) { | ||
| 1163 | + fprintf(stderr, | ||
| 1164 | + "ERROR Too many coils status requested (%d > %d)\n", | ||
| 1165 | + nb, MAX_STATUS); | ||
| 1170 | } | 1166 | } |
| 1167 | + errno = EMBMDATA; | ||
| 1168 | + return -1; | ||
| 1169 | + } | ||
| 1171 | 1170 | ||
| 1172 | - rc = read_io_status(mb_param, slave, FC_READ_COIL_STATUS, start_addr, | ||
| 1173 | - nb, data_dest); | 1171 | + rc = read_io_status(mb_param, slave, FC_READ_COIL_STATUS, start_addr, |
| 1172 | + nb, data_dest); | ||
| 1174 | 1173 | ||
| 1175 | - if (rc == -1) | ||
| 1176 | - return -1; | ||
| 1177 | - else | ||
| 1178 | - return nb; | 1174 | + if (rc == -1) |
| 1175 | + return -1; | ||
| 1176 | + else | ||
| 1177 | + return nb; | ||
| 1179 | } | 1178 | } |
| 1180 | 1179 | ||
| 1181 | 1180 | ||
| @@ -1183,67 +1182,67 @@ int read_coil_status(modbus_param_t *mb_param, int slave, int start_addr, | @@ -1183,67 +1182,67 @@ int read_coil_status(modbus_param_t *mb_param, int slave, int start_addr, | ||
| 1183 | int read_input_status(modbus_param_t *mb_param, int slave, int start_addr, | 1182 | int read_input_status(modbus_param_t *mb_param, int slave, int start_addr, |
| 1184 | int nb, uint8_t *data_dest) | 1183 | int nb, uint8_t *data_dest) |
| 1185 | { | 1184 | { |
| 1186 | - int rc; | 1185 | + int rc; |
| 1187 | 1186 | ||
| 1188 | - if (nb > MAX_STATUS) { | ||
| 1189 | - if (mb_param->debug) { | ||
| 1190 | - fprintf(stderr, | ||
| 1191 | - "ERROR Too many input status requested (%d > %d)\n", | ||
| 1192 | - nb, MAX_STATUS); | ||
| 1193 | - } | ||
| 1194 | - errno = EMBMDATA; | ||
| 1195 | - return -1; | 1187 | + if (nb > MAX_STATUS) { |
| 1188 | + if (mb_param->debug) { | ||
| 1189 | + fprintf(stderr, | ||
| 1190 | + "ERROR Too many input status requested (%d > %d)\n", | ||
| 1191 | + nb, MAX_STATUS); | ||
| 1196 | } | 1192 | } |
| 1193 | + errno = EMBMDATA; | ||
| 1194 | + return -1; | ||
| 1195 | + } | ||
| 1197 | 1196 | ||
| 1198 | - rc = read_io_status(mb_param, slave, FC_READ_INPUT_STATUS, start_addr, | ||
| 1199 | - nb, data_dest); | 1197 | + rc = read_io_status(mb_param, slave, FC_READ_INPUT_STATUS, start_addr, |
| 1198 | + nb, data_dest); | ||
| 1200 | 1199 | ||
| 1201 | - if (rc == -1) | ||
| 1202 | - return -1; | ||
| 1203 | - else | ||
| 1204 | - return nb; | 1200 | + if (rc == -1) |
| 1201 | + return -1; | ||
| 1202 | + else | ||
| 1203 | + return nb; | ||
| 1205 | } | 1204 | } |
| 1206 | 1205 | ||
| 1207 | /* Reads the data from a modbus slave and put that data into an array */ | 1206 | /* Reads the data from a modbus slave and put that data into an array */ |
| 1208 | static int read_registers(modbus_param_t *mb_param, int slave, int function, | 1207 | static int read_registers(modbus_param_t *mb_param, int slave, int function, |
| 1209 | int start_addr, int nb, uint16_t *data_dest) | 1208 | int start_addr, int nb, uint16_t *data_dest) |
| 1210 | { | 1209 | { |
| 1211 | - int rc; | ||
| 1212 | - int query_length; | ||
| 1213 | - uint8_t query[MIN_QUERY_LENGTH]; | ||
| 1214 | - uint8_t response[MAX_MESSAGE_LENGTH]; | 1210 | + int rc; |
| 1211 | + int query_length; | ||
| 1212 | + uint8_t query[MIN_QUERY_LENGTH]; | ||
| 1213 | + uint8_t response[MAX_MESSAGE_LENGTH]; | ||
| 1215 | 1214 | ||
| 1216 | - if (nb > MAX_REGISTERS) { | ||
| 1217 | - if (mb_param->debug) { | ||
| 1218 | - fprintf(stderr, | ||
| 1219 | - "ERROR Too many holding registers requested (%d > %d)\n", | ||
| 1220 | - nb, MAX_REGISTERS); | ||
| 1221 | - } | ||
| 1222 | - errno = EMBMDATA; | ||
| 1223 | - return -1; | 1215 | + if (nb > MAX_REGISTERS) { |
| 1216 | + if (mb_param->debug) { | ||
| 1217 | + fprintf(stderr, | ||
| 1218 | + "ERROR Too many holding registers requested (%d > %d)\n", | ||
| 1219 | + nb, MAX_REGISTERS); | ||
| 1224 | } | 1220 | } |
| 1221 | + errno = EMBMDATA; | ||
| 1222 | + return -1; | ||
| 1223 | + } | ||
| 1225 | 1224 | ||
| 1226 | - query_length = build_query_basis(mb_param, slave, function, | ||
| 1227 | - start_addr, nb, query); | 1225 | + query_length = build_query_basis(mb_param, slave, function, |
| 1226 | + start_addr, nb, query); | ||
| 1228 | 1227 | ||
| 1229 | - rc = modbus_send(mb_param, query, query_length); | ||
| 1230 | - if (rc > 0) { | ||
| 1231 | - int offset; | ||
| 1232 | - int i; | 1228 | + rc = modbus_send(mb_param, query, query_length); |
| 1229 | + if (rc > 0) { | ||
| 1230 | + int offset; | ||
| 1231 | + int i; | ||
| 1233 | 1232 | ||
| 1234 | - rc = modbus_receive(mb_param, query, response); | 1233 | + rc = modbus_receive(mb_param, query, response); |
| 1235 | 1234 | ||
| 1236 | - offset = TAB_HEADER_LENGTH[mb_param->type_com]; | 1235 | + offset = TAB_HEADER_LENGTH[mb_param->type_com]; |
| 1237 | 1236 | ||
| 1238 | - /* If rc is negative, the loop is jumped ! */ | ||
| 1239 | - for (i = 0; i < rc; i++) { | ||
| 1240 | - /* shift reg hi_byte to temp OR with lo_byte */ | ||
| 1241 | - data_dest[i] = (response[offset + 2 + (i << 1)] << 8) | | ||
| 1242 | - response[offset + 3 + (i << 1)]; | ||
| 1243 | - } | 1237 | + /* If rc is negative, the loop is jumped ! */ |
| 1238 | + for (i = 0; i < rc; i++) { | ||
| 1239 | + /* shift reg hi_byte to temp OR with lo_byte */ | ||
| 1240 | + data_dest[i] = (response[offset + 2 + (i << 1)] << 8) | | ||
| 1241 | + response[offset + 3 + (i << 1)]; | ||
| 1244 | } | 1242 | } |
| 1243 | + } | ||
| 1245 | 1244 | ||
| 1246 | - return rc; | 1245 | + return rc; |
| 1247 | } | 1246 | } |
| 1248 | 1247 | ||
| 1249 | /* Reads the holding registers in a slave and put the data into an | 1248 | /* Reads the holding registers in a slave and put the data into an |
| @@ -1251,21 +1250,21 @@ static int read_registers(modbus_param_t *mb_param, int slave, int function, | @@ -1251,21 +1250,21 @@ static int read_registers(modbus_param_t *mb_param, int slave, int function, | ||
| 1251 | int read_holding_registers(modbus_param_t *mb_param, int slave, | 1250 | int read_holding_registers(modbus_param_t *mb_param, int slave, |
| 1252 | int start_addr, int nb, uint16_t *data_dest) | 1251 | int start_addr, int nb, uint16_t *data_dest) |
| 1253 | { | 1252 | { |
| 1254 | - int status; | 1253 | + int status; |
| 1255 | 1254 | ||
| 1256 | - if (nb > MAX_REGISTERS) { | ||
| 1257 | - if (mb_param->debug) { | ||
| 1258 | - fprintf(stderr, | ||
| 1259 | - "ERROR Too many holding registers requested (%d > %d)\n", | ||
| 1260 | - nb, MAX_REGISTERS); | ||
| 1261 | - } | ||
| 1262 | - errno = EMBMDATA; | ||
| 1263 | - return -1; | 1255 | + if (nb > MAX_REGISTERS) { |
| 1256 | + if (mb_param->debug) { | ||
| 1257 | + fprintf(stderr, | ||
| 1258 | + "ERROR Too many holding registers requested (%d > %d)\n", | ||
| 1259 | + nb, MAX_REGISTERS); | ||
| 1264 | } | 1260 | } |
| 1261 | + errno = EMBMDATA; | ||
| 1262 | + return -1; | ||
| 1263 | + } | ||
| 1265 | 1264 | ||
| 1266 | - status = read_registers(mb_param, slave, FC_READ_HOLDING_REGISTERS, | ||
| 1267 | - start_addr, nb, data_dest); | ||
| 1268 | - return status; | 1265 | + status = read_registers(mb_param, slave, FC_READ_HOLDING_REGISTERS, |
| 1266 | + start_addr, nb, data_dest); | ||
| 1267 | + return status; | ||
| 1269 | } | 1268 | } |
| 1270 | 1269 | ||
| 1271 | /* Reads the input registers in a slave and put the data into | 1270 | /* Reads the input registers in a slave and put the data into |
| @@ -1273,20 +1272,20 @@ int read_holding_registers(modbus_param_t *mb_param, int slave, | @@ -1273,20 +1272,20 @@ int read_holding_registers(modbus_param_t *mb_param, int slave, | ||
| 1273 | int read_input_registers(modbus_param_t *mb_param, int slave, int start_addr, | 1272 | int read_input_registers(modbus_param_t *mb_param, int slave, int start_addr, |
| 1274 | int nb, uint16_t *data_dest) | 1273 | int nb, uint16_t *data_dest) |
| 1275 | { | 1274 | { |
| 1276 | - int status; | 1275 | + int status; |
| 1277 | 1276 | ||
| 1278 | - if (nb > MAX_REGISTERS) { | ||
| 1279 | - fprintf(stderr, | ||
| 1280 | - "ERROR Too many input registers requested (%d > %d)\n", | ||
| 1281 | - nb, MAX_REGISTERS); | ||
| 1282 | - errno = EMBMDATA; | ||
| 1283 | - return -1; | ||
| 1284 | - } | 1277 | + if (nb > MAX_REGISTERS) { |
| 1278 | + fprintf(stderr, | ||
| 1279 | + "ERROR Too many input registers requested (%d > %d)\n", | ||
| 1280 | + nb, MAX_REGISTERS); | ||
| 1281 | + errno = EMBMDATA; | ||
| 1282 | + return -1; | ||
| 1283 | + } | ||
| 1285 | 1284 | ||
| 1286 | - status = read_registers(mb_param, slave, FC_READ_INPUT_REGISTERS, | ||
| 1287 | - start_addr, nb, data_dest); | 1285 | + status = read_registers(mb_param, slave, FC_READ_INPUT_REGISTERS, |
| 1286 | + start_addr, nb, data_dest); | ||
| 1288 | 1287 | ||
| 1289 | - return status; | 1288 | + return status; |
| 1290 | } | 1289 | } |
| 1291 | 1290 | ||
| 1292 | /* Sends a value to a register in a slave. | 1291 | /* Sends a value to a register in a slave. |
| @@ -1294,187 +1293,187 @@ int read_input_registers(modbus_param_t *mb_param, int slave, int start_addr, | @@ -1294,187 +1293,187 @@ int read_input_registers(modbus_param_t *mb_param, int slave, int start_addr, | ||
| 1294 | static int set_single(modbus_param_t *mb_param, int slave, int function, | 1293 | static int set_single(modbus_param_t *mb_param, int slave, int function, |
| 1295 | int addr, int value) | 1294 | int addr, int value) |
| 1296 | { | 1295 | { |
| 1297 | - int rc; | ||
| 1298 | - int query_length; | ||
| 1299 | - uint8_t query[MIN_QUERY_LENGTH]; | ||
| 1300 | - | ||
| 1301 | - query_length = build_query_basis(mb_param, slave, function, | ||
| 1302 | - addr, value, query); | ||
| 1303 | - | ||
| 1304 | - rc = modbus_send(mb_param, query, query_length); | ||
| 1305 | - if (rc > 0) { | ||
| 1306 | - /* Used by force_single_coil and | ||
| 1307 | - * preset_single_register */ | ||
| 1308 | - uint8_t response[MIN_QUERY_LENGTH]; | ||
| 1309 | - rc = modbus_receive(mb_param, query, response); | ||
| 1310 | - } | ||
| 1311 | - | ||
| 1312 | - return rc; | 1296 | + int rc; |
| 1297 | + int query_length; | ||
| 1298 | + uint8_t query[MIN_QUERY_LENGTH]; | ||
| 1299 | + | ||
| 1300 | + query_length = build_query_basis(mb_param, slave, function, | ||
| 1301 | + addr, value, query); | ||
| 1302 | + | ||
| 1303 | + rc = modbus_send(mb_param, query, query_length); | ||
| 1304 | + if (rc > 0) { | ||
| 1305 | + /* Used by force_single_coil and | ||
| 1306 | + * preset_single_register */ | ||
| 1307 | + uint8_t response[MIN_QUERY_LENGTH]; | ||
| 1308 | + rc = modbus_receive(mb_param, query, response); | ||
| 1309 | + } | ||
| 1310 | + | ||
| 1311 | + return rc; | ||
| 1313 | } | 1312 | } |
| 1314 | 1313 | ||
| 1315 | /* Turns ON or OFF a single coil in the slave device */ | 1314 | /* Turns ON or OFF a single coil in the slave device */ |
| 1316 | int force_single_coil(modbus_param_t *mb_param, int slave, int coil_addr, int state) | 1315 | int force_single_coil(modbus_param_t *mb_param, int slave, int coil_addr, int state) |
| 1317 | { | 1316 | { |
| 1318 | - int status; | 1317 | + int status; |
| 1319 | 1318 | ||
| 1320 | - if (state) | ||
| 1321 | - state = 0xFF00; | 1319 | + if (state) |
| 1320 | + state = 0xFF00; | ||
| 1322 | 1321 | ||
| 1323 | - status = set_single(mb_param, slave, FC_FORCE_SINGLE_COIL, | ||
| 1324 | - coil_addr, state); | 1322 | + status = set_single(mb_param, slave, FC_FORCE_SINGLE_COIL, |
| 1323 | + coil_addr, state); | ||
| 1325 | 1324 | ||
| 1326 | - return status; | 1325 | + return status; |
| 1327 | } | 1326 | } |
| 1328 | 1327 | ||
| 1329 | /* Sets a value in one holding register in the slave device */ | 1328 | /* Sets a value in one holding register in the slave device */ |
| 1330 | int preset_single_register(modbus_param_t *mb_param, int slave, int reg_addr, | 1329 | int preset_single_register(modbus_param_t *mb_param, int slave, int reg_addr, |
| 1331 | int value) | 1330 | int value) |
| 1332 | { | 1331 | { |
| 1333 | - int status; | 1332 | + int status; |
| 1334 | 1333 | ||
| 1335 | - status = set_single(mb_param, slave, FC_PRESET_SINGLE_REGISTER, | ||
| 1336 | - reg_addr, value); | 1334 | + status = set_single(mb_param, slave, FC_PRESET_SINGLE_REGISTER, |
| 1335 | + reg_addr, value); | ||
| 1337 | 1336 | ||
| 1338 | - return status; | 1337 | + return status; |
| 1339 | } | 1338 | } |
| 1340 | 1339 | ||
| 1341 | /* Sets/resets the coils in the slave from an array in argument */ | 1340 | /* Sets/resets the coils in the slave from an array in argument */ |
| 1342 | int force_multiple_coils(modbus_param_t *mb_param, int slave, int start_addr, | 1341 | int force_multiple_coils(modbus_param_t *mb_param, int slave, int start_addr, |
| 1343 | int nb, const uint8_t *data_src) | 1342 | int nb, const uint8_t *data_src) |
| 1344 | { | 1343 | { |
| 1345 | - int rc; | ||
| 1346 | - int i; | ||
| 1347 | - int byte_count; | ||
| 1348 | - int query_length; | ||
| 1349 | - int coil_check = 0; | ||
| 1350 | - int pos = 0; | 1344 | + int rc; |
| 1345 | + int i; | ||
| 1346 | + int byte_count; | ||
| 1347 | + int query_length; | ||
| 1348 | + int coil_check = 0; | ||
| 1349 | + int pos = 0; | ||
| 1351 | 1350 | ||
| 1352 | - uint8_t query[MAX_MESSAGE_LENGTH]; | 1351 | + uint8_t query[MAX_MESSAGE_LENGTH]; |
| 1353 | 1352 | ||
| 1354 | - if (nb > MAX_STATUS) { | ||
| 1355 | - if (mb_param->debug) { | ||
| 1356 | - fprintf(stderr, "ERROR Writing to too many coils (%d > %d)\n", | ||
| 1357 | - nb, MAX_STATUS); | ||
| 1358 | - } | ||
| 1359 | - errno = EMBMDATA; | ||
| 1360 | - return -1; | 1353 | + if (nb > MAX_STATUS) { |
| 1354 | + if (mb_param->debug) { | ||
| 1355 | + fprintf(stderr, "ERROR Writing to too many coils (%d > %d)\n", | ||
| 1356 | + nb, MAX_STATUS); | ||
| 1361 | } | 1357 | } |
| 1358 | + errno = EMBMDATA; | ||
| 1359 | + return -1; | ||
| 1360 | + } | ||
| 1362 | 1361 | ||
| 1363 | - query_length = build_query_basis(mb_param, slave, FC_FORCE_MULTIPLE_COILS, | ||
| 1364 | - start_addr, nb, query); | ||
| 1365 | - byte_count = (nb / 8) + ((nb % 8) ? 1 : 0); | ||
| 1366 | - query[query_length++] = byte_count; | 1362 | + query_length = build_query_basis(mb_param, slave, FC_FORCE_MULTIPLE_COILS, |
| 1363 | + start_addr, nb, query); | ||
| 1364 | + byte_count = (nb / 8) + ((nb % 8) ? 1 : 0); | ||
| 1365 | + query[query_length++] = byte_count; | ||
| 1367 | 1366 | ||
| 1368 | - for (i = 0; i < byte_count; i++) { | ||
| 1369 | - int bit; | 1367 | + for (i = 0; i < byte_count; i++) { |
| 1368 | + int bit; | ||
| 1370 | 1369 | ||
| 1371 | - bit = 0x01; | ||
| 1372 | - query[query_length] = 0; | 1370 | + bit = 0x01; |
| 1371 | + query[query_length] = 0; | ||
| 1373 | 1372 | ||
| 1374 | - while ((bit & 0xFF) && (coil_check++ < nb)) { | ||
| 1375 | - if (data_src[pos++]) | ||
| 1376 | - query[query_length] |= bit; | ||
| 1377 | - else | ||
| 1378 | - query[query_length] &=~ bit; | 1373 | + while ((bit & 0xFF) && (coil_check++ < nb)) { |
| 1374 | + if (data_src[pos++]) | ||
| 1375 | + query[query_length] |= bit; | ||
| 1376 | + else | ||
| 1377 | + query[query_length] &=~ bit; | ||
| 1379 | 1378 | ||
| 1380 | - bit = bit << 1; | ||
| 1381 | - } | ||
| 1382 | - query_length++; | 1379 | + bit = bit << 1; |
| 1383 | } | 1380 | } |
| 1381 | + query_length++; | ||
| 1382 | + } | ||
| 1384 | 1383 | ||
| 1385 | - rc = modbus_send(mb_param, query, query_length); | ||
| 1386 | - if (rc > 0) { | ||
| 1387 | - uint8_t response[MAX_MESSAGE_LENGTH]; | ||
| 1388 | - rc = modbus_receive(mb_param, query, response); | ||
| 1389 | - } | 1384 | + rc = modbus_send(mb_param, query, query_length); |
| 1385 | + if (rc > 0) { | ||
| 1386 | + uint8_t response[MAX_MESSAGE_LENGTH]; | ||
| 1387 | + rc = modbus_receive(mb_param, query, response); | ||
| 1388 | + } | ||
| 1390 | 1389 | ||
| 1391 | 1390 | ||
| 1392 | - return rc; | 1391 | + return rc; |
| 1393 | } | 1392 | } |
| 1394 | 1393 | ||
| 1395 | /* Copies the values in the slave from the array given in argument */ | 1394 | /* Copies the values in the slave from the array given in argument */ |
| 1396 | int preset_multiple_registers(modbus_param_t *mb_param, int slave, int start_addr, | 1395 | int preset_multiple_registers(modbus_param_t *mb_param, int slave, int start_addr, |
| 1397 | int nb, const uint16_t *data_src) | 1396 | int nb, const uint16_t *data_src) |
| 1398 | { | 1397 | { |
| 1399 | - int rc; | ||
| 1400 | - int i; | ||
| 1401 | - int query_length; | ||
| 1402 | - int byte_count; | ||
| 1403 | - | ||
| 1404 | - uint8_t query[MAX_MESSAGE_LENGTH]; | ||
| 1405 | - | ||
| 1406 | - if (nb > MAX_REGISTERS) { | ||
| 1407 | - if (mb_param->debug) { | ||
| 1408 | - fprintf(stderr, | ||
| 1409 | - "ERROR Trying to write to too many registers (%d > %d)\n", | ||
| 1410 | - nb, MAX_REGISTERS); | ||
| 1411 | - } | ||
| 1412 | - errno = EMBMDATA; | ||
| 1413 | - return -1; | ||
| 1414 | - } | ||
| 1415 | - | ||
| 1416 | - query_length = build_query_basis(mb_param, slave, FC_PRESET_MULTIPLE_REGISTERS, | ||
| 1417 | - start_addr, nb, query); | ||
| 1418 | - byte_count = nb * 2; | ||
| 1419 | - query[query_length++] = byte_count; | 1398 | + int rc; |
| 1399 | + int i; | ||
| 1400 | + int query_length; | ||
| 1401 | + int byte_count; | ||
| 1420 | 1402 | ||
| 1421 | - for (i = 0; i < nb; i++) { | ||
| 1422 | - query[query_length++] = data_src[i] >> 8; | ||
| 1423 | - query[query_length++] = data_src[i] & 0x00FF; | ||
| 1424 | - } | 1403 | + uint8_t query[MAX_MESSAGE_LENGTH]; |
| 1425 | 1404 | ||
| 1426 | - rc = modbus_send(mb_param, query, query_length); | ||
| 1427 | - if (rc > 0) { | ||
| 1428 | - uint8_t response[MAX_MESSAGE_LENGTH]; | ||
| 1429 | - rc = modbus_receive(mb_param, query, response); | ||
| 1430 | - } | 1405 | + if (nb > MAX_REGISTERS) { |
| 1406 | + if (mb_param->debug) { | ||
| 1407 | + fprintf(stderr, | ||
| 1408 | + "ERROR Trying to write to too many registers (%d > %d)\n", | ||
| 1409 | + nb, MAX_REGISTERS); | ||
| 1410 | + } | ||
| 1411 | + errno = EMBMDATA; | ||
| 1412 | + return -1; | ||
| 1413 | + } | ||
| 1414 | + | ||
| 1415 | + query_length = build_query_basis(mb_param, slave, FC_PRESET_MULTIPLE_REGISTERS, | ||
| 1416 | + start_addr, nb, query); | ||
| 1417 | + byte_count = nb * 2; | ||
| 1418 | + query[query_length++] = byte_count; | ||
| 1419 | + | ||
| 1420 | + for (i = 0; i < nb; i++) { | ||
| 1421 | + query[query_length++] = data_src[i] >> 8; | ||
| 1422 | + query[query_length++] = data_src[i] & 0x00FF; | ||
| 1423 | + } | ||
| 1424 | + | ||
| 1425 | + rc = modbus_send(mb_param, query, query_length); | ||
| 1426 | + if (rc > 0) { | ||
| 1427 | + uint8_t response[MAX_MESSAGE_LENGTH]; | ||
| 1428 | + rc = modbus_receive(mb_param, query, response); | ||
| 1429 | + } | ||
| 1431 | 1430 | ||
| 1432 | - return rc; | 1431 | + return rc; |
| 1433 | } | 1432 | } |
| 1434 | 1433 | ||
| 1435 | /* Request the slave ID */ | 1434 | /* Request the slave ID */ |
| 1436 | int report_slave_id(modbus_param_t *mb_param, int slave, uint8_t *data_dest) | 1435 | int report_slave_id(modbus_param_t *mb_param, int slave, uint8_t *data_dest) |
| 1437 | { | 1436 | { |
| 1438 | - int rc; | ||
| 1439 | - int query_length; | ||
| 1440 | - uint8_t query[MIN_QUERY_LENGTH]; | ||
| 1441 | - | ||
| 1442 | - query_length = build_query_basis(mb_param, slave, | ||
| 1443 | - FC_REPORT_SLAVE_ID, 0, 0, query); | ||
| 1444 | - | ||
| 1445 | - /* HACKISH, start_addr and count are not used */ | ||
| 1446 | - query_length -= 4; | ||
| 1447 | - | ||
| 1448 | - rc = modbus_send(mb_param, query, query_length); | ||
| 1449 | - if (rc > 0) { | ||
| 1450 | - int i; | ||
| 1451 | - int offset; | ||
| 1452 | - int offset_end; | ||
| 1453 | - uint8_t response[MAX_MESSAGE_LENGTH]; | ||
| 1454 | - | ||
| 1455 | - /* Byte count, slave id, run indicator status, | ||
| 1456 | - additional data */ | ||
| 1457 | - rc = modbus_receive(mb_param, query, response); | ||
| 1458 | - if (rc == -1) | ||
| 1459 | - return rc; | ||
| 1460 | - | ||
| 1461 | - offset = TAB_HEADER_LENGTH[mb_param->type_com] - 1; | ||
| 1462 | - offset_end = offset + rc; | ||
| 1463 | - | ||
| 1464 | - for (i = offset; i < offset_end; i++) | ||
| 1465 | - data_dest[i] = response[i]; | ||
| 1466 | - } | 1437 | + int rc; |
| 1438 | + int query_length; | ||
| 1439 | + uint8_t query[MIN_QUERY_LENGTH]; | ||
| 1440 | + | ||
| 1441 | + query_length = build_query_basis(mb_param, slave, | ||
| 1442 | + FC_REPORT_SLAVE_ID, 0, 0, query); | ||
| 1443 | + | ||
| 1444 | + /* HACKISH, start_addr and count are not used */ | ||
| 1445 | + query_length -= 4; | ||
| 1446 | + | ||
| 1447 | + rc = modbus_send(mb_param, query, query_length); | ||
| 1448 | + if (rc > 0) { | ||
| 1449 | + int i; | ||
| 1450 | + int offset; | ||
| 1451 | + int offset_end; | ||
| 1452 | + uint8_t response[MAX_MESSAGE_LENGTH]; | ||
| 1453 | + | ||
| 1454 | + /* Byte count, slave id, run indicator status, | ||
| 1455 | + additional data */ | ||
| 1456 | + rc = modbus_receive(mb_param, query, response); | ||
| 1457 | + if (rc == -1) | ||
| 1458 | + return rc; | ||
| 1459 | + | ||
| 1460 | + offset = TAB_HEADER_LENGTH[mb_param->type_com] - 1; | ||
| 1461 | + offset_end = offset + rc; | ||
| 1462 | + | ||
| 1463 | + for (i = offset; i < offset_end; i++) | ||
| 1464 | + data_dest[i] = response[i]; | ||
| 1465 | + } | ||
| 1467 | 1466 | ||
| 1468 | - return rc; | 1467 | + return rc; |
| 1469 | } | 1468 | } |
| 1470 | 1469 | ||
| 1471 | void init_common(modbus_param_t *mb_param) | 1470 | void init_common(modbus_param_t *mb_param) |
| 1472 | { | 1471 | { |
| 1473 | - mb_param->timeout_begin.tv_sec = 0; | ||
| 1474 | - mb_param->timeout_begin.tv_usec = TIME_OUT_BEGIN_OF_TRAME; | 1472 | + mb_param->timeout_begin.tv_sec = 0; |
| 1473 | + mb_param->timeout_begin.tv_usec = TIME_OUT_BEGIN_OF_TRAME; | ||
| 1475 | 1474 | ||
| 1476 | - mb_param->timeout_end.tv_sec = 0; | ||
| 1477 | - mb_param->timeout_end.tv_usec = TIME_OUT_END_OF_TRAME; | 1475 | + mb_param->timeout_end.tv_sec = 0; |
| 1476 | + mb_param->timeout_end.tv_usec = TIME_OUT_END_OF_TRAME; | ||
| 1478 | } | 1477 | } |
| 1479 | 1478 | ||
| 1480 | /* Initializes the modbus_param_t structure for RTU | 1479 | /* Initializes the modbus_param_t structure for RTU |
| @@ -1486,26 +1485,26 @@ void init_common(modbus_param_t *mb_param) | @@ -1486,26 +1485,26 @@ void init_common(modbus_param_t *mb_param) | ||
| 1486 | - slave: slave number | 1485 | - slave: slave number |
| 1487 | */ | 1486 | */ |
| 1488 | int modbus_init_rtu(modbus_param_t *mb_param, const char *device, | 1487 | int modbus_init_rtu(modbus_param_t *mb_param, const char *device, |
| 1489 | - int baud, char parity, int data_bit, | ||
| 1490 | - int stop_bit, int slave) | 1488 | + int baud, char parity, int data_bit, |
| 1489 | + int stop_bit, int slave) | ||
| 1491 | { | 1490 | { |
| 1492 | - memset(mb_param, 0, sizeof(modbus_param_t)); | ||
| 1493 | - init_common(mb_param); | ||
| 1494 | - | ||
| 1495 | - strcpy(mb_param->device, device); | ||
| 1496 | - mb_param->baud = baud; | ||
| 1497 | - if (parity == 'N' || parity == 'E' || parity == 'O') { | ||
| 1498 | - mb_param->parity = parity; | ||
| 1499 | - } else { | ||
| 1500 | - errno = EINVAL; | ||
| 1501 | - return -1; | ||
| 1502 | - } | ||
| 1503 | - mb_param->debug = FALSE; | ||
| 1504 | - mb_param->data_bit = data_bit; | ||
| 1505 | - mb_param->stop_bit = stop_bit; | ||
| 1506 | - mb_param->type_com = RTU; | ||
| 1507 | - mb_param->error_recovery = FALSE; | ||
| 1508 | - return modbus_set_slave(mb_param, slave); | 1491 | + memset(mb_param, 0, sizeof(modbus_param_t)); |
| 1492 | + init_common(mb_param); | ||
| 1493 | + | ||
| 1494 | + strcpy(mb_param->device, device); | ||
| 1495 | + mb_param->baud = baud; | ||
| 1496 | + if (parity == 'N' || parity == 'E' || parity == 'O') { | ||
| 1497 | + mb_param->parity = parity; | ||
| 1498 | + } else { | ||
| 1499 | + errno = EINVAL; | ||
| 1500 | + return -1; | ||
| 1501 | + } | ||
| 1502 | + mb_param->debug = FALSE; | ||
| 1503 | + mb_param->data_bit = data_bit; | ||
| 1504 | + mb_param->stop_bit = stop_bit; | ||
| 1505 | + mb_param->type_com = RTU; | ||
| 1506 | + mb_param->error_recovery = FALSE; | ||
| 1507 | + return modbus_set_slave(mb_param, slave); | ||
| 1509 | } | 1508 | } |
| 1510 | 1509 | ||
| 1511 | /* Initializes the modbus_param_t structure for TCP. | 1510 | /* Initializes the modbus_param_t structure for TCP. |
| @@ -1519,437 +1518,437 @@ int modbus_init_rtu(modbus_param_t *mb_param, const char *device, | @@ -1519,437 +1518,437 @@ int modbus_init_rtu(modbus_param_t *mb_param, const char *device, | ||
| 1519 | */ | 1518 | */ |
| 1520 | int modbus_init_tcp(modbus_param_t *mb_param, const char *ip, int port) | 1519 | int modbus_init_tcp(modbus_param_t *mb_param, const char *ip, int port) |
| 1521 | { | 1520 | { |
| 1522 | - memset(mb_param, 0, sizeof(modbus_param_t)); | ||
| 1523 | - init_common(mb_param); | 1521 | + memset(mb_param, 0, sizeof(modbus_param_t)); |
| 1522 | + init_common(mb_param); | ||
| 1524 | 1523 | ||
| 1525 | - strncpy(mb_param->ip, ip, sizeof(char)*16); | ||
| 1526 | - mb_param->port = port; | ||
| 1527 | - mb_param->type_com = TCP; | ||
| 1528 | - mb_param->error_recovery = FALSE; | ||
| 1529 | - /* Can be changed after to reach remote serial Modbus device */ | ||
| 1530 | - mb_param->slave = 0xFF; | 1524 | + strncpy(mb_param->ip, ip, sizeof(char)*16); |
| 1525 | + mb_param->port = port; | ||
| 1526 | + mb_param->type_com = TCP; | ||
| 1527 | + mb_param->error_recovery = FALSE; | ||
| 1528 | + /* Can be changed after to reach remote serial Modbus device */ | ||
| 1529 | + mb_param->slave = 0xFF; | ||
| 1531 | 1530 | ||
| 1532 | - return 0; | 1531 | + return 0; |
| 1533 | } | 1532 | } |
| 1534 | 1533 | ||
| 1535 | /* Define the slave number, the special value MODBUS_TCP_SLAVE (0xFF) can be | 1534 | /* Define the slave number, the special value MODBUS_TCP_SLAVE (0xFF) can be |
| 1536 | * used in TCP mode to restore the default value. */ | 1535 | * used in TCP mode to restore the default value. */ |
| 1537 | int modbus_set_slave(modbus_param_t *mb_param, int slave) | 1536 | int modbus_set_slave(modbus_param_t *mb_param, int slave) |
| 1538 | { | 1537 | { |
| 1539 | - if (slave >= 1 && slave <= 247) { | ||
| 1540 | - mb_param->slave = slave; | ||
| 1541 | - } else if (mb_param->type_com == TCP && slave == MODBUS_TCP_SLAVE) { | ||
| 1542 | - mb_param->slave = slave; | ||
| 1543 | - } else { | ||
| 1544 | - errno = EINVAL; | ||
| 1545 | - return -1; | ||
| 1546 | - } | ||
| 1547 | - | ||
| 1548 | - return 0; | 1538 | + if (slave >= 1 && slave <= 247) { |
| 1539 | + mb_param->slave = slave; | ||
| 1540 | + } else if (mb_param->type_com == TCP && slave == MODBUS_TCP_SLAVE) { | ||
| 1541 | + mb_param->slave = slave; | ||
| 1542 | + } else { | ||
| 1543 | + errno = EINVAL; | ||
| 1544 | + return -1; | ||
| 1545 | + } | ||
| 1546 | + | ||
| 1547 | + return 0; | ||
| 1549 | } | 1548 | } |
| 1550 | 1549 | ||
| 1551 | /* | 1550 | /* |
| 1552 | - When disabled (default), it is expected that the application will check for | ||
| 1553 | - error returns and deal with them as necessary. | 1551 | + When disabled (default), it is expected that the application will check for |
| 1552 | + error returns and deal with them as necessary. | ||
| 1554 | 1553 | ||
| 1555 | - It's not recommanded to enable error recovery for slave/server. | 1554 | + It's not recommanded to enable error recovery for slave/server. |
| 1556 | 1555 | ||
| 1557 | - When enabled, the library will attempt an immediate reconnection which may | ||
| 1558 | - hang for several seconds if the network to the remote target unit is down. | ||
| 1559 | - The write will try a infinite close/connect loop until to be successful and | ||
| 1560 | - the select/read calls will just try to retablish the connection one time then | ||
| 1561 | - will return an error (if the connecton was down, the values to read are | ||
| 1562 | - certainly not available anymore after reconnection, except for slave/server). | 1556 | + When enabled, the library will attempt an immediate reconnection which may |
| 1557 | + hang for several seconds if the network to the remote target unit is down. | ||
| 1558 | + The write will try a infinite close/connect loop until to be successful and | ||
| 1559 | + the select/read calls will just try to retablish the connection one time then | ||
| 1560 | + will return an error (if the connecton was down, the values to read are | ||
| 1561 | + certainly not available anymore after reconnection, except for slave/server). | ||
| 1563 | */ | 1562 | */ |
| 1564 | int modbus_set_error_recovery(modbus_param_t *mb_param, int enabled) | 1563 | int modbus_set_error_recovery(modbus_param_t *mb_param, int enabled) |
| 1565 | { | 1564 | { |
| 1566 | - if (enabled == TRUE || enabled == FALSE) { | ||
| 1567 | - mb_param->error_recovery = (uint8_t) enabled; | ||
| 1568 | - } else { | ||
| 1569 | - errno = EINVAL; | ||
| 1570 | - return -1; | ||
| 1571 | - } | ||
| 1572 | - | ||
| 1573 | - return 0; | 1565 | + if (enabled == TRUE || enabled == FALSE) { |
| 1566 | + mb_param->error_recovery = (uint8_t) enabled; | ||
| 1567 | + } else { | ||
| 1568 | + errno = EINVAL; | ||
| 1569 | + return -1; | ||
| 1570 | + } | ||
| 1571 | + | ||
| 1572 | + return 0; | ||
| 1574 | } | 1573 | } |
| 1575 | 1574 | ||
| 1576 | /* Get the timeout of begin of trame */ | 1575 | /* Get the timeout of begin of trame */ |
| 1577 | void modbus_get_timeout_begin(modbus_param_t *mb_param, struct timeval *timeout) | 1576 | void modbus_get_timeout_begin(modbus_param_t *mb_param, struct timeval *timeout) |
| 1578 | { | 1577 | { |
| 1579 | - *timeout = mb_param->timeout_begin; | 1578 | + *timeout = mb_param->timeout_begin; |
| 1580 | } | 1579 | } |
| 1581 | 1580 | ||
| 1582 | /* Set timeout when waiting the beginning of a trame */ | 1581 | /* Set timeout when waiting the beginning of a trame */ |
| 1583 | void modbus_set_timeout_begin(modbus_param_t *mb_param, const struct timeval *timeout) | 1582 | void modbus_set_timeout_begin(modbus_param_t *mb_param, const struct timeval *timeout) |
| 1584 | { | 1583 | { |
| 1585 | - mb_param->timeout_begin = *timeout; | 1584 | + mb_param->timeout_begin = *timeout; |
| 1586 | } | 1585 | } |
| 1587 | 1586 | ||
| 1588 | /* Get the timeout of end of trame */ | 1587 | /* Get the timeout of end of trame */ |
| 1589 | void modbus_get_timeout_end(modbus_param_t *mb_param, struct timeval *timeout) | 1588 | void modbus_get_timeout_end(modbus_param_t *mb_param, struct timeval *timeout) |
| 1590 | { | 1589 | { |
| 1591 | - *timeout = mb_param->timeout_end; | 1590 | + *timeout = mb_param->timeout_end; |
| 1592 | } | 1591 | } |
| 1593 | 1592 | ||
| 1594 | /* Set timeout when waiting the end of a trame */ | 1593 | /* Set timeout when waiting the end of a trame */ |
| 1595 | void modbus_set_timeout_end(modbus_param_t *mb_param, const struct timeval *timeout) | 1594 | void modbus_set_timeout_end(modbus_param_t *mb_param, const struct timeval *timeout) |
| 1596 | { | 1595 | { |
| 1597 | - mb_param->timeout_end = *timeout; | 1596 | + mb_param->timeout_end = *timeout; |
| 1598 | } | 1597 | } |
| 1599 | 1598 | ||
| 1600 | /* Sets up a serial port for RTU communications */ | 1599 | /* Sets up a serial port for RTU communications */ |
| 1601 | static int modbus_connect_rtu(modbus_param_t *mb_param) | 1600 | static int modbus_connect_rtu(modbus_param_t *mb_param) |
| 1602 | { | 1601 | { |
| 1603 | - struct termios tios; | ||
| 1604 | - speed_t speed; | ||
| 1605 | - | 1602 | + struct termios tios; |
| 1603 | + speed_t speed; | ||
| 1604 | + | ||
| 1605 | + if (mb_param->debug) { | ||
| 1606 | + printf("Opening %s at %d bauds (%c, %d, %d)\n", | ||
| 1607 | + mb_param->device, mb_param->baud, mb_param->parity, | ||
| 1608 | + mb_param->data_bit, mb_param->stop_bit); | ||
| 1609 | + } | ||
| 1610 | + | ||
| 1611 | + /* The O_NOCTTY flag tells UNIX that this program doesn't want | ||
| 1612 | + to be the "controlling terminal" for that port. If you | ||
| 1613 | + don't specify this then any input (such as keyboard abort | ||
| 1614 | + signals and so forth) will affect your process | ||
| 1615 | + | ||
| 1616 | + Timeouts are ignored in canonical input mode or when the | ||
| 1617 | + NDELAY option is set on the file via open or fcntl */ | ||
| 1618 | + mb_param->fd = open(mb_param->device, O_RDWR | O_NOCTTY | O_NDELAY | O_EXCL); | ||
| 1619 | + if (mb_param->fd == -1) { | ||
| 1620 | + fprintf(stderr, "ERROR Can't open the device %s (%s)\n", | ||
| 1621 | + mb_param->device, strerror(errno)); | ||
| 1622 | + return -1; | ||
| 1623 | + } | ||
| 1624 | + | ||
| 1625 | + /* Save */ | ||
| 1626 | + tcgetattr(mb_param->fd, &(mb_param->old_tios)); | ||
| 1627 | + | ||
| 1628 | + memset(&tios, 0, sizeof(struct termios)); | ||
| 1629 | + | ||
| 1630 | + /* C_ISPEED Input baud (new interface) | ||
| 1631 | + C_OSPEED Output baud (new interface) | ||
| 1632 | + */ | ||
| 1633 | + switch (mb_param->baud) { | ||
| 1634 | + case 110: | ||
| 1635 | + speed = B110; | ||
| 1636 | + break; | ||
| 1637 | + case 300: | ||
| 1638 | + speed = B300; | ||
| 1639 | + break; | ||
| 1640 | + case 600: | ||
| 1641 | + speed = B600; | ||
| 1642 | + break; | ||
| 1643 | + case 1200: | ||
| 1644 | + speed = B1200; | ||
| 1645 | + break; | ||
| 1646 | + case 2400: | ||
| 1647 | + speed = B2400; | ||
| 1648 | + break; | ||
| 1649 | + case 4800: | ||
| 1650 | + speed = B4800; | ||
| 1651 | + break; | ||
| 1652 | + case 9600: | ||
| 1653 | + speed = B9600; | ||
| 1654 | + break; | ||
| 1655 | + case 19200: | ||
| 1656 | + speed = B19200; | ||
| 1657 | + break; | ||
| 1658 | + case 38400: | ||
| 1659 | + speed = B38400; | ||
| 1660 | + break; | ||
| 1661 | + case 57600: | ||
| 1662 | + speed = B57600; | ||
| 1663 | + break; | ||
| 1664 | + case 115200: | ||
| 1665 | + speed = B115200; | ||
| 1666 | + break; | ||
| 1667 | + default: | ||
| 1668 | + speed = B9600; | ||
| 1606 | if (mb_param->debug) { | 1669 | if (mb_param->debug) { |
| 1607 | - printf("Opening %s at %d bauds (%c, %d, %d)\n", | ||
| 1608 | - mb_param->device, mb_param->baud, mb_param->parity, | ||
| 1609 | - mb_param->data_bit, mb_param->stop_bit); | ||
| 1610 | - } | ||
| 1611 | - | ||
| 1612 | - /* The O_NOCTTY flag tells UNIX that this program doesn't want | ||
| 1613 | - to be the "controlling terminal" for that port. If you | ||
| 1614 | - don't specify this then any input (such as keyboard abort | ||
| 1615 | - signals and so forth) will affect your process | ||
| 1616 | - | ||
| 1617 | - Timeouts are ignored in canonical input mode or when the | ||
| 1618 | - NDELAY option is set on the file via open or fcntl */ | ||
| 1619 | - mb_param->fd = open(mb_param->device, O_RDWR | O_NOCTTY | O_NDELAY | O_EXCL); | ||
| 1620 | - if (mb_param->fd == -1) { | ||
| 1621 | - fprintf(stderr, "ERROR Can't open the device %s (%s)\n", | ||
| 1622 | - mb_param->device, strerror(errno)); | ||
| 1623 | - return -1; | ||
| 1624 | - } | ||
| 1625 | - | ||
| 1626 | - /* Save */ | ||
| 1627 | - tcgetattr(mb_param->fd, &(mb_param->old_tios)); | ||
| 1628 | - | ||
| 1629 | - memset(&tios, 0, sizeof(struct termios)); | ||
| 1630 | - | ||
| 1631 | - /* C_ISPEED Input baud (new interface) | ||
| 1632 | - C_OSPEED Output baud (new interface) | ||
| 1633 | - */ | ||
| 1634 | - switch (mb_param->baud) { | ||
| 1635 | - case 110: | ||
| 1636 | - speed = B110; | ||
| 1637 | - break; | ||
| 1638 | - case 300: | ||
| 1639 | - speed = B300; | ||
| 1640 | - break; | ||
| 1641 | - case 600: | ||
| 1642 | - speed = B600; | ||
| 1643 | - break; | ||
| 1644 | - case 1200: | ||
| 1645 | - speed = B1200; | ||
| 1646 | - break; | ||
| 1647 | - case 2400: | ||
| 1648 | - speed = B2400; | ||
| 1649 | - break; | ||
| 1650 | - case 4800: | ||
| 1651 | - speed = B4800; | ||
| 1652 | - break; | ||
| 1653 | - case 9600: | ||
| 1654 | - speed = B9600; | ||
| 1655 | - break; | ||
| 1656 | - case 19200: | ||
| 1657 | - speed = B19200; | ||
| 1658 | - break; | ||
| 1659 | - case 38400: | ||
| 1660 | - speed = B38400; | ||
| 1661 | - break; | ||
| 1662 | - case 57600: | ||
| 1663 | - speed = B57600; | ||
| 1664 | - break; | ||
| 1665 | - case 115200: | ||
| 1666 | - speed = B115200; | ||
| 1667 | - break; | ||
| 1668 | - default: | ||
| 1669 | - speed = B9600; | ||
| 1670 | - if (mb_param->debug) { | ||
| 1671 | - fprintf(stderr, | ||
| 1672 | - "WARNING Unknown baud rate %d for %s (B9600 used)\n", | ||
| 1673 | - mb_param->baud, mb_param->device); | ||
| 1674 | - } | ||
| 1675 | - } | ||
| 1676 | - | ||
| 1677 | - /* Set the baud rate */ | ||
| 1678 | - if ((cfsetispeed(&tios, speed) < 0) || | ||
| 1679 | - (cfsetospeed(&tios, speed) < 0)) { | ||
| 1680 | - return -1; | ||
| 1681 | - } | ||
| 1682 | - | ||
| 1683 | - /* C_CFLAG Control options | ||
| 1684 | - CLOCAL Local line - do not change "owner" of port | ||
| 1685 | - CREAD Enable receiver | ||
| 1686 | - */ | ||
| 1687 | - tios.c_cflag |= (CREAD | CLOCAL); | ||
| 1688 | - /* CSIZE, HUPCL, CRTSCTS (hardware flow control) */ | ||
| 1689 | - | ||
| 1690 | - /* Set data bits (5, 6, 7, 8 bits) | ||
| 1691 | - CSIZE Bit mask for data bits | ||
| 1692 | - */ | ||
| 1693 | - tios.c_cflag &= ~CSIZE; | ||
| 1694 | - switch (mb_param->data_bit) { | ||
| 1695 | - case 5: | ||
| 1696 | - tios.c_cflag |= CS5; | ||
| 1697 | - break; | ||
| 1698 | - case 6: | ||
| 1699 | - tios.c_cflag |= CS6; | ||
| 1700 | - break; | ||
| 1701 | - case 7: | ||
| 1702 | - tios.c_cflag |= CS7; | ||
| 1703 | - break; | ||
| 1704 | - case 8: | ||
| 1705 | - default: | ||
| 1706 | - tios.c_cflag |= CS8; | ||
| 1707 | - break; | ||
| 1708 | - } | ||
| 1709 | - | ||
| 1710 | - /* Stop bit (1 or 2) */ | ||
| 1711 | - if (mb_param->stop_bit == 1) | ||
| 1712 | - tios.c_cflag &=~ CSTOPB; | ||
| 1713 | - else /* 2 */ | ||
| 1714 | - tios.c_cflag |= CSTOPB; | ||
| 1715 | - | ||
| 1716 | - /* PARENB Enable parity bit | ||
| 1717 | - PARODD Use odd parity instead of even */ | ||
| 1718 | - if (mb_param->parity == 'N') { | ||
| 1719 | - /* None */ | ||
| 1720 | - tios.c_cflag &=~ PARENB; | ||
| 1721 | - } else if (mb_param->parity == 'E') { | ||
| 1722 | - /* Even */ | ||
| 1723 | - tios.c_cflag |= PARENB; | ||
| 1724 | - tios.c_cflag &=~ PARODD; | ||
| 1725 | - } else { | ||
| 1726 | - /* Odd */ | ||
| 1727 | - tios.c_cflag |= PARENB; | ||
| 1728 | - tios.c_cflag |= PARODD; | ||
| 1729 | - } | ||
| 1730 | - | ||
| 1731 | - /* Read the man page of termios if you need more information. */ | ||
| 1732 | - | ||
| 1733 | - /* This field isn't used on POSIX systems | ||
| 1734 | - tios.c_line = 0; | ||
| 1735 | - */ | ||
| 1736 | - | ||
| 1737 | - /* C_LFLAG Line options | ||
| 1738 | - | ||
| 1739 | - ISIG Enable SIGINTR, SIGSUSP, SIGDSUSP, and SIGQUIT signals | ||
| 1740 | - ICANON Enable canonical input (else raw) | ||
| 1741 | - XCASE Map uppercase \lowercase (obsolete) | ||
| 1742 | - ECHO Enable echoing of input characters | ||
| 1743 | - ECHOE Echo erase character as BS-SP-BS | ||
| 1744 | - ECHOK Echo NL after kill character | ||
| 1745 | - ECHONL Echo NL | ||
| 1746 | - NOFLSH Disable flushing of input buffers after | ||
| 1747 | - interrupt or quit characters | ||
| 1748 | - IEXTEN Enable extended functions | ||
| 1749 | - ECHOCTL Echo control characters as ^char and delete as ~? | ||
| 1750 | - ECHOPRT Echo erased character as character erased | ||
| 1751 | - ECHOKE BS-SP-BS entire line on line kill | ||
| 1752 | - FLUSHO Output being flushed | ||
| 1753 | - PENDIN Retype pending input at next read or input char | ||
| 1754 | - TOSTOP Send SIGTTOU for background output | ||
| 1755 | - | ||
| 1756 | - Canonical input is line-oriented. Input characters are put | ||
| 1757 | - into a buffer which can be edited interactively by the user | ||
| 1758 | - until a CR (carriage return) or LF (line feed) character is | ||
| 1759 | - received. | ||
| 1760 | - | ||
| 1761 | - Raw input is unprocessed. Input characters are passed | ||
| 1762 | - through exactly as they are received, when they are | ||
| 1763 | - received. Generally you'll deselect the ICANON, ECHO, | ||
| 1764 | - ECHOE, and ISIG options when using raw input | ||
| 1765 | - */ | ||
| 1766 | - | ||
| 1767 | - /* Raw input */ | ||
| 1768 | - tios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); | ||
| 1769 | - | ||
| 1770 | - /* C_IFLAG Input options | ||
| 1771 | - | ||
| 1772 | - Constant Description | ||
| 1773 | - INPCK Enable parity check | ||
| 1774 | - IGNPAR Ignore parity errors | ||
| 1775 | - PARMRK Mark parity errors | ||
| 1776 | - ISTRIP Strip parity bits | ||
| 1777 | - IXON Enable software flow control (outgoing) | ||
| 1778 | - IXOFF Enable software flow control (incoming) | ||
| 1779 | - IXANY Allow any character to start flow again | ||
| 1780 | - IGNBRK Ignore break condition | ||
| 1781 | - BRKINT Send a SIGINT when a break condition is detected | ||
| 1782 | - INLCR Map NL to CR | ||
| 1783 | - IGNCR Ignore CR | ||
| 1784 | - ICRNL Map CR to NL | ||
| 1785 | - IUCLC Map uppercase to lowercase | ||
| 1786 | - IMAXBEL Echo BEL on input line too long | ||
| 1787 | - */ | ||
| 1788 | - if (mb_param->parity == 'N') { | ||
| 1789 | - /* None */ | ||
| 1790 | - tios.c_iflag &= ~INPCK; | ||
| 1791 | - } else { | ||
| 1792 | - tios.c_iflag |= INPCK; | ||
| 1793 | - } | ||
| 1794 | - | ||
| 1795 | - /* Software flow control is disabled */ | ||
| 1796 | - tios.c_iflag &= ~(IXON | IXOFF | IXANY); | ||
| 1797 | - | ||
| 1798 | - /* C_OFLAG Output options | ||
| 1799 | - OPOST Postprocess output (not set = raw output) | ||
| 1800 | - ONLCR Map NL to CR-NL | ||
| 1801 | - | ||
| 1802 | - ONCLR ant others needs OPOST to be enabled | ||
| 1803 | - */ | ||
| 1804 | - | ||
| 1805 | - /* Raw ouput */ | ||
| 1806 | - tios.c_oflag &=~ OPOST; | ||
| 1807 | - | ||
| 1808 | - /* C_CC Control characters | ||
| 1809 | - VMIN Minimum number of characters to read | ||
| 1810 | - VTIME Time to wait for data (tenths of seconds) | ||
| 1811 | - | ||
| 1812 | - UNIX serial interface drivers provide the ability to | ||
| 1813 | - specify character and packet timeouts. Two elements of the | ||
| 1814 | - c_cc array are used for timeouts: VMIN and VTIME. Timeouts | ||
| 1815 | - are ignored in canonical input mode or when the NDELAY | ||
| 1816 | - option is set on the file via open or fcntl. | ||
| 1817 | - | ||
| 1818 | - VMIN specifies the minimum number of characters to read. If | ||
| 1819 | - it is set to 0, then the VTIME value specifies the time to | ||
| 1820 | - wait for every character read. Note that this does not mean | ||
| 1821 | - that a read call for N bytes will wait for N characters to | ||
| 1822 | - come in. Rather, the timeout will apply to the first | ||
| 1823 | - character and the read call will return the number of | ||
| 1824 | - characters immediately available (up to the number you | ||
| 1825 | - request). | ||
| 1826 | - | ||
| 1827 | - If VMIN is non-zero, VTIME specifies the time to wait for | ||
| 1828 | - the first character read. If a character is read within the | ||
| 1829 | - time given, any read will block (wait) until all VMIN | ||
| 1830 | - characters are read. That is, once the first character is | ||
| 1831 | - read, the serial interface driver expects to receive an | ||
| 1832 | - entire packet of characters (VMIN bytes total). If no | ||
| 1833 | - character is read within the time allowed, then the call to | ||
| 1834 | - read returns 0. This method allows you to tell the serial | ||
| 1835 | - driver you need exactly N bytes and any read call will | ||
| 1836 | - return 0 or N bytes. However, the timeout only applies to | ||
| 1837 | - the first character read, so if for some reason the driver | ||
| 1838 | - misses one character inside the N byte packet then the read | ||
| 1839 | - call could block forever waiting for additional input | ||
| 1840 | - characters. | ||
| 1841 | - | ||
| 1842 | - VTIME specifies the amount of time to wait for incoming | ||
| 1843 | - characters in tenths of seconds. If VTIME is set to 0 (the | ||
| 1844 | - default), reads will block (wait) indefinitely unless the | ||
| 1845 | - NDELAY option is set on the port with open or fcntl. | ||
| 1846 | - */ | ||
| 1847 | - /* Unused because we use open with the NDELAY option */ | ||
| 1848 | - tios.c_cc[VMIN] = 0; | ||
| 1849 | - tios.c_cc[VTIME] = 0; | ||
| 1850 | - | ||
| 1851 | - if (tcsetattr(mb_param->fd, TCSANOW, &tios) < 0) { | ||
| 1852 | - return -1; | ||
| 1853 | - } | ||
| 1854 | - | ||
| 1855 | - return 0; | 1670 | + fprintf(stderr, |
| 1671 | + "WARNING Unknown baud rate %d for %s (B9600 used)\n", | ||
| 1672 | + mb_param->baud, mb_param->device); | ||
| 1673 | + } | ||
| 1674 | + } | ||
| 1675 | + | ||
| 1676 | + /* Set the baud rate */ | ||
| 1677 | + if ((cfsetispeed(&tios, speed) < 0) || | ||
| 1678 | + (cfsetospeed(&tios, speed) < 0)) { | ||
| 1679 | + return -1; | ||
| 1680 | + } | ||
| 1681 | + | ||
| 1682 | + /* C_CFLAG Control options | ||
| 1683 | + CLOCAL Local line - do not change "owner" of port | ||
| 1684 | + CREAD Enable receiver | ||
| 1685 | + */ | ||
| 1686 | + tios.c_cflag |= (CREAD | CLOCAL); | ||
| 1687 | + /* CSIZE, HUPCL, CRTSCTS (hardware flow control) */ | ||
| 1688 | + | ||
| 1689 | + /* Set data bits (5, 6, 7, 8 bits) | ||
| 1690 | + CSIZE Bit mask for data bits | ||
| 1691 | + */ | ||
| 1692 | + tios.c_cflag &= ~CSIZE; | ||
| 1693 | + switch (mb_param->data_bit) { | ||
| 1694 | + case 5: | ||
| 1695 | + tios.c_cflag |= CS5; | ||
| 1696 | + break; | ||
| 1697 | + case 6: | ||
| 1698 | + tios.c_cflag |= CS6; | ||
| 1699 | + break; | ||
| 1700 | + case 7: | ||
| 1701 | + tios.c_cflag |= CS7; | ||
| 1702 | + break; | ||
| 1703 | + case 8: | ||
| 1704 | + default: | ||
| 1705 | + tios.c_cflag |= CS8; | ||
| 1706 | + break; | ||
| 1707 | + } | ||
| 1708 | + | ||
| 1709 | + /* Stop bit (1 or 2) */ | ||
| 1710 | + if (mb_param->stop_bit == 1) | ||
| 1711 | + tios.c_cflag &=~ CSTOPB; | ||
| 1712 | + else /* 2 */ | ||
| 1713 | + tios.c_cflag |= CSTOPB; | ||
| 1714 | + | ||
| 1715 | + /* PARENB Enable parity bit | ||
| 1716 | + PARODD Use odd parity instead of even */ | ||
| 1717 | + if (mb_param->parity == 'N') { | ||
| 1718 | + /* None */ | ||
| 1719 | + tios.c_cflag &=~ PARENB; | ||
| 1720 | + } else if (mb_param->parity == 'E') { | ||
| 1721 | + /* Even */ | ||
| 1722 | + tios.c_cflag |= PARENB; | ||
| 1723 | + tios.c_cflag &=~ PARODD; | ||
| 1724 | + } else { | ||
| 1725 | + /* Odd */ | ||
| 1726 | + tios.c_cflag |= PARENB; | ||
| 1727 | + tios.c_cflag |= PARODD; | ||
| 1728 | + } | ||
| 1729 | + | ||
| 1730 | + /* Read the man page of termios if you need more information. */ | ||
| 1731 | + | ||
| 1732 | + /* This field isn't used on POSIX systems | ||
| 1733 | + tios.c_line = 0; | ||
| 1734 | + */ | ||
| 1735 | + | ||
| 1736 | + /* C_LFLAG Line options | ||
| 1737 | + | ||
| 1738 | + ISIG Enable SIGINTR, SIGSUSP, SIGDSUSP, and SIGQUIT signals | ||
| 1739 | + ICANON Enable canonical input (else raw) | ||
| 1740 | + XCASE Map uppercase \lowercase (obsolete) | ||
| 1741 | + ECHO Enable echoing of input characters | ||
| 1742 | + ECHOE Echo erase character as BS-SP-BS | ||
| 1743 | + ECHOK Echo NL after kill character | ||
| 1744 | + ECHONL Echo NL | ||
| 1745 | + NOFLSH Disable flushing of input buffers after | ||
| 1746 | + interrupt or quit characters | ||
| 1747 | + IEXTEN Enable extended functions | ||
| 1748 | + ECHOCTL Echo control characters as ^char and delete as ~? | ||
| 1749 | + ECHOPRT Echo erased character as character erased | ||
| 1750 | + ECHOKE BS-SP-BS entire line on line kill | ||
| 1751 | + FLUSHO Output being flushed | ||
| 1752 | + PENDIN Retype pending input at next read or input char | ||
| 1753 | + TOSTOP Send SIGTTOU for background output | ||
| 1754 | + | ||
| 1755 | + Canonical input is line-oriented. Input characters are put | ||
| 1756 | + into a buffer which can be edited interactively by the user | ||
| 1757 | + until a CR (carriage return) or LF (line feed) character is | ||
| 1758 | + received. | ||
| 1759 | + | ||
| 1760 | + Raw input is unprocessed. Input characters are passed | ||
| 1761 | + through exactly as they are received, when they are | ||
| 1762 | + received. Generally you'll deselect the ICANON, ECHO, | ||
| 1763 | + ECHOE, and ISIG options when using raw input | ||
| 1764 | + */ | ||
| 1765 | + | ||
| 1766 | + /* Raw input */ | ||
| 1767 | + tios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); | ||
| 1768 | + | ||
| 1769 | + /* C_IFLAG Input options | ||
| 1770 | + | ||
| 1771 | + Constant Description | ||
| 1772 | + INPCK Enable parity check | ||
| 1773 | + IGNPAR Ignore parity errors | ||
| 1774 | + PARMRK Mark parity errors | ||
| 1775 | + ISTRIP Strip parity bits | ||
| 1776 | + IXON Enable software flow control (outgoing) | ||
| 1777 | + IXOFF Enable software flow control (incoming) | ||
| 1778 | + IXANY Allow any character to start flow again | ||
| 1779 | + IGNBRK Ignore break condition | ||
| 1780 | + BRKINT Send a SIGINT when a break condition is detected | ||
| 1781 | + INLCR Map NL to CR | ||
| 1782 | + IGNCR Ignore CR | ||
| 1783 | + ICRNL Map CR to NL | ||
| 1784 | + IUCLC Map uppercase to lowercase | ||
| 1785 | + IMAXBEL Echo BEL on input line too long | ||
| 1786 | + */ | ||
| 1787 | + if (mb_param->parity == 'N') { | ||
| 1788 | + /* None */ | ||
| 1789 | + tios.c_iflag &= ~INPCK; | ||
| 1790 | + } else { | ||
| 1791 | + tios.c_iflag |= INPCK; | ||
| 1792 | + } | ||
| 1793 | + | ||
| 1794 | + /* Software flow control is disabled */ | ||
| 1795 | + tios.c_iflag &= ~(IXON | IXOFF | IXANY); | ||
| 1796 | + | ||
| 1797 | + /* C_OFLAG Output options | ||
| 1798 | + OPOST Postprocess output (not set = raw output) | ||
| 1799 | + ONLCR Map NL to CR-NL | ||
| 1800 | + | ||
| 1801 | + ONCLR ant others needs OPOST to be enabled | ||
| 1802 | + */ | ||
| 1803 | + | ||
| 1804 | + /* Raw ouput */ | ||
| 1805 | + tios.c_oflag &=~ OPOST; | ||
| 1806 | + | ||
| 1807 | + /* C_CC Control characters | ||
| 1808 | + VMIN Minimum number of characters to read | ||
| 1809 | + VTIME Time to wait for data (tenths of seconds) | ||
| 1810 | + | ||
| 1811 | + UNIX serial interface drivers provide the ability to | ||
| 1812 | + specify character and packet timeouts. Two elements of the | ||
| 1813 | + c_cc array are used for timeouts: VMIN and VTIME. Timeouts | ||
| 1814 | + are ignored in canonical input mode or when the NDELAY | ||
| 1815 | + option is set on the file via open or fcntl. | ||
| 1816 | + | ||
| 1817 | + VMIN specifies the minimum number of characters to read. If | ||
| 1818 | + it is set to 0, then the VTIME value specifies the time to | ||
| 1819 | + wait for every character read. Note that this does not mean | ||
| 1820 | + that a read call for N bytes will wait for N characters to | ||
| 1821 | + come in. Rather, the timeout will apply to the first | ||
| 1822 | + character and the read call will return the number of | ||
| 1823 | + characters immediately available (up to the number you | ||
| 1824 | + request). | ||
| 1825 | + | ||
| 1826 | + If VMIN is non-zero, VTIME specifies the time to wait for | ||
| 1827 | + the first character read. If a character is read within the | ||
| 1828 | + time given, any read will block (wait) until all VMIN | ||
| 1829 | + characters are read. That is, once the first character is | ||
| 1830 | + read, the serial interface driver expects to receive an | ||
| 1831 | + entire packet of characters (VMIN bytes total). If no | ||
| 1832 | + character is read within the time allowed, then the call to | ||
| 1833 | + read returns 0. This method allows you to tell the serial | ||
| 1834 | + driver you need exactly N bytes and any read call will | ||
| 1835 | + return 0 or N bytes. However, the timeout only applies to | ||
| 1836 | + the first character read, so if for some reason the driver | ||
| 1837 | + misses one character inside the N byte packet then the read | ||
| 1838 | + call could block forever waiting for additional input | ||
| 1839 | + characters. | ||
| 1840 | + | ||
| 1841 | + VTIME specifies the amount of time to wait for incoming | ||
| 1842 | + characters in tenths of seconds. If VTIME is set to 0 (the | ||
| 1843 | + default), reads will block (wait) indefinitely unless the | ||
| 1844 | + NDELAY option is set on the port with open or fcntl. | ||
| 1845 | + */ | ||
| 1846 | + /* Unused because we use open with the NDELAY option */ | ||
| 1847 | + tios.c_cc[VMIN] = 0; | ||
| 1848 | + tios.c_cc[VTIME] = 0; | ||
| 1849 | + | ||
| 1850 | + if (tcsetattr(mb_param->fd, TCSANOW, &tios) < 0) { | ||
| 1851 | + return -1; | ||
| 1852 | + } | ||
| 1853 | + | ||
| 1854 | + return 0; | ||
| 1856 | } | 1855 | } |
| 1857 | 1856 | ||
| 1858 | /* Establishes a modbus TCP connection with a modbus slave */ | 1857 | /* Establishes a modbus TCP connection with a modbus slave */ |
| 1859 | static int modbus_connect_tcp(modbus_param_t *mb_param) | 1858 | static int modbus_connect_tcp(modbus_param_t *mb_param) |
| 1860 | { | 1859 | { |
| 1861 | - int rc; | ||
| 1862 | - int option; | ||
| 1863 | - struct sockaddr_in addr; | ||
| 1864 | - | ||
| 1865 | - mb_param->fd = socket(PF_INET, SOCK_STREAM, 0); | ||
| 1866 | - if (mb_param->fd == -1) { | ||
| 1867 | - return -1; | ||
| 1868 | - } | ||
| 1869 | - | ||
| 1870 | - /* Set the TCP no delay flag */ | ||
| 1871 | - /* SOL_TCP = IPPROTO_TCP */ | ||
| 1872 | - option = 1; | ||
| 1873 | - rc = setsockopt(mb_param->fd, IPPROTO_TCP, TCP_NODELAY, | ||
| 1874 | - (const void *)&option, sizeof(int)); | ||
| 1875 | - if (rc == -1) { | ||
| 1876 | - close(mb_param->fd); | ||
| 1877 | - return -1; | ||
| 1878 | - } | 1860 | + int rc; |
| 1861 | + int option; | ||
| 1862 | + struct sockaddr_in addr; | ||
| 1863 | + | ||
| 1864 | + mb_param->fd = socket(PF_INET, SOCK_STREAM, 0); | ||
| 1865 | + if (mb_param->fd == -1) { | ||
| 1866 | + return -1; | ||
| 1867 | + } | ||
| 1868 | + | ||
| 1869 | + /* Set the TCP no delay flag */ | ||
| 1870 | + /* SOL_TCP = IPPROTO_TCP */ | ||
| 1871 | + option = 1; | ||
| 1872 | + rc = setsockopt(mb_param->fd, IPPROTO_TCP, TCP_NODELAY, | ||
| 1873 | + (const void *)&option, sizeof(int)); | ||
| 1874 | + if (rc == -1) { | ||
| 1875 | + close(mb_param->fd); | ||
| 1876 | + return -1; | ||
| 1877 | + } | ||
| 1879 | 1878 | ||
| 1880 | #if (!HAVE_DECL___CYGWIN__) | 1879 | #if (!HAVE_DECL___CYGWIN__) |
| 1881 | - /** | ||
| 1882 | - * Cygwin defines IPTOS_LOWDELAY but can't handle that flag so it's | ||
| 1883 | - * necessary to workaround that problem. | ||
| 1884 | - **/ | ||
| 1885 | - /* Set the IP low delay option */ | ||
| 1886 | - option = IPTOS_LOWDELAY; | ||
| 1887 | - rc = setsockopt(mb_param->fd, IPPROTO_IP, IP_TOS, | ||
| 1888 | - (const void *)&option, sizeof(int)); | ||
| 1889 | - if (rc == -1) { | ||
| 1890 | - close(mb_param->fd); | ||
| 1891 | - return -1; | ||
| 1892 | - } | 1880 | + /** |
| 1881 | + * Cygwin defines IPTOS_LOWDELAY but can't handle that flag so it's | ||
| 1882 | + * necessary to workaround that problem. | ||
| 1883 | + **/ | ||
| 1884 | + /* Set the IP low delay option */ | ||
| 1885 | + option = IPTOS_LOWDELAY; | ||
| 1886 | + rc = setsockopt(mb_param->fd, IPPROTO_IP, IP_TOS, | ||
| 1887 | + (const void *)&option, sizeof(int)); | ||
| 1888 | + if (rc == -1) { | ||
| 1889 | + close(mb_param->fd); | ||
| 1890 | + return -1; | ||
| 1891 | + } | ||
| 1893 | #endif | 1892 | #endif |
| 1894 | 1893 | ||
| 1895 | - if (mb_param->debug) { | ||
| 1896 | - printf("Connecting to %s\n", mb_param->ip); | ||
| 1897 | - } | 1894 | + if (mb_param->debug) { |
| 1895 | + printf("Connecting to %s\n", mb_param->ip); | ||
| 1896 | + } | ||
| 1898 | 1897 | ||
| 1899 | - addr.sin_family = AF_INET; | ||
| 1900 | - addr.sin_port = htons(mb_param->port); | ||
| 1901 | - addr.sin_addr.s_addr = inet_addr(mb_param->ip); | ||
| 1902 | - rc = connect(mb_param->fd, (struct sockaddr *)&addr, | ||
| 1903 | - sizeof(struct sockaddr_in)); | ||
| 1904 | - if (rc == -1) { | ||
| 1905 | - close(mb_param->fd); | ||
| 1906 | - return -1; | ||
| 1907 | - } | 1898 | + addr.sin_family = AF_INET; |
| 1899 | + addr.sin_port = htons(mb_param->port); | ||
| 1900 | + addr.sin_addr.s_addr = inet_addr(mb_param->ip); | ||
| 1901 | + rc = connect(mb_param->fd, (struct sockaddr *)&addr, | ||
| 1902 | + sizeof(struct sockaddr_in)); | ||
| 1903 | + if (rc == -1) { | ||
| 1904 | + close(mb_param->fd); | ||
| 1905 | + return -1; | ||
| 1906 | + } | ||
| 1908 | 1907 | ||
| 1909 | - return 0; | 1908 | + return 0; |
| 1910 | } | 1909 | } |
| 1911 | 1910 | ||
| 1912 | /* Establishes a modbus connexion. | 1911 | /* Establishes a modbus connexion. |
| 1913 | Returns 0 on success or -1 on failure. */ | 1912 | Returns 0 on success or -1 on failure. */ |
| 1914 | int modbus_connect(modbus_param_t *mb_param) | 1913 | int modbus_connect(modbus_param_t *mb_param) |
| 1915 | { | 1914 | { |
| 1916 | - int rc; | 1915 | + int rc; |
| 1917 | 1916 | ||
| 1918 | - if (mb_param->type_com == RTU) | ||
| 1919 | - rc = modbus_connect_rtu(mb_param); | ||
| 1920 | - else | ||
| 1921 | - rc = modbus_connect_tcp(mb_param); | 1917 | + if (mb_param->type_com == RTU) |
| 1918 | + rc = modbus_connect_rtu(mb_param); | ||
| 1919 | + else | ||
| 1920 | + rc = modbus_connect_tcp(mb_param); | ||
| 1922 | 1921 | ||
| 1923 | - return rc; | 1922 | + return rc; |
| 1924 | } | 1923 | } |
| 1925 | 1924 | ||
| 1926 | /* Closes the file descriptor in RTU mode */ | 1925 | /* Closes the file descriptor in RTU mode */ |
| 1927 | static void modbus_close_rtu(modbus_param_t *mb_param) | 1926 | static void modbus_close_rtu(modbus_param_t *mb_param) |
| 1928 | { | 1927 | { |
| 1929 | - tcsetattr(mb_param->fd, TCSANOW, &(mb_param->old_tios)); | ||
| 1930 | - close(mb_param->fd); | 1928 | + tcsetattr(mb_param->fd, TCSANOW, &(mb_param->old_tios)); |
| 1929 | + close(mb_param->fd); | ||
| 1931 | } | 1930 | } |
| 1932 | 1931 | ||
| 1933 | /* Closes the network connection and socket in TCP mode */ | 1932 | /* Closes the network connection and socket in TCP mode */ |
| 1934 | static void modbus_close_tcp(modbus_param_t *mb_param) | 1933 | static void modbus_close_tcp(modbus_param_t *mb_param) |
| 1935 | { | 1934 | { |
| 1936 | - shutdown(mb_param->fd, SHUT_RDWR); | ||
| 1937 | - close(mb_param->fd); | 1935 | + shutdown(mb_param->fd, SHUT_RDWR); |
| 1936 | + close(mb_param->fd); | ||
| 1938 | } | 1937 | } |
| 1939 | 1938 | ||
| 1940 | /* Closes a modbus connection */ | 1939 | /* Closes a modbus connection */ |
| 1941 | void modbus_close(modbus_param_t *mb_param) | 1940 | void modbus_close(modbus_param_t *mb_param) |
| 1942 | { | 1941 | { |
| 1943 | - if (mb_param->type_com == RTU) | ||
| 1944 | - modbus_close_rtu(mb_param); | ||
| 1945 | - else | ||
| 1946 | - modbus_close_tcp(mb_param); | 1942 | + if (mb_param->type_com == RTU) |
| 1943 | + modbus_close_rtu(mb_param); | ||
| 1944 | + else | ||
| 1945 | + modbus_close_tcp(mb_param); | ||
| 1947 | } | 1946 | } |
| 1948 | 1947 | ||
| 1949 | /* Activates the debug messages */ | 1948 | /* Activates the debug messages */ |
| 1950 | void modbus_set_debug(modbus_param_t *mb_param, int boolean) | 1949 | void modbus_set_debug(modbus_param_t *mb_param, int boolean) |
| 1951 | { | 1950 | { |
| 1952 | - mb_param->debug = boolean; | 1951 | + mb_param->debug = boolean; |
| 1953 | } | 1952 | } |
| 1954 | 1953 | ||
| 1955 | /* Allocates 4 arrays to store coils, input status, input registers and | 1954 | /* Allocates 4 arrays to store coils, input status, input registers and |
| @@ -1962,103 +1961,103 @@ int modbus_mapping_new(modbus_mapping_t *mb_mapping, | @@ -1962,103 +1961,103 @@ int modbus_mapping_new(modbus_mapping_t *mb_mapping, | ||
| 1962 | int nb_coil_status, int nb_input_status, | 1961 | int nb_coil_status, int nb_input_status, |
| 1963 | int nb_holding_registers, int nb_input_registers) | 1962 | int nb_holding_registers, int nb_input_registers) |
| 1964 | { | 1963 | { |
| 1965 | - /* 0X */ | ||
| 1966 | - mb_mapping->nb_coil_status = nb_coil_status; | ||
| 1967 | - mb_mapping->tab_coil_status = | ||
| 1968 | - (uint8_t *) malloc(nb_coil_status * sizeof(uint8_t)); | ||
| 1969 | - if (mb_mapping->tab_coil_status == NULL) { | ||
| 1970 | - errno = ENOMEM; | ||
| 1971 | - return -1; | ||
| 1972 | - } | ||
| 1973 | - memset(mb_mapping->tab_coil_status, 0, | ||
| 1974 | - nb_coil_status * sizeof(uint8_t)); | ||
| 1975 | - | ||
| 1976 | - /* 1X */ | ||
| 1977 | - mb_mapping->nb_input_status = nb_input_status; | ||
| 1978 | - mb_mapping->tab_input_status = | ||
| 1979 | - (uint8_t *) malloc(nb_input_status * sizeof(uint8_t)); | ||
| 1980 | - if (mb_mapping->tab_input_status == NULL) { | ||
| 1981 | - free(mb_mapping->tab_coil_status); | ||
| 1982 | - errno = ENOMEM; | ||
| 1983 | - return -1; | ||
| 1984 | - } | ||
| 1985 | - memset(mb_mapping->tab_input_status, 0, | ||
| 1986 | - nb_input_status * sizeof(uint8_t)); | ||
| 1987 | - | ||
| 1988 | - /* 4X */ | ||
| 1989 | - mb_mapping->nb_holding_registers = nb_holding_registers; | ||
| 1990 | - mb_mapping->tab_holding_registers = | ||
| 1991 | - (uint16_t *) malloc(nb_holding_registers * sizeof(uint16_t)); | ||
| 1992 | - if (mb_mapping->tab_holding_registers == NULL) { | ||
| 1993 | - free(mb_mapping->tab_coil_status); | ||
| 1994 | - free(mb_mapping->tab_input_status); | ||
| 1995 | - errno = ENOMEM; | ||
| 1996 | - return -1; | ||
| 1997 | - } | ||
| 1998 | - memset(mb_mapping->tab_holding_registers, 0, | ||
| 1999 | - nb_holding_registers * sizeof(uint16_t)); | ||
| 2000 | - | ||
| 2001 | - /* 3X */ | ||
| 2002 | - mb_mapping->nb_input_registers = nb_input_registers; | ||
| 2003 | - mb_mapping->tab_input_registers = | ||
| 2004 | - (uint16_t *) malloc(nb_input_registers * sizeof(uint16_t)); | ||
| 2005 | - if (mb_mapping->tab_input_registers == NULL) { | ||
| 2006 | - free(mb_mapping->tab_coil_status); | ||
| 2007 | - free(mb_mapping->tab_input_status); | ||
| 2008 | - free(mb_mapping->tab_holding_registers); | ||
| 2009 | - errno = ENOMEM; | ||
| 2010 | - return -1; | ||
| 2011 | - } | ||
| 2012 | - memset(mb_mapping->tab_input_registers, 0, | ||
| 2013 | - nb_input_registers * sizeof(uint16_t)); | 1964 | + /* 0X */ |
| 1965 | + mb_mapping->nb_coil_status = nb_coil_status; | ||
| 1966 | + mb_mapping->tab_coil_status = | ||
| 1967 | + (uint8_t *) malloc(nb_coil_status * sizeof(uint8_t)); | ||
| 1968 | + if (mb_mapping->tab_coil_status == NULL) { | ||
| 1969 | + errno = ENOMEM; | ||
| 1970 | + return -1; | ||
| 1971 | + } | ||
| 1972 | + memset(mb_mapping->tab_coil_status, 0, | ||
| 1973 | + nb_coil_status * sizeof(uint8_t)); | ||
| 1974 | + | ||
| 1975 | + /* 1X */ | ||
| 1976 | + mb_mapping->nb_input_status = nb_input_status; | ||
| 1977 | + mb_mapping->tab_input_status = | ||
| 1978 | + (uint8_t *) malloc(nb_input_status * sizeof(uint8_t)); | ||
| 1979 | + if (mb_mapping->tab_input_status == NULL) { | ||
| 1980 | + free(mb_mapping->tab_coil_status); | ||
| 1981 | + errno = ENOMEM; | ||
| 1982 | + return -1; | ||
| 1983 | + } | ||
| 1984 | + memset(mb_mapping->tab_input_status, 0, | ||
| 1985 | + nb_input_status * sizeof(uint8_t)); | ||
| 1986 | + | ||
| 1987 | + /* 4X */ | ||
| 1988 | + mb_mapping->nb_holding_registers = nb_holding_registers; | ||
| 1989 | + mb_mapping->tab_holding_registers = | ||
| 1990 | + (uint16_t *) malloc(nb_holding_registers * sizeof(uint16_t)); | ||
| 1991 | + if (mb_mapping->tab_holding_registers == NULL) { | ||
| 1992 | + free(mb_mapping->tab_coil_status); | ||
| 1993 | + free(mb_mapping->tab_input_status); | ||
| 1994 | + errno = ENOMEM; | ||
| 1995 | + return -1; | ||
| 1996 | + } | ||
| 1997 | + memset(mb_mapping->tab_holding_registers, 0, | ||
| 1998 | + nb_holding_registers * sizeof(uint16_t)); | ||
| 1999 | + | ||
| 2000 | + /* 3X */ | ||
| 2001 | + mb_mapping->nb_input_registers = nb_input_registers; | ||
| 2002 | + mb_mapping->tab_input_registers = | ||
| 2003 | + (uint16_t *) malloc(nb_input_registers * sizeof(uint16_t)); | ||
| 2004 | + if (mb_mapping->tab_input_registers == NULL) { | ||
| 2005 | + free(mb_mapping->tab_coil_status); | ||
| 2006 | + free(mb_mapping->tab_input_status); | ||
| 2007 | + free(mb_mapping->tab_holding_registers); | ||
| 2008 | + errno = ENOMEM; | ||
| 2009 | + return -1; | ||
| 2010 | + } | ||
| 2011 | + memset(mb_mapping->tab_input_registers, 0, | ||
| 2012 | + nb_input_registers * sizeof(uint16_t)); | ||
| 2014 | 2013 | ||
| 2015 | - return 0; | 2014 | + return 0; |
| 2016 | } | 2015 | } |
| 2017 | 2016 | ||
| 2018 | /* Frees the 4 arrays */ | 2017 | /* Frees the 4 arrays */ |
| 2019 | void modbus_mapping_free(modbus_mapping_t *mb_mapping) | 2018 | void modbus_mapping_free(modbus_mapping_t *mb_mapping) |
| 2020 | { | 2019 | { |
| 2021 | - free(mb_mapping->tab_coil_status); | ||
| 2022 | - free(mb_mapping->tab_input_status); | ||
| 2023 | - free(mb_mapping->tab_holding_registers); | ||
| 2024 | - free(mb_mapping->tab_input_registers); | 2020 | + free(mb_mapping->tab_coil_status); |
| 2021 | + free(mb_mapping->tab_input_status); | ||
| 2022 | + free(mb_mapping->tab_holding_registers); | ||
| 2023 | + free(mb_mapping->tab_input_registers); | ||
| 2025 | } | 2024 | } |
| 2026 | 2025 | ||
| 2027 | /* Listens for any query from one or many modbus masters in TCP */ | 2026 | /* Listens for any query from one or many modbus masters in TCP */ |
| 2028 | int modbus_slave_listen_tcp(modbus_param_t *mb_param, int nb_connection) | 2027 | int modbus_slave_listen_tcp(modbus_param_t *mb_param, int nb_connection) |
| 2029 | { | 2028 | { |
| 2030 | - int new_socket; | ||
| 2031 | - int yes; | ||
| 2032 | - struct sockaddr_in addr; | ||
| 2033 | - | ||
| 2034 | - new_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); | ||
| 2035 | - if (new_socket == -1) { | ||
| 2036 | - return -1; | ||
| 2037 | - } | ||
| 2038 | - | ||
| 2039 | - yes = 1; | ||
| 2040 | - if (setsockopt(new_socket, SOL_SOCKET, SO_REUSEADDR, | ||
| 2041 | - (char *) &yes, sizeof(yes)) == -1) { | ||
| 2042 | - close(new_socket); | ||
| 2043 | - return -1; | ||
| 2044 | - } | ||
| 2045 | - | ||
| 2046 | - memset(&addr, 0, sizeof(addr)); | ||
| 2047 | - addr.sin_family = AF_INET; | ||
| 2048 | - /* If the modbus port is < to 1024, we need the setuid root. */ | ||
| 2049 | - addr.sin_port = htons(mb_param->port); | ||
| 2050 | - addr.sin_addr.s_addr = INADDR_ANY; | ||
| 2051 | - if (bind(new_socket, (struct sockaddr *)&addr, sizeof(addr)) == -1) { | ||
| 2052 | - close(new_socket); | ||
| 2053 | - return -1; | ||
| 2054 | - } | ||
| 2055 | - | ||
| 2056 | - if (listen(new_socket, nb_connection) == -1) { | ||
| 2057 | - close(new_socket); | ||
| 2058 | - return -1; | ||
| 2059 | - } | ||
| 2060 | - | ||
| 2061 | - return new_socket; | 2029 | + int new_socket; |
| 2030 | + int yes; | ||
| 2031 | + struct sockaddr_in addr; | ||
| 2032 | + | ||
| 2033 | + new_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); | ||
| 2034 | + if (new_socket == -1) { | ||
| 2035 | + return -1; | ||
| 2036 | + } | ||
| 2037 | + | ||
| 2038 | + yes = 1; | ||
| 2039 | + if (setsockopt(new_socket, SOL_SOCKET, SO_REUSEADDR, | ||
| 2040 | + (char *) &yes, sizeof(yes)) == -1) { | ||
| 2041 | + close(new_socket); | ||
| 2042 | + return -1; | ||
| 2043 | + } | ||
| 2044 | + | ||
| 2045 | + memset(&addr, 0, sizeof(addr)); | ||
| 2046 | + addr.sin_family = AF_INET; | ||
| 2047 | + /* If the modbus port is < to 1024, we need the setuid root. */ | ||
| 2048 | + addr.sin_port = htons(mb_param->port); | ||
| 2049 | + addr.sin_addr.s_addr = INADDR_ANY; | ||
| 2050 | + if (bind(new_socket, (struct sockaddr *)&addr, sizeof(addr)) == -1) { | ||
| 2051 | + close(new_socket); | ||
| 2052 | + return -1; | ||
| 2053 | + } | ||
| 2054 | + | ||
| 2055 | + if (listen(new_socket, nb_connection) == -1) { | ||
| 2056 | + close(new_socket); | ||
| 2057 | + return -1; | ||
| 2058 | + } | ||
| 2059 | + | ||
| 2060 | + return new_socket; | ||
| 2062 | } | 2061 | } |
| 2063 | 2062 | ||
| 2064 | /* On success, the function return a non-negative integer that is a descriptor | 2063 | /* On success, the function return a non-negative integer that is a descriptor |
| @@ -2066,30 +2065,30 @@ int modbus_slave_listen_tcp(modbus_param_t *mb_param, int nb_connection) | @@ -2066,30 +2065,30 @@ int modbus_slave_listen_tcp(modbus_param_t *mb_param, int nb_connection) | ||
| 2066 | appropriately. */ | 2065 | appropriately. */ |
| 2067 | int modbus_slave_accept_tcp(modbus_param_t *mb_param, int *socket) | 2066 | int modbus_slave_accept_tcp(modbus_param_t *mb_param, int *socket) |
| 2068 | { | 2067 | { |
| 2069 | - struct sockaddr_in addr; | ||
| 2070 | - socklen_t addrlen; | ||
| 2071 | - | ||
| 2072 | - addrlen = sizeof(struct sockaddr_in); | ||
| 2073 | - mb_param->fd = accept(*socket, (struct sockaddr *)&addr, &addrlen); | ||
| 2074 | - if (mb_param->fd == -1) { | ||
| 2075 | - close(*socket); | ||
| 2076 | - *socket = 0; | ||
| 2077 | - return -1; | ||
| 2078 | - } | ||
| 2079 | - | ||
| 2080 | - if (mb_param->debug) { | ||
| 2081 | - printf("The client %s is connected\n", | ||
| 2082 | - inet_ntoa(addr.sin_addr)); | ||
| 2083 | - } | ||
| 2084 | - | ||
| 2085 | - return mb_param->fd; | 2068 | + struct sockaddr_in addr; |
| 2069 | + socklen_t addrlen; | ||
| 2070 | + | ||
| 2071 | + addrlen = sizeof(struct sockaddr_in); | ||
| 2072 | + mb_param->fd = accept(*socket, (struct sockaddr *)&addr, &addrlen); | ||
| 2073 | + if (mb_param->fd == -1) { | ||
| 2074 | + close(*socket); | ||
| 2075 | + *socket = 0; | ||
| 2076 | + return -1; | ||
| 2077 | + } | ||
| 2078 | + | ||
| 2079 | + if (mb_param->debug) { | ||
| 2080 | + printf("The client %s is connected\n", | ||
| 2081 | + inet_ntoa(addr.sin_addr)); | ||
| 2082 | + } | ||
| 2083 | + | ||
| 2084 | + return mb_param->fd; | ||
| 2086 | } | 2085 | } |
| 2087 | 2086 | ||
| 2088 | /* Closes a TCP socket */ | 2087 | /* Closes a TCP socket */ |
| 2089 | void modbus_slave_close_tcp(int socket) | 2088 | void modbus_slave_close_tcp(int socket) |
| 2090 | { | 2089 | { |
| 2091 | - shutdown(socket, SHUT_RDWR); | ||
| 2092 | - close(socket); | 2090 | + shutdown(socket, SHUT_RDWR); |
| 2091 | + close(socket); | ||
| 2093 | } | 2092 | } |
| 2094 | 2093 | ||
| 2095 | /** Utils **/ | 2094 | /** Utils **/ |
| @@ -2098,11 +2097,11 @@ void modbus_slave_close_tcp(int socket) | @@ -2098,11 +2097,11 @@ void modbus_slave_close_tcp(int socket) | ||
| 2098 | the byte value are set) */ | 2097 | the byte value are set) */ |
| 2099 | void set_bits_from_byte(uint8_t *dest, int address, const uint8_t value) | 2098 | void set_bits_from_byte(uint8_t *dest, int address, const uint8_t value) |
| 2100 | { | 2099 | { |
| 2101 | - int i; | 2100 | + int i; |
| 2102 | 2101 | ||
| 2103 | - for (i=0; i<8; i++) { | ||
| 2104 | - dest[address+i] = (value & (1 << i)) ? ON : OFF; | ||
| 2105 | - } | 2102 | + for (i=0; i<8; i++) { |
| 2103 | + dest[address+i] = (value & (1 << i)) ? ON : OFF; | ||
| 2104 | + } | ||
| 2106 | } | 2105 | } |
| 2107 | 2106 | ||
| 2108 | /* Sets many input/coil status from a table of bytes (only the bits | 2107 | /* Sets many input/coil status from a table of bytes (only the bits |
| @@ -2110,53 +2109,53 @@ void set_bits_from_byte(uint8_t *dest, int address, const uint8_t value) | @@ -2110,53 +2109,53 @@ void set_bits_from_byte(uint8_t *dest, int address, const uint8_t value) | ||
| 2110 | void set_bits_from_bytes(uint8_t *dest, int address, unsigned int nb_bits, | 2109 | void set_bits_from_bytes(uint8_t *dest, int address, unsigned int nb_bits, |
| 2111 | const uint8_t tab_byte[]) | 2110 | const uint8_t tab_byte[]) |
| 2112 | { | 2111 | { |
| 2113 | - int i; | ||
| 2114 | - int shift = 0; | ||
| 2115 | - | ||
| 2116 | - for (i = address; i < address + nb_bits; i++) { | ||
| 2117 | - dest[i] = tab_byte[(i - address) / 8] & (1 << shift) ? ON : OFF; | ||
| 2118 | - /* gcc doesn't like: shift = (++shift) % 8; */ | ||
| 2119 | - shift++; | ||
| 2120 | - shift %= 8; | ||
| 2121 | - } | 2112 | + int i; |
| 2113 | + int shift = 0; | ||
| 2114 | + | ||
| 2115 | + for (i = address; i < address + nb_bits; i++) { | ||
| 2116 | + dest[i] = tab_byte[(i - address) / 8] & (1 << shift) ? ON : OFF; | ||
| 2117 | + /* gcc doesn't like: shift = (++shift) % 8; */ | ||
| 2118 | + shift++; | ||
| 2119 | + shift %= 8; | ||
| 2120 | + } | ||
| 2122 | } | 2121 | } |
| 2123 | 2122 | ||
| 2124 | /* Gets the byte value from many input/coil status. | 2123 | /* Gets the byte value from many input/coil status. |
| 2125 | To obtain a full byte, set nb_bits to 8. */ | 2124 | To obtain a full byte, set nb_bits to 8. */ |
| 2126 | uint8_t get_byte_from_bits(const uint8_t *src, int address, unsigned int nb_bits) | 2125 | uint8_t get_byte_from_bits(const uint8_t *src, int address, unsigned int nb_bits) |
| 2127 | { | 2126 | { |
| 2128 | - int i; | ||
| 2129 | - uint8_t value = 0; | 2127 | + int i; |
| 2128 | + uint8_t value = 0; | ||
| 2130 | 2129 | ||
| 2131 | - if (nb_bits > 8) { | ||
| 2132 | - assert(nb_bits < 8); | ||
| 2133 | - nb_bits = 8; | ||
| 2134 | - } | 2130 | + if (nb_bits > 8) { |
| 2131 | + assert(nb_bits < 8); | ||
| 2132 | + nb_bits = 8; | ||
| 2133 | + } | ||
| 2135 | 2134 | ||
| 2136 | - for (i=0; i < nb_bits; i++) { | ||
| 2137 | - value |= (src[address+i] << i); | ||
| 2138 | - } | 2135 | + for (i=0; i < nb_bits; i++) { |
| 2136 | + value |= (src[address+i] << i); | ||
| 2137 | + } | ||
| 2139 | 2138 | ||
| 2140 | - return value; | 2139 | + return value; |
| 2141 | } | 2140 | } |
| 2142 | 2141 | ||
| 2143 | /* Read a float from 4 bytes in Modbus format */ | 2142 | /* Read a float from 4 bytes in Modbus format */ |
| 2144 | float modbus_read_float(const uint16_t *src) | 2143 | float modbus_read_float(const uint16_t *src) |
| 2145 | { | 2144 | { |
| 2146 | - float r = 0.0f; | ||
| 2147 | - uint32_t i; | 2145 | + float r = 0.0f; |
| 2146 | + uint32_t i; | ||
| 2148 | 2147 | ||
| 2149 | - i = (((uint32_t)src[1]) << 16) + src[0]; | ||
| 2150 | - memcpy(&r, &i, sizeof (r)); | ||
| 2151 | - return r; | 2148 | + i = (((uint32_t)src[1]) << 16) + src[0]; |
| 2149 | + memcpy(&r, &i, sizeof (r)); | ||
| 2150 | + return r; | ||
| 2152 | } | 2151 | } |
| 2153 | 2152 | ||
| 2154 | /* Write a float to 4 bytes in Modbus format */ | 2153 | /* Write a float to 4 bytes in Modbus format */ |
| 2155 | void modbus_write_float(float real, uint16_t *dest) | 2154 | void modbus_write_float(float real, uint16_t *dest) |
| 2156 | { | 2155 | { |
| 2157 | - uint32_t i = 0; | 2156 | + uint32_t i = 0; |
| 2158 | 2157 | ||
| 2159 | - memcpy(&i, &real, sizeof (i)); | ||
| 2160 | - dest[0] = (uint16_t)i; | ||
| 2161 | - dest[1] = (uint16_t)(i >> 16); | 2158 | + memcpy(&i, &real, sizeof (i)); |
| 2159 | + dest[0] = (uint16_t)i; | ||
| 2160 | + dest[1] = (uint16_t)(i >> 16); | ||
| 2162 | } | 2161 | } |
src/modbus.h.in
| @@ -59,7 +59,7 @@ extern "C" { | @@ -59,7 +59,7 @@ extern "C" { | ||
| 59 | * Maximum between : | 59 | * Maximum between : |
| 60 | * - HEADER_LENGTH_TCP (7) + function (1) + address (2) + number (2) | 60 | * - HEADER_LENGTH_TCP (7) + function (1) + address (2) + number (2) |
| 61 | * - HEADER_LENGTH_RTU (1) + function (1) + address (2) + number (2) + CRC (2) | 61 | * - HEADER_LENGTH_RTU (1) + function (1) + address (2) + number (2) + CRC (2) |
| 62 | -*/ | 62 | + */ |
| 63 | #define MIN_QUERY_LENGTH 12 | 63 | #define MIN_QUERY_LENGTH 12 |
| 64 | 64 | ||
| 65 | /* Modbus_Application_Protocol_V1_1b.pdf Chapter 4 Section 1 Page 5: | 65 | /* Modbus_Application_Protocol_V1_1b.pdf Chapter 4 Section 1 Page 5: |
| @@ -123,20 +123,20 @@ extern "C" { | @@ -123,20 +123,20 @@ extern "C" { | ||
| 123 | #define MODBUS_ENOBASE 112345678 | 123 | #define MODBUS_ENOBASE 112345678 |
| 124 | 124 | ||
| 125 | /* Protocol exceptions */ | 125 | /* Protocol exceptions */ |
| 126 | -enum { | ||
| 127 | - MODBUS_EXCEPTION_ILLEGAL_FUNCTION = 0x01, | ||
| 128 | - MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, | ||
| 129 | - MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, | ||
| 130 | - MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE, | ||
| 131 | - MODBUS_EXCEPTION_ACKNOWLEDGE, | ||
| 132 | - MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY, | ||
| 133 | - MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE, | ||
| 134 | - MODBUS_EXCEPTION_MEMORY_PARITY, | ||
| 135 | - MODBUS_EXCEPTION_NOT_DEFINED, | ||
| 136 | - MODBUS_EXCEPTION_GATEWAY_PATH, | ||
| 137 | - MODBUS_EXCEPTION_GATEWAY_TARGET, | ||
| 138 | - MODBUS_EXCEPTION_MAX | ||
| 139 | -}; | 126 | +typedef enum { |
| 127 | + MODBUS_EXCEPTION_ILLEGAL_FUNCTION = 0x01, | ||
| 128 | + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, | ||
| 129 | + MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, | ||
| 130 | + MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE, | ||
| 131 | + MODBUS_EXCEPTION_ACKNOWLEDGE, | ||
| 132 | + MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY, | ||
| 133 | + MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE, | ||
| 134 | + MODBUS_EXCEPTION_MEMORY_PARITY, | ||
| 135 | + MODBUS_EXCEPTION_NOT_DEFINED, | ||
| 136 | + MODBUS_EXCEPTION_GATEWAY_PATH, | ||
| 137 | + MODBUS_EXCEPTION_GATEWAY_TARGET, | ||
| 138 | + MODBUS_EXCEPTION_MAX | ||
| 139 | +} modbus_exception_t; | ||
| 140 | 140 | ||
| 141 | #define EMBXILFUN (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_FUNCTION) | 141 | #define EMBXILFUN (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_FUNCTION) |
| 142 | #define EMBXILADD (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS) | 142 | #define EMBXILADD (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS) |
| @@ -177,20 +177,20 @@ enum { | @@ -177,20 +177,20 @@ enum { | ||
| 177 | #define LIBMODBUS_VERSION_STRING "@LIBMODBUS_VERSION@" | 177 | #define LIBMODBUS_VERSION_STRING "@LIBMODBUS_VERSION@" |
| 178 | 178 | ||
| 179 | /* Numerically encoded version libmb, like 0x010203 */ | 179 | /* Numerically encoded version libmb, like 0x010203 */ |
| 180 | -#define LIBMODBUS_VERSION_HEX ((LIBMODBUS_MAJOR_VERSION << 24) | \ | ||
| 181 | - (LIBMODBUS_MINOR_VERSION << 16) | \ | 180 | +#define LIBMODBUS_VERSION_HEX ((LIBMODBUS_MAJOR_VERSION << 24) | \ |
| 181 | + (LIBMODBUS_MINOR_VERSION << 16) | \ | ||
| 182 | (LIBMODBUS_MICRO_VERSION << 8)) | 182 | (LIBMODBUS_MICRO_VERSION << 8)) |
| 183 | 183 | ||
| 184 | /* Evaluates to True if the version of libmb is greater than @major, @minor and | 184 | /* Evaluates to True if the version of libmb is greater than @major, @minor and |
| 185 | * @micro | 185 | * @micro |
| 186 | */ | 186 | */ |
| 187 | -#define LIBMODBUS_VERSION_CHECK(major,minor,micro) \ | ||
| 188 | - (LIBMODBUS_VERSION_MAJOR > (major) || \ | ||
| 189 | - (LIBMODBUS_VERSION_MAJOR == (major) && \ | ||
| 190 | - LIBMODBUS_VERSION_MINOR > (minor)) || \ | ||
| 191 | - (LIBMODBUS_VERSION_MAJOR == (major) && \ | ||
| 192 | - LIBMODBUS_VERSION_MINOR == (minor) && \ | ||
| 193 | - LIBMODBUS_VERSION_MICRO >= (micro))) | 187 | +#define LIBMODBUS_VERSION_CHECK(major,minor,micro) \ |
| 188 | + (LIBMODBUS_VERSION_MAJOR > (major) || \ | ||
| 189 | + (LIBMODBUS_VERSION_MAJOR == (major) && \ | ||
| 190 | + LIBMODBUS_VERSION_MINOR > (minor)) || \ | ||
| 191 | + (LIBMODBUS_VERSION_MAJOR == (major) && \ | ||
| 192 | + LIBMODBUS_VERSION_MINOR == (minor) && \ | ||
| 193 | + LIBMODBUS_VERSION_MICRO >= (micro))) | ||
| 194 | 194 | ||
| 195 | extern const unsigned int libmodbus_version_major; | 195 | extern const unsigned int libmodbus_version_major; |
| 196 | extern const unsigned int libmodbus_version_minor; | 196 | extern const unsigned int libmodbus_version_minor; |
| @@ -200,54 +200,53 @@ typedef enum { RTU=0, TCP } type_com_t; | @@ -200,54 +200,53 @@ typedef enum { RTU=0, TCP } type_com_t; | ||
| 200 | 200 | ||
| 201 | /* This structure is byte-aligned */ | 201 | /* This structure is byte-aligned */ |
| 202 | typedef struct { | 202 | typedef struct { |
| 203 | - /* Slave address */ | ||
| 204 | - int slave; | ||
| 205 | - /* Descriptor (tty or socket) */ | ||
| 206 | - int fd; | ||
| 207 | - /* Communication mode: RTU or TCP */ | ||
| 208 | - type_com_t type_com; | ||
| 209 | - /* Flag debug */ | ||
| 210 | - int debug; | ||
| 211 | - /* TCP port */ | ||
| 212 | - int port; | ||
| 213 | - /* Device: "/dev/ttyS0", "/dev/ttyUSB0" or "/dev/tty.USA19*" | ||
| 214 | - on Mac OS X for KeySpan USB<->Serial adapters this string | ||
| 215 | - had to be made bigger on OS X as the directory+file name | ||
| 216 | - was bigger than 19 bytes. Making it 67 bytes for now, but | ||
| 217 | - OS X does support 256 byte file names. May become a problem | ||
| 218 | - in the future. */ | 203 | + /* Slave address */ |
| 204 | + int slave; | ||
| 205 | + /* Descriptor (tty or socket) */ | ||
| 206 | + int fd; | ||
| 207 | + /* Communication mode: RTU or TCP */ | ||
| 208 | + type_com_t type_com; | ||
| 209 | + /* Flag debug */ | ||
| 210 | + int debug; | ||
| 211 | + /* TCP port */ | ||
| 212 | + int port; | ||
| 213 | + /* Device: "/dev/ttyS0", "/dev/ttyUSB0" or "/dev/tty.USA19*" on Mac OS X for | ||
| 214 | + KeySpan USB<->Serial adapters this string had to be made bigger on OS X | ||
| 215 | + as the directory+file name was bigger than 19 bytes. Making it 67 bytes | ||
| 216 | + for now, but OS X does support 256 byte file names. May become a problem | ||
| 217 | + in the future. */ | ||
| 219 | #ifdef __APPLE_CC__ | 218 | #ifdef __APPLE_CC__ |
| 220 | - char device[64]; | 219 | + char device[64]; |
| 221 | #else | 220 | #else |
| 222 | - char device[16]; | 221 | + char device[16]; |
| 223 | #endif | 222 | #endif |
| 224 | - /* Bauds: 9600, 19200, 57600, 115200, etc */ | ||
| 225 | - int baud; | ||
| 226 | - /* Data bit */ | ||
| 227 | - uint8_t data_bit; | ||
| 228 | - /* Stop bit */ | ||
| 229 | - uint8_t stop_bit; | ||
| 230 | - /* Parity: 'N', 'O', 'E' */ | ||
| 231 | - char parity; | ||
| 232 | - /* In error_treat with TCP, do a reconnect or just dump the error */ | ||
| 233 | - uint8_t error_recovery; | 223 | + /* Bauds: 9600, 19200, 57600, 115200, etc */ |
| 224 | + int baud; | ||
| 225 | + /* Data bit */ | ||
| 226 | + uint8_t data_bit; | ||
| 227 | + /* Stop bit */ | ||
| 228 | + uint8_t stop_bit; | ||
| 229 | + /* Parity: 'N', 'O', 'E' */ | ||
| 230 | + char parity; | ||
| 231 | + /* In error_treat with TCP, do a reconnect or just dump the error */ | ||
| 232 | + uint8_t error_recovery; | ||
| 234 | /* IP address */ | 233 | /* IP address */ |
| 235 | - char ip[16]; | ||
| 236 | - /* Save old termios settings */ | ||
| 237 | - struct termios old_tios; | ||
| 238 | - struct timeval timeout_begin; | ||
| 239 | - struct timeval timeout_end; | 234 | + char ip[16]; |
| 235 | + /* Save old termios settings */ | ||
| 236 | + struct termios old_tios; | ||
| 237 | + struct timeval timeout_begin; | ||
| 238 | + struct timeval timeout_end; | ||
| 240 | } modbus_param_t; | 239 | } modbus_param_t; |
| 241 | 240 | ||
| 242 | typedef struct { | 241 | typedef struct { |
| 243 | - int nb_coil_status; | ||
| 244 | - int nb_input_status; | ||
| 245 | - int nb_input_registers; | ||
| 246 | - int nb_holding_registers; | ||
| 247 | - uint8_t *tab_coil_status; | ||
| 248 | - uint8_t *tab_input_status; | ||
| 249 | - uint16_t *tab_input_registers; | ||
| 250 | - uint16_t *tab_holding_registers; | 242 | + int nb_coil_status; |
| 243 | + int nb_input_status; | ||
| 244 | + int nb_input_registers; | ||
| 245 | + int nb_holding_registers; | ||
| 246 | + uint8_t *tab_coil_status; | ||
| 247 | + uint8_t *tab_input_status; | ||
| 248 | + uint16_t *tab_input_registers; | ||
| 249 | + uint16_t *tab_holding_registers; | ||
| 251 | } modbus_mapping_t; | 250 | } modbus_mapping_t; |
| 252 | 251 | ||
| 253 | int modbus_init_rtu(modbus_param_t *mb_param, const char *device, | 252 | int modbus_init_rtu(modbus_param_t *mb_param, const char *device, |
tests/bandwidth-master.c
| @@ -33,123 +33,123 @@ | @@ -33,123 +33,123 @@ | ||
| 33 | 33 | ||
| 34 | uint32_t gettime_ms(void) | 34 | uint32_t gettime_ms(void) |
| 35 | { | 35 | { |
| 36 | - struct timeval tv; | ||
| 37 | - gettimeofday (&tv, NULL); | 36 | + struct timeval tv; |
| 37 | + gettimeofday (&tv, NULL); | ||
| 38 | 38 | ||
| 39 | - return (uint32_t) tv.tv_sec * 1000 + tv.tv_usec / 1000; | 39 | + return (uint32_t) tv.tv_sec * 1000 + tv.tv_usec / 1000; |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | int main(void) | 42 | int main(void) |
| 43 | { | 43 | { |
| 44 | - uint8_t *tab_rp_status; | ||
| 45 | - uint16_t *tab_rp_registers; | ||
| 46 | - modbus_param_t mb_param; | ||
| 47 | - int i; | ||
| 48 | - int nb_points; | ||
| 49 | - double elapsed; | ||
| 50 | - uint32_t start; | ||
| 51 | - uint32_t end; | ||
| 52 | - uint32_t bytes; | ||
| 53 | - uint32_t rate; | ||
| 54 | - int rc; | ||
| 55 | - | ||
| 56 | - /* TCP */ | ||
| 57 | - modbus_init_tcp(&mb_param, "127.0.0.1", 1502); | ||
| 58 | - rc = modbus_connect(&mb_param); | 44 | + uint8_t *tab_rp_status; |
| 45 | + uint16_t *tab_rp_registers; | ||
| 46 | + modbus_param_t mb_param; | ||
| 47 | + int i; | ||
| 48 | + int nb_points; | ||
| 49 | + double elapsed; | ||
| 50 | + uint32_t start; | ||
| 51 | + uint32_t end; | ||
| 52 | + uint32_t bytes; | ||
| 53 | + uint32_t rate; | ||
| 54 | + int rc; | ||
| 55 | + | ||
| 56 | + /* TCP */ | ||
| 57 | + modbus_init_tcp(&mb_param, "127.0.0.1", 1502); | ||
| 58 | + rc = modbus_connect(&mb_param); | ||
| 59 | + if (rc == -1) { | ||
| 60 | + fprintf(stderr, "Connexion failed: %s\n", | ||
| 61 | + modbus_strerror(errno)); | ||
| 62 | + return -1; | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + /* Allocate and initialize the memory to store the status */ | ||
| 66 | + tab_rp_status = (uint8_t *) malloc(MAX_STATUS * sizeof(uint8_t)); | ||
| 67 | + memset(tab_rp_status, 0, MAX_STATUS * sizeof(uint8_t)); | ||
| 68 | + | ||
| 69 | + /* Allocate and initialize the memory to store the registers */ | ||
| 70 | + tab_rp_registers = (uint16_t *) malloc(MAX_REGISTERS * sizeof(uint16_t)); | ||
| 71 | + memset(tab_rp_registers, 0, MAX_REGISTERS * sizeof(uint16_t)); | ||
| 72 | + | ||
| 73 | + printf("READ COIL STATUS\n\n"); | ||
| 74 | + | ||
| 75 | + nb_points = MAX_STATUS; | ||
| 76 | + start = gettime_ms(); | ||
| 77 | + for (i=0; i<NB_LOOPS; i++) { | ||
| 78 | + rc = read_coil_status(&mb_param, SERVER_ID, 0, nb_points, tab_rp_status); | ||
| 59 | if (rc == -1) { | 79 | if (rc == -1) { |
| 60 | - fprintf(stderr, "Connexion failed: %s\n", | ||
| 61 | - modbus_strerror(errno)); | ||
| 62 | - return -1; | 80 | + fprintf(stderr, "%s\n", modbus_strerror(errno)); |
| 81 | + return -1; | ||
| 63 | } | 82 | } |
| 64 | - | ||
| 65 | - /* Allocate and initialize the memory to store the status */ | ||
| 66 | - tab_rp_status = (uint8_t *) malloc(MAX_STATUS * sizeof(uint8_t)); | ||
| 67 | - memset(tab_rp_status, 0, MAX_STATUS * sizeof(uint8_t)); | ||
| 68 | - | ||
| 69 | - /* Allocate and initialize the memory to store the registers */ | ||
| 70 | - tab_rp_registers = (uint16_t *) malloc(MAX_REGISTERS * sizeof(uint16_t)); | ||
| 71 | - memset(tab_rp_registers, 0, MAX_REGISTERS * sizeof(uint16_t)); | ||
| 72 | - | ||
| 73 | - printf("READ COIL STATUS\n\n"); | ||
| 74 | - | ||
| 75 | - nb_points = MAX_STATUS; | ||
| 76 | - start = gettime_ms(); | ||
| 77 | - for (i=0; i<NB_LOOPS; i++) { | ||
| 78 | - rc = read_coil_status(&mb_param, SERVER_ID, 0, nb_points, tab_rp_status); | ||
| 79 | - if (rc == -1) { | ||
| 80 | - fprintf(stderr, "%s\n", modbus_strerror(errno)); | ||
| 81 | - return -1; | ||
| 82 | - } | ||
| 83 | - } | ||
| 84 | - end = gettime_ms(); | ||
| 85 | - elapsed = end - start; | ||
| 86 | - | ||
| 87 | - rate = (NB_LOOPS * nb_points) * G_MSEC_PER_SEC / (end - start); | ||
| 88 | - printf("Transfert rate in points/seconds:\n"); | ||
| 89 | - printf("* %'d points/s\n", rate); | ||
| 90 | - printf("\n"); | ||
| 91 | - | ||
| 92 | - bytes = NB_LOOPS * (nb_points / 8) + ((nb_points % 8) ? 1 : 0); | ||
| 93 | - rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start); | ||
| 94 | - printf("Values:\n"); | ||
| 95 | - printf("* %d x %d values\n", NB_LOOPS, nb_points); | ||
| 96 | - printf("* %.3f ms for %d bytes\n", elapsed, bytes); | ||
| 97 | - printf("* %'d KiB/s\n", rate); | ||
| 98 | - printf("\n"); | ||
| 99 | - | ||
| 100 | - /* TCP: Query and reponse header and values */ | ||
| 101 | - bytes = 12 + 9 + (nb_points / 8) + ((nb_points % 8) ? 1 : 0); | ||
| 102 | - printf("Values and TCP Modbus overhead:\n"); | ||
| 103 | - printf("* %d x %d bytes\n", NB_LOOPS, bytes); | ||
| 104 | - bytes = NB_LOOPS * bytes; | ||
| 105 | - rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start); | ||
| 106 | - printf("* %.3f ms for %d bytes\n", elapsed, bytes); | ||
| 107 | - printf("* %'d KiB/s\n", rate); | ||
| 108 | - printf("\n\n"); | ||
| 109 | - | ||
| 110 | - printf("READ HOLDING REGISTERS\n\n"); | ||
| 111 | - | ||
| 112 | - nb_points = MAX_REGISTERS; | ||
| 113 | - start = gettime_ms(); | ||
| 114 | - for (i=0; i<NB_LOOPS; i++) { | ||
| 115 | - rc = read_holding_registers(&mb_param, SERVER_ID, 0, nb_points, tab_rp_registers); | ||
| 116 | - if (rc == -1) { | ||
| 117 | - fprintf(stderr, "%s\n", modbus_strerror(errno)); | ||
| 118 | - return -1; | ||
| 119 | - } | 83 | + } |
| 84 | + end = gettime_ms(); | ||
| 85 | + elapsed = end - start; | ||
| 86 | + | ||
| 87 | + rate = (NB_LOOPS * nb_points) * G_MSEC_PER_SEC / (end - start); | ||
| 88 | + printf("Transfert rate in points/seconds:\n"); | ||
| 89 | + printf("* %'d points/s\n", rate); | ||
| 90 | + printf("\n"); | ||
| 91 | + | ||
| 92 | + bytes = NB_LOOPS * (nb_points / 8) + ((nb_points % 8) ? 1 : 0); | ||
| 93 | + rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start); | ||
| 94 | + printf("Values:\n"); | ||
| 95 | + printf("* %d x %d values\n", NB_LOOPS, nb_points); | ||
| 96 | + printf("* %.3f ms for %d bytes\n", elapsed, bytes); | ||
| 97 | + printf("* %'d KiB/s\n", rate); | ||
| 98 | + printf("\n"); | ||
| 99 | + | ||
| 100 | + /* TCP: Query and reponse header and values */ | ||
| 101 | + bytes = 12 + 9 + (nb_points / 8) + ((nb_points % 8) ? 1 : 0); | ||
| 102 | + printf("Values and TCP Modbus overhead:\n"); | ||
| 103 | + printf("* %d x %d bytes\n", NB_LOOPS, bytes); | ||
| 104 | + bytes = NB_LOOPS * bytes; | ||
| 105 | + rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start); | ||
| 106 | + printf("* %.3f ms for %d bytes\n", elapsed, bytes); | ||
| 107 | + printf("* %'d KiB/s\n", rate); | ||
| 108 | + printf("\n\n"); | ||
| 109 | + | ||
| 110 | + printf("READ HOLDING REGISTERS\n\n"); | ||
| 111 | + | ||
| 112 | + nb_points = MAX_REGISTERS; | ||
| 113 | + start = gettime_ms(); | ||
| 114 | + for (i=0; i<NB_LOOPS; i++) { | ||
| 115 | + rc = read_holding_registers(&mb_param, SERVER_ID, 0, nb_points, tab_rp_registers); | ||
| 116 | + if (rc == -1) { | ||
| 117 | + fprintf(stderr, "%s\n", modbus_strerror(errno)); | ||
| 118 | + return -1; | ||
| 120 | } | 119 | } |
| 121 | - end = gettime_ms(); | ||
| 122 | - elapsed = end - start; | ||
| 123 | - | ||
| 124 | - rate = (NB_LOOPS * nb_points) * G_MSEC_PER_SEC / (end - start); | ||
| 125 | - printf("Transfert rate in points/seconds:\n"); | ||
| 126 | - printf("* %'d registers/s\n", rate); | ||
| 127 | - printf("\n"); | ||
| 128 | - | ||
| 129 | - bytes = NB_LOOPS * nb_points * sizeof(uint16_t); | ||
| 130 | - rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start); | ||
| 131 | - printf("Values:\n"); | ||
| 132 | - printf("* %d x %d values\n", NB_LOOPS, nb_points); | ||
| 133 | - printf("* %.3f ms for %d bytes\n", elapsed, bytes); | ||
| 134 | - printf("* %'d KiB/s\n", rate); | ||
| 135 | - printf("\n"); | ||
| 136 | - | ||
| 137 | - /* TCP:Query and reponse header and values */ | ||
| 138 | - bytes = 12 + 9 + (nb_points * sizeof(uint16_t)); | ||
| 139 | - printf("Values and TCP Modbus overhead:\n"); | ||
| 140 | - printf("* %d x %d bytes\n", NB_LOOPS, bytes); | ||
| 141 | - bytes = NB_LOOPS * bytes; | ||
| 142 | - rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start); | ||
| 143 | - printf("* %.3f ms for %d bytes\n", elapsed, bytes); | ||
| 144 | - printf("* %'d KiB/s\n", rate); | ||
| 145 | - printf("\n"); | ||
| 146 | - | ||
| 147 | - /* Free the memory */ | ||
| 148 | - free(tab_rp_status); | ||
| 149 | - free(tab_rp_registers); | ||
| 150 | - | ||
| 151 | - /* Close the connection */ | ||
| 152 | - modbus_close(&mb_param); | ||
| 153 | - | ||
| 154 | - return 0; | 120 | + } |
| 121 | + end = gettime_ms(); | ||
| 122 | + elapsed = end - start; | ||
| 123 | + | ||
| 124 | + rate = (NB_LOOPS * nb_points) * G_MSEC_PER_SEC / (end - start); | ||
| 125 | + printf("Transfert rate in points/seconds:\n"); | ||
| 126 | + printf("* %'d registers/s\n", rate); | ||
| 127 | + printf("\n"); | ||
| 128 | + | ||
| 129 | + bytes = NB_LOOPS * nb_points * sizeof(uint16_t); | ||
| 130 | + rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start); | ||
| 131 | + printf("Values:\n"); | ||
| 132 | + printf("* %d x %d values\n", NB_LOOPS, nb_points); | ||
| 133 | + printf("* %.3f ms for %d bytes\n", elapsed, bytes); | ||
| 134 | + printf("* %'d KiB/s\n", rate); | ||
| 135 | + printf("\n"); | ||
| 136 | + | ||
| 137 | + /* TCP:Query and reponse header and values */ | ||
| 138 | + bytes = 12 + 9 + (nb_points * sizeof(uint16_t)); | ||
| 139 | + printf("Values and TCP Modbus overhead:\n"); | ||
| 140 | + printf("* %d x %d bytes\n", NB_LOOPS, bytes); | ||
| 141 | + bytes = NB_LOOPS * bytes; | ||
| 142 | + rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start); | ||
| 143 | + printf("* %.3f ms for %d bytes\n", elapsed, bytes); | ||
| 144 | + printf("* %'d KiB/s\n", rate); | ||
| 145 | + printf("\n"); | ||
| 146 | + | ||
| 147 | + /* Free the memory */ | ||
| 148 | + free(tab_rp_status); | ||
| 149 | + free(tab_rp_registers); | ||
| 150 | + | ||
| 151 | + /* Close the connection */ | ||
| 152 | + modbus_close(&mb_param); | ||
| 153 | + | ||
| 154 | + return 0; | ||
| 155 | } | 155 | } |
tests/bandwidth-slave-many-up.c
| @@ -31,101 +31,101 @@ modbus_mapping_t mb_mapping; | @@ -31,101 +31,101 @@ modbus_mapping_t mb_mapping; | ||
| 31 | 31 | ||
| 32 | static void close_sigint(int dummy) | 32 | static void close_sigint(int dummy) |
| 33 | { | 33 | { |
| 34 | - modbus_slave_close_tcp(slave_socket); | ||
| 35 | - modbus_mapping_free(&mb_mapping); | 34 | + modbus_slave_close_tcp(slave_socket); |
| 35 | + modbus_mapping_free(&mb_mapping); | ||
| 36 | 36 | ||
| 37 | - exit(dummy); | 37 | + exit(dummy); |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | int main(void) | 40 | int main(void) |
| 41 | { | 41 | { |
| 42 | - int master_socket; | ||
| 43 | - modbus_param_t mb_param; | ||
| 44 | - int rc; | ||
| 45 | - fd_set refset; | ||
| 46 | - fd_set rdset; | ||
| 47 | - | ||
| 48 | - /* Maximum file descriptor number */ | ||
| 49 | - int fdmax; | ||
| 50 | - | ||
| 51 | - modbus_init_tcp(&mb_param, "127.0.0.1", 1502); | ||
| 52 | - | ||
| 53 | - rc = modbus_mapping_new(&mb_mapping, MAX_STATUS, 0, MAX_REGISTERS, 0); | ||
| 54 | - if (rc == -1) { | ||
| 55 | - fprintf(stderr, "Failed to allocate the mapping: %s\n", | ||
| 56 | - modbus_strerror(errno)); | ||
| 57 | - return -1; | ||
| 58 | - } | 42 | + int master_socket; |
| 43 | + modbus_param_t mb_param; | ||
| 44 | + int rc; | ||
| 45 | + fd_set refset; | ||
| 46 | + fd_set rdset; | ||
| 59 | 47 | ||
| 60 | - slave_socket = modbus_slave_listen_tcp(&mb_param, NB_CONNECTION); | 48 | + /* Maximum file descriptor number */ |
| 49 | + int fdmax; | ||
| 61 | 50 | ||
| 62 | - signal(SIGINT, close_sigint); | 51 | + modbus_init_tcp(&mb_param, "127.0.0.1", 1502); |
| 63 | 52 | ||
| 64 | - /* Clear the reference set of socket */ | ||
| 65 | - FD_ZERO(&refset); | ||
| 66 | - /* Add the slave socket */ | ||
| 67 | - FD_SET(slave_socket, &refset); | 53 | + rc = modbus_mapping_new(&mb_mapping, MAX_STATUS, 0, MAX_REGISTERS, 0); |
| 54 | + if (rc == -1) { | ||
| 55 | + fprintf(stderr, "Failed to allocate the mapping: %s\n", | ||
| 56 | + modbus_strerror(errno)); | ||
| 57 | + return -1; | ||
| 58 | + } | ||
| 68 | 59 | ||
| 69 | - /* Keep track of the max file descriptor */ | ||
| 70 | - fdmax = slave_socket; | 60 | + slave_socket = modbus_slave_listen_tcp(&mb_param, NB_CONNECTION); |
| 71 | 61 | ||
| 72 | - for (;;) { | ||
| 73 | - rdset = refset; | ||
| 74 | - if (select(fdmax+1, &rdset, NULL, NULL, NULL) == -1) { | ||
| 75 | - perror("Slave select() failure."); | ||
| 76 | - close_sigint(1); | ||
| 77 | - } | 62 | + signal(SIGINT, close_sigint); |
| 63 | + | ||
| 64 | + /* Clear the reference set of socket */ | ||
| 65 | + FD_ZERO(&refset); | ||
| 66 | + /* Add the slave socket */ | ||
| 67 | + FD_SET(slave_socket, &refset); | ||
| 68 | + | ||
| 69 | + /* Keep track of the max file descriptor */ | ||
| 70 | + fdmax = slave_socket; | ||
| 78 | 71 | ||
| 79 | - /* Run through the existing connections looking for data to be | ||
| 80 | - * read */ | ||
| 81 | - for (master_socket = 0; master_socket <= fdmax; master_socket++) { | ||
| 82 | - | ||
| 83 | - if (FD_ISSET(master_socket, &rdset)) { | ||
| 84 | - if (master_socket == slave_socket) { | ||
| 85 | - /* A client is asking a new connection */ | ||
| 86 | - socklen_t addrlen; | ||
| 87 | - struct sockaddr_in clientaddr; | ||
| 88 | - int newfd; | ||
| 89 | - | ||
| 90 | - /* Handle new connections */ | ||
| 91 | - addrlen = sizeof(clientaddr); | ||
| 92 | - memset(&clientaddr, 0, sizeof(clientaddr)); | ||
| 93 | - newfd = accept(slave_socket, (struct sockaddr *)&clientaddr, &addrlen); | ||
| 94 | - if (newfd == -1) { | ||
| 95 | - perror("Server accept() error"); | ||
| 96 | - } else { | ||
| 97 | - FD_SET(newfd, &refset); | ||
| 98 | - | ||
| 99 | - if (newfd > fdmax) { | ||
| 100 | - /* Keep track of the maximum */ | ||
| 101 | - fdmax = newfd; | ||
| 102 | - } | ||
| 103 | - printf("New connection from %s:%d on socket %d\n", | ||
| 104 | - inet_ntoa(clientaddr.sin_addr), clientaddr.sin_port, newfd); | ||
| 105 | - } | ||
| 106 | - } else { | ||
| 107 | - /* An already connected master has sent a new query */ | ||
| 108 | - uint8_t query[MAX_MESSAGE_LENGTH]; | ||
| 109 | - | ||
| 110 | - rc = modbus_slave_receive(&mb_param, master_socket, query); | ||
| 111 | - if (rc != -1) { | ||
| 112 | - modbus_slave_manage(&mb_param, query, rc, &mb_mapping); | ||
| 113 | - } else { | ||
| 114 | - /* Connection closed by the client, end of server */ | ||
| 115 | - printf("Connection closed on socket %d\n", master_socket); | ||
| 116 | - modbus_slave_close_tcp(master_socket); | ||
| 117 | - | ||
| 118 | - /* Remove from reference set */ | ||
| 119 | - FD_CLR(master_socket, &refset); | ||
| 120 | - | ||
| 121 | - if (master_socket == fdmax) { | ||
| 122 | - fdmax--; | ||
| 123 | - } | ||
| 124 | - } | ||
| 125 | - } | 72 | + for (;;) { |
| 73 | + rdset = refset; | ||
| 74 | + if (select(fdmax+1, &rdset, NULL, NULL, NULL) == -1) { | ||
| 75 | + perror("Slave select() failure."); | ||
| 76 | + close_sigint(1); | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + /* Run through the existing connections looking for data to be | ||
| 80 | + * read */ | ||
| 81 | + for (master_socket = 0; master_socket <= fdmax; master_socket++) { | ||
| 82 | + | ||
| 83 | + if (FD_ISSET(master_socket, &rdset)) { | ||
| 84 | + if (master_socket == slave_socket) { | ||
| 85 | + /* A client is asking a new connection */ | ||
| 86 | + socklen_t addrlen; | ||
| 87 | + struct sockaddr_in clientaddr; | ||
| 88 | + int newfd; | ||
| 89 | + | ||
| 90 | + /* Handle new connections */ | ||
| 91 | + addrlen = sizeof(clientaddr); | ||
| 92 | + memset(&clientaddr, 0, sizeof(clientaddr)); | ||
| 93 | + newfd = accept(slave_socket, (struct sockaddr *)&clientaddr, &addrlen); | ||
| 94 | + if (newfd == -1) { | ||
| 95 | + perror("Server accept() error"); | ||
| 96 | + } else { | ||
| 97 | + FD_SET(newfd, &refset); | ||
| 98 | + | ||
| 99 | + if (newfd > fdmax) { | ||
| 100 | + /* Keep track of the maximum */ | ||
| 101 | + fdmax = newfd; | ||
| 102 | + } | ||
| 103 | + printf("New connection from %s:%d on socket %d\n", | ||
| 104 | + inet_ntoa(clientaddr.sin_addr), clientaddr.sin_port, newfd); | ||
| 105 | + } | ||
| 106 | + } else { | ||
| 107 | + /* An already connected master has sent a new query */ | ||
| 108 | + uint8_t query[MAX_MESSAGE_LENGTH]; | ||
| 109 | + | ||
| 110 | + rc = modbus_slave_receive(&mb_param, master_socket, query); | ||
| 111 | + if (rc != -1) { | ||
| 112 | + modbus_slave_manage(&mb_param, query, rc, &mb_mapping); | ||
| 113 | + } else { | ||
| 114 | + /* Connection closed by the client, end of server */ | ||
| 115 | + printf("Connection closed on socket %d\n", master_socket); | ||
| 116 | + modbus_slave_close_tcp(master_socket); | ||
| 117 | + | ||
| 118 | + /* Remove from reference set */ | ||
| 119 | + FD_CLR(master_socket, &refset); | ||
| 120 | + | ||
| 121 | + if (master_socket == fdmax) { | ||
| 122 | + fdmax--; | ||
| 126 | } | 123 | } |
| 124 | + } | ||
| 127 | } | 125 | } |
| 126 | + } | ||
| 128 | } | 127 | } |
| 128 | + } | ||
| 129 | 129 | ||
| 130 | - return 0; | 130 | + return 0; |
| 131 | } | 131 | } |
tests/bandwidth-slave-one.c
| @@ -25,40 +25,40 @@ | @@ -25,40 +25,40 @@ | ||
| 25 | 25 | ||
| 26 | int main(void) | 26 | int main(void) |
| 27 | { | 27 | { |
| 28 | - int socket; | ||
| 29 | - modbus_param_t mb_param; | ||
| 30 | - modbus_mapping_t mb_mapping; | ||
| 31 | - int rc; | 28 | + int socket; |
| 29 | + modbus_param_t mb_param; | ||
| 30 | + modbus_mapping_t mb_mapping; | ||
| 31 | + int rc; | ||
| 32 | 32 | ||
| 33 | - modbus_init_tcp(&mb_param, "127.0.0.1", 1502); | 33 | + modbus_init_tcp(&mb_param, "127.0.0.1", 1502); |
| 34 | 34 | ||
| 35 | - rc = modbus_mapping_new(&mb_mapping, MAX_STATUS, 0, MAX_REGISTERS, 0); | ||
| 36 | - if (rc == -1) { | ||
| 37 | - fprintf(stderr, "Failed to allocate the mapping: %s\n", | ||
| 38 | - modbus_strerror(errno)); | ||
| 39 | - return -1; | ||
| 40 | - } | 35 | + rc = modbus_mapping_new(&mb_mapping, MAX_STATUS, 0, MAX_REGISTERS, 0); |
| 36 | + if (rc == -1) { | ||
| 37 | + fprintf(stderr, "Failed to allocate the mapping: %s\n", | ||
| 38 | + modbus_strerror(errno)); | ||
| 39 | + return -1; | ||
| 40 | + } | ||
| 41 | 41 | ||
| 42 | - socket = modbus_slave_listen_tcp(&mb_param, 1); | ||
| 43 | - modbus_slave_accept_tcp(&mb_param, &socket); | 42 | + socket = modbus_slave_listen_tcp(&mb_param, 1); |
| 43 | + modbus_slave_accept_tcp(&mb_param, &socket); | ||
| 44 | 44 | ||
| 45 | - for(;;) { | ||
| 46 | - uint8_t query[MAX_MESSAGE_LENGTH]; | 45 | + for(;;) { |
| 46 | + uint8_t query[MAX_MESSAGE_LENGTH]; | ||
| 47 | 47 | ||
| 48 | - rc = modbus_slave_receive(&mb_param, -1, query); | ||
| 49 | - if (rc >= 0) { | ||
| 50 | - modbus_slave_manage(&mb_param, query, rc, &mb_mapping); | ||
| 51 | - } else { | ||
| 52 | - /* Connection closed by the client or server */ | ||
| 53 | - break; | ||
| 54 | - } | 48 | + rc = modbus_slave_receive(&mb_param, -1, query); |
| 49 | + if (rc >= 0) { | ||
| 50 | + modbus_slave_manage(&mb_param, query, rc, &mb_mapping); | ||
| 51 | + } else { | ||
| 52 | + /* Connection closed by the client or server */ | ||
| 53 | + break; | ||
| 55 | } | 54 | } |
| 55 | + } | ||
| 56 | 56 | ||
| 57 | - printf("Quit the loop: %s\n", modbus_strerror(errno)); | 57 | + printf("Quit the loop: %s\n", modbus_strerror(errno)); |
| 58 | 58 | ||
| 59 | - close(socket); | ||
| 60 | - modbus_mapping_free(&mb_mapping); | ||
| 61 | - modbus_close(&mb_param); | 59 | + close(socket); |
| 60 | + modbus_mapping_free(&mb_mapping); | ||
| 61 | + modbus_close(&mb_param); | ||
| 62 | 62 | ||
| 63 | - return 0; | 63 | + return 0; |
| 64 | } | 64 | } |
tests/random-test-master.c
| @@ -47,175 +47,175 @@ | @@ -47,175 +47,175 @@ | ||
| 47 | */ | 47 | */ |
| 48 | int main(void) | 48 | int main(void) |
| 49 | { | 49 | { |
| 50 | - int rc; | ||
| 51 | - int nb_fail; | ||
| 52 | - int nb_loop; | ||
| 53 | - int addr; | ||
| 54 | - int nb; | ||
| 55 | - uint8_t *tab_rq_status; | ||
| 56 | - uint8_t *tab_rp_status; | ||
| 57 | - uint16_t *tab_rq_registers; | ||
| 58 | - uint16_t *tab_rp_registers; | ||
| 59 | - modbus_param_t mb_param; | ||
| 60 | - | ||
| 61 | - /* | ||
| 62 | - modbus_init_rtu(&mb_param, "/dev/ttyS0", 19200, 'N', 8, 1, MY_ID); | ||
| 63 | - */ | ||
| 64 | - | ||
| 65 | - /* TCP */ | ||
| 66 | - modbus_init_tcp(&mb_param, "127.0.0.1", 1502); | ||
| 67 | - modbus_set_debug(&mb_param, TRUE); | ||
| 68 | - if (modbus_connect(&mb_param) == -1) { | ||
| 69 | - fprintf(stderr, "Connection failed: %s\n", | ||
| 70 | - modbus_strerror(errno)); | ||
| 71 | - return -1; | ||
| 72 | - } | ||
| 73 | - | ||
| 74 | - /* Allocate and initialize the different memory spaces */ | ||
| 75 | - nb = ADDRESS_END - ADDRESS_START; | ||
| 76 | - | ||
| 77 | - tab_rq_status = (uint8_t *) malloc(nb * sizeof(uint8_t)); | ||
| 78 | - memset(tab_rq_status, 0, nb * sizeof(uint8_t)); | ||
| 79 | - | ||
| 80 | - tab_rp_status = (uint8_t *) malloc(nb * sizeof(uint8_t)); | ||
| 81 | - memset(tab_rp_status, 0, nb * sizeof(uint8_t)); | ||
| 82 | - | ||
| 83 | - tab_rq_registers = (uint16_t *) malloc(nb * sizeof(uint16_t)); | ||
| 84 | - memset(tab_rq_registers, 0, nb * sizeof(uint16_t)); | ||
| 85 | - | ||
| 86 | - tab_rp_registers = (uint16_t *) malloc(nb * sizeof(uint16_t)); | ||
| 87 | - memset(tab_rp_registers, 0, nb * sizeof(uint16_t)); | ||
| 88 | - | ||
| 89 | - nb_loop = nb_fail = 0; | ||
| 90 | - while (nb_loop++ < LOOP) { | ||
| 91 | - for (addr = ADDRESS_START; addr <= ADDRESS_END; addr++) { | ||
| 92 | - int i; | ||
| 93 | - | ||
| 94 | - /* Random numbers (short) */ | ||
| 95 | - for (i=0; i<nb; i++) { | ||
| 96 | - tab_rq_registers[i] = (uint16_t) (65535.0*rand() / (RAND_MAX + 1.0)); | ||
| 97 | - tab_rq_status[i] = tab_rq_registers[i] % 2; | ||
| 98 | - } | ||
| 99 | - nb = ADDRESS_END - addr; | ||
| 100 | - | ||
| 101 | - /* SINGLE COIL */ | ||
| 102 | - rc = force_single_coil(&mb_param, SERVER_ID, addr, tab_rq_status[0]); | ||
| 103 | - if (rc != 1) { | ||
| 104 | - printf("ERROR force_single_coil (%d)\n", rc); | ||
| 105 | - printf("Slave = %d, address = %d, value = %d\n", | ||
| 106 | - SERVER_ID, addr, tab_rq_status[0]); | ||
| 107 | - nb_fail++; | ||
| 108 | - } else { | ||
| 109 | - rc = read_coil_status(&mb_param, SERVER_ID, addr, 1, tab_rp_status); | ||
| 110 | - if (rc != 1 || tab_rq_status[0] != tab_rp_status[0]) { | ||
| 111 | - printf("ERROR read_coil_status single (%d)\n", rc); | ||
| 112 | - printf("Slave = %d, address = %d\n", | ||
| 113 | - SERVER_ID, addr); | ||
| 114 | - nb_fail++; | ||
| 115 | - } | ||
| 116 | - } | ||
| 117 | - | ||
| 118 | - /* MULTIPLE COILS */ | ||
| 119 | - rc = force_multiple_coils(&mb_param, SERVER_ID, addr, nb, tab_rq_status); | ||
| 120 | - if (rc != nb) { | ||
| 121 | - printf("ERROR force_multiple_coils (%d)\n", rc); | ||
| 122 | - printf("Slave = %d, address = %d, nb = %d\n", | ||
| 123 | - SERVER_ID, addr, nb); | ||
| 124 | - nb_fail++; | ||
| 125 | - } else { | ||
| 126 | - rc = read_coil_status(&mb_param, SERVER_ID, addr, nb, tab_rp_status); | ||
| 127 | - if (rc != nb) { | ||
| 128 | - printf("ERROR read_coil_status\n"); | ||
| 129 | - printf("Slave = %d, address = %d, nb = %d\n", | ||
| 130 | - SERVER_ID, addr, nb); | ||
| 131 | - nb_fail++; | ||
| 132 | - } else { | ||
| 133 | - for (i=0; i<nb; i++) { | ||
| 134 | - if (tab_rp_status[i] != tab_rq_status[i]) { | ||
| 135 | - printf("ERROR read_coil_status\n"); | ||
| 136 | - printf("Slave = %d, address = %d, value %d (0x%X) != %d (0x%X)\n", | ||
| 137 | - SERVER_ID, addr, | ||
| 138 | - tab_rq_status[i], tab_rq_status[i], | ||
| 139 | - tab_rp_status[i], tab_rp_status[i]); | ||
| 140 | - nb_fail++; | ||
| 141 | - } | ||
| 142 | - } | ||
| 143 | - } | ||
| 144 | - } | ||
| 145 | - | ||
| 146 | - /* SINGLE REGISTER */ | ||
| 147 | - rc = preset_single_register(&mb_param, SERVER_ID, addr, tab_rq_registers[0]); | ||
| 148 | - if (rc != 1) { | ||
| 149 | - printf("ERROR preset_single_register (%d)\n", rc); | ||
| 150 | - printf("Slave = %d, address = %d, value = %d (0x%X)\n", | ||
| 151 | - SERVER_ID, addr, tab_rq_registers[0], tab_rq_registers[0]); | ||
| 152 | - nb_fail++; | ||
| 153 | - } else { | ||
| 154 | - rc = read_holding_registers(&mb_param, SERVER_ID, addr, 1, tab_rp_registers); | ||
| 155 | - if (rc != 1) { | ||
| 156 | - printf("ERROR read_holding_registers single (%d)\n", rc); | ||
| 157 | - printf("Slave = %d, address = %d\n", | ||
| 158 | - SERVER_ID, addr); | ||
| 159 | - nb_fail++; | ||
| 160 | - } else { | ||
| 161 | - if (tab_rq_registers[0] != tab_rp_registers[0]) { | ||
| 162 | - printf("ERROR read_holding_registers single\n"); | ||
| 163 | - printf("Slave = %d, address = %d, value = %d (0x%X) != %d (0x%X)\n", | ||
| 164 | - SERVER_ID, addr, | ||
| 165 | - tab_rq_registers[0], tab_rq_registers[0], | ||
| 166 | - tab_rp_registers[0], tab_rp_registers[0]); | ||
| 167 | - nb_fail++; | ||
| 168 | - } | ||
| 169 | - } | 50 | + int rc; |
| 51 | + int nb_fail; | ||
| 52 | + int nb_loop; | ||
| 53 | + int addr; | ||
| 54 | + int nb; | ||
| 55 | + uint8_t *tab_rq_status; | ||
| 56 | + uint8_t *tab_rp_status; | ||
| 57 | + uint16_t *tab_rq_registers; | ||
| 58 | + uint16_t *tab_rp_registers; | ||
| 59 | + modbus_param_t mb_param; | ||
| 60 | + | ||
| 61 | + /* | ||
| 62 | + modbus_init_rtu(&mb_param, "/dev/ttyS0", 19200, 'N', 8, 1, MY_ID); | ||
| 63 | + */ | ||
| 64 | + | ||
| 65 | + /* TCP */ | ||
| 66 | + modbus_init_tcp(&mb_param, "127.0.0.1", 1502); | ||
| 67 | + modbus_set_debug(&mb_param, TRUE); | ||
| 68 | + if (modbus_connect(&mb_param) == -1) { | ||
| 69 | + fprintf(stderr, "Connection failed: %s\n", | ||
| 70 | + modbus_strerror(errno)); | ||
| 71 | + return -1; | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + /* Allocate and initialize the different memory spaces */ | ||
| 75 | + nb = ADDRESS_END - ADDRESS_START; | ||
| 76 | + | ||
| 77 | + tab_rq_status = (uint8_t *) malloc(nb * sizeof(uint8_t)); | ||
| 78 | + memset(tab_rq_status, 0, nb * sizeof(uint8_t)); | ||
| 79 | + | ||
| 80 | + tab_rp_status = (uint8_t *) malloc(nb * sizeof(uint8_t)); | ||
| 81 | + memset(tab_rp_status, 0, nb * sizeof(uint8_t)); | ||
| 82 | + | ||
| 83 | + tab_rq_registers = (uint16_t *) malloc(nb * sizeof(uint16_t)); | ||
| 84 | + memset(tab_rq_registers, 0, nb * sizeof(uint16_t)); | ||
| 85 | + | ||
| 86 | + tab_rp_registers = (uint16_t *) malloc(nb * sizeof(uint16_t)); | ||
| 87 | + memset(tab_rp_registers, 0, nb * sizeof(uint16_t)); | ||
| 88 | + | ||
| 89 | + nb_loop = nb_fail = 0; | ||
| 90 | + while (nb_loop++ < LOOP) { | ||
| 91 | + for (addr = ADDRESS_START; addr <= ADDRESS_END; addr++) { | ||
| 92 | + int i; | ||
| 93 | + | ||
| 94 | + /* Random numbers (short) */ | ||
| 95 | + for (i=0; i<nb; i++) { | ||
| 96 | + tab_rq_registers[i] = (uint16_t) (65535.0*rand() / (RAND_MAX + 1.0)); | ||
| 97 | + tab_rq_status[i] = tab_rq_registers[i] % 2; | ||
| 98 | + } | ||
| 99 | + nb = ADDRESS_END - addr; | ||
| 100 | + | ||
| 101 | + /* SINGLE COIL */ | ||
| 102 | + rc = force_single_coil(&mb_param, SERVER_ID, addr, tab_rq_status[0]); | ||
| 103 | + if (rc != 1) { | ||
| 104 | + printf("ERROR force_single_coil (%d)\n", rc); | ||
| 105 | + printf("Slave = %d, address = %d, value = %d\n", | ||
| 106 | + SERVER_ID, addr, tab_rq_status[0]); | ||
| 107 | + nb_fail++; | ||
| 108 | + } else { | ||
| 109 | + rc = read_coil_status(&mb_param, SERVER_ID, addr, 1, tab_rp_status); | ||
| 110 | + if (rc != 1 || tab_rq_status[0] != tab_rp_status[0]) { | ||
| 111 | + printf("ERROR read_coil_status single (%d)\n", rc); | ||
| 112 | + printf("Slave = %d, address = %d\n", | ||
| 113 | + SERVER_ID, addr); | ||
| 114 | + nb_fail++; | ||
| 115 | + } | ||
| 116 | + } | ||
| 117 | + | ||
| 118 | + /* MULTIPLE COILS */ | ||
| 119 | + rc = force_multiple_coils(&mb_param, SERVER_ID, addr, nb, tab_rq_status); | ||
| 120 | + if (rc != nb) { | ||
| 121 | + printf("ERROR force_multiple_coils (%d)\n", rc); | ||
| 122 | + printf("Slave = %d, address = %d, nb = %d\n", | ||
| 123 | + SERVER_ID, addr, nb); | ||
| 124 | + nb_fail++; | ||
| 125 | + } else { | ||
| 126 | + rc = read_coil_status(&mb_param, SERVER_ID, addr, nb, tab_rp_status); | ||
| 127 | + if (rc != nb) { | ||
| 128 | + printf("ERROR read_coil_status\n"); | ||
| 129 | + printf("Slave = %d, address = %d, nb = %d\n", | ||
| 130 | + SERVER_ID, addr, nb); | ||
| 131 | + nb_fail++; | ||
| 132 | + } else { | ||
| 133 | + for (i=0; i<nb; i++) { | ||
| 134 | + if (tab_rp_status[i] != tab_rq_status[i]) { | ||
| 135 | + printf("ERROR read_coil_status\n"); | ||
| 136 | + printf("Slave = %d, address = %d, value %d (0x%X) != %d (0x%X)\n", | ||
| 137 | + SERVER_ID, addr, | ||
| 138 | + tab_rq_status[i], tab_rq_status[i], | ||
| 139 | + tab_rp_status[i], tab_rp_status[i]); | ||
| 140 | + nb_fail++; | ||
| 170 | } | 141 | } |
| 171 | - | ||
| 172 | - /* MULTIPLE REGISTERS */ | ||
| 173 | - rc = preset_multiple_registers(&mb_param, SERVER_ID, addr, nb, | ||
| 174 | - tab_rq_registers); | ||
| 175 | - if (rc != nb) { | ||
| 176 | - printf("ERROR preset_multiple_registers (%d)\n", rc); | ||
| 177 | - printf("Slave = %d, address = %d, nb = %d\n", | ||
| 178 | - SERVER_ID, addr, nb); | ||
| 179 | - nb_fail++; | ||
| 180 | - } else { | ||
| 181 | - rc = read_holding_registers(&mb_param, SERVER_ID, addr, nb, | ||
| 182 | - tab_rp_registers); | ||
| 183 | - if (rc != nb) { | ||
| 184 | - printf("ERROR read_holding_registers (%d)\n", rc); | ||
| 185 | - printf("Slave = %d, address = %d, nb = %d\n", | ||
| 186 | - SERVER_ID, addr, nb); | ||
| 187 | - nb_fail++; | ||
| 188 | - } else { | ||
| 189 | - for (i=0; i<nb; i++) { | ||
| 190 | - if (tab_rq_registers[i] != tab_rp_registers[i]) { | ||
| 191 | - printf("ERROR read_holding_registers\n"); | ||
| 192 | - printf("Slave = %d, address = %d, value %d (0x%X) != %d (0x%X)\n", | ||
| 193 | - SERVER_ID, addr, | ||
| 194 | - tab_rq_registers[i], tab_rq_registers[i], | ||
| 195 | - tab_rp_registers[i], tab_rp_registers[i]); | ||
| 196 | - nb_fail++; | ||
| 197 | - } | ||
| 198 | - } | ||
| 199 | - } | 142 | + } |
| 143 | + } | ||
| 144 | + } | ||
| 145 | + | ||
| 146 | + /* SINGLE REGISTER */ | ||
| 147 | + rc = preset_single_register(&mb_param, SERVER_ID, addr, tab_rq_registers[0]); | ||
| 148 | + if (rc != 1) { | ||
| 149 | + printf("ERROR preset_single_register (%d)\n", rc); | ||
| 150 | + printf("Slave = %d, address = %d, value = %d (0x%X)\n", | ||
| 151 | + SERVER_ID, addr, tab_rq_registers[0], tab_rq_registers[0]); | ||
| 152 | + nb_fail++; | ||
| 153 | + } else { | ||
| 154 | + rc = read_holding_registers(&mb_param, SERVER_ID, addr, 1, tab_rp_registers); | ||
| 155 | + if (rc != 1) { | ||
| 156 | + printf("ERROR read_holding_registers single (%d)\n", rc); | ||
| 157 | + printf("Slave = %d, address = %d\n", | ||
| 158 | + SERVER_ID, addr); | ||
| 159 | + nb_fail++; | ||
| 160 | + } else { | ||
| 161 | + if (tab_rq_registers[0] != tab_rp_registers[0]) { | ||
| 162 | + printf("ERROR read_holding_registers single\n"); | ||
| 163 | + printf("Slave = %d, address = %d, value = %d (0x%X) != %d (0x%X)\n", | ||
| 164 | + SERVER_ID, addr, | ||
| 165 | + tab_rq_registers[0], tab_rq_registers[0], | ||
| 166 | + tab_rp_registers[0], tab_rp_registers[0]); | ||
| 167 | + nb_fail++; | ||
| 168 | + } | ||
| 169 | + } | ||
| 170 | + } | ||
| 171 | + | ||
| 172 | + /* MULTIPLE REGISTERS */ | ||
| 173 | + rc = preset_multiple_registers(&mb_param, SERVER_ID, addr, nb, | ||
| 174 | + tab_rq_registers); | ||
| 175 | + if (rc != nb) { | ||
| 176 | + printf("ERROR preset_multiple_registers (%d)\n", rc); | ||
| 177 | + printf("Slave = %d, address = %d, nb = %d\n", | ||
| 178 | + SERVER_ID, addr, nb); | ||
| 179 | + nb_fail++; | ||
| 180 | + } else { | ||
| 181 | + rc = read_holding_registers(&mb_param, SERVER_ID, addr, nb, | ||
| 182 | + tab_rp_registers); | ||
| 183 | + if (rc != nb) { | ||
| 184 | + printf("ERROR read_holding_registers (%d)\n", rc); | ||
| 185 | + printf("Slave = %d, address = %d, nb = %d\n", | ||
| 186 | + SERVER_ID, addr, nb); | ||
| 187 | + nb_fail++; | ||
| 188 | + } else { | ||
| 189 | + for (i=0; i<nb; i++) { | ||
| 190 | + if (tab_rq_registers[i] != tab_rp_registers[i]) { | ||
| 191 | + printf("ERROR read_holding_registers\n"); | ||
| 192 | + printf("Slave = %d, address = %d, value %d (0x%X) != %d (0x%X)\n", | ||
| 193 | + SERVER_ID, addr, | ||
| 194 | + tab_rq_registers[i], tab_rq_registers[i], | ||
| 195 | + tab_rp_registers[i], tab_rp_registers[i]); | ||
| 196 | + nb_fail++; | ||
| 200 | } | 197 | } |
| 201 | - | 198 | + } |
| 202 | } | 199 | } |
| 200 | + } | ||
| 203 | 201 | ||
| 204 | - printf("Test: "); | ||
| 205 | - if (nb_fail) | ||
| 206 | - printf("%d FAILS\n", nb_fail); | ||
| 207 | - else | ||
| 208 | - printf("SUCCESS\n"); | ||
| 209 | } | 202 | } |
| 210 | 203 | ||
| 211 | - /* Free the memory */ | ||
| 212 | - free(tab_rq_status); | ||
| 213 | - free(tab_rp_status); | ||
| 214 | - free(tab_rq_registers); | ||
| 215 | - free(tab_rp_registers); | 204 | + printf("Test: "); |
| 205 | + if (nb_fail) | ||
| 206 | + printf("%d FAILS\n", nb_fail); | ||
| 207 | + else | ||
| 208 | + printf("SUCCESS\n"); | ||
| 209 | + } | ||
| 210 | + | ||
| 211 | + /* Free the memory */ | ||
| 212 | + free(tab_rq_status); | ||
| 213 | + free(tab_rp_status); | ||
| 214 | + free(tab_rq_registers); | ||
| 215 | + free(tab_rp_registers); | ||
| 216 | 216 | ||
| 217 | - /* Close the connection */ | ||
| 218 | - modbus_close(&mb_param); | 217 | + /* Close the connection */ |
| 218 | + modbus_close(&mb_param); | ||
| 219 | 219 | ||
| 220 | - return 0; | 220 | + return 0; |
| 221 | } | 221 | } |
tests/random-test-slave.c
| @@ -24,43 +24,43 @@ | @@ -24,43 +24,43 @@ | ||
| 24 | 24 | ||
| 25 | int main(void) | 25 | int main(void) |
| 26 | { | 26 | { |
| 27 | - int socket; | ||
| 28 | - modbus_param_t mb_param; | ||
| 29 | - modbus_mapping_t mb_mapping; | ||
| 30 | - int rc; | 27 | + int socket; |
| 28 | + modbus_param_t mb_param; | ||
| 29 | + modbus_mapping_t mb_mapping; | ||
| 30 | + int rc; | ||
| 31 | 31 | ||
| 32 | - modbus_init_tcp(&mb_param, "127.0.0.1", 1502); | ||
| 33 | - /* modbus_set_debug(&mb_param, TRUE); */ | 32 | + modbus_init_tcp(&mb_param, "127.0.0.1", 1502); |
| 33 | + /* modbus_set_debug(&mb_param, TRUE); */ | ||
| 34 | 34 | ||
| 35 | - rc = modbus_mapping_new(&mb_mapping, 500, 500, 500, 500); | ||
| 36 | - if (rc == -1) { | ||
| 37 | - fprintf(stderr, "Failed to allocate the mapping: %s\n", | ||
| 38 | - modbus_strerror(errno)); | ||
| 39 | - return -1; | ||
| 40 | - } | 35 | + rc = modbus_mapping_new(&mb_mapping, 500, 500, 500, 500); |
| 36 | + if (rc == -1) { | ||
| 37 | + fprintf(stderr, "Failed to allocate the mapping: %s\n", | ||
| 38 | + modbus_strerror(errno)); | ||
| 39 | + return -1; | ||
| 40 | + } | ||
| 41 | 41 | ||
| 42 | - socket = modbus_slave_listen_tcp(&mb_param, 1); | ||
| 43 | - modbus_slave_accept_tcp(&mb_param, &socket); | 42 | + socket = modbus_slave_listen_tcp(&mb_param, 1); |
| 43 | + modbus_slave_accept_tcp(&mb_param, &socket); | ||
| 44 | 44 | ||
| 45 | - for (;;) { | ||
| 46 | - uint8_t query[MAX_MESSAGE_LENGTH]; | ||
| 47 | - int rc; | 45 | + for (;;) { |
| 46 | + uint8_t query[MAX_MESSAGE_LENGTH]; | ||
| 47 | + int rc; | ||
| 48 | 48 | ||
| 49 | - rc = modbus_slave_receive(&mb_param, -1, query); | ||
| 50 | - if (rc != -1) { | ||
| 51 | - /* rc is the query size */ | ||
| 52 | - modbus_slave_manage(&mb_param, query, rc, &mb_mapping); | ||
| 53 | - } else { | ||
| 54 | - /* Connection closed by the client or error */ | ||
| 55 | - break; | ||
| 56 | - } | 49 | + rc = modbus_slave_receive(&mb_param, -1, query); |
| 50 | + if (rc != -1) { | ||
| 51 | + /* rc is the query size */ | ||
| 52 | + modbus_slave_manage(&mb_param, query, rc, &mb_mapping); | ||
| 53 | + } else { | ||
| 54 | + /* Connection closed by the client or error */ | ||
| 55 | + break; | ||
| 57 | } | 56 | } |
| 57 | + } | ||
| 58 | 58 | ||
| 59 | - printf("Quit the loop: %s\n", modbus_strerror(errno)); | 59 | + printf("Quit the loop: %s\n", modbus_strerror(errno)); |
| 60 | 60 | ||
| 61 | - close(socket); | ||
| 62 | - modbus_mapping_free(&mb_mapping); | ||
| 63 | - modbus_close(&mb_param); | 61 | + close(socket); |
| 62 | + modbus_mapping_free(&mb_mapping); | ||
| 63 | + modbus_close(&mb_param); | ||
| 64 | 64 | ||
| 65 | - return 0; | 65 | + return 0; |
| 66 | } | 66 | } |
tests/unit-test-master.c
| @@ -26,516 +26,516 @@ | @@ -26,516 +26,516 @@ | ||
| 26 | 26 | ||
| 27 | int main(void) | 27 | int main(void) |
| 28 | { | 28 | { |
| 29 | - uint8_t *tab_rp_status; | ||
| 30 | - uint16_t *tab_rp_registers; | ||
| 31 | - uint16_t *tab_rp_registers_bad; | ||
| 32 | - modbus_param_t mb_param; | ||
| 33 | - int i; | ||
| 34 | - uint8_t value; | ||
| 35 | - int address; | ||
| 36 | - int nb_points; | ||
| 37 | - int rc; | ||
| 38 | - float real; | ||
| 39 | - struct timeval timeout_begin_old; | ||
| 40 | - struct timeval timeout_begin_new; | ||
| 41 | - | ||
| 42 | - /* | ||
| 43 | - modbus_init_rtu(&mb_param, "/dev/ttyS0", 19200, 'N', 8, 1, | ||
| 44 | - CLIENT_ID); | ||
| 45 | - */ | ||
| 46 | - | ||
| 47 | - /* TCP */ | ||
| 48 | - modbus_init_tcp(&mb_param, "127.0.0.1", 1502); | ||
| 49 | - modbus_set_debug(&mb_param, TRUE); | ||
| 50 | - | ||
| 51 | - if (modbus_connect(&mb_param) == -1) { | ||
| 52 | - fprintf(stderr, "Connection failed: %s\n", | ||
| 53 | - modbus_strerror(errno)); | ||
| 54 | - return -1; | ||
| 55 | - } | ||
| 56 | - | ||
| 57 | - /* Allocate and initialize the memory to store the status */ | ||
| 58 | - nb_points = (UT_COIL_STATUS_NB_POINTS > UT_INPUT_STATUS_NB_POINTS) ? | ||
| 59 | - UT_COIL_STATUS_NB_POINTS : UT_INPUT_STATUS_NB_POINTS; | ||
| 60 | - tab_rp_status = (uint8_t *) malloc(nb_points * sizeof(uint8_t)); | ||
| 61 | - memset(tab_rp_status, 0, nb_points * sizeof(uint8_t)); | ||
| 62 | - | ||
| 63 | - /* Allocate and initialize the memory to store the registers */ | ||
| 64 | - nb_points = (UT_HOLDING_REGISTERS_NB_POINTS > | ||
| 65 | - UT_INPUT_REGISTERS_NB_POINTS) ? | ||
| 66 | - UT_HOLDING_REGISTERS_NB_POINTS : UT_INPUT_REGISTERS_NB_POINTS; | ||
| 67 | - tab_rp_registers = (uint16_t *) malloc(nb_points * sizeof(uint16_t)); | ||
| 68 | - memset(tab_rp_registers, 0, nb_points * sizeof(uint16_t)); | ||
| 69 | - | ||
| 70 | - printf("** UNIT TESTING **\n"); | ||
| 71 | - | ||
| 72 | - printf("\nTEST WRITE/READ:\n"); | ||
| 73 | - | ||
| 74 | - /** COIL STATUS **/ | ||
| 75 | - | ||
| 76 | - /* Single */ | ||
| 77 | - rc = force_single_coil(&mb_param, SERVER_ID, UT_COIL_STATUS_ADDRESS, ON); | ||
| 78 | - printf("1/2 force_single_coil: "); | ||
| 79 | - if (rc == 1) { | ||
| 80 | - printf("OK\n"); | 29 | + uint8_t *tab_rp_status; |
| 30 | + uint16_t *tab_rp_registers; | ||
| 31 | + uint16_t *tab_rp_registers_bad; | ||
| 32 | + modbus_param_t mb_param; | ||
| 33 | + int i; | ||
| 34 | + uint8_t value; | ||
| 35 | + int address; | ||
| 36 | + int nb_points; | ||
| 37 | + int rc; | ||
| 38 | + float real; | ||
| 39 | + struct timeval timeout_begin_old; | ||
| 40 | + struct timeval timeout_begin_new; | ||
| 41 | + | ||
| 42 | + /* | ||
| 43 | + modbus_init_rtu(&mb_param, "/dev/ttyS0", 19200, 'N', 8, 1, | ||
| 44 | + CLIENT_ID); | ||
| 45 | + */ | ||
| 46 | + | ||
| 47 | + /* TCP */ | ||
| 48 | + modbus_init_tcp(&mb_param, "127.0.0.1", 1502); | ||
| 49 | + modbus_set_debug(&mb_param, TRUE); | ||
| 50 | + | ||
| 51 | + if (modbus_connect(&mb_param) == -1) { | ||
| 52 | + fprintf(stderr, "Connection failed: %s\n", | ||
| 53 | + modbus_strerror(errno)); | ||
| 54 | + return -1; | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + /* Allocate and initialize the memory to store the status */ | ||
| 58 | + nb_points = (UT_COIL_STATUS_NB_POINTS > UT_INPUT_STATUS_NB_POINTS) ? | ||
| 59 | + UT_COIL_STATUS_NB_POINTS : UT_INPUT_STATUS_NB_POINTS; | ||
| 60 | + tab_rp_status = (uint8_t *) malloc(nb_points * sizeof(uint8_t)); | ||
| 61 | + memset(tab_rp_status, 0, nb_points * sizeof(uint8_t)); | ||
| 62 | + | ||
| 63 | + /* Allocate and initialize the memory to store the registers */ | ||
| 64 | + nb_points = (UT_HOLDING_REGISTERS_NB_POINTS > | ||
| 65 | + UT_INPUT_REGISTERS_NB_POINTS) ? | ||
| 66 | + UT_HOLDING_REGISTERS_NB_POINTS : UT_INPUT_REGISTERS_NB_POINTS; | ||
| 67 | + tab_rp_registers = (uint16_t *) malloc(nb_points * sizeof(uint16_t)); | ||
| 68 | + memset(tab_rp_registers, 0, nb_points * sizeof(uint16_t)); | ||
| 69 | + | ||
| 70 | + printf("** UNIT TESTING **\n"); | ||
| 71 | + | ||
| 72 | + printf("\nTEST WRITE/READ:\n"); | ||
| 73 | + | ||
| 74 | + /** COIL STATUS **/ | ||
| 75 | + | ||
| 76 | + /* Single */ | ||
| 77 | + rc = force_single_coil(&mb_param, SERVER_ID, UT_COIL_STATUS_ADDRESS, ON); | ||
| 78 | + printf("1/2 force_single_coil: "); | ||
| 79 | + if (rc == 1) { | ||
| 80 | + printf("OK\n"); | ||
| 81 | + } else { | ||
| 82 | + printf("FAILED\n"); | ||
| 83 | + goto close; | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + rc = read_coil_status(&mb_param, SERVER_ID, UT_COIL_STATUS_ADDRESS, 1, | ||
| 87 | + tab_rp_status); | ||
| 88 | + printf("2/2 read_coil_status: "); | ||
| 89 | + if (rc != 1) { | ||
| 90 | + printf("FAILED (nb points %d)\n", rc); | ||
| 91 | + goto close; | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + if (tab_rp_status[0] != ON) { | ||
| 95 | + printf("FAILED (%0X = != %0X)\n", tab_rp_status[0], ON); | ||
| 96 | + goto close; | ||
| 97 | + } | ||
| 98 | + printf("OK\n"); | ||
| 99 | + /* End single */ | ||
| 100 | + | ||
| 101 | + /* Multiple coils */ | ||
| 102 | + { | ||
| 103 | + uint8_t tab_value[UT_COIL_STATUS_NB_POINTS]; | ||
| 104 | + | ||
| 105 | + set_bits_from_bytes(tab_value, 0, UT_COIL_STATUS_NB_POINTS, | ||
| 106 | + UT_COIL_STATUS_TAB); | ||
| 107 | + rc = force_multiple_coils(&mb_param, SERVER_ID, | ||
| 108 | + UT_COIL_STATUS_ADDRESS, | ||
| 109 | + UT_COIL_STATUS_NB_POINTS, | ||
| 110 | + tab_value); | ||
| 111 | + printf("1/2 force_multiple_coils: "); | ||
| 112 | + if (rc == UT_COIL_STATUS_NB_POINTS) { | ||
| 113 | + printf("OK\n"); | ||
| 81 | } else { | 114 | } else { |
| 82 | - printf("FAILED\n"); | ||
| 83 | - goto close; | ||
| 84 | - } | ||
| 85 | - | ||
| 86 | - rc = read_coil_status(&mb_param, SERVER_ID, UT_COIL_STATUS_ADDRESS, 1, | ||
| 87 | - tab_rp_status); | ||
| 88 | - printf("2/2 read_coil_status: "); | ||
| 89 | - if (rc != 1) { | ||
| 90 | - printf("FAILED (nb points %d)\n", rc); | ||
| 91 | - goto close; | ||
| 92 | - } | ||
| 93 | - | ||
| 94 | - if (tab_rp_status[0] != ON) { | ||
| 95 | - printf("FAILED (%0X = != %0X)\n", tab_rp_status[0], ON); | ||
| 96 | - goto close; | ||
| 97 | - } | 115 | + printf("FAILED\n"); |
| 116 | + goto close; | ||
| 117 | + } | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + rc = read_coil_status(&mb_param, SERVER_ID, UT_COIL_STATUS_ADDRESS, | ||
| 121 | + UT_COIL_STATUS_NB_POINTS, tab_rp_status); | ||
| 122 | + printf("2/2 read_coil_status: "); | ||
| 123 | + if (rc != UT_COIL_STATUS_NB_POINTS) { | ||
| 124 | + printf("FAILED (nb points %d)\n", rc); | ||
| 125 | + goto close; | ||
| 126 | + } | ||
| 127 | + | ||
| 128 | + i = 0; | ||
| 129 | + address = UT_COIL_STATUS_ADDRESS; | ||
| 130 | + nb_points = UT_COIL_STATUS_NB_POINTS; | ||
| 131 | + while (nb_points > 0) { | ||
| 132 | + int nb_bits = (nb_points > 8) ? 8 : nb_points; | ||
| 133 | + | ||
| 134 | + value = get_byte_from_bits(tab_rp_status, i*8, nb_bits); | ||
| 135 | + if (value != UT_COIL_STATUS_TAB[i]) { | ||
| 136 | + printf("FAILED (%0X != %0X)\n", | ||
| 137 | + value, UT_COIL_STATUS_TAB[i]); | ||
| 138 | + goto close; | ||
| 139 | + } | ||
| 140 | + | ||
| 141 | + nb_points -= nb_bits; | ||
| 142 | + i++; | ||
| 143 | + } | ||
| 144 | + printf("OK\n"); | ||
| 145 | + /* End of multiple coils */ | ||
| 146 | + | ||
| 147 | + /** INPUT STATUS **/ | ||
| 148 | + rc = read_input_status(&mb_param, SERVER_ID, UT_INPUT_STATUS_ADDRESS, | ||
| 149 | + UT_INPUT_STATUS_NB_POINTS, tab_rp_status); | ||
| 150 | + printf("1/1 read_input_status: "); | ||
| 151 | + | ||
| 152 | + if (rc != UT_INPUT_STATUS_NB_POINTS) { | ||
| 153 | + printf("FAILED (nb points %d)\n", rc); | ||
| 154 | + goto close; | ||
| 155 | + } | ||
| 156 | + | ||
| 157 | + i = 0; | ||
| 158 | + address = UT_INPUT_STATUS_ADDRESS; | ||
| 159 | + nb_points = UT_INPUT_STATUS_NB_POINTS; | ||
| 160 | + while (nb_points > 0) { | ||
| 161 | + int nb_bits = (nb_points > 8) ? 8 : nb_points; | ||
| 162 | + | ||
| 163 | + value = get_byte_from_bits(tab_rp_status, i*8, nb_bits); | ||
| 164 | + if (value != UT_INPUT_STATUS_TAB[i]) { | ||
| 165 | + printf("FAILED (%0X != %0X)\n", | ||
| 166 | + value, UT_INPUT_STATUS_TAB[i]); | ||
| 167 | + goto close; | ||
| 168 | + } | ||
| 169 | + | ||
| 170 | + nb_points -= nb_bits; | ||
| 171 | + i++; | ||
| 172 | + } | ||
| 173 | + printf("OK\n"); | ||
| 174 | + | ||
| 175 | + /** HOLDING REGISTERS **/ | ||
| 176 | + | ||
| 177 | + /* Single register */ | ||
| 178 | + rc = preset_single_register(&mb_param, SERVER_ID, | ||
| 179 | + UT_HOLDING_REGISTERS_ADDRESS, 0x1234); | ||
| 180 | + printf("1/2 preset_single_register: "); | ||
| 181 | + if (rc == 1) { | ||
| 98 | printf("OK\n"); | 182 | printf("OK\n"); |
| 99 | - /* End single */ | ||
| 100 | - | ||
| 101 | - /* Multiple coils */ | ||
| 102 | - { | ||
| 103 | - uint8_t tab_value[UT_COIL_STATUS_NB_POINTS]; | ||
| 104 | - | ||
| 105 | - set_bits_from_bytes(tab_value, 0, UT_COIL_STATUS_NB_POINTS, | ||
| 106 | - UT_COIL_STATUS_TAB); | ||
| 107 | - rc = force_multiple_coils(&mb_param, SERVER_ID, | ||
| 108 | - UT_COIL_STATUS_ADDRESS, | ||
| 109 | - UT_COIL_STATUS_NB_POINTS, | ||
| 110 | - tab_value); | ||
| 111 | - printf("1/2 force_multiple_coils: "); | ||
| 112 | - if (rc == UT_COIL_STATUS_NB_POINTS) { | ||
| 113 | - printf("OK\n"); | ||
| 114 | - } else { | ||
| 115 | - printf("FAILED\n"); | ||
| 116 | - goto close; | ||
| 117 | - } | ||
| 118 | - } | ||
| 119 | - | ||
| 120 | - rc = read_coil_status(&mb_param, SERVER_ID, UT_COIL_STATUS_ADDRESS, | ||
| 121 | - UT_COIL_STATUS_NB_POINTS, tab_rp_status); | ||
| 122 | - printf("2/2 read_coil_status: "); | ||
| 123 | - if (rc != UT_COIL_STATUS_NB_POINTS) { | ||
| 124 | - printf("FAILED (nb points %d)\n", rc); | ||
| 125 | - goto close; | ||
| 126 | - } | ||
| 127 | - | ||
| 128 | - i = 0; | ||
| 129 | - address = UT_COIL_STATUS_ADDRESS; | ||
| 130 | - nb_points = UT_COIL_STATUS_NB_POINTS; | ||
| 131 | - while (nb_points > 0) { | ||
| 132 | - int nb_bits = (nb_points > 8) ? 8 : nb_points; | ||
| 133 | - | ||
| 134 | - value = get_byte_from_bits(tab_rp_status, i*8, nb_bits); | ||
| 135 | - if (value != UT_COIL_STATUS_TAB[i]) { | ||
| 136 | - printf("FAILED (%0X != %0X)\n", | ||
| 137 | - value, UT_COIL_STATUS_TAB[i]); | ||
| 138 | - goto close; | ||
| 139 | - } | ||
| 140 | - | ||
| 141 | - nb_points -= nb_bits; | ||
| 142 | - i++; | ||
| 143 | - } | 183 | + } else { |
| 184 | + printf("FAILED\n"); | ||
| 185 | + goto close; | ||
| 186 | + } | ||
| 187 | + | ||
| 188 | + rc = read_holding_registers(&mb_param, SERVER_ID, | ||
| 189 | + UT_HOLDING_REGISTERS_ADDRESS, | ||
| 190 | + 1, tab_rp_registers); | ||
| 191 | + printf("2/2 read_holding_registers: "); | ||
| 192 | + if (rc != 1) { | ||
| 193 | + printf("FAILED (nb points %d)\n", rc); | ||
| 194 | + goto close; | ||
| 195 | + } | ||
| 196 | + | ||
| 197 | + if (tab_rp_registers[0] != 0x1234) { | ||
| 198 | + printf("FAILED (%0X != %0X)\n", | ||
| 199 | + tab_rp_registers[0], 0x1234); | ||
| 200 | + goto close; | ||
| 201 | + } | ||
| 202 | + printf("OK\n"); | ||
| 203 | + /* End of single register */ | ||
| 204 | + | ||
| 205 | + /* Many registers */ | ||
| 206 | + rc = preset_multiple_registers(&mb_param, SERVER_ID, | ||
| 207 | + UT_HOLDING_REGISTERS_ADDRESS, | ||
| 208 | + UT_HOLDING_REGISTERS_NB_POINTS, | ||
| 209 | + UT_HOLDING_REGISTERS_TAB); | ||
| 210 | + printf("1/2 preset_multiple_registers: "); | ||
| 211 | + if (rc == UT_HOLDING_REGISTERS_NB_POINTS) { | ||
| 144 | printf("OK\n"); | 212 | printf("OK\n"); |
| 145 | - /* End of multiple coils */ | ||
| 146 | - | ||
| 147 | - /** INPUT STATUS **/ | ||
| 148 | - rc = read_input_status(&mb_param, SERVER_ID, UT_INPUT_STATUS_ADDRESS, | ||
| 149 | - UT_INPUT_STATUS_NB_POINTS, tab_rp_status); | ||
| 150 | - printf("1/1 read_input_status: "); | ||
| 151 | - | ||
| 152 | - if (rc != UT_INPUT_STATUS_NB_POINTS) { | ||
| 153 | - printf("FAILED (nb points %d)\n", rc); | ||
| 154 | - goto close; | ||
| 155 | - } | ||
| 156 | - | ||
| 157 | - i = 0; | ||
| 158 | - address = UT_INPUT_STATUS_ADDRESS; | ||
| 159 | - nb_points = UT_INPUT_STATUS_NB_POINTS; | ||
| 160 | - while (nb_points > 0) { | ||
| 161 | - int nb_bits = (nb_points > 8) ? 8 : nb_points; | ||
| 162 | - | ||
| 163 | - value = get_byte_from_bits(tab_rp_status, i*8, nb_bits); | ||
| 164 | - if (value != UT_INPUT_STATUS_TAB[i]) { | ||
| 165 | - printf("FAILED (%0X != %0X)\n", | ||
| 166 | - value, UT_INPUT_STATUS_TAB[i]); | ||
| 167 | - goto close; | ||
| 168 | - } | ||
| 169 | - | ||
| 170 | - nb_points -= nb_bits; | ||
| 171 | - i++; | ||
| 172 | - } | 213 | + } else { |
| 214 | + printf("FAILED\n"); | ||
| 215 | + goto close; | ||
| 216 | + } | ||
| 217 | + | ||
| 218 | + rc = read_holding_registers(&mb_param, SERVER_ID, | ||
| 219 | + UT_HOLDING_REGISTERS_ADDRESS, | ||
| 220 | + UT_HOLDING_REGISTERS_NB_POINTS, | ||
| 221 | + tab_rp_registers); | ||
| 222 | + printf("2/2 read_holding_registers: "); | ||
| 223 | + if (rc != UT_HOLDING_REGISTERS_NB_POINTS) { | ||
| 224 | + printf("FAILED (nb points %d)\n", rc); | ||
| 225 | + goto close; | ||
| 226 | + } | ||
| 227 | + | ||
| 228 | + for (i=0; i < UT_HOLDING_REGISTERS_NB_POINTS; i++) { | ||
| 229 | + if (tab_rp_registers[i] != UT_HOLDING_REGISTERS_TAB[i]) { | ||
| 230 | + printf("FAILED (%0X != %0X)\n", | ||
| 231 | + tab_rp_registers[i], | ||
| 232 | + UT_HOLDING_REGISTERS_TAB[i]); | ||
| 233 | + goto close; | ||
| 234 | + } | ||
| 235 | + } | ||
| 236 | + printf("OK\n"); | ||
| 237 | + /* End of many registers */ | ||
| 238 | + | ||
| 239 | + | ||
| 240 | + /** INPUT REGISTERS **/ | ||
| 241 | + rc = read_input_registers(&mb_param, SERVER_ID, | ||
| 242 | + UT_INPUT_REGISTERS_ADDRESS, | ||
| 243 | + UT_INPUT_REGISTERS_NB_POINTS, | ||
| 244 | + tab_rp_registers); | ||
| 245 | + printf("1/1 read_input_registers: "); | ||
| 246 | + if (rc != UT_INPUT_REGISTERS_NB_POINTS) { | ||
| 247 | + printf("FAILED (nb points %d)\n", rc); | ||
| 248 | + goto close; | ||
| 249 | + } | ||
| 250 | + | ||
| 251 | + for (i=0; i < UT_INPUT_REGISTERS_NB_POINTS; i++) { | ||
| 252 | + if (tab_rp_registers[i] != UT_INPUT_REGISTERS_TAB[i]) { | ||
| 253 | + printf("FAILED (%0X != %0X)\n", | ||
| 254 | + tab_rp_registers[i], UT_INPUT_REGISTERS_TAB[i]); | ||
| 255 | + goto close; | ||
| 256 | + } | ||
| 257 | + } | ||
| 258 | + printf("OK\n"); | ||
| 259 | + | ||
| 260 | + | ||
| 261 | + printf("\nTEST FLOATS\n"); | ||
| 262 | + /** FLOAT **/ | ||
| 263 | + printf("1/2 Write float: "); | ||
| 264 | + modbus_write_float(UT_REAL, tab_rp_registers); | ||
| 265 | + if (tab_rp_registers[1] == (UT_IREAL >> 16) && | ||
| 266 | + tab_rp_registers[0] == (UT_IREAL & 0xFFFF)) { | ||
| 267 | + printf("OK\n"); | ||
| 268 | + } else { | ||
| 269 | + printf("FAILED (%x != %x)\n", | ||
| 270 | + *((uint32_t *)tab_rp_registers), UT_IREAL); | ||
| 271 | + goto close; | ||
| 272 | + } | ||
| 273 | + | ||
| 274 | + printf("2/2 Read float: "); | ||
| 275 | + real = modbus_read_float(tab_rp_registers); | ||
| 276 | + if (real == UT_REAL) { | ||
| 173 | printf("OK\n"); | 277 | printf("OK\n"); |
| 278 | + } else { | ||
| 279 | + printf("FAILED (%f != %f)\n", real, UT_REAL); | ||
| 280 | + goto close; | ||
| 281 | + } | ||
| 174 | 282 | ||
| 175 | - /** HOLDING REGISTERS **/ | 283 | + printf("\nAt this point, error messages doesn't mean the test has failed\n"); |
| 176 | 284 | ||
| 177 | - /* Single register */ | ||
| 178 | - rc = preset_single_register(&mb_param, SERVER_ID, | ||
| 179 | - UT_HOLDING_REGISTERS_ADDRESS, 0x1234); | ||
| 180 | - printf("1/2 preset_single_register: "); | ||
| 181 | - if (rc == 1) { | ||
| 182 | - printf("OK\n"); | ||
| 183 | - } else { | ||
| 184 | - printf("FAILED\n"); | ||
| 185 | - goto close; | ||
| 186 | - } | 285 | + /** ILLEGAL DATA ADDRESS **/ |
| 286 | + printf("\nTEST ILLEGAL DATA ADDRESS:\n"); | ||
| 187 | 287 | ||
| 188 | - rc = read_holding_registers(&mb_param, SERVER_ID, | ||
| 189 | - UT_HOLDING_REGISTERS_ADDRESS, | ||
| 190 | - 1, tab_rp_registers); | ||
| 191 | - printf("2/2 read_holding_registers: "); | ||
| 192 | - if (rc != 1) { | ||
| 193 | - printf("FAILED (nb points %d)\n", rc); | ||
| 194 | - goto close; | ||
| 195 | - } | 288 | + /* The mapping begins at 0 and ending at address + nb_points so |
| 289 | + * the addresses below are not valid. */ | ||
| 196 | 290 | ||
| 197 | - if (tab_rp_registers[0] != 0x1234) { | ||
| 198 | - printf("FAILED (%0X != %0X)\n", | ||
| 199 | - tab_rp_registers[0], 0x1234); | ||
| 200 | - goto close; | ||
| 201 | - } | 291 | + rc = read_coil_status(&mb_param, SERVER_ID, |
| 292 | + UT_COIL_STATUS_ADDRESS, | ||
| 293 | + UT_COIL_STATUS_NB_POINTS + 1, | ||
| 294 | + tab_rp_status); | ||
| 295 | + printf("* read_coil_status: "); | ||
| 296 | + if (rc == -1 && errno == EMBXILADD) | ||
| 202 | printf("OK\n"); | 297 | printf("OK\n"); |
| 203 | - /* End of single register */ | ||
| 204 | - | ||
| 205 | - /* Many registers */ | ||
| 206 | - rc = preset_multiple_registers(&mb_param, SERVER_ID, | ||
| 207 | - UT_HOLDING_REGISTERS_ADDRESS, | ||
| 208 | - UT_HOLDING_REGISTERS_NB_POINTS, | ||
| 209 | - UT_HOLDING_REGISTERS_TAB); | ||
| 210 | - printf("1/2 preset_multiple_registers: "); | ||
| 211 | - if (rc == UT_HOLDING_REGISTERS_NB_POINTS) { | ||
| 212 | - printf("OK\n"); | ||
| 213 | - } else { | ||
| 214 | - printf("FAILED\n"); | ||
| 215 | - goto close; | ||
| 216 | - } | ||
| 217 | - | ||
| 218 | - rc = read_holding_registers(&mb_param, SERVER_ID, | ||
| 219 | - UT_HOLDING_REGISTERS_ADDRESS, | ||
| 220 | - UT_HOLDING_REGISTERS_NB_POINTS, | ||
| 221 | - tab_rp_registers); | ||
| 222 | - printf("2/2 read_holding_registers: "); | ||
| 223 | - if (rc != UT_HOLDING_REGISTERS_NB_POINTS) { | ||
| 224 | - printf("FAILED (nb points %d)\n", rc); | ||
| 225 | - goto close; | ||
| 226 | - } | ||
| 227 | - | ||
| 228 | - for (i=0; i < UT_HOLDING_REGISTERS_NB_POINTS; i++) { | ||
| 229 | - if (tab_rp_registers[i] != UT_HOLDING_REGISTERS_TAB[i]) { | ||
| 230 | - printf("FAILED (%0X != %0X)\n", | ||
| 231 | - tab_rp_registers[i], | ||
| 232 | - UT_HOLDING_REGISTERS_TAB[i]); | ||
| 233 | - goto close; | ||
| 234 | - } | ||
| 235 | - } | 298 | + else { |
| 299 | + printf("FAILED\n"); | ||
| 300 | + goto close; | ||
| 301 | + } | ||
| 302 | + | ||
| 303 | + rc = read_input_status(&mb_param, SERVER_ID, | ||
| 304 | + UT_INPUT_STATUS_ADDRESS, | ||
| 305 | + UT_INPUT_STATUS_NB_POINTS + 1, | ||
| 306 | + tab_rp_status); | ||
| 307 | + printf("* read_input_status: "); | ||
| 308 | + if (rc == -1 && errno == EMBXILADD) | ||
| 236 | printf("OK\n"); | 309 | printf("OK\n"); |
| 237 | - /* End of many registers */ | ||
| 238 | - | ||
| 239 | - | ||
| 240 | - /** INPUT REGISTERS **/ | ||
| 241 | - rc = read_input_registers(&mb_param, SERVER_ID, | ||
| 242 | - UT_INPUT_REGISTERS_ADDRESS, | ||
| 243 | - UT_INPUT_REGISTERS_NB_POINTS, | ||
| 244 | - tab_rp_registers); | ||
| 245 | - printf("1/1 read_input_registers: "); | ||
| 246 | - if (rc != UT_INPUT_REGISTERS_NB_POINTS) { | ||
| 247 | - printf("FAILED (nb points %d)\n", rc); | ||
| 248 | - goto close; | ||
| 249 | - } | ||
| 250 | - | ||
| 251 | - for (i=0; i < UT_INPUT_REGISTERS_NB_POINTS; i++) { | ||
| 252 | - if (tab_rp_registers[i] != UT_INPUT_REGISTERS_TAB[i]) { | ||
| 253 | - printf("FAILED (%0X != %0X)\n", | ||
| 254 | - tab_rp_registers[i], UT_INPUT_REGISTERS_TAB[i]); | ||
| 255 | - goto close; | ||
| 256 | - } | ||
| 257 | - } | 310 | + else { |
| 311 | + printf("FAILED\n"); | ||
| 312 | + goto close; | ||
| 313 | + } | ||
| 314 | + | ||
| 315 | + rc = read_holding_registers(&mb_param, SERVER_ID, | ||
| 316 | + UT_HOLDING_REGISTERS_ADDRESS, | ||
| 317 | + UT_HOLDING_REGISTERS_NB_POINTS + 1, | ||
| 318 | + tab_rp_registers); | ||
| 319 | + printf("* read_holding_registers: "); | ||
| 320 | + if (rc == -1 && errno == EMBXILADD) | ||
| 258 | printf("OK\n"); | 321 | printf("OK\n"); |
| 259 | - | ||
| 260 | - | ||
| 261 | - printf("\nTEST FLOATS\n"); | ||
| 262 | - /** FLOAT **/ | ||
| 263 | - printf("1/2 Write float: "); | ||
| 264 | - modbus_write_float(UT_REAL, tab_rp_registers); | ||
| 265 | - if (tab_rp_registers[1] == (UT_IREAL >> 16) && | ||
| 266 | - tab_rp_registers[0] == (UT_IREAL & 0xFFFF)) { | ||
| 267 | - printf("OK\n"); | ||
| 268 | - } else { | ||
| 269 | - printf("FAILED (%x != %x)\n", | ||
| 270 | - *((uint32_t *)tab_rp_registers), UT_IREAL); | ||
| 271 | - goto close; | ||
| 272 | - } | ||
| 273 | - | ||
| 274 | - printf("2/2 Read float: "); | ||
| 275 | - real = modbus_read_float(tab_rp_registers); | ||
| 276 | - if (real == UT_REAL) { | ||
| 277 | - printf("OK\n"); | ||
| 278 | - } else { | ||
| 279 | - printf("FAILED (%f != %f)\n", real, UT_REAL); | ||
| 280 | - goto close; | ||
| 281 | - } | ||
| 282 | - | ||
| 283 | - printf("\nAt this point, error messages doesn't mean the test has failed\n"); | ||
| 284 | - | ||
| 285 | - /** ILLEGAL DATA ADDRESS **/ | ||
| 286 | - printf("\nTEST ILLEGAL DATA ADDRESS:\n"); | ||
| 287 | - | ||
| 288 | - /* The mapping begins at 0 and ending at address + nb_points so | ||
| 289 | - * the addresses below are not valid. */ | ||
| 290 | - | ||
| 291 | - rc = read_coil_status(&mb_param, SERVER_ID, | ||
| 292 | - UT_COIL_STATUS_ADDRESS, | ||
| 293 | - UT_COIL_STATUS_NB_POINTS + 1, | 322 | + else { |
| 323 | + printf("FAILED\n"); | ||
| 324 | + goto close; | ||
| 325 | + } | ||
| 326 | + | ||
| 327 | + rc = read_input_registers(&mb_param, SERVER_ID, | ||
| 328 | + UT_INPUT_REGISTERS_ADDRESS, | ||
| 329 | + UT_INPUT_REGISTERS_NB_POINTS + 1, | ||
| 330 | + tab_rp_registers); | ||
| 331 | + printf("* read_input_registers: "); | ||
| 332 | + if (rc == -1 && errno == EMBXILADD) | ||
| 333 | + printf("OK\n"); | ||
| 334 | + else { | ||
| 335 | + printf("FAILED\n"); | ||
| 336 | + goto close; | ||
| 337 | + } | ||
| 338 | + | ||
| 339 | + rc = force_single_coil(&mb_param, SERVER_ID, | ||
| 340 | + UT_COIL_STATUS_ADDRESS + UT_COIL_STATUS_NB_POINTS, | ||
| 341 | + ON); | ||
| 342 | + printf("* force_single_coil: "); | ||
| 343 | + if (rc == -1 && errno == EMBXILADD) { | ||
| 344 | + printf("OK\n"); | ||
| 345 | + } else { | ||
| 346 | + printf("FAILED\n"); | ||
| 347 | + goto close; | ||
| 348 | + } | ||
| 349 | + | ||
| 350 | + rc = force_multiple_coils(&mb_param, SERVER_ID, | ||
| 351 | + UT_COIL_STATUS_ADDRESS + UT_COIL_STATUS_NB_POINTS, | ||
| 352 | + UT_COIL_STATUS_NB_POINTS, | ||
| 294 | tab_rp_status); | 353 | tab_rp_status); |
| 295 | - printf("* read_coil_status: "); | ||
| 296 | - if (rc == -1 && errno == EMBXILADD) | ||
| 297 | - printf("OK\n"); | ||
| 298 | - else { | ||
| 299 | - printf("FAILED\n"); | ||
| 300 | - goto close; | ||
| 301 | - } | ||
| 302 | - | ||
| 303 | - rc = read_input_status(&mb_param, SERVER_ID, | ||
| 304 | - UT_INPUT_STATUS_ADDRESS, | ||
| 305 | - UT_INPUT_STATUS_NB_POINTS + 1, | ||
| 306 | - tab_rp_status); | ||
| 307 | - printf("* read_input_status: "); | ||
| 308 | - if (rc == -1 && errno == EMBXILADD) | ||
| 309 | - printf("OK\n"); | ||
| 310 | - else { | ||
| 311 | - printf("FAILED\n"); | ||
| 312 | - goto close; | ||
| 313 | - } | ||
| 314 | - | ||
| 315 | - rc = read_holding_registers(&mb_param, SERVER_ID, | ||
| 316 | - UT_HOLDING_REGISTERS_ADDRESS, | ||
| 317 | - UT_HOLDING_REGISTERS_NB_POINTS + 1, | ||
| 318 | - tab_rp_registers); | ||
| 319 | - printf("* read_holding_registers: "); | ||
| 320 | - if (rc == -1 && errno == EMBXILADD) | ||
| 321 | - printf("OK\n"); | ||
| 322 | - else { | ||
| 323 | - printf("FAILED\n"); | ||
| 324 | - goto close; | ||
| 325 | - } | ||
| 326 | - | ||
| 327 | - rc = read_input_registers(&mb_param, SERVER_ID, | ||
| 328 | - UT_INPUT_REGISTERS_ADDRESS, | ||
| 329 | - UT_INPUT_REGISTERS_NB_POINTS + 1, | ||
| 330 | - tab_rp_registers); | ||
| 331 | - printf("* read_input_registers: "); | ||
| 332 | - if (rc == -1 && errno == EMBXILADD) | ||
| 333 | - printf("OK\n"); | ||
| 334 | - else { | ||
| 335 | - printf("FAILED\n"); | ||
| 336 | - goto close; | ||
| 337 | - } | ||
| 338 | - | ||
| 339 | - rc = force_single_coil(&mb_param, SERVER_ID, | ||
| 340 | - UT_COIL_STATUS_ADDRESS + UT_COIL_STATUS_NB_POINTS, | ||
| 341 | - ON); | ||
| 342 | - printf("* force_single_coil: "); | ||
| 343 | - if (rc == -1 && errno == EMBXILADD) { | ||
| 344 | - printf("OK\n"); | ||
| 345 | - } else { | ||
| 346 | - printf("FAILED\n"); | ||
| 347 | - goto close; | ||
| 348 | - } | ||
| 349 | - | ||
| 350 | - rc = force_multiple_coils(&mb_param, SERVER_ID, | ||
| 351 | - UT_COIL_STATUS_ADDRESS + UT_COIL_STATUS_NB_POINTS, | ||
| 352 | - UT_COIL_STATUS_NB_POINTS, | ||
| 353 | - tab_rp_status); | ||
| 354 | - printf("* force_multiple_coils: "); | ||
| 355 | - if (rc == -1 && errno == EMBXILADD) { | ||
| 356 | - printf("OK\n"); | ||
| 357 | - } else { | ||
| 358 | - printf("FAILED\n"); | ||
| 359 | - goto close; | ||
| 360 | - } | 354 | + printf("* force_multiple_coils: "); |
| 355 | + if (rc == -1 && errno == EMBXILADD) { | ||
| 356 | + printf("OK\n"); | ||
| 357 | + } else { | ||
| 358 | + printf("FAILED\n"); | ||
| 359 | + goto close; | ||
| 360 | + } | ||
| 361 | + | ||
| 362 | + rc = preset_multiple_registers(&mb_param, SERVER_ID, | ||
| 363 | + UT_HOLDING_REGISTERS_ADDRESS + UT_HOLDING_REGISTERS_NB_POINTS, | ||
| 364 | + UT_HOLDING_REGISTERS_NB_POINTS, | ||
| 365 | + tab_rp_registers); | ||
| 366 | + printf("* preset_multiple_registers: "); | ||
| 367 | + if (rc == -1 && errno == EMBXILADD) { | ||
| 368 | + printf("OK\n"); | ||
| 369 | + } else { | ||
| 370 | + printf("FAILED\n"); | ||
| 371 | + goto close; | ||
| 372 | + } | ||
| 361 | 373 | ||
| 362 | - rc = preset_multiple_registers(&mb_param, SERVER_ID, | ||
| 363 | - UT_HOLDING_REGISTERS_ADDRESS + UT_HOLDING_REGISTERS_NB_POINTS, | ||
| 364 | - UT_HOLDING_REGISTERS_NB_POINTS, | ||
| 365 | - tab_rp_registers); | ||
| 366 | - printf("* preset_multiple_registers: "); | ||
| 367 | - if (rc == -1 && errno == EMBXILADD) { | ||
| 368 | - printf("OK\n"); | ||
| 369 | - } else { | ||
| 370 | - printf("FAILED\n"); | ||
| 371 | - goto close; | ||
| 372 | - } | ||
| 373 | 374 | ||
| 375 | + /** TOO MANY DATA **/ | ||
| 376 | + printf("\nTEST TOO MANY DATA ERROR:\n"); | ||
| 374 | 377 | ||
| 375 | - /** TOO MANY DATA **/ | ||
| 376 | - printf("\nTEST TOO MANY DATA ERROR:\n"); | 378 | + rc = read_coil_status(&mb_param, SERVER_ID, |
| 379 | + UT_COIL_STATUS_ADDRESS, | ||
| 380 | + MAX_STATUS + 1, | ||
| 381 | + tab_rp_status); | ||
| 382 | + printf("* read_coil_status: "); | ||
| 383 | + if (rc == -1 && errno == EMBMDATA) { | ||
| 384 | + printf("OK\n"); | ||
| 385 | + } else { | ||
| 386 | + printf("FAILED\n"); | ||
| 387 | + goto close; | ||
| 388 | + } | ||
| 389 | + | ||
| 390 | + rc = read_input_status(&mb_param, SERVER_ID, | ||
| 391 | + UT_INPUT_STATUS_ADDRESS, | ||
| 392 | + MAX_STATUS + 1, | ||
| 393 | + tab_rp_status); | ||
| 394 | + printf("* read_input_status: "); | ||
| 395 | + if (rc == -1 && errno == EMBMDATA) { | ||
| 396 | + printf("OK\n"); | ||
| 397 | + } else { | ||
| 398 | + printf("FAILED\n"); | ||
| 399 | + goto close; | ||
| 400 | + } | ||
| 401 | + | ||
| 402 | + rc = read_holding_registers(&mb_param, SERVER_ID, | ||
| 403 | + UT_HOLDING_REGISTERS_ADDRESS, | ||
| 404 | + MAX_REGISTERS + 1, | ||
| 405 | + tab_rp_registers); | ||
| 406 | + printf("* read_holding_registers: "); | ||
| 407 | + if (rc == -1 && errno == EMBMDATA) { | ||
| 408 | + printf("OK\n"); | ||
| 409 | + } else { | ||
| 410 | + printf("FAILED\n"); | ||
| 411 | + goto close; | ||
| 412 | + } | ||
| 413 | + | ||
| 414 | + rc = read_input_registers(&mb_param, SERVER_ID, | ||
| 415 | + UT_INPUT_REGISTERS_ADDRESS, | ||
| 416 | + MAX_REGISTERS + 1, | ||
| 417 | + tab_rp_registers); | ||
| 418 | + printf("* read_input_registers: "); | ||
| 419 | + if (rc == -1 && errno == EMBMDATA) { | ||
| 420 | + printf("OK\n"); | ||
| 421 | + } else { | ||
| 422 | + printf("FAILED\n"); | ||
| 423 | + goto close; | ||
| 424 | + } | ||
| 377 | 425 | ||
| 378 | - rc = read_coil_status(&mb_param, SERVER_ID, | 426 | + rc = force_multiple_coils(&mb_param, SERVER_ID, |
| 379 | UT_COIL_STATUS_ADDRESS, | 427 | UT_COIL_STATUS_ADDRESS, |
| 380 | MAX_STATUS + 1, | 428 | MAX_STATUS + 1, |
| 381 | tab_rp_status); | 429 | tab_rp_status); |
| 382 | - printf("* read_coil_status: "); | ||
| 383 | - if (rc == -1 && errno == EMBMDATA) { | ||
| 384 | - printf("OK\n"); | ||
| 385 | - } else { | ||
| 386 | - printf("FAILED\n"); | ||
| 387 | - goto close; | ||
| 388 | - } | ||
| 389 | - | ||
| 390 | - rc = read_input_status(&mb_param, SERVER_ID, | ||
| 391 | - UT_INPUT_STATUS_ADDRESS, | ||
| 392 | - MAX_STATUS + 1, | ||
| 393 | - tab_rp_status); | ||
| 394 | - printf("* read_input_status: "); | ||
| 395 | - if (rc == -1 && errno == EMBMDATA) { | ||
| 396 | - printf("OK\n"); | ||
| 397 | - } else { | ||
| 398 | - printf("FAILED\n"); | ||
| 399 | - goto close; | ||
| 400 | - } | ||
| 401 | - | ||
| 402 | - rc = read_holding_registers(&mb_param, SERVER_ID, | ||
| 403 | - UT_HOLDING_REGISTERS_ADDRESS, | ||
| 404 | - MAX_REGISTERS + 1, | ||
| 405 | - tab_rp_registers); | ||
| 406 | - printf("* read_holding_registers: "); | ||
| 407 | - if (rc == -1 && errno == EMBMDATA) { | ||
| 408 | - printf("OK\n"); | ||
| 409 | - } else { | ||
| 410 | - printf("FAILED\n"); | ||
| 411 | - goto close; | ||
| 412 | - } | ||
| 413 | - | ||
| 414 | - rc = read_input_registers(&mb_param, SERVER_ID, | ||
| 415 | - UT_INPUT_REGISTERS_ADDRESS, | ||
| 416 | - MAX_REGISTERS + 1, | ||
| 417 | - tab_rp_registers); | ||
| 418 | - printf("* read_input_registers: "); | ||
| 419 | - if (rc == -1 && errno == EMBMDATA) { | ||
| 420 | - printf("OK\n"); | ||
| 421 | - } else { | ||
| 422 | - printf("FAILED\n"); | ||
| 423 | - goto close; | ||
| 424 | - } | ||
| 425 | - | ||
| 426 | - rc = force_multiple_coils(&mb_param, SERVER_ID, | ||
| 427 | - UT_COIL_STATUS_ADDRESS, | ||
| 428 | - MAX_STATUS + 1, | ||
| 429 | - tab_rp_status); | ||
| 430 | - printf("* force_multiple_coils: "); | ||
| 431 | - if (rc == -1 && errno == EMBMDATA) { | ||
| 432 | - printf("OK\n"); | ||
| 433 | - } else { | ||
| 434 | - goto close; | ||
| 435 | - printf("FAILED\n"); | ||
| 436 | - } | ||
| 437 | - | ||
| 438 | - rc = preset_multiple_registers(&mb_param, SERVER_ID, | ||
| 439 | - UT_HOLDING_REGISTERS_ADDRESS, | ||
| 440 | - MAX_REGISTERS + 1, | ||
| 441 | - tab_rp_registers); | ||
| 442 | - printf("* preset_multiple_registers: "); | ||
| 443 | - if (rc == -1 && errno == EMBMDATA) { | ||
| 444 | - printf("OK\n"); | ||
| 445 | - } else { | ||
| 446 | - printf("FAILED\n"); | ||
| 447 | - goto close; | ||
| 448 | - } | ||
| 449 | - | ||
| 450 | - /** SLAVE REPLY **/ | ||
| 451 | - printf("\nTEST SLAVE REPLY:\n"); | ||
| 452 | - | ||
| 453 | - rc = read_holding_registers(&mb_param, 18, | ||
| 454 | - UT_HOLDING_REGISTERS_ADDRESS, | ||
| 455 | - UT_HOLDING_REGISTERS_NB_POINTS, | ||
| 456 | - tab_rp_registers); | ||
| 457 | - printf("1/3 No or response from slave %d: ", 18); | ||
| 458 | - if (mb_param.type_com == RTU) { | ||
| 459 | - /* No response in RTU mode */ | ||
| 460 | - if (rc == -1 && errno == ETIMEDOUT) { | ||
| 461 | - printf("OK\n"); | ||
| 462 | - } else { | ||
| 463 | - printf("FAILED\n"); | ||
| 464 | - goto close; | ||
| 465 | - } | 430 | + printf("* force_multiple_coils: "); |
| 431 | + if (rc == -1 && errno == EMBMDATA) { | ||
| 432 | + printf("OK\n"); | ||
| 433 | + } else { | ||
| 434 | + goto close; | ||
| 435 | + printf("FAILED\n"); | ||
| 436 | + } | ||
| 437 | + | ||
| 438 | + rc = preset_multiple_registers(&mb_param, SERVER_ID, | ||
| 439 | + UT_HOLDING_REGISTERS_ADDRESS, | ||
| 440 | + MAX_REGISTERS + 1, | ||
| 441 | + tab_rp_registers); | ||
| 442 | + printf("* preset_multiple_registers: "); | ||
| 443 | + if (rc == -1 && errno == EMBMDATA) { | ||
| 444 | + printf("OK\n"); | ||
| 445 | + } else { | ||
| 446 | + printf("FAILED\n"); | ||
| 447 | + goto close; | ||
| 448 | + } | ||
| 449 | + | ||
| 450 | + /** SLAVE REPLY **/ | ||
| 451 | + printf("\nTEST SLAVE REPLY:\n"); | ||
| 452 | + | ||
| 453 | + rc = read_holding_registers(&mb_param, 18, | ||
| 454 | + UT_HOLDING_REGISTERS_ADDRESS, | ||
| 455 | + UT_HOLDING_REGISTERS_NB_POINTS, | ||
| 456 | + tab_rp_registers); | ||
| 457 | + printf("1/3 No or response from slave %d: ", 18); | ||
| 458 | + if (mb_param.type_com == RTU) { | ||
| 459 | + /* No response in RTU mode */ | ||
| 460 | + if (rc == -1 && errno == ETIMEDOUT) { | ||
| 461 | + printf("OK\n"); | ||
| 466 | } else { | 462 | } else { |
| 467 | - /* Response in TCP mode */ | ||
| 468 | - if (rc == UT_HOLDING_REGISTERS_NB_POINTS) { | ||
| 469 | - printf("OK\n"); | ||
| 470 | - } else { | ||
| 471 | - printf("FAILED\n"); | ||
| 472 | - goto close; | ||
| 473 | - } | 463 | + printf("FAILED\n"); |
| 464 | + goto close; | ||
| 474 | } | 465 | } |
| 475 | - | ||
| 476 | - rc = read_holding_registers(&mb_param, MODBUS_BROADCAST_ADDRESS, | ||
| 477 | - UT_HOLDING_REGISTERS_ADDRESS, | ||
| 478 | - UT_HOLDING_REGISTERS_NB_POINTS, | ||
| 479 | - tab_rp_registers); | ||
| 480 | - printf("2/3 Reply after a broadcast query: "); | 466 | + } else { |
| 467 | + /* Response in TCP mode */ | ||
| 481 | if (rc == UT_HOLDING_REGISTERS_NB_POINTS) { | 468 | if (rc == UT_HOLDING_REGISTERS_NB_POINTS) { |
| 482 | - printf("OK\n"); | ||
| 483 | - } else { | ||
| 484 | - printf("FAILED\n"); | ||
| 485 | - goto close; | ||
| 486 | - } | ||
| 487 | - | ||
| 488 | - /* Save original timeout */ | ||
| 489 | - modbus_get_timeout_begin(&mb_param, &timeout_begin_old); | ||
| 490 | - | ||
| 491 | - /* Define a new and too short timeout */ | ||
| 492 | - timeout_begin_new.tv_sec = 0; | ||
| 493 | - timeout_begin_new.tv_usec = 0; | ||
| 494 | - modbus_set_timeout_begin(&mb_param, &timeout_begin_new); | ||
| 495 | - | ||
| 496 | - rc = read_holding_registers(&mb_param, SERVER_ID, | ||
| 497 | - UT_HOLDING_REGISTERS_ADDRESS, | ||
| 498 | - UT_HOLDING_REGISTERS_NB_POINTS, | ||
| 499 | - tab_rp_registers); | ||
| 500 | - printf("3/3 Too short timeout: "); | ||
| 501 | - if (rc == -1 && errno == ETIMEDOUT) { | ||
| 502 | - printf("OK\n"); | 469 | + printf("OK\n"); |
| 503 | } else { | 470 | } else { |
| 504 | - printf("FAILED\n"); | ||
| 505 | - goto close; | 471 | + printf("FAILED\n"); |
| 472 | + goto close; | ||
| 506 | } | 473 | } |
| 474 | + } | ||
| 507 | 475 | ||
| 508 | - /* Restore original timeout */ | ||
| 509 | - modbus_set_timeout_begin(&mb_param, &timeout_begin_old); | ||
| 510 | - | ||
| 511 | - /** BAD RESPONSE **/ | ||
| 512 | - printf("\nTEST BAD RESPONSE ERROR:\n"); | ||
| 513 | - | ||
| 514 | - /* Allocate only the required space */ | ||
| 515 | - tab_rp_registers_bad = (uint16_t *) malloc( | ||
| 516 | - UT_HOLDING_REGISTERS_NB_POINTS_SPECIAL * sizeof(uint16_t)); | ||
| 517 | - rc = read_holding_registers(&mb_param, SERVER_ID, | ||
| 518 | - UT_HOLDING_REGISTERS_ADDRESS, | ||
| 519 | - UT_HOLDING_REGISTERS_NB_POINTS_SPECIAL, | ||
| 520 | - tab_rp_registers_bad); | ||
| 521 | - printf("* read_holding_registers: "); | ||
| 522 | - if (rc == -1 && errno == EMBBADDATA) { | ||
| 523 | - printf("OK\n"); | ||
| 524 | - } else { | ||
| 525 | - printf("FAILED\n"); | ||
| 526 | - goto close; | ||
| 527 | - } | ||
| 528 | - free(tab_rp_registers_bad); | 476 | + rc = read_holding_registers(&mb_param, MODBUS_BROADCAST_ADDRESS, |
| 477 | + UT_HOLDING_REGISTERS_ADDRESS, | ||
| 478 | + UT_HOLDING_REGISTERS_NB_POINTS, | ||
| 479 | + tab_rp_registers); | ||
| 480 | + printf("2/3 Reply after a broadcast query: "); | ||
| 481 | + if (rc == UT_HOLDING_REGISTERS_NB_POINTS) { | ||
| 482 | + printf("OK\n"); | ||
| 483 | + } else { | ||
| 484 | + printf("FAILED\n"); | ||
| 485 | + goto close; | ||
| 486 | + } | ||
| 487 | + | ||
| 488 | + /* Save original timeout */ | ||
| 489 | + modbus_get_timeout_begin(&mb_param, &timeout_begin_old); | ||
| 490 | + | ||
| 491 | + /* Define a new and too short timeout */ | ||
| 492 | + timeout_begin_new.tv_sec = 0; | ||
| 493 | + timeout_begin_new.tv_usec = 0; | ||
| 494 | + modbus_set_timeout_begin(&mb_param, &timeout_begin_new); | ||
| 495 | + | ||
| 496 | + rc = read_holding_registers(&mb_param, SERVER_ID, | ||
| 497 | + UT_HOLDING_REGISTERS_ADDRESS, | ||
| 498 | + UT_HOLDING_REGISTERS_NB_POINTS, | ||
| 499 | + tab_rp_registers); | ||
| 500 | + printf("3/3 Too short timeout: "); | ||
| 501 | + if (rc == -1 && errno == ETIMEDOUT) { | ||
| 502 | + printf("OK\n"); | ||
| 503 | + } else { | ||
| 504 | + printf("FAILED\n"); | ||
| 505 | + goto close; | ||
| 506 | + } | ||
| 507 | + | ||
| 508 | + /* Restore original timeout */ | ||
| 509 | + modbus_set_timeout_begin(&mb_param, &timeout_begin_old); | ||
| 510 | + | ||
| 511 | + /** BAD RESPONSE **/ | ||
| 512 | + printf("\nTEST BAD RESPONSE ERROR:\n"); | ||
| 513 | + | ||
| 514 | + /* Allocate only the required space */ | ||
| 515 | + tab_rp_registers_bad = (uint16_t *) malloc( | ||
| 516 | + UT_HOLDING_REGISTERS_NB_POINTS_SPECIAL * sizeof(uint16_t)); | ||
| 517 | + rc = read_holding_registers(&mb_param, SERVER_ID, | ||
| 518 | + UT_HOLDING_REGISTERS_ADDRESS, | ||
| 519 | + UT_HOLDING_REGISTERS_NB_POINTS_SPECIAL, | ||
| 520 | + tab_rp_registers_bad); | ||
| 521 | + printf("* read_holding_registers: "); | ||
| 522 | + if (rc == -1 && errno == EMBBADDATA) { | ||
| 523 | + printf("OK\n"); | ||
| 524 | + } else { | ||
| 525 | + printf("FAILED\n"); | ||
| 526 | + goto close; | ||
| 527 | + } | ||
| 528 | + free(tab_rp_registers_bad); | ||
| 529 | 529 | ||
| 530 | - printf("\nALL TESTS PASS WITH SUCCESS.\n"); | 530 | + printf("\nALL TESTS PASS WITH SUCCESS.\n"); |
| 531 | 531 | ||
| 532 | close: | 532 | close: |
| 533 | - /* Free the memory */ | ||
| 534 | - free(tab_rp_status); | ||
| 535 | - free(tab_rp_registers); | 533 | + /* Free the memory */ |
| 534 | + free(tab_rp_status); | ||
| 535 | + free(tab_rp_registers); | ||
| 536 | 536 | ||
| 537 | - /* Close the connection */ | ||
| 538 | - modbus_close(&mb_param); | 537 | + /* Close the connection */ |
| 538 | + modbus_close(&mb_param); | ||
| 539 | 539 | ||
| 540 | - return 0; | 540 | + return 0; |
| 541 | } | 541 | } |
tests/unit-test-slave.c
| @@ -26,72 +26,72 @@ | @@ -26,72 +26,72 @@ | ||
| 26 | 26 | ||
| 27 | int main(void) | 27 | int main(void) |
| 28 | { | 28 | { |
| 29 | - int socket; | ||
| 30 | - modbus_param_t mb_param; | ||
| 31 | - modbus_mapping_t mb_mapping; | ||
| 32 | - int rc; | ||
| 33 | - int i; | 29 | + int socket; |
| 30 | + modbus_param_t mb_param; | ||
| 31 | + modbus_mapping_t mb_mapping; | ||
| 32 | + int rc; | ||
| 33 | + int i; | ||
| 34 | 34 | ||
| 35 | - modbus_init_tcp(&mb_param, "127.0.0.1", 1502); | ||
| 36 | - modbus_set_debug(&mb_param, TRUE); | ||
| 37 | - modbus_set_error_recovery(&mb_param, TRUE); | 35 | + modbus_init_tcp(&mb_param, "127.0.0.1", 1502); |
| 36 | + modbus_set_debug(&mb_param, TRUE); | ||
| 37 | + modbus_set_error_recovery(&mb_param, TRUE); | ||
| 38 | 38 | ||
| 39 | - rc = modbus_mapping_new(&mb_mapping, | ||
| 40 | - UT_COIL_STATUS_ADDRESS + UT_COIL_STATUS_NB_POINTS, | ||
| 41 | - UT_INPUT_STATUS_ADDRESS + UT_INPUT_STATUS_NB_POINTS, | ||
| 42 | - UT_HOLDING_REGISTERS_ADDRESS + UT_HOLDING_REGISTERS_NB_POINTS, | ||
| 43 | - UT_INPUT_REGISTERS_ADDRESS + UT_INPUT_REGISTERS_NB_POINTS); | ||
| 44 | - if (rc == -1) { | ||
| 45 | - fprintf(stderr, "Failed to allocate the mapping: %s\n", | ||
| 46 | - modbus_strerror(errno)); | ||
| 47 | - return -1; | ||
| 48 | - } | 39 | + rc = modbus_mapping_new(&mb_mapping, |
| 40 | + UT_COIL_STATUS_ADDRESS + UT_COIL_STATUS_NB_POINTS, | ||
| 41 | + UT_INPUT_STATUS_ADDRESS + UT_INPUT_STATUS_NB_POINTS, | ||
| 42 | + UT_HOLDING_REGISTERS_ADDRESS + UT_HOLDING_REGISTERS_NB_POINTS, | ||
| 43 | + UT_INPUT_REGISTERS_ADDRESS + UT_INPUT_REGISTERS_NB_POINTS); | ||
| 44 | + if (rc == -1) { | ||
| 45 | + fprintf(stderr, "Failed to allocate the mapping: %s\n", | ||
| 46 | + modbus_strerror(errno)); | ||
| 47 | + return -1; | ||
| 48 | + } | ||
| 49 | 49 | ||
| 50 | - /* Examples from PI_MODBUS_300.pdf. | ||
| 51 | - Only the read-only input values are assigned. */ | 50 | + /* Examples from PI_MODBUS_300.pdf. |
| 51 | + Only the read-only input values are assigned. */ | ||
| 52 | 52 | ||
| 53 | - /** INPUT STATUS **/ | ||
| 54 | - set_bits_from_bytes(mb_mapping.tab_input_status, | ||
| 55 | - UT_INPUT_STATUS_ADDRESS, UT_INPUT_STATUS_NB_POINTS, | ||
| 56 | - UT_INPUT_STATUS_TAB); | 53 | + /** INPUT STATUS **/ |
| 54 | + set_bits_from_bytes(mb_mapping.tab_input_status, | ||
| 55 | + UT_INPUT_STATUS_ADDRESS, UT_INPUT_STATUS_NB_POINTS, | ||
| 56 | + UT_INPUT_STATUS_TAB); | ||
| 57 | 57 | ||
| 58 | - /** INPUT REGISTERS **/ | ||
| 59 | - for (i=0; i < UT_INPUT_REGISTERS_NB_POINTS; i++) { | ||
| 60 | - mb_mapping.tab_input_registers[UT_INPUT_REGISTERS_ADDRESS+i] = | ||
| 61 | - UT_INPUT_REGISTERS_TAB[i];; | ||
| 62 | - } | 58 | + /** INPUT REGISTERS **/ |
| 59 | + for (i=0; i < UT_INPUT_REGISTERS_NB_POINTS; i++) { | ||
| 60 | + mb_mapping.tab_input_registers[UT_INPUT_REGISTERS_ADDRESS+i] = | ||
| 61 | + UT_INPUT_REGISTERS_TAB[i];; | ||
| 62 | + } | ||
| 63 | 63 | ||
| 64 | - socket = modbus_slave_listen_tcp(&mb_param, 1); | ||
| 65 | - modbus_slave_accept_tcp(&mb_param, &socket); | 64 | + socket = modbus_slave_listen_tcp(&mb_param, 1); |
| 65 | + modbus_slave_accept_tcp(&mb_param, &socket); | ||
| 66 | 66 | ||
| 67 | - for (;;) { | ||
| 68 | - uint8_t query[MAX_MESSAGE_LENGTH]; | 67 | + for (;;) { |
| 68 | + uint8_t query[MAX_MESSAGE_LENGTH]; | ||
| 69 | 69 | ||
| 70 | - rc = modbus_slave_receive(&mb_param, -1, query); | ||
| 71 | - if (rc > 0) { | ||
| 72 | - if (((query[HEADER_LENGTH_TCP + 3] << 8) + query[HEADER_LENGTH_TCP + 4]) | ||
| 73 | - == UT_HOLDING_REGISTERS_NB_POINTS_SPECIAL) { | ||
| 74 | - /* Change the number of values (offset | ||
| 75 | - TCP = 6) */ | ||
| 76 | - query[HEADER_LENGTH_TCP + 3] = 0; | ||
| 77 | - query[HEADER_LENGTH_TCP + 4] = UT_HOLDING_REGISTERS_NB_POINTS; | ||
| 78 | - } | 70 | + rc = modbus_slave_receive(&mb_param, -1, query); |
| 71 | + if (rc > 0) { | ||
| 72 | + if (((query[HEADER_LENGTH_TCP + 3] << 8) + query[HEADER_LENGTH_TCP + 4]) | ||
| 73 | + == UT_HOLDING_REGISTERS_NB_POINTS_SPECIAL) { | ||
| 74 | + /* Change the number of values (offset | ||
| 75 | + TCP = 6) */ | ||
| 76 | + query[HEADER_LENGTH_TCP + 3] = 0; | ||
| 77 | + query[HEADER_LENGTH_TCP + 4] = UT_HOLDING_REGISTERS_NB_POINTS; | ||
| 78 | + } | ||
| 79 | 79 | ||
| 80 | - rc = modbus_slave_manage(&mb_param, query, rc, &mb_mapping); | ||
| 81 | - if (rc == -1) { | ||
| 82 | - return -1; | ||
| 83 | - } | ||
| 84 | - } else { | ||
| 85 | - /* Connection closed by the client or error */ | ||
| 86 | - break; | ||
| 87 | - } | 80 | + rc = modbus_slave_manage(&mb_param, query, rc, &mb_mapping); |
| 81 | + if (rc == -1) { | ||
| 82 | + return -1; | ||
| 83 | + } | ||
| 84 | + } else { | ||
| 85 | + /* Connection closed by the client or error */ | ||
| 86 | + break; | ||
| 88 | } | 87 | } |
| 88 | + } | ||
| 89 | 89 | ||
| 90 | - printf("Quit the loop: %s\n", modbus_strerror(errno)); | 90 | + printf("Quit the loop: %s\n", modbus_strerror(errno)); |
| 91 | 91 | ||
| 92 | - close(socket); | ||
| 93 | - modbus_mapping_free(&mb_mapping); | ||
| 94 | - modbus_close(&mb_param); | 92 | + close(socket); |
| 93 | + modbus_mapping_free(&mb_mapping); | ||
| 94 | + modbus_close(&mb_param); | ||
| 95 | 95 | ||
| 96 | - return 0; | 96 | + return 0; |
| 97 | } | 97 | } |
tests/version.c
| @@ -20,12 +20,12 @@ | @@ -20,12 +20,12 @@ | ||
| 20 | 20 | ||
| 21 | int main(void) | 21 | int main(void) |
| 22 | { | 22 | { |
| 23 | - printf("Compiled with libmodbus version %s\n", LIBMODBUS_VERSION_STRING); | ||
| 24 | - printf("Linked with libmodbus version %d.%d.%d\n", | ||
| 25 | - libmodbus_version_major, libmodbus_version_minor, libmodbus_version_micro); | 23 | + printf("Compiled with libmodbus version %s\n", LIBMODBUS_VERSION_STRING); |
| 24 | + printf("Linked with libmodbus version %d.%d.%d\n", | ||
| 25 | + libmodbus_version_major, libmodbus_version_minor, libmodbus_version_micro); | ||
| 26 | 26 | ||
| 27 | - if (LIBMODBUS_VERSION_CHECK(2, 1, 0)) { | ||
| 28 | - printf("The functions to read/write float values are available.\n"); | ||
| 29 | - } | ||
| 30 | - return 0; | 27 | + if (LIBMODBUS_VERSION_CHECK(2, 1, 0)) { |
| 28 | + printf("The functions to read/write float values are available.\n"); | ||
| 29 | + } | ||
| 30 | + return 0; | ||
| 31 | } | 31 | } |