#ifndef __KERNEL__
#  define __KERNEL__
#endif

#ifndef MODULE
#  define MODULE
#endif

#include	<linux/sched.h>
#include	<linux/fs.h>	 							/* everything... */
#include	<linux/errno.h>  							/* error codes */
#include	<linux/malloc.h>
#include	<linux/mm.h>
#include	<linux/interrupt.h>
#include	<linux/tqueue.h>
#include	<linux/malloc.h>


#ifndef		TRUE
#define		FALSE		0
#define		TRUE		(!FALSE)
#endif

#define		SUCCESS		0

typedef	unsigned char	byte;
typedef			char	*String;


#include	<linux/delay.h>
#include	<rtl.h>
#include 	<rtl_sched.h>
#include	<rtl_time.h>

#include	<raft/sys/device-raft.h>
#include	<raft/sys/device-ptt.h>


/********************************************************
*	Local data
********************************************************/
static	pthread_t		threadPhase1		= NULL;
static	pthread_t		threadPhase2		= NULL;

/********************************************************
*	These are the prototypes for the local functions	*
********************************************************/
extern		void	*pttKThread1( void  *dumdum );
extern		void	*pttKThread2( void  *dumber );

/********************************************************
*********************************************************
*														*
*	Function to initialize a periodic thread.  When		*
*	a module has more than one to create, it's neater	*
*	to have all of the error-checking logic in one		*
*	compact place instead of littering the landscape	*
*														*
*	ENTRY												*
*		see below										*
*														*
*	RETURN												*
*		usual *NIX status codes							*
*														*
*********************************************************
********************************************************/
int		InitializePeriodicThread( pthread_attr_t *pthreadAttribute	// pointer to thread's attribute
								, pthread_t *ppthread 				// pointer to thread's pointer
								, long long StartTime 				// time to start (use gethrtime())
								, long long Period 					// time between (ns)
								, void  * (*Function)(void*) 		// function to do
								, void *arg 						// and its arg
								, int Priority )					// and priority
{
				int		status;
struct	sched_param		schedparam;

	status = pthread_create( ppthread , pthreadAttribute , Function , arg );
	if( status )
		{
		printk( KERN_ERR "ptt init: Failed pthread_create, status %d\n" , status );
		return( status );
		}
	status = pthread_make_periodic_np( *ppthread , StartTime , Period );
	if( status )
		{
		printk( KERN_ERR "ptt init: Failed pthread_make_periodic, status %d\n" , status );
		pthread_delete_np( threadPhase1 );
		return( status );
		}
	schedparam.sched_priority = Priority;
	status = pthread_setschedparam( *ppthread , SCHED_FIFO , &schedparam );
	if( status )
		{
		printk( KERN_ERR "ptt init: Failed pthread_setschedparam, status %d\n" , status );
		pthread_delete_np( threadPhase1 );
		return( status );
		}
	return( SUCCESS );
}

/********************************************************
*********************************************************
*														*
*	this function does thread-cleanup when the module	*
*	is ready to terminate								*
*														*
*	ENTRY												*
*		int		pttTerminate()							*
*														*
*	RETURN												*
*		standard *NIX status codes						*
*														*
*********************************************************
********************************************************/
int		pttTerminate()
{
	int		status1 = 0 , status2 = 0;
	if( threadPhase1 )
		{
		printk( KERN_INFO "ptt term: deleting thread 1\n" );
		status1 = pthread_delete_np( threadPhase1 );
		if( status1 )
			printk( KERN_ERR "ptt term: unable to delete thread 1 (%d)\n" , status1 );
		}
	else
		{
		printk( KERN_INFO "ptt term: deleted thread 1\n" );
		}		
	threadPhase1 = NULL;

	if( threadPhase2 )
		{
		printk( KERN_INFO "ptt term: deleting thread 2\n" );
		status2 = pthread_delete_np( threadPhase2 );
		if( status2 )
			printk( KERN_ERR "ptt term: unable to delete thread 2 (%d)\n" , status2 );
		}
	else
		{
		printk( KERN_INFO "ptt term: deleted thread 1\n" );
		}		
	threadPhase2 = NULL;	

	return( status1 | status2 );
}

/********************************************************
*********************************************************
*														*
*	
*														*
*********************************************************
********************************************************/
int pttInitialize( void )
{
				int		status;
	pthread_attr_t		threadAttribute;
	hrtime_t			Now = gethrtime();

	status = pthread_attr_init( &threadAttribute );
	if( status )
		{
		printk( KERN_ERR "ptt init: Failed pthread_attr_init, status %d\n" , status );
		return( status );
		}
	status = pthread_attr_setfp_np( &threadAttribute , 1 );
	if( status )
		{
		printk( KERN_ERR "ptt init: Failed pthread_attr_setfp, status %d\n" , status );
		return( status );
		}
	status = InitializePeriodicThread(     &threadAttribute			// thread attrib
										,  &threadPhase1			// thread address
										,  Now + 1 * NSECS_PER_SEC	// starting
										,  1 * NSECS_PER_SEC		// period
										,  pttKThread1				// function
										,  (void*)1					// argument
										,  1						// priority
										);
	if( status )
		{
		printk( KERN_ERR "ptt bit: Failed to initialize thread\n" );
		return( status );
		}
	status = InitializePeriodicThread(     &threadAttribute			// thread attrib
										,  &threadPhase2			// thread address
										,  Now + 1 * NSECS_PER_SEC	
												+ NSECS_PER_SEC / 2	// starting
										,  NSECS_PER_SEC + 
											NSECS_PER_SEC/10		// period
										,  pttKThread2				// function
										,  (void*)1					// argument
										,  1						// priority
										);
	if( status )
		{
		printk( KERN_ERR "ptt bit: Failed to initialize thread\n" );
		return( status );
		}
	printk( KERN_INFO  "ptt bit: Passed BIT\n" );
	return( SUCCESS );
}

/********************************************************
*********************************************************
*														*
*	These are the thread functions						*
*														*
*	ENTRY												*
*		once via rt-kernel and then the function stays	*
*		in an infinite loop using pthread_wait_np()		*
*		after it has finished each cycle				*
*														*
*	RETURN												*
*		these don't but others might; this is equivalent*
*		to calling thread_exit()						*
*														*
*********************************************************
********************************************************/
void	*pttKThread1( void *dumdum )
{
static	int		pttKounter = 0;

	rtl_printf( KERN_INFO "pttK1 entry\n" );
	while( 1 )
		{
		pthread_wait_np();
		rtl_printf( KERN_INFO "pttK1 execution# # %d\n" , ++pttKounter );
		}
	return( NULL );
}


void	*pttKThread2( void  *dumber )
{
static	int		pttKounter = 0;

	rtl_printf( KERN_INFO "pttK2 entry\n" );
	while( 1 )
		{
		pthread_wait_np();
		rtl_printf( KERN_INFO "pttK2 --- execution# # %d\n" , ++pttKounter );
		}
	return( NULL );

}



