#include "main.h"

#define UINT8 unsigned char
#define UINT32 unsigned long
#define MAX_PACKET_LEN  32   //legfeljebb 32Byte payload a FIFO-ban

#define RED_LED PIN_C5 //Adást jelzo LED
#define GREEN_LED PIN_C3 //Vételt jelzo LED
#define CE   PIN_A2 //Chip Enable: a chip adjon-e vagy vegyen
#define CSN   PIN_C0 //Chip Select Not: az SPI figyeljen-e a parancsokra
#define SCK   PIN_C1 //SPI ClocK: órajel a hardveres vezérléshez
#define MISO PIN_A5 //Master In Slave Out: lekérdezés
#define MOSI PIN_C2 //Master Out Slave In: parancsok

#define RED_LED_OUT() TRISC5=0   //adás LED kimenet
#define HI_RED_LED()   Output_high(RED_LED)
#define LOW_RED_LED() Output_low(RED_LED)

#define GREEN_LED_OUT() TRISC3=0 //vétel LED kimenet
#define HI_GREEN_LED()  Output_high(GREEN_LED)
#define LOW_GREEN_LED() Output_low(GREEN_LED)

#define CE_OUT() TRISA2=0    //CE kimenet
#define HI_CE()   Output_high(CE)
#define LOW_CE() Output_low(CE)

#define CSN_OUT()  TRISC0=0    //CSN kimenet
#define HI_CSN()   Output_high(CSN)
#define LOW_CSN()  Output_low(CSN)

#define SCK_OUT()  TRISC1=0    //vezérlő órajel kimenet
#define HI_SCK()   Output_high(SCK)
#define LOW_SCK()  Output_low(SCK)

#define MISO_IN()   TRISA5=1  //lekérdezés bemenet
#define MISO_HI()   input(MISO)

#define MOSI_OUT()  TRISC2=0    //parancs kimenet
#define HI_MOSI()   Output_high(MOSI)
#define LOW_MOSI()  Output_low(MOSI)

// fontosabb parancsok
#define READ_REG         0x00 //regiszterbol olvas: 001xxxxx, ahol x=cím
#define WRITE_REG       0x20 //regiszterbe ír: 001xxxxx, ahol x=cím
#define RD_RX_PLOAD     0x61 //kiolvas 32B adatot az Rx FIFO-ból
#define FLUSH_TX         0xE1 //kiüríti Tx FIFO-t
#define FLUSH_RX         0xE2 //kiüríti Rx FIFO-t
#define W_TX_PAYLOAD_NOACK_CMD 0xb0 //kikapcsolja a nyugtázást
#define ACTIVATE_CMD 0x50 //a feature regisztereket ki/be kapcsolja
#define R_RX_PL_WID_CMD 0x60 //lekérdezi az Rx FIFO hosszát: 01100000

// fontosabb regiszter címek
#define CONFIG           0x00 //CONFIG regiszter címe (Bank0)
#define STATUS           0x07 //STATUS regiszter címe (Bank0)
#define FIFO_STATUS     0x17 //FIFO_STATUS regiszter címe (Bank0)
#define FEATURE 0x1D //FEATURE regiszter címe (Bank0)

//fontosabb állapot értékek
#define STATUS_RX_DR 0x40 //ha a STATUS regiszterben az RX_DR bit=1
#define FIFO_STATUS_TX_FULL   0x20 //ha a FIFO_STATUS regiszterben a TX_FULL=1
#define FIFO_STATUS_RX_EMPTY 0x01 //ha a FIFO_STATUS regiszterben az RX_EMPTY=1

