From 452a9b09cba3bf34a37f3f8da7b2b244603bc988 Mon Sep 17 00:00:00 2001 From: oliver Date: Tue, 7 Nov 2017 16:19:45 +0100 Subject: [PATCH 1/9] Added functions 0x14 and 0x15 ( read and write general-reference ) --- src/modbus-private.h | 4 + src/modbus.c | 382 ++++++++++++++++++++++++++++++++++++++++++- src/modbus.h | 22 +++ 3 files changed, 406 insertions(+), 2 deletions(-) diff --git a/src/modbus-private.h b/src/modbus-private.h index 2c601c495..ccaaff4d3 100644 --- a/src/modbus-private.h +++ b/src/modbus-private.h @@ -39,6 +39,10 @@ MODBUS_BEGIN_DECLS #define _RESPONSE_TIMEOUT 500000 #define _BYTE_TIMEOUT 500000 +#define SUB_REQUEST_LENGHT 0x07 +#define SUB_REQUEST_REF_TYPE \ + 0x06 // Reference-Type for General Reference Read + Write + typedef enum { _MODBUS_BACKEND_TYPE_RTU=0, _MODBUS_BACKEND_TYPE_TCP diff --git a/src/modbus.c b/src/modbus.c index 03d8da248..145512ab9 100644 --- a/src/modbus.c +++ b/src/modbus.c @@ -152,6 +152,11 @@ 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_WRITE_GENERAL_REFERENCE: + length = 2 + req[offset + 1]; + break; + case MODBUS_FC_READ_GENERAL_REFERENCE: + return MSG_LENGTH_UNDEFINED; // Lenght is dedepnding of the subrequests case MODBUS_FC_MASK_WRITE_REGISTER: length = 7; break; @@ -264,6 +269,9 @@ static uint8_t compute_meta_length_after_function(int function, length = 6; } else if (function == MODBUS_FC_WRITE_AND_READ_REGISTERS) { length = 9; + } else if (function == MODBUS_FC_READ_GENERAL_REFERENCE || + function == MODBUS_FC_WRITE_GENERAL_REFERENCE) { + length = 1; // After the function, the number of bytes is transmitted } else { /* MODBUS_FC_READ_EXCEPTION_STATUS, MODBUS_FC_REPORT_SLAVE_ID */ length = 0; @@ -280,6 +288,11 @@ static uint8_t compute_meta_length_after_function(int function, case MODBUS_FC_MASK_WRITE_REGISTER: length = 6; break; + case MODBUS_FC_WRITE_GENERAL_REFERENCE: + case MODBUS_FC_READ_GENERAL_REFERENCE: + length = 1; // After the function, the number of bytes is transmitted + // and at least one SUB_REQUEST + break; default: length = 1; } @@ -304,6 +317,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_WRITE_GENERAL_REFERENCE: + case MODBUS_FC_READ_GENERAL_REFERENCE: + length = msg[ctx->backend->header_length + 1]; + break; default: length = 0; } @@ -313,6 +330,9 @@ 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_GENERAL_REFERENCE || + function == MODBUS_FC_WRITE_GENERAL_REFERENCE) { + length = msg[ctx->backend->header_length + 1]; } else { length = 0; } @@ -596,6 +616,15 @@ static int check_confirmation(modbus_t *ctx, uint8_t *req, req_nb_value = (req[offset + 3] << 8) + req[offset + 4]; rsp_nb_value = (rsp[offset + 3] << 8) | rsp[offset + 4]; break; + case MODBUS_FC_WRITE_GENERAL_REFERENCE: + /* Check for Bytes recevied, response is copy of the request */ + req_nb_value = req[offset + 1]; + rsp_nb_value = rsp[offset + 1]; + break; + case MODBUS_FC_READ_GENERAL_REFERENCE: + /* Check for Bytes recevied */ + req_nb_value = rsp_nb_value = rsp[offset + 1]; + break; case MODBUS_FC_REPORT_SLAVE_ID: /* Report slave ID (bytes received) */ req_nb_value = rsp_nb_value = rsp[offset + 1]; @@ -985,8 +1014,148 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, rsp[rsp_length++] = mb_mapping->tab_registers[i] & 0xFF; } } - } - break; + } break; + case MODBUS_FC_WRITE_GENERAL_REFERENCE: { + // Each "Read_General_Reference", aka as "Read_File", can consists of + // several Subrequests + uint8_t nb = req[offset + 1]; + uint16_t i; + int nsr = 0; + uint8_t ref_type = 0; + + /* Each Subrequest has at least 7 Bytes */ + if (nb < SUB_REQUEST_LENGHT) { + rsp_length = response_exception( + ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE, + "Illegal nb of subrequests %d in write_general_reference \n", nb); + break; + } + + rsp_length = ctx->backend->build_response_basis(&sft, rsp); + if (rsp_length + nb >= MODBUS_MAX_READ_REGISTERS) { + rsp_length = response_exception( + ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE, + "Responselenght exceeds telegram-size %d in subrequests %d in " + "write_general_reference \n", + rsp_length + nb, nsr); + + } else { + /* Response is a simple copy of the request */ + memcpy(rsp + rsp_length, req + offset + 1, + 1 + nb); // number of bytes + the place for the nb itself + rsp_length += nb + 1; + + do { + offset += 2; + ref_type = req[offset]; + if (ref_type != SUB_REQUEST_REF_TYPE) { + rsp_length = response_exception( + ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE, + "Illegal reference Type %d in subrequests %d in " + "write_general_reference \n", + ref_type, nsr); + } else { + uint16_t file_no = (req[offset + 1] << 8) + req[offset + 2]; + uint16_t f_address = (req[offset + 3] << 8) + req[offset + 4]; + uint16_t nb_write = (req[offset + 5] << 8) + req[offset + 6]; + + offset += SUB_REQUEST_LENGHT; + nb -= SUB_REQUEST_LENGHT; + + if ((file_no == 0) || (file_no > MODBUS_MAX_REFERENCE_FILES) || + (mb_mapping->file_registers[file_no - 1] == NULL)) { + rsp_length = response_exception( + ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE, + "Illegal parameter file %d in subrequests %d in " + "write_general_reference \n", + file_no, nsr); + break; + } else { + /* Write Registers to file at position adress */ + for (i = f_address; i < f_address + nb_write; i++) { + mb_mapping->file_registers[file_no - 1][i] = + (req[offset] << 8) + req[offset + 1]; + offset += 2; + nb -= 2; + } + } + } + nsr++; + } while (nb > 0); + } + } break; + case MODBUS_FC_READ_GENERAL_REFERENCE: { + // Each "Read_General_Reference", aka as "Read_File", can consists of + // several Subrequests + uint8_t nb = req[offset + 1]; + uint16_t i; + int nsr = 0; + uint8_t ref_type = 0; + int rsp_length_byte_count = 0; + + /* Each Subrequest has 7 Bytes */ + if (nb % SUB_REQUEST_LENGHT != 0) { + rsp_length = response_exception( + ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE, + "Illegal nb of subrequests %d in read_general_reference \n", nb); + break; + } + + rsp_length = ctx->backend->build_response_basis(&sft, rsp); + + rsp_length_byte_count = + rsp_length; // Place-holder of overall message-size. + rsp[rsp_length++] = 0; + + do { + offset += 2; + ref_type = req[offset]; + + if (ref_type != SUB_REQUEST_REF_TYPE) { + rsp_length = response_exception( + ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE, + "Illegal reference Type %d in subrequests %d in " + "read_general_reference \n", + ref_type, nsr); + } else { + uint16_t file_no = (req[offset + 1] << 8) + req[offset + 2]; + uint16_t f_address = (req[offset + 3] << 8) + req[offset + 4]; + uint16_t nb_read = (req[offset + 5] << 8) + req[offset + 6]; + + if ((file_no == 0) || (file_no > MODBUS_MAX_REFERENCE_FILES) || + (mb_mapping->file_registers[file_no - 1] == NULL)) { + rsp_length = response_exception( + ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE, + "Illegal parameter file %d in subrequests %d in " + "read_general_reference \n", + file_no, nsr); + + } else if (rsp_length + nb_read >= MODBUS_MAX_READ_REGISTERS) { + rsp_length = response_exception( + ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE, + "Responselenght exceeds telegram-size %d in subrequests %d in " + "read_general_reference \n", + rsp_length + nb_read, nsr); + + } else { + rsp[rsp_length++] = nb_read; + rsp[rsp_length++] = SUB_REQUEST_REF_TYPE; + /* and read the data for the response */ + for (i = f_address; i < f_address + nb_read; i++) { + rsp[rsp_length++] = + mb_mapping->file_registers[file_no - 1][i] >> 8; + rsp[rsp_length++] = + mb_mapping->file_registers[file_no - 1][i] & 0xFF; + } + } + } + offset += SUB_REQUEST_LENGHT; + nsr++; + } while (nsr < (nb / SUB_REQUEST_LENGHT)); + // put overall lenght of message at the reserved space in the beginning. + rsp[rsp_length_byte_count] = (rsp_length - rsp_length_byte_count) - 1; + + } break; default: rsp_length = response_exception( @@ -1559,6 +1728,140 @@ int modbus_report_slave_id(modbus_t *ctx, int max_dest, uint8_t *dest) return rc; } +/* Read General Reference ( aka as Read File ) reads nb registers (16-bit) from + * an offset ( also 16-bit stepping ) of a given filenumber*/ +/* This implements only the simple case with one subrequest. More complex can be + * created with raw-message. */ +/* !!! Take care, that dest must have the size of at least read_nb +1 !!! */ + +int modbus_read_general_reference(modbus_t *ctx, int file_no, int read_addr, + int read_nb, uint16_t *dest) + +{ + int rc; + int req_length; + int i; + int byte_count; + uint8_t req[MAX_MESSAGE_LENGTH]; + uint8_t rsp[MAX_MESSAGE_LENGTH]; + + if (read_nb > MODBUS_MAX_READ_REGISTERS) { + if (ctx->debug) { + fprintf(stderr, "ERROR Too many registers requested (%d > %d)\n", read_nb, + MODBUS_MAX_READ_REGISTERS); + } + errno = EMBMDATA; + return -1; + } + byte_count = SUB_REQUEST_LENGHT; + req_length = ctx->backend->build_request_basis( + ctx, MODBUS_FC_READ_GENERAL_REFERENCE, ((byte_count << 8) | 0x06), + file_no, req); + + req[req_length++] = read_addr >> 8; + req[req_length++] = read_addr & 0x00ff; + req[req_length++] = read_nb >> 8; + req[req_length++] = read_nb & 0x00ff; + + rc = send_msg(ctx, req, req_length); + if (rc > 0) { + int offset; + + 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; + + rc /= 2; /* rc is in byte, we count in uint16-steps */ + offset = ctx->backend->header_length; + if (rc > (read_nb + 1)) { /* One register is extra for size and ref-type */ + if (ctx->debug) { + fprintf(stderr, "ERROR Too many data for destination (%d > %d)\n", rc, + read_nb); + } + rc = read_nb; + } + + /* If rc is negative, the loop is jumped ! */ + for (i = 0; i < rc; i++) { + /* shift reg hi_byte to temp OR with lo_byte */ + dest[i] = (rsp[offset + 2 + (i << 1)] << 8) | rsp[offset + 3 + (i << 1)]; + } + } + + return rc; +} + +/* Write General Reference ( aka as Write File ) writes nb registers (16-bit) + * from an offset ( also 16-bit stepping ) of a given filenumber*/ +/* This implements only the simple case with one subrequest. More complex can be + * created with raw-message. */ +int modbus_write_general_reference(modbus_t *ctx, int file_no, int write_addr, + int write_nb, const uint16_t *src) + +{ + int rc; + int req_length; + int i; + int byte_count; + uint8_t req[MAX_MESSAGE_LENGTH]; + uint8_t rsp[MAX_MESSAGE_LENGTH]; + + if (write_nb > MODBUS_MAX_READ_REGISTERS) { + if (ctx->debug) { + fprintf(stderr, "ERROR Too many registers requested (%d > %d)\n", + write_nb, MODBUS_MAX_READ_REGISTERS); + } + errno = EMBMDATA; + return -1; + } + byte_count = SUB_REQUEST_LENGHT + (write_nb * 2); + req_length = ctx->backend->build_request_basis( + ctx, MODBUS_FC_WRITE_GENERAL_REFERENCE, ((byte_count << 8) | 0x06), + file_no, req); + + req[req_length++] = write_addr >> 8; + req[req_length++] = write_addr & 0x00ff; + req[req_length++] = write_nb >> 8; + req[req_length++] = write_nb & 0x00ff; + + for (i = 0; i < write_nb; i++) { + req[req_length++] = src[i] >> 8; + req[req_length++] = src[i] & 0xff; + } + + rc = send_msg(ctx, req, req_length); + if (rc > 0) { + + 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; + + rc /= 2; /* rc is in byte, we count in uint16-steps */ + +#if 0 // Does it make sense to copy back the response to the caller ? It's a + // copy of the request + offset = ctx->backend->header_length; + + /* If rc is negative, the loop is jumped ! */ + for (i = 0; i < rc; i++) { + /* shift reg hi_byte to temp OR with lo_byte */ + src[i] = (rsp[offset + 2 + (i << 1)] << 8) | + rsp[offset + 3 + (i << 1)]; + } + +#endif + } + return rc; +} void _modbus_init_common(modbus_t *ctx) { /* Slave and socket are initialized to -1 */ @@ -1771,6 +2074,7 @@ modbus_mapping_t* modbus_mapping_new_start_address( unsigned int start_input_registers, unsigned int nb_input_registers) { modbus_mapping_t *mb_mapping; + int i; mb_mapping = (modbus_mapping_t *)malloc(sizeof(modbus_mapping_t)); if (mb_mapping == NULL) { @@ -1845,6 +2149,10 @@ modbus_mapping_t* modbus_mapping_new_start_address( nb_input_registers * sizeof(uint16_t)); } + for (i = 0; i < MODBUS_MAX_REFERENCE_FILES; i++) { + mb_mapping->file_registers[i] = NULL; + } + return mb_mapping; } @@ -1855,13 +2163,83 @@ modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits, 0, nb_bits, 0, nb_input_bits, 0, nb_registers, 0, nb_input_registers); } +/* Allocates 4 arrays to store bits, input bits, registers and inputs + registers. The pointers are stored in modbus_mapping structure. + Aditionally the array for the file-reference acces are allocated, where the + size for the files is >0 + + The modbus_mapping_new() function shall return the new allocated structure if + successful. Otherwise it shall return NULL and set errno to ENOMEM. */ +modbus_mapping_t *modbus_mapping_new_extend( + int nb_bits, int nb_input_bits, int nb_registers, int nb_input_registers, + uint16_t nb_file_register[MODBUS_MAX_REFERENCE_FILES]) +{ + int i; + + modbus_mapping_t *mb_mapping = modbus_mapping_new( + nb_bits, nb_input_bits, nb_registers, nb_input_registers); + + if (mb_mapping) { + for (i = 0; i < MODBUS_MAX_REFERENCE_FILES; i++) { + if (nb_file_register[i]) { + mb_mapping->file_registers[i] = + (uint16_t *)malloc(nb_file_register[i] * sizeof(uint16_t)); + memset(mb_mapping->file_registers[i], 0, + nb_file_register[i] * sizeof(uint16_t)); + } + } + } + + return mb_mapping; +} + +/* Allocates 4 arrays to store bits, input bits, registers and inputs + registers. The pointers are stored in modbus_mapping structure. + Aditionally the array for the file-reference acces are allocated, where the + size for the files is >0 + + The modbus_mapping_new() function shall return the new allocated structure if + successful. Otherwise it shall return NULL and set errno to ENOMEM. */ +MODBUS_API modbus_mapping_t *modbus_mapping_new_start_address_extend( + unsigned int start_bits, unsigned int nb_bits, + unsigned int start_input_bits, unsigned int nb_input_bits, + unsigned int start_registers, unsigned int nb_registers, + unsigned int start_input_registers, unsigned int nb_input_registers, + uint16_t nb_file_registers[MODBUS_MAX_REFERENCE_FILES]) +{ + + int i; + + modbus_mapping_t *mb_mapping = modbus_mapping_new_start_address( + start_bits, nb_bits, start_input_bits, nb_input_bits, start_registers, + nb_registers, start_input_registers, nb_input_registers); + + if (mb_mapping) { + for (i = 0; i < MODBUS_MAX_REFERENCE_FILES; i++) { + if (nb_file_registers[i]) { + mb_mapping->file_registers[i] = + (uint16_t *)malloc(nb_file_registers[i] * sizeof(uint16_t)); + memset(mb_mapping->file_registers[i], 0, + nb_file_registers[i] * sizeof(uint16_t)); + } + } + } + return mb_mapping; +} /* Frees the 4 arrays */ void modbus_mapping_free(modbus_mapping_t *mb_mapping) { + int i; + if (mb_mapping == NULL) { return; } + for (i = 0; i < MODBUS_MAX_REFERENCE_FILES; i++) { + if (mb_mapping->file_registers[i]) { + free(mb_mapping->file_registers[i]); + } + } free(mb_mapping->tab_input_registers); free(mb_mapping->tab_registers); free(mb_mapping->tab_input_bits); diff --git a/src/modbus.h b/src/modbus.h index fda3f02b7..3f763e166 100644 --- a/src/modbus.h +++ b/src/modbus.h @@ -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_GENERAL_REFERENCE 0x14 +#define MODBUS_FC_WRITE_GENERAL_REFERENCE 0x15 #define MODBUS_FC_MASK_WRITE_REGISTER 0x16 #define MODBUS_FC_WRITE_AND_READ_REGISTERS 0x17 @@ -92,6 +94,7 @@ MODBUS_BEGIN_DECLS #define MODBUS_MAX_WRITE_REGISTERS 123 #define MODBUS_MAX_WR_WRITE_REGISTERS 121 #define MODBUS_MAX_WR_READ_REGISTERS 125 +#define MODBUS_MAX_REFERENCE_FILES 10 /* The size of the MODBUS PDU is limited by the size constraint inherited from * the first MODBUS implementation on Serial Line network (max. RS485 ADU = 256 @@ -167,6 +170,7 @@ typedef struct { uint8_t *tab_input_bits; uint16_t *tab_input_registers; uint16_t *tab_registers; + uint16_t *file_registers[MODBUS_MAX_REFERENCE_FILES]; } modbus_mapping_t; typedef enum @@ -215,6 +219,13 @@ MODBUS_API int modbus_mask_write_register(modbus_t *ctx, int addr, uint16_t and_ 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, uint16_t *dest); +MODBUS_API int modbus_read_general_reference(modbus_t *ctx, int file_no, + int read_addr, int read_nb, + uint16_t *dest); +MODBUS_API int modbus_write_general_reference(modbus_t *ctx, int file_no, + int write_addr, int write_nb, + const uint16_t *src); + MODBUS_API int modbus_report_slave_id(modbus_t *ctx, int max_dest, uint8_t *dest); MODBUS_API modbus_mapping_t* modbus_mapping_new_start_address( @@ -223,8 +234,19 @@ MODBUS_API modbus_mapping_t* modbus_mapping_new_start_address( unsigned int start_registers, unsigned int nb_registers, unsigned int start_input_registers, unsigned int nb_input_registers); +MODBUS_API modbus_mapping_t *modbus_mapping_new_start_address_extend( + unsigned int start_bits, unsigned int nb_bits, + unsigned int start_input_bits, unsigned int nb_input_bits, + unsigned int start_registers, unsigned int nb_registers, + unsigned int start_input_registers, unsigned int nb_input_registers, + uint16_t nb_file_registers[MODBUS_MAX_REFERENCE_FILES]); + MODBUS_API modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits, int nb_registers, int nb_input_registers); +MODBUS_API modbus_mapping_t *modbus_mapping_new_extend( + int nb_bits, int nb_input_bits, int nb_registers, int nb_input_registers, + uint16_t nb_file_registers[MODBUS_MAX_REFERENCE_FILES]); + MODBUS_API void modbus_mapping_free(modbus_mapping_t *mb_mapping); MODBUS_API int modbus_send_raw_request(modbus_t *ctx, uint8_t *raw_req, int raw_req_length); From 1dece16f36a0a24923aead34fb16dc33a65d7725 Mon Sep 17 00:00:00 2001 From: oliver Date: Tue, 7 Nov 2017 16:38:15 +0100 Subject: [PATCH 2/9] Added documentation for new functions 0x14 and 0x15 and new mappings for file-registers --- doc/modbus_mapping_new_extend.txt | 63 ++++++++++++++ ...odbus_mapping_new_start_address_extend.txt | 81 ++++++++++++++++++ doc/modbus_read_general_reference.txt | 84 +++++++++++++++++++ doc/modbus_write_general_reference.txt | 80 ++++++++++++++++++ 4 files changed, 308 insertions(+) create mode 100644 doc/modbus_mapping_new_extend.txt create mode 100644 doc/modbus_mapping_new_start_address_extend.txt create mode 100644 doc/modbus_read_general_reference.txt create mode 100644 doc/modbus_write_general_reference.txt diff --git a/doc/modbus_mapping_new_extend.txt b/doc/modbus_mapping_new_extend.txt new file mode 100644 index 000000000..c10cb6b64 --- /dev/null +++ b/doc/modbus_mapping_new_extend.txt @@ -0,0 +1,63 @@ +modbus_mapping_new_extend(3) +===================== + + +NAME +---- +modbus_mapping_new_extend - allocate four arrays of bits and registers and file registers + + +SYNOPSIS +-------- +*modbus_mapping_t* modbus_mapping_new_extend(int 'nb_bits', int 'nb_input_bits', int 'nb_registers', int 'nb_input_registers', uint16_t nb_file_register[MODBUS_MAX_REFERENCE_FILES]);* + + +DESCRIPTION +----------- +The *modbus_mapping_new_extend()* calls linkmb:modbus_mapping_new[3] and additionally allocates up to +MODBUS_MAX_REFERENCE_FILES (current specification limit it to 10) arrays for file registers. + +Each _value_ in the array, which is not 0 allocates _value_ registers in the file of _index_ -1 . +( The file registers start with "1" for the first file ) + +RETURN VALUE +------------ +The function shall return the new allocated structure if successful. Otherwise +it shall return NULL and set errno. + + +ERRORS +------ +*ENOMEM*:: +Not enough memory + + +EXAMPLE +------- +[source,c] +------------------- +/* The first value of each array is accessible from the 0 address. */ +mb_mapping = modbus_mapping_new_extend(BITS_ADDRESS + BITS_NB, + INPUT_BITS_ADDRESS + INPUT_BITS_NB, + REGISTERS_ADDRESS + REGISTERS_NB, + INPUT_REGISTERS_ADDRESS + INPUT_REGISTERS_NB, + FILE_REGISTERS_NB[MODBUS_MAX_REFERENCE_FILES]); +if (mb_mapping == NULL) { + fprintf(stderr, "Failed to allocate the mapping: %s\n", + modbus_strerror(errno)); + modbus_free(ctx); + return -1; +} +------------------- + +SEE ALSO +-------- +linkmb:modbus_mapping_new[3] +linkmb:modbus_mapping_free[3] +linkmb:modbus_mapping_new_start_address[3] + + +AUTHORS +------- +The libmodbus documentation was written by Stéphane Raimbault + diff --git a/doc/modbus_mapping_new_start_address_extend.txt b/doc/modbus_mapping_new_start_address_extend.txt new file mode 100644 index 000000000..d63b31966 --- /dev/null +++ b/doc/modbus_mapping_new_start_address_extend.txt @@ -0,0 +1,81 @@ +modbus_mapping_new_start_address_extend(3) +=================================== + + +NAME +---- +modbus_mapping_new_start_address_extend - allocate four arrays of bits and registers accessible from their starting addresses and file registers + + +SYNOPSIS +-------- +*modbus_mapping_t* modbus_mapping_new_start_address(int 'start_bits', int 'nb_bits', + int 'start_input_bits', int 'nb_input_bits', + int 'start_registers', int 'nb_registers', + int 'start_input_registers', int 'nb_input_registers', + 'uint16_t nb_file_register[MODBUS_MAX_REFERENCE_FILES]');* + + +DESCRIPTION +----------- +The *modbus_mapping_new_extend()* calls linkmb:modbus_mapping_new_start_address[3] and additionally allocates up to +MODBUS_MAX_REFERENCE_FILES (current specification limit it to 10) arrays for file registers. + +Each _value_ in the array, which is not 0 allocates _value_ registers in the file of _index_ -1 . +( The file registers start with "1" for the first file ) + +[source,c] +------------------- +mb_mapping = modbus_mapping_new_start_address_extend(0, 0, 0, 0, 10000, 10, 0, 0,{0,100,0,20,0,0,10000,0,0,0,0}); +------------------- + +With this code, 3 file registers ( 2, 4 and 7 ) with the size of 100 , 20 and 10000 registers are allocated. + +If it isn't necessary to allocate an array for a specific type of data, you can +pass the zero value in argument, the associated pointer will be NULL. + +This function is convenient to handle requests in a Modbus server/slave. + + +RETURN VALUE +------------ +The _modbus_mapping_new_start_address_extend()_ function shall return the new allocated structure if +successful. Otherwise it shall return NULL and set errno. + + +ERRORS +------ +ENOMEM:: +Not enough memory + + +EXAMPLE +------- +[source,c] +------------------- +/* The first value of each array is accessible at the defined address. + The end address is ADDRESS + NB - 1. */ +mb_mapping = modbus_mapping_new_start_address_extend(BITS_ADDRESS, BITS_NB, + INPUT_BITS_ADDRESS, INPUT_BITS_NB, + REGISTERS_ADDRESS, REGISTERS_NB, + INPUT_REGISTERS_ADDRESS, INPUT_REGISTERS_NB, + FILE_REGISTERS_NB[MODBUS_MAX_REFERENCE_FILES]); +if (mb_mapping == NULL) { + fprintf(stderr, "Failed to allocate the mapping: %s\n", + modbus_strerror(errno)); + modbus_free(ctx); + return -1; +} +------------------- + +SEE ALSO +-------- +linkmb:modbus_mapping_new_start_address[3] +linkmb:modbus_mapping_new[3] +linkmb:modbus_mapping_free[3] + + +AUTHORS +------- +The libmodbus documentation was written by Stéphane Raimbault + diff --git a/doc/modbus_read_general_reference.txt b/doc/modbus_read_general_reference.txt new file mode 100644 index 000000000..c1ad58e6f --- /dev/null +++ b/doc/modbus_read_general_reference.txt @@ -0,0 +1,84 @@ +modbus_read_general_reference(3) +======================== + + +NAME +---- +modbus_read_general_reference - read from file registers + + +SYNOPSIS +-------- +*int modbus_read_general_reference(modbus_t *ctx, int file_no, int read_addr, int read_nb, uint16_t *dest);* + + +DESCRIPTION +----------- +The *modbus_read_general_reference()* function shall read the number of _read_nb_ registers of the _file_no_ +reference file at the address _read_addr_ of the remote device. The result of +reading is stored in _dest_ array as word values (16 bits). + +_file_no_ has to be >= 1 and <= 10 . + +You must take care to allocate enough memory to store the results in _dest_ +(at least (_read_nb_ + 1 ) * sizeof(uint16_t)). + +The function uses the Modbus function code 0x14 (read file record). + + +RETURN VALUE +------------ +The function shall return the number of read registers + 1 +if successful. Otherwise it shall return -1 and set errno. + + +ERRORS +------ +*EMBMDATA*:: +Too many registers requested +*EMBXILVAL*:: +_file_no_ out of range , or file is not found. + + +EXAMPLE +------- +[source,c] +------------------- +modbus_t *ctx; +uint16_t tab_reg[64+1]; // one additional reg for filesize and reftype +int rc; +int i; + +ctx = modbus_new_tcp("127.0.0.1", 1502); +if (modbus_connect(ctx) == -1) { + fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno)); + modbus_free(ctx); + return -1; +} + + rc = modbus_read_general_reference(ctx, 1, 10 , 64, tab_reg ); + if (rc == -1) { + fprintf(stderr, "%s\n", modbus_strerror(errno)); + return -1; +} + +printf("size=%d subtype_ref=%d\n", i, tab_reg[0]>>8, tab_reg[0] &0xff); +for (i=1; i < rc; i++) { + printf("reg[%d]=%d (0x%X)\n", i, tab_reg[i], tab_reg[i]); +} + +modbus_close(ctx); +modbus_free(ctx); +------------------- + + +SEE ALSO +-------- +linkmb:modbus_write_general_reference[3] +linkmb:modbus_mapping_new_start_address_extend[3] +linkmb:modbus_mapping_new_extend[3] + +AUTHORS +------- +The libmodbus documentation was written by Stéphane Raimbault + diff --git a/doc/modbus_write_general_reference.txt b/doc/modbus_write_general_reference.txt new file mode 100644 index 000000000..9d1fd28bc --- /dev/null +++ b/doc/modbus_write_general_reference.txt @@ -0,0 +1,80 @@ +modbus_write_general_reference(3) +======================== + + +NAME +---- +modbus_write_general_reference - write to file registers + + +SYNOPSIS +-------- +*int modbus_write_general_reference(modbus_t *ctx, int file_no, int write_addr, int write_nb, const uint16_t *src);* + + +DESCRIPTION +----------- +The *modbus_read_general_reference()* function shall write the number of _write_nb_ registers of the _file_no_ +reference file at the address _write_addr_ of the remote device. The content for +writing is delivered in _src_ array as word values (16 bits). + +_file_no_ has to be >= 1 and <= 10 . + + +The function uses the Modbus function code 0x15 (write file record). + + +RETURN VALUE +------------ +The function shall return the number of written registers + 1 +if successful. Otherwise it shall return -1 and set errno. + + +ERRORS +------ +*EMBMDATA*:: +Too many registers requested +*EMBXILVAL*:: +_file_no_ out of range , or file is not found. + + +EXAMPLE +------- +[source,c] +------------------- +modbus_t *ctx; +uint16_t tab_reg[64]; +int rc; +int i; + +ctx = modbus_new_tcp("127.0.0.1", 1502); +if (modbus_connect(ctx) == -1) { + fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno)); + modbus_free(ctx); + return -1; +} + +for (i=0; i < 64; i++){ + tab_reg[i]=i+i*0x100; +} + rc = modbus_write_general_reference(ctx, 1, 10 , 64, tab_reg ); + if (rc == -1) { + fprintf(stderr, "%s\n", modbus_strerror(errno)); + return -1; +} + +modbus_close(ctx); +modbus_free(ctx); +------------------- + + +SEE ALSO +-------- +linkmb:modbus_read_general_reference[3] +linkmb:modbus_mapping_new_start_address_extend[3] +linkmb:modbus_mapping_new_extend[3] + +AUTHORS +------- +The libmodbus documentation was written by Stéphane Raimbault + From 41d3f3ade7c6f48ce37c03279e551da4b2df037c Mon Sep 17 00:00:00 2001 From: oliver Date: Tue, 7 Nov 2017 16:41:00 +0100 Subject: [PATCH 3/9] Added test for functions 0x14 and 0x15 and mappings of file-registers --- tests/unit-test-client.c | 96 +++++++++++++++++++++++++++++++++++++++- tests/unit-test-server.c | 9 ++-- tests/unit-test.h.in | 5 +++ 3 files changed, 104 insertions(+), 6 deletions(-) diff --git a/tests/unit-test-client.c b/tests/unit-test-client.c index fdf5c26ed..e8c9ee78f 100644 --- a/tests/unit-test-client.c +++ b/tests/unit-test-client.c @@ -49,9 +49,10 @@ int main(int argc, char *argv[]) const int NB_REPORT_SLAVE_ID = 10; uint8_t *tab_rp_bits = NULL; uint16_t *tab_rp_registers = NULL; + uint16_t *tab_rp_file = NULL; uint16_t *tab_rp_registers_bad = NULL; modbus_t *ctx = NULL; - int i; + int i, j; uint8_t value; int nb_points; int rc; @@ -127,6 +128,9 @@ int main(int argc, char *argv[]) tab_rp_registers = (uint16_t *) malloc(nb_points * sizeof(uint16_t)); memset(tab_rp_registers, 0, nb_points * sizeof(uint16_t)); + tab_rp_file = + (uint16_t *)malloc((MAX_REGISTER_PER_QUERY + 2) * sizeof(uint16_t)); + memset(tab_rp_file, 0, (MAX_REGISTER_PER_QUERY + 2) * sizeof(uint16_t)); printf("\nTEST WRITE/READ:\n"); /** COIL BITS **/ @@ -657,6 +661,95 @@ int main(int argc, char *argv[]) printf("* modbus_read_registers at special address: "); ASSERT_TRUE(rc == -1 && errno == EMBXSBUSY, ""); + /** Read File*/ + printf("\nTEST READ GENERAL REFERENCE\n"); + { + + rc = modbus_read_general_reference(ctx, 1, 10, MAX_REGISTER_PER_QUERY, + tab_rp_file); + printf("modbus_read_general_reference: "); + + if (rc < (MAX_REGISTER_PER_QUERY + + 1)) { // 2 bytes per register + 2 bytes header + printf("FAILED (nb points %d)\n", rc); + goto close; + } + + if (((tab_rp_file[0]) >> 8) != MAX_REGISTER_PER_QUERY) { + printf("FAILED Received size wrong(%0X != %0X)\n", + (tab_rp_file[0]) >> 8, MAX_REGISTER_PER_QUERY); + goto close; + } + + if ((tab_rp_file[0] & 0xff) != 0x06) { + printf("FAILED Received Subrequest Reference(%0X != %0X)\n", + tab_rp_file[0] & 0xff, 0x06); + goto close; + } + + for (i = 0; i < MAX_REGISTER_PER_QUERY; i++) { + if (tab_rp_file[i + 1] != 0) { + printf("FAILED (%0X != %0X)\n", tab_rp_file[i + 1], 0); + goto close; + } + } + printf("OK\n"); + } + + printf("\nTEST WRITE GENERAL REFERENCE\n"); + { + + for (i = 1; i < 5; i++) { + rc = modbus_write_general_reference( + ctx, i, i * 7, UT_FILE_REGISTER_NB - i, &UT_FILE_REGISTER_TAB[i]); + + printf("modbus_write_general_reference File_no %d: ", i); + + if (rc < (UT_FILE_REGISTER_NB + 1 - + i)) { // 2 bytes per register + 2 bytes header + printf("FAILED (nb points %d)\n", rc); + goto close; + } + printf("OK\n"); + } + + for (i = 1; i < 5; i++) { + rc = modbus_read_general_reference( + ctx, i, i * 7, UT_FILE_REGISTER_NB - 1, tab_rp_file); + + printf("modbus_read_general_reference File_no %d: ", i); + + if (rc < (UT_FILE_REGISTER_NB + 1 - + i)) { // 2 bytes per register + 2 bytes header + printf("FAILED (nb points %d)\n", rc); + goto close; + } + + printf("OK , Verify : "); + + for (j = 0; j < (UT_FILE_REGISTER_NB - i); j++) { + if (tab_rp_file[j + 1] != UT_FILE_REGISTER_TAB[j + i]) { + printf("FAILED (%0X != %0X) at %d \n", tab_rp_file[j + 1], + UT_FILE_REGISTER_TAB[j + i], j); + goto close; + } + } + printf("OK\n"); + } + } + + /* Writing to a non existing file */ + rc = modbus_write_general_reference(ctx, 6, 0, UT_FILE_REGISTER_NB, + UT_FILE_REGISTER_TAB); + + printf("modbus_write_general_reference File_no 6 "); + + if (rc == -1 && errno == EMBXILVAL) { // This should fail + printf("OK\n"); + } else { + printf("FAILED (nb points %d) errno %d \n", rc, errno); + goto close; + } /** Run a few tests to challenge the server code **/ if (test_server(ctx, use_backend) == -1) { @@ -685,6 +778,7 @@ int main(int argc, char *argv[]) /* Free the memory */ free(tab_rp_bits); free(tab_rp_registers); + free(tab_rp_file); /* Close the connection */ modbus_close(ctx); diff --git a/tests/unit-test-server.c b/tests/unit-test-server.c index 7002b10c6..e69d589d0 100644 --- a/tests/unit-test-server.c +++ b/tests/unit-test-server.c @@ -71,11 +71,10 @@ int main(int argc, char*argv[]) modbus_set_debug(ctx, TRUE); - mb_mapping = modbus_mapping_new_start_address( - UT_BITS_ADDRESS, UT_BITS_NB, - UT_INPUT_BITS_ADDRESS, UT_INPUT_BITS_NB, - UT_REGISTERS_ADDRESS, UT_REGISTERS_NB_MAX, - UT_INPUT_REGISTERS_ADDRESS, UT_INPUT_REGISTERS_NB); + mb_mapping = modbus_mapping_new_start_address_extend( + UT_BITS_ADDRESS, UT_BITS_NB, UT_INPUT_BITS_ADDRESS, UT_INPUT_BITS_NB, + UT_REGISTERS_ADDRESS, UT_REGISTERS_NB_MAX, UT_INPUT_REGISTERS_ADDRESS, + UT_INPUT_REGISTERS_NB, UT_FILE_REGISTERS_NB); if (mb_mapping == NULL) { fprintf(stderr, "Failed to allocate the mapping: %s\n", modbus_strerror(errno)); diff --git a/tests/unit-test.h.in b/tests/unit-test.h.in index dca826f46..62f92f874 100644 --- a/tests/unit-test.h.in +++ b/tests/unit-test.h.in @@ -25,6 +25,8 @@ #define SERVER_ID 17 #define INVALID_SERVER_ID 18 +#define MAX_REGISTER_PER_QUERY 100 + const uint16_t UT_BITS_ADDRESS = 0x130; const uint16_t UT_BITS_NB = 0x25; const uint8_t UT_BITS_TAB[] = { 0xCD, 0x6B, 0xB2, 0x0E, 0x1B }; @@ -55,6 +57,9 @@ const uint16_t UT_REGISTERS_NB_SPECIAL = 0x2; const uint16_t UT_INPUT_REGISTERS_ADDRESS = 0x108; const uint16_t UT_INPUT_REGISTERS_NB = 0x1; const uint16_t UT_INPUT_REGISTERS_TAB[] = { 0x000A }; +#define UT_FILE_REGISTER_NB 20 +const uint16_t UT_FILE_REGISTER_TAB[UT_FILE_REGISTER_NB] = { 0x0001,0x0101,0xFF55,0x1234,0x6789,0xABCD,0xDEFF,0x2222,0x3333,0x4444,0x5555,0x0505,0x6060,0xcafe, }; +uint16_t UT_FILE_REGISTERS_NB[MODBUS_MAX_REFERENCE_FILES] = { 200,500,100,700,50 }; const float UT_REAL = 123456.00; From 455f7cbd43f440d9c21ea39d0bafd827f9421c92 Mon Sep 17 00:00:00 2001 From: oliver Date: Tue, 7 Nov 2017 16:44:09 +0100 Subject: [PATCH 4/9] Improved commandline for tests, devicenames and baudrate of rtu-test can be provided --- tests/unit-test-client.c | 19 +++++++++++++++++-- tests/unit-test-server.c | 19 +++++++++++++++++-- tests/unit-test.h.in | 1 + 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/tests/unit-test-client.c b/tests/unit-test-client.c index e8c9ee78f..3e7dec6ab 100644 --- a/tests/unit-test-client.c +++ b/tests/unit-test-client.c @@ -67,6 +67,10 @@ int main(int argc, char *argv[]) int success = FALSE; int old_slave; + char devicename[MAX_DEVICENAME_LENGHT] = { + 0, + }; + int baudrate = 115200; if (argc > 1) { if (strcmp(argv[1], "tcp") == 0) { use_backend = TCP; @@ -75,7 +79,9 @@ int main(int argc, char *argv[]) } else if (strcmp(argv[1], "rtu") == 0) { use_backend = RTU; } else { - printf("Usage:\n %s [tcp|tcppi|rtu] - Modbus client for unit testing\n\n", argv[0]); + printf("Usage:\n %s [tcp|tcppi|rtu] ('device-name for rtu') " + "(baudrate for rtu) - Modbus client for unit testing\n\n", + argv[0]); exit(1); } } else { @@ -83,12 +89,21 @@ int main(int argc, char *argv[]) use_backend = TCP; } + if (argc > 2) { + strncpy(devicename, argv[2], MAX_DEVICENAME_LENGHT); + } else { + strncpy(devicename, "/dev/ttyUSB1", MAX_DEVICENAME_LENGHT); + } + if (argc > 3) { + baudrate = atoi(argv[3]); + } + if (use_backend == TCP) { ctx = modbus_new_tcp("127.0.0.1", 1502); } else if (use_backend == TCP_PI) { ctx = modbus_new_tcp_pi("::1", "1502"); } else { - ctx = modbus_new_rtu("/dev/ttyUSB1", 115200, 'N', 8, 1); + ctx = modbus_new_rtu(devicename, baudrate, 'N', 8, 1); } if (ctx == NULL) { fprintf(stderr, "Unable to allocate libmodbus context\n"); diff --git a/tests/unit-test-server.c b/tests/unit-test-server.c index e69d589d0..ca36021f4 100644 --- a/tests/unit-test-server.c +++ b/tests/unit-test-server.c @@ -39,6 +39,10 @@ int main(int argc, char*argv[]) int use_backend; uint8_t *query; int header_length; + char devicename[MAX_DEVICENAME_LENGHT] = { + 0, + }; + int baudrate = 115200; if (argc > 1) { if (strcmp(argv[1], "tcp") == 0) { @@ -48,7 +52,9 @@ int main(int argc, char*argv[]) } else if (strcmp(argv[1], "rtu") == 0) { use_backend = RTU; } else { - printf("Usage:\n %s [tcp|tcppi|rtu] - Modbus server for unit testing\n\n", argv[0]); + printf("Usage:\n %s [tcp|tcppi|rtu] ('device-name for rtu') " + "(baudrate for rtu) - Modbus server for unit testing\n\n", + argv[0]); return -1; } } else { @@ -56,6 +62,15 @@ int main(int argc, char*argv[]) use_backend = TCP; } + if (argc > 2) { + strncpy(devicename, argv[2], MAX_DEVICENAME_LENGHT); + } else { + strncpy(devicename, "/dev/ttyUSB0", MAX_DEVICENAME_LENGHT); + } + if (argc > 3) { + baudrate = atoi(argv[3]); + } + if (use_backend == TCP) { ctx = modbus_new_tcp("127.0.0.1", 1502); query = malloc(MODBUS_TCP_MAX_ADU_LENGTH); @@ -63,7 +78,7 @@ int main(int argc, char*argv[]) ctx = modbus_new_tcp_pi("::0", "1502"); query = malloc(MODBUS_TCP_MAX_ADU_LENGTH); } else { - ctx = modbus_new_rtu("/dev/ttyUSB0", 115200, 'N', 8, 1); + ctx = modbus_new_rtu(devicename, baudrate, 'N', 8, 1); modbus_set_slave(ctx, SERVER_ID); query = malloc(MODBUS_RTU_MAX_ADU_LENGTH); } diff --git a/tests/unit-test.h.in b/tests/unit-test.h.in index 62f92f874..1e1ddc072 100644 --- a/tests/unit-test.h.in +++ b/tests/unit-test.h.in @@ -25,6 +25,7 @@ #define SERVER_ID 17 #define INVALID_SERVER_ID 18 +#define MAX_DEVICENAME_LENGHT 256 #define MAX_REGISTER_PER_QUERY 100 const uint16_t UT_BITS_ADDRESS = 0x130; From 54ca52775363550d856b54d4aca0eb22c3720504 Mon Sep 17 00:00:00 2001 From: oliver Date: Wed, 8 Nov 2017 11:43:08 +0100 Subject: [PATCH 5/9] Changed c++ comments to c-style --- src/modbus-private.h | 4 ++-- src/modbus.c | 32 ++++++++++---------------------- tests/unit-test-client.c | 8 ++++---- 3 files changed, 16 insertions(+), 28 deletions(-) diff --git a/src/modbus-private.h b/src/modbus-private.h index ccaaff4d3..5e049df02 100644 --- a/src/modbus-private.h +++ b/src/modbus-private.h @@ -40,8 +40,8 @@ MODBUS_BEGIN_DECLS #define _BYTE_TIMEOUT 500000 #define SUB_REQUEST_LENGHT 0x07 -#define SUB_REQUEST_REF_TYPE \ - 0x06 // Reference-Type for General Reference Read + Write +#define SUB_REQUEST_REF_TYPE 0x06 + /* Reference-Type for File-Record Read + Write */ typedef enum { _MODBUS_BACKEND_TYPE_RTU=0, diff --git a/src/modbus.c b/src/modbus.c index 145512ab9..faf1131e0 100644 --- a/src/modbus.c +++ b/src/modbus.c @@ -156,7 +156,7 @@ static unsigned int compute_response_length_from_request(modbus_t *ctx, uint8_t length = 2 + req[offset + 1]; break; case MODBUS_FC_READ_GENERAL_REFERENCE: - return MSG_LENGTH_UNDEFINED; // Lenght is dedepnding of the subrequests + return MSG_LENGTH_UNDEFINED; /* Lenght is dedepnding of the subrequests */ case MODBUS_FC_MASK_WRITE_REGISTER: length = 7; break; @@ -290,8 +290,8 @@ static uint8_t compute_meta_length_after_function(int function, break; case MODBUS_FC_WRITE_GENERAL_REFERENCE: case MODBUS_FC_READ_GENERAL_REFERENCE: - length = 1; // After the function, the number of bytes is transmitted - // and at least one SUB_REQUEST + length = 1; /* After the function, the number of bytes is transmitted + and at least one SUB_REQUEST*/ break; default: length = 1; @@ -1016,8 +1016,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, } } break; case MODBUS_FC_WRITE_GENERAL_REFERENCE: { - // Each "Read_General_Reference", aka as "Read_File", can consists of - // several Subrequests + /* Each "Write_File_Record", can consists of several Subrequests */ uint8_t nb = req[offset + 1]; uint16_t i; int nsr = 0; @@ -1042,7 +1041,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, } else { /* Response is a simple copy of the request */ memcpy(rsp + rsp_length, req + offset + 1, - 1 + nb); // number of bytes + the place for the nb itself + 1 + nb); /* number of bytes + the place for the nb itself */ rsp_length += nb + 1; do { @@ -1085,8 +1084,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, } } break; case MODBUS_FC_READ_GENERAL_REFERENCE: { - // Each "Read_General_Reference", aka as "Read_File", can consists of - // several Subrequests + /* Each "Read_FielRecord", can consists of several Subrequests */ uint8_t nb = req[offset + 1]; uint16_t i; int nsr = 0; @@ -1104,7 +1102,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, rsp_length = ctx->backend->build_response_basis(&sft, rsp); rsp_length_byte_count = - rsp_length; // Place-holder of overall message-size. + rsp_length; /* Place-holder of overall message-size. */ rsp[rsp_length++] = 0; do { @@ -1152,7 +1150,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, offset += SUB_REQUEST_LENGHT; nsr++; } while (nsr < (nb / SUB_REQUEST_LENGHT)); - // put overall lenght of message at the reserved space in the beginning. + /* put overall lenght of message at the reserved space in the beginning. */ rsp[rsp_length_byte_count] = (rsp_length - rsp_length_byte_count) - 1; } break; @@ -1847,18 +1845,8 @@ int modbus_write_general_reference(modbus_t *ctx, int file_no, int write_addr, rc /= 2; /* rc is in byte, we count in uint16-steps */ -#if 0 // Does it make sense to copy back the response to the caller ? It's a - // copy of the request - offset = ctx->backend->header_length; - - /* If rc is negative, the loop is jumped ! */ - for (i = 0; i < rc; i++) { - /* shift reg hi_byte to temp OR with lo_byte */ - src[i] = (rsp[offset + 2 + (i << 1)] << 8) | - rsp[offset + 3 + (i << 1)]; - } - -#endif + /* It does not make sense to copy back the response to the caller, so + it is left out */ } return rc; } diff --git a/tests/unit-test-client.c b/tests/unit-test-client.c index 3e7dec6ab..1023bbde6 100644 --- a/tests/unit-test-client.c +++ b/tests/unit-test-client.c @@ -685,7 +685,7 @@ int main(int argc, char *argv[]) printf("modbus_read_general_reference: "); if (rc < (MAX_REGISTER_PER_QUERY + - 1)) { // 2 bytes per register + 2 bytes header + 1)) { /* 2 bytes per register + 2 bytes header */ printf("FAILED (nb points %d)\n", rc); goto close; } @@ -721,7 +721,7 @@ int main(int argc, char *argv[]) printf("modbus_write_general_reference File_no %d: ", i); if (rc < (UT_FILE_REGISTER_NB + 1 - - i)) { // 2 bytes per register + 2 bytes header + i)) { /* 2 bytes per register + 2 bytes header*/ printf("FAILED (nb points %d)\n", rc); goto close; } @@ -735,7 +735,7 @@ int main(int argc, char *argv[]) printf("modbus_read_general_reference File_no %d: ", i); if (rc < (UT_FILE_REGISTER_NB + 1 - - i)) { // 2 bytes per register + 2 bytes header + i)) { /* 2 bytes per register + 2 bytes header */ printf("FAILED (nb points %d)\n", rc); goto close; } @@ -759,7 +759,7 @@ int main(int argc, char *argv[]) printf("modbus_write_general_reference File_no 6 "); - if (rc == -1 && errno == EMBXILVAL) { // This should fail + if (rc == -1 && errno == EMBXILVAL) { /* This should fail */ printf("OK\n"); } else { printf("FAILED (nb points %d) errno %d \n", rc, errno); From ad8f21c8fc2e1d923fedc30beb0c0714f530e617 Mon Sep 17 00:00:00 2001 From: oliver Date: Wed, 8 Nov 2017 12:03:54 +0100 Subject: [PATCH 6/9] Changed naming to write+read file record and _sub_req_hdr_length --- src/modbus-private.h | 6 +-- src/modbus.c | 95 ++++++++++++++++++++-------------------- src/modbus.h | 8 ++-- tests/unit-test-client.c | 20 ++++----- 4 files changed, 65 insertions(+), 64 deletions(-) diff --git a/src/modbus-private.h b/src/modbus-private.h index 5e049df02..b38cd7086 100644 --- a/src/modbus-private.h +++ b/src/modbus-private.h @@ -39,9 +39,9 @@ MODBUS_BEGIN_DECLS #define _RESPONSE_TIMEOUT 500000 #define _BYTE_TIMEOUT 500000 -#define SUB_REQUEST_LENGHT 0x07 -#define SUB_REQUEST_REF_TYPE 0x06 - /* Reference-Type for File-Record Read + Write */ +/* Reference-Type for File-Record Read + Write */ +#define _SUB_REQ_HDR_LENGTH 0x07 +#define _SUB_REQUEST_REF_TYPE 0x06 typedef enum { _MODBUS_BACKEND_TYPE_RTU=0, diff --git a/src/modbus.c b/src/modbus.c index faf1131e0..8917de0c9 100644 --- a/src/modbus.c +++ b/src/modbus.c @@ -152,11 +152,11 @@ 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_WRITE_GENERAL_REFERENCE: + case MODBUS_FC_WRITE_FILE_RECORD: length = 2 + req[offset + 1]; break; - case MODBUS_FC_READ_GENERAL_REFERENCE: - return MSG_LENGTH_UNDEFINED; /* Lenght is dedepnding of the subrequests */ + case MODBUS_FC_READ_FILE_RECORD: + return MSG_LENGTH_UNDEFINED; /* Length is dedepnding of the subrequests */ case MODBUS_FC_MASK_WRITE_REGISTER: length = 7; break; @@ -269,8 +269,8 @@ static uint8_t compute_meta_length_after_function(int function, length = 6; } else if (function == MODBUS_FC_WRITE_AND_READ_REGISTERS) { length = 9; - } else if (function == MODBUS_FC_READ_GENERAL_REFERENCE || - function == MODBUS_FC_WRITE_GENERAL_REFERENCE) { + } else if (function == MODBUS_FC_READ_FILE_RECORD || + function == MODBUS_FC_WRITE_FILE_RECORD) { length = 1; // After the function, the number of bytes is transmitted } else { /* MODBUS_FC_READ_EXCEPTION_STATUS, MODBUS_FC_REPORT_SLAVE_ID */ @@ -288,8 +288,8 @@ static uint8_t compute_meta_length_after_function(int function, case MODBUS_FC_MASK_WRITE_REGISTER: length = 6; break; - case MODBUS_FC_WRITE_GENERAL_REFERENCE: - case MODBUS_FC_READ_GENERAL_REFERENCE: + case MODBUS_FC_WRITE_FILE_RECORD: + case MODBUS_FC_READ_FILE_RECORD: length = 1; /* After the function, the number of bytes is transmitted and at least one SUB_REQUEST*/ break; @@ -317,8 +317,8 @@ 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_WRITE_GENERAL_REFERENCE: - case MODBUS_FC_READ_GENERAL_REFERENCE: + case MODBUS_FC_WRITE_FILE_RECORD: + case MODBUS_FC_READ_FILE_RECORD: length = msg[ctx->backend->header_length + 1]; break; default: @@ -330,8 +330,8 @@ 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_GENERAL_REFERENCE || - function == MODBUS_FC_WRITE_GENERAL_REFERENCE) { + } else if (function == MODBUS_FC_READ_FILE_RECORD || + function == MODBUS_FC_WRITE_FILE_RECORD) { length = msg[ctx->backend->header_length + 1]; } else { length = 0; @@ -616,12 +616,12 @@ static int check_confirmation(modbus_t *ctx, uint8_t *req, req_nb_value = (req[offset + 3] << 8) + req[offset + 4]; rsp_nb_value = (rsp[offset + 3] << 8) | rsp[offset + 4]; break; - case MODBUS_FC_WRITE_GENERAL_REFERENCE: + case MODBUS_FC_WRITE_FILE_RECORD: /* Check for Bytes recevied, response is copy of the request */ req_nb_value = req[offset + 1]; rsp_nb_value = rsp[offset + 1]; break; - case MODBUS_FC_READ_GENERAL_REFERENCE: + case MODBUS_FC_READ_FILE_RECORD: /* Check for Bytes recevied */ req_nb_value = rsp_nb_value = rsp[offset + 1]; break; @@ -1015,7 +1015,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, } } } break; - case MODBUS_FC_WRITE_GENERAL_REFERENCE: { + case MODBUS_FC_WRITE_FILE_RECORD: { /* Each "Write_File_Record", can consists of several Subrequests */ uint8_t nb = req[offset + 1]; uint16_t i; @@ -1023,7 +1023,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, uint8_t ref_type = 0; /* Each Subrequest has at least 7 Bytes */ - if (nb < SUB_REQUEST_LENGHT) { + if (nb < _SUB_REQ_HDR_LENGTH) { rsp_length = response_exception( ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE, "Illegal nb of subrequests %d in write_general_reference \n", nb); @@ -1034,8 +1034,8 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, if (rsp_length + nb >= MODBUS_MAX_READ_REGISTERS) { rsp_length = response_exception( ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE, - "Responselenght exceeds telegram-size %d in subrequests %d in " - "write_general_reference \n", + "Responselength exceeds telegram-size %d in subrequests %d in " + "write_file_record \n", rsp_length + nb, nsr); } else { @@ -1047,26 +1047,26 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, do { offset += 2; ref_type = req[offset]; - if (ref_type != SUB_REQUEST_REF_TYPE) { + if (ref_type != _SUB_REQUEST_REF_TYPE) { rsp_length = response_exception( ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE, "Illegal reference Type %d in subrequests %d in " - "write_general_reference \n", + "write_file_record \n", ref_type, nsr); } else { uint16_t file_no = (req[offset + 1] << 8) + req[offset + 2]; uint16_t f_address = (req[offset + 3] << 8) + req[offset + 4]; uint16_t nb_write = (req[offset + 5] << 8) + req[offset + 6]; - offset += SUB_REQUEST_LENGHT; - nb -= SUB_REQUEST_LENGHT; + offset += _SUB_REQ_HDR_LENGTH; + nb -= _SUB_REQ_HDR_LENGTH; if ((file_no == 0) || (file_no > MODBUS_MAX_REFERENCE_FILES) || (mb_mapping->file_registers[file_no - 1] == NULL)) { rsp_length = response_exception( ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE, "Illegal parameter file %d in subrequests %d in " - "write_general_reference \n", + "write_file_record \n", file_no, nsr); break; } else { @@ -1083,7 +1083,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, } while (nb > 0); } } break; - case MODBUS_FC_READ_GENERAL_REFERENCE: { + case MODBUS_FC_READ_FILE_RECORD: { /* Each "Read_FielRecord", can consists of several Subrequests */ uint8_t nb = req[offset + 1]; uint16_t i; @@ -1092,10 +1092,10 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, int rsp_length_byte_count = 0; /* Each Subrequest has 7 Bytes */ - if (nb % SUB_REQUEST_LENGHT != 0) { + if (nb % _SUB_REQ_HDR_LENGTH != 0) { rsp_length = response_exception( ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE, - "Illegal nb of subrequests %d in read_general_reference \n", nb); + "Illegal nb of subrequests %d in read_read_file \n", nb); break; } @@ -1109,11 +1109,11 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, offset += 2; ref_type = req[offset]; - if (ref_type != SUB_REQUEST_REF_TYPE) { + if (ref_type != _SUB_REQUEST_REF_TYPE) { rsp_length = response_exception( ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE, "Illegal reference Type %d in subrequests %d in " - "read_general_reference \n", + "read_file_record \n", ref_type, nsr); } else { uint16_t file_no = (req[offset + 1] << 8) + req[offset + 2]; @@ -1131,13 +1131,13 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, } else if (rsp_length + nb_read >= MODBUS_MAX_READ_REGISTERS) { rsp_length = response_exception( ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE, - "Responselenght exceeds telegram-size %d in subrequests %d in " - "read_general_reference \n", + "Responselength exceeds telegram-size %d in subrequests %d in " + "read_file_record \n", rsp_length + nb_read, nsr); } else { rsp[rsp_length++] = nb_read; - rsp[rsp_length++] = SUB_REQUEST_REF_TYPE; + rsp[rsp_length++] = _SUB_REQUEST_REF_TYPE; /* and read the data for the response */ for (i = f_address; i < f_address + nb_read; i++) { rsp[rsp_length++] = @@ -1147,10 +1147,10 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, } } } - offset += SUB_REQUEST_LENGHT; + offset += _SUB_REQ_HDR_LENGTH; nsr++; - } while (nsr < (nb / SUB_REQUEST_LENGHT)); - /* put overall lenght of message at the reserved space in the beginning. */ + } while (nsr < (nb / _SUB_REQ_HDR_LENGTH)); + /* put overall length of message at the reserved space in the beginning. */ rsp[rsp_length_byte_count] = (rsp_length - rsp_length_byte_count) - 1; } break; @@ -1726,13 +1726,13 @@ int modbus_report_slave_id(modbus_t *ctx, int max_dest, uint8_t *dest) return rc; } -/* Read General Reference ( aka as Read File ) reads nb registers (16-bit) from - * an offset ( also 16-bit stepping ) of a given filenumber*/ -/* This implements only the simple case with one subrequest. More complex can be - * created with raw-message. */ -/* !!! Take care, that dest must have the size of at least read_nb +1 !!! */ +/* Read File Record reads nb registers (16-bit) from + * an offset ( also 16-bit stepping ) of a given filenumber + * This implements only the simple case with one subrequest. More complex can be + * created with raw-message. + * !!! Take care, that dest array must have the size of at least read_nb +1 !!! */ -int modbus_read_general_reference(modbus_t *ctx, int file_no, int read_addr, +int modbus_read_file_record(modbus_t *ctx, int file_no, int read_addr, int read_nb, uint16_t *dest) { @@ -1751,9 +1751,9 @@ int modbus_read_general_reference(modbus_t *ctx, int file_no, int read_addr, errno = EMBMDATA; return -1; } - byte_count = SUB_REQUEST_LENGHT; + byte_count = _SUB_REQ_HDR_LENGTH; req_length = ctx->backend->build_request_basis( - ctx, MODBUS_FC_READ_GENERAL_REFERENCE, ((byte_count << 8) | 0x06), + ctx, MODBUS_FC_READ_FILE_RECORD, ((byte_count << 8) | 0x06), file_no, req); req[req_length++] = read_addr >> 8; @@ -1793,11 +1793,12 @@ int modbus_read_general_reference(modbus_t *ctx, int file_no, int read_addr, return rc; } -/* Write General Reference ( aka as Write File ) writes nb registers (16-bit) - * from an offset ( also 16-bit stepping ) of a given filenumber*/ -/* This implements only the simple case with one subrequest. More complex can be +/* Write File Record writes nb registers (16-bit) + * from an offset ( also 16-bit stepping ) of a given filenumber + * This implements only the simple case with one subrequest. More complex can be * created with raw-message. */ -int modbus_write_general_reference(modbus_t *ctx, int file_no, int write_addr, + +int modbus_write_file_record(modbus_t *ctx, int file_no, int write_addr, int write_nb, const uint16_t *src) { @@ -1816,9 +1817,9 @@ int modbus_write_general_reference(modbus_t *ctx, int file_no, int write_addr, errno = EMBMDATA; return -1; } - byte_count = SUB_REQUEST_LENGHT + (write_nb * 2); + byte_count = _SUB_REQ_HDR_LENGTH + (write_nb * 2); req_length = ctx->backend->build_request_basis( - ctx, MODBUS_FC_WRITE_GENERAL_REFERENCE, ((byte_count << 8) | 0x06), + ctx, MODBUS_FC_WRITE_FILE_RECORD, ((byte_count << 8) | 0x06), file_no, req); req[req_length++] = write_addr >> 8; diff --git a/src/modbus.h b/src/modbus.h index 3f763e166..d32918087 100644 --- a/src/modbus.h +++ b/src/modbus.h @@ -68,8 +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_GENERAL_REFERENCE 0x14 -#define MODBUS_FC_WRITE_GENERAL_REFERENCE 0x15 +#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 @@ -219,10 +219,10 @@ MODBUS_API int modbus_mask_write_register(modbus_t *ctx, int addr, uint16_t and_ 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, uint16_t *dest); -MODBUS_API int modbus_read_general_reference(modbus_t *ctx, int file_no, +MODBUS_API int modbus_read_file_record(modbus_t *ctx, int file_no, int read_addr, int read_nb, uint16_t *dest); -MODBUS_API int modbus_write_general_reference(modbus_t *ctx, int file_no, +MODBUS_API int modbus_write_file_record(modbus_t *ctx, int file_no, int write_addr, int write_nb, const uint16_t *src); diff --git a/tests/unit-test-client.c b/tests/unit-test-client.c index 1023bbde6..c293d798d 100644 --- a/tests/unit-test-client.c +++ b/tests/unit-test-client.c @@ -677,12 +677,12 @@ int main(int argc, char *argv[]) printf("* modbus_read_registers at special address: "); ASSERT_TRUE(rc == -1 && errno == EMBXSBUSY, ""); /** Read File*/ - printf("\nTEST READ GENERAL REFERENCE\n"); + printf("\nTEST READ FILE RECORD\n"); { - rc = modbus_read_general_reference(ctx, 1, 10, MAX_REGISTER_PER_QUERY, + rc = modbus_read_file_record(ctx, 1, 10, MAX_REGISTER_PER_QUERY, tab_rp_file); - printf("modbus_read_general_reference: "); + printf("modbus_read_file_record: "); if (rc < (MAX_REGISTER_PER_QUERY + 1)) { /* 2 bytes per register + 2 bytes header */ @@ -711,14 +711,14 @@ int main(int argc, char *argv[]) printf("OK\n"); } - printf("\nTEST WRITE GENERAL REFERENCE\n"); + printf("\nTEST WRITE FILE RECORD\n"); { for (i = 1; i < 5; i++) { - rc = modbus_write_general_reference( + rc = modbus_write_file_record( ctx, i, i * 7, UT_FILE_REGISTER_NB - i, &UT_FILE_REGISTER_TAB[i]); - printf("modbus_write_general_reference File_no %d: ", i); + printf("modbus_write_file_record File_no %d: ", i); if (rc < (UT_FILE_REGISTER_NB + 1 - i)) { /* 2 bytes per register + 2 bytes header*/ @@ -729,10 +729,10 @@ int main(int argc, char *argv[]) } for (i = 1; i < 5; i++) { - rc = modbus_read_general_reference( + rc = modbus_read_file_record( ctx, i, i * 7, UT_FILE_REGISTER_NB - 1, tab_rp_file); - printf("modbus_read_general_reference File_no %d: ", i); + printf("modbus_read_file_record File_no %d: ", i); if (rc < (UT_FILE_REGISTER_NB + 1 - i)) { /* 2 bytes per register + 2 bytes header */ @@ -754,10 +754,10 @@ int main(int argc, char *argv[]) } /* Writing to a non existing file */ - rc = modbus_write_general_reference(ctx, 6, 0, UT_FILE_REGISTER_NB, + rc = modbus_write_file_record(ctx, 6, 0, UT_FILE_REGISTER_NB, UT_FILE_REGISTER_TAB); - printf("modbus_write_general_reference File_no 6 "); + printf("modbus_write_file_record File_no 6 "); if (rc == -1 && errno == EMBXILVAL) { /* This should fail */ printf("OK\n"); From f5292519d6783c4d660bceb64c3ae260aab1f1b0 Mon Sep 17 00:00:00 2001 From: oliver Date: Wed, 8 Nov 2017 12:37:49 +0100 Subject: [PATCH 7/9] Changed naming of define for maximum record-files to MODBUS_MAX_RECORD_FILES --- src/modbus.c | 16 ++++++++-------- src/modbus.h | 14 ++++++++++---- tests/unit-test.h.in | 2 +- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/modbus.c b/src/modbus.c index 8917de0c9..b77569cab 100644 --- a/src/modbus.c +++ b/src/modbus.c @@ -1061,7 +1061,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, offset += _SUB_REQ_HDR_LENGTH; nb -= _SUB_REQ_HDR_LENGTH; - if ((file_no == 0) || (file_no > MODBUS_MAX_REFERENCE_FILES) || + if ((file_no == 0) || (file_no > MODBUS_MAX_RECORD_FILES) || (mb_mapping->file_registers[file_no - 1] == NULL)) { rsp_length = response_exception( ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE, @@ -1120,7 +1120,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, uint16_t f_address = (req[offset + 3] << 8) + req[offset + 4]; uint16_t nb_read = (req[offset + 5] << 8) + req[offset + 6]; - if ((file_no == 0) || (file_no > MODBUS_MAX_REFERENCE_FILES) || + if ((file_no == 0) || (file_no > MODBUS_MAX_RECORD_FILES) || (mb_mapping->file_registers[file_no - 1] == NULL)) { rsp_length = response_exception( ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE, @@ -2138,7 +2138,7 @@ modbus_mapping_t* modbus_mapping_new_start_address( nb_input_registers * sizeof(uint16_t)); } - for (i = 0; i < MODBUS_MAX_REFERENCE_FILES; i++) { + for (i = 0; i < MODBUS_MAX_RECORD_FILES; i++) { mb_mapping->file_registers[i] = NULL; } @@ -2161,7 +2161,7 @@ modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits, successful. Otherwise it shall return NULL and set errno to ENOMEM. */ modbus_mapping_t *modbus_mapping_new_extend( int nb_bits, int nb_input_bits, int nb_registers, int nb_input_registers, - uint16_t nb_file_register[MODBUS_MAX_REFERENCE_FILES]) + uint16_t nb_file_register[MODBUS_MAX_RECORD_FILES]) { int i; @@ -2169,7 +2169,7 @@ modbus_mapping_t *modbus_mapping_new_extend( nb_bits, nb_input_bits, nb_registers, nb_input_registers); if (mb_mapping) { - for (i = 0; i < MODBUS_MAX_REFERENCE_FILES; i++) { + for (i = 0; i < MODBUS_MAX_RECORD_FILES; i++) { if (nb_file_register[i]) { mb_mapping->file_registers[i] = (uint16_t *)malloc(nb_file_register[i] * sizeof(uint16_t)); @@ -2194,7 +2194,7 @@ MODBUS_API modbus_mapping_t *modbus_mapping_new_start_address_extend( unsigned int start_input_bits, unsigned int nb_input_bits, unsigned int start_registers, unsigned int nb_registers, unsigned int start_input_registers, unsigned int nb_input_registers, - uint16_t nb_file_registers[MODBUS_MAX_REFERENCE_FILES]) + uint16_t nb_file_registers[MODBUS_MAX_RECORD_FILES]) { int i; @@ -2204,7 +2204,7 @@ MODBUS_API modbus_mapping_t *modbus_mapping_new_start_address_extend( nb_registers, start_input_registers, nb_input_registers); if (mb_mapping) { - for (i = 0; i < MODBUS_MAX_REFERENCE_FILES; i++) { + for (i = 0; i < MODBUS_MAX_RECORD_FILES; i++) { if (nb_file_registers[i]) { mb_mapping->file_registers[i] = (uint16_t *)malloc(nb_file_registers[i] * sizeof(uint16_t)); @@ -2224,7 +2224,7 @@ void modbus_mapping_free(modbus_mapping_t *mb_mapping) return; } - for (i = 0; i < MODBUS_MAX_REFERENCE_FILES; i++) { + for (i = 0; i < MODBUS_MAX_RECORD_FILES; i++) { if (mb_mapping->file_registers[i]) { free(mb_mapping->file_registers[i]); } diff --git a/src/modbus.h b/src/modbus.h index d32918087..cf3eb5bcc 100644 --- a/src/modbus.h +++ b/src/modbus.h @@ -94,7 +94,13 @@ MODBUS_BEGIN_DECLS #define MODBUS_MAX_WRITE_REGISTERS 123 #define MODBUS_MAX_WR_WRITE_REGISTERS 121 #define MODBUS_MAX_WR_READ_REGISTERS 125 -#define MODBUS_MAX_REFERENCE_FILES 10 + +/* While it is allowed for the File Number to be in the range 1 to 0xFFFF, it should be noted that + * interoperability with legacy equipment may be compromised if the File Number is greater than + * 10 (0x0A). + * (chapter 6 section 15 page 35) + */ +#define MODBUS_MAX_RECORD_FILES 10 /* The size of the MODBUS PDU is limited by the size constraint inherited from * the first MODBUS implementation on Serial Line network (max. RS485 ADU = 256 @@ -170,7 +176,7 @@ typedef struct { uint8_t *tab_input_bits; uint16_t *tab_input_registers; uint16_t *tab_registers; - uint16_t *file_registers[MODBUS_MAX_REFERENCE_FILES]; + uint16_t *file_registers[MODBUS_MAX_RECORD_FILES]; } modbus_mapping_t; typedef enum @@ -239,13 +245,13 @@ MODBUS_API modbus_mapping_t *modbus_mapping_new_start_address_extend( unsigned int start_input_bits, unsigned int nb_input_bits, unsigned int start_registers, unsigned int nb_registers, unsigned int start_input_registers, unsigned int nb_input_registers, - uint16_t nb_file_registers[MODBUS_MAX_REFERENCE_FILES]); + uint16_t nb_file_registers[MODBUS_MAX_RECORD_FILES]); MODBUS_API modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits, int nb_registers, int nb_input_registers); MODBUS_API modbus_mapping_t *modbus_mapping_new_extend( int nb_bits, int nb_input_bits, int nb_registers, int nb_input_registers, - uint16_t nb_file_registers[MODBUS_MAX_REFERENCE_FILES]); + uint16_t nb_file_registers[MODBUS_MAX_RECORD_FILES]); MODBUS_API void modbus_mapping_free(modbus_mapping_t *mb_mapping); diff --git a/tests/unit-test.h.in b/tests/unit-test.h.in index 1e1ddc072..2a295b2ba 100644 --- a/tests/unit-test.h.in +++ b/tests/unit-test.h.in @@ -60,7 +60,7 @@ const uint16_t UT_INPUT_REGISTERS_NB = 0x1; const uint16_t UT_INPUT_REGISTERS_TAB[] = { 0x000A }; #define UT_FILE_REGISTER_NB 20 const uint16_t UT_FILE_REGISTER_TAB[UT_FILE_REGISTER_NB] = { 0x0001,0x0101,0xFF55,0x1234,0x6789,0xABCD,0xDEFF,0x2222,0x3333,0x4444,0x5555,0x0505,0x6060,0xcafe, }; -uint16_t UT_FILE_REGISTERS_NB[MODBUS_MAX_REFERENCE_FILES] = { 200,500,100,700,50 }; +uint16_t UT_FILE_REGISTERS_NB[MODBUS_MAX_RECORD_FILES] = { 200,500,100,700,50 }; const float UT_REAL = 123456.00; From 034b24ca00ff300083fd5418a0a18baf0d8d398b Mon Sep 17 00:00:00 2001 From: oliver Date: Wed, 8 Nov 2017 12:39:39 +0100 Subject: [PATCH 8/9] Updated documentation to new function-names and defines --- doc/modbus_mapping_new_extend.txt | 8 ++++---- doc/modbus_mapping_new_start_address_extend.txt | 6 +++--- ...ral_reference.txt => modbus_read_file_record.txt} | 12 ++++++------ ...al_reference.txt => modbus_write_file_record.txt} | 10 +++++----- 4 files changed, 18 insertions(+), 18 deletions(-) rename doc/{modbus_read_general_reference.txt => modbus_read_file_record.txt} (79%) rename doc/{modbus_write_general_reference.txt => modbus_write_file_record.txt} (81%) diff --git a/doc/modbus_mapping_new_extend.txt b/doc/modbus_mapping_new_extend.txt index c10cb6b64..fe9b487d6 100644 --- a/doc/modbus_mapping_new_extend.txt +++ b/doc/modbus_mapping_new_extend.txt @@ -4,18 +4,18 @@ modbus_mapping_new_extend(3) NAME ---- -modbus_mapping_new_extend - allocate four arrays of bits and registers and file registers +modbus_mapping_new_extend - allocate four arrays of bits and registers and file records SYNOPSIS -------- -*modbus_mapping_t* modbus_mapping_new_extend(int 'nb_bits', int 'nb_input_bits', int 'nb_registers', int 'nb_input_registers', uint16_t nb_file_register[MODBUS_MAX_REFERENCE_FILES]);* +*modbus_mapping_t* modbus_mapping_new_extend(int 'nb_bits', int 'nb_input_bits', int 'nb_registers', int 'nb_input_registers', uint16_t nb_file_register[MODBUS_MAX_RECORD_FILESMODBUS_MAX_RECORD_FILES]);* DESCRIPTION ----------- The *modbus_mapping_new_extend()* calls linkmb:modbus_mapping_new[3] and additionally allocates up to -MODBUS_MAX_REFERENCE_FILES (current specification limit it to 10) arrays for file registers. +MODBUS_MAX_RECORD_FILES (current specification limit it to 10) arrays for file records. Each _value_ in the array, which is not 0 allocates _value_ registers in the file of _index_ -1 . ( The file registers start with "1" for the first file ) @@ -41,7 +41,7 @@ mb_mapping = modbus_mapping_new_extend(BITS_ADDRESS + BITS_NB, INPUT_BITS_ADDRESS + INPUT_BITS_NB, REGISTERS_ADDRESS + REGISTERS_NB, INPUT_REGISTERS_ADDRESS + INPUT_REGISTERS_NB, - FILE_REGISTERS_NB[MODBUS_MAX_REFERENCE_FILES]); + FILE_REGISTERS_NB[MODBUS_MAX_RECORD_FILES]); if (mb_mapping == NULL) { fprintf(stderr, "Failed to allocate the mapping: %s\n", modbus_strerror(errno)); diff --git a/doc/modbus_mapping_new_start_address_extend.txt b/doc/modbus_mapping_new_start_address_extend.txt index d63b31966..4027f79ef 100644 --- a/doc/modbus_mapping_new_start_address_extend.txt +++ b/doc/modbus_mapping_new_start_address_extend.txt @@ -13,13 +13,13 @@ SYNOPSIS int 'start_input_bits', int 'nb_input_bits', int 'start_registers', int 'nb_registers', int 'start_input_registers', int 'nb_input_registers', - 'uint16_t nb_file_register[MODBUS_MAX_REFERENCE_FILES]');* + 'uint16_t nb_file_register[MODBUS_MAX_RECORD_FILES]');* DESCRIPTION ----------- The *modbus_mapping_new_extend()* calls linkmb:modbus_mapping_new_start_address[3] and additionally allocates up to -MODBUS_MAX_REFERENCE_FILES (current specification limit it to 10) arrays for file registers. +MODBUS_MAX_RECORD_FILES (current specification limit it to 10) arrays for file registers. Each _value_ in the array, which is not 0 allocates _value_ registers in the file of _index_ -1 . ( The file registers start with "1" for the first file ) @@ -59,7 +59,7 @@ mb_mapping = modbus_mapping_new_start_address_extend(BITS_ADDRESS, BITS_NB, INPUT_BITS_ADDRESS, INPUT_BITS_NB, REGISTERS_ADDRESS, REGISTERS_NB, INPUT_REGISTERS_ADDRESS, INPUT_REGISTERS_NB, - FILE_REGISTERS_NB[MODBUS_MAX_REFERENCE_FILES]); + FILE_REGISTERS_NB[MODBUS_MAX_RECORD_FILES]); if (mb_mapping == NULL) { fprintf(stderr, "Failed to allocate the mapping: %s\n", modbus_strerror(errno)); diff --git a/doc/modbus_read_general_reference.txt b/doc/modbus_read_file_record.txt similarity index 79% rename from doc/modbus_read_general_reference.txt rename to doc/modbus_read_file_record.txt index c1ad58e6f..d105a26d7 100644 --- a/doc/modbus_read_general_reference.txt +++ b/doc/modbus_read_file_record.txt @@ -1,20 +1,20 @@ -modbus_read_general_reference(3) +modbus_read_file_register(3) ======================== NAME ---- -modbus_read_general_reference - read from file registers +modbus_read_file_register - read from file registers SYNOPSIS -------- -*int modbus_read_general_reference(modbus_t *ctx, int file_no, int read_addr, int read_nb, uint16_t *dest);* +*int modbus_read_file_register(modbus_t *ctx, int file_no, int read_addr, int read_nb, uint16_t *dest);* DESCRIPTION ----------- -The *modbus_read_general_reference()* function shall read the number of _read_nb_ registers of the _file_no_ +The *modbus_read_file_register()* function shall read the number of _read_nb_ registers of the _file_no_ reference file at the address _read_addr_ of the remote device. The result of reading is stored in _dest_ array as word values (16 bits). @@ -56,7 +56,7 @@ if (modbus_connect(ctx) == -1) { return -1; } - rc = modbus_read_general_reference(ctx, 1, 10 , 64, tab_reg ); + rc = modbus_read_file_register(ctx, 1, 10 , 64, tab_reg ); if (rc == -1) { fprintf(stderr, "%s\n", modbus_strerror(errno)); return -1; @@ -74,7 +74,7 @@ modbus_free(ctx); SEE ALSO -------- -linkmb:modbus_write_general_reference[3] +linkmb:modbus_write_file_register[3] linkmb:modbus_mapping_new_start_address_extend[3] linkmb:modbus_mapping_new_extend[3] diff --git a/doc/modbus_write_general_reference.txt b/doc/modbus_write_file_record.txt similarity index 81% rename from doc/modbus_write_general_reference.txt rename to doc/modbus_write_file_record.txt index 9d1fd28bc..97f5fc9c4 100644 --- a/doc/modbus_write_general_reference.txt +++ b/doc/modbus_write_file_record.txt @@ -1,15 +1,15 @@ -modbus_write_general_reference(3) +modbus_write_file_register(3) ======================== NAME ---- -modbus_write_general_reference - write to file registers +modbus_write_file_register - write to file registers SYNOPSIS -------- -*int modbus_write_general_reference(modbus_t *ctx, int file_no, int write_addr, int write_nb, const uint16_t *src);* +*int modbus_write_file_register(modbus_t *ctx, int file_no, int write_addr, int write_nb, const uint16_t *src);* DESCRIPTION @@ -57,7 +57,7 @@ if (modbus_connect(ctx) == -1) { for (i=0; i < 64; i++){ tab_reg[i]=i+i*0x100; } - rc = modbus_write_general_reference(ctx, 1, 10 , 64, tab_reg ); + rc = modbus_write_file_register(ctx, 1, 10 , 64, tab_reg ); if (rc == -1) { fprintf(stderr, "%s\n", modbus_strerror(errno)); return -1; @@ -70,7 +70,7 @@ modbus_free(ctx); SEE ALSO -------- -linkmb:modbus_read_general_reference[3] +linkmb:modbus_read_file_register[3] linkmb:modbus_mapping_new_start_address_extend[3] linkmb:modbus_mapping_new_extend[3] From 44973921a3b65e24a37a52957128bf9deacd3145 Mon Sep 17 00:00:00 2001 From: oliver Date: Wed, 8 Nov 2017 17:43:34 +0100 Subject: [PATCH 9/9] Increased number of files to 0xffff, due to review finding, removed checks due to limited range --- src/modbus.c | 4 ++-- src/modbus.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modbus.c b/src/modbus.c index b77569cab..655070532 100644 --- a/src/modbus.c +++ b/src/modbus.c @@ -1061,7 +1061,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, offset += _SUB_REQ_HDR_LENGTH; nb -= _SUB_REQ_HDR_LENGTH; - if ((file_no == 0) || (file_no > MODBUS_MAX_RECORD_FILES) || + if ((file_no == 0) || (mb_mapping->file_registers[file_no - 1] == NULL)) { rsp_length = response_exception( ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE, @@ -1120,7 +1120,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, uint16_t f_address = (req[offset + 3] << 8) + req[offset + 4]; uint16_t nb_read = (req[offset + 5] << 8) + req[offset + 6]; - if ((file_no == 0) || (file_no > MODBUS_MAX_RECORD_FILES) || + if ((file_no == 0) || (mb_mapping->file_registers[file_no - 1] == NULL)) { rsp_length = response_exception( ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE, diff --git a/src/modbus.h b/src/modbus.h index cf3eb5bcc..108a06388 100644 --- a/src/modbus.h +++ b/src/modbus.h @@ -100,7 +100,7 @@ MODBUS_BEGIN_DECLS * 10 (0x0A). * (chapter 6 section 15 page 35) */ -#define MODBUS_MAX_RECORD_FILES 10 +#define MODBUS_MAX_RECORD_FILES 0xffff /* The size of the MODBUS PDU is limited by the size constraint inherited from * the first MODBUS implementation on Serial Line network (max. RS485 ADU = 256