/*
 *
 *   Copyright (C) 2016 Texas Instruments Incorporated
 *
 *   All rights reserved. Property of Texas Instruments Incorporated.
 *   Restricted rights to use, duplicate or disclose this code are
 *   granted through contract.
 *
 *   The program may not be used without the written permission of
 *   Texas Instruments Incorporated or against the terms and conditions
 *   stipulated in the agreement under which this program has been supplied,
 *   and under no circumstances can it be used with non-TI connectivity device.
 *
 */

/*
 * Application Name     -   Radio Tool Application on CC3220
 * Application Overview -   The main usage of the Radio Tool is to serve as a
                            control panel for direct access to the Radio.
                            It can be used for the RF evaluation and for
                            certification purposes (Like FCC, ETSI, Telec etc.).
 * Application Details  -   doc\examples\radio_tool.pdf
 */



/* Driverlib includes */
//#include "hw_types.h"
//#include "hw_ints.h"

//#include <driverlib/rom.h>
//#include <driverlib/rom_map.h>
//#include <driverlib/interrupt.h>
//#include <driverlib/prcm.h>
//#include <driverlib/utils.h>


#include "uart_cli.h"
#include "uart_term.h"
/* Platform includes */
//#include "osi.h"
#include "RadioTool.h"
//#include "pinmux.h"
//#include "common.h"


/* Standard includes */
#include <stdlib.h>
#include <stdint.h>

/* TI-DRIVERS Header files */
#include <board.h>
#include <ti/drivers/GPIO.h>
#include <ti/drivers/SPI.h>
#include <ti/drivers/Power.h>
#include <ti/drivers/power/PowerCC3200.h>
#include <ti/drivers/net/wifi/simplelink.h>

#include "semaphore.h"
#include "pthread.h"
#include "time.h"

#define RADIO_TOOL_TASK_NAME    "RadioToolTask"
//#define SPAWN_TASK_PRIORITY     7
#define OSI_STACK_SIZE          4096

#define TASK_STACK_SIZE			(2048)
#define SPAWN_TASK_PRIORITY		(9)
#define SSID_LEN_MAX			(32)
#define BSSID_LEN_MAX       	(6)
#define PASSWD_LEN_MAX       	(63)
#define PASSWD_LEN_MIN       	(8)
#define WLAN_SCAN_COUNT			(20)
#define MAX_FILE_NAME_LEN		(32)
#define MAX_TEXT_PAD_SIZE		(256)
#define MAX_FILE_LIST			(20)
#define MAX_BUF_SIZE			(1400)
#define CHANNEL_MASK_ALL		(0x1FFF)
#define RSSI_TH_MAX				(-95)
#define SL_STOP_TIMEOUT			(200)
#define DEV_TYPE_LEN			(17)
#define IPV6_ADDR_LEN			(16)
#define IPV4_ADDR_LEN			(4)
#define	DEVICE_ERROR			("Device error, please refer \"DEVICE ERRORS CODES\" section in errors.h")
#define WLAN_ERROR				("WLAN error, please refer \"WLAN ERRORS CODES\" section in errors.h")
#define SOCKET_ERROR			("BSD Socket error, please refer \"BSD SOCKET ERRORS CODES\" section in errors.h")
#define NETAPP_ERROR			("Netapp error, please refer \"NETAPP ERRORS CODES\" section in errors.h")
#define OS_ERROR				("OS error, please refer \"NETAPP ERRORS CODES\" section in errno.h")
#define	CMD_ERROR				("Invalid option/command.")

#define ASSERT_ON_ERROR_NO_PRINT(error_code)\
            {\
                 if(error_code < 0) \
                   {\
                        return error_code;\
                 }\
            }
#define ASSERT_ON_ERROR(ret, errortype)\
		{\
			if(ret < 0)\
			{\
				SHOW_WARNING(ret, errortype);\
				return -1;\
			}\
		}
#define SHOW_WARNING(ret, errortype)		UART_PRINT("\n\r[line:%d, error code:%d] %s\n\r", __LINE__, ret, errortype);
extern _u32 uiUartCmd;

_u8 ucUARTBuffer[RADIO_CMD_BUFF_SIZE_MAX];
pthread_t 			gSpawn_thread = (pthread_t)NULL;

#ifdef USE_FREERTOS
//*****************************************************************************
// FreeRTOS User Hook Functions enabled in FreeRTOSConfig.h
//*****************************************************************************

