/* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved.
*
* The information contained herein is property of Nordic Semiconductor ASA.
* Terms and conditions of usage are described in detail in NORDIC
* SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
*
* Licensees are granted free, non-transferable use of the information. NO
* WARRANTY of ANY KIND is provided. This heading must NOT be removed from
* the file.
*
* $LastChangedRevision: 40042 $
*/

/** 
 * @file
 * @brief Gazell Link Layer Device with Payload in ACK example
 * @defgroup gzll_device_ack_payload_example Gazell Link Layer Device with Payload in ACK
 * @{
 * @ingroup gzll_03_examples
 *
 * This project requires that a Host running the 
 * @ref gzll_host_ack_payload_example example be used as a counterpart for 
 * receiving the data. This can be on either nRF51 device or a nRF24Lxx device
 * running the \b gzll_host_ack_payload example in the nRFgo SDK. 
 * 
 * This example sends a packet and adds a new packet to the TX queue every time
 * it receives an ACK. Before adding a packet to the TX queue, the contents of 
 * the GPIO Port BUTTONS is copied to the first payload byte (byte 0). 
 * When an ACK is received, the contents of the first payload byte of 
 * the ACK are output on GPIO Port LEDS. 
 */


#include "nrf_gzll.h"
#include "nrf_gpio.h"
#include "nrf_delay.h"
#include "boards.h"
#include "radio_test.h"

/*****************************************************************************/
/** @name Configuration */
/*****************************************************************************/

// Define pipe
#define PIPE_NUMBER 0 ///< We use pipe 0 in this example

// Define payload length
#define TX_PAYLOAD_LENGTH 6 ///< We use 1 byte payload length when transmitting

// Data and acknowledgement payloads
static uint8_t data_payload[TX_PAYLOAD_LENGTH];///< Payload to send to Host. 
static uint8_t ack_payload[TX_PAYLOAD_LENGTH]; ///< Placeholder for received ACK payloads from Host.

static uint32_t stored_param;
static uint32_t   pg_size;
static uint32_t   pg_num;
static uint32_t * addr;
        
// Debug helper variables
static volatile bool init_ok, enable_ok, push_ok, pop_ok, tx_success,rf_test_on;  

/** @} */

typedef enum
{
    RADIO_TEST_NOP,      /**< No test running.      */
    RADIO_TEST_TXCC,     /**< TX constant carrier.  */
    RADIO_TEST_TXMC,     /**< TX modulated carrier. */
    RADIO_TEST_TXSWEEP,  /**< TX sweep.             */
    RADIO_TEST_RXC,      /**< RX constant carrier.  */
    RADIO_TEST_RXSWEEP,  /**< RX sweep.             */    
} radio_tests_t;

/*****************************************************************************/
/** 
* @brief Main function. 
* 
* @return ANSI required int return type.
*/
/*****************************************************************************/
//lint -save -e514 Unusual use of a boolean expression (use of &= assignment).

static void init(void)
{
    NRF_RNG->TASKS_START = 1;
    
    // Start 16 MHz crystal oscillator
    NRF_CLOCK->EVENTS_HFCLKSTARTED  = 0;
    NRF_CLOCK->TASKS_HFCLKSTART     = 1;

    // Wait for the external oscillator to start up
    while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0)
    {
        // Do nothing.
    }  
}

/** @brief Function for erasing a page in flash.
 *
 * @param page_address Address of the first word in the page to be erased.
 */
static void flash_page_erase(uint32_t * page_address)
{
    // Turn on flash erase enable and wait until the NVMC is ready:
    NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Een << NVMC_CONFIG_WEN_Pos);

    while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
    {
        // Do nothing.
    }

    // Erase page:
    NRF_NVMC->ERASEPAGE = (uint32_t)page_address;

    while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
    {
        // Do nothing.
    }

    // Turn off flash erase enable and wait until the NVMC is ready:
    NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos);

    while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
    {
        // Do nothing.
    }
}

/** @brief Function for filling a page in flash with a value.
 *
 * @param[in] address Address of the first word in the page to be filled.
 * @param[in] value Value to be written to flash.
 */
static void flash_word_write(uint32_t * address, uint32_t value)
{
    // Turn on flash write enable and wait until the NVMC is ready:
    NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos);

    while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
    {
        // Do nothing.
    }

    *address = value;

    while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
    {
        // Do nothing.
    }

    // Turn off flash write enable and wait until the NVMC is ready:
    NRF_NVMC->CONFIG = (NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos);

    while (NRF_NVMC->READY == NVMC_READY_READY_Busy)
    {
        // Do nothing.
    }
}

