#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include <math.h>
#include "rfm02.h"
#include "sht.h"

//********************** DEFINICE PINU A STAVU ********************************

#define LENGTH_MSG      20

#define SDI             PB3
#define SDI_PORT       PORTB
#define SDI_DDR        DDRB

#define FSK             PB1
#define FSK_PORT       PORTB
#define FSK_DDR        DDRB

#define SCK             PB5
#define SCK_PORT       PORTB
#define SCK_DDR        DDRB

#define nIRQ            PD2      
#define nIRQ_PORT      PORTD
#define nIRQ_DDR       DDRD
#define nIRQ_PIN       PIND

#define nSEL            PB2
#define nSEL_PORT      PORTB
#define nSEL_DDR       DDRB

#define LED             PC0
#define LED_PORT       PORTC
#define LED_DDR        DDRC

// interni stavove definice
#define SDI_H           SDI_PORT |= _BV(SDI)
#define SDI_L           SDI_PORT &= (~(_BV(SDI)))
#define SDI_INIT        SDI_DDR |= _BV(SDI)

#define FSK_H           FSK_PORT |= _BV(FSK)
#define FSK_L           FSK_PORT &= (~(_BV(FSK)))
#define FSK_INIT        FSK_DDR |= _BV(FSK)

#define SDO_INPUT       (SDO_PIN & _BV(SDO))
#define SDO_INIT        SDO_DDR &= (~(_BV(SDO)))

#define SCK_H           SCK_PORT |= _BV(SCK)
#define SCK_L           SCK_PORT &= (~(_BV(SCK)))
#define SCK_INIT        SCK_DDR |= _BV(SCK)

#define nIRQ_INPUT      (nIRQ_PIN & _BV(nIRQ))
#define nIRQ_INIT       nIRQ_DDR &= (~(_BV(nIRQ)))

#define nSEL_H          nSEL_PORT |= _BV(nSEL)
#define nSEL_L          nSEL_PORT &= (~(_BV(nSEL)))
#define nSEL_INIT       nSEL_DDR |= _BV(nSEL)

#define LED_L           LED_PORT |= _BV(LED)
#define LED_H           LED_PORT &= (~(_BV(LED)))
#define LED_INIT        LED_DDR |= _BV(LED)

#define START_TX        RF_WRITE_CMD(CMD_POWER|POWER_EX|POWER_ES|POWER_EA|POWER_DC)
#define STOP_TX         RF_WRITE_CMD(CMD_POWER|POWER_DC)

//*****************************************************************************

uint8_t test[LENGTH_MSG+1];					// definice delky prenosoveho slova
//uint8_t test[20]="11111111112222222222"; 	// testovaci zprava
float pokus[20];

//*****************************************************************************

enum {TEMP,HUMI}; 


void delay_ms(uint16_t time)
{
        while(time--) _delay_ms(1);
}


// inicializace pinu
void IO_INIT(void)	
{
        SDI_INIT;
        //SDO_INIT;
        SCK_INIT;
        nIRQ_INIT;
        nSEL_INIT;
        FSK_INIT;
        LED_INIT;
}


// inicializace RFM modulu
void RF_INIT(void)	
{
   nSEL_H;
   SDI_H;
   SCK_L;
   nIRQ_INPUT;
   //SDO_INPUT;
   FSK_H;
}


// zapis 16bit. prikazoveho slova do RFM
void RF_WRITE_CMD(uint16_t cmd)	
{
   uint8_t i;

   SCK_L;
   nSEL_L;
   for (i=0;i<16;i++)
   {
      SCK_L;
          SCK_L;
      if (cmd & 0x8000) SDI_H;
      else SDI_L;
          SCK_H;
      SCK_H;
      cmd <<= 1;
   }
   SCK_L;
   nSEL_H;
}


