Rename [gs]et_timeout_[begin|end] to [gs]et_[response|byte]_timeout
[libmodbus.git] / src / modbus-rtu.c
blob2e0ca77d7f96547622187338fbbf2d13cb4862fd
1 /*
2 * Copyright © 2001-2010 Stéphane Raimbault <stephane.raimbault@gmail.com>
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
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 Lesser Public License for more details.
14 * You should have received a copy of the GNU Lesser Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <string.h>
23 #ifndef _MSC_VER
24 #include <unistd.h>
25 #endif
26 #include <assert.h>
28 #include "modbus-private.h"
30 #include "modbus-rtu.h"
31 #include "modbus-rtu-private.h"
33 /* Table of CRC values for high-order byte */
34 static const uint8_t table_crc_hi[] = {
35 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
36 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
37 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
38 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
39 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
40 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
41 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
42 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
43 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
44 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
45 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
46 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
47 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
48 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
49 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
50 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
51 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
52 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
53 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
54 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
55 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
56 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
57 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
58 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
59 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
60 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
63 /* Table of CRC values for low-order byte */
64 static const uint8_t table_crc_lo[] = {
65 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
66 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
67 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
68 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
69 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
70 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
71 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
72 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
73 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
74 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
75 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
76 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
77 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
78 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
79 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
80 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
81 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
82 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
83 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
84 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
85 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
86 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
87 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
88 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
89 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
90 0x43, 0x83, 0x41, 0x81, 0x80, 0x40
93 /* Define the slave ID of the remote device to talk in master mode or set the
94 * internal slave ID in slave mode */
95 static int _modbus_set_slave(modbus_t *ctx, int slave)
97 /* Broadcast address is 0 (MODBUS_BROADCAST_ADDRESS) */
98 if (slave >= 0 && slave <= 247) {
99 ctx->slave = slave;
100 } else {
101 errno = EINVAL;
102 return -1;
105 return 0;
108 /* Builds a RTU request header */
109 static int _modbus_rtu_build_request_basis(modbus_t *ctx, int function,
110 int addr, int nb,
111 uint8_t *req)
113 assert(ctx->slave != -1);
114 req[0] = ctx->slave;
115 req[1] = function;
116 req[2] = addr >> 8;
117 req[3] = addr & 0x00ff;
118 req[4] = nb >> 8;
119 req[5] = nb & 0x00ff;
121 return _MODBUS_RTU_PRESET_REQ_LENGTH;
124 /* Builds a RTU response header */
125 static int _modbus_rtu_build_response_basis(sft_t *sft, uint8_t *rsp)
127 /* In this case, the slave is certainly valid because a check is already
128 * done in _modbus_rtu_listen */
129 rsp[0] = sft->slave;
130 rsp[1] = sft->function;
132 return _MODBUS_RTU_PRESET_RSP_LENGTH;
135 static uint16_t crc16(uint8_t *buffer, uint16_t buffer_length)
137 uint8_t crc_hi = 0xFF; /* high CRC byte initialized */
138 uint8_t crc_lo = 0xFF; /* low CRC byte initialized */
139 unsigned int i; /* will index into CRC lookup */
141 /* pass through message buffer */
142 while (buffer_length--) {
143 i = crc_hi ^ *buffer++; /* calculate the CRC */
144 crc_hi = crc_lo ^ table_crc_hi[i];
145 crc_lo = table_crc_lo[i];
148 return (crc_hi << 8 | crc_lo);
151 int _modbus_rtu_prepare_response_tid(const uint8_t *req, int *req_length)
153 (*req_length) -= _MODBUS_RTU_CHECKSUM_LENGTH;
154 /* No TID */
155 return 0;
158 int _modbus_rtu_send_msg_pre(uint8_t *req, int req_length)
160 uint16_t crc = crc16(req, req_length);
161 req[req_length++] = crc >> 8;
162 req[req_length++] = crc & 0x00FF;
164 return req_length;
167 #if defined(_WIN32)
169 /* This simple implementation is sort of a substitute of the select() call,
170 * working this way: the win32_ser_select() call tries to read some data from
171 * the serial port, setting the timeout as the select() call would. Data read is
172 * stored into the receive buffer, that is then consumed by the win32_ser_read()
173 * call. So win32_ser_select() does both the event waiting and the reading,
174 * while win32_ser_read() only consumes the receive buffer.
177 static void win32_ser_init(struct win32_ser *ws) {
178 /* Clear everything */
179 memset(ws, 0x00, sizeof(struct win32_ser));
181 /* Set file handle to invalid */
182 ws->fd = INVALID_HANDLE_VALUE;
185 /* FIXME Try to remove length_to_read -> max_len argument, only used by win32 */
186 static int win32_ser_select(struct win32_ser *ws, int max_len,
187 struct timeval *tv) {
188 COMMTIMEOUTS comm_to;
189 unsigned int msec = 0;
191 /* Check if some data still in the buffer to be consumed */
192 if (ws->n_bytes > 0) {
193 return 1;
196 /* Setup timeouts like select() would do */
197 msec = tv->tv_sec * 1000 + tv->tv_usec / 1000;
198 if (msec < 1)
199 msec = 1;
201 comm_to.ReadIntervalTimeout = msec;
202 comm_to.ReadTotalTimeoutMultiplier = 0;
203 comm_to.ReadTotalTimeoutConstant = msec;
204 comm_to.WriteTotalTimeoutMultiplier = 0;
205 comm_to.WriteTotalTimeoutConstant = 1000;
206 SetCommTimeouts(ws->fd, &comm_to);
208 /* Read some bytes */
209 if ((max_len > PY_BUF_SIZE) || (max_len < 0)) {
210 max_len = PY_BUF_SIZE;
213 if (ReadFile(ws->fd, &ws->buf, max_len, &ws->n_bytes, NULL)) {
214 /* Check if some bytes available */
215 if (ws->n_bytes > 0) {
216 /* Some bytes read */
217 return 1;
218 } else {
219 /* Just timed out */
220 return 0;
222 } else {
223 /* Some kind of error */
224 return -1;
228 static int win32_ser_read(struct win32_ser *ws, uint8_t *p_msg,
229 unsigned int max_len) {
230 unsigned int n = ws->n_bytes;
232 if (max_len < n) {
233 n = max_len;
236 if (n > 0) {
237 memcpy(p_msg, ws->buf, n);
240 ws->n_bytes -= n;
242 return n;
244 #endif
246 ssize_t _modbus_rtu_send(modbus_t *ctx, const uint8_t *req, int req_length)
248 #if defined(_WIN32)
249 modbus_rtu_t *ctx_rtu = ctx->backend_data;
250 DWORD n_bytes = 0;
251 return (WriteFile(ctx_rtu->w_ser.fd, req, req_length, &n_bytes, NULL)) ? n_bytes : -1;
252 #else
253 return write(ctx->s, req, req_length);
254 #endif
257 ssize_t _modbus_rtu_recv(modbus_t *ctx, uint8_t *rsp, int rsp_length)
259 #if defined(_WIN32)
260 return win32_ser_read(&((modbus_rtu_t *)ctx->backend_data)->w_ser, rsp, rsp_length);
261 #else
262 return read(ctx->s, rsp, rsp_length);
263 #endif
266 int _modbus_rtu_flush(modbus_t *);
268 /* The check_crc16 function shall return the message length if the CRC is
269 valid. Otherwise it shall return -1 and set errno to EMBADCRC. */
270 int _modbus_rtu_check_integrity(modbus_t *ctx, uint8_t *msg,
271 const int msg_length)
273 uint16_t crc_calculated;
274 uint16_t crc_received;
276 crc_calculated = crc16(msg, msg_length - 2);
277 crc_received = (msg[msg_length - 2] << 8) | msg[msg_length - 1];
279 /* Check CRC of msg */
280 if (crc_calculated == crc_received) {
281 return msg_length;
282 } else {
283 if (ctx->debug) {
284 fprintf(stderr, "ERROR CRC received %0X != CRC calculated %0X\n",
285 crc_received, crc_calculated);
287 if (ctx->error_recovery) {
288 _modbus_rtu_flush(ctx);
290 errno = EMBBADCRC;
291 return -1;
295 /* Sets up a serial port for RTU communications */
296 static int _modbus_rtu_connect(modbus_t *ctx)
298 #if defined(_WIN32)
299 DCB dcb;
300 #else
301 struct termios tios;
302 speed_t speed;
303 #endif
304 modbus_rtu_t *ctx_rtu = ctx->backend_data;
306 if (ctx->debug) {
307 printf("Opening %s at %d bauds (%c, %d, %d)\n",
308 ctx_rtu->device, ctx_rtu->baud, ctx_rtu->parity,
309 ctx_rtu->data_bit, ctx_rtu->stop_bit);
312 #if defined(_WIN32)
313 /* Some references here:
314 * http://msdn.microsoft.com/en-us/library/aa450602.aspx
316 win32_ser_init(&ctx_rtu->w_ser);
318 /* ctx_rtu->device should contain a string like "COMxx:" xx being a decimal
319 * number */
320 ctx_rtu->w_ser.fd = CreateFileA(ctx_rtu->device,
321 GENERIC_READ | GENERIC_WRITE,
323 NULL,
324 OPEN_EXISTING,
326 NULL);
328 /* Error checking */
329 if (ctx_rtu->w_ser.fd == INVALID_HANDLE_VALUE) {
330 fprintf(stderr, "ERROR Can't open the device %s (%s)\n",
331 ctx_rtu->device, strerror(errno));
332 return -1;
335 /* Save params */
336 ctx_rtu->old_dcb.DCBlength = sizeof(DCB);
337 if (!GetCommState(ctx_rtu->w_ser.fd, &ctx_rtu->old_dcb)) {
338 fprintf(stderr, "ERROR Error getting configuration (LastError %d)\n",
339 (int)GetLastError());
340 return -1;
343 /* Build new configuration (starting from current settings) */
344 dcb = ctx_rtu->old_dcb;
346 /* Speed setting */
347 switch (ctx_rtu->baud) {
348 case 110:
349 dcb.BaudRate = CBR_110;
350 break;
351 case 300:
352 dcb.BaudRate = CBR_300;
353 break;
354 case 600:
355 dcb.BaudRate = CBR_600;
356 break;
357 case 1200:
358 dcb.BaudRate = CBR_1200;
359 break;
360 case 2400:
361 dcb.BaudRate = CBR_2400;
362 break;
363 case 4800:
364 dcb.BaudRate = CBR_4800;
365 break;
366 case 9600:
367 dcb.BaudRate = CBR_9600;
368 break;
369 case 19200:
370 dcb.BaudRate = CBR_19200;
371 break;
372 case 38400:
373 dcb.BaudRate = CBR_38400;
374 break;
375 case 57600:
376 dcb.BaudRate = CBR_57600;
377 break;
378 case 115200:
379 dcb.BaudRate = CBR_115200;
380 break;
381 default:
382 dcb.BaudRate = CBR_9600;
383 printf("WARNING Unknown baud rate %d for %s (B9600 used)\n",
384 ctx_rtu->baud, ctx_rtu->device);
387 /* Data bits */
388 switch (ctx_rtu->data_bit) {
389 case 5:
390 dcb.ByteSize = 5;
391 break;
392 case 6:
393 dcb.ByteSize = 6;
394 break;
395 case 7:
396 dcb.ByteSize = 7;
397 break;
398 case 8:
399 default:
400 dcb.ByteSize = 8;
401 break;
404 /* Stop bits */
405 if (ctx_rtu->stop_bit == 1)
406 dcb.StopBits = ONESTOPBIT;
407 else /* 2 */
408 dcb.StopBits = TWOSTOPBITS;
410 /* Parity */
411 if (ctx_rtu->parity == 'N') {
412 dcb.Parity = NOPARITY;
413 dcb.fParity = FALSE;
414 } else if (ctx_rtu->parity == 'E') {
415 dcb.Parity = EVENPARITY;
416 dcb.fParity = TRUE;
417 } else {
418 /* odd */
419 dcb.Parity = ODDPARITY;
420 dcb.fParity = TRUE;
423 /* Hardware handshaking left as default settings retrieved */
425 /* No software handshaking */
426 dcb.fTXContinueOnXoff = TRUE;
427 dcb.fOutX = FALSE;
428 dcb.fInX = FALSE;
430 /* Binary mode (it's the only supported on Windows anyway) */
431 dcb.fBinary = TRUE;
433 /* Don't want errors to be blocking */
434 dcb.fAbortOnError = FALSE;
436 /* TODO: any other flags!? */
438 /* Setup port */
439 if (!SetCommState(ctx_rtu->w_ser.fd, &dcb)) {
440 fprintf(stderr, "ERROR Error setting new configuration (LastError %d)\n",
441 (int)GetLastError());
442 return -1;
444 #else
445 /* The O_NOCTTY flag tells UNIX that this program doesn't want
446 to be the "controlling terminal" for that port. If you
447 don't specify this then any input (such as keyboard abort
448 signals and so forth) will affect your process
450 Timeouts are ignored in canonical input mode or when the
451 NDELAY option is set on the file via open or fcntl */
452 ctx->s = open(ctx_rtu->device, O_RDWR | O_NOCTTY | O_NDELAY | O_EXCL);
453 if (ctx->s == -1) {
454 fprintf(stderr, "ERROR Can't open the device %s (%s)\n",
455 ctx_rtu->device, strerror(errno));
456 return -1;
459 /* Save */
460 tcgetattr(ctx->s, &(ctx_rtu->old_tios));
462 memset(&tios, 0, sizeof(struct termios));
464 /* C_ISPEED Input baud (new interface)
465 C_OSPEED Output baud (new interface)
467 switch (ctx_rtu->baud) {
468 case 110:
469 speed = B110;
470 break;
471 case 300:
472 speed = B300;
473 break;
474 case 600:
475 speed = B600;
476 break;
477 case 1200:
478 speed = B1200;
479 break;
480 case 2400:
481 speed = B2400;
482 break;
483 case 4800:
484 speed = B4800;
485 break;
486 case 9600:
487 speed = B9600;
488 break;
489 case 19200:
490 speed = B19200;
491 break;
492 case 38400:
493 speed = B38400;
494 break;
495 case 57600:
496 speed = B57600;
497 break;
498 case 115200:
499 speed = B115200;
500 break;
501 default:
502 speed = B9600;
503 if (ctx->debug) {
504 fprintf(stderr,
505 "WARNING Unknown baud rate %d for %s (B9600 used)\n",
506 ctx_rtu->baud, ctx_rtu->device);
510 /* Set the baud rate */
511 if ((cfsetispeed(&tios, speed) < 0) ||
512 (cfsetospeed(&tios, speed) < 0)) {
513 return -1;
516 /* C_CFLAG Control options
517 CLOCAL Local line - do not change "owner" of port
518 CREAD Enable receiver
520 tios.c_cflag |= (CREAD | CLOCAL);
521 /* CSIZE, HUPCL, CRTSCTS (hardware flow control) */
523 /* Set data bits (5, 6, 7, 8 bits)
524 CSIZE Bit mask for data bits
526 tios.c_cflag &= ~CSIZE;
527 switch (ctx_rtu->data_bit) {
528 case 5:
529 tios.c_cflag |= CS5;
530 break;
531 case 6:
532 tios.c_cflag |= CS6;
533 break;
534 case 7:
535 tios.c_cflag |= CS7;
536 break;
537 case 8:
538 default:
539 tios.c_cflag |= CS8;
540 break;
543 /* Stop bit (1 or 2) */
544 if (ctx_rtu->stop_bit == 1)
545 tios.c_cflag &=~ CSTOPB;
546 else /* 2 */
547 tios.c_cflag |= CSTOPB;
549 /* PARENB Enable parity bit
550 PARODD Use odd parity instead of even */
551 if (ctx_rtu->parity == 'N') {
552 /* None */
553 tios.c_cflag &=~ PARENB;
554 } else if (ctx_rtu->parity == 'E') {
555 /* Even */
556 tios.c_cflag |= PARENB;
557 tios.c_cflag &=~ PARODD;
558 } else {
559 /* Odd */
560 tios.c_cflag |= PARENB;
561 tios.c_cflag |= PARODD;
564 /* Read the man page of termios if you need more information. */
566 /* This field isn't used on POSIX systems
567 tios.c_line = 0;
570 /* C_LFLAG Line options
572 ISIG Enable SIGINTR, SIGSUSP, SIGDSUSP, and SIGQUIT signals
573 ICANON Enable canonical input (else raw)
574 XCASE Map uppercase \lowercase (obsolete)
575 ECHO Enable echoing of input characters
576 ECHOE Echo erase character as BS-SP-BS
577 ECHOK Echo NL after kill character
578 ECHONL Echo NL
579 NOFLSH Disable flushing of input buffers after
580 interrupt or quit characters
581 IEXTEN Enable extended functions
582 ECHOCTL Echo control characters as ^char and delete as ~?
583 ECHOPRT Echo erased character as character erased
584 ECHOKE BS-SP-BS entire line on line kill
585 FLUSHO Output being flushed
586 PENDIN Retype pending input at next read or input char
587 TOSTOP Send SIGTTOU for background output
589 Canonical input is line-oriented. Input characters are put
590 into a buffer which can be edited interactively by the user
591 until a CR (carriage return) or LF (line feed) character is
592 received.
594 Raw input is unprocessed. Input characters are passed
595 through exactly as they are received, when they are
596 received. Generally you'll deselect the ICANON, ECHO,
597 ECHOE, and ISIG options when using raw input
600 /* Raw input */
601 tios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
603 /* C_IFLAG Input options
605 Constant Description
606 INPCK Enable parity check
607 IGNPAR Ignore parity errors
608 PARMRK Mark parity errors
609 ISTRIP Strip parity bits
610 IXON Enable software flow control (outgoing)
611 IXOFF Enable software flow control (incoming)
612 IXANY Allow any character to start flow again
613 IGNBRK Ignore break condition
614 BRKINT Send a SIGINT when a break condition is detected
615 INLCR Map NL to CR
616 IGNCR Ignore CR
617 ICRNL Map CR to NL
618 IUCLC Map uppercase to lowercase
619 IMAXBEL Echo BEL on input line too long
621 if (ctx_rtu->parity == 'N') {
622 /* None */
623 tios.c_iflag &= ~INPCK;
624 } else {
625 tios.c_iflag |= INPCK;
628 /* Software flow control is disabled */
629 tios.c_iflag &= ~(IXON | IXOFF | IXANY);
631 /* C_OFLAG Output options
632 OPOST Postprocess output (not set = raw output)
633 ONLCR Map NL to CR-NL
635 ONCLR ant others needs OPOST to be enabled
638 /* Raw ouput */
639 tios.c_oflag &=~ OPOST;
641 /* C_CC Control characters
642 VMIN Minimum number of characters to read
643 VTIME Time to wait for data (tenths of seconds)
645 UNIX serial interface drivers provide the ability to
646 specify character and packet timeouts. Two elements of the
647 c_cc array are used for timeouts: VMIN and VTIME. Timeouts
648 are ignored in canonical input mode or when the NDELAY
649 option is set on the file via open or fcntl.
651 VMIN specifies the minimum number of characters to read. If
652 it is set to 0, then the VTIME value specifies the time to
653 wait for every character read. Note that this does not mean
654 that a read call for N bytes will wait for N characters to
655 come in. Rather, the timeout will apply to the first
656 character and the read call will return the number of
657 characters immediately available (up to the number you
658 request).
660 If VMIN is non-zero, VTIME specifies the time to wait for
661 the first character read. If a character is read within the
662 time given, any read will block (wait) until all VMIN
663 characters are read. That is, once the first character is
664 read, the serial interface driver expects to receive an
665 entire packet of characters (VMIN bytes total). If no
666 character is read within the time allowed, then the call to
667 read returns 0. This method allows you to tell the serial
668 driver you need exactly N bytes and any read call will
669 return 0 or N bytes. However, the timeout only applies to
670 the first character read, so if for some reason the driver
671 misses one character inside the N byte packet then the read
672 call could block forever waiting for additional input
673 characters.
675 VTIME specifies the amount of time to wait for incoming
676 characters in tenths of seconds. If VTIME is set to 0 (the
677 default), reads will block (wait) indefinitely unless the
678 NDELAY option is set on the port with open or fcntl.
680 /* Unused because we use open with the NDELAY option */
681 tios.c_cc[VMIN] = 0;
682 tios.c_cc[VTIME] = 0;
684 if (tcsetattr(ctx->s, TCSANOW, &tios) < 0) {
685 return -1;
687 #endif
689 return 0;
692 void _modbus_rtu_close(modbus_t *ctx)
694 /* Closes the file descriptor in RTU mode */
695 modbus_rtu_t *ctx_rtu = ctx->backend_data;
697 #if defined(_WIN32)
698 /* Revert settings */
699 if (!SetCommState(ctx_rtu->w_ser.fd, &ctx_rtu->old_dcb))
700 fprintf(stderr, "ERROR Couldn't revert to configuration (LastError %d)\n",
701 (int)GetLastError());
703 if (!CloseHandle(ctx_rtu->w_ser.fd))
704 fprintf(stderr, "ERROR Error while closing handle (LastError %d)\n",
705 (int)GetLastError());
706 #else
707 tcsetattr(ctx->s, TCSANOW, &(ctx_rtu->old_tios));
708 close(ctx->s);
709 #endif
712 int _modbus_rtu_flush(modbus_t *ctx)
714 #if defined(_WIN32)
715 modbus_rtu_t *ctx_rtu = ctx->backend_data;
716 ctx_rtu->w_ser.n_bytes = 0;
717 return (FlushFileBuffers(ctx_rtu->w_ser.fd) == FALSE);
718 #else
719 return tcflush(ctx->s, TCIOFLUSH);
720 #endif
723 int _modbus_rtu_select(modbus_t *ctx, fd_set *rfds,
724 struct timeval *tv, int length_to_read)
726 int s_rc;
727 #if defined(_WIN32)
728 s_rc = win32_ser_select(&(((modbus_rtu_t*)ctx->backend_data)->w_ser),
729 length_to_read, tv);
730 if (s_rc == 0) {
731 errno = ETIMEDOUT;
732 return -1;
735 if (s_rc < 0) {
736 _error_print(ctx, "select");
737 if (ctx->error_recovery && (errno == EBADF)) {
738 modbus_close(ctx);
739 modbus_connect(ctx);
740 errno = EBADF;
741 return -1;
742 } else {
743 return -1;
746 #else
747 while ((s_rc = select(ctx->s+1, rfds, NULL, NULL, tv)) == -1) {
748 if (errno == EINTR) {
749 if (ctx->debug) {
750 fprintf(stderr, "A non blocked signal was caught\n");
752 /* Necessary after an error */
753 FD_ZERO(rfds);
754 FD_SET(ctx->s, rfds);
755 } else {
756 _error_print(ctx, "select");
757 if (ctx->error_recovery && (errno == EBADF)) {
758 modbus_close(ctx);
759 modbus_connect(ctx);
760 errno = EBADF;
761 return -1;
762 } else {
763 return -1;
768 if (s_rc == 0) {
769 /* Timeout */
770 errno = ETIMEDOUT;
771 _error_print(ctx, "select");
772 return -1;
774 #endif
776 return s_rc;
779 int _modbus_rtu_filter_request(modbus_t *ctx, int slave)
781 /* Filter on the Modbus unit identifier (slave) in RTU mode */
782 if (slave != ctx->slave && slave != MODBUS_BROADCAST_ADDRESS) {
783 /* Ignores the request (not for me) */
784 if (ctx->debug) {
785 printf("Request for slave %d ignored (not %d)\n",
786 slave, ctx->slave);
788 return 1;
789 } else {
790 return 0;
794 const modbus_backend_t _modbus_rtu_backend = {
795 _MODBUS_BACKEND_TYPE_RTU,
796 _MODBUS_RTU_HEADER_LENGTH,
797 _MODBUS_RTU_CHECKSUM_LENGTH,
798 MODBUS_RTU_MAX_ADU_LENGTH,
799 _modbus_set_slave,
800 _modbus_rtu_build_request_basis,
801 _modbus_rtu_build_response_basis,
802 _modbus_rtu_prepare_response_tid,
803 _modbus_rtu_send_msg_pre,
804 _modbus_rtu_send,
805 _modbus_rtu_recv,
806 _modbus_rtu_check_integrity,
807 _modbus_rtu_connect,
808 _modbus_rtu_close,
809 _modbus_rtu_flush,
810 _modbus_rtu_select,
811 _modbus_rtu_filter_request
814 modbus_t* modbus_new_rtu(const char *device,
815 int baud, char parity, int data_bit,
816 int stop_bit)
818 modbus_t *ctx;
819 modbus_rtu_t *ctx_rtu;
820 size_t dest_size;
821 size_t ret_size;
823 ctx = (modbus_t *) malloc(sizeof(modbus_t));
824 _modbus_init_common(ctx);
826 ctx->backend = &_modbus_rtu_backend;
827 ctx->backend_data = (modbus_rtu_t *) malloc(sizeof(modbus_rtu_t));
828 ctx_rtu = (modbus_rtu_t *)ctx->backend_data;
830 dest_size = sizeof(ctx_rtu->device);
831 ret_size = strlcpy(ctx_rtu->device, device, dest_size);
832 if (ret_size == 0) {
833 fprintf(stderr, "The device string is empty\n");
834 modbus_free(ctx);
835 errno = EINVAL;
836 return NULL;
839 if (ret_size >= dest_size) {
840 fprintf(stderr, "The device string has been truncated\n");
841 modbus_free(ctx);
842 errno = EINVAL;
843 return NULL;
846 ctx_rtu->baud = baud;
847 if (parity == 'N' || parity == 'E' || parity == 'O') {
848 ctx_rtu->parity = parity;
849 } else {
850 modbus_free(ctx);
851 errno = EINVAL;
852 return NULL;
854 ctx_rtu->data_bit = data_bit;
855 ctx_rtu->stop_bit = stop_bit;
857 return ctx;