Skip to content

Commit

Permalink
Updated 2018-08-20 with respect to comments from @karlp
Browse files Browse the repository at this point in the history
Added function "modbus_read_device_information_object" to access device
specific information like "vendor name" or "product name".

Definitions for device information objects are added to modbus.h.

Signed-off-by: Oliver Schwaneberg <oliver.schwaneberg@gmail.com>
  • Loading branch information
Schwaneberg committed Aug 20, 2018
1 parent ddac0cf commit 14c4269
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 0 deletions.
88 changes: 88 additions & 0 deletions doc/modbus_read_device_information_object.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
modbus_read_device_information_object(3)
========================================


NAME
----
modbus_read_device_information_object - retrieving device information


SYNOPSIS
--------
*int modbus_read_device_information_object(modbus_t *ctx, unsigned char object_id, uint16_t *dest);*


DESCRIPTION
-----------
The *modbus_read_device_information_object()* function reads the content
of a single object within the device identification registers.
There are several standardized objects:

Object ID | Type | Object Name | Data Type | Mandatory
----------+----------+---------------------+--------------+----------
0x00 | Basic | VendorName | ASCII String | yes
0x01 | Basic | ProductCode | ASCII String | yes
0x02 | Basic | MajorMinorRevision | ASCII String | yes
0x03 | Regular | VendorUrl | ASCII String | no
0x04 | Regular | ProductName | ASCII String | no
0x05 | Regular | ModelName | ASCII String | no
0x06 | Regular | UserApplicationName | ASCII String | no
0x80 + n | Extended | Device specific | Binary | no

The result of reading is stored in _dest_ array as word values (16 bits).

You must take care to allocate enough memory to store the results in _dest_
(130 * sizeof(uint16_t) will always be enough).

The function uses the Modbus function code 0x2B (read device identification).


RETURN VALUE
------------
The function returns the number of read bytes if successful.
Otherwise it shall return -1 and set errno.


ERRORS
------


EXAMPLE
-------
[source,c]
-------------------
modbus_t *ctx;
uint16_t vendor_name[130];
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_device_information_object(ctx, 0x04, vendor_name);
if (rc == -1) {
fprintf(stderr, "%s\n", modbus_strerror(errno));
return -1;
}

printf("Vendor Name: '%s'", (char*)vendor_name);

modbus_close(ctx);
modbus_free(ctx);
-------------------


SEE ALSO
--------


AUTHORS
-------
This function was introduced by Oliver Schwaneberg
<oliver.schwaneberg@gmail.com>
The libmodbus documentation was written by Stéphane Raimbault
<stephane.raimbault@gmail.com>
48 changes: 48 additions & 0 deletions src/modbus.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ static unsigned int compute_response_length_from_request(modbus_t *ctx, uint8_t
length = 3;
break;
case MODBUS_FC_REPORT_SLAVE_ID:
case MODBUS_FC_READ_DEVICE_INFORMATION:
/* The response is device specific (the header provides the
length) */
return MSG_LENGTH_UNDEFINED;
Expand Down Expand Up @@ -280,6 +281,9 @@ static uint8_t compute_meta_length_after_function(int function,
case MODBUS_FC_MASK_WRITE_REGISTER:
length = 6;
break;
case MODBUS_FC_READ_DEVICE_INFORMATION:
length = 8;
break;
default:
length = 1;
}
Expand Down Expand Up @@ -313,6 +317,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_DEVICE_INFORMATION) {
length = msg[ctx->backend->header_length + 8];
} else {
length = 0;
}
Expand Down Expand Up @@ -600,6 +606,10 @@ 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_DEVICE_INFORMATION:
/* Length of object in byte */
req_nb_value = rsp_nb_value = rsp[offset + 8];
break;
default:
/* 1 Write functions & others */
req_nb_value = rsp_nb_value = 1;
Expand Down Expand Up @@ -1399,6 +1409,44 @@ int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src)
return rc;
}

int modbus_read_device_information_object(modbus_t *ctx, unsigned char object_id, uint16_t *dest)
{
uint8_t req[_MIN_REQ_LENGTH];
uint8_t rsp[MAX_MESSAGE_LENGTH];
int rc;
int req_length;
int offset;
int i;
req_length = ctx->backend->build_request_basis(ctx, MODBUS_FC_READ_DEVICE_INFORMATION, 0x0E04, (object_id<<8), req) - 1;
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;

offset = ctx->backend->header_length + 9;

if (object_id <= 0x06) {
/* Append string terminator */
if (rc < MAX_MESSAGE_LENGTH)
rsp[rc+offset] = '\0';
/* keep original byte order for ASCII string */
memcpy((void*)dest, (void*)(rsp+offset), (rc+1)*sizeof(char));
} else {
for (i = 0; i < rc / 2; i++) {
/* shift reg hi_byte to temp OR with lo_byte */
dest[i] = (rsp[offset + (i << 1)] << 8) |
rsp[offset + 1 + (i << 1)];
}
}
}
return rc;
}

int modbus_mask_write_register(modbus_t *ctx, int addr, uint16_t and_mask, uint16_t or_mask)
{
int rc;
Expand Down
11 changes: 11 additions & 0 deletions src/modbus.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,19 @@ MODBUS_BEGIN_DECLS
#define MODBUS_FC_REPORT_SLAVE_ID 0x11
#define MODBUS_FC_MASK_WRITE_REGISTER 0x16
#define MODBUS_FC_WRITE_AND_READ_REGISTERS 0x17
#define MODBUS_FC_READ_DEVICE_INFORMATION 0x2B

#define MODBUS_BROADCAST_ADDRESS 0

/* Modbus device information object codes */
#define MODBUS_OBJID_VENDORNAME 0x00
#define MODBUS_OBJID_PRODUCTCODE 0x01
#define MODBUS_OBJID_MAJOR_MINOR_REVISION 0x02
#define MODBUS_OBJID_VENDOR_URL 0x03
#define MODBUS_OBJID_PRODUCTNAME 0x04
#define MODBUS_OBJID_MODELNAME 0x05
#define MODBUS_OBJID_USERAPPLICATION 0x06

/* Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 1 page 12)
* Quantity of Coils to read (2 bytes): 1 to 2000 (0x7D0)
* (chapter 6 section 11 page 29)
Expand Down Expand Up @@ -203,6 +213,7 @@ MODBUS_API int modbus_set_debug(modbus_t *ctx, int flag);

MODBUS_API const char *modbus_strerror(int errnum);

MODBUS_API int modbus_read_device_information_object(modbus_t *ctx, unsigned char object_id, uint16_t *dest);
MODBUS_API int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
MODBUS_API int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
MODBUS_API int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
Expand Down

0 comments on commit 14c4269

Please sign in to comment.