#define F_CPU 4000000
#include <stdlib.h>
#include <avr/io.h>				// knihovna vstupu a výstupu
#include <util/delay.h>			// knihovna s easovaeem
#include <avr/interrupt.h>	// knihovna pro přerušení
#include <string.h>
#include <stdio.h>
#include <avr/pgmspace.h>
#define LCD
#include "lcd_h.h"	 		//knihovna pro LCD
#include "sht75.h"				//knihovna sht75 sensibus
#include "twi_lib.h"			// knihovna i2c/twi
#include "adc_ex.h"				//knihovna SPI A/D prevodnik

//hp03m///////////////////
#define READ_EEPROM 0xA1 	// adresa pro cteni (0xA0+1)
#define WRITE_EEPROM 0xA0
#define READ_AD 0xEE
//MAX44009///////////////
#define MAX44009_W 0b10010100
#define MAX44009_R 0b10010101
#define HIGHH_BYTE 0x03
#define LOWW_BYTE 0x04
//CO2 K30////////////////
#define k30_W 0xD0	//write k30 adress
#define k30_R 0xD1 //read k30 adress
//RTC cas////////////////
#define READ_adresa 0xA3 	// adresa pro čtení (0xA2+1)
#define WRITE_adresa 0xA2	// adresa pro zápis
// adresace uvnitř PCF8563T - výběr požadované položky
#define sekundy_A 0x02
#define minuty_A 0x03
#define hodiny_A 0x04
#define dny_A 0x05
#define den_A 0x06		// neděle až sobota (0 ... 6)
#define mesic_A 0x07
#define rok_A 0x08
#define control_status_1 0x01


/////////////////////////sht75 fce
void temp_humid(void);
/////////////////////////hp03m fce
void icoef(void);
void khz(void);
void meas_press(void);
unsigned int teplota(void);
unsigned int tlak(void);
void teplota_a_tlak(void);
long int Get2_x(unsigned char i);
void Pocitej(void);
void reset_high(void);
void reset_low(void);
unsigned int C1;
unsigned int C2;
unsigned int C3;
unsigned int C4;
unsigned int C5;
unsigned int C6;
unsigned int C7;
unsigned char A;
unsigned char B;
unsigned char C;
unsigned char D;
unsigned int D1;
unsigned int D2;
float DUT;
float OFF;
float SENS;
float X;
float Press;
float Temperatur;
///////////////////////////Max44009 fce
void LightLevel(void);
float lux;
int lowwByte;
int highhByte;
int exponent;
int mantissa;
//////////////////////////CO2 K30 fce
void co2_value(void);
int old_co2_value;
/////////////////////////GUVA GUVB fce
void UV_value(void);
////////////////////////UART a O2 Flux fce
void switch_xbee(void);
void switch_o2(void);
void uart_config(void);
unsigned char uart_getc(void);
void uart_putc(unsigned char uartdata);
void uart_pstr(char *s);
////////////////////////RTC fce
unsigned int hodnota;
unsigned char sekundy;
unsigned char minuty;
unsigned char hodiny;
unsigned char dny;
unsigned char mesic;
unsigned char rok;
unsigned char den;

//void nacti (void);						// nacte stav hodin a alarmu do pameti
void time (void);						// vypíše stav hodin na LCD
void readRTC (unsigned char adresa);						// ctení RTC
void writeRTC(unsigned char adresa,unsigned char data);		// zápis do RTC
//////////////////////////////////////
char buffer1[16];
char buffer2[16];



