/**************** Preprocessor Constants ***************************************/
#define CONFIG             0x20
#define EN_AA              0x21
#define EN_RXADDR          0x22
#define SETUP_AW           0x23
#define SETUP_RETR         0x24
#define RF_CH              0x25
#define RF_SETUP           0x26
#define STATUS             0x27
#define RX_ADDR_P0         0x2A
#define TX_ADDR            0x30
#define RX_PW_P0           0x31
#define FLUSH_TX           0xE1
#define FLUSH_RX           0xE2
#define TX_PAYLOAD         0xA0
#define RX_PAYLOAD         0x61
#define NO_OP              0xFF
#define ZERO               0x00
#define EOT                0x04
#define PAYLOAD_SIZE       0x20
#define start_transmit    {output_high(rf_CE);delay_us(20);output_low(rf_CE);}  //Pulse NRF24L01 CE pin for 20us

int1 rf_interrupt=false;                                                        // Declare interrupt flag default is false
static int16 rf_CE,rf_CSN;                                                      // Declare NRF24L01 SPI CE & CSN pins

/**************** Gets The Length Of A Data Packet *****************************/
unsigned int* length(unsigned int *data)
{
   int *cnt;                                                                    // Declare a pointer
   for (cnt = data; *cnt != 0; cnt++);                                          // Loop
   return(cnt - data);                                                          // Return the length of the data                             
}

/**************** Write To NRF24L01 Configuration Register *********************/
void set_register(unsigned int command,unsigned int data)
{
   output_low(rf_CSN);                                                          // Engage SPI chip select
   spi_write(command);                                                          // Write to register
   if(data!=NO_OP){spi_write(data);}                                            // Write data to register
   output_high(rf_CSN);                                                         // Dis-engage SPI chip select
   delay_us(10);
}

/**************** Write To NRF24L01 Configuration Register *********************/
void set_register(unsigned int command,unsigned int* data)
{
   int i,len;
   len=length(data);                                                            // Get the length of the data
   output_low(rf_CSN);                                                          // Engage SPI chip select
   spi_write(command);                                                          // Write to register
   for(i=0;i<len;i++){spi_write(data[i]);}                                      // Write data to register
   output_high(rf_CSN);                                                         // Dis-engage SPI chip select
   delay_us(10);
}

/**************** Enables NRF24L01 Transmit/Receive Mode ***********************/
void transmit_mode(unsigned int1 enable)
{
   output_low(rf_CE);                                                           // Disable receiver
   set_register(STATUS,0x7E);                                                   // Clear all interrupts
   if(enable)
   {
      set_register(FLUSH_TX,NO_OP);                                             // Flush TX FIFO buffer
      set_register(CONFIG,0x52);                                                // Power up in select transmit mode
   }
   else
   {
      set_register(FLUSH_RX,NO_OP);                                             // Flush RX FIFO buffer
      set_register(CONFIG,0x33);                                                // Power up in receive mode
      output_high(rf_CE);                                                       // Enable receiver
      delay_us(130);                                                            // Delay 130us
   }
}

/**************** Transmits A Single Byte **************************************/
void rf_transmit(unsigned int data)
{
   transmit_mode(true);                                                         // Enable transmit mode
   output_low(rf_CSN);                                                          // Engage SPI chip select
   spi_write(TX_PAYLOAD);                                                       // Select tx payload register
   spi_write(data);                                                             // Write data to tx payload register
   spi_write(EOT);                                                              // End of transmission
   output_high(rf_CSN);                                                         // Dis-engage SPI chip select
   start_transmit;                                                              // Start transmission
   transmit_mode(false);                                                        // Enable receive mode
   delay_ms(50);                                                                // Delay 50ms
}

/**************** Transmits A String Of Data ***********************************/
void rf_transmit(unsigned char *string)
{
   int i,len=0;
   len=length(string);                                                          // Get the length of the data to transmit
   transmit_mode(true);                                                         // Enable transmit mode
   output_low(rf_CSN);                                                          // Engage SPI chip select
   spi_write(TX_PAYLOAD);                                                       // Select tx payload register
   for(i=0;i<len;i++){spi_write(string[i]);}                                    // Write data to tx payload register
   spi_write(EOT);                                                              // End of transmission
   output_high(rf_CSN);                                                         // Dis-engage SPI chip select
   start_transmit;                                                              // Start transmission
   transmit_mode(false);                                                        // Enable receive mode
   delay_ms(50);                                                                // Delay 50ms
}

