
#include "nrf24.h"
#include "global.h"

uint8_t payload_len;

/* init the hardware pins */
void nrf24_init() 
{
	DDRB |= ((1<<CSN)|(1<<CE));
    wl_module_CE_lo;
    wl_module_CSN_hi; 
	
	spi_init(); 
}


/* configure the module */
void nrf24_config(uint8_t channel, uint8_t pay_length)//(2,4)
{
    /* Use static payload length ... */
    payload_len = pay_length;

    // CRC enable, 1 byte CRC length
    nrf24_configRegister(CONFIG,(1<<MASK_RX_DR)|(1<<MASK_TX_DS)|(1<<MASK_MAX_RT)|(1<<EN_CRC)|(0<<CRCO)|(1<<PWR_UP)|(0<<PRIM_RX));
	
	// Auto Acknowledgment
	nrf24_configRegister(EN_AA,(1<<ENAA_P0)|(1<<ENAA_P1)|(0<<ENAA_P2)|(0<<ENAA_P3)|(0<<ENAA_P4)|(0<<ENAA_P5));

	// Enable RX addresses
	nrf24_configRegister(EN_RXADDR,(1<<ERX_P0)|(1<<ERX_P1)|(0<<ERX_P2)|(0<<ERX_P3)|(0<<ERX_P4)|(0<<ERX_P5));

	// Setup of Address Widths
	nrf24_configRegister(SETUP_AW, (0x03<<AW));

	// Auto retransmit delay: 1000 us and Up to 15 retransmit trials
	nrf24_configRegister(SETUP_RETR,(0x04<<ARD)|(0x0F<<ARC));
			
	// Set RF channel
    nrf24_configRegister(RF_CH,channel);

    // 1 Mbps, TX gain: 0dbm
    nrf24_configRegister(RF_SETUP, (0<<RF_DR)|((0x03)<<RF_PWR));
	

	// Set length of incoming payload 
    nrf24_configRegister(RX_PW_P0, 0x00); // Auto-ACK pipe ...
    nrf24_configRegister(RX_PW_P1, payload_len); // Data payload pipe
    nrf24_configRegister(RX_PW_P2, 0x00); // Pipe not used 
    nrf24_configRegister(RX_PW_P3, 0x00); // Pipe not used 
    nrf24_configRegister(RX_PW_P4, 0x00); // Pipe not used 
    nrf24_configRegister(RX_PW_P5, 0x00); // Pipe not used 
   

    // Dynamic length configurations: No dynamic length
    nrf24_configRegister(DYNPD,(0<<DPL_P0)|(0<<DPL_P1)|(0<<DPL_P2)|(0<<DPL_P3)|(0<<DPL_P4)|(0<<DPL_P5));

	PTX = 0;

    // Start listening
    nrf24_powerUpRx();
}

/* Set the RX address */
void nrf24_rx_address(uint8_t * adr) 
{
    wl_module_CE_lo;
    nrf24_writeRegister(RX_ADDR_P1,adr,nrf24_ADDR_LEN);
    wl_module_CE_hi;
}

/* Returns the payload length */
uint8_t nrf24_payload_length()
{
    return payload_len;
}

/* Set the TX address */
void nrf24_tx_address(uint8_t* adr)
{
    /* RX_ADDR_P0 must be set to the sending addr for auto ack to work. */
    nrf24_writeRegister(RX_ADDR_P0,adr,nrf24_ADDR_LEN);
    nrf24_writeRegister(TX_ADDR,adr,nrf24_ADDR_LEN);
}

/* Checks if data is available for reading */
/* Returns 1 if data is ready ... */
uint8_t nrf24_dataReady() 
{
    // See note in getData() function - just checking RX_DR isn't good enough
    uint8_t status = nrf24_getStatus();

    // We can short circuit on RX_DR, but if it's not set, we still need
    // to check the FIFO for any pending packets
    if ( status & (1 << RX_DR) ) 
    {
        return 1;
    }

    return !nrf24_rxFifoEmpty();;
}

/* Checks if receive FIFO is empty or not */
uint8_t nrf24_rxFifoEmpty()
{
    uint8_t fifoStatus;

    nrf24_readRegister(FIFO_STATUS,&fifoStatus,1);
    
    return (fifoStatus & (1 << RX_EMPTY));
}

/* Returns the length of data waiting in the RX fifo */
uint8_t nrf24_payloadLength()
{
    uint8_t status;
    wl_module_CSN_lo;
    spi_fast_shift(R_RX_PL_WID);
    status = spi_fast_shift(0x00);
    wl_module_CSN_hi;
    return status;
}

