Commit 78d301ed68af30e86665e5272ed8f68120be6352

Authored by Martijn de Gouw
Committed by Stéphane Raimbault
1 parent 912953a4

Add support for Mask Write Register

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);