Commit 527f96d4ef8e258e1f2f90c6c9b8b214bc555770

Authored by Peter M. Groen
1 parent e1f771b9

Setting up working version

src/ConnectionConfig.h
@@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
7 #include <unordered_map> 7 #include <unordered_map>
8 8
9 /*! 9 /*!
10 - * \brief The ConnectionPort enum. 10 + * The ConnectionPort enum.
11 * CP_EXTERNAL - the first serial port 11 * CP_EXTERNAL - the first serial port
12 * CP_IOBUS - The second serial port through RJ45 connector 12 * CP_IOBUS - The second serial port through RJ45 connector
13 * CP_TCP - TCP Connections 13 * CP_TCP - TCP Connections
@@ -20,7 +20,7 @@ enum class ConnectionPort : unsigned int @@ -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 * Used in a serial port context 24 * Used in a serial port context
25 */ 25 */
26 enum class Parity : unsigned int 26 enum class Parity : unsigned int
@@ -31,7 +31,7 @@ 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 * Added for convenience, to distinguish between types. 35 * Added for convenience, to distinguish between types.
36 */ 36 */
37 enum class ConnectionType : unsigned int 37 enum class ConnectionType : unsigned int
@@ -42,7 +42,7 @@ 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 * It can be created by a configuration object and passed on to the ModBus stack. 46 * It can be created by a configuration object and passed on to the ModBus stack.
47 * By using this class, all the connectioninfo is within its context for convenience. 47 * By using this class, all the connectioninfo is within its context for convenience.
48 * 48 *
@@ -53,88 +53,88 @@ class ConnectionConfig @@ -53,88 +53,88 @@ class ConnectionConfig
53 { 53 {
54 public: 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 ConnectionConfig( ConnectionPort port, int baud = 115200, Parity parity = Parity::PAR_NONE, int dataBits = 8, int stopBits = 1, int timeOut = -1 ) 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 * \brief ConnectionConfig Constructor. Used to create a new TCP connection. 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 ConnectionConfig( ConnectionPort port, const std::string &ip, int portnum, int timeOut = -1 ) 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 // Getters and Setters. Implemented to avoid outside meddling on the member variables. 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 private: 110 private:
111 111
112 /// Serial connections 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 /// TCP connections 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 /// Generic 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 /// Translation tables for portnames and parity. 127 /// Translation tables for portnames and parity.
128 // ============================================================ 128 // ============================================================
129 // == Change accordingly to the devicenames on your platform == 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 { ConnectionPort::CP_EXTERNAL, "/dev/ttyUSB0" }, 133 { ConnectionPort::CP_EXTERNAL, "/dev/ttyUSB0" },
134 { ConnectionPort::CP_IOBUS, "/dev/ttyUSB1" } 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 { Parity::PAR_EVEN, 'E' }, 139 { Parity::PAR_EVEN, 'E' },
140 { Parity::PAR_ODD, 'O' }, 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,7 +15,7 @@ using modbusData = std::vector&lt;std::variant&lt;uint8_t, uint16_t&gt;&gt;;
15 class ConnectionConfig; 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 * the modbus stack. Implemented as a pure virtual, it cannot be instantiated. 19 * the modbus stack. Implemented as a pure virtual, it cannot be instantiated.
20 * This represents a unique connection to either a serial bus or a TCP connection. 20 * This represents a unique connection to either a serial bus or a TCP connection.
21 */ 21 */
@@ -30,55 +30,55 @@ public: @@ -30,55 +30,55 @@ public:
30 virtual bool ModbusConnect( const ConnectionConfig &conncfg ) = 0; 30 virtual bool ModbusConnect( const ConnectionConfig &conncfg ) = 0;
31 31
32 /*! 32 /*!
33 - * \brief ModbusDisconnect 33 + * ModbusDisconnect
34 * Disconnect from the serial bus or the TCP connection, freeing its resources 34 * Disconnect from the serial bus or the TCP connection, freeing its resources
35 */ 35 */
36 virtual bool ModbusDisconnect() = 0; 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 * Given by an enum, provided by the modbus-stack. 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 * Empty if no data was received. 46 * Empty if no data was received.
47 */ 47 */
48 virtual modbusData ModbusReadData( int slaveId, int functionCode, int startAddress, int noOfItems ) = 0; 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 * Empty if no data was received. 56 * Empty if no data was received.
57 */ 57 */
58 virtual modbusData ModbusReadHoldReg( int slaveId, int startAddress, int noOfItems ) = 0; 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 * given by an enum, provided by the modbus-stack. 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 * and they will be sent in sequence. 68 * and they will be sent in sequence.
69 */ 69 */
70 virtual void ModBusWriteData( int slaveId, int functionCode, int startAddress, int noOfItems, std::vector<int>values ) = 0; 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 virtual bool isConnected() const = 0; 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 virtual std::string ErrorString( int errnum ) const = 0; 83 virtual std::string ErrorString( int errnum ) const = 0;
84 }; 84 };
src/ModbusAdapter.cpp
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 #include <cstring> /// Added for memset functionality 5 #include <cstring> /// Added for memset functionality
6 6
7 ModbusAdapter::ModbusAdapter() 7 ModbusAdapter::ModbusAdapter()
8 - : m_modbus( nullptr ) 8 + : modbus( nullptr )
9 { 9 {
10 this->InitBuffers(); 10 this->InitBuffers();
11 } 11 }
@@ -15,52 +15,52 @@ ModbusAdapter::~ModbusAdapter() @@ -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 this->ModbusDisconnect(); // Will already set m_connected 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 case ConnectionType::CT_SERIAL: 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 break; 31 break;
32 32
33 case ConnectionType::CT_TCP: 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 break; 35 break;
36 36
37 default: 37 default:
38 // throw a sensible message or return an errorcode. 38 // throw a sensible message or return an errorcode.
39 break; 39 break;
40 } 40 }
41 - return m_connected; 41 + return connected;
42 } 42 }
43 43
44 bool ModbusAdapter::ModbusDisconnect() 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 // Clean up after ourselves. 53 // Clean up after ourselves.
54 - m_modbus = nullptr; 54 + modbus = nullptr;
55 } 55 }
56 56
57 - m_connected = false; 57 + connected = false;
58 return true; 58 return true;
59 } 59 }
60 60
61 modbusData ModbusAdapter::ModbusReadData( int slaveId, int functionCode, int startAddress, int noOfItems ) 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 // No context 65 // No context
66 return modbusData(); 66 return modbusData();
@@ -69,22 +69,22 @@ modbusData ModbusAdapter::ModbusReadData( int slaveId, int functionCode, int sta @@ -69,22 +69,22 @@ modbusData ModbusAdapter::ModbusReadData( int slaveId, int functionCode, int sta
69 int resultValue = -1; 69 int resultValue = -1;
70 bool is16Bit = false; 70 bool is16Bit = false;
71 71
72 - modbus_set_slave( m_modbus, slaveId ); 72 + modbus_set_slave( modbus, slaveId );
73 73
74 // Request data from modbus. 74 // Request data from modbus.
75 switch( functionCode ) 75 switch( functionCode )
76 { 76 {
77 case MODBUS_FC_READ_COILS: 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 break; 79 break;
80 case MODBUS_FC_READ_DISCRETE_INPUTS: 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 break; 82 break;
83 case MODBUS_FC_READ_HOLDING_REGISTERS: 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 break; 85 break;
86 case MODBUS_FC_READ_INPUT_REGISTERS: 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 break; 88 break;
89 89
90 default: 90 default:
@@ -104,7 +104,7 @@ modbusData ModbusAdapter::ModbusReadData( int slaveId, int functionCode, int sta @@ -104,7 +104,7 @@ modbusData ModbusAdapter::ModbusReadData( int slaveId, int functionCode, int sta
104 resultData.push_back( (is16Bit ? static_cast<uint16_t>(m_dest16[index]) : static_cast<uint16_t>(m_dest[index])) ); 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 this->ClearBuffers(); 108 this->ClearBuffers();
109 109
110 return resultData; 110 return resultData;
@@ -112,7 +112,7 @@ modbusData ModbusAdapter::ModbusReadData( int slaveId, int functionCode, int sta @@ -112,7 +112,7 @@ modbusData ModbusAdapter::ModbusReadData( int slaveId, int functionCode, int sta
112 112
113 modbusData ModbusAdapter::ModbusReadHoldReg( int slaveId, int startAddress, int noOfItems ) 113 modbusData ModbusAdapter::ModbusReadHoldReg( int slaveId, int startAddress, int noOfItems )
114 { 114 {
115 - if( m_modbus == nullptr ) 115 + if( modbus == nullptr )
116 { 116 {
117 return modbusData(); 117 return modbusData();
118 } 118 }
@@ -121,9 +121,9 @@ modbusData ModbusAdapter::ModbusReadHoldReg( int slaveId, int startAddress, int @@ -121,9 +121,9 @@ modbusData ModbusAdapter::ModbusReadHoldReg( int slaveId, int startAddress, int
121 121
122 // -- Start Critical Section --- ?? // 122 // -- Start Critical Section --- ?? //
123 123
124 - modbus_set_slave( m_modbus, slaveId ); 124 + modbus_set_slave( modbus, slaveId );
125 /// Request data from modbus 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 /// Read the databuffers 128 /// Read the databuffers
129 if( resultValue != noOfItems ) 129 if( resultValue != noOfItems )
@@ -137,7 +137,7 @@ modbusData ModbusAdapter::ModbusReadHoldReg( int slaveId, int startAddress, int @@ -137,7 +137,7 @@ modbusData ModbusAdapter::ModbusReadHoldReg( int slaveId, int startAddress, int
137 resultData.push_back( static_cast<uint16_t>(m_dest16[index]) ); 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 this->ClearBuffers(); 141 this->ClearBuffers();
142 142
143 // -- End Critical Section --- ?? // 143 // -- End Critical Section --- ?? //
@@ -147,7 +147,7 @@ modbusData ModbusAdapter::ModbusReadHoldReg( int slaveId, int startAddress, int @@ -147,7 +147,7 @@ modbusData ModbusAdapter::ModbusReadHoldReg( int slaveId, int startAddress, int
147 147
148 void ModbusAdapter::ModBusWriteData( int slaveId, int functionCode, int startAddress, int noOfItems, std::vector<int>values ) 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 // No modbus context. Sensible log-line and exit. 152 // No modbus context. Sensible log-line and exit.
153 return; 153 return;
@@ -171,31 +171,31 @@ void ModbusAdapter::ModBusWriteData( int slaveId, int functionCode, int startAdd @@ -171,31 +171,31 @@ void ModbusAdapter::ModBusWriteData( int slaveId, int functionCode, int startAdd
171 171
172 int resultValue = -1; 172 int resultValue = -1;
173 173
174 - modbus_set_slave( m_modbus, slaveId ); 174 + modbus_set_slave( modbus, slaveId );
175 175
176 // Request data from modbus 176 // Request data from modbus
177 switch( functionCode ) 177 switch( functionCode )
178 { 178 {
179 case MODBUS_FC_WRITE_SINGLE_COIL: 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 noOfItems = 1; 181 noOfItems = 1;
182 break; 182 break;
183 case MODBUS_FC_WRITE_SINGLE_REGISTER: 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 noOfItems = 1; 185 noOfItems = 1;
186 break; 186 break;
187 case MODBUS_FC_WRITE_MULTIPLE_COILS: 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 break; 190 break;
191 case MODBUS_FC_WRITE_MULTIPLE_REGISTERS: 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 break; 193 break;
194 } 194 }
195 195
196 delete[] data8; 196 delete[] data8;
197 delete[] data16; 197 delete[] data16;
198 - modbus_flush(m_modbus); // Flush data. 198 + modbus_flush(modbus); // Flush data.
199 199
200 if( resultValue != noOfItems ) 200 if( resultValue != noOfItems )
201 { 201 {
@@ -205,7 +205,7 @@ void ModbusAdapter::ModBusWriteData( int slaveId, int functionCode, int startAdd @@ -205,7 +205,7 @@ void ModbusAdapter::ModBusWriteData( int slaveId, int functionCode, int startAdd
205 205
206 bool ModbusAdapter::isConnected() const 206 bool ModbusAdapter::isConnected() const
207 { 207 {
208 - return m_connected; 208 + return connected;
209 } 209 }
210 210
211 std::string ModbusAdapter::ErrorString( int errnum ) const 211 std::string ModbusAdapter::ErrorString( int errnum ) const
@@ -235,37 +235,37 @@ std::string ModbusAdapter::ErrorString( int errnum ) const @@ -235,37 +235,37 @@ std::string ModbusAdapter::ErrorString( int errnum ) const
235 /* ============= PRIVATE METHODS ============= */ 235 /* ============= PRIVATE METHODS ============= */
236 bool ModbusAdapter::ModbusConnectRTU( const std::string &serialport, int baud, char parity, int dataBits, int stopBits, int RTS, int timeOut ) 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 #ifdef LIB_MODBUS_DEBUG_OUTPUT 240 #ifdef LIB_MODBUS_DEBUG_OUTPUT
241 // Do sensible logging through PRIVA_LOG 241 // Do sensible logging through PRIVA_LOG
242 m_modbus_set_debug( m_modbus, 1 ); 242 m_modbus_set_debug( m_modbus, 1 );
243 #endif 243 #endif
244 - if( m_modbus == nullptr ) 244 + if( modbus == nullptr )
245 { 245 {
246 // We can stop here. Nothing to be done as we don't have a valid context 246 // We can stop here. Nothing to be done as we don't have a valid context
247 // Log to PRIVA_LOG 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 // We could not connect to the selected serial port. 253 // We could not connect to the selected serial port.
254 // We can stop here. Nothing to be done as we don't have a valid connection 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 // Set recovery mode 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 // Set the response timeout 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 bool ModbusAdapter::ModbusConnectTCP( const std::string &ip, int port, int timeOut ) 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,37 +276,37 @@ bool ModbusAdapter::ModbusConnectTCP( const std::string &amp;ip, int port, int timeO
276 return false; 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 #ifdef LIB_MODBUS_DEBUG_OUTPUT 281 #ifdef LIB_MODBUS_DEBUG_OUTPUT
282 // Do sensible logging through PRIVA_LOG 282 // Do sensible logging through PRIVA_LOG
283 m_modbus_set_debug( m_modbus, 1 ); 283 m_modbus_set_debug( m_modbus, 1 );
284 #endif 284 #endif
285 285
286 - if( m_modbus == nullptr ) 286 + if( modbus == nullptr )
287 { 287 {
288 // We can stop here. Nothing to be done as we don't have a valid context 288 // We can stop here. Nothing to be done as we don't have a valid context
289 // Log to PRIVA_LOG 289 // Log to PRIVA_LOG
290 return false; 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 // We could not connect to the selected serial port. 294 // We could not connect to the selected serial port.
295 // We can stop here. Nothing to be done as we don't have a valid connection 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 // Set recovery mode 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 // Set the response timeout 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 void ModbusAdapter::InitBuffers() 312 void ModbusAdapter::InitBuffers()
src/ModbusAdapter.h
@@ -13,78 +13,79 @@ @@ -13,78 +13,79 @@
13 #include <variant> 13 #include <variant>
14 #include <vector> 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 class ModbusAdapter : public IModbusAdapter 21 class ModbusAdapter : public IModbusAdapter
21 { 22 {
22 public: 23 public:
23 /*! 24 /*!
24 - * \brief Default constructor 25 + * Default constructor
25 */ 26 */
26 explicit ModbusAdapter(); 27 explicit ModbusAdapter();
27 28
28 /*! 29 /*!
29 - * \brief Default destructor 30 + * Default destructor
30 */ 31 */
31 virtual ~ModbusAdapter(); 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 * Disconnect from the serial bus or the TCP connection, freeing its resources 41 * Disconnect from the serial bus or the TCP connection, freeing its resources
41 */ 42 */
42 bool ModbusDisconnect() override; 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 * Given by an enum, provided by the modbus-stack. 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 * Empty if no data was received. 53 * Empty if no data was received.
53 */ 54 */
54 modbusData ModbusReadData( int slaveId, int functionCode, int startAddress, int noOfItems ) override; 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 * Empty if no data was received. 63 * Empty if no data was received.
63 */ 64 */
64 modbusData ModbusReadHoldReg( int slaveId, int startAddress, int noOfItems ) override; 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 * given by an enum, provided by the modbus-stack. 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 * and they will be sent in sequence. 75 * and they will be sent in sequence.
75 */ 76 */
76 void ModBusWriteData( int slaveId, int functionCode, int startAddress, int noOfItems, std::vector<int>values ) override; 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 bool isConnected() const override; 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 std::string ErrorString( int errnum ) const override; 90 std::string ErrorString( int errnum ) const override;
90 91
@@ -96,11 +97,11 @@ private: // Methods @@ -96,11 +97,11 @@ private: // Methods
96 void ClearBuffers(); 97 void ClearBuffers();
97 98
98 private: // Members 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 // Return value Buffers ( Room for improvement ) 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 -