//*****************************************************************************
//
// File Name	: 'main.c'
// Target MCU	: Atmel mega32 AVR series
//
// Project		: MPPT integrated
// Version		: Beta 0.1
// Author		: Tony Bazouni.
//
//*****************************************************************************

#include <stdint.h> 
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <stdio.h>
#include "lcd_lib.h"


char buffer[8]; 
uint16_t rawV = 0;
uint16_t rawC = 0;
uint16_t rawVnew = 0;
uint16_t rawCnew = 0;

uint32_t rawW;

uint32_t Wh = 0;
uint32_t Ah = 0;
uint16_t Wx = 0;
uint16_t Ax = 0;
uint16_t Wh3 = 0;
uint16_t Ah3 = 0;
uint32_t Wh2 = 0;
uint8_t AorW = 0;

uint16_t PeakV = 0;
uint16_t PeakC = 0;
uint16_t PeakW = 0;

uint16_t timer1 = 0;
uint8_t timer2 = 0;
uint8_t minutes = 0;
uint8_t hours = 0;
uint16_t days = 0;

uint16_t PPV = 0;
uint16_t PPC = 0;
uint32_t PPW = 0;
uint16_t PPS = 0;

uint8_t menu = 0;


//volatile uint8_t DEBUG = 1;


void delay1s(void);
void showData(void);
void showDataUART(void);
void gatherData(void);
void showtimer(void);
void Wattmeter(void);
void getData(void);
void sweep(void);
void PPD(void);
void WAH(void);
void WH(void);
void AH(void);



////////////////////////////////////////////////////////////////

#define UP   	1
#define DOWN   	0
#define PWM   	OCR2 // OCR2A 664
#define MAX		250
#define MIN		5
#define INC		2
#define RSPNS	3000

uint8_t timerM = 0;

uint16_t voltage;
uint32_t newpower;
uint32_t oldpower;
uint8_t direction = UP;

uint16_t refV = 300;

void findPower(void);
void SearchAndDestroy(void);

////////////////////////////////////////////////////////////////

ISR(__vector_default)
{
	asm("NOP");
} 

ISR(INT0_vect)
{
	if(AorW)
	{
		AorW++;
	}

	else if(AorW == 0)
	{
		AorW--;
	}

//	DEBUG++;
}

ISR(INT1_vect)
{	
//		DEBUG++;
	timer1 = 0;
	timer2 = 0;
	minutes = 0;
	hours = 0;
	days = 0;

	Wh = 0;
	Ah = 0;
	Wx = 0;
	Ax = 0;
	Wh3 = 0;
	Ah3 = 0;

	PeakV = 0;
	PeakC = 0;
	PeakW = 0;
}

void ports_Init(void)
{
	DDRB = 0b11101111;
	DDRD = 0b10000000;
	PORTB = 0xFF;
	PORTD = 0xFF;

	MCUCR = 0b00001111;
	
//	EICRA = 0b00001010;//644 only
//	EIMSK = 0b00000011;//644 only


	GICR = 0b11000000;
}

void InitTimer(void)
{
	TCCR1A = 0b00000000;
	TCCR1B = 0b00000011;

	//TCCR2A = 0b10000011;  //mega16 = 0b01101001;
	//TCCR2B = 0b00000001;
	TCCR2 = 0b01101001;
	
	PWM = 150;

	//TCCR0 = 0b00000101;
	//TIMSK = 0b00000001;
	//TIFR  = 0b00000001;
}

