//================================================================================================================//
//====================================Relevant libraries==========================================================//
//================================================================================================================//

#include <stdlib.h>                             //Standard includes
#include <pthread.h>
//#include <time.h>
#include <unistd.h>
#include <stddef.h>
#include <stdint.h>

#include <ti/drivers/GPIO.h>                    //TI-Driver includes
#include <ti/drivers/ADC.h>
#include <ti/drivers/ADCBuf.h>
#include <ti/drivers/SPI.h>



#include <ti/drivers/net/wifi/simplelink.h>     //Simplelink includes

#include <ti/drivers/net/wifi/slnetifwifi.h>    //SlNetSock includes

#include "network_if.h"                         // Common interface includes
#include "uart_term.h"

#include "Board.h"                              // Application includes

#include "MQTT_Paho/MQTTPacket.h"               //MQTT-Paho Libraries
#include "arm_math.h"
//#include "arm_const_structs.h"                  // Remember to make the neccesary adjustments to the symbols

//*****************************************************************************
//                          LOCAL DEFINES
//*****************************************************************************
#define MQTT_INIT_STATE          (0x04)
#define APPLICATION_NAME         "MQTT client"
#define SLNET_IF_WIFI_PRIO       (5)

/* Spawn task priority and Task and Thread Stack Size                        */
#define TASKSTACKSIZE            2048
#define SPAWN_TASK_PRIORITY      9


/* Expiration value for the timer that is being used to toggle the Led.      */
#define TIMER_EXPIRATION_VALUE   100 * 1000000

//*****************************************************************************
//                      LOCAL FUNCTION PROTOTYPES
//*****************************************************************************

void TimerPeriodicIntHandler(sigval val);
void LedTimerConfigNStart();
void LedTimerDeinitStop();
static void DisplayBanner(char * AppName);
void Mqtt_start();
int32_t Mqtt_IF_Connect();

//*****************************************************************************
//                 GLOBAL VARIABLES
//*****************************************************************************

/* Connection state: (0) - connected, (negative) - disconnected              */
int32_t ApConnectionState = -1;
uint32_t InitState = 0;
bool ResetApp = false;
unsigned short g_usTimerInts;

/* AP Security Parameters                                                    */
SlWlanSecParams_t SecurityParams = { 0 };

/* Client ID                                                                 */
/* If ClientId isn't set, the MAC address of the device will be copied into  */
/* the ClientID parameter.                                                   */
char ClientId[13] = {'\0'};
timer_t g_timer;


//*****************************************************************************
//! Periodic Timer Interrupt Handler
//! \param None
//! \return None
//*****************************************************************************
void TimerPeriodicIntHandler(sigval val)
{
    /* Increment our interrupt counter.                                      */
    g_usTimerInts++;

    if(!(g_usTimerInts & 0x1))
    {
        /* Turn Led Off                                                      */
        GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_OFF);
    }
    else
    {
        /* Turn Led On                                                       */
        GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_ON);
    }
}

//*****************************************************************************
//! Function to configure and start timer to blink the LED while device is
//! trying to connect to an AP
//! \param none
//! return none
//*****************************************************************************
void LedTimerConfigNStart()
{
    struct itimerspec value;
    sigevent sev;

    /* Create Timer                                                          */
    sev.sigev_notify = SIGEV_SIGNAL;
    sev.sigev_notify_function = &TimerPeriodicIntHandler;
    timer_create(2, &sev, &g_timer);

    /* start timer                                                           */
    value.it_interval.tv_sec = 0;
    value.it_interval.tv_nsec = TIMER_EXPIRATION_VALUE;
    value.it_value.tv_sec = 0;
    value.it_value.tv_nsec = TIMER_EXPIRATION_VALUE;

    timer_settime(g_timer, 0, &value, NULL);
}

//*****************************************************************************
//! Disable the LED blinking Timer as Device is connected to AP
//! \param none
//! return none
//*****************************************************************************
void LedTimerDeinitStop()
{
    /* Disable the LED blinking Timer as Device is connected to AP.          */
    timer_delete(g_timer);
}

//*****************************************************************************
//! Application startup display on UART
//! \param  none
//! \return none
//*****************************************************************************
static void DisplayBanner(char * AppName)
{
    UART_PRINT("\n\n\n\r");
    UART_PRINT("\t\t *************************************************\n\r");
    UART_PRINT("\t\t    CC32xx %s Application       \n\r", AppName);
    UART_PRINT("\t\t *************************************************\n\r");
    UART_PRINT("\n\n\n\r");
}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
//The function provides Internet connection to the SimpleLink device, the parameters of the network can be found
//in network_if.h which, the function returns 0 when successful while -1 when failing
//----------------------------------------------------------------------------------------------------------------//