int main (void)
{
	DDRA = 0xff;	// portA výstupní LCD
	lcd_init();		//inicializace LCD
    lcd_clrscr();	// smazání LCD displeje
    _delay_ms(10);
    khz();			//spustit clk pro hp03m
    _delay_ms(10);
	i2c_init();		//init i2c
	_delay_ms(10);
	icoef();		//vycte koeficienty hp03m
	_delay_ms(100);
	InitADCEx();    //inicializace spi
	_delay_ms(10);
	uart_config();	//configurate uart
	_delay_ms(10);
	switch_xbee();		//uart na xbee
	// RTC zápis data, provede se pouze jednou pri nastaveni, pak zakomentovat
	//writeRTC(minuty_A,15);
	//writeRTC(hodiny_A,11);
	//writeRTC(rok_A,16);
	//writeRTC(den_A,6);
	//writeRTC(dny_A,21);
	//writeRTC(mesic_A,5);
	//writeRTC(control_status_1,0x00);//priznak alarmu off

	_delay_ms(200);

while(1)//nekonecna smycka mereni hodnot
	{
		time();		//odecte z RTC cas a datum a posle do zigbee a na LCD
		temp_humid();//zmer teplotu a vlhkost C a %
		meas_press();//zmer tlak hpa
		LightLevel();//zmer osvetleni lux
		UV_value();//zmer uva a uvb index
		co2_value();//zmer CO2 ppm

	}
	return 1;
}










void temp_humid(void)//fce pro zmereni teploty a tlaku
{
	int T;
	int RH;
	double RHlinear = 0.0;
	double RHtrue   = 0.0;
	double Temp    = 0.0;

		ShtInit(6);//inicializace sht portC6
        ShtReset(6);

		T   = ShtMeasure(SHT_TEMPERATURE, 6);//zmer teplotu, pin C6
		Temp     = ((double) T)*0.01 - 39.7;//vypocet teploty


		RH  = ShtMeasure(SHT_HUMIDITY, 6);//zmer tlak
		RHlinear = -2.0468 + 0.0367 * ((double) RH) - 0.0000015955 * ((double) RH * (double) RH);
		RHtrue   = (Temp - 25) * (0.01 + 0.00008 * (double) RH) + RHlinear;//vypocet tlaku

   		dtostrf(Temp, 2, 2, buffer1);//prevod float na string
   		dtostrf(RHtrue, 3, 2, buffer2);//prevod float na string

		uart_pstr("Teplota: ");//posle uart do xbee
		uart_pstr(buffer1);
		uart_pstr(" °C\r\n");
		uart_pstr("RH: ");
		uart_pstr(buffer2);
		uart_pstr(" %\r\n");

		lcd_gotoxy(0,0);//zobrazi na lcd
		lcd_put_string("T:");
		lcd_gotoxy(2,0);
		lcd_put_string(buffer1);
		lcd_gotoxy(7,0);
		lcd_put_string("°C");
		lcd_gotoxy(10,0);
		lcd_put_string("RH:");
		lcd_gotoxy(13,0);
		lcd_put_string(buffer2);
		lcd_gotoxy(19,0);
		lcd_put_string("%");
		_delay_ms(100);
}

void icoef(void)//fce pro vycteni koeficientu z EEPROM HP03M
{
	unsigned char ucValue;

	i2c_start_wait(WRITE_EEPROM);
	i2c_write(16); //zaciname na 16. registru
	//i2c_stop();

	i2c_rep_start(READ_EEPROM);

	ucValue=i2c_readAck();
	C1=ucValue;
	ucValue = i2c_readAck();
	C1 <<= 8;
	C1 |= ucValue;

	ucValue=i2c_readAck();
	C2=ucValue;
	ucValue = i2c_readAck();
	C2 <<= 8;
	C2 |= ucValue;

	ucValue=i2c_readAck();
	C3=ucValue;
	ucValue = i2c_readAck();
	C3 <<= 8;
	C3 |= ucValue;

	ucValue=i2c_readAck();
	C4=ucValue;
	ucValue = i2c_readAck();
	C4 <<= 8;
	C4 |= ucValue;

	ucValue=i2c_readAck();
	C5=ucValue;
	ucValue = i2c_readAck();
	C5 <<= 8;
	C5 |= ucValue;

	ucValue=i2c_readAck();
	C6=ucValue;
	ucValue = i2c_readAck();
	C6 <<= 8;
	C6 |= ucValue;

	ucValue=i2c_readAck();
	C7=ucValue;
	ucValue = i2c_readAck();
	C7 <<= 8;
	C7 |= ucValue;

	ucValue=i2c_readAck();
	A=ucValue;

	ucValue=i2c_readAck();
	B=ucValue;

	ucValue=i2c_readAck();
	C=ucValue;

	ucValue=i2c_readNak();
	D=ucValue;
	i2c_stop();


}

