Commit f0e7ad217d41429930f87b884d074f04efca1f7f
1 parent
bb13bb7b
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
Showing
9 changed files
with
744 additions
and
730 deletions
modbus/modbus.c
| ... | ... | @@ -41,6 +41,7 @@ |
| 41 | 41 | #include <sys/time.h> |
| 42 | 42 | #include <unistd.h> |
| 43 | 43 | #include <errno.h> |
| 44 | +#include <assert.h> | |
| 44 | 45 | #include <limits.h> |
| 45 | 46 | #include <fcntl.h> |
| 46 | 47 | |
| ... | ... | @@ -61,9 +62,8 @@ |
| 61 | 62 | #endif |
| 62 | 63 | |
| 63 | 64 | #include <config.h> |
| 64 | -#include <modbus/modbus.h> | |
| 65 | 65 | |
| 66 | -#define UNKNOWN_ERROR_MSG "Not defined in modbus specification" | |
| 66 | +#include <modbus/modbus.h> | |
| 67 | 67 | |
| 68 | 68 | /* Exported version */ |
| 69 | 69 | const unsigned int mb_version_major = MB_VERSION_MAJOR; |
| ... | ... | @@ -78,22 +78,6 @@ typedef struct { |
| 78 | 78 | int t_id; |
| 79 | 79 | } sft_t; |
| 80 | 80 | |
| 81 | -static const uint8_t NB_TAB_ERROR_MSG = 12; | |
| 82 | -static const char *TAB_ERROR_MSG[] = { | |
| 83 | - /* 0x00 */ UNKNOWN_ERROR_MSG, | |
| 84 | - /* 0x01 */ "Illegal function code", | |
| 85 | - /* 0x02 */ "Illegal data address", | |
| 86 | - /* 0x03 */ "Illegal data value", | |
| 87 | - /* 0x04 */ "Slave device or server failure", | |
| 88 | - /* 0x05 */ "Acknowledge", | |
| 89 | - /* 0x06 */ "Slave device or server busy", | |
| 90 | - /* 0x07 */ "Negative acknowledge", | |
| 91 | - /* 0x08 */ "Memory parity error", | |
| 92 | - /* 0x09 */ UNKNOWN_ERROR_MSG, | |
| 93 | - /* 0x0A */ "Gateway path unavailable", | |
| 94 | - /* 0x0B */ "Target device failed to respond" | |
| 95 | -}; | |
| 96 | - | |
| 97 | 81 | /* Table of CRC values for high-order byte */ |
| 98 | 82 | static uint8_t table_crc_hi[] = { |
| 99 | 83 | 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, |
| ... | ... | @@ -169,42 +153,65 @@ static const int TAB_MAX_ADU_LENGTH[2] = { |
| 169 | 153 | MAX_ADU_LENGTH_TCP, |
| 170 | 154 | }; |
| 171 | 155 | |
| 172 | -/* Treats errors and flush or close connection if necessary */ | |
| 173 | -static void error_treat(modbus_param_t *mb_param, int code, const char *string) | |
| 174 | -{ | |
| 175 | - fprintf(stderr, "\nERROR %s (%0X)\n", string, -code); | |
| 156 | +const char *modbus_strerror(int errnum) { | |
| 157 | + switch (errnum) { | |
| 158 | + case EMBXILFUN: | |
| 159 | + return "Illegal function"; | |
| 160 | + case EMBXILADD: | |
| 161 | + return "Illegal data address"; | |
| 162 | + case EMBXILVAL: | |
| 163 | + return "Illegal data value"; | |
| 164 | + case EMBXSFAIL: | |
| 165 | + return "Slave device or server failure"; | |
| 166 | + case EMBXACK: | |
| 167 | + return "Acknowledge"; | |
| 168 | + case EMBXSBUSY: | |
| 169 | + return "Slave device or server is busy"; | |
| 170 | + case EMBXNACK: | |
| 171 | + return "Negative acknowledge"; | |
| 172 | + case EMBXMEMPAR: | |
| 173 | + return "Memory parity error"; | |
| 174 | + case EMBXGPATH: | |
| 175 | + return "Gateway path unavailable"; | |
| 176 | + case EMBXGTAR: | |
| 177 | + return "Target device failed to respond"; | |
| 178 | + case EMBBADCRC: | |
| 179 | + return "Invalid CRC"; | |
| 180 | + case EMBBADDATA: | |
| 181 | + return "Invalid data"; | |
| 182 | + case EMBBADEXC: | |
| 183 | + return "Invalid exception code"; | |
| 184 | + case EMBMDATA: | |
| 185 | + return "Too many data"; | |
| 186 | + default: | |
| 187 | + return strerror(errnum); | |
| 188 | + } | |
| 189 | +} | |
| 176 | 190 | |
| 177 | - if (mb_param->error_handling == FLUSH_OR_CONNECT_ON_ERROR) { | |
| 178 | - switch (code) { | |
| 179 | - case INVALID_DATA: | |
| 180 | - case INVALID_CRC: | |
| 181 | - case INVALID_EXCEPTION_CODE: | |
| 182 | - modbus_flush(mb_param); | |
| 183 | - break; | |
| 184 | - case SELECT_FAILURE: | |
| 185 | - case SOCKET_FAILURE: | |
| 186 | - case CONNECTION_CLOSED: | |
| 187 | - modbus_close(mb_param); | |
| 188 | - modbus_connect(mb_param); | |
| 189 | - break; | |
| 190 | - default: | |
| 191 | - /* NOP */ | |
| 192 | - break; | |
| 191 | +static void error_print(modbus_param_t *mb_param, const char *context) | |
| 192 | +{ | |
| 193 | + if (mb_param->debug) { | |
| 194 | + fprintf(stderr, "ERROR %s", modbus_strerror(errno)); | |
| 195 | + if (context != NULL) { | |
| 196 | + fprintf(stderr, ": %s\n", context); | |
| 197 | + } else { | |
| 198 | + fprintf(stderr, "\n"); | |
| 193 | 199 | } |
| 194 | 200 | } |
| 195 | 201 | } |
| 196 | 202 | |
| 197 | -void modbus_flush(modbus_param_t *mb_param) | |
| 203 | +int modbus_flush(modbus_param_t *mb_param) | |
| 198 | 204 | { |
| 205 | + int rc; | |
| 206 | + | |
| 199 | 207 | if (mb_param->type_com == RTU) { |
| 200 | - tcflush(mb_param->fd, TCIOFLUSH); | |
| 208 | + rc = tcflush(mb_param->fd, TCIOFLUSH); | |
| 201 | 209 | } else { |
| 202 | - int ret; | |
| 203 | 210 | do { |
| 204 | 211 | /* Extract the garbage from the socket */ |
| 205 | 212 | char devnull[MAX_ADU_LENGTH_TCP]; |
| 206 | 213 | #if (!HAVE_DECL___CYGWIN__) |
| 207 | - ret = recv(mb_param->fd, devnull, MAX_ADU_LENGTH_TCP, MSG_DONTWAIT); | |
| 214 | + rc = recv(mb_param->fd, devnull, MAX_ADU_LENGTH_TCP, MSG_DONTWAIT); | |
| 208 | 215 | #else |
| 209 | 216 | /* On Cygwin, it's a bit more complicated to not wait */ |
| 210 | 217 | fd_set rfds; |
| ... | ... | @@ -214,19 +221,17 @@ void modbus_flush(modbus_param_t *mb_param) |
| 214 | 221 | tv.tv_usec = 0; |
| 215 | 222 | FD_ZERO(&rfds); |
| 216 | 223 | FD_SET(mb_param->fd, &rfds); |
| 217 | - ret = select(mb_param->fd+1, &rfds, NULL, NULL, &tv); | |
| 218 | - if (ret > 0) { | |
| 219 | - ret = recv(mb_param->fd, devnull, MAX_ADU_LENGTH_TCP, 0); | |
| 220 | - } else if (ret == -1) { | |
| 221 | - /* error_treat() doesn't call modbus_flush() in | |
| 222 | - this case (avoid infinite loop) */ | |
| 223 | - error_treat(mb_param, SELECT_FAILURE, "Select failure"); | |
| 224 | + rc = select(mb_param->fd+1, &rfds, NULL, NULL, &tv); | |
| 225 | + if (rc == -1) { | |
| 226 | + return -1; | |
| 224 | 227 | } |
| 228 | + | |
| 229 | + rc = recv(mb_param->fd, devnull, MAX_ADU_LENGTH_TCP, 0); | |
| 225 | 230 | #endif |
| 226 | - if (mb_param->debug && ret > 0) { | |
| 227 | - printf("%d bytes flushed\n", ret); | |
| 231 | + if (mb_param->debug && rc != -1) { | |
| 232 | + printf("\n%d bytes flushed\n", rc); | |
| 228 | 233 | } |
| 229 | - } while (ret > 0); | |
| 234 | + } while (rc > 0); | |
| 230 | 235 | } |
| 231 | 236 | } |
| 232 | 237 | |
| ... | ... | @@ -288,12 +293,11 @@ static int build_query_basis_tcp(int slave, int function, |
| 288 | 293 | uint8_t *query) |
| 289 | 294 | { |
| 290 | 295 | |
| 291 | - /* Extract from MODBUS Messaging on TCP/IP Implementation | |
| 292 | - Guide V1.0b (page 23/46): | |
| 293 | - The transaction identifier is used to associate the future | |
| 294 | - response with the request. So, at a time, on a TCP | |
| 295 | - connection, this identifier must be unique. | |
| 296 | - */ | |
| 296 | + /* Extract from MODBUS Messaging on TCP/IP Implementation Guide V1.0b | |
| 297 | + (page 23/46): | |
| 298 | + The transaction identifier is used to associate the future response | |
| 299 | + with the request. So, at a time, on a TCP connection, this identifier | |
| 300 | + must be unique. */ | |
| 297 | 301 | static uint16_t t_id = 0; |
| 298 | 302 | |
| 299 | 303 | /* Transaction ID */ |
| ... | ... | @@ -309,7 +313,7 @@ static int build_query_basis_tcp(int slave, int function, |
| 309 | 313 | query[3] = 0; |
| 310 | 314 | |
| 311 | 315 | /* Length will be defined later by set_query_length_tcp at offsets 4 |
| 312 | - * and 5 */ | |
| 316 | + and 5 */ | |
| 313 | 317 | |
| 314 | 318 | query[6] = slave; |
| 315 | 319 | query[7] = function; |
| ... | ... | @@ -400,38 +404,39 @@ static uint16_t crc16(uint8_t *buffer, uint16_t buffer_length) |
| 400 | 404 | return (crc_hi << 8 | crc_lo); |
| 401 | 405 | } |
| 402 | 406 | |
| 403 | -/* If CRC is correct returns msg_length else returns INVALID_CRC */ | |
| 407 | +/* The check_crc16 function shall return the message length if the CRC is | |
| 408 | + valid. Otherwise it shall return -1 and set errno to EMBADCRC. */ | |
| 404 | 409 | static int check_crc16(modbus_param_t *mb_param, |
| 405 | 410 | uint8_t *msg, |
| 406 | 411 | const int msg_length) |
| 407 | 412 | { |
| 408 | - int ret; | |
| 409 | - uint16_t crc_calc; | |
| 413 | + uint16_t crc_calculated; | |
| 410 | 414 | uint16_t crc_received; |
| 411 | 415 | |
| 412 | - crc_calc = crc16(msg, msg_length - 2); | |
| 416 | + crc_calculated = crc16(msg, msg_length - 2); | |
| 413 | 417 | crc_received = (msg[msg_length - 2] << 8) | msg[msg_length - 1]; |
| 414 | 418 | |
| 415 | 419 | /* Check CRC of msg */ |
| 416 | - if (crc_calc == crc_received) { | |
| 417 | - ret = msg_length; | |
| 420 | + if (crc_calculated == crc_received) { | |
| 421 | + return msg_length; | |
| 418 | 422 | } else { |
| 419 | - char s_error[64]; | |
| 420 | - sprintf(s_error, | |
| 421 | - "invalid crc received %0X - crc_calc %0X", | |
| 422 | - crc_received, crc_calc); | |
| 423 | - ret = INVALID_CRC; | |
| 424 | - error_treat(mb_param, ret, s_error); | |
| 423 | + if (mb_param->debug) { | |
| 424 | + fprintf(stderr, "ERROR CRC received %0X != CRC calculated %0X\n", | |
| 425 | + crc_received, crc_calculated); | |
| 426 | + } | |
| 427 | + if (mb_param->error_recovery) { | |
| 428 | + modbus_flush(mb_param); | |
| 429 | + } | |
| 430 | + errno = EMBBADCRC; | |
| 431 | + return -1; | |
| 425 | 432 | } |
| 426 | - | |
| 427 | - return ret; | |
| 428 | 433 | } |
| 429 | 434 | |
| 430 | 435 | /* Sends a query/response over a serial or a TCP communication */ |
| 431 | 436 | static int modbus_send(modbus_param_t *mb_param, uint8_t *query, |
| 432 | 437 | int query_length) |
| 433 | 438 | { |
| 434 | - int ret; | |
| 439 | + int rc; | |
| 435 | 440 | uint16_t s_crc; |
| 436 | 441 | int i; |
| 437 | 442 | |
| ... | ... | @@ -449,19 +454,35 @@ static int modbus_send(modbus_param_t *mb_param, uint8_t *query, |
| 449 | 454 | printf("\n"); |
| 450 | 455 | } |
| 451 | 456 | |
| 452 | - if (mb_param->type_com == RTU) | |
| 453 | - ret = write(mb_param->fd, query, query_length); | |
| 454 | - else | |
| 455 | - ret = send(mb_param->fd, query, query_length, MSG_NOSIGNAL); | |
| 457 | + /* In recovery mode, the write command will be issued until to be | |
| 458 | + successful! Disabled by default. | |
| 459 | + */ | |
| 460 | + do { | |
| 461 | + if (mb_param->type_com == RTU) | |
| 462 | + rc = write(mb_param->fd, query, query_length); | |
| 463 | + else | |
| 464 | + /* MSG_NOSIGNAL | |
| 465 | + Requests not to send SIGPIPE on errors on stream oriented | |
| 466 | + sockets when the other end breaks the connection. The EPIPE | |
| 467 | + error is still returned. */ | |
| 468 | + rc = send(mb_param->fd, query, query_length, MSG_NOSIGNAL); | |
| 469 | + | |
| 470 | + if (rc == -1) { | |
| 471 | + error_print(mb_param, NULL); | |
| 472 | + if (mb_param->error_recovery && (errno == EBADF || | |
| 473 | + errno == ECONNRESET || errno == EPIPE)) { | |
| 474 | + modbus_close(mb_param); | |
| 475 | + modbus_connect(mb_param); | |
| 476 | + } | |
| 477 | + } | |
| 478 | + } while (mb_param->error_recovery && rc == -1); | |
| 456 | 479 | |
| 457 | - /* Return the number of bytes written (0 to n) | |
| 458 | - or SOCKET_FAILURE on error */ | |
| 459 | - if ((ret == -1) || (ret != query_length)) { | |
| 460 | - ret = SOCKET_FAILURE; | |
| 461 | - error_treat(mb_param, ret, "Write socket failure"); | |
| 480 | + if (rc > 0 && rc != query_length) { | |
| 481 | + errno = EMBBADDATA; | |
| 482 | + return -1; | |
| 462 | 483 | } |
| 463 | 484 | |
| 464 | - return ret; | |
| 485 | + return rc; | |
| 465 | 486 | } |
| 466 | 487 | |
| 467 | 488 | /* 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) |
| 504 | 525 | return length; |
| 505 | 526 | } |
| 506 | 527 | |
| 507 | -#define WAIT_DATA() \ | |
| 508 | -{ \ | |
| 509 | - while ((select_ret = select(mb_param->fd+1, &rfds, NULL, NULL, &tv)) == -1) { \ | |
| 510 | - if (errno == EINTR) { \ | |
| 511 | - fprintf(stderr, "A non blocked signal was caught\n"); \ | |
| 512 | - /* Necessary after an error */ \ | |
| 513 | - FD_ZERO(&rfds); \ | |
| 514 | - FD_SET(mb_param->fd, &rfds); \ | |
| 515 | - } else { \ | |
| 516 | - error_treat(mb_param, SELECT_FAILURE, "Select failure"); \ | |
| 517 | - return SELECT_FAILURE; \ | |
| 518 | - } \ | |
| 519 | - } \ | |
| 520 | - \ | |
| 521 | - if (select_ret == 0) { \ | |
| 522 | - /* Timeout */ \ | |
| 523 | - if (msg_length == (TAB_HEADER_LENGTH[mb_param->type_com] + 2 + \ | |
| 524 | - TAB_CHECKSUM_LENGTH[mb_param->type_com])) { \ | |
| 525 | - /* Optimization allowed because exception response is \ | |
| 526 | - the smallest trame in modbus protocol (3) so always \ | |
| 527 | - raise a timeout error */ \ | |
| 528 | - return MB_EXCEPTION; \ | |
| 529 | - } else { \ | |
| 530 | - /* Call to error_treat is done later to manage exceptions */ \ | |
| 531 | - return SELECT_TIMEOUT; \ | |
| 532 | - } \ | |
| 533 | - } \ | |
| 528 | +#define WAIT_DATA() \ | |
| 529 | +{ \ | |
| 530 | + while ((s_rc = select(mb_param->fd+1, &rfds, NULL, NULL, &tv)) == -1) { \ | |
| 531 | + if (errno == EINTR) { \ | |
| 532 | + if (mb_param->debug) { \ | |
| 533 | + fprintf(stderr, \ | |
| 534 | + "A non blocked signal was caught\n"); \ | |
| 535 | + } \ | |
| 536 | + /* Necessary after an error */ \ | |
| 537 | + FD_ZERO(&rfds); \ | |
| 538 | + FD_SET(mb_param->fd, &rfds); \ | |
| 539 | + } else { \ | |
| 540 | + error_print(mb_param, "select"); \ | |
| 541 | + if (mb_param->error_recovery && (errno == EBADF)) { \ | |
| 542 | + modbus_close(mb_param); \ | |
| 543 | + modbus_connect(mb_param); \ | |
| 544 | + errno = EBADF; \ | |
| 545 | + return -1; \ | |
| 546 | + } else { \ | |
| 547 | + return -1; \ | |
| 548 | + } \ | |
| 549 | + } \ | |
| 550 | + } \ | |
| 551 | + \ | |
| 552 | + if (s_rc == 0) { \ | |
| 553 | + /* Timeout */ \ | |
| 554 | + if (msg_length == (TAB_HEADER_LENGTH[mb_param->type_com] + 2 + \ | |
| 555 | + TAB_CHECKSUM_LENGTH[mb_param->type_com])) { \ | |
| 556 | + /* Optimization allowed because exception response is \ | |
| 557 | + the smallest trame in modbus protocol (3) so always \ | |
| 558 | + raise a timeout error. \ | |
| 559 | + Temporary error before exception analyze. */ \ | |
| 560 | + errno = EMBUNKEXC; \ | |
| 561 | + } else { \ | |
| 562 | + errno = ETIMEDOUT; \ | |
| 563 | + error_print(mb_param, "select"); \ | |
| 564 | + } \ | |
| 565 | + return -1; \ | |
| 566 | + } \ | |
| 534 | 567 | } |
| 535 | 568 | |
| 536 | 569 | /* Waits a reply from a modbus slave or a query from a modbus master. |
| 537 | 570 | This function blocks if there is no replies (3 timeouts). |
| 538 | 571 | |
| 539 | - In | |
| 540 | - - msg_length_computed must be set to MSG_LENGTH_UNDEFINED if undefined | |
| 541 | - | |
| 542 | - Out | |
| 543 | - - msg is an array of uint8_t to receive the message | |
| 544 | - | |
| 545 | - On success, return the number of received characters. On error, return | |
| 546 | - a negative value. | |
| 572 | + The argument msg_length_computed must be set to MSG_LENGTH_UNDEFINED if | |
| 573 | + undefined. | |
| 574 | + | |
| 575 | + The function shall return the number of received characters and the received | |
| 576 | + message in an array of uint8_t if successful. Otherwise it shall return -1 | |
| 577 | + and errno is set to one of the values defined below: | |
| 578 | + - ECONNRESET | |
| 579 | + - EMBBADDATA | |
| 580 | + - EMBUNKEXC | |
| 581 | + - ETIMEDOUT | |
| 582 | + - read() or recv() error codes | |
| 547 | 583 | */ |
| 548 | 584 | static int receive_msg(modbus_param_t *mb_param, |
| 549 | 585 | int msg_length_computed, |
| 550 | 586 | uint8_t *msg) |
| 551 | 587 | { |
| 552 | - int select_ret; | |
| 553 | - int read_ret; | |
| 588 | + int s_rc; | |
| 589 | + int read_rc; | |
| 554 | 590 | fd_set rfds; |
| 555 | 591 | struct timeval tv; |
| 556 | 592 | int length_to_read; |
| ... | ... | @@ -591,32 +627,41 @@ static int receive_msg(modbus_param_t *mb_param, |
| 591 | 627 | |
| 592 | 628 | length_to_read = msg_length_computed; |
| 593 | 629 | |
| 594 | - select_ret = 0; | |
| 630 | + s_rc = 0; | |
| 595 | 631 | WAIT_DATA(); |
| 596 | 632 | |
| 597 | 633 | p_msg = msg; |
| 598 | - while (select_ret) { | |
| 634 | + while (s_rc) { | |
| 599 | 635 | if (mb_param->type_com == RTU) |
| 600 | - read_ret = read(mb_param->fd, p_msg, length_to_read); | |
| 636 | + read_rc = read(mb_param->fd, p_msg, length_to_read); | |
| 601 | 637 | else |
| 602 | - read_ret = recv(mb_param->fd, p_msg, length_to_read, 0); | |
| 603 | - | |
| 604 | - if (read_ret == 0) { | |
| 605 | - return CONNECTION_CLOSED; | |
| 606 | - } else if (read_ret < 0) { | |
| 607 | - /* The only negative possible value is -1 */ | |
| 608 | - error_treat(mb_param, SOCKET_FAILURE, | |
| 609 | - "Read socket failure"); | |
| 610 | - return SOCKET_FAILURE; | |
| 638 | + read_rc = recv(mb_param->fd, p_msg, length_to_read, 0); | |
| 639 | + | |
| 640 | + if (read_rc == 0) { | |
| 641 | + errno = ECONNRESET; | |
| 642 | + read_rc = -1; | |
| 643 | + } | |
| 644 | + | |
| 645 | + if (read_rc == -1) { | |
| 646 | + error_print(mb_param, "read"); | |
| 647 | + if (mb_param->error_recovery && (errno == ECONNRESET || | |
| 648 | + errno == ECONNREFUSED)) { | |
| 649 | + modbus_close(mb_param); | |
| 650 | + modbus_connect(mb_param); | |
| 651 | + /* Could be removed by previous calls */ | |
| 652 | + errno = ECONNRESET; | |
| 653 | + return -1; | |
| 654 | + } | |
| 655 | + return -1; | |
| 611 | 656 | } |
| 612 | 657 | |
| 613 | 658 | /* Sums bytes received */ |
| 614 | - msg_length += read_ret; | |
| 659 | + msg_length += read_rc; | |
| 615 | 660 | |
| 616 | 661 | /* Display the hex code of each character received */ |
| 617 | 662 | if (mb_param->debug) { |
| 618 | 663 | int i; |
| 619 | - for (i=0; i < read_ret; i++) | |
| 664 | + for (i=0; i < read_rc; i++) | |
| 620 | 665 | printf("<%.2X>", p_msg[i]); |
| 621 | 666 | } |
| 622 | 667 | |
| ... | ... | @@ -639,8 +684,9 @@ static int receive_msg(modbus_param_t *mb_param, |
| 639 | 684 | length_to_read = compute_query_length_data(mb_param, msg); |
| 640 | 685 | msg_length_computed += length_to_read; |
| 641 | 686 | if (msg_length_computed > TAB_MAX_ADU_LENGTH[mb_param->type_com]) { |
| 642 | - error_treat(mb_param, INVALID_DATA, "Too many data"); | |
| 643 | - return INVALID_DATA; | |
| 687 | + errno = EMBBADDATA; | |
| 688 | + error_print(mb_param, "too many data"); | |
| 689 | + return -1; | |
| 644 | 690 | } |
| 645 | 691 | state = COMPLETE; |
| 646 | 692 | break; |
| ... | ... | @@ -651,7 +697,7 @@ static int receive_msg(modbus_param_t *mb_param, |
| 651 | 697 | } |
| 652 | 698 | |
| 653 | 699 | /* Moves the pointer to receive other data */ |
| 654 | - p_msg = &(p_msg[read_ret]); | |
| 700 | + p_msg = &(p_msg[read_rc]); | |
| 655 | 701 | |
| 656 | 702 | if (length_to_read > 0) { |
| 657 | 703 | /* If no character at the buffer wait |
| ... | ... | @@ -662,7 +708,7 @@ static int receive_msg(modbus_param_t *mb_param, |
| 662 | 708 | WAIT_DATA(); |
| 663 | 709 | } else { |
| 664 | 710 | /* All chars are received */ |
| 665 | - select_ret = FALSE; | |
| 711 | + s_rc = FALSE; | |
| 666 | 712 | } |
| 667 | 713 | } |
| 668 | 714 | |
| ... | ... | @@ -683,11 +729,8 @@ static int receive_msg(modbus_param_t *mb_param, |
| 683 | 729 | descriptor etablished with the master device in argument or -1 to use the |
| 684 | 730 | internal one of modbus_param_t. |
| 685 | 731 | |
| 686 | - Returns: | |
| 687 | - - byte length of the message on success, or a negative error number if the | |
| 688 | - request fails | |
| 689 | - - query, message received | |
| 690 | -*/ | |
| 732 | + The modbus_slave_receive function shall return the request received and its | |
| 733 | + byte length if successul. Otherwise, it shall return -1 and errno is set. */ | |
| 691 | 734 | int modbus_slave_receive(modbus_param_t *mb_param, int sockfd, uint8_t *query) |
| 692 | 735 | { |
| 693 | 736 | if (sockfd != -1) { |
| ... | ... | @@ -700,10 +743,8 @@ int modbus_slave_receive(modbus_param_t *mb_param, int sockfd, uint8_t *query) |
| 700 | 743 | |
| 701 | 744 | /* Receives the response and checks values (and checksum in RTU). |
| 702 | 745 | |
| 703 | - Returns: | |
| 704 | - - the number of values (bits or words) if success or the response | |
| 705 | - length if no value is returned | |
| 706 | - - less than 0 for exception errors | |
| 746 | + The function shall return the number of values (bits or words) and the | |
| 747 | + response if successful. Otherwise, its shall return -1 and errno is set. | |
| 707 | 748 | |
| 708 | 749 | Note: all functions used to send or receive data with modbus return |
| 709 | 750 | these values. */ |
| ... | ... | @@ -711,13 +752,13 @@ static int modbus_receive(modbus_param_t *mb_param, |
| 711 | 752 | uint8_t *query, |
| 712 | 753 | uint8_t *response) |
| 713 | 754 | { |
| 714 | - int ret; | |
| 755 | + int rc; | |
| 715 | 756 | int response_length_computed; |
| 716 | 757 | int offset = TAB_HEADER_LENGTH[mb_param->type_com]; |
| 717 | 758 | |
| 718 | 759 | response_length_computed = compute_response_length(mb_param, query); |
| 719 | - ret = receive_msg(mb_param, response_length_computed, response); | |
| 720 | - if (ret >= 0) { | |
| 760 | + rc = receive_msg(mb_param, response_length_computed, response); | |
| 761 | + if (rc != -1) { | |
| 721 | 762 | /* GOOD RESPONSE */ |
| 722 | 763 | int query_nb_value; |
| 723 | 764 | int response_nb_value; |
| ... | ... | @@ -748,7 +789,7 @@ static int modbus_receive(modbus_param_t *mb_param, |
| 748 | 789 | break; |
| 749 | 790 | case FC_REPORT_SLAVE_ID: |
| 750 | 791 | /* Report slave ID (bytes received) */ |
| 751 | - query_nb_value = response_nb_value = ret; | |
| 792 | + query_nb_value = response_nb_value = rc; | |
| 752 | 793 | break; |
| 753 | 794 | default: |
| 754 | 795 | /* 1 Write functions & others */ |
| ... | ... | @@ -756,58 +797,42 @@ static int modbus_receive(modbus_param_t *mb_param, |
| 756 | 797 | } |
| 757 | 798 | |
| 758 | 799 | if (query_nb_value == response_nb_value) { |
| 759 | - ret = response_nb_value; | |
| 800 | + rc = response_nb_value; | |
| 760 | 801 | } else { |
| 761 | - char *s_error = malloc(64 * sizeof(char)); | |
| 762 | - sprintf(s_error, "Quantity not corresponding to the query (%d != %d)", | |
| 763 | - response_nb_value, query_nb_value); | |
| 764 | - ret = INVALID_DATA; | |
| 765 | - error_treat(mb_param, ret, s_error); | |
| 766 | - free(s_error); | |
| 802 | + if (mb_param->debug) { | |
| 803 | + fprintf(stderr, | |
| 804 | + "Quantity not corresponding to the query (%d != %d)\n", | |
| 805 | + response_nb_value, query_nb_value); | |
| 806 | + } | |
| 807 | + errno = EMBBADDATA; | |
| 808 | + rc = -1; | |
| 767 | 809 | } |
| 768 | - } else if (ret == MB_EXCEPTION) { | |
| 810 | + } else if (errno == EMBUNKEXC) { | |
| 769 | 811 | /* EXCEPTION CODE RECEIVED */ |
| 770 | 812 | |
| 771 | 813 | /* CRC must be checked here (not done in receive_msg) */ |
| 772 | 814 | if (mb_param->type_com == RTU) { |
| 773 | - ret = check_crc16(mb_param, response, EXCEPTION_RESPONSE_LENGTH_RTU); | |
| 774 | - if (ret < 0) | |
| 775 | - return ret; | |
| 815 | + rc = check_crc16(mb_param, response, EXCEPTION_RESPONSE_LENGTH_RTU); | |
| 816 | + if (rc == -1) | |
| 817 | + return -1; | |
| 776 | 818 | } |
| 777 | 819 | |
| 778 | 820 | /* Check for exception response. |
| 779 | 821 | 0x80 + function is stored in the exception |
| 780 | 822 | response. */ |
| 781 | 823 | if (0x80 + query[offset] == response[offset]) { |
| 782 | - | |
| 783 | 824 | int exception_code = response[offset + 1]; |
| 784 | - // FIXME check test | |
| 785 | - if (exception_code < NB_TAB_ERROR_MSG) { | |
| 786 | - error_treat(mb_param, -exception_code, | |
| 787 | - TAB_ERROR_MSG[response[offset + 1]]); | |
| 788 | - /* RETURN THE EXCEPTION CODE */ | |
| 789 | - /* Modbus error code is negative */ | |
| 790 | - return -exception_code; | |
| 825 | + if (exception_code < MODBUS_EXCEPTION_MAX) { | |
| 826 | + errno = MODBUS_ENOBASE + exception_code; | |
| 791 | 827 | } else { |
| 792 | - /* The chances are low to hit this | |
| 793 | - case but it can avoid a vicious | |
| 794 | - segfault */ | |
| 795 | - char *s_error = malloc(64 * sizeof(char)); | |
| 796 | - sprintf(s_error, | |
| 797 | - "Invalid exception code %d", | |
| 798 | - response[offset + 1]); | |
| 799 | - error_treat(mb_param, INVALID_EXCEPTION_CODE, | |
| 800 | - s_error); | |
| 801 | - free(s_error); | |
| 802 | - return INVALID_EXCEPTION_CODE; | |
| 828 | + errno = EMBBADEXC; | |
| 803 | 829 | } |
| 830 | + error_print(mb_param, NULL); | |
| 831 | + return -1; | |
| 804 | 832 | } |
| 805 | - } else { | |
| 806 | - /* Other errors */ | |
| 807 | - error_treat(mb_param, ret, "receive_msg"); | |
| 808 | 833 | } |
| 809 | 834 | |
| 810 | - return ret; | |
| 835 | + return rc; | |
| 811 | 836 | } |
| 812 | 837 | |
| 813 | 838 | 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, |
| 845 | 870 | response_length = build_response_basis(mb_param, sft, response); |
| 846 | 871 | |
| 847 | 872 | /* Positive exception code */ |
| 848 | - response[response_length++] = -exception_code; | |
| 873 | + response[response_length++] = exception_code; | |
| 849 | 874 | |
| 850 | 875 | return response_length; |
| 851 | 876 | } |
| ... | ... | @@ -856,8 +881,8 @@ static int response_exception(modbus_param_t *mb_param, sft_t *sft, |
| 856 | 881 | If an error occurs, this function construct the response |
| 857 | 882 | accordingly. |
| 858 | 883 | */ |
| 859 | -void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query, | |
| 860 | - int query_length, modbus_mapping_t *mb_mapping) | |
| 884 | +int modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query, | |
| 885 | + int query_length, modbus_mapping_t *mb_mapping) | |
| 861 | 886 | { |
| 862 | 887 | int offset = TAB_HEADER_LENGTH[mb_param->type_com]; |
| 863 | 888 | int slave = query[offset - 1]; |
| ... | ... | @@ -873,7 +898,7 @@ void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query, |
| 873 | 898 | printf("Request for slave %d ignored (not %d)\n", |
| 874 | 899 | slave, mb_param->slave); |
| 875 | 900 | } |
| 876 | - return; | |
| 901 | + return 0; | |
| 877 | 902 | } |
| 878 | 903 | |
| 879 | 904 | sft.slave = slave; |
| ... | ... | @@ -890,10 +915,13 @@ void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query, |
| 890 | 915 | int nb = (query[offset + 3] << 8) + query[offset + 4]; |
| 891 | 916 | |
| 892 | 917 | if ((address + nb) > mb_mapping->nb_coil_status) { |
| 893 | - printf("Illegal data address %0X in read_coil_status\n", | |
| 894 | - address + nb); | |
| 895 | - resp_length = response_exception(mb_param, &sft, | |
| 896 | - ILLEGAL_DATA_ADDRESS, response); | |
| 918 | + if (mb_param->debug) { | |
| 919 | + fprintf(stderr, "Illegal data address %0X in read_coil_status\n", | |
| 920 | + address + nb); | |
| 921 | + } | |
| 922 | + resp_length = response_exception( | |
| 923 | + mb_param, &sft, | |
| 924 | + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response); | |
| 897 | 925 | } else { |
| 898 | 926 | resp_length = build_response_basis(mb_param, &sft, response); |
| 899 | 927 | 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, |
| 909 | 937 | int nb = (query[offset + 3] << 8) + query[offset + 4]; |
| 910 | 938 | |
| 911 | 939 | if ((address + nb) > mb_mapping->nb_input_status) { |
| 912 | - printf("Illegal data address %0X in read_input_status\n", | |
| 913 | - address + nb); | |
| 914 | - resp_length = response_exception(mb_param, &sft, | |
| 915 | - ILLEGAL_DATA_ADDRESS, response); | |
| 940 | + if (mb_param->debug) { | |
| 941 | + fprintf(stderr, "Illegal data address %0X in read_input_status\n", | |
| 942 | + address + nb); | |
| 943 | + } | |
| 944 | + resp_length = response_exception( | |
| 945 | + mb_param, &sft, | |
| 946 | + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response); | |
| 916 | 947 | } else { |
| 917 | 948 | resp_length = build_response_basis(mb_param, &sft, response); |
| 918 | 949 | 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, |
| 926 | 957 | int nb = (query[offset + 3] << 8) + query[offset + 4]; |
| 927 | 958 | |
| 928 | 959 | if ((address + nb) > mb_mapping->nb_holding_registers) { |
| 929 | - printf("Illegal data address %0X in read_holding_registers\n", | |
| 930 | - address + nb); | |
| 931 | - resp_length = response_exception(mb_param, &sft, | |
| 932 | - ILLEGAL_DATA_ADDRESS, response); | |
| 960 | + if (mb_param->debug) { | |
| 961 | + fprintf(stderr, "Illegal data address %0X in read_holding_registers\n", | |
| 962 | + address + nb); | |
| 963 | + } | |
| 964 | + resp_length = response_exception( | |
| 965 | + mb_param, &sft, | |
| 966 | + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response); | |
| 933 | 967 | } else { |
| 934 | 968 | int i; |
| 935 | 969 | |
| ... | ... | @@ -948,10 +982,13 @@ void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query, |
| 948 | 982 | int nb = (query[offset + 3] << 8) + query[offset + 4]; |
| 949 | 983 | |
| 950 | 984 | if ((address + nb) > mb_mapping->nb_input_registers) { |
| 951 | - printf("Illegal data address %0X in read_input_registers\n", | |
| 952 | - address + nb); | |
| 953 | - resp_length = response_exception(mb_param, &sft, | |
| 954 | - ILLEGAL_DATA_ADDRESS, response); | |
| 985 | + if (mb_param->debug) { | |
| 986 | + fprintf(stderr, "Illegal data address %0X in read_input_registers\n", | |
| 987 | + address + nb); | |
| 988 | + } | |
| 989 | + resp_length = response_exception( | |
| 990 | + mb_param, &sft, | |
| 991 | + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response); | |
| 955 | 992 | } else { |
| 956 | 993 | int i; |
| 957 | 994 | |
| ... | ... | @@ -966,9 +1003,13 @@ void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query, |
| 966 | 1003 | break; |
| 967 | 1004 | case FC_FORCE_SINGLE_COIL: |
| 968 | 1005 | if (address >= mb_mapping->nb_coil_status) { |
| 969 | - printf("Illegal data address %0X in force_singe_coil\n", address); | |
| 970 | - resp_length = response_exception(mb_param, &sft, | |
| 971 | - ILLEGAL_DATA_ADDRESS, response); | |
| 1006 | + if (mb_param->debug) { | |
| 1007 | + fprintf(stderr, "Illegal data address %0X in force_singe_coil\n", | |
| 1008 | + address); | |
| 1009 | + } | |
| 1010 | + resp_length = response_exception( | |
| 1011 | + mb_param, &sft, | |
| 1012 | + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response); | |
| 972 | 1013 | } else { |
| 973 | 1014 | int data = (query[offset + 3] << 8) + query[offset + 4]; |
| 974 | 1015 | |
| ... | ... | @@ -982,18 +1023,25 @@ void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query, |
| 982 | 1023 | memcpy(response, query, query_length); |
| 983 | 1024 | resp_length = query_length; |
| 984 | 1025 | } else { |
| 985 | - printf("Illegal data value %0X in force_single_coil request at address %0X\n", | |
| 986 | - data, address); | |
| 987 | - resp_length = response_exception(mb_param, &sft, | |
| 988 | - ILLEGAL_DATA_VALUE, response); | |
| 1026 | + if (mb_param->debug) { | |
| 1027 | + fprintf(stderr, "Illegal data value %0X in force_single_coil request at address %0X\n", | |
| 1028 | + data, address); | |
| 1029 | + } | |
| 1030 | + resp_length = response_exception( | |
| 1031 | + mb_param, &sft, | |
| 1032 | + MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, response); | |
| 989 | 1033 | } |
| 990 | 1034 | } |
| 991 | 1035 | break; |
| 992 | 1036 | case FC_PRESET_SINGLE_REGISTER: |
| 993 | 1037 | if (address >= mb_mapping->nb_holding_registers) { |
| 994 | - printf("Illegal data address %0X in preset_holding_register\n", address); | |
| 995 | - resp_length = response_exception(mb_param, &sft, | |
| 996 | - ILLEGAL_DATA_ADDRESS, response); | |
| 1038 | + if (mb_param->debug) { | |
| 1039 | + fprintf(stderr, "Illegal data address %0X in preset_holding_register\n", | |
| 1040 | + address); | |
| 1041 | + } | |
| 1042 | + resp_length = response_exception( | |
| 1043 | + mb_param, &sft, | |
| 1044 | + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response); | |
| 997 | 1045 | } else { |
| 998 | 1046 | int data = (query[offset + 3] << 8) + query[offset + 4]; |
| 999 | 1047 | |
| ... | ... | @@ -1006,10 +1054,13 @@ void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query, |
| 1006 | 1054 | int nb = (query[offset + 3] << 8) + query[offset + 4]; |
| 1007 | 1055 | |
| 1008 | 1056 | if ((address + nb) > mb_mapping->nb_coil_status) { |
| 1009 | - printf("Illegal data address %0X in force_multiple_coils\n", | |
| 1010 | - address + nb); | |
| 1011 | - resp_length = response_exception(mb_param, &sft, | |
| 1012 | - ILLEGAL_DATA_ADDRESS, response); | |
| 1057 | + if (mb_param->debug) { | |
| 1058 | + fprintf(stderr, "Illegal data address %0X in force_multiple_coils\n", | |
| 1059 | + address + nb); | |
| 1060 | + } | |
| 1061 | + resp_length = response_exception( | |
| 1062 | + mb_param, &sft, | |
| 1063 | + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response); | |
| 1013 | 1064 | } else { |
| 1014 | 1065 | /* 6 = byte count */ |
| 1015 | 1066 | 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, |
| 1025 | 1076 | int nb = (query[offset + 3] << 8) + query[offset + 4]; |
| 1026 | 1077 | |
| 1027 | 1078 | if ((address + nb) > mb_mapping->nb_holding_registers) { |
| 1028 | - printf("Illegal data address %0X in preset_multiple_registers\n", | |
| 1029 | - address + nb); | |
| 1030 | - resp_length = response_exception(mb_param, &sft, | |
| 1031 | - ILLEGAL_DATA_ADDRESS, response); | |
| 1079 | + if (mb_param->debug) { | |
| 1080 | + fprintf(stderr, "Illegal data address %0X in preset_multiple_registers\n", | |
| 1081 | + address + nb); | |
| 1082 | + } | |
| 1083 | + resp_length = response_exception( | |
| 1084 | + mb_param, &sft, | |
| 1085 | + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, response); | |
| 1032 | 1086 | } else { |
| 1033 | 1087 | int i, j; |
| 1034 | 1088 | 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, |
| 1046 | 1100 | break; |
| 1047 | 1101 | case FC_READ_EXCEPTION_STATUS: |
| 1048 | 1102 | case FC_REPORT_SLAVE_ID: |
| 1049 | - printf("Not implemented\n"); | |
| 1103 | + if (mb_param->debug) { | |
| 1104 | + fprintf(stderr, "FIXME Not implemented\n"); | |
| 1105 | + } | |
| 1106 | + errno = ENOPROTOOPT; | |
| 1107 | + return -1; | |
| 1108 | + break; | |
| 1109 | + default: | |
| 1110 | + /* FIXME Invalid function exception */ | |
| 1050 | 1111 | break; |
| 1051 | 1112 | } |
| 1052 | 1113 | |
| 1053 | - modbus_send(mb_param, response, resp_length); | |
| 1114 | + return modbus_send(mb_param, response, resp_length); | |
| 1054 | 1115 | } |
| 1055 | 1116 | |
| 1056 | 1117 | /* Reads IO status */ |
| 1057 | 1118 | static int read_io_status(modbus_param_t *mb_param, int function, |
| 1058 | 1119 | int start_addr, int nb, uint8_t *data_dest) |
| 1059 | 1120 | { |
| 1060 | - int ret; | |
| 1121 | + int rc; | |
| 1061 | 1122 | int query_length; |
| 1062 | 1123 | |
| 1063 | 1124 | uint8_t query[MIN_QUERY_LENGTH]; |
| ... | ... | @@ -1066,19 +1127,19 @@ static int read_io_status(modbus_param_t *mb_param, int function, |
| 1066 | 1127 | query_length = build_query_basis(mb_param, function, |
| 1067 | 1128 | start_addr, nb, query); |
| 1068 | 1129 | |
| 1069 | - ret = modbus_send(mb_param, query, query_length); | |
| 1070 | - if (ret > 0) { | |
| 1130 | + rc = modbus_send(mb_param, query, query_length); | |
| 1131 | + if (rc > 0) { | |
| 1071 | 1132 | int i, temp, bit; |
| 1072 | 1133 | int pos = 0; |
| 1073 | 1134 | int offset; |
| 1074 | 1135 | int offset_end; |
| 1075 | 1136 | |
| 1076 | - ret = modbus_receive(mb_param, query, response); | |
| 1077 | - if (ret < 0) | |
| 1078 | - return ret; | |
| 1137 | + rc = modbus_receive(mb_param, query, response); | |
| 1138 | + if (rc == -1) | |
| 1139 | + return -1; | |
| 1079 | 1140 | |
| 1080 | 1141 | offset = TAB_HEADER_LENGTH[mb_param->type_com]; |
| 1081 | - offset_end = offset + ret; | |
| 1142 | + offset_end = offset + rc; | |
| 1082 | 1143 | for (i = offset; i < offset_end; i++) { |
| 1083 | 1144 | /* Shift reg hi_byte to temp */ |
| 1084 | 1145 | temp = response[i + 2]; |
| ... | ... | @@ -1091,7 +1152,7 @@ static int read_io_status(modbus_param_t *mb_param, int function, |
| 1091 | 1152 | } |
| 1092 | 1153 | } |
| 1093 | 1154 | |
| 1094 | - return ret; | |
| 1155 | + return rc; | |
| 1095 | 1156 | } |
| 1096 | 1157 | |
| 1097 | 1158 | /* 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, |
| 1099 | 1160 | int read_coil_status(modbus_param_t *mb_param, int start_addr, |
| 1100 | 1161 | int nb, uint8_t *data_dest) |
| 1101 | 1162 | { |
| 1102 | - int status; | |
| 1163 | + int rc; | |
| 1103 | 1164 | |
| 1104 | 1165 | if (nb > MAX_STATUS) { |
| 1105 | - fprintf(stderr, | |
| 1106 | - "ERROR Too many coils status requested (%d > %d)\n", | |
| 1107 | - nb, MAX_STATUS); | |
| 1108 | - return INVALID_DATA; | |
| 1166 | + if (mb_param->debug) { | |
| 1167 | + fprintf(stderr, | |
| 1168 | + "ERROR Too many coils status requested (%d > %d)\n", | |
| 1169 | + nb, MAX_STATUS); | |
| 1170 | + } | |
| 1171 | + errno = EMBMDATA; | |
| 1172 | + return -1; | |
| 1109 | 1173 | } |
| 1110 | 1174 | |
| 1111 | - status = read_io_status(mb_param, FC_READ_COIL_STATUS, | |
| 1112 | - start_addr, nb, data_dest); | |
| 1113 | - | |
| 1114 | - if (status > 0) | |
| 1115 | - status = nb; | |
| 1175 | + rc = read_io_status(mb_param, FC_READ_COIL_STATUS, start_addr, nb, | |
| 1176 | + data_dest); | |
| 1116 | 1177 | |
| 1117 | - return status; | |
| 1178 | + if (rc == -1) | |
| 1179 | + return -1; | |
| 1180 | + else | |
| 1181 | + return nb; | |
| 1118 | 1182 | } |
| 1119 | 1183 | |
| 1120 | 1184 | |
| ... | ... | @@ -1122,61 +1186,67 @@ int read_coil_status(modbus_param_t *mb_param, int start_addr, |
| 1122 | 1186 | int read_input_status(modbus_param_t *mb_param, int start_addr, |
| 1123 | 1187 | int nb, uint8_t *data_dest) |
| 1124 | 1188 | { |
| 1125 | - int status; | |
| 1189 | + int rc; | |
| 1126 | 1190 | |
| 1127 | 1191 | if (nb > MAX_STATUS) { |
| 1128 | - fprintf(stderr, | |
| 1129 | - "ERROR Too many input status requested (%d > %d)\n", | |
| 1130 | - nb, MAX_STATUS); | |
| 1131 | - return INVALID_DATA; | |
| 1192 | + if (mb_param->debug) { | |
| 1193 | + fprintf(stderr, | |
| 1194 | + "ERROR Too many input status requested (%d > %d)\n", | |
| 1195 | + nb, MAX_STATUS); | |
| 1196 | + } | |
| 1197 | + errno = EMBMDATA; | |
| 1198 | + return -1; | |
| 1132 | 1199 | } |
| 1133 | 1200 | |
| 1134 | - status = read_io_status(mb_param, FC_READ_INPUT_STATUS, | |
| 1135 | - start_addr, nb, data_dest); | |
| 1201 | + rc = read_io_status(mb_param, FC_READ_INPUT_STATUS, start_addr, | |
| 1202 | + nb, data_dest); | |
| 1136 | 1203 | |
| 1137 | - if (status > 0) | |
| 1138 | - status = nb; | |
| 1139 | - | |
| 1140 | - return status; | |
| 1204 | + if (rc == -1) | |
| 1205 | + return -1; | |
| 1206 | + else | |
| 1207 | + return nb; | |
| 1141 | 1208 | } |
| 1142 | 1209 | |
| 1143 | 1210 | /* Reads the data from a modbus slave and put that data into an array */ |
| 1144 | 1211 | static int read_registers(modbus_param_t *mb_param, int function, |
| 1145 | 1212 | int start_addr, int nb, uint16_t *data_dest) |
| 1146 | 1213 | { |
| 1147 | - int ret; | |
| 1214 | + int rc; | |
| 1148 | 1215 | int query_length; |
| 1149 | 1216 | uint8_t query[MIN_QUERY_LENGTH]; |
| 1150 | 1217 | uint8_t response[MAX_MESSAGE_LENGTH]; |
| 1151 | 1218 | |
| 1152 | 1219 | if (nb > MAX_REGISTERS) { |
| 1153 | - fprintf(stderr, | |
| 1154 | - "ERROR Too many holding registers requested (%d > %d)\n", | |
| 1155 | - nb, MAX_REGISTERS); | |
| 1156 | - return INVALID_DATA; | |
| 1220 | + if (mb_param->debug) { | |
| 1221 | + fprintf(stderr, | |
| 1222 | + "ERROR Too many holding registers requested (%d > %d)\n", | |
| 1223 | + nb, MAX_REGISTERS); | |
| 1224 | + } | |
| 1225 | + errno = EMBMDATA; | |
| 1226 | + return -1; | |
| 1157 | 1227 | } |
| 1158 | 1228 | |
| 1159 | 1229 | query_length = build_query_basis(mb_param, function, |
| 1160 | 1230 | start_addr, nb, query); |
| 1161 | 1231 | |
| 1162 | - ret = modbus_send(mb_param, query, query_length); | |
| 1163 | - if (ret > 0) { | |
| 1232 | + rc = modbus_send(mb_param, query, query_length); | |
| 1233 | + if (rc > 0) { | |
| 1164 | 1234 | int offset; |
| 1165 | 1235 | int i; |
| 1166 | 1236 | |
| 1167 | - ret = modbus_receive(mb_param, query, response); | |
| 1237 | + rc = modbus_receive(mb_param, query, response); | |
| 1168 | 1238 | |
| 1169 | 1239 | offset = TAB_HEADER_LENGTH[mb_param->type_com]; |
| 1170 | 1240 | |
| 1171 | - /* If ret is negative, the loop is jumped ! */ | |
| 1172 | - for (i = 0; i < ret; i++) { | |
| 1241 | + /* If rc is negative, the loop is jumped ! */ | |
| 1242 | + for (i = 0; i < rc; i++) { | |
| 1173 | 1243 | /* shift reg hi_byte to temp OR with lo_byte */ |
| 1174 | 1244 | data_dest[i] = (response[offset + 2 + (i << 1)] << 8) | |
| 1175 | 1245 | response[offset + 3 + (i << 1)]; |
| 1176 | 1246 | } |
| 1177 | 1247 | } |
| 1178 | 1248 | |
| 1179 | - return ret; | |
| 1249 | + return rc; | |
| 1180 | 1250 | } |
| 1181 | 1251 | |
| 1182 | 1252 | /* 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, |
| 1187 | 1257 | int status; |
| 1188 | 1258 | |
| 1189 | 1259 | if (nb > MAX_REGISTERS) { |
| 1190 | - fprintf(stderr, | |
| 1191 | - "ERROR Too many holding registers requested (%d > %d)\n", | |
| 1192 | - nb, MAX_REGISTERS); | |
| 1193 | - return INVALID_DATA; | |
| 1260 | + if (mb_param->debug) { | |
| 1261 | + fprintf(stderr, | |
| 1262 | + "ERROR Too many holding registers requested (%d > %d)\n", | |
| 1263 | + nb, MAX_REGISTERS); | |
| 1264 | + } | |
| 1265 | + errno = EMBMDATA; | |
| 1266 | + return -1; | |
| 1194 | 1267 | } |
| 1195 | 1268 | |
| 1196 | 1269 | 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, |
| 1209 | 1282 | fprintf(stderr, |
| 1210 | 1283 | "ERROR Too many input registers requested (%d > %d)\n", |
| 1211 | 1284 | nb, MAX_REGISTERS); |
| 1212 | - return INVALID_DATA; | |
| 1285 | + errno = EMBMDATA; | |
| 1286 | + return -1; | |
| 1213 | 1287 | } |
| 1214 | 1288 | |
| 1215 | 1289 | 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, |
| 1223 | 1297 | static int set_single(modbus_param_t *mb_param, int function, |
| 1224 | 1298 | int addr, int value) |
| 1225 | 1299 | { |
| 1226 | - int ret; | |
| 1300 | + int rc; | |
| 1227 | 1301 | int query_length; |
| 1228 | 1302 | uint8_t query[MIN_QUERY_LENGTH]; |
| 1229 | 1303 | |
| 1230 | 1304 | query_length = build_query_basis(mb_param, function, |
| 1231 | 1305 | addr, value, query); |
| 1232 | 1306 | |
| 1233 | - ret = modbus_send(mb_param, query, query_length); | |
| 1234 | - if (ret > 0) { | |
| 1307 | + rc = modbus_send(mb_param, query, query_length); | |
| 1308 | + if (rc > 0) { | |
| 1235 | 1309 | /* Used by force_single_coil and |
| 1236 | 1310 | * preset_single_register */ |
| 1237 | 1311 | uint8_t response[MIN_QUERY_LENGTH]; |
| 1238 | - ret = modbus_receive(mb_param, query, response); | |
| 1312 | + rc = modbus_receive(mb_param, query, response); | |
| 1239 | 1313 | } |
| 1240 | 1314 | |
| 1241 | - return ret; | |
| 1315 | + return rc; | |
| 1242 | 1316 | } |
| 1243 | 1317 | |
| 1244 | 1318 | /* 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) |
| 1270 | 1344 | int force_multiple_coils(modbus_param_t *mb_param, int start_addr, int nb, |
| 1271 | 1345 | const uint8_t *data_src) |
| 1272 | 1346 | { |
| 1273 | - int ret; | |
| 1347 | + int rc; | |
| 1274 | 1348 | int i; |
| 1275 | 1349 | int byte_count; |
| 1276 | 1350 | int query_length; |
| ... | ... | @@ -1280,9 +1354,12 @@ int force_multiple_coils(modbus_param_t *mb_param, int start_addr, int nb, |
| 1280 | 1354 | uint8_t query[MAX_MESSAGE_LENGTH]; |
| 1281 | 1355 | |
| 1282 | 1356 | if (nb > MAX_STATUS) { |
| 1283 | - fprintf(stderr, "ERROR Writing to too many coils (%d > %d)\n", | |
| 1284 | - nb, MAX_STATUS); | |
| 1285 | - return INVALID_DATA; | |
| 1357 | + if (mb_param->debug) { | |
| 1358 | + fprintf(stderr, "ERROR Writing to too many coils (%d > %d)\n", | |
| 1359 | + nb, MAX_STATUS); | |
| 1360 | + } | |
| 1361 | + errno = EMBMDATA; | |
| 1362 | + return -1; | |
| 1286 | 1363 | } |
| 1287 | 1364 | |
| 1288 | 1365 | 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, |
| 1307 | 1384 | query_length++; |
| 1308 | 1385 | } |
| 1309 | 1386 | |
| 1310 | - ret = modbus_send(mb_param, query, query_length); | |
| 1311 | - if (ret > 0) { | |
| 1387 | + rc = modbus_send(mb_param, query, query_length); | |
| 1388 | + if (rc > 0) { | |
| 1312 | 1389 | uint8_t response[MAX_MESSAGE_LENGTH]; |
| 1313 | - ret = modbus_receive(mb_param, query, response); | |
| 1390 | + rc = modbus_receive(mb_param, query, response); | |
| 1314 | 1391 | } |
| 1315 | 1392 | |
| 1316 | 1393 | |
| 1317 | - return ret; | |
| 1394 | + return rc; | |
| 1318 | 1395 | } |
| 1319 | 1396 | |
| 1320 | 1397 | /* Copies the values in the slave from the array given in argument */ |
| 1321 | 1398 | int preset_multiple_registers(modbus_param_t *mb_param, int start_addr, int nb, |
| 1322 | 1399 | const uint16_t *data_src) |
| 1323 | 1400 | { |
| 1324 | - int ret; | |
| 1401 | + int rc; | |
| 1325 | 1402 | int i; |
| 1326 | 1403 | int query_length; |
| 1327 | 1404 | int byte_count; |
| ... | ... | @@ -1329,10 +1406,13 @@ int preset_multiple_registers(modbus_param_t *mb_param, int start_addr, int nb, |
| 1329 | 1406 | uint8_t query[MAX_MESSAGE_LENGTH]; |
| 1330 | 1407 | |
| 1331 | 1408 | if (nb > MAX_REGISTERS) { |
| 1332 | - fprintf(stderr, | |
| 1333 | - "ERROR Trying to write to too many registers (%d > %d)\n", | |
| 1334 | - nb, MAX_REGISTERS); | |
| 1335 | - return INVALID_DATA; | |
| 1409 | + if (mb_param->debug) { | |
| 1410 | + fprintf(stderr, | |
| 1411 | + "ERROR Trying to write to too many registers (%d > %d)\n", | |
| 1412 | + nb, MAX_REGISTERS); | |
| 1413 | + } | |
| 1414 | + errno = EMBMDATA; | |
| 1415 | + return -1; | |
| 1336 | 1416 | } |
| 1337 | 1417 | |
| 1338 | 1418 | 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, |
| 1345 | 1425 | query[query_length++] = data_src[i] & 0x00FF; |
| 1346 | 1426 | } |
| 1347 | 1427 | |
| 1348 | - ret = modbus_send(mb_param, query, query_length); | |
| 1349 | - if (ret > 0) { | |
| 1428 | + rc = modbus_send(mb_param, query, query_length); | |
| 1429 | + if (rc > 0) { | |
| 1350 | 1430 | uint8_t response[MAX_MESSAGE_LENGTH]; |
| 1351 | - ret = modbus_receive(mb_param, query, response); | |
| 1431 | + rc = modbus_receive(mb_param, query, response); | |
| 1352 | 1432 | } |
| 1353 | 1433 | |
| 1354 | - return ret; | |
| 1434 | + return rc; | |
| 1355 | 1435 | } |
| 1356 | 1436 | |
| 1357 | 1437 | /* Returns the slave id! */ |
| 1358 | 1438 | int report_slave_id(modbus_param_t *mb_param, uint8_t *data_dest) |
| 1359 | 1439 | { |
| 1360 | - int ret; | |
| 1440 | + int rc; | |
| 1361 | 1441 | int query_length; |
| 1362 | 1442 | uint8_t query[MIN_QUERY_LENGTH]; |
| 1363 | 1443 | |
| ... | ... | @@ -1366,8 +1446,8 @@ int report_slave_id(modbus_param_t *mb_param, uint8_t *data_dest) |
| 1366 | 1446 | /* HACKISH, start_addr and count are not used */ |
| 1367 | 1447 | query_length -= 4; |
| 1368 | 1448 | |
| 1369 | - ret = modbus_send(mb_param, query, query_length); | |
| 1370 | - if (ret > 0) { | |
| 1449 | + rc = modbus_send(mb_param, query, query_length); | |
| 1450 | + if (rc > 0) { | |
| 1371 | 1451 | int i; |
| 1372 | 1452 | int offset; |
| 1373 | 1453 | int offset_end; |
| ... | ... | @@ -1375,18 +1455,18 @@ int report_slave_id(modbus_param_t *mb_param, uint8_t *data_dest) |
| 1375 | 1455 | |
| 1376 | 1456 | /* Byte count, slave id, run indicator status, |
| 1377 | 1457 | additional data */ |
| 1378 | - ret = modbus_receive(mb_param, query, response); | |
| 1379 | - if (ret < 0) | |
| 1380 | - return ret; | |
| 1458 | + rc = modbus_receive(mb_param, query, response); | |
| 1459 | + if (rc == -1) | |
| 1460 | + return rc; | |
| 1381 | 1461 | |
| 1382 | 1462 | offset = TAB_HEADER_LENGTH[mb_param->type_com] - 1; |
| 1383 | - offset_end = offset + ret; | |
| 1463 | + offset_end = offset + rc; | |
| 1384 | 1464 | |
| 1385 | 1465 | for (i = offset; i < offset_end; i++) |
| 1386 | 1466 | data_dest[i] = response[i]; |
| 1387 | 1467 | } |
| 1388 | 1468 | |
| 1389 | - return ret; | |
| 1469 | + return rc; | |
| 1390 | 1470 | } |
| 1391 | 1471 | |
| 1392 | 1472 | /* Initializes the modbus_param_t structure for RTU |
| ... | ... | @@ -1408,7 +1488,7 @@ void modbus_init_rtu(modbus_param_t *mb_param, const char *device, |
| 1408 | 1488 | mb_param->data_bit = data_bit; |
| 1409 | 1489 | mb_param->stop_bit = stop_bit; |
| 1410 | 1490 | mb_param->type_com = RTU; |
| 1411 | - mb_param->error_handling = FLUSH_OR_CONNECT_ON_ERROR; | |
| 1491 | + mb_param->error_recovery = FALSE; | |
| 1412 | 1492 | mb_param->slave = slave; |
| 1413 | 1493 | } |
| 1414 | 1494 | |
| ... | ... | @@ -1427,7 +1507,7 @@ void modbus_init_tcp(modbus_param_t *mb_param, const char *ip, int port, int sla |
| 1427 | 1507 | strncpy(mb_param->ip, ip, sizeof(char)*16); |
| 1428 | 1508 | mb_param->port = port; |
| 1429 | 1509 | mb_param->type_com = TCP; |
| 1430 | - mb_param->error_handling = FLUSH_OR_CONNECT_ON_ERROR; | |
| 1510 | + mb_param->error_recovery = FALSE; | |
| 1431 | 1511 | mb_param->slave = slave; |
| 1432 | 1512 | } |
| 1433 | 1513 | |
| ... | ... | @@ -1438,27 +1518,30 @@ void modbus_set_slave(modbus_param_t *mb_param, int slave) |
| 1438 | 1518 | mb_param->slave = slave; |
| 1439 | 1519 | } |
| 1440 | 1520 | |
| 1441 | -/* By default, the error handling mode used is FLUSH_OR_CONNECT_ON_ERROR. | |
| 1521 | +/* | |
| 1522 | + When disabled (default), it is expected that the application will check for error | |
| 1523 | + returns and deal with them as necessary. | |
| 1442 | 1524 | |
| 1443 | - With FLUSH_OR_CONNECT_ON_ERROR, the library will attempt an immediate | |
| 1444 | - reconnection which may hang for several seconds if the network to | |
| 1445 | - the remote target unit is down. | |
| 1525 | + It's not recommanded to enable error recovery for slave/server. | |
| 1446 | 1526 | |
| 1447 | - With NOP_ON_ERROR, it is expected that the application will | |
| 1448 | - check for error returns and deal with them as necessary. | |
| 1527 | + When enabled, the library will attempt an immediate reconnection which may | |
| 1528 | + hang for several seconds if the network to the remote target unit is down. | |
| 1529 | + The write will try a infinite close/connect loop until to be successful and | |
| 1530 | + the select/read calls will just try to retablish the connection one time | |
| 1531 | + then will return an error (if the connecton was down, the values to read are | |
| 1532 | + certainly not available anymore after reconnection, except for slave/server). | |
| 1449 | 1533 | */ |
| 1450 | -void modbus_set_error_handling(modbus_param_t *mb_param, | |
| 1451 | - error_handling_t error_handling) | |
| 1534 | +int modbus_set_error_recovery(modbus_param_t *mb_param, int enabled) | |
| 1452 | 1535 | { |
| 1453 | - if (error_handling == FLUSH_OR_CONNECT_ON_ERROR || | |
| 1454 | - error_handling == NOP_ON_ERROR) { | |
| 1455 | - mb_param->error_handling = error_handling; | |
| 1536 | + if (enabled == TRUE || enabled == FALSE) { | |
| 1537 | + mb_param->error_recovery = (uint8_t) enabled; | |
| 1456 | 1538 | } else { |
| 1457 | - fprintf(stderr, | |
| 1458 | - "Invalid setting for error handling (not changed)\n"); | |
| 1539 | + errno = EINVAL; | |
| 1540 | + return -1; | |
| 1459 | 1541 | } |
| 1460 | -} | |
| 1461 | 1542 | |
| 1543 | + return 0; | |
| 1544 | +} | |
| 1462 | 1545 | |
| 1463 | 1546 | /* Sets up a serial port for RTU communications */ |
| 1464 | 1547 | static int modbus_connect_rtu(modbus_param_t *mb_param) |
| ... | ... | @@ -1467,8 +1550,8 @@ static int modbus_connect_rtu(modbus_param_t *mb_param) |
| 1467 | 1550 | speed_t speed; |
| 1468 | 1551 | |
| 1469 | 1552 | if (mb_param->debug) { |
| 1470 | - fprintf(stderr, "Opening %s at %d bauds (%s)\n", | |
| 1471 | - mb_param->device, mb_param->baud, mb_param->parity); | |
| 1553 | + printf("Opening %s at %d bauds (%s)\n", | |
| 1554 | + mb_param->device, mb_param->baud, mb_param->parity); | |
| 1472 | 1555 | } |
| 1473 | 1556 | |
| 1474 | 1557 | /* 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) |
| 1479 | 1562 | Timeouts are ignored in canonical input mode or when the |
| 1480 | 1563 | NDELAY option is set on the file via open or fcntl */ |
| 1481 | 1564 | mb_param->fd = open(mb_param->device, O_RDWR | O_NOCTTY | O_NDELAY | O_EXCL); |
| 1482 | - if (mb_param->fd < 0) { | |
| 1565 | + if (mb_param->fd == -1) { | |
| 1483 | 1566 | fprintf(stderr, "ERROR Can't open the device %s (%s)\n", |
| 1484 | 1567 | mb_param->device, strerror(errno)); |
| 1485 | 1568 | return -1; |
| ... | ... | @@ -1529,15 +1612,16 @@ static int modbus_connect_rtu(modbus_param_t *mb_param) |
| 1529 | 1612 | break; |
| 1530 | 1613 | default: |
| 1531 | 1614 | speed = B9600; |
| 1532 | - fprintf(stderr, | |
| 1533 | - "WARNING Unknown baud rate %d for %s (B9600 used)\n", | |
| 1534 | - mb_param->baud, mb_param->device); | |
| 1615 | + if (mb_param->debug) { | |
| 1616 | + fprintf(stderr, | |
| 1617 | + "WARNING Unknown baud rate %d for %s (B9600 used)\n", | |
| 1618 | + mb_param->baud, mb_param->device); | |
| 1619 | + } | |
| 1535 | 1620 | } |
| 1536 | 1621 | |
| 1537 | 1622 | /* Set the baud rate */ |
| 1538 | 1623 | if ((cfsetispeed(&tios, speed) < 0) || |
| 1539 | 1624 | (cfsetospeed(&tios, speed) < 0)) { |
| 1540 | - perror("cfsetispeed/cfsetospeed\n"); | |
| 1541 | 1625 | return -1; |
| 1542 | 1626 | } |
| 1543 | 1627 | |
| ... | ... | @@ -1707,7 +1791,6 @@ static int modbus_connect_rtu(modbus_param_t *mb_param) |
| 1707 | 1791 | tios.c_cc[VTIME] = 0; |
| 1708 | 1792 | |
| 1709 | 1793 | if (tcsetattr(mb_param->fd, TCSANOW, &tios) < 0) { |
| 1710 | - perror("tcsetattr\n"); | |
| 1711 | 1794 | return -1; |
| 1712 | 1795 | } |
| 1713 | 1796 | |
| ... | ... | @@ -1717,24 +1800,23 @@ static int modbus_connect_rtu(modbus_param_t *mb_param) |
| 1717 | 1800 | /* Establishes a modbus TCP connection with a modbus slave */ |
| 1718 | 1801 | static int modbus_connect_tcp(modbus_param_t *mb_param) |
| 1719 | 1802 | { |
| 1720 | - int ret; | |
| 1803 | + int rc; | |
| 1721 | 1804 | int option; |
| 1722 | 1805 | struct sockaddr_in addr; |
| 1723 | 1806 | |
| 1724 | 1807 | mb_param->fd = socket(PF_INET, SOCK_STREAM, 0); |
| 1725 | - if (mb_param->fd < 0) { | |
| 1726 | - return mb_param->fd; | |
| 1808 | + if (mb_param->fd == -1) { | |
| 1809 | + return -1; | |
| 1727 | 1810 | } |
| 1728 | 1811 | |
| 1729 | 1812 | /* Set the TCP no delay flag */ |
| 1730 | 1813 | /* SOL_TCP = IPPROTO_TCP */ |
| 1731 | 1814 | option = 1; |
| 1732 | - ret = setsockopt(mb_param->fd, IPPROTO_TCP, TCP_NODELAY, | |
| 1815 | + rc = setsockopt(mb_param->fd, IPPROTO_TCP, TCP_NODELAY, | |
| 1733 | 1816 | (const void *)&option, sizeof(int)); |
| 1734 | - if (ret < 0) { | |
| 1735 | - perror("setsockopt TCP_NODELAY"); | |
| 1817 | + if (rc == -1) { | |
| 1736 | 1818 | close(mb_param->fd); |
| 1737 | - return ret; | |
| 1819 | + return -1; | |
| 1738 | 1820 | } |
| 1739 | 1821 | |
| 1740 | 1822 | #if (!HAVE_DECL___CYGWIN__) |
| ... | ... | @@ -1744,12 +1826,11 @@ static int modbus_connect_tcp(modbus_param_t *mb_param) |
| 1744 | 1826 | **/ |
| 1745 | 1827 | /* Set the IP low delay option */ |
| 1746 | 1828 | option = IPTOS_LOWDELAY; |
| 1747 | - ret = setsockopt(mb_param->fd, IPPROTO_IP, IP_TOS, | |
| 1829 | + rc = setsockopt(mb_param->fd, IPPROTO_IP, IP_TOS, | |
| 1748 | 1830 | (const void *)&option, sizeof(int)); |
| 1749 | - if (ret < 0) { | |
| 1750 | - perror("setsockopt IP_TOS"); | |
| 1831 | + if (rc == -1) { | |
| 1751 | 1832 | close(mb_param->fd); |
| 1752 | - return ret; | |
| 1833 | + return -1; | |
| 1753 | 1834 | } |
| 1754 | 1835 | #endif |
| 1755 | 1836 | |
| ... | ... | @@ -1760,12 +1841,11 @@ static int modbus_connect_tcp(modbus_param_t *mb_param) |
| 1760 | 1841 | addr.sin_family = AF_INET; |
| 1761 | 1842 | addr.sin_port = htons(mb_param->port); |
| 1762 | 1843 | addr.sin_addr.s_addr = inet_addr(mb_param->ip); |
| 1763 | - ret = connect(mb_param->fd, (struct sockaddr *)&addr, | |
| 1844 | + rc = connect(mb_param->fd, (struct sockaddr *)&addr, | |
| 1764 | 1845 | sizeof(struct sockaddr_in)); |
| 1765 | - if (ret < 0) { | |
| 1766 | - perror("connect"); | |
| 1846 | + if (rc == -1) { | |
| 1767 | 1847 | close(mb_param->fd); |
| 1768 | - return ret; | |
| 1848 | + return -1; | |
| 1769 | 1849 | } |
| 1770 | 1850 | |
| 1771 | 1851 | return 0; |
| ... | ... | @@ -1775,22 +1855,20 @@ static int modbus_connect_tcp(modbus_param_t *mb_param) |
| 1775 | 1855 | Returns 0 on success or -1 on failure. */ |
| 1776 | 1856 | int modbus_connect(modbus_param_t *mb_param) |
| 1777 | 1857 | { |
| 1778 | - int ret; | |
| 1858 | + int rc; | |
| 1779 | 1859 | |
| 1780 | 1860 | if (mb_param->type_com == RTU) |
| 1781 | - ret = modbus_connect_rtu(mb_param); | |
| 1861 | + rc = modbus_connect_rtu(mb_param); | |
| 1782 | 1862 | else |
| 1783 | - ret = modbus_connect_tcp(mb_param); | |
| 1863 | + rc = modbus_connect_tcp(mb_param); | |
| 1784 | 1864 | |
| 1785 | - return ret; | |
| 1865 | + return rc; | |
| 1786 | 1866 | } |
| 1787 | 1867 | |
| 1788 | 1868 | /* Closes the file descriptor in RTU mode */ |
| 1789 | 1869 | static void modbus_close_rtu(modbus_param_t *mb_param) |
| 1790 | 1870 | { |
| 1791 | - if (tcsetattr(mb_param->fd, TCSANOW, &(mb_param->old_tios)) < 0) | |
| 1792 | - perror("tcsetattr"); | |
| 1793 | - | |
| 1871 | + tcsetattr(mb_param->fd, TCSANOW, &(mb_param->old_tios)); | |
| 1794 | 1872 | close(mb_param->fd); |
| 1795 | 1873 | } |
| 1796 | 1874 | |
| ... | ... | @@ -1819,7 +1897,8 @@ void modbus_set_debug(modbus_param_t *mb_param, int boolean) |
| 1819 | 1897 | /* Allocates 4 arrays to store coils, input status, input registers and |
| 1820 | 1898 | holding registers. The pointers are stored in modbus_mapping structure. |
| 1821 | 1899 | |
| 1822 | - Returns 0 on success and -1 on failure. | |
| 1900 | + The modbus_mapping_new() function shall return 0 if successful. Otherwise it | |
| 1901 | + shall return -1 and set errno to ENOMEM. | |
| 1823 | 1902 | */ |
| 1824 | 1903 | int modbus_mapping_new(modbus_mapping_t *mb_mapping, |
| 1825 | 1904 | int nb_coil_status, int nb_input_status, |
| ... | ... | @@ -1829,46 +1908,51 @@ int modbus_mapping_new(modbus_mapping_t *mb_mapping, |
| 1829 | 1908 | mb_mapping->nb_coil_status = nb_coil_status; |
| 1830 | 1909 | mb_mapping->tab_coil_status = |
| 1831 | 1910 | (uint8_t *) malloc(nb_coil_status * sizeof(uint8_t)); |
| 1911 | + if (mb_mapping->tab_coil_status == NULL) { | |
| 1912 | + errno = ENOMEM; | |
| 1913 | + return -1; | |
| 1914 | + } | |
| 1832 | 1915 | memset(mb_mapping->tab_coil_status, 0, |
| 1833 | 1916 | nb_coil_status * sizeof(uint8_t)); |
| 1834 | - if (mb_mapping->tab_coil_status == NULL) | |
| 1835 | - return -1; | |
| 1836 | 1917 | |
| 1837 | 1918 | /* 1X */ |
| 1838 | 1919 | mb_mapping->nb_input_status = nb_input_status; |
| 1839 | 1920 | mb_mapping->tab_input_status = |
| 1840 | 1921 | (uint8_t *) malloc(nb_input_status * sizeof(uint8_t)); |
| 1841 | - memset(mb_mapping->tab_input_status, 0, | |
| 1842 | - nb_input_status * sizeof(uint8_t)); | |
| 1843 | 1922 | if (mb_mapping->tab_input_status == NULL) { |
| 1844 | 1923 | free(mb_mapping->tab_coil_status); |
| 1924 | + errno = ENOMEM; | |
| 1845 | 1925 | return -1; |
| 1846 | 1926 | } |
| 1927 | + memset(mb_mapping->tab_input_status, 0, | |
| 1928 | + nb_input_status * sizeof(uint8_t)); | |
| 1847 | 1929 | |
| 1848 | 1930 | /* 4X */ |
| 1849 | 1931 | mb_mapping->nb_holding_registers = nb_holding_registers; |
| 1850 | 1932 | mb_mapping->tab_holding_registers = |
| 1851 | 1933 | (uint16_t *) malloc(nb_holding_registers * sizeof(uint16_t)); |
| 1852 | - memset(mb_mapping->tab_holding_registers, 0, | |
| 1853 | - nb_holding_registers * sizeof(uint16_t)); | |
| 1854 | 1934 | if (mb_mapping->tab_holding_registers == NULL) { |
| 1855 | 1935 | free(mb_mapping->tab_coil_status); |
| 1856 | 1936 | free(mb_mapping->tab_input_status); |
| 1937 | + errno = ENOMEM; | |
| 1857 | 1938 | return -1; |
| 1858 | 1939 | } |
| 1940 | + memset(mb_mapping->tab_holding_registers, 0, | |
| 1941 | + nb_holding_registers * sizeof(uint16_t)); | |
| 1859 | 1942 | |
| 1860 | 1943 | /* 3X */ |
| 1861 | 1944 | mb_mapping->nb_input_registers = nb_input_registers; |
| 1862 | 1945 | mb_mapping->tab_input_registers = |
| 1863 | 1946 | (uint16_t *) malloc(nb_input_registers * sizeof(uint16_t)); |
| 1864 | - memset(mb_mapping->tab_input_registers, 0, | |
| 1865 | - nb_input_registers * sizeof(uint16_t)); | |
| 1866 | 1947 | if (mb_mapping->tab_input_registers == NULL) { |
| 1867 | 1948 | free(mb_mapping->tab_coil_status); |
| 1868 | 1949 | free(mb_mapping->tab_input_status); |
| 1869 | 1950 | free(mb_mapping->tab_holding_registers); |
| 1951 | + errno = ENOMEM; | |
| 1870 | 1952 | return -1; |
| 1871 | 1953 | } |
| 1954 | + memset(mb_mapping->tab_input_registers, 0, | |
| 1955 | + nb_input_registers * sizeof(uint16_t)); | |
| 1872 | 1956 | |
| 1873 | 1957 | return 0; |
| 1874 | 1958 | } |
| ... | ... | @@ -1890,15 +1974,13 @@ int modbus_slave_listen_tcp(modbus_param_t *mb_param, int nb_connection) |
| 1890 | 1974 | struct sockaddr_in addr; |
| 1891 | 1975 | |
| 1892 | 1976 | new_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); |
| 1893 | - if (new_socket < 0) { | |
| 1894 | - perror("socket"); | |
| 1977 | + if (new_socket == -1) { | |
| 1895 | 1978 | return -1; |
| 1896 | 1979 | } |
| 1897 | 1980 | |
| 1898 | 1981 | yes = 1; |
| 1899 | 1982 | if (setsockopt(new_socket, SOL_SOCKET, SO_REUSEADDR, |
| 1900 | - (char *) &yes, sizeof(yes)) < 0) { | |
| 1901 | - perror("setsockopt"); | |
| 1983 | + (char *) &yes, sizeof(yes)) == -1) { | |
| 1902 | 1984 | close(new_socket); |
| 1903 | 1985 | return -1; |
| 1904 | 1986 | } |
| ... | ... | @@ -1908,14 +1990,12 @@ int modbus_slave_listen_tcp(modbus_param_t *mb_param, int nb_connection) |
| 1908 | 1990 | /* If the modbus port is < to 1024, we need the setuid root. */ |
| 1909 | 1991 | addr.sin_port = htons(mb_param->port); |
| 1910 | 1992 | addr.sin_addr.s_addr = INADDR_ANY; |
| 1911 | - if (bind(new_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) { | |
| 1912 | - perror("bind"); | |
| 1993 | + if (bind(new_socket, (struct sockaddr *)&addr, sizeof(addr)) == -1) { | |
| 1913 | 1994 | close(new_socket); |
| 1914 | 1995 | return -1; |
| 1915 | 1996 | } |
| 1916 | 1997 | |
| 1917 | - if (listen(new_socket, nb_connection) < 0) { | |
| 1918 | - perror("listen"); | |
| 1998 | + if (listen(new_socket, nb_connection) == -1) { | |
| 1919 | 1999 | close(new_socket); |
| 1920 | 2000 | return -1; |
| 1921 | 2001 | } |
| ... | ... | @@ -1923,6 +2003,9 @@ int modbus_slave_listen_tcp(modbus_param_t *mb_param, int nb_connection) |
| 1923 | 2003 | return new_socket; |
| 1924 | 2004 | } |
| 1925 | 2005 | |
| 2006 | +/* On success, the function return a non-negative integer that is a descriptor | |
| 2007 | + for the accepted socket. On error, -1 is returned, and errno is set | |
| 2008 | + appropriately. */ | |
| 1926 | 2009 | int modbus_slave_accept_tcp(modbus_param_t *mb_param, int *socket) |
| 1927 | 2010 | { |
| 1928 | 2011 | struct sockaddr_in addr; |
| ... | ... | @@ -1930,11 +2013,13 @@ int modbus_slave_accept_tcp(modbus_param_t *mb_param, int *socket) |
| 1930 | 2013 | |
| 1931 | 2014 | addrlen = sizeof(struct sockaddr_in); |
| 1932 | 2015 | mb_param->fd = accept(*socket, (struct sockaddr *)&addr, &addrlen); |
| 1933 | - if (mb_param->fd < 0) { | |
| 1934 | - perror("accept"); | |
| 2016 | + if (mb_param->fd == -1) { | |
| 1935 | 2017 | close(*socket); |
| 1936 | 2018 | *socket = 0; |
| 1937 | - } else { | |
| 2019 | + return -1; | |
| 2020 | + } | |
| 2021 | + | |
| 2022 | + if (mb_param->debug) { | |
| 1938 | 2023 | printf("The client %s is connected\n", |
| 1939 | 2024 | inet_ntoa(addr.sin_addr)); |
| 1940 | 2025 | } |
| ... | ... | @@ -1964,7 +2049,7 @@ void set_bits_from_byte(uint8_t *dest, int address, const uint8_t value) |
| 1964 | 2049 | |
| 1965 | 2050 | /* Sets many input/coil status from a table of bytes (only the bits |
| 1966 | 2051 | between address and address + nb_bits are set) */ |
| 1967 | -void set_bits_from_bytes(uint8_t *dest, int address, int nb_bits, | |
| 2052 | +void set_bits_from_bytes(uint8_t *dest, int address, unsigned int nb_bits, | |
| 1968 | 2053 | const uint8_t tab_byte[]) |
| 1969 | 2054 | { |
| 1970 | 2055 | int i; |
| ... | ... | @@ -1980,13 +2065,13 @@ void set_bits_from_bytes(uint8_t *dest, int address, int nb_bits, |
| 1980 | 2065 | |
| 1981 | 2066 | /* Gets the byte value from many input/coil status. |
| 1982 | 2067 | To obtain a full byte, set nb_bits to 8. */ |
| 1983 | -uint8_t get_byte_from_bits(const uint8_t *src, int address, int nb_bits) | |
| 2068 | +uint8_t get_byte_from_bits(const uint8_t *src, int address, unsigned int nb_bits) | |
| 1984 | 2069 | { |
| 1985 | 2070 | int i; |
| 1986 | 2071 | uint8_t value = 0; |
| 1987 | 2072 | |
| 1988 | 2073 | if (nb_bits > 8) { |
| 1989 | - fprintf(stderr, "ERROR nb_bits is too big\n"); | |
| 2074 | + assert(nb_bits < 8); | |
| 1990 | 2075 | nb_bits = 8; |
| 1991 | 2076 | } |
| 1992 | 2077 | ... | ... |
modbus/modbus.h
| ... | ... | @@ -120,36 +120,47 @@ extern "C" { |
| 120 | 120 | #define FC_PRESET_MULTIPLE_REGISTERS 0x10 |
| 121 | 121 | #define FC_REPORT_SLAVE_ID 0x11 |
| 122 | 122 | |
| 123 | +/* Random number to avoid errno conflicts */ | |
| 124 | +#define MODBUS_ENOBASE 112345678 | |
| 125 | + | |
| 123 | 126 | /* Protocol exceptions */ |
| 124 | -#define ILLEGAL_FUNCTION -0x01 | |
| 125 | -#define ILLEGAL_DATA_ADDRESS -0x02 | |
| 126 | -#define ILLEGAL_DATA_VALUE -0x03 | |
| 127 | -#define SLAVE_DEVICE_FAILURE -0x04 | |
| 128 | -#define SERVER_FAILURE -0x04 | |
| 129 | -#define ACKNOWLEDGE -0x05 | |
| 130 | -#define SLAVE_DEVICE_BUSY -0x06 | |
| 131 | -#define SERVER_BUSY -0x06 | |
| 132 | -#define NEGATIVE_ACKNOWLEDGE -0x07 | |
| 133 | -#define MEMORY_PARITY_ERROR -0x08 | |
| 134 | -#define GATEWAY_PROBLEM_PATH -0x0A | |
| 135 | -#define GATEWAY_PROBLEM_TARGET -0x0B | |
| 136 | - | |
| 137 | -/* Local */ | |
| 138 | -#define INVALID_DATA -0x10 | |
| 139 | -#define INVALID_CRC -0x11 | |
| 140 | -#define INVALID_EXCEPTION_CODE -0x12 | |
| 141 | - | |
| 142 | -#define SELECT_TIMEOUT -0x13 | |
| 143 | -#define SELECT_FAILURE -0x14 | |
| 144 | -#define SOCKET_FAILURE -0x15 | |
| 145 | -#define CONNECTION_CLOSED -0x16 | |
| 146 | -#define MB_EXCEPTION -0x17 | |
| 127 | +enum { | |
| 128 | + MODBUS_EXCEPTION_ILLEGAL_FUNCTION = 0x01, | |
| 129 | + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, | |
| 130 | + MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, | |
| 131 | + MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE, | |
| 132 | + MODBUS_EXCEPTION_ACKNOWLEDGE, | |
| 133 | + MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY, | |
| 134 | + MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE, | |
| 135 | + MODBUS_EXCEPTION_MEMORY_PARITY, | |
| 136 | + MODBUS_EXCEPTION_NOT_DEFINED, | |
| 137 | + MODBUS_EXCEPTION_GATEWAY_PATH, | |
| 138 | + MODBUS_EXCEPTION_GATEWAY_TARGET, | |
| 139 | + MODBUS_EXCEPTION_MAX | |
| 140 | +}; | |
| 141 | + | |
| 142 | +#define EMBXILFUN (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_FUNCTION) | |
| 143 | +#define EMBXILADD (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS) | |
| 144 | +#define EMBXILVAL (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE) | |
| 145 | +#define EMBXSFAIL (MODBUS_ENOBASE + MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE) | |
| 146 | +#define EMBXACK (MODBUS_ENOBASE + MODBUS_EXCEPTION_ACKNOWLEDGE) | |
| 147 | +#define EMBXSBUSY (MODBUS_ENOBASE + MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY) | |
| 148 | +#define EMBXNACK (MODBUS_ENOBASE + MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE) | |
| 149 | +#define EMBXMEMPAR (MODBUS_ENOBASE + MODBUS_EXCEPTION_MEMORY_PARITY) | |
| 150 | +#define EMBXGPATH (MODBUS_ENOBASE + MODBUS_EXCEPTION_GATEWAY_PATH) | |
| 151 | +#define EMBXGTAR (MODBUS_ENOBASE + MODBUS_EXCEPTION_GATEWAY_TARGET) | |
| 152 | + | |
| 153 | +/* Native libmodbus error codes */ | |
| 154 | +#define EMBBADCRC (EMBXGTAR + 1) | |
| 155 | +#define EMBBADDATA (EMBXGTAR + 2) | |
| 156 | +#define EMBBADEXC (EMBXGTAR + 3) | |
| 157 | +#define EMBUNKEXC (EMBXGTAR + 4) | |
| 158 | +#define EMBMDATA (EMBXGTAR + 5) | |
| 147 | 159 | |
| 148 | 160 | /* Internal using */ |
| 149 | 161 | #define MSG_LENGTH_UNDEFINED -1 |
| 150 | 162 | |
| 151 | 163 | typedef enum { RTU=0, TCP } type_com_t; |
| 152 | -typedef enum { FLUSH_OR_CONNECT_ON_ERROR, NOP_ON_ERROR } error_handling_t; | |
| 153 | 164 | |
| 154 | 165 | /* This structure is byte-aligned */ |
| 155 | 166 | typedef struct { |
| ... | ... | @@ -183,7 +194,7 @@ typedef struct { |
| 183 | 194 | /* Parity: "even", "odd", "none" */ |
| 184 | 195 | char parity[5]; |
| 185 | 196 | /* In error_treat with TCP, do a reconnect or just dump the error */ |
| 186 | - uint8_t error_handling; | |
| 197 | + uint8_t error_recovery; | |
| 187 | 198 | /* IP address */ |
| 188 | 199 | char ip[16]; |
| 189 | 200 | /* Save old termios settings */ |
| ... | ... | @@ -201,171 +212,60 @@ typedef struct { |
| 201 | 212 | uint16_t *tab_holding_registers; |
| 202 | 213 | } modbus_mapping_t; |
| 203 | 214 | |
| 215 | +void modbus_init_rtu(modbus_param_t *mb_param, const char *device, | |
| 216 | + int baud, const char *parity, int data_bit, | |
| 217 | + int stop_bit, int slave); | |
| 218 | +void modbus_init_tcp(modbus_param_t *mb_param, const char *ip_address, int port, | |
| 219 | + int slave); | |
| 220 | +void modbus_set_slave(modbus_param_t *mb_param, int slave); | |
| 221 | +int modbus_set_error_recovery(modbus_param_t *mb_param, int enabled); | |
| 204 | 222 | |
| 205 | -/* All functions used for sending or receiving data return: | |
| 206 | - - the numbers of values (bits or word) if success (0 or more) | |
| 207 | - - less than 0 for exceptions errors | |
| 208 | -*/ | |
| 223 | +int modbus_connect(modbus_param_t *mb_param); | |
| 224 | +void modbus_close(modbus_param_t *mb_param); | |
| 225 | + | |
| 226 | +int modbus_flush(modbus_param_t *mb_param); | |
| 227 | +void modbus_set_debug(modbus_param_t *mb_param, int boolean); | |
| 228 | + | |
| 229 | +const char *modbus_strerror(int errnum); | |
| 209 | 230 | |
| 210 | -/* Reads the boolean status of coils and sets the array elements in | |
| 211 | - the destination to TRUE or FALSE */ | |
| 212 | 231 | int read_coil_status(modbus_param_t *mb_param, int start_addr, int nb, |
| 213 | 232 | uint8_t *dest); |
| 214 | - | |
| 215 | -/* Same as read_coil_status but reads the slaves input table */ | |
| 216 | 233 | int read_input_status(modbus_param_t *mb_param, int start_addr, int nb, |
| 217 | 234 | uint8_t *dest); |
| 218 | - | |
| 219 | -/* Reads the holding registers in a slave and put the data into an | |
| 220 | - array */ | |
| 221 | 235 | int read_holding_registers(modbus_param_t *mb_param, int start_addr, int nb, |
| 222 | 236 | uint16_t *dest); |
| 223 | - | |
| 224 | -/* Reads the input registers in a slave and put the data into an | |
| 225 | - array */ | |
| 226 | 237 | int read_input_registers(modbus_param_t *mb_param, int start_addr, int nb, |
| 227 | 238 | uint16_t *dest); |
| 228 | - | |
| 229 | -/* Turns ON or OFF a single coil in the slave device */ | |
| 230 | 239 | int force_single_coil(modbus_param_t *mb_param, int coil_addr, int state); |
| 231 | 240 | |
| 232 | -/* Sets a value in one holding register in the slave device */ | |
| 233 | 241 | int preset_single_register(modbus_param_t *mb_param, int reg_addr, int value); |
| 234 | - | |
| 235 | -/* Sets/resets the coils in the slave from an array in argument */ | |
| 236 | 242 | int force_multiple_coils(modbus_param_t *mb_param, int start_addr, int nb, |
| 237 | 243 | const uint8_t *data); |
| 238 | - | |
| 239 | -/* Copies the values in the slave from the array given in argument */ | |
| 240 | 244 | int preset_multiple_registers(modbus_param_t *mb_param, int start_addr, int nb, |
| 241 | 245 | const uint16_t *data); |
| 242 | - | |
| 243 | -/* Returns the slave id! */ | |
| 244 | 246 | int report_slave_id(modbus_param_t *mb_param, uint8_t *dest); |
| 245 | 247 | |
| 246 | -/* Initializes the modbus_param_t structure for RTU. | |
| 247 | - - device: "/dev/ttyS0" | |
| 248 | - - baud: 9600, 19200, 57600, 115200, etc | |
| 249 | - - parity: "even", "odd" or "none" | |
| 250 | - - data_bits: 5, 6, 7, 8 | |
| 251 | - - stop_bits: 1, 2 | |
| 252 | -*/ | |
| 253 | -void modbus_init_rtu(modbus_param_t *mb_param, const char *device, | |
| 254 | - int baud, const char *parity, int data_bit, | |
| 255 | - int stop_bit, int slave); | |
| 256 | - | |
| 257 | -/* Initializes the modbus_param_t structure for TCP. | |
| 258 | - - ip: "192.168.0.5" | |
| 259 | - - port: 1099 | |
| 260 | - - slave: 5 | |
| 261 | - | |
| 262 | - Set the port to MODBUS_TCP_DEFAULT_PORT to use the default one | |
| 263 | - (502). It's convenient to use a port number greater than or equal | |
| 264 | - to 1024 because it's not necessary to be root to use this port | |
| 265 | - number. | |
| 266 | -*/ | |
| 267 | -void modbus_init_tcp(modbus_param_t *mb_param, const char *ip_address, int port, | |
| 268 | - int slave); | |
| 269 | - | |
| 270 | -/* Define the slave number. | |
| 271 | - The special value MODBUS_BROADCAST_ADDRESS can be used. */ | |
| 272 | -void modbus_set_slave(modbus_param_t *mb_param, int slave); | |
| 273 | - | |
| 274 | -/* By default, the error handling mode used is CONNECT_ON_ERROR. | |
| 275 | - | |
| 276 | - With FLUSH_OR_CONNECT_ON_ERROR, the library will attempt an immediate | |
| 277 | - reconnection which may hang for several seconds if the network to | |
| 278 | - the remote target unit is down. | |
| 279 | - | |
| 280 | - With NOP_ON_ERROR, it is expected that the application will | |
| 281 | - check for network error returns and deal with them as necessary. | |
| 282 | - | |
| 283 | - This function is only useful in TCP mode. | |
| 284 | - */ | |
| 285 | -void modbus_set_error_handling(modbus_param_t *mb_param, error_handling_t error_handling); | |
| 286 | - | |
| 287 | -/* Establishes a modbus connexion. | |
| 288 | - Returns 0 on success or -1 on failure. */ | |
| 289 | -int modbus_connect(modbus_param_t *mb_param); | |
| 290 | - | |
| 291 | -/* Closes a modbus connection */ | |
| 292 | -void modbus_close(modbus_param_t *mb_param); | |
| 293 | - | |
| 294 | -/* Flush the pending request */ | |
| 295 | -void modbus_flush(modbus_param_t *mb_param); | |
| 296 | - | |
| 297 | -/* Activates the debug messages */ | |
| 298 | -void modbus_set_debug(modbus_param_t *mb_param, int boolean); | |
| 299 | - | |
| 300 | -/** | |
| 301 | - * SLAVE/CLIENT FUNCTIONS | |
| 302 | - **/ | |
| 303 | - | |
| 304 | -/* Allocates 4 arrays to store coils, input status, input registers and | |
| 305 | - holding registers. The pointers are stored in modbus_mapping structure. | |
| 306 | - | |
| 307 | - Returns 0 on success and -1 on failure | |
| 308 | - */ | |
| 309 | 248 | int modbus_mapping_new(modbus_mapping_t *mb_mapping, |
| 310 | 249 | int nb_coil_status, int nb_input_status, |
| 311 | 250 | int nb_holding_registers, int nb_input_registers); |
| 312 | - | |
| 313 | -/* Frees the 4 arrays */ | |
| 314 | 251 | void modbus_mapping_free(modbus_mapping_t *mb_mapping); |
| 315 | 252 | |
| 316 | -/* Listens for any query from one or many modbus masters in TCP. | |
| 317 | - | |
| 318 | - Returns: socket | |
| 319 | - */ | |
| 320 | 253 | int modbus_slave_listen_tcp(modbus_param_t *mb_param, int nb_connection); |
| 321 | - | |
| 322 | -/* Waits for a connection */ | |
| 323 | 254 | int modbus_slave_accept_tcp(modbus_param_t *mb_param, int *socket); |
| 324 | - | |
| 325 | -/* Listens for any query from a modbus master in TCP, requires the socket file | |
| 326 | - descriptor etablished with the master device in argument or -1 to use the | |
| 327 | - internal one of modbus_param_t. | |
| 328 | - | |
| 329 | - Returns: | |
| 330 | - - byte length of the message on success, or a negative error number if the | |
| 331 | - request fails | |
| 332 | - - query, message received | |
| 333 | -*/ | |
| 334 | 255 | int modbus_slave_receive(modbus_param_t *mb_param, int sockfd, uint8_t *query); |
| 335 | - | |
| 336 | -/* Manages the received query. | |
| 337 | - Analyses the query and constructs a response. | |
| 338 | - | |
| 339 | - If an error occurs, this function construct the response | |
| 340 | - accordingly. | |
| 341 | -*/ | |
| 342 | -void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query, | |
| 343 | - int query_length, modbus_mapping_t *mb_mapping); | |
| 344 | - | |
| 345 | -/* Closes a TCP socket */ | |
| 256 | +int modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query, | |
| 257 | + int query_length, modbus_mapping_t *mb_mapping); | |
| 346 | 258 | void modbus_slave_close_tcp(int socket); |
| 347 | 259 | |
| 348 | 260 | /** |
| 349 | 261 | * UTILS FUNCTIONS |
| 350 | 262 | **/ |
| 351 | 263 | |
| 352 | -/* Sets many input/coil status from a single byte value (all 8 bits of | |
| 353 | - the byte value are set) */ | |
| 354 | 264 | void set_bits_from_byte(uint8_t *dest, int address, const uint8_t value); |
| 355 | - | |
| 356 | -/* Sets many input/coil status from a table of bytes (only the bits | |
| 357 | - between address and address + nb_bits are set) */ | |
| 358 | -void set_bits_from_bytes(uint8_t *dest, int address, int nb_bits, | |
| 265 | +void set_bits_from_bytes(uint8_t *dest, int address, unsigned int nb_bits, | |
| 359 | 266 | const uint8_t *tab_byte); |
| 360 | - | |
| 361 | -/* Gets the byte value from many input/coil status. | |
| 362 | - To obtain a full byte, set nb_bits to 8. */ | |
| 363 | -uint8_t get_byte_from_bits(const uint8_t *src, int address, int nb_bits); | |
| 364 | - | |
| 365 | -/* Read a float from 4 bytes in Modbus format */ | |
| 267 | +uint8_t get_byte_from_bits(const uint8_t *src, int address, unsigned int nb_bits); | |
| 366 | 268 | float modbus_read_float(const uint16_t *src); |
| 367 | - | |
| 368 | -/* Write a float to 4 bytes in Modbus format */ | |
| 369 | 269 | void modbus_write_float(float real, uint16_t *dest); |
| 370 | 270 | |
| 371 | 271 | #ifdef __cplusplus | ... | ... |
tests/bandwidth-master.c
| ... | ... | @@ -21,6 +21,7 @@ |
| 21 | 21 | #include <stdlib.h> |
| 22 | 22 | #include <time.h> |
| 23 | 23 | #include <sys/time.h> |
| 24 | +#include <errno.h> | |
| 24 | 25 | |
| 25 | 26 | #include <modbus/modbus.h> |
| 26 | 27 | |
| ... | ... | @@ -44,18 +45,21 @@ int main(void) |
| 44 | 45 | uint16_t *tab_rp_registers; |
| 45 | 46 | modbus_param_t mb_param; |
| 46 | 47 | int i; |
| 47 | - int ret; | |
| 48 | 48 | int nb_points; |
| 49 | 49 | double elapsed; |
| 50 | 50 | uint32_t start; |
| 51 | 51 | uint32_t end; |
| 52 | 52 | uint32_t bytes; |
| 53 | 53 | uint32_t rate; |
| 54 | + int rc; | |
| 54 | 55 | |
| 55 | 56 | /* TCP */ |
| 56 | 57 | modbus_init_tcp(&mb_param, "127.0.0.1", 1502, SLAVE); |
| 57 | - if (modbus_connect(&mb_param) == -1) { | |
| 58 | - exit(1); | |
| 58 | + rc = modbus_connect(&mb_param); | |
| 59 | + if (rc == -1) { | |
| 60 | + fprintf(stderr, "Connexion failed: %s\n", | |
| 61 | + modbus_strerror(errno)); | |
| 62 | + return -1; | |
| 59 | 63 | } |
| 60 | 64 | |
| 61 | 65 | /* Allocate and initialize the memory to store the status */ |
| ... | ... | @@ -71,7 +75,11 @@ int main(void) |
| 71 | 75 | nb_points = MAX_STATUS; |
| 72 | 76 | start = gettime_ms(); |
| 73 | 77 | for (i=0; i<NB_LOOPS; i++) { |
| 74 | - ret = read_coil_status(&mb_param, 0, nb_points, tab_rp_status); | |
| 78 | + rc = read_coil_status(&mb_param, 0, nb_points, tab_rp_status); | |
| 79 | + if (rc == -1) { | |
| 80 | + fprintf(stderr, modbus_strerror(errno)); | |
| 81 | + return -1; | |
| 82 | + } | |
| 75 | 83 | } |
| 76 | 84 | end = gettime_ms(); |
| 77 | 85 | elapsed = end - start; |
| ... | ... | @@ -104,7 +112,11 @@ int main(void) |
| 104 | 112 | nb_points = MAX_REGISTERS; |
| 105 | 113 | start = gettime_ms(); |
| 106 | 114 | for (i=0; i<NB_LOOPS; i++) { |
| 107 | - ret = read_holding_registers(&mb_param, 0, nb_points, tab_rp_registers); | |
| 115 | + rc = read_holding_registers(&mb_param, 0, nb_points, tab_rp_registers); | |
| 116 | + if (rc == -1) { | |
| 117 | + fprintf(stderr, modbus_strerror(errno)); | |
| 118 | + return -1; | |
| 119 | + } | |
| 108 | 120 | } |
| 109 | 121 | end = gettime_ms(); |
| 110 | 122 | elapsed = end - start; | ... | ... |
tests/bandwidth-slave-many-up.c
| ... | ... | @@ -42,7 +42,7 @@ int main(void) |
| 42 | 42 | { |
| 43 | 43 | int master_socket; |
| 44 | 44 | modbus_param_t mb_param; |
| 45 | - int ret; | |
| 45 | + int rc; | |
| 46 | 46 | fd_set refset; |
| 47 | 47 | fd_set rdset; |
| 48 | 48 | |
| ... | ... | @@ -51,10 +51,11 @@ int main(void) |
| 51 | 51 | |
| 52 | 52 | modbus_init_tcp(&mb_param, "127.0.0.1", 1502, SLAVE); |
| 53 | 53 | |
| 54 | - ret = modbus_mapping_new(&mb_mapping, MAX_STATUS, 0, MAX_REGISTERS, 0); | |
| 55 | - if (ret < 0) { | |
| 56 | - fprintf(stderr, "Memory allocation failure\n"); | |
| 57 | - exit(1); | |
| 54 | + rc = modbus_mapping_new(&mb_mapping, MAX_STATUS, 0, MAX_REGISTERS, 0); | |
| 55 | + if (rc == -1) { | |
| 56 | + fprintf(stderr, "Failed to allocate the mapping: %s\n", | |
| 57 | + modbus_strerror(errno)); | |
| 58 | + return -1; | |
| 58 | 59 | } |
| 59 | 60 | |
| 60 | 61 | slave_socket = modbus_slave_listen_tcp(&mb_param, NB_CONNECTION); |
| ... | ... | @@ -107,9 +108,9 @@ int main(void) |
| 107 | 108 | /* An already connected master has sent a new query */ |
| 108 | 109 | uint8_t query[MAX_MESSAGE_LENGTH]; |
| 109 | 110 | |
| 110 | - ret = modbus_slave_receive(&mb_param, master_socket, query); | |
| 111 | - if (ret >= 0) { | |
| 112 | - modbus_slave_manage(&mb_param, query, ret, &mb_mapping); | |
| 111 | + rc = modbus_slave_receive(&mb_param, master_socket, query); | |
| 112 | + if (rc != -1) { | |
| 113 | + modbus_slave_manage(&mb_param, query, rc, &mb_mapping); | |
| 113 | 114 | } else { |
| 114 | 115 | /* Connection closed by the client, end of server */ |
| 115 | 116 | printf("Connection closed on socket %d\n", master_socket); | ... | ... |
tests/bandwidth-slave-one.c
| ... | ... | @@ -19,6 +19,7 @@ |
| 19 | 19 | #include <unistd.h> |
| 20 | 20 | #include <string.h> |
| 21 | 21 | #include <stdlib.h> |
| 22 | +#include <errno.h> | |
| 22 | 23 | |
| 23 | 24 | #include <modbus/modbus.h> |
| 24 | 25 | |
| ... | ... | @@ -29,33 +30,34 @@ int main(void) |
| 29 | 30 | int socket; |
| 30 | 31 | modbus_param_t mb_param; |
| 31 | 32 | modbus_mapping_t mb_mapping; |
| 32 | - int ret; | |
| 33 | + int rc; | |
| 33 | 34 | |
| 34 | 35 | modbus_init_tcp(&mb_param, "127.0.0.1", 1502, SLAVE); |
| 35 | 36 | |
| 36 | - ret = modbus_mapping_new(&mb_mapping, MAX_STATUS, 0, MAX_REGISTERS, 0); | |
| 37 | - if (ret < 0) { | |
| 38 | - fprintf(stderr, "Memory allocation failed\n"); | |
| 39 | - exit(1); | |
| 37 | + rc = modbus_mapping_new(&mb_mapping, MAX_STATUS, 0, MAX_REGISTERS, 0); | |
| 38 | + if (rc == -1) { | |
| 39 | + fprintf(stderr, "Failed to allocate the mapping: %s\n", | |
| 40 | + modbus_strerror(errno)); | |
| 41 | + return -1; | |
| 40 | 42 | } |
| 41 | 43 | |
| 42 | 44 | socket = modbus_slave_listen_tcp(&mb_param, 1); |
| 43 | 45 | modbus_slave_accept_tcp(&mb_param, &socket); |
| 44 | 46 | |
| 45 | - while (1) { | |
| 47 | + for(;;) { | |
| 46 | 48 | uint8_t query[MAX_MESSAGE_LENGTH]; |
| 47 | 49 | |
| 48 | - ret = modbus_slave_receive(&mb_param, -1, query); | |
| 49 | - if (ret >= 0) { | |
| 50 | - modbus_slave_manage(&mb_param, query, ret, &mb_mapping); | |
| 51 | - } else if (ret == CONNECTION_CLOSED) { | |
| 52 | - /* Connection closed by the client, end of server */ | |
| 53 | - break; | |
| 50 | + rc = modbus_slave_receive(&mb_param, -1, query); | |
| 51 | + if (rc >= 0) { | |
| 52 | + modbus_slave_manage(&mb_param, query, rc, &mb_mapping); | |
| 54 | 53 | } else { |
| 55 | - fprintf(stderr, "Error in modbus_listen (%d)\n", ret); | |
| 54 | + /* Connection closed by the client or server */ | |
| 55 | + break; | |
| 56 | 56 | } |
| 57 | 57 | } |
| 58 | 58 | |
| 59 | + printf("Quit the loop: %s\n", modbus_strerror(errno)); | |
| 60 | + | |
| 59 | 61 | close(socket); |
| 60 | 62 | modbus_mapping_free(&mb_mapping); |
| 61 | 63 | modbus_close(&mb_param); | ... | ... |
tests/random-test-master.c
| ... | ... | @@ -19,6 +19,7 @@ |
| 19 | 19 | #include <unistd.h> |
| 20 | 20 | #include <string.h> |
| 21 | 21 | #include <stdlib.h> |
| 22 | +#include <errno.h> | |
| 22 | 23 | |
| 23 | 24 | #include <modbus/modbus.h> |
| 24 | 25 | |
| ... | ... | @@ -45,7 +46,7 @@ |
| 45 | 46 | */ |
| 46 | 47 | int main(void) |
| 47 | 48 | { |
| 48 | - int ret; | |
| 49 | + int rc; | |
| 49 | 50 | int nb_fail; |
| 50 | 51 | int nb_loop; |
| 51 | 52 | int addr; |
| ... | ... | @@ -63,7 +64,9 @@ int main(void) |
| 63 | 64 | modbus_init_tcp(&mb_param, "127.0.0.1", 1502, SLAVE); |
| 64 | 65 | modbus_set_debug(&mb_param, TRUE); |
| 65 | 66 | if (modbus_connect(&mb_param) == -1) { |
| 66 | - exit(1); | |
| 67 | + fprintf(stderr, "Connection failed: %s\n", | |
| 68 | + modbus_strerror(errno)); | |
| 69 | + return -1; | |
| 67 | 70 | } |
| 68 | 71 | |
| 69 | 72 | /* Allocate and initialize the different memory spaces */ |
| ... | ... | @@ -94,16 +97,16 @@ int main(void) |
| 94 | 97 | nb = ADDRESS_END - addr; |
| 95 | 98 | |
| 96 | 99 | /* SINGLE COIL */ |
| 97 | - ret = force_single_coil(&mb_param, addr, tab_rq_status[0]); | |
| 98 | - if (ret != 1) { | |
| 99 | - printf("ERROR force_single_coil (%d)\n", ret); | |
| 100 | + rc = force_single_coil(&mb_param, addr, tab_rq_status[0]); | |
| 101 | + if (rc != 1) { | |
| 102 | + printf("ERROR force_single_coil (%d)\n", rc); | |
| 100 | 103 | printf("Slave = %d, address = %d, value = %d\n", |
| 101 | 104 | SLAVE, addr, tab_rq_status[0]); |
| 102 | 105 | nb_fail++; |
| 103 | 106 | } else { |
| 104 | - ret = read_coil_status(&mb_param, addr, 1, tab_rp_status); | |
| 105 | - if (ret != 1 || tab_rq_status[0] != tab_rp_status[0]) { | |
| 106 | - printf("ERROR read_coil_status single (%d)\n", ret); | |
| 107 | + rc = read_coil_status(&mb_param, addr, 1, tab_rp_status); | |
| 108 | + if (rc != 1 || tab_rq_status[0] != tab_rp_status[0]) { | |
| 109 | + printf("ERROR read_coil_status single (%d)\n", rc); | |
| 107 | 110 | printf("Slave = %d, address = %d\n", |
| 108 | 111 | SLAVE, addr); |
| 109 | 112 | nb_fail++; |
| ... | ... | @@ -111,15 +114,15 @@ int main(void) |
| 111 | 114 | } |
| 112 | 115 | |
| 113 | 116 | /* MULTIPLE COILS */ |
| 114 | - ret = force_multiple_coils(&mb_param, addr, nb, tab_rq_status); | |
| 115 | - if (ret != nb) { | |
| 116 | - printf("ERROR force_multiple_coils (%d)\n", ret); | |
| 117 | + rc = force_multiple_coils(&mb_param, addr, nb, tab_rq_status); | |
| 118 | + if (rc != nb) { | |
| 119 | + printf("ERROR force_multiple_coils (%d)\n", rc); | |
| 117 | 120 | printf("Slave = %d, address = %d, nb = %d\n", |
| 118 | 121 | SLAVE, addr, nb); |
| 119 | 122 | nb_fail++; |
| 120 | 123 | } else { |
| 121 | - ret = read_coil_status(&mb_param, addr, nb, tab_rp_status); | |
| 122 | - if (ret != nb) { | |
| 124 | + rc = read_coil_status(&mb_param, addr, nb, tab_rp_status); | |
| 125 | + if (rc != nb) { | |
| 123 | 126 | printf("ERROR read_coil_status\n"); |
| 124 | 127 | printf("Slave = %d, address = %d, nb = %d\n", |
| 125 | 128 | SLAVE, addr, nb); |
| ... | ... | @@ -139,16 +142,16 @@ int main(void) |
| 139 | 142 | } |
| 140 | 143 | |
| 141 | 144 | /* SINGLE REGISTER */ |
| 142 | - ret = preset_single_register(&mb_param, addr, tab_rq_registers[0]); | |
| 143 | - if (ret != 1) { | |
| 144 | - printf("ERROR preset_single_register (%d)\n", ret); | |
| 145 | + rc = preset_single_register(&mb_param, addr, tab_rq_registers[0]); | |
| 146 | + if (rc != 1) { | |
| 147 | + printf("ERROR preset_single_register (%d)\n", rc); | |
| 145 | 148 | printf("Slave = %d, address = %d, value = %d (0x%X)\n", |
| 146 | 149 | SLAVE, addr, tab_rq_registers[0], tab_rq_registers[0]); |
| 147 | 150 | nb_fail++; |
| 148 | 151 | } else { |
| 149 | - ret = read_holding_registers(&mb_param, addr, 1, tab_rp_registers); | |
| 150 | - if (ret != 1) { | |
| 151 | - printf("ERROR read_holding_registers single (%d)\n", ret); | |
| 152 | + rc = read_holding_registers(&mb_param, addr, 1, tab_rp_registers); | |
| 153 | + if (rc != 1) { | |
| 154 | + printf("ERROR read_holding_registers single (%d)\n", rc); | |
| 152 | 155 | printf("Slave = %d, address = %d\n", |
| 153 | 156 | SLAVE, addr); |
| 154 | 157 | nb_fail++; |
| ... | ... | @@ -165,18 +168,18 @@ int main(void) |
| 165 | 168 | } |
| 166 | 169 | |
| 167 | 170 | /* MULTIPLE REGISTERS */ |
| 168 | - ret = preset_multiple_registers(&mb_param, addr, nb, | |
| 171 | + rc = preset_multiple_registers(&mb_param, addr, nb, | |
| 169 | 172 | tab_rq_registers); |
| 170 | - if (ret != nb) { | |
| 171 | - printf("ERROR preset_multiple_registers (%d)\n", ret); | |
| 173 | + if (rc != nb) { | |
| 174 | + printf("ERROR preset_multiple_registers (%d)\n", rc); | |
| 172 | 175 | printf("Slave = %d, address = %d, nb = %d\n", |
| 173 | 176 | SLAVE, addr, nb); |
| 174 | 177 | nb_fail++; |
| 175 | 178 | } else { |
| 176 | - ret = read_holding_registers(&mb_param, addr, nb, | |
| 179 | + rc = read_holding_registers(&mb_param, addr, nb, | |
| 177 | 180 | tab_rp_registers); |
| 178 | - if (ret != nb) { | |
| 179 | - printf("ERROR read_holding_registers (%d)\n", ret); | |
| 181 | + if (rc != nb) { | |
| 182 | + printf("ERROR read_holding_registers (%d)\n", rc); | |
| 180 | 183 | printf("Slave = %d, address = %d, nb = %d\n", |
| 181 | 184 | SLAVE, addr, nb); |
| 182 | 185 | nb_fail++; | ... | ... |
tests/random-test-slave.c
| ... | ... | @@ -18,6 +18,7 @@ |
| 18 | 18 | #include <stdio.h> |
| 19 | 19 | #include <unistd.h> |
| 20 | 20 | #include <stdlib.h> |
| 21 | +#include <errno.h> | |
| 21 | 22 | |
| 22 | 23 | #include <modbus/modbus.h> |
| 23 | 24 | |
| ... | ... | @@ -28,36 +29,37 @@ int main(void) |
| 28 | 29 | int socket; |
| 29 | 30 | modbus_param_t mb_param; |
| 30 | 31 | modbus_mapping_t mb_mapping; |
| 31 | - int ret; | |
| 32 | + int rc; | |
| 32 | 33 | |
| 33 | 34 | modbus_init_tcp(&mb_param, "127.0.0.1", 1502, SLAVE); |
| 34 | 35 | /* modbus_set_debug(&mb_param, TRUE); */ |
| 35 | 36 | |
| 36 | - ret = modbus_mapping_new(&mb_mapping, 500, 500, 500, 500); | |
| 37 | - if (ret < 0) { | |
| 38 | - fprintf(stderr, "Memory allocation failed\n"); | |
| 39 | - exit(1); | |
| 37 | + rc = modbus_mapping_new(&mb_mapping, 500, 500, 500, 500); | |
| 38 | + if (rc == -1) { | |
| 39 | + fprintf(stderr, "Failed to allocate the mapping: %s\n", | |
| 40 | + modbus_strerror(errno)); | |
| 41 | + return -1; | |
| 40 | 42 | } |
| 41 | 43 | |
| 42 | 44 | socket = modbus_slave_listen_tcp(&mb_param, 1); |
| 43 | 45 | modbus_slave_accept_tcp(&mb_param, &socket); |
| 44 | 46 | |
| 45 | - while (1) { | |
| 47 | + for (;;) { | |
| 46 | 48 | uint8_t query[MAX_MESSAGE_LENGTH]; |
| 47 | - int ret; | |
| 49 | + int rc; | |
| 48 | 50 | |
| 49 | - ret = modbus_slave_receive(&mb_param, -1, query); | |
| 50 | - if (ret >= 0) { | |
| 51 | - /* ret is the query size */ | |
| 52 | - modbus_slave_manage(&mb_param, query, ret, &mb_mapping); | |
| 53 | - } else if (ret == CONNECTION_CLOSED) { | |
| 54 | - /* Connection closed by the client, end of server */ | |
| 55 | - break; | |
| 51 | + rc = modbus_slave_receive(&mb_param, -1, query); | |
| 52 | + if (rc != -1) { | |
| 53 | + /* rc is the query size */ | |
| 54 | + modbus_slave_manage(&mb_param, query, rc, &mb_mapping); | |
| 56 | 55 | } else { |
| 57 | - fprintf(stderr, "Error in modbus_listen (%d)\n", ret); | |
| 56 | + /* Connection closed by the client or error */ | |
| 57 | + break; | |
| 58 | 58 | } |
| 59 | 59 | } |
| 60 | 60 | |
| 61 | + printf("Quit the loop: %s\n", modbus_strerror(errno)); | |
| 62 | + | |
| 61 | 63 | close(socket); |
| 62 | 64 | modbus_mapping_free(&mb_mapping); |
| 63 | 65 | modbus_close(&mb_param); | ... | ... |
tests/unit-test-master.c
| ... | ... | @@ -19,6 +19,7 @@ |
| 19 | 19 | #include <unistd.h> |
| 20 | 20 | #include <string.h> |
| 21 | 21 | #include <stdlib.h> |
| 22 | +#include <errno.h> | |
| 22 | 23 | |
| 23 | 24 | #include <modbus/modbus.h> |
| 24 | 25 | #include "unit-test.h" |
| ... | ... | @@ -36,7 +37,7 @@ int main(void) |
| 36 | 37 | uint8_t value; |
| 37 | 38 | int address; |
| 38 | 39 | int nb_points; |
| 39 | - int ret; | |
| 40 | + int rc; | |
| 40 | 41 | float real; |
| 41 | 42 | |
| 42 | 43 | /* RTU parity : none, even, odd */ |
| ... | ... | @@ -44,10 +45,12 @@ int main(void) |
| 44 | 45 | |
| 45 | 46 | /* TCP */ |
| 46 | 47 | modbus_init_tcp(&mb_param, "127.0.0.1", 1502, SLAVE); |
| 47 | -/* modbus_set_debug(&mb_param, TRUE); */ | |
| 48 | + modbus_set_debug(&mb_param, TRUE); | |
| 48 | 49 | |
| 49 | 50 | if (modbus_connect(&mb_param) == -1) { |
| 50 | - exit(1); | |
| 51 | + fprintf(stderr, "Connection failed: %s\n", | |
| 52 | + modbus_strerror(errno)); | |
| 53 | + return -1; | |
| 51 | 54 | } |
| 52 | 55 | |
| 53 | 56 | /* Allocate and initialize the memory to store the status */ |
| ... | ... | @@ -70,20 +73,20 @@ int main(void) |
| 70 | 73 | /** COIL STATUS **/ |
| 71 | 74 | |
| 72 | 75 | /* Single */ |
| 73 | - ret = force_single_coil(&mb_param, UT_COIL_STATUS_ADDRESS, ON); | |
| 76 | + rc = force_single_coil(&mb_param, UT_COIL_STATUS_ADDRESS, ON); | |
| 74 | 77 | printf("1/2 force_single_coil: "); |
| 75 | - if (ret == 1) { | |
| 78 | + if (rc == 1) { | |
| 76 | 79 | printf("OK\n"); |
| 77 | 80 | } else { |
| 78 | 81 | printf("FAILED\n"); |
| 79 | 82 | goto close; |
| 80 | 83 | } |
| 81 | 84 | |
| 82 | - ret = read_coil_status(&mb_param, UT_COIL_STATUS_ADDRESS, 1, | |
| 83 | - tab_rp_status); | |
| 85 | + rc = read_coil_status(&mb_param, UT_COIL_STATUS_ADDRESS, 1, | |
| 86 | + tab_rp_status); | |
| 84 | 87 | printf("2/2 read_coil_status: "); |
| 85 | - if (ret != 1) { | |
| 86 | - printf("FAILED (nb points %d)\n", ret); | |
| 88 | + if (rc != 1) { | |
| 89 | + printf("FAILED (nb points %d)\n", rc); | |
| 87 | 90 | goto close; |
| 88 | 91 | } |
| 89 | 92 | |
| ... | ... | @@ -100,12 +103,12 @@ int main(void) |
| 100 | 103 | |
| 101 | 104 | set_bits_from_bytes(tab_value, 0, UT_COIL_STATUS_NB_POINTS, |
| 102 | 105 | UT_COIL_STATUS_TAB); |
| 103 | - ret = force_multiple_coils(&mb_param, | |
| 104 | - UT_COIL_STATUS_ADDRESS, | |
| 105 | - UT_COIL_STATUS_NB_POINTS, | |
| 106 | - tab_value); | |
| 106 | + rc = force_multiple_coils(&mb_param, | |
| 107 | + UT_COIL_STATUS_ADDRESS, | |
| 108 | + UT_COIL_STATUS_NB_POINTS, | |
| 109 | + tab_value); | |
| 107 | 110 | printf("1/2 force_multiple_coils: "); |
| 108 | - if (ret == UT_COIL_STATUS_NB_POINTS) { | |
| 111 | + if (rc == UT_COIL_STATUS_NB_POINTS) { | |
| 109 | 112 | printf("OK\n"); |
| 110 | 113 | } else { |
| 111 | 114 | printf("FAILED\n"); |
| ... | ... | @@ -113,11 +116,11 @@ int main(void) |
| 113 | 116 | } |
| 114 | 117 | } |
| 115 | 118 | |
| 116 | - ret = read_coil_status(&mb_param, UT_COIL_STATUS_ADDRESS, | |
| 117 | - UT_COIL_STATUS_NB_POINTS, tab_rp_status); | |
| 119 | + rc = read_coil_status(&mb_param, UT_COIL_STATUS_ADDRESS, | |
| 120 | + UT_COIL_STATUS_NB_POINTS, tab_rp_status); | |
| 118 | 121 | printf("2/2 read_coil_status: "); |
| 119 | - if (ret != UT_COIL_STATUS_NB_POINTS) { | |
| 120 | - printf("FAILED (nb points %d)\n", ret); | |
| 122 | + if (rc != UT_COIL_STATUS_NB_POINTS) { | |
| 123 | + printf("FAILED (nb points %d)\n", rc); | |
| 121 | 124 | goto close; |
| 122 | 125 | } |
| 123 | 126 | |
| ... | ... | @@ -141,12 +144,12 @@ int main(void) |
| 141 | 144 | /* End of multiple coils */ |
| 142 | 145 | |
| 143 | 146 | /** INPUT STATUS **/ |
| 144 | - ret = read_input_status(&mb_param, UT_INPUT_STATUS_ADDRESS, | |
| 145 | - UT_INPUT_STATUS_NB_POINTS, tab_rp_status); | |
| 147 | + rc = read_input_status(&mb_param, UT_INPUT_STATUS_ADDRESS, | |
| 148 | + UT_INPUT_STATUS_NB_POINTS, tab_rp_status); | |
| 146 | 149 | printf("1/1 read_input_status: "); |
| 147 | 150 | |
| 148 | - if (ret != UT_INPUT_STATUS_NB_POINTS) { | |
| 149 | - printf("FAILED (nb points %d)\n", ret); | |
| 151 | + if (rc != UT_INPUT_STATUS_NB_POINTS) { | |
| 152 | + printf("FAILED (nb points %d)\n", rc); | |
| 150 | 153 | goto close; |
| 151 | 154 | } |
| 152 | 155 | |
| ... | ... | @@ -171,22 +174,22 @@ int main(void) |
| 171 | 174 | /** HOLDING REGISTERS **/ |
| 172 | 175 | |
| 173 | 176 | /* Single register */ |
| 174 | - ret = preset_single_register(&mb_param, | |
| 175 | - UT_HOLDING_REGISTERS_ADDRESS, 0x1234); | |
| 177 | + rc = preset_single_register(&mb_param, | |
| 178 | + UT_HOLDING_REGISTERS_ADDRESS, 0x1234); | |
| 176 | 179 | printf("1/2 preset_single_register: "); |
| 177 | - if (ret == 1) { | |
| 180 | + if (rc == 1) { | |
| 178 | 181 | printf("OK\n"); |
| 179 | 182 | } else { |
| 180 | 183 | printf("FAILED\n"); |
| 181 | 184 | goto close; |
| 182 | 185 | } |
| 183 | 186 | |
| 184 | - ret = read_holding_registers(&mb_param, | |
| 185 | - UT_HOLDING_REGISTERS_ADDRESS, | |
| 186 | - 1, tab_rp_registers); | |
| 187 | + rc = read_holding_registers(&mb_param, | |
| 188 | + UT_HOLDING_REGISTERS_ADDRESS, | |
| 189 | + 1, tab_rp_registers); | |
| 187 | 190 | printf("2/2 read_holding_registers: "); |
| 188 | - if (ret != 1) { | |
| 189 | - printf("FAILED (nb points %d)\n", ret); | |
| 191 | + if (rc != 1) { | |
| 192 | + printf("FAILED (nb points %d)\n", rc); | |
| 190 | 193 | goto close; |
| 191 | 194 | } |
| 192 | 195 | |
| ... | ... | @@ -199,25 +202,25 @@ int main(void) |
| 199 | 202 | /* End of single register */ |
| 200 | 203 | |
| 201 | 204 | /* Many registers */ |
| 202 | - ret = preset_multiple_registers(&mb_param, | |
| 203 | - UT_HOLDING_REGISTERS_ADDRESS, | |
| 204 | - UT_HOLDING_REGISTERS_NB_POINTS, | |
| 205 | - UT_HOLDING_REGISTERS_TAB); | |
| 205 | + rc = preset_multiple_registers(&mb_param, | |
| 206 | + UT_HOLDING_REGISTERS_ADDRESS, | |
| 207 | + UT_HOLDING_REGISTERS_NB_POINTS, | |
| 208 | + UT_HOLDING_REGISTERS_TAB); | |
| 206 | 209 | printf("1/2 preset_multiple_registers: "); |
| 207 | - if (ret == UT_HOLDING_REGISTERS_NB_POINTS) { | |
| 210 | + if (rc == UT_HOLDING_REGISTERS_NB_POINTS) { | |
| 208 | 211 | printf("OK\n"); |
| 209 | 212 | } else { |
| 210 | 213 | printf("FAILED\n"); |
| 211 | 214 | goto close; |
| 212 | 215 | } |
| 213 | 216 | |
| 214 | - ret = read_holding_registers(&mb_param, | |
| 215 | - UT_HOLDING_REGISTERS_ADDRESS, | |
| 216 | - UT_HOLDING_REGISTERS_NB_POINTS, | |
| 217 | - tab_rp_registers); | |
| 217 | + rc = read_holding_registers(&mb_param, | |
| 218 | + UT_HOLDING_REGISTERS_ADDRESS, | |
| 219 | + UT_HOLDING_REGISTERS_NB_POINTS, | |
| 220 | + tab_rp_registers); | |
| 218 | 221 | printf("2/2 read_holding_registers: "); |
| 219 | - if (ret != UT_HOLDING_REGISTERS_NB_POINTS) { | |
| 220 | - printf("FAILED (nb points %d)\n", ret); | |
| 222 | + if (rc != UT_HOLDING_REGISTERS_NB_POINTS) { | |
| 223 | + printf("FAILED (nb points %d)\n", rc); | |
| 221 | 224 | goto close; |
| 222 | 225 | } |
| 223 | 226 | |
| ... | ... | @@ -234,13 +237,13 @@ int main(void) |
| 234 | 237 | |
| 235 | 238 | |
| 236 | 239 | /** INPUT REGISTERS **/ |
| 237 | - ret = read_input_registers(&mb_param, | |
| 238 | - UT_INPUT_REGISTERS_ADDRESS, | |
| 239 | - UT_INPUT_REGISTERS_NB_POINTS, | |
| 240 | - tab_rp_registers); | |
| 240 | + rc = read_input_registers(&mb_param, | |
| 241 | + UT_INPUT_REGISTERS_ADDRESS, | |
| 242 | + UT_INPUT_REGISTERS_NB_POINTS, | |
| 243 | + tab_rp_registers); | |
| 241 | 244 | printf("1/1 read_input_registers: "); |
| 242 | - if (ret != UT_INPUT_REGISTERS_NB_POINTS) { | |
| 243 | - printf("FAILED (nb points %d)\n", ret); | |
| 245 | + if (rc != UT_INPUT_REGISTERS_NB_POINTS) { | |
| 246 | + printf("FAILED (nb points %d)\n", rc); | |
| 244 | 247 | goto close; |
| 245 | 248 | } |
| 246 | 249 | |
| ... | ... | @@ -284,83 +287,83 @@ int main(void) |
| 284 | 287 | /* The mapping begins at 0 and ending at address + nb_points so |
| 285 | 288 | * the addresses below are not valid. */ |
| 286 | 289 | |
| 287 | - ret = read_coil_status(&mb_param, | |
| 288 | - UT_COIL_STATUS_ADDRESS, | |
| 289 | - UT_COIL_STATUS_NB_POINTS + 1, | |
| 290 | - tab_rp_status); | |
| 290 | + rc = read_coil_status(&mb_param, | |
| 291 | + UT_COIL_STATUS_ADDRESS, | |
| 292 | + UT_COIL_STATUS_NB_POINTS + 1, | |
| 293 | + tab_rp_status); | |
| 291 | 294 | printf("* read_coil_status: "); |
| 292 | - if (ret == ILLEGAL_DATA_ADDRESS) | |
| 295 | + if (rc == -1 && errno == EMBXILADD) | |
| 293 | 296 | printf("OK\n"); |
| 294 | 297 | else { |
| 295 | 298 | printf("FAILED\n"); |
| 296 | 299 | goto close; |
| 297 | 300 | } |
| 298 | 301 | |
| 299 | - ret = read_input_status(&mb_param, | |
| 300 | - UT_INPUT_STATUS_ADDRESS, | |
| 301 | - UT_INPUT_STATUS_NB_POINTS + 1, | |
| 302 | - tab_rp_status); | |
| 302 | + rc = read_input_status(&mb_param, | |
| 303 | + UT_INPUT_STATUS_ADDRESS, | |
| 304 | + UT_INPUT_STATUS_NB_POINTS + 1, | |
| 305 | + tab_rp_status); | |
| 303 | 306 | printf("* read_input_status: "); |
| 304 | - if (ret == ILLEGAL_DATA_ADDRESS) | |
| 307 | + if (rc == -1 && errno == EMBXILADD) | |
| 305 | 308 | printf("OK\n"); |
| 306 | 309 | else { |
| 307 | 310 | printf("FAILED\n"); |
| 308 | 311 | goto close; |
| 309 | 312 | } |
| 310 | 313 | |
| 311 | - ret = read_holding_registers(&mb_param, | |
| 312 | - UT_HOLDING_REGISTERS_ADDRESS, | |
| 313 | - UT_HOLDING_REGISTERS_NB_POINTS + 1, | |
| 314 | - tab_rp_registers); | |
| 314 | + rc = read_holding_registers(&mb_param, | |
| 315 | + UT_HOLDING_REGISTERS_ADDRESS, | |
| 316 | + UT_HOLDING_REGISTERS_NB_POINTS + 1, | |
| 317 | + tab_rp_registers); | |
| 315 | 318 | printf("* read_holding_registers: "); |
| 316 | - if (ret == ILLEGAL_DATA_ADDRESS) | |
| 319 | + if (rc == -1 && errno == EMBXILADD) | |
| 317 | 320 | printf("OK\n"); |
| 318 | 321 | else { |
| 319 | 322 | printf("FAILED\n"); |
| 320 | 323 | goto close; |
| 321 | 324 | } |
| 322 | 325 | |
| 323 | - ret = read_input_registers(&mb_param, | |
| 324 | - UT_INPUT_REGISTERS_ADDRESS, | |
| 325 | - UT_INPUT_REGISTERS_NB_POINTS + 1, | |
| 326 | - tab_rp_registers); | |
| 326 | + rc = read_input_registers(&mb_param, | |
| 327 | + UT_INPUT_REGISTERS_ADDRESS, | |
| 328 | + UT_INPUT_REGISTERS_NB_POINTS + 1, | |
| 329 | + tab_rp_registers); | |
| 327 | 330 | printf("* read_input_registers: "); |
| 328 | - if (ret == ILLEGAL_DATA_ADDRESS) | |
| 331 | + if (rc == -1 && errno == EMBXILADD) | |
| 329 | 332 | printf("OK\n"); |
| 330 | 333 | else { |
| 331 | 334 | printf("FAILED\n"); |
| 332 | 335 | goto close; |
| 333 | 336 | } |
| 334 | 337 | |
| 335 | - ret = force_single_coil(&mb_param, | |
| 336 | - UT_COIL_STATUS_ADDRESS + UT_COIL_STATUS_NB_POINTS, | |
| 337 | - ON); | |
| 338 | + rc = force_single_coil(&mb_param, | |
| 339 | + UT_COIL_STATUS_ADDRESS + UT_COIL_STATUS_NB_POINTS, | |
| 340 | + ON); | |
| 338 | 341 | printf("* force_single_coil: "); |
| 339 | - if (ret == ILLEGAL_DATA_ADDRESS) { | |
| 342 | + if (rc == -1 && errno == EMBXILADD) { | |
| 340 | 343 | printf("OK\n"); |
| 341 | 344 | } else { |
| 342 | 345 | printf("FAILED\n"); |
| 343 | 346 | goto close; |
| 344 | 347 | } |
| 345 | 348 | |
| 346 | - ret = force_multiple_coils(&mb_param, | |
| 347 | - UT_COIL_STATUS_ADDRESS + UT_COIL_STATUS_NB_POINTS, | |
| 348 | - UT_COIL_STATUS_NB_POINTS, | |
| 349 | - tab_rp_status); | |
| 349 | + rc = force_multiple_coils(&mb_param, | |
| 350 | + UT_COIL_STATUS_ADDRESS + UT_COIL_STATUS_NB_POINTS, | |
| 351 | + UT_COIL_STATUS_NB_POINTS, | |
| 352 | + tab_rp_status); | |
| 350 | 353 | printf("* force_multiple_coils: "); |
| 351 | - if (ret == ILLEGAL_DATA_ADDRESS) { | |
| 354 | + if (rc == -1 && errno == EMBXILADD) { | |
| 352 | 355 | printf("OK\n"); |
| 353 | 356 | } else { |
| 354 | 357 | printf("FAILED\n"); |
| 355 | 358 | goto close; |
| 356 | 359 | } |
| 357 | 360 | |
| 358 | - ret = preset_multiple_registers(&mb_param, | |
| 359 | - UT_HOLDING_REGISTERS_ADDRESS + UT_HOLDING_REGISTERS_NB_POINTS, | |
| 360 | - UT_HOLDING_REGISTERS_NB_POINTS, | |
| 361 | - tab_rp_registers); | |
| 361 | + rc = preset_multiple_registers(&mb_param, | |
| 362 | + UT_HOLDING_REGISTERS_ADDRESS + UT_HOLDING_REGISTERS_NB_POINTS, | |
| 363 | + UT_HOLDING_REGISTERS_NB_POINTS, | |
| 364 | + tab_rp_registers); | |
| 362 | 365 | printf("* preset_multiple_registers: "); |
| 363 | - if (ret == ILLEGAL_DATA_ADDRESS) { | |
| 366 | + if (rc == -1 && errno == EMBXILADD) { | |
| 364 | 367 | printf("OK\n"); |
| 365 | 368 | } else { |
| 366 | 369 | printf("FAILED\n"); |
| ... | ... | @@ -371,72 +374,72 @@ int main(void) |
| 371 | 374 | /** TOO MANY DATA **/ |
| 372 | 375 | printf("\nTEST TOO MANY DATA ERROR:\n"); |
| 373 | 376 | |
| 374 | - ret = read_coil_status(&mb_param, | |
| 375 | - UT_COIL_STATUS_ADDRESS, | |
| 376 | - MAX_STATUS + 1, | |
| 377 | - tab_rp_status); | |
| 377 | + rc = read_coil_status(&mb_param, | |
| 378 | + UT_COIL_STATUS_ADDRESS, | |
| 379 | + MAX_STATUS + 1, | |
| 380 | + tab_rp_status); | |
| 378 | 381 | printf("* read_coil_status: "); |
| 379 | - if (ret == INVALID_DATA) { | |
| 382 | + if (rc == -1 && errno == EMBMDATA) { | |
| 380 | 383 | printf("OK\n"); |
| 381 | 384 | } else { |
| 382 | 385 | printf("FAILED\n"); |
| 383 | 386 | goto close; |
| 384 | 387 | } |
| 385 | 388 | |
| 386 | - ret = read_input_status(&mb_param, | |
| 387 | - UT_INPUT_STATUS_ADDRESS, | |
| 388 | - MAX_STATUS + 1, | |
| 389 | - tab_rp_status); | |
| 389 | + rc = read_input_status(&mb_param, | |
| 390 | + UT_INPUT_STATUS_ADDRESS, | |
| 391 | + MAX_STATUS + 1, | |
| 392 | + tab_rp_status); | |
| 390 | 393 | printf("* read_input_status: "); |
| 391 | - if (ret == INVALID_DATA) { | |
| 394 | + if (rc == -1 && errno == EMBMDATA) { | |
| 392 | 395 | printf("OK\n"); |
| 393 | 396 | } else { |
| 394 | 397 | printf("FAILED\n"); |
| 395 | 398 | goto close; |
| 396 | 399 | } |
| 397 | 400 | |
| 398 | - ret = read_holding_registers(&mb_param, | |
| 399 | - UT_HOLDING_REGISTERS_ADDRESS, | |
| 400 | - MAX_REGISTERS + 1, | |
| 401 | - tab_rp_registers); | |
| 401 | + rc = read_holding_registers(&mb_param, | |
| 402 | + UT_HOLDING_REGISTERS_ADDRESS, | |
| 403 | + MAX_REGISTERS + 1, | |
| 404 | + tab_rp_registers); | |
| 402 | 405 | printf("* read_holding_registers: "); |
| 403 | - if (ret == INVALID_DATA) { | |
| 406 | + if (rc == -1 && errno == EMBMDATA) { | |
| 404 | 407 | printf("OK\n"); |
| 405 | 408 | } else { |
| 406 | 409 | printf("FAILED\n"); |
| 407 | 410 | goto close; |
| 408 | 411 | } |
| 409 | 412 | |
| 410 | - ret = read_input_registers(&mb_param, | |
| 411 | - UT_INPUT_REGISTERS_ADDRESS, | |
| 412 | - MAX_REGISTERS + 1, | |
| 413 | - tab_rp_registers); | |
| 413 | + rc = read_input_registers(&mb_param, | |
| 414 | + UT_INPUT_REGISTERS_ADDRESS, | |
| 415 | + MAX_REGISTERS + 1, | |
| 416 | + tab_rp_registers); | |
| 414 | 417 | printf("* read_input_registers: "); |
| 415 | - if (ret == INVALID_DATA) { | |
| 418 | + if (rc == -1 && errno == EMBMDATA) { | |
| 416 | 419 | printf("OK\n"); |
| 417 | 420 | } else { |
| 418 | 421 | printf("FAILED\n"); |
| 419 | 422 | goto close; |
| 420 | 423 | } |
| 421 | 424 | |
| 422 | - ret = force_multiple_coils(&mb_param, | |
| 423 | - UT_COIL_STATUS_ADDRESS, | |
| 424 | - MAX_STATUS + 1, | |
| 425 | - tab_rp_status); | |
| 425 | + rc = force_multiple_coils(&mb_param, | |
| 426 | + UT_COIL_STATUS_ADDRESS, | |
| 427 | + MAX_STATUS + 1, | |
| 428 | + tab_rp_status); | |
| 426 | 429 | printf("* force_multiple_coils: "); |
| 427 | - if (ret == INVALID_DATA) { | |
| 430 | + if (rc == -1 && errno == EMBMDATA) { | |
| 428 | 431 | printf("OK\n"); |
| 429 | 432 | } else { |
| 430 | 433 | goto close; |
| 431 | 434 | printf("FAILED\n"); |
| 432 | 435 | } |
| 433 | 436 | |
| 434 | - ret = preset_multiple_registers(&mb_param, | |
| 435 | - UT_HOLDING_REGISTERS_ADDRESS, | |
| 436 | - MAX_REGISTERS + 1, | |
| 437 | - tab_rp_registers); | |
| 437 | + rc = preset_multiple_registers(&mb_param, | |
| 438 | + UT_HOLDING_REGISTERS_ADDRESS, | |
| 439 | + MAX_REGISTERS + 1, | |
| 440 | + tab_rp_registers); | |
| 438 | 441 | printf("* preset_multiple_registers: "); |
| 439 | - if (ret == INVALID_DATA) { | |
| 442 | + if (rc == -1 && errno == EMBMDATA) { | |
| 440 | 443 | printf("OK\n"); |
| 441 | 444 | } else { |
| 442 | 445 | printf("FAILED\n"); |
| ... | ... | @@ -446,12 +449,12 @@ int main(void) |
| 446 | 449 | /** SLAVE REPLY **/ |
| 447 | 450 | printf("\nTEST SLAVE REPLY:\n"); |
| 448 | 451 | modbus_set_slave(&mb_param, 18); |
| 449 | - ret = read_holding_registers(&mb_param, | |
| 450 | - UT_HOLDING_REGISTERS_ADDRESS+1, | |
| 451 | - UT_HOLDING_REGISTERS_NB_POINTS, | |
| 452 | - tab_rp_registers); | |
| 452 | + rc = read_holding_registers(&mb_param, | |
| 453 | + UT_HOLDING_REGISTERS_ADDRESS+1, | |
| 454 | + UT_HOLDING_REGISTERS_NB_POINTS, | |
| 455 | + tab_rp_registers); | |
| 453 | 456 | printf("1/2 No reply from slave %d: ", mb_param.slave); |
| 454 | - if (ret == SELECT_TIMEOUT) { | |
| 457 | + if (rc == -1 && errno == ETIMEDOUT) { | |
| 455 | 458 | printf("OK\n"); |
| 456 | 459 | } else { |
| 457 | 460 | printf("FAILED\n"); |
| ... | ... | @@ -459,12 +462,12 @@ int main(void) |
| 459 | 462 | } |
| 460 | 463 | |
| 461 | 464 | modbus_set_slave(&mb_param, MODBUS_BROADCAST_ADDRESS); |
| 462 | - ret = read_holding_registers(&mb_param, | |
| 463 | - UT_HOLDING_REGISTERS_ADDRESS, | |
| 464 | - UT_HOLDING_REGISTERS_NB_POINTS, | |
| 465 | - tab_rp_registers); | |
| 465 | + rc = read_holding_registers(&mb_param, | |
| 466 | + UT_HOLDING_REGISTERS_ADDRESS, | |
| 467 | + UT_HOLDING_REGISTERS_NB_POINTS, | |
| 468 | + tab_rp_registers); | |
| 466 | 469 | printf("2/2 Reply after a broadcast query: "); |
| 467 | - if (ret == UT_HOLDING_REGISTERS_NB_POINTS) { | |
| 470 | + if (rc == UT_HOLDING_REGISTERS_NB_POINTS) { | |
| 468 | 471 | printf("OK\n"); |
| 469 | 472 | } else { |
| 470 | 473 | goto close; |
| ... | ... | @@ -477,12 +480,12 @@ int main(void) |
| 477 | 480 | /* Allocate only the required space */ |
| 478 | 481 | tab_rp_registers_bad = (uint16_t *) malloc( |
| 479 | 482 | UT_HOLDING_REGISTERS_NB_POINTS_SPECIAL * sizeof(uint16_t)); |
| 480 | - ret = read_holding_registers(&mb_param, | |
| 481 | - UT_HOLDING_REGISTERS_ADDRESS, | |
| 482 | - UT_HOLDING_REGISTERS_NB_POINTS_SPECIAL, | |
| 483 | - tab_rp_registers_bad); | |
| 483 | + rc = read_holding_registers(&mb_param, | |
| 484 | + UT_HOLDING_REGISTERS_ADDRESS, | |
| 485 | + UT_HOLDING_REGISTERS_NB_POINTS_SPECIAL, | |
| 486 | + tab_rp_registers_bad); | |
| 484 | 487 | printf("* read_holding_registers: "); |
| 485 | - if (ret == INVALID_DATA) { | |
| 488 | + if (rc == -1 && errno == EMBBADDATA) { | |
| 486 | 489 | printf("OK\n"); |
| 487 | 490 | } else { |
| 488 | 491 | printf("FAILED\n"); | ... | ... |
tests/unit-test-slave.c
| ... | ... | @@ -19,6 +19,7 @@ |
| 19 | 19 | #include <unistd.h> |
| 20 | 20 | #include <string.h> |
| 21 | 21 | #include <stdlib.h> |
| 22 | +#include <errno.h> | |
| 22 | 23 | |
| 23 | 24 | #include <modbus/modbus.h> |
| 24 | 25 | #include "unit-test.h" |
| ... | ... | @@ -28,20 +29,22 @@ int main(void) |
| 28 | 29 | int socket; |
| 29 | 30 | modbus_param_t mb_param; |
| 30 | 31 | modbus_mapping_t mb_mapping; |
| 31 | - int ret; | |
| 32 | + int rc; | |
| 32 | 33 | int i; |
| 33 | 34 | |
| 34 | 35 | modbus_init_tcp(&mb_param, "127.0.0.1", 1502, SLAVE); |
| 35 | 36 | modbus_set_debug(&mb_param, TRUE); |
| 37 | + modbus_set_error_recovery(&mb_param, TRUE); | |
| 36 | 38 | |
| 37 | - ret = modbus_mapping_new(&mb_mapping, | |
| 39 | + rc = modbus_mapping_new(&mb_mapping, | |
| 38 | 40 | UT_COIL_STATUS_ADDRESS + UT_COIL_STATUS_NB_POINTS, |
| 39 | 41 | UT_INPUT_STATUS_ADDRESS + UT_INPUT_STATUS_NB_POINTS, |
| 40 | 42 | UT_HOLDING_REGISTERS_ADDRESS + UT_HOLDING_REGISTERS_NB_POINTS, |
| 41 | 43 | UT_INPUT_REGISTERS_ADDRESS + UT_INPUT_REGISTERS_NB_POINTS); |
| 42 | - if (ret < 0) { | |
| 43 | - printf("Memory allocation failed\n"); | |
| 44 | - exit(1); | |
| 44 | + if (rc == -1) { | |
| 45 | + fprintf(stderr, "Failed to allocate the mapping: %s\n", | |
| 46 | + modbus_strerror(errno)); | |
| 47 | + return -1; | |
| 45 | 48 | } |
| 46 | 49 | |
| 47 | 50 | /* Examples from PI_MODBUS_300.pdf. |
| ... | ... | @@ -61,11 +64,11 @@ int main(void) |
| 61 | 64 | socket = modbus_slave_listen_tcp(&mb_param, 1); |
| 62 | 65 | modbus_slave_accept_tcp(&mb_param, &socket); |
| 63 | 66 | |
| 64 | - while (1) { | |
| 67 | + for (;;) { | |
| 65 | 68 | uint8_t query[MAX_MESSAGE_LENGTH]; |
| 66 | 69 | |
| 67 | - ret = modbus_slave_receive(&mb_param, -1, query); | |
| 68 | - if (ret >= 0) { | |
| 70 | + rc = modbus_slave_receive(&mb_param, -1, query); | |
| 71 | + if (rc > 0) { | |
| 69 | 72 | if (((query[HEADER_LENGTH_TCP + 3] << 8) + query[HEADER_LENGTH_TCP + 4]) |
| 70 | 73 | == UT_HOLDING_REGISTERS_NB_POINTS_SPECIAL) { |
| 71 | 74 | /* Change the number of values (offset |
| ... | ... | @@ -74,15 +77,18 @@ int main(void) |
| 74 | 77 | query[HEADER_LENGTH_TCP + 4] = UT_HOLDING_REGISTERS_NB_POINTS; |
| 75 | 78 | } |
| 76 | 79 | |
| 77 | - modbus_slave_manage(&mb_param, query, ret, &mb_mapping); | |
| 78 | - } else if (ret == CONNECTION_CLOSED) { | |
| 79 | - /* Connection closed by the client, end of server */ | |
| 80 | - break; | |
| 80 | + rc = modbus_slave_manage(&mb_param, query, rc, &mb_mapping); | |
| 81 | + if (rc == -1) { | |
| 82 | + return -1; | |
| 83 | + } | |
| 81 | 84 | } else { |
| 82 | - fprintf(stderr, "Error in modbus_listen (%d)\n", ret); | |
| 85 | + /* Connection closed by the client or error */ | |
| 86 | + break; | |
| 83 | 87 | } |
| 84 | 88 | } |
| 85 | 89 | |
| 90 | + printf("Quit the loop: %s\n", modbus_strerror(errno)); | |
| 91 | + | |
| 86 | 92 | close(socket); |
| 87 | 93 | modbus_mapping_free(&mb_mapping); |
| 88 | 94 | modbus_close(&mb_param); | ... | ... |