/*
 *  FILE: timerstuff.c
 *  Support routines for dealing with timerequests and additional timer support.
 *
 *  Public Domain, but keep my name in it as the original author.
 *  31-Oct-88	Jan Sven Trabandt   split from timer.c
 */


#define I_AM_TIMERSTUFF
#include "gimmelib/gimmefuncs.h"

extern struct Device *TimerBase;


LONG timeDelay( secs, micros, unit, mytr )
    ULONG		secs, micros;
    ULONG		unit;
    struct timerequest	*mytr;
{
    register struct timerequest *tr;
    LONG    err;

    if( !secs && !micros ) {
	return( 0L );           /* so we don't crash, return right away */
    }
    if( mytr ) {
	tr = mytr;
    } else {
#ifdef GIMME_WIMPY
	if( unit != UNIT_VBLANK && unit != UNIT_MICROHZ ) {
	    return( -1L );
	}
#endif
	if( !secs ) {
	    unit = UNIT_MICROHZ;	    /* force more efficient method */
	}
	if( !(tr = accessTimer(unit, NULL)) ) {
	    return( -1L );
	}
    }
    tr->tr_node.io_Command = TR_ADDREQUEST;
    tr->tr_time.tv_secs = secs;
    tr->tr_time.tv_micro = micros;
    err = DoIO( tr );
    tr->tr_node.io_Message.mn_Node.ln_Type = NT_FREEMSG;
    if( !mytr ) {
	releaseTimer( tr, NULL );
    }
    return( err );
} /* timeDelay */


struct timerequest *timeDelayAsync( secs, micros, unit, tr )
    ULONG   secs, micros;
    ULONG   unit;
    register struct timerequest *tr;
{
    if( !tr ) {
#ifdef GIMME_WIMPY
	if( unit != UNIT_VBLANK && unit != UNIT_MICROHZ ) {
	    return( NULL );
	}
#endif
	if( !secs ) {
	    unit = UNIT_MICROHZ;	    /* force more efficient method */
	}
	if( !(tr = accessTimer(unit, NULL)) ) {
	    return( NULL );
	}
    }
    if( !secs && !micros ) {
	micros = 1L;			/* so we don't crash on zero-delay */
    }
    tr->tr_node.io_Command = TR_ADDREQUEST;
    tr->tr_time.tv_secs = secs;
    tr->tr_time.tv_micro = micros;
    SendIO( tr );
    return( tr );
} /* timeDelayAsync */


LONG waitTimer( tr )
    struct timerequest	*tr;
{
    LONG    err = 0L;

#ifdef GIMME_WIMPY
    if( !tr ) {
	return( err );
    }
#endif
    err = WaitIO( tr );
    tr->tr_node.io_Message.mn_Node.ln_Type = NT_FREEMSG;
    return( err );
} /* waitTimer */


LONG killTimeDelay( tr )
    register struct timerequest *tr;
{
    LONG    err;

#ifdef GIMME_WIMPY
    if( !tr ) {
	return( 0L );
    }
#endif
    Forbid();
    if( tr->tr_node.io_Message.mn_Node.ln_Type == NT_MESSAGE ) {
	if( err = AbortIO(tr) ) {
	    Permit();
	    return( err );
	}
	Remove( tr );
	tr->tr_node.io_Message.mn_Node.ln_Type = NT_FREEMSG;
    }
    Permit();
    return( 0L );
} /* killTimeDelay */


short getSysTime( secs, micros, mytr )
    ULONG		*secs, *micros;
    struct timerequest	*mytr;
{
    register struct timerequest *tr;

    if( mytr ) {
	tr = mytr;
    } else {
	if( !(tr = accessTimer(UNIT_MICROHZ, NULL)) ) {
	    return( -1 );
	}
    }
    tr->tr_node.io_Command = TR_GETSYSTIME;
    DoIO( tr );
    tr->tr_node.io_Message.mn_Node.ln_Type = NT_FREEMSG;
    if( secs ) {
	*secs = tr->tr_time.tv_secs;
    }
    if( micros ) {
	*micros = tr->tr_time.tv_micro;
    }
    if( !mytr ) {
	releaseTimer( tr, NULL );
    }
    return( 0 );
} /* getSysTime */


short setSysTime( secs, micros, mytr )
    ULONG		secs, micros;
    struct timerequest	*mytr;
{
    register struct timerequest *tr;

    if( mytr ) {
	tr = mytr;
    } else {
	if( !(tr = accessTimer(UNIT_MICROHZ, NULL)) ) {
	    return( -1 );
	}
    }
    tr->tr_node.io_Command = TR_SETSYSTIME;
    tr->tr_time.tv_secs = secs;
    tr->tr_time.tv_micro = micros;
    DoIO( tr );
    tr->tr_node.io_Message.mn_Node.ln_Type = NT_FREEMSG;
    if( !mytr ) {
	releaseTimer( tr, NULL );
    }
    return( 0 );
} /* setSysTime */