void setADC(void)
{
	ADCSRA |= (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
}

void getADC(int channel)
{
	ADMUX = channel;
	
	ADCSRA |= (1<<ADSC);
	while (!(ADCSRA & (1<<ADIF)));
	
	ADCSRA |= (1<<ADSC);
	while (!(ADCSRA & (1<<ADIF)));
}

int main(void)
{
	ports_Init();
	InitTimer();
	setADC();
	LCDinit();
	LCDclr();
	sei();


	while(1)
	{	
		Wattmeter();
//	SearchAndDestroy();
	}
	return 0;
}

void Wattmeter(void)
{
	getData();
	showData();

/*	//sprintf(buffer, "%d", TCNT1);
	sprintf(buffer, "%d", DEBUG);
	LCDGotoXY(14,0);
	LCD_Print(buffer);*/

	if(TCNT1 >= 31250)
	{
		TCNT1 = TCNT1 - 31250;
		WAH();
	}
}

void getData(void)
{
	getADC(0b01000000);
	rawVnew = ADC*5;

	getADC(0b01000001);
	rawCnew = ADC*2;

/*	if(rawVnew > PeakV)
	{
		PeakV = rawVnew;

		sprintf(buffer, "%2d.%02dVp ", (uint16_t)PeakV/100, (uint16_t)PeakV%100); 
		LCDGotoXY(13,0);
		LCD_Print(buffer);


	}

	if(rawCnew > PeakC && rawVnew > 400)
	{
		PeakC = rawCnew;

		sprintf(buffer, "%2d.%02dAp ", (uint16_t)PeakC/100, (uint16_t)PeakC%100);   ///////  0x%d x/100
		LCDGotoXY(13,1);
		LCD_Print(buffer);
	}*/
}

void showData(void)
{
	rawV = rawVnew;//((7*rawV+1*rawVnew)/8);
	rawC = rawCnew;//((7*rawC+1*rawCnew)/8);

	rawW = ((uint32_t)rawV*(uint32_t)rawC);
	uint32_t rawW2= rawW/100;                   // x/100
	uint16_t watts = rawW2/100;
	uint8_t watts2 = rawW2%100;

	sprintf(buffer, "%2d.%02d Volts ", (uint16_t)rawV/100, (uint16_t)rawV%100); 
	LCDGotoXY(0,0);
	LCD_Print(buffer);

	sprintf(buffer, "%2d.%02d Amps ", (uint16_t)rawC/100, (uint16_t)rawC%100);   ///////  0x%d x/100
	LCDGotoXY(0,1);
	LCD_Print(buffer);

	if(watts >= 1000)
	{
		sprintf(buffer, "%d.%03d KW ", watts/1000, watts%1000);
		LCDGotoXY(0,2);
		LCD_Print(buffer);
	}

	else
	{
		sprintf(buffer, "%2d.%02d Watts ", watts, watts2);
		LCDGotoXY(0,2);
		LCD_Print(buffer);
	}

	if(watts >= PeakW)
	{
		if(watts >= 1000)
		{
			sprintf(buffer, "%d.%03dKWp ", watts/1000, watts%1000);
			LCDGotoXY(12,1);
			LCD_Print(buffer);
		}

		else
		{
			sprintf(buffer, "%2d.%02dWp ", watts, watts2);
			LCDGotoXY(12,1);
			LCD_Print(buffer);
		}

		PeakW = watts;
	}
}
////////////////////////////////////////////////////////
void WAH(void)
{
	gatherData();
	showtimer();
	
	if(AorW)
	{
		WH();
	}

	else
	{
		AH();
	}
}

void gatherData(void)
{
	Wh = Wh + rawW;

	if(Wh > 1000000000)
	{
		Wh = Wh - 1000000000;
		Wx++;
	}
	
	Wh2 = Wh/3600000 + 277.77*Wx;  //277.777    3600000-2A 36000000-20A

	Ah = Ah + rawC;

	if(Ah > 1000000000)
	{
		Ah = Ah - 1000000000;
		Ax++;
	}
	
	uint32_t Ah2 = Ah/36000 + 27777.77*Ax;  //277.777    3600000-2A 36000000-20A
	Ah3 = Ah2;
}

void WH(void)
{
	uint16_t wt1 = Wh2/100;
	uint8_t wt2 = Wh2%100;
	
	
	sprintf(buffer, "%2d.%02d W/hr ",wt1 ,wt2 );
	LCDGotoXY(0,3);
	LCD_Print(buffer);
}

void AH(void)
{
	sprintf(buffer, "%2d.%02d A/hr ", Ah3/100, Ah3%100);
	LCDGotoXY(0,3);
	LCD_Print(buffer);
}
//////////////////////////////////////////////////////////////////////////////
void showtimer(void)
{
	timer1++;
	timerM++;

	if(timerM == 6)
	{
		SearchAndDestroy();
		timerM = 0;
	}


	if(timer1 == 600)
	{
		timer1 = 0;
		minutes++;
	}
	
	if(minutes == 60)
	{
		minutes = 0;
		hours++;
	}

	if(hours == 24)
	{
		hours = 0;
		days++;
	}

	sprintf(buffer, "%2d:%02d.%0d", minutes, timer1/10, timer1%10);
	LCDGotoXY(13,3);
	LCD_Print(buffer);

	if(hours||days)
	{
		sprintf(buffer, "%2dd%2dh", days, hours);
		LCDGotoXY(14,2);
		LCD_Print(buffer);
	}
}

void SearchAndDestroy(void)
{
	PWM++;
	
	newpower = rawW;

	if(newpower == oldpower)
	{
		PWM = PWM-INC;
	}
	
	if(newpower > oldpower && direction == UP && PWM < MAX)
	{
		PWM = PWM+INC;
	}

	else if(newpower > oldpower && direction == DOWN && PWM > MIN)
	{
		PWM = PWM-INC;
	}

	if(newpower < oldpower && direction == UP)
	{
		PWM = PWM-INC;
		direction = DOWN;
	}

	else if(newpower < oldpower && direction == DOWN)
	{
		PWM = PWM+INC;
		direction = UP;
	}

	oldpower = newpower;
}


