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 2 libmodbus_la_SOURCES = \
3 3 modbus.c \
4 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 13 modbus-version.h
6 14 libmodbus_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(LIBMODBUS_LT_VERSION_INFO)
7 15  
8 16 # Header files to install
9 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 20 DISTCLEANFILES = modbus-version.h
13 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 22  
23 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 25 /* It's not really the minimal length (the real one is report slave ID
37 26 * in RTU (4 bytes)) but it's a convenient size to use in RTU or TCP
38 27 * communications to read many values or write a single one.
... ... @@ -40,34 +29,66 @@ MODBUS_BEGIN_DECLS
40 29 * - HEADER_LENGTH_TCP (7) + function (1) + address (2) + number (2)
41 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 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 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 91 struct _modbus {
69   - /* Communication mode: RTU or TCP */
70   - type_com_t type_com;
71 92 /* Slave address */
72 93 int slave;
73 94 /* Socket or file descriptor */
... ... @@ -76,38 +97,11 @@ struct _modbus {
76 97 int error_recovery;
77 98 struct timeval timeout_begin;
78 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 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 13 *
14 14 * You should have received a copy of the GNU Lesser Public License
15 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 22 #include <stdio.h>
32 23 #include <string.h>
33 24 #include <stdlib.h>
34   -#ifdef HAVE_INTTYPES_H
35   -#include <inttypes.h>
36   -#endif
37   -#ifdef HAVE_STDINT_H
38 25 #include <stdint.h>
39   -#endif
40 26 #include <termios.h>
41 27 #include <unistd.h>
42 28 #include <errno.h>
43   -#include <assert.h>
44 29 #include <limits.h>
45   -#include <fcntl.h>
46 30  
47 31 /* Add this for macros that defined unix flavor */
48 32 #if (defined(__unix__) || defined(unix)) && !defined(USG)
49 33 #include <sys/param.h>
50 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 36 #if !defined(UINT16_MAX)
65 37 #define UINT16_MAX 0xFFFF
66 38 #endif
67 39  
68   -#include <config.h>
69 40 #include "modbus.h"
70 41 #include "modbus-private.h"
71 42  
... ... @@ -77,91 +48,8 @@ const unsigned int libmodbus_version_major = LIBMODBUS_VERSION_MAJOR;
77 48 const unsigned int libmodbus_version_minor = LIBMODBUS_VERSION_MINOR;
78 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 54 const char *modbus_strerror(int errnum) {
167 55 switch (errnum) {
... ... @@ -212,39 +100,7 @@ static void error_print(modbus_t *ctx, const char *context)
212 100  
213 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 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 109 int length;
254 110 int offset;
255 111  
256   - offset = TAB_HEADER_LENGTH[ctx->type_com];
  112 + offset = ctx->backend->header_length;
257 113  
258 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 117 /* Header + nb values (code from write_bits) */
262 118 int nb = (req[offset + 3] << 8) | req[offset + 4];
263 119 length = 2 + (nb / 8) + ((nb % 8) ? 1 : 0);
264 120 }
265 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 125 /* Header + 2 * nb values */
270 126 length = 2 + 2 * (req[offset + 3] << 8 | req[offset + 4]);
271 127 break;
272   - case FC_READ_EXCEPTION_STATUS:
  128 + case _FC_READ_EXCEPTION_STATUS:
273 129 length = 3;
274 130 break;
275   - case FC_REPORT_SLAVE_ID:
  131 + case _FC_REPORT_SLAVE_ID:
276 132 /* The response is device specific (the header provides the
277 133 length) */
278 134 return MSG_LENGTH_UNDEFINED;
... ... @@ -280,171 +136,16 @@ static unsigned int compute_response_length(modbus_t *ctx, uint8_t *req)
280 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 143 static int send_msg(modbus_t *ctx, uint8_t *req, int req_length)
432 144 {
433 145 int rc;
434   - uint16_t s_crc;
435 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 150 if (ctx->debug) {
450 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 156 /* In recovery mode, the write command will be issued until to be
456 157 successful! Disabled by default. */
457 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 160 if (rc == -1) {
468 161 error_print(ctx, NULL);
469 162 if (ctx->error_recovery &&
... ... @@ -501,20 +194,20 @@ static uint8_t compute_header_length(int function, msg_type_t msg_type)
501 194 int length;
502 195  
503 196 if (msg_type == MSG_CONFIRMATION) {
504   - if (function == FC_REPORT_SLAVE_ID) {
  197 + if (function == _FC_REPORT_SLAVE_ID) {
505 198 length = 1;
506 199 } else {
507 200 /* Should never happen, the other header lengths are precomputed */
508 201 abort();
509 202 }
510 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 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 209 length = 5;
517   - } else if (function == FC_READ_AND_WRITE_REGISTERS) {
  210 + } else if (function == _FC_READ_AND_WRITE_REGISTERS) {
518 211 length = 9;
519 212 } else {
520 213 length = 0;
... ... @@ -526,63 +219,62 @@ static uint8_t compute_header_length(int function, msg_type_t msg_type)
526 219 /* Computes the length of the data to write in the request */
527 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 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 232 } else
540 233 length = 0;
541 234  
542   - length += TAB_CHECKSUM_LENGTH[ctx->type_com];
  235 + length += ctx->backend->checksum_length;
543 236  
544 237 return length;
545 238 }
546 239  
547 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 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 279 /* Waits a response from a modbus server or a request from a modbus client.
588 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 332 * reach the function code because all packets contains this
641 333 * information. */
642 334 state = FUNCTION;
643   - msg_length_computed = TAB_HEADER_LENGTH[ctx->type_com] + 1;
  335 + msg_length_computed = ctx->backend->header_length + 1;
644 336 } else {
645 337 tv.tv_sec = ctx->timeout_begin.tv_sec;
646 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 346  
655 347 p_msg = msg;
656 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 350 if (read_rc == 0) {
663 351 errno = ECONNRESET;
664 352 read_rc = -1;
... ... @@ -695,7 +383,7 @@ static int receive_msg(modbus_t *ctx, int msg_length_computed,
695 383 case FUNCTION:
696 384 /* Function code position */
697 385 length_to_read = compute_header_length(
698   - msg[TAB_HEADER_LENGTH[ctx->type_com]],
  386 + msg[ctx->backend->header_length],
699 387 msg_type);
700 388 msg_length_computed += length_to_read;
701 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 394 case DATA:
707 395 length_to_read = compute_data_length(ctx, msg);
708 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 398 errno = EMBBADDATA;
711 399 error_print(ctx, "too many data");
712 400 return -1;
... ... @@ -738,14 +426,7 @@ static int receive_msg(modbus_t *ctx, int msg_length_computed,
738 426 if (ctx->debug)
739 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 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 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 450 The function shall return the number of values (bits or words) and the
770 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 456 {
776 457 int rc;
777 458 int rsp_length_computed;
778   - int offset = TAB_HEADER_LENGTH[ctx->type_com];
  459 + int offset = ctx->backend->header_length;
779 460  
780 461 rsp_length_computed = compute_response_length(ctx, req);
781 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 468 /* The number of values is returned if it's corresponding
788 469 * to the request */
789 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 473 /* Read functions, 8 values in a byte (nb
793 474 * of values in the request and byte count in
794 475 * the response. */
... ... @@ -796,20 +477,20 @@ static int receive_msg_req(modbus_t *ctx, uint8_t *req, uint8_t *rsp)
796 477 req_nb_value = (req_nb_value / 8) + ((req_nb_value % 8) ? 1 : 0);
797 478 rsp_nb_value = rsp[offset + 1];
798 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 483 /* Read functions 1 value = 2 bytes */
803 484 req_nb_value = (req[offset + 3] << 8) + req[offset + 4];
804 485 rsp_nb_value = (rsp[offset + 1] / 2);
805 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 489 /* N Write functions */
809 490 req_nb_value = (req[offset + 3] << 8) + req[offset + 4];
810 491 rsp_nb_value = (rsp[offset + 3] << 8) | rsp[offset + 4];
811 492 break;
812   - case FC_REPORT_SLAVE_ID:
  493 + case _FC_REPORT_SLAVE_ID:
813 494 /* Report slave ID (bytes received) */
814 495 req_nb_value = rsp_nb_value = rsp[offset + 1];
815 496 break;
... ... @@ -833,11 +514,10 @@ static int receive_msg_req(modbus_t *ctx, uint8_t *req, uint8_t *rsp)
833 514 /* EXCEPTION CODE RECEIVED */
834 515  
835 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 522 /* Check for exception response.
843 523 0x80 + function is stored in the exception
... ... @@ -889,7 +569,7 @@ static int response_exception(modbus_t *ctx, sft_t *sft,
889 569 int rsp_length;
890 570  
891 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 574 /* Positive exception code */
895 575 rsp[rsp_length++] = exception_code;
... ... @@ -906,7 +586,7 @@ static int response_exception(modbus_t *ctx, sft_t *sft,
906 586 int modbus_reply(modbus_t *ctx, const uint8_t *req,
907 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 590 int slave = req[offset - 1];
911 591 int function = req[offset];
912 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 594 int rsp_length = 0;
915 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 599 return 0;
926 600 }
927 601  
928 602 sft.slave = slave;
929 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 606 switch (function) {
938   - case FC_READ_COILS: {
  607 + case _FC_READ_COILS: {
939 608 int nb = (req[offset + 3] << 8) + req[offset + 4];
940 609  
941 610 if ((address + nb) > mb_mapping->nb_bits) {
... ... @@ -947,7 +616,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
947 616 ctx, &sft,
948 617 MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp);
949 618 } else {
950   - rsp_length = build_response_basis(ctx, &sft, rsp);
  619 + rsp_length = ctx->backend->build_response_basis(&sft, rsp);
951 620 rsp[rsp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0);
952 621 rsp_length = response_io_status(address, nb,
953 622 mb_mapping->tab_bits,
... ... @@ -955,7 +624,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
955 624 }
956 625 }
957 626 break;
958   - case FC_READ_DISCRETE_INPUTS: {
  627 + case _FC_READ_DISCRETE_INPUTS: {
959 628 /* Similar to coil status (but too many arguments to use a
960 629 * function) */
961 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 638 ctx, &sft,
970 639 MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp);
971 640 } else {
972   - rsp_length = build_response_basis(ctx, &sft, rsp);
  641 + rsp_length = ctx->backend->build_response_basis(&sft, rsp);
973 642 rsp[rsp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0);
974 643 rsp_length = response_io_status(address, nb,
975 644 mb_mapping->tab_input_bits,
... ... @@ -977,7 +646,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
977 646 }
978 647 }
979 648 break;
980   - case FC_READ_HOLDING_REGISTERS: {
  649 + case _FC_READ_HOLDING_REGISTERS: {
981 650 int nb = (req[offset + 3] << 8) + req[offset + 4];
982 651  
983 652 if ((address + nb) > mb_mapping->nb_registers) {
... ... @@ -991,7 +660,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
991 660 } else {
992 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 664 rsp[rsp_length++] = nb << 1;
996 665 for (i = address; i < address + nb; i++) {
997 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 669 }
1001 670 }
1002 671 break;
1003   - case FC_READ_INPUT_REGISTERS: {
  672 + case _FC_READ_INPUT_REGISTERS: {
1004 673 /* Similar to holding registers (but too many arguments to use a
1005 674 * function) */
1006 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 685 } else {
1017 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 689 rsp[rsp_length++] = nb << 1;
1021 690 for (i = address; i < address + nb; i++) {
1022 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 694 }
1026 695 }
1027 696 break;
1028   - case FC_WRITE_SINGLE_COIL:
  697 + case _FC_WRITE_SINGLE_COIL:
1029 698 if (address >= mb_mapping->nb_bits) {
1030 699 if (ctx->debug) {
1031 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 708  
1040 709 if (data == 0xFF00 || data == 0x0) {
1041 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 711 memcpy(rsp, req, req_length);
1048 712 rsp_length = req_length;
1049 713 } else {
... ... @@ -1058,7 +722,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
1058 722 }
1059 723 }
1060 724 break;
1061   - case FC_WRITE_SINGLE_REGISTER:
  725 + case _FC_WRITE_SINGLE_REGISTER:
1062 726 if (address >= mb_mapping->nb_registers) {
1063 727 if (ctx->debug) {
1064 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 739 rsp_length = req_length;
1076 740 }
1077 741 break;
1078   - case FC_WRITE_MULTIPLE_COILS: {
  742 + case _FC_WRITE_MULTIPLE_COILS: {
1079 743 int nb = (req[offset + 3] << 8) + req[offset + 4];
1080 744  
1081 745 if ((address + nb) > mb_mapping->nb_bits) {
... ... @@ -1090,14 +754,14 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
1090 754 /* 6 = byte count */
1091 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 758 /* 4 to copy the bit address (2) and the quantity of bits */
1095 759 memcpy(rsp + rsp_length, req + rsp_length, 4);
1096 760 rsp_length += 4;
1097 761 }
1098 762 }
1099 763 break;
1100   - case FC_WRITE_MULTIPLE_REGISTERS: {
  764 + case _FC_WRITE_MULTIPLE_REGISTERS: {
1101 765 int nb = (req[offset + 3] << 8) + req[offset + 4];
1102 766  
1103 767 if ((address + nb) > mb_mapping->nb_registers) {
... ... @@ -1116,22 +780,22 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
1116 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 784 /* 4 to copy the address (2) and the no. of registers */
1121 785 memcpy(rsp + rsp_length, req + rsp_length, 4);
1122 786 rsp_length += 4;
1123 787 }
1124 788 }
1125 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 792 /* 2 bytes */
1129 793 rsp[rsp_length++] = 2;
1130 794 rsp[rsp_length++] = ctx->slave;
1131 795 /* Slave is ON */
1132 796 rsp[rsp_length++] = 0xFF;
1133 797 break;
1134   - case FC_READ_EXCEPTION_STATUS:
  798 + case _FC_READ_EXCEPTION_STATUS:
1135 799 if (ctx->debug) {
1136 800 fprintf(stderr, "FIXME Not implemented\n");
1137 801 }
... ... @@ -1139,7 +803,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
1139 803 return -1;
1140 804 break;
1141 805  
1142   - case FC_READ_AND_WRITE_REGISTERS: {
  806 + case _FC_READ_AND_WRITE_REGISTERS: {
1143 807 int nb = (req[offset + 3] << 8) + req[offset + 4];
1144 808 uint16_t address_write = (req[offset + 5] << 8) + req[offset + 6];
1145 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 819 MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp);
1156 820 } else {
1157 821 int i, j;
1158   - rsp_length = build_response_basis(ctx, &sft, rsp);
  822 + rsp_length = ctx->backend->build_response_basis(&sft, rsp);
1159 823 rsp[rsp_length++] = nb << 1;
1160 824  
1161 825 for (i = address; i < address + nb; i++) {
... ... @@ -1189,10 +853,10 @@ static int read_io_status(modbus_t *ctx, int function,
1189 853 int rc;
1190 854 int req_length;
1191 855  
1192   - uint8_t req[MIN_REQ_LENGTH];
  856 + uint8_t req[_MIN_REQ_LENGTH];
1193 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 861 rc = send_msg(ctx, req, req_length);
1198 862 if (rc > 0) {
... ... @@ -1205,7 +869,7 @@ static int read_io_status(modbus_t *ctx, int function,
1205 869 if (rc == -1)
1206 870 return -1;
1207 871  
1208   - offset = TAB_HEADER_LENGTH[ctx->type_com] + 2;
  872 + offset = ctx->backend->header_length + 2;
1209 873 offset_end = offset + rc;
1210 874 for (i = offset; i < offset_end; i++) {
1211 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 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 907 if (rc == -1)
1244 908 return -1;
... ... @@ -1262,7 +926,7 @@ int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *data_dest)
1262 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 931 if (rc == -1)
1268 932 return -1;
... ... @@ -1276,7 +940,7 @@ static int read_registers(modbus_t *ctx, int function, int addr, int nb,
1276 940 {
1277 941 int rc;
1278 942 int req_length;
1279   - uint8_t req[MIN_REQ_LENGTH];
  943 + uint8_t req[_MIN_REQ_LENGTH];
1280 944 uint8_t rsp[MAX_MESSAGE_LENGTH];
1281 945  
1282 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 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 958 rc = send_msg(ctx, req, req_length);
1295 959 if (rc > 0) {
... ... @@ -1301,7 +965,7 @@ static int read_registers(modbus_t *ctx, int function, int addr, int nb,
1301 965 return -1;
1302 966 }
1303 967  
1304   - offset = TAB_HEADER_LENGTH[ctx->type_com];
  968 + offset = ctx->backend->header_length;
1305 969  
1306 970 for (i = 0; i < rc; i++) {
1307 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 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 997 addr, nb, data_dest);
1334 998 return status;
1335 999 }
... ... @@ -1348,7 +1012,7 @@ int modbus_read_input_registers(modbus_t *ctx, int addr, int nb,
1348 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 1016 addr, nb, data_dest);
1353 1017  
1354 1018 return status;
... ... @@ -1360,14 +1024,14 @@ static int write_single(modbus_t *ctx, int function, int addr, int value)
1360 1024 {
1361 1025 int rc;
1362 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 1031 rc = send_msg(ctx, req, req_length);
1368 1032 if (rc > 0) {
1369 1033 /* Used by write_bit and write_register */
1370   - uint8_t rsp[MIN_REQ_LENGTH];
  1034 + uint8_t rsp[_MIN_REQ_LENGTH];
1371 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 1046 if (state)
1383 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 1051 return status;
1388 1052 }
... ... @@ -1392,7 +1056,7 @@ int modbus_write_register(modbus_t *ctx, int addr, int value)
1392 1056 {
1393 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 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 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 1087 byte_count = (nb / 8) + ((nb % 8) ? 1 : 0);
1424 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 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 1140 byte_count = nb * 2;
1476 1141 req[req_length++] = byte_count;
1477 1142  
... ... @@ -1521,8 +1186,9 @@ int modbus_read_and_write_registers(modbus_t *ctx,
1521 1186 errno = EMBMDATA;
1522 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 1193 req[req_length++] = write_addr >> 8;
1528 1194 req[req_length++] = write_addr & 0x00ff;
... ... @@ -1541,7 +1207,7 @@ int modbus_read_and_write_registers(modbus_t *ctx,
1541 1207 int offset;
1542 1208  
1543 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 1212 /* If rc is negative, the loop is jumped ! */
1547 1213 for (i = 0; i < rc; i++) {
... ... @@ -1560,9 +1226,10 @@ int modbus_report_slave_id(modbus_t *ctx, uint8_t *data_dest)
1560 1226 {
1561 1227 int rc;
1562 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 1234 /* HACKISH, addr and count are not used */
1568 1235 req_length -= 4;
... ... @@ -1579,7 +1246,7 @@ int modbus_report_slave_id(modbus_t *ctx, uint8_t *data_dest)
1579 1246 if (rc == -1)
1580 1247 return -1;
1581 1248  
1582   - offset = TAB_HEADER_LENGTH[ctx->type_com] + 2;
  1249 + offset = ctx->backend->header_length + 2;
1583 1250  
1584 1251 for (i=0; i < rc; i++) {
1585 1252 data_dest[i] = rsp[offset + i];
... ... @@ -1589,105 +1256,22 @@ int modbus_report_slave_id(modbus_t *ctx, uint8_t *data_dest)
1589 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 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 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 1267 ctx->error_recovery = FALSE;
1601 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 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 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 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 1331 /* Closes a connection */
... ... @@ -2089,10 +1334,7 @@ void modbus_close(modbus_t *ctx)
2089 1334 if (ctx == NULL)
2090 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 1340 /* Free an initialized modbus_t */
... ... @@ -2101,7 +1343,7 @@ void modbus_free(modbus_t *ctx)
2101 1343 if (ctx == NULL)
2102 1344 return;
2103 1345  
2104   - free(ctx->com);
  1346 + free(ctx->backend_data);
2105 1347 free(ctx);
2106 1348 }
2107 1349  
... ... @@ -2203,146 +1445,12 @@ void modbus_mapping_free(modbus_mapping_t *mb_mapping)
2203 1445 free(mb_mapping);
2204 1446 }
2205 1447  
2206   -/* Listens for any request from one or many modbus masters in TCP */
2207 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 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 22 #if (defined(__unix__) || defined(unix)) && !defined(USG)
23 23 #include <sys/param.h>
24 24 #endif
25   -
26   -#ifdef HAVE_INTTYPES_H
27   -#include <inttypes.h>
28   -#endif
29   -#ifdef HAVE_STDINT_H
30 25 #include <stdint.h>
31   -#endif
32 26 #include <termios.h>
33   -#if defined(OpenBSD) || (defined(__FreeBSD__ ) && __FreeBSD__ < 5)
  27 +#if defined(OpenBSD) || (defined(__FreeBSD__) && __FreeBSD__ < 5)
34 28 #include <netinet/in_systm.h>
35 29 #endif
36 30 #include <netinet/in.h>
... ... @@ -67,16 +61,7 @@ MODBUS_BEGIN_DECLS
67 61 #define ON 1
68 62 #endif
69 63  
70   -#define MODBUS_TCP_DEFAULT_PORT 502
71 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 66 /* Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 1 page 12)
82 67 * Quantity of Coils to read (2 bytes): 1 to 2000 (0x7D0)
... ... @@ -151,12 +136,8 @@ typedef struct {
151 136 uint16_t *tab_registers;
152 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 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 141 int modbus_set_error_recovery(modbus_t *ctx, int enabled);
161 142  
162 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 195  
215 196 MODBUS_END_DECLS
216 197  
  198 +#include "modbus-tcp.h"
  199 +#include "modbus-rtu.h"
  200 +
217 201 #endif /* _MODBUS_H_ */
... ...
tests/bandwidth-server-many-up.c
... ... @@ -108,7 +108,7 @@ int main(void)
108 108 }
109 109 } else {
110 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 113 rc = modbus_receive(ctx, master_socket, query);
114 114 if (rc != -1) {
... ...
tests/bandwidth-server-one.c
... ... @@ -45,7 +45,7 @@ int main(void)
45 45 modbus_accept(ctx, &socket);
46 46  
47 47 for(;;) {
48   - uint8_t query[MODBUS_MAX_ADU_LENGTH_TCP];
  48 + uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];
49 49  
50 50 rc = modbus_receive(ctx, -1, query);
51 51 if (rc >= 0) {
... ...
tests/random-test-server.c
... ... @@ -43,7 +43,7 @@ int main(void)
43 43 modbus_accept(ctx, &socket);
44 44  
45 45 for (;;) {
46   - uint8_t query[MODBUS_MAX_ADU_LENGTH_TCP];
  46 + uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];
47 47 int rc;
48 48  
49 49 rc = modbus_receive(ctx, -1, query);
... ...
tests/unit-test-server.c
... ... @@ -69,7 +69,7 @@ int main(void)
69 69 modbus_accept(ctx, &socket);
70 70  
71 71 for (;;) {
72   - uint8_t query[MODBUS_MAX_ADU_LENGTH_TCP];
  72 + uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];
73 73  
74 74 rc = modbus_receive(ctx, -1, query);
75 75 if (rc > 0) {
... ...