/*
    uLog

	This version of the code is what went up in the rocket. It works on the hardware
	that shares the ADC and UART/SPI lines.
*/

#include <avr/io.h>
#include <avr/interrupt.h>

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

#define x_active	5
#define y_active	4
#define z_active	3

#define STAT 0	//PB0


//Define functions
//======================
//void delay_halfbit(uint16_t x);//4800 baud half-bit width
void delay_ms(short x);
//void delay_1_4bit(uint16_t x);
void delay_us(uint8_t x);

void write_buffer(void);
char read_flash(short page);
void erase(void);
void buffer_to_main(short block);
char status_read(void);
void send_command(char command);
void flash_clk(void);

char getc(void);
void putchr(char x);


void menu(void);
void print_num(short num);

//void settings(char byte);
//int get_adc(void);




//======================
//Global variables
//=========================
volatile short nasty[33];
volatile char nasty_write = 0;
volatile char nasty_mark = 0;
volatile char record = 0;
short flash_buff_mark = 0;
short page_mark = 1;
char holdoff = 5;
char active_channels = 0b00111111;
//float freq = 100;
int tmr_cnt;

volatile int x_accel;
volatile int y_accel;
volatile int z_accel;



ISR (TIM1_OVF_vect)
{
	cli();//Disable Interrupts
	
	PORTB ^= (1<<STAT);
	
	int l2;//temp low
	int h2;//temp high

	x_accel = 0;
	y_accel = 0;
	z_accel = 0;
	
	h2 = 0; l2 = 0;

	if (active_channels & (1<<x_active))
	{	
		//x_accel conversion====================================================================
		ADMUX = 0x04;
		ADCSRA = (1 << ADEN)|(1 << ADSC)|(1<<ADPS2)|(1<<ADPS1);
		
		while(ADCSRA & (1 << ADSC));
		l2 = (ADCL & 0xFF);
		h2 = (ADCH & 0x03);
		x_accel = ((h2<<8) | l2);

		h2 = 0; l2 = 0;
	}
	
	
	if (active_channels & (1<<y_active))
	{
		//y_accel conversion===================================================================
		ADMUX = 0x05;
		ADCSRA = (1 << ADEN)|(1 << ADSC)|(1<<ADPS2)|(1<<ADPS1);
		
		while(ADCSRA & (1 << ADSC));
		l2 = (ADCL & 0xFF);
		h2 = (ADCH & 0x03);
		y_accel = ((h2<<8) | l2);
		
		h2 = 0; l2 = 0;
	}
	
	
	if (active_channels & (1<<z_active))
	{
		//z_accel conversion=================================================================
		ADMUX = 0x06;
		ADCSRA = (1 << ADEN)|(1 << ADSC)|(1<<ADPS2)|(1<<ADPS1);
		
		while(ADCSRA & (1 << ADSC));
		l2 = (ADCL & 0xFF);
		h2 = (ADCH & 0x03);
		z_accel = ((h2<<8) | l2);
		
		h2 = 0; l2 = 0;
	}
	
	
	if (record == 1)
	{
		//log the readings to the array...
		nasty[nasty_mark] = x_accel;
		nasty[nasty_mark+1] = y_accel;
		nasty[nasty_mark+2] = z_accel;
		nasty_mark += 3;
		if (nasty_mark >= 33) nasty_write = 1, nasty_mark = 0;
	}
	
	
	ADMUX = 0;
	
	PORTB ^= (1<<STAT);
	
	//TCNT1 = 56250;//100Hz
	TCNT1 = 46965;//50Hz
	
	sei();//Enable Interrupts
}




