/*! *********************************************************************************
 * \addtogroup Wireless UART Application
 * @{
 ********************************************************************************** */
/*!
 * Copyright (c) 2015, Freescale Semiconductor, Inc.
 * All rights reserved.
 * \file app.c
 * This file is the source file for the Wireless UART Application
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * o Redistributions of source code must retain the above copyright notice, this list
 *   of conditions and the following disclaimer.
 *
 * o Redistributions in binary form must reproduce the above copyright notice, this
 *   list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/************************************************************************************
 *************************************************************************************
 * Include
 *************************************************************************************
 ************************************************************************************/
/* Framework / Drivers */
#include "RNG_interface.h"
#include "Keyboard.h"
#include "Led.h"
#include "TimersManager.h"
#include "FunctionLib.h"
#include "fsl_os_abstraction.h"
#include "shell.h"
#include "panic.h"
#include "MemManager.h"
#include "board.h"
#include "per.h"

/* BLE Host Stack */
#include "gap_types.h"
#include "gatt_client_interface.h"
#include "gatt_server_interface.h"

/* Shell APIs*/
#include "shell_per.h"

#include "ApplMain.h"
#include "app.h"

#include <stdio.h>
/************************************************************************************
*************************************************************************************
* Private macros
*************************************************************************************
************************************************************************************/

/************************************************************************************
*************************************************************************************
* Private type definitions
*************************************************************************************
************************************************************************************/

static PER_Data_Store_t per_data_store;
static int32_t per_test_counts = 0;

/************************************************************************************
 *************************************************************************************
 * Private memory declarations
 *************************************************************************************
 ************************************************************************************/
const char mpPerHelp[] = "\r\n"
           "per reset\r\n"
           "per config [-len dataLength] [-payload pkgPayLoad] [-time testDuration] [-txdbm TxdBmPowLevel] [-conndbm ConndBmPowerLevel]\r\n"
           "    dataLength   - Length in bytes of payload data, value 0 - 255\r\n"
           "    pkgPayload   - Package type, values can be 0(PRBS9), 1(11110000), 2(10101010), 3(Vender specific)\r\n"
           "    testDuration - Test duration. Default value is 10 seconds\r\n"
           "    TxdBmPowLevel   - Value for TX Power level on advertising channel, values can be 0 - 31\r\n"
           "    ConndBmPowLevel - Value for TX Power level on connection  channel, values can be 0 - 31\r\n"
           "User need to do configuration one by one!\r\n"
           "per tx -ch channelNum\r\n"
           "per rx -ch channelNum\r\n"
           "per end\r\n"
           "per printnvm\r\n"
           "\r\n"
           "These commands will do PER(Packet Error Rate) Test\r\n"
           "Normally BLE physical speed is 1Mb/Sec, that is, 1b/us\r\n"
           "The LE Test package length and packet interval table is as below:\r\n"
           " _____________________________________________________________________________________________\r\n"
           "| LE Test Packet Length     | Packet Interval    | Packets / Seconds  | Max Duration (Second) |\r\n"
           "| <= 376 us                 | 625  us            | 1600               | 20                    |\r\n"
           "| >= 377  and <= 1000 us    | 1250 us            | 800                | 40                    |\r\n"
           "| >= 1001 and <= 1624 us    | 1875 us            | 533                | 61                    |\r\n"
           "| >= 1625 and <= 2120 us    | 2500 us            | 400                | 81                    |\r\n"
           "|_____________________________________________________________________________________________|\r\n"
           "The maximum received packets in a testing is 32768. The there's a limitatin in test duration.\r\n"
           "\r\n"
           "Power Level and corresponding dBm\r\n"
           " _______________________________________________________________________\r\n"
           "| Level | [dBm]   | Level | [dBm]   | Level | [dBm]   | Level | [dBm]   |\r\n"
           "| 0     | -31.85  | 8     | -7.98   | 16    | -2.13   | 24    | 1.03    |\r\n"
           "| 1     | -25.68  | 9     | -6.97   | 17    | -1.65   | 25    | 1.36    |\r\n"
           "| 2     | -19.69  | 10    | -6.06   | 18    | -1.17   | 26    | 1.67    |\r\n"
           "| 3     | -16.2   | 11    | -5.24   | 19    | -0.74   | 27    | 1.95    |\r\n"
           "| 4     | -13.81  | 12    | -4.52   | 20    | -0.35   | 28    | 2.2     |\r\n"
           "| 5     | -11.89  | 13    | -3.84   | 21    | 0.02    | 39    | 2.46    |\r\n"
           "| 6     | -10.31  | 14    | -3.21   | 22    | 0.4     | 30    | 2.69    |\r\n"
           "| 7     | -8.99   | 15    | -2.63   | 23    | 0.75    | 31    | 2.9     |\r\n"
           "|_______________________________________________________________________|\r\n"
           "\r\n"
           "The LE Test Packet Length is (dataLength + 10) bytes. So it is (dataLength + 10) * 8 us\r\n"
           "The transmitted packets within 1 sec is: 1000000 / Packet Interval\r\n"
           "The End command will return the number of received packets\r\n"
           "So PER = (1 - received_pkts / transmitted_pkts) * 100%\r\n"
           "\r\n";

