/* -----------------------------------------------------------------------
 * Title:    Sun to sound (piezo, photoresistor)
 * Author:   Samuel St-Aubin (samuel.staubin@gmail.com)
 * Date:     10.7.2008
 * Hardware: Atmega168
 * Software: WinAVR 20060421
 * // PhotoResistor on vtg 50k on gnd //
 * -----------------------------------------------------------------------*/

#define F_CPU 8000000UL  

#include <avr/io.h>                       // Un include pour les fonctions d'entrés/sortie
#include <util/delay.h>
#include <util/stdlib.h>                  // Je sais pas ??héhé je crois que c'est pour le Acii
#include <stdio.h>

#define FOSC 8000000                     // Clock Speed
#define BAUD 14400                        // Baud rate
#define MYUBRR FOSC/16/BAUD-1             // Calcule magique pour configurer la communication

#define Led PD2                        // Led qui indique l'échantillonage
#define Speaker PD4                    // Piezo speaker

#define startpulse 240                 // 760 memory array startup value

int FlagNight;                         // Flag night = 1 / day = 0 
int check;                             // anti hystérésis
int SunCounter;                        // 730 memory array
int SunTrig;                           // Triger value between day/nigh

unsigned char Nuit[] = "C'est la nuit";
unsigned char Jour[] = "C'est le jour";



unsigned char mem[730];

// ********************************* Initialisation du USART *********************************

void USART_Init( unsigned int ubrr)
{

UBRR0H = (unsigned char)(ubrr>>8);        // | Charger la vitesse de communication 
UBRR0L = (unsigned char)ubrr;             // | UBRR0H 8bit avec UBRR0L 8b = ensemble ubrr 18 bit   

UCSR0B = (1<<RXEN0)|(1<<TXEN0);           // Rx Tx enable

UCSR0C = (3<<UCSZ00);                     // Set frame format: 8data, 1 stop bit 

}

// ************************************* ADC init *************************************************
 
void InitADC()
{
 
ADCSRA |= (1 << ADEN) |               // Analog-Digital enable bit
          (1 << ADPS1)|               // set prescaler to 8    (clock / 8)
          (1 << ADPS0);               // set prescaler to 8    (doc Atmega168 23.8.2 p.258)
 
ADMUX |=  (1 << ADLAR)|               // AD result store in (more significant bit in ADCH)
          (1 << MUX1);                // Choose AD input AD2 (PC2)
 
}


// ********************************** USART Envois *******************************************

void USART_Transmit( unsigned char data )
{

while ( !( UCSR0A & (1<<UDRE0)) );        // Attendre que le buffer se vide

UDR0 = data;                              // Envoyer le Data

}

// ********************************** USART Reception ****************************************

unsigned char USART_Receive( void )
{

while ( !(UCSR0A & (1<<RXC0)) );          // Attendre la reception du Data


return UDR0;                              // Retour de fonction
}

// *********************************** ascii Jour/Nuit *************************************
void Send_Jour(void){
int x; 
USART_Transmit(13);

	for (x = 0 ; x < 13 ; x++)
	{
	USART_Transmit(Jour[x]);
	}
USART_Transmit(13);
USART_Transmit(13);
}

void Send_Nuit(void){
int x; 
USART_Transmit(13);
	for (x = 0 ; x < 13 ; x++)
	{
	USART_Transmit(Nuit[x]);
	}
USART_Transmit(13);
USART_Transmit(13);
}

// *********************************** Send value (ascii)*************************************
void Send_Val(int value)
{

int x;

char buffer [10];

	for (x =0 ; x < 10 ; x++ )                 // fill buffer with 0
	{
	buffer[x] = 0;
	}

	itoa(value, buffer, 10);                     // convert value into array of ascii

	for (x =0 ; x < 10 ; x++ )
	{
	USART_Transmit(buffer[x]);
	if (buffer[(x + 1)] == 0) x = 10;
	}

USART_Transmit(32);
}
// *********************************** Analog/digital converter*********************************



unsigned char adc()
{
    ADCSRA |= (1 << ADEN);            // Analog-Digital enable bit
    ADCSRA |= (1 << ADSC);            // Discarte first conversion
        while (ADCSRA & (1 << ADSC)); // wait until conversion is done
    ADCSRA |= (1 << ADSC);            // start single conversion
        while (ADCSRA & (1 << ADSC))  // wait until conversion is done
    ADCSRA &= ~(1<<ADEN);             // shut down the ADC
 
return ADCH;
}