unsigned int teplota(void)//zmeri teplotu hp03m
{
	unsigned char ucData;
	unsigned int wADT;

	i2c_start_wait(READ_AD);
	i2c_write(0xff);
	i2c_write(0xE8);
	i2c_stop();

	_delay_ms(40);

	i2c_rep_start(READ_AD);
	i2c_write(0xFD);
	i2c_rep_start(0xEF);

	ucData = i2c_readAck();
	wADT = ucData;
	wADT <<= 8;
	ucData = i2c_readNak();
	i2c_stop();
	wADT |= ucData;

	return wADT;
}

unsigned int tlak(void)//zmeri tlak hp03m
{
	unsigned char ucData;
	unsigned int wADp;

	i2c_start_wait(READ_AD);
	i2c_write(0xff);
	i2c_write(0xF0);
	i2c_stop();

	_delay_ms(45);

	i2c_rep_start(READ_AD);
	i2c_write(0xFD);
	i2c_rep_start(0xEF);

	ucData = i2c_readAck();
	wADp = ucData;
	wADp <<= 8;
	ucData = i2c_readNak();
	i2c_stop();
	wADp |= ucData;

	return wADp;

}


void teplota_a_tlak(void)//spojeni bytu teploty a tlaku
{
	long uiSumADValue;
	uiSumADValue = 0;
	reset_high();
	_delay_ms(2);

	D1 = tlak();
	uiSumADValue += D1;
	D1= tlak();
	uiSumADValue += D1;
	D1= tlak();
	uiSumADValue += D1;
	D1= tlak();
	uiSumADValue += D1;
	D1=uiSumADValue >> 2;

	D2=teplota();

	reset_low();
	//mozna pridat i twir=0x00; a mozna vypnout i clock
}

long int Get2_x(unsigned char i) //vypocte dva na ntou
{
	long int uiData;
	uiData=2;
	i=i-1;
 while(i)
 	{
		uiData <<= 1;
		i--;
	 }
 return uiData;
}

void Pocitej(void)//vypocte teplotu a tlak
{
	float middle1;
	float middle2;
	float middle3;
	float middle4;

	//vypocitat DUT
	if(D2<C5)
   	 {
		middle1 = (float)D2-(float)C5;
		middle2 = (middle1*middle1)/16384;
		middle3 = middle2*B;
		middle4 = Get2_x(C);
		middle4 = middle3/middle4;
		DUT = middle1 - middle4;
	 }
	else
	 {
		middle1 = (float)D2-(float)C5;
		middle2 = middle1*middle1/16384;
		middle3 = middle2*A;
		middle4 = Get2_x(C);
		middle4 = middle3/middle4;
		DUT = middle1 - middle4;
	 }

	//vypocitat OFF
	middle1=(float)C4-1024;
	middle2=16384;//Get2_x(14);
	middle3=DUT*middle1;
	middle4=middle3/middle2;
	middle4=(float)C2+middle4;
	OFF = middle4*4;

	//vypocet SENS
	middle1=(float)C3*DUT;
	middle2 = 1024;//Get2_x(10);
	middle3 = middle1/middle2;
	SENS = C1+middle3;

	//vypocti X
	middle1=16384;//Get2_x(14);
	middle2=(float)D1-7168;
	middle3=middle2*SENS;
	middle4=middle3/middle1;
	X=middle4-OFF;

	//vypocet tlaku na 2 decimal
	middle1=X*100;
	middle2=32;//Get2_x(5);
	middle3=middle1/middle2;
	middle4=C7*10;
	Press = middle3+middle4;//pa
	Press = Press/100;//hpa

	//vypocet teploty
	/*middle1=DUT*C6;
	middle1=middle1/65536;//Get2_x(16);
	middle2=DUT/Get2_x(D);
	middle3=250+middle1-middle2;
	Temp=middle3;*/
	Temperatur = 250+((DUT*C6)/65536)-(DUT/Get2_x(D));
	Temperatur = (Temperatur/10)-10;
}

