/*
    Cat Tracker
	This is for v12
*/

#include <avr/io.h>
#include "sleep.h"
#include "wdt.h"
#include "interrupt.h"
//#include "rprintf.h"


#define FOSC 8000000// Clock Speed
#define BAUD 9600
#define MYUBRR FOSC/16/BAUD-1


//Define functions
//======================
void ioinit(void);      //Initializes IO
void delay_ms(uint16_t x); //General purpose delay
void delay(void);
void delay_halfbit(uint16_t x);//4800 baud half-bit width
char getc(char port);
void putchr(char x);
void delay_1_4bit(uint16_t x);
short get_GPS(void);
void write_buffer(short bytes);
void read_flash(short page);
void erase(void);
void buffer_to_main(short block);
char status_read(void);

//======================

//Global variables
//=========================
char GPS_buff[80];
char command = 0;
short flash_buff_mark = 0;
short page_mark = 0;
short GPS_buff_mark = 0;
//char data_array[264];

int main (void)
{

	MCUSR = 0;
	WDTCSR = 0x18;//set WDCE and WDE high
	//WDTCSR = 0;//disable the WDT
	WDTCSR = 0;//disable the WDT, data sheet says gotta set WDIE...?
	//PRR = 0x0F;
	//ADCSRA = 0;
	//ADCSRB |= 0x40;
	//DIDR0 = 0;
		
	int j = 0;
	char a;
	//short q;
    //ioinit(); //Setup IO pins and defaults
	
	//ADCSRB = 0x40;
	//ADMUX = 0x87;
	//ACSR = 0x40;
	
	ADCSRB = 0;
	ADMUX = 0;
	ACSR = 0;
	
	DDRA = 0b01001110;//PA6 = out (TX/MOSI), PA0 = SO(local input), PA1 = SI, PA2 = SCK, PA3 = CS
	DDRB = 0b00000100;//PB2 = out (GPS_en)
	
	PORTB = 0b00000100;//turn on GPS
	
	PORTA = 0b11101000;
	//delay_ms(1000);
	PORTA &= 0b10111111;
	//j = getc(0);
	
	while(!(status_read() & 0x80));//check the ready bit
	
	erase();
	
	while(1)
	{
		/*
		putchr('?');
		putchr(10);
		putchr(13);
		a = getc(0);//command
		b = getc(0);//page
		b -= 48;
		//putchr(b+48);
		
		if (a == 'r') read_flash((short)b);
		
		else if (a == 'w')
		{
			a = getc(0);//byte
			write_buffer(a);//write byte to buffer
			buffer_to_main(b);//write buffer to page b
		}
		
		else if (a == 'e') erase();
		
		putchr(10);
		putchr(13);
		putchr('O');
		putchr('K');
		putchr(10);
		putchr(13);
		*/
		
		for (j = 0; j < 20; j++)
		{
			
			a = get_GPS();
			write_buffer(a);
			
			if (flash_buff_mark >= 528) buffer_to_main(page_mark);
			
			if (GPS_buff_mark != 0)
			{
				write_buffer(a - GPS_buff_mark);
			}
			
			
			/*
			j = getc(0);
			read_flash(0);
			putchr('1');
			
			j = getc(0);
			a = get_GPS();
			putchr('2');
			
			j = getc(0);
			write_buffer(a);
			putchr('3');
			
			j = getc(0);
			buffer_to_main(0);
			putchr('4');
			
			j = getc(0);
			read_flash(0);
			putchr('5');
			
			j = getc(0);
			erase();
			putchr('6');
			*/
			
			//j = PINA;
			//if (j & 0b10000000) PORTA |= 0b01000000;
			//else PORTA &= 0b10111111;
			
			//uart_sync();
			//while(j & 0b10000000) j = PINA;
			
			//j = getc(0);
			//putchr(j);
			
			//putchr(65);
			
			//PORTA |= 0b01000000;
			//delay_ms(100);
			//PORTA &= 0b10111111;
			//delay_ms(100);
			
			
			/*
			//8/1/08, works through PA7!!!
			//tested this through RX line, all works
			//=============================================
			//while (j != 'R') j = getc(1);
			a = get_GPS();
			for (j = 0; j < a; j++)
			{
				putchr(GPS_buff[j]);
				//delay_ms(10);
			}
			
			putchr(10);
			//delay_ms(1);
			putchr(13);
			//=============================================
			*/
			
			//j = getc();
			//putchr(j);
			
			/*
			putchr('H');
			delay_ms(1);
			putchr('e');
			delay_ms(1);
			putchr('l');
			delay_ms(1);
			putchr('l');
			delay_ms(1);
			putchr('o');
			delay_ms(1);
			putchr(' ');
			delay_ms(1);
			putchr('W');
			delay_ms(1);
			putchr('o');
			delay_ms(1);
			putchr('r');
			delay_ms(1);
			putchr('l');
			delay_ms(1);
			putchr('d');
			delay_ms(1);
			
			putchr(10);
			delay_ms(1);
			putchr(13);
			delay_ms(1000);
			*/
		}
		
		for (j = 0; j < page_mark; j++)
		{
			read_flash(j);
		}
		
		erase();
	
	}
	
	//PORTB = 0b00000100;//turn on GPS
	//PRR = 0x01;//shut down ADC
	
	
	/*
	//Sleep with WDT reset=====================================================================
	DDRA = 0;
	DDRB = 0;
	//SE should only be written 1 just before sleep
	MCUCR = 0b00010000;//bit 5 is SE, bit 4 is SM1, bit 3 is SM0
	
	WDTCSR = 0x18;//set WDCE and WDE high
	WDTCSR = 0x29;//set WDE and prescale bits
	
	//PRR = 0x0F;//shut down everything...I can't tell a difference whether this is used or not
	MCUCR |= 0b00100000;//set SE
	//sleep_cpu();
	asm volatile ("sleep");
	//=========================================================================================
	*/
	
	
	
	/*
	while(1)
	{
		//wdt_enable(WDTO_500MS);
		
		//PORTA = 0b11100000;
		//delay_ms(1000);
		//PORTA &= 0b10111111;
		
		
		
		//WDTCSR = 0x69;//set WDE and prescale bits, set WDIE
		
		//sleep_enable();
        //sei();
		
		//this is a timed sequence
		//MCUCR |= 0b10000100;//BODS and BODSE set high...
		//MCUCR |= 0b10100000;//set SE and BODS high
		
		MCUCR &= 0b11011111;//clear SE bit
		MCUSR &= 0b11110111;//clear WDRF
		
		WDTCSR = 0x18;//set WDCE and WDE high
		//WDTCSR = 0;//disable the WDT
		WDTCSR = 0x40;//disable the WDT, data sheet says gotta set WDIE...?
		
		//sleep_disable();
		//sei();
		
		//wdt_disable();
		
		delay_ms(1000);
		
	}
	*/
	
	}	
    
}

