Prepare NEWS file for next release
[libmodbus.git] / src / modbus-rtu.c
blob8b5ee08acaf538712f184b3dd9ee04b0b1f75447
1 /*
2 * Copyright © Stéphane Raimbault <stephane.raimbault@gmail.com>
4 * SPDX-License-Identifier: LGPL-2.1-or-later
5 */
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #ifndef _MSC_VER
13 #include <unistd.h>
14 #endif
15 #include "modbus-private.h"
16 #include <assert.h>
18 #include "modbus-rtu-private.h"
19 #include "modbus-rtu.h"
21 #if HAVE_DECL_TIOCSRS485 || HAVE_DECL_TIOCM_RTS
22 #include <sys/ioctl.h>
23 #endif
25 #if HAVE_DECL_TIOCSRS485
26 #include <linux/serial.h>
27 #endif
29 /* Table of CRC values for high-order byte */
30 static const uint8_t table_crc_hi[] = {
31 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
32 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
33 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1,
34 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
35 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
36 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
37 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1,
38 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
39 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
40 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
41 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
42 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
43 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
44 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
45 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
46 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
47 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
48 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
49 0x00, 0xC1, 0x81, 0x40};
51 /* Table of CRC values for low-order byte */
52 static const uint8_t table_crc_lo[] = {
53 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5,
54 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B,
55 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE,
56 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6,
57 0xD2, 0x12, 0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
58 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D,
59 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8,
60 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C,
61 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21,
62 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
63 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A,
64 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
65 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5, 0x77, 0xB7,
66 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51,
67 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
68 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98,
69 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D,
70 0x4C, 0x8C, 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83,
71 0x41, 0x81, 0x80, 0x40};
73 /* Define the slave ID of the remote device to talk in master mode or set the
74 * internal slave ID in slave mode */
75 static int _modbus_set_slave(modbus_t *ctx, int slave)
77 int max_slave = (ctx->quirks & MODBUS_QUIRK_MAX_SLAVE) ? 255 : 247;
79 /* Broadcast address is 0 (MODBUS_BROADCAST_ADDRESS) */
80 if (slave >= 0 && slave <= max_slave) {
81 ctx->slave = slave;
82 } else {
83 errno = EINVAL;
84 return -1;
87 return 0;
90 /* Builds a RTU request header */
91 static int _modbus_rtu_build_request_basis(
92 modbus_t *ctx, int function, int addr, int nb, uint8_t *req)
94 assert(ctx->slave != -1);
95 req[0] = ctx->slave;
96 req[1] = function;
97 req[2] = addr >> 8;
98 req[3] = addr & 0x00ff;
99 req[4] = nb >> 8;
100 req[5] = nb & 0x00ff;
102 return _MODBUS_RTU_PRESET_REQ_LENGTH;
105 /* Builds a RTU response header */
106 static int _modbus_rtu_build_response_basis(sft_t *sft, uint8_t *rsp)
108 /* In this case, the slave is certainly valid because a check is already
109 * done in _modbus_rtu_listen */
110 rsp[0] = sft->slave;
111 rsp[1] = sft->function;
113 return _MODBUS_RTU_PRESET_RSP_LENGTH;
116 static uint16_t crc16(uint8_t *buffer, uint16_t buffer_length)
118 uint8_t crc_hi = 0xFF; /* high CRC byte initialized */
119 uint8_t crc_lo = 0xFF; /* low CRC byte initialized */
120 unsigned int i; /* will index into CRC lookup */
122 /* pass through message buffer */
123 while (buffer_length--) {
124 i = crc_lo ^ *buffer++; /* calculate the CRC */
125 crc_lo = crc_hi ^ table_crc_hi[i];
126 crc_hi = table_crc_lo[i];
129 return (crc_hi << 8 | crc_lo);
132 static int _modbus_rtu_get_response_tid(const uint8_t *req)
134 /* No TID */
135 return 0;
138 static int _modbus_rtu_send_msg_pre(uint8_t *req, int req_length)
140 uint16_t crc = crc16(req, req_length);
142 /* According to the MODBUS specs (p. 14), the low order byte of the CRC comes
143 * first in the RTU message */
144 req[req_length++] = crc & 0x00FF;
145 req[req_length++] = crc >> 8;
147 return req_length;
150 #if defined(_WIN32)
152 /* This simple implementation is sort of a substitute of the select() call,
153 * working this way: the win32_ser_select() call tries to read some data from
154 * the serial port, setting the timeout as the select() call would. Data read is
155 * stored into the receive buffer, that is then consumed by the win32_ser_read()
156 * call. So win32_ser_select() does both the event waiting and the reading,
157 * while win32_ser_read() only consumes the receive buffer.
160 static void win32_ser_init(struct win32_ser *ws)
162 /* Clear everything */
163 memset(ws, 0x00, sizeof(struct win32_ser));
165 /* Set file handle to invalid */
166 ws->fd = INVALID_HANDLE_VALUE;
169 /* FIXME Try to remove length_to_read -> max_len argument, only used by win32 */
170 static int win32_ser_select(struct win32_ser *ws, int max_len, const struct timeval *tv)
172 COMMTIMEOUTS comm_to;
173 unsigned int msec = 0;
175 /* Check if some data still in the buffer to be consumed */
176 if (ws->n_bytes > 0) {
177 return 1;
180 /* Setup timeouts like select() would do.
181 FIXME Please someone on Windows can look at this?
182 Does it possible to use WaitCommEvent?
183 When tv is NULL, MAXDWORD isn't infinite!
185 if (tv == NULL) {
186 msec = MAXDWORD;
187 } else {
188 msec = tv->tv_sec * 1000 + tv->tv_usec / 1000;
189 if (msec < 1)
190 msec = 1;
193 comm_to.ReadIntervalTimeout = msec;
194 comm_to.ReadTotalTimeoutMultiplier = 0;
195 comm_to.ReadTotalTimeoutConstant = msec;
196 comm_to.WriteTotalTimeoutMultiplier = 0;
197 comm_to.WriteTotalTimeoutConstant = 1000;
198 SetCommTimeouts(ws->fd, &comm_to);
200 /* Read some bytes */
201 if ((max_len > PY_BUF_SIZE) || (max_len < 0)) {
202 max_len = PY_BUF_SIZE;
205 if (ReadFile(ws->fd, &ws->buf, max_len, &ws->n_bytes, NULL)) {
206 /* Check if some bytes available */
207 if (ws->n_bytes > 0) {
208 /* Some bytes read */
209 return 1;
210 } else {
211 /* Just timed out */
212 return 0;
214 } else {
215 /* Some kind of error */
216 return -1;
220 static int win32_ser_read(struct win32_ser *ws, uint8_t *p_msg, unsigned int max_len)
222 unsigned int n = ws->n_bytes;
224 if (max_len < n) {
225 n = max_len;
228 if (n > 0) {
229 memcpy(p_msg, ws->buf, n);
232 ws->n_bytes -= n;
234 return n;
236 #endif
238 #if HAVE_DECL_TIOCM_RTS
239 static void _modbus_rtu_ioctl_rts(modbus_t *ctx, int on)
241 int fd = ctx->s;
242 int flags;
244 ioctl(fd, TIOCMGET, &flags);
245 if (on) {
246 flags |= TIOCM_RTS;
247 } else {
248 flags &= ~TIOCM_RTS;
250 ioctl(fd, TIOCMSET, &flags);
252 #endif
254 static ssize_t _modbus_rtu_send(modbus_t *ctx, const uint8_t *req, int req_length)
256 #if defined(_WIN32)
257 modbus_rtu_t *ctx_rtu = ctx->backend_data;
258 DWORD n_bytes = 0;
259 return (WriteFile(ctx_rtu->w_ser.fd, req, req_length, &n_bytes, NULL))
260 ? (ssize_t) n_bytes
261 : -1;
262 #else
263 #if HAVE_DECL_TIOCM_RTS
264 modbus_rtu_t *ctx_rtu = ctx->backend_data;
265 if (ctx_rtu->rts != MODBUS_RTU_RTS_NONE) {
266 ssize_t size;
268 if (ctx->debug) {
269 fprintf(stderr, "Sending request using RTS signal\n");
272 ctx_rtu->set_rts(ctx, ctx_rtu->rts == MODBUS_RTU_RTS_UP);
273 usleep(ctx_rtu->rts_delay);
275 size = write(ctx->s, req, req_length);
277 usleep(ctx_rtu->onebyte_time * req_length + ctx_rtu->rts_delay);
278 ctx_rtu->set_rts(ctx, ctx_rtu->rts != MODBUS_RTU_RTS_UP);
280 return size;
281 } else {
282 #endif
283 return write(ctx->s, req, req_length);
284 #if HAVE_DECL_TIOCM_RTS
286 #endif
287 #endif
290 static int _modbus_rtu_receive(modbus_t *ctx, uint8_t *req)
292 int rc;
293 modbus_rtu_t *ctx_rtu = ctx->backend_data;
295 if (ctx_rtu->confirmation_to_ignore) {
296 _modbus_receive_msg(ctx, req, MSG_CONFIRMATION);
297 /* Ignore errors and reset the flag */
298 ctx_rtu->confirmation_to_ignore = FALSE;
299 rc = 0;
300 if (ctx->debug) {
301 printf("Confirmation to ignore\n");
303 } else {
304 rc = _modbus_receive_msg(ctx, req, MSG_INDICATION);
305 if (rc == 0) {
306 /* The next expected message is a confirmation to ignore */
307 ctx_rtu->confirmation_to_ignore = TRUE;
310 return rc;
313 static ssize_t _modbus_rtu_recv(modbus_t *ctx, uint8_t *rsp, int rsp_length)
315 #if defined(_WIN32)
316 return win32_ser_read(&((modbus_rtu_t *) ctx->backend_data)->w_ser, rsp, rsp_length);
317 #else
318 return read(ctx->s, rsp, rsp_length);
319 #endif
322 static int _modbus_rtu_flush(modbus_t *);
324 static int _modbus_rtu_pre_check_confirmation(modbus_t *ctx,
325 const uint8_t *req,
326 const uint8_t *rsp,
327 int rsp_length)
329 /* Check responding slave is the slave we requested (except for broacast
330 * request) */
331 if (req[0] != rsp[0] && req[0] != MODBUS_BROADCAST_ADDRESS) {
332 if (ctx->debug) {
333 fprintf(stderr,
334 "The responding slave %d isn't the requested slave %d\n",
335 rsp[0],
336 req[0]);
338 errno = EMBBADSLAVE;
339 return -1;
340 } else {
341 return 0;
345 /* The check_crc16 function shall return 0 if the message is ignored and the
346 message length if the CRC is valid. Otherwise it shall return -1 and set
347 errno to EMBBADCRC. */
348 static int _modbus_rtu_check_integrity(modbus_t *ctx, uint8_t *msg, const int msg_length)
350 uint16_t crc_calculated;
351 uint16_t crc_received;
352 int slave = msg[0];
354 /* Filter on the Modbus unit identifier (slave) in RTU mode to avoid useless
355 * CRC computing. */
356 if (slave != ctx->slave && slave != MODBUS_BROADCAST_ADDRESS) {
357 if (ctx->debug) {
358 printf("Request for slave %d ignored (not %d)\n", slave, ctx->slave);
360 /* Following call to check_confirmation handles this error */
361 return 0;
364 crc_calculated = crc16(msg, msg_length - 2);
365 crc_received = (msg[msg_length - 1] << 8) | msg[msg_length - 2];
367 /* Check CRC of msg */
368 if (crc_calculated == crc_received) {
369 return msg_length;
370 } else {
371 if (ctx->debug) {
372 fprintf(stderr,
373 "ERROR CRC received 0x%0X != CRC calculated 0x%0X\n",
374 crc_received,
375 crc_calculated);
378 if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_PROTOCOL) {
379 _modbus_rtu_flush(ctx);
381 errno = EMBBADCRC;
382 return -1;
386 /* Sets up a serial port for RTU communications */
387 #if defined(_WIN32)
388 static int _modbus_rtu_connect(modbus_t *ctx)
390 DCB dcb;
391 modbus_rtu_t *ctx_rtu = ctx->backend_data;
393 if (ctx->debug) {
394 printf("Opening %s at %d bauds (%c, %d, %d)\n",
395 ctx_rtu->device,
396 ctx_rtu->baud,
397 ctx_rtu->parity,
398 ctx_rtu->data_bit,
399 ctx_rtu->stop_bit);
402 /* Some references here:
403 * http://msdn.microsoft.com/en-us/library/aa450602.aspx
405 win32_ser_init(&ctx_rtu->w_ser);
407 /* ctx_rtu->device should contain a string like "COMxx:" xx being a decimal
408 * number */
409 ctx_rtu->w_ser.fd = CreateFileA(
410 ctx_rtu->device, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
412 /* Error checking */
413 if (ctx_rtu->w_ser.fd == INVALID_HANDLE_VALUE) {
414 if (ctx->debug) {
415 fprintf(stderr,
416 "ERROR Can't open the device %s (LastError %d)\n",
417 ctx_rtu->device,
418 (int) GetLastError());
420 return -1;
423 /* Save params */
424 ctx_rtu->old_dcb.DCBlength = sizeof(DCB);
425 if (!GetCommState(ctx_rtu->w_ser.fd, &ctx_rtu->old_dcb)) {
426 if (ctx->debug) {
427 fprintf(stderr,
428 "ERROR Error getting configuration (LastError %d)\n",
429 (int) GetLastError());
431 CloseHandle(ctx_rtu->w_ser.fd);
432 ctx_rtu->w_ser.fd = INVALID_HANDLE_VALUE;
433 return -1;
436 /* Build new configuration (starting from current settings) */
437 dcb = ctx_rtu->old_dcb;
439 /* Speed setting */
440 dcb.BaudRate = ctx_rtu->baud;
442 /* Data bits */
443 switch (ctx_rtu->data_bit) {
444 case 5:
445 dcb.ByteSize = 5;
446 break;
447 case 6:
448 dcb.ByteSize = 6;
449 break;
450 case 7:
451 dcb.ByteSize = 7;
452 break;
453 case 8:
454 default:
455 dcb.ByteSize = 8;
456 break;
459 /* Stop bits */
460 if (ctx_rtu->stop_bit == 1)
461 dcb.StopBits = ONESTOPBIT;
462 else /* 2 */
463 dcb.StopBits = TWOSTOPBITS;
465 /* Parity */
466 if (ctx_rtu->parity == 'N') {
467 dcb.Parity = NOPARITY;
468 dcb.fParity = FALSE;
469 } else if (ctx_rtu->parity == 'E') {
470 dcb.Parity = EVENPARITY;
471 dcb.fParity = TRUE;
472 } else {
473 /* odd */
474 dcb.Parity = ODDPARITY;
475 dcb.fParity = TRUE;
478 /* Hardware handshaking left as default settings retrieved */
480 /* No software handshaking */
481 dcb.fTXContinueOnXoff = TRUE;
482 dcb.fOutX = FALSE;
483 dcb.fInX = FALSE;
485 /* Binary mode (it's the only supported on Windows anyway) */
486 dcb.fBinary = TRUE;
488 /* Don't want errors to be blocking */
489 dcb.fAbortOnError = FALSE;
491 /* Setup port */
492 if (!SetCommState(ctx_rtu->w_ser.fd, &dcb)) {
493 if (ctx->debug) {
494 fprintf(stderr,
495 "ERROR Error setting new configuration (LastError %d)\n",
496 (int) GetLastError());
498 CloseHandle(ctx_rtu->w_ser.fd);
499 ctx_rtu->w_ser.fd = INVALID_HANDLE_VALUE;
500 return -1;
503 return 0;
505 #else
507 static speed_t _get_termios_speed(int baud, int debug)
509 speed_t speed;
511 switch (baud) {
512 case 110:
513 speed = B110;
514 break;
515 case 300:
516 speed = B300;
517 break;
518 case 600:
519 speed = B600;
520 break;
521 case 1200:
522 speed = B1200;
523 break;
524 case 2400:
525 speed = B2400;
526 break;
527 case 4800:
528 speed = B4800;
529 break;
530 case 9600:
531 speed = B9600;
532 break;
533 case 19200:
534 speed = B19200;
535 break;
536 case 38400:
537 speed = B38400;
538 break;
539 #ifdef B57600
540 case 57600:
541 speed = B57600;
542 break;
543 #endif
544 #ifdef B115200
545 case 115200:
546 speed = B115200;
547 break;
548 #endif
549 #ifdef B230400
550 case 230400:
551 speed = B230400;
552 break;
553 #endif
554 #ifdef B460800
555 case 460800:
556 speed = B460800;
557 break;
558 #endif
559 #ifdef B500000
560 case 500000:
561 speed = B500000;
562 break;
563 #endif
564 #ifdef B576000
565 case 576000:
566 speed = B576000;
567 break;
568 #endif
569 #ifdef B921600
570 case 921600:
571 speed = B921600;
572 break;
573 #endif
574 #ifdef B1000000
575 case 1000000:
576 speed = B1000000;
577 break;
578 #endif
579 #ifdef B1152000
580 case 1152000:
581 speed = B1152000;
582 break;
583 #endif
584 #ifdef B1500000
585 case 1500000:
586 speed = B1500000;
587 break;
588 #endif
589 #ifdef B2500000
590 case 2500000:
591 speed = B2500000;
592 break;
593 #endif
594 #ifdef B3000000
595 case 3000000:
596 speed = B3000000;
597 break;
598 #endif
599 #ifdef B3500000
600 case 3500000:
601 speed = B3500000;
602 break;
603 #endif
604 #ifdef B4000000
605 case 4000000:
606 speed = B4000000;
607 break;
608 #endif
609 default:
610 speed = B9600;
611 if (debug) {
612 fprintf(stderr, "WARNING Unknown baud rate %d (B9600 used)\n", baud);
616 return speed;
619 /* POSIX */
620 static int _modbus_rtu_connect(modbus_t *ctx)
622 struct termios tios;
623 int flags;
624 speed_t speed;
625 modbus_rtu_t *ctx_rtu = ctx->backend_data;
627 if (ctx->debug) {
628 printf("Opening %s at %d bauds (%c, %d, %d)\n",
629 ctx_rtu->device,
630 ctx_rtu->baud,
631 ctx_rtu->parity,
632 ctx_rtu->data_bit,
633 ctx_rtu->stop_bit);
636 /* The O_NOCTTY flag tells UNIX that this program doesn't want
637 to be the "controlling terminal" for that port. If you
638 don't specify this then any input (such as keyboard abort
639 signals and so forth) will affect your process
641 Timeouts are ignored in canonical input mode or when the
642 NDELAY option is set on the file via open or fcntl */
643 flags = O_RDWR | O_NOCTTY | O_NDELAY | O_EXCL;
644 #ifdef O_CLOEXEC
645 flags |= O_CLOEXEC;
646 #endif
648 ctx->s = open(ctx_rtu->device, flags);
649 if (ctx->s < 0) {
650 if (ctx->debug) {
651 fprintf(stderr,
652 "ERROR Can't open the device %s (%s)\n",
653 ctx_rtu->device,
654 strerror(errno));
656 return -1;
659 /* Save */
660 tcgetattr(ctx->s, &ctx_rtu->old_tios);
662 memset(&tios, 0, sizeof(struct termios));
664 /* C_ISPEED Input baud (new interface)
665 C_OSPEED Output baud (new interface)
668 /* Set the baud rate */
671 On MacOS, constants of baud rates are equal to the integer in argument but
672 that's not the case under Linux so we have to find the corresponding
673 constant. Until the code is upgraded to termios2, the list of possible
674 values is limited (no 14400 for example).
676 if (9600 == B9600) {
677 speed = ctx_rtu->baud;
678 } else {
679 speed = _get_termios_speed(ctx_rtu->baud, ctx->debug);
682 if ((cfsetispeed(&tios, speed) < 0) || (cfsetospeed(&tios, speed) < 0)) {
683 close(ctx->s);
684 ctx->s = -1;
685 return -1;
688 /* C_CFLAG Control options
689 CLOCAL Local line - do not change "owner" of port
690 CREAD Enable receiver
692 tios.c_cflag |= (CREAD | CLOCAL);
693 /* CSIZE, HUPCL, CRTSCTS (hardware flow control) */
695 /* Set data bits (5, 6, 7, 8 bits)
696 CSIZE Bit mask for data bits
698 tios.c_cflag &= ~CSIZE;
699 switch (ctx_rtu->data_bit) {
700 case 5:
701 tios.c_cflag |= CS5;
702 break;
703 case 6:
704 tios.c_cflag |= CS6;
705 break;
706 case 7:
707 tios.c_cflag |= CS7;
708 break;
709 case 8:
710 default:
711 tios.c_cflag |= CS8;
712 break;
715 /* Stop bit (1 or 2) */
716 if (ctx_rtu->stop_bit == 1)
717 tios.c_cflag &= ~CSTOPB;
718 else /* 2 */
719 tios.c_cflag |= CSTOPB;
721 /* PARENB Enable parity bit
722 PARODD Use odd parity instead of even */
723 if (ctx_rtu->parity == 'N') {
724 /* None */
725 tios.c_cflag &= ~PARENB;
726 } else if (ctx_rtu->parity == 'E') {
727 /* Even */
728 tios.c_cflag |= PARENB;
729 tios.c_cflag &= ~PARODD;
730 } else {
731 /* Odd */
732 tios.c_cflag |= PARENB;
733 tios.c_cflag |= PARODD;
736 /* Read the man page of termios if you need more information. */
738 /* This field isn't used on POSIX systems
739 tios.c_line = 0;
742 /* C_LFLAG Line options
744 ISIG Enable SIGINTR, SIGSUSP, SIGDSUSP, and SIGQUIT signals
745 ICANON Enable canonical input (else raw)
746 XCASE Map uppercase \lowercase (obsolete)
747 ECHO Enable echoing of input characters
748 ECHOE Echo erase character as BS-SP-BS
749 ECHOK Echo NL after kill character
750 ECHONL Echo NL
751 NOFLSH Disable flushing of input buffers after
752 interrupt or quit characters
753 IEXTEN Enable extended functions
754 ECHOCTL Echo control characters as ^char and delete as ~?
755 ECHOPRT Echo erased character as character erased
756 ECHOKE BS-SP-BS entire line on line kill
757 FLUSHO Output being flushed
758 PENDIN Retype pending input at next read or input char
759 TOSTOP Send SIGTTOU for background output
761 Canonical input is line-oriented. Input characters are put
762 into a buffer which can be edited interactively by the user
763 until a CR (carriage return) or LF (line feed) character is
764 received.
766 Raw input is unprocessed. Input characters are passed
767 through exactly as they are received, when they are
768 received. Generally you'll deselect the ICANON, ECHO,
769 ECHOE, and ISIG options when using raw input
772 /* Raw input */
773 tios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
775 /* C_IFLAG Input options
777 Constant Description
778 INPCK Enable parity check
779 IGNPAR Ignore parity errors
780 PARMRK Mark parity errors
781 ISTRIP Strip parity bits
782 IXON Enable software flow control (outgoing)
783 IXOFF Enable software flow control (incoming)
784 IXANY Allow any character to start flow again
785 IGNBRK Ignore break condition
786 BRKINT Send a SIGINT when a break condition is detected
787 INLCR Map NL to CR
788 IGNCR Ignore CR
789 ICRNL Map CR to NL
790 IUCLC Map uppercase to lowercase
791 IMAXBEL Echo BEL on input line too long
793 if (ctx_rtu->parity == 'N') {
794 /* None */
795 tios.c_iflag &= ~INPCK;
796 } else {
797 tios.c_iflag |= INPCK;
800 /* Software flow control is disabled */
801 tios.c_iflag &= ~(IXON | IXOFF | IXANY);
803 /* C_OFLAG Output options
804 OPOST Postprocess output (not set = raw output)
805 ONLCR Map NL to CR-NL
807 ONCLR ant others needs OPOST to be enabled
810 /* Raw output */
811 tios.c_oflag &= ~OPOST;
813 /* C_CC Control characters
814 VMIN Minimum number of characters to read
815 VTIME Time to wait for data (tenths of seconds)
817 UNIX serial interface drivers provide the ability to
818 specify character and packet timeouts. Two elements of the
819 c_cc array are used for timeouts: VMIN and VTIME. Timeouts
820 are ignored in canonical input mode or when the NDELAY
821 option is set on the file via open or fcntl.
823 VMIN specifies the minimum number of characters to read. If
824 it is set to 0, then the VTIME value specifies the time to
825 wait for every character read. Note that this does not mean
826 that a read call for N bytes will wait for N characters to
827 come in. Rather, the timeout will apply to the first
828 character and the read call will return the number of
829 characters immediately available (up to the number you
830 request).
832 If VMIN is non-zero, VTIME specifies the time to wait for
833 the first character read. If a character is read within the
834 time given, any read will block (wait) until all VMIN
835 characters are read. That is, once the first character is
836 read, the serial interface driver expects to receive an
837 entire packet of characters (VMIN bytes total). If no
838 character is read within the time allowed, then the call to
839 read returns 0. This method allows you to tell the serial
840 driver you need exactly N bytes and any read call will
841 return 0 or N bytes. However, the timeout only applies to
842 the first character read, so if for some reason the driver
843 misses one character inside the N byte packet then the read
844 call could block forever waiting for additional input
845 characters.
847 VTIME specifies the amount of time to wait for incoming
848 characters in tenths of seconds. If VTIME is set to 0 (the
849 default), reads will block (wait) indefinitely unless the
850 NDELAY option is set on the port with open or fcntl.
852 /* Unused because we use open with the NDELAY option */
853 tios.c_cc[VMIN] = 0;
854 tios.c_cc[VTIME] = 0;
856 if (tcsetattr(ctx->s, TCSANOW, &tios) < 0) {
857 close(ctx->s);
858 ctx->s = -1;
859 return -1;
862 return 0;
864 #endif
866 // FIXME Temporary solution before rewriting Windows RTU backend
867 static unsigned int _modbus_rtu_is_connected(modbus_t *ctx)
869 #if defined(_WIN32)
870 modbus_rtu_t *ctx_rtu = ctx->backend_data;
872 /* Check if file handle is valid */
873 return ctx_rtu->w_ser.fd != INVALID_HANDLE_VALUE;
874 #else
875 return ctx->s >= 0;
876 #endif
879 int modbus_rtu_set_serial_mode(modbus_t *ctx, int mode)
881 if (ctx == NULL) {
882 errno = EINVAL;
883 return -1;
886 if (ctx->backend->backend_type == _MODBUS_BACKEND_TYPE_RTU) {
887 #if HAVE_DECL_TIOCSRS485
888 modbus_rtu_t *ctx_rtu = ctx->backend_data;
889 struct serial_rs485 rs485conf;
891 if (mode == MODBUS_RTU_RS485) {
892 // Get
893 if (ioctl(ctx->s, TIOCGRS485, &rs485conf) < 0) {
894 return -1;
896 // Set
897 rs485conf.flags |= SER_RS485_ENABLED;
898 if (ioctl(ctx->s, TIOCSRS485, &rs485conf) < 0) {
899 return -1;
902 ctx_rtu->serial_mode = MODBUS_RTU_RS485;
903 return 0;
904 } else if (mode == MODBUS_RTU_RS232) {
905 /* Turn off RS485 mode only if required */
906 if (ctx_rtu->serial_mode == MODBUS_RTU_RS485) {
907 /* The ioctl call is avoided because it can fail on some RS232 ports */
908 if (ioctl(ctx->s, TIOCGRS485, &rs485conf) < 0) {
909 return -1;
911 rs485conf.flags &= ~SER_RS485_ENABLED;
912 if (ioctl(ctx->s, TIOCSRS485, &rs485conf) < 0) {
913 return -1;
916 ctx_rtu->serial_mode = MODBUS_RTU_RS232;
917 return 0;
919 #else
920 if (ctx->debug) {
921 fprintf(stderr, "This function isn't supported on your platform\n");
923 errno = ENOTSUP;
924 return -1;
925 #endif
928 /* Wrong backend and invalid mode specified */
929 errno = EINVAL;
930 return -1;
933 int modbus_rtu_get_serial_mode(modbus_t *ctx)
935 if (ctx == NULL) {
936 errno = EINVAL;
937 return -1;
940 if (ctx->backend->backend_type == _MODBUS_BACKEND_TYPE_RTU) {
941 #if HAVE_DECL_TIOCSRS485
942 modbus_rtu_t *ctx_rtu = ctx->backend_data;
943 return ctx_rtu->serial_mode;
944 #else
945 if (ctx->debug) {
946 fprintf(stderr, "This function isn't supported on your platform\n");
948 errno = ENOTSUP;
949 return -1;
950 #endif
951 } else {
952 errno = EINVAL;
953 return -1;
957 int modbus_rtu_get_rts(modbus_t *ctx)
959 if (ctx == NULL) {
960 errno = EINVAL;
961 return -1;
964 if (ctx->backend->backend_type == _MODBUS_BACKEND_TYPE_RTU) {
965 #if HAVE_DECL_TIOCM_RTS
966 modbus_rtu_t *ctx_rtu = ctx->backend_data;
967 return ctx_rtu->rts;
968 #else
969 if (ctx->debug) {
970 fprintf(stderr, "This function isn't supported on your platform\n");
972 errno = ENOTSUP;
973 return -1;
974 #endif
975 } else {
976 errno = EINVAL;
977 return -1;
981 int modbus_rtu_set_rts(modbus_t *ctx, int mode)
983 if (ctx == NULL) {
984 errno = EINVAL;
985 return -1;
988 if (ctx->backend->backend_type == _MODBUS_BACKEND_TYPE_RTU) {
989 #if HAVE_DECL_TIOCM_RTS
990 modbus_rtu_t *ctx_rtu = ctx->backend_data;
992 if (mode == MODBUS_RTU_RTS_NONE || mode == MODBUS_RTU_RTS_UP ||
993 mode == MODBUS_RTU_RTS_DOWN) {
994 ctx_rtu->rts = mode;
996 /* Set the RTS bit in order to not reserve the RS485 bus */
997 ctx_rtu->set_rts(ctx, ctx_rtu->rts != MODBUS_RTU_RTS_UP);
999 return 0;
1000 } else {
1001 errno = EINVAL;
1002 return -1;
1004 #else
1005 if (ctx->debug) {
1006 fprintf(stderr, "This function isn't supported on your platform\n");
1008 errno = ENOTSUP;
1009 return -1;
1010 #endif
1012 /* Wrong backend or invalid mode specified */
1013 errno = EINVAL;
1014 return -1;
1017 int modbus_rtu_set_custom_rts(modbus_t *ctx, void (*set_rts)(modbus_t *ctx, int on))
1019 if (ctx == NULL) {
1020 errno = EINVAL;
1021 return -1;
1024 if (ctx->backend->backend_type == _MODBUS_BACKEND_TYPE_RTU) {
1025 #if HAVE_DECL_TIOCM_RTS
1026 modbus_rtu_t *ctx_rtu = ctx->backend_data;
1027 ctx_rtu->set_rts = set_rts;
1028 return 0;
1029 #else
1030 if (ctx->debug) {
1031 fprintf(stderr, "This function isn't supported on your platform\n");
1033 errno = ENOTSUP;
1034 return -1;
1035 #endif
1036 } else {
1037 errno = EINVAL;
1038 return -1;
1042 int modbus_rtu_get_rts_delay(modbus_t *ctx)
1044 if (ctx == NULL) {
1045 errno = EINVAL;
1046 return -1;
1049 if (ctx->backend->backend_type == _MODBUS_BACKEND_TYPE_RTU) {
1050 #if HAVE_DECL_TIOCM_RTS
1051 modbus_rtu_t *ctx_rtu;
1052 ctx_rtu = (modbus_rtu_t *) ctx->backend_data;
1053 return ctx_rtu->rts_delay;
1054 #else
1055 if (ctx->debug) {
1056 fprintf(stderr, "This function isn't supported on your platform\n");
1058 errno = ENOTSUP;
1059 return -1;
1060 #endif
1061 } else {
1062 errno = EINVAL;
1063 return -1;
1067 int modbus_rtu_set_rts_delay(modbus_t *ctx, int us)
1069 if (ctx == NULL || us < 0) {
1070 errno = EINVAL;
1071 return -1;
1074 if (ctx->backend->backend_type == _MODBUS_BACKEND_TYPE_RTU) {
1075 #if HAVE_DECL_TIOCM_RTS
1076 modbus_rtu_t *ctx_rtu;
1077 ctx_rtu = (modbus_rtu_t *) ctx->backend_data;
1078 ctx_rtu->rts_delay = us;
1079 return 0;
1080 #else
1081 if (ctx->debug) {
1082 fprintf(stderr, "This function isn't supported on your platform\n");
1084 errno = ENOTSUP;
1085 return -1;
1086 #endif
1087 } else {
1088 errno = EINVAL;
1089 return -1;
1093 static void _modbus_rtu_close(modbus_t *ctx)
1095 /* Restore line settings and close file descriptor in RTU mode */
1096 modbus_rtu_t *ctx_rtu = ctx->backend_data;
1098 #if defined(_WIN32)
1099 /* Revert settings */
1100 if (!SetCommState(ctx_rtu->w_ser.fd, &ctx_rtu->old_dcb) && ctx->debug) {
1101 fprintf(stderr,
1102 "ERROR Couldn't revert to configuration (LastError %d)\n",
1103 (int) GetLastError());
1106 if (!CloseHandle(ctx_rtu->w_ser.fd) && ctx->debug) {
1107 fprintf(stderr,
1108 "ERROR Error while closing handle (LastError %d)\n",
1109 (int) GetLastError());
1111 #else
1112 if (ctx->s >= 0) {
1113 tcsetattr(ctx->s, TCSANOW, &ctx_rtu->old_tios);
1114 close(ctx->s);
1115 ctx->s = -1;
1117 #endif
1120 static int _modbus_rtu_flush(modbus_t *ctx)
1122 #if defined(_WIN32)
1123 modbus_rtu_t *ctx_rtu = ctx->backend_data;
1124 ctx_rtu->w_ser.n_bytes = 0;
1125 return (PurgeComm(ctx_rtu->w_ser.fd, PURGE_RXCLEAR) == FALSE);
1126 #else
1127 return tcflush(ctx->s, TCIOFLUSH);
1128 #endif
1131 static int
1132 _modbus_rtu_select(modbus_t *ctx, fd_set *rset, struct timeval *tv, int length_to_read)
1134 int s_rc;
1135 #if defined(_WIN32)
1136 s_rc = win32_ser_select(
1137 &((modbus_rtu_t *) ctx->backend_data)->w_ser, length_to_read, tv);
1138 if (s_rc == 0) {
1139 errno = ETIMEDOUT;
1140 return -1;
1143 if (s_rc < 0) {
1144 return -1;
1146 #else
1147 while ((s_rc = select(ctx->s + 1, rset, NULL, NULL, tv)) == -1) {
1148 if (errno == EINTR) {
1149 if (ctx->debug) {
1150 fprintf(stderr, "A non blocked signal was caught\n");
1152 /* Necessary after an error */
1153 FD_ZERO(rset);
1154 FD_SET(ctx->s, rset);
1155 } else {
1156 return -1;
1160 if (s_rc == 0) {
1161 /* Timeout */
1162 errno = ETIMEDOUT;
1163 return -1;
1165 #endif
1167 return s_rc;
1170 static void _modbus_rtu_free(modbus_t *ctx)
1172 if (ctx->backend_data) {
1173 free(((modbus_rtu_t *) ctx->backend_data)->device);
1174 free(ctx->backend_data);
1177 free(ctx);
1180 // clang-format off
1181 const modbus_backend_t _modbus_rtu_backend = {
1182 _MODBUS_BACKEND_TYPE_RTU,
1183 _MODBUS_RTU_HEADER_LENGTH,
1184 _MODBUS_RTU_CHECKSUM_LENGTH,
1185 MODBUS_RTU_MAX_ADU_LENGTH,
1186 _modbus_set_slave,
1187 _modbus_rtu_build_request_basis,
1188 _modbus_rtu_build_response_basis,
1189 _modbus_rtu_get_response_tid,
1190 _modbus_rtu_send_msg_pre,
1191 _modbus_rtu_send,
1192 _modbus_rtu_receive,
1193 _modbus_rtu_recv,
1194 _modbus_rtu_check_integrity,
1195 _modbus_rtu_pre_check_confirmation,
1196 _modbus_rtu_connect,
1197 _modbus_rtu_is_connected,
1198 _modbus_rtu_close,
1199 _modbus_rtu_flush,
1200 _modbus_rtu_select,
1201 _modbus_rtu_free
1204 // clang-format on
1206 modbus_t *
1207 modbus_new_rtu(const char *device, int baud, char parity, int data_bit, int stop_bit)
1209 modbus_t *ctx;
1210 modbus_rtu_t *ctx_rtu;
1212 /* Check device argument */
1213 if (device == NULL || *device == 0) {
1214 fprintf(stderr, "The device string is empty\n");
1215 errno = EINVAL;
1216 return NULL;
1219 /* Check baud argument */
1220 if (baud == 0) {
1221 fprintf(stderr, "The baud rate value must not be zero\n");
1222 errno = EINVAL;
1223 return NULL;
1226 ctx = (modbus_t *) malloc(sizeof(modbus_t));
1227 if (ctx == NULL) {
1228 return NULL;
1231 _modbus_init_common(ctx);
1232 ctx->backend = &_modbus_rtu_backend;
1233 ctx->backend_data = (modbus_rtu_t *) malloc(sizeof(modbus_rtu_t));
1234 if (ctx->backend_data == NULL) {
1235 modbus_free(ctx);
1236 errno = ENOMEM;
1237 return NULL;
1239 ctx_rtu = (modbus_rtu_t *) ctx->backend_data;
1241 /* Device name and \0 */
1242 ctx_rtu->device = (char *) malloc((strlen(device) + 1) * sizeof(char));
1243 if (ctx_rtu->device == NULL) {
1244 modbus_free(ctx);
1245 errno = ENOMEM;
1246 return NULL;
1249 #if defined(_WIN32)
1250 strcpy_s(ctx_rtu->device, strlen(device) + 1, device);
1251 #else
1252 strcpy(ctx_rtu->device, device);
1253 #endif
1255 ctx_rtu->baud = baud;
1256 if (parity == 'N' || parity == 'E' || parity == 'O') {
1257 ctx_rtu->parity = parity;
1258 } else {
1259 modbus_free(ctx);
1260 errno = EINVAL;
1261 return NULL;
1263 ctx_rtu->data_bit = data_bit;
1264 ctx_rtu->stop_bit = stop_bit;
1266 #if HAVE_DECL_TIOCSRS485
1267 /* The RS232 mode has been set by default */
1268 ctx_rtu->serial_mode = MODBUS_RTU_RS232;
1269 #endif
1271 #if HAVE_DECL_TIOCM_RTS
1272 /* The RTS use has been set by default */
1273 ctx_rtu->rts = MODBUS_RTU_RTS_NONE;
1275 /* Calculate estimated time in micro second to send one byte */
1276 ctx_rtu->onebyte_time =
1277 1000000 * (1 + data_bit + (parity == 'N' ? 0 : 1) + stop_bit) / baud;
1279 /* The internal function is used by default to set RTS */
1280 ctx_rtu->set_rts = _modbus_rtu_ioctl_rts;
1282 /* The delay before and after transmission when toggling the RTS pin */
1283 ctx_rtu->rts_delay = ctx_rtu->onebyte_time;
1284 #endif
1286 ctx_rtu->confirmation_to_ignore = FALSE;
1288 return ctx;