modbus/mb_runtime.c
changeset 1912 8391c11477f4
parent 1909 bb883e063175
child 1913 338e2f51b685
equal deleted inserted replaced
1908:d0b1ffcb9368 1912:8391c11477f4
       
     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