
/**************************************
	DML_timer.cpp
	
	introduces the timer class, for simplification of timers.
	
	author:  ryan findley
	
	history:
	when	who		what
	-----------------------------------
	5/11/99	ryan	created
	
****************************************/
//#define TEST

//------------------ private includes ------------------
#include "DML_timer.h"
#include <stdio.h>
#include <unistd.h>
#include <sys/psinfo.h>
#include <sys/seginfo.h>

#ifdef TEST
	#include "conio.h"
#endif

//------------------ private definitions ---------------
#define MILLION *1000000L


//------------------ module code -----------------------
//construct a blank timer... 
DML_timer::DML_timer()
{
	id = -1;
	proxyTarget = -1;
	proxyPriority = -1;
}

//copy constructor
DML_timer::DML_timer(const DML_timer &src)
{
	id = src.id;
	proxy = src.proxy;
	proxyTarget = src.proxyTarget;
	timing = src.timing;
	event = src.event;
}

//do all set-up immediately, start timer running
DML_timer::DML_timer(int period_ms, pid_t theProxyTarget)
{
	id = -1;
	proxyTarget = theProxyTarget;
	if(proxyTarget == SELF) proxyTarget = getpid();
	proxyPriority = -1;
	arm();
	setPeriod(period_ms);
}

//one-shot timer
DML_timer::DML_timer(int period_ms, char dummy, pid_t theProxyTarget)
{
    id = -1;
    proxyTarget = theProxyTarget;
    if(proxyTarget == SELF) proxyTarget = getpid();
    proxyPriority = -1;
    arm();
    setPeriod(period_ms);
}

DML_timer::~DML_timer()
{
    if(id != -1)
	timer_delete(id);
}

DML_timer::setPeriod(int period_ms)
{
    timing.it_value.tv_sec = period_ms/1000;
    timing.it_value.tv_nsec = (period_ms % 1000) MILLION;
    timing.it_interval.tv_sec = period_ms/1000;
    timing.it_interval.tv_nsec = (period_ms % 1000) MILLION;
    
    if(id > 0)
	if(timer_settime(id,0,&timing,NULL) == -1)   
	{
            timer_delete(id);
            id = -1;
            printf("error setting timer to proscribed period.\n");
        }
}


DML_timer::timeLeft(struct itimerspec & theTiming)
{
    if(id == -1)
        printf("error: tried to get remaining time on non-existant timer.\n");
    else
        timer_gettime(id,&theTiming);
}       

DML_timer::arm()
{
    if(proxy != -1)
        qnx_proxy_detach(proxy);
    if(id != -1)
        timer_delete(id);
    proxy = qnx_proxy_attach(proxyTarget,0,0,proxyPriority);
    event.sigev_signo = -proxy;
    id = timer_create(CLOCK_REALTIME,&event);
}    
    
DML_timer::stop()
{
    static itimerspec stopTiming;
    stopTiming.it_value.tv_sec = 0;
    stopTiming.it_value.tv_sec = 0;
    timer_settime(id, 0, &stopTiming, NULL);	//disarm the timer
}

DML_timer::restart()
{
    timer_settime(id,0,&timing,NULL);
}

int DML_timer::checkProxyBackup()
{
    static struct _psinfo theInfo;	//big structure: don't let the stack overflow... dynamic mem alloc etc.
	
    if( proxy >= 0 													
		&& qnx_psinfo( PROC_PID, proxy, &theInfo, 0, NULL ) == proxy	
		&& theInfo.pid == proxy )
	    	return( theInfo.un.mproc.count );
	
    //else implied by return statement
    return(PROXY_DNE);
}

DML_timer::clearProxyQueue()
{
	if(proxy > 0)
	{
		arm();
		setPeriod( timing.it_interval.tv_nsec/1000000  +  1000 * timing.it_interval.tv_sec );
	}
	else
		printf("Error: tried to clear proxy queue on a timer without proxy attached!!!!\n");
}




//------------------------- test harness --------------------------
#ifdef TEST

void main( void )
{
	
    DML_timer timer(500);	//2 Hz
	
	int nProxies;
    while( getchar() )
	{
		nProxies = timer.checkProxyBackup();
		printf("proxies backed up: %d\n",nProxies );
		if( nProxies > 10 )
		{
			printf("Clearing proxies.\n");
			timer.clearProxyQueue();
		}
	}
}

#endif
