|
1 /* File generated by Beremiz (PlugGenerate_C method of Modbus plugin) */ |
|
2 |
|
3 /* |
|
4 * Copyright (c) 2016 Mario de Sousa (msousa@fe.up.pt) |
|
5 * |
|
6 * This file is part of the Modbus library for Beremiz and matiec. |
|
7 * |
|
8 * This Modbus library is free software: you can redistribute it and/or modify |
|
9 * it under the terms of the GNU Lesser General Public License as published by |
|
10 * the Free Software Foundation, either version 3 of the License, or |
|
11 * (at your option) any later version. |
|
12 * |
|
13 * This program is distributed in the hope that it will be useful, but |
|
14 * WITHOUT ANY WARRANTY; without even the implied warranty of |
|
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
|
16 * General Public License for more details. |
|
17 * |
|
18 * You should have received a copy of the GNU Lesser General Public License |
|
19 * along with this Modbus library. If not, see <http://www.gnu.org/licenses/>. |
|
20 * |
|
21 * This code is made available on the understanding that it will not be |
|
22 * used in safety-critical situations without a full and competent review. |
|
23 */ |
|
24 |
|
25 |
|
26 #include <stdio.h> |
|
27 #include <string.h> /* required for memcpy() */ |
|
28 #include "mb_slave_and_master.h" |
|
29 #include "MB_%(locstr)s.h" |
|
30 |
|
31 |
|
32 #define MAX_MODBUS_ERROR_CODE 11 |
|
33 static const char *modbus_error_messages[MAX_MODBUS_ERROR_CODE+1] = { |
|
34 /* 0 */ "", /* un-used -> no error! */ |
|
35 /* 1 */ "illegal/unsuported function", |
|
36 /* 2 */ "illegal data address", |
|
37 /* 3 */ "illegal data value", |
|
38 /* 4 */ "slave device failure", |
|
39 /* 5 */ "acknowledge -> slave intends to reply later", |
|
40 /* 6 */ "slave device busy", |
|
41 /* 7 */ "negative acknowledge", |
|
42 /* 8 */ "memory parity error", |
|
43 /* 9 */ "", /* undefined by Modbus */ |
|
44 /* 10*/ "gateway path unavalilable", |
|
45 /* 11*/ "gateway target device failed to respond" |
|
46 }; |
|
47 |
|
48 |
|
49 /* Execute a modbus client transaction/request */ |
|
50 static int __execute_mb_request(int request_id){ |
|
51 switch (client_requests[request_id].mb_function){ |
|
52 |
|
53 case 1: /* read coils */ |
|
54 return read_output_bits(client_requests[request_id].slave_id, |
|
55 client_requests[request_id].address, |
|
56 client_requests[request_id].count, |
|
57 client_requests[request_id].coms_buffer, |
|
58 (int) client_requests[request_id].count, |
|
59 client_nodes[client_requests[request_id].client_node_id].mb_nd, |
|
60 client_requests[request_id].retries, |
|
61 &(client_requests[request_id].error_code), |
|
62 &(client_requests[request_id].resp_timeout), |
|
63 &(client_requests[request_id].coms_buf_mutex)); |
|
64 |
|
65 case 2: /* read discrete inputs */ |
|
66 return read_input_bits( client_requests[request_id].slave_id, |
|
67 client_requests[request_id].address, |
|
68 client_requests[request_id].count, |
|
69 client_requests[request_id].coms_buffer, |
|
70 (int) client_requests[request_id].count, |
|
71 client_nodes[client_requests[request_id].client_node_id].mb_nd, |
|
72 client_requests[request_id].retries, |
|
73 &(client_requests[request_id].error_code), |
|
74 &(client_requests[request_id].resp_timeout), |
|
75 &(client_requests[request_id].coms_buf_mutex)); |
|
76 |
|
77 case 3: /* read holding registers */ |
|
78 return read_output_words(client_requests[request_id].slave_id, |
|
79 client_requests[request_id].address, |
|
80 client_requests[request_id].count, |
|
81 client_requests[request_id].coms_buffer, |
|
82 (int) client_requests[request_id].count, |
|
83 client_nodes[client_requests[request_id].client_node_id].mb_nd, |
|
84 client_requests[request_id].retries, |
|
85 &(client_requests[request_id].error_code), |
|
86 &(client_requests[request_id].resp_timeout), |
|
87 &(client_requests[request_id].coms_buf_mutex)); |
|
88 |
|
89 case 4: /* read input registers */ |
|
90 return read_input_words(client_requests[request_id].slave_id, |
|
91 client_requests[request_id].address, |
|
92 client_requests[request_id].count, |
|
93 client_requests[request_id].coms_buffer, |
|
94 (int) client_requests[request_id].count, |
|
95 client_nodes[client_requests[request_id].client_node_id].mb_nd, |
|
96 client_requests[request_id].retries, |
|
97 &(client_requests[request_id].error_code), |
|
98 &(client_requests[request_id].resp_timeout), |
|
99 &(client_requests[request_id].coms_buf_mutex)); |
|
100 |
|
101 case 5: /* write single coil */ |
|
102 return write_output_bit(client_requests[request_id].slave_id, |
|
103 client_requests[request_id].address, |
|
104 client_requests[request_id].coms_buffer[0], |
|
105 client_nodes[client_requests[request_id].client_node_id].mb_nd, |
|
106 client_requests[request_id].retries, |
|
107 &(client_requests[request_id].error_code), |
|
108 &(client_requests[request_id].resp_timeout), |
|
109 &(client_requests[request_id].coms_buf_mutex)); |
|
110 |
|
111 case 6: /* write single register */ |
|
112 return write_output_word(client_requests[request_id].slave_id, |
|
113 client_requests[request_id].address, |
|
114 client_requests[request_id].coms_buffer[0], |
|
115 client_nodes[client_requests[request_id].client_node_id].mb_nd, |
|
116 client_requests[request_id].retries, |
|
117 &(client_requests[request_id].error_code), |
|
118 &(client_requests[request_id].resp_timeout), |
|
119 &(client_requests[request_id].coms_buf_mutex)); |
|
120 |
|
121 case 7: break; /* function not yet supported */ |
|
122 case 8: break; /* function not yet supported */ |
|
123 case 9: break; /* function not yet supported */ |
|
124 case 10: break; /* function not yet supported */ |
|
125 case 11: break; /* function not yet supported */ |
|
126 case 12: break; /* function not yet supported */ |
|
127 case 13: break; /* function not yet supported */ |
|
128 case 14: break; /* function not yet supported */ |
|
129 |
|
130 case 15: /* write multiple coils */ |
|
131 return write_output_bits(client_requests[request_id].slave_id, |
|
132 client_requests[request_id].address, |
|
133 client_requests[request_id].count, |
|
134 client_requests[request_id].coms_buffer, |
|
135 client_nodes[client_requests[request_id].client_node_id].mb_nd, |
|
136 client_requests[request_id].retries, |
|
137 &(client_requests[request_id].error_code), |
|
138 &(client_requests[request_id].resp_timeout), |
|
139 &(client_requests[request_id].coms_buf_mutex)); |
|
140 |
|
141 case 16: /* write multiple registers */ |
|
142 return write_output_words(client_requests[request_id].slave_id, |
|
143 client_requests[request_id].address, |
|
144 client_requests[request_id].count, |
|
145 client_requests[request_id].coms_buffer, |
|
146 client_nodes[client_requests[request_id].client_node_id].mb_nd, |
|
147 client_requests[request_id].retries, |
|
148 &(client_requests[request_id].error_code), |
|
149 &(client_requests[request_id].resp_timeout), |
|
150 &(client_requests[request_id].coms_buf_mutex)); |
|
151 |
|
152 default: break; /* should never occur, if file generation is correct */ |
|
153 } |
|
154 |
|
155 fprintf(stderr, "Modbus plugin: Modbus function %%d not supported\n", request_id); /* should never occur, if file generation is correct */ |
|
156 return -1; |
|
157 } |
|
158 |
|
159 |
|
160 |
|
161 /* pack bits from unpacked_data to packed_data */ |
|
162 static inline int __pack_bits(u16 *unpacked_data, u16 start_addr, u16 bit_count, u8 *packed_data) { |
|
163 u8 bit; |
|
164 u16 byte, coils_processed; |
|
165 |
|
166 if ((0 == bit_count) || (65535-start_addr < bit_count-1)) |
|
167 return -ERR_ILLEGAL_DATA_ADDRESS; /* ERR_ILLEGAL_DATA_ADDRESS defined in mb_util.h */ |
|
168 |
|
169 for( byte = 0, coils_processed = 0; coils_processed < bit_count; byte++) { |
|
170 packed_data[byte] = 0; |
|
171 for( bit = 0x01; (bit & 0xFF) && (coils_processed < bit_count); bit <<= 1, coils_processed++ ) { |
|
172 if(unpacked_data[start_addr + coils_processed]) |
|
173 packed_data[byte] |= bit; /* set bit */ |
|
174 else packed_data[byte] &= ~bit; /* reset bit */ |
|
175 } |
|
176 } |
|
177 return 0; |
|
178 } |
|
179 |
|
180 |
|
181 /* unpack bits from packed_data to unpacked_data */ |
|
182 static inline int __unpack_bits(u16 *unpacked_data, u16 start_addr, u16 bit_count, u8 *packed_data) { |
|
183 u8 temp, bit; |
|
184 u16 byte, coils_processed; |
|
185 |
|
186 if ((0 == bit_count) || (65535-start_addr < bit_count-1)) |
|
187 return -ERR_ILLEGAL_DATA_ADDRESS; /* ERR_ILLEGAL_DATA_ADDRESS defined in mb_util.h */ |
|
188 |
|
189 for(byte = 0, coils_processed = 0; coils_processed < bit_count; byte++) { |
|
190 temp = packed_data[byte] ; |
|
191 for(bit = 0x01; (bit & 0xff) && (coils_processed < bit_count); bit <<= 1, coils_processed++) { |
|
192 unpacked_data[start_addr + coils_processed] = (temp & bit)?1:0; |
|
193 } |
|
194 } |
|
195 return 0; |
|
196 } |
|
197 |
|
198 |
|
199 static int __read_inbits (void *mem_map, u16 start_addr, u16 bit_count, u8 *data_bytes) |
|
200 {return __pack_bits(((server_mem_t *)mem_map)->ro_bits, start_addr, bit_count, data_bytes);} |
|
201 static int __read_outbits (void *mem_map, u16 start_addr, u16 bit_count, u8 *data_bytes) |
|
202 {return __pack_bits(((server_mem_t *)mem_map)->rw_bits, start_addr, bit_count, data_bytes);} |
|
203 static int __write_outbits (void *mem_map, u16 start_addr, u16 bit_count, u8 *data_bytes) |
|
204 {return __unpack_bits(((server_mem_t *)mem_map)->rw_bits, start_addr, bit_count, data_bytes); } |
|
205 |
|
206 |
|
207 |
|
208 static int __read_inwords (void *mem_map, u16 start_addr, u16 word_count, u16 *data_words) { |
|
209 u16 count; |
|
210 // return -ERR_ILLEGAL_FUNCTION; /* function not yet supported *//* ERR_ILLEGAL_FUNCTION defined in mb_util.h */ |
|
211 |
|
212 if ((start_addr + word_count) > MEM_AREA_SIZE) |
|
213 return -ERR_ILLEGAL_DATA_ADDRESS; /* ERR_ILLEGAL_DATA_ADDRESS defined in mb_util.h */ |
|
214 |
|
215 /* use memcpy() as it is more efficient... |
|
216 for (count = 0; count < word_count ; count++) |
|
217 data_words[count] = ((server_mem_t *)mem_map)->ro_words[count + start_addr]; |
|
218 */ |
|
219 memcpy(/* dest */ (void *)data_words, |
|
220 /* src */ (void *)&(((server_mem_t *)mem_map)->ro_words[start_addr]), |
|
221 /* size */ word_count * 2); |
|
222 return 0; |
|
223 } |
|
224 |
|
225 |
|
226 |
|
227 static int __read_outwords (void *mem_map, u16 start_addr, u16 word_count, u16 *data_words) { |
|
228 u16 count; |
|
229 // return -ERR_ILLEGAL_FUNCTION; /* function not yet supported *//* ERR_ILLEGAL_FUNCTION defined in mb_util.h */ |
|
230 |
|
231 if ((start_addr + word_count) > MEM_AREA_SIZE) |
|
232 return -ERR_ILLEGAL_DATA_ADDRESS; /* ERR_ILLEGAL_DATA_ADDRESS defined in mb_util.h */ |
|
233 |
|
234 /* use memcpy() as it is more efficient... |
|
235 for (count = 0; count < word_count ; count++) |
|
236 data_words[count] = ((server_mem_t *)mem_map)->rw_words[count + start_addr]; |
|
237 */ |
|
238 memcpy(/* dest */ (void *)data_words, |
|
239 /* src */ (void *)&(((server_mem_t *)mem_map)->rw_words[start_addr]), |
|
240 /* size */ word_count * 2); |
|
241 return 0; |
|
242 } |
|
243 |
|
244 |
|
245 |
|
246 |
|
247 static int __write_outwords(void *mem_map, u16 start_addr, u16 word_count, u16 *data_words) { |
|
248 u16 count; |
|
249 // return -ERR_ILLEGAL_FUNCTION; /* function not yet supported *//* ERR_ILLEGAL_FUNCTION defined in mb_util.h */ |
|
250 |
|
251 if ((start_addr + word_count) > MEM_AREA_SIZE) |
|
252 return -ERR_ILLEGAL_DATA_ADDRESS; /* ERR_ILLEGAL_DATA_ADDRESS defined in mb_util.h */ |
|
253 |
|
254 /* WARNING: The data returned in the data_words[] array is not guaranteed to be 16 bit aligned. |
|
255 * It is not therefore safe to cast it to an u16 data type. |
|
256 * The following code cannot be used. memcpy() is used instead. |
|
257 */ |
|
258 /* |
|
259 for (count = 0; count < word_count ; count++) |
|
260 ((server_mem_t *)mem_map)->rw_words[count + start_addr] = data_words[count]; |
|
261 */ |
|
262 memcpy(/* dest */ (void *)&(((server_mem_t *)mem_map)->rw_words[start_addr]), |
|
263 /* src */ (void *)data_words, |
|
264 /* size */ word_count * 2); |
|
265 return 0; |
|
266 } |
|
267 |
|
268 |
|
269 |
|
270 |
|
271 #include <pthread.h> |
|
272 |
|
273 static void *__mb_server_thread(void *_server_node) { |
|
274 server_node_t *server_node = _server_node; |
|
275 mb_slave_callback_t callbacks = { |
|
276 &__read_inbits, |
|
277 &__read_outbits, |
|
278 &__write_outbits, |
|
279 &__read_inwords, |
|
280 &__read_outwords, |
|
281 &__write_outwords, |
|
282 (void *)&(server_node->mem_area) |
|
283 }; |
|
284 |
|
285 // Enable thread cancelation. Enabled is default, but set it anyway to be safe. |
|
286 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); |
|
287 |
|
288 // mb_slave_run() should never return! |
|
289 mb_slave_run(server_node->mb_nd /* nd */, callbacks, server_node->slave_id); |
|
290 fprintf(stderr, "Modbus plugin: Modbus server for node %%s died unexpectedly!\n", server_node->location); /* should never occur */ |
|
291 return NULL; |
|
292 } |
|
293 |
|
294 |
|
295 |
|
296 static void *__mb_client_thread(void *_index) { |
|
297 int client_node_id = (char *)_index - (char *)NULL; // Use pointer arithmetic (more portable than cast) |
|
298 struct timespec next_cycle; |
|
299 int period_sec = client_nodes[client_node_id].comm_period / 1000; /* comm_period is in ms */ |
|
300 int period_nsec = (client_nodes[client_node_id].comm_period %%1000)*1000000; /* comm_period is in ms */ |
|
301 |
|
302 // Enable thread cancelation. Enabled is default, but set it anyway to be safe. |
|
303 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); |
|
304 |
|
305 // get the current time |
|
306 clock_gettime(CLOCK_MONOTONIC, &next_cycle); |
|
307 |
|
308 // loop the communication with the client |
|
309 while (1) { |
|
310 /* |
|
311 struct timespec cur_time; |
|
312 clock_gettime(CLOCK_MONOTONIC, &cur_time); |
|
313 fprintf(stderr, "Modbus client thread - new cycle (%%ld:%%ld)!\n", cur_time.tv_sec, cur_time.tv_nsec); |
|
314 */ |
|
315 int req; |
|
316 for (req=0; req < NUMBER_OF_CLIENT_REQTS; req ++){ |
|
317 /*just do the requests belonging to the client */ |
|
318 if (client_requests[req].client_node_id != client_node_id) |
|
319 continue; |
|
320 int res_tmp = __execute_mb_request(req); |
|
321 switch (res_tmp) { |
|
322 case PORT_FAILURE: { |
|
323 if (res_tmp != client_nodes[client_node_id].prev_error) |
|
324 fprintf(stderr, "Modbus plugin: Error connecting Modbus client %%s to remote server.\n", client_nodes[client_node_id].location); |
|
325 client_nodes[client_node_id].prev_error = res_tmp; |
|
326 break; |
|
327 } |
|
328 case INVALID_FRAME: { |
|
329 if ((res_tmp != client_requests[req].prev_error) && (0 == client_nodes[client_node_id].prev_error)) |
|
330 fprintf(stderr, "Modbus plugin: Modbus client request configured at location %%s was unsuccesful. Server/slave returned an invalid/corrupted frame.\n", client_requests[req].location); |
|
331 client_requests[req].prev_error = res_tmp; |
|
332 break; |
|
333 } |
|
334 case TIMEOUT: { |
|
335 if ((res_tmp != client_requests[req].prev_error) && (0 == client_nodes[client_node_id].prev_error)) |
|
336 fprintf(stderr, "Modbus plugin: Modbus client request configured at location %%s timed out waiting for reply from server.\n", client_requests[req].location); |
|
337 client_requests[req].prev_error = res_tmp; |
|
338 break; |
|
339 } |
|
340 case MODBUS_ERROR: { |
|
341 if (client_requests[req].prev_error != client_requests[req].error_code) { |
|
342 fprintf(stderr, "Modbus plugin: Modbus client request configured at location %%s was unsuccesful. Server/slave returned error code 0x%%2x", client_requests[req].location, client_requests[req].error_code); |
|
343 if (client_requests[req].error_code <= MAX_MODBUS_ERROR_CODE ) { |
|
344 fprintf(stderr, "(%%s)", modbus_error_messages[client_requests[req].error_code]); |
|
345 fprintf(stderr, ".\n"); |
|
346 } |
|
347 } |
|
348 client_requests[req].prev_error = client_requests[req].error_code; |
|
349 break; |
|
350 } |
|
351 default: { |
|
352 if ((res_tmp >= 0) && (client_nodes[client_node_id].prev_error != 0)) { |
|
353 fprintf(stderr, "Modbus plugin: Modbus client %%s has reconnected to server/slave.\n", client_nodes[client_node_id].location); |
|
354 } |
|
355 if ((res_tmp >= 0) && (client_requests[req] .prev_error != 0)) { |
|
356 fprintf(stderr, "Modbus plugin: Modbus client request configured at location %%s has succesfully resumed comunication.\n", client_requests[req].location); |
|
357 } |
|
358 client_nodes[client_node_id].prev_error = 0; |
|
359 client_requests[req] .prev_error = 0; |
|
360 break; |
|
361 } |
|
362 } |
|
363 } |
|
364 // Determine absolute time instant for starting the next cycle |
|
365 // struct timespec prev_cycle; |
|
366 // prev_cycle = next_cycle; |
|
367 next_cycle.tv_sec += period_sec; |
|
368 next_cycle.tv_nsec += period_nsec; |
|
369 if (next_cycle.tv_nsec >= 1000000000) { |
|
370 next_cycle.tv_sec ++; |
|
371 next_cycle.tv_nsec -= 1000000000; |
|
372 } |
|
373 /* It probably does not make sense to check for overflow of timer. |
|
374 * Even in 32 bit systems this will take at least 68 years since the computer booted |
|
375 * (remember, we are using CLOCK_MONOTONIC, which should start counting from 0 |
|
376 * every time the system boots). On 64 bit systems, it will take over |
|
377 * 10^11 years to overflow. |
|
378 */ |
|
379 /* |
|
380 if (next_cycle.tv_sec) < prev_cycle.tv_sec) { |
|
381 // we will lose some precision by reading the time again, |
|
382 // but it is better than the alternative... |
|
383 clock_gettime(CLOCK_MONOTONIC, &next_cycle); |
|
384 next_cycle.tv_sec += period_sec; |
|
385 next_cycle.tv_nsec += period_nsec; |
|
386 if (next_cycle.tv_nsec >= 1000000000) { |
|
387 next_cycle.tv_sec ++; |
|
388 next_cycle.tv_nsec -= 1000000000; |
|
389 } |
|
390 } |
|
391 */ |
|
392 clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next_cycle, NULL); |
|
393 } |
|
394 |
|
395 // humour the compiler. |
|
396 return NULL; |
|
397 } |
|
398 |
|
399 |
|
400 |
|
401 int __init_%(locstr)s (int argc, char **argv){ |
|
402 int index; |
|
403 |
|
404 for (index=0; index < NUMBER_OF_CLIENT_NODES;index++) |
|
405 client_nodes[index].mb_nd = -1; |
|
406 for (index=0; index < NUMBER_OF_SERVER_NODES;index++) |
|
407 // mb_nd with negative numbers indicate how far it has been initialised (or not) |
|
408 // -2 --> no modbus node created; no thread created |
|
409 // -1 --> modbus node created!; no thread created |
|
410 // >=0 --> modbus node created!; thread created! |
|
411 server_nodes[index].mb_nd = -2; |
|
412 |
|
413 /* modbus library init */ |
|
414 /* Note that TOTAL_xxxNODE_COUNT are the nodes required by _ALL_ the instances of the modbus |
|
415 * extension currently in the user's project. This file (MB_xx.c) is handling only one instance, |
|
416 * but must initialize the library for all instances. Only the first call to mb_slave_and_master_init() |
|
417 * will result in memory being allocated. All subsequent calls (by other MB_xx,c files) will be ignored |
|
418 * by the mb_slave_and_master_init() funtion, as long as they are called with the same arguments. |
|
419 */ |
|
420 if (mb_slave_and_master_init(TOTAL_TCPNODE_COUNT, TOTAL_RTUNODE_COUNT, TOTAL_ASCNODE_COUNT) <0) { |
|
421 fprintf(stderr, "Modbus plugin: Error starting modbus library\n"); |
|
422 // return imediately. Do NOT goto error_exit, as we did not get to |
|
423 // start the modbus library! |
|
424 return -1; |
|
425 } |
|
426 |
|
427 /* init the mutex for each client request */ |
|
428 /* Must be done _before_ launching the client threads!! */ |
|
429 for (index=0; index < NUMBER_OF_CLIENT_REQTS; index ++){ |
|
430 if (pthread_mutex_init(&(client_requests[index].coms_buf_mutex), NULL)) { |
|
431 fprintf(stderr, "Modbus plugin: Error initializing request for modbus client node %%s\n", client_nodes[client_requests[index].client_node_id].location); |
|
432 goto error_exit; |
|
433 } |
|
434 } |
|
435 |
|
436 /* init each client connection to remote modbus server, and launch thread */ |
|
437 /* NOTE: All client_nodes[].init_state are initialised to 0 in the code |
|
438 * generated by the modbus plugin |
|
439 */ |
|
440 for (index=0; index < NUMBER_OF_CLIENT_NODES;index++){ |
|
441 /* establish client connection */ |
|
442 client_nodes[index].mb_nd = mb_master_connect (client_nodes[index].node_address); |
|
443 if (client_nodes[index].mb_nd < 0){ |
|
444 fprintf(stderr, "Modbus plugin: Error creating modbus client node %%s\n", client_nodes[index].location); |
|
445 goto error_exit; |
|
446 } |
|
447 client_nodes[index].init_state = 1; // we have created the node |
|
448 |
|
449 /* launch a thread to handle this client node */ |
|
450 { |
|
451 int res = 0; |
|
452 pthread_attr_t attr; |
|
453 res |= pthread_attr_init(&attr); |
|
454 res |= pthread_create(&(client_nodes[index].thread_id), &attr, &__mb_client_thread, (void *)((char *)NULL + index)); |
|
455 if (res != 0) { |
|
456 fprintf(stderr, "Modbus plugin: Error starting modbus client thread for node %%s\n", client_nodes[index].location); |
|
457 goto error_exit; |
|
458 } |
|
459 } |
|
460 client_nodes[index].init_state = 2; // we have created the node and a thread |
|
461 } |
|
462 |
|
463 /* init each local server */ |
|
464 /* NOTE: All server_nodes[].init_state are initialised to 0 in the code |
|
465 * generated by the modbus plugin |
|
466 */ |
|
467 for (index=0; index < NUMBER_OF_SERVER_NODES;index++){ |
|
468 /* create the modbus server */ |
|
469 server_nodes[index].mb_nd = mb_slave_new (server_nodes[index].node_address); |
|
470 if (server_nodes[index].mb_nd < 0){ |
|
471 fprintf(stderr, "Modbus plugin: Error creating modbus server node %%s\n", server_nodes[index].location); |
|
472 goto error_exit; |
|
473 } |
|
474 server_nodes[index].init_state = 1; // we have created the node |
|
475 |
|
476 /* launch a thread to handle this server node */ |
|
477 { |
|
478 int res = 0; |
|
479 pthread_attr_t attr; |
|
480 res |= pthread_attr_init(&attr); |
|
481 res |= pthread_create(&(server_nodes[index].thread_id), &attr, &__mb_server_thread, (void *)&(server_nodes[index])); |
|
482 if (res != 0) { |
|
483 fprintf(stderr, "Modbus plugin: Error starting modbus server thread for node %%s\n", server_nodes[index].location); |
|
484 goto error_exit; |
|
485 } |
|
486 } |
|
487 server_nodes[index].init_state = 2; // we have created the node and thread |
|
488 } |
|
489 |
|
490 return 0; |
|
491 |
|
492 error_exit: |
|
493 __cleanup_%(locstr)s (); |
|
494 return -1; |
|
495 } |
|
496 |
|
497 |
|
498 |
|
499 |
|
500 |
|
501 void __publish_%(locstr)s (){ |
|
502 int index; |
|
503 |
|
504 for (index=0; index < NUMBER_OF_CLIENT_REQTS; index ++){ |
|
505 /*just do the output requests */ |
|
506 if (client_requests[index].req_type == req_output){ |
|
507 pthread_mutex_lock(&(client_requests[index].coms_buf_mutex)); |
|
508 // copy from plcv_buffer to coms_buffer |
|
509 memcpy((void *)client_requests[index].coms_buffer /* destination */, |
|
510 (void *)client_requests[index].plcv_buffer /* source */, |
|
511 REQ_BUF_SIZE * sizeof(u16) /* size in bytes */); |
|
512 pthread_mutex_unlock(&(client_requests[index].coms_buf_mutex)); |
|
513 } |
|
514 } |
|
515 } |
|
516 |
|
517 |
|
518 |
|
519 |
|
520 |
|
521 void __retrieve_%(locstr)s (){ |
|
522 int index; |
|
523 |
|
524 for (index=0; index < NUMBER_OF_CLIENT_REQTS; index ++){ |
|
525 /*just do the input requests */ |
|
526 if (client_requests[index].req_type == req_input){ |
|
527 pthread_mutex_lock(&(client_requests[index].coms_buf_mutex)); |
|
528 // copy from coms_buffer to plcv_buffer |
|
529 memcpy((void *)client_requests[index].plcv_buffer /* destination */, |
|
530 (void *)client_requests[index].coms_buffer /* source */, |
|
531 REQ_BUF_SIZE * sizeof(u16) /* size in bytes */); |
|
532 pthread_mutex_unlock(&(client_requests[index].coms_buf_mutex)); |
|
533 } |
|
534 } |
|
535 } |
|
536 |
|
537 |
|
538 |
|
539 |
|
540 |
|
541 int __cleanup_%(locstr)s (){ |
|
542 int index, close; |
|
543 int res = 0; |
|
544 |
|
545 /* kill thread and close connections of each modbus client node */ |
|
546 for (index=0; index < NUMBER_OF_CLIENT_NODES; index++) { |
|
547 close = 0; |
|
548 if (client_nodes[index].init_state >= 2) { |
|
549 // thread was launched, so we try to cancel it! |
|
550 close = pthread_cancel(client_nodes[index].thread_id); |
|
551 close |= pthread_join (client_nodes[index].thread_id, NULL); |
|
552 if (close < 0) |
|
553 fprintf(stderr, "Modbus plugin: Error closing thread for modbus client %%s\n", client_nodes[index].location); |
|
554 } |
|
555 res |= close; |
|
556 |
|
557 close = 0; |
|
558 if (client_nodes[index].init_state >= 1) { |
|
559 // modbus client node was created, so we try to close it! |
|
560 close = mb_master_close (client_nodes[index].mb_nd); |
|
561 if (close < 0){ |
|
562 fprintf(stderr, "Modbus plugin: Error closing modbus client node %%s\n", client_nodes[index].location); |
|
563 // We try to shut down as much as possible, so we do not return noW! |
|
564 } |
|
565 client_nodes[index].mb_nd = -1; |
|
566 } |
|
567 res |= close; |
|
568 client_nodes[index].init_state = 0; |
|
569 } |
|
570 |
|
571 /* kill thread and close connections of each modbus server node */ |
|
572 for (index=0; index < NUMBER_OF_SERVER_NODES; index++) { |
|
573 close = 0; |
|
574 if (server_nodes[index].init_state >= 2) { |
|
575 // thread was launched, so we try to cancel it! |
|
576 close = pthread_cancel(server_nodes[index].thread_id); |
|
577 close |= pthread_join (server_nodes[index].thread_id, NULL); |
|
578 if (close < 0) |
|
579 fprintf(stderr, "Modbus plugin: Error closing thread for modbus server %%s\n", server_nodes[index].location); |
|
580 } |
|
581 res |= close; |
|
582 |
|
583 close = 0; |
|
584 if (server_nodes[index].init_state >= 1) { |
|
585 // modbus server node was created, so we try to close it! |
|
586 close = mb_slave_close (server_nodes[index].mb_nd); |
|
587 if (close < 0) { |
|
588 fprintf(stderr, "Modbus plugin: Error closing node for modbus server %%s (%%d)\n", server_nodes[index].location, server_nodes[index].mb_nd); |
|
589 // We try to shut down as much as possible, so we do not return noW! |
|
590 } |
|
591 server_nodes[index].mb_nd = -1; |
|
592 } |
|
593 res |= close; |
|
594 server_nodes[index].init_state = 0; |
|
595 } |
|
596 |
|
597 /* destroy the mutex of each client request */ |
|
598 for (index=0; index < NUMBER_OF_CLIENT_REQTS; index ++) { |
|
599 if (pthread_mutex_destroy(&(client_requests[index].coms_buf_mutex))) { |
|
600 fprintf(stderr, "Modbus plugin: Error destroying request for modbus client node %%s\n", client_nodes[client_requests[index].client_node_id].location); |
|
601 // We try to shut down as much as possible, so we do not return noW! |
|
602 res |= -1; |
|
603 } |
|
604 } |
|
605 |
|
606 /* modbus library close */ |
|
607 //fprintf(stderr, "Shutting down modbus library...\n"); |
|
608 if (mb_slave_and_master_done()<0) { |
|
609 fprintf(stderr, "Modbus plugin: Error shutting down modbus library\n"); |
|
610 res |= -1; |
|
611 } |
|
612 |
|
613 return res; |
|
614 } |
|
615 |