/*
This software is subject to the license described in the license.txt file included with
this software distribution.
You may not use this file except in compliance with this license.

Copyright © Dynastream Innovations Inc. 2015
All rights reserved.
*/


#include <stdint.h>
#include "string.h"
#include "ant_interface.h"
#include "ant_parameters.h"
#include "app_error.h"
#include "ant_error.h"
#include "boards.h"
#include "ant_stack_config_defs.h"
#include "ant_channel_config.h"
#include "ant_advanced_burst.h"
#include "nrf_soc.h"

// Channel ID configuration.
#define CHAN_ID_DEV_TYPE               0x02                         ///< Device type.
#define CHAN_ID_TRANS_TYPE             0x01                         ///< Transmission type.

// Channel Period configuration.
#define CHAN_PERIOD                    8192                         ///< Channel Period. 4 Hz

// RF Frequency configuration.
#define RF_FREQ                        66                           ///< RF Freq.

// Miscellaneous defines.
#define ANT_CHANNEL_DEFAULT_NETWORK    0x00                         ///< ANT Channel Network.
#define ANT_CHANNEL_NUMBER             0x00                         ///< ANT Channel Number.
#define EXT_TYPE                       0                            ///< Extended assign.
//#define CONFIGURE_AS_SLAVE

#define BURST_PACKET_SIZE              8u                           ///< The burst packet size, in bytes.
#define BURST_PACKET_TOTAL_SIZE        (BURST_PACKET_SIZE + 1u)     ///< The burst packet total size in bytes, including channel number/sequence number.

#define BURST_TOTAL_PACKETS            1024u                        ///< Total size of burst data to send.
#define BURST_BLOCK_SIZE               ANT_CONFIG_BURST_QUEUE_SIZE  ///< Burst block size, in number of bytes.


static uint8_t  m_sequence_number;                ///< Burst sequence number.
static uint8_t  m_burst_data[BURST_BLOCK_SIZE];   ///< Burst buffer.
static uint32_t m_bytes;                          ///< Counter for number of transmitted bytes.
static uint8_t  m_counter;                        ///< Counter for populating dummy data.
static bool     m_burst_rx;                       ///< Flag to indicate if we are receiving a burst.


/**@brief Fill burst buffer with dummy data
 *
 * @param[in] p_ buffer Pointer to the burst buffer.
 * @param[in] size      Size of the burst buffer.
 */
static void burst_buffer_fill(uint8_t * p_buffer, uint16_t size)
{
    // Fill up burst buffer with dummy data
    for (uint8_t i = 0; i < size; i++)
    {
        p_buffer[i] = m_counter;
        m_counter++;
    }
}


/**@brief Function to send burst data
 */
static void burst_data_send(void)
{
    uint32_t err_code;
    uint8_t  burst_segment = BURST_SEGMENT_CONTINUE;
    uint8_t  bytes_to_send = BURST_BLOCK_SIZE;

    if (m_bytes >= BURST_TOTAL_PACKETS * BURST_PACKET_SIZE)
    {
        // There is no more data to send
        return;
    }

    if (m_bytes == 0)
    {
        // This is the first block
        burst_segment = BURST_SEGMENT_START;
    }

    if ((BURST_TOTAL_PACKETS * BURST_PACKET_SIZE - m_bytes) <= BURST_BLOCK_SIZE)
    {
        // This is the last block
        burst_segment |= BURST_SEGMENT_END;
        bytes_to_send  = BURST_TOTAL_PACKETS * BURST_PACKET_SIZE - m_bytes;
    }

    memset(m_burst_data, 0, BURST_BLOCK_SIZE);
    burst_buffer_fill(m_burst_data, bytes_to_send);

    err_code = sd_ant_burst_handler_request(ANT_CHANNEL_NUMBER,
                                            bytes_to_send,
                                            m_burst_data,
                                            burst_segment);
    APP_ERROR_CHECK(err_code);
    m_bytes += bytes_to_send;
}


/**@brief Function to handle received burst data
 *
 * @param[in] p_burst_message  Buffer containing burst message, including channel/sequence number.
 */
static void burst_data_process(uint8_t * p_burst_message)
{
    // If this is the first packet
    if ((p_burst_message[0] & SEQUENCE_NUMBER_MASK) == SEQUENCE_FIRST_MESSAGE)
    {
        LEDS_ON(BSP_LED_0_MASK);  // Turn on LED 0 to indicate burst started
        LEDS_OFF(BSP_LED_1_MASK); // Clear error indication
        m_burst_rx = true;
    }
    else if ((p_burst_message[0] & SEQUENCE_LAST_MESSAGE) != 0) // If this is the last packet
    {
        LEDS_OFF(BSP_LED_0_MASK);   // Turn off LED 0 to indicate burst ended
        m_burst_rx = false;
    }
    // The burst data is available in p_burst_message[1] to p_burst_message[8]
}


