Преглед изворни кода

Error conventions of POSIX systems and error recovery

- returns -1 on error and set errno
- error recovery system was flawed
- error recovery disabled by default
- remove a malloc
Stéphane Raimbault пре 15 година
родитељ
комит
f0e7ad217d

+ 456 - 371
modbus/modbus.c

@@ -41,6 +41,7 @@
 #include <sys/time.h>
 #include <sys/time.h>
 #include <unistd.h>
 #include <unistd.h>
 #include <errno.h>
 #include <errno.h>
+#include <assert.h>
 #include <limits.h>
 #include <limits.h>
 #include <fcntl.h>
 #include <fcntl.h>
 
 
@@ -61,9 +62,8 @@
 #endif
 #endif
 
 
 #include <config.h>
 #include <config.h>
-#include <modbus/modbus.h>
 
 
-#define UNKNOWN_ERROR_MSG "Not defined in modbus specification"
+#include <modbus/modbus.h>
 
 
 /* Exported version */
 /* Exported version */
 const unsigned int mb_version_major = MB_VERSION_MAJOR;
 const unsigned int mb_version_major = MB_VERSION_MAJOR;
@@ -78,22 +78,6 @@ typedef struct {
         int t_id;
         int t_id;
 } sft_t;
 } sft_t;
 
 
-static const uint8_t NB_TAB_ERROR_MSG = 12;
-static const char *TAB_ERROR_MSG[] = {
-        /* 0x00 */ UNKNOWN_ERROR_MSG,
-        /* 0x01 */ "Illegal function code",
-        /* 0x02 */ "Illegal data address",
-        /* 0x03 */ "Illegal data value",
-        /* 0x04 */ "Slave device or server failure",
-        /* 0x05 */ "Acknowledge",
-        /* 0x06 */ "Slave device or server busy",
-        /* 0x07 */ "Negative acknowledge",
-        /* 0x08 */ "Memory parity error",
-        /* 0x09 */ UNKNOWN_ERROR_MSG,
-        /* 0x0A */ "Gateway path unavailable",
-        /* 0x0B */ "Target device failed to respond"
-};
-
 /* Table of CRC values for high-order byte */
 /* Table of CRC values for high-order byte */
 static uint8_t table_crc_hi[] = {
 static uint8_t table_crc_hi[] = {
         0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
         0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
@@ -169,42 +153,65 @@ static const int TAB_MAX_ADU_LENGTH[2] = {
         MAX_ADU_LENGTH_TCP,
         MAX_ADU_LENGTH_TCP,
 };
 };
 
 
-/* Treats errors and flush or close connection if necessary */
-static void error_treat(modbus_param_t *mb_param, int code, const char *string)
-{
-        fprintf(stderr, "\nERROR %s (%0X)\n", string, -code);
+const char *modbus_strerror(int errnum) {
+        switch (errnum) {
+        case EMBXILFUN:
+                return "Illegal function";
+        case EMBXILADD:
+                return "Illegal data address";
+        case EMBXILVAL:
+                return "Illegal data value";
+        case EMBXSFAIL:
+                return "Slave device or server failure";
+        case EMBXACK:
+                return "Acknowledge";
+        case EMBXSBUSY:
+                return "Slave device or server is busy";
+        case EMBXNACK:
+                return "Negative acknowledge";
+        case EMBXMEMPAR:
+                return "Memory parity error";
+        case EMBXGPATH:
+                return "Gateway path unavailable";
+        case EMBXGTAR:
+                return "Target device failed to respond";
+        case EMBBADCRC:
+                return "Invalid CRC";
+        case EMBBADDATA:
+                return "Invalid data";
+        case EMBBADEXC:
+                return "Invalid exception code";
+        case EMBMDATA:
+                return "Too many data";
+        default:
+                return strerror(errnum);
+        }
+}
 
 
-        if (mb_param->error_handling == FLUSH_OR_CONNECT_ON_ERROR) {
-                switch (code) {
-                case INVALID_DATA:
-                case INVALID_CRC:
-                case INVALID_EXCEPTION_CODE:
-                        modbus_flush(mb_param);
-                        break;
-                case SELECT_FAILURE:
-                case SOCKET_FAILURE:
-                case CONNECTION_CLOSED:
-                        modbus_close(mb_param);
-                        modbus_connect(mb_param);
-                        break;
-                default:
-                        /* NOP */
-                        break;
+static void error_print(modbus_param_t *mb_param, const char *context)
+{
+        if (mb_param->debug) {
+                fprintf(stderr, "ERROR %s", modbus_strerror(errno));
+                if (context != NULL) {
+                        fprintf(stderr, ": %s\n", context);
+                } else {
+                        fprintf(stderr, "\n");
                 }
                 }
         }
         }
 }
 }
 
 
-void modbus_flush(modbus_param_t *mb_param)
+int modbus_flush(modbus_param_t *mb_param)
 {
 {
+        int rc;
+
         if (mb_param->type_com == RTU) {
         if (mb_param->type_com == RTU) {
-                tcflush(mb_param->fd, TCIOFLUSH);
+                rc = tcflush(mb_param->fd, TCIOFLUSH);
         } else {
         } else {
-                int ret;
                 do {
                 do {
                         /* Extract the garbage from the socket */
                         /* Extract the garbage from the socket */
                         char devnull[MAX_ADU_LENGTH_TCP];
                         char devnull[MAX_ADU_LENGTH_TCP];
 #if (!HAVE_DECL___CYGWIN__)
 #if (!HAVE_DECL___CYGWIN__)
-                        ret = recv(mb_param->fd, devnull, MAX_ADU_LENGTH_TCP, MSG_DONTWAIT);
+                        rc = recv(mb_param->fd, devnull, MAX_ADU_LENGTH_TCP, MSG_DONTWAIT);
 #else
 #else
                         /* On Cygwin, it's a bit more complicated to not wait */
                         /* On Cygwin, it's a bit more complicated to not wait */
                         fd_set rfds;
                         fd_set rfds;
@@ -214,19 +221,17 @@ void modbus_flush(modbus_param_t *mb_param)
                         tv.tv_usec = 0;
                         tv.tv_usec = 0;
                         FD_ZERO(&rfds);
                         FD_ZERO(&rfds);
                         FD_SET(mb_param->fd, &rfds);
                         FD_SET(mb_param->fd, &rfds);
-                        ret = select(mb_param->fd+1, &rfds, NULL, NULL, &tv);
-                        if (ret > 0) {
-                                ret = recv(mb_param->fd, devnull, MAX_ADU_LENGTH_TCP, 0);
-                        } else if (ret == -1) {
-                                /* error_treat() doesn't call modbus_flush() in
-                                   this case (avoid infinite loop) */
-                                error_treat(mb_param, SELECT_FAILURE, "Select failure");
+                        rc = select(mb_param->fd+1, &rfds, NULL, NULL, &tv);
+                        if (rc == -1) {
+                                return -1;
                         }
                         }
+
+                        rc = recv(mb_param->fd, devnull, MAX_ADU_LENGTH_TCP, 0);
 #endif
 #endif
-                        if (mb_param->debug && ret > 0) {
-                                printf("%d bytes flushed\n", ret);
+                        if (mb_param->debug && rc != -1) {
+                                printf("\n%d bytes flushed\n", rc);
                         }
                         }
-                } while (ret > 0);
+                } while (rc > 0);
         }
         }
 }
 }
 
 
@@ -288,12 +293,11 @@ static int build_query_basis_tcp(int slave, int function,
                                  uint8_t *query)
                                  uint8_t *query)
 {
 {
 
 
-        /* Extract from MODBUS Messaging on TCP/IP Implementation
-           Guide V1.0b (page 23/46):
-           The transaction identifier is used to associate the future
-           response with the request. So, at a time, on a TCP
-           connection, this identifier must be unique.
-        */
+        /* Extract from MODBUS Messaging on TCP/IP Implementation Guide V1.0b
+           (page 23/46):
+           The transaction identifier is used to associate the future response
+           with the request. So, at a time, on a TCP connection, this identifier
+           must be unique. */
         static uint16_t t_id = 0;
         static uint16_t t_id = 0;
 
 
         /* Transaction ID */
         /* Transaction ID */
@@ -309,7 +313,7 @@ static int build_query_basis_tcp(int slave, int function,
         query[3] = 0;
         query[3] = 0;
 
 
         /* Length will be defined later by set_query_length_tcp at offsets 4
         /* Length will be defined later by set_query_length_tcp at offsets 4
-         * and 5 */
+           and 5 */
 
 
         query[6] = slave;
         query[6] = slave;
         query[7] = function;
         query[7] = function;
@@ -400,38 +404,39 @@ static uint16_t crc16(uint8_t *buffer, uint16_t buffer_length)
         return (crc_hi << 8 | crc_lo);
         return (crc_hi << 8 | crc_lo);
 }
 }
 
 
-/* If CRC is correct returns msg_length else returns INVALID_CRC */
+/* The check_crc16 function shall return the message length if the CRC is
+   valid. Otherwise it shall return -1 and set errno to EMBADCRC. */
 static int check_crc16(modbus_param_t *mb_param,
 static int check_crc16(modbus_param_t *mb_param,
                        uint8_t *msg,
                        uint8_t *msg,
                        const int msg_length)
                        const int msg_length)
 {
 {
-        int ret;
-        uint16_t crc_calc;
+        uint16_t crc_calculated;
         uint16_t crc_received;
         uint16_t crc_received;
 
 
-        crc_calc = crc16(msg, msg_length - 2);
+        crc_calculated = crc16(msg, msg_length - 2);
         crc_received = (msg[msg_length - 2] << 8) | msg[msg_length - 1];
         crc_received = (msg[msg_length - 2] << 8) | msg[msg_length - 1];
 
 
         /* Check CRC of msg */
         /* Check CRC of msg */
-        if (crc_calc == crc_received) {
-                ret = msg_length;
+        if (crc_calculated == crc_received) {
+                return msg_length;
         } else {
         } else {
-                char s_error[64];
-                sprintf(s_error,
-                        "invalid crc received %0X - crc_calc %0X",
-                        crc_received, crc_calc);
-                ret = INVALID_CRC;
-                error_treat(mb_param, ret, s_error);
+                if (mb_param->debug) {
+                        fprintf(stderr, "ERROR CRC received %0X != CRC calculated %0X\n",
+                                crc_received, crc_calculated);
+                }
+                if (mb_param->error_recovery) {
+                        modbus_flush(mb_param);
+                }
+                errno = EMBBADCRC;
+                return -1;
         }
         }
-
-        return ret;
 }
 }
 
 
 /* Sends a query/response over a serial or a TCP communication */
 /* Sends a query/response over a serial or a TCP communication */
 static int modbus_send(modbus_param_t *mb_param, uint8_t *query,
 static int modbus_send(modbus_param_t *mb_param, uint8_t *query,
                        int query_length)
                        int query_length)
 {
 {
-        int ret;
+        int rc;
         uint16_t s_crc;
         uint16_t s_crc;
         int i;
         int i;
 
 
@@ -449,19 +454,35 @@ static int modbus_send(modbus_param_t *mb_param, uint8_t *query,
                 printf("\n");
                 printf("\n");
         }
         }
 
 
-        if (mb_param->type_com == RTU)
-                ret = write(mb_param->fd, query, query_length);
-        else
-                ret = send(mb_param->fd, query, query_length, MSG_NOSIGNAL);
+        /* In recovery mode, the write command will be issued until to be
+           successful! Disabled by default.
+         */
+        do {
+                if (mb_param->type_com == RTU)
+                        rc = write(mb_param->fd, query, query_length);
+                else
+                        /* MSG_NOSIGNAL
+                           Requests not to send SIGPIPE on errors on stream oriented
+                           sockets when the other end breaks the connection.  The EPIPE
+                           error is still returned. */
+                        rc = send(mb_param->fd, query, query_length, MSG_NOSIGNAL);
+
+                if (rc == -1) {
+                        error_print(mb_param, NULL);
+                        if (mb_param->error_recovery && (errno == EBADF ||
+                            errno == ECONNRESET || errno == EPIPE)) {
+                                modbus_close(mb_param);
+                                modbus_connect(mb_param);
+                        }
+                }
+        } while (mb_param->error_recovery && rc == -1);
 
 
-        /* Return the number of bytes written (0 to n)
-           or SOCKET_FAILURE on error */
-        if ((ret == -1) || (ret != query_length)) {
-                ret = SOCKET_FAILURE;
-                error_treat(mb_param, ret, "Write socket failure");
+        if (rc > 0 && rc != query_length) {
+                errno = EMBBADDATA;
+                return -1;
         }
         }
 
 
-        return ret;
+        return rc;
 }
 }
 
 
 /* Computes the length of the header following the function code */
 /* Computes the length of the header following the function code */
@@ -504,53 +525,68 @@ static int compute_query_length_data(modbus_param_t *mb_param, uint8_t *msg)
         return length;
         return length;
 }
 }
 
 