const UINT32 Bank1_Reg0_13[]={ //Bank1-ben az értékek sorrendje: MSB byte -> LSB byte
0xE2014B40, //00 = 40.4B.01.E2 - kötelezo érték
0x00004BC0, //01 = C0.4B.00.00 - kötelezo érték
0x028CFCD0, //02 = D0.FC.8C.02 - kötelezo érték
0x41390099, //03 = 99.00.39.41 - kötelezo érték
0x0B869ED9, //04 = D9.9E.86.0B - kötelezo érték
0xA67F0624, //05 = 24.06.7F.A6 - kötelezo érték
0x00000000, //06 = 00.00.00.00 - lefoglalt
0x00000000, //07 = 00.00.00.00 - lefoglalt
0x63000000, //08 = 00.00.00.63 - csak olvasni lehet (chip ID)
0x00000000, //09 = 00.00.00.00 - lefoglalt
0x00000000, //0A = 00.00.00.00 - lefoglalt
0x00000000, //0B = 00.00.00.00 - lefoglalt
0x00127300, //0C = 00.73.12.00 - 120us mód, Dynamic compatible
0x36B48000};//0D = 00.80.B4.36 - kötelezo érték

const UINT8 Bank1_Reg14[]={ //FF.EF.7D.F2.08.08.20.82.04.10.41 - kötelezo érték
0x41,0x10,0x04,0x82,0x20,0x08,0x08,0xF2,0x7D,0xEF,0xFF};

const UINT8 Bank0_Reg[][2] ={ //Bank0-ban az értékek sorrendje: LSB byte -> MSB byte
{0,0x03},  //00-CONFIG:    00000011 = PRX, bekapcs, nincs CRC
{1,0x00},  //01-EN_AA:     00000000 = nem nyugtáz semmit sem
{2,0x01},  //02-EN_RXADDR: 00111111 = csak az adatpipe0 címet használjuk
{3,0x03},  //03-SETUP_AW:  00000011 = 5 byte cimhossz
{4,0x00},  //04-SETUP_RETR:00000000 = újraküldés kikapcs
{5,0x00},  //05-RF_CH:     00000000 = 2400+0=2400MHz
{6,0x07},  //06-RF_SETUP:  00000111 = 1Mbps; 5dBm sugárzás; magas nyereség
{7,0x00},  //07-STATUS:    00000000 = csak olvasni lehet
{28,0x3F}, //1C-DYNPD:    00111111 = dinamikus payload mindenik pipe-nak
{29,0x07}};//1D-FEATURE:   00000111 = dinamikus payload hossz bekapcs; Payload nyugtával és anélkül 

const UINT8 RX0_Address[]={0xE7,0xE7,0xE7,0xE7,0xE7};//0A - pipe0 vételi címei és a Tx adási címei

void Initialize(void);
void Send(void); 
void Receive(void);
void RFM73_Initialize(void);
void SwitchToTxMode(void);
void SwitchToRxMode(void);
UINT8 SPI_RW(UINT8 value);
void SPI_Write_Reg(UINT8 reg, UINT8 value); 
UINT8 SPI_Read_Reg(UINT8 reg);
void SPI_Read_Buf(UINT8 reg, UINT8 *pBuf, UINT8 length); 
void SPI_Write_Buf(UINT8 reg, UINT8 *pBuf, UINT8 length);
void SwitchCFG(char _cfg);

const UINT8 tx_buf[17] ={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,
0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x78}; //küldendo adat, az utolsó byte az ellenörzoösszeg
UINT8 rx_buf[MAX_PACKET_LEN];

//********************************************************************************************************
int main(void)
{
delay_ms(1000); //bekapcsolási késés 1mp
  Initialize(); //portok, regiszterek inicializálása
while(1)
{
//Send();
Receive();
}
}

