/*
** ===================================================================
** Název souboru   : Base_unit.c
** Mikrokontroler  : ATmega128, 
** Popis           : Program pro Základnovou jednotku pristupoveho systemu BodyCom
**                 :  
** Autor           : Jan Kristel (kristel_ml@volny,cz)
**                 : xx.04.2014
** ===================================================================
*/


#define AVR_ATmega128A
#define F_CPU 8192000UL

#include "lcd_h.h"
#include "Base_unit.h"
#include "RFM12Bx.h"
#include "jk_xtea.h"



#include <avr/io.h>
#include <stdlib.h>
#include <avr/wdt.h>
#include <avr/interrupt.h> 
#include <util/delay.h>
#include <string.h>
#include <avr/sleep.h>
#include <avr/eeprom.h>

//------------proměne------

volatile unsigned char buffer_0[16];

volatile unsigned char mobile_ID[10];  // data z mobilni jednotky

volatile char unsigned buff_rf_rx[16];  // prijem dat RFM12B
volatile char unsigned buff_rf_tx[16];

volatile uint8_t flag_tag = 0; 
volatile uint8_t flag_rfm = 0;
volatile uint8_t tim = 0;              // promena na hodiny
volatile char rx_base_data [10];
//---------
volatile unsigned long  key_enc[4] = { 1234,7777,1234,5544};      // Klic pro Upload na Rf_USB data
volatile unsigned long  key_dec[4] = { 1234,7777,1234,4455};      // Klic pro Download z Rf_USB data
volatile unsigned long  key_dec_mob[4] = { 1234,7766,1234,2233};  // Klic pro desi. mobilni jed.
	
volatile unsigned char crypting_buffer[7];
volatile unsigned char buffer_dec [7];
volatile unsigned char buffer_dec_mob [7];

//----

void init()
{
//****************Interupt***********

EIFR=0x00;

//********************* UART *******************
// USART0 initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART0 Receiver: On
// USART0 Transmitter: On
// USART0 Mode: Asynchronous
// focs 8,192 Mhz
// USART0 Baud Rate: 1200
UCSR0A=0x00;
//UCSR0B=0x18; //puvodni 
UCSR0B=0x00;
UCSR0B |= (1<<TXEN0)|(1<<RXEN0);//|(1<<RXCIE0); //UCSR0B=0x18;  
UCSR0C |= (1<<UCSZ01)|(1<<UCSZ00);

unsigned int ubrr;

//ubrr = (fosc/16*baud)-1
ubrr = 0x01A9;
//UBRR UBRRH a UBRRL 0 - 4095

UBRR0H = (unsigned char)(ubrr>>8);// 0x01; //dec 426
UBRR0L = (unsigned char) ubrr ;  //0x01AA;

//---------------------

// DDRA -- LCD nastavuje knihovna
DDRB =  0b00010000;  // out mod osc PB4 out
DDRC =  0b00000011;  // PORT0,1 - RELE1,2
//DDRD = LF data - rezerva 
PORTE = 0x00;
DDRE =  0b00000010;  // USART
PORTF = 0b00001111;  // pull-up
DDRF =  0b00110000; //LED PF5 OUT  -- TL1-4 IN


//-------test init HW----

PORTF |= (1<<LED1);
_delay_ms(200);
PORTF &= ~(1<<LED1);
_delay_ms(200);
PORTF |= (1<<LED2);
_delay_ms(200);
PORTF &= ~(1<<LED2);
_delay_ms(200);

PORTC |= (1<<REL1);
_delay_ms(200);
PORTC &= ~(1<<REL1);
_delay_ms(200);
PORTC |= (1<<REL2);
_delay_ms(200);
PORTC &= ~(1<<REL2);
_delay_ms(200);

osc_rx_pwm_stop(); // stopne PWM gen.
beep(10);
init_eepr();
lcd_init();
lcd_clrscr();
lcd_gotoxy( 4,0 );
lcd_puts( "BodyCom");
lcd_gotoxy( 0,1 );
lcd_puts( "J.K. beta V.1.0  ");
_delay_ms(1200);
}


ISR(INT5_vect){ 
 //**********RFM12b - RX ***********
   EIMSK &= ~ (1<<INT5);
   EIFR=0x00;
   PORTF |= (1<<LED1); //indikace prijmu Blue LED 
  
   for (int i=0; i<14; i++)  { // prijima 16 znaky
     buff_rf_rx[i] = rfRecv();
     }
	  
   rffifo_reset(); // po prijmu vsech znaku reset FIFO RFM12B 
   flag_rfm = 1; // priznak prijmu
   PORTF &= ~(1<<LED1); 
//--------------------------------------
}   
   


void osc_rx_pwm()
{
	
//mod CTC, No prescaling  
  TCCR0 |= (1<<WGM01)|(1<<CS00)|(1<<COM00); 
 
  // CPU ofc 8,192MHz
  //Foc0 = fclk/(2*N*(1+OCRN0)) 
   OCR0 = 32; // 125Khz
 }

void osc_rx_pwm_stop()
{
	
//mod CTC, No prescaling  
  TCCR0 &= ~(1<<CS00); // stop Fclk 
}