-#define WAIT_DATA()                                                                \
-{                                                                                  \
-    while ((select_ret = select(mb_param->fd+1, &rfds, NULL, NULL, &tv)) == -1) {  \
-            if (errno == EINTR) {                                                  \
-                    fprintf(stderr, "A non blocked signal was caught\n");          \
-                    /* Necessary after an error */                                 \
-                    FD_ZERO(&rfds);                                                \
-                    FD_SET(mb_param->fd, &rfds);                                   \
-            } else {                                                               \
-                    error_treat(mb_param, SELECT_FAILURE, "Select failure");       \
-                    return SELECT_FAILURE;                                         \
-            }                                                                      \
-    }                                                                              \
-                                                                                   \
-    if (select_ret == 0) {                                                         \
-            /* Timeout */                                                          \
-            if (msg_length == (TAB_HEADER_LENGTH[mb_param->type_com] + 2 +         \
-                               TAB_CHECKSUM_LENGTH[mb_param->type_com])) {         \
-                    /* Optimization allowed because exception response is          \
-                       the smallest trame in modbus protocol (3) so always         \
-                       raise a timeout error */                                    \
-                    return MB_EXCEPTION;                                           \
-            } else {                                                               \
-                    /* Call to error_treat is done later to manage exceptions */   \
-                    return SELECT_TIMEOUT;                                         \
-            }                                                                      \
-    }                                                                              \
+#define WAIT_DATA()                                                           \
+{                                                                             \
+    while ((s_rc = select(mb_param->fd+1, &rfds, NULL, NULL, &tv)) == -1) {   \
+            if (errno == EINTR) {                                             \
+                    if (mb_param->debug) {                                    \
+                            fprintf(stderr,                                   \
+                                    "A non blocked signal was caught\n");     \
+                    }                                                         \
+                    /* Necessary after an error */                            \
+                    FD_ZERO(&rfds);                                           \
+                    FD_SET(mb_param->fd, &rfds);                              \
+            } else {                                                          \
+                    error_print(mb_param, "select");                          \
+                    if (mb_param->error_recovery && (errno == EBADF)) {       \
+                            modbus_close(mb_param);                           \
+                            modbus_connect(mb_param);                         \
+                            errno = EBADF;                                    \
+                            return -1;                                        \
+                    } else {                                                  \
+                            return -1;                                        \
+                    }                                                         \
+            }                                                                 \
+    }                                                                         \
+                                                                              \
+    if (s_rc == 0) {                                                          \
+            /* Timeout */                                                     \
+            if (msg_length == (TAB_HEADER_LENGTH[mb_param->type_com] + 2 +    \
+                               TAB_CHECKSUM_LENGTH[mb_param->type_com])) {    \
+                    /* Optimization allowed because exception response is     \
+                       the smallest trame in modbus protocol (3) so always    \
+                       raise a timeout error.                                 \
+                       Temporary error before exception analyze. */           \
+                    errno = EMBUNKEXC;                                        \
+            } else {                                                          \
+                    errno = ETIMEDOUT;                                        \
+                    error_print(mb_param, "select");                          \
+            }                                                                 \
+            return -1;                                                        \
+    }                                                                         \
 }
 }
 
 
 /* Waits a reply from a modbus slave or a query from a modbus master.
 /* Waits a reply from a modbus slave or a query from a modbus master.
    This function blocks if there is no replies (3 timeouts).
    This function blocks if there is no replies (3 timeouts).
 
 
-   In
-   - msg_length_computed must be set to MSG_LENGTH_UNDEFINED if undefined
-
-   Out
-   - msg is an array of uint8_t to receive the message
-
-   On success, return the number of received characters. On error, return
-   a negative value.
+   The argument msg_length_computed must be set to MSG_LENGTH_UNDEFINED if
+   undefined.
+
+   The function shall return the number of received characters and the received
+   message in an array of uint8_t if successful. Otherwise it shall return -1
+   and errno is set to one of the values defined below:
+   - ECONNRESET
+   - EMBBADDATA
+   - EMBUNKEXC
+   - ETIMEDOUT
+   - read() or recv() error codes
 */
 */
 static int receive_msg(modbus_param_t *mb_param,
 static int receive_msg(modbus_param_t *mb_param,
                        int msg_length_computed,
                        int msg_length_computed,
                        uint8_t *msg)
                        uint8_t *msg)
 {
 {
-        int select_ret;
-        int read_ret;
+        int s_rc;
+        int read_rc;
         fd_set rfds;
         fd_set rfds;
         struct timeval tv;
         struct timeval tv;
         int length_to_read;
         int length_to_read;
@@ -591,32 +627,41 @@ static int receive_msg(modbus_param_t *mb_param,
 
 
         length_to_read = msg_length_computed;
         length_to_read = msg_length_computed;
 
 
-        select_ret = 0;
+        s_rc = 0;
         WAIT_DATA();
         WAIT_DATA();
 
 
         p_msg = msg;
         p_msg = msg;
-        while (select_ret) {
+        while (s_rc) {
                 if (mb_param->type_com == RTU)
                 if (mb_param->type_com == RTU)
-                        read_ret = read(mb_param->fd, p_msg, length_to_read);
+                        read_rc = read(mb_param->fd, p_msg, length_to_read);
                 else
                 else
-                        read_ret = recv(mb_param->fd, p_msg, length_to_read, 0);
-
-                if (read_ret == 0) {
-                        return CONNECTION_CLOSED;
-                } else if (read_ret < 0) {
-                        /* The only negative possible value is -1 */
-                        error_treat(mb_param, SOCKET_FAILURE,
-                                    "Read socket failure");
-                        return SOCKET_FAILURE;
+                        read_rc = recv(mb_param->fd, p_msg, length_to_read, 0);
+
+                if (read_rc == 0) {
+                        errno = ECONNRESET;
+                        read_rc = -1;
+                }
+
+                if (read_rc == -1) {
+                        error_print(mb_param, "read");
+                        if (mb_param->error_recovery && (errno == ECONNRESET ||
+                            errno == ECONNREFUSED)) {
+                                modbus_close(mb_param);
+                                modbus_connect(mb_param);
+                                /* Could be removed by previous calls */
+                                errno = ECONNRESET;
+                                return -1;
+                        }
+                        return -1;
                 }
                 }
 
 
                 /* Sums bytes received */
                 /* Sums bytes received */
-                msg_length += read_ret;
+                msg_length += read_rc;
 
 
                 /* Display the hex code of each character received */
                 /* Display the hex code of each character received */
                 if (mb_param->debug) {
                 if (mb_param->debug) {
                         int i;
                         int i;
-                        for (i=0; i < read_ret; i++)
+                        for (i=0; i < read_rc; i++)
                                 printf("<%.2X>", p_msg[i]);
                                 printf("<%.2X>", p_msg[i]);
                 }
                 }
 
 
@@ -639,8 +684,9 @@ static int receive_msg(modbus_param_t *mb_param,
                                 length_to_read = compute_query_length_data(mb_param, msg);
                                 length_to_read = compute_query_length_data(mb_param, msg);
                                 msg_length_computed += length_to_read;
                                 msg_length_computed += length_to_read;
                                 if (msg_length_computed > TAB_MAX_ADU_LENGTH[mb_param->type_com]) {
                                 if (msg_length_computed > TAB_MAX_ADU_LENGTH[mb_param->type_com]) {
-                                     error_treat(mb_param, INVALID_DATA, "Too many data");
-                                     return INVALID_DATA;
+                                        errno = EMBBADDATA;
+                                        error_print(mb_param, "too many data");
+                                        return -1;
                                 }
                                 }
                                 state = COMPLETE;
                                 state = COMPLETE;
                                 break;
                                 break;
@@ -651,7 +697,7 @@ static int receive_msg(modbus_param_t *mb_param,
                 }
                 }
 
 
                 /* Moves the pointer to receive other data */
                 /* Moves the pointer to receive other data */
-                p_msg = &(p_msg[read_ret]);
+                p_msg = &(p_msg[read_rc]);
 
 
                 if (length_to_read > 0) {
                 if (length_to_read > 0) {
                         /* If no character at the buffer wait
                         /* If no character at the buffer wait
@@ -662,7 +708,7 @@ static int receive_msg(modbus_param_t *mb_param,
                         WAIT_DATA();
                         WAIT_DATA();
                 } else {
                 } else {
                         /* All chars are received */
                         /* All chars are received */
-                        select_ret = FALSE;
+                        s_rc = FALSE;
                 }
                 }
         }
         }
 
 
@@ -683,11 +729,8 @@ static int receive_msg(modbus_param_t *mb_param,
    descriptor etablished with the master device in argument or -1 to use the
    descriptor etablished with the master device in argument or -1 to use the
    internal one of modbus_param_t.
    internal one of modbus_param_t.
 
 
-   Returns:
-   - byte length of the message on success, or a negative error number if the
-     request fails
-   - query, message received
-*/
+   The modbus_slave_receive function shall return the request received and its
+   byte length if successul. Otherwise, it shall return -1 and errno is set. */
 int modbus_slave_receive(modbus_param_t *mb_param, int sockfd, uint8_t *query)
 int modbus_slave_receive(modbus_param_t *mb_param, int sockfd, uint8_t *query)
 {
 {
         if (sockfd != -1) {
         if (sockfd != -1) {
@@ -700,10 +743,8 @@ int modbus_slave_receive(modbus_param_t *mb_param, int sockfd, uint8_t *query)
 
 
 /* Receives the response and checks values (and checksum in RTU).
 /* Receives the response and checks values (and checksum in RTU).
 
 
-   Returns:
-   - the number of values (bits or words) if success or the response
-     length if no value is returned
-   - less than 0 for exception errors
+   The function shall return the number of values (bits or words) and the
+   response if successful. Otherwise, its shall return -1 and errno is set.
 
 
    Note: all functions used to send or receive data with modbus return
    Note: all functions used to send or receive data with modbus return
    these values. */
    these values. */
@@ -711,13 +752,13 @@ static int modbus_receive(modbus_param_t *mb_param,
                           uint8_t *query,
                           uint8_t *query,
                           uint8_t *response)
                           uint8_t *response)
 {
 {
-        int ret;
+        int rc;
         int response_length_computed;
         int response_length_computed;
         int offset = TAB_HEADER_LENGTH[mb_param->type_com];
         int offset = TAB_HEADER_LENGTH[mb_param->type_com];
 
 
         response_length_computed = compute_response_length(mb_param, query);
         response_length_computed = compute_response_length(mb_param, query);
-        ret = receive_msg(mb_param, response_length_computed, response);
-        if (ret >= 0) {
+        rc = receive_msg(mb_param, response_length_computed, response);
+        if (rc != -1) {
                 /* GOOD RESPONSE */
                 /* GOOD RESPONSE */
                 int query_nb_value;
                 int query_nb_value;
                 int response_nb_value;
                 int response_nb_value;
@@ -748,7 +789,7 @@ static int modbus_receive(modbus_param_t *mb_param,
                         break;
                         break;
                 case FC_REPORT_SLAVE_ID:
                 case FC_REPORT_SLAVE_ID:
                         /* Report slave ID (bytes received) */
                         /* Report slave ID (bytes received) */
-                        query_nb_value = response_nb_value = ret;
+                        query_nb_value = response_nb_value = rc;
                         break;
                         break;
                 default:
                 default:
                         /* 1 Write functions & others */
                         /* 1 Write functions & others */
@@ -756,58 +797,42 @@ static int modbus_receive(modbus_param_t *mb_param,
                 }
                 }
 
 
                 if (query_nb_value == response_nb_value) {
                 if (query_nb_value == response_nb_value) {
-                        ret = response_nb_value;
+                        rc = response_nb_value;
                 } else {
                 } else {
-                        char *s_error = malloc(64 * sizeof(char));
-                        sprintf(s_error, "Quantity not corresponding to the query (%d != %d)",
-                                response_nb_value, query_nb_value);
-                        ret = INVALID_DATA;
-                        error_treat(mb_param, ret, s_error);
-                        free(s_error);
+                        if (mb_param->debug) {
+                                fprintf(stderr,
+                                        "Quantity not corresponding to the query (%d != %d)\n",
+                                        response_nb_value, query_nb_value);
+                        }
+                        errno = EMBBADDATA;
+                        rc = -1;
                 }
                 }
-        } else if (ret == MB_EXCEPTION) {
+        } else if (errno == EMBUNKEXC) {
                 /* EXCEPTION CODE RECEIVED */
                 /* EXCEPTION CODE RECEIVED */
 
 
                 /* CRC must be checked here (not done in receive_msg) */
                 /* CRC must be checked here (not done in receive_msg) */
                 if (mb_param->type_com == RTU) {
                 if (mb_param->type_com == RTU) {
-                        ret = check_crc16(mb_param, response, EXCEPTION_RESPONSE_LENGTH_RTU);
-                        if (ret < 0)
-                                return ret;
+                        rc = check_crc16(mb_param, response, EXCEPTION_RESPONSE_LENGTH_RTU);
+                        if (rc == -1)
+                                return -1;
                 }
                 }
 
 
                 /* Check for exception response.
                 /* Check for exception response.
                    0x80 + function is stored in the exception
                    0x80 + function is stored in the exception
                    response. */
                    response. */
                 if (0x80 + query[offset] == response[offset]) {
                 if (0x80 + query[offset] == response[offset]) {
-
                         int exception_code = response[offset + 1];
                         int exception_code = response[offset + 1];
-                        // FIXME check test
-                        if (exception_code < NB_TAB_ERROR_MSG) {
-                                error_treat(mb_param, -exception_code,
-                                            TAB_ERROR_MSG[response[offset + 1]]);
-                                /* RETURN THE EXCEPTION CODE */
-                                /* Modbus error code is negative */
-                                return -exception_code;
+                        if (exception_code < MODBUS_EXCEPTION_MAX) {
+                                errno = MODBUS_ENOBASE + exception_code;
                         } else {
                         } else {
-                                /* The chances are low to hit this
-                                   case but it can avoid a vicious
-                                   segfault */
-                                char *s_error = malloc(64 * sizeof(char));
-                                sprintf(s_error,
-                                        "Invalid exception code %d",
-                                        response[offset + 1]);
-                                error_treat(mb_param, INVALID_EXCEPTION_CODE,
-                                            s_error);
-                                free(s_error);
-                                return INVALID_EXCEPTION_CODE;
+                                errno = EMBBADEXC;
                         }
                         }
+                        error_print(mb_param, NULL);
+                        return -1;
                 }
                 }
-        } else {
-                /* Other errors */
-                error_treat(mb_param, ret, "receive_msg");
         }
         }
 
 
-        return ret;
+        return rc;
 }
 }
 
 
 static int response_io_status(int address, int nb,
 static int response_io_status(int address, int nb,
@@ -845,7 +870,7 @@ static int response_exception(modbus_param_t *mb_param, sft_t *sft,
         response_length = build_response_basis(mb_param, sft, response);
         response_length = build_response_basis(mb_param, sft, response);
 
 
         /* Positive exception code */
         /* Positive exception code */
-        response[response_length++] = -exception_code;
+        response[response_length++] = exception_code;
 
 
         return response_length;
         return response_length;
 }
 }
@@ -856,8 +881,8 @@ static int response_exception(modbus_param_t *mb_param, sft_t *sft,
    If an error occurs, this function construct the response
    If an error occurs, this function construct the response
    accordingly.
    accordingly.
 */
 */
-void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query,
-                         int query_length, modbus_mapping_t *mb_mapping)
+int modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query,
+                        int query_length, modbus_mapping_t *mb_mapping)
 {
 {
         int offset = TAB_HEADER_LENGTH[mb_param->type_com];
         int offset = TAB_HEADER_LENGTH[mb_param->type_com];
         int slave = query[offset - 1];
         int slave = query[offset - 1];
@@ -873,7 +898,7 @@ void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query,
                         printf("Request for slave %d ignored (not %d)\n",
                         printf("Request for slave %d ignored (not %d)\n",
                                slave, mb_param->slave);
                                slave, mb_param->slave);
                 }
                 }
-                return;
+                return 0;
         }
         }
 
 
         sft.slave = slave;
         sft.slave = slave;
@@ -890,10 +915,13 @@ void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query,
                 int nb = (query[offset + 3] << 8) + query[offset + 4];
                 int nb = (query[offset + 3] << 8) + query[offset + 4];
 
 
                 if ((address + nb) > mb_mapping->nb_coil_status) {
                 if ((address + nb) > mb_mapping->nb_coil_status) {
-                        printf("Illegal data address %0X in read_coil_status\n",
-                               address + nb);
-                        resp_length = response_exception(mb_param, &sft,
-                                                         ILLEGAL_DATA_ADDRESS, response);
+                        if (mb_param->debug) {
+                                fprintf(stderr, "Illegal data address %0X in read_coil_status\n",
+                                        address + nb);
+                        }
+                        resp_length = response_exception(
+                                mb_param, &sft,
+                                MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response);
                 } else {
                 } else {
                         resp_length = build_response_basis(mb_param, &sft, response);
                         resp_length = build_response_basis(mb_param, &sft, response);
                         response[resp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0);
                         response[resp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0);
@@ -909,10 +937,13 @@ void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query,
                 int nb = (query[offset + 3] << 8) + query[offset + 4];
                 int nb = (query[offset + 3] << 8) + query[offset + 4];
 
 
                 if ((address + nb) > mb_mapping->nb_input_status) {
                 if ((address + nb) > mb_mapping->nb_input_status) {
-                        printf("Illegal data address %0X in read_input_status\n",
-                               address + nb);
-                        resp_length = response_exception(mb_param, &sft,
-                                                         ILLEGAL_DATA_ADDRESS, response);
+                        if (mb_param->debug) {
+                                fprintf(stderr, "Illegal data address %0X in read_input_status\n",
+                                        address + nb);
+                        }
+                        resp_length = response_exception(
+                                mb_param, &sft,
+                                MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response);
                 } else {
                 } else {
                         resp_length = build_response_basis(mb_param, &sft, response);
                         resp_length = build_response_basis(mb_param, &sft, response);
                         response[resp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0);
                         response[resp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0);
@@ -926,10 +957,13 @@ void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query,
                 int nb = (query[offset + 3] << 8) + query[offset + 4];
                 int nb = (query[offset + 3] << 8) + query[offset + 4];
 
 
                 if ((address + nb) > mb_mapping->nb_holding_registers) {
                 if ((address + nb) > mb_mapping->nb_holding_registers) {
-                        printf("Illegal data address %0X in read_holding_registers\n",
-                               address + nb);
-                        resp_length = response_exception(mb_param, &sft,
-                                                         ILLEGAL_DATA_ADDRESS, response);
+                        if (mb_param->debug) {
+                                fprintf(stderr, "Illegal data address %0X in read_holding_registers\n",
+                                        address + nb);
+                        }
+                        resp_length = response_exception(
+                                mb_param, &sft,
+                                MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response);
                 } else {
                 } else {
                         int i;
                         int i;
 
 
@@ -948,10 +982,13 @@ void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query,
                 int nb = (query[offset + 3] << 8) + query[offset + 4];
                 int nb = (query[offset + 3] << 8) + query[offset + 4];
 
 
                 if ((address + nb) > mb_mapping->nb_input_registers) {
                 if ((address + nb) > mb_mapping->nb_input_registers) {
-                        printf("Illegal data address %0X in read_input_registers\n",
-                               address + nb);
-                        resp_length = response_exception(mb_param, &sft,
-                                                         ILLEGAL_DATA_ADDRESS, response);
+                        if (mb_param->debug) {
+                                fprintf(stderr, "Illegal data address %0X in read_input_registers\n",
+                                        address + nb);
+                        }
+                        resp_length = response_exception(
+                                mb_param, &sft,
+                                MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response);
                 } else {
                 } else {
                         int i;
                         int i;
 
 
@@ -966,9 +1003,13 @@ void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query,
                 break;
                 break;
         case FC_FORCE_SINGLE_COIL:
         case FC_FORCE_SINGLE_COIL:
                 if (address >= mb_mapping->nb_coil_status) {
                 if (address >= mb_mapping->nb_coil_status) {
-                        printf("Illegal data address %0X in force_singe_coil\n", address);
-                        resp_length = response_exception(mb_param, &sft,
-                                                         ILLEGAL_DATA_ADDRESS, response);
+                        if (mb_param->debug) {
+                                fprintf(stderr, "Illegal data address %0X in force_singe_coil\n",
+                                        address);
+                        }
+                        resp_length = response_exception(
+                                mb_param, &sft,
+                                MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response);
                 } else {
                 } else {
                         int data = (query[offset + 3] << 8) + query[offset + 4];
                         int data = (query[offset + 3] << 8) + query[offset + 4];
 
 
@@ -982,18 +1023,25 @@ void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query,
                                 memcpy(response, query, query_length);
                                 memcpy(response, query, query_length);
                                 resp_length = query_length;
                                 resp_length = query_length;
                         } else {
                         } else {
-                                printf("Illegal data value %0X in force_single_coil request at address %0X\n",
-                                       data, address);
-                                resp_length = response_exception(mb_param, &sft,
-                                                                 ILLEGAL_DATA_VALUE, response);
+                                if (mb_param->debug) {
+                                        fprintf(stderr, "Illegal data value %0X in force_single_coil request at address %0X\n",
+                                               data, address);
+                                }
+                                resp_length = response_exception(
+                                        mb_param, &sft,
+                                        MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, response);
                         }
                         }
                 }
                 }
                 break;
                 break;
         case FC_PRESET_SINGLE_REGISTER:
         case FC_PRESET_SINGLE_REGISTER:
                 if (address >= mb_mapping->nb_holding_registers) {
                 if (address >= mb_mapping->nb_holding_registers) {
-                        printf("Illegal data address %0X in preset_holding_register\n", address);
-                        resp_length = response_exception(mb_param, &sft,
-                                                         ILLEGAL_DATA_ADDRESS, response);
+                        if (mb_param->debug) {
+                                fprintf(stderr, "Illegal data address %0X in preset_holding_register\n",
+                                        address);
+                        }
+                        resp_length = response_exception(
+                                mb_param, &sft,
+                                MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response);
                 } else {
                 } else {
                         int data = (query[offset + 3] << 8) + query[offset + 4];
                         int data = (query[offset + 3] << 8) + query[offset + 4];
 
 
@@ -1006,10 +1054,13 @@ void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query,
                 int nb = (query[offset + 3] << 8) + query[offset + 4];
                 int nb = (query[offset + 3] << 8) + query[offset + 4];
 
 
                 if ((address + nb) > mb_mapping->nb_coil_status) {
                 if ((address + nb) > mb_mapping->nb_coil_status) {
-                        printf("Illegal data address %0X in force_multiple_coils\n",
-                               address + nb);
-                        resp_length = response_exception(mb_param, &sft,
-                                                         ILLEGAL_DATA_ADDRESS, response);
+                        if (mb_param->debug) {
+                                fprintf(stderr, "Illegal data address %0X in force_multiple_coils\n",
+                                        address + nb);
+                        }
+                        resp_length = response_exception(
+                                mb_param, &sft,
+                                MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response);
                 } else {
                 } else {
                         /* 6 = byte count */
                         /* 6 = byte count */
                         set_bits_from_bytes(mb_mapping->tab_coil_status, address, nb, &query[offset + 6]);
                         set_bits_from_bytes(mb_mapping->tab_coil_status, address, nb, &query[offset + 6]);
@@ -1025,10 +1076,13 @@ void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query,
                 int nb = (query[offset + 3] << 8) + query[offset + 4];
                 int nb = (query[offset + 3] << 8) + query[offset + 4];
 
 
                 if ((address + nb) > mb_mapping->nb_holding_registers) {
                 if ((address + nb) > mb_mapping->nb_holding_registers) {
-                        printf("Illegal data address %0X in preset_multiple_registers\n",
-                               address + nb);
-                        resp_length = response_exception(mb_param, &sft,
-                                                         ILLEGAL_DATA_ADDRESS, response);
+                        if (mb_param->debug) {
+                                fprintf(stderr, "Illegal data address %0X in preset_multiple_registers\n",
+                                        address + nb);
+                        }
+                        resp_length = response_exception(
+                                mb_param, &sft,
+                                MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response);
                 } else {
                 } else {
                         int i, j;
                         int i, j;
                         for (i = address, j = 6; i < address + nb; i++, j += 2) {
                         for (i = address, j = 6; i < address + nb; i++, j += 2) {
@@ -1046,18 +1100,25 @@ void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query,
                 break;
                 break;
         case FC_READ_EXCEPTION_STATUS:
         case FC_READ_EXCEPTION_STATUS:
         case FC_REPORT_SLAVE_ID:
         case FC_REPORT_SLAVE_ID:
-                printf("Not implemented\n");
+                if (mb_param->debug) {
+                        fprintf(stderr, "FIXME Not implemented\n");
+                }
+                errno = ENOPROTOOPT;
+                return -1;
+                break;
+        default:
+                /* FIXME Invalid function exception */
                 break;
                 break;
         }
         }
 
 
-        modbus_send(mb_param, response, resp_length);
+        return modbus_send(mb_param, response, resp_length);
 }
 }
 
 
 /* Reads IO status */
 /* Reads IO status */
 static int read_io_status(modbus_param_t *mb_param, int function,
 static int read_io_status(modbus_param_t *mb_param, int function,
                           int start_addr, int nb, uint8_t *data_dest)
                           int start_addr, int nb, uint8_t *data_dest)
 {
 {
-        int ret;
+        int rc;
         int query_length;
         int query_length;
 
 
         uint8_t query[MIN_QUERY_LENGTH];
         uint8_t query[MIN_QUERY_LENGTH];
@@ -1066,19 +1127,19 @@ static int read_io_status(modbus_param_t *mb_param, int function,
         query_length = build_query_basis(mb_param, function,
         query_length = build_query_basis(mb_param, function,
                                          start_addr, nb, query);
                                          start_addr, nb, query);
 
 
-        ret = modbus_send(mb_param, query, query_length);
-        if (ret > 0) {
+        rc = modbus_send(mb_param, query, query_length);
+        if (rc > 0) {
                 int i, temp, bit;
                 int i, temp, bit;
                 int pos = 0;
                 int pos = 0;
                 int offset;
                 int offset;
                 int offset_end;
                 int offset_end;
 
 
-                ret = modbus_receive(mb_param, query, response);
-                if (ret < 0)
-                        return ret;
+                rc = modbus_receive(mb_param, query, response);
+                if (rc == -1)
+                        return -1;
 
 
                 offset = TAB_HEADER_LENGTH[mb_param->type_com];
                 offset = TAB_HEADER_LENGTH[mb_param->type_com];
-                offset_end = offset + ret;
+                offset_end = offset + rc;
                 for (i = offset; i < offset_end; i++) {
                 for (i = offset; i < offset_end; i++) {
                         /* Shift reg hi_byte to temp */
                         /* Shift reg hi_byte to temp */
                         temp = response[i + 2];
                         temp = response[i + 2];
@@ -1091,7 +1152,7 @@ static int read_io_status(modbus_param_t *mb_param, int function,
                 }
                 }
         }
         }
 
 
-        return ret;
+        return rc;
 }
 }
 
 
 /* Reads the boolean status of coils and sets the array elements
 /* Reads the boolean status of coils and sets the array elements
@@ -1099,22 +1160,25 @@ static int read_io_status(modbus_param_t *mb_param, int function,
 int read_coil_status(modbus_param_t *mb_param, int start_addr,
 int read_coil_status(modbus_param_t *mb_param, int start_addr,
                      int nb, uint8_t *data_dest)
                      int nb, uint8_t *data_dest)
 {
 {
-        int status;
+        int rc;
 
 
         if (nb > MAX_STATUS) {
         if (nb > MAX_STATUS) {
-                fprintf(stderr,
-                        "ERROR Too many coils status requested (%d > %d)\n",
-                        nb, MAX_STATUS);
-                return INVALID_DATA;
+                if (mb_param->debug) {
+                        fprintf(stderr,
+                                "ERROR Too many coils status requested (%d > %d)\n",
+                                nb, MAX_STATUS);
+                }
+                errno = EMBMDATA;
+                return -1;
         }
         }
 
 
-        status = read_io_status(mb_param, FC_READ_COIL_STATUS,
-                                start_addr, nb, data_dest);
-
-        if (status > 0)
-                status = nb;
+        rc = read_io_status(mb_param, FC_READ_COIL_STATUS, start_addr, nb,
+                            data_dest);
 
 
-        return status;
+        if (rc == -1)
+                return -1;
+        else
+                return nb;
 }
 }
 
 
 
 
@@ -1122,61 +1186,67 @@ int read_coil_status(modbus_param_t *mb_param, int start_addr,
 int read_input_status(modbus_param_t *mb_param, int start_addr,
 int read_input_status(modbus_param_t *mb_param, int start_addr,
                       int nb, uint8_t *data_dest)
                       int nb, uint8_t *data_dest)
 {
 {
-        int status;
+        int rc;
 
 
         if (nb > MAX_STATUS) {
         if (nb > MAX_STATUS) {
-                fprintf(stderr,
-                        "ERROR Too many input status requested (%d > %d)\n",
-                       nb, MAX_STATUS);
-                return INVALID_DATA;
+                if (mb_param->debug) {
+                        fprintf(stderr,
+                                "ERROR Too many input status requested (%d > %d)\n",
+                                nb, MAX_STATUS);
+                }
+                errno = EMBMDATA;
+                return -1;
         }
         }
 
 
-        status = read_io_status(mb_param, FC_READ_INPUT_STATUS,
-                                start_addr, nb, data_dest);
+        rc = read_io_status(mb_param, FC_READ_INPUT_STATUS, start_addr,
+                            nb, data_dest);
 
 
-        if (status > 0)
-                status = nb;
-
-        return status;
+        if (rc == -1)
+                return -1;
+        else
+                return nb;
 }
 }
 
 
 /* Reads the data from a modbus slave and put that data into an array */
 /* Reads the data from a modbus slave and put that data into an array */
 static int read_registers(modbus_param_t *mb_param, int function,
 static int read_registers(modbus_param_t *mb_param, int function,
                           int start_addr, int nb, uint16_t *data_dest)
                           int start_addr, int nb, uint16_t *data_dest)
 {
 {
-        int ret;
+        int rc;
         int query_length;
         int query_length;
         uint8_t query[MIN_QUERY_LENGTH];
         uint8_t query[MIN_QUERY_LENGTH];
         uint8_t response[MAX_MESSAGE_LENGTH];
         uint8_t response[MAX_MESSAGE_LENGTH];
 
 
         if (nb > MAX_REGISTERS) {
         if (nb > MAX_REGISTERS) {
-                fprintf(stderr,
-                        "ERROR Too many holding registers requested (%d > %d)\n",
-                        nb, MAX_REGISTERS);
-                return INVALID_DATA;
+                if (mb_param->debug) {
+                        fprintf(stderr,
+                                "ERROR Too many holding registers requested (%d > %d)\n",
+                                nb, MAX_REGISTERS);
+                }
+                errno = EMBMDATA;
+                return -1;
         }
         }
 
 
         query_length = build_query_basis(mb_param, function,
         query_length = build_query_basis(mb_param, function,
                                          start_addr, nb, query);
                                          start_addr, nb, query);
 
 
-        ret = modbus_send(mb_param, query, query_length);
-        if (ret > 0) {
+        rc = modbus_send(mb_param, query, query_length);
+        if (rc > 0) {
                 int offset;
                 int offset;
                 int i;
                 int i;
 
 
-                ret = modbus_receive(mb_param, query, response);
+                rc = modbus_receive(mb_param, query, response);
 
 
                 offset = TAB_HEADER_LENGTH[mb_param->type_com];
                 offset = TAB_HEADER_LENGTH[mb_param->type_com];
 
 
-                /* If ret is negative, the loop is jumped ! */
-                for (i = 0; i < ret; i++) {
+                /* If rc is negative, the loop is jumped ! */
+                for (i = 0; i < rc; i++) {
                         /* shift reg hi_byte to temp OR with lo_byte */
                         /* shift reg hi_byte to temp OR with lo_byte */
                         data_dest[i] = (response[offset + 2 + (i << 1)] << 8) |
                         data_dest[i] = (response[offset + 2 + (i << 1)] << 8) |
                                 response[offset + 3 + (i << 1)];
                                 response[offset + 3 + (i << 1)];
                 }
                 }
         }
         }
 
 
-        return ret;
+        return rc;
 }
 }
 
 
 /* Reads the holding registers in a slave and put the data into an
 /* Reads the holding registers in a slave and put the data into an
@@ -1187,10 +1257,13 @@ int read_holding_registers(modbus_param_t *mb_param,
         int status;
         int status;
 
 
         if (nb > MAX_REGISTERS) {
         if (nb > MAX_REGISTERS) {
-                fprintf(stderr,
-                        "ERROR Too many holding registers requested (%d > %d)\n",
-                        nb, MAX_REGISTERS);
-                return INVALID_DATA;
+                if (mb_param->debug) {
+                        fprintf(stderr,
+                                "ERROR Too many holding registers requested (%d > %d)\n",
+                                nb, MAX_REGISTERS);
+                }
+                errno = EMBMDATA;
+                return -1;
         }
         }
 
 
         status = read_registers(mb_param, FC_READ_HOLDING_REGISTERS,
         status = read_registers(mb_param, FC_READ_HOLDING_REGISTERS,
@@ -1209,7 +1282,8 @@ int read_input_registers(modbus_param_t *mb_param, int start_addr, int nb,
                 fprintf(stderr,
                 fprintf(stderr,
                         "ERROR Too many input registers requested (%d > %d)\n",
                         "ERROR Too many input registers requested (%d > %d)\n",
                         nb, MAX_REGISTERS);
                         nb, MAX_REGISTERS);
-                return INVALID_DATA;
+                errno = EMBMDATA;
+                return -1;
         }
         }
 
 
         status = read_registers(mb_param, FC_READ_INPUT_REGISTERS,
         status = read_registers(mb_param, FC_READ_INPUT_REGISTERS,
@@ -1223,22 +1297,22 @@ int read_input_registers(modbus_param_t *mb_param, int start_addr, int nb,
 static int set_single(modbus_param_t *mb_param, int function,
 static int set_single(modbus_param_t *mb_param, int function,
                       int addr, int value)
                       int addr, int value)
 {
 {
-        int ret;
+        int rc;
         int query_length;
         int query_length;
         uint8_t query[MIN_QUERY_LENGTH];
         uint8_t query[MIN_QUERY_LENGTH];
 
 
         query_length = build_query_basis(mb_param, function,
         query_length = build_query_basis(mb_param, function,
                                          addr, value, query);
                                          addr, value, query);
 
 
-        ret = modbus_send(mb_param, query, query_length);
-        if (ret > 0) {
+        rc = modbus_send(mb_param, query, query_length);
+        if (rc > 0) {
                 /* Used by force_single_coil and
                 /* Used by force_single_coil and
                  * preset_single_register */
                  * preset_single_register */
                 uint8_t response[MIN_QUERY_LENGTH];
                 uint8_t response[MIN_QUERY_LENGTH];
-                ret = modbus_receive(mb_param, query, response);
+                rc = modbus_receive(mb_param, query, response);
         }
         }
 
 
-        return ret;
+        return rc;
 }
 }
 
 
 /* Turns ON or OFF a single coil in the slave device */
 /* Turns ON or OFF a single coil in the slave device */
@@ -1270,7 +1344,7 @@ int preset_single_register(modbus_param_t *mb_param, int reg_addr, int value)
 int force_multiple_coils(modbus_param_t *mb_param, int start_addr, int nb,
 int force_multiple_coils(modbus_param_t *mb_param, int start_addr, int nb,
                          const uint8_t *data_src)
                          const uint8_t *data_src)
 {
 {
-        int ret;
+        int rc;
         int i;
         int i;
         int byte_count;
         int byte_count;
         int query_length;
         int query_length;
@@ -1280,9 +1354,12 @@ int force_multiple_coils(modbus_param_t *mb_param, int start_addr, int nb,
         uint8_t query[MAX_MESSAGE_LENGTH];
         uint8_t query[MAX_MESSAGE_LENGTH];
 
 
         if (nb > MAX_STATUS) {
         if (nb > MAX_STATUS) {
-                fprintf(stderr, "ERROR Writing to too many coils (%d > %d)\n",
-                        nb, MAX_STATUS);
-                return INVALID_DATA;
+                if (mb_param->debug) {
+                        fprintf(stderr, "ERROR Writing to too many coils (%d > %d)\n",
+                                nb, MAX_STATUS);
+                }
+                errno = EMBMDATA;
+                return -1;
         }
         }
 
 
         query_length = build_query_basis(mb_param, FC_FORCE_MULTIPLE_COILS,
         query_length = build_query_basis(mb_param, FC_FORCE_MULTIPLE_COILS,
@@ -1307,21 +1384,21 @@ int force_multiple_coils(modbus_param_t *mb_param, int start_addr, int nb,
                 query_length++;
                 query_length++;
         }
         }
 
 
-        ret = modbus_send(mb_param, query, query_length);
-        if (ret > 0) {
+        rc = modbus_send(mb_param, query, query_length);
+        if (rc > 0) {
                 uint8_t response[MAX_MESSAGE_LENGTH];
                 uint8_t response[MAX_MESSAGE_LENGTH];
-                ret = modbus_receive(mb_param, query, response);
+                rc = modbus_receive(mb_param, query, response);
         }
         }
 
 
 
 
-        return ret;
+        return rc;
 }
 }
 
 
 /* Copies the values in the slave from the array given in argument */
 /* Copies the values in the slave from the array given in argument */
 int preset_multiple_registers(modbus_param_t *mb_param, int start_addr, int nb,
 int preset_multiple_registers(modbus_param_t *mb_param, int start_addr, int nb,
                               const uint16_t *data_src)
                               const uint16_t *data_src)
 {
 {
-        int ret;
+        int rc;
         int i;
         int i;
         int query_length;
         int query_length;
         int byte_count;
         int byte_count;
@@ -1329,10 +1406,13 @@ int preset_multiple_registers(modbus_param_t *mb_param, int start_addr, int nb,
         uint8_t query[MAX_MESSAGE_LENGTH];
         uint8_t query[MAX_MESSAGE_LENGTH];
 
 
         if (nb > MAX_REGISTERS) {
         if (nb > MAX_REGISTERS) {
-                fprintf(stderr,
-                        "ERROR Trying to write to too many registers (%d > %d)\n",
-                        nb, MAX_REGISTERS);
-                return INVALID_DATA;
+                if (mb_param->debug) {
+                        fprintf(stderr,
+                                "ERROR Trying to write to too many registers (%d > %d)\n",
+                                nb, MAX_REGISTERS);
+                }
+                errno = EMBMDATA;
+                return -1;
         }
         }
 
 
         query_length = build_query_basis(mb_param, FC_PRESET_MULTIPLE_REGISTERS,
         query_length = build_query_basis(mb_param, FC_PRESET_MULTIPLE_REGISTERS,
@@ -1345,19 +1425,19 @@ int preset_multiple_registers(modbus_param_t *mb_param, int start_addr, int nb,
                 query[query_length++] = data_src[i] & 0x00FF;
                 query[query_length++] = data_src[i] & 0x00FF;
         }
         }
 
 
-        ret = modbus_send(mb_param, query, query_length);
-        if (ret > 0) {
+        rc = modbus_send(mb_param, query, query_length);
+        if (rc > 0) {
                 uint8_t response[MAX_MESSAGE_LENGTH];
                 uint8_t response[MAX_MESSAGE_LENGTH];
-                ret = modbus_receive(mb_param, query, response);
+                rc = modbus_receive(mb_param, query, response);
         }
         }
 
 
-        return ret;
+        return rc;
 }
 }
 
 
 /* Returns the slave id! */
 /* Returns the slave id! */
 int report_slave_id(modbus_param_t *mb_param, uint8_t *data_dest)
 int report_slave_id(modbus_param_t *mb_param, uint8_t *data_dest)
 {
 {
-        int ret;
+        int rc;
         int query_length;
         int query_length;
         uint8_t query[MIN_QUERY_LENGTH];
         uint8_t query[MIN_QUERY_LENGTH];
 
 
@@ -1366,8 +1446,8 @@ int report_slave_id(modbus_param_t *mb_param, uint8_t *data_dest)
         /* HACKISH, start_addr and count are not used */
         /* HACKISH, start_addr and count are not used */
         query_length -= 4;
         query_length -= 4;
 
 
-        ret = modbus_send(mb_param, query, query_length);
-        if (ret > 0) {
+        rc = modbus_send(mb_param, query, query_length);
+        if (rc > 0) {
                 int i;
                 int i;
                 int offset;
                 int offset;
                 int offset_end;
                 int offset_end;
@@ -1375,18 +1455,18 @@ int report_slave_id(modbus_param_t *mb_param, uint8_t *data_dest)
 
 
                 /* Byte count, slave id, run indicator status,
                 /* Byte count, slave id, run indicator status,
                    additional data */
                    additional data */
-                ret = modbus_receive(mb_param, query, response);
-                if (ret < 0)
-                        return ret;
+                rc = modbus_receive(mb_param, query, response);
+                if (rc == -1)
+                        return rc;
 
 
                 offset = TAB_HEADER_LENGTH[mb_param->type_com] - 1;
                 offset = TAB_HEADER_LENGTH[mb_param->type_com] - 1;
-                offset_end = offset + ret;
+                offset_end = offset + rc;
 
 
                 for (i = offset; i < offset_end; i++)
                 for (i = offset; i < offset_end; i++)
                         data_dest[i] = response[i];
                         data_dest[i] = response[i];
         }
         }
 
 
-        return ret;
+        return rc;
 }
 }
 
 
 /* Initializes the modbus_param_t structure for RTU
 /* Initializes the modbus_param_t structure for RTU
@@ -1408,7 +1488,7 @@ void modbus_init_rtu(modbus_param_t *mb_param, const char *device,
         mb_param->data_bit = data_bit;
         mb_param->data_bit = data_bit;
         mb_param->stop_bit = stop_bit;
         mb_param->stop_bit = stop_bit;
         mb_param->type_com = RTU;
         mb_param->type_com = RTU;
-        mb_param->error_handling = FLUSH_OR_CONNECT_ON_ERROR;
+        mb_param->error_recovery = FALSE;
         mb_param->slave = slave;
         mb_param->slave = slave;
 }
 }
 
 
@@ -1427,7 +1507,7 @@ void modbus_init_tcp(modbus_param_t *mb_param, const char *ip, int port, int sla
         strncpy(mb_param->ip, ip, sizeof(char)*16);
         strncpy(mb_param->ip, ip, sizeof(char)*16);
         mb_param->port = port;
         mb_param->port = port;
         mb_param->type_com = TCP;
         mb_param->type_com = TCP;
-        mb_param->error_handling = FLUSH_OR_CONNECT_ON_ERROR;
+        mb_param->error_recovery = FALSE;
         mb_param->slave = slave;
         mb_param->slave = slave;
 }
 }
 
 
@@ -1438,27 +1518,30 @@ void modbus_set_slave(modbus_param_t *mb_param, int slave)
         mb_param->slave = slave;
         mb_param->slave = slave;
 }
 }
 
 
-/* By default, the error handling mode used is FLUSH_OR_CONNECT_ON_ERROR.
+/*
+   When disabled (default), it is expected that the application will check for error
+   returns and deal with them as necessary. 
 
 
-   With FLUSH_OR_CONNECT_ON_ERROR, the library will attempt an immediate
-   reconnection which may hang for several seconds if the network to
-   the remote target unit is down.
+   It's not recommanded to enable error recovery for slave/server.
 
 
-   With NOP_ON_ERROR, it is expected that the application will
-   check for error returns and deal with them as necessary.
+   When enabled, the library will attempt an immediate reconnection which may
+   hang for several seconds if the network to the remote target unit is down.
+   The write will try a infinite close/connect loop until to be successful and
+   the select/read calls will just try to retablish the connection one time
+   then will return an error (if the connecton was down, the values to read are
+   certainly not available anymore after reconnection, except for slave/server).
 */
 */
-void modbus_set_error_handling(modbus_param_t *mb_param,
-                               error_handling_t error_handling)
+int modbus_set_error_recovery(modbus_param_t *mb_param, int enabled)
 {
 {
-        if (error_handling == FLUSH_OR_CONNECT_ON_ERROR ||
-            error_handling == NOP_ON_ERROR) {
-                mb_param->error_handling = error_handling;
+        if (enabled == TRUE || enabled == FALSE) {
+                mb_param->error_recovery = (uint8_t) enabled;
         } else {
         } else {
-                fprintf(stderr,
-                        "Invalid setting for error handling (not changed)\n");
+                errno = EINVAL;
+                return -1;
         }
         }
-}
 
 
+        return 0;
+}
 
 
 /* Sets up a serial port for RTU communications */
 /* Sets up a serial port for RTU communications */
 static int modbus_connect_rtu(modbus_param_t *mb_param)
 static int modbus_connect_rtu(modbus_param_t *mb_param)
@@ -1467,8 +1550,8 @@ static int modbus_connect_rtu(modbus_param_t *mb_param)
         speed_t speed;
         speed_t speed;
 
 
         if (mb_param->debug) {
         if (mb_param->debug) {
-                fprintf(stderr, "Opening %s at %d bauds (%s)\n",
-                        mb_param->device, mb_param->baud, mb_param->parity);
+                printf("Opening %s at %d bauds (%s)\n",
+                       mb_param->device, mb_param->baud, mb_param->parity);
         }
         }
 
 
         /* The O_NOCTTY flag tells UNIX that this program doesn't want
         /* The O_NOCTTY flag tells UNIX that this program doesn't want
@@ -1479,7 +1562,7 @@ static int modbus_connect_rtu(modbus_param_t *mb_param)
            Timeouts are ignored in canonical input mode or when the
            Timeouts are ignored in canonical input mode or when the
            NDELAY option is set on the file via open or fcntl */
            NDELAY option is set on the file via open or fcntl */
         mb_param->fd = open(mb_param->device, O_RDWR | O_NOCTTY | O_NDELAY | O_EXCL);
         mb_param->fd = open(mb_param->device, O_RDWR | O_NOCTTY | O_NDELAY | O_EXCL);
-        if (mb_param->fd < 0) {
+        if (mb_param->fd == -1) {
                 fprintf(stderr, "ERROR Can't open the device %s (%s)\n",
                 fprintf(stderr, "ERROR Can't open the device %s (%s)\n",
                         mb_param->device, strerror(errno));
                         mb_param->device, strerror(errno));
                 return -1;
                 return -1;
@@ -1529,15 +1612,16 @@ static int modbus_connect_rtu(modbus_param_t *mb_param)
                 break;
                 break;
         default:
         default:
                 speed = B9600;
                 speed = B9600;
-                fprintf(stderr,
-                        "WARNING Unknown baud rate %d for %s (B9600 used)\n",
-                        mb_param->baud, mb_param->device);
+                if (mb_param->debug) {
+                        fprintf(stderr,
+                                "WARNING Unknown baud rate %d for %s (B9600 used)\n",
+                                mb_param->baud, mb_param->device);
+                }
         }
         }
 
 
         /* Set the baud rate */
         /* Set the baud rate */
         if ((cfsetispeed(&tios, speed) < 0) ||
         if ((cfsetispeed(&tios, speed) < 0) ||
             (cfsetospeed(&tios, speed) < 0)) {
             (cfsetospeed(&tios, speed) < 0)) {
-                perror("cfsetispeed/cfsetospeed\n");
                 return -1;
                 return -1;
         }
         }
 
 
@@ -1707,7 +1791,6 @@ static int modbus_connect_rtu(modbus_param_t *mb_param)
         tios.c_cc[VTIME] = 0;
         tios.c_cc[VTIME] = 0;
 
 
         if (tcsetattr(mb_param->fd, TCSANOW, &tios) < 0) {
         if (tcsetattr(mb_param->fd, TCSANOW, &tios) < 0) {
-                perror("tcsetattr\n");
                 return -1;
                 return -1;
         }
         }
 
 
@@ -1717,24 +1800,23 @@ static int modbus_connect_rtu(modbus_param_t *mb_param)
 /* Establishes a modbus TCP connection with a modbus slave */
 /* Establishes a modbus TCP connection with a modbus slave */
 static int modbus_connect_tcp(modbus_param_t *mb_param)
 static int modbus_connect_tcp(modbus_param_t *mb_param)
 {
 {
-        int ret;
+        int rc;
         int option;
         int option;
         struct sockaddr_in addr;
         struct sockaddr_in addr;
 
 
         mb_param->fd = socket(PF_INET, SOCK_STREAM, 0);
         mb_param->fd = socket(PF_INET, SOCK_STREAM, 0);
-        if (mb_param->fd < 0) {
-                return mb_param->fd;
+        if (mb_param->fd == -1) {
+                return -1;
         }
         }
 
 
         /* Set the TCP no delay flag */
         /* Set the TCP no delay flag */
         /* SOL_TCP = IPPROTO_TCP */
         /* SOL_TCP = IPPROTO_TCP */
         option = 1;
         option = 1;
-        ret = setsockopt(mb_param->fd, IPPROTO_TCP, TCP_NODELAY,
+        rc = setsockopt(mb_param->fd, IPPROTO_TCP, TCP_NODELAY,
                          (const void *)&option, sizeof(int));
                          (const void *)&option, sizeof(int));
-        if (ret < 0) {
-                perror("setsockopt TCP_NODELAY");
+        if (rc == -1) {
                 close(mb_param->fd);
                 close(mb_param->fd);
-                return ret;
+                return -1;
         }
         }
 
 
 #if (!HAVE_DECL___CYGWIN__)
 #if (!HAVE_DECL___CYGWIN__)
@@ -1744,12 +1826,11 @@ static int modbus_connect_tcp(modbus_param_t *mb_param)
          **/
          **/
         /* Set the IP low delay option */
         /* Set the IP low delay option */
         option = IPTOS_LOWDELAY;
         option = IPTOS_LOWDELAY;
-        ret = setsockopt(mb_param->fd, IPPROTO_IP, IP_TOS,
+        rc = setsockopt(mb_param->fd, IPPROTO_IP, IP_TOS,
                          (const void *)&option, sizeof(int));
                          (const void *)&option, sizeof(int));
-        if (ret < 0) {
-                perror("setsockopt IP_TOS");
+        if (rc == -1) {
                 close(mb_param->fd);
                 close(mb_param->fd);
-                return ret;
+                return -1;
         }
         }
 #endif
 #endif
 
 
@@ -1760,12 +1841,11 @@ static int modbus_connect_tcp(modbus_param_t *mb_param)
         addr.sin_family = AF_INET;
         addr.sin_family = AF_INET;
         addr.sin_port = htons(mb_param->port);
         addr.sin_port = htons(mb_param->port);
         addr.sin_addr.s_addr = inet_addr(mb_param->ip);
         addr.sin_addr.s_addr = inet_addr(mb_param->ip);
-        ret = connect(mb_param->fd, (struct sockaddr *)&addr,
+        rc = connect(mb_param->fd, (struct sockaddr *)&addr,
                       sizeof(struct sockaddr_in));
                       sizeof(struct sockaddr_in));
-        if (ret < 0) {
-                perror("connect");
+        if (rc == -1) {
                 close(mb_param->fd);
                 close(mb_param->fd);
-                return ret;
+                return -1;
         }
         }
 
 
         return 0;
         return 0;
@@ -1775,22 +1855,20 @@ static int modbus_connect_tcp(modbus_param_t *mb_param)
    Returns 0 on success or -1 on failure. */
    Returns 0 on success or -1 on failure. */
 int modbus_connect(modbus_param_t *mb_param)
 int modbus_connect(modbus_param_t *mb_param)
 {
 {
-        int ret;
+        int rc;
 
 
         if (mb_param->type_com == RTU)
         if (mb_param->type_com == RTU)
-                ret = modbus_connect_rtu(mb_param);
+                rc = modbus_connect_rtu(mb_param);
         else
         else
-                ret = modbus_connect_tcp(mb_param);
+                rc = modbus_connect_tcp(mb_param);
 
 
-        return ret;
+        return rc;
 }
 }
 
 
 /* Closes the file descriptor in RTU mode */
 /* Closes the file descriptor in RTU mode */
 static void modbus_close_rtu(modbus_param_t *mb_param)
 static void modbus_close_rtu(modbus_param_t *mb_param)
 {
 {
-        if (tcsetattr(mb_param->fd, TCSANOW, &(mb_param->old_tios)) < 0)
-                perror("tcsetattr");
-
+        tcsetattr(mb_param->fd, TCSANOW, &(mb_param->old_tios));
         close(mb_param->fd);
         close(mb_param->fd);
 }
 }
 
 
@@ -1819,7 +1897,8 @@ void modbus_set_debug(modbus_param_t *mb_param, int boolean)
 /* Allocates 4 arrays to store coils, input status, input registers and
 /* Allocates 4 arrays to store coils, input status, input registers and
    holding registers. The pointers are stored in modbus_mapping structure.
    holding registers. The pointers are stored in modbus_mapping structure.
 
 
-   Returns 0 on success and -1 on failure.
+   The modbus_mapping_new() function shall return 0 if successful. Otherwise it
+   shall return -1 and set errno to ENOMEM.
 */
 */
 int modbus_mapping_new(modbus_mapping_t *mb_mapping,
 int modbus_mapping_new(modbus_mapping_t *mb_mapping,
                        int nb_coil_status, int nb_input_status,
                        int nb_coil_status, int nb_input_status,
@@ -1829,46 +1908,51 @@ int modbus_mapping_new(modbus_mapping_t *mb_mapping,
         mb_mapping->nb_coil_status = nb_coil_status;
         mb_mapping->nb_coil_status = nb_coil_status;
         mb_mapping->tab_coil_status =
         mb_mapping->tab_coil_status =
                 (uint8_t *) malloc(nb_coil_status * sizeof(uint8_t));
                 (uint8_t *) malloc(nb_coil_status * sizeof(uint8_t));
+        if (mb_mapping->tab_coil_status == NULL) {
+                errno = ENOMEM;
+                return -1;
+        }
         memset(mb_mapping->tab_coil_status, 0,
         memset(mb_mapping->tab_coil_status, 0,
                nb_coil_status * sizeof(uint8_t));
                nb_coil_status * sizeof(uint8_t));
-        if (mb_mapping->tab_coil_status == NULL)
-                return -1;
 
 
         /* 1X */
         /* 1X */
         mb_mapping->nb_input_status = nb_input_status;
         mb_mapping->nb_input_status = nb_input_status;
         mb_mapping->tab_input_status =
         mb_mapping->tab_input_status =
                 (uint8_t *) malloc(nb_input_status * sizeof(uint8_t));
                 (uint8_t *) malloc(nb_input_status * sizeof(uint8_t));
-        memset(mb_mapping->tab_input_status, 0,
-               nb_input_status * sizeof(uint8_t));
         if (mb_mapping->tab_input_status == NULL) {
         if (mb_mapping->tab_input_status == NULL) {
                 free(mb_mapping->tab_coil_status);
                 free(mb_mapping->tab_coil_status);
+                errno = ENOMEM;
                 return -1;
                 return -1;
         }
         }
+        memset(mb_mapping->tab_input_status, 0,
+               nb_input_status * sizeof(uint8_t));
 
 
         /* 4X */
         /* 4X */
         mb_mapping->nb_holding_registers = nb_holding_registers;
         mb_mapping->nb_holding_registers = nb_holding_registers;
         mb_mapping->tab_holding_registers =
         mb_mapping->tab_holding_registers =
                 (uint16_t *) malloc(nb_holding_registers * sizeof(uint16_t));
                 (uint16_t *) malloc(nb_holding_registers * sizeof(uint16_t));
-        memset(mb_mapping->tab_holding_registers, 0,
-               nb_holding_registers * sizeof(uint16_t));
         if (mb_mapping->tab_holding_registers == NULL) {
         if (mb_mapping->tab_holding_registers == NULL) {
                 free(mb_mapping->tab_coil_status);
                 free(mb_mapping->tab_coil_status);
                 free(mb_mapping->tab_input_status);
                 free(mb_mapping->tab_input_status);
+                errno = ENOMEM;
                 return -1;
                 return -1;
         }
         }
+        memset(mb_mapping->tab_holding_registers, 0,
+               nb_holding_registers * sizeof(uint16_t));
 
 
         /* 3X */
         /* 3X */
         mb_mapping->nb_input_registers = nb_input_registers;
         mb_mapping->nb_input_registers = nb_input_registers;
         mb_mapping->tab_input_registers =
         mb_mapping->tab_input_registers =
                 (uint16_t *) malloc(nb_input_registers * sizeof(uint16_t));
                 (uint16_t *) malloc(nb_input_registers * sizeof(uint16_t));
-        memset(mb_mapping->tab_input_registers, 0,
-               nb_input_registers * sizeof(uint16_t));
         if (mb_mapping->tab_input_registers == NULL) {
         if (mb_mapping->tab_input_registers == NULL) {
                 free(mb_mapping->tab_coil_status);
                 free(mb_mapping->tab_coil_status);
                 free(mb_mapping->tab_input_status);
                 free(mb_mapping->tab_input_status);
                 free(mb_mapping->tab_holding_registers);
                 free(mb_mapping->tab_holding_registers);
+                errno = ENOMEM;
                 return -1;
                 return -1;
         }
         }
+        memset(mb_mapping->tab_input_registers, 0,
+               nb_input_registers * sizeof(uint16_t));
 
 
         return 0;
         return 0;
 }
 }
@@ -1890,15 +1974,13 @@ int modbus_slave_listen_tcp(modbus_param_t *mb_param, int nb_connection)
         struct sockaddr_in addr;
         struct sockaddr_in addr;
 
 
         new_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
         new_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
-        if (new_socket < 0) {
-                perror("socket");
+        if (new_socket == -1) {
                 return -1;
                 return -1;
         }
         }
 
 
         yes = 1;
         yes = 1;
         if (setsockopt(new_socket, SOL_SOCKET, SO_REUSEADDR,
         if (setsockopt(new_socket, SOL_SOCKET, SO_REUSEADDR,
-                       (char *) &yes, sizeof(yes)) < 0) {
-                perror("setsockopt");
+                       (char *) &yes, sizeof(yes)) == -1) {
                 close(new_socket);
                 close(new_socket);
                 return -1;
                 return -1;
         }
         }
@@ -1908,14 +1990,12 @@ int modbus_slave_listen_tcp(modbus_param_t *mb_param, int nb_connection)
         /* If the modbus port is < to 1024, we need the setuid root. */
         /* If the modbus port is < to 1024, we need the setuid root. */
         addr.sin_port = htons(mb_param->port);
         addr.sin_port = htons(mb_param->port);
         addr.sin_addr.s_addr = INADDR_ANY;
         addr.sin_addr.s_addr = INADDR_ANY;
-        if (bind(new_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
-                perror("bind");
+        if (bind(new_socket, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
                 close(new_socket);
                 close(new_socket);
                 return -1;
                 return -1;
         }
         }
 
 
-        if (listen(new_socket, nb_connection) < 0) {
-                perror("listen");
+        if (listen(new_socket, nb_connection) == -1) {
                 close(new_socket);
                 close(new_socket);
                 return -1;
                 return -1;
         }
         }
@@ -1923,6 +2003,9 @@ int modbus_slave_listen_tcp(modbus_param_t *mb_param, int nb_connection)
         return new_socket;
         return new_socket;
 }
 }
 
 
+/* On success, the function return a non-negative integer that is a descriptor
+   for the accepted socket. On error, -1 is returned, and errno is set
+   appropriately. */
 int modbus_slave_accept_tcp(modbus_param_t *mb_param, int *socket)
 int modbus_slave_accept_tcp(modbus_param_t *mb_param, int *socket)
 {
 {
         struct sockaddr_in addr;
         struct sockaddr_in addr;
@@ -1930,11 +2013,13 @@ int modbus_slave_accept_tcp(modbus_param_t *mb_param, int *socket)
 
 
         addrlen = sizeof(struct sockaddr_in);
         addrlen = sizeof(struct sockaddr_in);
         mb_param->fd = accept(*socket, (struct sockaddr *)&addr, &addrlen);
         mb_param->fd = accept(*socket, (struct sockaddr *)&addr, &addrlen);
-        if (mb_param->fd < 0) {
-                perror("accept");
+        if (mb_param->fd == -1) {
                 close(*socket);
                 close(*socket);
                 *socket = 0;
                 *socket = 0;
-        } else {
+                return -1;
+        }
+
+        if (mb_param->debug) {
                 printf("The client %s is connected\n",
                 printf("The client %s is connected\n",
                        inet_ntoa(addr.sin_addr));
                        inet_ntoa(addr.sin_addr));
         }
         }
@@ -1964,7 +2049,7 @@ void set_bits_from_byte(uint8_t *dest, int address, const uint8_t value)
 
 
 /* Sets many input/coil status from a table of bytes (only the bits
 /* Sets many input/coil status from a table of bytes (only the bits
    between address and address + nb_bits are set) */
    between address and address + nb_bits are set) */
-void set_bits_from_bytes(uint8_t *dest, int address, int nb_bits,
+void set_bits_from_bytes(uint8_t *dest, int address, unsigned int nb_bits,
                          const uint8_t tab_byte[])
                          const uint8_t tab_byte[])
 {
 {
         int i;
         int i;
@@ -1980,13 +2065,13 @@ void set_bits_from_bytes(uint8_t *dest, int address, int nb_bits,
 
 
 /* Gets the byte value from many input/coil status.
 /* Gets the byte value from many input/coil status.
    To obtain a full byte, set nb_bits to 8. */
    To obtain a full byte, set nb_bits to 8. */
-uint8_t get_byte_from_bits(const uint8_t *src, int address, int nb_bits)
+uint8_t get_byte_from_bits(const uint8_t *src, int address, unsigned int nb_bits)
 {
 {
         int i;
         int i;
         uint8_t value = 0;
         uint8_t value = 0;
 
 
         if (nb_bits > 8) {
         if (nb_bits > 8) {
-                fprintf(stderr, "ERROR nb_bits is too big\n");
+                assert(nb_bits < 8);
                 nb_bits = 8;
                 nb_bits = 8;
         }
         }
 
 

+ 54 - 154
modbus/modbus.h

@@ -120,36 +120,47 @@ extern "C" {
 #define FC_PRESET_MULTIPLE_REGISTERS 0x10
 #define FC_PRESET_MULTIPLE_REGISTERS 0x10
 #define FC_REPORT_SLAVE_ID           0x11
 #define FC_REPORT_SLAVE_ID           0x11
 
 
+/* Random number to avoid errno conflicts */
+#define MODBUS_ENOBASE 112345678
+
 /* Protocol exceptions */
 /* Protocol exceptions */
-#define ILLEGAL_FUNCTION        -0x01
-#define ILLEGAL_DATA_ADDRESS    -0x02
-#define ILLEGAL_DATA_VALUE      -0x03
-#define SLAVE_DEVICE_FAILURE    -0x04
-#define SERVER_FAILURE          -0x04
-#define ACKNOWLEDGE             -0x05
-#define SLAVE_DEVICE_BUSY       -0x06
-#define SERVER_BUSY             -0x06
-#define NEGATIVE_ACKNOWLEDGE    -0x07
-#define MEMORY_PARITY_ERROR     -0x08
-#define GATEWAY_PROBLEM_PATH    -0x0A
-#define GATEWAY_PROBLEM_TARGET  -0x0B
-
-/* Local */
-#define INVALID_DATA            -0x10
-#define INVALID_CRC             -0x11
-#define INVALID_EXCEPTION_CODE  -0x12
-
-#define SELECT_TIMEOUT          -0x13
-#define SELECT_FAILURE          -0x14
-#define SOCKET_FAILURE          -0x15
-#define CONNECTION_CLOSED       -0x16
-#define MB_EXCEPTION             -0x17
+enum {
+        MODBUS_EXCEPTION_ILLEGAL_FUNCTION = 0x01,
+        MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS,
+        MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,
+        MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE,
+        MODBUS_EXCEPTION_ACKNOWLEDGE,
+        MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY,
+        MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE,
+        MODBUS_EXCEPTION_MEMORY_PARITY,
+        MODBUS_EXCEPTION_NOT_DEFINED,
+        MODBUS_EXCEPTION_GATEWAY_PATH,
+        MODBUS_EXCEPTION_GATEWAY_TARGET,
+        MODBUS_EXCEPTION_MAX
+};
+
+#define EMBXILFUN  (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_FUNCTION)
+#define EMBXILADD  (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS)
+#define EMBXILVAL  (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE)
+#define EMBXSFAIL  (MODBUS_ENOBASE + MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE)
+#define EMBXACK    (MODBUS_ENOBASE + MODBUS_EXCEPTION_ACKNOWLEDGE)
+#define EMBXSBUSY  (MODBUS_ENOBASE + MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY)
+#define EMBXNACK   (MODBUS_ENOBASE + MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE)
+#define EMBXMEMPAR (MODBUS_ENOBASE + MODBUS_EXCEPTION_MEMORY_PARITY)
+#define EMBXGPATH  (MODBUS_ENOBASE + MODBUS_EXCEPTION_GATEWAY_PATH)
+#define EMBXGTAR   (MODBUS_ENOBASE + MODBUS_EXCEPTION_GATEWAY_TARGET)
+
+/* Native libmodbus error codes */
+#define EMBBADCRC  (EMBXGTAR + 1)
+#define EMBBADDATA (EMBXGTAR + 2)
+#define EMBBADEXC  (EMBXGTAR + 3)
+#define EMBUNKEXC  (EMBXGTAR + 4)
+#define EMBMDATA   (EMBXGTAR + 5)
 
 
 /* Internal using */
 /* Internal using */
 #define MSG_LENGTH_UNDEFINED -1
 #define MSG_LENGTH_UNDEFINED -1
 
 
 typedef enum { RTU=0, TCP } type_com_t;
 typedef enum { RTU=0, TCP } type_com_t;
-typedef enum { FLUSH_OR_CONNECT_ON_ERROR, NOP_ON_ERROR } error_handling_t;
 
 
 /* This structure is byte-aligned */
 /* This structure is byte-aligned */
 typedef struct {
 typedef struct {
@@ -183,7 +194,7 @@ typedef struct {
         /* Parity: "even", "odd", "none" */
         /* Parity: "even", "odd", "none" */
         char parity[5];
         char parity[5];
         /* In error_treat with TCP, do a reconnect or just dump the error */
         /* In error_treat with TCP, do a reconnect or just dump the error */
-        uint8_t error_handling;
+        uint8_t error_recovery;
         /* IP address */
         /* IP address */
         char ip[16];
         char ip[16];
         /* Save old termios settings */
         /* Save old termios settings */
@@ -201,171 +212,60 @@ typedef struct {
         uint16_t *tab_holding_registers;
         uint16_t *tab_holding_registers;
 } modbus_mapping_t;
 } modbus_mapping_t;
 
 
+void modbus_init_rtu(modbus_param_t *mb_param, const char *device,
+                     int baud, const char *parity, int data_bit,
+                     int stop_bit, int slave);
+void modbus_init_tcp(modbus_param_t *mb_param, const char *ip_address, int port,
+                     int slave);
+void modbus_set_slave(modbus_param_t *mb_param, int slave);
+int modbus_set_error_recovery(modbus_param_t *mb_param, int enabled);
 
 
-/* All functions used for sending or receiving data return:
-   - the numbers of values (bits or word) if success (0 or more)
-   - less than 0 for exceptions errors
-*/
+int modbus_connect(modbus_param_t *mb_param);
+void modbus_close(modbus_param_t *mb_param);
+
+int modbus_flush(modbus_param_t *mb_param);
+void modbus_set_debug(modbus_param_t *mb_param, int boolean);
+
+const char *modbus_strerror(int errnum);
 
 
-/* Reads the boolean status of coils and sets the array elements in
-   the destination to TRUE or FALSE */
 int read_coil_status(modbus_param_t *mb_param, int start_addr, int nb,
 int read_coil_status(modbus_param_t *mb_param, int start_addr, int nb,
                      uint8_t *dest);
                      uint8_t *dest);
-
-/* Same as read_coil_status but reads the slaves input table */
 int read_input_status(modbus_param_t *mb_param, int start_addr, int nb,
 int read_input_status(modbus_param_t *mb_param, int start_addr, int nb,
                       uint8_t *dest);
                       uint8_t *dest);
-
-/* Reads the holding registers in a slave and put the data into an
-   array */
 int read_holding_registers(modbus_param_t *mb_param, int start_addr, int nb,
 int read_holding_registers(modbus_param_t *mb_param, int start_addr, int nb,
                            uint16_t *dest);
                            uint16_t *dest);
-
-/* Reads the input registers in a slave and put the data into an
-   array */
 int read_input_registers(modbus_param_t *mb_param, int start_addr, int nb,
 int read_input_registers(modbus_param_t *mb_param, int start_addr, int nb,
                          uint16_t *dest);
                          uint16_t *dest);
-
-/* Turns ON or OFF a single coil in the slave device */
 int force_single_coil(modbus_param_t *mb_param, int coil_addr, int state);
 int force_single_coil(modbus_param_t *mb_param, int coil_addr, int state);
 
 
-/* Sets a value in one holding register in the slave device */
 int preset_single_register(modbus_param_t *mb_param, int reg_addr, int value);
 int preset_single_register(modbus_param_t *mb_param, int reg_addr, int value);
-
-/* Sets/resets the coils in the slave from an array in argument */
 int force_multiple_coils(modbus_param_t *mb_param, int start_addr, int nb,
 int force_multiple_coils(modbus_param_t *mb_param, int start_addr, int nb,
                          const uint8_t *data);
                          const uint8_t *data);
-
-/* Copies the values in the slave from the array given in argument */
 int preset_multiple_registers(modbus_param_t *mb_param, int start_addr, int nb,
 int preset_multiple_registers(modbus_param_t *mb_param, int start_addr, int nb,
                               const uint16_t *data);
                               const uint16_t *data);
-
-/* Returns the slave id! */
 int report_slave_id(modbus_param_t *mb_param, uint8_t *dest);
 int report_slave_id(modbus_param_t *mb_param, uint8_t *dest);
 
 
-/* Initializes the modbus_param_t structure for RTU.
-   - device: "/dev/ttyS0"
-   - baud:   9600, 19200, 57600, 115200, etc
-   - parity: "even", "odd" or "none"
-   - data_bits: 5, 6, 7, 8
-   - stop_bits: 1, 2
-*/
-void modbus_init_rtu(modbus_param_t *mb_param, const char *device,
-                     int baud, const char *parity, int data_bit,
-                     int stop_bit, int slave);
-
-/* Initializes the modbus_param_t structure for TCP.
-   - ip: "192.168.0.5"
-   - port: 1099
-   - slave: 5
-
-   Set the port to MODBUS_TCP_DEFAULT_PORT to use the default one
-   (502). It's convenient to use a port number greater than or equal
-   to 1024 because it's not necessary to be root to use this port
-   number.
-*/
-void modbus_init_tcp(modbus_param_t *mb_param, const char *ip_address, int port,
-                     int slave);
-
-/* Define the slave number.
-   The special value MODBUS_BROADCAST_ADDRESS can be used. */
-void modbus_set_slave(modbus_param_t *mb_param, int slave);
-
-/* By default, the error handling mode used is CONNECT_ON_ERROR.
-
-   With FLUSH_OR_CONNECT_ON_ERROR, the library will attempt an immediate
-   reconnection which may hang for several seconds if the network to
-   the remote target unit is down.
-
-   With NOP_ON_ERROR, it is expected that the application will
-   check for network error returns and deal with them as necessary.
-
-   This function is only useful in TCP mode.
- */
-void modbus_set_error_handling(modbus_param_t *mb_param, error_handling_t error_handling);
-
-/* Establishes a modbus connexion.
-   Returns 0 on success or -1 on failure. */
-int modbus_connect(modbus_param_t *mb_param);
-
-/* Closes a modbus connection */
-void modbus_close(modbus_param_t *mb_param);
-
-/* Flush the pending request */
-void modbus_flush(modbus_param_t *mb_param);
-
-/* Activates the debug messages */
-void modbus_set_debug(modbus_param_t *mb_param, int boolean);
-
-/**
- * SLAVE/CLIENT FUNCTIONS
- **/
-
-/* Allocates 4 arrays to store coils, input status, input registers and
-   holding registers. The pointers are stored in modbus_mapping structure.
-
-   Returns 0 on success and -1 on failure
- */
 int modbus_mapping_new(modbus_mapping_t *mb_mapping,
 int modbus_mapping_new(modbus_mapping_t *mb_mapping,
                        int nb_coil_status, int nb_input_status,
                        int nb_coil_status, int nb_input_status,
                        int nb_holding_registers, int nb_input_registers);
                        int nb_holding_registers, int nb_input_registers);
-
-/* Frees the 4 arrays */
 void modbus_mapping_free(modbus_mapping_t *mb_mapping);
 void modbus_mapping_free(modbus_mapping_t *mb_mapping);
 
 
-/* Listens for any query from one or many modbus masters in TCP.
-
-   Returns: socket
- */
 int modbus_slave_listen_tcp(modbus_param_t *mb_param, int nb_connection);
 int modbus_slave_listen_tcp(modbus_param_t *mb_param, int nb_connection);
-
-/* Waits for a connection */
 int modbus_slave_accept_tcp(modbus_param_t *mb_param, int *socket);
 int modbus_slave_accept_tcp(modbus_param_t *mb_param, int *socket);
-
-/* Listens for any query from a modbus master in TCP, requires the socket file
-   descriptor etablished with the master device in argument or -1 to use the
-   internal one of modbus_param_t.
-
-   Returns:
-   - byte length of the message on success, or a negative error number if the
-     request fails
-   - query, message received
-*/
 int modbus_slave_receive(modbus_param_t *mb_param, int sockfd, uint8_t *query);
 int modbus_slave_receive(modbus_param_t *mb_param, int sockfd, uint8_t *query);
-
-/* Manages the received query.
-   Analyses the query and constructs a response.
-
-   If an error occurs, this function construct the response
-   accordingly.
-*/
-void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query,
-                         int query_length, modbus_mapping_t *mb_mapping);
-
-/* Closes a TCP socket */
+int modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query,
+                        int query_length, modbus_mapping_t *mb_mapping);
 void modbus_slave_close_tcp(int socket);
 void modbus_slave_close_tcp(int socket);
 
 
 /**
 /**
  * UTILS FUNCTIONS
  * UTILS FUNCTIONS
  **/
  **/
 
 
-/* Sets many input/coil status from a single byte value (all 8 bits of
-   the byte value are set) */
 void set_bits_from_byte(uint8_t *dest, int address, const uint8_t value);
 void set_bits_from_byte(uint8_t *dest, int address, const uint8_t value);
-
-/* Sets many input/coil status from a table of bytes (only the bits
-   between address and address + nb_bits are set) */
-void set_bits_from_bytes(uint8_t *dest, int address, int nb_bits,
+void set_bits_from_bytes(uint8_t *dest, int address, unsigned int nb_bits,
                          const uint8_t *tab_byte);
                          const uint8_t *tab_byte);
-
-/* Gets the byte value from many input/coil status.
-   To obtain a full byte, set nb_bits to 8. */
-uint8_t get_byte_from_bits(const uint8_t *src, int address, int nb_bits);
-
-/* Read a float from 4 bytes in Modbus format */
+uint8_t get_byte_from_bits(const uint8_t *src, int address, unsigned int nb_bits);
 float modbus_read_float(const uint16_t *src);
 float modbus_read_float(const uint16_t *src);
-
-/* Write a float to 4 bytes in Modbus format */
 void modbus_write_float(float real, uint16_t *dest);
 void modbus_write_float(float real, uint16_t *dest);
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus

+ 17 - 5
tests/bandwidth-master.c

@@ -21,6 +21,7 @@
 #include <stdlib.h>
 #include <stdlib.h>
 #include <time.h>
 #include <time.h>
 #include <sys/time.h>
 #include <sys/time.h>
+#include <errno.h>
 
 
 #include <modbus/modbus.h>
 #include <modbus/modbus.h>
 
 
@@ -44,18 +45,21 @@ int main(void)
         uint16_t *tab_rp_registers;
         uint16_t *tab_rp_registers;
         modbus_param_t mb_param;
         modbus_param_t mb_param;
         int i;
         int i;
-        int ret;
         int nb_points;
         int nb_points;
         double elapsed;
         double elapsed;
         uint32_t start;
         uint32_t start;
         uint32_t end;
         uint32_t end;
         uint32_t bytes;
         uint32_t bytes;
         uint32_t rate;
         uint32_t rate;
+        int rc;
 
 
         /* TCP */
         /* TCP */
         modbus_init_tcp(&mb_param, "127.0.0.1", 1502, SLAVE);
         modbus_init_tcp(&mb_param, "127.0.0.1", 1502, SLAVE);
-        if (modbus_connect(&mb_param) == -1) {
-                exit(1);
+        rc = modbus_connect(&mb_param);
+        if (rc == -1) {
+                fprintf(stderr, "Connexion failed: %s\n",
+                        modbus_strerror(errno));
+                return -1;
         }
         }
 
 
         /* Allocate and initialize the memory to store the status */
         /* Allocate and initialize the memory to store the status */
@@ -71,7 +75,11 @@ int main(void)
         nb_points = MAX_STATUS;
         nb_points = MAX_STATUS;
         start = gettime_ms();
         start = gettime_ms();
         for (i=0; i<NB_LOOPS; i++) {
         for (i=0; i<NB_LOOPS; i++) {
-                ret = read_coil_status(&mb_param, 0, nb_points, tab_rp_status);
+                rc = read_coil_status(&mb_param, 0, nb_points, tab_rp_status);
+                if (rc == -1) {
+                        fprintf(stderr, modbus_strerror(errno));
+                        return -1;
+                }
         }
         }
         end = gettime_ms();
         end = gettime_ms();
         elapsed = end - start;
         elapsed = end - start;
@@ -104,7 +112,11 @@ int main(void)
         nb_points = MAX_REGISTERS;
         nb_points = MAX_REGISTERS;
         start = gettime_ms();
         start = gettime_ms();
         for (i=0; i<NB_LOOPS; i++) {
         for (i=0; i<NB_LOOPS; i++) {
-                ret = read_holding_registers(&mb_param, 0, nb_points, tab_rp_registers);
+                rc = read_holding_registers(&mb_param, 0, nb_points, tab_rp_registers);
+                if (rc == -1) {
+                        fprintf(stderr, modbus_strerror(errno));
+                        return -1;
+                }
         }
         }
         end = gettime_ms();
         end = gettime_ms();
         elapsed = end - start;
         elapsed = end - start;

+ 9 - 8
tests/bandwidth-slave-many-up.c

@@ -42,7 +42,7 @@ int main(void)
 {
 {
         int master_socket;
         int master_socket;
         modbus_param_t mb_param;
         modbus_param_t mb_param;
-        int ret;
+        int rc;
         fd_set refset;
         fd_set refset;
         fd_set rdset;
         fd_set rdset;
 
 
@@ -51,10 +51,11 @@ int main(void)
 
 
         modbus_init_tcp(&mb_param, "127.0.0.1", 1502, SLAVE);
         modbus_init_tcp(&mb_param, "127.0.0.1", 1502, SLAVE);
 
 
-        ret = modbus_mapping_new(&mb_mapping,  MAX_STATUS, 0, MAX_REGISTERS, 0);
-        if (ret < 0) {
-                fprintf(stderr, "Memory allocation failure\n");
-                exit(1);
+        rc = modbus_mapping_new(&mb_mapping,  MAX_STATUS, 0, MAX_REGISTERS, 0);
+        if (rc == -1) {
+                fprintf(stderr, "Failed to allocate the mapping: %s\n",
+                        modbus_strerror(errno));
+                return -1;
         }
         }
 
 
         slave_socket = modbus_slave_listen_tcp(&mb_param, NB_CONNECTION);
         slave_socket = modbus_slave_listen_tcp(&mb_param, NB_CONNECTION);
@@ -107,9 +108,9 @@ int main(void)
                                         /* An already connected master has sent a new query */
                                         /* An already connected master has sent a new query */
                                         uint8_t query[MAX_MESSAGE_LENGTH];
                                         uint8_t query[MAX_MESSAGE_LENGTH];
 
 
-                                        ret = modbus_slave_receive(&mb_param, master_socket, query);
-                                        if (ret >= 0) {
-                                                modbus_slave_manage(&mb_param, query, ret, &mb_mapping);
+                                        rc = modbus_slave_receive(&mb_param, master_socket, query);
+                                        if (rc != -1) {
+                                                modbus_slave_manage(&mb_param, query, rc, &mb_mapping);
                                         } else {
                                         } else {
                                                 /* Connection closed by the client, end of server */
                                                 /* Connection closed by the client, end of server */
                                                 printf("Connection closed on socket %d\n", master_socket);
                                                 printf("Connection closed on socket %d\n", master_socket);

+ 15 - 13
tests/bandwidth-slave-one.c

@@ -19,6 +19,7 @@
 #include <unistd.h>
 #include <unistd.h>
 #include <string.h>
 #include <string.h>
 #include <stdlib.h>
 #include <stdlib.h>
+#include <errno.h>
 
 
 #include <modbus/modbus.h>
 #include <modbus/modbus.h>
 
 
@@ -29,33 +30,34 @@ int main(void)
         int socket;
         int socket;
         modbus_param_t mb_param;
         modbus_param_t mb_param;
         modbus_mapping_t mb_mapping;
         modbus_mapping_t mb_mapping;
-        int ret;
+        int rc;
 
 
         modbus_init_tcp(&mb_param, "127.0.0.1", 1502, SLAVE);
         modbus_init_tcp(&mb_param, "127.0.0.1", 1502, SLAVE);
 
 
-        ret = modbus_mapping_new(&mb_mapping,  MAX_STATUS, 0, MAX_REGISTERS, 0);
-        if (ret < 0) {
-                fprintf(stderr, "Memory allocation failed\n");
-                exit(1);
+        rc = modbus_mapping_new(&mb_mapping,  MAX_STATUS, 0, MAX_REGISTERS, 0);
+        if (rc == -1) {
+                fprintf(stderr, "Failed to allocate the mapping: %s\n",
+                        modbus_strerror(errno));
+                return -1;
         }
         }
 
 
         socket = modbus_slave_listen_tcp(&mb_param, 1);
         socket = modbus_slave_listen_tcp(&mb_param, 1);
         modbus_slave_accept_tcp(&mb_param, &socket);
         modbus_slave_accept_tcp(&mb_param, &socket);
 
 
-        while (1) {
+        for(;;) {
                 uint8_t query[MAX_MESSAGE_LENGTH];
                 uint8_t query[MAX_MESSAGE_LENGTH];
 
 
-                ret = modbus_slave_receive(&mb_param, -1, query);
-                if (ret >= 0) {
-                        modbus_slave_manage(&mb_param, query, ret, &mb_mapping);
-                } else if (ret == CONNECTION_CLOSED) {
-                        /* Connection closed by the client, end of server */
-                        break;
+                rc = modbus_slave_receive(&mb_param, -1, query);
+                if (rc >= 0) {
+                        modbus_slave_manage(&mb_param, query, rc, &mb_mapping);
                 } else {
                 } else {
-                        fprintf(stderr, "Error in modbus_listen (%d)\n", ret);
+                        /* Connection closed by the client or server */
+                        break;
                 }
                 }
         }
         }
 
 
+        printf("Quit the loop: %s\n", modbus_strerror(errno));
+
         close(socket);
         close(socket);
         modbus_mapping_free(&mb_mapping);
         modbus_mapping_free(&mb_mapping);
         modbus_close(&mb_param);
         modbus_close(&mb_param);

+ 28 - 25
tests/random-test-master.c

@@ -19,6 +19,7 @@
 #include <unistd.h>
 #include <unistd.h>
 #include <string.h>
 #include <string.h>
 #include <stdlib.h>
 #include <stdlib.h>
+#include <errno.h>
 
 
 #include <modbus/modbus.h>
 #include <modbus/modbus.h>
 
 
@@ -45,7 +46,7 @@
  */
  */
 int main(void)
 int main(void)
 {
 {
-        int ret;
+        int rc;
         int nb_fail;
         int nb_fail;
         int nb_loop;
         int nb_loop;
         int addr;
         int addr;
@@ -63,7 +64,9 @@ int main(void)
         modbus_init_tcp(&mb_param, "127.0.0.1", 1502, SLAVE);
         modbus_init_tcp(&mb_param, "127.0.0.1", 1502, SLAVE);
         modbus_set_debug(&mb_param, TRUE);
         modbus_set_debug(&mb_param, TRUE);
         if (modbus_connect(&mb_param) == -1) {
         if (modbus_connect(&mb_param) == -1) {
-                exit(1);
+                fprintf(stderr, "Connection failed: %s\n",
+                        modbus_strerror(errno));
+                return -1;
         }
         }
 
 
         /* Allocate and initialize the different memory spaces */
         /* Allocate and initialize the different memory spaces */
@@ -94,16 +97,16 @@ int main(void)
                         nb = ADDRESS_END - addr;
                         nb = ADDRESS_END - addr;
 
 
                         /* SINGLE COIL */
                         /* SINGLE COIL */
-                        ret = force_single_coil(&mb_param, addr, tab_rq_status[0]);
-                        if (ret != 1) {
-                                printf("ERROR force_single_coil (%d)\n", ret);
+                        rc = force_single_coil(&mb_param, addr, tab_rq_status[0]);
+                        if (rc != 1) {
+                                printf("ERROR force_single_coil (%d)\n", rc);
                                 printf("Slave = %d, address = %d, value = %d\n",
                                 printf("Slave = %d, address = %d, value = %d\n",
                                        SLAVE, addr, tab_rq_status[0]);
                                        SLAVE, addr, tab_rq_status[0]);
                                 nb_fail++;
                                 nb_fail++;
                         } else {
                         } else {
-                                ret = read_coil_status(&mb_param, addr, 1, tab_rp_status);
-                                if (ret != 1 || tab_rq_status[0] != tab_rp_status[0]) {
-                                        printf("ERROR read_coil_status single (%d)\n", ret);
+                                rc = read_coil_status(&mb_param, addr, 1, tab_rp_status);
+                                if (rc != 1 || tab_rq_status[0] != tab_rp_status[0]) {
+                                        printf("ERROR read_coil_status single (%d)\n", rc);
                                         printf("Slave = %d, address = %d\n",
                                         printf("Slave = %d, address = %d\n",
                                                SLAVE, addr);
                                                SLAVE, addr);
                                         nb_fail++;
                                         nb_fail++;
@@ -111,15 +114,15 @@ int main(void)
                         }
                         }
 
 
                         /* MULTIPLE COILS */
                         /* MULTIPLE COILS */
-                        ret = force_multiple_coils(&mb_param, addr, nb, tab_rq_status);
-                        if (ret != nb) {
-                                printf("ERROR force_multiple_coils (%d)\n", ret);
+                        rc = force_multiple_coils(&mb_param, addr, nb, tab_rq_status);
+                        if (rc != nb) {
+                                printf("ERROR force_multiple_coils (%d)\n", rc);
                                 printf("Slave = %d, address = %d, nb = %d\n",
                                 printf("Slave = %d, address = %d, nb = %d\n",
                                        SLAVE, addr, nb);
                                        SLAVE, addr, nb);
                                 nb_fail++;
                                 nb_fail++;
                         } else {
                         } else {
-                                ret = read_coil_status(&mb_param, addr, nb, tab_rp_status);
-                                if (ret != nb) {
+                                rc = read_coil_status(&mb_param, addr, nb, tab_rp_status);
+                                if (rc != nb) {
                                         printf("ERROR read_coil_status\n");
                                         printf("ERROR read_coil_status\n");
                                         printf("Slave = %d, address = %d, nb = %d\n",
                                         printf("Slave = %d, address = %d, nb = %d\n",
                                                SLAVE, addr, nb);
                                                SLAVE, addr, nb);
@@ -139,16 +142,16 @@ int main(void)
                         }
                         }
 
 
                         /* SINGLE REGISTER */
                         /* SINGLE REGISTER */
-                        ret = preset_single_register(&mb_param, addr, tab_rq_registers[0]);
-                        if (ret != 1) {
-                                printf("ERROR preset_single_register (%d)\n", ret);
+                        rc = preset_single_register(&mb_param, addr, tab_rq_registers[0]);
+                        if (rc != 1) {
+                                printf("ERROR preset_single_register (%d)\n", rc);
                                 printf("Slave = %d, address = %d, value = %d (0x%X)\n",
                                 printf("Slave = %d, address = %d, value = %d (0x%X)\n",
                                        SLAVE, addr, tab_rq_registers[0], tab_rq_registers[0]);
                                        SLAVE, addr, tab_rq_registers[0], tab_rq_registers[0]);
                                 nb_fail++;
                                 nb_fail++;
                         } else {
                         } else {
-                                ret = read_holding_registers(&mb_param, addr, 1, tab_rp_registers);
-                                if (ret != 1) {
-                                        printf("ERROR read_holding_registers single (%d)\n", ret);
+                                rc = read_holding_registers(&mb_param, addr, 1, tab_rp_registers);
+                                if (rc != 1) {
+                                        printf("ERROR read_holding_registers single (%d)\n", rc);
                                         printf("Slave = %d, address = %d\n",
                                         printf("Slave = %d, address = %d\n",
                                                SLAVE, addr);
                                                SLAVE, addr);
                                         nb_fail++;
                                         nb_fail++;
@@ -165,18 +168,18 @@ int main(void)
                         }
                         }
 
 
                         /* MULTIPLE REGISTERS */
                         /* MULTIPLE REGISTERS */
-                        ret = preset_multiple_registers(&mb_param, addr, nb,
+                        rc = preset_multiple_registers(&mb_param, addr, nb,
                                                         tab_rq_registers);
                                                         tab_rq_registers);
-                        if (ret != nb) {
-                                printf("ERROR preset_multiple_registers (%d)\n", ret);
+                        if (rc != nb) {
+                                printf("ERROR preset_multiple_registers (%d)\n", rc);
                                 printf("Slave = %d, address = %d, nb = %d\n",
                                 printf("Slave = %d, address = %d, nb = %d\n",
                                                SLAVE, addr, nb);
                                                SLAVE, addr, nb);
                                 nb_fail++;
                                 nb_fail++;
                         } else {
                         } else {
-                                ret = read_holding_registers(&mb_param, addr, nb,
+                                rc = read_holding_registers(&mb_param, addr, nb,
                                                              tab_rp_registers);
                                                              tab_rp_registers);
-                                if (ret != nb) {
-                                        printf("ERROR read_holding_registers (%d)\n", ret);
+                                if (rc != nb) {
+                                        printf("ERROR read_holding_registers (%d)\n", rc);
                                         printf("Slave = %d, address = %d, nb = %d\n",
                                         printf("Slave = %d, address = %d, nb = %d\n",
                                                SLAVE, addr, nb);
                                                SLAVE, addr, nb);
                                         nb_fail++;
                                         nb_fail++;

+ 17 - 15
tests/random-test-slave.c

@@ -18,6 +18,7 @@
 #include <stdio.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <stdlib.h>
+#include <errno.h>
 
 
 #include <modbus/modbus.h>
 #include <modbus/modbus.h>
 
 
@@ -28,36 +29,37 @@ int main(void)
         int socket;
         int socket;
         modbus_param_t mb_param;
         modbus_param_t mb_param;
         modbus_mapping_t mb_mapping;
         modbus_mapping_t mb_mapping;
-        int ret;
+        int rc;
 
 
         modbus_init_tcp(&mb_param, "127.0.0.1", 1502, SLAVE);
         modbus_init_tcp(&mb_param, "127.0.0.1", 1502, SLAVE);
         /* modbus_set_debug(&mb_param, TRUE); */
         /* modbus_set_debug(&mb_param, TRUE); */
 
 
-        ret = modbus_mapping_new(&mb_mapping, 500, 500, 500, 500);
-        if (ret < 0) {
-                fprintf(stderr, "Memory allocation failed\n");
-                exit(1);
+        rc = modbus_mapping_new(&mb_mapping, 500, 500, 500, 500);
+        if (rc == -1) {
+                fprintf(stderr, "Failed to allocate the mapping: %s\n",
+                        modbus_strerror(errno));
+                return -1;
         }
         }
 
 
         socket = modbus_slave_listen_tcp(&mb_param, 1);
         socket = modbus_slave_listen_tcp(&mb_param, 1);
         modbus_slave_accept_tcp(&mb_param, &socket);
         modbus_slave_accept_tcp(&mb_param, &socket);
 
 
-        while (1) {
+        for (;;) {
                 uint8_t query[MAX_MESSAGE_LENGTH];
                 uint8_t query[MAX_MESSAGE_LENGTH];
-                int ret;
+                int rc;
 
 
-                ret = modbus_slave_receive(&mb_param, -1, query);
-                if (ret >= 0) {
-                        /* ret is the query size */
-                        modbus_slave_manage(&mb_param, query, ret, &mb_mapping);
-                } else if (ret == CONNECTION_CLOSED) {
-                        /* Connection closed by the client, end of server */
-                        break;
+                rc = modbus_slave_receive(&mb_param, -1, query);
+                if (rc != -1) {
+                        /* rc is the query size */
+                        modbus_slave_manage(&mb_param, query, rc, &mb_mapping);
                 } else {
                 } else {
-                        fprintf(stderr, "Error in modbus_listen (%d)\n", ret);
+                        /* Connection closed by the client or error */
+                        break;
                 }
                 }
         }
         }
 
 
+        printf("Quit the loop: %s\n", modbus_strerror(errno));
+
         close(socket);
         close(socket);
         modbus_mapping_free(&mb_mapping);
         modbus_mapping_free(&mb_mapping);
         modbus_close(&mb_param);
         modbus_close(&mb_param);

+ 129 - 126
tests/unit-test-master.c

@@ -19,6 +19,7 @@
 #include <unistd.h>
 #include <unistd.h>
 #include <string.h>
 #include <string.h>
 #include <stdlib.h>
 #include <stdlib.h>
+#include <errno.h>
 
 
 #include <modbus/modbus.h>
 #include <modbus/modbus.h>
 #include "unit-test.h"
 #include "unit-test.h"
@@ -36,7 +37,7 @@ int main(void)
         uint8_t value;
         uint8_t value;
         int address;
         int address;
         int nb_points;
         int nb_points;
-        int ret;
+        int rc;
         float real;
         float real;
 
 
         /* RTU parity : none, even, odd */
         /* RTU parity : none, even, odd */
@@ -44,10 +45,12 @@ int main(void)
 
 
         /* TCP */
         /* TCP */
         modbus_init_tcp(&mb_param, "127.0.0.1", 1502, SLAVE);
         modbus_init_tcp(&mb_param, "127.0.0.1", 1502, SLAVE);
-/*        modbus_set_debug(&mb_param, TRUE); */
+        modbus_set_debug(&mb_param, TRUE);
 
 
         if (modbus_connect(&mb_param) == -1) {
         if (modbus_connect(&mb_param) == -1) {
-                exit(1);
+                fprintf(stderr, "Connection failed: %s\n",
+                        modbus_strerror(errno));
+                return -1;
         }
         }
 
 
         /* Allocate and initialize the memory to store the status */
         /* Allocate and initialize the memory to store the status */
@@ -70,20 +73,20 @@ int main(void)
         /** COIL STATUS **/
         /** COIL STATUS **/
 
 
         /* Single */
         /* Single */
-        ret = force_single_coil(&mb_param, UT_COIL_STATUS_ADDRESS, ON);
+        rc = force_single_coil(&mb_param, UT_COIL_STATUS_ADDRESS, ON);
         printf("1/2 force_single_coil: ");
         printf("1/2 force_single_coil: ");
-        if (ret == 1) {
+        if (rc == 1) {
                 printf("OK\n");
                 printf("OK\n");
         } else {
         } else {
                 printf("FAILED\n");
                 printf("FAILED\n");
                 goto close;
                 goto close;
         }
         }
 
 
-        ret = read_coil_status(&mb_param, UT_COIL_STATUS_ADDRESS, 1,
-                               tab_rp_status);
+        rc = read_coil_status(&mb_param, UT_COIL_STATUS_ADDRESS, 1,
+                              tab_rp_status);
         printf("2/2 read_coil_status: ");
         printf("2/2 read_coil_status: ");
-        if (ret != 1) {
-                printf("FAILED (nb points %d)\n", ret);
+        if (rc != 1) {
+                printf("FAILED (nb points %d)\n", rc);
                 goto close;
                 goto close;
         }
         }
 
 
@@ -100,12 +103,12 @@ int main(void)
 
 
                 set_bits_from_bytes(tab_value, 0, UT_COIL_STATUS_NB_POINTS,
                 set_bits_from_bytes(tab_value, 0, UT_COIL_STATUS_NB_POINTS,
                                     UT_COIL_STATUS_TAB);
                                     UT_COIL_STATUS_TAB);
-                ret = force_multiple_coils(&mb_param,
-                                           UT_COIL_STATUS_ADDRESS,
-                                           UT_COIL_STATUS_NB_POINTS,
-                                           tab_value);
+                rc = force_multiple_coils(&mb_param,
+                                          UT_COIL_STATUS_ADDRESS,
+                                          UT_COIL_STATUS_NB_POINTS,
+                                          tab_value);
                 printf("1/2 force_multiple_coils: ");
                 printf("1/2 force_multiple_coils: ");
-                if (ret == UT_COIL_STATUS_NB_POINTS) {
+                if (rc == UT_COIL_STATUS_NB_POINTS) {
                         printf("OK\n");
                         printf("OK\n");
                 } else {
                 } else {
                         printf("FAILED\n");
                         printf("FAILED\n");
@@ -113,11 +116,11 @@ int main(void)
                 }
                 }
         }
         }
 
 
-        ret = read_coil_status(&mb_param, UT_COIL_STATUS_ADDRESS,
-                               UT_COIL_STATUS_NB_POINTS, tab_rp_status);
+        rc = read_coil_status(&mb_param, UT_COIL_STATUS_ADDRESS,
+                              UT_COIL_STATUS_NB_POINTS, tab_rp_status);
         printf("2/2 read_coil_status: ");
         printf("2/2 read_coil_status: ");
-        if (ret != UT_COIL_STATUS_NB_POINTS) {
-                printf("FAILED (nb points %d)\n", ret);
+        if (rc != UT_COIL_STATUS_NB_POINTS) {
+                printf("FAILED (nb points %d)\n", rc);
                 goto close;
                 goto close;
         }
         }
 
 
@@ -141,12 +144,12 @@ int main(void)
         /* End of multiple coils */
         /* End of multiple coils */
 
 
         /** INPUT STATUS **/
         /** INPUT STATUS **/
-        ret = read_input_status(&mb_param, UT_INPUT_STATUS_ADDRESS,
-                                UT_INPUT_STATUS_NB_POINTS, tab_rp_status);
+        rc = read_input_status(&mb_param, UT_INPUT_STATUS_ADDRESS,
+                               UT_INPUT_STATUS_NB_POINTS, tab_rp_status);
         printf("1/1 read_input_status: ");
         printf("1/1 read_input_status: ");
 
 
-        if (ret != UT_INPUT_STATUS_NB_POINTS) {
-                printf("FAILED (nb points %d)\n", ret);
+        if (rc != UT_INPUT_STATUS_NB_POINTS) {
+                printf("FAILED (nb points %d)\n", rc);
                 goto close;
                 goto close;
         }
         }
 
 
@@ -171,22 +174,22 @@ int main(void)
         /** HOLDING REGISTERS **/
         /** HOLDING REGISTERS **/
 
 
         /* Single register */
         /* Single register */
-        ret = preset_single_register(&mb_param,
-                                     UT_HOLDING_REGISTERS_ADDRESS, 0x1234);
+        rc = preset_single_register(&mb_param,
+                                    UT_HOLDING_REGISTERS_ADDRESS, 0x1234);
         printf("1/2 preset_single_register: ");
         printf("1/2 preset_single_register: ");
-        if (ret == 1) {
+        if (rc == 1) {
                 printf("OK\n");
                 printf("OK\n");
         } else {
         } else {
                 printf("FAILED\n");
                 printf("FAILED\n");
                 goto close;
                 goto close;
         }
         }
 
 
-        ret = read_holding_registers(&mb_param,
-                                     UT_HOLDING_REGISTERS_ADDRESS,
-                                     1, tab_rp_registers);
+        rc = read_holding_registers(&mb_param,
+                                    UT_HOLDING_REGISTERS_ADDRESS,
+                                    1, tab_rp_registers);
         printf("2/2 read_holding_registers: ");
         printf("2/2 read_holding_registers: ");
-        if (ret != 1) {
-                printf("FAILED (nb points %d)\n", ret);
+        if (rc != 1) {
+                printf("FAILED (nb points %d)\n", rc);
                 goto close;
                 goto close;
         }
         }
 
 
@@ -199,25 +202,25 @@ int main(void)
         /* End of single register */
         /* End of single register */
 
 
         /* Many registers */
         /* Many registers */
-        ret = preset_multiple_registers(&mb_param,
-                                        UT_HOLDING_REGISTERS_ADDRESS,
-                                        UT_HOLDING_REGISTERS_NB_POINTS,
-                                        UT_HOLDING_REGISTERS_TAB);
+        rc = preset_multiple_registers(&mb_param,
+                                       UT_HOLDING_REGISTERS_ADDRESS,
+                                       UT_HOLDING_REGISTERS_NB_POINTS,
+                                       UT_HOLDING_REGISTERS_TAB);
         printf("1/2 preset_multiple_registers: ");
         printf("1/2 preset_multiple_registers: ");
-        if (ret == UT_HOLDING_REGISTERS_NB_POINTS) {
+        if (rc == UT_HOLDING_REGISTERS_NB_POINTS) {
                 printf("OK\n");
                 printf("OK\n");
         } else {
         } else {
                 printf("FAILED\n");
                 printf("FAILED\n");
                 goto close;
                 goto close;
         }
         }
 
 
-        ret = read_holding_registers(&mb_param,
-                                     UT_HOLDING_REGISTERS_ADDRESS,
-                                     UT_HOLDING_REGISTERS_NB_POINTS,
-                                     tab_rp_registers);
+        rc = read_holding_registers(&mb_param,
+                                    UT_HOLDING_REGISTERS_ADDRESS,
+                                    UT_HOLDING_REGISTERS_NB_POINTS,
+                                    tab_rp_registers);
         printf("2/2 read_holding_registers: ");
         printf("2/2 read_holding_registers: ");
-        if (ret != UT_HOLDING_REGISTERS_NB_POINTS) {
-                printf("FAILED (nb points %d)\n", ret);
+        if (rc != UT_HOLDING_REGISTERS_NB_POINTS) {
+                printf("FAILED (nb points %d)\n", rc);
                 goto close;
                 goto close;
         }
         }
 
 
@@ -234,13 +237,13 @@ int main(void)
 
 
 
 
         /** INPUT REGISTERS **/
         /** INPUT REGISTERS **/
-        ret = read_input_registers(&mb_param,
-                                   UT_INPUT_REGISTERS_ADDRESS,
-                                   UT_INPUT_REGISTERS_NB_POINTS,
-                                   tab_rp_registers);
+        rc = read_input_registers(&mb_param,
+                                  UT_INPUT_REGISTERS_ADDRESS,
+                                  UT_INPUT_REGISTERS_NB_POINTS,
+                                  tab_rp_registers);
         printf("1/1 read_input_registers: ");
         printf("1/1 read_input_registers: ");
-        if (ret != UT_INPUT_REGISTERS_NB_POINTS) {
-                printf("FAILED (nb points %d)\n", ret);
+        if (rc != UT_INPUT_REGISTERS_NB_POINTS) {
+                printf("FAILED (nb points %d)\n", rc);
                 goto close;
                 goto close;
         }
         }
 
 
@@ -284,83 +287,83 @@ int main(void)
         /* The mapping begins at 0 and ending at address + nb_points so
         /* The mapping begins at 0 and ending at address + nb_points so
          * the addresses below are not valid. */
          * the addresses below are not valid. */
 
 
-        ret = read_coil_status(&mb_param,
-                               UT_COIL_STATUS_ADDRESS,
-                               UT_COIL_STATUS_NB_POINTS + 1,
-                               tab_rp_status);
+        rc = read_coil_status(&mb_param,
+                              UT_COIL_STATUS_ADDRESS,
+                              UT_COIL_STATUS_NB_POINTS + 1,
+                              tab_rp_status);
         printf("* read_coil_status: ");
         printf("* read_coil_status: ");
-        if (ret == ILLEGAL_DATA_ADDRESS)
+        if (rc == -1 && errno == EMBXILADD)
                 printf("OK\n");
                 printf("OK\n");
         else {
         else {
                 printf("FAILED\n");
                 printf("FAILED\n");
                 goto close;
                 goto close;
         }
         }
 
 
-        ret = read_input_status(&mb_param,
-                                UT_INPUT_STATUS_ADDRESS,
-                                UT_INPUT_STATUS_NB_POINTS + 1,
-                                tab_rp_status);
+        rc = read_input_status(&mb_param,
+                               UT_INPUT_STATUS_ADDRESS,
+                               UT_INPUT_STATUS_NB_POINTS + 1,
+                               tab_rp_status);
         printf("* read_input_status: ");
         printf("* read_input_status: ");
-        if (ret == ILLEGAL_DATA_ADDRESS)
+        if (rc == -1 && errno == EMBXILADD)
                 printf("OK\n");
                 printf("OK\n");
         else {
         else {
                 printf("FAILED\n");
                 printf("FAILED\n");
                 goto close;
                 goto close;
         }
         }
 
 
-        ret = read_holding_registers(&mb_param,
-                                     UT_HOLDING_REGISTERS_ADDRESS,
-                                     UT_HOLDING_REGISTERS_NB_POINTS + 1,
-                                     tab_rp_registers);
+        rc = read_holding_registers(&mb_param,
+                                    UT_HOLDING_REGISTERS_ADDRESS,
+                                    UT_HOLDING_REGISTERS_NB_POINTS + 1,
+                                    tab_rp_registers);
         printf("* read_holding_registers: ");
         printf("* read_holding_registers: ");
-        if (ret == ILLEGAL_DATA_ADDRESS)
+        if (rc == -1 && errno == EMBXILADD)
                 printf("OK\n");
                 printf("OK\n");
         else {
         else {
                 printf("FAILED\n");
                 printf("FAILED\n");
                 goto close;
                 goto close;
         }
         }
 
 
-        ret = read_input_registers(&mb_param,
-                                   UT_INPUT_REGISTERS_ADDRESS,
-                                   UT_INPUT_REGISTERS_NB_POINTS + 1,
-                                   tab_rp_registers);
+        rc = read_input_registers(&mb_param,
+                                  UT_INPUT_REGISTERS_ADDRESS,
+                                  UT_INPUT_REGISTERS_NB_POINTS + 1,
+                                  tab_rp_registers);
         printf("* read_input_registers: ");
         printf("* read_input_registers: ");
-        if (ret == ILLEGAL_DATA_ADDRESS)
+        if (rc == -1 && errno == EMBXILADD)
                 printf("OK\n");
                 printf("OK\n");
         else {
         else {
                 printf("FAILED\n");
                 printf("FAILED\n");
                 goto close;
                 goto close;
         }
         }
 
 
-        ret = force_single_coil(&mb_param,
-                                UT_COIL_STATUS_ADDRESS + UT_COIL_STATUS_NB_POINTS,
-                                ON);
+        rc = force_single_coil(&mb_param,
+                               UT_COIL_STATUS_ADDRESS + UT_COIL_STATUS_NB_POINTS,
+                               ON);
         printf("* force_single_coil: ");
         printf("* force_single_coil: ");
-        if (ret == ILLEGAL_DATA_ADDRESS) {
+        if (rc == -1 && errno == EMBXILADD) {
                 printf("OK\n");
                 printf("OK\n");
         } else {
         } else {
                 printf("FAILED\n");
                 printf("FAILED\n");
                 goto close;
                 goto close;
         }
         }
 
 
-        ret = force_multiple_coils(&mb_param,
-                                   UT_COIL_STATUS_ADDRESS + UT_COIL_STATUS_NB_POINTS,
-                                   UT_COIL_STATUS_NB_POINTS,
-                                   tab_rp_status);
+        rc = force_multiple_coils(&mb_param,
+                                  UT_COIL_STATUS_ADDRESS + UT_COIL_STATUS_NB_POINTS,
+                                  UT_COIL_STATUS_NB_POINTS,
+                                  tab_rp_status);
         printf("* force_multiple_coils: ");
         printf("* force_multiple_coils: ");
-        if (ret == ILLEGAL_DATA_ADDRESS) {
+        if (rc == -1 && errno == EMBXILADD) {
                 printf("OK\n");
                 printf("OK\n");
         } else {
         } else {
                 printf("FAILED\n");
                 printf("FAILED\n");
                 goto close;
                 goto close;
         }
         }
 
 
-        ret = preset_multiple_registers(&mb_param,
-                                        UT_HOLDING_REGISTERS_ADDRESS + UT_HOLDING_REGISTERS_NB_POINTS,
-                                        UT_HOLDING_REGISTERS_NB_POINTS,
-                                        tab_rp_registers);
+        rc = preset_multiple_registers(&mb_param,
+                                       UT_HOLDING_REGISTERS_ADDRESS + UT_HOLDING_REGISTERS_NB_POINTS,
+                                       UT_HOLDING_REGISTERS_NB_POINTS,
+                                       tab_rp_registers);
         printf("* preset_multiple_registers: ");
         printf("* preset_multiple_registers: ");
-        if (ret == ILLEGAL_DATA_ADDRESS) {
+        if (rc == -1 && errno == EMBXILADD) {
                 printf("OK\n");
                 printf("OK\n");
         } else {
         } else {
                 printf("FAILED\n");
                 printf("FAILED\n");
@@ -371,72 +374,72 @@ int main(void)
         /** TOO MANY DATA **/
         /** TOO MANY DATA **/
         printf("\nTEST TOO MANY DATA ERROR:\n");
         printf("\nTEST TOO MANY DATA ERROR:\n");
 
 
-        ret = read_coil_status(&mb_param,
-                               UT_COIL_STATUS_ADDRESS,
-                               MAX_STATUS + 1,
-                               tab_rp_status);
+        rc = read_coil_status(&mb_param,
+                              UT_COIL_STATUS_ADDRESS,
+                              MAX_STATUS + 1,
+                              tab_rp_status);
         printf("* read_coil_status: ");
         printf("* read_coil_status: ");
-        if (ret == INVALID_DATA) {
+        if (rc == -1 && errno == EMBMDATA) {
                 printf("OK\n");
                 printf("OK\n");
         } else {
         } else {
                 printf("FAILED\n");
                 printf("FAILED\n");
                 goto close;
                 goto close;
         }
         }
 
 
-        ret = read_input_status(&mb_param,
-                                UT_INPUT_STATUS_ADDRESS,
-                                MAX_STATUS + 1,
-                                tab_rp_status);
+        rc = read_input_status(&mb_param,
+                               UT_INPUT_STATUS_ADDRESS,
+                               MAX_STATUS + 1,
+                               tab_rp_status);
         printf("* read_input_status: ");
         printf("* read_input_status: ");
-        if (ret == INVALID_DATA) {
+        if (rc == -1 && errno == EMBMDATA) {
                 printf("OK\n");
                 printf("OK\n");
         } else {
         } else {
                 printf("FAILED\n");
                 printf("FAILED\n");
                 goto close;
                 goto close;
         }
         }
 
 
-        ret = read_holding_registers(&mb_param,
-                                     UT_HOLDING_REGISTERS_ADDRESS,
-                                     MAX_REGISTERS + 1,
-                                     tab_rp_registers);
+        rc = read_holding_registers(&mb_param,
+                                    UT_HOLDING_REGISTERS_ADDRESS,
+                                    MAX_REGISTERS + 1,
+                                    tab_rp_registers);
         printf("* read_holding_registers: ");
         printf("* read_holding_registers: ");
-        if (ret == INVALID_DATA) {
+        if (rc == -1 && errno == EMBMDATA) {
                 printf("OK\n");
                 printf("OK\n");
         } else {
         } else {
                 printf("FAILED\n");
                 printf("FAILED\n");
                 goto close;
                 goto close;
         }
         }
 
 
-        ret = read_input_registers(&mb_param,
-                                   UT_INPUT_REGISTERS_ADDRESS,
-                                   MAX_REGISTERS + 1,
-                                   tab_rp_registers);
+        rc = read_input_registers(&mb_param,
+                                  UT_INPUT_REGISTERS_ADDRESS,
+                                  MAX_REGISTERS + 1,
+                                  tab_rp_registers);
         printf("* read_input_registers: ");
         printf("* read_input_registers: ");
-        if (ret == INVALID_DATA) {
+        if (rc == -1 && errno == EMBMDATA) {
                 printf("OK\n");
                 printf("OK\n");
         } else {
         } else {
                 printf("FAILED\n");
                 printf("FAILED\n");
                 goto close;
                 goto close;
         }
         }
 
 
-        ret = force_multiple_coils(&mb_param,
-                                   UT_COIL_STATUS_ADDRESS,
-                                   MAX_STATUS + 1,
-                                   tab_rp_status);
+        rc = force_multiple_coils(&mb_param,
+                                  UT_COIL_STATUS_ADDRESS,
+                                  MAX_STATUS + 1,
+                                  tab_rp_status);
         printf("* force_multiple_coils: ");
         printf("* force_multiple_coils: ");
-        if (ret == INVALID_DATA) {
+        if (rc == -1 && errno == EMBMDATA) {
                 printf("OK\n");
                 printf("OK\n");
         } else {
         } else {
                 goto close;
                 goto close;
                 printf("FAILED\n");
                 printf("FAILED\n");
         }
         }
 
 
-        ret = preset_multiple_registers(&mb_param,
-                                        UT_HOLDING_REGISTERS_ADDRESS,
-                                        MAX_REGISTERS + 1,
-                                        tab_rp_registers);
+        rc = preset_multiple_registers(&mb_param,
+                                       UT_HOLDING_REGISTERS_ADDRESS,
+                                       MAX_REGISTERS + 1,
+                                       tab_rp_registers);
         printf("* preset_multiple_registers: ");
         printf("* preset_multiple_registers: ");
-        if (ret == INVALID_DATA) {
+        if (rc == -1 && errno == EMBMDATA) {
                 printf("OK\n");
                 printf("OK\n");
         } else {
         } else {
                 printf("FAILED\n");
                 printf("FAILED\n");
@@ -446,12 +449,12 @@ int main(void)
         /** SLAVE REPLY **/
         /** SLAVE REPLY **/
         printf("\nTEST SLAVE REPLY:\n");
         printf("\nTEST SLAVE REPLY:\n");
         modbus_set_slave(&mb_param, 18);
         modbus_set_slave(&mb_param, 18);
-        ret = read_holding_registers(&mb_param,
-                                     UT_HOLDING_REGISTERS_ADDRESS+1,
-                                     UT_HOLDING_REGISTERS_NB_POINTS,
-                                     tab_rp_registers);
+        rc = read_holding_registers(&mb_param,
+                                    UT_HOLDING_REGISTERS_ADDRESS+1,
+                                    UT_HOLDING_REGISTERS_NB_POINTS,
+                                    tab_rp_registers);
         printf("1/2 No reply from slave %d: ", mb_param.slave);
         printf("1/2 No reply from slave %d: ", mb_param.slave);
-        if (ret == SELECT_TIMEOUT) {
+        if (rc == -1 && errno == ETIMEDOUT) {
                 printf("OK\n");
                 printf("OK\n");
         } else {
         } else {
                 printf("FAILED\n");
                 printf("FAILED\n");
@@ -459,12 +462,12 @@ int main(void)
         }
         }
 
 
         modbus_set_slave(&mb_param, MODBUS_BROADCAST_ADDRESS);
         modbus_set_slave(&mb_param, MODBUS_BROADCAST_ADDRESS);
-        ret = read_holding_registers(&mb_param,
-                                     UT_HOLDING_REGISTERS_ADDRESS,
-                                     UT_HOLDING_REGISTERS_NB_POINTS,
-                                     tab_rp_registers);
+        rc = read_holding_registers(&mb_param,
+                                    UT_HOLDING_REGISTERS_ADDRESS,
+                                    UT_HOLDING_REGISTERS_NB_POINTS,
+                                    tab_rp_registers);
         printf("2/2 Reply after a broadcast query: ");
         printf("2/2 Reply after a broadcast query: ");
-        if (ret == UT_HOLDING_REGISTERS_NB_POINTS) {
+        if (rc == UT_HOLDING_REGISTERS_NB_POINTS) {
                 printf("OK\n");
                 printf("OK\n");
         } else {
         } else {
                 goto close;
                 goto close;
@@ -477,12 +480,12 @@ int main(void)
         /* Allocate only the required space */
         /* Allocate only the required space */
         tab_rp_registers_bad = (uint16_t *) malloc(
         tab_rp_registers_bad = (uint16_t *) malloc(
                 UT_HOLDING_REGISTERS_NB_POINTS_SPECIAL * sizeof(uint16_t));
                 UT_HOLDING_REGISTERS_NB_POINTS_SPECIAL * sizeof(uint16_t));
-        ret = read_holding_registers(&mb_param,
-                                     UT_HOLDING_REGISTERS_ADDRESS,
-                                     UT_HOLDING_REGISTERS_NB_POINTS_SPECIAL,
-                                     tab_rp_registers_bad);
+        rc = read_holding_registers(&mb_param,
+                                    UT_HOLDING_REGISTERS_ADDRESS,
+                                    UT_HOLDING_REGISTERS_NB_POINTS_SPECIAL,
+                                    tab_rp_registers_bad);
         printf("* read_holding_registers: ");
         printf("* read_holding_registers: ");
-        if (ret == INVALID_DATA) {
+        if (rc == -1 && errno == EMBBADDATA) {
                 printf("OK\n");
                 printf("OK\n");
         } else {
         } else {
                 printf("FAILED\n");
                 printf("FAILED\n");

+ 19 - 13
tests/unit-test-slave.c

@@ -19,6 +19,7 @@
 #include <unistd.h>
 #include <unistd.h>
 #include <string.h>
 #include <string.h>
 #include <stdlib.h>
 #include <stdlib.h>
+#include <errno.h>
 
 
 #include <modbus/modbus.h>
 #include <modbus/modbus.h>
 #include "unit-test.h"
 #include "unit-test.h"
@@ -28,20 +29,22 @@ int main(void)
         int socket;
         int socket;
         modbus_param_t mb_param;
         modbus_param_t mb_param;
         modbus_mapping_t mb_mapping;
         modbus_mapping_t mb_mapping;
-        int ret;
+        int rc;
         int i;
         int i;
 
 
         modbus_init_tcp(&mb_param, "127.0.0.1", 1502, SLAVE);
         modbus_init_tcp(&mb_param, "127.0.0.1", 1502, SLAVE);
         modbus_set_debug(&mb_param, TRUE);
         modbus_set_debug(&mb_param, TRUE);
+        modbus_set_error_recovery(&mb_param, TRUE);
 
 
-        ret = modbus_mapping_new(&mb_mapping,
+        rc = modbus_mapping_new(&mb_mapping,
                                  UT_COIL_STATUS_ADDRESS + UT_COIL_STATUS_NB_POINTS,
                                  UT_COIL_STATUS_ADDRESS + UT_COIL_STATUS_NB_POINTS,
                                  UT_INPUT_STATUS_ADDRESS + UT_INPUT_STATUS_NB_POINTS,
                                  UT_INPUT_STATUS_ADDRESS + UT_INPUT_STATUS_NB_POINTS,
                                  UT_HOLDING_REGISTERS_ADDRESS + UT_HOLDING_REGISTERS_NB_POINTS,
                                  UT_HOLDING_REGISTERS_ADDRESS + UT_HOLDING_REGISTERS_NB_POINTS,
                                  UT_INPUT_REGISTERS_ADDRESS + UT_INPUT_REGISTERS_NB_POINTS);
                                  UT_INPUT_REGISTERS_ADDRESS + UT_INPUT_REGISTERS_NB_POINTS);
-        if (ret < 0) {
-                printf("Memory allocation failed\n");
-                exit(1);
+        if (rc == -1) {
+                fprintf(stderr, "Failed to allocate the mapping: %s\n",
+                        modbus_strerror(errno));
+                return -1;
         }
         }
 
 
         /* Examples from PI_MODBUS_300.pdf.
         /* Examples from PI_MODBUS_300.pdf.
@@ -61,11 +64,11 @@ int main(void)
         socket = modbus_slave_listen_tcp(&mb_param, 1);
         socket = modbus_slave_listen_tcp(&mb_param, 1);
         modbus_slave_accept_tcp(&mb_param, &socket);
         modbus_slave_accept_tcp(&mb_param, &socket);
 
 
-        while (1) {
+        for (;;) {
                 uint8_t query[MAX_MESSAGE_LENGTH];
                 uint8_t query[MAX_MESSAGE_LENGTH];
 
 
-                ret = modbus_slave_receive(&mb_param, -1, query);
-                if (ret >= 0) {
+                rc = modbus_slave_receive(&mb_param, -1, query);
+                if (rc > 0) {
                         if (((query[HEADER_LENGTH_TCP + 3] << 8) + query[HEADER_LENGTH_TCP + 4])
                         if (((query[HEADER_LENGTH_TCP + 3] << 8) + query[HEADER_LENGTH_TCP + 4])
                             == UT_HOLDING_REGISTERS_NB_POINTS_SPECIAL) {
                             == UT_HOLDING_REGISTERS_NB_POINTS_SPECIAL) {
                                 /* Change the number of values (offset
                                 /* Change the number of values (offset
@@ -74,15 +77,18 @@ int main(void)
                                 query[HEADER_LENGTH_TCP + 4] = UT_HOLDING_REGISTERS_NB_POINTS;
                                 query[HEADER_LENGTH_TCP + 4] = UT_HOLDING_REGISTERS_NB_POINTS;
                         }
                         }
 
 
-                        modbus_slave_manage(&mb_param, query, ret, &mb_mapping);
-                } else if (ret == CONNECTION_CLOSED) {
-                        /* Connection closed by the client, end of server */
-                        break;
+                        rc = modbus_slave_manage(&mb_param, query, rc, &mb_mapping);
+                        if (rc == -1) {
+                                return -1;
+                        }
                 } else {
                 } else {
-                        fprintf(stderr, "Error in modbus_listen (%d)\n", ret);
+                        /* Connection closed by the client or error */
+                        break;
                 }
                 }
         }
         }
 
 
+        printf("Quit the loop: %s\n", modbus_strerror(errno));
+
         close(socket);
         close(socket);
         modbus_mapping_free(&mb_mapping);
         modbus_mapping_free(&mb_mapping);
         modbus_close(&mb_param);
         modbus_close(&mb_param);