modbus/mb_runtime.c
changeset 2683 5d8a4deacfe1
parent 2665 978cf239c689
child 2684 da8de4ef0449
equal deleted inserted replaced
2682:4d3320fdab19 2683:5d8a4deacfe1
    23  */
    23  */
    24 
    24 
    25 
    25 
    26 #include <stdio.h>
    26 #include <stdio.h>
    27 #include <string.h>  /* required for memcpy() */
    27 #include <string.h>  /* required for memcpy() */
       
    28 #include <errno.h>
    28 #include <time.h>
    29 #include <time.h>
    29 #include <signal.h>
    30 #include <signal.h>
    30 #include "mb_slave_and_master.h"
    31 #include "mb_slave_and_master.h"
    31 #include "MB_%(locstr)s.h"
    32 #include "MB_%(locstr)s.h"
    32 
    33 
   468  * condition variable.
   469  * condition variable.
   469  * 
   470  * 
   470  * The same callback function is called by the timers of all client nodes. The id of the client node
   471  * The same callback function is called by the timers of all client nodes. The id of the client node
   471  * in question will be passed as a parameter to the call back function.
   472  * in question will be passed as a parameter to the call back function.
   472  */
   473  */
   473 void __client_node_timer_callback_function(union sigval sigev_value) {
   474 void __client_node_timer_callback_function(int client_node_id) {
   474     /* signal the client node's condition variable on which the client node's thread should be waiting... */
   475     /* signal the client node's condition variable on which the client node's thread should be waiting... */
   475     /* Since the communication cycle is run with the mutex locked, we use trylock() instead of lock() */
   476     /* Since the communication cycle is run with the mutex locked, we use trylock() instead of lock() */
   476     //pthread_mutex_lock  (&(client_nodes[sigev_value.sival_int].mutex));
   477     if (pthread_mutex_trylock (&(client_nodes[client_node_id].mutex)) != 0)
   477     if (pthread_mutex_trylock (&(client_nodes[sigev_value.sival_int].mutex)) != 0)
       
   478         /* we never get to signal the thread for activation. But that is OK.
   478         /* we never get to signal the thread for activation. But that is OK.
   479          * If it still in the communication cycle (during which the mutex is kept locked)
   479          * If it still in the communication cycle (during which the mutex is kept locked)
   480          * then that means that the communication cycle is falling behing in the periodic 
   480          * then that means that the communication cycle is falling behing in the periodic 
   481          * communication cycle, and we therefore need to skip a period.
   481          * communication cycle, and we therefore need to skip a period.
   482          */
   482          */
   483         return;
   483         return;
   484     client_nodes[sigev_value.sival_int].execute_req  = 1; // tell the thread to execute
   484     client_nodes[client_node_id].execute_req  = 1; // tell the thread to execute
   485     client_nodes[sigev_value.sival_int].periodic_act = 1; // tell the thread the activation was done by periodic timer   
   485     client_nodes[client_node_id].periodic_act = 1; // tell the thread the activation was done by periodic timer   
   486     pthread_cond_signal (&(client_nodes[sigev_value.sival_int].condv));
   486     pthread_cond_signal (&(client_nodes[client_node_id].condv));
   487     pthread_mutex_unlock(&(client_nodes[sigev_value.sival_int].mutex));
   487     pthread_mutex_unlock(&(client_nodes[client_node_id].mutex));
   488 }
   488 }
   489 
   489 
       
   490 
       
   491 
       
   492 static int stop_mb_client_timer_thread;
       
   493 static void *__mb_client_timer_thread(void *_index) {
       
   494     sigset_t set;
       
   495     int signum = SIGALRM;
       
   496 	int client_node_id = (char *)_index - (char *)NULL; // Use pointer arithmetic (more portable than cast)
       
   497     printf("%%d\n", client_node_id);
       
   498     /* initialize the timer that will be used to periodically activate the client node */
       
   499     {
       
   500         // start off by reseting the flag that will be set whenever the timer expires
       
   501         client_nodes[client_node_id].periodic_act = 0;
       
   502 
       
   503         struct sigevent evp = {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);
       
   510             return NULL;
       
   511         }
       
   512     }
       
   513 
       
   514     stop_mb_client_timer_thread = 0;
       
   515     while(!stop_mb_client_timer_thread) {
       
   516         if(sigwait (&set, &signum) == -1)
       
   517             perror ("sigwait");
       
   518         if(stop_mb_client_timer_thread)
       
   519             break;
       
   520         __client_node_timer_callback_function(client_node_id);
       
   521     }
       
   522 
       
   523     // timer was created, so we try to destroy it!
       
   524     int res = timer_delete(client_nodes[client_node_id].timer_id);
       
   525     if (res < 0)
       
   526         fprintf(stderr, "Modbus plugin: Error destroying timer for modbus client node %%s\n", client_nodes[client_node_id].location);
       
   527 
       
   528     return NULL;
       
   529 }
   490 
   530 
   491 
   531 
   492 int __cleanup_%(locstr)s ();
   532 int __cleanup_%(locstr)s ();
   493 int __init_%(locstr)s (int argc, char **argv){
   533 int __init_%(locstr)s (int argc, char **argv){
   494 	int index;
   534 	int index;
   579 			goto error_exit;                
   619 			goto error_exit;                
   580         }
   620         }
   581         client_nodes[index].execute_req = 0; //variable associated with condition variable
   621         client_nodes[index].execute_req = 0; //variable associated with condition variable
   582 		client_nodes[index].init_state = 3; // we have created the condition variable
   622 		client_nodes[index].init_state = 3; // we have created the condition variable
   583 		
   623 		
   584 		/* initialize the timer that will be used to periodically activate the client node */
   624 		/* launch a thread to handle this client node timer */
   585         {
   625 		{
   586             // start off by reseting the flag that will be set whenever the timer expires
   626 			int res = 0;
   587             client_nodes[index].periodic_act = 0;
   627 			pthread_attr_t attr;
   588 
   628 			res |= pthread_attr_init(&attr);
   589             struct sigevent evp;
   629 			res |= pthread_create(&(client_nodes[index].timer_thread_id), &attr, &__mb_client_timer_thread, (void *)((char *)NULL + index));
   590             evp.sigev_notify            = SIGEV_THREAD; /* Notification method - call a function in a new thread context */
   630 			if (res !=  0) {
   591             evp.sigev_value.sival_int   = index;        /* Data passed to function upon notification - used to indentify which client node to activate */
   631 				fprintf(stderr, "Modbus plugin: Error starting timer thread for modbus client node %%s\n", client_nodes[index].location);
   592             evp.sigev_notify_function   = __client_node_timer_callback_function; /* function to call upon timer expiration */
   632 				goto error_exit;
   593             evp.sigev_notify_attributes = NULL;         /* attributes for new thread in which sigev_notify_function will be called/executed */
   633 			}
   594             
   634 		}
   595             if (timer_create(CLOCK_MONOTONIC, &evp, &(client_nodes[index].timer_id)) < 0) {
       
   596                 fprintf(stderr, "Modbus plugin: Error creating timer for modbus client node %%s\n", client_nodes[index].location);
       
   597                 goto error_exit;                
       
   598             }
       
   599         }
       
   600         client_nodes[index].init_state = 4; // we have created the timer
   635         client_nodes[index].init_state = 4; // we have created the timer
   601 
   636 
   602 		/* launch a thread to handle this client node */
   637 		/* launch a thread to handle this client node */
   603 		{
   638 		{
   604 			int res = 0;
   639 			int res = 0;
   752 		}
   787 		}
   753 		res |= close;
   788 		res |= close;
   754 
   789 
   755 		close = 0;
   790 		close = 0;
   756 		if (client_nodes[index].init_state >= 4) {
   791 		if (client_nodes[index].init_state >= 4) {
   757 			// timer was created, so we try to destroy it!
   792             stop_mb_client_timer_thread = 1;
   758 			close  = timer_delete(client_nodes[index].timer_id);
   793             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);
   759 			if (close < 0)
   797 			if (close < 0)
   760 				fprintf(stderr, "Modbus plugin: Error destroying timer for modbus client node %%s\n", client_nodes[index].location);
   798 				fprintf(stderr, "Modbus plugin: Error closing timer thread for modbus client node %%s\n", client_nodes[index].location);
       
   799 
   761 		}
   800 		}
   762 		res |= close;
   801 		res |= close;
   763 
   802 
   764 		close = 0;
   803 		close = 0;
   765 		if (client_nodes[index].init_state >= 3) {
   804 		if (client_nodes[index].init_state >= 3) {