void ioinit (void)
{
	
    //1 = output, 0 = input
    //DDRB = 0b11111111; //All outputs
    //DDRC = 0b11111111; //All outputs
    //DDRD = 0b11111110; //PORTD (RX on PD0)
	
	//PORTC = 0b00111111;
	
	//DDRB = 0b00000011; //PB0 and PB1 are outs
	//DDRC = 0b00111111; //PC0-PC5 are also outs.  These are the display control lines
	//DDRD = 0b11111100; //PD2-PD8 are also outs.  Ports B and D are the data bus.
	
}

//General short delays
void delay_ms(uint16_t x)
{
  uint8_t y, z;
  for ( ; x > 0 ; x--){
    for ( y = 0 ; y < 90 ; y++){
      for ( z = 0 ; z < 6 ; z++){
        asm volatile ("nop");
      }
    }
  }
}


//4800 baud half-bit width
void delay_halfbit(uint16_t x)
{
  uint8_t y;
  for ( ; x > 0 ; x--){
    for ( y = 0 ; y < 15 ; y++){
      
        asm volatile ("nop");
      
    }
  }
}


//4800 baud quarter-bit width
void delay_1_4bit(uint16_t x)
{
  uint8_t y;
  for ( ; x > 0 ; x--){
    for ( y = 0 ; y < 7 ; y++){
      
        asm volatile ("nop");
      
    }
  }
}


