/********************************************************************
* FileName:        Transceiver.c
* Company:         KRALICEK
*
*
* Author Martin Kralicek				Date 8/4/2010        Comment
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
********************************************************************/

//	Including
//===================================================================
#include <avr/io.h>							// Hlavickovy soubor popisujici microcontroler
#include <avr/interrupt.h>	
#include <stdio.h>
#include <util/delay.h>
#include "Transceiver.h"
//===================================================================


// Declaration
//==============================================================
volatile N_ROTE_paket Paket_out, Paket_in;
unsigned char ID_RX, my_ID;
volatile unsigned char Receiv_int;


//	Function
//===================================================================
/********************************************************************
*    Function Name:  delay                              	    *
*    Return Value:   void                                           *
*    Parameters:     cas					    *
*    Description:    Pauza vykonavajici prazdne cykly		    *
*    								    *
********************************************************************/
void delay(unsigned int cas)
{
	while(--cas){
		asm("nop");
	}
}

/********************************************************************
*    Function Name:  Init_Transceiver                               *
*    Return Value:   void                                           *
*    Parameters:     void					    *
*    Description:    Nastaveni modulu a komunikace s modulem        *
*    								    *
********************************************************************/
void Init_Transceiver(void)
{
//	Start_SPI();
    Start_SPI_soft();							//Nastaveni softwarove SPI komunikace
	Start_Inter();							//Nastaveni preruseni od RF modulu pro prijem
	delay(200);
	Low_power();							//Nastaveni RF modulu do Low Power modu
	delay(200);
	Init_RF();							//Aktivace RF modulu a jeho nastaveni pro komunikaci
	delay(200);
	FIFO_reset();							//Reset prijimaci pametu RF modulu
  	delay(200);
  	Write_cmd(0x0000);
  	Write_cmd(0x0000);
	delay(200);



}


/********************************************************************
*    Function Name:  Start_SPI                                      *
*    Return Value:   void                                           *
*    Parameters:     void                                           *
*                                                                   *
*    Description:    Konfigurace SPI komunikace                	    *
*    								    *
********************************************************************/
void Start_SPI(void){

	DDRB  = 0b00000010;						//Nastaveni vstupu/vystupu
	PORTB = 0b00001001;						//Nastaveni pull-up pro vstupu/vystupu
	SPCR  = 0b01011011;	

}


/********************************************************************
*    Function Name:  Start_SPI_soft                                 *
*    Return Value:   void                                           *
*    Parameters:     void                                           *
*                                                                   *
*    Description:    Konfigurace softwarove SPI komunikace     	    *
*    								    *
********************************************************************/
void Start_SPI_soft(void){
    
    DDRB  = 0b10110010;							//Nastaveni vstupu/vystupu
	PORTB = 0b00000000;						//Nastaveni pull-up pro vstupu/vystupu
	
	CS_1;
	
}


/********************************************************************
*    Function Name:  Start_Inter                                    *
*    Return Value:   void                                           *
*    Parameters:     void                                           *
*                                                                   *
*    Description:    Konfigurace softwarove SPI komunikace     	    *
*    								    *
********************************************************************/
void Start_Inter(void)
{
	MCUCSR |= (1<<ISC2);						//Nastaveni preruseni na vzestupnou hranu
	GICR |= (1<<INT2);						//Aktivace preruseni INT2
}


/********************************************************************
*    Function Name:  Init_RF	                                    *
*    Return Value:   void                                           *
*    Parameters:     void					    *
*    Description:    Nastaveni RF modulu                            *
*    								    *
********************************************************************/
void Init_RF(void){

	  Write_cmd(0x80E7); 						// 868MHz, Tx, Rx FIFO, 12pF
	  Write_cmd(0x8299); 						// turn ON receiver, synthesizer, ocillator, Disables the clock output 
	  Write_cmd(0xA640);						// center frequency 860,32MHz
	  Write_cmd(0xC647); 						// 4.8kbps
	  Write_cmd(0x96A0);						// VDI, SLOW, 134kHz, 0dBm, -103dBm
	  Write_cmd(0xC2AC);						// automatically start, digital filter, DQD
	  Write_cmd(0xCAF1);						// interupt level 2
	  Write_cmd(0xCED4);									
	  Write_cmd(0xC483); 						// VDI=1, 
	  Write_cmd(0x9850); 						// modulation parameters, 90kHz, max POWER
	  Write_cmd(0xCC17);
	  Write_cmd(0xE000);						// wake-up time
	  Write_cmd(0xC800);						// Low Duty-Cycle
	  Write_cmd(0xC040);
}