void reset_high(void)//reset hp03m
{
	DDRB|=(1<<PB2);
	PORTB|=(1<<PB2);

}

void reset_low(void)//stop reset hp03m
{
	DDRB|=(1<<PB2);
	PORTB&=(~(1<<PB2));
}

void khz(void)//generuje 32 khz z timeru 0
{
	DDRB|=(1<<PB3);

	TCCR0|=(1<<WGM01)|(1<<COM00)|(1<<CS00);
	OCR0=61; //generuje 32 khz  f= f(proc)/(2*preddelicka*(1+OCR0))
}

void meas_press(void)//celkova fce tlaku HP03M
{
		teplota_a_tlak();	//zmeri teplotu a tlak
		Pocitej(); //spocita teplotu a tlak

		//dtostrf(Temperatur, 2, 2, buffer1);
		dtostrf(Press, 4, 2, buffer2);

		uart_pstr("Tlak: ");//odesle pres UART do XBee
		uart_pstr(buffer2);
		uart_pstr(" hPa\r\n");

		lcd_gotoxy(0,1);//zobrazi na LCD
		lcd_put_string("P:");
		lcd_gotoxy(2,1);
		lcd_put_string(buffer2);
		lcd_gotoxy(9,1);
		lcd_put_string("hPa");
		_delay_ms(200);


}

void LightLevel(void)//zmeri intenzitu osvetleni MAX44009
{

	i2c_start_wait(MAX44009_W);
	i2c_write(HIGHH_BYTE);
	i2c_rep_start(MAX44009_R);

	highhByte = i2c_readNak();

	i2c_rep_start(MAX44009_W);
	i2c_write(LOWW_BYTE);
	i2c_rep_start(MAX44009_R);

	lowwByte=i2c_readNak();

	i2c_stop();



	 exponent = ((highhByte & 0xF0) >> 4);// upper four bits of high byte register
	 mantissa = ((highhByte & 0x0F) << 4);// lower four bits of high byte register
	 // upper four bits of mantissa
	 mantissa += (lowwByte & 0x0F); // lower four bits of low byte register
	 // lower four bits of mantissa

 	lux = mantissa * Get2_x(exponent) * 0.045;
 	dtostrf(lux, 6, 1, buffer1);//6 cele 1 desetinne, max hodnota 188 000 lx

	uart_pstr("Osvetleni: ");//posle UART do XBee
	uart_pstr(buffer1);
	uart_pstr(" lux\r\n");

	lcd_gotoxy(0,2);//posle na LCD
	lcd_put_string("I:");
	lcd_gotoxy(2,2);
	lcd_put_string(buffer1);
	lcd_gotoxy(10,2);
	lcd_put_string("lx");
	_delay_ms(200);

}

