Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added function "modbus_read_device_information_object" #443

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
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