// ***********************************************************
// Project: AVR time interval counter 4 - assigns 64 bit time stamp to event --> send to host via serial port
// Author: Dr Simon Schroedle
// Started: 3/19/2016
// ***********************************************************

#include <avr\io.h>              // Most basic include files
#include <avr\interrupt.h>       // Add the necessary ones
#include <avr\signal.h>          // here


#define F_CPU 10000000UL  // 10 MHz


#define BAUD     38400UL
#define UBRR_BAUD   ((F_CPU/(16UL*BAUD))-1)
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))    
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD) 

#if ((BAUD_ERROR<980) || (BAUD_ERROR>1020))
  #error Deviation of actual vs target baud rate exceeds 2% - not good
#endif



void wait_10k(void) {  /*wait 10 k cycles*/
uint16_t counter;

  counter=10000;
  do {
  } while (--counter);
}


// USART initialisieren
void uart_init(void)
{
    // Baudrate einstellen (Normaler Modus)
    UBRRH = (uint8_t) (UBRR_BAUD>>8);
    UBRRL = (uint8_t) (UBRR_BAUD & 0x0ff);

    // Aktivieren von transmitter
    UCSRB |= (1<<TXEN);

    // Einstellen des Datenformats: 8 Datenbits, 1 Stoppbit
    UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
}

uint8_t ticdata[12];
uint8_t last_send;

uint64_t timestamp_last;

uint64_t otof, tof; //global timer overflow counter; async update to avoid double interrrupt
                    //(need to capture any external int1 events,
                    //    even if timer is overflowing at same time --> can't use timer overflow int)


void usend(void) {
uint8_t i;
    for (i=0;i<12;i++) {
        while ( !( UCSRA & (1<<UDRE)) )
            ;
        UDR = ticdata[i];
        last_send=1; //data has been transmitted
    }
}


uint16_t timer_c, timer_c_adj; //captured timestamp data
uint8_t tof_upd_c, tof_upd,tofupd2; //overflow update
uint64_t tof_c;

uint8_t missed_ts; //missed ts
	

// Interrupt handler example for INT1
//
SIGNAL(SIG_INTERRUPT1) {
   timer_c=TCNT1;

   tof_upd_c=tof_upd; //need to capture update flag, because tof occurs at 0x8000 or beyond - asynchronous
                      //if upd is 0 but timer>0x8000, need to increment tof to reflect actual counts
   tof_c=tof; //capture tof data
   if (timer_c&0x8000) {
     if (!tof_upd_c) {tof_c++;}
   }

   if ((tof_upd_c)&&(!tofupd2)) {

      if (otof==tof) {tof_c++;}  //in case that overflow count flag has been set, but actual count not yet occured
   }



   if (timer_c<0x8000) { timer_c_adj=timer_c+0x7fff;}   //need to adjust because tof counts +1 when counter reaches 0x1000
   if (timer_c>=0x8000) { timer_c_adj=timer_c-0x8000;}


   timestamp_last=tof_c;
   timestamp_last<<=16;
   timestamp_last|=timer_c_adj;


   if (last_send) { missed_ts=0;} //need to ensure that missed ts info is actually transmitted, even if many missed events
   if (!last_send) {
      missed_ts=1;
   }
   last_send=0;
}


void send_data(void) {
uint8_t i;
  for (i=0;i<8;i++)  {
    ticdata[8-i]=(timestamp_last>>(i<<3))&0xff;
  }
  ticdata[0]='T';
  ticdata[9]=0; //reserved for checksum
  ticdata[10]=0x80|missed_ts; //status code 0x80 - OK; 0x81 -missed last ts transmit (too many events)
  ticdata[11]='E'; //END OF TRANSMIT

  usend(); //sets last_send
}

void send_timerv(void) {

uint16_t t_tmp;

   t_tmp=TCNT1;

   while ( !( UCSRA & (1<<UDRE)) )
            ;
        UDR = 0;
   while ( !( UCSRA & (1<<UDRE)) )
            ;
        UDR = (t_tmp>>8)&0xff;
   while ( !( UCSRA & (1<<UDRE)) )
            ;
        UDR = (t_tmp)&0xff;
}

// ***********************************************************
// Main program
//
int main(void) {

uint8_t timer_t;


   uart_init();

   last_send=1; //no last transmission

   tof=0;

   timestamp_last=0x1020304050607080;

  // set up timer with prescaler = 1
   TCCR1B |= (1 << CS10);

   // set up timer with prescaler = 8
   // TCCR1B |= (1 << CS11);


    // initialize counter
    TCNT1 = 0;
    tof=0;
    tof_upd=0;
    tofupd2=0;

   GICR = 1<<INT1;					// Enable INT1
	MCUCR = 1<<ISC11 | 1<<ISC10;	// Trigger INT1 on rising edge

    // enable global interrupts
   sei();

   DDRC=0xff;



   while(1) {


     timer_t=TCNT1>>15; //highest bit value

     if (!timer_t){ tof_upd=0; PORTC=0x00;}

     if ((timer_t)&&(!tof_upd)) {
          tofupd2=0; //after execution: tofupd2=0, tof_upd=0   --> need to increment tof
          otof=tof;
          tof_upd=1; //tofupd2=0, tof_upd=1   --> need to increment tof only if otof=tof
          tof++;     //tofupd2=0, tof_upd=1   --> tof incremented, otof!=tof
          tofupd2=1; //tofupd2=1, tof_upd=1   --> tof incremented
           //what if interrupt happens in between flag update and actual count? - this will eliminate such error
           //send_timerv();
          PORTC=0x02;

         if (!last_send){ //transmit last event data, need to send it after overflow otherwise timeout! --for fast clock
           send_data();
        }


     }
       //asyn overflow and set upd to indicate that tof has been incremented
       //need to ensure that asyn update check occurs frequently enough - need to monitor data transfer time
   }
}



