Commit 78d301ed68af30e86665e5272ed8f68120be6352
Committed by
Stéphane Raimbault
1 parent
912953a4
Add support for Mask Write Register
Showing
3 changed files
with
60 additions
and
0 deletions
src/modbus-private.h
| @@ -62,6 +62,7 @@ MODBUS_BEGIN_DECLS | @@ -62,6 +62,7 @@ MODBUS_BEGIN_DECLS | ||
| 62 | #define _FC_WRITE_MULTIPLE_COILS 0x0F | 62 | #define _FC_WRITE_MULTIPLE_COILS 0x0F |
| 63 | #define _FC_WRITE_MULTIPLE_REGISTERS 0x10 | 63 | #define _FC_WRITE_MULTIPLE_REGISTERS 0x10 |
| 64 | #define _FC_REPORT_SLAVE_ID 0x11 | 64 | #define _FC_REPORT_SLAVE_ID 0x11 |
| 65 | +#define _FC_MASK_WRITE_REGISTER 0x16 | ||
| 65 | #define _FC_WRITE_AND_READ_REGISTERS 0x17 | 66 | #define _FC_WRITE_AND_READ_REGISTERS 0x17 |
| 66 | 67 | ||
| 67 | typedef enum { | 68 | typedef enum { |
src/modbus.c
| @@ -157,6 +157,9 @@ static unsigned int compute_response_length_from_request(modbus_t *ctx, uint8_t | @@ -157,6 +157,9 @@ static unsigned int compute_response_length_from_request(modbus_t *ctx, uint8_t | ||
| 157 | /* The response is device specific (the header provides the | 157 | /* The response is device specific (the header provides the |
| 158 | length) */ | 158 | length) */ |
| 159 | return MSG_LENGTH_UNDEFINED; | 159 | return MSG_LENGTH_UNDEFINED; |
| 160 | + case _FC_MASK_WRITE_REGISTER: | ||
| 161 | + length = 7; | ||
| 162 | + break; | ||
| 160 | default: | 163 | default: |
| 161 | length = 5; | 164 | length = 5; |
| 162 | } | 165 | } |
| @@ -253,6 +256,8 @@ static uint8_t compute_meta_length_after_function(int function, | @@ -253,6 +256,8 @@ static uint8_t compute_meta_length_after_function(int function, | ||
| 253 | } else if (function == _FC_WRITE_MULTIPLE_COILS || | 256 | } else if (function == _FC_WRITE_MULTIPLE_COILS || |
| 254 | function == _FC_WRITE_MULTIPLE_REGISTERS) { | 257 | function == _FC_WRITE_MULTIPLE_REGISTERS) { |
| 255 | length = 5; | 258 | length = 5; |
| 259 | + } else if (function == _FC_MASK_WRITE_REGISTER) { | ||
| 260 | + length = 6; | ||
| 256 | } else if (function == _FC_WRITE_AND_READ_REGISTERS) { | 261 | } else if (function == _FC_WRITE_AND_READ_REGISTERS) { |
| 257 | length = 9; | 262 | length = 9; |
| 258 | } else { | 263 | } else { |
| @@ -268,6 +273,9 @@ static uint8_t compute_meta_length_after_function(int function, | @@ -268,6 +273,9 @@ static uint8_t compute_meta_length_after_function(int function, | ||
| 268 | case _FC_WRITE_MULTIPLE_REGISTERS: | 273 | case _FC_WRITE_MULTIPLE_REGISTERS: |
| 269 | length = 4; | 274 | length = 4; |
| 270 | break; | 275 | break; |
| 276 | + case _FC_MASK_WRITE_REGISTER: | ||
| 277 | + length = 6; | ||
| 278 | + break; | ||
| 271 | default: | 279 | default: |
| 272 | length = 1; | 280 | length = 1; |
| 273 | } | 281 | } |
| @@ -870,7 +878,26 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | @@ -870,7 +878,26 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 870 | errno = ENOPROTOOPT; | 878 | errno = ENOPROTOOPT; |
| 871 | return -1; | 879 | return -1; |
| 872 | break; | 880 | break; |
| 881 | + case _FC_MASK_WRITE_REGISTER: | ||
| 882 | + if (address >= mb_mapping->nb_registers) { | ||
| 883 | + if (ctx->debug) { | ||
| 884 | + fprintf(stderr, "Illegal data address %0X in write_register\n", | ||
| 885 | + address); | ||
| 886 | + } | ||
| 887 | + rsp_length = response_exception( | ||
| 888 | + ctx, &sft, | ||
| 889 | + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp); | ||
| 890 | + } else { | ||
| 891 | + uint16_t data = mb_mapping->tab_registers[address]; | ||
| 892 | + uint16_t and = (req[offset + 3] << 8) + req[offset + 4]; | ||
| 893 | + uint16_t or = (req[offset + 5] << 8) + req[offset + 6]; | ||
| 873 | 894 | ||
| 895 | + data = (data & and) | (or & (~and)); | ||
| 896 | + mb_mapping->tab_registers[address] = data; | ||
| 897 | + memcpy(rsp, req, req_length); | ||
| 898 | + rsp_length = req_length; | ||
| 899 | + } | ||
| 900 | + break; | ||
| 874 | case _FC_WRITE_AND_READ_REGISTERS: { | 901 | case _FC_WRITE_AND_READ_REGISTERS: { |
| 875 | int nb = (req[offset + 3] << 8) + req[offset + 4]; | 902 | int nb = (req[offset + 3] << 8) + req[offset + 4]; |
| 876 | uint16_t address_write = (req[offset + 5] << 8) + req[offset + 6]; | 903 | uint16_t address_write = (req[offset + 5] << 8) + req[offset + 6]; |
| @@ -1263,6 +1290,37 @@ int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src) | @@ -1263,6 +1290,37 @@ int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src) | ||
| 1263 | return rc; | 1290 | return rc; |
| 1264 | } | 1291 | } |
| 1265 | 1292 | ||
| 1293 | +int modbus_mask_write_register(modbus_t *ctx, int addr, uint16_t and, uint16_t or) | ||
| 1294 | +{ | ||
| 1295 | + int rc; | ||
| 1296 | + int req_length; | ||
| 1297 | + uint8_t req[_MIN_REQ_LENGTH]; | ||
| 1298 | + | ||
| 1299 | + req_length = ctx->backend->build_request_basis(ctx, _FC_MASK_WRITE_REGISTER, addr, 0, req); | ||
| 1300 | + | ||
| 1301 | + /* HACKISH, count is not used */ | ||
| 1302 | + req_length -=2; | ||
| 1303 | + | ||
| 1304 | + req[req_length++] = and >> 8; | ||
| 1305 | + req[req_length++] = and & 0x00ff; | ||
| 1306 | + req[req_length++] = or >> 8; | ||
| 1307 | + req[req_length++] = or & 0x00ff; | ||
| 1308 | + | ||
| 1309 | + rc = send_msg(ctx, req, req_length); | ||
| 1310 | + if (rc > 0) { | ||
| 1311 | + /* Used by write_bit and write_register */ | ||
| 1312 | + uint8_t rsp[_MIN_REQ_LENGTH]; | ||
| 1313 | + | ||
| 1314 | + rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION); | ||
| 1315 | + if (rc == -1) | ||
| 1316 | + return -1; | ||
| 1317 | + | ||
| 1318 | + rc = check_confirmation(ctx, req, rsp, rc); | ||
| 1319 | + } | ||
| 1320 | + | ||
| 1321 | + return rc; | ||
| 1322 | +} | ||
| 1323 | + | ||
| 1266 | /* Write multiple registers from src array to remote device and read multiple | 1324 | /* Write multiple registers from src array to remote device and read multiple |
| 1267 | registers from remote device to dest array. */ | 1325 | registers from remote device to dest array. */ |
| 1268 | int modbus_write_and_read_registers(modbus_t *ctx, | 1326 | int modbus_write_and_read_registers(modbus_t *ctx, |
src/modbus.h
| @@ -185,6 +185,7 @@ EXPORT int modbus_write_bit(modbus_t *ctx, int coil_addr, int status); | @@ -185,6 +185,7 @@ EXPORT int modbus_write_bit(modbus_t *ctx, int coil_addr, int status); | ||
| 185 | EXPORT int modbus_write_register(modbus_t *ctx, int reg_addr, int value); | 185 | EXPORT int modbus_write_register(modbus_t *ctx, int reg_addr, int value); |
| 186 | EXPORT int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *data); | 186 | EXPORT int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *data); |
| 187 | EXPORT int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *data); | 187 | EXPORT int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *data); |
| 188 | +EXPORT int modbus_mask_write_register(modbus_t *ctx, int addr, uint16_t and, uint16_t or); | ||
| 188 | EXPORT int modbus_write_and_read_registers(modbus_t *ctx, int write_addr, int write_nb, | 189 | EXPORT int modbus_write_and_read_registers(modbus_t *ctx, int write_addr, int write_nb, |
| 189 | const uint16_t *src, int read_addr, int read_nb, | 190 | const uint16_t *src, int read_addr, int read_nb, |
| 190 | uint16_t *dest); | 191 | uint16_t *dest); |