//*****************************************************************************
//
//! \brief Application defined hook (or callback) function - assert
//!
//! \param[in]  pcFile - Pointer to the File Name
//! \param[in]  ulLine - Line Number
//!
//! \return none
//!
//*****************************************************************************
void
vAssertCalled( const char *pcFile, _u32 ulLine )
{
    //Handle Assert here
    while(1)
    {
    }
}

//*****************************************************************************
//
//! \brief Application defined idle task hook
//!
//! \param  none
//!
//! \return none
//!
//*****************************************************************************
void
vApplicationIdleHook( void)
{
    //Handle Idle Hook for Profiling, Power Management etc
}

//*****************************************************************************
//
//! \brief Application defined malloc failed hook
//!
//! \param  none
//!
//! \return none
//!
//*****************************************************************************
void
vApplicationMallocFailedHook()
{
    //Handle Memory Allocation Errors
    while(1)
    {
    }
}

//*****************************************************************************
//
//! \brief Application defined stack overflow hook
//!
//! \param  none
//!
//! \return none
//!
//*****************************************************************************
void
vApplicationStackOverflowHook( OsiTaskHandle *pxTask, signed char *pcTaskName)
{
    //Handle FreeRTOS Stack Overflow
    while(1)
    {
    }
}
#endif //USE_FREERTOS

/*!
 *  \brief      This function configures the SimpleLink in its default state. It:
 *                  - Sets the role to STATION
 *                  - Configures connection policy to NONE
 *                  - Deletes all the stored profiles
 *                  - Disables DHCP
 *                  - Disables scan policy
 *                  - Sets Tx power to maximum
 *                  - Sets power policy to normal
 *                  - Unregisters mDNS services
 *                  - Removes all filters
 *  \param      None
 *  \return     0 on success, -ve otherwise
 */
static _i32 ConfigSimplelinkToDefault();

/*!
 *  \brief      This function handles general events
 *  \param[in]  pDevEvent - Pointer to stucture containing general event info
 *  \return     None
 */
void SimpleLinkGeneralEventHandler(SlDeviceEvent_t *pDevEvent)
{
    // Unused in this application
}

/*!
 *  \brief      This function handles WLAN async events
 *  \param[in]  pWlanEvent - Pointer to the structure containg WLAN event info
 *  \return     None
 */
void SimpleLinkWlanEventHandler(SlWlanEvent_t *pWlanEvent)
{
    /* Unused in this application */
}

/*!
 *  \brief      This function handles socket events indication
 *  \param[in]  pSock - Pointer to the stucture containing socket event info
 *  \return     None
 */
void SimpleLinkSockEventHandler(SlSockEvent_t *pSock)
{
    // Unused in this application
}

/*!
 *  \brief      This function handles network events such as IP acquisition, IP leased, IP released etc.
 *  \param[in]  pNetAppEvent - Pointer to the structure containing acquired IP
 *  \return     None
 */

void SimpleLinkSocketTriggerEventHandler(SlSockTriggerEvent_t	*pSlTriggerEvent)
{



}

void SimpleLinkNetAppEventHandler(SlNetAppEvent_t *pNetAppEvent)
{
    /* Unused in this application */
}

/*!
 *  \brief      This function handles resource request
 *  \param[in]  pNetAppRequest - Contains the resource requests
 *  \param[in]  pNetAppResponse - Should be filled by the user with the relevant response information
 *  \return     None
 */
void SimpleLinkNetAppRequestHandler(SlNetAppRequest_t  *pNetAppRequest,
                                    SlNetAppResponse_t *pNetAppResponse)
{
    /* Unused in this application */
}

/*!
 *  \brief      This function gets triggered when HTTP Server receives
 *              application defined GET and POST HTTP tokens.
 *  \param[in]  pHttpServerEvent - Pointer indicating http server event
 *  \param[in]  pHttpServerResponse - Pointer indicating http server response
 *  \return     None
 */
/*
void SimpleLinkHttpServerCallback(SlNetAppHttpServerEvent_t *pSlHttpServerEvent,
                                  SlNetAppHttpServerResponse_t *pSlHttpServerResponse)
{

}*/

void SimpleLinkHttpServerEventHandler(SlNetAppHttpServerEvent_t *pHttpEvent,
									  SlNetAppHttpServerResponse_t *pHttpResponse)
{
    /* Unused in this application */
}

/*!
 *  \brief      This function handles resource request
 *  \param[in]  pFatalErrorEvent - Contains the fatal error data
 *  \return     None
 */
void SimpleLinkFatalErrorEventHandler(SlDeviceFatal_t *slFatalErrorEvent)
{
    /* Unused in this application */
}