//delay for flash timing
void delay(void)
{
	asm volatile ("nop");
	asm volatile ("nop");
	asm volatile ("nop");
	asm volatile ("nop");
	
}


//port = 0 indicates user input, port = 1 is GPS port
char getc(char port)
{
	char k, l = 0, m = 0;
	
	if (port == 1) port = 0b10000000;// GPS input
	else port = 0b00100000;//user input
	
	k = port;
	while(port & k) k = PINA;//wait for whichever pin to go low
	
	//if (port == 0) while(port0 & 0b00100000) port0 = PINA; //wait for PA5 to go low, user input
	//else if (port == 1) while(port1 & 0b10000000) port1 = PINA; //wait for PA7 to go low, GPS input
	//while(j & 0b00000010) j = PINB; //wait for PB1 to go low, alternate input
	//while((j & 0b00100000)) j = ACSR;
	
	delay_halfbit(1);
	delay_1_4bit(1);
	delay_halfbit(1);
	//delay_halfbit(1);
	//delay_halfbit(1);//this should put us in the middle of the first data bit
	
	for (k = 0; k < 8; k++)
	{
		l >>= 1;
		//delay_halfbit(1);
		
		m = PINA;
		if (port & m) l |= 0b10000000;
		//j = PINB;
		//j = ACSR;
		//if (m & 0b00100000) l |= 0b10000000;//user input
		//if (m & 0b10000000) l |= 0b10000000;//GPS input
		//if (j & 0b00000010) l |= 0b10000000;//alternate input
		//if ((j & 0b00100000)) l |= 0b10000000;
		else l &= 0b01111111;
		
		delay_halfbit(1);
		//if (k == 7) break;
		delay_halfbit(1);
	}
	
	//delay_halfbit(1);//one stop bit
	//delay_halfbit(1);
	
	return l;
}


short get_GPS(void)
{
	short a = 0;
	
	//the array is 80 chars, should be arbitrarily large
	for (a = 0; a < 80; a++)//zero the array
	{
		GPS_buff[a] = 0;
	}
	
	a = 0;
	
	while(1)
	{
		while (a != '$') a = (short)getc(1);//wait for the right sentence
		GPS_buff[0] = (char)a;
		GPS_buff[1] = getc(1);
		GPS_buff[2] = getc(1);
		GPS_buff[3] = getc(1);
		GPS_buff[4] = getc(1);
		GPS_buff[5] = getc(1);
		
		if ((GPS_buff[3] == 'R') & (GPS_buff[5] == 'C'))//looking for RMC
		{
			for (a = 6; a < 80; a++)//get everything up to the line feed
			{
				GPS_buff[a] = getc(1);
				if (GPS_buff[a] == 13)
				{
					GPS_buff[a+1] = 10;
					return a+2;//return the number of bytes
				}
			}
		}
	}
	
}



void putchr(char x)
{
	char k;
	
	PORTA &= 0b10111111;
	delay_halfbit(1);//1 start bit
	delay_halfbit(1);
	//delay_halfbit(1);
	//delay_halfbit(1);
	
	for (k = 0; k < 8; k++)//8 data bits
	{
		if (x & 0b00000001) PORTA |= 0b01000000;
		else PORTA &= 0b10111111;
		x >>= 1;
		delay_halfbit(1);
		delay_halfbit(1);
	}
	
	//PORTA &= 0b10111111;
	//delay_1_4bit(1);
	//delay_halfbit(1);//1 stop bit
	//delay_halfbit(1);
	
	PORTA |= 0b01000000;//set it high again
	delay_halfbit(1);
	delay_halfbit(1);
	
	//extras...
	delay_halfbit(1);
	delay_halfbit(1);
	delay_halfbit(1);
	delay_halfbit(1);
}



