Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion doc/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ TXT3 = \
modbus_get_float_dcba.txt \
modbus_get_header_length.txt \
modbus_get_response_timeout.txt \
modbus_get_slave.txt \
modbus_get_slave.txt \
modbus_get_socket.txt \
modbus_mapping_free.txt \
modbus_mapping_new.txt \
Expand All @@ -22,6 +22,7 @@ TXT3 = \
modbus_new_tcp_pi.txt \
modbus_new_tcp.txt \
modbus_read_bits.txt \
modbus_read_file_record.txt \
modbus_read_input_bits.txt \
modbus_read_input_registers.txt \
modbus_read_registers.txt \
Expand Down Expand Up @@ -59,6 +60,7 @@ TXT3 = \
modbus_write_and_read_registers.txt \
modbus_write_bits.txt \
modbus_write_bit.txt \
modbus_write_file_record.txt \
modbus_write_registers.txt \
modbus_write_register.txt
TXT7 = libmodbus.txt
Expand Down
42 changes: 42 additions & 0 deletions doc/modbus_read_file_record.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
modbus_read_file_record(3)
==========================


NAME
----
modbus_read_file_record - Read values from a file register


SYNOPSIS
--------
*int modbus_read_file_record(modbus_t *'ctx', int 'addr', int 'sub_addr', int 'nb', uint16_t '*dest');*


DESCRIPTION
-----------
The *modbus_read_file_record()* function reads _nb_ values from file
register _addr_, starting from position _sub_addr_ in the file register.

A file register is an array of values.
A modbus device may have up to 65535 file registers, addressed 1 to 65535
decimal.
Each file register contains 10000 values, addressed 0000 to 9999 decimal.

This function uses the Modbus function code 0x14 (Read File Record).


RETURN VALUE
------------
The function shall return the number of records read (i.e. the value of _nb_) if successful.
Otherwise it shall return -1 and set errno.


SEE ALSO
--------
linkmb:modbus_read_register[3]
linkmb:modbus_write_file_register[3]


AUTHORS
-------
The libmodbus file register documentation was added by Richard Ash at EA Technology.
42 changes: 42 additions & 0 deletions doc/modbus_write_file_record.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
modbus_write_file_record(3)
==========================


NAME
----
modbus_write_file_record - Write values to a file register


SYNOPSIS
--------
*int modbus_write_file_record(modbus_t *'ctx', int 'addr', int 'sub_addr', int 'nb', const uint16_t '*src');*


DESCRIPTION
-----------
The *modbus_write_file_record()* function writes _nb_ values to file
register _addr_, starting from position _sub_addr_ in the file register.

A file register is an array of values.
A modbus device may have up to 65535 file registers, addressed 1 to 65535
decimal.
Each file register contains 10000 values, addressed 0000 to 9999 decimal.

This function uses the Modbus function code 0x15 (Write File Record).


RETURN VALUE
------------
The function shall return the number of records written (i.e. the value of _nb_) if successful.
Otherwise it shall return -1 and set errno.


SEE ALSO
--------
linkmb:modbus_write_register[3]
linkmb:modbus_read_file_register[3]