void SimpleLinkNetAppRequestMemFreeEventHandler(uint8_t *buffer)
{
	/* Unused in this application */
}


void SimpleLinkNetAppRequestEventHandler(SlNetAppRequest_t *pNetAppRequest, SlNetAppResponse_t *pNetAppResponse)
{
	/* Unused in this application */
}


/*!
 *  \brief      It initializes the variables used in this application to its initial values.
 *  \param      None.
 *  \return     0 on success, -ve otherwise
 */
void InitializeAppVariables()
{

}

/* */
int32_t ConfigureSimpleLinkToDefaultState()
{
     uint8_t 							  ucConfigOpt;
     uint8_t 							  ucPower;
     int32_t   							  RetVal = -1;
     int32_t 							  Mode = -1;
     uint32_t 							  IfBitmap = 0;
     SlWlanScanParamCommand_t			  ScanDefault = {0};
     SlWlanRxFilterOperationCommandBuff_t RxFilterIdMask = {0};

     /* Turn NWP on */
     Mode = sl_Start(0, 0, 0);
     ASSERT_ON_ERROR(Mode, DEVICE_ERROR);

     if(Mode != ROLE_STA)
     {
      	 /* Set NWP role as STA */
      	 Mode = sl_WlanSetMode(ROLE_STA);
      	 ASSERT_ON_ERROR(Mode, WLAN_ERROR);

         /* For changes to take affect, we restart the NWP */
         RetVal = sl_Stop(SL_STOP_TIMEOUT);
         ASSERT_ON_ERROR(RetVal, DEVICE_ERROR);

         Mode = sl_Start(0, 0, 0);
         ASSERT_ON_ERROR(Mode, DEVICE_ERROR);
     }

     if(Mode != ROLE_STA)
     {
    	 UART_PRINT("Failed to configure device to it's default state");
    	 return -1;
     }

     /* Set policy to auto only */
     RetVal = sl_WlanPolicySet(SL_WLAN_POLICY_CONNECTION, SL_WLAN_CONNECTION_POLICY(1,0,0,0), NULL ,0);
     ASSERT_ON_ERROR(RetVal, WLAN_ERROR);

     /* Disable Auto Provisioning */
     RetVal = sl_WlanProvisioning(SL_WLAN_PROVISIONING_CMD_STOP, 0xFF, 0, NULL, 0x0);
     ASSERT_ON_ERROR(RetVal, WLAN_ERROR);

     RetVal = sl_WlanProfileDel(0xFF);
     ASSERT_ON_ERROR(RetVal, WLAN_ERROR);

     /* enable DHCP client */
     RetVal = sl_NetCfgSet(SL_NETCFG_IPV4_STA_ADDR_MODE, SL_NETCFG_ADDR_DHCP, 0, 0);
     ASSERT_ON_ERROR(RetVal, NETAPP_ERROR);

     /* Disable ipv6 */
     IfBitmap = !(SL_NETCFG_IF_IPV6_STA_LOCAL | SL_NETCFG_IF_IPV6_STA_GLOBAL);

     RetVal = sl_NetCfgSet(SL_NETCFG_IF, SL_NETCFG_IF_STATE, sizeof(IfBitmap),(const unsigned char *)&IfBitmap);
     ASSERT_ON_ERROR(RetVal, NETAPP_ERROR);

     /* Configure scan parameters to default */
     ScanDefault.ChannelsMask = CHANNEL_MASK_ALL;
     ScanDefault.RssiThershold = RSSI_TH_MAX;

     RetVal = sl_WlanSet(SL_WLAN_CFG_GENERAL_PARAM_ID, SL_WLAN_GENERAL_PARAM_OPT_SCAN_PARAMS, sizeof(ScanDefault), (uint8_t *)&ScanDefault);
     ASSERT_ON_ERROR(RetVal, WLAN_ERROR);

     /* Disable scans */
     ucConfigOpt = SL_WLAN_SCAN_POLICY(0, 0);
     RetVal = sl_WlanPolicySet(SL_WLAN_POLICY_SCAN , ucConfigOpt, NULL, 0);
     ASSERT_ON_ERROR(RetVal, WLAN_ERROR);

     /* Set TX power lvl to max */
     ucPower = 0;
     RetVal = sl_WlanSet(SL_WLAN_CFG_GENERAL_PARAM_ID, SL_WLAN_GENERAL_PARAM_OPT_STA_TX_POWER, 1, (uint8_t *)&ucPower);
     ASSERT_ON_ERROR(RetVal, WLAN_ERROR);

     /* Set NWP Power policy to 'normal' */
     RetVal = sl_WlanPolicySet(SL_WLAN_POLICY_PM, SL_WLAN_NORMAL_POLICY, NULL, 0);
     ASSERT_ON_ERROR(RetVal, WLAN_ERROR);

     /* Unregister mDNS services */
     RetVal = sl_NetAppMDNSUnRegisterService(0, 0, 0);
     ASSERT_ON_ERROR(RetVal, NETAPP_ERROR);

     /* Remove all 64 RX filters (8*8) */
     memset(RxFilterIdMask.FilterBitmap , 0xFF, 8);

     RetVal = sl_WlanSet(SL_WLAN_RX_FILTERS_ID, SL_WLAN_RX_FILTER_REMOVE, sizeof(SlWlanRxFilterOperationCommandBuff_t),(uint8_t *)&RxFilterIdMask);
     ASSERT_ON_ERROR(RetVal, WLAN_ERROR);

  	 /* Set NWP role as STA */
     RetVal = sl_WlanSetMode(ROLE_STA);
  	 ASSERT_ON_ERROR(RetVal, WLAN_ERROR);

     /* For changes to take affect, we restart the NWP */
     RetVal = sl_Stop(0xFF);
     ASSERT_ON_ERROR(RetVal, DEVICE_ERROR);

     Mode = sl_Start(0, 0, 0);
     ASSERT_ON_ERROR(Mode, DEVICE_ERROR);

     if(ROLE_STA != Mode)
     {
    	 UART_PRINT("Failed to configure device to it's default state");
    	 return -1 ;
     }
     else
     {
    	 //app_CB.Role = ROLE_STA;
    	 //SET_STATUS_BIT(app_CB.Status, STATUS_BIT_NWP_INIT);
     }

     return 0;
}

