Commit 527f96d4ef8e258e1f2f90c6c9b8b214bc555770

Authored by Peter M. Groen
1 parent e1f771b9

Setting up working version

src/ConnectionConfig.h
... ... @@ -7,7 +7,7 @@
7 7 #include <unordered_map>
8 8  
9 9 /*!
10   - * \brief The ConnectionPort enum.
  10 + * The ConnectionPort enum.
11 11 * CP_EXTERNAL - the first serial port
12 12 * CP_IOBUS - The second serial port through RJ45 connector
13 13 * CP_TCP - TCP Connections
... ... @@ -20,7 +20,7 @@ enum class ConnectionPort : unsigned int
20 20 };
21 21  
22 22 /*!
23   - * \brief The Parity enum.
  23 + * The Parity enum.
24 24 * Used in a serial port context
25 25 */
26 26 enum class Parity : unsigned int
... ... @@ -31,7 +31,7 @@ enum class Parity : unsigned int
31 31 };
32 32  
33 33 /*!
34   - * \brief The ConnectionType enum.
  34 + * The ConnectionType enum.
35 35 * Added for convenience, to distinguish between types.
36 36 */
37 37 enum class ConnectionType : unsigned int
... ... @@ -42,7 +42,7 @@ enum class ConnectionType : unsigned int
42 42 };
43 43  
44 44 /*!
45   - * \brief The ConnectionConfig class holds all the information we need to establish a proper connection.
  45 + * The ConnectionConfig class holds all the information we need to establish a proper connection.
46 46 * It can be created by a configuration object and passed on to the ModBus stack.
47 47 * By using this class, all the connectioninfo is within its context for convenience.
48 48 *
... ... @@ -53,88 +53,88 @@ class ConnectionConfig
53 53 {
54 54 public:
55 55 /*!
56   - * \brief ConnectionConfig Constructor. Used to create a new serial connection.
57   - * \param port - The portname given by its enum.
58   - * \param baud - The port speed in a serial port context ( default = 115200 )
59   - * \param parity - The parity. ( Default : None, no parity )
60   - * \param dataBits - The number of databits. RTU uses 8 (0 - 255), ASCII uses 7 (0 - 127). Default is RTU
61   - * \param stopBits - The number of stopbits used to detect the end of the frame. ( Default = 1 )
62   - * \param timeOut - Timeout in .1 secs. See the termios documentation for deviations on this.
  56 + * ConnectionConfig Constructor. Used to create a new serial connection.
  57 + * @param port - The portname given by its enum.
  58 + * @param baud - The port speed in a serial port context ( default = 115200 )
  59 + * @param parity - The parity. ( Default : None, no parity )
  60 + * @param dataBits - The number of databits. RTU uses 8 (0 - 255), ASCII uses 7 (0 - 127). Default is RTU
  61 + * @param stopBits - The number of stopbits used to detect the end of the frame. ( Default = 1 )
  62 + * @param timeOut - Timeout in .1 secs. See the termios documentation for deviations on this.
63 63 */
64 64 ConnectionConfig( ConnectionPort port, int baud = 115200, Parity parity = Parity::PAR_NONE, int dataBits = 8, int stopBits = 1, int timeOut = -1 )
65   - : m_port( port )
66   - , m_baudRate( baud )
67   - , m_parity( parity )
68   - , m_dataBits( dataBits )
69   - , m_stopBits( stopBits )
70   - , m_ipaddress()
71   - , m_portnumber( -1 )
72   - , m_timeOut( timeOut )
73   - , m_conType( ConnectionType::CT_SERIAL )
  65 + : port( port )
  66 + , baudRate( baud )
  67 + , parity( parity )
  68 + , dataBits( dataBits )
  69 + , stopBits( stopBits )
  70 + , ipaddress()
  71 + , portnumber( -1 )
  72 + , timeOut( timeOut )
  73 + , connectionType( ConnectionType::CT_SERIAL )
74 74 {}
75 75  
76 76 /*!
77 77 * \brief ConnectionConfig Constructor. Used to create a new TCP connection.
78   - * \param port - The portname given by its enaum. ( Should be CP_TCP )
79   - * \param ip - The ip address of the ModBus device we want to connect to.
80   - * \param portnum - The portnumber the ModBus device is using
81   - * \param timeOut - Timeout in which a modbus device should respond.
  78 + * @param port - The portname given by its enaum. ( Should be CP_TCP )
  79 + * @param ip - The ip address of the ModBus device we want to connect to.
  80 + * @param portnum - The portnumber the ModBus device is using
  81 + * @param timeOut - Timeout in which a modbus device should respond.
82 82 */
83 83 ConnectionConfig( ConnectionPort port, const std::string &ip, int portnum, int timeOut = -1 )
84   - : m_port( port )
85   - , m_baudRate( -1 )
86   - , m_parity( Parity::PAR_NONE )
87   - , m_dataBits( -1 )
88   - , m_stopBits( -1 )
89   - , m_ipaddress( ip )
90   - , m_portnumber( portnum )
91   - , m_timeOut( timeOut )
92   - , m_conType( ConnectionType::CT_TCP )
  84 + : port( port )
  85 + , baudRate( -1 )
  86 + , parity( Parity::PAR_NONE )
  87 + , dataBits( -1 )
  88 + , stopBits( -1 )
  89 + , ipaddress( ip )
  90 + , portnumber( portnum )
  91 + , timeOut( timeOut )
  92 + , connectionType( ConnectionType::CT_TCP )
93 93 {}
94 94  
95 95 // Getters and Setters. Implemented to avoid outside meddling on the member variables.
96   - std::string getPort() const { return m_portMap.at(m_port); } ///< Get the translated portName.
97   - ConnectionPort getPortEnum() const { return m_port; } ///< Get the portname Enum
98   - int getBaudRate() const { return m_baudRate; } ///< Get the given baudrate as int.
99   - char getParity() const { return m_parityMap.at(m_parity); } ///< Get the translated parity.
100   - Parity getParityEnum() const { return m_parity; } ///< Get the parity Enum
101   - int getDataBits() const { return m_dataBits; } ///< Get the number of databits ( 7 for ASCII, 8 for RTU )
102   - int getStopBits() const { return m_stopBits; } ///< Get the number of stopBits. ( de-facto = 1 )
  96 + std::string getPort() const { return portMap.at(port); } ///< Get the translated portName.
  97 + ConnectionPort getPortEnum() const { return port; } ///< Get the portname Enum
  98 + int getBaudRate() const { return baudRate; } ///< Get the given baudrate as int.
  99 + char getParity() const { return parityMap.at( parity ); } ///< Get the translated parity.
  100 + Parity getParityEnum() const { return parity; } ///< Get the parity Enum
  101 + int getDataBits() const { return dataBits; } ///< Get the number of databits ( 7 for ASCII, 8 for RTU )
  102 + int getStopBits() const { return stopBits; } ///< Get the number of stopBits. ( de-facto = 1 )
103 103  
104   - std::string getIpAddress() const { return m_ipaddress; } ///< Get the ip-address as string
105   - int getTcpPort() const { return m_portnumber; } ///< Get the tcp portnumber as int
  104 + std::string getIpAddress() const { return ipaddress; } ///< Get the ip-address as string
  105 + int getTcpPort() const { return portnumber; } ///< Get the tcp portnumber as int
106 106  
107   - int getTimeOut() const { return m_timeOut; } ///< Get the timeout as a multitude of 0.1 sec.
108   - ConnectionType getType() const { return m_conType; } ///< Get the connection type ( Serial, TCP or Unknown )
  107 + int getTimeOut() const { return timeOut; } ///< Get the timeout as a multitude of 0.1 sec.
  108 + ConnectionType getType() const { return connectionType; } ///< Get the connection type ( Serial, TCP or Unknown )
109 109  
110 110 private:
111 111  
112 112 /// Serial connections
113   - ConnectionPort m_port; ///< Member variable holding the portName Enum
114   - int m_baudRate; ///< Member variable holding the Serial port Baudrate
115   - Parity m_parity; ///< Member variable holding the Serial port Parity
116   - int m_dataBits; ///< Member variable holding the number of databits
117   - int m_stopBits; ///< Member variable holding the number of stopbits
  113 + ConnectionPort port; ///< Member variable holding the portName Enum
  114 + int baudRate; ///< Member variable holding the Serial port Baudrate
  115 + Parity parity; ///< Member variable holding the Serial port Parity
  116 + int dataBits; ///< Member variable holding the number of databits
  117 + int stopBits; ///< Member variable holding the number of stopbits
118 118  
119 119 /// TCP connections
120   - std::string m_ipaddress; ///< Member variable holding the ip-address of the TCP-connection
121   - int m_portnumber; ///< Member variable holding the portnumber of the TCP-connection
  120 + std::string ipaddress; ///< Member variable holding the ip-address of the TCP-connection
  121 + int portnumber; ///< Member variable holding the portnumber of the TCP-connection
122 122  
123 123 /// Generic
124   - int m_timeOut; ///< Member variable holding the timeOut value
125   - ConnectionType m_conType; ///< Member variable holding the connection type.
  124 + int timeOut; ///< Member variable holding the timeOut value
  125 + ConnectionType connectionType; ///< Member variable holding the connection type.
126 126  
127 127 /// Translation tables for portnames and parity.
128 128 // ============================================================
129 129 // == Change accordingly to the devicenames on your platform ==
130 130 // ============================================================
131   - std::unordered_map<ConnectionPort, std::string> m_portMap =
  131 + std::unordered_map<ConnectionPort, std::string> portMap =
132 132 {
133 133 { ConnectionPort::CP_EXTERNAL, "/dev/ttyUSB0" },
134 134 { ConnectionPort::CP_IOBUS, "/dev/ttyUSB1" }
135 135 };
136 136  
137   - std::unordered_map<Parity, char> m_parityMap =
  137 + std::unordered_map<Parity, char> parityMap =
138 138 {
139 139 { Parity::PAR_EVEN, 'E' },
140 140 { Parity::PAR_ODD, 'O' },
... ...
src/IModbusAdapter.h
... ... @@ -15,7 +15,7 @@ using modbusData = std::vector&lt;std::variant&lt;uint8_t, uint16_t&gt;&gt;;
15 15 class ConnectionConfig;
16 16  
17 17 /*!
18   - * \brief The IModbusAdapter class provides an abstract way of using
  18 + * The IModbusAdapter class provides an abstract way of using
19 19 * the modbus stack. Implemented as a pure virtual, it cannot be instantiated.
20 20 * This represents a unique connection to either a serial bus or a TCP connection.
21 21 */
... ... @@ -30,55 +30,55 @@ public:
30 30 virtual bool ModbusConnect( const ConnectionConfig &conncfg ) = 0;
31 31  
32 32 /*!
33   - * \brief ModbusDisconnect
  33 + * ModbusDisconnect
34 34 * Disconnect from the serial bus or the TCP connection, freeing its resources
35 35 */
36 36 virtual bool ModbusDisconnect() = 0;
37 37  
38 38 /*!
39   - * \brief Read data from a modbus device given by its parameters.
40   - * \param slaveId - The Id of the ModbusDevice.
41   - * \param functionCode - The code describing the action we want to perform on the device.
  39 + * Read data from a modbus device given by its parameters.
  40 + * @param slaveId - The Id of the ModbusDevice.
  41 + * @param functionCode - The code describing the action we want to perform on the device.
42 42 * Given by an enum, provided by the modbus-stack.
43   - * \param startAddress - Startaddres of the register we want to read.
44   - * \param noOfItems - The number of items we expect back.
45   - * \returns modbusData - A vector holding each register in an entry in the same order as they are received.
  43 + * @param startAddress - Startaddres of the register we want to read.
  44 + * @param noOfItems - The number of items we expect back.
  45 + * @returns modbusData - A vector holding each register in an entry in the same order as they are received.
46 46 * Empty if no data was received.
47 47 */
48 48 virtual modbusData ModbusReadData( int slaveId, int functionCode, int startAddress, int noOfItems ) = 0;
49 49  
50 50 /*!
51   - * \brief Read data from the holdregisters ( or keep-registers ) of a modbus device.
52   - * \param slaveId - The Id of the ModbusDevice.
53   - * \param startAddress - Startaddres of the register we want to read.
54   - * \param noOfItems - The number of items we expect back.
55   - * \returns modbusData - A vector holding each register in an entry in the same order as they are received.
  51 + * Read data from the holdregisters ( or keep-registers ) of a modbus device.
  52 + * @param slaveId - The Id of the ModbusDevice.
  53 + * @param startAddress - Startaddres of the register we want to read.
  54 + * @param noOfItems - The number of items we expect back.
  55 + * @returns modbusData - A vector holding each register in an entry in the same order as they are received.
56 56 * Empty if no data was received.
57 57 */
58 58 virtual modbusData ModbusReadHoldReg( int slaveId, int startAddress, int noOfItems ) = 0;
59 59  
60 60 /*!
61   - * \brief Write data to the device.
62   - * \param slaveId - The Id of the Modbus device
63   - * \param funtionCode - The code describing the action we want to perform on the device
  61 + * Write data to the device.
  62 + * @param slaveId - The Id of the Modbus device
  63 + * @param funtionCode - The code describing the action we want to perform on the device
64 64 * given by an enum, provided by the modbus-stack.
65   - * \param startAddress - Startaddres of the register we want to read.
66   - * \param noOfItems - The number of items we expect to be written
67   - * \param values - The values we want to write to the given device. Each vector-entry represents a single byte
  65 + * @param startAddress - Startaddres of the register we want to read.
  66 + * @param noOfItems - The number of items we expect to be written
  67 + * @param values - The values we want to write to the given device. Each vector-entry represents a single byte
68 68 * and they will be sent in sequence.
69 69 */
70 70 virtual void ModBusWriteData( int slaveId, int functionCode, int startAddress, int noOfItems, std::vector<int>values ) = 0;
71 71  
72 72 /*!
73   - * \brief Indicates if this connection is alive.
74   - * \return True if alive, false if not.
  73 + * Indicates if this connection is alive.
  74 + * @return True if alive, false if not.
75 75 */
76 76 virtual bool isConnected() const = 0;
77 77  
78 78 /*!
79   - * \brief returns the translated error code coming from the modbus stack.
80   - * \param errnum - error Number coming from the stack.
81   - * \return The translated error as a string. Empty if not resolvable.
  79 + * returns the translated error code coming from the modbus stack.
  80 + * @param errnum - error Number coming from the stack.
  81 + * @return The translated error as a string. Empty if not resolvable.
82 82 */
83 83 virtual std::string ErrorString( int errnum ) const = 0;
84 84 };
... ...
src/ModbusAdapter.cpp
... ... @@ -5,7 +5,7 @@
5 5 #include <cstring> /// Added for memset functionality
6 6  
7 7 ModbusAdapter::ModbusAdapter()
8   - : m_modbus( nullptr )
  8 + : modbus( nullptr )
9 9 {
10 10 this->InitBuffers();
11 11 }
... ... @@ -15,52 +15,52 @@ ModbusAdapter::~ModbusAdapter()
15 15  
16 16 }
17 17  
18   -bool ModbusAdapter::ModbusConnect( const ConnectionConfig &conncfg )
  18 +bool ModbusAdapter::ModbusConnect( const ConnectionConfig &config )