/* Shell */
const cmd_tbl_t mPerCmd =
{
    .name = "per",
    .maxargs = 12,
    .repeatable = 1,
    .cmd = Shell_Per_Command,
    .usage = (char*)mpPerHelp,
    .help = "Contains commands of reset, tx, rx and end for Per testing."
};

/************************************************************************************
*************************************************************************************
* Public memory declarations
*************************************************************************************
************************************************************************************/
/************************************************************************************
 *************************************************************************************
 * Private functions prototypes
 *************************************************************************************
 ************************************************************************************/
static int32_t BleApp_EvtExeResultCB(perTestEvtType_t evt_type, const perCalResult_t *per_result);
static void BleApp_Config ();
/************************************************************************************
*************************************************************************************
* Public functions
*************************************************************************************
************************************************************************************/

/*! *********************************************************************************
* \brief    Initializes application specific functionality before the BLE stack init.
*
********************************************************************************** */
void BleApp_Init(void)
{
    perReadFlashData(&per_data_store);

    /* UI */
    shell_init("Kinetis BLE Shell> ");
    shell_register_function((cmd_tbl_t *)&mPerCmd);
}

/*! *********************************************************************************
* \brief        Handles keyboard events.
*
* \param[in]    events    Key event structure.
********************************************************************************** */
void BleApp_HandleKeys(key_event_t events)
{
    bleResult_t ret;

    switch (events)
    {
        case gKBD_EventPressPB1_c:
            /* TX, LED2 as indicactor */
            {
                if (FALSE == perGetRxStatus())
                {
                    if (FALSE == perGetTxStatus())
                    {
                        perUnregisterCmdExeRsltCB();
                        perRegisterCmdExeRsltCB(BleApp_EvtExeResultCB);
                        ret = perStartTx(PER_DEFAULT_TEST_CHANNEL);
                        if (gBleSuccess_c != ret)
                        {
                            TurnOffLeds();
                            Led1Flashing();
                        }
                    }
                }
            }
            break;
        case gKBD_EventPressPB2_c:
            /* RX, LED3 as indicactor */
            {
                if (FALSE == perGetTxStatus())
                {
                    if (FALSE == perGetRxStatus())
                    {
                        perUnregisterCmdExeRsltCB();
                        perRegisterCmdExeRsltCB(BleApp_EvtExeResultCB);
                        ret = perStartRx(PER_DEFAULT_TEST_CHANNEL);
                        if (gBleSuccess_c != ret)
                        {
                            TurnOffLeds();
                            Led1Flashing();
                        }
                    }
                }
            }
            break;
        case gKBD_EventLongPB1_c:
            /* TX, LED2 as indicactor */
            {
                if (FALSE == perGetRxStatus())
                {
                    if (TRUE == perGetTxStatus())
                    {
                        ret = perTestEnd(0);
                        if (gBleSuccess_c !=  ret)
                        {
                            TurnOffLeds();
                            Led1Flashing();
                        }
                    }
                }
            }
            break;
        case gKBD_EventLongPB2_c:
            /* RX, LED3 as indicactor */
            {
                if (FALSE == perGetTxStatus())
                {
                    if (TRUE == perGetRxStatus())
                    {
                        ret = perTestEnd(0);
                        if (gBleSuccess_c !=  ret)
                        {
                            TurnOffLeds();
                            Led1Flashing();
                        }
                    }
                }
            }
            break;
        default:
            break;
    }
}