int main (void)
{
	char a;
	
	flash_buff_mark = 0;
	record = 0;
	
	DIDR0 = 0xFF;//digital input disable all ADC lines
	
	DDRA = 0b00001110;//PA6 = out (TX/MOSI), PA0 = SO(local input), PA1 = SI, PA2 = SCK, PA3 = CS
	PORTB = 0x01;
	DDRB = 0b00000001;//PB0 = stat
	
	//We want to sample to see what's connected,
	//but we don't want to log yet
	//log = 0;
	
	
	 /*
	for (a = 0; a < 5; a++)
	{
		PORTB = 0;
		delay_ms(20);
		PORTB = 0x01;
		delay_ms(50);
	}
	*/
	
	//delay_ms(1000);
	
	//setup timer0
	TCCR0B = 2;//clk/8
	
	//setup timer1
	//TCCR1A = 0;
	TCCR1B = 2;// clk/8
	TIMSK1 = 1;
	TIFR1 |= 0x01;
	TCNT1 = 65536 - 3000;//? 118Hz?
	
	sei();//Enable Interrupts
	
	delay_ms(1000);
	
	cli();//disable ints
	
	PORTB = 0x01;
	
	delay_ms(1000);
	
	//PORTA |= 0x6E;
	//DDRA |= 0x4E;//PA1,2,3,6 are outputs
	//DIDR0 = 0;
	
	//If there's a high-ish voltage on the MISO line,
	//we're likely connected to a serial link
	if (y_accel > 950) 
	{
		DIDR0 = 0;//enable digital inputs
		DDRA |= 0x40;//PA6 is TX
		menu();
	}
	
	//else start logging
	record = 1;
	//DIDR0 = 0xFF;
	//DDRA &= 0xBF;//PA6 as input
	sei();
	
	while(1)
	{
		
		if (nasty_write == 1)
		{
			nasty_write = 0;
			
			write_buffer();
			flash_buff_mark += 66;
			//
			if (flash_buff_mark >= 528)
			{
				
				flash_buff_mark = 0;
				
				buffer_to_main(page_mark);
				page_mark++;
				if (page_mark >= 4096) while(1);
			}
		}
	}
    
}


/*
//4800 baud half-bit width
void delay_halfbit(uint16_t x)
{
	uint8_t y;
	for ( ; x > 0; x--)
	{
		for ( y = 0; y < 18; 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 < 4 ; y++)//was 7
	{
      
        asm volatile ("nop");
      
    }
  }
}
*/

//General short delays, not terribly accurate
void delay_us(uint8_t x)
{
	char y;
	
	TIFR0 |= 0x01;//Clear any interrupt flags on Timer0
	TCNT0 = 256 - x; 
	while(!(TIFR0 & 0x01));	
	
	/*
	for (y = 0; y < x; y++)
	{
		TIFR0 |= 0x01;//Clear any interrupt flags on Timer2
		
		TCNT0 = 255; 
	
		while(!(TIFR0 & 0x01));	
	}
	*/
	
}

//General short delays
void delay_ms(short x)
{
	for (; x > 0 ; x--)
    {
        delay_us(250);
        delay_us(250);
        delay_us(250);
        delay_us(250);
    }
	
}



char getc(void)
{
	char k, l = 0, m = 0;
	
	//if (port == 1) port = 0b10000000;// GPS input
	//else port = 0b00100000;//user input
	k = 0x20;
	while(k & 0x20) 
	{
		k = PINA;
		k &= 0x20;
	}
	
	//delay_halfbit(1);
	//delay_1_4bit(1);
	delay_us(36);
	
	//delay_halfbit(1);
	
	for (k = 0; k < 8; k++)
	{
		l >>= 1;
		
		m = PINA;
		if (m & 0x20) l |= 0b10000000;
		else l &= 0b01111111;
		
		//delay_halfbit(1);
		//delay_halfbit(1);
		delay_us(24);
	}
	
	return l;
}




void putchr(char x)
{
	char k;
	
	PORTA &= 0b10111111;
	delay_us(24);//bit width at 38400
	
	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);
		delay_us(24);
	}
	
	PORTA |= 0b01000000;//set it high again
	//delay_halfbit(1);
	//delay_halfbit(1);
	delay_us(24);
	
	//extras...
	//delay_halfbit(1);
	//delay_halfbit(1);
	//delay_halfbit(1);
	//delay_halfbit(1);
}