unsigned char USART_receive_0(void){
//********* USART0 - RX *************
  	while(1)
	{
	  if(bit_is_set(UCSR0A,RXC0))   
	    {
	     return(UDR0);
	    }
		return(0);
	}
}

unsigned char USART_receive_0_char(void){
	//cte 8 znaku
uint8_t y = 1;
	
  	for (uint8_t x = 0 ; x<8; x++)
	{
	 y = 1;
	 	
	 while( y == 1 )
	 {
	  if(bit_is_set(UCSR0A,RXC0))    
	    {
	     rx_base_data [x] = UDR0;   //
	     y = 0 ; // pryc ze smycky - dalsi znak 
	    }
	 }	  	
	}
	
rx_base_data [8]= '\0';
}

void USART_send_0( unsigned char data){
	 
 while(!(UCSR0A & (1<<UDRE0)));
	 UDR0 = data;
}

void USART_putstring_0(volatile char* StringPtr){
		  
	 while(*StringPtr != 0x00){
	 USART_send_0(*StringPtr);
	 StringPtr++;}
}

void TX_data ()
{
//*****init MCP2030 wakeup TOEH =4ms TOEL = 4ms TOET = 10ms
 
    osc_rx_pwm(); // zapne OSC_TX
    _delay_ms(4);
    osc_rx_pwm_stop(); //vypne OSC
    _delay_ms(1);
   
   osc_rx_pwm();     // TOEH
   _delay_us(4500);
   osc_rx_pwm_stop(); //TOEL
   _delay_us(4500);
  
   osc_rx_pwm(); // zapne OSC_TX
   _delay_ms(1);  // start bit
 //-----------  musi poslat znovu 
   _delay_ms(10); // kvuli prehlednosti - toto
    osc_rx_pwm_stop(); //vypne OSC

   _delay_ms(50);
 
    osc_rx_pwm(); // zapne OSC_TX
    _delay_ms(4);
    osc_rx_pwm_stop(); //vypne OSC
	_delay_ms(1);
 
   
   osc_rx_pwm(); // TOEH
   _delay_us(4500);
   osc_rx_pwm_stop(); //TOEL
   _delay_us(4500);
  
   osc_rx_pwm(); // zapne OSC_TX
   
  // mobilni MCU probuzen dal platna DATA
   _delay_ms(1);  // start bit
  
  sprintf ( buffer_0 , "xxx*wake%"); // inicializacni data
  USART_putstring_0(buffer_0);
   	
  _delay_ms(10);
  osc_rx_pwm_stop(); //vypne OSC
	
}

unsigned int RX_data ()
{
//------------test prijem dat-----------

  unsigned int temp = 0;
  
 for (int i = 0 ; i < 1000 ; i++ )  {
  _delay_ms(1);  //bude cekaat 20 sec na prichozi znak
  temp = USART_receive_0();
  if (temp == '@')// ceka na synch znak
    {
	  USART_receive_0_char();	
	  i = 220;
	  if (rx_base_data[7] == '+')
	   {	   
	   flag_tag = 1; // nastavi priznak prijmu
	   }      
	} 
 }
 
 strcpy(mobile_ID, rx_base_data);
 
 }
 
void beep(unsigned int lng) {
// funkce pipaku s nastavitelnou delkou piskani 	
     for (int x = 0; x < lng; x++ )
	 { // generuje ton
	 PORTC |= (1<<BZ);    
     _delay_us(500);
     PORTC &= ~(1<<BZ);
     _delay_us(500);	
	}
 }