static int32_t BleApp_EvtExeResultCB(perTestEvtType_t evt_type, const perCalResult_t *per_result)
{
    bleResult_t ret;

    switch (evt_type)
    {
    case PER_EVT_TEST_END:
        /* Invalid PER result means user stop RX manually, no need to start RX again */
        if (PER_DATA_FLAG_DUMMY != per_result->integer_val)
        {
            uint32_t rec_index = per_data_store.rec_index;
            perCalResult_t *pTmpCalData = NULL;

            if (rec_index <= PER_TEST_RECORD_COUNT)
            {
                /* Cal PER */
                pTmpCalData = &(per_data_store.per_data[rec_index][per_test_counts]);
                pTmpCalData->integer_val = per_result->integer_val;
                pTmpCalData->frac_val = per_result->frac_val;
                if (per_test_counts < (PER_TEST_LOOP_COUNT - 1))
                {
                    per_test_counts++;
                    /* Restart RX */
                    BleApp_HandleKeys(gKBD_EventPressPB2_c);
                }
                else
                {
                    int32_t tmp = 0;
        
                    /* Check data */
                    for (tmp = 0; tmp < PER_TEST_LOOP_COUNT; ++tmp)
                    {
                        pTmpCalData = &(per_data_store.per_data[rec_index][per_test_counts]);
                        if (100 == pTmpCalData->integer_val)
                        {
                            TurnOffLeds();
                            Led1Flashing();
                        }
                    }

                    per_data_store.rec_index++;
                    if (gBleSuccess_c != perStoreFlashData(&per_data_store))
                    {
                        TurnOffLeds();
                        Led1Flashing();
                    }
                    per_test_counts = 0;
                }
            }
        }
        break;
    default:
        break;
    }

    return 0;
}

/*! *********************************************************************************
 * \brief        Handles BLE generic callback.
 *
 * \param[in]    pGenericEvent    Pointer to gapGenericEvent_t.
 ********************************************************************************** */
void BleApp_GenericCallback (gapGenericEvent_t* pGenericEvent)
{
    switch (pGenericEvent->eventType)
    {
    case gInitializationComplete_c:
        BleApp_Config();
        break;
    case gControllerTestEvent_c:
        perTriggerTestCmdCompleted(&pGenericEvent->eventData.testEvent);
        break;
    default:
        break;
    }
}

/************************************************************************************
 *************************************************************************************
 * Private functions
 *************************************************************************************
 ************************************************************************************/

/*! *********************************************************************************
 * \brief        Configures BLE Stack after initialization. Usually used for
 *               configuring advertising, scanning, white list, services, et al.
 *
 ********************************************************************************** */
static void BleApp_Config (void)
{
    perTestInit();
    perConfig(PER_CFG_DATA_LEN, PER_DEFAULT_DATA_LEN);
    perConfig(PER_CFG_PAYLOAD, PER_DEFAULT_PAYLOAD);
    perConfig(PER_CFG_TEST_DURATION, PER_DEFAULT_TEST_DURATION);
    perConfig(PER_CFG_TXDBM, PER_DEFAULT_TXDBM);
    perConfig(PER_CFG_CONNDBM, PER_DEFAULT_CONNDBM);

    Shell_Per_Init();
}
/*! *********************************************************************************
 * @}
 ********************************************************************************** */