//--------------------------------------------------------------------------------------------------------
void Initialize(void) //inicializáló függvény
{
CE_OUT(); //adás/vétel inicializáló kimenet
CSN_OUT(); //SPI inicializáló kimenet
SCK_OUT(); //órajel kimenet
MISO_IN(); //nyugta bemenet
MOSI_OUT(); //parancs kimenet
RED_LED_OUT(); //adó LED kimenet
GREEN_LED_OUT(); //vevo LED kimenet
LOW_CE(); //nincs se adás se vétel
HI_CSN(); //nincs SPI kommunikáció
LOW_SCK(); //nincs órajel
LOW_MOSI(); //nincs parancs
LOW_RED_LED(); //adó LEd kikapcs
LOW_GREEN_LED(); //vevo LED kikapcs
RFM73_Initialize();     //adatbankok feltöltése, vevo üzemmód
}

//--------------------------------------------------------------------------------------------------------
void Send(void) //adó függvény
{
      UINT8 i,fifo_sta;
      UINT8 temp_buf[32];

      for(i=0;i<17;i++)
            temp_buf[i]=tx_buf[i]; //a küldendo 17 byte eltárolása
     
      SwitchToTxMode(); //adó üzemmód
      fifo_sta=SPI_Read_Reg(FIFO_STATUS);   //FIFO állapotának lekérdezése
      if((fifo_sta&FIFO_STATUS_TX_FULL)==0)//ha nem üres (TX_EMPTY=1 => full)
      {
            HI_RED_LED(); //akkor bkapcsol a piros LED 30 miliszekundumig
            SPI_Write_Buf(W_TX_PAYLOAD_NOACK_CMD, temp_buf, 17); //adatok FIFO-ba írása
            delay_ms(30);
            LOW_RED_LED();
            delay_ms(30);
      }
}

//--------------------------------------------------------------------------------------------------------
void Receive(void) //vevo függvény
{
      UINT8 len,sta,fifo_sta,chksum;
      UINT8 rx_buf[MAX_PACKET_LEN];

      sta=SPI_Read_Reg(STATUS);       //állapotregiszter kiolvasása
   
      if((STATUS_RX_DR&sta) == STATUS_RX_DR)  //ha új adat került a FIFO-ba
      {
            do
            {
                  len=SPI_Read_Reg(R_RX_PL_WID_CMD);  //csomaghossz lekérdezése

                  if(len<=MAX_PACKET_LEN)     //ha a csomag mérete megfelelo
                        SPI_Read_Buf(RD_RX_PLOAD,rx_buf,len); //akkor a FIFO kiolvasása
                  else
                        SPI_Write_Reg(FLUSH_RX,0);          //különben a FIFO kiüríése

                  fifo_sta=SPI_Read_Reg(FIFO_STATUS); //maradt-e még a FIFO-ban valami
                                         
            }while((fifo_sta&FIFO_STATUS_RX_EMPTY)==0); //ismételd míg üres nem lesz
           
            chksum = rx_buf[0]+rx_buf[1]+rx_buf[2]+rx_buf[3]+rx_buf[4]+rx_buf[5]+rx_buf[6]+
                  +rx_buf[7]+rx_buf[8]+rx_buf[9]+rx_buf[10]+rx_buf[11]+rx_buf[12]+rx_buf[13]+
                  +rx_buf[14]+rx_buf[15]; //ellenörzoösszeg kiszámítása
           
            if(chksum==rx_buf[16]&&rx_buf[0]==0x30) //ha az ellenörzoösszeg és az elso byte stimel
            {
                  HI_GREEN_LED();//akkor bekapcsolja a zöld LEDet
                  delay_ms(30);
                  LOW_GREEN_LED();
                  delay_ms(30);
            }
            SwitchToRxMode(); //adó üzemmód és egyben a FIFO kiürítése
      }
      SPI_Write_Reg(WRITE_REG|STATUS,sta);//RX_DR,TX_DS,MAX_RT megszakításjelzo bitek kikapcs
}