void write_buffer(short bytes)
{
    //printf("Writing to buffer...\r\n",0);
    
    char i, j;
	short x;
    
    command = 0x84; //buffer #1
	
	//PORTA = 0b11100000;
	//delay_ms(1000);
	PORTA &= 0b11110111;//CS low//flash_CS = 0;
    delay();
	
    //send write command
    for (i = 0 ; i < 8 ; i++)
    {
        //nop();
        //SI = command.7;
        if (command & 0x80) PORTA |= 0b00000010;//SI high
		else PORTA &= 0b11111101;//SI low
        delay();
        PORTA |= 0b00000100;//SCK hi//SCK = 1;          
        delay();
        PORTA &= 0b11111011;//SCK low//SCK = 0;
    
        command <<= 1;
        
    }
    
    //send 14 "dont care" bits
    PORTA &= 0b11111101;//SI low//SI = 0;
    for (i = 0 ; i < 14 ; i++)
    {
        delay();
        PORTA |= 0b00000100;//SCK hi//SCK = 1;         
    
        delay();
        PORTA &= 0b11111011;//SCK low//SCK = 0;
        
    }
    
    x = flash_buff_mark;
    
	//PORTA &= 0b11111101;//write from zero
	
    for (i = 0 ; i < 10 ; i++)   //send 10 address bits, flash buffer marker
    {
        if (x & 0x200) PORTA |= 0b00000010;//SI high
		else PORTA &= 0b11111101;//SI low
        
        delay();
        PORTA |= 0b00000100;//SCK hi//SCK = 1;          
    
        delay();
        PORTA &= 0b11111011;//SCK low//SCK = 0;
        
        x <<= 1;
        
    }

    //send data out...
       
    for (x = 0; x < bytes; x++)
	//for (x = 0; x < 528; x++)
    {
		j = GPS_buff[GPS_buff_mark];
		           
        for (i = 0 ; i < 8 ; i++)
        {   
            if (j & 0x80) PORTA |= 0b00000010;//SI high
			else PORTA &= 0b11111101;//SI low
            
			delay();
            PORTA |= 0b00000100;//SCK hi//SCK = 1;  
        
            delay();
            PORTA &= 0b11111011;//SCK low//SCK = 0;
			
			j <<= 1;
        }
		
		GPS_buff_mark++;
		flash_buff_mark++;//flash buffer 1
		
		if (flash_buff_mark >= 528)
		{
			PORTA |= 0b00001000;//CS hi//flash_CS = 1;  
			return;
		}
    }
	
	PORTA |= 0b00001000;//CS hi//flash_CS = 1;  
   
    GPS_buff_mark = 0;//zero the marker if we get al the way through
}