/*********************************************************************
*       Function Name:  Low_power                                    *
*       Return Value:   void                                         *
*       Parameters:                                                  *
*       Description:    Vypne RF modul                               *
*********************************************************************/
void Low_power(void)
{
	  Write_cmd(0x8008);
	  Write_cmd(0x8201); 						// turn OFF krystal
	  Write_cmd(0xA640);
	  Write_cmd(0xC647);
	  Write_cmd(0x94A0);
	  Write_cmd(0xC22C);
	  Write_cmd(0xCA81);
	  Write_cmd(0xCED4);
	  Write_cmd(0xC430);
	  Write_cmd(0x9850);
	  Write_cmd(0xCC76);
	  Write_cmd(0xE000);
	  Write_cmd(0xC800);
	  Write_cmd(0xC040);
}


/*********************************************************************
*       Function Name:  Write_FSK                                    *
*       Return Value:   void                                         *
*       Parameters:     data (8bitů)                                 *
*       Description:    odešle data do modulu (vysílaná data)        *
*********************************************************************/
void Write_FSK(unsigned char data_m)
{
   while((SPI_int & (1 << IRQ)));					//cekani na ready modulu
   Write_cmd(0xB800 + data_m);						//odeslni dat
}


/*********************************************************************
*       Function Name:  FIFO_Reset                                   *
*       Return Value:   void                                         *
*       Parameters:                                                  *
*       Description:    reset zásobníku přijatých dat                *
*********************************************************************/
void FIFO_reset(void)
{
	   Write_cmd(0xCA81);
	   Write_cmd(0xCA83);
}


/*********************************************************************
*       Function Name:  receive_mode                                 *
*       Return Value:   void                                         *
*       Parameters:                                                  *
*       Description:    prijimaci mod                                *
*********************************************************************/
void receive_mode(void)
{
	  Write_cmd(0x8299); 						//!er,!ebb,ET,ES,EX,!eb,!ew,DC
	  Write_cmd(0x0000);
}


/*********************************************************************
*       Function Name:  transmit_mode                                *
*       Return Value:   void                                         *
*       Parameters:                                                  *
*       Description:    vysilaci mod                                 *
*********************************************************************/
void transmit_mode(void)
{
	  Write_cmd(0x8239); 						//!er,!ebb,ET,ES,EX,!eb,!ew,DC
	  Write_cmd(0x0000);
}


/*********************************************************************
*       Function Name:  rf_sleep                                     *
*       Return Value:   void                                         *
*       Parameters:                                                  *
*       Description:    rezim spanku                                 *
*********************************************************************/
void rf_sleep(void)
{
	  Write_cmd(0x8201); 						//!er,!ebb,ET,ES,EX,!eb,!ew,DC
	  Write_cmd(0x0000);
}


/*********************************************************************
*       Function Name:  Clr_VDI				             *
*       Return Value:   void                                         *
*       Parameters:                                                  *
*       Description:    vynulování pinu VDI                          *
*********************************************************************/
void Clr_VDI(void)
{
	   Write_cmd(0x8008);
	   Write_cmd(0x0000);
	   Write_cmd(0x80E7);
	   Write_cmd(0x0000);
}


/*********************************************************************
*       Function Name:  Rx_FIFO                                      *
*       Return Value:   void                                         *
*       Parameters:                                                  *
*       Description:                                                 *
*********************************************************************/
unsigned char Rx_FIFO(void)
{
   unsigned int data_rx, x=30;						//x - pocet opakovani pro prijem platných dat

   while(x--)								//smycka cekajici na platna data	
   {
     data_rx = Write_cmd(0x0000);					//vycteni prikazoveho bytu
     if((data_rx & 0x8000))						//overeni prikazu, ze jsou prijata data platna
     {
       data_rx = Write_cmd(0xB000);					//vycteni datoveho bytu
       return (data_rx & 0x00FF);					//maska a navrat datoveho bytu
     }
   }

   return 0;      							//navrat nula - ruseni zadna data
}  


/*********************************************************************
*       Function Name:  Write_cmd                                    *
*       Return Value:   void                                         *
*       Parameters:                                                  *
*       Description:    Funkce vysilani/prijem pro softwarove SPI    *
*********************************************************************/