//--------------------------------------------------------------------------------------------------------
UINT8 SPI_RW(UINT8 value) //parancsadó és választ fogadó függvény
{                                                          
      UINT8 bit_ctr;
     
      for(bit_ctr=0;bit_ctr<8;bit_ctr++)  //a "value" bitenkénti átjárása
      {   //mindig a MSB bitet adjuk
            if(value & 0x80) HI_MOSI(); else LOW_MOSI(); //parancs bitek
            value = (value << 1);           //következo bit betolása a MSB-be
            HI_SCK();                                 //órajel félciklus
            if(MISO_HI()) value |= 0x01;    //a visszajelzo bitek betöltése "value"-ba
            LOW_SCK();                           //órajel félciklus
      }
      return(value);                           //a visszajelzés visszatérítése
}

//--------------------------------------------------------------------------------------------------------
void SPI_Write_Reg(UINT8 reg, UINT8 value) //"reg" címu regiszterbe írja a "value"-t
{    //az írás sorrendje: parancs(regisztercím) és parancs(érték)
      LOW_CSN();       //az SPI parancs elején a CSN alacsony kell legyen
      SPI_RW(reg);     //regiszter kiválasztása
      SPI_RW(value);   //az érték beleírása
      HI_CSN();        //az SPI parancs magas CSN-el zárul
}  

//--------------------------------------------------------------------------------------------------------
UINT8 SPI_Read_Reg(UINT8 reg) //kiolvassa "reg" regiszter tartalmát és visszatéríti
{                                                          
      UINT8 value;
     
      LOW_CSN();          //SPI parancs eleje
      SPI_RW(reg);        //regiszter kiválasztása
      value = SPI_RW(READ_REG);  //az érték kiolvasása
      HI_CSN();           //SPI parancs vége
      return(value);      //a kiolvasott érték visszatérítése
}

//--------------------------------------------------------------------------------------------------------
void SPI_Read_Buf(UINT8 reg, UINT8 *pBuf, UINT8 length)
{        //"reg" regiszterbol kiolvassa a "length" hosszúságú "pBuf" tömböt
      UINT8 byte_ctr;                             
 
      LOW_CSN();                    //SPI parancs eleje
      SPI_RW(reg);                  //regiszter kiválasztása
      for(byte_ctr=0;byte_ctr<length;byte_ctr++) //a tömb minden eleme egy-egy byte
            pBuf[byte_ctr] = SPI_RW(READ_REG);  //az érték kiolvasása
      HI_CSN();                     //SPI parancs vége
}

//--------------------------------------------------------------------------------------------------------
void SPI_Write_Buf(UINT8 reg, UINT8 *pBuf, UINT8 length)   
{        //"reg" regiszterbe beleírja a "length" hosszúságú "pBuf" tömböt
      UINT8 byte_ctr;                             
 
      LOW_CSN();                    //SPI parancs eleje
      SPI_RW(reg);                  //regiszter kiválasztása
      for(byte_ctr=0; byte_ctr<length; byte_ctr++) //a tömb minden eleme egy-egy byte
            SPI_RW(*pBuf++);        //az érték beleírása                         
      HI_CSN();                     //SPI parancs vége
}

//--------------------------------------------------------------------------------------------------------
void SwitchToRxMode() //átvált Rx üzemmódba (PRIM_RX=1 és CE=1)
{
      UINT8 value;
     
      SPI_Write_Reg(FLUSH_RX,0);    //Rx FIFO kiürítése
      LOW_CE();                     //standby-I üzemmód
      value=SPI_Read_Reg(CONFIG);   //a konfigurációs bitek
      value=value|0x01;             //melyek közül az elsot 1-re állítjuk (PRX üzemmód)
      SPI_Write_Reg(WRITE_REG | CONFIG, value); //a megváltoztatott érték visszatöltése
      HI_CE();                      //CE=1
}

