Commit c7a6ffb357dd0f31e0ab61f4462af2ee84f355db
1 parent
fe8d9de6
New slave able to manage many connections on uniprocessor architecture
- new functions modbus_slave_init_listen_tcp, modbus_slave_accept_tcp, modbus_slave_slave_receive. - removed printf in modbus.c: 'Connection closed' - new slave test, bandwith-slave-many-up - updated build scripts - updated MIGRATION document file
Showing
10 changed files
with
277 additions
and
84 deletions
MIGRATION
| 1 | +============================= | ||
| 2 | +Migration from the 2.0 series | ||
| 3 | +============================= | ||
| 4 | + | ||
| 5 | +modbus_init_listen_tcp() has been renamed to modbus_slave_listen_tcp() and | ||
| 6 | +requires a new argument, the maximal number of connections: | ||
| 7 | + | ||
| 8 | +int modbus_slave_init_tcp(modbus_param_t *mb_param, int nb_connection); | ||
| 9 | + | ||
| 10 | + | ||
| 11 | +New function modbus_slave_accept_tcp() to etablish a new connection (previously | ||
| 12 | +in modbus_init_listen_tcp()): | ||
| 13 | + | ||
| 14 | +int modbus_slave_accept_tcp(modbus_param_t *mb_param, int *socket); | ||
| 15 | + | ||
| 16 | + | ||
| 17 | +modbus_listen() has been renamed to modbus_slave_receive() and requires a new | ||
| 18 | +argument, the socket file descriptor to listen on. If the sockfd is -1, the | ||
| 19 | +internal fd of modbus_param_t is used: | ||
| 20 | + | ||
| 21 | +int modbus_slave_receive(modbus_param_t *mb_param, int sockfd, | ||
| 22 | + uint8_t *query, int *query_length); | ||
| 23 | + | ||
| 24 | + | ||
| 1 | =================================== | 25 | =================================== |
| 2 | Migration notes from the 1.2 series | 26 | Migration notes from the 1.2 series |
| 3 | =================================== | 27 | =================================== |
modbus/modbus.c
| @@ -498,7 +498,7 @@ static int receive_msg(modbus_param_t *mb_param, | @@ -498,7 +498,7 @@ static int receive_msg(modbus_param_t *mb_param, | ||
| 498 | tv.tv_usec = TIME_OUT_BEGIN_OF_TRAME; | 498 | tv.tv_usec = TIME_OUT_BEGIN_OF_TRAME; |
| 499 | state = COMPLETE; | 499 | state = COMPLETE; |
| 500 | } | 500 | } |
| 501 | - | 501 | + |
| 502 | length_to_read = msg_length_computed; | 502 | length_to_read = msg_length_computed; |
| 503 | 503 | ||
| 504 | select_ret = 0; | 504 | select_ret = 0; |
| @@ -515,7 +515,6 @@ static int receive_msg(modbus_param_t *mb_param, | @@ -515,7 +515,6 @@ static int receive_msg(modbus_param_t *mb_param, | ||
| 515 | read_ret = recv(mb_param->fd, p_msg, length_to_read, 0); | 515 | read_ret = recv(mb_param->fd, p_msg, length_to_read, 0); |
| 516 | 516 | ||
| 517 | if (read_ret == 0) { | 517 | if (read_ret == 0) { |
| 518 | - printf("Connection closed\n"); | ||
| 519 | return CONNECTION_CLOSED; | 518 | return CONNECTION_CLOSED; |
| 520 | } else if (read_ret < 0) { | 519 | } else if (read_ret < 0) { |
| 521 | /* The only negative possible value is -1 */ | 520 | /* The only negative possible value is -1 */ |
| @@ -524,7 +523,7 @@ static int receive_msg(modbus_param_t *mb_param, | @@ -524,7 +523,7 @@ static int receive_msg(modbus_param_t *mb_param, | ||
| 524 | return PORT_SOCKET_FAILURE; | 523 | return PORT_SOCKET_FAILURE; |
| 525 | } | 524 | } |
| 526 | 525 | ||
| 527 | - /* Sums bytes received */ | 526 | + /* Sums bytes received */ |
| 528 | (*p_msg_length) += read_ret; | 527 | (*p_msg_length) += read_ret; |
| 529 | 528 | ||
| 530 | /* Display the hex code of each character received */ | 529 | /* Display the hex code of each character received */ |
| @@ -590,6 +589,28 @@ static int receive_msg(modbus_param_t *mb_param, | @@ -590,6 +589,28 @@ static int receive_msg(modbus_param_t *mb_param, | ||
| 590 | return 0; | 589 | return 0; |
| 591 | } | 590 | } |
| 592 | 591 | ||
| 592 | +/* Listens for any query from a modbus master in TCP, requires the socket file | ||
| 593 | + descriptor etablished with the master device in argument or -1 to use the | ||
| 594 | + internal one of modbus_param_t. | ||
| 595 | + | ||
| 596 | + Returns: | ||
| 597 | + - 0 if OK, or a negative error number if the request fails | ||
| 598 | + - query, message received | ||
| 599 | + - query_length, length in bytes of the message */ | ||
| 600 | +int modbus_slave_receive(modbus_param_t *mb_param, int sockfd, | ||
| 601 | + uint8_t *query, int *query_length) | ||
| 602 | +{ | ||
| 603 | + int ret; | ||
| 604 | + | ||
| 605 | + if (sockfd != -1) { | ||
| 606 | + mb_param->fd = sockfd; | ||
| 607 | + } | ||
| 608 | + | ||
| 609 | + /* The length of the query to receive isn't known. */ | ||
| 610 | + ret = receive_msg(mb_param, MSG_LENGTH_UNDEFINED, query, query_length); | ||
| 611 | + | ||
| 612 | + return ret; | ||
| 613 | +} | ||
| 593 | 614 | ||
| 594 | /* Receives the response and checks values (and checksum in RTU). | 615 | /* Receives the response and checks values (and checksum in RTU). |
| 595 | 616 | ||
| @@ -757,6 +778,7 @@ static int response_exception(modbus_param_t *mb_param, sft_t *sft, | @@ -757,6 +778,7 @@ static int response_exception(modbus_param_t *mb_param, sft_t *sft, | ||
| 757 | 778 | ||
| 758 | /* Manages the received query. | 779 | /* Manages the received query. |
| 759 | Analyses the query and constructs a response. | 780 | Analyses the query and constructs a response. |
| 781 | + | ||
| 760 | If an error occurs, this function construct the response | 782 | If an error occurs, this function construct the response |
| 761 | accordingly. | 783 | accordingly. |
| 762 | */ | 784 | */ |
| @@ -948,21 +970,6 @@ void modbus_manage_query(modbus_param_t *mb_param, const uint8_t *query, | @@ -948,21 +970,6 @@ void modbus_manage_query(modbus_param_t *mb_param, const uint8_t *query, | ||
| 948 | modbus_send(mb_param, response, resp_length); | 970 | modbus_send(mb_param, response, resp_length); |
| 949 | } | 971 | } |
| 950 | 972 | ||
| 951 | -/* Listens any message on a socket or file descriptor. | ||
| 952 | - Returns: | ||
| 953 | - - 0 if OK, or a negative error number if the request fails | ||
| 954 | - - query, message received | ||
| 955 | - - query_length, length in bytes of the message */ | ||
| 956 | -int modbus_listen(modbus_param_t *mb_param, uint8_t *query, int *query_length) | ||
| 957 | -{ | ||
| 958 | - int ret; | ||
| 959 | - | ||
| 960 | - /* The length of the query to receive isn't known. */ | ||
| 961 | - ret = receive_msg(mb_param, MSG_LENGTH_UNDEFINED, query, query_length); | ||
| 962 | - | ||
| 963 | - return ret; | ||
| 964 | -} | ||
| 965 | - | ||
| 966 | /* Reads IO status */ | 973 | /* Reads IO status */ |
| 967 | static int read_io_status(modbus_param_t *mb_param, int slave, int function, | 974 | static int read_io_status(modbus_param_t *mb_param, int slave, int function, |
| 968 | int start_addr, int nb, uint8_t *data_dest) | 975 | int start_addr, int nb, uint8_t *data_dest) |
| @@ -1628,10 +1635,6 @@ static int modbus_connect_tcp(modbus_param_t *mb_param) | @@ -1628,10 +1635,6 @@ static int modbus_connect_tcp(modbus_param_t *mb_param) | ||
| 1628 | int option; | 1635 | int option; |
| 1629 | struct sockaddr_in addr; | 1636 | struct sockaddr_in addr; |
| 1630 | 1637 | ||
| 1631 | - addr.sin_family = AF_INET; | ||
| 1632 | - addr.sin_port = htons(mb_param->port); | ||
| 1633 | - addr.sin_addr.s_addr = inet_addr(mb_param->ip); | ||
| 1634 | - | ||
| 1635 | mb_param->fd = socket(AF_INET, SOCK_STREAM, 0); | 1638 | mb_param->fd = socket(AF_INET, SOCK_STREAM, 0); |
| 1636 | if (mb_param->fd < 0) { | 1639 | if (mb_param->fd < 0) { |
| 1637 | return mb_param->fd; | 1640 | return mb_param->fd; |
| @@ -1661,7 +1664,10 @@ static int modbus_connect_tcp(modbus_param_t *mb_param) | @@ -1661,7 +1664,10 @@ static int modbus_connect_tcp(modbus_param_t *mb_param) | ||
| 1661 | if (mb_param->debug) { | 1664 | if (mb_param->debug) { |
| 1662 | printf("Connecting to %s\n", mb_param->ip); | 1665 | printf("Connecting to %s\n", mb_param->ip); |
| 1663 | } | 1666 | } |
| 1664 | - | 1667 | + |
| 1668 | + addr.sin_family = AF_INET; | ||
| 1669 | + addr.sin_port = htons(mb_param->port); | ||
| 1670 | + addr.sin_addr.s_addr = inet_addr(mb_param->ip); | ||
| 1665 | ret = connect(mb_param->fd, (struct sockaddr *)&addr, | 1671 | ret = connect(mb_param->fd, (struct sockaddr *)&addr, |
| 1666 | sizeof(struct sockaddr_in)); | 1672 | sizeof(struct sockaddr_in)); |
| 1667 | if (ret < 0) { | 1673 | if (ret < 0) { |
| @@ -1784,60 +1790,64 @@ void modbus_mapping_free(modbus_mapping_t *mb_mapping) | @@ -1784,60 +1790,64 @@ void modbus_mapping_free(modbus_mapping_t *mb_mapping) | ||
| 1784 | free(mb_mapping->tab_input_registers); | 1790 | free(mb_mapping->tab_input_registers); |
| 1785 | } | 1791 | } |
| 1786 | 1792 | ||
| 1787 | -/* Listens for any query from a modbus master in TCP */ | ||
| 1788 | -int modbus_init_listen_tcp(modbus_param_t *mb_param) | 1793 | +/* Listens for any query from one or many modbus masters in TCP */ |
| 1794 | +int modbus_slave_listen_tcp(modbus_param_t *mb_param, int nb_connection) | ||
| 1789 | { | 1795 | { |
| 1790 | - int ret; | ||
| 1791 | int new_socket; | 1796 | int new_socket; |
| 1797 | + int yes; | ||
| 1792 | struct sockaddr_in addr; | 1798 | struct sockaddr_in addr; |
| 1793 | - socklen_t addrlen; | ||
| 1794 | - | ||
| 1795 | - addr.sin_family = AF_INET; | ||
| 1796 | - /* If the modbus port is < to 1024, we need the setuid root. */ | ||
| 1797 | - addr.sin_port = htons(mb_param->port); | ||
| 1798 | - addr.sin_addr.s_addr = INADDR_ANY; | ||
| 1799 | - memset(&(addr.sin_zero), '\0', 8); | ||
| 1800 | 1799 | ||
| 1801 | new_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); | 1800 | new_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); |
| 1802 | if (new_socket < 0) { | 1801 | if (new_socket < 0) { |
| 1803 | perror("socket"); | 1802 | perror("socket"); |
| 1804 | - exit(1); | ||
| 1805 | - } else { | ||
| 1806 | - printf("Socket OK\n"); | 1803 | + return -1; |
| 1807 | } | 1804 | } |
| 1808 | 1805 | ||
| 1809 | - ret = bind(new_socket, (struct sockaddr *)&addr, | ||
| 1810 | - sizeof(struct sockaddr_in)); | ||
| 1811 | - if (ret < 0) { | 1806 | + yes = 1; |
| 1807 | + if (setsockopt(new_socket, SOL_SOCKET, SO_REUSEADDR, | ||
| 1808 | + (char *) &yes, sizeof(yes)) < 0) { | ||
| 1809 | + perror("setsockopt"); | ||
| 1810 | + close(new_socket); | ||
| 1811 | + return -1; | ||
| 1812 | + } | ||
| 1813 | + | ||
| 1814 | + memset(&addr, 0, sizeof(addr)); | ||
| 1815 | + addr.sin_family = AF_INET; | ||
| 1816 | + /* If the modbus port is < to 1024, we need the setuid root. */ | ||
| 1817 | + addr.sin_port = htons(mb_param->port); | ||
| 1818 | + addr.sin_addr.s_addr = INADDR_ANY; | ||
| 1819 | + if (bind(new_socket, (struct sockaddr *)&addr, sizeof(addr)) < 0) { | ||
| 1812 | perror("bind"); | 1820 | perror("bind"); |
| 1813 | close(new_socket); | 1821 | close(new_socket); |
| 1814 | - exit(1); | ||
| 1815 | - } else { | ||
| 1816 | - printf("Bind OK\n"); | 1822 | + return -1; |
| 1817 | } | 1823 | } |
| 1818 | 1824 | ||
| 1819 | - ret = listen(new_socket, 1); | ||
| 1820 | - if (ret != 0) { | 1825 | + if (listen(new_socket, nb_connection) < 0) { |
| 1821 | perror("listen"); | 1826 | perror("listen"); |
| 1822 | close(new_socket); | 1827 | close(new_socket); |
| 1823 | - exit(1); | ||
| 1824 | - } else { | ||
| 1825 | - printf("Listen OK\n"); | 1828 | + return -1; |
| 1826 | } | 1829 | } |
| 1827 | 1830 | ||
| 1831 | + return new_socket; | ||
| 1832 | +} | ||
| 1833 | + | ||
| 1834 | +int modbus_slave_accept_tcp(modbus_param_t *mb_param, int *socket) | ||
| 1835 | +{ | ||
| 1836 | + struct sockaddr_in addr; | ||
| 1837 | + socklen_t addrlen; | ||
| 1838 | + | ||
| 1828 | addrlen = sizeof(struct sockaddr_in); | 1839 | addrlen = sizeof(struct sockaddr_in); |
| 1829 | - mb_param->fd = accept(new_socket, (struct sockaddr *)&addr, &addrlen); | 1840 | + mb_param->fd = accept(*socket, (struct sockaddr *)&addr, &addrlen); |
| 1830 | if (mb_param->fd < 0) { | 1841 | if (mb_param->fd < 0) { |
| 1831 | perror("accept"); | 1842 | perror("accept"); |
| 1832 | - close(new_socket); | ||
| 1833 | - new_socket = 0; | ||
| 1834 | - exit(1); | 1843 | + close(*socket); |
| 1844 | + *socket = 0; | ||
| 1835 | } else { | 1845 | } else { |
| 1836 | printf("The client %s is connected\n", | 1846 | printf("The client %s is connected\n", |
| 1837 | inet_ntoa(addr.sin_addr)); | 1847 | inet_ntoa(addr.sin_addr)); |
| 1838 | } | 1848 | } |
| 1839 | 1849 | ||
| 1840 | - return new_socket; | 1850 | + return mb_param->fd; |
| 1841 | } | 1851 | } |
| 1842 | 1852 | ||
| 1843 | /** Utils **/ | 1853 | /** Utils **/ |
modbus/modbus.h
| @@ -279,12 +279,25 @@ int modbus_mapping_new(modbus_mapping_t *mb_mapping, | @@ -279,12 +279,25 @@ int modbus_mapping_new(modbus_mapping_t *mb_mapping, | ||
| 279 | /* Frees the 4 arrays */ | 279 | /* Frees the 4 arrays */ |
| 280 | void modbus_mapping_free(modbus_mapping_t *mb_mapping); | 280 | void modbus_mapping_free(modbus_mapping_t *mb_mapping); |
| 281 | 281 | ||
| 282 | -/* Initializes the modbus_param_t structure for a TCP slave (server) */ | ||
| 283 | -int modbus_init_listen_tcp(modbus_param_t *mb_param); | 282 | +/* Listens for any query from one or many modbus masters in TCP. |
| 284 | 283 | ||
| 285 | -/* Listens for any query from a modbus master in TCP | ||
| 286 | - Not tested in RTU communication. */ | ||
| 287 | -int modbus_listen(modbus_param_t *mb_param, uint8_t *query, int *query_length); | 284 | + Returns: socket |
| 285 | + */ | ||
| 286 | +int modbus_slave_listen_tcp(modbus_param_t *mb_param, int nb_connection); | ||
| 287 | + | ||
| 288 | +/* Waits for a connection */ | ||
| 289 | +int modbus_slave_accept_tcp(modbus_param_t *mb_param, int *socket); | ||
| 290 | + | ||
| 291 | +/* Listens for any query from a modbus master in TCP, requires the socket file | ||
| 292 | + descriptor etablished with the master device in argument. | ||
| 293 | + | ||
| 294 | + Returns: | ||
| 295 | + - 0 if OK, or a negative error number if the request fails | ||
| 296 | + - query, message received | ||
| 297 | + - query_length, length in bytes of the message | ||
| 298 | +*/ | ||
| 299 | +int modbus_slave_receive(modbus_param_t *mb_param, int sockfd, | ||
| 300 | + uint8_t *query, int *query_length); | ||
| 288 | 301 | ||
| 289 | /* Manages the received query. | 302 | /* Manages the received query. |
| 290 | Analyses the query and constructs a response. | 303 | Analyses the query and constructs a response. |
tests/Makefile.am
| @@ -5,8 +5,9 @@ noinst_PROGRAMS = \ | @@ -5,8 +5,9 @@ noinst_PROGRAMS = \ | ||
| 5 | random-test-master \ | 5 | random-test-master \ |
| 6 | unit-test-slave \ | 6 | unit-test-slave \ |
| 7 | unit-test-master \ | 7 | unit-test-master \ |
| 8 | - bench-bandwidth-slave \ | ||
| 9 | - bench-bandwidth-master | 8 | + bandwidth-slave-one \ |
| 9 | + bandwidth-slave-many-up \ | ||
| 10 | + bandwidth-master | ||
| 10 | 11 | ||
| 11 | common_ldflags = \ | 12 | common_ldflags = \ |
| 12 | $(top_builddir)/modbus/libmodbus.la | 13 | $(top_builddir)/modbus/libmodbus.la |
| @@ -23,11 +24,14 @@ unit_test_slave_LDADD = $(common_ldflags) | @@ -23,11 +24,14 @@ unit_test_slave_LDADD = $(common_ldflags) | ||
| 23 | unit_test_master_SOURCES = unit-test-master.c unit-test.h | 24 | unit_test_master_SOURCES = unit-test-master.c unit-test.h |
| 24 | unit_test_master_LDADD = $(common_ldflags) | 25 | unit_test_master_LDADD = $(common_ldflags) |
| 25 | 26 | ||
| 26 | -bench_bandwidth_slave_SOURCES = bench-bandwidth-slave.c | ||
| 27 | -bench_bandwidth_slave_LDADD = $(common_ldflags) | 27 | +bandwidth_slave_one_SOURCES = bandwidth-slave-one.c |
| 28 | +bandwidth_slave_one_LDADD = $(common_ldflags) | ||
| 28 | 29 | ||
| 29 | -bench_bandwidth_master_SOURCES = bench-bandwidth-master.c | ||
| 30 | -bench_bandwidth_master_LDADD = $(common_ldflags) | 30 | +bandwidth_slave_many_up_SOURCES = bandwidth-slave-many-up.c |
| 31 | +bandwidth_slave_many_up_LDADD = $(common_ldflags) | ||
| 32 | + | ||
| 33 | +bandwidth_master_SOURCES = bandwidth-master.c | ||
| 34 | +bandwidth_master_LDADD = $(common_ldflags) | ||
| 31 | 35 | ||
| 32 | INCLUDES = -I$(top_srcdir) | 36 | INCLUDES = -I$(top_srcdir) |
| 33 | CLEANFILES = *~ | 37 | CLEANFILES = *~ |
tests/bench-bandwidth-master.c renamed to tests/bandwidth-master.c
| @@ -33,7 +33,7 @@ uint32_t gettime(void) | @@ -33,7 +33,7 @@ uint32_t gettime(void) | ||
| 33 | { | 33 | { |
| 34 | struct timeval tv; | 34 | struct timeval tv; |
| 35 | gettimeofday (&tv, NULL); | 35 | gettimeofday (&tv, NULL); |
| 36 | - | 36 | + |
| 37 | return (uint32_t) tv.tv_sec * G_USEC_PER_SEC + tv.tv_usec; | 37 | return (uint32_t) tv.tv_sec * G_USEC_PER_SEC + tv.tv_usec; |
| 38 | } | 38 | } |
| 39 | 39 | ||
| @@ -61,7 +61,7 @@ int main(void) | @@ -61,7 +61,7 @@ int main(void) | ||
| 61 | /* Allocate and initialize the memory to store the status */ | 61 | /* Allocate and initialize the memory to store the status */ |
| 62 | tab_rp_status = (uint8_t *) malloc(MAX_STATUS * sizeof(uint8_t)); | 62 | tab_rp_status = (uint8_t *) malloc(MAX_STATUS * sizeof(uint8_t)); |
| 63 | memset(tab_rp_status, 0, MAX_STATUS * sizeof(uint8_t)); | 63 | memset(tab_rp_status, 0, MAX_STATUS * sizeof(uint8_t)); |
| 64 | - | 64 | + |
| 65 | /* Allocate and initialize the memory to store the registers */ | 65 | /* Allocate and initialize the memory to store the registers */ |
| 66 | tab_rp_registers = (uint16_t *) malloc(MAX_REGISTERS * sizeof(uint16_t)); | 66 | tab_rp_registers = (uint16_t *) malloc(MAX_REGISTERS * sizeof(uint16_t)); |
| 67 | memset(tab_rp_registers, 0, MAX_REGISTERS * sizeof(uint16_t)); | 67 | memset(tab_rp_registers, 0, MAX_REGISTERS * sizeof(uint16_t)); |
| @@ -78,7 +78,7 @@ int main(void) | @@ -78,7 +78,7 @@ int main(void) | ||
| 78 | 78 | ||
| 79 | rate = (NB_LOOPS * nb_points) * G_USEC_PER_SEC / (end - start); | 79 | rate = (NB_LOOPS * nb_points) * G_USEC_PER_SEC / (end - start); |
| 80 | printf("Transfert rate in points/seconds:\n"); | 80 | printf("Transfert rate in points/seconds:\n"); |
| 81 | - printf("* %'d points/s\n", rate); | 81 | + printf("* %'d points/s\n", rate); |
| 82 | printf("\n"); | 82 | printf("\n"); |
| 83 | 83 | ||
| 84 | bytes = NB_LOOPS * (nb_points / 8) + ((nb_points % 8) ? 1 : 0); | 84 | bytes = NB_LOOPS * (nb_points / 8) + ((nb_points % 8) ? 1 : 0); |
| @@ -88,7 +88,7 @@ int main(void) | @@ -88,7 +88,7 @@ int main(void) | ||
| 88 | printf("* %.3f ms for %d bytes\n", elapsed, bytes); | 88 | printf("* %.3f ms for %d bytes\n", elapsed, bytes); |
| 89 | printf("* %'d KiB/s\n", rate); | 89 | printf("* %'d KiB/s\n", rate); |
| 90 | printf("\n"); | 90 | printf("\n"); |
| 91 | - | 91 | + |
| 92 | /* TCP: Query and reponse header and values */ | 92 | /* TCP: Query and reponse header and values */ |
| 93 | bytes = 12 + 9 + (nb_points / 8) + ((nb_points % 8) ? 1 : 0); | 93 | bytes = 12 + 9 + (nb_points / 8) + ((nb_points % 8) ? 1 : 0); |
| 94 | printf("Values and TCP Modbus overhead:\n"); | 94 | printf("Values and TCP Modbus overhead:\n"); |
| @@ -111,7 +111,7 @@ int main(void) | @@ -111,7 +111,7 @@ int main(void) | ||
| 111 | 111 | ||
| 112 | rate = (NB_LOOPS * nb_points) * G_USEC_PER_SEC / (end - start); | 112 | rate = (NB_LOOPS * nb_points) * G_USEC_PER_SEC / (end - start); |
| 113 | printf("Transfert rate in points/seconds:\n"); | 113 | printf("Transfert rate in points/seconds:\n"); |
| 114 | - printf("* %'d registers/s\n", rate); | 114 | + printf("* %'d registers/s\n", rate); |
| 115 | printf("\n"); | 115 | printf("\n"); |
| 116 | 116 | ||
| 117 | bytes = NB_LOOPS * nb_points * sizeof(uint16_t); | 117 | bytes = NB_LOOPS * nb_points * sizeof(uint16_t); |
| @@ -121,7 +121,7 @@ int main(void) | @@ -121,7 +121,7 @@ int main(void) | ||
| 121 | printf("* %.3f ms for %d bytes\n", elapsed, bytes); | 121 | printf("* %.3f ms for %d bytes\n", elapsed, bytes); |
| 122 | printf("* %'d KiB/s\n", rate); | 122 | printf("* %'d KiB/s\n", rate); |
| 123 | printf("\n"); | 123 | printf("\n"); |
| 124 | - | 124 | + |
| 125 | /* TCP:Query and reponse header and values */ | 125 | /* TCP:Query and reponse header and values */ |
| 126 | bytes = 12 + 9 + (nb_points * sizeof(uint16_t)); | 126 | bytes = 12 + 9 + (nb_points * sizeof(uint16_t)); |
| 127 | printf("Values and TCP Modbus overhead:\n"); | 127 | printf("Values and TCP Modbus overhead:\n"); |
| @@ -133,11 +133,11 @@ int main(void) | @@ -133,11 +133,11 @@ int main(void) | ||
| 133 | printf("\n"); | 133 | printf("\n"); |
| 134 | 134 | ||
| 135 | /* Free the memory */ | 135 | /* Free the memory */ |
| 136 | - free(tab_rp_status); | 136 | + free(tab_rp_status); |
| 137 | free(tab_rp_registers); | 137 | free(tab_rp_registers); |
| 138 | 138 | ||
| 139 | /* Close the connection */ | 139 | /* Close the connection */ |
| 140 | modbus_close(&mb_param); | 140 | modbus_close(&mb_param); |
| 141 | - | 141 | + |
| 142 | return 0; | 142 | return 0; |
| 143 | } | 143 | } |
tests/bandwidth-slave-many-up.c
0 → 100644
| 1 | +/* | ||
| 2 | + * Copyright © 2009 Stéphane Raimbault <stephane.raimbault@gmail.com> | ||
| 3 | + * | ||
| 4 | + * This program is free software: you can redistribute it and/or modify | ||
| 5 | + * it under the terms of the GNU General Public License as published by | ||
| 6 | + * the Free Software Foundation; either version 3 of the License, or | ||
| 7 | + * (at your option) any later version. | ||
| 8 | + * | ||
| 9 | + * This program is distributed in the hope that it will be useful, | ||
| 10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | + * GNU General Public License for more details. | ||
| 13 | + * | ||
| 14 | + * You should have received a copy of the GNU General Public License | ||
| 15 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | + */ | ||
| 17 | + | ||
| 18 | +#include <stdio.h> | ||
| 19 | +#include <unistd.h> | ||
| 20 | +#include <string.h> | ||
| 21 | +#include <stdlib.h> | ||
| 22 | +#include <errno.h> | ||
| 23 | +#include <signal.h> | ||
| 24 | + | ||
| 25 | +#include <modbus/modbus.h> | ||
| 26 | + | ||
| 27 | +#define NB_CONNECTION 5 | ||
| 28 | +int slave_socket; | ||
| 29 | +modbus_mapping_t mb_mapping; | ||
| 30 | + | ||
| 31 | +static void close_sigint(int dummy) | ||
| 32 | +{ | ||
| 33 | + shutdown(slave_socket, SHUT_RDWR); | ||
| 34 | + close(slave_socket); | ||
| 35 | + modbus_mapping_free(&mb_mapping); | ||
| 36 | + | ||
| 37 | + exit(dummy); | ||
| 38 | +} | ||
| 39 | + | ||
| 40 | +int main(void) | ||
| 41 | +{ | ||
| 42 | + int master_socket; | ||
| 43 | + modbus_param_t mb_param; | ||
| 44 | + int ret; | ||
| 45 | + fd_set refset; | ||
| 46 | + fd_set rdset; | ||
| 47 | + | ||
| 48 | + /* Maximum file descriptor number */ | ||
| 49 | + int fdmax; | ||
| 50 | + | ||
| 51 | + modbus_init_tcp(&mb_param, "127.0.0.1", 1502); | ||
| 52 | + | ||
| 53 | + ret = modbus_mapping_new(&mb_mapping, MAX_STATUS, 0, MAX_REGISTERS, 0); | ||
| 54 | + if (ret == FALSE) { | ||
| 55 | + printf("Memory allocation failure\n"); | ||
| 56 | + exit(1); | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + slave_socket = modbus_slave_listen_tcp(&mb_param, NB_CONNECTION); | ||
| 60 | + | ||
| 61 | + signal(SIGINT, close_sigint); | ||
| 62 | + | ||
| 63 | + /* Clear the reference set of socket */ | ||
| 64 | + FD_ZERO(&refset); | ||
| 65 | + /* Add the slave socket */ | ||
| 66 | + FD_SET(slave_socket, &refset); | ||
| 67 | + | ||
| 68 | + /* Keep track of the max file descriptor */ | ||
| 69 | + fdmax = slave_socket; | ||
| 70 | + | ||
| 71 | + for (;;) { | ||
| 72 | + rdset = refset; | ||
| 73 | + if (select(fdmax+1, &rdset, NULL, NULL, NULL) == -1) { | ||
| 74 | + perror("Slave select() failure."); | ||
| 75 | + close_sigint(1); | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + /* Run through the existing connections looking for data to be | ||
| 79 | + * read */ | ||
| 80 | + for (master_socket = 0; master_socket <= fdmax; master_socket++) { | ||
| 81 | + | ||
| 82 | + if (FD_ISSET(master_socket, &rdset)) { | ||
| 83 | + if (master_socket == slave_socket) { | ||
| 84 | + /* A client is asking a new connection */ | ||
| 85 | + socklen_t addrlen; | ||
| 86 | + struct sockaddr_in clientaddr; | ||
| 87 | + int newfd; | ||
| 88 | + | ||
| 89 | + /* Handle new connections */ | ||
| 90 | + addrlen = sizeof(clientaddr); | ||
| 91 | + memset(&clientaddr, 0, sizeof(clientaddr)); | ||
| 92 | + newfd = accept(slave_socket, (struct sockaddr *)&clientaddr, &addrlen); | ||
| 93 | + if (newfd == -1) { | ||
| 94 | + perror("Server accept() error"); | ||
| 95 | + } else { | ||
| 96 | + FD_SET(newfd, &refset); | ||
| 97 | + | ||
| 98 | + if (newfd > fdmax) { | ||
| 99 | + /* Keep track of the maximum */ | ||
| 100 | + fdmax = newfd; | ||
| 101 | + } | ||
| 102 | + printf("New connection from %s:%d on socket %d\n", | ||
| 103 | + inet_ntoa(clientaddr.sin_addr), clientaddr.sin_port, newfd); | ||
| 104 | + } | ||
| 105 | + } else { | ||
| 106 | + /* An already connected master has sent a new query */ | ||
| 107 | + uint8_t query[MAX_MESSAGE_LENGTH]; | ||
| 108 | + int query_size; | ||
| 109 | + | ||
| 110 | + ret = modbus_slave_receive(&mb_param, master_socket, query, &query_size); | ||
| 111 | + if (ret == 0) { | ||
| 112 | + modbus_manage_query(&mb_param, query, query_size, &mb_mapping); | ||
| 113 | + } else { | ||
| 114 | + /* Connection closed by the client, end of server */ | ||
| 115 | + printf("Connection closed on socket %d\n", master_socket); | ||
| 116 | + shutdown(master_socket, SHUT_RDWR); | ||
| 117 | + close(master_socket); | ||
| 118 | + | ||
| 119 | + /* Remove from reference set */ | ||
| 120 | + FD_CLR(master_socket, &refset); | ||
| 121 | + | ||
| 122 | + if (master_socket == fdmax) { | ||
| 123 | + fdmax--; | ||
| 124 | + } | ||
| 125 | + } | ||
| 126 | + } | ||
| 127 | + } | ||
| 128 | + } | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + return 0; | ||
| 132 | +} |
tests/bench-bandwidth-slave.c renamed to tests/bandwidth-slave-one.c
| @@ -37,13 +37,14 @@ int main(void) | @@ -37,13 +37,14 @@ int main(void) | ||
| 37 | exit(1); | 37 | exit(1); |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | - socket = modbus_init_listen_tcp(&mb_param); | ||
| 41 | - | 40 | + socket = modbus_slave_listen_tcp(&mb_param, 1); |
| 41 | + modbus_slave_accept_tcp(&mb_param, &socket); | ||
| 42 | + | ||
| 42 | while (1) { | 43 | while (1) { |
| 43 | uint8_t query[MAX_MESSAGE_LENGTH]; | 44 | uint8_t query[MAX_MESSAGE_LENGTH]; |
| 44 | int query_size; | 45 | int query_size; |
| 45 | 46 | ||
| 46 | - ret = modbus_listen(&mb_param, query, &query_size); | 47 | + ret = modbus_slave_receive(&mb_param, -1, query, &query_size); |
| 47 | if (ret == 0) { | 48 | if (ret == 0) { |
| 48 | modbus_manage_query(&mb_param, query, query_size, &mb_mapping); | 49 | modbus_manage_query(&mb_param, query, query_size, &mb_mapping); |
| 49 | } else if (ret == CONNECTION_CLOSED) { | 50 | } else if (ret == CONNECTION_CLOSED) { |
tests/random-test-slave.c
| @@ -37,13 +37,14 @@ int main(void) | @@ -37,13 +37,14 @@ int main(void) | ||
| 37 | exit(1); | 37 | exit(1); |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | - socket = modbus_init_listen_tcp(&mb_param); | ||
| 41 | - | 40 | + socket = modbus_slave_listen_tcp(&mb_param, 1); |
| 41 | + modbus_slave_accept_tcp(&mb_param, &socket); | ||
| 42 | + | ||
| 42 | while (1) { | 43 | while (1) { |
| 43 | uint8_t query[MAX_MESSAGE_LENGTH]; | 44 | uint8_t query[MAX_MESSAGE_LENGTH]; |
| 44 | int query_size; | 45 | int query_size; |
| 45 | 46 | ||
| 46 | - ret = modbus_listen(&mb_param, query, &query_size); | 47 | + ret = modbus_slave_receive(&mb_param, -1, query, &query_size); |
| 47 | if (ret == 0) { | 48 | if (ret == 0) { |
| 48 | modbus_manage_query(&mb_param, query, query_size, &mb_mapping); | 49 | modbus_manage_query(&mb_param, query, query_size, &mb_mapping); |
| 49 | } else if (ret == CONNECTION_CLOSED) { | 50 | } else if (ret == CONNECTION_CLOSED) { |
tests/unit-test-slave.c
| @@ -59,13 +59,14 @@ int main(void) | @@ -59,13 +59,14 @@ int main(void) | ||
| 59 | UT_INPUT_REGISTERS_TAB[i];; | 59 | UT_INPUT_REGISTERS_TAB[i];; |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | - socket = modbus_init_listen_tcp(&mb_param); | ||
| 63 | - | 62 | + socket = modbus_slave_listen_tcp(&mb_param, 1); |
| 63 | + modbus_slave_accept_tcp(&mb_param, &socket); | ||
| 64 | + | ||
| 64 | while (1) { | 65 | while (1) { |
| 65 | uint8_t query[MAX_MESSAGE_LENGTH]; | 66 | uint8_t query[MAX_MESSAGE_LENGTH]; |
| 66 | int query_size; | 67 | int query_size; |
| 67 | 68 | ||
| 68 | - ret = modbus_listen(&mb_param, query, &query_size); | 69 | + ret = modbus_slave_receive(&mb_param, -1, query, &query_size); |
| 69 | if (ret == 0) { | 70 | if (ret == 0) { |
| 70 | if (((query[HEADER_LENGTH_TCP + 4] << 8) + query[HEADER_LENGTH_TCP + 5]) | 71 | if (((query[HEADER_LENGTH_TCP + 4] << 8) + query[HEADER_LENGTH_TCP + 5]) |
| 71 | == UT_HOLDING_REGISTERS_NB_POINTS_SPECIAL) { | 72 | == UT_HOLDING_REGISTERS_NB_POINTS_SPECIAL) { |
tests/wscript
| @@ -28,15 +28,22 @@ def build(bld): | @@ -28,15 +28,22 @@ def build(bld): | ||
| 28 | obj.inst_var = 0 | 28 | obj.inst_var = 0 |
| 29 | 29 | ||
| 30 | obj = bld.create_obj('cc', 'program') | 30 | obj = bld.create_obj('cc', 'program') |
| 31 | - obj.source = 'bench-bandwidth-slave.c' | 31 | + obj.source = 'bandwidth-slave-one.c' |
| 32 | obj.includes = '. ..' | 32 | obj.includes = '. ..' |
| 33 | obj.uselib_local = 'modbus' | 33 | obj.uselib_local = 'modbus' |
| 34 | - obj.target = 'bench-bandwidth-slave' | 34 | + obj.target = 'bandwidth-slave-one' |
| 35 | obj.inst_var = 0 | 35 | obj.inst_var = 0 |
| 36 | 36 | ||
| 37 | obj = bld.create_obj('cc', 'program') | 37 | obj = bld.create_obj('cc', 'program') |
| 38 | - obj.source = 'bench-bandwidth-master.c' | 38 | + obj.source = 'bandwidth-slave-many-up.c' |
| 39 | obj.includes = '. ..' | 39 | obj.includes = '. ..' |
| 40 | obj.uselib_local = 'modbus' | 40 | obj.uselib_local = 'modbus' |
| 41 | - obj.target = 'bench-bandwidth-master' | 41 | + obj.target = 'bandwidth-slave-many-up' |
| 42 | + obj.inst_var = 0 | ||
| 43 | + | ||
| 44 | + obj = bld.create_obj('cc', 'program') | ||
| 45 | + obj.source = 'bandwidth-master.c' | ||
| 46 | + obj.includes = '. ..' | ||
| 47 | + obj.uselib_local = 'modbus' | ||
| 48 | + obj.target = 'bandwidth-master' | ||
| 42 | obj.inst_var = 0 | 49 | obj.inst_var = 0 |