// *********************************** Pause second **************************************

void PauseS(int sec)                  // Timer for Sec
{
int t;
int y;

	for( t = 0 ; t < sec ; t++ )
	{
		for ( y = 0 ; y < 32 ; y++ )
		{
		_delay_ms(49);
		}
	}
}

// *********************************** Pause Msecond ******************************************

void PauseMS(int Msec)                // Timer for mSec
{
int t;

	for( t = 0 ; t < Msec ; t++ )
	{
	_delay_ms(1);
	}

}

// *********************************** Pause Usecond *******************************************

void PauseUS(int Usec)                // Timer for uSec
{
int t;

	for( t = 0 ; t < Usec ; t++ )
	{
	_delay_us(3);
	}

}

// *********************************** Fill Buffer **********************************************
void FillBuffer()                     // Fill the 730 mem array with startup 
{
int t;

	for( t = 0 ; t < 730 ; t++ )
	{
	mem[t] = startpulse;
	}

}
// *********************************** Trigger nigh flag ********************************************
void SetSunTri(void){                 // Set SunTrig on momentary sunlight

// SunTri = adc();
SunTrig = 100;

}

// ************************************ Beep ****************************************************

void PlayBeep(void)
{
int x;
PORTD &= ~(1 << Led);                 // Set 0 on LED pin (led turn on)

	for (x =0 ; x < 730 ; x++)
	{
	PORTD |= (1 << Speaker);          // Set 1 on piezo pin 
	PauseUS (mem[x]);                 // Call delay from 730 mem array
	x++;                          
	PORTD &= ~(1 << Speaker);         // Set 0 on piezo pin 
	PauseUS (mem[x]);                 // Call delay from 730 mem array
	}

PORTD |= (1 << Led);                  // Set 1 on LED pin (led turn off)
}

unsigned char SunSumSam(){            // Get 1 value of 6 acculator sample average
int z;
int SunSum;
int Sunminute[6];
SunSum = 0;

	for (z = 0; z < 6 ; z++)           
	{
	Sunminute[z] = adc();             // Get light from photo resistor
	SunSum = SunSum + Sunminute[z];   // Add sample to 6 sample accumulator

	PauseMS(100);                       // one minute break

//	PauseS(60);                       // one minute break

	}

SunSum = ( SunSum / 6 );              // get average of 6 minutes sampling
Send_Val(SunSum);
		USART_Transmit(13);

return SunSum;
}



// ************************************* Serial send memory ascii ***********************************
 
void serial_send(void) {
int z;

	USART_Transmit(13);
for (z = 0 ; z < 730 ; z++){ 
		Send_Val(mem[z]);
		}
		USART_Transmit(13);
		USART_Transmit(13);

}

// ************************************* Main ******************************************************
 
int main() {

DDRD |= (1 << Led);                   // Set output direction on LED 
DDRD |= (1 << Speaker);               // Set output direction on Speaker
PORTD |= (1 << Led);          	      // Set 1 on LED pin (led turn off) 

check = 0;                             // anti hystérésis
SunCounter = 0;                        // 730 memory array
FlagNight = 1;

InitADC();
FillBuffer();
SetSunTri();
USART_Init(MYUBRR);



PauseS(2);


	for (;;)
	{

	SunCounter %= 730;
	Send_Nuit();
	PlayBeep();    
	mem[SunCounter] = 0;

		for (;FlagNight == 1;)
		{


			if (SunSumSam() <= SunTrig)                      // Get 6 minutes sample
			{                     
			mem[SunCounter] = mem[SunCounter] + 1;           // mem night + 1 
			}
			else
			{

			check++;

				if (check > 4) 				   				 // After 10 time day sample 
				{
				FlagNight = 0;                               // => turn into day mode
				check = 0;
				}
			}


		}




	serial_send();

	PlayBeep();                                          // Play sun array
	Send_Jour();
	SunCounter++;	
	mem[SunCounter] = 0;


		for (;FlagNight == 0;)
		{
                                      // Play sun array

			if (SunSumSam() > SunTrig)                       // Get 6 minutes sample
			{
			mem[SunCounter] = mem[SunCounter] + 1;           // mem night + 1 
			}
			else
			{
			check++;

				if (check > 4)                               // After 10 time day sample 
				{
				FlagNight = 1;                               // => turn into day mode
				check = 0;
				}
			}
	}	
		serial_send();
 		SunCounter++;
	}
return 0;
}