//--------------------------------------------------------------------------------------------------------
void SwitchToTxMode() //átvált Tx üzemmódba (PRIM_RX=0 és CE=1)
{
      UINT8 value;
     
      SPI_Write_Reg(FLUSH_TX,0);  //Tx FIFO kiürítése
      LOW_CE();                   //standby-I üzemmód
      value=SPI_Read_Reg(CONFIG); //a konfigurációs bitek
      value=value&0xfe;           //melyek közül az elsot 0-ra állítjuk (PTX üzemmód)
      SPI_Write_Reg(WRITE_REG | CONFIG, value); //a megváltoztatott érték visszatöltése
      HI_CE();                    //CE=1
}

//--------------------------------------------------------------------------------------------------------
void SwitchCFG(char _cfg) //váltogatás a bankok között: 1=Bank1 0=Bank0
{
      UINT8 Tmp;

      Tmp=SPI_Read_Reg(STATUS);     //állapotregiszter bitjei
      Tmp=Tmp&0x80;                 //melyek közül a hetedik (MSB) jelzi a bankot

      if( ( (Tmp)&&(_cfg==0) )||( ((Tmp)==0)&&(_cfg) ) ) //ha nem ugyanarra történik a váltás
            SPI_Write_Reg(ACTIVATE_CMD,0x53); //akkor váltson át a másikra
}

//--------------------------------------------------------------------------------------------------------
void RFM73_Initialize()
{
      UINT8 i,j;
      UINT8 WriteArr[12];

      delay_ms(100);
     
      SwitchCFG(0); //-----------------------------Bank0-----------------------------------------

      for(i=0;i<8;i++) // a Bank0_Reg tömb elso 8 elemének betöltése a Bank0-ba
            SPI_Write_Reg((WRITE_REG|Bank0_Reg[i][0]),Bank0_Reg[i][1]);

      for(j=0;j<5;j++) //Bank0 0A regisztere: az 5 byte-os pipe0 címe
            WriteArr[j]=RX0_Address[j];
      SPI_Write_Buf((WRITE_REG|10),&(WriteArr[0]),5);

      for(j=0;j<5;j++) //Bank0 10 regisztere: a Tx cím ugyanaz kell legyen mint a pipe0 vételi címe
            WriteArr[j]=RX0_Address[j];
      SPI_Write_Buf((WRITE_REG|16),&(WriteArr[0]),5);
     
      i=SPI_Read_Reg(FEATURE);//a FEATURE regisztert kiolvasva
      if(i==0)                       //ha mindenik bitje 0, akkor nem volt aktiválva
            SPI_Write_Reg(ACTIVATE_CMD,0x73); //és aktiválni kell
           
      for(i=9;i>=8;i--) //a FEATURE aktiválása után betöltjük az értékeket
            SPI_Write_Reg((WRITE_REG|Bank0_Reg[i][0]),Bank0_Reg[i][1]);
     
      SwitchCFG(1);  //-----------------------------Bank1-----------------------------------------
     
      for(i=0;i<=8;i++)//a Bank1 0-8 regisztereiben a byte-ok fordított sorrendben vannak (MSB->LSB)
      {
            for(j=0;j<4;j++) //4 byte-os regiszterek vannak a Bank1-ben
                  WriteArr[j]=Bank1_Reg0_13[i]>>(8*(j));
            SPI_Write_Buf((WRITE_REG|i),&(WriteArr[0]),4);
      }

      for(i=9;i<=13;i++)//a Bank1 9-13 regisztereiben a sorrend LSB->MSB
      {
            for(j=0;j<4;j++)
                  WriteArr[j]=Bank1_Reg0_13[i]>>(8*(3-j));
            SPI_Write_Buf((WRITE_REG|i),&(WriteArr[0]),4);
      }

      for(j=0;j<11;j++) //Bank1 0E regisztere 11 byte hosszú
            WriteArr[j]=Bank1_Reg14[j];
      SPI_Write_Buf((WRITE_REG|0x0E),&(WriteArr[0]),11);

      delay_ms(50);
      SwitchCFG(0);
      SwitchToRxMode(); //Alapállás a vevo üemmód
}
