Commit 87293e459ec35576b0a8c502a523f7f2d2d7d7f1

Authored by Stéphane Raimbault
1 parent cfe875e7

MAJOR Rewrite of the message reading

The goal of this rewriting is to avoid the timeouts on the receiving
of exceptions and to be more robust on bad requests. Some devices
use the exception MODBUS_EXCEPTION_ACKNOWLEDGE to response to some
valid requests, so in this case, you'll really appreciate this
change!

- Slower! More system calls are used.
- The code is cleaner and easier to understand.
- Really faster when an exception occurs.
- Fix unit test of bad request in RTU
src/modbus-private.h
@@ -88,7 +88,7 @@ typedef struct _modbus_backend { @@ -88,7 +88,7 @@ typedef struct _modbus_backend {
88 int (*connect) (modbus_t *ctx); 88 int (*connect) (modbus_t *ctx);
89 void (*close) (modbus_t *ctx); 89 void (*close) (modbus_t *ctx);
90 int (*flush) (modbus_t *ctx); 90 int (*flush) (modbus_t *ctx);
91 - int (*select) (modbus_t *ctx, fd_set *rfds, struct timeval *tv, int msg_length_computed, int msg_length); 91 + int (*select) (modbus_t *ctx, fd_set *rfds, struct timeval *tv, int msg_length);
92 int (*filter_request) (modbus_t *ctx, int slave); 92 int (*filter_request) (modbus_t *ctx, int slave);
93 } modbus_backend_t; 93 } modbus_backend_t;
94 94
src/modbus-rtu.c
@@ -179,12 +179,13 @@ static void win32_ser_init(struct win32_ser *ws) { @@ -179,12 +179,13 @@ static void win32_ser_init(struct win32_ser *ws) {
179 ws->fd = INVALID_HANDLE_VALUE; 179 ws->fd = INVALID_HANDLE_VALUE;
180 } 180 }
181 181
  182 +/* FIXME Try to remove length_to_read -> max_len argument, only used by win32 */
