#define _TIME_C

#include <irq.h>
#include "setup.h"
#include "sync.h"
#include "detector.h"
#include "time.h"
#include "ladc.h"

unsigned long mls;
unsigned long iter;
unsigned char rest_flag = 1;
unsigned char reset_flag = 0;
unsigned short int rest_counting_duration;
unsigned short int counting_duration;

unsigned short int sync_flag = 0;


static void TIMEirq() __irq;

void TIMERsetup() {
/*
    T0TCR:
	0:	Enable Counter
	1:	Reset Counter (should be set to 0 after certain delay)

    T0PR:
		Maximum value for Prescale Counter. Timer value will increment 
		on every (T0PR+1) cycles of Pclk. 32bit
    T0MR[1-4]:
		Match register, something happens when counter reaches 
		the specified value.
    T0MCR:
	0:	Interrupt on MR0
	1:	Reset counter on MR0
	2:	Stop counter on MR0
	3-5:	... MR1
	6-8:	... MR2
	9-11:	... MR3
*/


    T0PR = Fpclk / 1000000 - 1;	/* 1 */
    T0MR0 = 999;		/* Fpclk / 1000 */
    T0MCR = 3;
    T0TCR = 1;


    install_irq(TIMER0_INT, (void*)TIMEirq);

/*    
    VICVectAddr0 = (unsigned long)tc0;          // set interrupt vector in 0
    VICVectCntl0 = 0x20 | 4;                    // use it for Timer 0 Interrupt
    VICIntEnable = 0x00000010;                  // Enable Timer0 Interrupt
*/
}

static void TIMEirq () {
  if (--mls==0) {
    if (rest_flag) {
	mls=counting_duration;
	DETECTORswitch();
	if (insync) {
	    if (!(++iter)) iter = 2;
	    buffer1_new_iteration = buffer1_end + 1;	/* Check buffer1_start = buffer1_end overflow Event case */
	}
	rest_flag = 0;
    } else {
	if (sync) {
	    if (sync>0) {
		if (sync>sync_step) {
		    mls = rest_counting_duration - sync_step;
		    sync_flag = -sync_step;
	    	    sync -= sync_step;
		} else {
		    mls = rest_counting_duration - sync;
		    sync_flag = -sync;
	    	    sync = 0;
		}
	    } else {
		if ((-sync)>sync_step) {
		    mls = rest_counting_duration + sync_step;
		    sync_flag = sync_step;
		    sync += sync_step;
		} else {
		    mls = rest_counting_duration + sync;
		    sync_flag = sync;
		    sync = 0;
		}
	    }
	} else {
	    mls = rest_counting_duration;
	    sync_flag = 0;
	}
	rest_flag = 1;
	reset_flag = 1;
    }
  }

    T0IR        = 1;		// Clear interrupt flag
    VICVectAddr = 0;		// Acknowledge Interrupt
}

void TIMEsetup() {
	// Iteration
    iter = 0;

	// Time
    mls = DEFAULT_COUNTING_DURATION;
    rest_flag = 1;
    rest_counting_duration = DEFAULT_COUNTING_DURATION / COUNTING_DIVIDER;
    counting_duration = DEFAULT_COUNTING_DURATION - rest_counting_duration;

	// Synchronization
    sync_flag = 0;

    TIMERsetup();

}

void TIMEduration(int ms) {
    counting_duration = ms;
    rest_counting_duration = counting_duration / COUNTING_DIVIDER;
    SYNCduration(counting_duration, rest_counting_duration);
    counting_duration -= rest_counting_duration;
}

void TIMEdelay(unsigned long us) {
    unsigned long offset;

    while (us > 100) {
	TIMEdelay(100);
	us -= 100;
    }
	    
    offset = T0TC;

    if ((offset+us)>999) {
	while (T0TC > offset) ;	
	offset -= 1000 - us;
    } else offset += us;
    while (T0TC < offset) ;
}
