Commit 815d11f0568fdf7a9032051cbb84b24b8b7f4345

Authored by Stéphane Raimbault
1 parent dfff6b35

MAJOR Split RTU and TCP code in two backends

All private functions and constants are now prefixed by _.
The modbus protocol uses entry points to call specific functions.
src/Makefile.am
@@ -2,12 +2,20 @@ lib_LTLIBRARIES = libmodbus.la @@ -2,12 +2,20 @@ lib_LTLIBRARIES = libmodbus.la
2 libmodbus_la_SOURCES = \ 2 libmodbus_la_SOURCES = \
3 modbus.c \ 3 modbus.c \
4 modbus.h \ 4 modbus.h \
  5 + modbus-data.c \
  6 + modbus-private.h \
  7 + modbus-rtu.c \
  8 + modbus-rtu.h \
  9 + modbus-rtu-private.h \
  10 + modbus-tcp.c \
  11 + modbus-tcp.h \
  12 + modbus-tcp-private.h \
5 modbus-version.h 13 modbus-version.h
6 libmodbus_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(LIBMODBUS_LT_VERSION_INFO) 14 libmodbus_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(LIBMODBUS_LT_VERSION_INFO)
7 15
8 # Header files to install 16 # Header files to install
9 libmodbusincludedir = $(includedir)/modbus 17 libmodbusincludedir = $(includedir)/modbus
10 -libmodbusinclude_HEADERS = modbus.h modbus-version.h 18 +libmodbusinclude_HEADERS = modbus.h modbus-version.h modbus-rtu.h modbus-tcp.h
11 19
12 DISTCLEANFILES = modbus-version.h 20 DISTCLEANFILES = modbus-version.h
13 EXTRA_DIST = modbus-version.h.in 21 EXTRA_DIST = modbus-version.h.in
src/modbus-data.c 0 → 100644
  1 +/*
  2 + * Copyright © 2010 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 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.
  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 Lesser Public License for more details.
  13 + *
  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/>.
  16 + */
  17 +
  18 +#include <stdlib.h>
  19 +#include <stdint.h>
  20 +#include <string.h>
  21 +#include <assert.h>
  22 +
  23 +/* Sets many bits from a single byte value (all 8 bits of the byte value are
  24 + set) */
  25 +void modbus_set_bits_from_byte(uint8_t *dest, int address, const uint8_t value)
  26 +{
  27 + int i;
  28 +
  29 + for (i=0; i<8; i++) {
  30 + dest[address+i] = (value & (1 << i)) ? 1 : 0;
  31 + }
  32 +}
  33 +
  34 +/* Sets many bits from a table of bytes (only the bits between address and
  35 + address + nb_bits are set) */
  36 +void modbus_set_bits_from_bytes(uint8_t *dest, int address, unsigned int nb_bits,
  37 + const uint8_t *tab_byte)
  38 +{
  39 + int i;
  40 + int shift = 0;
  41 +
  42 + for (i = address; i < address + nb_bits; i++) {
  43 + dest[i] = tab_byte[(i - address) / 8] & (1 << shift) ? 1 : 0;
  44 + /* gcc doesn't like: shift = (++shift) % 8; */
  45 + shift++;
  46 + shift %= 8;
  47 + }
  48 +}
  49 +
  50 +/* Gets the byte value from many bits.
  51 + To obtain a full byte, set nb_bits to 8. */
  52 +uint8_t modbus_get_byte_from_bits(const uint8_t *src, int address,
  53 + unsigned int nb_bits)
  54 +{
  55 + int i;
  56 + uint8_t value = 0;
  57 +
  58 + if (nb_bits > 8) {
  59 + assert(nb_bits < 8);
  60 + nb_bits = 8;
  61 + }
  62 +
  63 + for (i=0; i < nb_bits; i++) {
  64 + value |= (src[address+i] << i);
  65 + }
  66 +
  67 + return value;
  68 +}
  69 +
  70 +/* Get a float from 4 bytes in Modbus format */
  71 +float modbus_get_float(const uint16_t *src)
  72 +{
  73 + float r = 0.0f;
  74 + uint32_t i;
  75 +
  76 + i = (((uint32_t)src[1]) << 16) + src[0];
  77 + memcpy(&r, &i, sizeof (r));
  78 + return r;
  79 +}
  80 +
  81 +/* Set a float to 4 bytes in Modbus format */
  82 +void modbus_set_float(float real, uint16_t *dest)
  83 +{
  84 + uint32_t i = 0;
  85 +
  86 + memcpy(&i, &real, sizeof (i));
  87 + dest[0] = (uint16_t)i;
  88 + dest[1] = (uint16_t)(i >> 16);
  89 +}
src/modbus-private.h
@@ -22,17 +22,6 @@ @@ -22,17 +22,6 @@
22 22
23 MODBUS_BEGIN_DECLS 23 MODBUS_BEGIN_DECLS
24 24
25 -#define HEADER_LENGTH_RTU 1  
26 -#define PRESET_REQ_LENGTH_RTU 6  
27 -#define PRESET_RSP_LENGTH_RTU 2  
28 -  
29 -#define HEADER_LENGTH_TCP 7  
30 -#define PRESET_REQ_LENGTH_TCP 12  
31 -#define PRESET_RSP_LENGTH_TCP 8  
32 -  
33 -#define CHECKSUM_LENGTH_RTU 2  
34 -#define CHECKSUM_LENGTH_TCP 0  
35 -  
36 /* It's not really the minimal length (the real one is report slave ID 25 /* It's not really the minimal length (the real one is report slave ID
37 * in RTU (4 bytes)) but it's a convenient size to use in RTU or TCP 26 * in RTU (4 bytes)) but it's a convenient size to use in RTU or TCP
38 * communications to read many values or write a single one. 27 * communications to read many values or write a single one.
@@ -40,34 +29,66 @@ MODBUS_BEGIN_DECLS @@ -40,34 +29,66 @@ MODBUS_BEGIN_DECLS
40 * - HEADER_LENGTH_TCP (7) + function (1) + address (2) + number (2) 29 * - HEADER_LENGTH_TCP (7) + function (1) + address (2) + number (2)
41 * - HEADER_LENGTH_RTU (1) + function (1) + address (2) + number (2) + CRC (2) 30 * - HEADER_LENGTH_RTU (1) + function (1) + address (2) + number (2) + CRC (2)
42 */ 31 */
43 -#define MIN_REQ_LENGTH 12 32 +#define _MIN_REQ_LENGTH 12
44 33
45 -#define EXCEPTION_RSP_LENGTH_RTU 5 34 +#define _REPORT_SLAVE_ID_LENGTH 75
46 35
47 -#define REPORT_SLAVE_ID_LENGTH 75 36 +#define _MODBUS_EXCEPTION_RSP_LENGTH 5
48 37
49 /* Time out between trames in microsecond */ 38 /* Time out between trames in microsecond */
50 -#define TIME_OUT_BEGIN_OF_TRAME 500000  
51 -#define TIME_OUT_END_OF_TRAME 500000 39 +#define _TIME_OUT_BEGIN_OF_TRAME 500000
  40 +#define _TIME_OUT_END_OF_TRAME 500000
52 41
53 /* Function codes */ 42 /* Function codes */
54 -#define FC_READ_COILS 0x01  
55 -#define FC_READ_DISCRETE_INPUTS 0x02  
56 -#define FC_READ_HOLDING_REGISTERS 0x03  
57 -#define FC_READ_INPUT_REGISTERS 0x04  
58 -#define FC_WRITE_SINGLE_COIL 0x05  
59 -#define FC_WRITE_SINGLE_REGISTER 0x06  
60 -#define FC_READ_EXCEPTION_STATUS 0x07  
61 -#define FC_WRITE_MULTIPLE_COILS 0x0F  
62 -#define FC_WRITE_MULTIPLE_REGISTERS 0x10  
63 -#define FC_REPORT_SLAVE_ID 0x11  
64 -#define FC_READ_AND_WRITE_REGISTERS 0x17  
65 -  
66 -typedef enum { RTU=0, TCP } type_com_t; 43 +#define _FC_READ_COILS 0x01
  44 +#define _FC_READ_DISCRETE_INPUTS 0x02
  45 +#define _FC_READ_HOLDING_REGISTERS 0x03
  46 +#define _FC_READ_INPUT_REGISTERS 0x04
  47 +#define _FC_WRITE_SINGLE_COIL 0x05
  48 +#define _FC_WRITE_SINGLE_REGISTER 0x06
  49 +#define _FC_READ_EXCEPTION_STATUS 0x07
  50 +#define _FC_WRITE_MULTIPLE_COILS 0x0F
  51 +#define _FC_WRITE_MULTIPLE_REGISTERS 0x10
  52 +#define _FC_REPORT_SLAVE_ID 0x11
  53 +#define _FC_READ_AND_WRITE_REGISTERS 0x17
  54 +
  55 +typedef enum {
  56 + _MODBUS_BACKEND_TYPE_RTU=0,
  57 + _MODBUS_BACKEND_TYPE_TCP
  58 +} modbus_bakend_type_t;
  59 +
  60 +/* This structure reduces the number of params in functions and so
  61 + * optimizes the speed of execution (~ 37%). */
  62 +typedef struct _sft {
  63 + int slave;
  64 + int function;
  65 + int t_id;
  66 +} sft_t;
  67 +
  68 +typedef struct _modbus_backend {
  69 + unsigned int backend_type;
  70 + unsigned int header_length;
  71 + unsigned int checksum_length;
  72 + unsigned int max_adu_length;
  73 + int (*set_slave) (modbus_t *ctx, int slave);
  74 + int (*build_request_basis) (modbus_t *ctx, int function, int addr,
  75 + int nb, uint8_t *req);
  76 + int (*build_response_basis) (sft_t *sft, uint8_t *rsp);
  77 + int (*prepare_response_tid) (const uint8_t *req, int *req_length);
  78 + int (*send_msg_pre) (uint8_t *req, int req_length);
  79 + ssize_t (*send) (int s, const uint8_t *req, int req_length);
  80 + ssize_t (*recv) (int s, uint8_t *rsp, int rsp_length);
  81 + int (*check_integrity) (modbus_t *ctx, uint8_t *msg,
  82 + const int msg_length);
  83 + int (*connect) (modbus_t *ctx);
  84 + void (*close) (modbus_t *ctx);
  85 + int (*flush) (modbus_t *ctx);
  86 + int (*listen) (modbus_t *ctx, int nb_connection);
  87 + int (*accept) (modbus_t *ctx, int *socket);
  88 + int (*filter_request) (modbus_t *ctx, int slave);
  89 +} modbus_backend_t;