unsigned int Write_cmd(unsigned int cmd)
{
  unsigned char i;
  unsigned int recv=0;
 
  SCK_0;								//nastaveni pinu SCK na nulu
  CS_0;									//nastaveni pinu CS na nulu
  delay(50);
  for(i=0;i<16;i++)							//cyklus vycitani a zapisu dat
  {
    if(cmd&0x8000)
      MDO_1;								//nastaveni pinu MDO na jednicku
    else
      MDO_0;								//nastaveni pinu MDO na nulu
	delay(1);
    SCK_1;								//nastaveni pinu SCK na jednicku
	delay(7);							//posun prijatych dat o jednicku do leva
    recv <<= 1;
    if((SPI_int & (1 << MDI)))
      recv |= 1;							//logicke pricteni jednicky k promene s prijatymi daty
    SCK_0;								//nastaveni pinu SCK na nulu
	delay(8);
    cmd <<= 1;								//posun odesílaných dat o jednicku do leva
  }
  CS_1;									//nastaveni pinu CS na jednicku
  return recv;								//navrat prijatych dat
  
}
/*
unsigned int Write_cmd(unsigned int cmd)
{

  reset:	
  	SPDR = (char)(cmd >> 8);
  	while(!(SPSR & 0x80))
  	{
  		if (!(SPSR & 0x40))
			goto reset;  
  	}

    return SPDR;

}
*/

/*********************************************************************
*       Function Name:  Send_paket                                   *
*       Return Value:   void                                         *
*       Parameters:                                                  *
*       Description:    Funkce odesilani N-ROTE paketu               *
*********************************************************************/
//	Paket_setting
//===================================================================
//DB7 - (1 = příkazy, 0 = data)
//DB6 - DB4 musí přijít v hodnotě 001 
//DB3 - DB0 => délka datového/příkazového bloku
//DB6 nastaví příjmač do 1, pokud souhlasí CRC, 
//DB5 nastaví příjmač pokud se adresa shoduje s adresou zařízení ; 
//DB4 nastaví příjmač do nuly, tím označí data za použitá, nepotřebná...
//=================================================================== 

void Send_paket(void)
{
    unsigned char x;
    unsigned int CRCin;
 
    cli();   								//zakazani preruseni
    FIFO_reset();							//reset prijimaci pametu RF modulu

    CRCin=0;
    transmit_mode();							//nastaveni RF modulu do vysilaciho modu
    delay(500);
    Write_cmd(0x0000);
    Write_FSK(0xAA);							//odesilani synchronizacnich dat
    Write_FSK(0xAA);
    Write_FSK(0xAA);
    Write_FSK(0x2D);
    Write_FSK(0xD4);
    Paket_out.Adr_RX = ID_RX;						//nastaveni adresy prijimace
    Paket_out.Adr_TX = my_ID;						//nastaveni vlastni identifikacni adresy
    Paket_out.Paket_setting = 0x1F;					//nastaveni setting paketu

    Write_FSK(Paket_out.Adr_RX);					//odeslani adresy prijimace
    Write_FSK(Paket_out.Adr_TX);					//odeslani vlastni identifikacni adresy
    Write_FSK(Paket_out.Paket_setting);					//odeslani setting paketu
    Write_FSK(Paket_out.Reserved);					//odeslani reserved paketu

    CRCin += Paket_out.Adr_RX;						//vypocet kontrolniho souctu
    CRCin += Paket_out.Adr_TX;
    CRCin += Paket_out.Paket_setting;
    CRCin += Paket_out.Reserved;

    for(x=0;x<11;x++)
    {
      Write_FSK(Paket_out.Data_buf[x]);					//odesilani datovych bytu
      CRCin += Paket_out.Data_buf[x];					//vypocet kontrolniho souctu
    }

    Paket_out.CRC = (unsigned char)CRCin;			
    Write_FSK(Paket_out.CRC);						//odeslani kontrolniho souctu

    Write_FSK(0xAA);							//odesilani synchronizacnich dat
    Write_FSK(0xAA);
    Write_FSK(0xAA);

  receive_mode();							//nastaveni RF modulu do prijimaciho modu
  FIFO_reset();								//reset prijimaci pametu RF modulu
  Clr_VDI();								//vynulování pinu VDI

  sei();								//povoleni preruseni
}


