From 2014c85cf38c0daf96f33f1da1b95f2066a08bed Mon Sep 17 00:00:00 2001 From: Michael Heimpold Date: Sat, 28 Sep 2013 23:51:30 +0200 Subject: [PATCH 1/2] Move msg_type_t to modbus.h and rename to modbus_msg_type_t Signed-off-by: Michael Heimpold --- src/modbus-private.h | 14 +------------- src/modbus-rtu.c | 4 ++-- src/modbus-tcp.c | 2 +- src/modbus.c | 40 ++++++++++++++++++++++------------------ src/modbus.h | 12 ++++++++++++ 5 files changed, 38 insertions(+), 34 deletions(-) diff --git a/src/modbus-private.h b/src/modbus-private.h index c5af0f939..32526866d 100644 --- a/src/modbus-private.h +++ b/src/modbus-private.h @@ -44,18 +44,6 @@ typedef enum { _MODBUS_BACKEND_TYPE_TCP } modbus_backend_type_t; -/* - * ---------- Request Indication ---------- - * | Client | ---------------------->| Server | - * ---------- Confirmation Response ---------- - */ -typedef enum { - /* Request message on the server side */ - MSG_INDICATION, - /* Request message on the client side */ - MSG_CONFIRMATION -} msg_type_t; - /* This structure reduces the number of params in functions and so * optimizes the speed of execution (~ 37%). */ typedef struct _sft { @@ -104,7 +92,7 @@ struct _modbus { void _modbus_init_common(modbus_t *ctx); void _error_print(modbus_t *ctx, const char *context); -int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type); +int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, modbus_msg_type_t msg_type); #ifndef HAVE_STRLCPY size_t strlcpy(char *dest, const char *src, size_t dest_size); diff --git a/src/modbus-rtu.c b/src/modbus-rtu.c index 430a0e197..76577ca05 100644 --- a/src/modbus-rtu.c +++ b/src/modbus-rtu.c @@ -306,7 +306,7 @@ static int _modbus_rtu_receive(modbus_t *ctx, uint8_t *req) modbus_rtu_t *ctx_rtu = ctx->backend_data; if (ctx_rtu->confirmation_to_ignore) { - _modbus_receive_msg(ctx, req, MSG_CONFIRMATION); + _modbus_receive_msg(ctx, req, MODBUS_MSG_CONFIRMATION); /* Ignore errors and reset the flag */ ctx_rtu->confirmation_to_ignore = FALSE; rc = 0; @@ -314,7 +314,7 @@ static int _modbus_rtu_receive(modbus_t *ctx, uint8_t *req) printf("Confirmation to ignore\n"); } } else { - rc = _modbus_receive_msg(ctx, req, MSG_INDICATION); + rc = _modbus_receive_msg(ctx, req, MODBUS_MSG_INDICATION); if (rc == 0) { /* The next expected message is a confirmation to ignore */ ctx_rtu->confirmation_to_ignore = TRUE; diff --git a/src/modbus-tcp.c b/src/modbus-tcp.c index 3fd0ebe5e..e7350b453 100644 --- a/src/modbus-tcp.c +++ b/src/modbus-tcp.c @@ -166,7 +166,7 @@ static ssize_t _modbus_tcp_send(modbus_t *ctx, const uint8_t *req, int req_lengt } static int _modbus_tcp_receive(modbus_t *ctx, uint8_t *req) { - return _modbus_receive_msg(ctx, req, MSG_INDICATION); + return _modbus_receive_msg(ctx, req, MODBUS_MSG_INDICATION); } static ssize_t _modbus_tcp_recv(modbus_t *ctx, uint8_t *rsp, int rsp_length) { diff --git a/src/modbus.c b/src/modbus.c index 5477b3d3f..d1fb83c6c 100644 --- a/src/modbus.c +++ b/src/modbus.c @@ -246,12 +246,12 @@ int modbus_send_raw_request(modbus_t *ctx, uint8_t *raw_req, int raw_req_length) */ /* Computes the length to read after the function received */ -static uint8_t compute_meta_length_after_function(int function, - msg_type_t msg_type) +static uint8_t compute_meta_length_after_function(modbus_t *ctx, int function, + modbus_msg_type_t msg_type) { int length; - if (msg_type == MSG_INDICATION) { + if (msg_type == MODBUS_MSG_INDICATION) { if (function <= MODBUS_FC_WRITE_SINGLE_REGISTER) { length = 4; } else if (function == MODBUS_FC_WRITE_MULTIPLE_COILS || @@ -266,7 +266,7 @@ static uint8_t compute_meta_length_after_function(int function, length = 0; } } else { - /* MSG_CONFIRMATION */ + /* MODBUS_MSG_CONFIRMATION */ switch (function) { case MODBUS_FC_WRITE_SINGLE_COIL: case MODBUS_FC_WRITE_SINGLE_REGISTER: @@ -282,17 +282,21 @@ static uint8_t compute_meta_length_after_function(int function, } } + if (ctx->callback[MODBUS_CALLBACK_COMPUTE_META_LENGTH]) { + ctx->callback[MODBUS_CALLBACK_COMPUTE_META_LENGTH](ctx, function, msg_type, &length); + } + return length; } /* Computes the length to read after the meta information (address, count, etc) */ static int compute_data_length_after_meta(modbus_t *ctx, uint8_t *msg, - msg_type_t msg_type) + modbus_msg_type_t msg_type) { int function = msg[ctx->backend->header_length]; int length; - if (msg_type == MSG_INDICATION) { + if (msg_type == MODBUS_MSG_INDICATION) { switch (function) { case MODBUS_FC_WRITE_MULTIPLE_COILS: case MODBUS_FC_WRITE_MULTIPLE_REGISTERS: @@ -334,7 +338,7 @@ static int compute_data_length_after_meta(modbus_t *ctx, uint8_t *msg, - read() or recv() error codes */ -int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type) +int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, modbus_msg_type_t msg_type) { int rc; fd_set rset; @@ -345,7 +349,7 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type) _step_t step; if (ctx->debug) { - if (msg_type == MSG_INDICATION) { + if (msg_type == MODBUS_MSG_INDICATION) { printf("Waiting for a indication...\n"); } else { printf("Waiting for a confirmation...\n"); @@ -362,7 +366,7 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type) step = _STEP_FUNCTION; length_to_read = ctx->backend->header_length + 1; - if (msg_type == MSG_INDICATION) { + if (msg_type == MODBUS_MSG_INDICATION) { /* Wait for a message, we don't know when the message will be * received */ p_tv = NULL; @@ -494,7 +498,7 @@ int modbus_receive_confirmation(modbus_t *ctx, uint8_t *rsp) return -1; } - return _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION); + return _modbus_receive_msg(ctx, rsp, MODBUS_MSG_CONFIRMATION); } static int check_confirmation(modbus_t *ctx, uint8_t *req, @@ -1106,7 +1110,7 @@ static int read_io_status(modbus_t *ctx, int function, int offset; int offset_end; - rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION); + rc = _modbus_receive_msg(ctx, rsp, MODBUS_MSG_CONFIRMATION); if (rc == -1) return -1; @@ -1215,7 +1219,7 @@ static int read_registers(modbus_t *ctx, int function, int addr, int nb, int offset; int i; - rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION); + rc = _modbus_receive_msg(ctx, rsp, MODBUS_MSG_CONFIRMATION); if (rc == -1) return -1; @@ -1306,7 +1310,7 @@ static int write_single(modbus_t *ctx, int function, int addr, int value) /* Used by write_bit and write_register */ uint8_t rsp[MAX_MESSAGE_LENGTH]; - rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION); + rc = _modbus_receive_msg(ctx, rsp, MODBUS_MSG_CONFIRMATION); if (rc == -1) return -1; @@ -1391,7 +1395,7 @@ int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *src) if (rc > 0) { uint8_t rsp[MAX_MESSAGE_LENGTH]; - rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION); + rc = _modbus_receive_msg(ctx, rsp, MODBUS_MSG_CONFIRMATION); if (rc == -1) return -1; @@ -1441,7 +1445,7 @@ int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src) if (rc > 0) { uint8_t rsp[MAX_MESSAGE_LENGTH]; - rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION); + rc = _modbus_receive_msg(ctx, rsp, MODBUS_MSG_CONFIRMATION); if (rc == -1) return -1; @@ -1474,7 +1478,7 @@ int modbus_mask_write_register(modbus_t *ctx, int addr, uint16_t and_mask, uint1 /* Used by write_bit and write_register */ uint8_t rsp[MAX_MESSAGE_LENGTH]; - rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION); + rc = _modbus_receive_msg(ctx, rsp, MODBUS_MSG_CONFIRMATION); if (rc == -1) return -1; @@ -1544,7 +1548,7 @@ int modbus_write_and_read_registers(modbus_t *ctx, if (rc > 0) { int offset; - rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION); + rc = _modbus_receive_msg(ctx, rsp, MODBUS_MSG_CONFIRMATION); if (rc == -1) return -1; @@ -1588,7 +1592,7 @@ int modbus_report_slave_id(modbus_t *ctx, int max_dest, uint8_t *dest) int offset; uint8_t rsp[MAX_MESSAGE_LENGTH]; - rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION); + rc = _modbus_receive_msg(ctx, rsp, MODBUS_MSG_CONFIRMATION); if (rc == -1) return -1; diff --git a/src/modbus.h b/src/modbus.h index 2f0d7616c..e081c4237 100644 --- a/src/modbus.h +++ b/src/modbus.h @@ -219,6 +219,18 @@ MODBUS_API int modbus_reply(modbus_t *ctx, const uint8_t *req, MODBUS_API int modbus_reply_exception(modbus_t *ctx, const uint8_t *req, unsigned int exception_code); +/* + * ---------- Request Indication ---------- + * | Client | ---------------------->| Server | + * ---------- Confirmation Response ---------- + */ +typedef enum { + /* Request message on the server side */ + MODBUS_MSG_INDICATION, + /* Request message on the client side */ + MODBUS_MSG_CONFIRMATION +} modbus_msg_type_t; + /** * UTILS FUNCTIONS **/ From 2bf681a2f6ac1296e735eb8aa3d9274d9ae228db Mon Sep 17 00:00:00 2001 From: Michael Heimpold Date: Sat, 28 Sep 2013 23:53:53 +0200 Subject: [PATCH 2/2] Introduce callback functions for length calculations When a Modbus device supports vendor specific function codes, then the current length calculation is not sufficient. Allow the calling programm to register callback functions which can handle such cases. Signed-off-by: Michael Heimpold --- src/modbus-private.h | 1 + src/modbus.c | 23 +++++++++++++++++++++++ src/modbus.h | 11 +++++++++++ 3 files changed, 35 insertions(+) diff --git a/src/modbus-private.h b/src/modbus-private.h index 32526866d..df4fba5cd 100644 --- a/src/modbus-private.h +++ b/src/modbus-private.h @@ -86,6 +86,7 @@ struct _modbus { int error_recovery; struct timeval response_timeout; struct timeval byte_timeout; + modbus_callback_t callback[MODBUS_CALLBACK_MAX]; const modbus_backend_t *backend; void *backend_data; }; diff --git a/src/modbus.c b/src/modbus.c index d1fb83c6c..98a6fc145 100644 --- a/src/modbus.c +++ b/src/modbus.c @@ -107,6 +107,24 @@ static void _sleep_response_timeout(modbus_t *ctx) #endif } +/* Assign a callback function pointer to context */ +int modbus_register_callback(modbus_t *ctx, modbus_callback_type_t cb_type, modbus_callback_t cb) +{ + if (ctx == NULL) { + errno = EINVAL; + return -1; + } + + /* prevent abuse */ + if (cb_type >= MODBUS_CALLBACK_MAX) { + errno = EINVAL; + return -1; + } + + ctx->callback[cb_type] = cb; + return 0; +} + int modbus_flush(modbus_t *ctx) { int rc; @@ -319,6 +337,10 @@ static int compute_data_length_after_meta(modbus_t *ctx, uint8_t *msg, } } + if (ctx->callback[MODBUS_CALLBACK_COMPUTE_DATA_LENGTH]) { + ctx->callback[MODBUS_CALLBACK_COMPUTE_DATA_LENGTH](ctx, msg, msg_type, &length); + } + length += ctx->backend->checksum_length; return length; @@ -432,6 +454,7 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, modbus_msg_type_t msg_type) case _STEP_FUNCTION: /* Function code position */ length_to_read = compute_meta_length_after_function( + ctx, msg[ctx->backend->header_length], msg_type); if (length_to_read != 0) { diff --git a/src/modbus.h b/src/modbus.h index e081c4237..da53b7636 100644 --- a/src/modbus.h +++ b/src/modbus.h @@ -231,6 +231,17 @@ typedef enum { MODBUS_MSG_CONFIRMATION } modbus_msg_type_t; +typedef enum +{ + MODBUS_CALLBACK_COMPUTE_META_LENGTH, + MODBUS_CALLBACK_COMPUTE_DATA_LENGTH, + MODBUS_CALLBACK_MAX +} modbus_callback_type_t; + +typedef int (*modbus_callback_t)(modbus_t *ctx, ...); + +MODBUS_API int modbus_register_callback(modbus_t *ctx, modbus_callback_type_t cb_type, modbus_callback_t cb); + /** * UTILS FUNCTIONS **/