diff --git a/docs/index.md b/docs/index.md index 89fcbbba8..d8d8cfbed 100644 --- a/docs/index.md +++ b/docs/index.md @@ -249,6 +249,16 @@ The *modbus_strerror()* function is provided to translate libmodbus-specific error codes into error message strings; for details refer to [modbus_strerror](modbus_strerror.md). +## Extended debug + +By default, the debug output created by enabling [modbus_set_debug](modbus_set_debug.md) +is written to stdout/stderr. With the following functions those can be redirected +to files or a callback. + +- [modbus_set_out_user_data](modbus_set_out_user_data.md) +- [modbus_set_error_user_data](modbus_set_error_user_data.md) +- [modbus_set_trace_handler](modbus_set_trace_handler.md) + ## Miscellaneous To deviate from the Modbus standard, you can enable or disable quirks with: diff --git a/docs/modbus_set_error_user_data.md b/docs/modbus_set_error_user_data.md new file mode 100644 index 000000000..113f3dbe7 --- /dev/null +++ b/docs/modbus_set_error_user_data.md @@ -0,0 +1,32 @@ +# modbus_set_error_user_data + +## Name + +modbus_set_error_user_data - set file stream to write log output + +## Synopsis + +```c +void modbus_set_error_user_data(modbus_t *ctx, void* out_user_data); +``` + +## Description + +The *modbus_set_error_user_data()* changes where log output is written +to when enabled with [modbus_set_debug](modbus_set_debug.md). Defaults +to stderr when not set. + + +## Example + +```c +FILE *fp; +fp = fopen("error.txt", "w"); +modbus_set_error_user_data(ctx, fp); +modbus_set_debug(ctx, 1) +``` + +## See also + +- [modbus_set_out_user_data](modbus_set_out_user_data.md) +- [modbus_set_trace_handler](modbus_set_trace_handler.md) diff --git a/docs/modbus_set_out_user_data.md b/docs/modbus_set_out_user_data.md new file mode 100644 index 000000000..2e3b024cf --- /dev/null +++ b/docs/modbus_set_out_user_data.md @@ -0,0 +1,32 @@ +# modbus_set_out_user_data + +## Name + +modbus_set_out_user_data - set file stream to write log output + +## Synopsis + +```c +void modbus_set_out_user_data(modbus_t *ctx, void* out_user_data); +``` + +## Description + +The *modbus_set_out_user_data()* changes where log output is written +to when enabled with [modbus_set_debug](modbus_set_debug.md). Defaults +to stdout when not set. + + +## Example + +```c +FILE *fp; +fp = fopen("output.txt", "w"); +modbus_set_out_user_data(ctx, fp); +modbus_set_debug(ctx, 1) +``` + +## See also + +- [modbus_set_error_user_data](modbus_set_error_user_data.md) +- [modbus_set_trace_handler](modbus_set_trace_handler.md) diff --git a/docs/modbus_set_trace_handler.md b/docs/modbus_set_trace_handler.md new file mode 100644 index 000000000..1c732b42e --- /dev/null +++ b/docs/modbus_set_trace_handler.md @@ -0,0 +1,44 @@ +# modbus_set_trace_handler + +## Name + +modbus_set_trace_handler - call method when log data is written + +## Synopsis + +```c +typedef int (*modbus_stream_handler_t)(void *user, const char *format, va_list ap); +void modbus_set_trace_handler(modbus_t *ctx, modbus_stream_handler_t handler); +``` + +## Description + +The *modbus_set_trace_handler()* sets a callback. When log data is written, the +callback is called. A log message is finalized with a '\n' as last character. +Defaults to vfprintf when not set. + + +## Example + +```c++ +class Test { + public: + static int log_callback(void *user, const char *format, va_list ap) + { + auto *inst = reinterpret_cast(user); + //call methods + } + void setup() + { + modbus_set_out_user_data(reinterpret_cast(this)); + modbus_set_error_user_data(reinterpret_cast(this)); + modbus_set_trace_handler(log_callback); + modbus_set_debug(true); + } +} +``` + +## See also + +- [modbus_set_out_user_data](modbus_set_out_user_data.md) +- [modbus_set_error_user_data](modbus_set_error_user_data.md) diff --git a/src/Makefile.am b/src/Makefile.am index 551fe4328..7eda6ba85 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -14,6 +14,8 @@ libmodbus_la_SOURCES = \ modbus.h \ modbus-data.c \ modbus-private.h \ + modbus-log.c \ + modbus-log.h \ modbus-rtu.c \ modbus-rtu.h \ modbus-rtu-private.h \ @@ -35,7 +37,7 @@ endif # Header files to install libmodbusincludedir = $(includedir)/modbus -libmodbusinclude_HEADERS = modbus.h modbus-version.h modbus-rtu.h modbus-tcp.h +libmodbusinclude_HEADERS = modbus.h modbus-version.h modbus-log.h modbus-rtu.h modbus-tcp.h DISTCLEANFILES = modbus-version.h EXTRA_DIST += modbus-version.h.in diff --git a/src/modbus-log.c b/src/modbus-log.c new file mode 100644 index 000000000..1e95f3d3a --- /dev/null +++ b/src/modbus-log.c @@ -0,0 +1,82 @@ +#include "modbus-log.h" +#include "modbus-private.h" +#include "modbus.h" + +#include +#include +#include + +MODBUS_API void modbus_set_out_user_data(modbus_t *ctx, void* out_user_data) +{ + if (ctx == NULL) { + errno = EINVAL; + return; + } + ctx->out_user_data = out_user_data; +} + +MODBUS_API void modbus_set_error_user_data(modbus_t *ctx, void* error_user_data) +{ + if (ctx == NULL) { + errno = EINVAL; + return; + } + ctx->error_user_data = error_user_data; +} + +MODBUS_API void modbus_set_trace_handler(modbus_t *ctx, modbus_stream_handler_t handler) +{ + if (ctx == NULL) { + errno = EINVAL; + return; + } + ctx->stream_handler = handler; +} + +MODBUS_API int modbus_trace(modbus_t *ctx, const char* format, ...) +{ + int result; + va_list argp; + va_start(argp, format); + + result = modbus_vtrace(ctx, format, argp); + + va_end(argp); + return result; +} + +MODBUS_API int modbus_vtrace(modbus_t *ctx, const char* format, va_list ap) +{ + if (ctx == NULL || ctx->stream_handler == NULL) { + errno = EINVAL; + return -1; + } + if (!ctx->out_user_data) { + ctx->out_user_data = stdout; + } + return ctx->stream_handler(ctx->out_user_data, format, ap); +} + +MODBUS_API int modbus_trace_error(modbus_t *ctx, const char* format, ...) +{ + int result; + va_list argp; + va_start(argp, format); + + result = modbus_vtrace_error(ctx, format, argp); + + va_end(argp); + return result; +} + +MODBUS_API int modbus_vtrace_error(modbus_t *ctx, const char* format, va_list ap) +{ + if (ctx == NULL || ctx->stream_handler == NULL) { + errno = EINVAL; + return -1; + } + if (!ctx->error_user_data) { + ctx->error_user_data = stderr; + } + return ctx->stream_handler(ctx->error_user_data, format, ap); +} diff --git a/src/modbus-log.h b/src/modbus-log.h new file mode 100644 index 000000000..37e622cf4 --- /dev/null +++ b/src/modbus-log.h @@ -0,0 +1,19 @@ +#ifndef MODBUS_LOG_H +#define MODBUS_LOG_H + +#include "modbus.h" + +#include + +MODBUS_API void modbus_set_out_user_data(modbus_t *ctx, void* out_user_data); +MODBUS_API void modbus_set_error_user_data(modbus_t *ctx, void* error_user_data); + +typedef int (*modbus_stream_handler_t)(void *user, const char *format, va_list ap); +MODBUS_API void modbus_set_trace_handler(modbus_t *ctx, modbus_stream_handler_t handler); + +MODBUS_API int modbus_trace(modbus_t *ctx, const char* format, ...); +MODBUS_API int modbus_vtrace(modbus_t *ctx, const char* format, va_list ap); +MODBUS_API int modbus_trace_error(modbus_t *ctx, const char* format, ...); +MODBUS_API int modbus_vtrace_error(modbus_t *ctx, const char* format, va_list ap); + +#endif /* MODBUS_LOG_H */ diff --git a/src/modbus-private.h b/src/modbus-private.h index 6cd342482..590e19eb5 100644 --- a/src/modbus-private.h +++ b/src/modbus-private.h @@ -106,6 +106,10 @@ struct _modbus { struct timeval indication_timeout; const modbus_backend_t *backend; void *backend_data; + /* redirect for logging */ + void* out_user_data; + void* error_user_data; + modbus_stream_handler_t stream_handler; }; void _modbus_init_common(modbus_t *ctx); diff --git a/src/modbus-rtu.c b/src/modbus-rtu.c index b7749230c..e3d43919d 100644 --- a/src/modbus-rtu.c +++ b/src/modbus-rtu.c @@ -267,7 +267,7 @@ static ssize_t _modbus_rtu_send(modbus_t *ctx, const uint8_t *req, int req_lengt ssize_t size; if (ctx->debug) { - fprintf(stderr, "Sending request using RTS signal\n"); + modbus_trace_error(ctx, "Sending request using RTS signal\n"); } ctx_rtu->set_rts(ctx, ctx_rtu->rts == MODBUS_RTU_RTS_UP); @@ -299,7 +299,7 @@ static int _modbus_rtu_receive(modbus_t *ctx, uint8_t *req) ctx_rtu->confirmation_to_ignore = FALSE; rc = 0; if (ctx->debug) { - printf("Confirmation to ignore\n"); + modbus_trace(ctx, "Confirmation to ignore\n"); } } else { rc = _modbus_receive_msg(ctx, req, MSG_INDICATION); @@ -331,7 +331,7 @@ static int _modbus_rtu_pre_check_confirmation(modbus_t *ctx, * request) */ if (req[0] != rsp[0] && req[0] != MODBUS_BROADCAST_ADDRESS) { if (ctx->debug) { - fprintf(stderr, + modbus_trace_error(ctx, "The responding slave %d isn't the requested slave %d\n", rsp[0], req[0]); @@ -356,7 +356,7 @@ static int _modbus_rtu_check_integrity(modbus_t *ctx, uint8_t *msg, const int ms * CRC computing. */ if (slave != ctx->slave && slave != MODBUS_BROADCAST_ADDRESS) { if (ctx->debug) { - printf("Request for slave %d ignored (not %d)\n", slave, ctx->slave); + modbus_trace(ctx, "Request for slave %d ignored (not %d)\n", slave, ctx->slave); } /* Following call to check_confirmation handles this error */ return 0; @@ -370,7 +370,7 @@ static int _modbus_rtu_check_integrity(modbus_t *ctx, uint8_t *msg, const int ms return msg_length; } else { if (ctx->debug) { - fprintf(stderr, + modbus_trace_error(ctx, "ERROR CRC received 0x%0X != CRC calculated 0x%0X\n", crc_received, crc_calculated); @@ -392,7 +392,7 @@ static int _modbus_rtu_connect(modbus_t *ctx) modbus_rtu_t *ctx_rtu = ctx->backend_data; if (ctx->debug) { - printf("Opening %s at %d bauds (%c, %d, %d)\n", + modbus_trace(ctx, "Opening %s at %d bauds (%c, %d, %d)\n", ctx_rtu->device, ctx_rtu->baud, ctx_rtu->parity, @@ -413,7 +413,7 @@ static int _modbus_rtu_connect(modbus_t *ctx) /* Error checking */ if (ctx_rtu->w_ser.fd == INVALID_HANDLE_VALUE) { if (ctx->debug) { - fprintf(stderr, + modbus_trace_error(ctx, "ERROR Can't open the device %s (LastError %d)\n", ctx_rtu->device, (int) GetLastError()); @@ -425,9 +425,9 @@ static int _modbus_rtu_connect(modbus_t *ctx) ctx_rtu->old_dcb.DCBlength = sizeof(DCB); if (!GetCommState(ctx_rtu->w_ser.fd, &ctx_rtu->old_dcb)) { if (ctx->debug) { - fprintf(stderr, + modbus_trace_error(ctx, "ERROR Error getting configuration (LastError %d)\n", - (int) GetLastError()); + (int)GetLastError()); } CloseHandle(ctx_rtu->w_ser.fd); ctx_rtu->w_ser.fd = INVALID_HANDLE_VALUE; @@ -492,9 +492,9 @@ static int _modbus_rtu_connect(modbus_t *ctx) /* Setup port */ if (!SetCommState(ctx_rtu->w_ser.fd, &dcb)) { if (ctx->debug) { - fprintf(stderr, + modbus_trace_error(ctx, "ERROR Error setting new configuration (LastError %d)\n", - (int) GetLastError()); + (int)GetLastError()); } CloseHandle(ctx_rtu->w_ser.fd); ctx_rtu->w_ser.fd = INVALID_HANDLE_VALUE; @@ -502,10 +502,10 @@ static int _modbus_rtu_connect(modbus_t *ctx) } return 0; -} + } #else -static speed_t _get_termios_speed(int baud, int debug) +static speed_t _get_termios_speed(modbus_t *ctx, int baud) { speed_t speed; @@ -609,8 +609,8 @@ static speed_t _get_termios_speed(int baud, int debug) #endif default: speed = B9600; - if (debug) { - fprintf(stderr, "WARNING Unknown baud rate %d (B9600 used)\n", baud); + if (ctx->debug) { + modbus_trace_error(ctx, "WARNING Unknown baud rate %d (B9600 used)\n", baud); } } @@ -626,7 +626,7 @@ static int _modbus_rtu_connect(modbus_t *ctx) modbus_rtu_t *ctx_rtu = ctx->backend_data; if (ctx->debug) { - printf("Opening %s at %d bauds (%c, %d, %d)\n", + modbus_trace(ctx, "Opening %s at %d bauds (%c, %d, %d)\n", ctx_rtu->device, ctx_rtu->baud, ctx_rtu->parity, @@ -649,7 +649,7 @@ static int _modbus_rtu_connect(modbus_t *ctx) ctx->s = open(ctx_rtu->device, flags); if (ctx->s < 0) { if (ctx->debug) { - fprintf(stderr, + modbus_trace_error(ctx, "ERROR Can't open the device %s (%s)\n", ctx_rtu->device, strerror(errno)); @@ -677,7 +677,7 @@ static int _modbus_rtu_connect(modbus_t *ctx) if (9600 == B9600) { speed = ctx_rtu->baud; } else { - speed = _get_termios_speed(ctx_rtu->baud, ctx->debug); + speed = _get_termios_speed(ctx, ctx_rtu->baud); } if ((cfsetispeed(&tios, speed) < 0) || (cfsetospeed(&tios, speed) < 0)) { @@ -919,7 +919,7 @@ int modbus_rtu_set_serial_mode(modbus_t *ctx, int mode) } #else if (ctx->debug) { - fprintf(stderr, "This function isn't supported on your platform\n"); + modbus_trace_error(ctx, "This function isn't supported on your platform\n"); } errno = ENOTSUP; return -1; @@ -944,7 +944,7 @@ int modbus_rtu_get_serial_mode(modbus_t *ctx) return ctx_rtu->serial_mode; #else if (ctx->debug) { - fprintf(stderr, "This function isn't supported on your platform\n"); + modbus_trace_error(ctx, "This function isn't supported on your platform\n"); } errno = ENOTSUP; return -1; @@ -968,7 +968,7 @@ int modbus_rtu_get_rts(modbus_t *ctx) return ctx_rtu->rts; #else if (ctx->debug) { - fprintf(stderr, "This function isn't supported on your platform\n"); + modbus_trace_error(ctx, "This function isn't supported on your platform\n"); } errno = ENOTSUP; return -1; @@ -1004,7 +1004,7 @@ int modbus_rtu_set_rts(modbus_t *ctx, int mode) } #else if (ctx->debug) { - fprintf(stderr, "This function isn't supported on your platform\n"); + modbus_trace_error(ctx, "This function isn't supported on your platform\n"); } errno = ENOTSUP; return -1; @@ -1029,7 +1029,7 @@ int modbus_rtu_set_custom_rts(modbus_t *ctx, void (*set_rts)(modbus_t *ctx, int return 0; #else if (ctx->debug) { - fprintf(stderr, "This function isn't supported on your platform\n"); + modbus_trace_error(ctx, "This function isn't supported on your platform\n"); } errno = ENOTSUP; return -1; @@ -1054,7 +1054,7 @@ int modbus_rtu_get_rts_delay(modbus_t *ctx) return ctx_rtu->rts_delay; #else if (ctx->debug) { - fprintf(stderr, "This function isn't supported on your platform\n"); + modbus_trace_error(ctx, "This function isn't supported on your platform\n"); } errno = ENOTSUP; return -1; @@ -1080,7 +1080,7 @@ int modbus_rtu_set_rts_delay(modbus_t *ctx, int us) return 0; #else if (ctx->debug) { - fprintf(stderr, "This function isn't supported on your platform\n"); + modbus_trace_error(ctx, "This function isn't supported on your platform\n"); } errno = ENOTSUP; return -1; @@ -1099,15 +1099,15 @@ static void _modbus_rtu_close(modbus_t *ctx) #if defined(_WIN32) /* Revert settings */ if (!SetCommState(ctx_rtu->w_ser.fd, &ctx_rtu->old_dcb) && ctx->debug) { - fprintf(stderr, + modbus_trace_error(ctx, "ERROR Couldn't revert to configuration (LastError %d)\n", - (int) GetLastError()); + (int)GetLastError()); } if (!CloseHandle(ctx_rtu->w_ser.fd) && ctx->debug) { - fprintf(stderr, + modbus_trace_error(ctx, "ERROR Error while closing handle (LastError %d)\n", - (int) GetLastError()); + (int)GetLastError()); } #else if (ctx->s >= 0) { @@ -1148,7 +1148,7 @@ _modbus_rtu_select(modbus_t *ctx, fd_set *rset, struct timeval *tv, int length_t while ((s_rc = select(ctx->s + 1, rset, NULL, NULL, tv)) == -1) { if (errno == EINTR) { if (ctx->debug) { - fprintf(stderr, "A non blocked signal was caught\n"); + modbus_trace_error(ctx, "A non blocked signal was caught\n"); } /* Necessary after an error */ FD_ZERO(rset); @@ -1210,26 +1210,28 @@ modbus_new_rtu(const char *device, int baud, char parity, int data_bit, int stop modbus_t *ctx; modbus_rtu_t *ctx_rtu; + ctx = (modbus_t *) malloc(sizeof(modbus_t)); + if (ctx == NULL) { + return NULL; + } + _modbus_init_common(ctx); + /* Check device argument */ if (device == NULL || *device == 0) { - fprintf(stderr, "The device string is empty\n"); + modbus_trace_error(ctx, "The device string is empty\n"); + free(ctx); errno = EINVAL; return NULL; } /* Check baud argument */ if (baud == 0) { - fprintf(stderr, "The baud rate value must not be zero\n"); + modbus_trace_error(ctx, "The baud rate value must not be zero\n"); + free(ctx); errno = EINVAL; return NULL; } - ctx = (modbus_t *) malloc(sizeof(modbus_t)); - if (ctx == NULL) { - return NULL; - } - - _modbus_init_common(ctx); ctx->backend = &_modbus_rtu_backend; ctx->backend_data = (modbus_rtu_t *) malloc(sizeof(modbus_rtu_t)); if (ctx->backend_data == NULL) { diff --git a/src/modbus-tcp.c b/src/modbus-tcp.c index 8389eaedf..2418fca9d 100644 --- a/src/modbus-tcp.c +++ b/src/modbus-tcp.c @@ -62,15 +62,15 @@ #include "modbus-tcp.h" #ifdef OS_WIN32 -static int _modbus_tcp_init_win32(void) +static int _modbus_tcp_init_win32(modbus_t *ctx) { /* Initialise Windows Socket API */ WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { - fprintf(stderr, + modbus_trace_error(ctx, "WSAStartup() returned error code %d\n", - (unsigned int) GetLastError()); + (unsigned int)GetLastError()); errno = EIO; return -1; } @@ -200,7 +200,7 @@ static int _modbus_tcp_pre_check_confirmation(modbus_t *ctx, /* Check transaction ID */ if (req[0] != rsp[0] || req[1] != rsp[1]) { if (ctx->debug) { - fprintf(stderr, + modbus_trace_error(ctx, "Invalid transaction ID received 0x%X (not 0x%X)\n", (rsp[0] << 8) + rsp[1], (req[0] << 8) + req[1]); @@ -213,7 +213,7 @@ static int _modbus_tcp_pre_check_confirmation(modbus_t *ctx, protocol_id = (rsp[2] << 8) + rsp[3]; if (protocol_id != 0x0) { if (ctx->debug) { - fprintf(stderr, "Invalid protocol ID received 0x%X (not 0x0)\n", protocol_id); + modbus_trace_error(ctx, "Invalid protocol ID received 0x%X (not 0x0)\n", protocol_id); } errno = EMBBADDATA; return -1; @@ -320,7 +320,7 @@ static int _modbus_tcp_connect(modbus_t *ctx) int flags = SOCK_STREAM; #ifdef OS_WIN32 - if (_modbus_tcp_init_win32() == -1) { + if (_modbus_tcp_init_win32(ctx) == -1) { return -1; } #endif @@ -346,7 +346,7 @@ static int _modbus_tcp_connect(modbus_t *ctx) } if (ctx->debug) { - printf("Connecting to %s:%d\n", ctx_tcp->ip, ctx_tcp->port); + modbus_trace(ctx, "Connecting to %s:%d\n", ctx_tcp->ip, ctx_tcp->port); } addr.sin_family = AF_INET; @@ -354,7 +354,7 @@ static int _modbus_tcp_connect(modbus_t *ctx) rc = inet_pton(addr.sin_family, ctx_tcp->ip, &(addr.sin_addr)); if (rc <= 0) { if (ctx->debug) { - fprintf(stderr, "Invalid IP address: %s\n", ctx_tcp->ip); + modbus_trace_error(ctx, "Invalid IP address: %s\n", ctx_tcp->ip); } close(ctx->s); ctx->s = -1; @@ -382,7 +382,7 @@ static int _modbus_tcp_pi_connect(modbus_t *ctx) modbus_tcp_pi_t *ctx_tcp_pi = ctx->backend_data; #ifdef OS_WIN32 - if (_modbus_tcp_init_win32() == -1) { + if (_modbus_tcp_init_win32(ctx) == -1) { return -1; } #endif @@ -401,7 +401,7 @@ static int _modbus_tcp_pi_connect(modbus_t *ctx) rc = getaddrinfo(ctx_tcp_pi->node, ctx_tcp_pi->service, &ai_hints, &ai_list); if (rc != 0) { if (ctx->debug) { - fprintf(stderr, "Error returned by getaddrinfo: %s\n", gai_strerror(rc)); + modbus_trace_error(ctx, "Error returned by getaddrinfo: %s\n", gai_strerror(rc)); } errno = ECONNREFUSED; return -1; @@ -427,7 +427,7 @@ static int _modbus_tcp_pi_connect(modbus_t *ctx) _modbus_tcp_set_ipv4_options(s); if (ctx->debug) { - printf("Connecting to [%s]:%s\n", ctx_tcp_pi->node, ctx_tcp_pi->service); + modbus_trace(ctx, "Connecting to [%s]:%s\n", ctx_tcp_pi->node, ctx_tcp_pi->service); } rc = _connect(s, ai_ptr->ai_addr, ai_ptr->ai_addrlen, &ctx->response_timeout); @@ -519,7 +519,7 @@ int modbus_tcp_listen(modbus_t *ctx, int nb_connection) ctx_tcp = ctx->backend_data; #ifdef OS_WIN32 - if (_modbus_tcp_init_win32() == -1) { + if (_modbus_tcp_init_win32(ctx) == -1) { return -1; } #endif @@ -554,7 +554,7 @@ int modbus_tcp_listen(modbus_t *ctx, int nb_connection) rc = inet_pton(addr.sin_family, ctx_tcp->ip, &(addr.sin_addr)); if (rc <= 0) { if (ctx->debug) { - fprintf(stderr, "Invalid IP address: %s\n", ctx_tcp->ip); + modbus_trace_error(ctx, "Invalid IP address: %s\n", ctx_tcp->ip); } close(new_s); return -1; @@ -593,7 +593,7 @@ int modbus_tcp_pi_listen(modbus_t *ctx, int nb_connection) ctx_tcp_pi = ctx->backend_data; #ifdef OS_WIN32 - if (_modbus_tcp_init_win32() == -1) { + if (_modbus_tcp_init_win32(ctx) == -1) { return -1; } #endif @@ -626,7 +626,7 @@ int modbus_tcp_pi_listen(modbus_t *ctx, int nb_connection) rc = getaddrinfo(node, service, &ai_hints, &ai_list); if (rc != 0) { if (ctx->debug) { - fprintf(stderr, "Error returned by getaddrinfo: %s\n", gai_strerror(rc)); + modbus_trace_error(ctx, "Error returned by getaddrinfo: %s\n", gai_strerror(rc)); } errno = ECONNREFUSED; return -1; @@ -644,7 +644,7 @@ int modbus_tcp_pi_listen(modbus_t *ctx, int nb_connection) s = socket(ai_ptr->ai_family, flags, ai_ptr->ai_protocol); if (s < 0) { if (ctx->debug) { - perror("socket"); + modbus_trace_error(ctx, "socket: %s\n", strerror(errno)); } continue; } else { @@ -654,7 +654,7 @@ int modbus_tcp_pi_listen(modbus_t *ctx, int nb_connection) if (rc != 0) { close(s); if (ctx->debug) { - perror("setsockopt"); + modbus_trace_error(ctx, "setsockopt: %s\n", strerror(errno)); } continue; } @@ -664,7 +664,7 @@ int modbus_tcp_pi_listen(modbus_t *ctx, int nb_connection) if (rc != 0) { close(s); if (ctx->debug) { - perror("bind"); + modbus_trace_error(ctx, "bind: %s\n", strerror(errno)); } continue; } @@ -673,7 +673,7 @@ int modbus_tcp_pi_listen(modbus_t *ctx, int nb_connection) if (rc != 0) { close(s); if (ctx->debug) { - perror("listen"); + modbus_trace_error(ctx, "listen: %s\n", strerror(errno)); } continue; } @@ -715,9 +715,9 @@ int modbus_tcp_accept(modbus_t *ctx, int *s) if (ctx->debug) { char buf[INET_ADDRSTRLEN]; if (inet_ntop(AF_INET, &(addr.sin_addr), buf, INET_ADDRSTRLEN) == NULL) { - fprintf(stderr, "Client connection accepted from unparsable IP.\n"); + modbus_trace_error(ctx, "Client connection accepted from unparsable IP.\n"); } else { - printf("Client connection accepted from %s.\n", buf); + modbus_trace(ctx, "Client connection accepted from %s.\n", buf); } } @@ -749,9 +749,9 @@ int modbus_tcp_pi_accept(modbus_t *ctx, int *s) if (ctx->debug) { char buf[INET6_ADDRSTRLEN]; if (inet_ntop(AF_INET6, &(addr.sin6_addr), buf, INET6_ADDRSTRLEN) == NULL) { - fprintf(stderr, "Client connection accepted from unparsable IP.\n"); + modbus_trace_error(ctx, "Client connection accepted from unparsable IP.\n"); } else { - printf("Client connection accepted from %s.\n", buf); + modbus_trace(ctx, "Client connection accepted from %s.\n", buf); } } @@ -765,7 +765,7 @@ _modbus_tcp_select(modbus_t *ctx, fd_set *rset, struct timeval *tv, int length_t while ((s_rc = select(ctx->s + 1, rset, NULL, NULL, tv)) == -1) { if (errno == EINTR) { if (ctx->debug) { - fprintf(stderr, "A non blocked signal was caught\n"); + modbus_trace_error(ctx, "A non blocked signal was caught\n"); } /* Necessary after an error */ FD_ZERO(rset); @@ -859,6 +859,12 @@ modbus_t *modbus_new_tcp(const char *ip, int port) size_t dest_size; size_t ret_size; + ctx = (modbus_t *) malloc(sizeof(modbus_t)); + if (ctx == NULL) { + return NULL; + } + _modbus_init_common(ctx); + #if defined(OS_BSD) /* MSG_NOSIGNAL is unsupported on *BSD so we install an ignore handler for SIGPIPE. */ @@ -867,17 +873,12 @@ modbus_t *modbus_new_tcp(const char *ip, int port) sa.sa_handler = SIG_IGN; if (sigaction(SIGPIPE, &sa, NULL) < 0) { /* The debug flag can't be set here... */ - fprintf(stderr, "Could not install SIGPIPE handler.\n"); + modbus_trace_error(ctx, "Could not install SIGPIPE handler.\n"); + free(ctx); return NULL; } #endif - ctx = (modbus_t *) malloc(sizeof(modbus_t)); - if (ctx == NULL) { - return NULL; - } - _modbus_init_common(ctx); - /* Could be changed after to reach a remote serial Modbus device */ ctx->slave = MODBUS_TCP_SLAVE; @@ -895,14 +896,14 @@ modbus_t *modbus_new_tcp(const char *ip, int port) dest_size = sizeof(char) * 16; ret_size = strlcpy(ctx_tcp->ip, ip, dest_size); if (ret_size == 0) { - fprintf(stderr, "The IP string is empty\n"); + modbus_trace_error(ctx, "The IP string is empty\n"); modbus_free(ctx); errno = EINVAL; return NULL; } if (ret_size >= dest_size) { - fprintf(stderr, "The IP string has been truncated\n"); + modbus_trace_error(ctx, "The IP string has been truncated\n"); modbus_free(ctx); errno = EINVAL; return NULL; @@ -932,11 +933,11 @@ modbus_t *modbus_new_tcp_pi(const char *node, const char *service) ctx->backend = &_modbus_tcp_pi_backend; - ctx->backend_data = (modbus_tcp_pi_t *) malloc(sizeof(modbus_tcp_pi_t)); + ctx->backend_data = (modbus_tcp_pi_t *)malloc(sizeof(modbus_tcp_pi_t)); if (ctx->backend_data == NULL) { - modbus_free(ctx); + modbus_free(ctx); errno = ENOMEM; - return NULL; + return NULL; } ctx_tcp_pi = (modbus_tcp_pi_t *) ctx->backend_data; ctx_tcp_pi->node = NULL; diff --git a/src/modbus.c b/src/modbus.c index 0360d5ccd..c4af9a564 100644 --- a/src/modbus.c +++ b/src/modbus.c @@ -82,11 +82,11 @@ const char *modbus_strerror(int errnum) void _error_print(modbus_t *ctx, const char *context) { if (ctx->debug) { - fprintf(stderr, "ERROR %s", modbus_strerror(errno)); + modbus_trace_error(ctx, "ERROR %s", modbus_strerror(errno)); if (context != NULL) { - fprintf(stderr, ": %s\n", context); + modbus_trace_error(ctx, ": %s\n", context); } else { - fprintf(stderr, "\n"); + modbus_trace_error(ctx, "\n"); } } } @@ -120,7 +120,7 @@ int modbus_flush(modbus_t *ctx) rc = ctx->backend->flush(ctx); if (rc != -1 && ctx->debug) { /* Not all backends are able to return the number of bytes flushed */ - printf("Bytes flushed (%d)\n", rc); + modbus_trace(ctx, "Bytes flushed (%d)\n", rc); } return rc; } @@ -171,8 +171,8 @@ static int send_msg(modbus_t *ctx, uint8_t *msg, int msg_length) if (ctx->debug) { for (i = 0; i < msg_length; i++) - printf("[%.2X]", msg[i]); - printf("\n"); + modbus_trace(ctx, "[%.2X]", msg[i]); + modbus_trace(ctx, "\n"); } /* In recovery mode, the write command will be issued until to be @@ -362,15 +362,15 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type) if (ctx->debug) { if (msg_type == MSG_INDICATION) { - printf("Waiting for an indication...\n"); + modbus_trace(ctx, "Waiting for an indication...\n"); } else { - printf("Waiting for a confirmation...\n"); + modbus_trace(ctx, "Waiting for a confirmation...\n"); } } if (!ctx->backend->is_connected(ctx)) { if (ctx->debug) { - fprintf(stderr, "ERROR The connection is not established.\n"); + modbus_trace_error(ctx, "ERROR The connection is not established.\n"); } return -1; } @@ -469,8 +469,8 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type) /* Display the hex code of each character received */ if (ctx->debug) { int i; - for (i = 0; i < rc; i++) - printf("<%.2X>", msg[msg_length + i]); + for (i=0; i < rc; i++) + modbus_trace(ctx, "<%.2X>", msg[msg_length + i]); } /* Sums bytes received */ @@ -516,7 +516,7 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type) } if (ctx->debug) - printf("\n"); + modbus_trace(ctx, "\n"); return ctx->backend->check_integrity(ctx, msg, msg_length); } @@ -603,9 +603,8 @@ static int check_confirmation(modbus_t *ctx, uint8_t *req, uint8_t *rsp, int rsp /* Check function code */ if (function != req[offset]) { if (ctx->debug) { - fprintf( - stderr, - "Received function not corresponding to the request (0x%X != 0x%X)\n", + modbus_trace_error(ctx, + "Received function not corresponding to the request (0x%X != 0x%X)\n", function, req[offset]); } @@ -676,7 +675,7 @@ static int check_confirmation(modbus_t *ctx, uint8_t *req, uint8_t *rsp, int rsp rc = rsp_nb_value; } else { if (ctx->debug) { - fprintf(stderr, + modbus_trace_error(ctx, "Received data not corresponding to the request (%d != %d)\n", rsp_nb_value, req_nb_value); @@ -692,9 +691,8 @@ static int check_confirmation(modbus_t *ctx, uint8_t *req, uint8_t *rsp, int rsp } } else { if (ctx->debug) { - fprintf( - stderr, - "Message length not corresponding to the computed length (%d != %d)\n", + modbus_trace_error(ctx, + "Message length not corresponding to the computed length (%d != %d)\n", rsp_length, rsp_length_computed); } @@ -750,7 +748,7 @@ static int response_exception(modbus_t *ctx, va_list ap; va_start(ap, template); - vfprintf(stderr, template, ap); + modbus_vtrace_error(ctx, template, ap); va_end(ap); } @@ -1031,7 +1029,7 @@ int modbus_reply(modbus_t *ctx, } break; case MODBUS_FC_READ_EXCEPTION_STATUS: if (ctx->debug) { - fprintf(stderr, "FIXME Not implemented\n"); + modbus_trace_error(ctx, "FIXME Not implemented\n"); } errno = ENOPROTOOPT; return -1; @@ -1226,7 +1224,7 @@ int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest) if (nb > MODBUS_MAX_READ_BITS) { if (ctx->debug) { - fprintf(stderr, + modbus_trace_error(ctx, "ERROR Too many bits requested (%d > %d)\n", nb, MODBUS_MAX_READ_BITS); @@ -1255,7 +1253,7 @@ int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest) if (nb > MODBUS_MAX_READ_BITS) { if (ctx->debug) { - fprintf(stderr, + modbus_trace_error(ctx, "ERROR Too many discrete inputs requested (%d > %d)\n", nb, MODBUS_MAX_READ_BITS); @@ -1282,7 +1280,7 @@ static int read_registers(modbus_t *ctx, int function, int addr, int nb, uint16_ if (nb > MODBUS_MAX_READ_REGISTERS) { if (ctx->debug) { - fprintf(stderr, + modbus_trace_error(ctx, "ERROR Too many registers requested (%d > %d)\n", nb, MODBUS_MAX_READ_REGISTERS); @@ -1330,7 +1328,7 @@ int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest) if (nb > MODBUS_MAX_READ_REGISTERS) { if (ctx->debug) { - fprintf(stderr, + modbus_trace_error(ctx, "ERROR Too many registers requested (%d > %d)\n", nb, MODBUS_MAX_READ_REGISTERS); @@ -1354,7 +1352,7 @@ int modbus_read_input_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest) } if (nb > MODBUS_MAX_READ_REGISTERS) { - fprintf(stderr, + modbus_trace_error(ctx, "ERROR Too many input registers requested (%d > %d)\n", nb, MODBUS_MAX_READ_REGISTERS); @@ -1437,7 +1435,7 @@ int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *src) if (nb > MODBUS_MAX_WRITE_BITS) { if (ctx->debug) { - fprintf(stderr, + modbus_trace_error(ctx, "ERROR Writing too many bits (%d > %d)\n", nb, MODBUS_MAX_WRITE_BITS); @@ -1498,7 +1496,7 @@ int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src) if (nb > MODBUS_MAX_WRITE_REGISTERS) { if (ctx->debug) { - fprintf(stderr, + modbus_trace_error(ctx, "ERROR Trying to write to too many registers (%d > %d)\n", nb, MODBUS_MAX_WRITE_REGISTERS); @@ -1594,7 +1592,7 @@ int modbus_write_and_read_registers(modbus_t *ctx, if (write_nb > MODBUS_MAX_WR_WRITE_REGISTERS) { if (ctx->debug) { - fprintf(stderr, + modbus_trace_error(ctx, "ERROR Too many registers to write (%d > %d)\n", write_nb, MODBUS_MAX_WR_WRITE_REGISTERS); @@ -1605,7 +1603,7 @@ int modbus_write_and_read_registers(modbus_t *ctx, if (read_nb > MODBUS_MAX_WR_READ_REGISTERS) { if (ctx->debug) { - fprintf(stderr, + modbus_trace_error(ctx, "ERROR Too many registers requested (%d > %d)\n", read_nb, MODBUS_MAX_WR_READ_REGISTERS); @@ -1713,6 +1711,10 @@ void _modbus_init_common(modbus_t *ctx) ctx->indication_timeout.tv_sec = 0; ctx->indication_timeout.tv_usec = 0; + + ctx->out_user_data = stdout; + ctx->error_user_data = stderr; + ctx->stream_handler = (modbus_stream_handler_t) vfprintf; } /* Define the slave number */ diff --git a/src/modbus.h b/src/modbus.h index 55ef08a0d..e78f1877b 100644 --- a/src/modbus.h +++ b/src/modbus.h @@ -324,6 +324,8 @@ MODBUS_API void modbus_set_float_cdab(float f, uint16_t *dest); #include "modbus-rtu.h" #include "modbus-tcp.h" +#include "modbus-log.h" + MODBUS_END_DECLS #endif /* MODBUS_H */