182 static int win32_ser_select(struct win32_ser *ws, int max_len, struct timeval *tv) { 183 static int win32_ser_select(struct win32_ser *ws, int max_len, struct timeval *tv) {
183 COMMTIMEOUTS comm_to; 184 COMMTIMEOUTS comm_to;
184 unsigned int msec = 0; 185 unsigned int msec = 0;
185 186
186 /* Check if some data still in the buffer to be consumed */ 187 /* Check if some data still in the buffer to be consumed */
187 - if (ws->n_bytes> 0) { 188 + if (ws->n_bytes > 0) {
188 return 1; 189 return 1;
189 } 190 }
190 191
@@ -713,11 +714,11 @@ int _modbus_rtu_flush(modbus_t *ctx) @@ -713,11 +714,11 @@ int _modbus_rtu_flush(modbus_t *ctx)
713 #endif 714 #endif
714 } 715 }
715 716
716 -int _modbus_rtu_select(modbus_t *ctx, fd_set *rfds, struct timeval *tv, int msg_length_computed, int msg_length) 717 +int _modbus_rtu_select(modbus_t *ctx, fd_set *rfds, struct timeval *tv, int length_to_read)
717 { 718 {
718 int s_rc; 719 int s_rc;
719 #if defined(_WIN32) 720 #if defined(_WIN32)
720 - s_rc = win32_ser_select(&(((modbus_rtu_t*)ctx->backend_data)->w_ser), msg_length_computed, tv); 721 + s_rc = win32_ser_select(&(((modbus_rtu_t*)ctx->backend_data)->w_ser), length_to_read, tv);
721 if (s_rc == 0) { 722 if (s_rc == 0) {
722 errno = ETIMEDOUT; 723 errno = ETIMEDOUT;
723 return -1; 724 return -1;
@@ -758,17 +759,8 @@ int _modbus_rtu_select(modbus_t *ctx, fd_set *rfds, struct timeval *tv, int msg_ @@ -758,17 +759,8 @@ int _modbus_rtu_select(modbus_t *ctx, fd_set *rfds, struct timeval *tv, int msg_
758 759
759 if (s_rc == 0) { 760 if (s_rc == 0) {
760 /* Timeout */ 761 /* Timeout */
761 - if (msg_length == (ctx->backend->header_length + 2 +  
762 - ctx->backend->checksum_length)) {  
763 - /* Optimization allowed because exception response is  
764 - the smallest trame in modbus protocol (3) so always  
765 - raise a timeout error.  
766 - Temporary error before exception analyze. */  
767 - errno = EMBUNKEXC;  
768 - } else {  
769 - errno = ETIMEDOUT;  
770 - _error_print(ctx, "select");  
771 - } 762 + errno = ETIMEDOUT;
  763 + _error_print(ctx, "select");
772 return -1; 764 return -1;
773 } 765 }
774 #endif 766 #endif
src/modbus-tcp.c
@@ -350,7 +350,7 @@ int modbus_tcp_accept(modbus_t *ctx, int *socket) @@ -350,7 +350,7 @@ int modbus_tcp_accept(modbus_t *ctx, int *socket)
350 return ctx->s; 350 return ctx->s;
351 } 351 }
352 352
353 -int _modbus_tcp_select(modbus_t *ctx, fd_set *rfds, struct timeval *tv, int msg_length_computed, int msg_length) 353 +int _modbus_tcp_select(modbus_t *ctx, fd_set *rfds, struct timeval *tv, int length_to_read)
354 { 354 {
355 int s_rc; 355 int s_rc;
356 while ((s_rc = select(ctx->s+1, rfds, NULL, NULL, tv)) == -1) { 356 while ((s_rc = select(ctx->s+1, rfds, NULL, NULL, tv)) == -1) {
@@ -375,18 +375,8 @@ int _modbus_tcp_select(modbus_t *ctx, fd_set *rfds, struct timeval *tv, int msg_ @@ -375,18 +375,8 @@ int _modbus_tcp_select(modbus_t *ctx, fd_set *rfds, struct timeval *tv, int msg_
375 } 375 }
376 376
377 if (s_rc == 0) { 377 if (s_rc == 0) {
378 - /* Timeout */  
379 - if (msg_length == (ctx->backend->header_length + 2 +  
380 - ctx->backend->checksum_length)) {  
381 - /* Optimization allowed because exception response is  
382 - the smallest trame in modbus protocol (3) so always  
383 - raise a timeout error.  
384 - Temporary error before exception analyze. */  
385 - errno = EMBUNKEXC;  
386 - } else {  
387 - errno = ETIMEDOUT;  
388 - _error_print(ctx, "select");  
389 - } 378 + errno = ETIMEDOUT;
  379 + _error_print(ctx, "select");
390 return -1; 380 return -1;
391 } 381 }
392 382
src/modbus.c
@@ -42,6 +42,13 @@ const unsigned int libmodbus_version_micro = LIBMODBUS_VERSION_MICRO; @@ -42,6 +42,13 @@ const unsigned int libmodbus_version_micro = LIBMODBUS_VERSION_MICRO;
42 /* Max between RTU and TCP max adu length (so TCP) */ 42 /* Max between RTU and TCP max adu length (so TCP) */
43 #define MAX_MESSAGE_LENGTH 260 43 #define MAX_MESSAGE_LENGTH 260
44 44
  45 +/* 3 steps are used to parse the query */
  46 +typedef enum {
  47 + _STEP_FUNCTION,
  48 + _STEP_META,
  49 + _STEP_DATA
  50 +} _step_t;
  51 +
45 const char *modbus_strerror(int errnum) { 52 const char *modbus_strerror(int errnum) {
46 switch (errnum) { 53 switch (errnum) {
47 case EMBXILFUN: 54 case EMBXILFUN:
@@ -95,7 +102,7 @@ int modbus_flush(modbus_t *ctx) @@ -95,7 +102,7 @@ int modbus_flush(modbus_t *ctx)
95 } 102 }
96 103
97 /* Computes the length of the expected response */ 104 /* Computes the length of the expected response */
98 -static unsigned int compute_response_length(modbus_t *ctx, uint8_t *req) 105 +static unsigned int compute_response_length_from_request(modbus_t *ctx, uint8_t *req)
99 { 106 {
100 int length; 107 int length;
101 int offset; 108 int offset;
@@ -127,7 +134,7 @@ static unsigned int compute_response_length(modbus_t *ctx, uint8_t *req) @@ -127,7 +134,7 @@ static unsigned int compute_response_length(modbus_t *ctx, uint8_t *req)
127 length = 5; 134 length = 5;
128 } 135 }
129 136
130 - return length + offset + ctx->backend->checksum_length; 137 + return offset + length + ctx->backend->checksum_length;
131 } 138 }
132 139
133 /* Sends a request/response */ 140 /* Sends a request/response */
@@ -179,21 +186,14 @@ typedef enum { @@ -179,21 +186,14 @@ typedef enum {
179 MSG_CONFIRMATION 186 MSG_CONFIRMATION
180 } msg_type_t; 187 } msg_type_t;
181 188
182 -/* Computes the header length (to reach the real data) */  
183 -static uint8_t compute_header_length(int function, msg_type_t msg_type) 189 +/* Computes the length to read after the function received */
  190 +static uint8_t compute_meta_length_after_function(int function,
  191 + msg_type_t msg_type)
184 { 192 {
185 int length; 193 int length;
186 194
187 - if (msg_type == MSG_CONFIRMATION) {  
188 - if (function == _FC_REPORT_SLAVE_ID) {  
189 - length = 1;  
190 - } else {  
191 - /* Should never happen, the other header lengths are precomputed */  
192 - abort();  
193 - }  
194 - } else /* MSG_INDICATION */ {  
195 - if (function <= _FC_WRITE_SINGLE_COIL ||  
196 - function == _FC_WRITE_SINGLE_REGISTER) { 195 + if (msg_type == MSG_INDICATION) {
  196 + if (function <= _FC_WRITE_SINGLE_REGISTER) {
197 length = 4; 197 length = 4;
198 } else if (function == _FC_WRITE_MULTIPLE_COILS || 198 } else if (function == _FC_WRITE_MULTIPLE_COILS ||
199 function == _FC_WRITE_MULTIPLE_REGISTERS) { 199 function == _FC_WRITE_MULTIPLE_REGISTERS) {
@@ -201,27 +201,54 @@ static uint8_t compute_header_length(int function, msg_type_t msg_type) @@ -201,27 +201,54 @@ static uint8_t compute_header_length(int function, msg_type_t msg_type)
201 } else if (function == _FC_READ_AND_WRITE_REGISTERS) { 201 } else if (function == _FC_READ_AND_WRITE_REGISTERS) {
202 length = 9; 202 length = 9;
203 } else { 203 } else {
  204 + /* _FC_READ_EXCEPTION_STATUS, _FC_REPORT_SLAVE_ID */
204 length = 0; 205 length = 0;
205 } 206 }
  207 + } else {
  208 + /* MSG_CONFIRMATION */
  209 + switch (function) {
  210 + case _FC_WRITE_SINGLE_COIL:
  211 + case _FC_WRITE_SINGLE_REGISTER:
  212 + case _FC_WRITE_MULTIPLE_COILS:
  213 + case _FC_WRITE_MULTIPLE_REGISTERS:
  214 + length = 4;
  215 + break;
  216 + default:
  217 + length = 1;
  218 + }
206 } 219 }
  220 +
207 return length; 221 return length;
208 } 222 }
209 223
210 -/* Computes the length of the data to write in the request */  
211 -static int compute_data_length(modbus_t *ctx, uint8_t *msg) 224 +/* Computes the length to read after the meta information (address, count, etc) */
  225 +static int compute_data_length_after_meta(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type)
212 { 226 {
213 int function = msg[ctx->backend->header_length]; 227 int function = msg[ctx->backend->header_length];
214 int length; 228 int length;
215 229
216 - if (function == _FC_WRITE_MULTIPLE_COILS ||  
217 - function == _FC_WRITE_MULTIPLE_REGISTERS) {  
218 - length = msg[ctx->backend->header_length + 5];  
219 - } else if (function == _FC_REPORT_SLAVE_ID) {  
220 - length = msg[ctx->backend->header_length + 1];  
221 - } else if (function == _FC_READ_AND_WRITE_REGISTERS) {  
222 - length = msg[ctx->backend->header_length + 9];  
223 - } else  
224 - length = 0; 230 + if (msg_type == MSG_INDICATION) {
  231 + switch (function) {
  232 + case _FC_WRITE_MULTIPLE_COILS:
  233 + case _FC_WRITE_MULTIPLE_REGISTERS:
  234 + length = msg[ctx->backend->header_length + 5];
  235 + break;
  236 + case _FC_READ_AND_WRITE_REGISTERS:
  237 + length = msg[ctx->backend->header_length + 9];
  238 + break;
  239 + default:
  240 + length = 0;
  241 + }
  242 + } else {
  243 + /* MSG_CONFIRMATION */
  244 + if (function <= _FC_READ_INPUT_REGISTERS ||
  245 + function == _FC_REPORT_SLAVE_ID ||
  246 + function == _FC_READ_AND_WRITE_REGISTERS) {
  247 + length = msg[ctx->backend->header_length + 1];
  248 + } else {
  249 + length = 0;
  250 + }
  251 + }
225 252
226 length += ctx->backend->checksum_length; 253 length += ctx->backend->checksum_length;
227 254
@@ -232,9 +259,6 @@ static int compute_data_length(modbus_t *ctx, uint8_t *msg) @@ -232,9 +259,6 @@ static int compute_data_length(modbus_t *ctx, uint8_t *msg)
232 /* Waits a response from a modbus server or a request from a modbus client. 259 /* Waits a response from a modbus server or a request from a modbus client.
233 This function blocks if there is no replies (3 timeouts). 260 This function blocks if there is no replies (3 timeouts).
234 261
235 - The argument msg_length_computed must be set to MSG_LENGTH_UNDEFINED if  
236 - undefined.  
237 -  
238 The function shall return the number of received characters and the received 262 The function shall return the number of received characters and the received
239 message in an array of uint8_t if successful. Otherwise it shall return -1 263 message in an array of uint8_t if successful. Otherwise it shall return -1
240 and errno is set to one of the values defined below: 264 and errno is set to one of the values defined below:
@@ -245,69 +269,59 @@ static int compute_data_length(modbus_t *ctx, uint8_t *msg) @@ -245,69 +269,59 @@ static int compute_data_length(modbus_t *ctx, uint8_t *msg)
245 - read() or recv() error codes 269 - read() or recv() error codes
246 */ 270 */
247 271
248 -static int receive_msg(modbus_t *ctx, int msg_length_computed,  
249 - uint8_t *msg, msg_type_t msg_type) 272 +static int receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type)
250 { 273 {
251 - int s_rc;  
252 - int read_rc; 274 + int rc;
253 fd_set rfds; 275 fd_set rfds;
254 struct timeval tv; 276 struct timeval tv;
255 int length_to_read; 277 int length_to_read;
256 uint8_t *p_msg; 278 uint8_t *p_msg;
257 - enum { FUNCTION, DATA, COMPLETE };  
258 - int state;  
259 int msg_length = 0; 279 int msg_length = 0;
  280 + _step_t step;
260 281
261 if (ctx->debug) { 282 if (ctx->debug) {
262 if (msg_type == MSG_INDICATION) { 283 if (msg_type == MSG_INDICATION) {
263 - printf("Waiting for a indication"); 284 + printf("Waiting for a indication...\n");
264 } else { 285 } else {
265 - printf("Waiting for a confirmation"); 286 + printf("Waiting for a confirmation...\n");
266 } 287 }
267 -  
268 - if (msg_length_computed == MSG_LENGTH_UNDEFINED)  
269 - printf("...\n");  
270 - else  
271 - printf(" (%d bytes)...\n", msg_length_computed);  
272 } 288 }
273 289
274 /* Add a file descriptor to the set */ 290 /* Add a file descriptor to the set */
275 FD_ZERO(&rfds); 291 FD_ZERO(&rfds);
276 FD_SET(ctx->s, &rfds); 292 FD_SET(ctx->s, &rfds);
277 293
278 - if (msg_length_computed == MSG_LENGTH_UNDEFINED) {  
279 - /* Wait for a message */ 294 + /* We need to analyse the message step by step. At the first step, we want
  295 + * to reach the function code because all packets contain this
  296 + * information. */
  297 + step = _STEP_FUNCTION;
  298 + length_to_read = ctx->backend->header_length + 1;
  299 +
  300 + if (msg_type == MSG_INDICATION) {
  301 + /* Wait for a message, we don't know when the message will be
  302 + * received */
  303 + /* FIXME Not infinite */
280 tv.tv_sec = 60; 304 tv.tv_sec = 60;
281 tv.tv_usec = 0; 305 tv.tv_usec = 0;
282 -  
283 - /* The message length is undefined (request receiving) so we need to  
284 - * analyse the message step by step. At the first step, we want to  
285 - * reach the function code because all packets contains this  
286 - * information. */  
287 - state = FUNCTION;  
288 - msg_length_computed = ctx->backend->header_length + 1;  
289 } else { 306 } else {
290 tv.tv_sec = ctx->timeout_begin.tv_sec; 307 tv.tv_sec = ctx->timeout_begin.tv_sec;
291 tv.tv_usec = ctx->timeout_begin.tv_usec; 308 tv.tv_usec = ctx->timeout_begin.tv_usec;
292 - state = COMPLETE;  
293 - }  
294 -  
295 - length_to_read = msg_length_computed;  
296 -  
297 - s_rc = ctx->backend->select(ctx, &rfds, &tv, msg_length_computed, msg_length);  
298 - if (s_rc == -1) {  
299 - return -1;  
300 } 309 }
301 310
302 p_msg = msg; 311 p_msg = msg;
303 - while (s_rc) {  
304 - read_rc = ctx->backend->recv(ctx, p_msg, length_to_read);  
305 - if (read_rc == 0) { 312 + while (length_to_read != 0) {
  313 + rc = ctx->backend->select(ctx, &rfds, &tv, length_to_read);
  314 + if (rc == -1) {
  315 + return -1;
  316 + }
  317 +
  318 + rc = ctx->backend->recv(ctx, p_msg, length_to_read);
  319 + if (rc == 0) {
306 errno = ECONNRESET; 320 errno = ECONNRESET;
307 - read_rc = -1; 321 + rc = -1;
308 } 322 }
309 323
310 - if (read_rc == -1) { 324 + if (rc == -1) {
311 _error_print(ctx, "read"); 325 _error_print(ctx, "read");
312 if (ctx->error_recovery && (errno == ECONNRESET || 326 if (ctx->error_recovery && (errno == ECONNRESET ||
313 errno == ECONNREFUSED)) { 327 errno == ECONNREFUSED)) {
@@ -315,71 +329,55 @@ static int receive_msg(modbus_t *ctx, int msg_length_computed, @@ -315,71 +329,55 @@ static int receive_msg(modbus_t *ctx, int msg_length_computed,
315 modbus_connect(ctx); 329 modbus_connect(ctx);
316 /* Could be removed by previous calls */ 330 /* Could be removed by previous calls */
317 errno = ECONNRESET; 331 errno = ECONNRESET;
318 - return -1;  
319 } 332 }
320 return -1; 333 return -1;
321 } 334 }
322 335
323 - /* Sums bytes received */  
324 - msg_length += read_rc;  
325 -  
326 /* Display the hex code of each character received */ 336 /* Display the hex code of each character received */
327 if (ctx->debug) { 337 if (ctx->debug) {
328 int i; 338 int i;
329 - for (i=0; i < read_rc; i++) 339 + for (i=0; i < rc; i++)
330 printf("<%.2X>", p_msg[i]); 340 printf("<%.2X>", p_msg[i]);
331 } 341 }
332 342
333 - if (msg_length < msg_length_computed) {  
334 - /* Message incomplete */  
335 - length_to_read = msg_length_computed - msg_length;  
336 - } else {  
337 - switch (state) {  
338 - case FUNCTION: 343 + /* Moves the pointer to receive other data */
  344 + p_msg = &(p_msg[rc]);
  345 + /* Sums bytes received */
  346 + msg_length += rc;
  347 + /* Computes remaining bytes */
  348 + length_to_read -= rc;
  349 +
  350 + if (length_to_read == 0) {
  351 + switch (step) {
  352 + case _STEP_FUNCTION:
339 /* Function code position */ 353 /* Function code position */
340 - length_to_read = compute_header_length( 354 + length_to_read = compute_meta_length_after_function(
341 msg[ctx->backend->header_length], 355 msg[ctx->backend->header_length],
342 msg_type); 356 msg_type);
343 - msg_length_computed += length_to_read;  
344 - /* It's useless to check the value of  
345 - msg_length_computed in this case (only  
346 - defined values are used). */  
347 if (length_to_read != 0) { 357 if (length_to_read != 0) {
348 - state = DATA; 358 + step = _STEP_META;
349 break; 359 break;
350 - } /* else switch straight to DATA */  
351 - case DATA:  
352 - length_to_read = compute_data_length(ctx, msg);  
353 - msg_length_computed += length_to_read;  
354 - if (msg_length_computed > ctx->backend->max_adu_length) { 360 + } /* else switches straight to the next step */
  361 + case _STEP_META:
  362 + length_to_read = compute_data_length_after_meta(
  363 + ctx, msg, msg_type);
  364 + if ((msg_length + length_to_read) > ctx->backend->max_adu_length) {
355 errno = EMBBADDATA; 365 errno = EMBBADDATA;
356 _error_print(ctx, "too many data"); 366 _error_print(ctx, "too many data");
357 return -1; 367 return -1;
358 } 368 }
359 - state = COMPLETE; 369 + step = _STEP_DATA;
360 break; 370 break;
361 - case COMPLETE:  
362 - length_to_read = 0; 371 + default:
363 break; 372 break;
364 } 373 }
365 } 374 }
366 375
367 - /* Moves the pointer to receive other data */  
368 - p_msg = &(p_msg[read_rc]);  
369 -  
370 if (length_to_read > 0) { 376 if (length_to_read > 0) {
371 /* If no character at the buffer wait 377 /* If no character at the buffer wait
372 - TIME_OUT_END_OF_TRAME before to generate an error. */ 378 + TIME_OUT_END_OF_TRAME before raising an error. */
373 tv.tv_sec = ctx->timeout_end.tv_sec; 379 tv.tv_sec = ctx->timeout_end.tv_sec;
374 tv.tv_usec = ctx->timeout_end.tv_usec; 380 tv.tv_usec = ctx->timeout_end.tv_usec;
375 -  
376 - s_rc = ctx->backend->select(ctx, &rfds, &tv, msg_length_computed, msg_length);  
377 - if (s_rc == -1) {  
378 - return -1;  
379 - }  
380 - } else {  
381 - /* All chars are received */  
382 - s_rc = FALSE;  
383 } 381 }
384 } 382 }
385 383
@@ -401,8 +399,7 @@ int modbus_receive(modbus_t *ctx, int sockfd, uint8_t *req) @@ -401,8 +399,7 @@ int modbus_receive(modbus_t *ctx, int sockfd, uint8_t *req)
401 ctx->s = sockfd; 399 ctx->s = sockfd;
402 } 400 }
403 401
404 - /* The length of the request to receive isn't known. */  
405 - return receive_msg(ctx, MSG_LENGTH_UNDEFINED, req, MSG_INDICATION); 402 + return receive_msg(ctx, req, MSG_INDICATION);
406 } 403 }
407 404
408 /* Receives the response and checks values. 405 /* Receives the response and checks values.
@@ -418,14 +415,21 @@ static int receive_msg_req(modbus_t *ctx, uint8_t *req, uint8_t *rsp) @@ -418,14 +415,21 @@ static int receive_msg_req(modbus_t *ctx, uint8_t *req, uint8_t *rsp)
418 int rsp_length_computed; 415 int rsp_length_computed;
419 int offset = ctx->backend->header_length; 416 int offset = ctx->backend->header_length;
420 417
421 - rsp_length_computed = compute_response_length(ctx, req);  
422 - rc = receive_msg(ctx, rsp_length_computed, rsp, MSG_CONFIRMATION);  
423 - if (rc != -1) {  
424 - /* GOOD RESPONSE */ 418 + rc = receive_msg(ctx, rsp, MSG_CONFIRMATION);
  419 + if (rc == -1) {
  420 + return -1;
  421 + }
  422 +
  423 + rsp_length_computed = compute_response_length_from_request(ctx, req);
  424 +
  425 + /* Check length */
  426 + if (rc == rsp_length_computed ||
  427 + rsp_length_computed == MSG_LENGTH_UNDEFINED) {
425 int req_nb_value; 428 int req_nb_value;
426 int rsp_nb_value; 429 int rsp_nb_value;
427 int function = rsp[offset]; 430 int function = rsp[offset];
428 431
  432 + /* Check function code */
429 if (function != req[offset]) { 433 if (function != req[offset]) {
430 if (ctx->debug) { 434 if (ctx->debug) {
431 fprintf(stderr, 435 fprintf(stderr,
@@ -436,8 +440,7 @@ static int receive_msg_req(modbus_t *ctx, uint8_t *req, uint8_t *rsp) @@ -436,8 +440,7 @@ static int receive_msg_req(modbus_t *ctx, uint8_t *req, uint8_t *rsp)
436 return -1; 440 return -1;
437 } 441 }
438 442
439 - /* The number of values is returned if it's corresponding  
440 - * to the request */ 443 + /* Check the number of values is corresponding to the request */
441 switch (function) { 444 switch (function) {
442 case _FC_READ_COILS: 445 case _FC_READ_COILS:
443 case _FC_READ_DISCRETE_INPUTS: 446 case _FC_READ_DISCRETE_INPUTS:
@@ -481,28 +484,21 @@ static int receive_msg_req(modbus_t *ctx, uint8_t *req, uint8_t *rsp) @@ -481,28 +484,21 @@ static int receive_msg_req(modbus_t *ctx, uint8_t *req, uint8_t *rsp)
481 errno = EMBBADDATA; 484 errno = EMBBADDATA;
482 rc = -1; 485 rc = -1;
483 } 486 }
484 - } else if (errno == EMBUNKEXC) { 487 + } else if (rc == (offset + 2 + ctx->backend->checksum_length) &&
  488 + req[offset] == (rsp[offset] - 0x80)) {
485 /* EXCEPTION CODE RECEIVED */ 489 /* EXCEPTION CODE RECEIVED */
486 490
487 - /* CRC must be checked here (not done in receive_msg) */  
488 - rc = ctx->backend->check_integrity(ctx, rsp,  
489 - _MODBUS_EXCEPTION_RSP_LENGTH);  
490 - if (rc == -1)  
491 - return -1;  
492 -  
493 - /* Check for exception response.  
494 - 0x80 + function is stored in the exception  
495 - response. */  
496 - if (0x80 + req[offset] == rsp[offset]) {  
497 - int exception_code = rsp[offset + 1];  
498 - if (exception_code < MODBUS_EXCEPTION_MAX) {  
499 - errno = MODBUS_ENOBASE + exception_code;  
500 - } else {  
501 - errno = EMBBADEXC;  
502 - }  
503 - _error_print(ctx, NULL);  
504 - return -1; 491 + int exception_code = rsp[offset + 1];
  492 + if (exception_code < MODBUS_EXCEPTION_MAX) {
  493 + errno = MODBUS_ENOBASE + exception_code;
  494 + } else {
  495 + errno = EMBBADEXC;
505 } 496 }
  497 + _error_print(ctx, NULL);
  498 + rc = -1;
  499 + } else {
  500 + errno = EMBBADDATA;
  501 + rc = -1;
506 } 502 }
507 503
508 return rc; 504 return rc;
tests/unit-test-client.c
@@ -270,7 +270,7 @@ int main(int argc, char *argv[]) @@ -270,7 +270,7 @@ int main(int argc, char *argv[])
270 memset(tab_rp_registers, 0, nb_points * sizeof(uint16_t)); 270 memset(tab_rp_registers, 0, nb_points * sizeof(uint16_t));
271 271
272 /* Write registers to zero from tab_rp_registers and read registers to 272 /* Write registers to zero from tab_rp_registers and read registers to
273 - tab_rp_registers. They should be same as UT_REGISTERS_TAB. */ 273 + tab_rp_registers. They should be same as UT_REGISTERS_TAB. */
274 rc = modbus_read_and_write_registers(ctx, 274 rc = modbus_read_and_write_registers(ctx,
275 UT_REGISTERS_ADDRESS, 275 UT_REGISTERS_ADDRESS,
276 UT_REGISTERS_NB_POINTS, 276 UT_REGISTERS_NB_POINTS,
@@ -280,7 +280,7 @@ int main(int argc, char *argv[]) @@ -280,7 +280,7 @@ int main(int argc, char *argv[])
280 tab_rp_registers); 280 tab_rp_registers);
281 printf("4/5 modbus_read_and_write_registers, read part: "); 281 printf("4/5 modbus_read_and_write_registers, read part: ");
282 if (rc != UT_REGISTERS_NB_POINTS) { 282 if (rc != UT_REGISTERS_NB_POINTS) {
283 - printf("FAILED (nb points %d)\n", rc); 283 + printf("FAILED (nb points %d != %d)\n", rc, UT_REGISTERS_NB_POINTS);
284 goto close; 284 goto close;
285 } 285 }
286 286
@@ -299,7 +299,7 @@ int main(int argc, char *argv[]) @@ -299,7 +299,7 @@ int main(int argc, char *argv[])
299 tab_rp_registers); 299 tab_rp_registers);
300 printf("5/5 modbus_read_and_write_registers, write part: "); 300 printf("5/5 modbus_read_and_write_registers, write part: ");
301 if (rc != UT_REGISTERS_NB_POINTS) { 301 if (rc != UT_REGISTERS_NB_POINTS) {
302 - printf("FAILED (nb points %d)\n", rc); 302 + printf("FAILED (nb points %d != %d)\n", rc, UT_REGISTERS_NB_POINTS);
303 goto close; 303 goto close;
304 } 304 }
305 305
@@ -362,8 +362,8 @@ int main(int argc, char *argv[]) @@ -362,8 +362,8 @@ int main(int argc, char *argv[])
362 /** ILLEGAL DATA ADDRESS **/ 362 /** ILLEGAL DATA ADDRESS **/
363 printf("\nTEST ILLEGAL DATA ADDRESS:\n"); 363 printf("\nTEST ILLEGAL DATA ADDRESS:\n");
364 364
365 - /* The mapping begins at 0 and ending at address + nb_points so  
366 - * the addresses below are not valid. */ 365 + /* The mapping begins at 0 and ends at address + nb_points so
  366 + * the addresses are not valid. */
367 367
368 rc = modbus_read_bits(ctx, UT_BITS_ADDRESS, 368 rc = modbus_read_bits(ctx, UT_BITS_ADDRESS,
369 UT_BITS_NB_POINTS + 1, 369 UT_BITS_NB_POINTS + 1,
tests/unit-test.h
1 /* 1 /*
2 - * Copyright © 2008 Stéphane Raimbault <stephane.raimbault@gmail.com> 2 + * Copyright © 2008-2010 Stéphane Raimbault <stephane.raimbault@gmail.com>
3 * 3 *
4 * This program is free software: you can redistribute it and/or modify 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 5 * it under the terms of the GNU General Public License as published by