1 /*
2  * Copyright © 2008-2014 Stéphane Raimbault <stephane.raimbault@gmail.com>
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <stdio.h>
8 #ifndef _MSC_VER
9 #include <unistd.h>
10 #include <sys/time.h>
11 #endif
12 #include <string.h>
13 #include <stdlib.h>
14 #include <time.h>
15 #include <errno.h>
16 
17 #include <modbus.h>
18 
19 #define G_MSEC_PER_SEC 1000
20 
gettime_ms(void)21 static uint32_t gettime_ms(void)
22 {
23     struct timeval tv;
24 #if !defined(_MSC_VER)
25     gettimeofday(&tv, NULL);
26     return (uint32_t) tv.tv_sec * 1000 + tv.tv_usec / 1000;
27 #else
28     return GetTickCount();
29 #endif
30 }
31 
32 enum {
33     TCP,
34     RTU
35 };
36 
37 /* Tests based on PI-MBUS-300 documentation */
main(int argc,char * argv[])38 int main(int argc, char *argv[])
39 {
40     uint8_t *tab_bit;
41     uint16_t *tab_reg;
42     modbus_t *ctx;
43     int i;
44     int nb_points;
45     double elapsed;
46     uint32_t start;
47     uint32_t end;
48     uint32_t bytes;
49     uint32_t rate;
50     int rc;
51     int n_loop;
52     int use_backend;
53 
54     if (argc > 1) {
55         if (strcmp(argv[1], "tcp") == 0) {
56             use_backend = TCP;
57             n_loop = 100000;
58         } else if (strcmp(argv[1], "rtu") == 0) {
59             use_backend = RTU;
60             n_loop = 100;
61         } else {
62             printf("Usage:\n  %s [tcp|rtu] - Modbus client to measure data bandwith\n\n", argv[0]);
63             exit(1);
64         }
65     } else {
66         /* By default */
67         use_backend = TCP;
68         n_loop = 100000;
69     }
70 
71     if (use_backend == TCP) {
72         ctx = modbus_new_tcp("127.0.0.1", 1502);
73     } else {
74         ctx = modbus_new_rtu("/dev/ttyUSB1", 115200, 'N', 8, 1);
75         modbus_set_slave(ctx, 1);
76     }
77     if (modbus_connect(ctx) == -1) {
78         fprintf(stderr, "Connection failed: %s\n",
79                 modbus_strerror(errno));
80         modbus_free(ctx);
81         return -1;
82     }
83 
84     /* Allocate and initialize the memory to store the status */
85     tab_bit = (uint8_t *) malloc(MODBUS_MAX_READ_BITS * sizeof(uint8_t));
86     memset(tab_bit, 0, MODBUS_MAX_READ_BITS * sizeof(uint8_t));
87 
88     /* Allocate and initialize the memory to store the registers */
89     tab_reg = (uint16_t *) malloc(MODBUS_MAX_READ_REGISTERS * sizeof(uint16_t));
90     memset(tab_reg, 0, MODBUS_MAX_READ_REGISTERS * sizeof(uint16_t));
91 
92     printf("READ BITS\n\n");
93 
94     nb_points = MODBUS_MAX_READ_BITS;
95     start = gettime_ms();
96     for (i=0; i<n_loop; i++) {
97         rc = modbus_read_bits(ctx, 0, nb_points, tab_bit);
98         if (rc == -1) {
99             fprintf(stderr, "%s\n", modbus_strerror(errno));
100             return -1;
101         }
102     }
103     end = gettime_ms();
104     elapsed = end - start;
105 
106     rate = (n_loop * nb_points) * G_MSEC_PER_SEC / (end - start);
107     printf("Transfert rate in points/seconds:\n");
108     printf("* %d points/s\n", rate);
109     printf("\n");
110 
111     bytes = n_loop * (nb_points / 8) + ((nb_points % 8) ? 1 : 0);
112     rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start);
113     printf("Values:\n");
114     printf("* %d x %d values\n", n_loop, nb_points);
115     printf("* %.3f ms for %d bytes\n", elapsed, bytes);
116     printf("* %d KiB/s\n", rate);
117     printf("\n");
118 
119     /* TCP: Query and reponse header and values */
120     bytes = 12 + 9 + (nb_points / 8) + ((nb_points % 8) ? 1 : 0);
121     printf("Values and TCP Modbus overhead:\n");
122     printf("* %d x %d bytes\n", n_loop, bytes);
123     bytes = n_loop * bytes;
124     rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start);
125     printf("* %.3f ms for %d bytes\n", elapsed, bytes);
126     printf("* %d KiB/s\n", rate);
127     printf("\n\n");
128 
129     printf("READ REGISTERS\n\n");
130 
131     nb_points = MODBUS_MAX_READ_REGISTERS;
132     start = gettime_ms();
133     for (i=0; i<n_loop; i++) {
134         rc = modbus_read_registers(ctx, 0, nb_points, tab_reg);
135         if (rc == -1) {
136             fprintf(stderr, "%s\n", modbus_strerror(errno));
137             return -1;
138         }
139     }
140     end = gettime_ms();
141     elapsed = end - start;
142 
143     rate = (n_loop * nb_points) * G_MSEC_PER_SEC / (end - start);
144     printf("Transfert rate in points/seconds:\n");
145     printf("* %d registers/s\n", rate);
146     printf("\n");
147 
148     bytes = n_loop * nb_points * sizeof(uint16_t);
149     rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start);
150     printf("Values:\n");
151     printf("* %d x %d values\n", n_loop, nb_points);
152     printf("* %.3f ms for %d bytes\n", elapsed, bytes);
153     printf("* %d KiB/s\n", rate);
154     printf("\n");
155 
156     /* TCP:Query and reponse header and values */
157     bytes = 12 + 9 + (nb_points * sizeof(uint16_t));
158     printf("Values and TCP Modbus overhead:\n");
159     printf("* %d x %d bytes\n", n_loop, bytes);
160     bytes = n_loop * bytes;
161     rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start);
162     printf("* %.3f ms for %d bytes\n", elapsed, bytes);
163     printf("* %d KiB/s\n", rate);
164     printf("\n\n");
165 
166     printf("WRITE AND READ REGISTERS\n\n");
167 
168     nb_points = MODBUS_MAX_WR_WRITE_REGISTERS;
169     start = gettime_ms();
170     for (i=0; i<n_loop; i++) {
171         rc = modbus_write_and_read_registers(ctx,
172                                              0, nb_points, tab_reg,
173                                              0, nb_points, tab_reg);
174         if (rc == -1) {
175             fprintf(stderr, "%s\n", modbus_strerror(errno));
176             return -1;
177         }
178     }
179     end = gettime_ms();
180     elapsed = end - start;
181 
182     rate = (n_loop * nb_points) * G_MSEC_PER_SEC / (end - start);
183     printf("Transfert rate in points/seconds:\n");
184     printf("* %d registers/s\n", rate);
185     printf("\n");
186 
187     bytes = n_loop * nb_points * sizeof(uint16_t);
188     rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start);
189     printf("Values:\n");
190     printf("* %d x %d values\n", n_loop, nb_points);
191     printf("* %.3f ms for %d bytes\n", elapsed, bytes);
192     printf("* %d KiB/s\n", rate);
193     printf("\n");
194 
195     /* TCP:Query and reponse header and values */
196     bytes = 12 + 9 + (nb_points * sizeof(uint16_t));
197     printf("Values and TCP Modbus overhead:\n");
198     printf("* %d x %d bytes\n", n_loop, bytes);
199     bytes = n_loop * bytes;
200     rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start);
201     printf("* %.3f ms for %d bytes\n", elapsed, bytes);
202     printf("* %d KiB/s\n", rate);
203     printf("\n");
204 
205     /* Free the memory */
206     free(tab_bit);
207     free(tab_reg);
208 
209     /* Close the connection */
210     modbus_close(ctx);
211     modbus_free(ctx);
212 
213     return 0;
214 }
215