void write_buffer(void)
{
    //printf("Writing to buffer...\r\n",0);
    
    char i, j = 0;
	short x, y;
	
	send_command(0x84);//buffer 1 write
	
    //send 14 "dont care" bits
    PORTA &= 0b11111101;//SI low//SI = 0;
    for (i = 0 ; i < 14 ; i++) flash_clk();
	
	x = flash_buff_mark;
	
    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
		
		flash_clk();
        
        x <<= 1;
        
    }

    //send data out...
       
    for (x = 0; x < 33; x++)
    {
		
		/*
		if (buffer == 1)
		{
			j = buffer[buffer_mark];
			buffer_mark++;
			flash_buff_mark++;//flash buffer 1
		}
		
		else if (buffer == 2) j = buffer[x];
		*/
		
		y = nasty[x];
		          
        for (i = 0 ; i < 16 ; i++)
        {   
            if (y & 0x8000) PORTA |= 0b00000010;//SI high
			else PORTA &= 0b11111101;//SI low
			
			flash_clk();
			
			y <<= 1;
        }
		
		//flash_buff_mark += 2;//

    }
	
	PORTA |= 0b00001000;//CS hi//flash_CS = 1;  
   
    //nasty_mark = 0;//zero the marker if we get al the way through
}


char read_flash(short page)
{
    char i,  x;
    short temp = 0, z;
	
	send_command(0x52);
	
	z = page;
	
	for (i = 0 ; i < 57 ; i++)//56 + 1, check AT45DB161 data sheet
	{
		//2 reserved bits, followed by 12 page address bits, then 9 bits for the exact starting byte
		if ((i >= 2) & (i < 14))
		{
			//page address is 12 bits
			if (z & 0x800) PORTA |= 0b00000010;//SI high
			else PORTA &= 0b11111101;//SI low
			z <<= 1;
		}
		
		else PORTA &= 0b11111101;//SI low//SI = 0;
		
		flash_clk();

	}
	
	//read data out...
	temp = 0;
	
	//if (page == page_mark) y = flash_buff_mark;
	
	for (z = 0; z < 264; z++)//pages are 528 bytes
	{ 
		if ((z % 3) == 0)
		{
			putchr(10);
			putchr(13);
		}
		
		for (x = 0; x < 16; x++)
		{
			
			temp <<= 1;
	
			PORTA |= 0b00000100;//SCK hi//SCK = 1
			
			i = PINA;
			if (i & 0x01) temp += 1;
			
			PORTA &= 0b11111011;//SCK low//SCK = 0;

		}
		
		if (temp == 0xFFFF) break;
		
		print_num(temp);
		putchr(9);
		
		//if (page == 0)
		//{
			//nasty[z] = temp;
			//if (z >= 7) break;
		//}
		
		//put this back later
		//else putchr(temp);
			
		temp = 0;
		
	}
	
    PORTA |= 0b00001000;//CS hi//flash_CS = 1;  
	
	if (temp == 0xFFFF) return 1;
	
    return 0;
}

//block erase, erases 8 pages at a time
void erase(void)
{
    char i;
	short j, temp;
    
	for (j = 0; j < 512; j++)//512*8=4096 pages
    {
		send_command(0x50);
		
		temp = j;
		
		for (i = 0; i < 24; i++)
		{
			if ((i > 2) & (i < 12))
			{
				if (temp & 0x100) PORTA |= 0b00000010;//SI high
				else PORTA &= 0b11111101;//SI low
				temp <<= 1;
			}
			
			else PORTA &= 0b11111101;//SI low
			flash_clk();
		}
			
		PORTA |= 0b00001000;//CS hi//flash_CS = 1;     //bolck erases at rising edge of flash_CS
        
		while(!(status_read() & 0x80));//check the ready bit
        
    }
	
	flash_buff_mark = 0;
	page_mark = 1;
	nasty_mark = 0;
    
}



