diff --git a/doc/modbus_reply_callback.txt b/doc/modbus_reply_callback.txt index 151914fc9..7d231eb73 100644 --- a/doc/modbus_reply_callback.txt +++ b/doc/modbus_reply_callback.txt @@ -24,7 +24,7 @@ typedef struct { DESCRIPTION ----------- *modbus_set_reply_callbacks()* has to be used to set the callback-structure into the -libmodbus-context. An optional parameter _user_ctx_ can be suppied which will be passed to the +libmodbus-context. An optional parameter _user_ctx_ can be supplied which will be passed to the callback function, typically for context purpose. The *modbus_reply_callback()* function receives the request-byte-buffer and its byte-length as @@ -43,16 +43,16 @@ a RTU-slave, the additional *accept_rtu_slave*-callback has to be provided. At different stages *modbus_reply_callback()* calls these callbacks by passing different arguments and the user-context-pointer _user_ctx_ as the first one. -The first callback invoked by modbus_reply_callback() is *accept_rtu_slave* if the user implements a +The first callback invoked by modbus_reply_callback() is *accept_rtu_slave* if the user implements an RTU-slave. In its implementation the user has to check whether the slave-id, _slave_, which was decoded from the request, should be answered to or not and returning TRUE if so, otherwise FALSE. -Returning FALSE will make *modbus_reply_callback()* exit immedialty and return 0. +Returning FALSE will make *modbus_reply_callback()* exit immediately and return 0. All callbacks hereafter receive the following arguments: * _slave_ still indicating the RTU-slave-id if the modbus-instance is in RTU-mode otherwise it has no meaning. - * _function_ containting the value of the modbus-function decoded from the request. + * _function_ containing the value of the modbus-function decoded from the request. * _address_, the first register or coil-address. * _nb_, the number of values to be handled. * _bytes[]_, the byte-buffer containing the raw-data (write-request) or where the raw-data has to @@ -63,7 +63,7 @@ All callbacks hereafter receive the following arguments: *modbus_reply_callback()* is then doing some basic sanitizing on standard-specific parameters before calling the second callback *verify*. -This is done to verify whether the access is valid for this instance in regards to the address-range +This is done to verify whether the access is valid for this instance in regard to the address-range or the modbus-function of the request. The user has to return 0 if the range defined by _address_ and _nb_ is inside the device's range and the modbus-function can be handled. @@ -80,11 +80,12 @@ modbus-specification and needs to be encoded, or decoded, properly inside the ca Coils are encoded as up to 8 coils per byte, registers are 16-bit wide and thus consume 2 bytes of the buffer per value. See below. -The return value of the read-callback. Negative numbers or zero are interpreted as no response -should be send. To, for example, trigger a timeout on the other side. - -The write-callbacks has to return 0 to signal success or a negative number to make the library -not send any response. +The read-callback should return the length (bytes) of data written if successful. +The write-callback should return 0 to signal success. +The read and write callbacks may return a negated error code within the range of modbus protocol +exception error codes (-EMBXILFUN to -EMBXGTAR) to send an exception response. Any other negative +numbers or zero are interpreted as no response should be sent. To, for example, trigger a timeout +on the other side. The library does not do any differentiation regarding the actual modbus-function and the appropriate invoked callback. All MODBUS_READ-functions are handled by the read-callback, all diff --git a/src/modbus-reply.c b/src/modbus-reply.c index ca79f0e30..537504f05 100644 --- a/src/modbus-reply.c +++ b/src/modbus-reply.c @@ -306,7 +306,7 @@ int modbus_reply_callback(modbus_t *ctx, const uint8_t *req, int req_length) /* user verification was successful */ - int rc; + int rc = 0; rsp_length = ctx->backend->build_response_basis(&sft, rsp); switch (function) { @@ -410,6 +410,21 @@ int modbus_reply_callback(modbus_t *ctx, const uint8_t *req, int req_length) } send_response: + /* Check if a user read/write callback returned a negated error code within the + * range of modbus protocol exceptions, if so respond with that exception */ + if (rc < 0) { + int modbus_errno = -rc; + int protocol_exception = modbus_errno - MODBUS_ENOBASE; + if (protocol_exception > 0 && protocol_exception < MODBUS_EXCEPTION_MAX) { + rsp_length = response_exception( + ctx, &sft, + protocol_exception, rsp, FALSE, + "%s: 0x%0X (%s)\n", + modbus_strerror(modbus_errno), + function, function_name); + } + } + if ((ctx->backend->backend_type == _MODBUS_BACKEND_TYPE_RTU && slave == MODBUS_BROADCAST_ADDRESS) || rsp_length == 0) /* this indicates that the user does not want us to send response,