void co2_value(void)//zmeri CO2 ppm
{
	int co2_value;
	char byte1;
	char byte2;
	char byte3;
	char byte4;
	int crcsum;
	_delay_ms(100);

		i2c_start_wait(k30_W);
		i2c_write(0x22);
		i2c_write(0x00);
		i2c_write(0x08);
		i2c_write(0x2A);
		i2c_stop();

		_delay_ms(10);

		i2c_rep_start(k30_R);

		byte1=i2c_readAck();//hlavicka
		byte2=i2c_readAck();//prvni polovina co2
		byte3=i2c_readAck();//druha polovina co2
		byte4=i2c_readNak();//crc soucet byte1+byte2+byte3
		i2c_stop();

		co2_value = 0;
		co2_value |= byte2 & 0xFF;//spojeni byte2+byte3
		co2_value = co2_value << 8;
		co2_value |= byte3 & 0xFF;

		if(co2_value>(old_co2_value+3000)) co2_value=old_co2_value;//filtrace obcasneho skokoveho zvyseni ppm o 3000ppm

		crcsum=0;//kontrolni soucet
		crcsum= byte1+byte2+byte3;

		if(crcsum==byte4);//pokud sedi crc soucet, tak zobraz hodnoty
		{
			itoa(co2_value, buffer1, 10);

			uart_pstr("CO2: ");
			uart_pstr(buffer1);
			uart_pstr(" ppm\r\n");

			lcd_gotoxy(0,3);
			lcd_put_string("CO2:");
			lcd_gotoxy(4,3);
			lcd_put_string(buffer1);
			lcd_gotoxy(8,3);
			lcd_put_string(" ppm");
			_delay_ms(200);
			co2_value=old_co2_value;//ulozi hodnotu pro porovnani s novou
		}
}

void UV_value(void)//zmeri UVA a UVB
{
float uva_index;
float uvb_index;
uint16_t result;

	  result = ReadADCEx(0); //Read Channel Number UVA, 0

	  uva_index = (((result*2.5)/4096)/6666666); //vypocet proudu na diode UVA
	  uva_index = ((uva_index - (0.000000030612))/0.000000025213);//vypocet uve indexu podle rovnice trendu
	  if(uva_index<0)//aby z rovnice nevyplyval zaporny uv index
	  	{
			uva_index=0;
		}
	  dtostrf(uva_index, 2, 1, buffer2);//uva index na 2 cele a jedno desetinne cislo

	  uart_pstr("UVA: ");//posle UART do XBEE
		uart_pstr(buffer2);
		uart_pstr("\r\n");

	  	lcd_gotoxy(13,1);//posle na LCD
		lcd_put_string("UVA:");
		lcd_gotoxy(17,1);
		lcd_put_string(buffer2);
/*
		itoa(result, buffer1, 10);//kontrola bity
		lcd_gotoxy(0,3);
		lcd_put_string("A:");
		lcd_put_string(buffer1);
*/
		_delay_ms(200);




	  result = ReadADCEx(1); //Read Channel Number UVB, 1

	  uvb_index = (((result*2.5)/4096)/57000000);//vypocet proudu na diode UVB
	  uvb_index = (uvb_index / 0.0000000016923);//vypocet uve indexu podle rovnice trendu
	  //uvb_index = (uvb_index-0.2);//korekce
	  dtostrf(uvb_index, 2, 1, buffer2);//uvb index na 2 cele a jedno desetinne cislo

	  uart_pstr("UVB: ");
		uart_pstr(buffer2);
		uart_pstr("\r\n");
		uart_pstr("\r\n");

	  lcd_gotoxy(13,2);
		lcd_put_string("UVB:");
		lcd_gotoxy(17,2);
		lcd_put_string(buffer2);
		/*
		itoa(result, buffer1, 10);
		lcd_gotoxy(8,3);
		lcd_put_string("B:");
		lcd_put_string(buffer1);
*/
		_delay_ms(200);

}

void uart_config(void)
{
	//UCSRA = 0b00100000;	// vymazání zásobníku UDR
	UBRRH = 0; //(UBRR_VALUE>>8);
	UBRRL = 25; //UBRR_VALUE; 25=9600bd
	UCSRB = 0b10011000; //UCSRB |= (1 << TXEN) | (1 << RXEN); //povolit prijmac i vysilac a preruseni na prijem
	UCSRC = 0b10000110; //UCSRC |= (1 << URSEL)| (1 << UCSZ0) | (1 << UCSZ1); //8bit data, 1-stop
}


void switch_xbee(void)//prepina analog NXP switch na XBee
{
	DDRD|=(1<<PD3);
	PORTD&=(~(1<<PD3));
}

void switch_o2(void)//prepina analog NXP switch na O2
{
	DDRD|=(1<<PD3);
	PORTD|=(1<<PD3);
}

