/* Der Magnetfelder Detektor V2.00 */
/*Copyright (c) 2009 by James Delaney

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "stdlib.h"  // itoa


#include <avr/io.h>
#include <avr/interrupt.h>
#ifndef F_CPU
// define cpu clock speed if not defined
#define F_CPU 1000000
#endif
#include <util/delay.h>


//#define MYDEBUG 1

#ifdef MYDEBUG
void ser_putchr(char);
void ser_sendnumber(int);
void ser_sendspace(void);
void ser_sendnegative(void);
#define USART_BAUDRATE 2400
// why -6 or -35...well cause thats how long it takes to hit the sub routines
// it was a hi-low guesstimage
#define  BAUD_PRESCALE (F_CPU/USART_BAUDRATE)-35 // -64 w/ a&b
#define BAUD _delay_us(BAUD_PRESCALE)
//#define BAUD _delay_us(410) working @ 2400bps

#endif

volatile int theCount;
volatile int theTemp;

void portBon(unsigned char pos)
{
		PORTB |= _BV(pos);
}
void portBoff(unsigned char pos)
{
        PORTB &= ~_BV(pos);
}
void portBtoggle(unsigned char pos)
{
        PORTB ^= _BV(pos);
}
void portAon(unsigned char pos)
{
		PORTA |= _BV(pos);
}
void portAoff(unsigned char pos)
{
        PORTA &= ~_BV(pos);
}
void portAtoggle(unsigned char pos)
{
        PORTA ^= _BV(pos);
}

// remeber ledOff and on are backward because of uln2803
void ledOff(unsigned char pos)
{
	if (pos>4)
	{
		PORTB &= ~_BV(7-pos);
	}
	else
	{
		if (pos==4) { pos=7; }
		PORTA &= ~_BV(pos);
	}
}
void ledOn(unsigned char pos)
{
	if (pos>4)
	{
		PORTB |= _BV(7-pos);
	}
	else
	{
		if (pos==4) { pos=7; }
		PORTA |= _BV(pos);
	}
}
void ledToggle(unsigned char pos)
{
	if (pos>4)
	{
		PORTB ^= _BV(7-pos);
		//PORTB = 0b00000001;
	}
	else
	{
		if (pos==4) { pos=7; }
		PORTA ^= _BV(pos);
	}
}
void allOff()
{
	int lop;
	for (lop=0; lop<8; lop++)
	{
		ledOff(lop);
	}
}

int main(void)
{
	int x,lop;
	int normalValue=0,theTemp;
	// init 
 	DDRA =  0b10101111;  // 1 = output 0=input
 	DDRB =  0b00000111;

 	/////////76543210
 	ADMUX= 0b00000100;
 	ADCSRB=0b00000000;
 	ADCSRA=0b00000011;
 
    ADCSRA |= (1 << ADEN);
 	_delay_ms(500);
 	ADCSRA |= (1 << ADSC);  // Start A2D Conversions
 	while ((ADCSRA & (1 << ADSC))) {}
 	normalValue=ADCW;
 
	// do a self calibration to get
	// normalValue
	for (x=0; x<8; x++)
	{
		ledOn(x);
		_delay_ms(100);
		ADCSRA |= (1 << ADSC);  // Start A2D Conversions
		while ((ADCSRA & (1 << ADSC))) {}
		theTemp=ADCW;		
		normalValue=(normalValue+theTemp)/2;
		ledOff(x);
	}

	char c;
	int value=-101; // dummy value
	for(;;) // loop forever
	{

 		ADCSRA |= (1 << ADSC);  // Start A2D Conversions
 		while ((ADCSRA & (1 << ADSC))) {}
 		theTemp=ADCW;

		value=theTemp-normalValue;

#ifdef MYDEBUG
			ser_senditoa(value);
			ser_sendspace();
#endif

		// Main Display Function
		// my calibration showed -300 to +300 for value
		// so /8 = 37.5 or 38
		if (value<-10 || value >10) // make a dead zone
		{
			if (value>0)
			{
				for (lop=0; lop<8; lop++)
				{
					if (lop > (value/38) ) ledOff(lop); // south
					else {ledOn(lop); }
					//ledOn(lop);
				}
			}
			if (value<0)
			{
				for (lop=0; lop<8; lop++)
				{
					if ( lop > ((value*-1)/38) ) ledOff(7-lop); // north
					else {ledOn(7-lop); }
				}
			}
		}
 		else 
		{ 
			allOff(); 
		}
		_delay_ms(10); // delay between updates
	}
}

#ifdef MYDEBUG

void ser_sendspace()
{
	char c;
	c=32;
	ser_putchr(c);
	//_delay_ms(1);
}
void ser_sendnegative()
{
	char c;
	c=45;
	ser_putchr(c);
	//_delay_ms(1);
}
void ser_senditoa(int x)
{
	int lop;
	char str[]="\0\0\0\0\0\0\0\0\0\0\0\0";
	itoa(x,str,10);
	for(lop=0; lop<10; lop++)
	{
		ser_putchr(str[lop]);
		//_delay_ms(1);
	}
	if (x==0) ser_writenum(0);
}
void ser_writenum(char c)
{
	switch(c)
	{
		case 0: 
				c=48; ser_putchr(c); break;
		case 1: 
				c=49; ser_putchr(c); break;
		case 2: 
				c=50; ser_putchr(c); break;
		case 3: 
				c=51; ser_putchr(c); break;
		case 4: 
				c=52; ser_putchr(c); break;
		case 5: 
				c=53; ser_putchr(c); break;
		case 6: 
				c=54; ser_putchr(c); break;
		case 7: 
				c=55; ser_putchr(c); break;
		case 8: 
				c=56; ser_putchr(c); break;
		case 9: 
				c=57; ser_putchr(c); break;

	}
	_delay_ms(250);
}
void ser_putchr(char x)
{
 char k;

	// start bit goes low
	//portBoff(0);
	portAoff(5);
	BAUD;//bit width
		
	for (k = 0; k < 8; k++)//8 data bits
	{
		if (x & 0b00000001) 
		{
			//pinon
			//portBon(0);
			portAon(5);

		}
		else 
		{
			// pin off
			//portBoff(0);
			portAoff(5);
		} //
		x >>= 1;
		
		BAUD;
	}
	// stopbit
	//portBon(0);
	portAon(5);
	BAUD;
}
#endif

/* attic */
/*
		//c=0b01010101;
		//ser_putchr(c);

		//value=another_random()%300;
		//value=value-150;

		//value=value+20;
		//if (value>300) { value=-300; }


*/