void ant_advanced_burst_setup(void)
{
    uint32_t err_code;

    m_counter  = 0;
    m_bytes    = 0;
    m_burst_rx = false;

    ant_channel_config_t channel_config =
    {
        .channel_number    = ANT_CHANNEL_NUMBER,
        .channel_type      = CHANNEL_TYPE_MASTER,
        .ext_assign        = EXT_TYPE,
        .rf_freq           = RF_FREQ,
        .transmission_type = CHAN_ID_TRANS_TYPE,
        .device_type       = CHAN_ID_DEV_TYPE,
        .device_number     = (uint16_t) (NRF_FICR->DEVICEID[0]),
        .channel_period    = CHAN_PERIOD,
        .network_number    = ANT_CHANNEL_DEFAULT_NETWORK,
    };

    uint8_t adv_burst_config[] =
    {
        ADV_BURST_MODE_ENABLE,
        ADV_BURST_MODES_MAX_SIZE,
        0,
        0,
        0,
        0,
        0,
        0
    };

#if defined(CONFIGURE_AS_SLAVE)
    channel_config.channel_type  = CHANNEL_TYPE_SLAVE;
    channel_config.device_number = 0; // Wild card
#endif

    err_code = ant_channel_init(&channel_config);
    APP_ERROR_CHECK(err_code);

    err_code = sd_ant_adv_burst_config_set(adv_burst_config, sizeof(adv_burst_config));
    APP_ERROR_CHECK(err_code);

    err_code = sd_ant_channel_open(ANT_CHANNEL_NUMBER);
    APP_ERROR_CHECK(err_code);
}


void ant_advanced_burst_bsp_evt_handler(bsp_event_t evt)
{
    switch (evt)
    {
        case BSP_EVENT_KEY_0:
            // Do not start a new burst if there is one in progress
            if (m_bytes == 0 && !m_burst_rx)
            {
                m_counter = 0;
                burst_data_send();
            }
            break;

        default:
            return; // no implementation needed
    }
}


void ant_advanced_burst_event_handler(ant_evt_t * p_ant_evt)
{
    uint8_t       p_burst_message[BURST_PACKET_TOTAL_SIZE];
    ANT_MESSAGE * p_ant_message = (ANT_MESSAGE *) p_ant_evt->msg.evt_buffer;

    switch (p_ant_evt->event)
    {
        case EVENT_TRANSFER_TX_START:
            LEDS_ON(BSP_LED_0_MASK);  // Turn on LED 0 to indicate burst started
            LEDS_OFF(BSP_LED_1_MASK); // Clear error indication
            break;

        case EVENT_TRANSFER_NEXT_DATA_BLOCK:
            burst_data_send(); // Send the next block of data
            break;

        case EVENT_TRANSFER_TX_COMPLETED:
            LEDS_OFF(BSP_LED_0_MASK); // Turn off LED 0 to indicate burst ended
            m_bytes = 0;
            break;

        case EVENT_TRANSFER_TX_FAILED:
            LEDS_OFF(BSP_LED_0_MASK); // Turn off LED 0 to indicate burst ended
            LEDS_ON(BSP_LED_1_MASK);  // Turn on LED 1 to indicate burst failure
            m_bytes = 0;
            break;

        case EVENT_TRANSFER_RX_FAILED:
            LEDS_OFF(BSP_LED_0_MASK); // Turn off LED 0 to indicate burst ended
            LEDS_ON(BSP_LED_1_MASK);  // Turn on LED 1 to indicate burst failure
            m_burst_rx = false;
            break;

        case EVENT_RX:

            switch (p_ant_message->ANT_MESSAGE_ucMesgID)
            {
                case MESG_BURST_DATA_ID:
                    // The first packet of an advanced burst transfer will be a regular burst
                    // message. If the other end point does not have advanced burst enabled,
                    // we will receive regular burst messages as well.
                    p_burst_message[0] = p_ant_message->ANT_MESSAGE_ucChannel;
                    memcpy(&p_burst_message[1],
                           p_ant_message->ANT_MESSAGE_aucPayload,
                           BURST_PACKET_SIZE);
                    m_sequence_number = SEQUENCE_NUMBER_MASK & p_ant_message->ANT_MESSAGE_ucChannel;
                    burst_data_process(p_burst_message);
                    break;

                case MESG_ADV_BURST_DATA_ID:

                    // If it is an advanced burst message, split it into a series of regular 8-byte
                    // burst messages so everything can be processed in the same function
                    for (uint8_t i = 0;
                         (int32_t)(i * BURST_PACKET_SIZE) < (p_ant_message->ANT_MESSAGE_ucSize - 1);
                         i++ ) // For each 8-byte packet
                    {
                        // Increment the sequence number
                        if (m_sequence_number == SEQUENCE_NUMBER_ROLLOVER)
                        {
                            m_sequence_number = 0;
                        }
                        m_sequence_number += SEQUENCE_NUMBER_INC;

                        // Check if it is the last packet
                        if (((p_ant_message->ANT_MESSAGE_ucChannel & SEQUENCE_LAST_MESSAGE) != 0)
                            && (((i + 1) * BURST_PACKET_SIZE) ==
                                (p_ant_message->ANT_MESSAGE_ucSize - 1)))
                        {
                            m_sequence_number |= SEQUENCE_LAST_MESSAGE;
                        }

                        // Package up the burst message data as a regular burst, replacing
                        // the sequence number.
                        p_burst_message[0] = m_sequence_number
                                             | (p_ant_message->ANT_MESSAGE_ucChannel
                                                & CHANNEL_NUMBER_MASK);
                        memcpy(&p_burst_message[1],
                               &p_ant_message->ANT_MESSAGE_aucMesgData[i * BURST_PACKET_SIZE + 1],
                               BURST_PACKET_SIZE);

                        // Process burst data
                        burst_data_process(p_burst_message);
                    }
                    break;
            }
            break;

        default:
            break;
    }
}