// Získání znaku
unsigned char uart_getc(void)
{
// Cekání na prijetí znaku
	while (!(UCSRA & (1<<RXC)));
	return UDR;
}

// Poslání znaku
void uart_putc(unsigned char uartdata)
{
// Cekání na vyprázdnení registru UDR
	while (!( UCSRA & (1<<UDRE)));
	UDR = uartdata;
}

void uart_pstr(char *s) {
    // loop through entire string
    while (*s) {
        uart_putc(*s);
        s++;
    }
}

void writeRTC(unsigned char adresa,unsigned char data)
{
	// data je nutné převést do BCD kódu pro zařízení
	// převod => každá číslice v desítkové soustavě odpovídá číslici v binární podobě
	// př. 23 => 2 = 0b0010; 3 = 0b0011; v BCD tedy platí 23 = 0b0010 0011
	// jednoduchá úprava s dělením 10
	data = ( ((((data/10)<<4)&0b01110000)|((data%10)&0b00001111)));

	i2c_start_wait(WRITE_adresa);	// adresace zařízení RTC
	i2c_write(adresa);				// adresace položky v zařízení RTC
	i2c_write(data);				// zapíši na sběrnici data
	i2c_stop();						// ukončím komunikaci na sběrnici
}

void readRTC (unsigned char adresa)		// pošlu adresaci položky k vyčtení z RTC
{
	i2c_start_wait(WRITE_adresa);		// adresace zařízení pro zápis
	i2c_write(adresa);					// adresace položky na danném zařízení
	i2c_rep_start(READ_adresa);			// načtení adresy pro čtení
	hodnota = i2c_readNak();
	i2c_stop();
}



void time(void)
{
	// vyčtení hodnot z RTC
	readRTC(hodiny_A);
	hodiny = (	(((hodnota&0x30)>>4)*10)	+(hodnota&0x0F)	);
	readRTC(minuty_A);
	minuty = ((((hodnota&0x70)>>4)*10)	+(hodnota&0x0F)	);
	readRTC(sekundy_A);
	sekundy = ((((hodnota&0x70)>>4)*10)	+(hodnota&0x0F)	);
	readRTC(dny_A);
	dny = ((((hodnota&0x30)>>4)*10)	+(hodnota&0x0F)	);
	readRTC(mesic_A);
	mesic = ((((hodnota&0x10)>>4)*10)	+(hodnota&0x0F)	);
	readRTC(rok_A);
	rok = ((((hodnota&0xF0)>>4)*10)	+(hodnota&0x0F)	);
	readRTC(den_A);
	den = (hodnota&0x07);


	switch (den)
	{
		case 0:	uart_pstr("Ne");
				break;
		case 1:	uart_pstr("Po");
				break;
		case 2: uart_pstr("Ut");
				break;
		case 3: uart_pstr("St");
				break;
		case 4: uart_pstr("Ct");
				break;
		case 5: uart_pstr("Pa");
				break;
		case 6: uart_pstr("So");
				break;
	}


	uart_pstr(" ");
	itoa(dny, buffer1, 10);
	uart_pstr(buffer1);
	uart_pstr(". ");
	itoa(mesic, buffer1, 10);
	uart_pstr(buffer1);
	uart_pstr(". ");
	uart_pstr("20");
	itoa(rok, buffer1, 10);
	uart_pstr(buffer1);

	itoa(hodiny, buffer1, 10);//prevede zobrazi a posle hodiny
	lcd_gotoxy(15,3);
	lcd_put_string(buffer1);
	uart_pstr(" ");
	uart_pstr(buffer1);
	lcd_gotoxy(17,3);//dvojtecka
	lcd_put_string(":");
	uart_pstr(":");
	itoa(minuty, buffer1, 10);//prevede zobrazi a posle minuty
	lcd_gotoxy(18,3);
	lcd_put_string(buffer1);
	uart_pstr(buffer1);
	uart_pstr("\r\n");
	uart_pstr("\r\n");
	_delay_ms(100);


}