AUTHORS
-------
The libmodbus file register documentation was added by Richard Ash at EA Technology.
151 changes: 151 additions & 0 deletions src/modbus.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,12 @@ static unsigned int compute_response_length_from_request(modbus_t *ctx, uint8_t
/* The response is device specific (the header provides the
length) */
return MSG_LENGTH_UNDEFINED;
case MODBUS_FC_READ_FILE_RECORD:
length = 4 + 2 * (req[offset + 7] << 8 | req[offset + 8]);
break;
case MODBUS_FC_WRITE_FILE_RECORD:
length = 9 + 2 * (req[offset + 7] << 8 | req[offset + 8]);
break;
case MODBUS_FC_MASK_WRITE_REGISTER:
length = 7;
break;
Expand Down Expand Up @@ -260,6 +266,9 @@ static uint8_t compute_meta_length_after_function(int function,
} else if (function == MODBUS_FC_WRITE_MULTIPLE_COILS ||
function == MODBUS_FC_WRITE_MULTIPLE_REGISTERS) {
length = 5;
} else if (function == MODBUS_FC_READ_FILE_RECORD ||
function == MODBUS_FC_WRITE_FILE_RECORD) {
length = 8;
} else if (function == MODBUS_FC_MASK_WRITE_REGISTER) {
length = 6;
} else if (function == MODBUS_FC_WRITE_AND_READ_REGISTERS) {
Expand All @@ -280,6 +289,12 @@ static uint8_t compute_meta_length_after_function(int function,
case MODBUS_FC_MASK_WRITE_REGISTER:
length = 6;
break;
case MODBUS_FC_READ_FILE_RECORD:
length = 3;
break;
case MODBUS_FC_WRITE_FILE_RECORD:
length = 8;
break;
default:
length = 1;
}
Expand All @@ -304,6 +319,10 @@ static int compute_data_length_after_meta(modbus_t *ctx, uint8_t *msg,
case MODBUS_FC_WRITE_AND_READ_REGISTERS:
length = msg[ctx->backend->header_length + 9];
break;
case MODBUS_FC_READ_FILE_RECORD:
case MODBUS_FC_WRITE_FILE_RECORD:
length = msg[ctx->backend->header_length + 1] - 7;
break;
default:
length = 0;
}
Expand All @@ -313,6 +332,10 @@ static int compute_data_length_after_meta(modbus_t *ctx, uint8_t *msg,
function == MODBUS_FC_REPORT_SLAVE_ID ||
function == MODBUS_FC_WRITE_AND_READ_REGISTERS) {
length = msg[ctx->backend->header_length + 1];
} else if (function == MODBUS_FC_READ_FILE_RECORD) {
length = msg[ctx->backend->header_length + 2] - 1;
} else if (function == MODBUS_FC_WRITE_FILE_RECORD) {
length = msg[ctx->backend->header_length + 1] - 7;
} else {
length = 0;
}
Expand Down Expand Up @@ -600,6 +623,14 @@ static int check_confirmation(modbus_t *ctx, uint8_t *req,
/* Report slave ID (bytes received) */
req_nb_value = rsp_nb_value = rsp[offset + 1];
break;
case MODBUS_FC_READ_FILE_RECORD:
req_nb_value = (req[offset + 7] << 8) + req[offset + 8];
rsp_nb_value = (rsp[offset + 2] - 1) / 2;
break;
case MODBUS_FC_WRITE_FILE_RECORD:
req_nb_value = (req[offset + 7] << 8) + req[offset + 8];
rsp_nb_value = (rsp[offset + 7] << 8) + rsp[offset + 8];
break;
default:
/* 1 Write functions & others */
req_nb_value = rsp_nb_value = 1;
Expand Down Expand Up @@ -1236,6 +1267,68 @@ int modbus_read_input_registers(modbus_t *ctx, int addr, int nb,
return status;
}

int modbus_read_file_record(modbus_t *ctx, int addr, int sub_addr, int nb, uint16_t *dest)
{
int rc;
int req_length;
uint8_t req[_MIN_REQ_LENGTH];
uint8_t rsp[MAX_MESSAGE_LENGTH];

if (ctx == NULL) {
errno = EINVAL;
return -1;
}
// check if record number is within range
if (sub_addr > MODBUS_MAX_FILE_RECORD_NUMBER) {
if (ctx->debug) {
fprintf(stderr,
"ERROR Too big file record number (%d > %d)\n",
sub_addr, MODBUS_MAX_FILE_RECORD_NUMBER);
}
errno = EMBMDATA;
return -1;
}

req_length = ctx->backend->build_request_basis(ctx,
MODBUS_FC_READ_FILE_RECORD,
0, 0, req);

req_length -= 4;
req[req_length++] = 7; // one request, so 7 bytes
req[req_length++] = 6;
req[req_length++] = addr >> 8;
req[req_length++] = addr & 0x00ff;
req[req_length++] = sub_addr >> 8;
req[req_length++] = sub_addr & 0x00ff;
req[req_length++] = nb >> 8;
req[req_length++] = nb & 0x00ff;

rc = send_msg(ctx, req, req_length);
if (rc > 0) {
int offset;
int i;

rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);
if (rc == -1)
return -1;

rc = check_confirmation(ctx, req, rsp, rc);
if (rc == -1)
return -1;

offset = ctx->backend->header_length;
// if all went well, copy returned data to caller's pointer, converting
// bytes into 16-bit words.
for (i = 0; i < rc; i++) {

dest[i] = (rsp[offset + 4 + (i << 1)] << 8) |
rsp[offset + 5 + (i << 1)];
}
}

return rc;
}

/* Write a value to the specified register of the remote device.
Used by write_bit and write_register */
static int write_single(modbus_t *ctx, int function, int addr, const uint16_t value)
Expand Down Expand Up @@ -1401,6 +1494,64 @@ int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src)
return rc;
}