/* Reads payload bytes into data array */
void nrf24_getData(uint8_t* data) 
{
    /* Pull down chip select */
    wl_module_CSN_lo;                               

    /* Send cmd to read rx payload */
    spi_fast_shift( R_RX_PAYLOAD );
    
    /* Read payload */
    spi_transfer_sync(data,data,payload_len);
    
    /* Pull up chip select */
    wl_module_CSN_hi;

    /* Reset status register */
    nrf24_configRegister(STATUS,(1<<RX_DR));   
}

/* Returns the number of retransmissions occured for the last message */
uint8_t nrf24_retransmissionCount()
{
    uint8_t rv;
    nrf24_readRegister(OBSERVE_TX,&rv,1);
    rv = rv & 0x0F;
    return rv;
}

// Sends a data package to the default address. Be sure to send the correct
// amount of bytes as configured as payload on the receiver.
void nrf24_send(uint8_t* value) 
{    
	while (PTX) {}        // Wait until last packet is send

	PTX = 1;
    /* Go to Standby-I first */
    wl_module_CE_lo;
     
    /* Set to transmitter mode , Power up if needed */
    nrf24_powerUpTx();

    /* Do we really need to flush TX fifo each time ? */
    #if 1
        /* Pull down chip select */
        wl_module_CSN_lo;           
   
        /* Write cmd to flush transmit FIFO */
        spi_fast_shift(FLUSH_TX);     
   
        /* Pull up chip select */
        wl_module_CSN_hi;                    
    #endif 

    /* Pull down chip select */
    wl_module_CSN_lo;

    /* Write cmd to write payload */
    spi_fast_shift(W_TX_PAYLOAD);

    /* Write payload */
    spi_transmit_sync(value,payload_len);   

    /* Pull up chip select */
    wl_module_CSN_hi;

    /* Start the transmission */
    wl_module_CE_hi    
}

uint8_t nrf24_isSending()
{
    uint8_t status;

    /* read the current status */
    status = nrf24_getStatus();
                
    /* if sending successful (TX_DS) or max retries exceded (MAX_RT). */
    if((status & ((1 << TX_DS)  | (1 << MAX_RT))))
    {        
        return 0; /* false */
    }

    return 1; /* true */

}

uint8_t nrf24_getStatus()
{
    uint8_t rv;
    wl_module_CSN_lo;
    rv = spi_fast_shift(NOP);
    wl_module_CSN_hi;
    return rv;
}

uint8_t nrf24_lastMessageStatus()
{
    uint8_t rv;

    rv = nrf24_getStatus();

    /* Transmission went OK */
    if((rv & ((1 << TX_DS))))
    {
        return NRF24_TRANSMISSON_OK;
    }
    /* Maximum retransmission count is reached */
    /* Last message probably went missing ... */
    else if((rv & ((1 << MAX_RT))))
    {
        return NRF24_MESSAGE_LOST;
    }  
    /* Probably still sending ... */
    else
    {
        return 0xFF;
    }
}

void nrf24_powerUpRx()
{     
    wl_module_CSN_lo;
    spi_fast_shift(FLUSH_RX);
    wl_module_CSN_hi;

    nrf24_configRegister(STATUS,(1<<RX_DR)|(1<<TX_DS)|(1<<MAX_RT)); 

    wl_module_CE_lo;   
    nrf24_configRegister(CONFIG,nrf24_CONFIG|((1<<PWR_UP)|(1<<PRIM_RX)));    
    wl_module_CE_hi
}

void nrf24_powerUpTx()
{
    nrf24_configRegister(STATUS, (1<<RX_DR) | (1<<TX_DS) | (1<<MAX_RT)); 

    nrf24_configRegister(CONFIG, nrf24_CONFIG | ((1<<PWR_UP) | (0<<PRIM_RX)));
}

void nrf24_powerDown()
{
    wl_module_CE_lo;
    nrf24_configRegister(CONFIG,nrf24_CONFIG);
}

/* Clocks only one byte into the given nrf24 register */
void nrf24_configRegister(uint8_t reg, uint8_t value)
{
    wl_module_CSN_lo;
    spi_fast_shift(W_REGISTER | (REGISTER_MASK & reg));
    spi_fast_shift(value);
    wl_module_CSN_hi;
}

/* Read single register from nrf24 */
void nrf24_readRegister(uint8_t reg, uint8_t* value, uint8_t len)
{
    wl_module_CSN_lo;
    spi_fast_shift(R_REGISTER | (REGISTER_MASK & reg));
    spi_transfer_sync(value,value,len);
    wl_module_CSN_hi;
}

/* Write to a single register of nrf24 */
void nrf24_writeRegister(uint8_t reg, uint8_t* value, uint8_t len) 
{
    wl_module_CSN_lo;
    spi_fast_shift(W_REGISTER | (REGISTER_MASK & reg));
    spi_transmit_sync(value,len);
    wl_module_CSN_hi;
}