int32_t Internet_Connect(){
    int32_t lRetVal;
    char SSID_Remote_Name[32];
    int8_t Str_Length;
    memset(SSID_Remote_Name, '\0', sizeof(SSID_Remote_Name));
    Str_Length = strlen(SSID_NAME);

    if(Str_Length){                                                 //Copy the Default SSID to the local variable, contained in Network_if.h
        strncpy(SSID_Remote_Name, SSID_NAME, Str_Length);
    }
    DisplayBanner(APPLICATION_NAME);                                //Display Application Banner

    GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_OFF);
    GPIO_write(Board_GPIO_LED1, Board_GPIO_LED_OFF);
    GPIO_write(Board_GPIO_LED2, Board_GPIO_LED_OFF);

    Network_IF_ResetMCUStateMachine();                              //Reset The state of the machine
    lRetVal = Network_IF_InitDriver(ROLE_STA);                      //Start the driver
    if(lRetVal < 0){
        UART_PRINT("Failed to start SimpleLink Device\n\r", lRetVal);
        return(-1);
    }

    GPIO_write(Board_GPIO_LED2, Board_GPIO_LED_ON);                 //switch on Board_GPIO_LED2 to indicate Simplelink is properly up.
    LedTimerConfigNStart();                                         //Start Timer to blink Board_GPIO_LED0 till AP connection


    SecurityParams.Key = (signed char *) SECURITY_KEY;              //Initialize AP security params (also check network_if.h)
    SecurityParams.KeyLen = strlen(SECURITY_KEY);
    SecurityParams.Type = SECURITY_TYPE;
    lRetVal = Network_IF_ConnectAP(SSID_Remote_Name, SecurityParams);//Connect to the Access Point
    if(lRetVal < 0){
        UART_PRINT("Connection to an AP failed\n\r");
        return(-1);
    }

    LedTimerDeinitStop();                                           //Disable the LED blinking Timer as Device is connected to AP.
    GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_ON);                 //Switch ON Board_GPIO_LED0 to indicate that Device acquired an IP
    sleep(1);
    GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_OFF);
    GPIO_write(Board_GPIO_LED1, Board_GPIO_LED_OFF);
    GPIO_write(Board_GPIO_LED2, Board_GPIO_LED_OFF);

    return(0);                                                     //When successful the function returns a 0
}
//----------------------------------------------------------------------------------------------------------------//
//====================================End of Internet_Connect()===================================================//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
//=== S=Get_Sample. Returns a complete 1024 points already processed form the ADC and that contain the relevant
//=== information to be sent to the network
//----------------------------------------------------------------------------------------------------------------//
#define ADCBUFFERSIZE    (10)
#define UARTBUFFERSIZE   ((20 * ADCBUFFERSIZE) + 24)

uint16_t sampleBufferOne[ADCBUFFERSIZE];
uint16_t sampleBufferTwo[ADCBUFFERSIZE];
uint32_t microVoltBuffer[ADCBUFFERSIZE];
uint32_t buffersCompletedCounter = 0;

void Get_Sample(){
//=====================Configure the UART, remove UART receive from LPDS===========================================//
//=====================Everything that is necessary to get the samples===========================================//

    ADCBuf_Handle adcHand;
    ADCBuf_Params adcBufParams;
    ADCBuf_Conversion continuousConversion;

    /* Call driver init functions */
    ADCBuf_init();

    /* Set up an ADCBuf peripheral in ADCBuf_RECURRENCE_MODE_CONTINUOUS */
    ADCBuf_Params_init(&adcBufParams);
    adcBufParams.callbackFxn = NULL;
    adcBufParams.recurrenceMode = ADCBuf_RECURRENCE_MODE_ONE_SHOT;
    adcBufParams.returnMode = ADCBuf_RETURN_MODE_BLOCKING;
    adcBufParams.samplingFrequency = 200;
    adcHand = ADCBuf_open(Board_ADCBUF0, &adcBufParams);

    /* Configure the conversion struct */
    continuousConversion.arg = NULL;
    continuousConversion.adcChannel = Board_ADCBUF0CHANNEL0;
    continuousConversion.sampleBuffer = sampleBufferOne;
    continuousConversion.samplesRequestedCount = ADCBUFFERSIZE;

    if (adcHand == NULL){
        /* ADCBuf failed to open. */
        while(1);
    }
    ADCBuf_convert(adcHand, &continuousConversion, 1);

    //int i=0;
    //int status = 8;
    //for(i=0; i<30; ++i){


        //if (GPIO_read(Board_ADC1)==0){                              //Small if statement to get the Positive edge of the signal
        //    while (GPIO_read(Board_ADC1)==0){;}
        //       }
        //else{
        //    while (GPIO_read(Board_ADC1)==1){;}
        //    while (GPIO_read(Board_ADC1)==0){;}
        // }

        //status = ADCBuf_convert(adcBuf, &ADC_Conversion, 1);
    //}

}

//----------------------------------------------------------------------------------------------------------------//
//====================================End of Get_Sample()=========================================================//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//