/* */
static _i32 InitSimplelink(_u8 const role)
{
    _i32 retVal = -1;

    retVal = sl_Start(0, 0, 0);
    ASSERT_ON_ERROR_NO_PRINT(retVal);

    if (role != retVal) {
        /* Switch to AP role and restart */
        retVal = sl_WlanSetMode(role);
        ASSERT_ON_ERROR_NO_PRINT(retVal);

        /* Restart Simplelink */
        retVal = sl_Stop(0xFF);
        ASSERT_ON_ERROR_NO_PRINT(retVal);
        retVal = sl_Start(0, 0, 0);
        ASSERT_ON_ERROR_NO_PRINT(retVal);

        /* We don't want to proceed if the device is not coming up as STA */
        if (role != retVal) {
            retVal = -1;
        }
    }

    return retVal;
}


void *mainThread(void *arg)
{
    _i32 retVal = -1;
    _u32 ulBuffLen = 0;

	int32_t 			RetVal ;
	pthread_attr_t      pAttrs_spawn;
	struct sched_param  priParam;

	/* HW modules init */
	Board_initGPIO();
	Board_initSPI();


	InitTerm();

    /* create the sl_Task internal spawn thread instead */
	pthread_attr_init(&pAttrs_spawn);
	priParam.sched_priority = SPAWN_TASK_PRIORITY;
	RetVal = pthread_attr_setschedparam(&pAttrs_spawn, &priParam);
	RetVal |= pthread_attr_setstacksize(&pAttrs_spawn, TASK_STACK_SIZE);

	RetVal = pthread_create(&gSpawn_thread, &pAttrs_spawn, sl_Task, NULL);
	if(RetVal < 0)
	{
		/* Handle Error */
	}

	RetVal = ConfigureSimpleLinkToDefaultState();
	if(RetVal < 0)
	{
		/* Handle Error */
	}


    /*
     * Assumption is that the device is configured in station mode already
     * and it is in its default state
     */
	/*
    retVal = InitSimplelink(ROLE_STA);
    if (retVal < 0)
    {
        LOOP_FOREVER();
    }
*/
    InitializeAppVariables();

    while(1)
    {
        /* Get command from UART */
        memset(ucUARTBuffer, 0, RADIO_CMD_BUFF_SIZE_MAX);
        uiUartCmd = GetPacket(&ucUARTBuffer[0], &ulBuffLen);

        if(ulBuffLen)
        {
            AckPacket();
            MSEC_SLEEP(70);

            /* Parse the command */
            retVal = RadioToolCommand(ucUARTBuffer[0],&ucUARTBuffer[1]);
            if(retVal < 0)
            {
                return;
            }
        }

        ulBuffLen=0;
    }
}


