//
// Compiler Atmel Studio 6.2
//************************************************************************
// Processor: ATMega32
//************************************************************************
// Written by 
// Peter Menges			9 of december 2015
// Paraguay
//
#include <avr/io.h>
#include <avr/interrupt.h>
#include "portdefs.h"


#ifndef F_CPU
#define F_CPU		16000000UL // Equals to 62,5 ns per tick
#endif


#define PRESCALER0      ((1 << CS00) | (1 << CS02))					// CLK/1024
#define PRESCALER1		((1 << CS12)|  (1 << CS10))					// same.
#define PRESCALER2		((1 << CS20) | (1 << CS21) | (1 << CS22))	// same.

volatile uint8_t key_press;				// This hold the key-bits
extern volatile uint8_t disp_data[];	// The data to be displayed

extern volatile uint8_t z_axis[];		// I use an 8-Bit array because of the faster access
extern volatile uint8_t x_axis[];		// Data from the calipers

volatile uint8_t cal_sig;				// signaling new values

volatile uint8_t bitcount_z=0;			//counting incoming bits (port pin values)
volatile uint8_t sample_z=0;			//monitor the input time to reset when not synchronized
volatile uint8_t running_z=0;			//Flag indicating that this input time should be monitored by sample_
volatile uint8_t bitcount_x=0;
volatile uint8_t sample_x=0;
volatile uint8_t running_x=0;
volatile uint8_t error_x=0;				// Incremented by the Timer 1 interrupt to recognize
volatile uint8_t error_z=0;				// a failure of the caliper (disconnected, battery weak, a.s.o)
										// A different reading at the display will be shown if this is the case

/* Multiplex of display */
ISR(TIMER0_COMP_vect)
{

	static int idx=0;
	static int seg=0x10;		// start with the 5th segment (From the left to the right)
	// ISR-Time measured at 4.12.2015 with gcc -O2 option
	// the isr consumes 5 us per segment to complete!
	
	
	OE_UPPER_DIS;
	OE_LOWER_DIS;
	DISP_DATA = 0x00;			// reset all data
	
	if ( idx == DISP_BUF_MAX) // end of buffer reached
			idx = 0;		  // reset idx
				
		if ( idx == 0 || idx == 5) /* Show the signs if any or (to be done: blink the row) */
		DISP_DATA = (disp_data[idx] & 0xf0);
	
		
		DISP_DATA |= seg;		// set the bit of the segment
		CLK_PULS;				// latch it
		DISP_DATA = disp_data[idx];
		if ( idx < 5) {
			OE_UPPER_EN;			// show it
		}else{
			OE_LOWER_EN;
		}
		idx++;	
		seg >>= 1;
		if ( seg == 0)				// start over
				seg = 0x10;
				
			
}
/* 3 ms interrupt for timeout handling of calipers */

ISR(TIMER1_COMPA_vect)
{
		/* Z-Axis */										
	if(running_z){							// Start monitoring the time consumed by the INT0 ISR						
		if((++sample_z)==5){				//After 15 ms it should be terminated hard
			bitcount_z=0;					//This condition shows that the input could not be completed
			sample_z=0;						// Reset all counters and flags to start with a new input frame

		}
	}
		/* X-Axis */
	if(running_x){
		if((++sample_x)==5){
			bitcount_x=0;
			sample_x=0;

		}
		
	}
	// Monitoring the interface (checking if it is unplugged or not sending data)	
	
	error_x++;
	error_z++;
				if ( error_x > 200){			// Beyond 600 ms, something happens wrong
					cal_sig |= CAL_INVALID_X;
					error_x = 0;
				}
				if ( error_z > 200){
					cal_sig |= CAL_INVALID_Z;		// offline?
					error_z = 0;
				}				
}
/* Thanks to Peter Dannegger, Germany*/
/* This is his coding!*/
ISR(TIMER2_COMP_vect)
{

  static uint8_t key_state=0;		
  static uint8_t ct0=0, ct1=0,i=0; 
  
    
 

 			i = key_state ^ ~(KEY_PIN);   // key changed ?

 			ct0 = ~( ct0 & i );			// reset or count ct0
  			ct1 = (ct0 ^ ct1) & i;	    // reset or count ct1  
  			i &= ct0 & ct1;			    // count until roll over ?
  			key_state ^= i;			    // then toggle debounced state
  
  /*
   * To notify main program of pressed key, the corresponding bit
   * in global variable key_press is set.
   * The main loop needs to clear this bit
   */
  			key_press |= key_state & i;	// 0->1: key press detect

			
}
/* ISR reading the data of the Z-Axis */
ISR(INT0_vect){

	
	if(bitcount_z==0)
		running_z=1;						//Start capturing of the packet frame
				
	
		
	if(bitcount_z < CAL_LENGTH){							
		if (CAL_PORT & CAL_ZPIN)
		z_axis[bitcount_z] = 1;				// Write into buffer of this axis
		else
		z_axis[bitcount_z] = 0;
		

	}
	
	bitcount_z++;
	
	if(bitcount_z == CAL_LENGTH){ 			//24 bits done
		if ( z_axis[CAL_UNIT] == CAL_INCHES)
		cal_sig |= CAL_INCH_Z;				// handled as an error
		else
		cal_sig |= CAL_NEW_Z;
		running_z=0;
		bitcount_z = 0;						
		sample_z=0;							//reset to stop the monitoring by ISR TIMER1
		error_z=0;
		
	}
	
	
}
/* ISR reading the data of the X-Axis */
ISR(INT1_vect){
	
	if(bitcount_x==0)
		running_x=1;						
	
	
	
	if(bitcount_x < CAL_LENGTH){							
		if (CAL_PORT & CAL_XPIN)
		x_axis[bitcount_x] = 1;
		else
		x_axis[bitcount_x] = 0;
		

	}
	
	bitcount_x++;
	
	if(bitcount_x == CAL_LENGTH){ 					
		if ( x_axis[CAL_UNIT] == CAL_INCHES)
		cal_sig |= CAL_INCH_X;				// handled as an error
		else
		cal_sig |= CAL_NEW_X;
		running_x=0;
		bitcount_x = 0;								
		sample_x=0;							
		error_x = 0;
		
	}
		
	
}
void Init_Timer(void)
{
	
	/* Init all timers */
	

	TIMSK  |= (1 << OCIE0)| (1 << OCIE1A) | ( 1 << OCIE2);	// OCIE0 and
															// OCIE1A int
															// OCIE2 int
	// Timer 0 is used to multiplex the display
	TCCR0 |= PRESCALER0| (1 << WGM01);						// Prescaler and CTC Mode WGM01
	TCNT0  = 0;
	OCR0 = 30;												// 30 => 2 ms per segment
	
	// Timer 1 for the timing of the calipers (central clocking)
	TCCR1B = PRESCALER1 | (1 << WGM12);					// Prescaler 1024 and CTC Mode
	TCNT1 = 0; 											// Set to zero
	OCR1A = CAL_TIMER1_VAL; 							// set to 3 ms

	// Timer2 is used to debounce the keys
	TCCR2 |= PRESCALER2 | (1 << WGM21);					// Prescaler 1024 and CTC Mode
	TCNT2 = 0;
	OCR2 = 255;											// 16 ms

	// INT1 and INT0 rising edge triggered (the interface to the calipers) 21.12.2015 (! changed from falling)
	MCUCR |= (1 << ISC11) | (1 << ISC01 ) | ( 1 << ISC10) | ( 1 << ISC00);
	
	GICR |= ( 1 << INT0 ) | ( 1 << INT1 );				//enable
	

	sei();												// Let ball roll...
}