//*****************************************************************************
//! MQTT Start - Initialize and create all the items required to run the MQTT
//! protocol
//! \param  none
//! \return None
//*****************************************************************************
void Mqtt_start()
{

    while(1){
        MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
        //int rc = 0;
        unsigned char buf[200];
        MQTTString topicString = MQTTString_initializer;
        char* payload = "La Puta!!!";
        int payloadlen = strlen(payload);
        int buflen = sizeof(buf);

        data.clientID.cstring = "me";
        data.keepAliveInterval = 20;
        data.cleansession = 1;
        int len = MQTTSerialize_connect(buf, buflen, &data); /* 1 */

        topicString.cstring = "MScCM";
        len += MQTTSerialize_publish(buf + len, buflen - len, 0, 0, 0, 0, topicString, payload, payloadlen); /* 2 */

        len += MQTTSerialize_disconnect(buf + len, buflen - len); /* 3 */

        int mysock = sl_Socket(SL_AF_INET, SL_SOCK_STREAM,0);
        SlSockAddrIn_t addr;
        addr.sin_family = SL_AF_INET;
        addr.sin_port = sl_Htons (1883);
        addr.sin_addr.s_addr = sl_Htonl (0x25BB6A10); //iot.eclipse.org  0xC6291EF1
                                                        //0x12B868B4
                                                       // 0x25BB6A10  test.mosquitto.org


        sl_Connect (mysock,(SlSockAddr_t *) &addr,sizeof(addr));
        sl_Send(mysock, buf, len, NULL);
        sl_Close(mysock);

        //rc = Socket_new("127.0.0.1", 1883, &mysock);
        //rc = write(mysock, buf, len);
        //rc = close(mysock);

        GPIO_write(Board_GPIO_LED3, Board_GPIO_LED_ON);
        sleep(1);
        GPIO_write(Board_GPIO_LED3, Board_GPIO_LED_OFF);
        sleep(1);

    }


    //InitState &= ~MQTT_INIT_STATE;
}

//==============================================================================================================//
//====================Main Thread of the flow called in main_tirtos starts here=================================//
//==============================================================================================================//

void mainThread(void * args)
{



    GPIO_init();
    SPI_init();

//=====================Configure the UART, remove UART receive from LPDS===========================================//
    UART_Handle UART_H;
    UART_H = InitTerm();
    UART_control(UART_H, UART_CMD_RXDISABLE, NULL);

//=====================Following steps are necessary to open the Internet connection==============================//
    uint32_t count = 0;
    pthread_t spawn_thread = (pthread_t) NULL;
    pthread_attr_t pAttrs_spawn;
    struct sched_param priParam;
    int32_t retc = 0;
                            //Initialize SlNetSock layer with CC31xx/CC32xx interface----------------------------//
    SlNetIf_init(0);
    SlNetIf_add(SLNETIF_ID_1, "CC3120", (const SlNetIf_Config_t *)&SlNetIfConfigWifi,SLNET_IF_WIFI_PRIO);
    SlNetSock_init(0);
    SlNetUtil_init(0);

                            //Create the sl_Task-----------------------------------------------------------------//
    pthread_attr_init(&pAttrs_spawn);
    priParam.sched_priority = SPAWN_TASK_PRIORITY;
    retc = pthread_attr_setschedparam(&pAttrs_spawn, &priParam);
    retc |= pthread_attr_setstacksize(&pAttrs_spawn, TASKSTACKSIZE);
    retc |= pthread_attr_setdetachstate(&pAttrs_spawn, PTHREAD_CREATE_DETACHED);
    retc = pthread_create(&spawn_thread, &pAttrs_spawn, sl_Task, NULL);
                            //Start, Stop of the SimpleLink Task, and infinite loops if an error occurs---------//
    if(retc != 0){UART_PRINT("could not create simplelink task\n\r");                   while(1){;}}
    retc = sl_Start(0, 0, 0);
    if(retc < 0){UART_PRINT("\n sl_Start failed\n");                                    while(1){;}}
    retc = sl_Stop(SL_STOP_TIMEOUT);
    if(retc < 0){UART_PRINT("\n sl_Stop failed\n");                                     while(1){;}}
    if(retc < 0){UART_PRINT("mqtt_client - Unable to retrieve device information \n");  while(1){;}}

//==============================================================================================================//
//====================This is the begging of the MAIN flow of the application===================================//
//==============================================================================================================//
    ResetApp = false;                                                   //Variable in case a reset is needed
    InitState = 0;
    ApConnectionState = Internet_Connect();                             //Connect the MQTT client to a valid Access Point (AP)
    InitState |= MQTT_INIT_STATE;


    while(1)
    {
        Get_Sample();
        /*Run MQTT Main Thread (it will open the Client and Server)          */
        Mqtt_start();

        /*Wait for init to be completed!!!                                   */
        while(InitState != 0)
        {
            UART_PRINT(".");
            sleep(1);
        }
        UART_PRINT(".\r\n");

        while(ResetApp == false)
        {
            ;
        }

        UART_PRINT("TO Complete - Closing all threads and resources\r\n");
        UART_PRINT("reopen MQTT # %d  \r\n", ++count);
    }
}





void RecvThread(void * args)
{
    while(1){
        sleep(10);
    }
}