// zapis dat do RFM modulu
void RF_WRITE_DATA(uint8_t data) 
{
        uint8_t i;
        
        for (i=0;i<8;i++)
        {
	        while (nIRQ_INPUT);
	        while (!nIRQ_INPUT);
	        if (data & 0x80)FSK_H;
	        else FSK_L;
	        data <<= 1;
        }
}


// zapis bytu na sbernici SHT a kontrola ACK  
char s_write_byte(unsigned char value) 
{  
  unsigned int i,error = 0;   
  
  for (i=0x80;i>0;i/=2)             
  {
	  if (i & value) SDA_H;          
	  else SDA_L;                         
	  _delay_us(1);                       
	  SCL_H;                          
	  _delay_us(3); // ochranny interval    
	  SCL_L; 
	  _delay_us(1);                  
  }
   
  SDA_H;                           
  _delay_us(1);            
  SCL_H;         
  error = SDA;	// kontrola ACK 
  SCL_L;  
         
  return error;	// vraci hodnotu 1 pri noACK
} 


// cteni dat ze sbernice cidla
char s_read_byte(unsigned char ack) 
{  
	  unsigned char i,val=0; 
	  SDA_H;                           
	  for (i=0x80;i>0;i/=2)             
	  { SCL_H;                          
	    if (SDA) val=(val | i); 
	    SCL_L;         
	  } 
  
	  if(ack==1) SDA_L;
	  else SDA_H;
 	
	  _delay_us(1);                          
	  SCL_H;                           
	  _delay_us(3);           
	  SCL_L; 
	  _delay_us(1);                 
	  SDA_H;                          
	  return val; 
} 


// generovani startovaci specificke podminky
void s_transstart(void) 
{   
   SDA_H; SCL_L;                  
   _delay_us(1); 
   SCL_H; 
   _delay_us(1); 
   SDA_L; 
   _delay_us(1); 
   SCL_L;   
   _delay_us(3);
   SCL_H; 
   _delay_us(1); 
   SDA_H;      
   _delay_us(1); 
   SCL_L;      
}


// softwarovy reset sbernice
void s_connectionreset(void) 
{   
  unsigned char i;  
  SDA_H; SCL_L;                   
  for(i=0;i<9;i++)                
  { SCL_H; 
    SCL_L; 
  } 
  s_transstart(); // zacatek prensosu
} 


// softreset cidla
char s_softreset(void) 
{  
  unsigned char error=0;   
  s_connectionreset();              
  error+=s_write_byte(RESET);       
  return error;                     
} 


// cteni stavoveho registru a kontrolni soucet Checsum SHT
char s_read_statusreg(unsigned char *p_value, unsigned char *p_checksum) 
{  
  unsigned char error=0; 
  s_transstart();                   // zacatek prenosu
  error=s_write_byte(STATUS_REG_R); // vyslani prikazu k senzoru
  *p_value=s_read_byte(ACK);        // cteni stavoveho registru
  *p_checksum=s_read_byte(noACK);   // kontrolni soucet
  return error;                  
} 


// zapis do stavoveho registru
char s_write_statusreg(unsigned char *p_value) 
{  
  unsigned char error=0; 
  s_transstart();                   
  error+=s_write_byte(STATUS_REG_W);
  error+=s_write_byte(*p_value);    // vyslani hodnoty registru
  return error;                    
} 
            

// provadeni samotneho mereni teploty a vlhkosti a kontrolni soucet
char s_measure(unsigned char *p_value, unsigned char *p_checksum, unsigned char 
mode) 
{  
  unsigned char error=0; 
  unsigned int i; 
  s_transstart();                   
  switch(mode){                     
    case TEMP : error+=s_write_byte(MEASURE_TEMP); break; 
    case HUMI : error+=s_write_byte(MEASURE_HUMI); break; 
    default     : break;   
  } 
  for (i=0;i<65535;i++) if(SDA==1) break; 
  if(SDA==1) error+=1;                
  *(p_value)  =s_read_byte(ACK);    // MSB
  *(p_value+1)=s_read_byte(ACK);    // LSB
  *p_checksum =s_read_byte(noACK);  
  return error; 
} 


