cadcf24a
Peter M. Groen
Setting up workin...
|
1
2
|
#include "ConnectionConfig.h"
|
cadcf24a
Peter M. Groen
Setting up workin...
|
3
|
#include "ModbusAdapter.h"
|
cadcf24a
Peter M. Groen
Setting up workin...
|
4
5
6
|
#include <cstring> /// Added for memset functionality
|
cadcf24a
Peter M. Groen
Setting up workin...
|
7
|
ModbusAdapter::ModbusAdapter()
|
527f96d4
Peter M. Groen
Setting up workin...
|
8
|
: modbus( nullptr )
|
cadcf24a
Peter M. Groen
Setting up workin...
|
9
|
{
|
5735b406
Peter M. Groen
Revert "Setting u...
|
10
|
this->InitBuffers();
|
cadcf24a
Peter M. Groen
Setting up workin...
|
11
12
13
14
15
16
17
|
}
ModbusAdapter::~ModbusAdapter()
{
}
|
527f96d4
Peter M. Groen
Setting up workin...
|
18
|
bool ModbusAdapter::ModbusConnect( const ConnectionConfig &config )
|
cadcf24a
Peter M. Groen
Setting up workin...
|
19
|
{
|
527f96d4
Peter M. Groen
Setting up workin...
|
20
|
if( connected )
|
cadcf24a
Peter M. Groen
Setting up workin...
|
21
|
{
|
b85a3e4a
Peter M. Groen
Setting up workin...
|
22
|
this->ModbusDisconnect(); // Will already set m_connected
|
cadcf24a
Peter M. Groen
Setting up workin...
|
23
24
|
}
|
527f96d4
Peter M. Groen
Setting up workin...
|
25
|
connectionType = config.getType();
|
cadcf24a
Peter M. Groen
Setting up workin...
|
26
|
|
527f96d4
Peter M. Groen
Setting up workin...
|
27
|
switch( connectionType )
|
cadcf24a
Peter M. Groen
Setting up workin...
|
28
29
|
{
case ConnectionType::CT_SERIAL:
|
527f96d4
Peter M. Groen
Setting up workin...
|
30
|
connected = this->ModbusConnectRTU( config.getPort(), config.getBaudRate(), config.getParity(), config.getDataBits(), config.getStopBits(), config.getTimeOut(), MODBUS_RTU_RTS_NONE );
|
cadcf24a
Peter M. Groen
Setting up workin...
|
31
32
33
|
break;
case ConnectionType::CT_TCP:
|
527f96d4
Peter M. Groen
Setting up workin...
|
34
|
connected = this->ModbusConnectTCP( config.getIpAddress(), config.getTcpPort(), 10 );
|
cadcf24a
Peter M. Groen
Setting up workin...
|
35
36
37
38
39
40
|
break;
default:
// throw a sensible message or return an errorcode.
break;
}
|
527f96d4
Peter M. Groen
Setting up workin...
|
41
|
return connected;
|
cadcf24a
Peter M. Groen
Setting up workin...
|
42
43
|
}
|
b85a3e4a
Peter M. Groen
Setting up workin...
|
44
|
bool ModbusAdapter::ModbusDisconnect()
|
cadcf24a
Peter M. Groen
Setting up workin...
|
45
|
{
|
527f96d4
Peter M. Groen
Setting up workin...
|
46
|
if( modbus != nullptr )
|
cadcf24a
Peter M. Groen
Setting up workin...
|
47
|
{
|
527f96d4
Peter M. Groen
Setting up workin...
|
48
|
if( connected )
|
cadcf24a
Peter M. Groen
Setting up workin...
|
49
|
{
|
527f96d4
Peter M. Groen
Setting up workin...
|
50
51
|
modbus_close( modbus );
modbus_free( modbus );
|
cadcf24a
Peter M. Groen
Setting up workin...
|
52
53
|
}
// Clean up after ourselves.
|
527f96d4
Peter M. Groen
Setting up workin...
|
54
|
modbus = nullptr;
|
cadcf24a
Peter M. Groen
Setting up workin...
|
55
|
}
|
b85a3e4a
Peter M. Groen
Setting up workin...
|
56
|
|
527f96d4
Peter M. Groen
Setting up workin...
|
57
|
connected = false;
|
b85a3e4a
Peter M. Groen
Setting up workin...
|
58
|
return true;
|
cadcf24a
Peter M. Groen
Setting up workin...
|
59
60
61
62
|
}
modbusData ModbusAdapter::ModbusReadData( int slaveId, int functionCode, int startAddress, int noOfItems )
{
|
527f96d4
Peter M. Groen
Setting up workin...
|
63
|
if( modbus == nullptr )
|
cadcf24a
Peter M. Groen
Setting up workin...
|
64
65
66
67
68
|
{
// No context
return modbusData();
}
|
cadcf24a
Peter M. Groen
Setting up workin...
|
69
70
71
|
int resultValue = -1;
bool is16Bit = false;
|
527f96d4
Peter M. Groen
Setting up workin...
|
72
|
modbus_set_slave( modbus, slaveId );
|
cadcf24a
Peter M. Groen
Setting up workin...
|
73
74
75
76
77
|
// Request data from modbus.
switch( functionCode )
{
case MODBUS_FC_READ_COILS:
|
527f96d4
Peter M. Groen
Setting up workin...
|
78
|
resultValue = modbus_read_bits( modbus, startAddress, noOfItems, m_dest );
|
cadcf24a
Peter M. Groen
Setting up workin...
|
79
80
|
break;
case MODBUS_FC_READ_DISCRETE_INPUTS:
|
527f96d4
Peter M. Groen
Setting up workin...
|
81
|
resultValue = modbus_read_input_bits( modbus, startAddress, noOfItems, m_dest );
|
cadcf24a
Peter M. Groen
Setting up workin...
|
82
83
|
break;
case MODBUS_FC_READ_HOLDING_REGISTERS:
|
527f96d4
Peter M. Groen
Setting up workin...
|
84
|
resultValue = modbus_read_registers( modbus, startAddress, noOfItems, m_dest16 );
|
cadcf24a
Peter M. Groen
Setting up workin...
|
85
86
|
break;
case MODBUS_FC_READ_INPUT_REGISTERS:
|
527f96d4
Peter M. Groen
Setting up workin...
|
87
|
resultValue = modbus_read_input_registers( modbus, startAddress, noOfItems, m_dest16 );
|
cadcf24a
Peter M. Groen
Setting up workin...
|
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
break;
default:
break;
}
// Read the databuffers
if( resultValue != noOfItems )
{
return modbusData();
}
modbusData resultData;
for( int index = 0; index < noOfItems; ++index )
{
resultData.push_back( (is16Bit ? static_cast<uint16_t>(m_dest16[index]) : static_cast<uint16_t>(m_dest[index])) );
}
|
527f96d4
Peter M. Groen
Setting up workin...
|
107
|
modbus_flush( modbus ); // flush data
|
cadcf24a
Peter M. Groen
Setting up workin...
|
108
109
110
111
112
113
114
|
this->ClearBuffers();
return resultData;
}
modbusData ModbusAdapter::ModbusReadHoldReg( int slaveId, int startAddress, int noOfItems )
{
|
527f96d4
Peter M. Groen
Setting up workin...
|
115
|
if( modbus == nullptr )
|
cadcf24a
Peter M. Groen
Setting up workin...
|
116
117
118
119
120
121
122
123
|
{
return modbusData();
}
int resultValue = -1; /// Return value from read functions
// -- Start Critical Section --- ?? //
|
527f96d4
Peter M. Groen
Setting up workin...
|
124
|
modbus_set_slave( modbus, slaveId );
|
cadcf24a
Peter M. Groen
Setting up workin...
|
125
|
/// Request data from modbus
|
527f96d4
Peter M. Groen
Setting up workin...
|
126
|
resultValue = modbus_read_registers( modbus, startAddress, noOfItems, m_dest16 );
|
cadcf24a
Peter M. Groen
Setting up workin...
|
127
128
129
130
131
132
133
134
135
136
137
138
139
|
/// Read the databuffers
if( resultValue != noOfItems )
{
return modbusData();
}
modbusData resultData;
for( int index = 0; index < noOfItems; ++index )
{
resultData.push_back( static_cast<uint16_t>(m_dest16[index]) );
}
|
527f96d4
Peter M. Groen
Setting up workin...
|
140
|
modbus_flush( modbus );
|
5735b406
Peter M. Groen
Revert "Setting u...
|
141
|
this->ClearBuffers();
|
cadcf24a
Peter M. Groen
Setting up workin...
|
142
143
144
145
146
147
148
149
|
// -- End Critical Section --- ?? //
return resultData;
}
void ModbusAdapter::ModBusWriteData( int slaveId, int functionCode, int startAddress, int noOfItems, std::vector<int>values )
{
|
527f96d4
Peter M. Groen
Setting up workin...
|
150
|
if( modbus == nullptr )
|
cadcf24a
Peter M. Groen
Setting up workin...
|
151
|
{
|
b85a3e4a
Peter M. Groen
Setting up workin...
|
152
|
// No modbus context. Sensible log-line and exit.
|
cadcf24a
Peter M. Groen
Setting up workin...
|
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
|
return;
}
// ------------------------------------------------
// Create 8 bits databuffer
auto * data8 = new uint8_t[noOfItems];
for( int index = 0; index < noOfItems; ++index )
{
data8[index] = values[index];
}
// Create same buffer for 16 bits data
auto * data16 = new uint8_t[noOfItems];
for( int index = 0; index < noOfItems; ++index )
{
data16[index] = values[index];
}
// ------------------------------------------------
int resultValue = -1;
|
527f96d4
Peter M. Groen
Setting up workin...
|
174
|
modbus_set_slave( modbus, slaveId );
|
cadcf24a
Peter M. Groen
Setting up workin...
|
175
176
177
178
179
|
// Request data from modbus
switch( functionCode )
{
case MODBUS_FC_WRITE_SINGLE_COIL:
|
527f96d4
Peter M. Groen
Setting up workin...
|
180
|
resultValue = modbus_write_bit( modbus, startAddress, values[0] );
|
cadcf24a
Peter M. Groen
Setting up workin...
|
181
182
183
|
noOfItems = 1;
break;
case MODBUS_FC_WRITE_SINGLE_REGISTER:
|
527f96d4
Peter M. Groen
Setting up workin...
|
184
|
resultValue = modbus_write_register( modbus, startAddress, values[0] );
|
cadcf24a
Peter M. Groen
Setting up workin...
|
185
186
187
188
|
noOfItems = 1;
break;
case MODBUS_FC_WRITE_MULTIPLE_COILS:
|
527f96d4
Peter M. Groen
Setting up workin...
|
189
|
resultValue = modbus_write_bits( modbus, startAddress, noOfItems, data8 );
|
cadcf24a
Peter M. Groen
Setting up workin...
|
190
191
|
break;
case MODBUS_FC_WRITE_MULTIPLE_REGISTERS:
|
527f96d4
Peter M. Groen
Setting up workin...
|
192
|
resultValue = modbus_write_bits( modbus, startAddress, noOfItems, data16 );
|
cadcf24a
Peter M. Groen
Setting up workin...
|
193
194
195
|
break;
}
|
5735b406
Peter M. Groen
Revert "Setting u...
|
196
197
|
delete[] data8;
delete[] data16;
|
527f96d4
Peter M. Groen
Setting up workin...
|
198
|
modbus_flush(modbus); // Flush data.
|
cadcf24a
Peter M. Groen
Setting up workin...
|
199
200
201
202
203
204
205
206
207
|
if( resultValue != noOfItems )
{
// Create a log line that writing the register failed. Maybe increment ErrorCounter(s)
}
}
bool ModbusAdapter::isConnected() const
{
|
527f96d4
Peter M. Groen
Setting up workin...
|
208
|
return connected;
|
cadcf24a
Peter M. Groen
Setting up workin...
|
209
210
|
}
|
46785270
Peter M. Groen
Setting up workin...
|
211
|
std::string ModbusAdapter::ErrorString( int errnum ) const
|
cadcf24a
Peter M. Groen
Setting up workin...
|
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
|
{
switch(errnum)
{
case EINVAL:
return "Protocol context is NULL";
break;
case ETIMEDOUT:
return "Timeout";
break;
case ECONNRESET:
return "Connection reset";
break;
case ECONNREFUSED:
return "Connection refused";
break;
case EPIPE:
return "Socket error";
break;
default:
return modbus_strerror(errno);
}
}
/* ============= PRIVATE METHODS ============= */
|
5735b406
Peter M. Groen
Revert "Setting u...
|
236
|
bool ModbusAdapter::ModbusConnectRTU( const std::string &serialport, int baud, char parity, int dataBits, int stopBits, int RTS, int timeOut )
|
cadcf24a
Peter M. Groen
Setting up workin...
|
237
|
{
|
527f96d4
Peter M. Groen
Setting up workin...
|
238
|
modbus = modbus_new_rtu( serialport.c_str(), baud, parity, dataBits, stopBits, RTS );
|
cadcf24a
Peter M. Groen
Setting up workin...
|
239
240
241
242
243
|
#ifdef LIB_MODBUS_DEBUG_OUTPUT
// Do sensible logging through PRIVA_LOG
m_modbus_set_debug( m_modbus, 1 );
#endif
|
527f96d4
Peter M. Groen
Setting up workin...
|
244
|
if( modbus == nullptr )
|
cadcf24a
Peter M. Groen
Setting up workin...
|
245
246
247
|
{
// We can stop here. Nothing to be done as we don't have a valid context
// Log to PRIVA_LOG
|
527f96d4
Peter M. Groen
Setting up workin...
|
248
249
|
connected = false;
return connected;
|
cadcf24a
Peter M. Groen
Setting up workin...
|
250
|
}
|
527f96d4
Peter M. Groen
Setting up workin...
|
251
|
else if( modbus && modbus_connect( modbus ) == -1 )
|
cadcf24a
Peter M. Groen
Setting up workin...
|
252
253
254
|
{
// We could not connect to the selected serial port.
// We can stop here. Nothing to be done as we don't have a valid connection
|
527f96d4
Peter M. Groen
Setting up workin...
|
255
256
257
|
modbus_free( modbus );
connected = false;
return connected;
|
cadcf24a
Peter M. Groen
Setting up workin...
|
258
259
|
}
|
527f96d4
Peter M. Groen
Setting up workin...
|
260
|
connected = true;
|
b85a3e4a
Peter M. Groen
Setting up workin...
|
261
|
|
cadcf24a
Peter M. Groen
Setting up workin...
|
262
|
// Set recovery mode
|
527f96d4
Peter M. Groen
Setting up workin...
|
263
|
modbus_set_error_recovery( modbus, MODBUS_ERROR_RECOVERY_PROTOCOL );
|
cadcf24a
Peter M. Groen
Setting up workin...
|
264
265
|
// Set the response timeout
|
527f96d4
Peter M. Groen
Setting up workin...
|
266
|
modbus_set_response_timeout( modbus, timeOut, 0 );
|
cadcf24a
Peter M. Groen
Setting up workin...
|
267
|
|
527f96d4
Peter M. Groen
Setting up workin...
|
268
|
return connected;
|
cadcf24a
Peter M. Groen
Setting up workin...
|
269
270
|
}
|
b85a3e4a
Peter M. Groen
Setting up workin...
|
271
|
bool ModbusAdapter::ModbusConnectTCP( const std::string &ip, int port, int timeOut )
|
cadcf24a
Peter M. Groen
Setting up workin...
|
272
273
274
275
|
{
if( ip.empty() )
{
// Nothing to be done. Set an Logline to PRIVA_LOG and exit.
|
b85a3e4a
Peter M. Groen
Setting up workin...
|
276
|
return false;
|
cadcf24a
Peter M. Groen
Setting up workin...
|
277
278
|
}
|
527f96d4
Peter M. Groen
Setting up workin...
|
279
|
modbus = modbus_new_tcp( ip.c_str(), port );
|
cadcf24a
Peter M. Groen
Setting up workin...
|
280
281
282
283
284
285
|
#ifdef LIB_MODBUS_DEBUG_OUTPUT
// Do sensible logging through PRIVA_LOG
m_modbus_set_debug( m_modbus, 1 );
#endif
|
527f96d4
Peter M. Groen
Setting up workin...
|
286
|
if( modbus == nullptr )
|
cadcf24a
Peter M. Groen
Setting up workin...
|
287
288
289
|
{
// We can stop here. Nothing to be done as we don't have a valid context
// Log to PRIVA_LOG
|
b85a3e4a
Peter M. Groen
Setting up workin...
|
290
|
return false;
|
cadcf24a
Peter M. Groen
Setting up workin...
|
291
|
}
|
527f96d4
Peter M. Groen
Setting up workin...
|
292
|
else if( modbus && modbus_connect( modbus ) == -1 )
|
cadcf24a
Peter M. Groen
Setting up workin...
|
293
294
295
|
{
// We could not connect to the selected serial port.
// We can stop here. Nothing to be done as we don't have a valid connection
|
527f96d4
Peter M. Groen
Setting up workin...
|
296
297
298
|
modbus_free( modbus );
connected = false;
return connected;
|
cadcf24a
Peter M. Groen
Setting up workin...
|
299
300
|
}
|
527f96d4
Peter M. Groen
Setting up workin...
|
301
|
connected = true;
|
b85a3e4a
Peter M. Groen
Setting up workin...
|
302
|
|
cadcf24a
Peter M. Groen
Setting up workin...
|
303
|
// Set recovery mode
|
527f96d4
Peter M. Groen
Setting up workin...
|
304
|
modbus_set_error_recovery( modbus, MODBUS_ERROR_RECOVERY_PROTOCOL );
|
cadcf24a
Peter M. Groen
Setting up workin...
|
305
306
|
// Set the response timeout
|
527f96d4
Peter M. Groen
Setting up workin...
|
307
|
modbus_set_response_timeout( modbus, timeOut, 0 );
|
cadcf24a
Peter M. Groen
Setting up workin...
|
308
|
|
527f96d4
Peter M. Groen
Setting up workin...
|
309
|
return connected;
|
cadcf24a
Peter M. Groen
Setting up workin...
|
310
|
}
|
5735b406
Peter M. Groen
Revert "Setting u...
|
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
|
void ModbusAdapter::InitBuffers()
{
// Setup memory for Data.
m_dest = (uint8_t *)malloc(2000 + sizeof(uint8_t));
m_dest16 = (uint16_t *)malloc(125 * sizeof(uint16_t));
this->ClearBuffers();
}
void ModbusAdapter::ClearBuffers()
{
memset(m_dest, 0, 2000 * sizeof(uint8_t));
memset(m_dest16, 0, 125 * sizeof(uint16_t));
}
|