void buffer_to_main(short page)
{    
    char i;
    
	if (page == 0) send_command(0x86);//write buffer 2 to page zero
	else send_command(0x83);
	
	for (i = 0; i < 24; i++)
	{
		if ((i >= 2) & (i < 14))
		{
			if (page & 0x800) PORTA |= 0b00000010;//SI high
			else PORTA &= 0b11111101;//SI low
			page <<= 1;
		}
		
		else PORTA &= 0b11111101;//SI low
		flash_clk();
	}
	
    PORTA |= 0b00001000;//CS hi   //buffer is written after this, takes 14mS
    
	//delay_halfbit(200);
	delay_ms(14);
    
}


char status_read(void)
{
	char i, j, temp = 0;
	
	send_command(0x57);
    
	flash_clk();
	
	for (i = 0; i < 8; i++)
	{
		
		temp <<= 1;

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

		PORTA &= 0b11111011;//SCK low//SCK = 0;

	}

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


void send_command(char command)
{
	char i;
	
	PORTA &= 0b11110111;//CS low
	
    //send command
    for (i = 0 ; i < 8 ; i++)
    {
        if (command & 0x80) PORTA |= 0b00000010;//SI high
		else PORTA &= 0b11111101;//SI low
		
		flash_clk();
		
		command <<= 1;
        
    }

}


void flash_clk(void)
{
	PORTA |= 0b00000100;//SCK hi//SCK = 1 
	PORTA &= 0b11111011;//SCK low//SCK = 0;
}


void menu(void)
{

	char x, z;
	short y;
	
	while(1)
	{
		putchr(10);
		putchr(13);
		putchr('?');
		
		x = getc();
		putchr(x);
		
		if (x == 'e') erase();
		
		else if (x == 'r')
		{
			for (y = 1; y < 4096; y++) 
			{
				x = read_flash(y);
				
				//putchr(10);
				//putchr(13);
				
				//print_num(y);
				//putchr(10);
				//putchr(13);
				
				if (x == 1) break;
			
			}
			
			putchr(10);
			putchr(13);
			
			/*
			else if (x == 'c')
			{
				y = ((getc(0)-48)*100 + (getc(0)-48)*10 + (getc(0)-48));
				
				if (y < 256)
				{
					//if (z == 's') sleep_ref = (char)y;
					//else if (z == 'h') holdoff = (char)y;
					//sleep_mark = 0;
					
					settings(0);//save
				
				}
				
				
			}
			*/
			
		}
		
	}
	
	
	
}


void print_num(short num)
{
	short a;
	char b, c;
	a = num;
	
	//print hex
	for (c = 0; c < 4; c++)
	{
		b = (char)((a & 0xF000) >> 12);
		if (b < 10) putchr(b+48);
		//if (b < 10) o_set = 48;
		else putchr(b+55);
		//else o_set = 55;
		//putchr(b+o_set);
		a <<= 4;
		
	}
	
	
}




/*
//get or save settings, send 0 to save
void settings(char byte)
{
	read_flash(0);
	
	if ((buffer[0] == 0xFF) | (byte == 0))//if it's blank...
	{
		//buffer[0] = sleep_ref;
		//buffer[1] = sleep_mark;
		//buffer[2] = holdoff;
		buffer[3] = (char)((flash_buff_mark & 0xFF00) >> 8);
		buffer[4] = (char)(flash_buff_mark & 0x00FF);
		buffer[5] = (char)((page_mark & 0xFF00) >> 8);
		buffer[6] = (char)(page_mark & 0x00FF);
		
		write_buffer(2,7);
		buffer_to_main(0);
		
	}
	
	else
	{
		//sleep_ref = buffer[0];
		//sleep_mark = buffer[1];
		//holdoff = buffer[2];
		flash_buff_mark = (buffer[3] << 8) + buffer[4];
		page_mark = (buffer[5] << 8) + buffer[6];
	}


}

*/