void read_flash(short page)
{
    char fl_read, i, temp = 0;
    short z, x;
    
	//putchr((char)(page+48));
    //config_TX_RX(0x1F);  //config to TX 14 bytes

    //for (y = 0; y < bl_count; y++)  //2048 pages, complete device read
    //{
        
	//printf("Block = %d\r\n", y);

	fl_read = 0x52;//was E8

	PORTA &= 0b11110111;//CS low//flash_CS = 0;
	delay();

	//send read command
	for (i = 0 ; i < 8 ; i++)
	{
		//nop();
		//SI = fl_read.7;
		
		if (fl_read & 0x80) PORTA |= 0b00000010;//SI high
		else PORTA &= 0b11111101;//SI low
	
		delay();
		PORTA |= 0b00000100;//SCK hi//SCK = 1;          
		delay();
		PORTA &= 0b11111011;//SCK low//SCK = 0;

		fl_read <<= 1;
	
	}
	
	PORTA &= 0b11111101;//SI low
	
	for (i = 0; i < 2; i++)//2 "don't care" bits
	{
		delay();
		PORTA |= 0b00000100;//SCK hi//SCK = 1;          
		delay();
		PORTA &= 0b11111011;//SCK low//SCK = 0;
	}
	
	//12 page address bits
	for (i = 0 ; i < 12 ; i++)
	{		
		if (page & 0x800) PORTA |= 0b00000010;//SI high
		else PORTA &= 0b11111101;//SI low
	
		delay();
		PORTA |= 0b00000100;//SCK hi//SCK = 1;          
		delay();
		PORTA &= 0b11111011;//SCK low//SCK = 0;

		page <<= 1;
	
	}
	
	PORTA &= 0b11111101;//SI low
	
	//10 address bits (zero) and 33 extra bits to init the read
	for (i = 0; i < 43; i++)//
	{
		delay();
		PORTA |= 0b00000100;//SCK hi//SCK = 1;          
		delay();
		PORTA &= 0b11111011;//SCK low//SCK = 0;
	}
	
	
	//send read address (start at 0) and "dont care" bits
	/*
	for (i = 0 ; i < 57 ; i++)//56 + 1, check AT45DB041 data sheet
	{
		//4 reserved bits, followed by 11 page address bits, then 9 bits for the exact starting byte
		if ((i >= 4) & (i < 15))
		{
			//page address is 11 bits
			if (page & 0x400) PORTA |= 0b00000010;//SI high
			else PORTA &= 0b11111101;//SI low
			page <<= 1;
		}
		
		else PORTA &= 0b11111101;//SI low//SI = 0;
		delay();
		PORTA |= 0b00000100;//SCK hi//SCK = 1;          
		delay();
		PORTA &= 0b11111011;//SCK low//SCK = 0;
	
	
	}
	*/
	
	//read data out...
	delay();
	temp = 0;
	
	for (z = 0; z < 528; z++)//pages are 528 bytes
	{ 
		for (x = 0; x < 8; x++)
		{
			
			temp <<= 1;
	
			PORTA |= 0b00000100;//SCK hi//SCK = 1
			delay();
			
			i = PINA;
			if (i & 0x01) temp += 1;
			
			PORTA &= 0b11111011;//SCK low//SCK = 0;
			delay();
		}
			
		//if (temp == 0) putchr('0');
		//else if (temp == 0xFF) putchr('F');
		putchr(temp);
		
		temp = 0;
		//still gotta do this
		//data_array[z] = temp;
	
		//printf(" %d\r\n",temp);
		
		//putc(temp);
	   

	}
                
            
    
    PORTA |= 0b00001000;//CS hi//flash_CS = 1;  
    
}

//block erase, erases 8 pages at a time
void erase(void)
{
    char i, temp;
	short j;
    
    //for (j = 0; j < 128; j++)//
	for (j = 0; j < 512; j++)//512*8=4096 pages
    {
        command = 0x50;
    
        PORTA &= 0b11110111;//CS low//flash_CS = 0;
		delay();
		
        //
        for (i = 0 ; i < 8 ; i++)
        {
            //nop();
			
			if (command & 0x80) PORTA |= 0b00000010;//SI high
			else PORTA &= 0b11111101;//SI low
			
			delay();
            PORTA |= 0b00000100;//SCK hi//SCK = 1
			
			delay();
            PORTA &= 0b11111011;//SCK low//SCK = 0;
			
			
            command <<= 1;
        
        }
    
        //send block address (start at 0)
        PORTA &= 0b11111101;//SI low,SI = 0;

        for (i = 0 ; i < 2 ; i++)   //These are reserved bits
        {
            delay();
            PORTA |= 0b00000100;//SCK hi//SCK = 1        
    
            delay();
            PORTA &= 0b11111011;//SCK low//SCK = 0;
        
        }
        
        temp = j;
        
        for (i = 0 ; i < 9 ; i++)   //block address
        {
            //nop();
            //SI = temp.6;
			
			if (temp & 0x100) PORTA |= 0b00000010;//SI high
			else PORTA &= 0b11111101;//SI low
			
            delay();
            PORTA |= 0b00000100;//SCK hi//SCK = 1            
    
            delay();
            PORTA &= 0b11111011;//SCK low//SCK = 0;
            temp <<= 1;
        
        }
    
        PORTA &= 0b11111101;//SI = 0;
    
        for (i = 0 ; i < 13 ; i++)  //"don't care" bits
        {
			delay();
            PORTA |= 0b00000100;//SCK hi//SCK = 1              
    
            delay();
            PORTA &= 0b11111011;//SCK low//SCK = 0;
        
        
        }
        
        //nop();
        PORTA |= 0b00001000;//CS hi//flash_CS = 1;     //bolck erases at rising edge of flash_CS
        
        //delay_ms(12);
		while(!(status_read() & 0x80));//check the ready bit
        
    }
	
	flash_buff_mark = 0;
	page_mark = 0;
	GPS_buff_mark = 0;
    
    //printf("Erased...\r\n",0);
    
}