int modbus_write_file_record(modbus_t *ctx, int addr, int sub_addr, int nb, const uint16_t *src)
{
int rc;
int i;
int req_length;
int byte_count;
uint8_t req[MAX_MESSAGE_LENGTH];

if (ctx == NULL) {
errno = EINVAL;
return -1;
}
// check record number is valid
if (sub_addr > MODBUS_MAX_FILE_RECORD_NUMBER) {
if (ctx->debug) {
fprintf(stderr,
"ERROR Too big file record number (%d > %d)\n",
sub_addr, MODBUS_MAX_FILE_RECORD_NUMBER);
}
errno = EMBMDATA;
return -1;
}

req_length = ctx->backend->build_request_basis(ctx,
MODBUS_FC_WRITE_FILE_RECORD,
0, 0, req);

byte_count = nb * 2;
req_length -= 4;
req[req_length++] = 7 + byte_count; // one request header + bytes to write
req[req_length++] = 6;
req[req_length++] = addr >> 8;
req[req_length++] = addr & 0x00ff;
req[req_length++] = sub_addr >> 8;
req[req_length++] = sub_addr & 0x00ff;
req[req_length++] = nb >> 8;
req[req_length++] = nb & 0x00ff;
// pack supplied data into request
for (i = 0; i < nb; i++) {
req[req_length++] = src[i] >> 8;
req[req_length++] = src[i] & 0x00FF;
}

rc = send_msg(ctx, req, req_length);
if (rc > 0) {
uint8_t rsp[MAX_MESSAGE_LENGTH];

rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);
if (rc == -1)
return -1;

rc = check_confirmation(ctx, req, rsp, rc);
}

return rc;
}


int modbus_mask_write_register(modbus_t *ctx, int addr, uint16_t and_mask, uint16_t or_mask)
{
int rc;
Expand Down
9 changes: 9 additions & 0 deletions src/modbus.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ MODBUS_BEGIN_DECLS
#define MODBUS_FC_WRITE_MULTIPLE_COILS 0x0F
#define MODBUS_FC_WRITE_MULTIPLE_REGISTERS 0x10
#define MODBUS_FC_REPORT_SLAVE_ID 0x11
#define MODBUS_FC_READ_FILE_RECORD 0x14
#define MODBUS_FC_WRITE_FILE_RECORD 0x15
#define MODBUS_FC_MASK_WRITE_REGISTER 0x16
#define MODBUS_FC_WRITE_AND_READ_REGISTERS 0x17

Expand All @@ -81,6 +83,11 @@ MODBUS_BEGIN_DECLS
#define MODBUS_MAX_READ_BITS 2000
#define MODBUS_MAX_WRITE_BITS 1968

/* Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 14 page 33)
* Sub-Req. x, Record Number (2 bytes): 1 to 9999 (0x270F)
*/
#define MODBUS_MAX_FILE_RECORD_NUMBER 9999

/* Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 3 page 15)
* Quantity of Registers to read (2 bytes): 1 to 125 (0x7D)
* (chapter 6 section 12 page 31)
Expand Down Expand Up @@ -211,6 +218,8 @@ MODBUS_API int modbus_write_bit(modbus_t *ctx, int coil_addr, int status);
MODBUS_API int modbus_write_register(modbus_t *ctx, int reg_addr, const uint16_t value);
MODBUS_API int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *data);
MODBUS_API int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *data);
MODBUS_API int modbus_write_file_record(modbus_t *ctx, int addr, int sub_addr, int nb, const uint16_t *src);
MODBUS_API int modbus_read_file_record(modbus_t *ctx, int addr, int sub_addr, int nb, uint16_t *dest);
MODBUS_API int modbus_mask_write_register(modbus_t *ctx, int addr, uint16_t and_mask, uint16_t or_mask);
MODBUS_API int modbus_write_and_read_registers(modbus_t *ctx, int write_addr, int write_nb,
const uint16_t *src, int read_addr, int read_nb,
Expand Down