/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    FILE NAME: 				test_case_heartbeat.c

    AUTHOR:  					K Vardin
    DATE:      			    02/10/09
    REV:     							1.00 - Initial Release

    DESCRIPTION:    Test Case: Heart Beat
    												 VM replies with the status information

    INCLUDE FILES:  ../_common/ipc.h include/test_includes.h

		MAKE INFO:				

		$Id: test_case_heartbeat.c,v 1.3 2009/05/07 15:42:16 softeng Exp $

 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
 #include		"test_includes.h"  
 #include		"ipc.h"

#define			QUERY_VM_TIME				(100000000)
#define			QUERY_VM_TIMEOUT	((QUERY_VM_TIME)/(4))	
#define			VM_HEART_BEAT_PULSE		_PULSE_CODE_MINAVAIL
 
 	/* Local Variables */
static		int		fd_vm = -1;
static		int		counter = 0;
		 
 	/* Global Variables */
 	
	/* External Variables */

	/* Local Prototypes */
static		int				query_vm( vm_cmnd_t	*);
	
	/* Global Prototypes */
int		test_case_heartbeat( vm_cmnd_t	*);	
void	*heart_beat_thread( void *);

	/* External Prototypes */
extern		void		print_status( int, vm_cmnd_t		*);

/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  FUNCTION NAME:  test_case_heartbeat()

  DESCRIPTION:      	Test Case: Heart Beating Functionality
  
  ARGUMENT LIST:   vm_cmnd_t		*
   
  RETURN:               int,
  														SUCC / FAIL

  GLOBALS USED:   

  ALGORITHMS:   

  ALSE:     

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ 
 int		test_case_heartbeat( vm_cmnd_t		*cmnd )
 	{int fd;
 		int error = SUCC;
 		int		i, count;
 	
 		fd = open( CAMERA_PROC_DNAME, O_RDWR );
 		if( fd < 0 )
 			return( FAIL );
 			
 		count = cmnd->camera_id;
 		for( i = 0; i < count; i++ )
 			{ 		
		 		error = devctl( fd, cmnd->id, cmnd, sizeof( vm_cmnd_t ), NULL );	
				if( error != EOK )
					break;
	 			print_status( i, cmnd );
	 			delay( 100 );
		 	}
 		
 		close( fd );
 		
 		return( error == EOK ? SUCC : FAIL );
 	}
 
 
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  FUNCTION NAME:  heart_beat_thread()

  DESCRIPTION:       HEART_BEAT Thread for VM Query

  ARGUMENT LIST:   void *

  RETURN:               void *

  GLOBALS USED:   

  ALGORITHMS:   

  ALSE:           

 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
void	*heart_beat_thread( void *in )
	{pthread_t		thread_id;
		struct	sigevent	event;
		int				chid;
		int				rcvid;
		timer_t	timer_id;
		struct	_itimer itime;
		struct	_pulse	 pulse;
		vm_cmnd_t	*vm_cmnd;
		
		thread_id = pthread_self();
//		pthread_detach( thread_id );							// For the test case let it be joinable
	
		vm_cmnd = ( vm_cmnd_t		* )in;
		
		chid = ChannelCreate( 0 );
		event.sigev_notify 		= SIGEV_PULSE;
		event.sigev_coid 			= ConnectAttach( 0,0,chid, _NTO_SIDE_CHANNEL, 0 ); 		
		event.sigev_priority	=	-1;
		event.sigev_code			=	VM_HEART_BEAT_PULSE;
		
		timer_id = TimerCreate( CLOCK_REALTIME, &event );
		itime.nsec = 1;
		itime.interval_nsec = QUERY_VM_TIME;
		TimerSettime( timer_id, 0, &itime, NULL );

 		fd_vm = open( CAMERA_PROC_DNAME_NET, O_RDWR );
 				
		while( 1 )
			{
				rcvid = MsgReceivePulse( chid, &pulse, sizeof(pulse), NULL);				
				switch( pulse.code )
					{
						case	VM_HEART_BEAT_PULSE:
							if(SUCC != query_vm( vm_cmnd ))
								{
									printf("VM not responding\n");
									pthread_exit( NULL );
								}
								
							if( counter > vm_cmnd->camera_id )
								pthread_exit( NULL );
								
								break;
						default:
							break;
					}/* switch */
			}/* while 1*/
		
	}/* heart beat thread */
	

/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  FUNCTION NAME:  query_vm()

  DESCRIPTION:       VM Query with timeout

  ARGUMENT LIST:   void *

  RETURN:               int,
  														SUCC / FAIL

  GLOBALS USED:   

  ALGORITHMS:   

  ALSE:           

 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
static		int				query_vm( vm_cmnd_t	*vm_cmnd)
	{int											ipc_err;
		uint64_t							ipc_timeout = QUERY_VM_TIMEOUT;
		struct	sigevent	event;
	
	
		if( fd_vm < 0 )
			return( FAIL );

		/* Time Out devctl, as it will block in case of LAN disconnected */
		SIGEV_UNBLOCK_INIT(&event);
		TimerTimeout( CLOCK_REALTIME, 
													_NTO_TIMEOUT_SEND | \
													_NTO_TIMEOUT_REPLY,
													&event,
													&ipc_timeout,
													NULL
		 );

	  ipc_err = devctl(fd_vm, vm_cmnd->id, vm_cmnd, sizeof( vm_cmnd_t ), NULL);

		// VM is not responding
	  if (ipc_err != EOK)	
	  	return( FAIL ); 

		// Here we have the report from VM
		print_status( counter++, vm_cmnd );
		
		return( SUCC );
	}