19 19 {
20   - if( m_connected )
  20 + if( connected )
21 21 {
22 22 this->ModbusDisconnect(); // Will already set m_connected
23 23 }
24 24  
25   - m_connType = conncfg.getType();
  25 + connectionType = config.getType();
26 26  
27   - switch( m_connType )
  27 + switch( connectionType )
28 28 {
29 29 case ConnectionType::CT_SERIAL:
30   - m_connected = this->ModbusConnectRTU( conncfg.getPort(), conncfg.getBaudRate(), conncfg.getParity(), conncfg.getDataBits(), conncfg.getStopBits(), conncfg.getTimeOut(), MODBUS_RTU_RTS_NONE );
  30 + connected = this->ModbusConnectRTU( config.getPort(), config.getBaudRate(), config.getParity(), config.getDataBits(), config.getStopBits(), config.getTimeOut(), MODBUS_RTU_RTS_NONE );
31 31 break;
32 32  
33 33 case ConnectionType::CT_TCP:
34   - m_connected = this->ModbusConnectTCP( conncfg.getIpAddress(), conncfg.getTcpPort(), 10 );
  34 + connected = this->ModbusConnectTCP( config.getIpAddress(), config.getTcpPort(), 10 );
35 35 break;
36 36  
37 37 default:
38 38 // throw a sensible message or return an errorcode.
39 39 break;
40 40 }
41   - return m_connected;
  41 + return connected;
42 42 }
43 43  
44 44 bool ModbusAdapter::ModbusDisconnect()
45 45 {
46   - if( m_modbus != nullptr )
  46 + if( modbus != nullptr )
47 47 {
48   - if( m_connected )
  48 + if( connected )
49 49 {
50   - modbus_close( m_modbus );
51   - modbus_free( m_modbus );
  50 + modbus_close( modbus );
  51 + modbus_free( modbus );
52 52 }
53 53 // Clean up after ourselves.
54   - m_modbus = nullptr;
  54 + modbus = nullptr;
55 55 }
56 56  
57   - m_connected = false;
  57 + connected = false;
58 58 return true;
59 59 }
60 60  
61 61 modbusData ModbusAdapter::ModbusReadData( int slaveId, int functionCode, int startAddress, int noOfItems )
62 62 {
63   - if( m_modbus == nullptr )
  63 + if( modbus == nullptr )
64 64 {
65 65 // No context
66 66 return modbusData();
... ... @@ -69,22 +69,22 @@ modbusData ModbusAdapter::ModbusReadData( int slaveId, int functionCode, int sta
69 69 int resultValue = -1;
70 70 bool is16Bit = false;
71 71  
72   - modbus_set_slave( m_modbus, slaveId );
  72 + modbus_set_slave( modbus, slaveId );
73 73  
74 74 // Request data from modbus.
75 75 switch( functionCode )
76 76 {
77 77 case MODBUS_FC_READ_COILS:
78   - resultValue = modbus_read_bits( m_modbus, startAddress, noOfItems, m_dest );
  78 + resultValue = modbus_read_bits( modbus, startAddress, noOfItems, m_dest );
79 79 break;
80 80 case MODBUS_FC_READ_DISCRETE_INPUTS:
81   - resultValue = modbus_read_input_bits( m_modbus, startAddress, noOfItems, m_dest );
  81 + resultValue = modbus_read_input_bits( modbus, startAddress, noOfItems, m_dest );
82 82 break;
83 83 case MODBUS_FC_READ_HOLDING_REGISTERS:
84   - resultValue = modbus_read_registers( m_modbus, startAddress, noOfItems, m_dest16 );
  84 + resultValue = modbus_read_registers( modbus, startAddress, noOfItems, m_dest16 );
85 85 break;
86 86 case MODBUS_FC_READ_INPUT_REGISTERS:
87   - resultValue = modbus_read_input_registers( m_modbus, startAddress, noOfItems, m_dest16 );
  87 + resultValue = modbus_read_input_registers( modbus, startAddress, noOfItems, m_dest16 );
88 88 break;
89 89  
90 90 default:
... ... @@ -104,7 +104,7 @@ modbusData ModbusAdapter::ModbusReadData( int slaveId, int functionCode, int sta
104 104 resultData.push_back( (is16Bit ? static_cast<uint16_t>(m_dest16[index]) : static_cast<uint16_t>(m_dest[index])) );
105 105 }
106 106  
107   - modbus_flush( m_modbus ); // flush data
  107 + modbus_flush( modbus ); // flush data
108 108 this->ClearBuffers();
109 109  
110 110 return resultData;
... ... @@ -112,7 +112,7 @@ modbusData ModbusAdapter::ModbusReadData( int slaveId, int functionCode, int sta
112 112  
113 113 modbusData ModbusAdapter::ModbusReadHoldReg( int slaveId, int startAddress, int noOfItems )
114 114 {
115   - if( m_modbus == nullptr )
  115 + if( modbus == nullptr )
116 116 {
117 117 return modbusData();
118 118 }
... ... @@ -121,9 +121,9 @@ modbusData ModbusAdapter::ModbusReadHoldReg( int slaveId, int startAddress, int
121 121  
122 122 // -- Start Critical Section --- ?? //
123 123  
124   - modbus_set_slave( m_modbus, slaveId );
  124 + modbus_set_slave( modbus, slaveId );
125 125 /// Request data from modbus
126   - resultValue = modbus_read_registers( m_modbus, startAddress, noOfItems, m_dest16 );
  126 + resultValue = modbus_read_registers( modbus, startAddress, noOfItems, m_dest16 );
127 127  
128 128 /// Read the databuffers
129 129 if( resultValue != noOfItems )
... ... @@ -137,7 +137,7 @@ modbusData ModbusAdapter::ModbusReadHoldReg( int slaveId, int startAddress, int
137 137 resultData.push_back( static_cast<uint16_t>(m_dest16[index]) );
138 138 }
139 139  
140   - modbus_flush( m_modbus );
  140 + modbus_flush( modbus );
141 141 this->ClearBuffers();
142 142  
143 143 // -- End Critical Section --- ?? //
... ... @@ -147,7 +147,7 @@ modbusData ModbusAdapter::ModbusReadHoldReg( int slaveId, int startAddress, int
147 147  
148 148 void ModbusAdapter::ModBusWriteData( int slaveId, int functionCode, int startAddress, int noOfItems, std::vector<int>values )
149 149 {
150   - if( m_modbus == nullptr )
  150 + if( modbus == nullptr )
151 151 {
152 152 // No modbus context. Sensible log-line and exit.
153 153 return;
... ... @@ -171,31 +171,31 @@ void ModbusAdapter::ModBusWriteData( int slaveId, int functionCode, int startAdd
171 171  
172 172 int resultValue = -1;
173 173  
174   - modbus_set_slave( m_modbus, slaveId );
  174 + modbus_set_slave( modbus, slaveId );
175 175  
176 176 // Request data from modbus
177 177 switch( functionCode )
178 178 {
179 179 case MODBUS_FC_WRITE_SINGLE_COIL:
180   - resultValue = modbus_write_bit( m_modbus, startAddress, values[0] );
  180 + resultValue = modbus_write_bit( modbus, startAddress, values[0] );
181 181 noOfItems = 1;
182 182 break;
183 183 case MODBUS_FC_WRITE_SINGLE_REGISTER:
184   - resultValue = modbus_write_register( m_modbus, startAddress, values[0] );
  184 + resultValue = modbus_write_register( modbus, startAddress, values[0] );
185 185 noOfItems = 1;
186 186 break;
187 187 case MODBUS_FC_WRITE_MULTIPLE_COILS:
188 188  
189   - resultValue = modbus_write_bits( m_modbus, startAddress, noOfItems, data8 );
  189 + resultValue = modbus_write_bits( modbus, startAddress, noOfItems, data8 );
190 190 break;
191 191 case MODBUS_FC_WRITE_MULTIPLE_REGISTERS:
192   - resultValue = modbus_write_bits( m_modbus, startAddress, noOfItems, data16 );
  192 + resultValue = modbus_write_bits( modbus, startAddress, noOfItems, data16 );
193 193 break;
194 194 }
195 195  
196 196 delete[] data8;
197 197 delete[] data16;
198   - modbus_flush(m_modbus); // Flush data.
  198 + modbus_flush(modbus); // Flush data.
199 199  
200 200 if( resultValue != noOfItems )
201 201 {
... ... @@ -205,7 +205,7 @@ void ModbusAdapter::ModBusWriteData( int slaveId, int functionCode, int startAdd
205 205  
206 206 bool ModbusAdapter::isConnected() const
207 207 {
208   - return m_connected;
  208 + return connected;
209 209 }
210 210  
211 211 std::string ModbusAdapter::ErrorString( int errnum ) const
... ... @@ -235,37 +235,37 @@ std::string ModbusAdapter::ErrorString( int errnum ) const
235 235 /* ============= PRIVATE METHODS ============= */
236 236 bool ModbusAdapter::ModbusConnectRTU( const std::string &serialport, int baud, char parity, int dataBits, int stopBits, int RTS, int timeOut )
237 237 {
238   - m_modbus = modbus_new_rtu( serialport.c_str(), baud, parity, dataBits, stopBits, RTS );
  238 + modbus = modbus_new_rtu( serialport.c_str(), baud, parity, dataBits, stopBits, RTS );
239 239  
240 240 #ifdef LIB_MODBUS_DEBUG_OUTPUT
241 241 // Do sensible logging through PRIVA_LOG
242 242 m_modbus_set_debug( m_modbus, 1 );
243 243 #endif
244   - if( m_modbus == nullptr )
  244 + if( modbus == nullptr )
245 245 {
246 246 // We can stop here. Nothing to be done as we don't have a valid context
247 247 // Log to PRIVA_LOG
248   - m_connected = false;
249   - return m_connected;
  248 + connected = false;
  249 + return connected;
250 250 }
251   - else if( m_modbus && modbus_connect( m_modbus ) == -1 )
  251 + else if( modbus && modbus_connect( modbus ) == -1 )
252 252 {
253 253 // We could not connect to the selected serial port.
254 254 // We can stop here. Nothing to be done as we don't have a valid connection
255   - modbus_free( m_modbus );
256   - m_connected = false;
257   - return m_connected;
  255 + modbus_free( modbus );
  256 + connected = false;
  257 + return connected;
258 258 }
259 259  
260   - m_connected = true;
  260 + connected = true;
261 261  
262 262 // Set recovery mode
263   - modbus_set_error_recovery( m_modbus, MODBUS_ERROR_RECOVERY_PROTOCOL );
  263 + modbus_set_error_recovery( modbus, MODBUS_ERROR_RECOVERY_PROTOCOL );
264 264  
265 265 // Set the response timeout
266   - modbus_set_response_timeout( m_modbus, timeOut, 0 );
  266 + modbus_set_response_timeout( modbus, timeOut, 0 );
267 267  
268   - return m_connected;
  268 + return connected;
269 269 }
270 270  
271 271 bool ModbusAdapter::ModbusConnectTCP( const std::string &ip, int port, int timeOut )
... ... @@ -276,37 +276,37 @@ bool ModbusAdapter::ModbusConnectTCP( const std::string &amp;ip, int port, int timeO
276 276 return false;
277 277 }
278 278  
279   - m_modbus = modbus_new_tcp( ip.c_str(), port );
  279 + modbus = modbus_new_tcp( ip.c_str(), port );
280 280  
281 281 #ifdef LIB_MODBUS_DEBUG_OUTPUT
282 282 // Do sensible logging through PRIVA_LOG
283 283 m_modbus_set_debug( m_modbus, 1 );
284 284 #endif
285 285  
286   - if( m_modbus == nullptr )
  286 + if( modbus == nullptr )
287 287 {
288 288 // We can stop here. Nothing to be done as we don't have a valid context
289 289 // Log to PRIVA_LOG
290 290 return false;
291 291 }
292   - else if( m_modbus && modbus_connect( m_modbus ) == -1 )
  292 + else if( modbus && modbus_connect( modbus ) == -1 )
293 293 {
294 294 // We could not connect to the selected serial port.
295 295 // We can stop here. Nothing to be done as we don't have a valid connection
296   - modbus_free( m_modbus );
297   - m_connected = false;
298   - return m_connected;
  296 + modbus_free( modbus );
  297 + connected = false;
  298 + return connected;
299 299 }
300 300  
301   - m_connected = true;
  301 + connected = true;
302 302  
303 303 // Set recovery mode
304   - modbus_set_error_recovery( m_modbus, MODBUS_ERROR_RECOVERY_PROTOCOL );
  304 + modbus_set_error_recovery( modbus, MODBUS_ERROR_RECOVERY_PROTOCOL );
305 305  
306 306 // Set the response timeout
307   - modbus_set_response_timeout( m_modbus, timeOut, 0 );
  307 + modbus_set_response_timeout( modbus, timeOut, 0 );
308 308  
309   - return m_connected;
  309 + return connected;
310 310 }
311 311  
312 312 void ModbusAdapter::InitBuffers()
... ...
src/ModbusAdapter.h
... ... @@ -13,78 +13,79 @@
13 13 #include <variant>
14 14 #include <vector>
15 15  
16   -/// @brief The ModbusAdapter class represents a single modbus context. Each context will
17   -/// result in an instance of this class. It is not intended to be
18   -/// created directly but through a factory. The factory will create
19   -/// the object and return the pointer to its interface.
  16 +
  17 +/// @class The ModbusAdapter class represents a single modbus context. Each context will
  18 +/// result in an instance of this class. It is not intended to be
  19 +/// created directly but through a factory. The factory will create
  20 +/// the object and return the pointer to its interface.
20 21 class ModbusAdapter : public IModbusAdapter
21 22 {
22 23 public:
23 24 /*!
24   - * \brief Default constructor
  25 + * Default constructor
25 26 */
26 27 explicit ModbusAdapter();
27 28  
28 29 /*!
29   - * \brief Default destructor
  30 + * Default destructor
30 31 */
31 32 virtual ~ModbusAdapter();
32 33  
33 34 /*!
34   - * \brief /// Create a modbus connection, accepting a configuration object.
  35 + * Create a modbus connection, accepting a configuration object.
35 36 */
36   - bool ModbusConnect( const ConnectionConfig &conncfg ) override;
  37 + bool ModbusConnect( const ConnectionConfig &config ) override;
37 38  
38 39 /*!
39   - * \brief ModbusDisconnect
  40 + * ModbusDisconnect
40 41 * Disconnect from the serial bus or the TCP connection, freeing its resources
41 42 */
42 43 bool ModbusDisconnect() override;
43 44  
44 45 /*!
45   - * \brief Read data from a modbus device given by its parameters.
46   - * \param slaveId - The Id of the ModbusDevice.
47   - * \param functionCode - The code describing the action we want to perform on the device.
  46 + * Read data from a modbus device given by its parameters.
  47 + * @param slaveId - The Id of the ModbusDevice.
  48 + * @param functionCode - The code describing the action we want to perform on the device.
48 49 * Given by an enum, provided by the modbus-stack.
49   - * \param startAddress - Startaddres of the register we want to read.
50   - * \param noOfItems - The number of items we expect back.
51   - * \returns modbusData - A vector holding each register in an entry in the same order as they are received.
  50 + * @param startAddress - Startaddres of the register we want to read.
  51 + * @param noOfItems - The number of items we expect back.
  52 + * @returns modbusData - A vector holding each register in an entry in the same order as they are received.
52 53 * Empty if no data was received.
53 54 */
54 55 modbusData ModbusReadData( int slaveId, int functionCode, int startAddress, int noOfItems ) override;
55 56  
56 57 /*!
57   - * \brief Read data from the holdregisters ( or keep-registers ) of a modbus device.
58   - * \param slaveId - The Id of the ModbusDevice.
59   - * \param startAddress - Startaddres of the register we want to read.
60   - * \param noOfItems - The number of items we expect back.
61   - * \returns modbusData - A vector holding each register in an entry in the same order as they are received.
  58 + * Read data from the holdregisters ( or keep-registers ) of a modbus device.
  59 + * @param slaveId - The Id of the ModbusDevice.
  60 + * @param startAddress - Startaddres of the register we want to read.
  61 + * @param noOfItems - The number of items we expect back.
  62 + * @returns modbusData - A vector holding each register in an entry in the same order as they are received.
62 63 * Empty if no data was received.
63 64 */
64 65 modbusData ModbusReadHoldReg( int slaveId, int startAddress, int noOfItems ) override;
65 66  
66 67 /*!
67   - * \brief Write data to the device.
68   - * \param slaveId - The Id of the Modbus device
69   - * \param funtionCode - The code describing the action we want to perform on the device
  68 + * Write data to the device.
  69 + * @param slaveId - The Id of the Modbus device
  70 + * @param funtionCode - The code describing the action we want to perform on the device
70 71 * given by an enum, provided by the modbus-stack.
71   - * \param startAddress - Startaddres of the register we want to read.
72   - * \param noOfItems - The number of items we expect to be written
73   - * \param values - The values we want to write to the given device. Each vector-entry represents a single byte
  72 + * @param startAddress - Startaddres of the register we want to read.
  73 + * @param noOfItems - The number of items we expect to be written
  74 + * @param values - The values we want to write to the given device. Each vector-entry represents a single byte
74 75 * and they will be sent in sequence.
75 76 */
76 77 void ModBusWriteData( int slaveId, int functionCode, int startAddress, int noOfItems, std::vector<int>values ) override;
77 78  
78 79 /*!
79   - * \brief Indicates if this connection is alive.
80   - * \return True if alive, false if not.
  80 + * Indicates if this connection is alive.
  81 + * @returns True if alive, false if not.
81 82 */
82 83 bool isConnected() const override;
83 84  
84 85 /*!
85   - * \brief returns the translated error code coming from the modbus stack.
86   - * \param errnum - error Number coming from the stack.
87   - * \return The translated error as a string. Empty if not resolvable.
  86 + * returns the translated error code coming from the modbus stack.
  87 + * @param errnum - error Number coming from the stack.
  88 + * @return The translated error as a string. Empty if not resolvable.
88 89 */
89 90 std::string ErrorString( int errnum ) const override;
90 91  
... ... @@ -96,11 +97,11 @@ private: // Methods
96 97 void ClearBuffers();
97 98  
98 99 private: // Members
99   - ConnectionType m_connType { ConnectionType::CT_UNKNOWN }; ///> The type of connection this instance provides. Needed for administration
100   - bool m_connected { false }; ///> Shows if the connection is still active.
101   - modbus_t *m_modbus; ///> The actual low-level modbus instance as a raw-pointer. ( unique_pointer gives an error on this struct )
  100 + ConnectionType connectionType { ConnectionType::CT_UNKNOWN }; ///> The type of connection this instance provides. Needed for administration
  101 + bool connected { false }; ///> Shows if the connection is still active.
  102 + modbus_t *modbus; ///> The actual low-level modbus instance as a raw-pointer. ( unique_pointer gives an error on this struct )
102 103  
103 104 // Return value Buffers ( Room for improvement )
104   - uint8_t *m_dest;
105   - uint16_t *m_dest16;
  105 + uint8_t *m_dest;
  106 + uint16_t *m_dest16;
106 107 };
... ...
stack/config.h deleted
1   -/* Define to 1 if you have the <arpa/inet.h> header file. */
2   -#define HAVE_ARPA_INET_H 1
3   -
4   -/* Define to 1 if you have the declaration of `TIOCSRS485', and to 0 if you don't. */
5   -#define HAVE_DECL_TIOCSRS485 0
6   -
7   -/* Define to 1 if you have the declaration of `TIOCM_RTS', and to 0 if you don't. */
8   -#define HAVE_DECL_TIOCM_RTS 0
9   -
10   -/* Define to 1 if you have the declaration of `__CYGWIN__', and to 0 if you don't. */
11   -#define HAVE_DECL___CYGWIN__ 0
12   -
13   -/* Define to 1 if you have the <dlfcn.h> header file. */
14   -#define HAVE_DLFCN_H 1
15   -
16   -/* Define to 1 if you have the <errno.h> header file. */
17   -#define HAVE_ERRNO_H 1
18   -
19   -/* Define to 1 if you have the <fcntl.h> header file. */
20   -#define HAVE_FCNTL_H 1
21   -
22   -/* Define to 1 if you have the `fork' function. */
23   -#define HAVE_FORK 1
24   -
25   -/* Define to 1 if you have the `getaddrinfo' function. */
26   -#define HAVE_GETADDRINFO 1
27   -
28   -/* Define to 1 if you have the `gettimeofday' function. */
29   -#define HAVE_GETTIMEOFDAY 1
30   -
31   -/* Define to 1 if you have the `inet_ntoa' function. */
32   -#define HAVE_INET_NTOA 1
33   -
34   -/* Define to 1 if you have the <inttypes.h> header file. */
35   -#define HAVE_INTTYPES_H 1
36   -
37   -/* Define to 1 if you have the <limits.h> header file. */
38   -#define HAVE_LIMITS_H 1
39   -
40   -/* Define to 1 if you have the <linux/serial.h> header file. */
41   -#define HAVE_LINUX_SERIAL_H 1
42   -
43   -/* Define to 1 if you have the <memory.h> header file. */
44   -#define HAVE_MEMORY_H 1
45   -
46   -/* Define to 1 if you have the `memset' function. */
47   -#define HAVE_MEMSET 1
48   -
49   -/* Define to 1 if you have the <netdb.h> header file. */
50   -#define HAVE_NETDB_H 1
51   -
52   -/* Define to 1 if you have the <netinet/in.h> header file. */
53   -#define HAVE_NETINET_IN_H 1
54   -
55   -/* Define to 1 if you have the <netinet/tcp.h> header file. */
56   -#define HAVE_NETINET_TCP_H 1
57   -
58   -/* Define to 1 if you have the `select' function. */
59   -#define HAVE_SELECT 1
60   -
61   -/* Define to 1 if you have the `socket' function. */
62   -#define HAVE_SOCKET 1
63   -
64   -/* Define to 1 if you have the <stdint.h> header file. */
65   -#define HAVE_STDINT_H 1
66   -
67   -/* Define to 1 if you have the <stdlib.h> header file. */
68   -#define HAVE_STDLIB_H 1
69   -
70   -/* Define to 1 if you have the `strerror' function. */
71   -#define HAVE_STRERROR 1
72   -
73   -/* Define to 1 if you have the <strings.h> header file. */
74   -#define HAVE_STRINGS_H 1
75   -
76   -/* Define to 1 if you have the <string.h> header file. */
77   -#define HAVE_STRING_H 1
78   -
79   -/* Define to 1 if you have the `strlcpy' function. */
80   -/* #undef HAVE_STRLCPY */
81   -
82   -/* Define to 1 if you have the <sys/ioctl.h> header file. */
83   -#define HAVE_SYS_IOCTL_H 1
84   -
85   -/* Define to 1 if you have the <sys/socket.h> header file. */
86   -#define HAVE_SYS_SOCKET_H 1
87   -
88   -/* Define to 1 if you have the <sys/stat.h> header file. */
89   -#define HAVE_SYS_STAT_H 1
90   -
91   -/* Define to 1 if you have the <sys/time.h> header file. */
92   -#define HAVE_SYS_TIME_H 1
93   -
94   -/* Define to 1 if you have the <sys/types.h> header file. */
95   -#define HAVE_SYS_TYPES_H 1
96   -
97   -/* Define to 1 if you have the <termios.h> header file. */
98   -#define HAVE_TERMIOS_H 1
99   -
100   -/* Define to 1 if you have the <time.h> header file. */
101   -#define HAVE_TIME_H 1
102   -
103   -/* Define to 1 if you have the <unistd.h> header file. */
104   -#define HAVE_UNISTD_H 1
105   -
106   -/* Define to 1 if you have the `vfork' function. */
107   -#define HAVE_VFORK 1
108   -
109   -/* Define to 1 if you have the <vfork.h> header file. */
110   -/* #undef HAVE_VFORK_H */
111   -
112   -/* Define to 1 if you have the <winsock2.h> header file. */
113   -/* #undef HAVE_WINSOCK2_H */
114   -
115   -/* Define to 1 if `fork' works. */
116   -#define HAVE_WORKING_FORK 1
117   -
118   -/* Define to 1 if `vfork' works. */
119   -#define HAVE_WORKING_VFORK 1
120   -
121   -/* Define to the sub-directory in which libtool stores uninstalled libraries.
122   - */
123   -#define LT_OBJDIR ".libs/"
124   -
125   -/* Name of package */
126   -#define PACKAGE "libmodbus"
127   -
128   -/* Define to the address where bug reports for this package should be sent. */
129   -#define PACKAGE_BUGREPORT "https://github.com/stephane/libmodbus/issues"
130   -
131   -/* Define to the full name of this package. */
132   -#define PACKAGE_NAME "libmodbus"
133   -
134   -/* Define to the full name and version of this package. */
135   -#define PACKAGE_STRING "libmodbus 3.1.0-1"
136   -
137   -/* Define to the one symbol short name of this package. */
138   -#define PACKAGE_TARNAME "modbus"
139   -
140   -/* Define to the home page for this package. */
141   -#define PACKAGE_URL ""
142   -
143   -/* Define to the version of this package. */
144   -#define PACKAGE_VERSION "1.0.0"
145   -
146   -/* Define to 1 if you have the ANSI C header files. */
147   -#define STDC_HEADERS 1
148   -
149   -/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
150   -#define TIME_WITH_SYS_TIME 1
151   -
152   -/* Version number of package */
153   -#define VERSION "1.0.0"
154   -
155   -/* Define to empty if `const' does not conform to ANSI C. */
156   -/* #undef const */
157   -
158   -/* Define to `int' if <sys/types.h> does not define. */
159   -/* #undef pid_t */
160   -
161   -/* Define to `unsigned int' if <sys/types.h> does not define. */
162   -/* #undef size_t */
163   -
164   -/* Define as `fork' if `vfork' does not work. */
165   -/* #undef vfork */
stack/modbus-data.c deleted
1   -
2   -#include <stdlib.h>
3   -
4   -#include "stdint.h"
5   -
6   -#include <string.h>
7   -#include <assert.h>
8   -#include <arpa/inet.h>
9   -#include <config.h>
10   -
11   -#include "modbus.h"
12   -
13   -#if defined(HAVE_BYTESWAP_H)
14   -# include <byteswap.h>
15   -#endif
16   -
17   -#if defined(__GNUC__)
18   -# define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__ * 10)
19   -# if GCC_VERSION >= 430
20   -// Since GCC >= 4.30, GCC provides __builtin_bswapXX() alternatives so we switch to them
21   -# undef bswap_32
22   -# define bswap_32 __builtin_bswap32
23   -# endif
24   -#endif
25   -
26   -#if !defined(__CYGWIN__) && !defined(bswap_16)
27   -#pragma message "Fallback on C functions for bswap_16"
28   -static inline uint16_t bswap_16(uint16_t x)
29   -{
30   - return (x >> 8) | (x << 8);
31   -}
32   -#endif
33   -
34   -#if !defined(bswap_32)
35   -#pragma message "Fallback on C functions for bswap_32"
36   -static inline uint32_t bswap_32(uint32_t x)
37   -{
38   - return (bswap_16(x & 0xffff) << 16) | (bswap_16(x >> 16));
39   -}
40   -#endif
41   -
42   -/* Sets many bits from a single byte value (all 8 bits of the byte value are
43   - set) */
44   -void modbus_set_bits_from_byte( uint8_t *dest, int idx, const uint8_t value )
45   -{
46   - int i;
47   -
48   - for (i=0; i < 8; i++)
49   - {
50   - dest[idx+i] = (value & (1 << i)) ? 1 : 0;
51   - }
52   -}
53   -
54   -/* Sets many bits from a table of bytes (only the bits between idx and
55   - idx + nb_bits are set) */
56   -void modbus_set_bits_from_bytes( uint8_t *dest, int idx, unsigned int nb_bits, const uint8_t *tab_byte )
57   -{
58   - unsigned int i;
59   - int shift = 0;
60   -
61   - for ( i = idx; i < idx + nb_bits; i++ )
62   - {
63   - dest[i] = tab_byte[(i - idx) / 8] & (1 << shift) ? 1 : 0;
64   - /* gcc doesn't like: shift = (++shift) % 8; */
65   - shift++;
66   - shift %= 8;
67   - }
68   -}
69   -
70   -/* Gets the byte value from many bits.
71   - To obtain a full byte, set nb_bits to 8. */
72   -uint8_t modbus_get_byte_from_bits( const uint8_t *src, int idx, unsigned int nb_bits )
73   -{
74   - unsigned int i;
75   - uint8_t value = 0;
76   -
77   - if (nb_bits > 8)
78   - {
79   - /* Assert is ignored if NDEBUG is set */
80   - assert(nb_bits < 8);
81   - nb_bits = 8;
82   - }
83   -
84   - for (i=0; i < nb_bits; i++)
85   - {
86   - value |= (src[idx+i] << i);
87   - }
88   -
89   - return value;
90   -}
91   -
92   -/* Get a float from 4 bytes (Modbus) without any conversion (ABCD) */
93   -float modbus_get_float_abcd(const uint16_t *src)
94   -{
95   - float f;
96   - uint32_t i;
97   -
98   - i = ntohl(((uint32_t)src[0] << 16) + src[1]);
99   - memcpy(&f, &i, sizeof(float));
100   -
101   - return f;
102   -}
103   -
104   -/* Get a float from 4 bytes (Modbus) in inversed format (DCBA) */
105   -float modbus_get_float_dcba(const uint16_t *src)
106   -{
107   - float f;
108   - uint32_t i;
109   -
110   - i = ntohl(bswap_32((((uint32_t)src[0]) << 16) + src[1]));
111   - memcpy(&f, &i, sizeof(float));
112   -
113   - return f;
114   -}
115   -
116   -/* Get a float from 4 bytes (Modbus) with swapped bytes (BADC) */
117   -float modbus_get_float_badc(const uint16_t *src)
118   -{
119   - float f;
120   - uint32_t i;
121   -
122   - i = ntohl((uint32_t)(bswap_16(src[0]) << 16) + bswap_16(src[1]));
123   - memcpy(&f, &i, sizeof(float));
124   -
125   - return f;
126   -}
127   -
128   -/* Get a float from 4 bytes (Modbus) with swapped words (CDAB) */
129   -float modbus_get_float_cdab(const uint16_t *src)
130   -{
131   - float f;
132   - uint32_t i;
133   -
134   - i = ntohl((((uint32_t)src[1]) << 16) + src[0]);
135   - memcpy(&f, &i, sizeof(float));
136   -
137   - return f;
138   -}
139   -
140   -/* DEPRECATED - Get a float from 4 bytes in sort of Modbus format */
141   -float modbus_get_float(const uint16_t *src)
142   -{
143   - float f;
144   - uint32_t i;
145   -
146   - i = (((uint32_t)src[1]) << 16) + src[0];
147   - memcpy(&f, &i, sizeof(float));
148   -
149   - return f;
150   -}
151   -
152   -/* Set a float to 4 bytes for Modbus w/o any conversion (ABCD) */
153   -void modbus_set_float_abcd(float f, uint16_t *dest)
154   -{
155   - uint32_t i;
156   -
157   - memcpy(&i, &f, sizeof(uint32_t));
158   - i = htonl(i);
159   - dest[0] = (uint16_t)(i >> 16);
160   - dest[1] = (uint16_t)i;
161   -}
162   -
163   -/* Set a float to 4 bytes for Modbus with byte and word swap conversion (DCBA) */
164   -void modbus_set_float_dcba(float f, uint16_t *dest)
165   -{
166   - uint32_t i;
167   -
168   - memcpy(&i, &f, sizeof(uint32_t));
169   - i = bswap_32(htonl(i));
170   - dest[0] = (uint16_t)(i >> 16);
171   - dest[1] = (uint16_t)i;
172   -}
173   -
174   -/* Set a float to 4 bytes for Modbus with byte swap conversion (BADC) */
175   -void modbus_set_float_badc(float f, uint16_t *dest)
176   -{
177   - uint32_t i;
178   -
179   - memcpy(&i, &f, sizeof(uint32_t));
180   - i = htonl(i);
181   - dest[0] = (uint16_t)bswap_16(i >> 16);
182   - dest[1] = (uint16_t)bswap_16(i & 0xFFFF);
183   -}
184   -
185   -/* Set a float to 4 bytes for Modbus with word swap conversion (CDAB) */
186   -void modbus_set_float_cdab(float f, uint16_t *dest)
187   -{
188   - uint32_t i;
189   -
190   - memcpy(&i, &f, sizeof(uint32_t));
191   - i = htonl(i);
192   - dest[0] = (uint16_t)i;
193   - dest[1] = (uint16_t)(i >> 16);
194   -}
195   -
196   -/* DEPRECATED - Set a float to 4 bytes in a sort of Modbus format! */
197   -void modbus_set_float(float f, uint16_t *dest)
198   -{
199   - uint32_t i;
200   -
201   - memcpy(&i, &f, sizeof(uint32_t));
202   - dest[0] = (uint16_t)i;
203   - dest[1] = (uint16_t)(i >> 16);
204   -}
stack/modbus-private.h deleted
1   -
2   -#pragma once
3   -
4   -# include <stdint.h>
5   -# include <sys/time.h>
6   -#include <sys/types.h>
7   -#include <config.h>
8   -
9   -#include "modbus.h"
10   -
11   -MODBUS_BEGIN_DECLS
12   -
13   -/* It's not really the minimal length (the real one is report slave ID
14   - * in RTU (4 bytes)) but it's a convenient size to use in RTU or TCP
15   - * communications to read many values or write a single one.
16   - * Maximum between :
17   - * - HEADER_LENGTH_TCP (7) + function (1) + address (2) + number (2)
18   - * - HEADER_LENGTH_RTU (1) + function (1) + address (2) + number (2) + CRC (2)
19   - */
20   -#define _MIN_REQ_LENGTH 12
21   -#define _REPORT_SLAVE_ID 180
22   -#define _MODBUS_EXCEPTION_RSP_LENGTH 5
23   -
24   -/* Timeouts in microsecond (0.5 s) */
25   -#define _RESPONSE_TIMEOUT 500000
26   -#define _BYTE_TIMEOUT 500000
27   -
28   -typedef enum
29   -{
30   - _MODBUS_BACKEND_TYPE_RTU=0,
31   - _MODBUS_BACKEND_TYPE_TCP
32   -} modbus_backend_type_t;
33   -
34   -/*
35   - * ---------- Request Indication ----------
36   - * | Client | ---------------------->| Server |
37   - * ---------- Confirmation Response ----------
38   - */
39   -typedef enum
40   -{
41   - /* Request message on the server side */
42   - MSG_INDICATION,
43   - /* Request message on the client side */
44   - MSG_CONFIRMATION
45   -} msg_type_t;
46   -
47   -/* This structure reduces the number of params in functions and so
48   - * optimizes the speed of execution (~ 37%). */
49   -typedef struct _sft
50   -{
51   - int slave;
52   - int function;
53   - int t_id;
54   -} sft_t;
55   -
56   -typedef struct _modbus_backend
57   -{
58   - unsigned int backend_type;
59   - unsigned int header_length;
60   - unsigned int checksum_length;
61   - unsigned int max_adu_length;
62   - int (*set_slave) (modbus_t *ctx, int slave);
63   - int (*build_request_basis) (modbus_t *ctx, int function, int addr, int nb, uint8_t *req);
64   - int (*build_response_basis) (sft_t *sft, uint8_t *rsp);
65   - int (*prepare_response_tid) (const uint8_t *req, int *req_length);
66   - int (*send_msg_pre) (uint8_t *req, int req_length);
67   - ssize_t (*send) (modbus_t *ctx, const uint8_t *req, int req_length);
68   - int (*receive) (modbus_t *ctx, uint8_t *req);
69   - ssize_t (*recv) (modbus_t *ctx, uint8_t *rsp, int rsp_length);
70   - int (*check_integrity) (modbus_t *ctx, uint8_t *msg, const int msg_length);
71   - int (*pre_check_confirmation) (modbus_t *ctx, const uint8_t *req, const uint8_t *rsp, int rsp_length);
72   - int (*connect) (modbus_t *ctx);
73   - void (*close) (modbus_t *ctx);
74   - int (*flush) (modbus_t *ctx);
75   - int (*select) (modbus_t *ctx, fd_set *rset, struct timeval *tv, int msg_length);
76   - void (*free) (modbus_t *ctx);
77   -} modbus_backend_t;
78   -
79   -struct _modbus
80   -{
81   - /* Slave address */
82   - int slave;
83   - /* Socket or file descriptor */
84   - int s;
85   - int debug;
86   - int error_recovery;
87   - struct timeval response_timeout;
88   - struct timeval byte_timeout;
89   - const modbus_backend_t *backend;
90   - void *backend_data;
91   -};
92   -
93   -void _modbus_init_common(modbus_t *ctx);
94   -void _error_print(modbus_t *ctx, const char *context);
95   -int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type);
96   -
97   -#ifndef HAVE_STRLCPY
98   -size_t strlcpy(char *dest, const char *src, size_t dest_size);
99   -#endif
100   -
101   -MODBUS_END_DECLS
stack/modbus-rtu-private.h deleted
1   -
2   -#pragma once
3   -
4   -#include <stdint.h>
5   -#include <termios.h>
6   -
7   -#define _MODBUS_RTU_HEADER_LENGTH 1
8   -#define _MODBUS_RTU_PRESET_REQ_LENGTH 6
9   -#define _MODBUS_RTU_PRESET_RSP_LENGTH 2
10   -
11   -#define _MODBUS_RTU_CHECKSUM_LENGTH 2
12   -
13   -typedef struct _modbus_rtu
14   -{
15   - /* Device: "/dev/ttyS0", "/dev/ttyUSB0" or "/dev/tty.USA19*" on Mac OS X. */
16   - char *device;
17   - /* Bauds: 9600, 19200, 57600, 115200, etc */
18   - int baud;
19   - /* Data bit */
20   - uint8_t data_bit;
21   - /* Stop bit */
22   - uint8_t stop_bit;
23   - /* Parity: 'N', 'O', 'E' */
24   - char parity;
25   - /* Save old termios settings */
26   - struct termios old_tios;
27   -
28   -#if HAVE_DECL_TIOCSRS485
29   - int serial_mode;
30   -#endif
31   -
32   - /* To handle many slaves on the same link */
33   - int confirmation_to_ignore;
34   -} modbus_rtu_t;
stack/modbus-rtu.c deleted
1   -
2   -#include <stdio.h>
3   -#include <stdlib.h>
4   -#include <errno.h>
5   -#include <fcntl.h>
6   -#include <string.h>
7   -#include <unistd.h>
8   -#include <assert.h>
9   -
10   -#include "modbus-private.h"
11   -
12   -#include "modbus-rtu.h"
13   -#include "modbus-rtu-private.h"
14   -
15   -#if HAVE_DECL_TIOCSRS485 || HAVE_DECL_TIOCM_RTS
16   -#include <sys/ioctl.h>
17   -#endif
18   -
19   -#if HAVE_DECL_TIOCSRS485
20   -#include <linux/serial.h>
21   -#endif
22   -
23   -/* Table of CRC values for high-order byte */
24   -static const uint8_t table_crc_hi[] = {
25   - 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
26   - 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
27   - 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
28   - 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
29   - 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
30   - 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
31   - 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
32   - 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
33   - 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
34   - 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
35   - 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
36   - 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
37   - 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
38   - 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
39   - 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
40   - 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
41   - 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
42   - 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
43   - 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
44   - 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
45   - 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
46   - 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
47   - 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
48   - 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
49   - 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
50   - 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
51   -};
52   -
53   -/* Table of CRC values for low-order byte */
54   -static const uint8_t table_crc_lo[] = {
55   - 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
56   - 0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
57   - 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
58   - 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
59   - 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
60   - 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
61   - 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
62   - 0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
63   - 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
64   - 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
65   - 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
66   - 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
67   - 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
68   - 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
69   - 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
70   - 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
71   - 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
72   - 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
73   - 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
74   - 0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
75   - 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
76   - 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
77   - 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
78   - 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
79   - 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
80   - 0x43, 0x83, 0x41, 0x81, 0x80, 0x40
81   -};
82   -
83   -/* Define the slave ID of the remote device to talk in master mode or set the
84   - * internal slave ID in slave mode */
85   -static int _modbus_set_slave( modbus_t *ctx, int slave )
86   -{
87   - /* Broadcast address is 0 (MODBUS_BROADCAST_ADDRESS) */
88   - if (slave >= 0 && slave <= 247)
89   - {
90   - ctx->slave = slave;
91   - }
92   - else
93   - {
94   - errno = EINVAL;
95   - return -1;
96   - }
97   -
98   - return 0;
99   -}
100   -
101   -/* Builds a RTU request header */
102   -static int _modbus_rtu_build_request_basis( modbus_t *ctx, int function, int addr, int nb, uint8_t *req )
103   -{
104   - assert(ctx->slave != -1);
105   - req[0] = ctx->slave;
106   - req[1] = function;
107   - req[2] = addr >> 8;
108   - req[3] = addr & 0x00ff;
109   - req[4] = nb >> 8;
110   - req[5] = nb & 0x00ff;
111   -
112   - return _MODBUS_RTU_PRESET_REQ_LENGTH;
113   -}
114   -
115   -/* Builds a RTU response header */
116   -static int _modbus_rtu_build_response_basis( sft_t *sft, uint8_t *rsp )
117   -{
118   - /* In this case, the slave is certainly valid because a check is already
119   - * done in _modbus_rtu_listen */
120   - rsp[0] = sft->slave;
121   - rsp[1] = sft->function;
122   -
123   - return _MODBUS_RTU_PRESET_RSP_LENGTH;
124   -}
125   -
126   -static uint16_t crc16( uint8_t *buffer, uint16_t buffer_length )
127   -{
128   - uint8_t crc_hi = 0xFF; /* high CRC byte initialized */
129   - uint8_t crc_lo = 0xFF; /* low CRC byte initialized */
130   - unsigned int i; /* will index into CRC lookup */
131   -
132   - /* pass through message buffer */
133   - while (buffer_length--) {
134   - i = crc_hi ^ *buffer++; /* calculate the CRC */
135   - crc_hi = crc_lo ^ table_crc_hi[i];
136   - crc_lo = table_crc_lo[i];
137   - }
138   -
139   - return (crc_hi << 8 | crc_lo);
140   -}
141   -
142   -static int _modbus_rtu_prepare_response_tid( const uint8_t *req, int *req_length )
143   -{
144   - (*req_length) -= _MODBUS_RTU_CHECKSUM_LENGTH;
145   - /* No TID */
146   - return 0;
147   -}
148   -
149   -static int _modbus_rtu_send_msg_pre( uint8_t *req, int req_length )
150   -{
151   - uint16_t crc = crc16( req, req_length );
152   - req[req_length++] = crc >> 8;
153   - req[req_length++] = crc & 0x00FF;
154   -
155   - return req_length;
156   -}
157   -
158   -#if HAVE_DECL_TIOCM_RTS
159   -static void _modbus_rtu_ioctl_rts( modbus_t *ctx, int on )
160   -{
161   - int fd = ctx->s;
162   - int flags;
163   -
164   - ioctl(fd, TIOCMGET, &flags);
165   - if (on)
166   - {
167   - flags |= TIOCM_RTS;
168   - }
169   - else
170   - {
171   - flags &= ~TIOCM_RTS;
172   - }
173   - ioctl(fd, TIOCMSET, &flags);
174   -}
175   -#endif
176   -
177   -static ssize_t _modbus_rtu_send( modbus_t *ctx, const uint8_t *req, int req_length )
178   -{
179   -#if HAVE_DECL_TIOCM_RTS
180   - modbus_rtu_t *ctx_rtu = ctx->backend_data;
181   - if (ctx_rtu->rts != MODBUS_RTU_RTS_NONE)
182   - {
183   - ssize_t size;
184   -
185   - if (ctx->debug) {
186   - fprintf(stderr, "Sending request using RTS signal\n");
187   - }
188   -
189   - ctx_rtu->set_rts(ctx, ctx_rtu->rts == MODBUS_RTU_RTS_UP);
190   - usleep(ctx_rtu->rts_delay);
191   -
192   - size = write(ctx->s, req, req_length);
193   -
194   - usleep(ctx_rtu->onebyte_time * req_length + ctx_rtu->rts_delay);
195   - ctx_rtu->set_rts(ctx, ctx_rtu->rts != MODBUS_RTU_RTS_UP);
196   -
197   - return size;
198   - }
199   - else
200   - {
201   -#endif
202   - return write(ctx->s, req, req_length);
203   -#if HAVE_DECL_TIOCM_RTS
204   - }
205   -#endif
206   -}
207   -
208   -static int _modbus_rtu_receive( modbus_t *ctx, uint8_t *req )
209   -{
210   - int rc;
211   - modbus_rtu_t *ctx_rtu = ctx->backend_data;
212   -
213   - if( ctx_rtu->confirmation_to_ignore )
214   - {
215   - _modbus_receive_msg(ctx, req, MSG_CONFIRMATION);
216   - /* Ignore errors and reset the flag */
217   - ctx_rtu->confirmation_to_ignore = FALSE;
218   - rc = 0;
219   - if( ctx->debug )
220   - {
221   - printf("Confirmation to ignore\n");
222   - }
223   - }
224   - else
225   - {
226   - rc = _modbus_receive_msg( ctx, req, MSG_INDICATION );
227   - if( rc == 0 )
228   - {
229   - /* The next expected message is a confirmation to ignore */
230   - ctx_rtu->confirmation_to_ignore = TRUE;
231   - }
232   - }
233   - return rc;
234   -}
235   -
236   -static ssize_t _modbus_rtu_recv( modbus_t *ctx, uint8_t *rsp, int rsp_length )
237   -{
238   - return read(ctx->s, rsp, rsp_length);
239   -}
240   -
241   -static int _modbus_rtu_flush(modbus_t *);
242   -
243   -static int _modbus_rtu_pre_check_confirmation(modbus_t *ctx, const uint8_t *req, const uint8_t *rsp, int rsp_length)
244   -{
245   - /* Check responding slave is the slave we requested (except for broacast request) */
246   - if (req[0] != rsp[0] && req[0] != MODBUS_BROADCAST_ADDRESS)
247   - {
248   - if (ctx->debug)
249   - {
250   - fprintf(stderr, "The responding slave %d isn't the requested slave %d\n", rsp[0], req[0]);
251   - }
252   - errno = EMBBADSLAVE;
253   - return -1;
254   - }
255   -
256   - return 0;
257   -}
258   -
259   -/* The check_crc16 function shall return 0 is the message is ignored and the
260   - message length if the CRC is valid. Otherwise it shall return -1 and set
261   - errno to EMBADCRC. */
262   -static int _modbus_rtu_check_integrity(modbus_t *ctx, uint8_t *msg, const int msg_length)
263   -{
264   - uint16_t crc_calculated;
265   - uint16_t crc_received;
266   - int slave = msg[0];
267   -
268   - /* Filter on the Modbus unit identifier (slave) in RTU mode to avoid useless
269   - * CRC computing. */
270   - if (slave != ctx->slave && slave != MODBUS_BROADCAST_ADDRESS)
271   - {
272   - if (ctx->debug)
273   - {
274   - printf("Request for slave %d ignored (not %d)\n", slave, ctx->slave);
275   - }
276   - /* Following call to check_confirmation handles this error */
277   - return 0;
278   - }
279   -
280   - crc_calculated = crc16(msg, msg_length - 2);
281   - crc_received = (msg[msg_length - 2] << 8) | msg[msg_length - 1];
282   -
283   - /* Check CRC of msg */
284   - if (crc_calculated == crc_received)
285   - {
286   - return msg_length;
287   - }
288   - else
289   - {
290   - if (ctx->debug)
291   - {
292   - fprintf(stderr, "ERROR CRC received 0x%0X != CRC calculated 0x%0X\n",
293   - crc_received, crc_calculated);
294   - }
295   -
296   - if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_PROTOCOL)
297   - {
298   - _modbus_rtu_flush(ctx);
299   - }
300   - errno = EMBBADCRC;
301   - return -1;
302   - }
303   -}
304   -
305   -/* Sets up a serial port for RTU communications */
306   -static int _modbus_rtu_connect(modbus_t *ctx)
307   -{
308   - struct termios tios;
309   - speed_t speed;
310   - int flags;
311   -
312   - modbus_rtu_t *ctx_rtu = ctx->backend_data;
313   -
314   - if (ctx->debug)
315   - {
316   - printf("Opening %s at %d bauds (%c, %d, %d)\n",
317   - ctx_rtu->device, ctx_rtu->baud, ctx_rtu->parity, ctx_rtu->data_bit, ctx_rtu->stop_bit);
318   - }
319   -
320   - /* The O_NOCTTY flag tells UNIX that this program doesn't want
321   - to be the "controlling terminal" for that port. If you
322   - don't specify this then any input (such as keyboard abort
323   - signals and so forth) will affect your process
324   -
325   - Timeouts are ignored in canonical input mode or when the
326   - NDELAY option is set on the file via open or fcntl */
327   - flags = O_RDWR | O_NOCTTY | O_NDELAY | O_EXCL;
328   -#ifdef O_CLOEXEC
329   - flags |= O_CLOEXEC;
330   -#endif
331   -
332   - ctx->s = open(ctx_rtu->device, flags);
333   - if (ctx->s == -1) {
334   - if (ctx->debug) {
335   - fprintf(stderr, "ERROR Can't open the device %s (%s)\n",
336   - ctx_rtu->device, strerror(errno));
337   - }
338   - return -1;
339   - }
340   -
341   - /* Save */
342   - tcgetattr(ctx->s, &ctx_rtu->old_tios);
343   -
344   - memset(&tios, 0, sizeof(struct termios));
345   -
346   - /* C_ISPEED Input baud (new interface)
347   - C_OSPEED Output baud (new interface)
348   - */
349   - switch (ctx_rtu->baud)
350   - {
351   - case 110:
352   - speed = B110;
353   - break;
354   - case 300:
355   - speed = B300;
356   - break;
357   - case 600:
358   - speed = B600;
359   - break;
360   - case 1200:
361   - speed = B1200;
362   - break;
363   - case 2400:
364   - speed = B2400;
365   - break;
366   - case 4800:
367   - speed = B4800;
368   - break;
369   - case 9600:
370   - speed = B9600;
371   - break;
372   - case 19200:
373   - speed = B19200;
374   - break;
375   - case 38400:
376   - speed = B38400;
377   - break;
378   -#ifdef B57600
379   - case 57600:
380   - speed = B57600;
381   - break;
382   -#endif
383   -#ifdef B115200
384   - case 115200:
385   - speed = B115200;
386   - break;
387   -#endif
388   -#ifdef B230400
389   - case 230400:
390   - speed = B230400;
391   - break;
392   -#endif
393   -#ifdef B460800
394   - case 460800:
395   - speed = B460800;
396   - break;
397   -#endif
398   -#ifdef B500000
399   - case 500000:
400   - speed = B500000;
401   - break;
402   -#endif
403   -#ifdef B576000
404   - case 576000:
405   - speed = B576000;
406   - break;
407   -#endif
408   -#ifdef B921600
409   - case 921600:
410   - speed = B921600;
411   - break;
412   -#endif
413   -#ifdef B1000000
414   - case 1000000:
415   - speed = B1000000;
416   - break;
417   -#endif
418   -#ifdef B1152000
419   - case 1152000:
420   - speed = B1152000;
421   - break;
422   -#endif
423   -#ifdef B1500000
424   - case 1500000:
425   - speed = B1500000;
426   - break;
427   -#endif
428   -#ifdef B2500000
429   - case 2500000:
430   - speed = B2500000;
431   - break;
432   -#endif
433   -#ifdef B3000000
434   - case 3000000:
435   - speed = B3000000;
436   - break;
437   -#endif
438   -#ifdef B3500000
439   - case 3500000:
440   - speed = B3500000;
441   - break;
442   -#endif
443   -#ifdef B4000000
444   - case 4000000:
445   - speed = B4000000;
446   - break;
447   -#endif
448   - default:
449   - speed = B9600;
450   - if (ctx->debug) {
451   - fprintf(stderr,
452   - "WARNING Unknown baud rate %d for %s (B9600 used)\n",
453   - ctx_rtu->baud, ctx_rtu->device);
454   - }
455   - }
456   -
457   - /* Set the baud rate */
458   - if ((cfsetispeed(&tios, speed) < 0) ||
459   - (cfsetospeed(&tios, speed) < 0)) {
460   - close(ctx->s);
461   - ctx->s = -1;
462   - return -1;
463   - }
464   -
465   - /* C_CFLAG Control options
466   - CLOCAL Local line - do not change "owner" of port
467   - CREAD Enable receiver
468   - */
469   - tios.c_cflag |= (CREAD | CLOCAL);
470   - /* CSIZE, HUPCL, CRTSCTS (hardware flow control) */
471   -
472   - /* Set data bits (5, 6, 7, 8 bits)
473   - CSIZE Bit mask for data bits
474   - */
475   - tios.c_cflag &= ~CSIZE;
476   - switch (ctx_rtu->data_bit) {
477   - case 5:
478   - tios.c_cflag |= CS5;
479   - break;
480   - case 6:
481   - tios.c_cflag |= CS6;
482   - break;
483   - case 7:
484   - tios.c_cflag |= CS7;
485   - break;
486   - case 8:
487   - default:
488   - tios.c_cflag |= CS8;
489   - break;
490   - }
491   -
492   - /* Stop bit (1 or 2) */
493   - if (ctx_rtu->stop_bit == 1)
494   - tios.c_cflag &=~ CSTOPB;
495   - else /* 2 */
496   - tios.c_cflag |= CSTOPB;
497   -
498   - /* PARENB Enable parity bit
499   - PARODD Use odd parity instead of even */
500   - if (ctx_rtu->parity == 'N') {
501   - /* None */
502   - tios.c_cflag &=~ PARENB;
503   - } else if (ctx_rtu->parity == 'E') {
504   - /* Even */
505   - tios.c_cflag |= PARENB;
506   - tios.c_cflag &=~ PARODD;
507   - } else {
508   - /* Odd */
509   - tios.c_cflag |= PARENB;
510   - tios.c_cflag |= PARODD;
511   - }
512   -
513   - /* Read the man page of termios if you need more information. */
514   -
515   - /* This field isn't used on POSIX systems
516   - tios.c_line = 0;
517   - */
518   -
519   - /* C_LFLAG Line options
520   -
521   - ISIG Enable SIGINTR, SIGSUSP, SIGDSUSP, and SIGQUIT signals
522   - ICANON Enable canonical input (else raw)
523   - XCASE Map uppercase \lowercase (obsolete)
524   - ECHO Enable echoing of input characters
525   - ECHOE Echo erase character as BS-SP-BS
526   - ECHOK Echo NL after kill character
527   - ECHONL Echo NL
528   - NOFLSH Disable flushing of input buffers after
529   - interrupt or quit characters
530   - IEXTEN Enable extended functions
531   - ECHOCTL Echo control characters as ^char and delete as ~?
532   - ECHOPRT Echo erased character as character erased
533   - ECHOKE BS-SP-BS entire line on line kill
534   - FLUSHO Output being flushed
535   - PENDIN Retype pending input at next read or input char
536   - TOSTOP Send SIGTTOU for background output
537   -
538   - Canonical input is line-oriented. Input characters are put
539   - into a buffer which can be edited interactively by the user
540   - until a CR (carriage return) or LF (line feed) character is
541   - received.
542   -
543   - Raw input is unprocessed. Input characters are passed
544   - through exactly as they are received, when they are
545   - received. Generally you'll deselect the ICANON, ECHO,
546   - ECHOE, and ISIG options when using raw input
547   - */
548   -
549   - /* Raw input */
550   - tios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
551   -
552   - /* C_IFLAG Input options
553   -
554   - Constant Description
555   - INPCK Enable parity check
556   - IGNPAR Ignore parity errors
557   - PARMRK Mark parity errors
558   - ISTRIP Strip parity bits
559   - IXON Enable software flow control (outgoing)
560   - IXOFF Enable software flow control (incoming)
561   - IXANY Allow any character to start flow again
562   - IGNBRK Ignore break condition
563   - BRKINT Send a SIGINT when a break condition is detected
564   - INLCR Map NL to CR
565   - IGNCR Ignore CR
566   - ICRNL Map CR to NL
567   - IUCLC Map uppercase to lowercase
568   - IMAXBEL Echo BEL on input line too long
569   - */
570   - if (ctx_rtu->parity == 'N') {
571   - /* None */
572   - tios.c_iflag &= ~INPCK;
573   - } else {
574   - tios.c_iflag |= INPCK;
575   - }
576   -
577   - /* Software flow control is disabled */
578   - tios.c_iflag &= ~(IXON | IXOFF | IXANY);
579   -
580   - /* C_OFLAG Output options
581   - OPOST Postprocess output (not set = raw output)
582   - ONLCR Map NL to CR-NL
583   -
584   - ONCLR ant others needs OPOST to be enabled
585   - */
586   -
587   - /* Raw ouput */
588   - tios.c_oflag &=~ OPOST;
589   -
590   - /* C_CC Control characters
591   - VMIN Minimum number of characters to read
592   - VTIME Time to wait for data (tenths of seconds)
593   -
594   - UNIX serial interface drivers provide the ability to
595   - specify character and packet timeouts. Two elements of the
596   - c_cc array are used for timeouts: VMIN and VTIME. Timeouts
597   - are ignored in canonical input mode or when the NDELAY
598   - option is set on the file via open or fcntl.
599   -
600   - VMIN specifies the minimum number of characters to read. If
601   - it is set to 0, then the VTIME value specifies the time to
602   - wait for every character read. Note that this does not mean
603   - that a read call for N bytes will wait for N characters to
604   - come in. Rather, the timeout will apply to the first
605   - character and the read call will return the number of
606   - characters immediately available (up to the number you
607   - request).
608   -
609   - If VMIN is non-zero, VTIME specifies the time to wait for
610   - the first character read. If a character is read within the
611   - time given, any read will block (wait) until all VMIN
612   - characters are read. That is, once the first character is
613   - read, the serial interface driver expects to receive an
614   - entire packet of characters (VMIN bytes total). If no
615   - character is read within the time allowed, then the call to
616   - read returns 0. This method allows you to tell the serial
617   - driver you need exactly N bytes and any read call will
618   - return 0 or N bytes. However, the timeout only applies to
619   - the first character read, so if for some reason the driver
620   - misses one character inside the N byte packet then the read
621   - call could block forever waiting for additional input
622   - characters.
623   -
624   - VTIME specifies the amount of time to wait for incoming
625   - characters in tenths of seconds. If VTIME is set to 0 (the
626   - default), reads will block (wait) indefinitely unless the
627   - NDELAY option is set on the port with open or fcntl.
628   - */
629   - /* Unused because we use open with the NDELAY option */
630   - tios.c_cc[VMIN] = 0;
631   - tios.c_cc[VTIME] = 10; // Set per default to 1 second
632   -
633   - if (tcsetattr(ctx->s, TCSANOW, &tios) < 0) {
634   - close(ctx->s);
635   - ctx->s = -1;
636   - return -1;
637   - }
638   - return 0;
639   -}
640   -
641   -int modbus_rtu_set_serial_mode(modbus_t *ctx, int mode)
642   -{
643   - if (ctx == NULL) {
644   - errno = EINVAL;
645   - return -1;
646   - }
647   -
648   - if (ctx->backend->backend_type == _MODBUS_BACKEND_TYPE_RTU) {
649   -#if HAVE_DECL_TIOCSRS485
650   - modbus_rtu_t *ctx_rtu = ctx->backend_data;
651   - struct serial_rs485 rs485conf;
652   - memset(&rs485conf, 0x0, sizeof(struct serial_rs485));
653   -
654   - if (mode == MODBUS_RTU_RS485) {
655   - rs485conf.flags = SER_RS485_ENABLED;
656   - if (ioctl(ctx->s, TIOCSRS485, &rs485conf) < 0) {
657   - return -1;
658   - }
659   -
660   - ctx_rtu->serial_mode = MODBUS_RTU_RS485;
661   - return 0;
662   - } else if (mode == MODBUS_RTU_RS232) {
663   - /* Turn off RS485 mode only if required */
664   - if (ctx_rtu->serial_mode == MODBUS_RTU_RS485) {
665   - /* The ioctl call is avoided because it can fail on some RS232 ports */
666   - if (ioctl(ctx->s, TIOCSRS485, &rs485conf) < 0) {
667   - return -1;
668   - }
669   - }
670   - ctx_rtu->serial_mode = MODBUS_RTU_RS232;
671   - return 0;
672   - }
673   -#else
674   - if (ctx->debug) {
675   - fprintf(stderr, "This function isn't supported on your platform\n");
676   - }
677   - errno = ENOTSUP;
678   - return -1;
679   -#endif
680   - }
681   -
682   - /* Wrong backend and invalid mode specified */
683   - errno = EINVAL;
684   - return -1;
685   -}
686   -
687   -int modbus_rtu_get_serial_mode(modbus_t *ctx)
688   -{
689   - if (ctx == NULL) {
690   - errno = EINVAL;
691   - return -1;
692   - }
693   -
694   - if (ctx->backend->backend_type == _MODBUS_BACKEND_TYPE_RTU) {
695   -#if HAVE_DECL_TIOCSRS485
696   - modbus_rtu_t *ctx_rtu = ctx->backend_data;
697   - return ctx_rtu->serial_mode;
698   -#else
699   - if (ctx->debug) {
700   - fprintf(stderr, "This function isn't supported on your platform\n");
701   - }
702   - errno = ENOTSUP;
703   - return -1;
704   -#endif
705   - } else {
706   - errno = EINVAL;
707   - return -1;
708   - }
709   -}
710   -
711   -int modbus_rtu_get_rts(modbus_t *ctx)
712   -{
713   - if (ctx == NULL) {
714   - errno = EINVAL;
715   - return -1;
716   - }
717   -
718   - if (ctx->backend->backend_type == _MODBUS_BACKEND_TYPE_RTU) {
719   -#if HAVE_DECL_TIOCM_RTS
720   - modbus_rtu_t *ctx_rtu = ctx->backend_data;
721   - return ctx_rtu->rts;
722   -#else
723   - if (ctx->debug) {
724   - fprintf(stderr, "This function isn't supported on your platform\n");
725   - }
726   - errno = ENOTSUP;
727   - return -1;
728   -#endif
729   - } else {
730   - errno = EINVAL;
731   - return -1;
732   - }
733   -}
734   -
735   -int modbus_rtu_set_rts(modbus_t *ctx, int mode)
736   -{
737   - if (ctx == NULL) {
738   - errno = EINVAL;
739   - return -1;
740   - }
741   -
742   - if (ctx->backend->backend_type == _MODBUS_BACKEND_TYPE_RTU) {
743   -#if HAVE_DECL_TIOCM_RTS
744   - modbus_rtu_t *ctx_rtu = ctx->backend_data;
745   -
746   - if (mode == MODBUS_RTU_RTS_NONE || mode == MODBUS_RTU_RTS_UP ||
747   - mode == MODBUS_RTU_RTS_DOWN) {
748   - ctx_rtu->rts = mode;
749   -
750   - /* Set the RTS bit in order to not reserve the RS485 bus */
751   - ctx_rtu->set_rts(ctx, ctx_rtu->rts != MODBUS_RTU_RTS_UP);
752   -
753   - return 0;
754   - } else {
755   - errno = EINVAL;
756   - return -1;
757   - }
758   -#else
759   - if (ctx->debug) {
760   - fprintf(stderr, "This function isn't supported on your platform\n");
761   - }
762   - errno = ENOTSUP;
763   - return -1;
764   -#endif
765   - }
766   - /* Wrong backend or invalid mode specified */
767   - errno = EINVAL;
768   - return -1;
769   -}
770   -
771   -int modbus_rtu_set_custom_rts(modbus_t *ctx, void (*set_rts) (modbus_t *ctx, int on))
772   -{
773   - if (ctx == NULL) {
774   - errno = EINVAL;
775   - return -1;
776   - }
777   -
778   - if (ctx->backend->backend_type == _MODBUS_BACKEND_TYPE_RTU) {
779   -#if HAVE_DECL_TIOCM_RTS
780   - modbus_rtu_t *ctx_rtu = ctx->backend_data;
781   - ctx_rtu->set_rts = set_rts;
782   - return 0;
783   -#else
784   - if (ctx->debug) {
785   - fprintf(stderr, "This function isn't supported on your platform\n");
786   - }
787   - errno = ENOTSUP;
788   - return -1;
789   -#endif
790   - } else {
791   - errno = EINVAL;
792   - return -1;
793   - }
794   -}
795   -
796   -int modbus_rtu_get_rts_delay(modbus_t *ctx)
797   -{
798   - if (ctx == NULL) {
799   - errno = EINVAL;
800   - return -1;
801   - }
802   -
803   - if (ctx->backend->backend_type == _MODBUS_BACKEND_TYPE_RTU) {
804   -#if HAVE_DECL_TIOCM_RTS
805   - modbus_rtu_t *ctx_rtu;
806   - ctx_rtu = (modbus_rtu_t *)ctx->backend_data;
807   - return ctx_rtu->rts_delay;
808   -#else
809   - if (ctx->debug) {
810   - fprintf(stderr, "This function isn't supported on your platform\n");
811   - }
812   - errno = ENOTSUP;
813   - return -1;
814   -#endif
815   - } else {
816   - errno = EINVAL;
817   - return -1;
818   - }
819   -}
820   -
821   -int modbus_rtu_set_rts_delay(modbus_t *ctx, int us)
822   -{
823   - if (ctx == NULL || us < 0) {
824   - errno = EINVAL;
825   - return -1;
826   - }
827   -
828   - if (ctx->backend->backend_type == _MODBUS_BACKEND_TYPE_RTU) {
829   -#if HAVE_DECL_TIOCM_RTS
830   - modbus_rtu_t *ctx_rtu;
831   - ctx_rtu = (modbus_rtu_t *)ctx->backend_data;
832   - ctx_rtu->rts_delay = us;
833   - return 0;
834   -#else
835   - if (ctx->debug) {
836   - fprintf(stderr, "This function isn't supported on your platform\n");
837   - }
838   - errno = ENOTSUP;
839   - return -1;
840   -#endif
841   - } else {
842   - errno = EINVAL;
843   - return -1;
844   - }
845   -}
846   -
847   -static void _modbus_rtu_close(modbus_t *ctx)
848   -{
849   - /* Restore line settings and close file descriptor in RTU mode */
850   - modbus_rtu_t *ctx_rtu = ctx->backend_data;
851   -
852   - if (ctx->s != -1) {
853   - tcsetattr(ctx->s, TCSANOW, &ctx_rtu->old_tios);
854   - close(ctx->s);
855   - ctx->s = -1;
856   - }
857   -}
858   -
859   -static int _modbus_rtu_flush(modbus_t *ctx)
860   -{
861   - return tcflush(ctx->s, TCIOFLUSH);
862   -}
863   -
864   -static int _modbus_rtu_select(modbus_t *ctx, fd_set *rset, struct timeval *tv, int length_to_read)
865   -{
866   - int s_rc;
867   - while ((s_rc = select(ctx->s+1, rset, NULL, NULL, tv)) == -1)
868   - {
869   - if (errno == EINTR)
870   - {
871   - if (ctx->debug)
872   - {
873   - fprintf(stderr, "A non blocked signal was caught\n");
874   - }
875   - /* Necessary after an error */
876   - FD_ZERO(rset);
877   - FD_SET(ctx->s, rset);
878   - }
879   - else
880   - {
881   - return -1;
882   - }
883   - }
884   -
885   - if (s_rc == 0) {
886   - /* Timeout */
887   - errno = ETIMEDOUT;
888   - return -1;
889   - }
890   -
891   - return s_rc;
892   -}
893   -
894   -static void _modbus_rtu_free(modbus_t *ctx) {
895   - free(((modbus_rtu_t*)ctx->backend_data)->device);
896   - free(ctx->backend_data);
897   - free(ctx);
898   -}
899   -
900   -const modbus_backend_t _modbus_rtu_backend = {
901   - _MODBUS_BACKEND_TYPE_RTU,
902   - _MODBUS_RTU_HEADER_LENGTH,
903   - _MODBUS_RTU_CHECKSUM_LENGTH,
904   - MODBUS_RTU_MAX_ADU_LENGTH,
905   - _modbus_set_slave,
906   - _modbus_rtu_build_request_basis,
907   - _modbus_rtu_build_response_basis,
908   - _modbus_rtu_prepare_response_tid,
909   - _modbus_rtu_send_msg_pre,
910   - _modbus_rtu_send,
911   - _modbus_rtu_receive,
912   - _modbus_rtu_recv,
913   - _modbus_rtu_check_integrity,
914   - _modbus_rtu_pre_check_confirmation,
915   - _modbus_rtu_connect,
916   - _modbus_rtu_close,
917   - _modbus_rtu_flush,
918   - _modbus_rtu_select,
919   - _modbus_rtu_free
920   -};
921   -
922   -modbus_t* modbus_new_rtu(const char *device,
923   - int baud, char parity, int data_bit,
924   - int stop_bit)
925   -{
926   - modbus_t *ctx;
927   - modbus_rtu_t *ctx_rtu;
928   -
929   - /* Check device argument */
930   - if (device == NULL || *device == 0) {
931   - fprintf(stderr, "The device string is empty\n");
932   - errno = EINVAL;
933   - return NULL;
934   - }
935   -
936   - /* Check baud argument */
937   - if (baud == 0) {
938   - fprintf(stderr, "The baud rate value must not be zero\n");
939   - errno = EINVAL;
940   - return NULL;
941   - }
942   -
943   - ctx = (modbus_t *)malloc(sizeof(modbus_t));
944   - _modbus_init_common(ctx);
945   - ctx->backend = &_modbus_rtu_backend;
946   - ctx->backend_data = (modbus_rtu_t *)malloc(sizeof(modbus_rtu_t));
947   - ctx_rtu = (modbus_rtu_t *)ctx->backend_data;
948   - ctx_rtu->device = NULL;
949   -
950   - /* Device name and \0 */
951   - ctx_rtu->device = (char *)malloc((strlen(device) + 1) * sizeof(char));
952   - strcpy(ctx_rtu->device, device);
953   -
954   - ctx_rtu->baud = baud;
955   - if (parity == 'N' || parity == 'E' || parity == 'O') {
956   - ctx_rtu->parity = parity;
957   - } else {
958   - modbus_free(ctx);
959   - errno = EINVAL;
960   - return NULL;
961   - }
962   - ctx_rtu->data_bit = data_bit;
963   - ctx_rtu->stop_bit = stop_bit;
964   -
965   -#if HAVE_DECL_TIOCSRS485
966   - /* The RS232 mode has been set by default */
967   - ctx_rtu->serial_mode = MODBUS_RTU_RS232;
968   -#endif
969   -
970   -#if HAVE_DECL_TIOCM_RTS
971   - /* The RTS use has been set by default */
972   - ctx_rtu->rts = MODBUS_RTU_RTS_NONE;
973   -
974   - /* Calculate estimated time in micro second to send one byte */
975   - ctx_rtu->onebyte_time = 1000000 * (1 + data_bit + (parity == 'N' ? 0 : 1) + stop_bit) / baud;
976   -
977   - /* The internal function is used by default to set RTS */
978   - ctx_rtu->set_rts = _modbus_rtu_ioctl_rts;
979   -
980   - /* The delay before and after transmission when toggling the RTS pin */
981   - ctx_rtu->rts_delay = ctx_rtu->onebyte_time;
982   -#endif
983   -
984   - ctx_rtu->confirmation_to_ignore = FALSE;
985   -
986   - return ctx;
987   -}
stack/modbus-rtu.h deleted
1   -
2   -#pragma once
3   -
4   -#include "modbus.h"
5   -
6   -MODBUS_BEGIN_DECLS
7   -
8   -/* Modbus_Application_Protocol_V1_1b.pdf Chapter 4 Section 1 Page 5
9   - * RS232 / RS485 ADU = 253 bytes + slave (1 byte) + CRC (2 bytes) = 256 bytes
10   - */
11   -#define MODBUS_RTU_MAX_ADU_LENGTH 256
12   -
13   -MODBUS_API modbus_t* modbus_new_rtu(const char *device, int baud, char parity, int data_bit, int stop_bit);
14   -
15   -#define MODBUS_RTU_RS232 0
16   -#define MODBUS_RTU_RS485 1
17   -
18   -MODBUS_API int modbus_rtu_set_serial_mode( modbus_t *ctx, int mode );
19   -MODBUS_API int modbus_rtu_get_serial_mode( modbus_t *ctx );
20   -
21   -#define MODBUS_RTU_RTS_NONE 0
22   -#define MODBUS_RTU_RTS_UP 1
23   -#define MODBUS_RTU_RTS_DOWN 2
24   -
25   -MODBUS_API int modbus_rtu_set_rts( modbus_t *ctx, int mode );
26   -MODBUS_API int modbus_rtu_get_rts( modbus_t *ctx );
27   -
28   -MODBUS_API int modbus_rtu_set_custom_rts( modbus_t *ctx, void ( *set_rts ) ( modbus_t *ctx, int on ) );
29   -
30   -MODBUS_API int modbus_rtu_set_rts_delay( modbus_t *ctx, int us );
31   -MODBUS_API int modbus_rtu_get_rts_delay( modbus_t *ctx );
32   -
33   -MODBUS_END_DECLS
34   -
stack/modbus-tcp-private.h deleted
1   -#pragma once
2   -
3   -#define _MODBUS_TCP_HEADER_LENGTH 7
4   -#define _MODBUS_TCP_PRESET_REQ_LENGTH 12
5   -#define _MODBUS_TCP_PRESET_RSP_LENGTH 8
6   -
7   -#define _MODBUS_TCP_CHECKSUM_LENGTH 0
8   -
9   -/* In both structures, the transaction ID must be placed on first position
10   - to have a quick access not dependant of the TCP backend */
11   -typedef struct _modbus_tcp
12   -{
13   - /* Extract from MODBUS Messaging on TCP/IP Implementation Guide V1.0b
14   - (page 23/46):
15   - The transaction identifier is used to associate the future response
16   - with the request. This identifier is unique on each TCP connection. */
17   - uint16_t t_id;
18   - /* TCP port */
19   - int port;
20   - /* IP address */
21   - char ip[16];
22   -} modbus_tcp_t;
23   -
24   -#define _MODBUS_TCP_PI_NODE_LENGTH 1025
25   -#define _MODBUS_TCP_PI_SERVICE_LENGTH 32
26   -
27   -typedef struct _modbus_tcp_pi
28   -{
29   - /* Transaction ID */
30   - uint16_t t_id;
31   - /* TCP port */
32   - int port;
33   - /* Node */
34   - char node[_MODBUS_TCP_PI_NODE_LENGTH];
35   - /* Service */
36   - char service[_MODBUS_TCP_PI_SERVICE_LENGTH];
37   -} modbus_tcp_pi_t;
38   -
39   -
stack/modbus-tcp.c deleted
1   -
2   -#include <stdio.h>
3   -#include <stdlib.h>
4   -#include <string.h>
5   -#include <errno.h>
6   -#include <unistd.h>
7   -#include <signal.h>
8   -#include <sys/types.h>
9   -
10   -# include <sys/socket.h>
11   -# include <sys/ioctl.h>
12   -
13   -#if defined(__OpenBSD__) || (defined(__FreeBSD__) && __FreeBSD__ < 5)
14   -# define OS_BSD
15   -# include <netinet/in_systm.h>
16   -#endif
17   -
18   -# include <netinet/in.h>
19   -# include <netinet/ip.h>
20   -# include <netinet/tcp.h>
21   -# include <arpa/inet.h>
22   -# include <netdb.h>
23   -
24   -#if !defined(MSG_NOSIGNAL)
25   -#define MSG_NOSIGNAL 0
26   -#endif
27   -
28   -#include "modbus-private.h"
29   -
30   -#include "modbus-tcp.h"
31   -#include "modbus-tcp-private.h"
32   -
33   -static int _modbus_set_slave(modbus_t *ctx, int slave)
34   -{
35   - /* Broadcast address is 0 (MODBUS_BROADCAST_ADDRESS) */
36   - if ( slave >= 0 && slave <= 247)
37   - {
38   - ctx->slave = slave;
39   - }
40   - else if ( slave == MODBUS_TCP_SLAVE )
41   - {
42   - /* The special value MODBUS_TCP_SLAVE (0xFF) can be used in TCP mode to
43   - * restore the default value. */
44   - ctx->slave = slave;
45   - }
46   - else
47   - {
48   - errno = EINVAL;
49   - return -1;
50   - }
51   -
52   - return 0;
53   -}
54   -
55   -/* Builds a TCP request header */
56   -static int _modbus_tcp_build_request_basis( modbus_t *ctx, int function, int addr, int nb, uint8_t *req )
57   -{
58   - modbus_tcp_t *ctx_tcp = ctx->backend_data;
59   -
60   - /* Increase transaction ID */
61   - if (ctx_tcp->t_id < UINT16_MAX)
62   - ctx_tcp->t_id++;
63   - else
64   - ctx_tcp->t_id = 0;
65   -
66   - req[0] = ctx_tcp->t_id >> 8;
67   - req[1] = ctx_tcp->t_id & 0x00ff;
68   -
69   - /* Protocol Modbus */
70   - req[2] = 0;
71   - req[3] = 0;
72   -
73   - /* Length will be defined later by set_req_length_tcp at offsets 4
74   - and 5 */
75   -
76   - req[6] = ctx->slave;
77   - req[7] = function;
78   - req[8] = addr >> 8;
79   - req[9] = addr & 0x00ff;
80   - req[10] = nb >> 8;
81   - req[11] = nb & 0x00ff;
82   -
83   - return _MODBUS_TCP_PRESET_REQ_LENGTH;
84   -}
85   -
86   -/* Builds a TCP response header */
87   -static int _modbus_tcp_build_response_basis( sft_t *sft, uint8_t *rsp )
88   -{
89   - /* Extract from MODBUS Messaging on TCP/IP Implementation
90   - Guide V1.0b (page 23/46):
91   - The transaction identifier is used to associate the future
92   - response with the request. */
93   - rsp[0] = sft->t_id >> 8;
94   - rsp[1] = sft->t_id & 0x00ff;
95   -
96   - /* Protocol Modbus */
97   - rsp[2] = 0;
98   - rsp[3] = 0;
99   -
100   - /* Length will be set later by send_msg (4 and 5) */
101   -
102   - /* The slave ID is copied from the indication */
103   - rsp[6] = sft->slave;
104   - rsp[7] = sft->function;
105   -
106   - return _MODBUS_TCP_PRESET_RSP_LENGTH;
107   -}
108   -
109   -
110   -static int _modbus_tcp_prepare_response_tid( const uint8_t *req, int *req_length )
111   -{
112   - return (req[0] << 8) + req[1];
113   -}
114   -
115   -static int _modbus_tcp_send_msg_pre( uint8_t *req, int req_length )
116   -{
117   - /* Substract the header length to the message length */
118   - int mbap_length = req_length - 6;
119   -
120   - req[4] = mbap_length >> 8;
121   - req[5] = mbap_length & 0x00FF;
122   -
123   - return req_length;
124   -}
125   -
126   -static ssize_t _modbus_tcp_send( modbus_t *ctx, const uint8_t *req, int req_length )
127   -{
128   - /* MSG_NOSIGNAL
129   - Requests not to send SIGPIPE on errors on stream oriented
130   - sockets when the other end breaks the connection. The EPIPE
131   - error is still returned. */
132   - return send(ctx->s, (const char *)req, req_length, MSG_NOSIGNAL);
133   -}
134   -
135   -static int _modbus_tcp_receive(modbus_t *ctx, uint8_t *req)
136   -{
137   - return _modbus_receive_msg(ctx, req, MSG_INDICATION);
138   -}
139   -
140   -static ssize_t _modbus_tcp_recv(modbus_t *ctx, uint8_t *rsp, int rsp_length)
141   -{
142   - return recv( ctx->s, (char *)rsp, rsp_length, 0 );
143   -}
144   -
145   -static int _modbus_tcp_check_integrity( modbus_t *ctx, uint8_t *msg, const int msg_length )
146   -{
147   - return msg_length;
148   -}
149   -
150   -static int _modbus_tcp_pre_check_confirmation( modbus_t *ctx, const uint8_t *req, const uint8_t *rsp, int rsp_length )
151   -{
152   - /* Check transaction ID */
153   - if (req[0] != rsp[0] || req[1] != rsp[1]) {
154   - if (ctx->debug)
155   - {
156   - fprintf(stderr, "Invalid transaction ID received 0x%X (not 0x%X)\n",
157   - (rsp[0] << 8) + rsp[1], (req[0] << 8) + req[1]);
158   - }
159   - errno = EMBBADDATA;
160   - return -1;
161   - }
162   -
163   - /* Check protocol ID */
164   - if (rsp[2] != 0x0 && rsp[3] != 0x0)
165   - {
166   - if (ctx->debug)
167   - {
168   - fprintf(stderr, "Invalid protocol ID received 0x%X (not 0x0)\n",
169   - (rsp[2] << 8) + rsp[3]);
170   - }
171   - errno = EMBBADDATA;
172   - return -1;
173   - }
174   -
175   - return 0;
176   -}
177   -
178   -static int _modbus_tcp_set_ipv4_options( int s )
179   -{
180   - int rc;
181   - int option;
182   -
183   - /* Set the TCP no delay flag */
184   - /* SOL_TCP = IPPROTO_TCP */
185   - option = 1;
186   - rc = setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (const void *)&option, sizeof(int) );
187   - if (rc == -1)
188   - {
189   - return -1;
190   - }
191   -
192   - /* If the OS does not offer SOCK_NONBLOCK, fall back to setting FIONBIO to
193   - * make sockets non-blocking */
194   - /* Do not care about the return value, this is optional */
195   -#if !defined(SOCK_NONBLOCK) && defined(FIONBIO)
196   - option = 1;
197   - ioctl(s, FIONBIO, &option);
198   -#endif
199   -
200   - /**
201   - * Cygwin defines IPTOS_LOWDELAY but can't handle that flag so it's
202   - * necessary to workaround that problem.
203   - **/
204   - /* Set the IP low delay option */
205   - option = IPTOS_LOWDELAY;
206   - rc = setsockopt(s, IPPROTO_IP, IP_TOS,
207   - (const void *)&option, sizeof(int));
208   - if (rc == -1) {
209   - return -1;
210   - }
211   -
212   - return 0;
213   -}
214   -
215   -static int _connect( int sockfd, const struct sockaddr *addr, socklen_t addrlen, const struct timeval *ro_tv )
216   -{
217   - int rc = connect(sockfd, addr, addrlen);
218   -
219   - if (rc == -1 && errno == EINPROGRESS)
220   - {
221   - fd_set wset;
222   - int optval;
223   - socklen_t optlen = sizeof(optval);
224   - struct timeval tv = *ro_tv;
225   -
226   - /* Wait to be available in writing */
227   - FD_ZERO(&wset);
228   - FD_SET(sockfd, &wset);
229   - rc = select(sockfd + 1, NULL, &wset, NULL, &tv);
230   - if (rc <= 0)
231   - {
232   - /* Timeout or fail */
233   - return -1;
234   - }
235   -
236   - /* The connection is established if SO_ERROR and optval are set to 0 */
237   - rc = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&optval, &optlen);
238   - if ( rc == 0 && optval == 0 )
239   - {
240   - return 0;
241   - }
242   - else
243   - {
244   - errno = ECONNREFUSED;
245   - return -1;
246   - }
247   - }
248   - return rc;
249   -}
250   -
251   -/* Establishes a modbus TCP connection with a Modbus server. */
252   -static int _modbus_tcp_connect( modbus_t *ctx )
253   -{
254   - int rc;
255   - /* Specialized version of sockaddr for Internet socket address (same size) */
256   - struct sockaddr_in addr;
257   - modbus_tcp_t *ctx_tcp = ctx->backend_data;
258   - int flags = SOCK_STREAM;
259   -
260   -#ifdef SOCK_CLOEXEC
261   - flags |= SOCK_CLOEXEC;
262   -#endif
263   -
264   -#ifdef SOCK_NONBLOCK
265   - flags |= SOCK_NONBLOCK;
266   -#endif
267   -
268   - ctx->s = socket(PF_INET, flags, 0);
269   - if (ctx->s == -1)
270   - {
271   - return -1;
272   - }
273   -
274   - rc = _modbus_tcp_set_ipv4_options(ctx->s);
275   - if (rc == -1)
276   - {
277   - close(ctx->s);
278   - ctx->s = -1;
279   - return -1;
280   - }
281   -
282   - if (ctx->debug)
283   - {
284   - printf("Connecting to %s:%d\n", ctx_tcp->ip, ctx_tcp->port);
285   - }
286   -
287   - addr.sin_family = AF_INET;
288   - addr.sin_port = htons(ctx_tcp->port);
289   - addr.sin_addr.s_addr = inet_addr(ctx_tcp->ip);
290   - rc = _connect(ctx->s, (struct sockaddr *)&addr, sizeof(addr), &ctx->response_timeout);
291   - if( rc == -1 )
292   - {
293   - close( ctx->s );
294   - ctx->s = -1;
295   - return -1;
296   - }
297   -
298   - return 0;
299   -}
300   -
301   -/* Establishes a modbus TCP PI connection with a Modbus server. */
302   -static int _modbus_tcp_pi_connect( modbus_t *ctx )
303   -{
304   - int rc;
305   - struct addrinfo *ai_list;
306   - struct addrinfo *ai_ptr;
307   - struct addrinfo ai_hints;
308   - modbus_tcp_pi_t *ctx_tcp_pi = ctx->backend_data;
309   -
310   - memset(&ai_hints, 0, sizeof(ai_hints));
311   -#ifdef AI_ADDRCONFIG
312   - ai_hints.ai_flags |= AI_ADDRCONFIG;
313   -#endif
314   - ai_hints.ai_family = AF_UNSPEC;
315   - ai_hints.ai_socktype = SOCK_STREAM;
316   - ai_hints.ai_addr = NULL;
317   - ai_hints.ai_canonname = NULL;
318   - ai_hints.ai_next = NULL;
319   -
320   - ai_list = NULL;
321   - rc = getaddrinfo(ctx_tcp_pi->node, ctx_tcp_pi->service, &ai_hints, &ai_list);
322   - if (rc != 0)
323   - {
324   - if (ctx->debug)
325   - {
326   - fprintf(stderr, "Error returned by getaddrinfo: %s\n", gai_strerror(rc));
327   - }
328   - errno = ECONNREFUSED;
329   - return -1;
330   - }
331   -
332   - for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
333   - {
334   - int flags = ai_ptr->ai_socktype;
335   - int s;
336   -
337   -#ifdef SOCK_CLOEXEC
338   - flags |= SOCK_CLOEXEC;
339   -#endif
340   -
341   -#ifdef SOCK_NONBLOCK
342   - flags |= SOCK_NONBLOCK;
343   -#endif
344   -
345   - s = socket(ai_ptr->ai_family, flags, ai_ptr->ai_protocol);
346   - if (s < 0)
347   - continue;
348   -
349   - if (ai_ptr->ai_family == AF_INET)
350   - _modbus_tcp_set_ipv4_options(s);
351   -
352   - if (ctx->debug)
353   - {
354   - printf("Connecting to [%s]:%s\n", ctx_tcp_pi->node, ctx_tcp_pi->service);
355   - }
356   -
357   - rc = _connect(s, ai_ptr->ai_addr, ai_ptr->ai_addrlen, &ctx->response_timeout);
358   - if (rc == -1)
359   - {
360   - close(s);
361   - continue;
362   - }
363   -
364   - ctx->s = s;
365   - break;
366   - }
367   -
368   - freeaddrinfo(ai_list);
369   -
370   - if (ctx->s < 0)
371   - {
372   - return -1;
373   - }
374   -
375   - return 0;
376   -}
377   -
378   -/* Closes the network connection and socket in TCP mode */
379   -static void _modbus_tcp_close( modbus_t *ctx )
380   -{
381   - if (ctx->s != -1)
382   - {
383   - shutdown(ctx->s, SHUT_RDWR);
384   - close(ctx->s);
385   - ctx->s = -1;
386   - }
387   -}
388   -
389   -static int _modbus_tcp_flush( modbus_t *ctx )
390   -{
391   - int rc;
392   - int rc_sum = 0;
393   -
394   - do
395   - {
396   - /* Extract the garbage from the socket */
397   - char devnull[MODBUS_TCP_MAX_ADU_LENGTH];
398   -
399   - rc = recv(ctx->s, devnull, MODBUS_TCP_MAX_ADU_LENGTH, MSG_DONTWAIT);
400   - if ( rc > 0 )
401   - {
402   - rc_sum += rc;
403   - }
404   - } while ( rc == MODBUS_TCP_MAX_ADU_LENGTH );
405   -
406   - return rc_sum;
407   -}
408   -
409   -/* Listens for any request from one or many modbus masters in TCP */
410   -int modbus_tcp_listen( modbus_t *ctx, int nb_connection )
411   -{
412   - int new_s;
413   - int enable;
414   - struct sockaddr_in addr;
415   - modbus_tcp_t *ctx_tcp;
416   -
417   - if (ctx == NULL)
418   - {
419   - errno = EINVAL;
420   - return -1;
421   - }
422   -
423   - ctx_tcp = ctx->backend_data;
424   -
425   - new_s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
426   - if ( new_s == -1 )
427   - {
428   - return -1;
429   - }
430   -
431   - enable = 1;
432   - if (setsockopt(new_s, SOL_SOCKET, SO_REUSEADDR, (char *)&enable, sizeof(enable)) == -1)
433   - {
434   - close(new_s);
435   - return -1;
436   - }
437   -
438   - memset(&addr, 0, sizeof(addr));
439   - addr.sin_family = AF_INET;
440   -
441   - /* If the modbus port is < to 1024, we need the setuid root. */
442   - addr.sin_port = htons(ctx_tcp->port);
443   - if (ctx_tcp->ip[0] == '0')
444   - {
445   - /* Listen any addresses */
446   - addr.sin_addr.s_addr = htonl(INADDR_ANY);
447   - }
448   - else
449   - {
450   - /* Listen only specified IP address */
451   - addr.sin_addr.s_addr = inet_addr(ctx_tcp->ip);
452   - }
453   - if (bind( new_s, (struct sockaddr *)&addr, sizeof(addr)) == -1)
454   - {
455   - close(new_s);
456   - return -1;
457   - }
458   -
459   - if (listen(new_s, nb_connection) == -1)
460   - {
461   - close(new_s);
462   - return -1;
463   - }
464   -
465   - return new_s;
466   -}
467   -
468   -int modbus_tcp_pi_listen( modbus_t *ctx, int nb_connection )
469   -{
470   - int rc;
471   - struct addrinfo *ai_list;
472   - struct addrinfo *ai_ptr;
473   - struct addrinfo ai_hints;
474   - const char *node;
475   - const char *service;
476   - int new_s;
477   - modbus_tcp_pi_t *ctx_tcp_pi;
478   -
479   - if (ctx == NULL)
480   - {
481   - errno = EINVAL;
482   - return -1;
483   - }
484   -
485   - ctx_tcp_pi = ctx->backend_data;
486   -
487   - if ( ctx_tcp_pi->node[0] == 0)
488   - {
489   - node = NULL; /* == any */
490   - }
491   - else
492   - {
493   - node = ctx_tcp_pi->node;
494   - }
495   -
496   - if ( ctx_tcp_pi->service[0] == 0 )
497   - {
498   - service = "502";
499   - }
500   - else
501   - {
502   - service = ctx_tcp_pi->service;
503   - }
504   -
505   - memset( &ai_hints, 0, sizeof (ai_hints) );
506   - /* If node is not NULL, than the AI_PASSIVE flag is ignored. */
507   - ai_hints.ai_flags |= AI_PASSIVE;
508   -#ifdef AI_ADDRCONFIG
509   - ai_hints.ai_flags |= AI_ADDRCONFIG;
510   -#endif
511   - ai_hints.ai_family = AF_UNSPEC;
512   - ai_hints.ai_socktype = SOCK_STREAM;
513   - ai_hints.ai_addr = NULL;
514   - ai_hints.ai_canonname = NULL;
515   - ai_hints.ai_next = NULL;
516   -
517   - ai_list = NULL;
518   - rc = getaddrinfo(node, service, &ai_hints, &ai_list);
519   - if (rc != 0)
520   - {
521   - if (ctx->debug)
522   - {
523   - fprintf(stderr, "Error returned by getaddrinfo: %s\n", gai_strerror(rc));
524   - }
525   - errno = ECONNREFUSED;
526   - return -1;
527   - }
528   -
529   - new_s = -1;
530   - for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next)
531   - {
532   - int s;
533   -
534   - s = socket( ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol );
535   - if (s < 0)
536   - {
537   - if (ctx->debug)
538   - {
539   - perror("socket");
540   - }
541   - continue;
542   - }
543   - else
544   - {
545   - int enable = 1;
546   - rc = setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (void *)&enable, sizeof (enable) );
547   - if (rc != 0)
548   - {
549   - close(s);
550   - if (ctx->debug)
551   - {
552   - perror("setsockopt");
553   - }
554   - continue;
555   - }
556   - }
557   -
558   - rc = bind(s, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
559   - if (rc != 0)
560   - {
561   - close(s);
562   - if (ctx->debug)
563   - {
564   - perror("bind");
565   - }
566   - continue;
567   - }
568   -
569   - rc = listen(s, nb_connection);
570   - if (rc != 0)
571   - {
572   - close(s);
573   - if (ctx->debug)
574   - {
575   - perror("listen");
576   - }
577   - continue;
578   - }
579   -
580   - new_s = s;
581   - break;
582   - }
583   - freeaddrinfo(ai_list);
584   -
585   - if (new_s < 0)
586   - {
587   - return -1;
588   - }
589   -
590   - return new_s;
591   -}
592   -
593   -int modbus_tcp_accept(modbus_t *ctx, int *s)
594   -{
595   - struct sockaddr_in addr;
596   - socklen_t addrlen;
597   -
598   - if (ctx == NULL)
599   - {
600   - errno = EINVAL;
601   - return -1;
602   - }
603   -
604   - addrlen = sizeof(addr);
605   -#ifdef HAVE_ACCEPT4
606   - /* Inherit socket flags and use accept4 call */
607   - ctx->s = accept4(*s, (struct sockaddr *)&addr, &addrlen, SOCK_CLOEXEC);
608   -#else
609   - ctx->s = accept(*s, (struct sockaddr *)&addr, &addrlen);
610   -#endif
611   -
612   - if (ctx->s == -1)
613   - {
614   - close(*s);
615   - *s = -1;
616   - return -1;
617   - }
618   -
619   - if (ctx->debug)
620   - {
621   - printf("The client connection from %s is accepted\n",
622   - inet_ntoa(addr.sin_addr));
623   - }
624   -
625   - return ctx->s;
626   -}
627   -
628   -int modbus_tcp_pi_accept( modbus_t *ctx, int *s )
629   -{
630   - struct sockaddr_storage addr;
631   - socklen_t addrlen;
632   -
633   - if (ctx == NULL)
634   - {
635   - errno = EINVAL;
636   - return -1;
637   - }
638   -
639   - addrlen = sizeof(addr);
640   -#ifdef HAVE_ACCEPT4
641   - /* Inherit socket flags and use accept4 call */
642   - ctx->s = accept4(*s, (struct sockaddr *)&addr, &addrlen, SOCK_CLOEXEC);
643   -#else
644   - ctx->s = accept(*s, (struct sockaddr *)&addr, &addrlen);
645   -#endif
646   - if (ctx->s == -1)
647   - {
648   - close(*s);
649   - *s = -1;
650   - }
651   -
652   - if (ctx->debug)
653   - {
654   - printf("The client connection is accepted.\n");
655   - }
656   -
657   - return ctx->s;
658   -}
659   -
660   -static int _modbus_tcp_select(modbus_t *ctx, fd_set *rset, struct timeval *tv, int length_to_read)
661   -{
662   - int s_rc;
663   - while ((s_rc = select(ctx->s+1, rset, NULL, NULL, tv)) == -1)
664   - {
665   - if (errno == EINTR)
666   - {
667   - if (ctx->debug)
668   - {
669   - fprintf(stderr, "A non blocked signal was caught\n");
670   - }
671   - /* Necessary after an error */
672   - FD_ZERO(rset);
673   - FD_SET(ctx->s, rset);
674   - }
675   - else
676   - {
677   - return -1;
678   - }
679   - }
680   -
681   - if ( s_rc == 0 )
682   - {
683   - errno = ETIMEDOUT;
684   - return -1;
685   - }
686   -
687   - return s_rc;
688   -}
689   -
690   -static void _modbus_tcp_free( modbus_t *ctx )
691   -{
692   - free(ctx->backend_data);
693   - free(ctx);
694   -}
695   -
696   -const modbus_backend_t _modbus_tcp_backend =
697   -{
698   - _MODBUS_BACKEND_TYPE_TCP,
699   - _MODBUS_TCP_HEADER_LENGTH,
700   - _MODBUS_TCP_CHECKSUM_LENGTH,
701   - MODBUS_TCP_MAX_ADU_LENGTH,
702   - _modbus_set_slave,
703   - _modbus_tcp_build_request_basis,
704   - _modbus_tcp_build_response_basis,
705   - _modbus_tcp_prepare_response_tid,
706   - _modbus_tcp_send_msg_pre,
707   - _modbus_tcp_send,
708   - _modbus_tcp_receive,
709   - _modbus_tcp_recv,
710   - _modbus_tcp_check_integrity,
711   - _modbus_tcp_pre_check_confirmation,
712   - _modbus_tcp_connect,
713   - _modbus_tcp_close,
714   - _modbus_tcp_flush,
715   - _modbus_tcp_select,
716   - _modbus_tcp_free
717   -};
718   -
719   -
720   -const modbus_backend_t _modbus_tcp_pi_backend =
721   -{
722   - _MODBUS_BACKEND_TYPE_TCP,
723   - _MODBUS_TCP_HEADER_LENGTH,
724   - _MODBUS_TCP_CHECKSUM_LENGTH,
725   - MODBUS_TCP_MAX_ADU_LENGTH,
726   - _modbus_set_slave,
727   - _modbus_tcp_build_request_basis,
728   - _modbus_tcp_build_response_basis,
729   - _modbus_tcp_prepare_response_tid,
730   - _modbus_tcp_send_msg_pre,
731   - _modbus_tcp_send,
732   - _modbus_tcp_receive,
733   - _modbus_tcp_recv,
734   - _modbus_tcp_check_integrity,
735   - _modbus_tcp_pre_check_confirmation,
736   - _modbus_tcp_pi_connect,
737   - _modbus_tcp_close,
738   - _modbus_tcp_flush,
739   - _modbus_tcp_select,
740   - _modbus_tcp_free
741   -};
742   -
743   -modbus_t* modbus_new_tcp( const char *ip, int port )
744   -{
745   - modbus_t *ctx;
746   - modbus_tcp_t *ctx_tcp;
747   - size_t dest_size;
748   - size_t ret_size;
749   -
750   - ctx = (modbus_t *)malloc(sizeof(modbus_t) );
751   - _modbus_init_common(ctx);
752   -
753   - /* Could be changed after to reach a remote serial Modbus device */
754   - ctx->slave = MODBUS_TCP_SLAVE;
755   -
756   - ctx->backend = &_modbus_tcp_backend;
757   -
758   - ctx->backend_data = ( modbus_tcp_t *)malloc(sizeof(modbus_tcp_t) );
759   - ctx_tcp = (modbus_tcp_t *)ctx->backend_data;
760   -
761   - if (ip != NULL)
762   - {
763   - dest_size = sizeof(char) * 16;
764   - ret_size = strlcpy(ctx_tcp->ip, ip, dest_size);
765   - if (ret_size == 0)
766   - {
767   - fprintf(stderr, "The IP string is empty\n");
768   - modbus_free(ctx);
769   - errno = EINVAL;
770   - return NULL;
771   - }
772   -
773   - if (ret_size >= dest_size)
774   - {
775   - fprintf(stderr, "The IP string has been truncated\n");
776   - modbus_free(ctx);
777   - errno = EINVAL;
778   - return NULL;
779   - }
780   - }
781   - else
782   - {
783   - ctx_tcp->ip[0] = '0';
784   - }
785   - ctx_tcp->port = port;
786   - ctx_tcp->t_id = 0;
787   -
788   - return ctx;
789   -}
790   -
791   -
792   -modbus_t* modbus_new_tcp_pi( const char *node, const char *service )
793   -{
794   - modbus_t *ctx;
795   - modbus_tcp_pi_t *ctx_tcp_pi;
796   - size_t dest_size;
797   - size_t ret_size;
798   -
799   - ctx = (modbus_t *)malloc(sizeof(modbus_t));
800   - _modbus_init_common(ctx);
801   -
802   - /* Could be changed after to reach a remote serial Modbus device */
803   - ctx->slave = MODBUS_TCP_SLAVE;
804   -
805   - ctx->backend = &_modbus_tcp_pi_backend;
806   -
807   - ctx->backend_data = (modbus_tcp_pi_t *)malloc(sizeof(modbus_tcp_pi_t));
808   - ctx_tcp_pi = (modbus_tcp_pi_t *)ctx->backend_data;
809   -
810   - if (node == NULL)
811   - {
812   - /* The node argument can be empty to indicate any hosts */
813   - ctx_tcp_pi->node[0] = 0;
814   - }
815   - else
816   - {
817   - dest_size = sizeof(char) * _MODBUS_TCP_PI_NODE_LENGTH;
818   - ret_size = strlcpy(ctx_tcp_pi->node, node, dest_size);
819   - if (ret_size == 0)
820   - {
821   - fprintf(stderr, "The node string is empty\n");
822   - modbus_free(ctx);
823   - errno = EINVAL;
824   - return NULL;
825   - }
826   -
827   - if (ret_size >= dest_size)
828   - {
829   - fprintf(stderr, "The node string has been truncated\n");
830   - modbus_free(ctx);
831   - errno = EINVAL;
832   - return NULL;
833   - }
834   - }
835   -
836   - if (service != NULL)
837   - {
838   - dest_size = sizeof(char) * _MODBUS_TCP_PI_SERVICE_LENGTH;
839   - ret_size = strlcpy(ctx_tcp_pi->service, service, dest_size);
840   - }
841   - else
842   - {
843   - /* Empty service is not allowed, error catched below. */
844   - ret_size = 0;
845   - }
846   -
847   - if (ret_size == 0)
848   - {
849   - fprintf(stderr, "The service string is empty\n");
850   - modbus_free(ctx);
851   - errno = EINVAL;
852   - return NULL;
853   - }
854   -
855   - if (ret_size >= dest_size)
856   - {
857   - fprintf(stderr, "The service string has been truncated\n");
858   - modbus_free(ctx);
859   - errno = EINVAL;
860   - return NULL;
861   - }
862   -
863   - ctx_tcp_pi->t_id = 0;
864   -
865   - return ctx;
866   -}
stack/modbus-tcp.h deleted
1   -#pragma once
2   -
3   -#include "modbus.h"
4   -
5   -MODBUS_BEGIN_DECLS
6   -
7   -#define MODBUS_TCP_DEFAULT_PORT 502
8   -#define MODBUS_TCP_SLAVE 0xFF
9   -
10   -/* Modbus_Application_Protocol_V1_1b.pdf Chapter 4 Section 1 Page 5
11   - * TCP MODBUS ADU = 253 bytes + MBAP (7 bytes) = 260 bytes
12   - */
13   -#define MODBUS_TCP_MAX_ADU_LENGTH 260
14   -
15   -MODBUS_API modbus_t* modbus_new_tcp(const char *ip_address, int port);
16   -MODBUS_API int modbus_tcp_listen(modbus_t *ctx, int nb_connection);
17   -MODBUS_API int modbus_tcp_accept(modbus_t *ctx, int *s);
18   -
19   -MODBUS_API modbus_t* modbus_new_tcp_pi(const char *node, const char *service);
20   -MODBUS_API int modbus_tcp_pi_listen(modbus_t *ctx, int nb_connection);
21   -MODBUS_API int modbus_tcp_pi_accept(modbus_t *ctx, int *s);
22   -
23   -MODBUS_END_DECLS
24   -
stack/modbus-version.h deleted
1   -#pragma once
2   -
3   -/* The major version, (1, if %LIBMODBUS_VERSION is 1.2.3) */
4   -#define LIBMODBUS_VERSION_MAJOR (3)
5   -
6   -/* The minor version (2, if %LIBMODBUS_VERSION is 1.2.3) */
7   -#define LIBMODBUS_VERSION_MINOR (1)
8   -
9   -/* The micro version (3, if %LIBMODBUS_VERSION is 1.2.3) */
10   -#define LIBMODBUS_VERSION_MICRO (4)
11   -
12   -/* The full version, like 1.2.3 */
13   -#define LIBMODBUS_VERSION 3.1.4
14   -
15   -/* The full version, in string form (suited for string concatenation)
16   - */
17   -#define LIBMODBUS_VERSION_STRING "3.1.4"
18   -
19   -/* Numerically encoded version, like 0x010203 */
20   -#define LIBMODBUS_VERSION_HEX ((LIBMODBUS_VERSION_MAJOR << 24) | \
21   - (LIBMODBUS_VERSION_MINOR << 16) | \
22   - (LIBMODBUS_VERSION_MICRO << 8))
23   -
24   -/* Evaluates to True if the version is greater than @major, @minor and @micro
25   - */
26   -#define LIBMODBUS_VERSION_CHECK(major,minor,micro) \
27   - (LIBMODBUS_VERSION_MAJOR > (major) || \
28   - (LIBMODBUS_VERSION_MAJOR == (major) && \
29   - LIBMODBUS_VERSION_MINOR > (minor)) || \
30   - (LIBMODBUS_VERSION_MAJOR == (major) && \
31   - LIBMODBUS_VERSION_MINOR == (minor) && \
32   - LIBMODBUS_VERSION_MICRO >= (micro)))
33   -
34   -
stack/modbus.c deleted
1   -#include <config.h>
2   -#include <errno.h>
3   -#include <limits.h>
4   -#include <stdio.h>
5   -#include <string.h>
6   -#include <stdlib.h>
7   -#include <stdarg.h>
8   -#include <time.h>
9   -#include <unistd.h>
10   -
11   -#include "modbus.h"
12   -#include "modbus-private.h"
13   -
14   -/* Internal use */
15   -#define MSG_LENGTH_UNDEFINED -1
16   -
17   -/* Max between RTU and TCP max adu length (so TCP) */
18   -#define MAX_MESSAGE_LENGTH 260
19   -
20   -/* 3 steps are used to parse the query */
21   -typedef enum
22   -{
23   - _STEP_FUNCTION,
24   - _STEP_META,
25   - _STEP_DATA
26   -} _step_t;
27   -
28   -const char *modbus_strerror( int errnum )
29   -{
30   - switch (errnum)
31   - {
32   - case EMBXILFUN:
33   - return "Illegal function";
34   - case EMBXILADD:
35   - return "Illegal data address";
36   - case EMBXILVAL:
37   - return "Illegal data value";
38   - case EMBXSFAIL:
39   - return "Slave device or server failure";
40   - case EMBXACK:
41   - return "Acknowledge";
42   - case EMBXSBUSY:
43   - return "Slave device or server is busy";
44   - case EMBXNACK:
45   - return "Negative acknowledge";
46   - case EMBXMEMPAR:
47   - return "Memory parity error";
48   - case EMBXGPATH:
49   - return "Gateway path unavailable";
50   - case EMBXGTAR:
51   - return "Target device failed to respond";
52   - case EMBBADCRC:
53   - return "Invalid CRC";
54   - case EMBBADDATA:
55   - return "Invalid data";
56   - case EMBBADEXC:
57   - return "Invalid exception code";
58   - case EMBMDATA:
59   - return "Too many data";
60   - case EMBBADSLAVE:
61   - return "Response not from requested slave";
62   - default:
63   - return strerror(errnum);
64   - }
65   -}
66   -
67   -void _error_print(modbus_t *ctx, const char *context)
68   -{
69   - if (ctx->debug)
70   - {
71   - fprintf(stderr, "ERROR %s", modbus_strerror(errno));
72   - if (context != NULL)
73   - {
74   - fprintf(stderr, ": %s\n", context);
75   - }
76   - else
77   - {
78   - fprintf(stderr, "\n");
79   - }
80   - }
81   -}
82   -
83   -static void _sleep_response_timeout(modbus_t *ctx)
84   -{
85   - /* Response timeout is always positive */
86   - /* usleep source code */
87   - struct timespec request, remaining;
88   - request.tv_sec = ctx->response_timeout.tv_sec;
89   - request.tv_nsec = ((long int)ctx->response_timeout.tv_usec) * 1000;
90   - while ( nanosleep( &request, &remaining ) == -1 && errno == EINTR )
91   - {
92   - request = remaining;
93   - }
94   -}
95   -
96   -int modbus_flush(modbus_t *ctx)
97   -{
98   - int rc;
99   -
100   - if (ctx == NULL)
101   - {
102   - errno = EINVAL;
103   - return -1;
104   - }
105   -
106   - rc = ctx->backend->flush( ctx );
107   - if (rc != -1 && ctx->debug)
108   - {
109   - /* Not all backends are able to return the number of bytes flushed */
110   - printf("Bytes flushed (%d)\n", rc);
111   - }
112   - return rc;
113   -}
114   -
115   -/* Computes the length of the expected response */
116   -static unsigned int compute_response_length_from_request(modbus_t *ctx, uint8_t *req)
117   -{
118   - int length;
119   - const int offset = ctx->backend->header_length;
120   -
121   - switch (req[offset])
122   - {
123   - case MODBUS_FC_READ_COILS:
124   - case MODBUS_FC_READ_DISCRETE_INPUTS:
125   - /* Header + nb values (code from write_bits) */
126   - int nb = (req[offset + 3] << 8) | req[offset + 4];
127   - length = 2 + (nb / 8) + ((nb % 8) ? 1 : 0);
128   - break;
129   - case MODBUS_FC_WRITE_AND_READ_REGISTERS:
130   - case MODBUS_FC_READ_HOLDING_REGISTERS:
131   - case MODBUS_FC_READ_INPUT_REGISTERS:
132   - /* Header + 2 * nb values */
133   - length = 2 + 2 * (req[offset + 3] << 8 | req[offset + 4]);
134   - break;
135   - case MODBUS_FC_READ_EXCEPTION_STATUS:
136   - length = 3;
137   - break;
138   - case MODBUS_FC_REPORT_SLAVE_ID:
139   - /* The response is device specific (the header provides the
140   - length) */
141   - return MSG_LENGTH_UNDEFINED;
142   - case MODBUS_FC_MASK_WRITE_REGISTER:
143   - length = 7;
144   - break;
145   - default:
146   - length = 5;
147   - }
148   -
149   - return offset + length + ctx->backend->checksum_length;
150   -}
151   -
152   -/* Sends a request/response */
153   -static int send_msg(modbus_t *ctx, uint8_t *msg, int msg_length)
154   -{
155   - int rc;
156   - int i;
157   -
158   - msg_length = ctx->backend->send_msg_pre(msg, msg_length);
159   -
160   - if (ctx->debug)
161   - {
162   - for (i = 0; i < msg_length; i++)
163   - {
164   - printf("[%.2X]", msg[i]);
165   - }
166   - printf("\n");
167   - }
168   -
169   - /* In recovery mode, the write command will be issued until to be
170   - successful! Disabled by default. */
171   - do
172   - {
173   - rc = ctx->backend->send(ctx, msg, msg_length);
174   - if (rc == -1)
175   - {
176   - _error_print(ctx, NULL);
177   - if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK)
178   - {
179   - int saved_errno = errno;
180   -
181   - if ( (errno == EBADF || errno == ECONNRESET || errno == EPIPE))
182   - {
183   - modbus_close(ctx);
184   - _sleep_response_timeout(ctx);
185   - modbus_connect(ctx);
186   - }
187   - else
188   - {
189   - _sleep_response_timeout(ctx);
190   - modbus_flush(ctx);
191   - }
192   - errno = saved_errno;
193   - }
194   - }
195   - } while ( (ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) && rc == -1);
196   -
197   - if (rc > 0 && rc != msg_length) {
198   - errno = EMBBADDATA;
199   - return -1;
200   - }
201   -
202   - return rc;
203   -}
204   -
205   -int modbus_send_raw_request( modbus_t *ctx, uint8_t *raw_req, int raw_req_length )
206   -{
207   - sft_t sft;
208   - uint8_t req[MAX_MESSAGE_LENGTH];
209   - int req_length;
210   -
211   - if (ctx == NULL)
212   - {
213   - errno = EINVAL;
214   - return -1;
215   - }
216   -
217   - if (raw_req_length < 2 || raw_req_length > (MODBUS_MAX_PDU_LENGTH + 1))
218   - {
219   - /* The raw request must contain function and slave at least and
220   - must not be longer than the maximum pdu length plus the slave
221   - address. */
222   - errno = EINVAL;
223   - return -1;
224   - }
225   -
226   - sft.slave = raw_req[0];
227   - sft.function = raw_req[1];
228   - /* The t_id is left to zero */
229   - sft.t_id = 0;
230   - /* This response function only set the header so it's convenient here */
231   - req_length = ctx->backend->build_response_basis(&sft, req);
232   -
233   - if( raw_req_length > 2 )
234   - {
235   - /* Copy data after function code */
236   - memcpy(req + req_length, raw_req + 2, raw_req_length - 2);
237   - req_length += raw_req_length - 2;
238   - }
239   -
240   - return send_msg(ctx, req, req_length);
241   -}
242   -
243   -/*
244   - * ---------- Request Indication ----------
245   - * | Client | ---------------------->| Server |
246   - * ---------- Confirmation Response ----------
247   - */
248   -
249   -/* Computes the length to read after the function received */
250   -static uint8_t compute_meta_length_after_function( int function, msg_type_t msg_type )
251   -{
252   - int length;
253   -
254   - if (msg_type == MSG_INDICATION)
255   - {
256   - if (function <= MODBUS_FC_WRITE_SINGLE_REGISTER)
257   - {
258   - length = 4;
259   - }
260   - else if (function == MODBUS_FC_WRITE_MULTIPLE_COILS || function == MODBUS_FC_WRITE_MULTIPLE_REGISTERS)
261   - {
262   - length = 5;
263   - }
264   - else if (function == MODBUS_FC_MASK_WRITE_REGISTER)
265   - {
266   - length = 6;
267   - }
268   - else if (function == MODBUS_FC_WRITE_AND_READ_REGISTERS)
269   - {
270   - length = 9;
271   - }
272   - else
273   - {
274   - /* MODBUS_FC_READ_EXCEPTION_STATUS, MODBUS_FC_REPORT_SLAVE_ID */
275   - length = 0;
276   - }
277   - }
278   - else
279   - {
280   - /* MSG_CONFIRMATION */
281   - switch (function)
282   - {
283   - case MODBUS_FC_WRITE_SINGLE_COIL:
284   - case MODBUS_FC_WRITE_SINGLE_REGISTER:
285   - case MODBUS_FC_WRITE_MULTIPLE_COILS:
286   - case MODBUS_FC_WRITE_MULTIPLE_REGISTERS:
287   - length = 4;
288   - break;
289   - case MODBUS_FC_MASK_WRITE_REGISTER:
290   - length = 6;
291   - break;
292   - default:
293   - length = 1;
294   - }
295   - }
296   -
297   - return length;
298   -}
299   -
300   -/* Computes the length to read after the meta information (address, count, etc) */
301   -static int compute_data_length_after_meta(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type)
302   -{
303   - int function = msg[ctx->backend->header_length];
304   - int length;
305   -
306   - if (msg_type == MSG_INDICATION)
307   - {
308   - switch (function)
309   - {
310   - case MODBUS_FC_WRITE_MULTIPLE_COILS:
311   - case MODBUS_FC_WRITE_MULTIPLE_REGISTERS:
312   - length = msg[ctx->backend->header_length + 5];
313   - break;
314   - case MODBUS_FC_WRITE_AND_READ_REGISTERS:
315   - length = msg[ctx->backend->header_length + 9];
316   - break;
317   - default:
318   - length = 0;
319   - }
320   - }
321   - else
322   - {
323   - /* MSG_CONFIRMATION */
324   - if (function <= MODBUS_FC_READ_INPUT_REGISTERS ||
325   - function == MODBUS_FC_REPORT_SLAVE_ID ||
326   - function == MODBUS_FC_WRITE_AND_READ_REGISTERS)
327   - {
328   - length = msg[ctx->backend->header_length + 1];
329   - }
330   - else
331   - {
332   - length = 0;
333   - }
334   - }
335   -
336   - length += ctx->backend->checksum_length;
337   -
338   - return length;
339   -}
340   -
341   -
342   -/* Waits a response from a modbus server or a request from a modbus client.
343   - This function blocks if there is no replies (3 timeouts).
344   -
345   - The function shall return the number of received characters and the received
346   - message in an array of uint8_t if successful. Otherwise it shall return -1
347   - and errno is set to one of the values defined below:
348   - - ECONNRESET
349   - - EMBBADDATA
350   - - EMBUNKEXC
351   - - ETIMEDOUT
352   - - read() or recv() error codes
353   -*/
354   -
355   -int _modbus_receive_msg( modbus_t *ctx, uint8_t *msg, msg_type_t msg_type )
356   -{
357   - int rc;
358   - fd_set rset;
359   - struct timeval tv;
360   - struct timeval *p_tv;
361   - int length_to_read;
362   - int msg_length = 0;
363   - _step_t step;
364   -
365   - if (ctx->debug)
366   - {
367   - if (msg_type == MSG_INDICATION)
368   - {
369   - printf("Waiting for a indication...\n");
370   - }
371   - else
372   - {
373   - printf("Waiting for a confirmation...\n");
374   - }
375   - }
376   -
377   - /* Add a file descriptor to the set */
378   - FD_ZERO(&rset);
379   - FD_SET(ctx->s, &rset);
380   -
381   - /* We need to analyse the message step by step. At the first step, we want
382   - * to reach the function code because all packets contain this
383   - * information. */
384   - step = _STEP_FUNCTION;
385   - length_to_read = ctx->backend->header_length + 1;
386   -
387   - if (msg_type == MSG_INDICATION)
388   - {
389   - /* Wait for a message, we don't know when the message will be
390   - * received */
391   - p_tv = NULL;
392   - }
393   - else
394   - {
395   - tv.tv_sec = ctx->response_timeout.tv_sec;
396   - tv.tv_usec = ctx->response_timeout.tv_usec;
397   - p_tv = &tv;
398   - }
399   -
400   - while (length_to_read != 0)
401   - {
402   - rc = ctx->backend->select(ctx, &rset, p_tv, length_to_read);
403   - if (rc == -1)
404   - {
405   - _error_print(ctx, "select");
406   - if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK)
407   - {
408   - int saved_errno = errno;
409   -
410   - if (errno == ETIMEDOUT)
411   - {
412   - _sleep_response_timeout(ctx);
413   - modbus_flush(ctx);
414   - }
415   - else if (errno == EBADF)
416   - {
417   - modbus_close(ctx);
418   - modbus_connect(ctx);
419   - }
420   - errno = saved_errno;
421   - }
422   - return -1;
423   - }
424   -
425   - rc = ctx->backend->recv(ctx, msg + msg_length, length_to_read);
426   - if (rc == 0)
427   - {
428   - errno = ECONNRESET;
429   - rc = -1;
430   - }
431   -
432   - if (rc == -1)
433   - {
434   - _error_print(ctx, "read");
435   - if ((ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) &&
436   - (errno == ECONNRESET || errno == ECONNREFUSED ||
437   - errno == EBADF))
438   - {
439   - int saved_errno = errno;
440   - modbus_close(ctx);
441   - modbus_connect(ctx);
442   - /* Could be removed by previous calls */
443   - errno = saved_errno;
444   - }
445   - return -1;
446   - }
447   -
448   - /* Display the hex code of each character received */
449   - if (ctx->debug)
450   - {
451   - int i;
452   - for (i=0; i < rc; i++)
453   - printf("<%.2X>", msg[msg_length + i]);
454   - }
455   -
456   - /* Sums bytes received */
457   - msg_length += rc;
458   - /* Computes remaining bytes */
459   - length_to_read -= rc;
460   -
461   - if (length_to_read == 0)
462   - {
463   - switch (step)
464   - {
465   - case _STEP_FUNCTION:
466   - /* Function code position */
467   - length_to_read = compute_meta_length_after_function( msg[ctx->backend->header_length], msg_type);
468   - if (length_to_read != 0)
469   - {
470   - step = _STEP_META;
471   - break;
472   - } /* else switches straight to the next step */
473   - case _STEP_META:
474   - length_to_read = compute_data_length_after_meta( ctx, msg, msg_type);
475   - if ( (msg_length + length_to_read) > (int)ctx->backend->max_adu_length )
476   - {
477   - errno = EMBBADDATA;
478   - _error_print(ctx, "too many data");
479   - return -1;
480   - }
481   - step = _STEP_DATA;
482   - break;
483   - default:
484   - break;
485   - }
486   - }
487   -
488   - if (length_to_read > 0 &&
489   - (ctx->byte_timeout.tv_sec > 0 || ctx->byte_timeout.tv_usec > 0)) {
490   - /* If there is no character in the buffer, the allowed timeout
491   - interval between two consecutive bytes is defined by
492   - byte_timeout */
493   - tv.tv_sec = ctx->byte_timeout.tv_sec;
494   - tv.tv_usec = ctx->byte_timeout.tv_usec;
495   - p_tv = &tv;
496   - }
497   - /* else timeout isn't set again, the full response must be read before
498   - expiration of response timeout (for CONFIRMATION only) */
499   - }
500   -
501   - if (ctx->debug)
502   - printf("\n");
503   -
504   - return ctx->backend->check_integrity(ctx, msg, msg_length);
505   -}
506   -
507   -/* Receive the request from a modbus master */
508   -int modbus_receive(modbus_t *ctx, uint8_t *req)
509   -{
510   - if (ctx == NULL) {
511   - errno = EINVAL;
512   - return -1;
513   - }
514   -
515   - return ctx->backend->receive(ctx, req);
516   -}
517   -
518   -/* Receives the confirmation.
519   -
520   - The function shall store the read response in rsp and return the number of
521   - values (bits or words). Otherwise, its shall return -1 and errno is set.
522   -
523   - The function doesn't check the confirmation is the expected response to the
524   - initial request.
525   -*/
526   -int modbus_receive_confirmation(modbus_t *ctx, uint8_t *rsp)
527   -{
528   - if (ctx == NULL) {
529   - errno = EINVAL;
530   - return -1;
531   - }
532   -
533   - return _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);
534   -}
535   -
536   -static int check_confirmation(modbus_t *ctx, uint8_t *req,
537   - uint8_t *rsp, int rsp_length)
538   -{
539   - int rc;
540   - int rsp_length_computed;
541   - const int offset = ctx->backend->header_length;
542   - const int function = rsp[offset];
543   -
544   - if (ctx->backend->pre_check_confirmation) {
545   - rc = ctx->backend->pre_check_confirmation(ctx, req, rsp, rsp_length);
546   - if (rc == -1) {
547   - if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_PROTOCOL) {
548   - _sleep_response_timeout(ctx);
549   - modbus_flush(ctx);
550   - }
551   - return -1;
552   - }
553   - }
554   -
555   - rsp_length_computed = compute_response_length_from_request(ctx, req);
556   -
557   - /* Exception code */
558   - if (function >= 0x80) {
559   - if (rsp_length == (offset + 2 + (int)ctx->backend->checksum_length) &&
560   - req[offset] == (rsp[offset] - 0x80)) {
561   - /* Valid exception code received */
562   -
563   - int exception_code = rsp[offset + 1];
564   - if (exception_code < MODBUS_EXCEPTION_MAX) {
565   - errno = MODBUS_ENOBASE + exception_code;
566   - } else {
567   - errno = EMBBADEXC;
568   - }
569   - _error_print(ctx, NULL);
570   - return -1;
571   - } else {
572   - errno = EMBBADEXC;
573   - _error_print(ctx, NULL);
574   - return -1;
575   - }
576   - }
577   -
578   - /* Check length */
579   - if ((rsp_length == rsp_length_computed ||
580   - rsp_length_computed == MSG_LENGTH_UNDEFINED) &&
581   - function < 0x80) {
582   - int req_nb_value;
583   - int rsp_nb_value;
584   -
585   - /* Check function code */
586   - if (function != req[offset]) {
587   - if (ctx->debug) {
588   - fprintf(stderr,
589   - "Received function not corresponding to the request (0x%X != 0x%X)\n",
590   - function, req[offset]);
591   - }
592   - if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_PROTOCOL) {
593   - _sleep_response_timeout(ctx);
594   - modbus_flush(ctx);
595   - }
596   - errno = EMBBADDATA;
597   - return -1;
598   - }
599   -
600   - /* Check the number of values is corresponding to the request */
601   - switch (function) {
602   - case MODBUS_FC_READ_COILS:
603   - case MODBUS_FC_READ_DISCRETE_INPUTS:
604   - /* Read functions, 8 values in a byte (nb
605   - * of values in the request and byte count in
606   - * the response. */
607   - req_nb_value = (req[offset + 3] << 8) + req[offset + 4];
608   - req_nb_value = (req_nb_value / 8) + ((req_nb_value % 8) ? 1 : 0);
609   - rsp_nb_value = rsp[offset + 1];
610   - break;
611   - case MODBUS_FC_WRITE_AND_READ_REGISTERS:
612   - case MODBUS_FC_READ_HOLDING_REGISTERS:
613   - case MODBUS_FC_READ_INPUT_REGISTERS:
614   - /* Read functions 1 value = 2 bytes */
615   - req_nb_value = (req[offset + 3] << 8) + req[offset + 4];
616   - rsp_nb_value = (rsp[offset + 1] / 2);
617   - break;
618   - case MODBUS_FC_WRITE_MULTIPLE_COILS:
619   - case MODBUS_FC_WRITE_MULTIPLE_REGISTERS:
620   - /* N Write functions */
621   - req_nb_value = (req[offset + 3] << 8) + req[offset + 4];
622   - rsp_nb_value = (rsp[offset + 3] << 8) | rsp[offset + 4];
623   - break;
624   - case MODBUS_FC_REPORT_SLAVE_ID:
625   - /* Report slave ID (bytes received) */
626   - req_nb_value = rsp_nb_value = rsp[offset + 1];
627   - break;
628   - default:
629   - /* 1 Write functions & others */
630   - req_nb_value = rsp_nb_value = 1;
631   - }
632   -
633   - if (req_nb_value == rsp_nb_value) {
634   - rc = rsp_nb_value;
635   - } else {
636   - if (ctx->debug) {
637   - fprintf(stderr,
638   - "Quantity not corresponding to the request (%d != %d)\n",
639   - rsp_nb_value, req_nb_value);
640   - }
641   -
642   - if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_PROTOCOL) {
643   - _sleep_response_timeout(ctx);
644   - modbus_flush(ctx);
645   - }
646   -
647   - errno = EMBBADDATA;
648   - rc = -1;
649   - }
650   - } else {
651   - if (ctx->debug) {
652   - fprintf(stderr,
653   - "Message length not corresponding to the computed length (%d != %d)\n",
654   - rsp_length, rsp_length_computed);
655   - }
656   - if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_PROTOCOL) {
657   - _sleep_response_timeout(ctx);
658   - modbus_flush(ctx);
659   - }
660   - errno = EMBBADDATA;
661   - rc = -1;
662   - }
663   -
664   - return rc;
665   -}
666   -
667   -static int response_io_status(uint8_t *tab_io_status,
668   - int address, int nb,
669   - uint8_t *rsp, int offset)
670   -{
671   - int shift = 0;
672   - /* Instead of byte (not allowed in Win32) */
673   - int one_byte = 0;
674   - int i;
675   -
676   - for (i = address; i < address + nb; i++) {
677   - one_byte |= tab_io_status[i] << shift;
678   - if (shift == 7) {
679   - /* Byte is full */
680   - rsp[offset++] = one_byte;
681   - one_byte = shift = 0;
682   - } else {
683   - shift++;
684   - }
685   - }
686   -
687   - if (shift != 0)
688   - rsp[offset++] = one_byte;
689   -
690   - return offset;
691   -}
692   -
693   -/* Build the exception response */
694   -static int response_exception(modbus_t *ctx, sft_t *sft,
695   - int exception_code, uint8_t *rsp,
696   - unsigned int to_flush,
697   - const char* template, ...)
698   -{
699   - int rsp_length;
700   -
701   - /* Print debug message */
702   - if (ctx->debug) {
703   - va_list ap;
704   -
705   - va_start(ap, template);
706   - vfprintf(stderr, template, ap);
707   - va_end(ap);
708   - }
709   -
710   - /* Flush if required */
711   - if (to_flush) {
712   - _sleep_response_timeout(ctx);
713   - modbus_flush(ctx);
714   - }
715   -
716   - /* Build exception response */
717   - sft->function = sft->function + 0x80;
718   - rsp_length = ctx->backend->build_response_basis(sft, rsp);
719   - rsp[rsp_length++] = exception_code;
720   -
721   - return rsp_length;
722   -}
723   -
724   -/* Send a response to the received request.
725   - Analyses the request and constructs a response.
726   -
727   - If an error occurs, this function construct the response
728   - accordingly.
729   -*/
730   -int modbus_reply(modbus_t *ctx, const uint8_t *req,
731   - int req_length, modbus_mapping_t *mb_mapping)
732   -{
733   - int offset;
734   - int slave;
735   - int function;
736   - uint16_t address;
737   - uint8_t rsp[MAX_MESSAGE_LENGTH];
738   - int rsp_length = 0;
739   - sft_t sft;
740   -
741   - if (ctx == NULL) {
742   - errno = EINVAL;
743   - return -1;
744   - }
745   -
746   - offset = ctx->backend->header_length;
747   - slave = req[offset - 1];
748   - function = req[offset];
749   - address = (req[offset + 1] << 8) + req[offset + 2];
750   -
751   - sft.slave = slave;
752   - sft.function = function;
753   - sft.t_id = ctx->backend->prepare_response_tid(req, &req_length);
754   -
755   - /* Data are flushed on illegal number of values errors. */
756   - switch (function) {
757   - case MODBUS_FC_READ_COILS:
758   - case MODBUS_FC_READ_DISCRETE_INPUTS: {
759   - unsigned int is_input = (function == MODBUS_FC_READ_DISCRETE_INPUTS);
760   - int start_bits = is_input ? mb_mapping->start_input_bits : mb_mapping->start_bits;
761   - int nb_bits = is_input ? mb_mapping->nb_input_bits : mb_mapping->nb_bits;
762   - uint8_t *tab_bits = is_input ? mb_mapping->tab_input_bits : mb_mapping->tab_bits;
763   - const char * const name = is_input ? "read_input_bits" : "read_bits";
764   - int nb = (req[offset + 3] << 8) + req[offset + 4];
765   - /* The mapping can be shifted to reduce memory consumption and it
766   - doesn't always start at address zero. */
767   - int mapping_address = address - start_bits;
768   -
769   - if (nb < 1 || MODBUS_MAX_READ_BITS < nb) {
770   - rsp_length = response_exception(
771   - ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE,
772   - "Illegal nb of values %d in %s (max %d)\n",
773   - nb, name, MODBUS_MAX_READ_BITS);
774   - } else if (mapping_address < 0 || (mapping_address + nb) > nb_bits) {
775   - rsp_length = response_exception(
776   - ctx, &sft,
777   - MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp, FALSE,
778   - "Illegal data address 0x%0X in %s\n",
779   - mapping_address < 0 ? address : address + nb, name);
780   - } else {
781   - rsp_length = ctx->backend->build_response_basis(&sft, rsp);
782   - rsp[rsp_length++] = (nb / 8) + ((nb % 8) ? 1 : 0);
783   - rsp_length = response_io_status(tab_bits, mapping_address, nb,
784   - rsp, rsp_length);
785   - }
786   - }
787   - break;
788   - case MODBUS_FC_READ_HOLDING_REGISTERS:
789   - case MODBUS_FC_READ_INPUT_REGISTERS: {
790   - unsigned int is_input = (function == MODBUS_FC_READ_INPUT_REGISTERS);
791   - int start_registers = is_input ? mb_mapping->start_input_registers : mb_mapping->start_registers;
792   - int nb_registers = is_input ? mb_mapping->nb_input_registers : mb_mapping->nb_registers;
793   - uint16_t *tab_registers = is_input ? mb_mapping->tab_input_registers : mb_mapping->tab_registers;
794   - const char * const name = is_input ? "read_input_registers" : "read_registers";
795   - int nb = (req[offset + 3] << 8) + req[offset + 4];
796   - /* The mapping can be shifted to reduce memory consumption and it
797   - doesn't always start at address zero. */
798   - int mapping_address = address - start_registers;
799   -
800   - if (nb < 1 || MODBUS_MAX_READ_REGISTERS < nb) {
801   - rsp_length = response_exception(
802   - ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE,
803   - "Illegal nb of values %d in %s (max %d)\n",
804   - nb, name, MODBUS_MAX_READ_REGISTERS);
805   - } else if (mapping_address < 0 || (mapping_address + nb) > nb_registers) {
806   - rsp_length = response_exception(
807   - ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp, FALSE,
808   - "Illegal data address 0x%0X in %s\n",
809   - mapping_address < 0 ? address : address + nb, name);
810   - } else {
811   - int i;
812   -
813   - rsp_length = ctx->backend->build_response_basis(&sft, rsp);
814   - rsp[rsp_length++] = nb << 1;
815   - for (i = mapping_address; i < mapping_address + nb; i++) {
816   - rsp[rsp_length++] = tab_registers[i] >> 8;
817   - rsp[rsp_length++] = tab_registers[i] & 0xFF;
818   - }
819   - }
820   - }
821   - break;
822   - case MODBUS_FC_WRITE_SINGLE_COIL: {
823   - int mapping_address = address - mb_mapping->start_bits;
824   -
825   - if (mapping_address < 0 || mapping_address >= mb_mapping->nb_bits) {
826   - rsp_length = response_exception(
827   - ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp, FALSE,
828   - "Illegal data address 0x%0X in write_bit\n",
829   - address);
830   - } else {
831   - int data = (req[offset + 3] << 8) + req[offset + 4];
832   -
833   - if (data == 0xFF00 || data == 0x0) {
834   - mb_mapping->tab_bits[mapping_address] = data ? ON : OFF;
835   - memcpy(rsp, req, req_length);
836   - rsp_length = req_length;
837   - } else {
838   - rsp_length = response_exception(
839   - ctx, &sft,
840   - MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, FALSE,
841   - "Illegal data value 0x%0X in write_bit request at address %0X\n",
842   - data, address);
843   - }
844   - }
845   - }
846   - break;
847   - case MODBUS_FC_WRITE_SINGLE_REGISTER: {
848   - int mapping_address = address - mb_mapping->start_registers;
849   -
850   - if (mapping_address < 0 || mapping_address >= mb_mapping->nb_registers) {
851   - rsp_length = response_exception(
852   - ctx, &sft,
853   - MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp, FALSE,
854   - "Illegal data address 0x%0X in write_register\n",
855   - address);
856   - } else {
857   - int data = (req[offset + 3] << 8) + req[offset + 4];
858   -
859   - mb_mapping->tab_registers[mapping_address] = data;
860   - memcpy(rsp, req, req_length);
861   - rsp_length = req_length;
862   - }
863   - }
864   - break;
865   - case MODBUS_FC_WRITE_MULTIPLE_COILS: {
866   - int nb = (req[offset + 3] << 8) + req[offset + 4];
867   - int mapping_address = address - mb_mapping->start_bits;
868   -
869   - if (nb < 1 || MODBUS_MAX_WRITE_BITS < nb) {
870   - /* May be the indication has been truncated on reading because of
871   - * invalid address (eg. nb is 0 but the request contains values to
872   - * write) so it's necessary to flush. */
873   - rsp_length = response_exception(
874   - ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE,
875   - "Illegal number of values %d in write_bits (max %d)\n",
876   - nb, MODBUS_MAX_WRITE_BITS);
877   - } else if (mapping_address < 0 ||
878   - (mapping_address + nb) > mb_mapping->nb_bits) {
879   - rsp_length = response_exception(
880   - ctx, &sft,
881   - MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp, FALSE,
882   - "Illegal data address 0x%0X in write_bits\n",
883   - mapping_address < 0 ? address : address + nb);
884   - } else {
885   - /* 6 = byte count */
886   - modbus_set_bits_from_bytes(mb_mapping->tab_bits, mapping_address, nb,
887   - &req[offset + 6]);
888   -
889   - rsp_length = ctx->backend->build_response_basis(&sft, rsp);
890   - /* 4 to copy the bit address (2) and the quantity of bits */
891   - memcpy(rsp + rsp_length, req + rsp_length, 4);
892   - rsp_length += 4;
893   - }
894   - }
895   - break;
896   - case MODBUS_FC_WRITE_MULTIPLE_REGISTERS: {
897   - int nb = (req[offset + 3] << 8) + req[offset + 4];
898   - int mapping_address = address - mb_mapping->start_registers;
899   -
900   - if (nb < 1 || MODBUS_MAX_WRITE_REGISTERS < nb) {
901   - rsp_length = response_exception(
902   - ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE,
903   - "Illegal number of values %d in write_registers (max %d)\n",
904   - nb, MODBUS_MAX_WRITE_REGISTERS);
905   - } else if (mapping_address < 0 ||
906   - (mapping_address + nb) > mb_mapping->nb_registers) {
907   - rsp_length = response_exception(
908   - ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp, FALSE,
909   - "Illegal data address 0x%0X in write_registers\n",
910   - mapping_address < 0 ? address : address + nb);
911   - } else {
912   - int i, j;
913   - for (i = mapping_address, j = 6; i < mapping_address + nb; i++, j += 2) {
914   - /* 6 and 7 = first value */
915   - mb_mapping->tab_registers[i] =
916   - (req[offset + j] << 8) + req[offset + j + 1];
917   - }
918   -
919   - rsp_length = ctx->backend->build_response_basis(&sft, rsp);
920   - /* 4 to copy the address (2) and the no. of registers */
921   - memcpy(rsp + rsp_length, req + rsp_length, 4);
922   - rsp_length += 4;
923   - }
924   - }
925   - break;
926   - case MODBUS_FC_REPORT_SLAVE_ID:
927   - {
928   - int str_len;
929   - int byte_count_pos;
930   -
931   - rsp_length = ctx->backend->build_response_basis(&sft, rsp);
932   - /* Skip byte count for now */
933   - byte_count_pos = rsp_length++;
934   - rsp[rsp_length++] = _REPORT_SLAVE_ID;
935   - /* Run indicator status to ON */
936   - rsp[rsp_length++] = 0xFF;
937   - str_len = 3 + strlen(MODBUS_VERSION_STRING);
938   - memcpy(rsp + rsp_length, "LMB" MODBUS_VERSION_STRING, str_len);
939   - rsp_length += str_len;
940   - rsp[byte_count_pos] = rsp_length - byte_count_pos - 1;
941   - }
942   - break;
943   - case MODBUS_FC_READ_EXCEPTION_STATUS:
944   - if (ctx->debug) {
945   - fprintf(stderr, "FIXME Not implemented\n");
946   - }
947   - errno = ENOPROTOOPT;
948   - return -1;
949   - break;
950   - case MODBUS_FC_MASK_WRITE_REGISTER: {
951   - int mapping_address = address - mb_mapping->start_registers;
952   -
953   - if (mapping_address < 0 || mapping_address >= mb_mapping->nb_registers) {
954   - rsp_length = response_exception(
955   - ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp, FALSE,
956   - "Illegal data address 0x%0X in write_register\n",
957   - address);
958   - } else {
959   - uint16_t data = mb_mapping->tab_registers[mapping_address];
960   - uint16_t and = (req[offset + 3] << 8) + req[offset + 4];
961   - uint16_t or = (req[offset + 5] << 8) + req[offset + 6];
962   -
963   - data = (data & and) | (or & (~and));
964   - mb_mapping->tab_registers[mapping_address] = data;
965   - memcpy(rsp, req, req_length);
966   - rsp_length = req_length;
967   - }
968   - }
969   - break;
970   - case MODBUS_FC_WRITE_AND_READ_REGISTERS: {
971   - int nb = (req[offset + 3] << 8) + req[offset + 4];
972   - uint16_t address_write = (req[offset + 5] << 8) + req[offset + 6];
973   - int nb_write = (req[offset + 7] << 8) + req[offset + 8];
974   - int nb_write_bytes = req[offset + 9];
975   - int mapping_address = address - mb_mapping->start_registers;
976   - int mapping_address_write = address_write - mb_mapping->start_registers;
977   -
978   - if (nb_write < 1 || MODBUS_MAX_WR_WRITE_REGISTERS < nb_write ||
979   - nb < 1 || MODBUS_MAX_WR_READ_REGISTERS < nb ||
980   - nb_write_bytes != nb_write * 2) {
981   - rsp_length = response_exception(
982   - ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, TRUE,
983   - "Illegal nb of values (W%d, R%d) in write_and_read_registers (max W%d, R%d)\n",
984   - nb_write, nb, MODBUS_MAX_WR_WRITE_REGISTERS, MODBUS_MAX_WR_READ_REGISTERS);
985   - } else if (mapping_address < 0 ||
986   - (mapping_address + nb) > mb_mapping->nb_registers ||
987   - mapping_address < 0 ||
988   - (mapping_address_write + nb_write) > mb_mapping->nb_registers) {
989   - rsp_length = response_exception(
990   - ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp, FALSE,
991   - "Illegal data read address 0x%0X or write address 0x%0X write_and_read_registers\n",
992   - mapping_address < 0 ? address : address + nb,
993   - mapping_address_write < 0 ? address_write : address_write + nb_write);
994   - } else {
995   - int i, j;
996   - rsp_length = ctx->backend->build_response_basis(&sft, rsp);
997   - rsp[rsp_length++] = nb << 1;
998   -
999   - /* Write first.
1000   - 10 and 11 are the offset of the first values to write */
1001   - for (i = mapping_address_write, j = 10;
1002   - i < mapping_address_write + nb_write; i++, j += 2) {
1003   - mb_mapping->tab_registers[i] =
1004   - (req[offset + j] << 8) + req[offset + j + 1];
1005   - }
1006   -
1007   - /* and read the data for the response */
1008   - for (i = mapping_address; i < mapping_address + nb; i++) {
1009   - rsp[rsp_length++] = mb_mapping->tab_registers[i] >> 8;
1010   - rsp[rsp_length++] = mb_mapping->tab_registers[i] & 0xFF;
1011   - }
1012   - }
1013   - }
1014   - break;
1015   -
1016   - default:
1017   - rsp_length = response_exception(
1018   - ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_FUNCTION, rsp, TRUE,
1019   - "Unknown Modbus function code: 0x%0X\n", function);
1020   - break;
1021   - }
1022   -
1023   - /* Suppress any responses when the request was a broadcast */
1024   - return (slave == MODBUS_BROADCAST_ADDRESS) ? 0 : send_msg(ctx, rsp, rsp_length);
1025   -}
1026   -
1027   -int modbus_reply_exception(modbus_t *ctx, const uint8_t *req,
1028   - unsigned int exception_code)
1029   -{
1030   - int offset;
1031   - int slave;
1032   - int function;
1033   - uint8_t rsp[MAX_MESSAGE_LENGTH];
1034   - int rsp_length;
1035   - int dummy_length = 99;
1036   - sft_t sft;
1037   -
1038   - if (ctx == NULL) {
1039   - errno = EINVAL;
1040   - return -1;
1041   - }
1042   -
1043   - offset = ctx->backend->header_length;
1044   - slave = req[offset - 1];
1045   - function = req[offset];
1046   -
1047   - sft.slave = slave;
1048   - sft.function = function + 0x80;;
1049   - sft.t_id = ctx->backend->prepare_response_tid(req, &dummy_length);
1050   - rsp_length = ctx->backend->build_response_basis(&sft, rsp);
1051   -
1052   - /* Positive exception code */
1053   - if (exception_code < MODBUS_EXCEPTION_MAX) {
1054   - rsp[rsp_length++] = exception_code;
1055   - return send_msg(ctx, rsp, rsp_length);
1056   - } else {
1057   - errno = EINVAL;
1058   - return -1;
1059   - }
1060   -}
1061   -
1062   -/* Reads IO status */
1063   -static int read_io_status(modbus_t *ctx, int function,
1064   - int addr, int nb, uint8_t *dest)
1065   -{
1066   - int rc;
1067   - int req_length;
1068   -
1069   - uint8_t req[_MIN_REQ_LENGTH];
1070   - uint8_t rsp[MAX_MESSAGE_LENGTH];
1071   -
1072   - req_length = ctx->backend->build_request_basis(ctx, function, addr, nb, req);
1073   -
1074   - rc = send_msg(ctx, req, req_length);
1075   - if (rc > 0) {
1076   - int i, temp, bit;
1077   - int pos = 0;
1078   - int offset;
1079   - int offset_end;
1080   -
1081   - rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);
1082   - if (rc == -1)
1083   - return -1;
1084   -
1085   - rc = check_confirmation(ctx, req, rsp, rc);
1086   - if (rc == -1)
1087   - return -1;
1088   -
1089   - offset = ctx->backend->header_length + 2;
1090   - offset_end = offset + rc;
1091   - for (i = offset; i < offset_end; i++) {
1092   - /* Shift reg hi_byte to temp */
1093   - temp = rsp[i];
1094   -
1095   - for (bit = 0x01; (bit & 0xff) && (pos < nb);) {
1096   - dest[pos++] = (temp & bit) ? TRUE : FALSE;
1097   - bit = bit << 1;
1098   - }
1099   -
1100   - }
1101   - }
1102   -
1103   - return rc;
1104   -}
1105   -
1106   -/* Reads the boolean status of bits and sets the array elements
1107   - in the destination to TRUE or FALSE (single bits). */
1108   -int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest)
1109   -{
1110   - int rc;
1111   -
1112   - if (ctx == NULL) {
1113   - errno = EINVAL;
1114   - return -1;
1115   - }
1116   -
1117   - if (nb > MODBUS_MAX_READ_BITS) {
1118   - if (ctx->debug) {
1119   - fprintf(stderr,
1120   - "ERROR Too many bits requested (%d > %d)\n",
1121   - nb, MODBUS_MAX_READ_BITS);
1122   - }
1123   - errno = EMBMDATA;
1124   - return -1;
1125   - }
1126   -
1127   - rc = read_io_status(ctx, MODBUS_FC_READ_COILS, addr, nb, dest);
1128   -
1129   - if (rc == -1)
1130   - return -1;
1131   - else
1132   - return nb;
1133   -}
1134   -
1135   -
1136   -/* Same as modbus_read_bits but reads the remote device input table */
1137   -int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest)
1138   -{
1139   - int rc;
1140   -
1141   - if (ctx == NULL) {
1142   - errno = EINVAL;
1143   - return -1;
1144   - }
1145   -
1146   - if (nb > MODBUS_MAX_READ_BITS) {
1147   - if (ctx->debug) {
1148   - fprintf(stderr,
1149   - "ERROR Too many discrete inputs requested (%d > %d)\n",
1150   - nb, MODBUS_MAX_READ_BITS);
1151   - }
1152   - errno = EMBMDATA;
1153   - return -1;
1154   - }
1155   -
1156   - rc = read_io_status(ctx, MODBUS_FC_READ_DISCRETE_INPUTS, addr, nb, dest);
1157   -
1158   - if (rc == -1)
1159   - return -1;
1160   - else
1161   - return nb;
1162   -}
1163   -
1164   -/* Reads the data from a remove device and put that data into an array */
1165   -static int read_registers(modbus_t *ctx, int function, int addr, int nb, uint16_t *dest)
1166   -{
1167   - int rc;
1168   - int req_length;
1169   - uint8_t req[_MIN_REQ_LENGTH];
1170   - uint8_t rsp[MAX_MESSAGE_LENGTH];
1171   -
1172   - if (nb > MODBUS_MAX_READ_REGISTERS)
1173   - {
1174   - if (ctx->debug)
1175   - {
1176   - fprintf(stderr,
1177   - "ERROR Too many registers requested (%d > %d)\n",
1178   - nb, MODBUS_MAX_READ_REGISTERS);
1179   - }
1180   - errno = EMBMDATA;
1181   - return -1;
1182   - }
1183   -
1184   - req_length = ctx->backend->build_request_basis(ctx, function, addr, nb, req);
1185   -
1186   - rc = send_msg(ctx, req, req_length);
1187   - if (rc > 0)
1188   - {
1189   - int offset;
1190   - int i;
1191   -
1192   - rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);
1193   - if (rc == -1)
1194   - return -1;
1195   -
1196   - rc = check_confirmation(ctx, req, rsp, rc);
1197   - if (rc == -1)
1198   - return -1;
1199   -
1200   - offset = ctx->backend->header_length;
1201   -
1202   - for (i = 0; i < rc; i++) {
1203   - /* shift reg hi_byte to temp OR with lo_byte */
1204   - dest[i] = (rsp[offset + 2 + (i << 1)] << 8) |
1205   - rsp[offset + 3 + (i << 1)];
1206   - }
1207   - }
1208   -
1209   - return rc;
1210   -}
1211   -
1212   -/* Reads the holding registers of remote device and put the data into an
1213   - array */
1214   -int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest)
1215   -{
1216   - int status;
1217   -
1218   - if (ctx == NULL) {
1219   - errno = EINVAL;
1220   - return -1;
1221   - }
1222   -
1223   - if (nb > MODBUS_MAX_READ_REGISTERS)
1224   - {
1225   - if (ctx->debug)
1226   - {
1227   - fprintf(stderr,
1228   - "ERROR Too many registers requested (%d > %d)\n",
1229   - nb, MODBUS_MAX_READ_REGISTERS);
1230   - }
1231   - errno = EMBMDATA;
1232   - return -1;
1233   - }
1234   -
1235   - status = read_registers(ctx, MODBUS_FC_READ_HOLDING_REGISTERS,
1236   - addr, nb, dest);
1237   - return status;
1238   -}
1239   -
1240   -/* Reads the input registers of remote device and put the data into an array */
1241   -int modbus_read_input_registers(modbus_t *ctx, int addr, int nb,
1242   - uint16_t *dest)
1243   -{
1244   - int status;
1245   -
1246   - if (ctx == NULL) {
1247   - errno = EINVAL;
1248   - return -1;
1249   - }
1250   -
1251   - if (nb > MODBUS_MAX_READ_REGISTERS) {
1252   - fprintf(stderr,
1253   - "ERROR Too many input registers requested (%d > %d)\n",
1254   - nb, MODBUS_MAX_READ_REGISTERS);
1255   - errno = EMBMDATA;
1256   - return -1;
1257   - }
1258   -
1259   - status = read_registers(ctx, MODBUS_FC_READ_INPUT_REGISTERS,
1260   - addr, nb, dest);
1261   -
1262   - return status;
1263   -}
1264   -
1265   -/* Write a value to the specified register of the remote device.
1266   - Used by write_bit and write_register */
1267   -static int write_single(modbus_t *ctx, int function, int addr, int value)
1268   -{
1269   - int rc;
1270   - int req_length;
1271   - uint8_t req[_MIN_REQ_LENGTH];
1272   -
1273   - if (ctx == NULL) {
1274   - errno = EINVAL;
1275   - return -1;
1276   - }
1277   -
1278   - req_length = ctx->backend->build_request_basis(ctx, function, addr, value, req);
1279   -
1280   - rc = send_msg(ctx, req, req_length);
1281   - if (rc > 0) {
1282   - /* Used by write_bit and write_register */
1283   - uint8_t rsp[MAX_MESSAGE_LENGTH];
1284   -
1285   - rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);
1286   - if (rc == -1)
1287   - return -1;
1288   -
1289   - rc = check_confirmation(ctx, req, rsp, rc);
1290   - }
1291   -
1292   - return rc;
1293   -}
1294   -
1295   -/* Turns ON or OFF a single bit of the remote device */
1296   -int modbus_write_bit(modbus_t *ctx, int addr, int status)
1297   -{
1298   - if (ctx == NULL) {
1299   - errno = EINVAL;
1300   - return -1;
1301   - }
1302   -
1303   - return write_single(ctx, MODBUS_FC_WRITE_SINGLE_COIL, addr,
1304   - status ? 0xFF00 : 0);
1305   -}
1306   -
1307   -/* Writes a value in one register of the remote device */
1308   -int modbus_write_register(modbus_t *ctx, int addr, int value)
1309   -{
1310   - if (ctx == NULL) {
1311   - errno = EINVAL;
1312   - return -1;
1313   - }
1314   -
1315   - return write_single(ctx, MODBUS_FC_WRITE_SINGLE_REGISTER, addr, value);
1316   -}
1317   -
1318   -/* Write the bits of the array in the remote device */
1319   -int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *src)
1320   -{
1321   - int rc;
1322   - int i;
1323   - int byte_count;
1324   - int req_length;
1325   - int bit_check = 0;
1326   - int pos = 0;
1327   - uint8_t req[MAX_MESSAGE_LENGTH];
1328   -
1329   - if (ctx == NULL) {
1330   - errno = EINVAL;
1331   - return -1;
1332   - }
1333   -
1334   - if (nb > MODBUS_MAX_WRITE_BITS) {
1335   - if (ctx->debug) {
1336   - fprintf(stderr, "ERROR Writing too many bits (%d > %d)\n",
1337   - nb, MODBUS_MAX_WRITE_BITS);
1338   - }
1339   - errno = EMBMDATA;
1340   - return -1;
1341   - }
1342   -
1343   - req_length = ctx->backend->build_request_basis(ctx,
1344   - MODBUS_FC_WRITE_MULTIPLE_COILS,
1345   - addr, nb, req);
1346   - byte_count = (nb / 8) + ((nb % 8) ? 1 : 0);
1347   - req[req_length++] = byte_count;
1348   -
1349   - for (i = 0; i < byte_count; i++) {
1350   - int bit;
1351   -
1352   - bit = 0x01;
1353   - req[req_length] = 0;
1354   -
1355   - while ((bit & 0xFF) && (bit_check++ < nb)) {
1356   - if (src[pos++])
1357   - req[req_length] |= bit;
1358   - else
1359   - req[req_length] &=~ bit;
1360   -
1361   - bit = bit << 1;
1362   - }
1363   - req_length++;
1364   - }
1365   -
1366   - rc = send_msg(ctx, req, req_length);
1367   - if (rc > 0) {
1368   - uint8_t rsp[MAX_MESSAGE_LENGTH];
1369   -
1370   - rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);
1371   - if (rc == -1)
1372   - return -1;
1373   -
1374   - rc = check_confirmation(ctx, req, rsp, rc);
1375   - }
1376   -
1377   -
1378   - return rc;
1379   -}
1380   -
1381   -/* Write the values from the array to the registers of the remote device */
1382   -int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *src)
1383   -{
1384   - int rc;
1385   - int i;
1386   - int req_length;
1387   - int byte_count;
1388   - uint8_t req[MAX_MESSAGE_LENGTH];
1389   -
1390   - if (ctx == NULL) {
1391   - errno = EINVAL;
1392   - return -1;
1393   - }
1394   -
1395   - if (nb > MODBUS_MAX_WRITE_REGISTERS) {
1396   - if (ctx->debug) {
1397   - fprintf(stderr,
1398   - "ERROR Trying to write to too many registers (%d > %d)\n",
1399   - nb, MODBUS_MAX_WRITE_REGISTERS);
1400   - }
1401   - errno = EMBMDATA;
1402   - return -1;
1403   - }
1404   -
1405   - req_length = ctx->backend->build_request_basis(ctx,
1406   - MODBUS_FC_WRITE_MULTIPLE_REGISTERS,
1407   - addr, nb, req);
1408   - byte_count = nb * 2;
1409   - req[req_length++] = byte_count;
1410   -
1411   - for (i = 0; i < nb; i++) {
1412   - req[req_length++] = src[i] >> 8;
1413   - req[req_length++] = src[i] & 0x00FF;
1414   - }
1415   -
1416   - rc = send_msg(ctx, req, req_length);
1417   - if (rc > 0) {
1418   - uint8_t rsp[MAX_MESSAGE_LENGTH];
1419   -
1420   - rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);
1421   - if (rc == -1)
1422   - return -1;
1423   -
1424   - rc = check_confirmation(ctx, req, rsp, rc);
1425   - }
1426   -
1427   - return rc;
1428   -}
1429   -
1430   -int modbus_mask_write_register(modbus_t *ctx, int addr, uint16_t and_mask, uint16_t or_mask)
1431   -{
1432   - int rc;
1433   - int req_length;
1434   - /* The request length can not exceed _MIN_REQ_LENGTH - 2 and 4 bytes to
1435   - * store the masks. The ugly substraction is there to remove the 'nb' value
1436   - * (2 bytes) which is not used. */
1437   - uint8_t req[_MIN_REQ_LENGTH + 2];
1438   -
1439   - req_length = ctx->backend->build_request_basis(ctx,
1440   - MODBUS_FC_MASK_WRITE_REGISTER,
1441   - addr, 0, req);
1442   -
1443   - /* HACKISH, count is not used */
1444   - req_length -= 2;
1445   -
1446   - req[req_length++] = and_mask >> 8;
1447   - req[req_length++] = and_mask & 0x00ff;
1448   - req[req_length++] = or_mask >> 8;
1449   - req[req_length++] = or_mask & 0x00ff;
1450   -
1451   - rc = send_msg(ctx, req, req_length);
1452   - if (rc > 0) {
1453   - /* Used by write_bit and write_register */
1454   - uint8_t rsp[MAX_MESSAGE_LENGTH];
1455   -
1456   - rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);
1457   - if (rc == -1)
1458   - return -1;
1459   -
1460   - rc = check_confirmation(ctx, req, rsp, rc);
1461   - }
1462   -
1463   - return rc;
1464   -}
1465   -
1466   -/* Write multiple registers from src array to remote device and read multiple
1467   - registers from remote device to dest array. */
1468   -int modbus_write_and_read_registers(modbus_t *ctx,
1469   - int write_addr, int write_nb,
1470   - const uint16_t *src,
1471   - int read_addr, int read_nb,
1472   - uint16_t *dest)
1473   -
1474   -{
1475   - int rc;
1476   - int req_length;
1477   - int i;
1478   - int byte_count;
1479   - uint8_t req[MAX_MESSAGE_LENGTH];
1480   - uint8_t rsp[MAX_MESSAGE_LENGTH];
1481   -
1482   - if (ctx == NULL) {
1483   - errno = EINVAL;
1484   - return -1;
1485   - }
1486   -
1487   - if (write_nb > MODBUS_MAX_WR_WRITE_REGISTERS) {
1488   - if (ctx->debug) {
1489   - fprintf(stderr,
1490   - "ERROR Too many registers to write (%d > %d)\n",
1491   - write_nb, MODBUS_MAX_WR_WRITE_REGISTERS);
1492   - }
1493   - errno = EMBMDATA;
1494   - return -1;
1495   - }
1496   -
1497   - if (read_nb > MODBUS_MAX_WR_READ_REGISTERS) {
1498   - if (ctx->debug) {
1499   - fprintf(stderr,
1500   - "ERROR Too many registers requested (%d > %d)\n",
1501   - read_nb, MODBUS_MAX_WR_READ_REGISTERS);
1502   - }
1503   - errno = EMBMDATA;
1504   - return -1;
1505   - }
1506   - req_length = ctx->backend->build_request_basis(ctx,
1507   - MODBUS_FC_WRITE_AND_READ_REGISTERS,
1508   - read_addr, read_nb, req);
1509   -
1510   - req[req_length++] = write_addr >> 8;
1511   - req[req_length++] = write_addr & 0x00ff;
1512   - req[req_length++] = write_nb >> 8;
1513   - req[req_length++] = write_nb & 0x00ff;
1514   - byte_count = write_nb * 2;
1515   - req[req_length++] = byte_count;
1516   -
1517   - for (i = 0; i < write_nb; i++) {
1518   - req[req_length++] = src[i] >> 8;
1519   - req[req_length++] = src[i] & 0x00FF;
1520   - }
1521   -
1522   - rc = send_msg(ctx, req, req_length);
1523   - if (rc > 0) {
1524   - int offset;
1525   -
1526   - rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);
1527   - if (rc == -1)
1528   - return -1;
1529   -
1530   - rc = check_confirmation(ctx, req, rsp, rc);
1531   - if (rc == -1)
1532   - return -1;
1533   -
1534   - offset = ctx->backend->header_length;
1535   - for (i = 0; i < rc; i++) {
1536   - /* shift reg hi_byte to temp OR with lo_byte */
1537   - dest[i] = (rsp[offset + 2 + (i << 1)] << 8) |
1538   - rsp[offset + 3 + (i << 1)];
1539   - }
1540   - }
1541   -
1542   - return rc;
1543   -}
1544   -
1545   -/* Send a request to get the slave ID of the device (only available in serial
1546   - communication). */
1547   -int modbus_report_slave_id(modbus_t *ctx, int max_dest, uint8_t *dest)
1548   -{
1549   - int rc;
1550   - int req_length;
1551   - uint8_t req[_MIN_REQ_LENGTH];
1552   -
1553   - if (ctx == NULL || max_dest <= 0) {
1554   - errno = EINVAL;
1555   - return -1;
1556   - }
1557   -
1558   - req_length = ctx->backend->build_request_basis(ctx, MODBUS_FC_REPORT_SLAVE_ID,
1559   - 0, 0, req);
1560   -
1561   - /* HACKISH, addr and count are not used */
1562   - req_length -= 4;
1563   -
1564   - rc = send_msg(ctx, req, req_length);
1565   - if (rc > 0) {
1566   - int i;
1567   - int offset;
1568   - uint8_t rsp[MAX_MESSAGE_LENGTH];
1569   -
1570   - rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);
1571   - if (rc == -1)
1572   - return -1;
1573   -
1574   - rc = check_confirmation(ctx, req, rsp, rc);
1575   - if (rc == -1)
1576   - return -1;
1577   -
1578   - offset = ctx->backend->header_length + 2;
1579   -
1580   - /* Byte count, slave id, run indicator status and
1581   - additional data. Truncate copy to max_dest. */
1582   - for (i=0; i < rc && i < max_dest; i++) {
1583   - dest[i] = rsp[offset + i];
1584   - }
1585   - }
1586   -
1587   - return rc;
1588   -}
1589   -
1590   -void _modbus_init_common(modbus_t *ctx)
1591   -{
1592   - /* Slave and socket are initialized to -1 */
1593   - ctx->slave = -1;
1594   - ctx->s = -1;
1595   -
1596   - ctx->debug = FALSE;
1597   - ctx->error_recovery = MODBUS_ERROR_RECOVERY_NONE;
1598   -
1599   - ctx->response_timeout.tv_sec = 0;
1600   - ctx->response_timeout.tv_usec = _RESPONSE_TIMEOUT;
1601   -
1602   - ctx->byte_timeout.tv_sec = 0;
1603   - ctx->byte_timeout.tv_usec = _BYTE_TIMEOUT;
1604   -}
1605   -
1606   -/* Define the slave number */
1607   -int modbus_set_slave(modbus_t *ctx, int slave)
1608   -{
1609   - if (ctx == NULL) {
1610   - errno = EINVAL;
1611   - return -1;
1612   - }
1613   -
1614   - return ctx->backend->set_slave(ctx, slave);
1615   -}
1616   -
1617   -int modbus_set_error_recovery(modbus_t *ctx,
1618   - modbus_error_recovery_mode error_recovery)
1619   -{
1620   - if (ctx == NULL) {
1621   - errno = EINVAL;
1622   - return -1;
1623   - }
1624   -
1625   - /* The type of modbus_error_recovery_mode is unsigned enum */
1626   - ctx->error_recovery = (uint8_t) error_recovery;
1627   - return 0;
1628   -}
1629   -
1630   -int modbus_set_socket(modbus_t *ctx, int s)
1631   -{
1632   - if (ctx == NULL) {
1633   - errno = EINVAL;
1634   - return -1;
1635   - }
1636   -
1637   - ctx->s = s;
1638   - return 0;
1639   -}
1640   -
1641   -int modbus_get_socket(modbus_t *ctx)
1642   -{
1643   - if (ctx == NULL) {
1644   - errno = EINVAL;
1645   - return -1;
1646   - }
1647   -
1648   - return ctx->s;
1649   -}
1650   -
1651   -/* Get the timeout interval used to wait for a response */
1652   -int modbus_get_response_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec)
1653   -{
1654   - if (ctx == NULL) {
1655   - errno = EINVAL;
1656   - return -1;
1657   - }
1658   -
1659   - *to_sec = ctx->response_timeout.tv_sec;
1660   - *to_usec = ctx->response_timeout.tv_usec;
1661   - return 0;
1662   -}
1663   -
1664   -int modbus_set_response_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec)
1665   -{
1666   - if (ctx == NULL ||
1667   - (to_sec == 0 && to_usec == 0) || to_usec > 999999) {
1668   - errno = EINVAL;
1669   - return -1;
1670   - }
1671   -
1672   - ctx->response_timeout.tv_sec = to_sec;
1673   - ctx->response_timeout.tv_usec = to_usec;
1674   - return 0;
1675   -}
1676   -
1677   -/* Get the timeout interval between two consecutive bytes of a message */
1678   -int modbus_get_byte_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec)
1679   -{
1680   - if (ctx == NULL) {
1681   - errno = EINVAL;
1682   - return -1;
1683   - }
1684   -
1685   - *to_sec = ctx->byte_timeout.tv_sec;
1686   - *to_usec = ctx->byte_timeout.tv_usec;
1687   - return 0;
1688   -}
1689   -
1690   -int modbus_set_byte_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec)
1691   -{
1692   - /* Byte timeout can be disabled when both values are zero */
1693   - if (ctx == NULL || to_usec > 999999) {
1694   - errno = EINVAL;
1695   - return -1;
1696   - }
1697   -
1698   - ctx->byte_timeout.tv_sec = to_sec;
1699   - ctx->byte_timeout.tv_usec = to_usec;
1700   - return 0;
1701   -}
1702   -
1703   -int modbus_get_header_length(modbus_t *ctx)
1704   -{
1705   - if (ctx == NULL) {
1706   - errno = EINVAL;
1707   - return -1;
1708   - }
1709   -
1710   - return ctx->backend->header_length;
1711   -}
1712   -
1713   -int modbus_connect(modbus_t *ctx)
1714   -{
1715   - if (ctx == NULL) {
1716   - errno = EINVAL;
1717   - return -1;
1718   - }
1719   -
1720   - return ctx->backend->connect(ctx);
1721   -}
1722   -
1723   -void modbus_close(modbus_t *ctx)
1724   -{
1725   - if (ctx == NULL)
1726   - return;
1727   -
1728   - ctx->backend->close(ctx);
1729   -}
1730   -
1731   -void modbus_free(modbus_t *ctx)
1732   -{
1733   - if (ctx == NULL)
1734   - return;
1735   -
1736   - ctx->backend->free(ctx);
1737   -}
1738   -
1739   -int modbus_set_debug(modbus_t *ctx, int flag)
1740   -{
1741   - if (ctx == NULL) {
1742   - errno = EINVAL;
1743   - return -1;
1744   - }
1745   -
1746   - ctx->debug = flag;
1747   - return 0;
1748   -}
1749   -
1750   -/* Allocates 4 arrays to store bits, input bits, registers and inputs
1751   - registers. The pointers are stored in modbus_mapping structure.
1752   -
1753   - The modbus_mapping_new_ranges() function shall return the new allocated
1754   - structure if successful. Otherwise it shall return NULL and set errno to
1755   - ENOMEM. */
1756   -modbus_mapping_t* modbus_mapping_new_start_address(
1757   - unsigned int start_bits, unsigned int nb_bits,
1758   - unsigned int start_input_bits, unsigned int nb_input_bits,
1759   - unsigned int start_registers, unsigned int nb_registers,
1760   - unsigned int start_input_registers, unsigned int nb_input_registers)
1761   -{
1762   - modbus_mapping_t *mb_mapping;
1763   -
1764   - mb_mapping = (modbus_mapping_t *)malloc(sizeof(modbus_mapping_t));
1765   - if (mb_mapping == NULL) {
1766   - return NULL;
1767   - }
1768   -
1769   - /* 0X */
1770   - mb_mapping->nb_bits = nb_bits;
1771   - mb_mapping->start_bits = start_bits;
1772   - if (nb_bits == 0) {
1773   - mb_mapping->tab_bits = NULL;
1774   - } else {
1775   - /* Negative number raises a POSIX error */
1776   - mb_mapping->tab_bits =
1777   - (uint8_t *) malloc(nb_bits * sizeof(uint8_t));
1778   - if (mb_mapping->tab_bits == NULL) {
1779   - free(mb_mapping);
1780   - return NULL;
1781   - }
1782   - memset(mb_mapping->tab_bits, 0, nb_bits * sizeof(uint8_t));
1783   - }
1784   -
1785   - /* 1X */
1786   - mb_mapping->nb_input_bits = nb_input_bits;
1787   - mb_mapping->start_input_bits = start_input_bits;
1788   - if (nb_input_bits == 0) {
1789   - mb_mapping->tab_input_bits = NULL;
1790   - } else {
1791   - mb_mapping->tab_input_bits =
1792   - (uint8_t *) malloc(nb_input_bits * sizeof(uint8_t));
1793   - if (mb_mapping->tab_input_bits == NULL) {
1794   - free(mb_mapping->tab_bits);
1795   - free(mb_mapping);
1796   - return NULL;
1797   - }
1798   - memset(mb_mapping->tab_input_bits, 0, nb_input_bits * sizeof(uint8_t));
1799   - }
1800   -
1801   - /* 4X */
1802   - mb_mapping->nb_registers = nb_registers;
1803   - mb_mapping->start_registers = start_registers;
1804   - if (nb_registers == 0) {
1805   - mb_mapping->tab_registers = NULL;
1806   - } else {
1807   - mb_mapping->tab_registers =
1808   - (uint16_t *) malloc(nb_registers * sizeof(uint16_t));
1809   - if (mb_mapping->tab_registers == NULL) {
1810   - free(mb_mapping->tab_input_bits);
1811   - free(mb_mapping->tab_bits);
1812   - free(mb_mapping);
1813   - return NULL;
1814   - }
1815   - memset(mb_mapping->tab_registers, 0, nb_registers * sizeof(uint16_t));
1816   - }
1817   -
1818   - /* 3X */
1819   - mb_mapping->nb_input_registers = nb_input_registers;
1820   - mb_mapping->start_input_registers = start_input_registers;
1821   - if (nb_input_registers == 0) {
1822   - mb_mapping->tab_input_registers = NULL;
1823   - } else {
1824   - mb_mapping->tab_input_registers =
1825   - (uint16_t *) malloc(nb_input_registers * sizeof(uint16_t));
1826   - if (mb_mapping->tab_input_registers == NULL) {
1827   - free(mb_mapping->tab_registers);
1828   - free(mb_mapping->tab_input_bits);
1829   - free(mb_mapping->tab_bits);
1830   - free(mb_mapping);
1831   - return NULL;
1832   - }
1833   - memset(mb_mapping->tab_input_registers, 0,
1834   - nb_input_registers * sizeof(uint16_t));
1835   - }
1836   -
1837   - return mb_mapping;
1838   -}
1839   -
1840   -modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits,
1841   - int nb_registers, int nb_input_registers)
1842   -{
1843   - return modbus_mapping_new_start_address(
1844   - 0, nb_bits, 0, nb_input_bits, 0, nb_registers, 0, nb_input_registers);
1845   -}
1846   -
1847   -/* Frees the 4 arrays */
1848   -void modbus_mapping_free(modbus_mapping_t *mb_mapping)
1849   -{
1850   - if (mb_mapping == NULL) {
1851   - return;
1852   - }
1853   -
1854   - free(mb_mapping->tab_input_registers);
1855   - free(mb_mapping->tab_registers);
1856   - free(mb_mapping->tab_input_bits);
1857   - free(mb_mapping->tab_bits);
1858   - free(mb_mapping);
1859   -}
1860   -
1861   -#ifndef HAVE_STRLCPY
1862   -/*
1863   - * Function strlcpy was originally developed by
1864   - * Todd C. Miller <Todd.Miller@courtesan.com> to simplify writing secure code.
1865   - * See ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/strlcpy.3
1866   - * for more information.
1867   - *
1868   - * Thank you Ulrich Drepper... not!
1869   - *
1870   - * Copy src to string dest of size dest_size. At most dest_size-1 characters
1871   - * will be copied. Always NUL terminates (unless dest_size == 0). Returns
1872   - * strlen(src); if retval >= dest_size, truncation occurred.
1873   - */
1874   -size_t strlcpy(char *dest, const char *src, size_t dest_size)
1875   -{
1876   - register char *d = dest;
1877   - register const char *s = src;
1878   - register size_t n = dest_size;
1879   -
1880   - /* Copy as many bytes as will fit */
1881   - if (n != 0 && --n != 0) {
1882   - do {
1883   - if ((*d++ = *s++) == 0)
1884   - break;
1885   - } while (--n != 0);
1886   - }
1887   -
1888   - /* Not enough room in dest, add NUL and traverse rest of src */
1889   - if (n == 0) {
1890   - if (dest_size != 0)
1891   - *d = '\0'; /* NUL-terminate dest */
1892   - while (*s++)
1893   - ;
1894   - }
1895   -
1896   - return (s - src - 1); /* count does not include NUL */
1897   -}
1898   -#endif
stack/modbus.h deleted
1   -
2   -#pragma once
3   -
4   -/* Add this for macros that defined unix flavor */
5   -#if (defined(__unix__) || defined(unix)) && !defined(USG)
6   -#include <sys/param.h>
7   -#endif
8   -
9   -#include <stdint.h>
10   -
11   -#define MODBUS_API
12   -
13   -#define MODBUS_VERSION_STRING "1.0.0"
14   -
15   -#ifdef __cplusplus
16   -#define MODBUS_BEGIN_DECLS extern "C" {
17   -#define MODBUS_END_DECLS }
18   -#else
19   -# define MODBUS_BEGIN_DECLS
20   -# define MODBUS_END_DECLS
21   -#endif
22   -
23   -MODBUS_BEGIN_DECLS
24   -
25   -#ifndef FALSE
26   -#define FALSE 0
27   -#endif
28   -
29   -#ifndef TRUE
30   -#define TRUE 1
31   -#endif
32   -
33   -#ifndef OFF
34   -#define OFF 0
35   -#endif
36   -
37   -#ifndef ON
38   -#define ON 1
39   -#endif
40   -
41   -/* Modbus function codes */
42   -#define MODBUS_FC_READ_COILS 0x01
43   -#define MODBUS_FC_READ_DISCRETE_INPUTS 0x02
44   -#define MODBUS_FC_READ_HOLDING_REGISTERS 0x03
45   -#define MODBUS_FC_READ_INPUT_REGISTERS 0x04
46   -#define MODBUS_FC_WRITE_SINGLE_COIL 0x05
47   -#define MODBUS_FC_WRITE_SINGLE_REGISTER 0x06
48   -#define MODBUS_FC_READ_EXCEPTION_STATUS 0x07
49   -#define MODBUS_FC_WRITE_MULTIPLE_COILS 0x0F
50   -#define MODBUS_FC_WRITE_MULTIPLE_REGISTERS 0x10
51   -#define MODBUS_FC_REPORT_SLAVE_ID 0x11
52   -#define MODBUS_FC_MASK_WRITE_REGISTER 0x16
53   -#define MODBUS_FC_WRITE_AND_READ_REGISTERS 0x17
54   -
55   -#define MODBUS_BROADCAST_ADDRESS 0
56   -
57   -/* Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 1 page 12)
58   - * Quantity of Coils to read (2 bytes): 1 to 2000 (0x7D0)
59   - * (chapter 6 section 11 page 29)
60   - * Quantity of Coils to write (2 bytes): 1 to 1968 (0x7B0)
61   - */
62   -#define MODBUS_MAX_READ_BITS 2000
63   -#define MODBUS_MAX_WRITE_BITS 1968
64   -
65   -/* Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 3 page 15)
66   - * Quantity of Registers to read (2 bytes): 1 to 125 (0x7D)
67   - * (chapter 6 section 12 page 31)
68   - * Quantity of Registers to write (2 bytes) 1 to 123 (0x7B)
69   - * (chapter 6 section 17 page 38)
70   - * Quantity of Registers to write in R/W registers (2 bytes) 1 to 121 (0x79)
71   - */
72   -#define MODBUS_MAX_READ_REGISTERS 125
73   -#define MODBUS_MAX_WRITE_REGISTERS 123
74   -#define MODBUS_MAX_WR_WRITE_REGISTERS 121
75   -#define MODBUS_MAX_WR_READ_REGISTERS 125
76   -
77   -/* The size of the MODBUS PDU is limited by the size constraint inherited from
78   - * the first MODBUS implementation on Serial Line network (max. RS485 ADU = 256
79   - * bytes). Therefore, MODBUS PDU for serial line communication = 256 - Server
80   - * address (1 byte) - CRC (2 bytes) = 253 bytes.
81   - */
82   -#define MODBUS_MAX_PDU_LENGTH 253
83   -
84   -/* Consequently:
85   - * - RTU MODBUS ADU = 253 bytes + Server address (1 byte) + CRC (2 bytes) = 256
86   - * bytes.
87   - * - TCP MODBUS ADU = 253 bytes + MBAP (7 bytes) = 260 bytes.
88   - * so the maximum of both backend in 260 bytes. This size can used to allocate
89   - * an array of bytes to store responses and it will be compatible with the two
90   - * backends.
91   - */
92   -#define MODBUS_MAX_ADU_LENGTH 260
93   -
94   -/* Random number to avoid errno conflicts */
95   -#define MODBUS_ENOBASE 112345678
96   -
97   -/* Protocol exceptions */
98   -enum {
99   - MODBUS_EXCEPTION_ILLEGAL_FUNCTION = 0x01,
100   - MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS,
101   - MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,
102   - MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE,
103   - MODBUS_EXCEPTION_ACKNOWLEDGE,
104   - MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY,
105   - MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE,
106   - MODBUS_EXCEPTION_MEMORY_PARITY,
107   - MODBUS_EXCEPTION_NOT_DEFINED,
108   - MODBUS_EXCEPTION_GATEWAY_PATH,
109   - MODBUS_EXCEPTION_GATEWAY_TARGET,
110   - MODBUS_EXCEPTION_MAX
111   -};
112   -
113   -#define EMBXILFUN (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_FUNCTION)
114   -#define EMBXILADD (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS)
115   -#define EMBXILVAL (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE)
116   -#define EMBXSFAIL (MODBUS_ENOBASE + MODBUS_EXCEPTION_SLAVE_OR_SERVER_FAILURE)
117   -#define EMBXACK (MODBUS_ENOBASE + MODBUS_EXCEPTION_ACKNOWLEDGE)
118   -#define EMBXSBUSY (MODBUS_ENOBASE + MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY)
119   -#define EMBXNACK (MODBUS_ENOBASE + MODBUS_EXCEPTION_NEGATIVE_ACKNOWLEDGE)
120   -#define EMBXMEMPAR (MODBUS_ENOBASE + MODBUS_EXCEPTION_MEMORY_PARITY)
121   -#define EMBXGPATH (MODBUS_ENOBASE + MODBUS_EXCEPTION_GATEWAY_PATH)
122   -#define EMBXGTAR (MODBUS_ENOBASE + MODBUS_EXCEPTION_GATEWAY_TARGET)
123   -
124   -/* Native libmodbus error codes */
125   -#define EMBBADCRC (EMBXGTAR + 1)
126   -#define EMBBADDATA (EMBXGTAR + 2)
127   -#define EMBBADEXC (EMBXGTAR + 3)
128   -#define EMBUNKEXC (EMBXGTAR + 4)
129   -#define EMBMDATA (EMBXGTAR + 5)
130   -#define EMBBADSLAVE (EMBXGTAR + 6)
131   -
132   -typedef struct _modbus modbus_t;
133   -
134   -typedef struct {
135   - int nb_bits;
136   - int start_bits;
137   - int nb_input_bits;
138   - int start_input_bits;
139   - int nb_input_registers;
140   - int start_input_registers;
141   - int nb_registers;
142   - int start_registers;
143   - uint8_t *tab_bits;
144   - uint8_t *tab_input_bits;
145   - uint16_t *tab_input_registers;
146   - uint16_t *tab_registers;
147   -} modbus_mapping_t;
148   -
149   -typedef enum
150   -{
151   - MODBUS_ERROR_RECOVERY_NONE = 0,
152   - MODBUS_ERROR_RECOVERY_LINK = (1<<1),
153   - MODBUS_ERROR_RECOVERY_PROTOCOL = (1<<2)
154   -} modbus_error_recovery_mode;
155   -
156   -MODBUS_API int modbus_set_slave(modbus_t* ctx, int slave);
157   -MODBUS_API int modbus_set_error_recovery(modbus_t *ctx, modbus_error_recovery_mode error_recovery);
158   -MODBUS_API int modbus_set_socket(modbus_t *ctx, int s);
159   -MODBUS_API int modbus_get_socket(modbus_t *ctx);
160   -
161   -MODBUS_API int modbus_get_response_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec);
162   -MODBUS_API int modbus_set_response_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec);
163   -
164   -MODBUS_API int modbus_get_byte_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec);
165   -MODBUS_API int modbus_set_byte_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec);
166   -
167   -MODBUS_API int modbus_get_header_length(modbus_t *ctx);
168   -
169   -MODBUS_API int modbus_connect(modbus_t *ctx);
170   -MODBUS_API void modbus_close(modbus_t *ctx);
171   -
172   -MODBUS_API void modbus_free(modbus_t *ctx);
173   -
174   -MODBUS_API int modbus_flush(modbus_t *ctx);
175   -MODBUS_API int modbus_set_debug(modbus_t *ctx, int flag);
176   -
177   -MODBUS_API const char *modbus_strerror(int errnum);
178   -
179   -MODBUS_API int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
180   -MODBUS_API int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
181   -MODBUS_API int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
182   -MODBUS_API int modbus_read_input_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
183   -MODBUS_API int modbus_write_bit(modbus_t *ctx, int coil_addr, int status);
184   -MODBUS_API int modbus_write_register(modbus_t *ctx, int reg_addr, int value);
185   -MODBUS_API int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *data);
186   -MODBUS_API int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *data);
187   -MODBUS_API int modbus_mask_write_register(modbus_t *ctx, int addr, uint16_t and_mask, uint16_t or_mask);
188   -MODBUS_API int modbus_write_and_read_registers(modbus_t *ctx, int write_addr, int write_nb,const uint16_t *src, int read_addr, int read_nb,uint16_t *dest);
189   -MODBUS_API int modbus_report_slave_id(modbus_t *ctx, int max_dest, uint8_t *dest);
190   -
191   -MODBUS_API modbus_mapping_t* modbus_mapping_new_start_address
192   -(
193   - unsigned int start_bits, unsigned int nb_bits,
194   - unsigned int start_input_bits, unsigned int nb_input_bits,
195   - unsigned int start_registers, unsigned int nb_registers,
196   - unsigned int start_input_registers, unsigned int nb_input_registers
197   -);
198   -
199   -MODBUS_API modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits, int nb_registers, int nb_input_registers);
200   -MODBUS_API void modbus_mapping_free(modbus_mapping_t *mb_mapping);
201   -
202   -MODBUS_API int modbus_send_raw_request(modbus_t *ctx, uint8_t *raw_req, int raw_req_length);
203   -
204   -MODBUS_API int modbus_receive(modbus_t *ctx, uint8_t *req);
205   -
206   -MODBUS_API int modbus_receive_confirmation(modbus_t *ctx, uint8_t *rsp);
207   -
208   -MODBUS_API int modbus_reply(modbus_t *ctx, const uint8_t *req, int req_length, modbus_mapping_t *mb_mapping);
209   -MODBUS_API int modbus_reply_exception(modbus_t *ctx, const uint8_t *req, unsigned int exception_code);
210   -
211   -/**
212   - * UTILS FUNCTIONS
213   - **/
214   -
215   -#define MODBUS_GET_HIGH_BYTE(data) (((data) >> 8) & 0xFF)
216   -#define MODBUS_GET_LOW_BYTE(data) ((data) & 0xFF)
217   -#define MODBUS_GET_INT64_FROM_INT16(tab_int16, index) \
218   - (((int64_t)tab_int16[(index) ] << 48) + \
219   - ((int64_t)tab_int16[(index) + 1] << 32) + \
220   - ((int64_t)tab_int16[(index) + 2] << 16) + \
221   - (int64_t)tab_int16[(index) + 3])
222   -#define MODBUS_GET_INT32_FROM_INT16(tab_int16, index) ((tab_int16[(index)] << 16) + tab_int16[(index) + 1])
223   -#define MODBUS_GET_INT16_FROM_INT8(tab_int8, index) ((tab_int8[(index)] << 8) + tab_int8[(index) + 1])
224   -#define MODBUS_SET_INT16_TO_INT8(tab_int8, index, value) \
225   - do { \
226   - tab_int8[(index)] = (value) >> 8; \
227   - tab_int8[(index) + 1] = (value) & 0xFF; \
228   - } while (0)
229   -#define MODBUS_SET_INT32_TO_INT16(tab_int16, index, value) \
230   - do { \
231   - tab_int16[(index) ] = (value) >> 16; \
232   - tab_int16[(index) + 1] = (value); \
233   - } while (0)
234   -#define MODBUS_SET_INT64_TO_INT16(tab_int16, index, value) \
235   - do { \
236   - tab_int16[(index) ] = (value) >> 48; \
237   - tab_int16[(index) + 1] = (value) >> 32; \
238   - tab_int16[(index) + 2] = (value) >> 16; \
239   - tab_int16[(index) + 3] = (value); \
240   - } while (0)
241   -
242   -MODBUS_API void modbus_set_bits_from_byte(uint8_t *dest, int idx, const uint8_t value);
243   -MODBUS_API void modbus_set_bits_from_bytes(uint8_t *dest, int idx, unsigned int nb_bits,
244   - const uint8_t *tab_byte);
245   -MODBUS_API uint8_t modbus_get_byte_from_bits(const uint8_t *src, int idx, unsigned int nb_bits);
246   -MODBUS_API float modbus_get_float(const uint16_t *src);
247   -MODBUS_API float modbus_get_float_abcd(const uint16_t *src);
248   -MODBUS_API float modbus_get_float_dcba(const uint16_t *src);
249   -MODBUS_API float modbus_get_float_badc(const uint16_t *src);
250   -MODBUS_API float modbus_get_float_cdab(const uint16_t *src);
251   -
252   -MODBUS_API void modbus_set_float(float f, uint16_t *dest);
253   -MODBUS_API void modbus_set_float_abcd(float f, uint16_t *dest);
254   -MODBUS_API void modbus_set_float_dcba(float f, uint16_t *dest);
255   -MODBUS_API void modbus_set_float_badc(float f, uint16_t *dest);
256   -MODBUS_API void modbus_set_float_cdab(float f, uint16_t *dest);
257   -
258   -#include "modbus-tcp.h"
259   -#include "modbus-rtu.h"
260   -
261   -MODBUS_END_DECLS
262   -