/*********************************************************************
*       Function Name:  Receiv_paket                                 *
*       Return Value:   void                                         *
*       Parameters:                                                  *
*       Description:    Funkce prijmu N-ROTE paketu                  *
*********************************************************************/
void Receiv_paket(void)
{
   unsigned char x;
   unsigned int CRC;

    cli();								//zakazani preruseni
	CRC=0;
    Paket_in.Adr_RX = Rx_FIFO();					//prijem paketu s RX adresou
    Paket_in.Adr_TX = Rx_FIFO();					//prijem paketu s TX adresou
    Paket_in.Paket_setting = Rx_FIFO();					//prijem setting paketu
    Paket_in.Reserved = Rx_FIFO();					//prijem reserved paketu

    CRC += Paket_in.Adr_RX;						//kotrolni soucet prijatych dat
    CRC += Paket_in.Adr_TX;
    CRC += Paket_in.Paket_setting;
    CRC += Paket_in.Reserved;

    for(x=0;x<11;x++)
    {
      Paket_in.Data_buf[x] = Rx_FIFO();					//prijem datovych paketu
      CRC += Paket_in.Data_buf[x];					//kotrolni soucet prijatych dat
    }
    Paket_in.CRC = Rx_FIFO();						//prijem kotrolniho souctu
    CRC &= 0x00FF;
    if ((unsigned char)CRC == Paket_in.CRC)       			//kontrola CRC...
    {
       Paket_in.Paket_setting |= 0x40;  				//data jou platná
    }
    if (my_ID == Paket_in.Adr_RX)					//kontrola adresy
    {
       Paket_in.Paket_setting |= 0x20;					//adresa vyhovuje my_ID
    }   
    FIFO_reset();							//reset prijimaci pametu RF modulu
    Clr_VDI();								//vynulování pinu VDI
	sei();								//povoleni preruseni
}


/*********************************************************************
*       Function Name:  Send_data                                    *
*       Return Value:   void                                         *
*       Parameters:                                                  *
*       Description:    Funkce odesilani dat			     *
*********************************************************************/
void Send_data(unsigned char *buffer, unsigned char size)
{
    unsigned char x;
 
    cli();   								//zakazani preruseni
    FIFO_reset();							//reset prijimaci pametu RF modulu

    transmit_mode();							//nastaveni RF modulu do vysilaciho modu
    _delay_us(500);
    Write_cmd(0x0000);
    Write_FSK(0xAA);							//odesilani synchronizacnich dat
    Write_FSK(0xAA);
    Write_FSK(0xAA);
    Write_FSK(0x2D);
    Write_FSK(0xD4);

    for(x=0;x<size;x++)							//odesilani datoveho bufferu
    {
      Write_FSK(*buffer);
      buffer++;
    }

    Write_FSK(0xAA);							//odesilani synchronizacnich dat
    Write_FSK(0xAA);
    Write_FSK(0xAA);

  receive_mode();							//nastaveni RF modulu do prijimaciho modu
  sei();								//povoleni preruseni
}


/*********************************************************************
*       Function Name:  Receiv_data                                  *
*       Return Value:   void                                         *
*       Parameters:                                                  *
*       Description:    Funkce prijmu dat			     *
*********************************************************************/
void Receiv_data(unsigned char *buffer, unsigned char size)
{
    unsigned char x;

    cli();								//zakazani preruseni
    for(x=0;x<size;x++)							//prijem dat do bufferu
    {
      *buffer = Rx_FIFO();
      buffer++;
    }
  
    FIFO_reset();							//reset prijimaci pametu RF modulu
    Clr_VDI();								//vynulování pinu VDI
	sei();								//povoleni preruseni
}


/*********************************************************************
*       Function Name:  ISR(INT1_vect)                               *
*       Return Value:   void                                         *
*       Parameters:                                                  *
*       Description:    Funkce preruseni od transceiveru             *
*********************************************************************/
ISR(INT2_vect)
{
	extern volatile unsigned char Receiv_int;
	extern volatile N_ROTE_paket Paket_in;
	
	delay(10000);							//pauza vylouci zakmity
	
	if ((SPI_int & (1 << INT)))					//overeni prijatych dat
	{
		LED_1;  						//rozsviceni kontrolni led

    	Receiv_paket();  						//prijem datoveho paketu
//		Receiv_data(*buffer, size);
		if ((Paket_in.Paket_setting & 0x20) == 0x20)		//overeni platnosti paketu
		{
			Receiv_int = 1;					//nastaveni priznaku prijmu
			REC_off;					//deaktivace prijimaciho preruseni
    	}

  	}
	LED_0;								//deaktivace kontrolni led

}