void buffer_to_main(short page)
{
    //printf("Writing buffer to main...",0);
    
    char i;
    
    command = 0x83; //buffer #1, built in erase
    
    PORTA &= 0b11110111;//CS low
    delay();
	
    //send write command
    for (i = 0 ; i < 8 ; i++)
    {
        //nop();
        if (command & 0x80) PORTA |= 0b00000010;//SI high
		else PORTA &= 0b11111101;//SI low
        
        delay();
        PORTA |= 0b00000100;//SCK hi//SCK = 1        
    
        delay();
        PORTA &= 0b11111011;//SCK low//SCK = 0;
    
        command <<= 1;
        
    }
    
    //send 2 reserved bits
    PORTA &= 0b11111101;//SI low
	
    for (i = 0 ; i < 2 ; i++)
    {
        
        delay();
        PORTA |= 0b00000100;//SCK hi//SCK = 1        
    
        delay();
        PORTA &= 0b11111011;//SCK low//SCK = 0;
        
        
    }
    
    for (i = 0 ; i < 12 ; i++)   //send 12 address bits
    {
        
        //SI = block.9;
		
		if (page & 0x800) PORTA |= 0b00000010;//SI high
		else PORTA &= 0b11111101;//SI low
		
        delay();
        PORTA |= 0b00000100;//SCK hi//SCK = 1        
    
        delay();
        PORTA &= 0b11111011;//SCK low//SCK = 0;
        
        page <<= 1;
        
    }
    
    for (i = 0 ; i < 10 ; i++)   //send 10 "dont care" bits
    {
        
        delay();
        PORTA |= 0b00000100;//SCK hi//SCK = 1        
    
        delay();
        PORTA &= 0b11111011;//SCK low//SCK = 0;
        
        
    }
    
    //nop();
    PORTA |= 0b00001000;//CS hi   //buffer is written after this, takes 14mS
	
	flash_buff_mark = 0;//zero the flash buffer marker
	
	page_mark++;
    
    delay_ms(14);
    
}


char status_read(void)
{
	char i, j, temp = 0;
    
    command = 0x57; //
    
    PORTA &= 0b11110111;//CS low
    delay();
	
    //send command
    for (i = 0 ; i < 8 ; i++)
    {
        //nop();
        if (command & 0x80) PORTA |= 0b00000010;//SI high
		else PORTA &= 0b11111101;//SI low
        
        delay();
        PORTA |= 0b00000100;//SCK hi//SCK = 1        
    
        delay();
        PORTA &= 0b11111011;//SCK low//SCK = 0;
    
        command <<= 1;
        
    }
	
	delay();
	PORTA |= 0b00000100;//SCK hi//SCK = 1        

	delay();
	PORTA &= 0b11111011;//SCK low//SCK = 0;
	delay();
	
	for (i = 0; i < 8; i++)
	{
		
		temp <<= 1;

		PORTA |= 0b00000100;//SCK hi//SCK = 1
		
		j = PINA;
		if (j & 0x01) temp += 1;
		
		delay();

		PORTA &= 0b11111011;//SCK low//SCK = 0;
		delay();
	}

	PORTA |= 0b00001000;//CS hi   //
	
	return temp;
}