int main(void)
{
	
   
   init();
   portInit();
   rfInit();
   rfreceiver_mode(); 
   init_eepr();
  //-------
   sei();
  
  lcd_clrscr();
  lcd_gotoxy( 5,0 ); 	  //Presun kurzoru na pozici
  lcd_puts( "Ready");
  lcd_gotoxy( 6,1 ); 	  
  lcd_puts( "..."); 
  
	  	
   while(1)
   {
//-------------pro ladeni-----		
	 if (!(PINF & (1<<TL1)))
	
	  {
	  flag_tag = 1;	   //tlacitko
	  }

//------------------ jednoducha kostra programu ------

  TX_data (); // init mobil unit 
  RX_data (); // prijme data
   
   EIMSK|= (1<<INT5); //preruseni povol az po zpravovani
   
 
  if(flag_tag == 1) //odesle data pouze v pripade nacteni cipu
	{
	beep(10);	// akusticky signal precteni tagu

	//--------		
	EIMSK &= ~ (1<<INT5);  // TX - disable init0
	decode(buffer_dec, mobile_ID, key_dec_mob);
   if (1 == anti_replay(mobile_ID, EE_SHIFT_2)) 
 	 { 
      // --- prijde li stejny kod jako predchozi - nebude resit!!
  	
      lcd_clrscr(); 
      // lcd_gotoxy( 0,0 );
      // lcd_puts(buffer_dec); // ladeni  - vypis  ID
      lcd_gotoxy( 0,1 ); 	// info na LCD o stavu precteni klicenky  
      lcd_puts( "Verifying...");
	    
      rftransmitter_mode();
	  //--  delky slov cte 4x8bitu --- vraci -- 6x8bitu -- 
	  encode(crypting_buffer, buffer_dec, key_enc, EE_SHIFT_0); // Zasifruje
	  strcat(buff_rf_tx, "!ver00" ); // |start byte|prikaz|ID ctecky|
	  strcat(buff_rf_tx,crypting_buffer ); 

	  PORTF |= (1<<LED1); //indikace posilani Blue LED 
	  rfSend_char (buff_rf_tx);	   // posle ID mobile unit na server
	  _delay_ms(2);
	  PORTF &= ~(1<<LED1); 
      rfreceiver_mode();
	  buff_rf_tx[0] = '\0';
	 }	 
 

//-------------------cast komunikace s RFM12B-------------	 
	 flag_tag = 0 ;
	 EIMSK|= (1<<INT5);
	 }
    
 if(flag_rfm == 1) //pouze v pripade priznaku prijmu rfm12b
  {

	  
	flag_rfm = 0;
   //---------porovnat start znak a podle toho vykonat
   
    if (buff_rf_rx[0] == '!')
    {
	 for (uint8_t x = 0; x<5; x++){ crypting_buffer[x] =  buff_rf_rx[x+1];} // vyzobe sifr ID k desesifr.
      
       // desifruje 6bytu
	    decode(buffer_dec, crypting_buffer, key_dec);	
        if (1 == anti_replay(crypting_buffer, EE_SHIFT_1 ))  //pozor init eeprom
          {
		  
         //--- Cas na LCD  --- 
          lcd_clrscr();
          lcd_gotoxy( 1,0 ); 	  //Presun kurzoru na pozici (0,0)
          lcd_puts( "Time: ");
	      for (int i = 6; i<14; i++ )
          {
		    tim = buff_rf_rx[i];   
            lcd_putc(tim);
	       }
	   
	      if (buffer_dec[1]=='0') // overi zda prikaz patri teto jed
           {
   	       switch (buffer_dec[0]) // podle druheho znaku(prikazu) v poradi provede prikaz
           {
 	   case  '0': 
       rftransmitter_mode();
       strcat(buff_rf_tx, "!ping0" ); // odpovi na dotaz
	   rfSend_char (buff_rf_tx);	   // posle ID mobile unit na server
       rfreceiver_mode();
	   buff_rf_tx[0] = '\0'; // uklidi
	   break;
	  
       case  '1': 
       lcd_gotoxy( 1,1 ); 	  
       lcd_puts("Access denied");  // akusticky odmitnuto 
       beep(30);
	   _delay_ms(50);
       beep(30);
	   _delay_ms(50);
       beep(30);
	   _delay_ms(1500); // podrzi hlasku
	   break;
	 
	   case  '2': 
	   lcd_gotoxy( 1,1 ); 	  //Presun 
       lcd_puts("Access allowed");
	   
       beep(70);  // --- pipne potvrzeni-----
	   _delay_ms(70);
       beep(70);
	   
	   PORTC |= (1<<REL1);    // REL1 on 1,5 sec
       _delay_ms(1500);
       PORTC &= ~(1<<REL1);
       break;
	  
	   case  '3': 
       PORTC |= (1<<REL1);    // REL1 ON
	   break;
	  
	   case  '4': 
       PORTC &= ~(1<<REL1);    // REL1 OFF
	   break;
	   
	   case  '5': 
       PORTC |= (1<<REL2);    // REL2 ON
	   break;
	  
	   case  '6': 
       PORTC &= ~(1<<REL2);    // REL2 OFF
	   break;
	

	   case  '7':             // libovolna hlaska na LCD
       lcd_clrscr();
       lcd_gotoxy( 2,0 ); 	  //Presun kurzoru na pozici (0,0)
       lcd_puts( "System Info:");
	   lcd_gotoxy( 4,1 );
	   for (int i = 6; i<14; i++ )
       {
		tim = buff_rf_rx[i];   
        lcd_putc(tim);
	   }
	   _delay_ms(15000); // podrzi hlasku (mozna to pak resit priznakem)	   
	   break;
	
	
 	   case  '8':
	   lcd_clrscr(); 
  	   lcd_gotoxy( 5,0 ); 	  
       lcd_puts("system");
	   lcd_gotoxy( 1,1 );
       lcd_puts("out of service");
 	   _delay_ms(60000); // zatim pro ladeni
	   break;

          // Panika
 	  case  '9':
	  lcd_clrscr();
	  lcd_gotoxy( 0,1 ); 	  
      lcd_puts(">>>>>>>  <<<<<<<"); 
    
	  for (int i=0; i<100; i++)
      {
	    beep(80);
        _delay_ms(100);
	  }
 	 		
	  break;


	
	 }
   } 	 
 } // anti replay if
   	
  lcd_clrscr();
  lcd_gotoxy( 5,0 ); 	  //Presun kurzoru na pozici (0,0)
  lcd_puts( "Ready");
  lcd_gotoxy( 6,1 ); 	  //Presun kurzoru na pozici (0,0)
  lcd_puts( "...");
	
	
		
	 } 
   }
	 

 }

}
