293 } |
293 } |
294 |
294 |
295 |
295 |
296 static void *__mb_client_thread(void *_index) { |
296 static void *__mb_client_thread(void *_index) { |
297 int client_node_id = (char *)_index - (char *)NULL; // Use pointer arithmetic (more portable than cast) |
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 |
298 |
302 // Enable thread cancelation. Enabled is default, but set it anyway to be safe. |
299 // Enable thread cancelation. Enabled is default, but set it anyway to be safe. |
303 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); |
300 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); |
304 |
301 |
305 // configure the timer for periodic activation |
|
306 { |
|
307 struct itimerspec timerspec; |
|
308 timerspec.it_interval.tv_sec = period_sec; |
|
309 timerspec.it_interval.tv_nsec = period_nsec; |
|
310 timerspec.it_value = timerspec.it_interval; |
|
311 |
|
312 if (timer_settime(client_nodes[client_node_id].timer_id, 0 /* flags */, &timerspec, NULL) < 0) |
|
313 fprintf(stderr, "Modbus plugin: Error configuring periodic activation timer for Modbus client %%s.\n", client_nodes[client_node_id].location); |
|
314 } |
|
315 |
|
316 /* loop the communication with the client |
302 /* loop the communication with the client |
317 * |
303 * |
318 * When the client thread has difficulty communicating with remote client and/or server (network issues, for example), |
304 * When the client thread has difficulty communicating with remote client and/or server (network issues, for example), |
319 * then the communications get delayed and we will fall behind in the period. |
305 * then the communications get delayed and we will fall behind in the period. |
320 * |
306 * |
490 |
476 |
491 |
477 |
492 static int stop_mb_client_timer_thread; |
478 static int stop_mb_client_timer_thread; |
493 static void *__mb_client_timer_thread(void *_index) { |
479 static void *__mb_client_timer_thread(void *_index) { |
494 sigset_t set; |
480 sigset_t set; |
495 int signum = SIGALRM; |
481 int signum; |
|
482 sigemptyset(&set); |
|
483 sigaddset(&set, SIGALRM); |
|
484 |
496 int client_node_id = (char *)_index - (char *)NULL; // Use pointer arithmetic (more portable than cast) |
485 int client_node_id = (char *)_index - (char *)NULL; // Use pointer arithmetic (more portable than cast) |
497 printf("%%d\n", client_node_id); |
486 printf("%%d\n", client_node_id); |
498 /* initialize the timer that will be used to periodically activate the client node */ |
487 /* initialize the timer that will be used to periodically activate the client node */ |
499 { |
488 { |
500 // start off by reseting the flag that will be set whenever the timer expires |
489 // start off by reseting the flag that will be set whenever the timer expires |
501 client_nodes[client_node_id].periodic_act = 0; |
490 client_nodes[client_node_id].periodic_act = 0; |
502 |
491 |
503 struct sigevent evp = {0}; |
492 if (timer_create(CLOCK_REALTIME, NULL, &(client_nodes[client_node_id].timer_id)) < 0) { |
504 evp.sigev_notify = SIGEV_THREAD_ID; /* Notification method - call a function in a new thread context */ |
|
505 evp.sigev_signo = SIGALRM; |
|
506 evp.sigev_value.sival_int = client_node_id; /* Data passed to function upon notification - used to indentify which client node to activate */ |
|
507 |
|
508 if (timer_create(CLOCK_MONOTONIC, &evp, &(client_nodes[client_node_id].timer_id)) < 0) { |
|
509 fprintf(stderr, "Modbus plugin: Error (%%s) creating timer for modbus client node %%s\n", strerror(errno), client_nodes[client_node_id].location); |
493 fprintf(stderr, "Modbus plugin: Error (%%s) creating timer for modbus client node %%s\n", strerror(errno), client_nodes[client_node_id].location); |
510 return NULL; |
494 return NULL; |
511 } |
495 } |
512 } |
496 } |
513 |
497 |
|
498 int period_sec = client_nodes[client_node_id].comm_period / 1000; /* comm_period is in ms */ |
|
499 int period_nsec = (client_nodes[client_node_id].comm_period %%1000)*1000000; /* comm_period is in ms */ |
|
500 |
|
501 // configure the timer for periodic activation |
|
502 { |
|
503 struct itimerspec timerspec; |
|
504 timerspec.it_interval.tv_sec = period_sec; |
|
505 timerspec.it_interval.tv_nsec = period_nsec; |
|
506 timerspec.it_value = timerspec.it_interval; |
|
507 |
|
508 if (timer_settime(client_nodes[client_node_id].timer_id, 0 /* flags */, &timerspec, NULL) < 0) |
|
509 fprintf(stderr, "Modbus plugin: Error configuring periodic activation timer for Modbus client %%s.\n", client_nodes[client_node_id].location); |
|
510 } |
|
511 |
514 stop_mb_client_timer_thread = 0; |
512 stop_mb_client_timer_thread = 0; |
515 while(!stop_mb_client_timer_thread) { |
513 while(!stop_mb_client_timer_thread) { |
516 if(sigwait (&set, &signum) == -1) |
514 if(sigwait (&set, &signum) == -1) |
517 perror ("sigwait"); |
515 perror ("sigwait"); |
|
516 |
518 if(stop_mb_client_timer_thread) |
517 if(stop_mb_client_timer_thread) |
519 break; |
518 break; |
520 __client_node_timer_callback_function(client_node_id); |
519 |
|
520 if(signum == SIGALRM) |
|
521 __client_node_timer_callback_function(client_node_id); |
|
522 else |
|
523 fprintf(stderr, "Modbus plugin: spurious wakeup of timer thread for Modbus client %%s.\n", client_nodes[client_node_id].location); |
|
524 |
521 } |
525 } |
522 |
526 |
523 // timer was created, so we try to destroy it! |
527 // timer was created, so we try to destroy it! |
524 int res = timer_delete(client_nodes[client_node_id].timer_id); |
528 int res = timer_delete(client_nodes[client_node_id].timer_id); |
525 if (res < 0) |
529 if (res < 0) |
789 |
793 |
790 close = 0; |
794 close = 0; |
791 if (client_nodes[index].init_state >= 4) { |
795 if (client_nodes[index].init_state >= 4) { |
792 stop_mb_client_timer_thread = 1; |
796 stop_mb_client_timer_thread = 1; |
793 pthread_kill(client_nodes[index].timer_thread_id, SIGALRM); |
797 pthread_kill(client_nodes[index].timer_thread_id, SIGALRM); |
794 // thread was launched, so we try to cancel it! |
|
795 close = pthread_cancel(client_nodes[index].timer_thread_id); |
|
796 close |= pthread_join (client_nodes[index].timer_thread_id, NULL); |
798 close |= pthread_join (client_nodes[index].timer_thread_id, NULL); |
797 if (close < 0) |
799 if (close < 0) |
798 fprintf(stderr, "Modbus plugin: Error closing timer thread for modbus client node %%s\n", client_nodes[index].location); |
800 fprintf(stderr, "Modbus plugin: Error closing timer thread for modbus client node %%s\n", client_nodes[index].location); |
799 |
801 |
800 } |
802 } |