67 90
68 struct _modbus { 91 struct _modbus {
69 - /* Communication mode: RTU or TCP */  
70 - type_com_t type_com;  
71 /* Slave address */ 92 /* Slave address */
72 int slave; 93 int slave;
73 /* Socket or file descriptor */ 94 /* Socket or file descriptor */
@@ -76,38 +97,11 @@ struct _modbus { @@ -76,38 +97,11 @@ struct _modbus {
76 int error_recovery; 97 int error_recovery;
77 struct timeval timeout_begin; 98 struct timeval timeout_begin;
78 struct timeval timeout_end; 99 struct timeval timeout_end;
79 - void *com; 100 + const modbus_backend_t *backend;
  101 + void *backend_data;
80 }; 102 };
81 103
82 -typedef struct _modbus_rtu {  
83 - /* Device: "/dev/ttyS0", "/dev/ttyUSB0" or "/dev/tty.USA19*" on Mac OS X for  
84 - KeySpan USB<->Serial adapters this string had to be made bigger on OS X  
85 - as the directory+file name was bigger than 19 bytes. Making it 67 bytes  
86 - for now, but OS X does support 256 byte file names. May become a problem  
87 - in the future. */  
88 -#ifdef __APPLE_CC__  
89 - char device[64];  
90 -#else  
91 - char device[16];  
92 -#endif  
93 - /* Bauds: 9600, 19200, 57600, 115200, etc */  
94 - int baud;  
95 - /* Data bit */  
96 - uint8_t data_bit;  
97 - /* Stop bit */  
98 - uint8_t stop_bit;  
99 - /* Parity: 'N', 'O', 'E' */  
100 - char parity;  
101 - /* Save old termios settings */  
102 - struct termios old_tios;  
103 -} modbus_rtu_t;  
104 -  
105 -typedef struct _modbus_tcp {  
106 - /* TCP port */  
107 - int port;  
108 - /* IP address */  
109 - char ip[16];  
110 -} modbus_tcp_t; 104 +void _modbus_init_common(modbus_t *ctx);
111 105
112 MODBUS_END_DECLS 106 MODBUS_END_DECLS
113 107
src/modbus-rtu-private.h 0 → 100644
  1 +/*
  2 + * Copyright © 2001-2010 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 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.
  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 Lesser Public License for more details.
  13 + *
  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/>.
  16 + */
  17 +
  18 +#ifndef _MODBUS_RTU_PRIVATE_H_
  19 +#define _MODBUS_RTU_PRIVATE_H_
  20 +
  21 +#define _MODBUS_RTU_HEADER_LENGTH 1
  22 +#define _MODBUS_RTU_PRESET_REQ_LENGTH 6
  23 +#define _MODBUS_RTU_PRESET_RSP_LENGTH 2
  24 +
  25 +#define _MODBUS_RTU_CHECKSUM_LENGTH 2
  26 +
  27 +typedef struct _modbus_rtu {
  28 + /* Device: "/dev/ttyS0", "/dev/ttyUSB0" or "/dev/tty.USA19*" on Mac OS X for
  29 + KeySpan USB<->Serial adapters this string had to be made bigger on OS X
  30 + as the directory+file name was bigger than 19 bytes. Making it 67 bytes
  31 + for now, but OS X does support 256 byte file names. May become a problem
  32 + in the future. */
  33 +#ifdef __APPLE_CC__
  34 + char device[64];
  35 +#else
  36 + char device[16];
  37 +#endif
  38 + /* Bauds: 9600, 19200, 57600, 115200, etc */
  39 + int baud;
  40 + /* Data bit */
  41 + uint8_t data_bit;
  42 + /* Stop bit */
  43 + uint8_t stop_bit;
  44 + /* Parity: 'N', 'O', 'E' */
  45 + char parity;
  46 + /* Save old termios settings */
  47 + struct termios old_tios;
  48 +} modbus_rtu_t;
  49 +
  50 +#endif /* _MODBUS_RTU_PRIVATE_H_ */
src/modbus-rtu.c 0 → 100644
  1 +/*
  2 + * Copyright © 2001-2010 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 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.
  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 Lesser Public License for more details.
  13 + *
  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/>.
  16 + */
  17 +
  18 +#include <stdio.h>
  19 +#include <stdlib.h>
  20 +#include <errno.h>
  21 +#include <termios.h>
  22 +#include <fcntl.h>
  23 +#include <string.h>
  24 +
  25 +#include "modbus.h"
  26 +#include "modbus-private.h"
  27 +
  28 +#include "modbus-rtu.h"
  29 +#include "modbus-rtu-private.h"
  30 +
  31 +/* Table of CRC values for high-order byte */
  32 +static const uint8_t table_crc_hi[] = {
  33 + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
  34 + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  35 + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
  36 + 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
  37 + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
  38 + 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
  39 + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
  40 + 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  41 + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
  42 + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
  43 + 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
  44 + 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
  45 + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
  46 + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
  47 + 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
  48 + 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
  49 + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
  50 + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  51 + 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
  52 + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  53 + 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
  54 + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
  55 + 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
  56 + 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  57 + 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
  58 + 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
  59 +};
  60 +
  61 +/* Table of CRC values for low-order byte */
  62 +static const uint8_t table_crc_lo[] = {
  63 + 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
  64 + 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
  65 + 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
  66 + 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
  67 + 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
  68 + 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
  69 + 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
  70 + 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
  71 + 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
  72 + 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
  73 + 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
  74 + 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
  75 + 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
  76 + 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
  77 + 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
  78 + 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
  79 + 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
  80 + 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
  81 + 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
  82 + 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
  83 + 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
  84 + 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
  85 + 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
  86 + 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
  87 + 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
  88 + 0x43, 0x83, 0x41, 0x81, 0x80, 0x40
  89 +};
  90 +
  91 +static int _modbus_set_slave(modbus_t *ctx, int slave)
  92 +{
  93 + if (slave >= 1 && slave <= 247) {
  94 + ctx->slave = slave;
  95 + } else {
  96 + errno = EINVAL;
  97 + return -1;
  98 + }
  99 +
  100 + return 0;
  101 +}
  102 +
  103 +/* Builds a RTU request header */
  104 +static int _modbus_rtu_build_request_basis(modbus_t *ctx, int function,
  105 + int addr, int nb,
  106 + uint8_t *req)
  107 +{
  108 + req[0] = ctx->slave;
  109 + req[1] = function;
  110 + req[2] = addr >> 8;
  111 + req[3] = addr & 0x00ff;
  112 + req[4] = nb >> 8;
  113 + req[5] = nb & 0x00ff;
  114 +
  115 + return _MODBUS_RTU_PRESET_REQ_LENGTH;
  116 +}
  117 +
  118 +/* Builds a RTU response header */
  119 +static int _modbus_rtu_build_response_basis(sft_t *sft, uint8_t *rsp)
  120 +{
  121 + rsp[0] = sft->slave;
  122 + rsp[1] = sft->function;
  123 +
  124 + return _MODBUS_RTU_PRESET_RSP_LENGTH;
  125 +}
  126 +
  127 +static uint16_t crc16(uint8_t *buffer, uint16_t buffer_length)
  128 +{
  129 + uint8_t crc_hi = 0xFF; /* high CRC byte initialized */
  130 + uint8_t crc_lo = 0xFF; /* low CRC byte initialized */
  131 + unsigned int i; /* will index into CRC lookup */
  132 +
  133 + /* pass through message buffer */
  134 + while (buffer_length--) {
  135 + i = crc_hi ^ *buffer++; /* calculate the CRC */
  136 + crc_hi = crc_lo ^ table_crc_hi[i];
  137 + crc_lo = table_crc_lo[i];
  138 + }
  139 +
  140 + return (crc_hi << 8 | crc_lo);
  141 +}
  142 +
  143 +int _modbus_rtu_prepare_response_tid(const uint8_t *req, int *req_length)
  144 +{
  145 + (*req_length) -= _MODBUS_RTU_CHECKSUM_LENGTH;
  146 + /* No TID */
  147 + return 0;
  148 +}
  149 +
  150 +int _modbus_rtu_send_msg_pre(uint8_t *req, int req_length)
  151 +{
  152 + uint16_t crc = crc16(req, req_length);
  153 + req[req_length++] = crc >> 8;
  154 + req[req_length++] = crc & 0x00FF;
  155 +
  156 + return req_length;
  157 +}
  158 +
  159 +ssize_t _modbus_rtu_send(int s, const uint8_t *req, int req_length)
  160 +{
  161 + return write(s, req, req_length);
  162 +}
  163 +
  164 +ssize_t _modbus_rtu_recv(int s, uint8_t *rsp, int rsp_length)
  165 +{
  166 + return read(s, rsp, rsp_length);
  167 +}
  168 +
  169 +/* The check_crc16 function shall return the message length if the CRC is
  170 + valid. Otherwise it shall return -1 and set errno to EMBADCRC. */
  171 +int _modbus_rtu_check_integrity(modbus_t *ctx, uint8_t *msg,
  172 + const int msg_length)
  173 +{
  174 + uint16_t crc_calculated;
  175 + uint16_t crc_received;
  176 +
  177 + crc_calculated = crc16(msg, msg_length - 2);
  178 + crc_received = (msg[msg_length - 2] << 8) | msg[msg_length - 1];
  179 +
  180 + /* Check CRC of msg */
  181 + if (crc_calculated == crc_received) {
  182 + return msg_length;
  183 + } else {
  184 + if (ctx->debug) {
  185 + fprintf(stderr, "ERROR CRC received %0X != CRC calculated %0X\n",
  186 + crc_received, crc_calculated);
  187 + }
  188 + if (ctx->error_recovery) {
  189 + _modbus_rtu_flush(ctx);
  190 + }
  191 + errno = EMBBADCRC;
  192 + return -1;
  193 + }
  194 +}
  195 +
  196 +/* Sets up a serial port for RTU communications */
  197 +static int _modbus_rtu_connect(modbus_t *ctx)
  198 +{
  199 + struct termios tios;
  200 + speed_t speed;
  201 + modbus_rtu_t *ctx_rtu = ctx->backend_data;
  202 +
  203 + if (ctx->debug) {
  204 + printf("Opening %s at %d bauds (%c, %d, %d)\n",
  205 + ctx_rtu->device, ctx_rtu->baud, ctx_rtu->parity,
  206 + ctx_rtu->data_bit, ctx_rtu->stop_bit);
  207 + }
  208 +
  209 + /* The O_NOCTTY flag tells UNIX that this program doesn't want
  210 + to be the "controlling terminal" for that port. If you
  211 + don't specify this then any input (such as keyboard abort
  212 + signals and so forth) will affect your process
  213 +
  214 + Timeouts are ignored in canonical input mode or when the
  215 + NDELAY option is set on the file via open or fcntl */
  216 + ctx->s = open(ctx_rtu->device, O_RDWR | O_NOCTTY | O_NDELAY | O_EXCL);
  217 + if (ctx->s == -1) {
  218 + fprintf(stderr, "ERROR Can't open the device %s (%s)\n",
  219 + ctx_rtu->device, strerror(errno));
  220 + return -1;
  221 + }
  222 +
  223 + /* Save */
  224 + tcgetattr(ctx->s, &(ctx_rtu->old_tios));
  225 +
  226 + memset(&tios, 0, sizeof(struct termios));
  227 +
  228 + /* C_ISPEED Input baud (new interface)
  229 + C_OSPEED Output baud (new interface)
  230 + */
  231 + switch (ctx_rtu->baud) {
  232 + case 110:
  233 + speed = B110;
  234 + break;
  235 + case 300:
  236 + speed = B300;
  237 + break;
  238 + case 600:
  239 + speed = B600;
  240 + break;
  241 + case 1200:
  242 + speed = B1200;
  243 + break;
  244 + case 2400:
  245 + speed = B2400;
  246 + break;
  247 + case 4800:
  248 + speed = B4800;
  249 + break;
  250 + case 9600:
  251 + speed = B9600;
  252 + break;
  253 + case 19200:
  254 + speed = B19200;
  255 + break;
  256 + case 38400:
  257 + speed = B38400;
  258 + break;
  259 + case 57600:
  260 + speed = B57600;
  261 + break;
  262 + case 115200:
  263 + speed = B115200;
  264 + break;
  265 + default:
  266 + speed = B9600;
  267 + if (ctx->debug) {
  268 + fprintf(stderr,
  269 + "WARNING Unknown baud rate %d for %s (B9600 used)\n",
  270 + ctx_rtu->baud, ctx_rtu->device);
  271 + }
  272 + }
  273 +
  274 + /* Set the baud rate */
  275 + if ((cfsetispeed(&tios, speed) < 0) ||
  276 + (cfsetospeed(&tios, speed) < 0)) {
  277 + return -1;
  278 + }
  279 +
  280 + /* C_CFLAG Control options
  281 + CLOCAL Local line - do not change "owner" of port
  282 + CREAD Enable receiver
  283 + */
  284 + tios.c_cflag |= (CREAD | CLOCAL);
  285 + /* CSIZE, HUPCL, CRTSCTS (hardware flow control) */
  286 +
  287 + /* Set data bits (5, 6, 7, 8 bits)
  288 + CSIZE Bit mask for data bits
  289 + */
  290 + tios.c_cflag &= ~CSIZE;
  291 + switch (ctx_rtu->data_bit) {
  292 + case 5:
  293 + tios.c_cflag |= CS5;
  294 + break;
  295 + case 6:
  296 + tios.c_cflag |= CS6;
  297 + break;
  298 + case 7:
  299 + tios.c_cflag |= CS7;
  300 + break;
  301 + case 8:
  302 + default:
  303 + tios.c_cflag |= CS8;
  304 + break;
  305 + }
  306 +
  307 + /* Stop bit (1 or 2) */
  308 + if (ctx_rtu->stop_bit == 1)
  309 + tios.c_cflag &=~ CSTOPB;
  310 + else /* 2 */
  311 + tios.c_cflag |= CSTOPB;
  312 +
  313 + /* PARENB Enable parity bit
  314 + PARODD Use odd parity instead of even */
  315 + if (ctx_rtu->parity == 'N') {
  316 + /* None */
  317 + tios.c_cflag &=~ PARENB;
  318 + } else if (ctx_rtu->parity == 'E') {
  319 + /* Even */
  320 + tios.c_cflag |= PARENB;
  321 + tios.c_cflag &=~ PARODD;
  322 + } else {
  323 + /* Odd */
  324 + tios.c_cflag |= PARENB;
  325 + tios.c_cflag |= PARODD;
  326 + }
  327 +
  328 + /* Read the man page of termios if you need more information. */
  329 +
  330 + /* This field isn't used on POSIX systems
  331 + tios.c_line = 0;
  332 + */
  333 +
  334 + /* C_LFLAG Line options
  335 +
  336 + ISIG Enable SIGINTR, SIGSUSP, SIGDSUSP, and SIGQUIT signals
  337 + ICANON Enable canonical input (else raw)
  338 + XCASE Map uppercase \lowercase (obsolete)
  339 + ECHO Enable echoing of input characters
  340 + ECHOE Echo erase character as BS-SP-BS
  341 + ECHOK Echo NL after kill character
  342 + ECHONL Echo NL
  343 + NOFLSH Disable flushing of input buffers after
  344 + interrupt or quit characters
  345 + IEXTEN Enable extended functions
  346 + ECHOCTL Echo control characters as ^char and delete as ~?
  347 + ECHOPRT Echo erased character as character erased
  348 + ECHOKE BS-SP-BS entire line on line kill
  349 + FLUSHO Output being flushed
  350 + PENDIN Retype pending input at next read or input char
  351 + TOSTOP Send SIGTTOU for background output
  352 +
  353 + Canonical input is line-oriented. Input characters are put
  354 + into a buffer which can be edited interactively by the user
  355 + until a CR (carriage return) or LF (line feed) character is
  356 + received.
  357 +
  358 + Raw input is unprocessed. Input characters are passed
  359 + through exactly as they are received, when they are
  360 + received. Generally you'll deselect the ICANON, ECHO,
  361 + ECHOE, and ISIG options when using raw input
  362 + */
  363 +
  364 + /* Raw input */
  365 + tios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
  366 +
  367 + /* C_IFLAG Input options
  368 +
  369 + Constant Description
  370 + INPCK Enable parity check
  371 + IGNPAR Ignore parity errors
  372 + PARMRK Mark parity errors
  373 + ISTRIP Strip parity bits
  374 + IXON Enable software flow control (outgoing)
  375 + IXOFF Enable software flow control (incoming)
  376 + IXANY Allow any character to start flow again
  377 + IGNBRK Ignore break condition
  378 + BRKINT Send a SIGINT when a break condition is detected
  379 + INLCR Map NL to CR
  380 + IGNCR Ignore CR
  381 + ICRNL Map CR to NL
  382 + IUCLC Map uppercase to lowercase
  383 + IMAXBEL Echo BEL on input line too long
  384 + */
  385 + if (ctx_rtu->parity == 'N') {
  386 + /* None */
  387 + tios.c_iflag &= ~INPCK;
  388 + } else {
  389 + tios.c_iflag |= INPCK;
  390 + }
  391 +
  392 + /* Software flow control is disabled */
  393 + tios.c_iflag &= ~(IXON | IXOFF | IXANY);
  394 +
  395 + /* C_OFLAG Output options
  396 + OPOST Postprocess output (not set = raw output)
  397 + ONLCR Map NL to CR-NL
  398 +
  399 + ONCLR ant others needs OPOST to be enabled
  400 + */
  401 +
  402 + /* Raw ouput */
  403 + tios.c_oflag &=~ OPOST;
  404 +
  405 + /* C_CC Control characters
  406 + VMIN Minimum number of characters to read
  407 + VTIME Time to wait for data (tenths of seconds)
  408 +
  409 + UNIX serial interface drivers provide the ability to
  410 + specify character and packet timeouts. Two elements of the
  411 + c_cc array are used for timeouts: VMIN and VTIME. Timeouts
  412 + are ignored in canonical input mode or when the NDELAY
  413 + option is set on the file via open or fcntl.
  414 +
  415 + VMIN specifies the minimum number of characters to read. If
  416 + it is set to 0, then the VTIME value specifies the time to
  417 + wait for every character read. Note that this does not mean
  418 + that a read call for N bytes will wait for N characters to
  419 + come in. Rather, the timeout will apply to the first
  420 + character and the read call will return the number of
  421 + characters immediately available (up to the number you
  422 + request).
  423 +
  424 + If VMIN is non-zero, VTIME specifies the time to wait for
  425 + the first character read. If a character is read within the
  426 + time given, any read will block (wait) until all VMIN
  427 + characters are read. That is, once the first character is
  428 + read, the serial interface driver expects to receive an
  429 + entire packet of characters (VMIN bytes total). If no
  430 + character is read within the time allowed, then the call to
  431 + read returns 0. This method allows you to tell the serial
  432 + driver you need exactly N bytes and any read call will
  433 + return 0 or N bytes. However, the timeout only applies to
  434 + the first character read, so if for some reason the driver
  435 + misses one character inside the N byte packet then the read
  436 + call could block forever waiting for additional input
  437 + characters.
  438 +
  439 + VTIME specifies the amount of time to wait for incoming
  440 + characters in tenths of seconds. If VTIME is set to 0 (the
  441 + default), reads will block (wait) indefinitely unless the
  442 + NDELAY option is set on the port with open or fcntl.
  443 + */
  444 + /* Unused because we use open with the NDELAY option */
  445 + tios.c_cc[VMIN] = 0;
  446 + tios.c_cc[VTIME] = 0;
  447 +
  448 + if (tcsetattr(ctx->s, TCSANOW, &tios) < 0) {
  449 + return -1;
  450 + }
  451 +
  452 + return 0;
  453 +}
  454 +
  455 +void _modbus_rtu_close(modbus_t *ctx)
  456 +{
  457 + /* Closes the file descriptor in RTU mode */
  458 + modbus_rtu_t *ctx_rtu = ctx->backend_data;
  459 +
  460 + tcsetattr(ctx->s, TCSANOW, &(ctx_rtu->old_tios));
  461 + close(ctx->s);
  462 +}
  463 +
  464 +int _modbus_rtu_flush(modbus_t *ctx)
  465 +{
  466 + return tcflush(ctx->s, TCIOFLUSH);
  467 +}
  468 +
  469 +int _modbus_rtu_listen(modbus_t *ctx, int nb_connection)
  470 +{
  471 + if (ctx->debug) {
  472 + fprintf(stderr, "Not implemented");
  473 + }
  474 +
  475 + errno = EINVAL;
  476 + return -1;
  477 +}
  478 +
  479 +int _modbus_rtu_accept(modbus_t *ctx, int *socket)
  480 +{
  481 + if (ctx->debug) {
  482 + fprintf(stderr, "Not implemented");
  483 + }
  484 +
  485 + errno = EINVAL;
  486 + return -1;
  487 +}
  488 +
  489 +int _modbus_rtu_filter_request(modbus_t *ctx, int slave)
  490 +{
  491 + /* Filter on the Modbus unit identifier (slave) in RTU mode */
  492 + if (slave != ctx->slave && slave != MODBUS_BROADCAST_ADDRESS) {
  493 + /* Ignores the request (not for me) */
  494 + if (ctx->debug) {
  495 + printf("Request for slave %d ignored (not %d)\n",
  496 + slave, ctx->slave);
  497 + }
  498 + return 1;
  499 + } else {
  500 + return 0;
  501 + }
  502 +}
  503 +
  504 +const modbus_backend_t _modbus_rtu_backend = {
  505 + _MODBUS_BACKEND_TYPE_RTU,
  506 + _MODBUS_RTU_HEADER_LENGTH,
  507 + _MODBUS_RTU_CHECKSUM_LENGTH,
  508 + MODBUS_RTU_MAX_ADU_LENGTH,
  509 + _modbus_set_slave,
  510 + _modbus_rtu_build_request_basis,
  511 + _modbus_rtu_build_response_basis,
  512 + _modbus_rtu_prepare_response_tid,
  513 + _modbus_rtu_send_msg_pre,
  514 + _modbus_rtu_send,
  515 + _modbus_rtu_recv,
  516 + _modbus_rtu_check_integrity,
  517 + _modbus_rtu_connect,
  518 + _modbus_rtu_close,
  519 + _modbus_rtu_flush,
  520 + _modbus_rtu_listen,
  521 + _modbus_rtu_accept,
  522 + _modbus_rtu_filter_request
  523 +};
  524 +
  525 +/* Allocate and initialize the modbus_t structure for RTU
  526 + - device: "/dev/ttyS0"
  527 + - baud: 9600, 19200, 57600, 115200, etc
  528 + - parity: 'N' stands for None, 'E' for Even and 'O' for odd
  529 + - data_bits: 5, 6, 7, 8
  530 + - stop_bits: 1, 2
  531 + - slave: slave number of the caller
  532 +*/
  533 +modbus_t* modbus_new_rtu(const char *device,
  534 + int baud, char parity, int data_bit,
  535 + int stop_bit, int slave)
  536 +{
  537 + modbus_t *ctx;
  538 + modbus_rtu_t *ctx_rtu;
  539 +
  540 + ctx = (modbus_t *) malloc(sizeof(modbus_t));
  541 + _modbus_init_common(ctx);
  542 + if (modbus_set_slave(ctx, slave) == -1) {
  543 + return NULL;
  544 + }
  545 +
  546 + ctx->backend = &_modbus_rtu_backend;
  547 +
  548 + ctx->backend_data = (modbus_rtu_t *) malloc(sizeof(modbus_rtu_t));
  549 + ctx_rtu = (modbus_rtu_t *)ctx->backend_data;
  550 +#if defined(OpenBSD)
  551 + strlcpy(ctx_rtu->device, device, sizeof(ctx_rtu->device));
  552 +#else
  553 + strcpy(ctx_rtu->device, device);
  554 +#endif
  555 + ctx_rtu->baud = baud;
  556 + if (parity == 'N' || parity == 'E' || parity == 'O') {
  557 + ctx_rtu->parity = parity;
  558 + } else {
  559 + errno = EINVAL;
  560 + return NULL;
  561 + }
  562 + ctx_rtu->data_bit = data_bit;
  563 + ctx_rtu->stop_bit = stop_bit;
  564 +
  565 + return ctx;
  566 +}
src/modbus-rtu.h 0 → 100644
  1 +/*
  2 + * Copyright © 2001-2010 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 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.
  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 Lesser Public License for more details.
  13 + *
  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/>.
  16 + */
  17 +
  18 +#ifndef _MODBUS_RTU_H_
  19 +#define _MODBUS_RTU_H_
  20 +
  21 +/* Modbus_Application_Protocol_V1_1b.pdf Chapter 4 Section 1 Page 5
  22 + * RS232 / RS485 ADU = 253 bytes + slave (1 byte) + CRC (2 bytes) = 256 bytes
  23 + */
  24 +#define MODBUS_RTU_MAX_ADU_LENGTH 256
  25 +
  26 +modbus_t* modbus_new_rtu(const char *device, int baud, char parity,
  27 + int data_bit, int stop_bit, int slave);
  28 +
  29 +#endif /* _MODBUS_RTU_H_ */
src/modbus-tcp-private.h 0 → 100644
  1 +/*
  2 + * Copyright © 2001-2010 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 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.
  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 Lesser Public License for more details.
  13 + *
  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/>.
  16 + */
  17 +
  18 +#ifndef _MODBUS_TCP_PRIVATE_H_
  19 +#define _MODBUS_TCP_PRIVATE_H_
  20 +
  21 +#define _MODBUS_TCP_HEADER_LENGTH 7
  22 +#define _MODBUS_TCP_PRESET_REQ_LENGTH 12
  23 +#define _MODBUS_TCP_PRESET_RSP_LENGTH 8
  24 +
  25 +#define _MODBUS_TCP_CHECKSUM_LENGTH 0
  26 +
  27 +typedef struct _modbus_tcp {
  28 + /* TCP port */
  29 + int port;
  30 + /* IP address */
  31 + char ip[16];
  32 +} modbus_tcp_t;
  33 +
  34 +#endif /* _MODBUS_TCP_PRIVATE_H_ */
src/modbus-tcp.c 0 → 100644
  1 +/*
  2 + * Copyright © 2001-2010 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 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.
  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 Lesser Public License for more details.
  13 + *
  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/>.
  16 + */
  17 +
  18 +#include <stdio.h>
  19 +#include <stdlib.h>
  20 +#include <string.h>
  21 +#include <errno.h>
  22 +
  23 +#include <sys/types.h>
  24 +#include <sys/socket.h>
  25 +#include <sys/ioctl.h>
  26 +#if (defined OpenBSD) || (defined(__FreeBSD__ ) && __FreeBSD__ < 5)
  27 +#include <netinet/in_systm.h>
  28 +#endif
  29 +#include <netinet/in.h>
  30 +#include <netinet/ip.h>
  31 +#include <netinet/tcp.h>
  32 +#include <arpa/inet.h>
  33 +
  34 +#include "modbus.h"
  35 +#include "modbus-private.h"
  36 +
  37 +#include "modbus-tcp.h"
  38 +#include "modbus-tcp-private.h"
  39 +
  40 +static int _modbus_set_slave(modbus_t *ctx, int slave)
  41 +{
  42 + if (slave >= 1 && slave <= 247) {
  43 + ctx->slave = slave;
  44 + } else if (slave == MODBUS_TCP_SLAVE) {
  45 + /* The special value MODBUS_TCP_SLAVE (0xFF) can be used in TCP mode to
  46 + * restore the default value. */
  47 + ctx->slave = slave;
  48 + } else {
  49 + errno = EINVAL;
  50 + return -1;
  51 + }
  52 +
  53 + return 0;
  54 +}
  55 +
  56 +/* Builds a TCP request header */
  57 +int _modbus_tcp_build_request_basis(modbus_t *ctx, int function,
  58 + int addr, int nb,
  59 + uint8_t *req)
  60 +{
  61 +
  62 + /* Extract from MODBUS Messaging on TCP/IP Implementation Guide V1.0b
  63 + (page 23/46):
  64 + The transaction identifier is used to associate the future response
  65 + with the request. So, at a time, on a TCP connection, this identifier
  66 + must be unique. */
  67 + static uint16_t t_id = 0;
  68 +
  69 + /* Transaction ID */
  70 + if (t_id < UINT16_MAX)
  71 + t_id++;
  72 + else
  73 + t_id = 0;
  74 + req[0] = t_id >> 8;
  75 + req[1] = t_id & 0x00ff;
  76 +
  77 + /* Protocol Modbus */
  78 + req[2] = 0;
  79 + req[3] = 0;
  80 +
  81 + /* Length will be defined later by set_req_length_tcp at offsets 4
  82 + and 5 */
  83 +
  84 + req[6] = ctx->slave;
  85 + req[7] = function;
  86 + req[8] = addr >> 8;
  87 + req[9] = addr & 0x00ff;
  88 + req[10] = nb >> 8;
  89 + req[11] = nb & 0x00ff;
  90 +
  91 + return _MODBUS_TCP_PRESET_REQ_LENGTH;
  92 +}
  93 +
  94 +/* Builds a TCP response header */
  95 +int _modbus_tcp_build_response_basis(sft_t *sft, uint8_t *rsp)
  96 +{
  97 + /* Extract from MODBUS Messaging on TCP/IP Implementation
  98 + Guide V1.0b (page 23/46):
  99 + The transaction identifier is used to associate the future
  100 + response with the request. */
  101 + rsp[0] = sft->t_id >> 8;
  102 + rsp[1] = sft->t_id & 0x00ff;
  103 +
  104 + /* Protocol Modbus */
  105 + rsp[2] = 0;
  106 + rsp[3] = 0;
  107 +
  108 + /* Length will be set later by send_msg (4 and 5) */
  109 +
  110 + rsp[6] = 0xFF;
  111 + rsp[7] = sft->function;
  112 +
  113 + return _MODBUS_TCP_PRESET_RSP_LENGTH;
  114 +}
  115 +
  116 +
  117 +int _modbus_tcp_prepare_response_tid(const uint8_t *req, int *req_length)
  118 +{
  119 + return (req[0] << 8) + req[1];
  120 +}
  121 +
  122 +int _modbus_tcp_send_msg_pre(uint8_t *req, int req_length)
  123 +{
  124 + /* Substract the header length to the message length */
  125 + int mbap_length = req_length - 6;
  126 +
  127 + req[4] = mbap_length >> 8;
  128 + req[5] = mbap_length & 0x00FF;
  129 +
  130 + return req_length;
  131 +}
  132 +
  133 +ssize_t _modbus_tcp_send(int s, const uint8_t *req, int req_length)
  134 +{
  135 + /* MSG_NOSIGNAL
  136 + Requests not to send SIGPIPE on errors on stream oriented
  137 + sockets when the other end breaks the connection. The EPIPE
  138 + error is still returned. */
  139 + return send(s, req, req_length, MSG_NOSIGNAL);
  140 +}
  141 +
  142 +ssize_t _modbus_tcp_recv(int s, uint8_t *rsp, int rsp_length) {
  143 + return recv(s, rsp, rsp_length, 0);
  144 +}
  145 +
  146 +int _modbus_tcp_check_integrity(modbus_t *ctx, uint8_t *msg, const int msg_length)
  147 +{
  148 + return msg_length;
  149 +}
  150 +
  151 +/* Establishes a modbus TCP connection with a Modbus server. */
  152 +static int _modbus_tcp_connect(modbus_t *ctx)
  153 +{
  154 + int rc;
  155 + int option;
  156 + struct sockaddr_in addr;
  157 + modbus_tcp_t *ctx_tcp = ctx->backend_data;
  158 +
  159 + ctx->s = socket(PF_INET, SOCK_STREAM, 0);
  160 + if (ctx->s == -1) {
  161 + return -1;
  162 + }
  163 +
  164 + /* Set the TCP no delay flag */
  165 + /* SOL_TCP = IPPROTO_TCP */
  166 + option = 1;
  167 + rc = setsockopt(ctx->s, IPPROTO_TCP, TCP_NODELAY,
  168 + (const void *)&option, sizeof(int));
  169 + if (rc == -1) {
  170 + close(ctx->s);
  171 + return -1;
  172 + }
  173 +
  174 +#if (!HAVE_DECL___CYGWIN__)
  175 + /**
  176 + * Cygwin defines IPTOS_LOWDELAY but can't handle that flag so it's
  177 + * necessary to workaround that problem.
  178 + **/
  179 + /* Set the IP low delay option */
  180 + option = IPTOS_LOWDELAY;
  181 + rc = setsockopt(ctx->s, IPPROTO_IP, IP_TOS,
  182 + (const void *)&option, sizeof(int));
  183 + if (rc == -1) {
  184 + close(ctx->s);
  185 + return -1;
  186 + }
  187 +#endif
  188 +
  189 + if (ctx->debug) {
  190 + printf("Connecting to %s\n", ctx_tcp->ip);
  191 + }
  192 +
  193 + addr.sin_family = AF_INET;
  194 + addr.sin_port = htons(ctx_tcp->port);
  195 + addr.sin_addr.s_addr = inet_addr(ctx_tcp->ip);
  196 + rc = connect(ctx->s, (struct sockaddr *)&addr,
  197 + sizeof(struct sockaddr_in));
  198 + if (rc == -1) {
  199 + close(ctx->s);
  200 + return -1;
  201 + }
  202 +
  203 + return 0;
  204 +}
  205 +
  206 +/* Closes the network connection and socket in TCP mode */
  207 +void _modbus_tcp_close(modbus_t *ctx)
  208 +{
  209 + shutdown(ctx->s, SHUT_RDWR);
  210 + close(ctx->s);
  211 +}
  212 +
  213 +int _modbus_tcp_flush(modbus_t *ctx)
  214 +{
  215 + int rc;
  216 +
  217 + do {
  218 + /* Extract the garbage from the socket */
  219 + char devnull[MODBUS_TCP_MAX_ADU_LENGTH];
  220 +#if (!HAVE_DECL___CYGWIN__)
  221 + rc = recv(ctx->s, devnull, MODBUS_TCP_MAX_ADU_LENGTH, MSG_DONTWAIT);
  222 +#else
  223 + /* On Cygwin, it's a bit more complicated to not wait */
  224 + fd_set rfds;
  225 + struct timeval tv;
  226 +
  227 + tv.tv_sec = 0;
  228 + tv.tv_usec = 0;
  229 + FD_ZERO(&rfds);
  230 + FD_SET(ctx->s, &rfds);
  231 + rc = select(ctx->s+1, &rfds, NULL, NULL, &tv);
  232 + if (rc == -1) {
  233 + return -1;
  234 + }
  235 +
  236 + rc = recv(ctx->s, devnull, MODBUS_TCP_MAX_ADU_LENGTH, 0);
  237 +#endif
  238 + if (ctx->debug && rc != -1) {
  239 + printf("\n%d bytes flushed\n", rc);
  240 + }
  241 + } while (rc > 0);
  242 +
  243 + return rc;
  244 +}
  245 +
  246 +/* Listens for any request from one or many modbus masters in TCP */
  247 +int _modbus_tcp_listen(modbus_t *ctx, int nb_connection)
  248 +{
  249 + int new_socket;
  250 + int yes;
  251 + struct sockaddr_in addr;
  252 + modbus_tcp_t *ctx_tcp = ctx->backend_data;
  253 +
  254 + new_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
  255 + if (new_socket == -1) {
  256 + return -1;
  257 + }
  258 +
  259 + yes = 1;
  260 + if (setsockopt(new_socket, SOL_SOCKET, SO_REUSEADDR,
  261 + (char *) &yes, sizeof(yes)) == -1) {
  262 + close(new_socket);
  263 + return -1;
  264 + }
  265 +
  266 + memset(&addr, 0, sizeof(addr));
  267 + addr.sin_family = AF_INET;
  268 + /* If the modbus port is < to 1024, we need the setuid root. */
  269 + addr.sin_port = htons(ctx_tcp->port);
  270 + addr.sin_addr.s_addr = INADDR_ANY;
  271 + if (bind(new_socket, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
  272 + close(new_socket);
  273 + return -1;
  274 + }
  275 +
  276 + if (listen(new_socket, nb_connection) == -1) {
  277 + close(new_socket);
  278 + return -1;
  279 + }
  280 +
  281 + return new_socket;
  282 +}
  283 +
  284 +/* On success, the function return a non-negative integer that is a descriptor
  285 + for the accepted socket. On error, -1 is returned, and errno is set
  286 + appropriately. */
  287 +int _modbus_tcp_accept(modbus_t *ctx, int *socket)
  288 +{
  289 + struct sockaddr_in addr;
  290 + socklen_t addrlen;
  291 +
  292 + addrlen = sizeof(struct sockaddr_in);
  293 + ctx->s = accept(*socket, (struct sockaddr *)&addr, &addrlen);
  294 + if (ctx->s == -1) {
  295 + close(*socket);
  296 + *socket = 0;
  297 + return -1;
  298 + }
  299 +
  300 + if (ctx->debug) {
  301 + printf("The client %s is connected\n", inet_ntoa(addr.sin_addr));
  302 + }
  303 +
  304 + return ctx->s;
  305 +}
  306 +
  307 +int _modbus_tcp_filter_request(modbus_t *ctx, int slave)
  308 +{
  309 + return 0;
  310 +}
  311 +
  312 +const modbus_backend_t _modbus_tcp_backend = {
  313 + _MODBUS_BACKEND_TYPE_TCP,
  314 + _MODBUS_TCP_HEADER_LENGTH,
  315 + _MODBUS_TCP_CHECKSUM_LENGTH,
  316 + MODBUS_TCP_MAX_ADU_LENGTH,
  317 + _modbus_set_slave,
  318 + _modbus_tcp_build_request_basis,
  319 + _modbus_tcp_build_response_basis,
  320 + _modbus_tcp_prepare_response_tid,
  321 + _modbus_tcp_send_msg_pre,
  322 + _modbus_tcp_send,
  323 + _modbus_tcp_recv,
  324 + _modbus_tcp_check_integrity,
  325 + _modbus_tcp_connect,
  326 + _modbus_tcp_close,
  327 + _modbus_tcp_flush,
  328 + _modbus_tcp_listen,
  329 + _modbus_tcp_accept,
  330 + _modbus_tcp_filter_request
  331 +};
  332 +
  333 +
  334 +/* Allocates and initializes the modbus_t structure for TCP.
  335 + - ip : "192.168.0.5"
  336 + - port : 1099
  337 +
  338 + Set the port to MODBUS_TCP_DEFAULT_PORT to use the default one
  339 + (502). It's convenient to use a port number greater than or equal
  340 + to 1024 because it's not necessary to be root to use this port
  341 + number.
  342 +*/
  343 +modbus_t* modbus_new_tcp(const char *ip, int port)
  344 +{
  345 + modbus_t *ctx;
  346 + modbus_tcp_t *ctx_tcp;
  347 +
  348 + ctx = (modbus_t *) malloc(sizeof(modbus_t));
  349 + _modbus_init_common(ctx);
  350 +
  351 + /* Could be changed after to reach a remote serial Modbus device */
  352 + ctx->slave = MODBUS_TCP_SLAVE;
  353 +
  354 + ctx->backend = &(_modbus_tcp_backend);
  355 +
  356 + ctx->backend_data = (modbus_tcp_t *) malloc(sizeof(modbus_tcp_t));
  357 + ctx_tcp = (modbus_tcp_t *)ctx->backend_data;
  358 +
  359 + strncpy(ctx_tcp->ip, ip, sizeof(char)*16);
  360 + ctx_tcp->port = port;
  361 +
  362 + return ctx;
  363 +}
src/modbus-tcp.h 0 → 100644
  1 +/*
  2 + * Copyright © 2001-2010 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 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.
  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 Lesser Public License for more details.
  13 + *
  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/>.
  16 + */
  17 +
  18 +#ifndef _MODBUS_TCP_H_
  19 +#define _MODBUS_TCP_H_
  20 +
  21 +#define MODBUS_TCP_DEFAULT_PORT 502
  22 +#define MODBUS_TCP_SLAVE 0xFF
  23 +
  24 +/* Modbus_Application_Protocol_V1_1b.pdf Chapter 4 Section 1 Page 5
  25 + * TCP MODBUS ADU = 253 bytes + MBAP (7 bytes) = 260 bytes
  26 + */
  27 +#define MODBUS_TCP_MAX_ADU_LENGTH 260
  28 +
  29 +modbus_t* modbus_new_tcp(const char *ip_address, int port);
  30 +
  31 +#endif /* _MODBUS_TCP_H_ */
src/modbus.c
@@ -13,59 +13,30 @@ @@ -13,59 +13,30 @@
13 * 13 *
14 * You should have received a copy of the GNU Lesser Public License 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/>. 15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16 + *
  17 + *
  18 + * This library implements the Modbus protocol.
  19 + * http://libmodbus.org/
16 */ 20 */
17 21
18 -/*  
19 - The library is designed to send and receive data from a device that  
20 - communicate via the Modbus protocol.  
21 -  
22 - The function names used are inspired by the Modicon Modbus Protocol  
23 - Reference Guide which can be obtained from Schneider at  
24 - www.schneiderautomation.com.  
25 -  
26 - Documentation:  
27 - http://www.easysw.com/~mike/serial/serial.html  
28 - http://copyleft.free.fr/wordpress/index.php/libmodbus/  
29 -*/  
30 -  
31 #include <stdio.h> 22 #include <stdio.h>
32 #include <string.h> 23 #include <string.h>
33 #include <stdlib.h> 24 #include <stdlib.h>
34 -#ifdef HAVE_INTTYPES_H  
35 -#include <inttypes.h>  
36 -#endif  
37 -#ifdef HAVE_STDINT_H  
38 #include <stdint.h> 25 #include <stdint.h>
39 -#endif  
40 #include <termios.h> 26 #include <termios.h>
41 #include <unistd.h> 27 #include <unistd.h>
42 #include <errno.h> 28 #include <errno.h>
43 -#include <assert.h>  
44 #include <limits.h> 29 #include <limits.h>
45 -#include <fcntl.h>  
46 30
47 /* Add this for macros that defined unix flavor */ 31 /* Add this for macros that defined unix flavor */
48 #if (defined(__unix__) || defined(unix)) && !defined(USG) 32 #if (defined(__unix__) || defined(unix)) && !defined(USG)
49 #include <sys/param.h> 33 #include <sys/param.h>
50 #endif 34 #endif
51 35
52 -/* TCP */  
53 -#include <sys/types.h>  
54 -#include <sys/socket.h>  
55 -#include <sys/ioctl.h>  
56 -#if (defined OpenBSD) || (defined(__FreeBSD__ ) && __FreeBSD__ < 5)  
57 -#include <netinet/in_systm.h>  
58 -#endif  
59 -#include <netinet/in.h>  
60 -#include <netinet/ip.h>  
61 -#include <netinet/tcp.h>  
62 -#include <arpa/inet.h>  
63 -  
64 #if !defined(UINT16_MAX) 36 #if !defined(UINT16_MAX)
65 #define UINT16_MAX 0xFFFF 37 #define UINT16_MAX 0xFFFF
66 #endif 38 #endif
67 39
68 -#include <config.h>  
69 #include "modbus.h" 40 #include "modbus.h"
70 #include "modbus-private.h" 41 #include "modbus-private.h"
71 42
@@ -77,91 +48,8 @@ const unsigned int libmodbus_version_major = LIBMODBUS_VERSION_MAJOR; @@ -77,91 +48,8 @@ const unsigned int libmodbus_version_major = LIBMODBUS_VERSION_MAJOR;
77 const unsigned int libmodbus_version_minor = LIBMODBUS_VERSION_MINOR; 48 const unsigned int libmodbus_version_minor = LIBMODBUS_VERSION_MINOR;
78 const unsigned int libmodbus_version_micro = LIBMODBUS_VERSION_MICRO; 49 const unsigned int libmodbus_version_micro = LIBMODBUS_VERSION_MICRO;
79 50
80 -/* This structure reduces the number of params in functions and so  
81 - * optimizes the speed of execution (~ 37%). */  
82 -typedef struct {  
83 - int slave;  
84 - int function;  
85 - int t_id;  
86 -} sft_t;  
87 -  
88 -/* Table of CRC values for high-order byte */  
89 -static uint8_t table_crc_hi[] = {  
90 - 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,  
91 - 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,  
92 - 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,  
93 - 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,  
94 - 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,  
95 - 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,  
96 - 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,  
97 - 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,  
98 - 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,  
99 - 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,  
100 - 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,  
101 - 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,  
102 - 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,  
103 - 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,  
104 - 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,  
105 - 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,  
106 - 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,  
107 - 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,  
108 - 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,  
109 - 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,  
110 - 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,  
111 - 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,  
112 - 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,  
113 - 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,  
114 - 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,  
115 - 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40  
116 -};  
117 -  
118 -/* Table of CRC values for low-order byte */  
119 -static uint8_t table_crc_lo[] = {  
120 - 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,  
121 - 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,  
122 - 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,  
123 - 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,  
124 - 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,  
125 - 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,  
126 - 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,  
127 - 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,  
128 - 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,  
129 - 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,  
130 - 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,  
131 - 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,  
132 - 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,  
133 - 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,  
134 - 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,  
135 - 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,  
136 - 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,  
137 - 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,  
138 - 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,  
139 - 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,  
140 - 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,  
141 - 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,  
142 - 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,  
143 - 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,  
144 - 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,  
145 - 0x43, 0x83, 0x41, 0x81, 0x80, 0x40  
146 -};  
147 -  
148 -static const int TAB_HEADER_LENGTH[2] = {  
149 - HEADER_LENGTH_RTU,  
150 - HEADER_LENGTH_TCP  
151 -};  
152 -  
153 -static const int TAB_CHECKSUM_LENGTH[2] = {  
154 - CHECKSUM_LENGTH_RTU,  
155 - CHECKSUM_LENGTH_TCP  
156 -};  
157 -  
158 -static const int TAB_MAX_ADU_LENGTH[2] = {  
159 - MODBUS_MAX_ADU_LENGTH_RTU,  
160 - MODBUS_MAX_ADU_LENGTH_TCP,  
161 -};  
162 -  
163 -/* Max between RTU and TCP max adu length */  
164 -#define MAX_MESSAGE_LENGTH MODBUS_MAX_ADU_LENGTH_TCP 51 +/* Max between RTU and TCP max adu length (so TCP) */
  52 +#define MAX_MESSAGE_LENGTH 260
165 53
166 const char *modbus_strerror(int errnum) { 54 const char *modbus_strerror(int errnum) {
167 switch (errnum) { 55 switch (errnum) {
@@ -212,39 +100,7 @@ static void error_print(modbus_t *ctx, const char *context) @@ -212,39 +100,7 @@ static void error_print(modbus_t *ctx, const char *context)
212 100
213 int modbus_flush(modbus_t *ctx) 101 int modbus_flush(modbus_t *ctx)
214 { 102 {
215 - int rc;  
216 -  
217 - if (ctx->type_com == RTU) {  
218 - rc = tcflush(ctx->s, TCIOFLUSH);  
219 - } else {  
220 - do {  
221 - /* Extract the garbage from the socket */  
222 - char devnull[MODBUS_MAX_ADU_LENGTH_TCP];  
223 -#if (!HAVE_DECL___CYGWIN__)  
224 - rc = recv(ctx->s, devnull, MODBUS_MAX_ADU_LENGTH_TCP, MSG_DONTWAIT);  
225 -#else  
226 - /* On Cygwin, it's a bit more complicated to not wait */  
227 - fd_set rfds;  
228 - struct timeval tv;  
229 -  
230 - tv.tv_sec = 0;  
231 - tv.tv_usec = 0;  
232 - FD_ZERO(&rfds);  
233 - FD_SET(ctx->s, &rfds);  
234 - rc = select(ctx->s+1, &rfds, NULL, NULL, &tv);  
235 - if (rc == -1) {  
236 - return -1;  
237 - }  
238 -  
239 - rc = recv(ctx->s, devnull, MODBUS_MAX_ADU_LENGTH_TCP, 0);  
240 -#endif  
241 - if (ctx->debug && rc != -1) {  
242 - printf("\n%d bytes flushed\n", rc);  
243 - }  
244 - } while (rc > 0);  
245 - }  
246 -  
247 - return rc; 103 + ctx->backend->flush(ctx);
248 } 104 }
249 105
250 /* Computes the length of the expected response */ 106 /* Computes the length of the expected response */
@@ -253,26 +109,26 @@ static unsigned int compute_response_length(modbus_t *ctx, uint8_t *req) @@ -253,26 +109,26 @@ static unsigned int compute_response_length(modbus_t *ctx, uint8_t *req)
253 int length; 109 int length;
254 int offset; 110 int offset;
255 111
256 - offset = TAB_HEADER_LENGTH[ctx->type_com]; 112 + offset = ctx->backend->header_length;
257 113
258 switch (req[offset]) { 114 switch (req[offset]) {
259 - case FC_READ_COILS:  
260 - case FC_READ_DISCRETE_INPUTS: { 115 + case _FC_READ_COILS:
  116 + case _FC_READ_DISCRETE_INPUTS: {
261 /* Header + nb values (code from write_bits) */ 117 /* Header + nb values (code from write_bits) */
262 int nb = (req[offset + 3] << 8) | req[offset + 4]; 118 int nb = (req[offset + 3] << 8) | req[offset + 4];
263 length = 2 + (nb / 8) + ((nb % 8) ? 1 : 0); 119 length = 2 + (nb / 8) + ((nb % 8) ? 1 : 0);
264 } 120 }
265 break; 121 break;
266 - case FC_READ_AND_WRITE_REGISTERS:  
267 - case FC_READ_HOLDING_REGISTERS:  
268 - case FC_READ_INPUT_REGISTERS: 122 + case _FC_READ_AND_WRITE_REGISTERS:
  123 + case _FC_READ_HOLDING_REGISTERS:
  124 + case _FC_READ_INPUT_REGISTERS:
269 /* Header + 2 * nb values */ 125 /* Header + 2 * nb values */
270 length = 2 + 2 * (req[offset + 3] << 8 | req[offset + 4]); 126 length = 2 + 2 * (req[offset + 3] << 8 | req[offset + 4]);
271 break; 127 break;
272 - case FC_READ_EXCEPTION_STATUS: 128 + case _FC_READ_EXCEPTION_STATUS:
273 length = 3; 129 length = 3;
274 break; 130 break;
275 - case FC_REPORT_SLAVE_ID: 131 + case _FC_REPORT_SLAVE_ID:
276 /* The response is device specific (the header provides the 132 /* The response is device specific (the header provides the
277 length) */ 133 length) */
278 return MSG_LENGTH_UNDEFINED; 134 return MSG_LENGTH_UNDEFINED;
@@ -280,171 +136,16 @@ static unsigned int compute_response_length(modbus_t *ctx, uint8_t *req) @@ -280,171 +136,16 @@ static unsigned int compute_response_length(modbus_t *ctx, uint8_t *req)
280 length = 5; 136 length = 5;
281 } 137 }
282 138
283 - return length + offset + TAB_CHECKSUM_LENGTH[ctx->type_com]; 139 + return length + offset + ctx->backend->checksum_length;
284 } 140 }
285 141
286 -/* Builds a RTU request header */  
287 -static int build_request_basis_rtu(int slave, int function,  
288 - int addr, int nb,  
289 - uint8_t *req)  
290 -{  
291 - req[0] = slave;  
292 - req[1] = function;  
293 - req[2] = addr >> 8;  
294 - req[3] = addr & 0x00ff;  
295 - req[4] = nb >> 8;  
296 - req[5] = nb & 0x00ff;  
297 -  
298 - return PRESET_REQ_LENGTH_RTU;  
299 -}  
300 -  
301 -/* Builds a TCP request header */  
302 -static int build_request_basis_tcp(int slave, int function,  
303 - int addr, int nb,  
304 - uint8_t *req)  
305 -{  
306 -  
307 - /* Extract from MODBUS Messaging on TCP/IP Implementation Guide V1.0b  
308 - (page 23/46):  
309 - The transaction identifier is used to associate the future response  
310 - with the request. So, at a time, on a TCP connection, this identifier  
311 - must be unique. */  
312 - static uint16_t t_id = 0;  
313 -  
314 - /* Transaction ID */  
315 - if (t_id < UINT16_MAX)  
316 - t_id++;  
317 - else  
318 - t_id = 0;  
319 - req[0] = t_id >> 8;  
320 - req[1] = t_id & 0x00ff;  
321 -  
322 - /* Protocol Modbus */  
323 - req[2] = 0;  
324 - req[3] = 0;  
325 -  
326 - /* Length will be defined later by set_req_length_tcp at offsets 4  
327 - and 5 */  
328 -  
329 - req[6] = slave;  
330 - req[7] = function;  
331 - req[8] = addr >> 8;  
332 - req[9] = addr & 0x00ff;  
333 - req[10] = nb >> 8;  
334 - req[11] = nb & 0x00ff;  
335 -  
336 - return PRESET_REQ_LENGTH_TCP;  
337 -}  
338 -  
339 -static int build_request_basis(modbus_t *ctx, int function, int addr,  
340 - int nb, uint8_t *req)  
341 -{  
342 - if (ctx->type_com == RTU)  
343 - return build_request_basis_rtu(ctx->slave, function, addr, nb, req);  
344 - else  
345 - return build_request_basis_tcp(ctx->slave, function, addr, nb, req);  
346 -}  
347 -  
348 -/* Builds a RTU response header */  
349 -static int build_response_basis_rtu(sft_t *sft, uint8_t *rsp)  
350 -{  
351 - rsp[0] = sft->slave;  
352 - rsp[1] = sft->function;  
353 -  
354 - return PRESET_RSP_LENGTH_RTU;  
355 -}  
356 -  
357 -/* Builds a TCP response header */  
358 -static int build_response_basis_tcp(sft_t *sft, uint8_t *rsp)  
359 -{  
360 - /* Extract from MODBUS Messaging on TCP/IP Implementation  
361 - Guide V1.0b (page 23/46):  
362 - The transaction identifier is used to associate the future  
363 - response with the request. */  
364 - rsp[0] = sft->t_id >> 8;  
365 - rsp[1] = sft->t_id & 0x00ff;  
366 -  
367 - /* Protocol Modbus */  
368 - rsp[2] = 0;  
369 - rsp[3] = 0;  
370 -  
371 - /* Length will be set later by send_msg (4 and 5) */  
372 -  
373 - rsp[6] = 0xFF;  
374 - rsp[7] = sft->function;  
375 -  
376 - return PRESET_RSP_LENGTH_TCP;  
377 -}  
378 -  
379 -static int build_response_basis(modbus_t *ctx, sft_t *sft, uint8_t *rsp)  
380 -{  
381 - if (ctx->type_com == RTU)  
382 - return build_response_basis_rtu(sft, rsp);  
383 - else  
384 - return build_response_basis_tcp(sft, rsp);  
385 -}  
386 -  
387 -/* Fast CRC */  
388 -static uint16_t crc16(uint8_t *buffer, uint16_t buffer_length)  
389 -{  
390 - uint8_t crc_hi = 0xFF; /* high CRC byte initialized */  
391 - uint8_t crc_lo = 0xFF; /* low CRC byte initialized */  
392 - unsigned int i; /* will index into CRC lookup */  
393 -  
394 - /* pass through message buffer */  
395 - while (buffer_length--) {  
396 - i = crc_hi ^ *buffer++; /* calculate the CRC */  
397 - crc_hi = crc_lo ^ table_crc_hi[i];  
398 - crc_lo = table_crc_lo[i];  
399 - }  
400 -  
401 - return (crc_hi << 8 | crc_lo);  
402 -}  
403 -  
404 -/* The check_crc16 function shall return the message length if the CRC is  
405 - valid. Otherwise it shall return -1 and set errno to EMBADCRC. */  
406 -static int check_crc16(modbus_t *ctx, uint8_t *msg, const int msg_length)  
407 -{  
408 - uint16_t crc_calculated;  
409 - uint16_t crc_received;  
410 -  
411 - crc_calculated = crc16(msg, msg_length - 2);  
412 - crc_received = (msg[msg_length - 2] << 8) | msg[msg_length - 1];  
413 -  
414 - /* Check CRC of msg */  
415 - if (crc_calculated == crc_received) {  
416 - return msg_length;  
417 - } else {  
418 - if (ctx->debug) {  
419 - fprintf(stderr, "ERROR CRC received %0X != CRC calculated %0X\n",  
420 - crc_received, crc_calculated);  
421 - }  
422 - if (ctx->error_recovery) {  
423 - modbus_flush(ctx);  
424 - }  
425 - errno = EMBBADCRC;  
426 - return -1;  
427 - }  
428 -}  
429 -  
430 -/* Sends a req/response over a serial or a TCP communication */ 142 +/* Sends a request/response */
431 static int send_msg(modbus_t *ctx, uint8_t *req, int req_length) 143 static int send_msg(modbus_t *ctx, uint8_t *req, int req_length)
432 { 144 {
433 int rc; 145 int rc;
434 - uint16_t s_crc;  
435 int i; 146 int i;
436 147
437 - if (ctx->type_com == RTU) {  
438 - s_crc = crc16(req, req_length);  
439 - req[req_length++] = s_crc >> 8;  
440 - req[req_length++] = s_crc & 0x00FF;  
441 - } else {  
442 - /* Substract the header length to the message length */  
443 - int mbap_length = req_length - 6;  
444 -  
445 - req[4] = mbap_length >> 8;  
446 - req[5] = mbap_length & 0x00FF;  
447 - } 148 + req_length = ctx->backend->send_msg_pre(req, req_length);
448 149
449 if (ctx->debug) { 150 if (ctx->debug) {
450 for (i = 0; i < req_length; i++) 151 for (i = 0; i < req_length; i++)
@@ -455,15 +156,7 @@ static int send_msg(modbus_t *ctx, uint8_t *req, int req_length) @@ -455,15 +156,7 @@ static int send_msg(modbus_t *ctx, uint8_t *req, int req_length)
455 /* In recovery mode, the write command will be issued until to be 156 /* In recovery mode, the write command will be issued until to be
456 successful! Disabled by default. */ 157 successful! Disabled by default. */
457 do { 158 do {
458 - if (ctx->type_com == RTU)  
459 - rc = write(ctx->s, req, req_length);  
460 - else  
461 - /* MSG_NOSIGNAL  
462 - Requests not to send SIGPIPE on errors on stream oriented  
463 - sockets when the other end breaks the connection. The EPIPE  
464 - error is still returned. */  
465 - rc = send(ctx->s, req, req_length, MSG_NOSIGNAL);  
466 - 159 + rc = ctx->backend->send(ctx->s, req, req_length);
467 if (rc == -1) { 160 if (rc == -1) {
468 error_print(ctx, NULL); 161 error_print(ctx, NULL);
469 if (ctx->error_recovery && 162 if (ctx->error_recovery &&
@@ -501,20 +194,20 @@ static uint8_t compute_header_length(int function, msg_type_t msg_type) @@ -501,20 +194,20 @@ static uint8_t compute_header_length(int function, msg_type_t msg_type)
501 int length; 194 int length;
502 195
503 if (msg_type == MSG_CONFIRMATION) { 196 if (msg_type == MSG_CONFIRMATION) {
504 - if (function == FC_REPORT_SLAVE_ID) { 197 + if (function == _FC_REPORT_SLAVE_ID) {
505 length = 1; 198 length = 1;
506 } else { 199 } else {
507 /* Should never happen, the other header lengths are precomputed */ 200 /* Should never happen, the other header lengths are precomputed */
508 abort(); 201 abort();
509 } 202 }
510 } else /* MSG_INDICATION */ { 203 } else /* MSG_INDICATION */ {
511 - if (function <= FC_WRITE_SINGLE_COIL ||  
512 - function == FC_WRITE_SINGLE_REGISTER) { 204 + if (function <= _FC_WRITE_SINGLE_COIL ||
  205 + function == _FC_WRITE_SINGLE_REGISTER) {
513 length = 4; 206 length = 4;
514 - } else if (function == FC_WRITE_MULTIPLE_COILS ||  
515 - function == FC_WRITE_MULTIPLE_REGISTERS) { 207 + } else if (function == _FC_WRITE_MULTIPLE_COILS ||
  208 + function == _FC_WRITE_MULTIPLE_REGISTERS) {
516 length = 5; 209 length = 5;
517 - } else if (function == FC_READ_AND_WRITE_REGISTERS) { 210 + } else if (function == _FC_READ_AND_WRITE_REGISTERS) {
518 length = 9; 211 length = 9;
519 } else { 212 } else {
520 length = 0; 213 length = 0;
@@ -526,63 +219,62 @@ static uint8_t compute_header_length(int function, msg_type_t msg_type) @@ -526,63 +219,62 @@ static uint8_t compute_header_length(int function, msg_type_t msg_type)
526 /* Computes the length of the data to write in the request */ 219 /* Computes the length of the data to write in the request */
527 static int compute_data_length(modbus_t *ctx, uint8_t *msg) 220 static int compute_data_length(modbus_t *ctx, uint8_t *msg)
528 { 221 {
529 - int function = msg[TAB_HEADER_LENGTH[ctx->type_com]]; 222 + int function = msg[ctx->backend->header_length];
530 int length; 223 int length;
531 224
532 - if (function == FC_WRITE_MULTIPLE_COILS ||  
533 - function == FC_WRITE_MULTIPLE_REGISTERS) {  
534 - length = msg[TAB_HEADER_LENGTH[ctx->type_com] + 5];  
535 - } else if (function == FC_REPORT_SLAVE_ID) {  
536 - length = msg[TAB_HEADER_LENGTH[ctx->type_com] + 1];  
537 - } else if (function == FC_READ_AND_WRITE_REGISTERS) {  
538 - length = msg[TAB_HEADER_LENGTH[ctx->type_com] + 9]; 225 + if (function == _FC_WRITE_MULTIPLE_COILS ||
  226 + function == _FC_WRITE_MULTIPLE_REGISTERS) {
  227 + length = msg[ctx->backend->header_length + 5];
  228 + } else if (function == _FC_REPORT_SLAVE_ID) {
  229 + length = msg[ctx->backend->header_length + 1];
  230 + } else if (function == _FC_READ_AND_WRITE_REGISTERS) {
  231 + length = msg[ctx->backend->header_length + 9];
539 } else 232 } else
540 length = 0; 233 length = 0;
541 234
542 - length += TAB_CHECKSUM_LENGTH[ctx->type_com]; 235 + length += ctx->backend->checksum_length;
543 236
544 return length; 237 return length;
545 } 238 }
546 239
547 #define WAIT_DATA() { \ 240 #define WAIT_DATA() { \
548 - while ((s_rc = select(ctx->s+1, &rfds, NULL, NULL, &tv)) == -1) { \  
549 - if (errno == EINTR) { \  
550 - if (ctx->debug) { \  
551 - fprintf(stderr, \  
552 - "A non blocked signal was caught\n"); \  
553 - } \  
554 - /* Necessary after an error */ \  
555 - FD_ZERO(&rfds); \  
556 - FD_SET(ctx->s, &rfds); \ 241 + while ((s_rc = select(ctx->s+1, &rfds, NULL, NULL, &tv)) == -1) { \
  242 + if (errno == EINTR) { \
  243 + if (ctx->debug) { \
  244 + fprintf(stderr, "A non blocked signal was caught\n"); \
  245 + } \
  246 + /* Necessary after an error */ \
  247 + FD_ZERO(&rfds); \
  248 + FD_SET(ctx->s, &rfds); \
  249 + } else { \
  250 + error_print(ctx, "select"); \
  251 + if (ctx->error_recovery && (errno == EBADF)) { \
  252 + modbus_close(ctx); \
  253 + modbus_connect(ctx); \
  254 + errno = EBADF; \
  255 + return -1; \
557 } else { \ 256 } else { \
558 - error_print(ctx, "select"); \  
559 - if (ctx->error_recovery && (errno == EBADF)) { \  
560 - modbus_close(ctx); \  
561 - modbus_connect(ctx); \  
562 - errno = EBADF; \  
563 - return -1; \  
564 - } else { \  
565 - return -1; \  
566 - } \ 257 + return -1; \
567 } \ 258 } \
568 } \ 259 } \
  260 + } \
569 \ 261 \
570 - if (s_rc == 0) { \  
571 - /* Timeout */ \  
572 - if (msg_length == (TAB_HEADER_LENGTH[ctx->type_com] + 2 + \  
573 - TAB_CHECKSUM_LENGTH[ctx->type_com])) { \  
574 - /* Optimization allowed because exception response is \  
575 - the smallest trame in modbus protocol (3) so always \  
576 - raise a timeout error. \  
577 - Temporary error before exception analyze. */ \  
578 - errno = EMBUNKEXC; \  
579 - } else { \  
580 - errno = ETIMEDOUT; \  
581 - error_print(ctx, "select"); \  
582 - } \  
583 - return -1; \ 262 + if (s_rc == 0) { \
  263 + /* Timeout */ \
  264 + if (msg_length == (ctx->backend->header_length + 2 + \
  265 + ctx->backend->checksum_length)) { \
  266 + /* Optimization allowed because exception response is \
  267 + the smallest trame in modbus protocol (3) so always \
  268 + raise a timeout error. \
  269 + Temporary error before exception analyze. */ \
  270 + errno = EMBUNKEXC; \
  271 + } else { \
  272 + errno = ETIMEDOUT; \
  273 + error_print(ctx, "select"); \
584 } \ 274 } \
585 - } 275 + return -1; \
  276 + } \
  277 +}
586 278
587 /* Waits a response from a modbus server or a request from a modbus client. 279 /* Waits a response from a modbus server or a request from a modbus client.
588 This function blocks if there is no replies (3 timeouts). 280 This function blocks if there is no replies (3 timeouts).
@@ -640,7 +332,7 @@ static int receive_msg(modbus_t *ctx, int msg_length_computed, @@ -640,7 +332,7 @@ static int receive_msg(modbus_t *ctx, int msg_length_computed,
640 * reach the function code because all packets contains this 332 * reach the function code because all packets contains this
641 * information. */ 333 * information. */
642 state = FUNCTION; 334 state = FUNCTION;
643 - msg_length_computed = TAB_HEADER_LENGTH[ctx->type_com] + 1; 335 + msg_length_computed = ctx->backend->header_length + 1;
644 } else { 336 } else {
645 tv.tv_sec = ctx->timeout_begin.tv_sec; 337 tv.tv_sec = ctx->timeout_begin.tv_sec;
646 tv.tv_usec = ctx->timeout_begin.tv_usec; 338 tv.tv_usec = ctx->timeout_begin.tv_usec;
@@ -654,11 +346,7 @@ static int receive_msg(modbus_t *ctx, int msg_length_computed, @@ -654,11 +346,7 @@ static int receive_msg(modbus_t *ctx, int msg_length_computed,
654 346
655 p_msg = msg; 347 p_msg = msg;
656 while (s_rc) { 348 while (s_rc) {
657 - if (ctx->type_com == RTU)  
658 - read_rc = read(ctx->s, p_msg, length_to_read);  
659 - else  
660 - read_rc = recv(ctx->s, p_msg, length_to_read, 0);  
661 - 349 + read_rc = ctx->backend->recv(ctx->s, p_msg, length_to_read);
662 if (read_rc == 0) { 350 if (read_rc == 0) {
663 errno = ECONNRESET; 351 errno = ECONNRESET;
664 read_rc = -1; 352 read_rc = -1;
@@ -695,7 +383,7 @@ static int receive_msg(modbus_t *ctx, int msg_length_computed, @@ -695,7 +383,7 @@ static int receive_msg(modbus_t *ctx, int msg_length_computed,
695 case FUNCTION: 383 case FUNCTION:
696 /* Function code position */ 384 /* Function code position */
697 length_to_read = compute_header_length( 385 length_to_read = compute_header_length(
698 - msg[TAB_HEADER_LENGTH[ctx->type_com]], 386 + msg[ctx->backend->header_length],
699 msg_type); 387 msg_type);
700 msg_length_computed += length_to_read; 388 msg_length_computed += length_to_read;
701 /* It's useless to check the value of 389 /* It's useless to check the value of
@@ -706,7 +394,7 @@ static int receive_msg(modbus_t *ctx, int msg_length_computed, @@ -706,7 +394,7 @@ static int receive_msg(modbus_t *ctx, int msg_length_computed,
706 case DATA: 394 case DATA:
707 length_to_read = compute_data_length(ctx, msg); 395 length_to_read = compute_data_length(ctx, msg);
708 msg_length_computed += length_to_read; 396 msg_length_computed += length_to_read;
709 - if (msg_length_computed > TAB_MAX_ADU_LENGTH[ctx->type_com]) { 397 + if (msg_length_computed > ctx->backend->max_adu_length) {
710 errno = EMBBADDATA; 398 errno = EMBBADDATA;
711 error_print(ctx, "too many data"); 399 error_print(ctx, "too many data");
712 return -1; 400 return -1;
@@ -738,14 +426,7 @@ static int receive_msg(modbus_t *ctx, int msg_length_computed, @@ -738,14 +426,7 @@ static int receive_msg(modbus_t *ctx, int msg_length_computed,
738 if (ctx->debug) 426 if (ctx->debug)
739 printf("\n"); 427 printf("\n");
740 428
741 - if (ctx->type_com == RTU) {  
742 - /* Returns msg_length on success and a negative value on  
743 - failure */  
744 - return check_crc16(ctx, msg, msg_length);  
745 - } else {  
746 - /* OK */  
747 - return msg_length;  
748 - } 429 + return ctx->backend->check_integrity(ctx, msg, msg_length);
749 } 430 }
750 431
751 /* Receive the request from a modbus master, requires the socket file descriptor 432 /* Receive the request from a modbus master, requires the socket file descriptor
@@ -764,7 +445,7 @@ int modbus_receive(modbus_t *ctx, int sockfd, uint8_t *req) @@ -764,7 +445,7 @@ int modbus_receive(modbus_t *ctx, int sockfd, uint8_t *req)
764 return receive_msg(ctx, MSG_LENGTH_UNDEFINED, req, MSG_INDICATION); 445 return receive_msg(ctx, MSG_LENGTH_UNDEFINED, req, MSG_INDICATION);
765 } 446 }
766 447
767 -/* Receives the response and checks values (and checksum in RTU). 448 +/* Receives the response and checks values.
768 449
769 The function shall return the number of values (bits or words) and the 450 The function shall return the number of values (bits or words) and the
770 response if successful. Otherwise, its shall return -1 and errno is set. 451 response if successful. Otherwise, its shall return -1 and errno is set.
@@ -775,7 +456,7 @@ static int receive_msg_req(modbus_t *ctx, uint8_t *req, uint8_t *rsp) @@ -775,7 +456,7 @@ static int receive_msg_req(modbus_t *ctx, uint8_t *req, uint8_t *rsp)
775 { 456 {
776 int rc; 457 int rc;
777 int rsp_length_computed; 458 int rsp_length_computed;
778 - int offset = TAB_HEADER_LENGTH[ctx->type_com]; 459 + int offset = ctx->backend->header_length;
779 460
780 rsp_length_computed = compute_response_length(ctx, req); 461 rsp_length_computed = compute_response_length(ctx, req);
781 rc = receive_msg(ctx, rsp_length_computed, rsp, MSG_CONFIRMATION); 462 rc = receive_msg(ctx, rsp_length_computed, rsp, MSG_CONFIRMATION);
@@ -787,8 +468,8 @@ static int receive_msg_req(modbus_t *ctx, uint8_t *req, uint8_t *rsp) @@ -787,8 +468,8 @@ static int receive_msg_req(modbus_t *ctx, uint8_t *req, uint8_t *rsp)
787 /* The number of values is returned if it's corresponding 468 /* The number of values is returned if it's corresponding
788 * to the request */ 469 * to the request */
789 switch (rsp[offset]) { 470 switch (rsp[offset]) {
790 - case FC_READ_COILS:  
791 - case FC_READ_DISCRETE_INPUTS: 471 + case _FC_READ_COILS:
  472 + case _FC_READ_DISCRETE_INPUTS:
792 /* Read functions, 8 values in a byte (nb 473 /* Read functions, 8 values in a byte (nb
793 * of values in the request and byte count in 474 * of values in the request and byte count in
794 * the response. */ 475 * the response. */
@@ -796,20 +477,20 @@ static int receive_msg_req(modbus_t *ctx, uint8_t *req, uint8_t *rsp) @@ -796,20 +477,20 @@ static int receive_msg_req(modbus_t *ctx, uint8_t *req, uint8_t *rsp)
796 req_nb_value = (req_nb_value / 8) + ((req_nb_value % 8) ? 1 : 0); 477 req_nb_value = (req_nb_value / 8) + ((req_nb_value % 8) ? 1 : 0);
797 rsp_nb_value = rsp[offset + 1]; 478 rsp_nb_value = rsp[offset + 1];
798 break; 479 break;
799 - case FC_READ_AND_WRITE_REGISTERS:  
800 - case FC_READ_HOLDING_REGISTERS:  
801 - case FC_READ_INPUT_REGISTERS: 480 + case _FC_READ_AND_WRITE_REGISTERS:
  481 + case _FC_READ_HOLDING_REGISTERS:
  482 + case _FC_READ_INPUT_REGISTERS:
802 /* Read functions 1 value = 2 bytes */ 483 /* Read functions 1 value = 2 bytes */
803 req_nb_value = (req[offset + 3] << 8) + req[offset + 4]; 484 req_nb_value = (req[offset + 3] << 8) + req[offset + 4];
804 rsp_nb_value = (rsp[offset + 1] / 2); 485 rsp_nb_value = (rsp[offset + 1] / 2);
805 break; 486 break;
806 - case FC_WRITE_MULTIPLE_COILS:  
807 - case FC_WRITE_MULTIPLE_REGISTERS: 487 + case _FC_WRITE_MULTIPLE_COILS:
  488 + case _FC_WRITE_MULTIPLE_REGISTERS:
808 /* N Write functions */ 489 /* N Write functions */
809 req_nb_value = (req[offset + 3] << 8) + req[offset + 4]; 490 req_nb_value = (req[offset + 3] << 8) + req[offset + 4];
810 rsp_nb_value = (rsp[offset + 3] << 8) | rsp[offset + 4]; 491 rsp_nb_value = (rsp[offset + 3] << 8) | rsp[offset + 4];
811 break; 492 break;
812 - case FC_REPORT_SLAVE_ID: 493 + case _FC_REPORT_SLAVE_ID:
813 /* Report slave ID (bytes received) */ 494 /* Report slave ID (bytes received) */
814 req_nb_value = rsp_nb_value = rsp[offset + 1]; 495 req_nb_value = rsp_nb_value = rsp[offset + 1];
815 break; 496 break;
@@ -833,11 +514,10 @@ static int receive_msg_req(modbus_t *ctx, uint8_t *req, uint8_t *rsp) @@ -833,11 +514,10 @@ static int receive_msg_req(modbus_t *ctx, uint8_t *req, uint8_t *rsp)
833 /* EXCEPTION CODE RECEIVED */ 514 /* EXCEPTION CODE RECEIVED */
834 515
835 /* CRC must be checked here (not done in receive_msg) */ 516 /* CRC must be checked here (not done in receive_msg) */
836 - if (ctx->type_com == RTU) {  
837 - rc = check_crc16(ctx, rsp, EXCEPTION_RSP_LENGTH_RTU);  
838 - if (rc == -1)  
839 - return -1;  
840 - } 517 + rc = ctx->backend->check_integrity(ctx, rsp,
  518 + _MODBUS_EXCEPTION_RSP_LENGTH);
  519 + if (rc == -1)
  520 + return -1;
841 521
842 /* Check for exception response. 522 /* Check for exception response.
843 0x80 + function is stored in the exception 523 0x80 + function is stored in the exception
@@ -889,7 +569,7 @@ static int response_exception(modbus_t *ctx, sft_t *sft, @@ -889,7 +569,7 @@ static int response_exception(modbus_t *ctx, sft_t *sft,
889 int rsp_length; 569 int rsp_length;
890 570
891 sft->function = sft->function + 0x80; 571 sft->function = sft->function + 0x80;
892 - rsp_length = build_response_basis(ctx, sft, rsp); 572 + rsp_length = ctx->backend->build_response_basis(sft, rsp);
893 573
894 /* Positive exception code */ 574 /* Positive exception code */
895 rsp[rsp_length++] = exception_code; 575 rsp[rsp_length++] = exception_code;
@@ -906,7 +586,7 @@ static int response_exception(modbus_t *ctx, sft_t *sft, @@ -906,7 +586,7 @@ static int response_exception(modbus_t *ctx, sft_t *sft,
906 int modbus_reply(modbus_t *ctx, const uint8_t *req, 586 int modbus_reply(modbus_t *ctx, const uint8_t *req,
907 int req_length, modbus_mapping_t *mb_mapping) 587 int req_length, modbus_mapping_t *mb_mapping)
908 { 588 {
909 - int offset = TAB_HEADER_LENGTH[ctx->type_com]; 589 + int offset = ctx->backend->header_length;
910 int slave = req[offset - 1]; 590 int slave = req[offset - 1];
911 int function = req[offset]; 591 int function = req[offset];
912 uint16_t address = (req[offset + 1] << 8) + req[offset + 2]; 592 uint16_t address = (req[offset + 1] << 8) + req[offset + 2];
@@ -914,28 +594,17 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -914,28 +594,17 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
914 int rsp_length = 0; 594 int rsp_length = 0;
915 sft_t sft; 595 sft_t sft;
916 596
917 - /* Filter on the Modbus unit identifier (slave) in RTU mode */  
918 - if (ctx->type_com == RTU &&  
919 - slave != ctx->slave && slave != MODBUS_BROADCAST_ADDRESS) {  
920 - /* Ignores the request (not for me) */  
921 - if (ctx->debug) {  
922 - printf("Request for slave %d ignored (not %d)\n",  
923 - slave, ctx->slave);  
924 - } 597 + if (ctx->backend->filter_request(ctx, slave) == 1) {
  598 + /* Filtered */
925 return 0; 599 return 0;
926 } 600 }
927 601
928 sft.slave = slave; 602 sft.slave = slave;
929 sft.function = function; 603 sft.function = function;
930 - if (ctx->type_com == TCP) {  
931 - sft.t_id = (req[0] << 8) + req[1];  
932 - } else {  
933 - sft.t_id = 0;  
934 - req_length -= CHECKSUM_LENGTH_RTU;  
935 - } 604 + sft.t_id = ctx->backend->prepare_response_tid(req, &req_length);
936 605
937 switch (function) { 606 switch (function) {
938 - case FC_READ_COILS: { 607 + case _FC_READ_COILS: {
939 int nb = (req[offset + 3] << 8) + req[offset + 4]; 608 int nb = (req[offset + 3] << 8) + req[offset + 4];
940 609
941 if ((address + nb) > mb_mapping->nb_bits) { 610 if ((address + nb) > mb_mapping->nb_bits) {
@@ -947,7 +616,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -947,7 +616,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
947 ctx, &sft, 616 ctx, &sft,
948 MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp); 617 MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp);
949 } else { 618 } else {
950 - rsp_length = build_response_basis(ctx, &sft, rsp); 619 + rsp_length = ctx->backend->build_response_basis(&sft, rsp);
951 rsp[rsp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0); 620 rsp[rsp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0);
952 rsp_length = response_io_status(address, nb, 621 rsp_length = response_io_status(address, nb,
953 mb_mapping->tab_bits, 622 mb_mapping->tab_bits,
@@ -955,7 +624,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -955,7 +624,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
955 } 624 }
956 } 625 }
957 break; 626 break;
958 - case FC_READ_DISCRETE_INPUTS: { 627 + case _FC_READ_DISCRETE_INPUTS: {
959 /* Similar to coil status (but too many arguments to use a 628 /* Similar to coil status (but too many arguments to use a
960 * function) */ 629 * function) */
961 int nb = (req[offset + 3] << 8) + req[offset + 4]; 630 int nb = (req[offset + 3] << 8) + req[offset + 4];
@@ -969,7 +638,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -969,7 +638,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
969 ctx, &sft, 638 ctx, &sft,
970 MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp); 639 MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp);
971 } else { 640 } else {
972 - rsp_length = build_response_basis(ctx, &sft, rsp); 641 + rsp_length = ctx->backend->build_response_basis(&sft, rsp);
973 rsp[rsp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0); 642 rsp[rsp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0);
974 rsp_length = response_io_status(address, nb, 643 rsp_length = response_io_status(address, nb,
975 mb_mapping->tab_input_bits, 644 mb_mapping->tab_input_bits,
@@ -977,7 +646,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -977,7 +646,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
977 } 646 }
978 } 647 }
979 break; 648 break;
980 - case FC_READ_HOLDING_REGISTERS: { 649 + case _FC_READ_HOLDING_REGISTERS: {
981 int nb = (req[offset + 3] << 8) + req[offset + 4]; 650 int nb = (req[offset + 3] << 8) + req[offset + 4];
982 651
983 if ((address + nb) > mb_mapping->nb_registers) { 652 if ((address + nb) > mb_mapping->nb_registers) {
@@ -991,7 +660,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -991,7 +660,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
991 } else { 660 } else {
992 int i; 661 int i;
993 662
994 - rsp_length = build_response_basis(ctx, &sft, rsp); 663 + rsp_length = ctx->backend->build_response_basis(&sft, rsp);
995 rsp[rsp_length++] = nb << 1; 664 rsp[rsp_length++] = nb << 1;
996 for (i = address; i < address + nb; i++) { 665 for (i = address; i < address + nb; i++) {
997 rsp[rsp_length++] = mb_mapping->tab_registers[i] >> 8; 666 rsp[rsp_length++] = mb_mapping->tab_registers[i] >> 8;
@@ -1000,7 +669,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -1000,7 +669,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
1000 } 669 }
1001 } 670 }
1002 break; 671 break;
1003 - case FC_READ_INPUT_REGISTERS: { 672 + case _FC_READ_INPUT_REGISTERS: {
1004 /* Similar to holding registers (but too many arguments to use a 673 /* Similar to holding registers (but too many arguments to use a
1005 * function) */ 674 * function) */
1006 int nb = (req[offset + 3] << 8) + req[offset + 4]; 675 int nb = (req[offset + 3] << 8) + req[offset + 4];
@@ -1016,7 +685,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -1016,7 +685,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
1016 } else { 685 } else {
1017 int i; 686 int i;
1018 687
1019 - rsp_length = build_response_basis(ctx, &sft, rsp); 688 + rsp_length = ctx->backend->build_response_basis(&sft, rsp);
1020 rsp[rsp_length++] = nb << 1; 689 rsp[rsp_length++] = nb << 1;
1021 for (i = address; i < address + nb; i++) { 690 for (i = address; i < address + nb; i++) {
1022 rsp[rsp_length++] = mb_mapping->tab_input_registers[i] >> 8; 691 rsp[rsp_length++] = mb_mapping->tab_input_registers[i] >> 8;
@@ -1025,7 +694,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -1025,7 +694,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
1025 } 694 }
1026 } 695 }
1027 break; 696 break;
1028 - case FC_WRITE_SINGLE_COIL: 697 + case _FC_WRITE_SINGLE_COIL:
1029 if (address >= mb_mapping->nb_bits) { 698 if (address >= mb_mapping->nb_bits) {
1030 if (ctx->debug) { 699 if (ctx->debug) {
1031 fprintf(stderr, "Illegal data address %0X in write_bit\n", 700 fprintf(stderr, "Illegal data address %0X in write_bit\n",
@@ -1039,11 +708,6 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -1039,11 +708,6 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
1039 708
1040 if (data == 0xFF00 || data == 0x0) { 709 if (data == 0xFF00 || data == 0x0) {
1041 mb_mapping->tab_bits[address] = (data) ? ON : OFF; 710 mb_mapping->tab_bits[address] = (data) ? ON : OFF;
1042 -  
1043 - /* In RTU mode, the CRC is computed and added  
1044 - to the request by send_msg, the computed  
1045 - CRC will be same and optimisation is  
1046 - possible here (FIXME). */  
1047 memcpy(rsp, req, req_length); 711 memcpy(rsp, req, req_length);
1048 rsp_length = req_length; 712 rsp_length = req_length;
1049 } else { 713 } else {
@@ -1058,7 +722,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -1058,7 +722,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
1058 } 722 }
1059 } 723 }
1060 break; 724 break;
1061 - case FC_WRITE_SINGLE_REGISTER: 725 + case _FC_WRITE_SINGLE_REGISTER:
1062 if (address >= mb_mapping->nb_registers) { 726 if (address >= mb_mapping->nb_registers) {
1063 if (ctx->debug) { 727 if (ctx->debug) {
1064 fprintf(stderr, "Illegal data address %0X in write_register\n", 728 fprintf(stderr, "Illegal data address %0X in write_register\n",
@@ -1075,7 +739,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -1075,7 +739,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
1075 rsp_length = req_length; 739 rsp_length = req_length;
1076 } 740 }
1077 break; 741 break;
1078 - case FC_WRITE_MULTIPLE_COILS: { 742 + case _FC_WRITE_MULTIPLE_COILS: {
1079 int nb = (req[offset + 3] << 8) + req[offset + 4]; 743 int nb = (req[offset + 3] << 8) + req[offset + 4];
1080 744
1081 if ((address + nb) > mb_mapping->nb_bits) { 745 if ((address + nb) > mb_mapping->nb_bits) {
@@ -1090,14 +754,14 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -1090,14 +754,14 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
1090 /* 6 = byte count */ 754 /* 6 = byte count */
1091 modbus_set_bits_from_bytes(mb_mapping->tab_bits, address, nb, &req[offset + 6]); 755 modbus_set_bits_from_bytes(mb_mapping->tab_bits, address, nb, &req[offset + 6]);
1092 756
1093 - rsp_length = build_response_basis(ctx, &sft, rsp); 757 + rsp_length = ctx->backend->build_response_basis(&sft, rsp);
1094 /* 4 to copy the bit address (2) and the quantity of bits */ 758 /* 4 to copy the bit address (2) and the quantity of bits */
1095 memcpy(rsp + rsp_length, req + rsp_length, 4); 759 memcpy(rsp + rsp_length, req + rsp_length, 4);
1096 rsp_length += 4; 760 rsp_length += 4;
1097 } 761 }
1098 } 762 }
1099 break; 763 break;
1100 - case FC_WRITE_MULTIPLE_REGISTERS: { 764 + case _FC_WRITE_MULTIPLE_REGISTERS: {
1101 int nb = (req[offset + 3] << 8) + req[offset + 4]; 765 int nb = (req[offset + 3] << 8) + req[offset + 4];
1102 766
1103 if ((address + nb) > mb_mapping->nb_registers) { 767 if ((address + nb) > mb_mapping->nb_registers) {
@@ -1116,22 +780,22 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -1116,22 +780,22 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
1116 (req[offset + j] << 8) + req[offset + j + 1]; 780 (req[offset + j] << 8) + req[offset + j + 1];
1117 } 781 }
1118 782
1119 - rsp_length = build_response_basis(ctx, &sft, rsp); 783 + rsp_length = ctx->backend->build_response_basis(&sft, rsp);
1120 /* 4 to copy the address (2) and the no. of registers */ 784 /* 4 to copy the address (2) and the no. of registers */
1121 memcpy(rsp + rsp_length, req + rsp_length, 4); 785 memcpy(rsp + rsp_length, req + rsp_length, 4);
1122 rsp_length += 4; 786 rsp_length += 4;
1123 } 787 }
1124 } 788 }
1125 break; 789 break;
1126 - case FC_REPORT_SLAVE_ID:  
1127 - rsp_length = build_response_basis(ctx, &sft, rsp); 790 + case _FC_REPORT_SLAVE_ID:
  791 + rsp_length = ctx->backend->build_response_basis(&sft, rsp);
1128 /* 2 bytes */ 792 /* 2 bytes */
1129 rsp[rsp_length++] = 2; 793 rsp[rsp_length++] = 2;
1130 rsp[rsp_length++] = ctx->slave; 794 rsp[rsp_length++] = ctx->slave;
1131 /* Slave is ON */ 795 /* Slave is ON */
1132 rsp[rsp_length++] = 0xFF; 796 rsp[rsp_length++] = 0xFF;
1133 break; 797 break;
1134 - case FC_READ_EXCEPTION_STATUS: 798 + case _FC_READ_EXCEPTION_STATUS:
1135 if (ctx->debug) { 799 if (ctx->debug) {
1136 fprintf(stderr, "FIXME Not implemented\n"); 800 fprintf(stderr, "FIXME Not implemented\n");
1137 } 801 }
@@ -1139,7 +803,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -1139,7 +803,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
1139 return -1; 803 return -1;
1140 break; 804 break;
1141 805
1142 - case FC_READ_AND_WRITE_REGISTERS: { 806 + case _FC_READ_AND_WRITE_REGISTERS: {
1143 int nb = (req[offset + 3] << 8) + req[offset + 4]; 807 int nb = (req[offset + 3] << 8) + req[offset + 4];
1144 uint16_t address_write = (req[offset + 5] << 8) + req[offset + 6]; 808 uint16_t address_write = (req[offset + 5] << 8) + req[offset + 6];
1145 int nb_write = (req[offset + 7] << 8) + req[offset + 8]; 809 int nb_write = (req[offset + 7] << 8) + req[offset + 8];
@@ -1155,7 +819,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -1155,7 +819,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
1155 MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp); 819 MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp);
1156 } else { 820 } else {
1157 int i, j; 821 int i, j;
1158 - rsp_length = build_response_basis(ctx, &sft, rsp); 822 + rsp_length = ctx->backend->build_response_basis(&sft, rsp);
1159 rsp[rsp_length++] = nb << 1; 823 rsp[rsp_length++] = nb << 1;
1160 824
1161 for (i = address; i < address + nb; i++) { 825 for (i = address; i < address + nb; i++) {
@@ -1189,10 +853,10 @@ static int read_io_status(modbus_t *ctx, int function, @@ -1189,10 +853,10 @@ static int read_io_status(modbus_t *ctx, int function,
1189 int rc; 853 int rc;
1190 int req_length; 854 int req_length;
1191 855
1192 - uint8_t req[MIN_REQ_LENGTH]; 856 + uint8_t req[_MIN_REQ_LENGTH];
1193 uint8_t rsp[MAX_MESSAGE_LENGTH]; 857 uint8_t rsp[MAX_MESSAGE_LENGTH];
1194 858
1195 - req_length = build_request_basis(ctx, function, addr, nb, req); 859 + req_length = ctx->backend->build_request_basis(ctx, function, addr, nb, req);
1196 860
1197 rc = send_msg(ctx, req, req_length); 861 rc = send_msg(ctx, req, req_length);
1198 if (rc > 0) { 862 if (rc > 0) {
@@ -1205,7 +869,7 @@ static int read_io_status(modbus_t *ctx, int function, @@ -1205,7 +869,7 @@ static int read_io_status(modbus_t *ctx, int function,
1205 if (rc == -1) 869 if (rc == -1)
1206 return -1; 870 return -1;
1207 871
1208 - offset = TAB_HEADER_LENGTH[ctx->type_com] + 2; 872 + offset = ctx->backend->header_length + 2;
1209 offset_end = offset + rc; 873 offset_end = offset + rc;
1210 for (i = offset; i < offset_end; i++) { 874 for (i = offset; i < offset_end; i++) {
1211 /* Shift reg hi_byte to temp */ 875 /* Shift reg hi_byte to temp */
@@ -1238,7 +902,7 @@ int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *data_dest) @@ -1238,7 +902,7 @@ int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *data_dest)
1238 return -1; 902 return -1;
1239 } 903 }
1240 904
1241 - rc = read_io_status(ctx, FC_READ_COILS, addr, nb, data_dest); 905 + rc = read_io_status(ctx, _FC_READ_COILS, addr, nb, data_dest);
1242 906
1243 if (rc == -1) 907 if (rc == -1)
1244 return -1; 908 return -1;
@@ -1262,7 +926,7 @@ int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *data_dest) @@ -1262,7 +926,7 @@ int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *data_dest)
1262 return -1; 926 return -1;
1263 } 927 }
1264 928
1265 - rc = read_io_status(ctx, FC_READ_DISCRETE_INPUTS, addr, nb, data_dest); 929 + rc = read_io_status(ctx, _FC_READ_DISCRETE_INPUTS, addr, nb, data_dest);
1266 930
1267 if (rc == -1) 931 if (rc == -1)
1268 return -1; 932 return -1;
@@ -1276,7 +940,7 @@ static int read_registers(modbus_t *ctx, int function, int addr, int nb, @@ -1276,7 +940,7 @@ static int read_registers(modbus_t *ctx, int function, int addr, int nb,
1276 { 940 {
1277 int rc; 941 int rc;
1278 int req_length; 942 int req_length;
1279 - uint8_t req[MIN_REQ_LENGTH]; 943 + uint8_t req[_MIN_REQ_LENGTH];
1280 uint8_t rsp[MAX_MESSAGE_LENGTH]; 944 uint8_t rsp[MAX_MESSAGE_LENGTH];
1281 945
1282 if (nb > MODBUS_MAX_READ_REGISTERS) { 946 if (nb > MODBUS_MAX_READ_REGISTERS) {
@@ -1289,7 +953,7 @@ static int read_registers(modbus_t *ctx, int function, int addr, int nb, @@ -1289,7 +953,7 @@ static int read_registers(modbus_t *ctx, int function, int addr, int nb,
1289 return -1; 953 return -1;
1290 } 954 }
1291 955
1292 - req_length = build_request_basis(ctx, function, addr, nb, req); 956 + req_length = ctx->backend->build_request_basis(ctx, function, addr, nb, req);
1293 957
1294 rc = send_msg(ctx, req, req_length); 958 rc = send_msg(ctx, req, req_length);
1295 if (rc > 0) { 959 if (rc > 0) {
@@ -1301,7 +965,7 @@ static int read_registers(modbus_t *ctx, int function, int addr, int nb, @@ -1301,7 +965,7 @@ static int read_registers(modbus_t *ctx, int function, int addr, int nb,
1301 return -1; 965 return -1;
1302 } 966 }
1303 967
1304 - offset = TAB_HEADER_LENGTH[ctx->type_com]; 968 + offset = ctx->backend->header_length;
1305 969
1306 for (i = 0; i < rc; i++) { 970 for (i = 0; i < rc; i++) {
1307 /* shift reg hi_byte to temp OR with lo_byte */ 971 /* shift reg hi_byte to temp OR with lo_byte */
@@ -1329,7 +993,7 @@ int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *data_dest) @@ -1329,7 +993,7 @@ int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *data_dest)
1329 return -1; 993 return -1;
1330 } 994 }
1331 995
1332 - status = read_registers(ctx, FC_READ_HOLDING_REGISTERS, 996 + status = read_registers(ctx, _FC_READ_HOLDING_REGISTERS,
1333 addr, nb, data_dest); 997 addr, nb, data_dest);
1334 return status; 998 return status;
1335 } 999 }
@@ -1348,7 +1012,7 @@ int modbus_read_input_registers(modbus_t *ctx, int addr, int nb, @@ -1348,7 +1012,7 @@ int modbus_read_input_registers(modbus_t *ctx, int addr, int nb,
1348 return -1; 1012 return -1;
1349 } 1013 }
1350 1014
1351 - status = read_registers(ctx, FC_READ_INPUT_REGISTERS, 1015 + status = read_registers(ctx, _FC_READ_INPUT_REGISTERS,
1352 addr, nb, data_dest); 1016 addr, nb, data_dest);
1353 1017
1354 return status; 1018 return status;
@@ -1360,14 +1024,14 @@ static int write_single(modbus_t *ctx, int function, int addr, int value) @@ -1360,14 +1024,14 @@ static int write_single(modbus_t *ctx, int function, int addr, int value)
1360 { 1024 {
1361 int rc; 1025 int rc;
1362 int req_length; 1026 int req_length;
1363 - uint8_t req[MIN_REQ_LENGTH]; 1027 + uint8_t req[_MIN_REQ_LENGTH];
1364 1028
1365 - req_length = build_request_basis(ctx, function, addr, value, req); 1029 + req_length = ctx->backend->build_request_basis(ctx, function, addr, value, req);
1366 1030
1367 rc = send_msg(ctx, req, req_length); 1031 rc = send_msg(ctx, req, req_length);
1368 if (rc > 0) { 1032 if (rc > 0) {
1369 /* Used by write_bit and write_register */ 1033 /* Used by write_bit and write_register */
1370 - uint8_t rsp[MIN_REQ_LENGTH]; 1034 + uint8_t rsp[_MIN_REQ_LENGTH];
1371 rc = receive_msg_req(ctx, req, rsp); 1035 rc = receive_msg_req(ctx, req, rsp);
1372 } 1036 }
1373 1037
@@ -1382,7 +1046,7 @@ int modbus_write_bit(modbus_t *ctx, int addr, int state) @@ -1382,7 +1046,7 @@ int modbus_write_bit(modbus_t *ctx, int addr, int state)
1382 if (state) 1046 if (state)
1383 state = 0xFF00; 1047 state = 0xFF00;
1384 1048
1385 - status = write_single(ctx, FC_WRITE_SINGLE_COIL, addr, state); 1049 + status = write_single(ctx, _FC_WRITE_SINGLE_COIL, addr, state);
1386 1050
1387 return status; 1051 return status;
1388 } 1052 }
@@ -1392,7 +1056,7 @@ int modbus_write_register(modbus_t *ctx, int addr, int value) @@ -1392,7 +1056,7 @@ int modbus_write_register(modbus_t *ctx, int addr, int value)
1392 { 1056 {
1393 int status; 1057 int status;
1394 1058
1395 - status = write_single(ctx, FC_WRITE_SINGLE_REGISTER, addr, value); 1059 + status = write_single(ctx, _FC_WRITE_SINGLE_REGISTER, addr, value);
1396 1060
1397 return status; 1061 return status;
1398 } 1062 }
@@ -1418,8 +1082,8 @@ int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *data_src) @@ -1418,8 +1082,8 @@ int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *data_src)
1418 return -1; 1082 return -1;
1419 } 1083 }
1420 1084
1421 - req_length = build_request_basis(ctx, FC_WRITE_MULTIPLE_COILS,  
1422 - addr, nb, req); 1085 + req_length = ctx->backend->build_request_basis(ctx, _FC_WRITE_MULTIPLE_COILS,
  1086 + addr, nb, req);
1423 byte_count = (nb / 8) + ((nb % 8) ? 1 : 0); 1087 byte_count = (nb / 8) + ((nb % 8) ? 1 : 0);
1424 req[req_length++] = byte_count; 1088 req[req_length++] = byte_count;
1425 1089
@@ -1470,8 +1134,9 @@ int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *data @@ -1470,8 +1134,9 @@ int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *data
1470 return -1; 1134 return -1;
1471 } 1135 }
1472 1136
1473 - req_length = build_request_basis(ctx, FC_WRITE_MULTIPLE_REGISTERS,  
1474 - addr, nb, req); 1137 + req_length = ctx->backend->build_request_basis(ctx,
  1138 + _FC_WRITE_MULTIPLE_REGISTERS,
  1139 + addr, nb, req);
1475 byte_count = nb * 2; 1140 byte_count = nb * 2;
1476 req[req_length++] = byte_count; 1141 req[req_length++] = byte_count;
1477 1142
@@ -1521,8 +1186,9 @@ int modbus_read_and_write_registers(modbus_t *ctx, @@ -1521,8 +1186,9 @@ int modbus_read_and_write_registers(modbus_t *ctx,
1521 errno = EMBMDATA; 1186 errno = EMBMDATA;
1522 return -1; 1187 return -1;
1523 } 1188 }
1524 - req_length = build_request_basis(ctx, FC_READ_AND_WRITE_REGISTERS,  
1525 - read_addr, read_nb, req); 1189 + req_length = ctx->backend->build_request_basis(ctx,
  1190 + _FC_READ_AND_WRITE_REGISTERS,
  1191 + read_addr, read_nb, req);
1526 1192
1527 req[req_length++] = write_addr >> 8; 1193 req[req_length++] = write_addr >> 8;
1528 req[req_length++] = write_addr & 0x00ff; 1194 req[req_length++] = write_addr & 0x00ff;
@@ -1541,7 +1207,7 @@ int modbus_read_and_write_registers(modbus_t *ctx, @@ -1541,7 +1207,7 @@ int modbus_read_and_write_registers(modbus_t *ctx,
1541 int offset; 1207 int offset;
1542 1208
1543 rc = receive_msg_req(ctx, req, rsp); 1209 rc = receive_msg_req(ctx, req, rsp);
1544 - offset = TAB_HEADER_LENGTH[ctx->type_com]; 1210 + offset = ctx->backend->header_length;
1545 1211
1546 /* If rc is negative, the loop is jumped ! */ 1212 /* If rc is negative, the loop is jumped ! */
1547 for (i = 0; i < rc; i++) { 1213 for (i = 0; i < rc; i++) {
@@ -1560,9 +1226,10 @@ int modbus_report_slave_id(modbus_t *ctx, uint8_t *data_dest) @@ -1560,9 +1226,10 @@ int modbus_report_slave_id(modbus_t *ctx, uint8_t *data_dest)
1560 { 1226 {
1561 int rc; 1227 int rc;
1562 int req_length; 1228 int req_length;
1563 - uint8_t req[MIN_REQ_LENGTH]; 1229 + uint8_t req[_MIN_REQ_LENGTH];
1564 1230
1565 - req_length = build_request_basis(ctx, FC_REPORT_SLAVE_ID, 0, 0, req); 1231 + req_length = ctx->backend->build_request_basis(ctx, _FC_REPORT_SLAVE_ID,
  1232 + 0, 0, req);
1566 1233
1567 /* HACKISH, addr and count are not used */ 1234 /* HACKISH, addr and count are not used */
1568 req_length -= 4; 1235 req_length -= 4;
@@ -1579,7 +1246,7 @@ int modbus_report_slave_id(modbus_t *ctx, uint8_t *data_dest) @@ -1579,7 +1246,7 @@ int modbus_report_slave_id(modbus_t *ctx, uint8_t *data_dest)
1579 if (rc == -1) 1246 if (rc == -1)
1580 return -1; 1247 return -1;
1581 1248
1582 - offset = TAB_HEADER_LENGTH[ctx->type_com] + 2; 1249 + offset = ctx->backend->header_length + 2;
1583 1250
1584 for (i=0; i < rc; i++) { 1251 for (i=0; i < rc; i++) {
1585 data_dest[i] = rsp[offset + i]; 1252 data_dest[i] = rsp[offset + i];
@@ -1589,105 +1256,22 @@ int modbus_report_slave_id(modbus_t *ctx, uint8_t *data_dest) @@ -1589,105 +1256,22 @@ int modbus_report_slave_id(modbus_t *ctx, uint8_t *data_dest)
1589 return rc; 1256 return rc;
1590 } 1257 }
1591 1258
1592 -static void init_common(modbus_t *ctx) 1259 +void _modbus_init_common(modbus_t *ctx)
1593 { 1260 {
1594 ctx->timeout_begin.tv_sec = 0; 1261 ctx->timeout_begin.tv_sec = 0;
1595 - ctx->timeout_begin.tv_usec = TIME_OUT_BEGIN_OF_TRAME; 1262 + ctx->timeout_begin.tv_usec = _TIME_OUT_BEGIN_OF_TRAME;
1596 1263
1597 ctx->timeout_end.tv_sec = 0; 1264 ctx->timeout_end.tv_sec = 0;
1598 - ctx->timeout_end.tv_usec = TIME_OUT_END_OF_TRAME; 1265 + ctx->timeout_end.tv_usec = _TIME_OUT_END_OF_TRAME;
1599 1266
1600 ctx->error_recovery = FALSE; 1267 ctx->error_recovery = FALSE;
1601 ctx->debug = FALSE; 1268 ctx->debug = FALSE;
1602 } 1269 }
1603 1270
1604 -/* Allocate and initialize the modbus_t structure for RTU  
1605 - - device: "/dev/ttyS0"  
1606 - - baud: 9600, 19200, 57600, 115200, etc  
1607 - - parity: 'N' stands for None, 'E' for Even and 'O' for odd  
1608 - - data_bits: 5, 6, 7, 8  
1609 - - stop_bits: 1, 2  
1610 - - slave: slave number of the caller  
1611 -*/  
1612 -modbus_t* modbus_new_rtu(const char *device,  
1613 - int baud, char parity, int data_bit,  
1614 - int stop_bit, int slave)  
1615 -{  
1616 - modbus_t *ctx;  
1617 - modbus_rtu_t *ctx_rtu;  
1618 -  
1619 - ctx = (modbus_t *) malloc(sizeof(modbus_t));  
1620 - init_common(ctx);  
1621 - if (modbus_set_slave(ctx, slave) == -1) {  
1622 - return NULL;  
1623 - }  
1624 -  
1625 - ctx->type_com = RTU;  
1626 -  
1627 - ctx->com = (modbus_rtu_t *) malloc(sizeof(modbus_rtu_t));  
1628 - ctx_rtu = (modbus_rtu_t *)ctx->com;  
1629 -#if defined(OpenBSD)  
1630 - strlcpy(ctx_rtu->device, device, sizeof(ctx_rtu->device));  
1631 -#else  
1632 - strcpy(ctx_rtu->device, device);  
1633 -#endif  
1634 - ctx_rtu->baud = baud;  
1635 - if (parity == 'N' || parity == 'E' || parity == 'O') {  
1636 - ctx_rtu->parity = parity;  
1637 - } else {  
1638 - errno = EINVAL;  
1639 - return NULL;  
1640 - }  
1641 - ctx_rtu->data_bit = data_bit;  
1642 - ctx_rtu->stop_bit = stop_bit;  
1643 -  
1644 - return ctx;  
1645 -}  
1646 -  
1647 -/* Allocates and initializes the modbus_t structure for TCP.  
1648 - - ip : "192.168.0.5"  
1649 - - port : 1099  
1650 -  
1651 - Set the port to MODBUS_TCP_DEFAULT_PORT to use the default one  
1652 - (502). It's convenient to use a port number greater than or equal  
1653 - to 1024 because it's not necessary to be root to use this port  
1654 - number.  
1655 -*/  
1656 -modbus_t* modbus_new_tcp(const char *ip, int port)  
1657 -{  
1658 - modbus_t *ctx;  
1659 - modbus_tcp_t *ctx_tcp;  
1660 -  
1661 - ctx = (modbus_t *) malloc(sizeof(modbus_t));  
1662 - init_common(ctx);  
1663 - ctx->slave = MODBUS_TCP_SLAVE;  
1664 -  
1665 - ctx->type_com = TCP;  
1666 -  
1667 - ctx->com = (modbus_tcp_t *) malloc(sizeof(modbus_tcp_t));  
1668 - ctx_tcp = (modbus_tcp_t *)ctx->com;  
1669 -  
1670 - strncpy(ctx_tcp->ip, ip, sizeof(char)*16);  
1671 - ctx_tcp->port = port;  
1672 -  
1673 - /* Can be changed after to reach remote serial Modbus device */  
1674 - return ctx;  
1675 -}  
1676 -  
1677 -/* Define the slave number, the special value MODBUS_TCP_SLAVE (0xFF) can be  
1678 - * used in TCP mode to restore the default value. */ 1271 +/* Define the slave number */
1679 int modbus_set_slave(modbus_t *ctx, int slave) 1272 int modbus_set_slave(modbus_t *ctx, int slave)
1680 { 1273 {
1681 - if (slave >= 1 && slave <= 247) {  
1682 - ctx->slave = slave;  
1683 - } else if (ctx->type_com == TCP && slave == MODBUS_TCP_SLAVE) {  
1684 - ctx->slave = slave;  
1685 - } else {  
1686 - errno = EINVAL;  
1687 - return -1;  
1688 - }  
1689 -  
1690 - return 0; 1274 + return ctx->backend->set_slave(ctx, slave);
1691 } 1275 }
1692 1276
1693 /* 1277 /*
@@ -1739,348 +1323,9 @@ void modbus_set_timeout_end(modbus_t *ctx, const struct timeval *timeout) @@ -1739,348 +1323,9 @@ void modbus_set_timeout_end(modbus_t *ctx, const struct timeval *timeout)
1739 ctx->timeout_end = *timeout; 1323 ctx->timeout_end = *timeout;
1740 } 1324 }
1741 1325
1742 -/* Sets up a serial port for RTU communications */  
1743 -static int modbus_connect_rtu(modbus_t *ctx)  
1744 -{  
1745 - struct termios tios;  
1746 - speed_t speed;  
1747 - modbus_rtu_t *ctx_rtu = ctx->com;  
1748 -  
1749 - if (ctx->debug) {  
1750 - printf("Opening %s at %d bauds (%c, %d, %d)\n",  
1751 - ctx_rtu->device, ctx_rtu->baud, ctx_rtu->parity,  
1752 - ctx_rtu->data_bit, ctx_rtu->stop_bit);  
1753 - }  
1754 -  
1755 - /* The O_NOCTTY flag tells UNIX that this program doesn't want  
1756 - to be the "controlling terminal" for that port. If you  
1757 - don't specify this then any input (such as keyboard abort  
1758 - signals and so forth) will affect your process  
1759 -  
1760 - Timeouts are ignored in canonical input mode or when the  
1761 - NDELAY option is set on the file via open or fcntl */  
1762 - ctx->s = open(ctx_rtu->device, O_RDWR | O_NOCTTY | O_NDELAY | O_EXCL);  
1763 - if (ctx->s == -1) {  
1764 - fprintf(stderr, "ERROR Can't open the device %s (%s)\n",  
1765 - ctx_rtu->device, strerror(errno));  
1766 - return -1;  
1767 - }  
1768 -  
1769 - /* Save */  
1770 - tcgetattr(ctx->s, &(ctx_rtu->old_tios));  
1771 -  
1772 - memset(&tios, 0, sizeof(struct termios));  
1773 -  
1774 - /* C_ISPEED Input baud (new interface)  
1775 - C_OSPEED Output baud (new interface)  
1776 - */  
1777 - switch (ctx_rtu->baud) {  
1778 - case 110:  
1779 - speed = B110;  
1780 - break;  
1781 - case 300:  
1782 - speed = B300;  
1783 - break;  
1784 - case 600:  
1785 - speed = B600;  
1786 - break;  
1787 - case 1200:  
1788 - speed = B1200;  
1789 - break;  
1790 - case 2400:  
1791 - speed = B2400;  
1792 - break;  
1793 - case 4800:  
1794 - speed = B4800;  
1795 - break;  
1796 - case 9600:  
1797 - speed = B9600;  
1798 - break;  
1799 - case 19200:  
1800 - speed = B19200;  
1801 - break;  
1802 - case 38400:  
1803 - speed = B38400;  
1804 - break;  
1805 - case 57600:  
1806 - speed = B57600;  
1807 - break;  
1808 - case 115200:  
1809 - speed = B115200;  
1810 - break;  
1811 - default:  
1812 - speed = B9600;  
1813 - if (ctx->debug) {  
1814 - fprintf(stderr,  
1815 - "WARNING Unknown baud rate %d for %s (B9600 used)\n",  
1816 - ctx_rtu->baud, ctx_rtu->device);  
1817 - }  
1818 - }  
1819 -  
1820 - /* Set the baud rate */  
1821 - if ((cfsetispeed(&tios, speed) < 0) ||  
1822 - (cfsetospeed(&tios, speed) < 0)) {  
1823 - return -1;  
1824 - }  
1825 -  
1826 - /* C_CFLAG Control options  
1827 - CLOCAL Local line - do not change "owner" of port  
1828 - CREAD Enable receiver  
1829 - */  
1830 - tios.c_cflag |= (CREAD | CLOCAL);  
1831 - /* CSIZE, HUPCL, CRTSCTS (hardware flow control) */  
1832 -  
1833 - /* Set data bits (5, 6, 7, 8 bits)  
1834 - CSIZE Bit mask for data bits  
1835 - */  
1836 - tios.c_cflag &= ~CSIZE;  
1837 - switch (ctx_rtu->data_bit) {  
1838 - case 5:  
1839 - tios.c_cflag |= CS5;  
1840 - break;  
1841 - case 6:  
1842 - tios.c_cflag |= CS6;  
1843 - break;  
1844 - case 7:  
1845 - tios.c_cflag |= CS7;  
1846 - break;  
1847 - case 8:  
1848 - default:  
1849 - tios.c_cflag |= CS8;  
1850 - break;  
1851 - }  
1852 -  
1853 - /* Stop bit (1 or 2) */  
1854 - if (ctx_rtu->stop_bit == 1)  
1855 - tios.c_cflag &=~ CSTOPB;  
1856 - else /* 2 */  
1857 - tios.c_cflag |= CSTOPB;  
1858 -  
1859 - /* PARENB Enable parity bit  
1860 - PARODD Use odd parity instead of even */  
1861 - if (ctx_rtu->parity == 'N') {  
1862 - /* None */  
1863 - tios.c_cflag &=~ PARENB;  
1864 - } else if (ctx_rtu->parity == 'E') {  
1865 - /* Even */  
1866 - tios.c_cflag |= PARENB;  
1867 - tios.c_cflag &=~ PARODD;  
1868 - } else {  
1869 - /* Odd */  
1870 - tios.c_cflag |= PARENB;  
1871 - tios.c_cflag |= PARODD;  
1872 - }  
1873 -  
1874 - /* Read the man page of termios if you need more information. */  
1875 -  
1876 - /* This field isn't used on POSIX systems  
1877 - tios.c_line = 0;  
1878 - */  
1879 -  
1880 - /* C_LFLAG Line options  
1881 -  
1882 - ISIG Enable SIGINTR, SIGSUSP, SIGDSUSP, and SIGQUIT signals  
1883 - ICANON Enable canonical input (else raw)  
1884 - XCASE Map uppercase \lowercase (obsolete)  
1885 - ECHO Enable echoing of input characters  
1886 - ECHOE Echo erase character as BS-SP-BS  
1887 - ECHOK Echo NL after kill character  
1888 - ECHONL Echo NL  
1889 - NOFLSH Disable flushing of input buffers after  
1890 - interrupt or quit characters  
1891 - IEXTEN Enable extended functions  
1892 - ECHOCTL Echo control characters as ^char and delete as ~?  
1893 - ECHOPRT Echo erased character as character erased  
1894 - ECHOKE BS-SP-BS entire line on line kill  
1895 - FLUSHO Output being flushed  
1896 - PENDIN Retype pending input at next read or input char  
1897 - TOSTOP Send SIGTTOU for background output  
1898 -  
1899 - Canonical input is line-oriented. Input characters are put  
1900 - into a buffer which can be edited interactively by the user  
1901 - until a CR (carriage return) or LF (line feed) character is  
1902 - received.  
1903 -  
1904 - Raw input is unprocessed. Input characters are passed  
1905 - through exactly as they are received, when they are  
1906 - received. Generally you'll deselect the ICANON, ECHO,  
1907 - ECHOE, and ISIG options when using raw input  
1908 - */  
1909 -  
1910 - /* Raw input */  
1911 - tios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);  
1912 -  
1913 - /* C_IFLAG Input options  
1914 -  
1915 - Constant Description  
1916 - INPCK Enable parity check  
1917 - IGNPAR Ignore parity errors  
1918 - PARMRK Mark parity errors  
1919 - ISTRIP Strip parity bits  
1920 - IXON Enable software flow control (outgoing)  
1921 - IXOFF Enable software flow control (incoming)  
1922 - IXANY Allow any character to start flow again  
1923 - IGNBRK Ignore break condition  
1924 - BRKINT Send a SIGINT when a break condition is detected  
1925 - INLCR Map NL to CR  
1926 - IGNCR Ignore CR  
1927 - ICRNL Map CR to NL  
1928 - IUCLC Map uppercase to lowercase  
1929 - IMAXBEL Echo BEL on input line too long  
1930 - */  
1931 - if (ctx_rtu->parity == 'N') {  
1932 - /* None */  
1933 - tios.c_iflag &= ~INPCK;  
1934 - } else {  
1935 - tios.c_iflag |= INPCK;  
1936 - }  
1937 -  
1938 - /* Software flow control is disabled */  
1939 - tios.c_iflag &= ~(IXON | IXOFF | IXANY);  
1940 -  
1941 - /* C_OFLAG Output options  
1942 - OPOST Postprocess output (not set = raw output)  
1943 - ONLCR Map NL to CR-NL  
1944 -  
1945 - ONCLR ant others needs OPOST to be enabled  
1946 - */  
1947 -  
1948 - /* Raw ouput */  
1949 - tios.c_oflag &=~ OPOST;  
1950 -  
1951 - /* C_CC Control characters  
1952 - VMIN Minimum number of characters to read  
1953 - VTIME Time to wait for data (tenths of seconds)  
1954 -  
1955 - UNIX serial interface drivers provide the ability to  
1956 - specify character and packet timeouts. Two elements of the  
1957 - c_cc array are used for timeouts: VMIN and VTIME. Timeouts  
1958 - are ignored in canonical input mode or when the NDELAY  
1959 - option is set on the file via open or fcntl.  
1960 -  
1961 - VMIN specifies the minimum number of characters to read. If  
1962 - it is set to 0, then the VTIME value specifies the time to  
1963 - wait for every character read. Note that this does not mean  
1964 - that a read call for N bytes will wait for N characters to  
1965 - come in. Rather, the timeout will apply to the first  
1966 - character and the read call will return the number of  
1967 - characters immediately available (up to the number you  
1968 - request).  
1969 -  
1970 - If VMIN is non-zero, VTIME specifies the time to wait for  
1971 - the first character read. If a character is read within the  
1972 - time given, any read will block (wait) until all VMIN  
1973 - characters are read. That is, once the first character is  
1974 - read, the serial interface driver expects to receive an  
1975 - entire packet of characters (VMIN bytes total). If no  
1976 - character is read within the time allowed, then the call to  
1977 - read returns 0. This method allows you to tell the serial  
1978 - driver you need exactly N bytes and any read call will  
1979 - return 0 or N bytes. However, the timeout only applies to  
1980 - the first character read, so if for some reason the driver  
1981 - misses one character inside the N byte packet then the read  
1982 - call could block forever waiting for additional input  
1983 - characters.  
1984 -  
1985 - VTIME specifies the amount of time to wait for incoming  
1986 - characters in tenths of seconds. If VTIME is set to 0 (the  
1987 - default), reads will block (wait) indefinitely unless the  
1988 - NDELAY option is set on the port with open or fcntl.  
1989 - */  
1990 - /* Unused because we use open with the NDELAY option */  
1991 - tios.c_cc[VMIN] = 0;  
1992 - tios.c_cc[VTIME] = 0;  
1993 -  
1994 - if (tcsetattr(ctx->s, TCSANOW, &tios) < 0) {  
1995 - return -1;  
1996 - }  
1997 -  
1998 - return 0;  
1999 -}  
2000 -  
2001 -/* Establishes a modbus TCP connection with a Modbus server. */  
2002 -static int modbus_connect_tcp(modbus_t *ctx)  
2003 -{  
2004 - int rc;  
2005 - int option;  
2006 - struct sockaddr_in addr;  
2007 - modbus_tcp_t *ctx_tcp = ctx->com;  
2008 -  
2009 - ctx->s = socket(PF_INET, SOCK_STREAM, 0);  
2010 - if (ctx->s == -1) {  
2011 - return -1;  
2012 - }  
2013 -  
2014 - /* Set the TCP no delay flag */  
2015 - /* SOL_TCP = IPPROTO_TCP */  
2016 - option = 1;  
2017 - rc = setsockopt(ctx->s, IPPROTO_TCP, TCP_NODELAY,  
2018 - (const void *)&option, sizeof(int));  
2019 - if (rc == -1) {  
2020 - close(ctx->s);  
2021 - return -1;  
2022 - }  
2023 -  
2024 -#if (!HAVE_DECL___CYGWIN__)  
2025 - /**  
2026 - * Cygwin defines IPTOS_LOWDELAY but can't handle that flag so it's  
2027 - * necessary to workaround that problem.  
2028 - **/  
2029 - /* Set the IP low delay option */  
2030 - option = IPTOS_LOWDELAY;  
2031 - rc = setsockopt(ctx->s, IPPROTO_IP, IP_TOS,  
2032 - (const void *)&option, sizeof(int));  
2033 - if (rc == -1) {  
2034 - close(ctx->s);  
2035 - return -1;  
2036 - }  
2037 -#endif  
2038 -  
2039 - if (ctx->debug) {  
2040 - printf("Connecting to %s\n", ctx_tcp->ip);  
2041 - }  
2042 -  
2043 - addr.sin_family = AF_INET;  
2044 - addr.sin_port = htons(ctx_tcp->port);  
2045 - addr.sin_addr.s_addr = inet_addr(ctx_tcp->ip);  
2046 - rc = connect(ctx->s, (struct sockaddr *)&addr,  
2047 - sizeof(struct sockaddr_in));  
2048 - if (rc == -1) {  
2049 - close(ctx->s);  
2050 - return -1;  
2051 - }  
2052 -  
2053 - return 0;  
2054 -}  
2055 -  
2056 -/* Establishes a modbus connection.  
2057 - Returns 0 on success or -1 on failure. */  
2058 int modbus_connect(modbus_t *ctx) 1326 int modbus_connect(modbus_t *ctx)
2059 { 1327 {
2060 - int rc;  
2061 -  
2062 - if (ctx->type_com == RTU)  
2063 - rc = modbus_connect_rtu(ctx);  
2064 - else  
2065 - rc = modbus_connect_tcp(ctx);  
2066 -  
2067 - return rc;  
2068 -}  
2069 -  
2070 -/* Closes the file descriptor in RTU mode */  
2071 -static void modbus_close_rtu(modbus_t *ctx)  
2072 -{  
2073 - modbus_rtu_t *ctx_rtu = ctx->com;  
2074 -  
2075 - tcsetattr(ctx->s, TCSANOW, &(ctx_rtu->old_tios));  
2076 - close(ctx->s);  
2077 -}  
2078 -  
2079 -/* Closes the network connection and socket in TCP mode */  
2080 -static void modbus_close_tcp(modbus_t *ctx)  
2081 -{  
2082 - shutdown(ctx->s, SHUT_RDWR);  
2083 - close(ctx->s); 1328 + return ctx->backend->connect(ctx);
2084 } 1329 }
2085 1330
2086 /* Closes a connection */ 1331 /* Closes a connection */
@@ -2089,10 +1334,7 @@ void modbus_close(modbus_t *ctx) @@ -2089,10 +1334,7 @@ void modbus_close(modbus_t *ctx)
2089 if (ctx == NULL) 1334 if (ctx == NULL)
2090 return; 1335 return;
2091 1336
2092 - if (ctx->type_com == RTU)  
2093 - modbus_close_rtu(ctx);  
2094 - else  
2095 - modbus_close_tcp(ctx); 1337 + ctx->backend->close(ctx);
2096 } 1338 }
2097 1339
2098 /* Free an initialized modbus_t */ 1340 /* Free an initialized modbus_t */
@@ -2101,7 +1343,7 @@ void modbus_free(modbus_t *ctx) @@ -2101,7 +1343,7 @@ void modbus_free(modbus_t *ctx)
2101 if (ctx == NULL) 1343 if (ctx == NULL)
2102 return; 1344 return;
2103 1345
2104 - free(ctx->com); 1346 + free(ctx->backend_data);
2105 free(ctx); 1347 free(ctx);
2106 } 1348 }
2107 1349
@@ -2203,146 +1445,12 @@ void modbus_mapping_free(modbus_mapping_t *mb_mapping) @@ -2203,146 +1445,12 @@ void modbus_mapping_free(modbus_mapping_t *mb_mapping)
2203 free(mb_mapping); 1445 free(mb_mapping);
2204 } 1446 }
2205 1447
2206 -/* Listens for any request from one or many modbus masters in TCP */  
2207 int modbus_listen(modbus_t *ctx, int nb_connection) 1448 int modbus_listen(modbus_t *ctx, int nb_connection)
2208 { 1449 {
2209 - int new_socket;  
2210 - int yes;  
2211 - struct sockaddr_in addr;  
2212 - modbus_tcp_t *ctx_tcp = ctx->com;  
2213 -  
2214 - if (ctx->type_com != TCP) {  
2215 - if (ctx->debug)  
2216 - fprintf(stderr, "Not implemented");  
2217 - errno = EINVAL;  
2218 - return -1;  
2219 - }  
2220 -  
2221 - new_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);  
2222 - if (new_socket == -1) {  
2223 - return -1;  
2224 - }  
2225 -  
2226 - yes = 1;  
2227 - if (setsockopt(new_socket, SOL_SOCKET, SO_REUSEADDR,  
2228 - (char *) &yes, sizeof(yes)) == -1) {  
2229 - close(new_socket);  
2230 - return -1;  
2231 - }  
2232 -  
2233 - memset(&addr, 0, sizeof(addr));  
2234 - addr.sin_family = AF_INET;  
2235 - /* If the modbus port is < to 1024, we need the setuid root. */  
2236 - addr.sin_port = htons(ctx_tcp->port);  
2237 - addr.sin_addr.s_addr = INADDR_ANY;  
2238 - if (bind(new_socket, (struct sockaddr *)&addr, sizeof(addr)) == -1) {  
2239 - close(new_socket);  
2240 - return -1;  
2241 - }  
2242 -  
2243 - if (listen(new_socket, nb_connection) == -1) {  
2244 - close(new_socket);  
2245 - return -1;  
2246 - }  
2247 -  
2248 - return new_socket; 1450 + return ctx->backend->listen(ctx, nb_connection);
2249 } 1451 }
2250 1452
2251 -/* On success, the function return a non-negative integer that is a descriptor  
2252 - for the accepted socket. On error, -1 is returned, and errno is set  
2253 - appropriately. */  
2254 int modbus_accept(modbus_t *ctx, int *socket) 1453 int modbus_accept(modbus_t *ctx, int *socket)
2255 { 1454 {
2256 - struct sockaddr_in addr;  
2257 - socklen_t addrlen;  
2258 -  
2259 - if (ctx->type_com != TCP) {  
2260 - if (ctx->debug)  
2261 - fprintf(stderr, "Not implemented");  
2262 - errno = EINVAL;  
2263 - return -1;  
2264 - }  
2265 -  
2266 - addrlen = sizeof(struct sockaddr_in);  
2267 - ctx->s = accept(*socket, (struct sockaddr *)&addr, &addrlen);  
2268 - if (ctx->s == -1) {  
2269 - close(*socket);  
2270 - *socket = 0;  
2271 - return -1;  
2272 - }  
2273 -  
2274 - if (ctx->debug) {  
2275 - printf("The client %s is connected\n", inet_ntoa(addr.sin_addr));  
2276 - }  
2277 -  
2278 - return ctx->s;  
2279 -}  
2280 -  
2281 -/** Utils **/  
2282 -  
2283 -/* Sets many bits from a single byte value (all 8 bits of the byte value are  
2284 - set) */  
2285 -void modbus_set_bits_from_byte(uint8_t *dest, int address, const uint8_t value)  
2286 -{  
2287 - int i;  
2288 -  
2289 - for (i=0; i<8; i++) {  
2290 - dest[address+i] = (value & (1 << i)) ? ON : OFF;  
2291 - }  
2292 -}  
2293 -  
2294 -/* Sets many bits from a table of bytes (only the bits between address and  
2295 - address + nb_bits are set) */  
2296 -void modbus_set_bits_from_bytes(uint8_t *dest, int address, unsigned int nb_bits,  
2297 - const uint8_t tab_byte[])  
2298 -{  
2299 - int i;  
2300 - int shift = 0;  
2301 -  
2302 - for (i = address; i < address + nb_bits; i++) {  
2303 - dest[i] = tab_byte[(i - address) / 8] & (1 << shift) ? ON : OFF;  
2304 - /* gcc doesn't like: shift = (++shift) % 8; */  
2305 - shift++;  
2306 - shift %= 8;  
2307 - }  
2308 -}  
2309 -  
2310 -/* Gets the byte value from many bits.  
2311 - To obtain a full byte, set nb_bits to 8. */  
2312 -uint8_t modbus_get_byte_from_bits(const uint8_t *src, int address, unsigned int nb_bits)  
2313 -{  
2314 - int i;  
2315 - uint8_t value = 0;  
2316 -  
2317 - if (nb_bits > 8) {  
2318 - assert(nb_bits < 8);  
2319 - nb_bits = 8;  
2320 - }  
2321 -  
2322 - for (i=0; i < nb_bits; i++) {  
2323 - value |= (src[address+i] << i);  
2324 - }  
2325 -  
2326 - return value;  
2327 -}  
2328 -  
2329 -/* Get a float from 4 bytes in Modbus format */  
2330 -float modbus_get_float(const uint16_t *src)  
2331 -{  
2332 - float r = 0.0f;  
2333 - uint32_t i;  
2334 -  
2335 - i = (((uint32_t)src[1]) << 16) + src[0];  
2336 - memcpy(&r, &i, sizeof (r));  
2337 - return r;  
2338 -}  
2339 -  
2340 -/* Set a float to 4 bytes in Modbus format */  
2341 -void modbus_set_float(float real, uint16_t *dest)  
2342 -{  
2343 - uint32_t i = 0;  
2344 -  
2345 - memcpy(&i, &real, sizeof (i));  
2346 - dest[0] = (uint16_t)i;  
2347 - dest[1] = (uint16_t)(i >> 16); 1455 + return ctx->backend->accept(ctx, socket);
2348 } 1456 }
src/modbus.h
@@ -22,15 +22,9 @@ @@ -22,15 +22,9 @@
22 #if (defined(__unix__) || defined(unix)) && !defined(USG) 22 #if (defined(__unix__) || defined(unix)) && !defined(USG)
23 #include <sys/param.h> 23 #include <sys/param.h>
24 #endif 24 #endif
25 -  
26 -#ifdef HAVE_INTTYPES_H  
27 -#include <inttypes.h>  
28 -#endif  
29 -#ifdef HAVE_STDINT_H  
30 #include <stdint.h> 25 #include <stdint.h>
31 -#endif  
32 #include <termios.h> 26 #include <termios.h>
33 -#if defined(OpenBSD) || (defined(__FreeBSD__ ) && __FreeBSD__ < 5) 27 +#if defined(OpenBSD) || (defined(__FreeBSD__) && __FreeBSD__ < 5)
34 #include <netinet/in_systm.h> 28 #include <netinet/in_systm.h>
35 #endif 29 #endif
36 #include <netinet/in.h> 30 #include <netinet/in.h>
@@ -67,16 +61,7 @@ MODBUS_BEGIN_DECLS @@ -67,16 +61,7 @@ MODBUS_BEGIN_DECLS
67 #define ON 1 61 #define ON 1
68 #endif 62 #endif
69 63
70 -#define MODBUS_TCP_DEFAULT_PORT 502  
71 #define MODBUS_BROADCAST_ADDRESS 0 64 #define MODBUS_BROADCAST_ADDRESS 0
72 -#define MODBUS_TCP_SLAVE 0xFF  
73 -  
74 -/* Modbus_Application_Protocol_V1_1b.pdf Chapter 4 Section 1 Page 5:  
75 - * - RS232 / RS485 ADU = 253 bytes + slave (1 byte) + CRC (2 bytes) = 256 bytes  
76 - * - TCP MODBUS ADU = 253 bytes + MBAP (7 bytes) = 260 bytes  
77 - */  
78 -#define MODBUS_MAX_ADU_LENGTH_RTU 256  
79 -#define MODBUS_MAX_ADU_LENGTH_TCP 260  
80 65
81 /* Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 1 page 12) 66 /* Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 1 page 12)
82 * Quantity of Coils to read (2 bytes): 1 to 2000 (0x7D0) 67 * Quantity of Coils to read (2 bytes): 1 to 2000 (0x7D0)
@@ -151,12 +136,8 @@ typedef struct { @@ -151,12 +136,8 @@ typedef struct {
151 uint16_t *tab_registers; 136 uint16_t *tab_registers;
152 } modbus_mapping_t; 137 } modbus_mapping_t;
153 138
154 -modbus_t* modbus_new_rtu(const char *device, int baud, char parity, int data_bit,  
155 - int stop_bit, int slave);  
156 int modbus_set_slave(modbus_t* ctx, int slave); 139 int modbus_set_slave(modbus_t* ctx, int slave);
157 140
158 -modbus_t* modbus_new_tcp(const char *ip_address, int port);  
159 -  
160 int modbus_set_error_recovery(modbus_t *ctx, int enabled); 141 int modbus_set_error_recovery(modbus_t *ctx, int enabled);
161 142
162 void modbus_get_timeout_begin(modbus_t *ctx, struct timeval *timeout); 143 void modbus_get_timeout_begin(modbus_t *ctx, struct timeval *timeout);
@@ -214,4 +195,7 @@ void modbus_set_float(float real, uint16_t *dest); @@ -214,4 +195,7 @@ void modbus_set_float(float real, uint16_t *dest);
214 195
215 MODBUS_END_DECLS 196 MODBUS_END_DECLS
216 197
  198 +#include "modbus-tcp.h"
  199 +#include "modbus-rtu.h"
  200 +
217 #endif /* _MODBUS_H_ */ 201 #endif /* _MODBUS_H_ */
tests/bandwidth-server-many-up.c
@@ -108,7 +108,7 @@ int main(void) @@ -108,7 +108,7 @@ int main(void)
108 } 108 }
109 } else { 109 } else {
110 /* An already connected master has sent a new query */ 110 /* An already connected master has sent a new query */
111 - uint8_t query[MODBUS_MAX_ADU_LENGTH_TCP]; 111 + uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];
112 112
113 rc = modbus_receive(ctx, master_socket, query); 113 rc = modbus_receive(ctx, master_socket, query);
114 if (rc != -1) { 114 if (rc != -1) {
tests/bandwidth-server-one.c
@@ -45,7 +45,7 @@ int main(void) @@ -45,7 +45,7 @@ int main(void)
45 modbus_accept(ctx, &socket); 45 modbus_accept(ctx, &socket);
46 46
47 for(;;) { 47 for(;;) {
48 - uint8_t query[MODBUS_MAX_ADU_LENGTH_TCP]; 48 + uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];
49 49
50 rc = modbus_receive(ctx, -1, query); 50 rc = modbus_receive(ctx, -1, query);
51 if (rc >= 0) { 51 if (rc >= 0) {
tests/random-test-server.c
@@ -43,7 +43,7 @@ int main(void) @@ -43,7 +43,7 @@ int main(void)
43 modbus_accept(ctx, &socket); 43 modbus_accept(ctx, &socket);
44 44
45 for (;;) { 45 for (;;) {
46 - uint8_t query[MODBUS_MAX_ADU_LENGTH_TCP]; 46 + uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];
47 int rc; 47 int rc;
48 48
49 rc = modbus_receive(ctx, -1, query); 49 rc = modbus_receive(ctx, -1, query);
tests/unit-test-server.c
@@ -69,7 +69,7 @@ int main(void) @@ -69,7 +69,7 @@ int main(void)
69 modbus_accept(ctx, &socket); 69 modbus_accept(ctx, &socket);
70 70
71 for (;;) { 71 for (;;) {
72 - uint8_t query[MODBUS_MAX_ADU_LENGTH_TCP]; 72 + uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];
73 73
74 rc = modbus_receive(ctx, -1, query); 74 rc = modbus_receive(ctx, -1, query);
75 if (rc > 0) { 75 if (rc > 0) {