Line data Source code
1 :
2 :
3 : #include "modbus.hpp"
4 :
5 0 : modbus::modbus( const std::string &host, uint16_t port ) : PORT{ port }, HOST{ host }
6 : {
7 0 : }
8 :
9 0 : modbus::modbus( const std::string &host ) : HOST{ host }
10 : {
11 0 : }
12 :
13 0 : modbus::~modbus( void )
14 : {
15 0 : }
16 :
17 0 : void modbus::modbus_set_slave_id( int id )
18 : {
19 0 : _slaveid = id;
20 0 : }
21 :
22 0 : bool modbus::modbus_connect()
23 : {
24 0 : if( HOST == "" || PORT == 0 )
25 : {
26 : // std::cout << "Missing Host and Port" << std::endl;
27 0 : return false;
28 : }
29 : else
30 : {
31 : // std::cout << "Found Proper Host "<< HOST << " and Port " <<PORT <<std::endl;
32 : }
33 :
34 0 : _socket = socket( AF_INET, SOCK_STREAM, 0 );
35 0 : if( _socket == -1 )
36 : {
37 : // std::cout <<"Error Opening Socket" <<std::endl;
38 0 : return false;
39 : }
40 : else
41 : {
42 : // std::cout <<"Socket Opened Successfully" << std::endl;
43 : }
44 :
45 0 : _server.sin_family = AF_INET;
46 0 : _server.sin_addr.s_addr = inet_addr( HOST.c_str() );
47 0 : _server.sin_port = htons( PORT );
48 :
49 0 : if( connect( _socket, (struct sockaddr *)&_server, sizeof( _server ) ) < 0 )
50 : {
51 : // std::cout<< "Connection Error" << std::endl;
52 0 : return false;
53 : }
54 :
55 : // std::cout<< "Connected" <<std::endl;
56 0 : _connected = true;
57 0 : return true;
58 : }
59 :
60 0 : void modbus::modbus_close()
61 : {
62 0 : close( _socket );
63 : // std::cout <<"Socket Closed" <<std::endl;
64 0 : }
65 :
66 0 : bool modbus::modbus_set_timeouts( int seconds, int microseconds )
67 : {
68 0 : if( !_connected || _socket < 0 )
69 : {
70 0 : return false;
71 : }
72 :
73 : struct timeval timeout;
74 0 : timeout.tv_sec = seconds;
75 0 : timeout.tv_usec = microseconds;
76 :
77 0 : if( setsockopt( _socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof( timeout ) ) != 0 )
78 : {
79 0 : return false;
80 : }
81 :
82 0 : if( setsockopt( _socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof( timeout ) ) != 0 )
83 : {
84 0 : return false;
85 : }
86 :
87 0 : return true;
88 : }
89 :
90 0 : void modbus::modbus_build_request( uint8_t *to_send, int address, int func )
91 : {
92 0 : to_send[0] = (uint8_t)_msg_id >> 8;
93 0 : to_send[1] = (uint8_t)( _msg_id & 0x00FF );
94 0 : to_send[2] = 0;
95 0 : to_send[3] = 0;
96 0 : to_send[4] = 0;
97 0 : to_send[6] = (uint8_t)_slaveid;
98 0 : to_send[7] = (uint8_t)func;
99 0 : to_send[8] = (uint8_t)( address >> 8 );
100 0 : to_send[9] = (uint8_t)( address & 0x00FF );
101 0 : }
102 :
103 0 : void modbus::modbus_write( int address, int amount, int func, uint16_t *value )
104 : {
105 0 : if( func == WRITE_COIL || func == WRITE_REG )
106 : {
107 : uint8_t to_send[12];
108 0 : modbus_build_request( to_send, address, func );
109 0 : to_send[5] = 6;
110 0 : to_send[10] = (uint8_t)( value[0] >> 8 );
111 0 : to_send[11] = (uint8_t)( value[0] & 0x00FF );
112 0 : modbus_send( to_send, 12 );
113 0 : }
114 0 : else if( func == WRITE_REGS )
115 : {
116 0 : uint8_t to_send[13 + 2 * amount];
117 0 : modbus_build_request( to_send, address, func );
118 0 : to_send[5] = (uint8_t)( 5 + 2 * amount );
119 0 : to_send[10] = (uint8_t)( amount >> 8 );
120 0 : to_send[11] = (uint8_t)( amount & 0x00FF );
121 0 : to_send[12] = (uint8_t)( 2 * amount );
122 0 : for( int i = 0; i < amount; i++ )
123 : {
124 0 : to_send[13 + 2 * i] = (uint8_t)( value[i] >> 8 );
125 0 : to_send[14 + 2 * i] = (uint8_t)( value[i] & 0x00FF );
126 : }
127 0 : modbus_send( to_send, 13 + 2 * amount );
128 0 : }
129 0 : else if( func == WRITE_COILS )
130 : {
131 0 : uint8_t to_send[14 + ( amount - 1 ) / 8];
132 0 : modbus_build_request( to_send, address, func );
133 0 : to_send[5] = (uint8_t)( 7 + ( amount - 1 ) / 8 );
134 0 : to_send[10] = (uint8_t)( amount >> 8 );
135 0 : to_send[11] = (uint8_t)( amount >> 8 );
136 0 : to_send[12] = (uint8_t)( ( amount + 7 ) / 8 );
137 0 : for( int i = 0; i < amount; i++ )
138 : {
139 0 : to_send[13 + ( i - 1 ) / 8] += (uint8_t)( value[i] << ( i % 8 ) );
140 : }
141 0 : modbus_send( to_send, 14 + ( amount - 1 ) / 8 );
142 0 : }
143 0 : }
144 :
145 0 : void modbus::modbus_read( int address, int amount, int func )
146 : {
147 : uint8_t to_send[12];
148 0 : modbus_build_request( to_send, address, func );
149 0 : to_send[5] = 6;
150 0 : to_send[10] = (uint8_t)( amount >> 8 );
151 0 : to_send[11] = (uint8_t)( amount & 0x00FF );
152 0 : modbus_send( to_send, 12 );
153 0 : }
154 :
155 0 : void modbus::modbus_read_holding_registers( int address, int amount, uint16_t *buffer )
156 : {
157 0 : if( _connected )
158 : {
159 0 : if( amount > 65535 || address > 65535 )
160 : {
161 0 : throw modbus_amount_exception();
162 : }
163 0 : modbus_read( address, amount, READ_REGS );
164 : uint8_t to_rec[MAX_MSG_LENGTH];
165 0 : modbus_receive( to_rec );
166 : try
167 : {
168 0 : modbus_error_handle( to_rec, READ_REGS );
169 0 : for( int i = 0; i < amount; i++ )
170 : {
171 0 : buffer[i] = ( (uint16_t)to_rec[9 + 2 * i] ) << 8;
172 0 : buffer[i] += (uint16_t)to_rec[10 + 2 * i];
173 : }
174 : }
175 0 : catch( std::exception &e )
176 : {
177 0 : throw; // e;
178 0 : }
179 : }
180 : else
181 : {
182 0 : throw modbus_connect_exception();
183 : }
184 0 : }
185 :
186 0 : void modbus::modbus_read_input_registers( int address, int amount, uint16_t *buffer )
187 : {
188 0 : if( _connected )
189 : {
190 0 : if( amount > 65535 || address > 65535 )
191 : {
192 0 : throw modbus_amount_exception();
193 : }
194 0 : modbus_read( address, amount, READ_INPUT_REGS );
195 : uint8_t to_rec[MAX_MSG_LENGTH];
196 0 : modbus_receive( to_rec );
197 : try
198 : {
199 0 : modbus_error_handle( to_rec, READ_INPUT_REGS );
200 0 : for( int i = 0; i < amount; i++ )
201 : {
202 0 : buffer[i] = ( (uint16_t)to_rec[9 + 2 * i] ) << 8;
203 0 : buffer[i] += (uint16_t)to_rec[10 + 2 * i];
204 : }
205 : }
206 0 : catch( std::exception &e )
207 : {
208 0 : throw; // e;
209 0 : }
210 : }
211 : else
212 : {
213 0 : throw modbus_connect_exception();
214 : }
215 0 : }
216 :
217 0 : void modbus::modbus_read_coils( int address, int amount, bool *buffer )
218 : {
219 0 : if( _connected )
220 : {
221 0 : if( amount > 2040 || address > 65535 )
222 : {
223 0 : throw modbus_amount_exception();
224 : }
225 0 : modbus_read( address, amount, READ_COILS );
226 : uint8_t to_rec[MAX_MSG_LENGTH];
227 0 : modbus_receive( to_rec );
228 : try
229 : {
230 0 : modbus_error_handle( to_rec, READ_COILS );
231 0 : for( int i = 0; i < amount; i++ )
232 : {
233 0 : buffer[i] = (bool)( ( to_rec[9 + i / 8] >> ( i % 8 ) ) & 1 );
234 : }
235 : }
236 0 : catch( std::exception &e )
237 : {
238 0 : throw; // e;
239 0 : }
240 : }
241 : else
242 : {
243 0 : throw modbus_connect_exception();
244 : }
245 0 : }
246 :
247 0 : void modbus::modbus_read_input_bits( int address, int amount, bool *buffer )
248 : {
249 0 : if( _connected )
250 : {
251 0 : if( amount > 2040 || address > 65535 )
252 : {
253 0 : throw modbus_amount_exception();
254 : }
255 0 : modbus_read( address, amount, READ_INPUT_BITS );
256 : uint8_t to_rec[MAX_MSG_LENGTH];
257 0 : modbus_receive( to_rec );
258 : try
259 : {
260 0 : modbus_error_handle( to_rec, READ_INPUT_BITS );
261 0 : for( int i = 0; i < amount; i++ )
262 : {
263 0 : buffer[i] = (bool)( ( to_rec[9 + i / 8] >> ( i % 8 ) ) & 1 );
264 : }
265 : }
266 0 : catch( std::exception &e )
267 : {
268 0 : throw; // e;
269 0 : }
270 : }
271 : else
272 : {
273 0 : throw modbus_connect_exception();
274 : }
275 0 : }
276 :
277 0 : void modbus::modbus_write_coil( int address, bool to_write )
278 : {
279 0 : if( _connected )
280 : {
281 0 : if( address > 65535 )
282 : {
283 0 : throw modbus_amount_exception();
284 : }
285 0 : int value = to_write * 0xFF00;
286 0 : modbus_write( address, 1, WRITE_COIL, (uint16_t *)&value );
287 : uint8_t to_rec[MAX_MSG_LENGTH];
288 0 : modbus_receive( to_rec );
289 : try
290 : {
291 0 : modbus_error_handle( to_rec, WRITE_COIL );
292 : }
293 0 : catch( std::exception &e )
294 : {
295 0 : throw; // e;
296 0 : }
297 : }
298 : else
299 : {
300 0 : throw modbus_connect_exception();
301 : }
302 0 : }
303 :
304 0 : void modbus::modbus_write_register( int address, uint16_t value )
305 : {
306 0 : if( _connected )
307 : {
308 0 : if( address > 65535 )
309 : {
310 0 : throw modbus_amount_exception();
311 : }
312 0 : modbus_write( address, 1, WRITE_REG, &value );
313 : uint8_t to_rec[MAX_MSG_LENGTH];
314 0 : modbus_receive( to_rec );
315 : try
316 : {
317 0 : modbus_error_handle( to_rec, WRITE_COIL );
318 : }
319 0 : catch( std::exception &e )
320 : {
321 0 : throw; // e;
322 0 : }
323 : }
324 : else
325 : {
326 0 : throw modbus_connect_exception();
327 : }
328 0 : }
329 :
330 0 : void modbus::modbus_write_coils( int address, int amount, bool *value )
331 : {
332 0 : if( _connected )
333 : {
334 0 : if( address > 65535 || amount > 65535 )
335 : {
336 0 : throw modbus_amount_exception();
337 : }
338 0 : uint16_t temp[amount];
339 0 : for( int i = 0; i < 4; i++ )
340 : {
341 0 : temp[i] = (uint16_t)value[i];
342 : }
343 0 : modbus_write( address, amount, WRITE_COILS, temp );
344 : uint8_t to_rec[MAX_MSG_LENGTH];
345 0 : modbus_receive( to_rec );
346 : try
347 : {
348 0 : modbus_error_handle( to_rec, WRITE_COILS );
349 : }
350 0 : catch( std::exception &e )
351 : {
352 0 : throw; // e;
353 0 : }
354 0 : }
355 : else
356 : {
357 0 : throw modbus_connect_exception();
358 : }
359 0 : }
360 :
361 0 : void modbus::modbus_write_registers( int address, int amount, uint16_t *value )
362 : {
363 0 : if( _connected )
364 : {
365 0 : if( address > 65535 || amount > 65535 )
366 : {
367 0 : throw modbus_amount_exception();
368 : }
369 0 : modbus_write( address, amount, WRITE_REGS, value );
370 : uint8_t to_rec[MAX_MSG_LENGTH];
371 0 : modbus_receive( to_rec );
372 : try
373 : {
374 0 : modbus_error_handle( to_rec, WRITE_REGS );
375 : }
376 0 : catch( std::exception &e )
377 : {
378 0 : throw; // e;
379 0 : }
380 : }
381 : else
382 : {
383 0 : throw modbus_connect_exception();
384 : }
385 0 : }
386 :
387 0 : ssize_t modbus::modbus_send( uint8_t *to_send, int length )
388 : {
389 0 : _msg_id++;
390 0 : return send( _socket, to_send, (size_t)length, 0 );
391 : }
392 :
393 0 : ssize_t modbus::modbus_receive( uint8_t *buffer )
394 : {
395 0 : return recv( _socket, (char *)buffer, MAX_MSG_LENGTH, 0 );
396 : }
397 :
398 0 : void modbus::modbus_error_handle( uint8_t *msg, int func )
399 : {
400 0 : if( msg[7] == func + 0x80 )
401 : {
402 0 : switch( msg[8] )
403 : {
404 0 : case EX_ILLEGAL_FUNCTION:
405 0 : throw modbus_illegal_function_exception();
406 0 : case EX_ILLEGAL_ADDRESS:
407 0 : throw modbus_illegal_address_exception();
408 0 : case EX_ILLEGAL_VALUE:
409 0 : throw modbus_illegal_data_value_exception();
410 0 : case EX_SERVER_FAILURE:
411 0 : throw modbus_server_failure_exception();
412 0 : case EX_ACKNOWLEDGE:
413 0 : throw modbus_acknowledge_exception();
414 0 : case EX_SERVER_BUSY:
415 0 : throw modbus_server_busy_exception();
416 0 : case EX_GATEWAY_PROBLEMP:
417 : case EX_GATEWYA_PROBLEMF:
418 0 : throw modbus_gateway_exception();
419 0 : default:
420 0 : break;
421 : }
422 : }
423 0 : }
|