// prepocet hodnot a jejich kompenzace dle datasheetu
void calc_sth11(float *p_humidity ,float *p_temperature) 
{
  const float C1=-2.0468;           
  const float C2=+0.0367;           
  const float C3=-0.0000015955;    
  const float T1=+0.01;            
  const float T2=+0.00008;          
  float rh=*p_humidity;             
  float t=*p_temperature;           
  float rh_lin;                     
  float rh_true;                    
  float t_C;                       
  t_C=t*0.01 - 40.1;                
  rh_lin=C3*rh*rh + C2*rh + C1;     
  rh_true=(t_C-25)*(T1+T2*rh)+rh_lin;  
  if(rh_true>100)rh_true=100;       
  if(rh_true<0.1)rh_true=0.1;        
  *p_temperature=t_C;              
  *p_humidity=rh_true;            
} 


// Vypocet rosneho bodu
float calc_dewpoint(float h,float t) 
{ 
  float k,dew_point ; 
  k = (log10(h)-2)/0.4343 + (17.62*t)/(243.12+t); 
  dew_point = 243.12*k/(17.62-k); 
  return dew_point; 
} 


// **************** MAIN *************


int main()
{
        uint8_t k,j,ChkSum;

        IO_INIT();
        RF_INIT();
        
        LED_H;
        delay_ms(100);

	// parametry vysilace
        RF_WRITE_CMD(CMD_STATUS);
        RF_WRITE_CMD(CMD_SETTING        |BAND_868       |C_12pF |TX_DEV_90);
        RF_WRITE_CMD(CMD_FREQUENCY      |FREQUENCY_868);
        RF_WRITE_CMD(0xD040);
        RF_WRITE_CMD(CMD_RATE           |RATE_19200);
        RF_WRITE_CMD(CMD_BATTERY        |TX_EBS);
        RF_WRITE_CMD(CMD_POWER          |POWER_DC);
        RF_WRITE_CMD(POWER_OUT_0);

        j= 0;
	
	// definice promenych
	value humi_val,temp_val; 
  	float dew_point; 
  	unsigned char error,checksum; 
	unsigned int i; 

  	s_connectionreset();

        while (1)		// zacatek nekonecne smycky
        {
               
			// vycet namerenych hodnot a jejich formatovani
			error=0; 
		    error+=s_measure((unsigned char*) &humi_val.i,&checksum,HUMI);  
		    error+=s_measure((unsigned char*) &temp_val.i,&checksum,TEMP);  
		    if(error!=0) s_connectionreset();        
		    else 
		    { humi_val.f=(float)humi_val.i;                  
		      temp_val.f=(float)temp_val.i;                   
		      calc_sth11(&humi_val.f,&temp_val.f);             
		      dew_point=calc_dewpoint(humi_val.f,temp_val.f);
		      printf("T:%4.1fC H:%4.1f%% DP:%4.1fC\n",temp_val.f,humi_val.f,dew_point); 
		    } 

		_delay_ms(800); // ochranny interval nutny v pripade vyhrivani cidla	   
		

        LED_L;	// indikace vysilani pomoci led
		_delay_ms(60);
    	LED_H;        
                

        START_TX;
        ChkSum = 0;
        for (k=0;k<3;k++) RF_WRITE_DATA(0xAA);  
        RF_WRITE_DATA(0x2D);
        RF_WRITE_DATA(0xD4);
      
        for (k=0;k<LENGTH_MSG;k++)
        {
                RF_WRITE_DATA(test[k]);
                ChkSum += test[k];
        }
        RF_WRITE_DATA(ChkSum);
        RF_WRITE_DATA(0xAA);
        RF_WRITE_DATA(0xAA);
        STOP_TX;

                
        }
        return 0;
}