int main()
{
    uint32_t * target_addr;    
    pg_size = NRF_FICR->CODEPAGESIZE;
    pg_num  = NRF_FICR->CODESIZE - 1;  // Use last page in flash
    addr = (uint32_t *)(pg_size * pg_num);

    stored_param = (uint32_t)*addr;
    
    init();
    NVIC_EnableIRQ(TIMER0_IRQn);
    __enable_irq();

    if(stored_param != 0xffffffff)  //stored something..
    {
        uint32_t param1, param2, param3,param4;
        target_addr = addr;
        switch(stored_param)            
        {
            case  RADIO_TEST_TXCC:
                param1 = *(uint32_t *)(++addr);
                param2 = *(uint32_t *)(++addr);
                param3 = *(uint32_t *)(++addr);
                radio_tx_carrier(param1, param2, param3);
                break;
                    
            case RADIO_TEST_TXMC:
                param1 = *(uint32_t *)(++addr);
                param2 = *(uint32_t *)(++addr);
                param3 = *(uint32_t *)(++addr);
                radio_modulated_tx_carrier(param1, param2, param3);
                break;
                    
            //TBD        
            case RADIO_TEST_TXSWEEP:
            case RADIO_TEST_RXC:
            case RADIO_TEST_RXSWEEP:
            default:
                break;
                        
        }
        
        flash_page_erase(target_addr);
    }
    else
    {
        // Initialize Gazell
        init_ok = nrf_gzll_init(NRF_GZLL_MODE_DEVICE);
        
        // Attempt sending every packet up to 100 times    
        init_ok &= nrf_gzll_set_max_tx_attempts(10);

        // Load data into TX queue
        data_payload[0] = RADIO_TEST_NOP; //Send Ready signal
        push_ok = nrf_gzll_add_packet_to_tx_fifo(PIPE_NUMBER, data_payload, 1);

        // Enable Gazell to start sending over the air
        enable_ok = nrf_gzll_enable();         
    }
    while(1){}
}


/*****************************************************************************/
/** @name Gazell callback function definitions  */
/*****************************************************************************/

// If an ACK was received, we send another packet. 
void  nrf_gzll_device_tx_success(uint32_t pipe, nrf_gzll_device_tx_info_t tx_info)
{
    uint32_t ack_payload_length;
    
    if (tx_info.payload_received_in_ack)
    {
        // Pop packet and write first byte of the payload to the GPIO port.
        pop_ok = nrf_gzll_fetch_packet_from_rx_fifo(pipe, ack_payload, &ack_payload_length);

        if ( (ack_payload_length > 0) && (ack_payload[0] != RADIO_TEST_NOP) )
        {
            switch(ack_payload[0])
            {
                case RADIO_TEST_TXCC:  
                    stored_param = (uint32_t)*addr;
                    flash_word_write(addr++, (uint32_t)ack_payload[0]);
                    flash_word_write(addr++, (uint32_t)ack_payload[1]);
                    flash_word_write(addr++, (uint32_t)ack_payload[2]);
                    flash_word_write(addr, (uint32_t)ack_payload[3]);
                    NVIC_SystemReset();                    
                    break;

                case RADIO_TEST_TXMC:
                    stored_param = (uint32_t)*addr;
                    flash_word_write(addr++, (uint32_t)ack_payload[0]);
                    flash_word_write(addr++, (uint32_t)ack_payload[1]);
                    flash_word_write(addr++, (uint32_t)ack_payload[2]);
                    flash_word_write(addr, (uint32_t)ack_payload[3]);
                    NVIC_SystemReset();                
                    break;

                case RADIO_TEST_TXSWEEP:
                    //radio_tx_sweep_start(ack_payload[1], ack_payload[2], ack_payload[3], ack_payload[4], ack_payload[5]);                      
                    break;

                case RADIO_TEST_RXC:
                    //radio_rx_carrier(ack_payload[1], ack_payload[2]);
                    break;

                case RADIO_TEST_RXSWEEP:
                    //radio_rx_sweep_start(ack_payload[1], ack_payload[2], ack_payload[3], ack_payload[4]);
                    break;

                default:                
                    break;
            }                     
        }
        else
        {
            data_payload[0] = RADIO_TEST_NOP;
            push_ok = nrf_gzll_add_packet_to_tx_fifo(pipe, data_payload, 1);            
        }
    }
    else
    {
        data_payload[0] = RADIO_TEST_NOP;
        push_ok = nrf_gzll_add_packet_to_tx_fifo(pipe, data_payload, 1);            
    }
}

/* If the transmission failed, send a new packet.
 * This callback does not occur by default since NRF_GZLL_DEFAULT_MAX_TX_ATTEMPTS 
 * is 0 (inifinite retransmits)
 */
void nrf_gzll_device_tx_failed(uint32_t pipe, nrf_gzll_device_tx_info_t tx_info)
{
    tx_success = false;

    // Load data into TX queue
    data_payload[0] = RADIO_TEST_NOP;
    push_ok = nrf_gzll_add_packet_to_tx_fifo(pipe, data_payload, TX_PAYLOAD_LENGTH);
}

// Callbacks not needed in this example.
void nrf_gzll_host_rx_data_ready(uint32_t pipe, nrf_gzll_host_rx_info_t rx_info){}
void nrf_gzll_disabled(){}

/** @} */
/** @} */