/**************** Receive RF Data **********************************************/
unsigned int* rf_receive()
{
      int i;
      static int rf_rx_buffer[PAYLOAD_SIZE]={0};                                // Declare a receive buffer 
      rf_interrupt = false;                                                     // Clear interrupt flag
      output_low(rf_CE);                                                        // Disable receiver
      output_low(rf_CSN);                                                       // Engage SPI chip select
      spi_write(RX_PAYLOAD);                                                    // Initialize RX payload register
      for(i=0;i<=PAYLOAD_SIZE;i++)                                       
      {
         rf_rx_buffer[i]=spi_read(RX_PAYLOAD);                                  // Copy data from NRF24L01 to buffer
         if(rf_rx_buffer[i]==EOT){rf_rx_buffer[i]=ZERO;break;}                  // Stop when EOT found
      }
      output_high(rf_CSN);                                                      // Dis-engage SPI chip select 
      transmit_mode(false);                                                     // Enable receive mode
      return rf_rx_buffer;                                                      // Return received payload
}

/**************** Checks The Status Register ***********************************/
void check_interrupt()
{
   int i,reg;
   output_low(rf_CSN);                                                          // Engage SPI chip select
   for(i=0;i<5;i++){reg=spi_read(0x07)&0xFF;}                                   // Read 5 chars of data from NRF24L01 RX register
   output_high(rf_CSN);                                                         // Dis-engage SPI chip select 
   if(reg>>6){rf_interrupt = true;}                                             // If RX_DR set,set data ready flag
   else{set_register(STATUS,0x7E);}                                             // Clear all interrupts
}

/**************** Se cambia la dirección a transmitir **************************/
void set_emisor(unsigned int direccionTX) {
   output_low(rf_CE);                                                           // Disable receiver
   set_register(TX_ADDR,direccionTX);
   transmit_mode(false);                                                        // Enable receive mode   
}

/**************** Initialize NRF24L01 Chip *************************************/
void setup_rf(unsigned int16 CE,unsigned int16 CSN,unsigned int direccionTX,unsigned int direccionRX,unsigned int CH,unsigned boolean Mbps,unsigned int dBm)
{
   rf_CE=CE;                                                                    // Define CE pin
   rf_CSN=CSN;                                                                  // Define CSN pin
   setup_spi(SPI_MASTER|SPI_L_TO_H|SPI_XMIT_L_TO_H|SPI_CLK_DIV_64);             // Setup hardware spi
   output_low(rf_CE);                                                           // Disable receiver
   set_register(CONFIG,0x31);                                                   // Power down chip
   set_register(RF_CH,CH);                                                      // Set RF channel. Va de 2.400GHz a 2.525GHz. Suma el valor de la variable CH a la base 2400, resultado en Mhz
   set_register(RF_SETUP,(Mbps<<3)|(dBm<<1)|0x01);                              // Set data rate and power level. Data rate puede ser 250kbs(0), 1mbps(1) o 2mbps(2). Power puede ser 0dbm(3, el más potente), -6dbm(2), -12dbm(1), -18dbm(0)
   set_register(SETUP_AW,0x03);                                                 // Set address width to 5 bytes
   set_register(EN_AA,0x00);                                                    // Disable auto acknowledgement
   set_register(SETUP_RETR,0x05);                                               // Set auto retransmission for 5 tries
   set_register(TX_ADDR,direccionTX);                                               // Set transmit address
   set_register(RX_ADDR_P0,direccionRX);                                            // Set receive address
   set_register(EN_RXADDR,0x01);                                                // Enable RX address 0
   set_register(RX_PW_P0,PAYLOAD_SIZE);                                         // Set RX payload to receive up to 32 characters
   transmit_mode(false);                                                        // Enable receive mode //Por defecto el modulo siempre está "escuchando"
}                                                                                                      //se configura el modo en transmisión sólo al enviar un paquete

