/*
 * Copyright (c) 2015-2016, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  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.
 *
 * *  Neither the name of Texas Instruments Incorporated 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 OWNER 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.
 */

/*
 *  ======== rfEasyLinkTx.c ========
 */
/* XDCtools Header files */

/* POSIX Header files */
#include <pthread.h>
#include <stdlib.h>
#include <xdc/std.h>
#include <xdc/runtime/System.h>
#include <xdc/runtime/Error.h>
#include <stdint.h>
#include <stddef.h>
#include <unistd.h>
#include <semaphore.h>

/* BIOS Header files */
#include <ti/drivers/rf/RF.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Task.h>
#include <ti/sysbios/knl/Clock.h>
#include <ti/drivers/GPIO.h>
#include <ti/drivers/I2C.h>

/* TI-RTOS Header files */
#include <ti/drivers/PIN.h>
#include <ti/drivers/Power.h>
#include <ti/devices/cc13x0/driverlib/aon_batmon.h>
#include <ti/devices/cc13x0/driverlib/aux_adc.h>
#include <ti/devices/cc13x0/driverlib/chipinfo.h>
#include <ti/devices/cc13x0/driverlib/sys_ctrl.h>
#include <semaphore.h>
#include <ti/sail/tmp116/tmp116.h>

/* Board Header files */
#include "Board.h"

/* EasyLink API Header files */
#include "easylink/EasyLink.h"

#include "sc/scif.h"

#include "version.h"
#include "../sonde_gw_fw/sys_intf.h"

#include <string.h>
#include <math.h>

#define RFEASYLINKTX_TASK_STACK_SIZE    1024
#define RFEASYLINKTX_TASK_PRIORITY      2

#define RFEASYLINKTX_BURST_SIZE         1

/* Stack size in bytes */
//#define THREADSTACKSIZE    768

Task_Struct txTask; /* not static so you can see in ROV */
static Task_Params txTaskParams;
static uint8_t txTaskStack[RFEASYLINKTX_TASK_STACK_SIZE];

Task_Struct sensorTask; /* not static so you can see in ROV */
static Task_Params sensorTaskParams;
static uint8_t sensorTaskStack[RFEASYLINKTX_TASK_STACK_SIZE];

#define SAMPLE_TIME     1        /*In seconds*/

#define THREADSTACKSIZE    768
#define TMP_TASK_STACK_SIZE   768

TMP116_Handle  tmp116Handle = NULL;
I2C_Handle     i2cHandle    = NULL;

sem_t tmp116Sem;
sem_t datatmp;


 float temp ;
 int16_t datatosend;


volatile uint16_t sampleTime;


static PIN_State pinState;
static PIN_Handle pin_handle;


typedef struct {
    uint8_t     reason;
    int16_t      temp_deg_frac_8;
    uint8_t     bat_20mV;
} opto_sonde_data_t;

//const int OPTOSONDE_BROKEN_TEMP_SENSOR_THRESHOLD = 1500 * 1000; // 1.5 V
//#define OPTOSONDE_DEMO_MODE 1



PIN_Config pinTable[] = {
    PIN_ID(8) | PIN_INPUT_EN | PIN_PULLUP | PIN_HYSTERESIS,
    PIN_TERMINATE
};
 /***********************i2c*******/

void tmp116Callback(uint_least8_t index)
{
    sem_post(&tmp116Sem);
}

void *tmp116AlertTask(void *arga)
{
    uint16_t data;

    while(1) {

        /* Pend on semaphore, tmp116Sem */
        if (0 == sem_wait(&tmp116Sem)) {

            /* Reads status register, resetting the ALERT pin */
            TMP116_readStatus(tmp116Handle, &data);

            /* Check Object Temperature High Flag */
            if (data & TMP116_STAT_ALR_HI) {
            }

            /* Check Object Temperature Low Flag */
            if (data & TMP116_STAT_ALR_LO) {
            }

        }
    }
}



/***********************/

void sleepAndReset(uint32_t sleep_time_secs) {

    // Enable button interrupt wake up
    PIN_setInterrupt(pin_handle, PIN_ID(8) | PIN_IRQ_NEGEDGE);

    uint32_t secs = sleep_time_secs;
    while (secs > 0)
    {
        uint32_t sleep_s = secs > 2000 ? 2000 : secs;
        Task_sleep((sleep_s * 1000u * 1000) / Clock_tickPeriod);
        secs -= sleep_s;
    }

    SysCtrlSystemReset();
}



static void rfEasyLinkTxFnx(UArg arg0, UArg arg1)
{

    opto_sonde_data_t* optosonde_data = (opto_sonde_data_t*) arg0;
   

    EasyLink_init(EasyLink_Phy_Custom);

    /*
     * If you wish to use a frequency other than the default, use
     * the following API:
     * EasyLink_setFrequency(868000000);
     */

    /* Set output power to 12dBm */
//    EasyLink_setRfPwr(12);
    EasyLink_setRfPwr(10);

    EasyLink_TxPacket txPacket;

    // Fill packet data
    uint8_t payload_ptr = 0;
    // Payload version
    txPacket.payload[payload_ptr++] = (uint8_t) (0x0);
    // Src MAC
    EasyLink_getIeeeAddr(&txPacket.payload[payload_ptr]);
    payload_ptr += 8;

    // Copy data
    txPacket.payload[payload_ptr++] = (uint8_t) (optosonde_data->reason);
    txPacket.payload[payload_ptr++] = (uint8_t) (optosonde_data->temp_deg_frac_8 >> 8);
    txPacket.payload[payload_ptr++] = (uint8_t) (optosonde_data->temp_deg_frac_8);
    txPacket.payload[payload_ptr++] = (uint8_t) (optosonde_data->bat_20mV);

    // Firmware version
    memcpy(&txPacket.payload[payload_ptr], &VERSION_HASH, sizeof(VERSION_HASH));
    payload_ptr += sizeof(VERSION_HASH);

    txPacket.len = payload_ptr;
    txPacket.absTime = 0;
    txPacket.dstAddr[0] = OPTOSONDE_ADDR;

    EasyLink_Status result = EasyLink_transmit(&txPacket);

    if (result == EasyLink_Status_Success)
    {
        /* Toggle LED1 to indicate TX */
//                    PIN_setOutputValue(pinHandle, Board_PIN_LED1,!PIN_getOutputValue(Board_PIN_LED1));
    }
    else
    {
        /* Toggle LED1 and LED2 to indicate error */
//                    PIN_setOutputValue(pinHandle, Board_PIN_LED1,!PIN_getOutputValue(Board_PIN_LED1));
//                    PIN_setOutputValue(pinHandle, Board_PIN_LED2,!PIN_getOutputValue(Board_PIN_LED2));
    }

    // Prevent button reset overload
    if (optosonde_data->reason == optosonde_reason_button) {
        Task_sleep(1000000 / Clock_tickPeriod);
    }

    // Tell RTC to sleep
#ifdef OPTOSONDE_DEMO_MODE
    uint32_t sleep_time_s = 30;
#elif OPTOSONDE_VITICODE
    uint32_t sleep_time_s = 10 * 60;
#else
    uint32_t sleep_time_s = 1 * 60;
#endif

    sleepAndReset(sleep_time_s);
}



void *mainThread(void *arga)
{
    

    I2C_Handle      i2cHandle;
    I2C_Params      i2cParams;
    int             retc;
    pthread_t alertTask;
    pthread_attr_t       pAttrs;
    sampleTime = SAMPLE_TIME;

    TMP116_Params  tmp116Params;

    /* Call driver init functions */
    //GPIO_init();
    I2C_init();
    TMP116_init();


    /* Create I2C for usage */
    I2C_Params_init(&i2cParams);

    i2cParams.bitRate = I2C_400kHz;

    i2cHandle = I2C_open(Board_I2C_TMP, &i2cParams);
    if (i2cHandle == NULL) {
        while (1);
    }
    else {
    }

    if(0 != sem_init(&tmp116Sem,0,0))
    {
        /* sem_init() failed */
        while (1);
    }

    pthread_attr_init(&pAttrs);
    pthread_attr_setstacksize(&pAttrs, TMP_TASK_STACK_SIZE);
    retc = pthread_create(&alertTask, &pAttrs, tmp116AlertTask, NULL);
    if (retc != 0) {
        /* pthread_create() failed */
        while (1);
    }

    /* Initialize tmp116Params structure to defaults */
    TMP116_Params_init(&tmp116Params);

    /* Callback for ALERT event */
    tmp116Params.callback = &tmp116Callback;

    /* Open TMP116 sensor with custom Params */
    tmp116Handle = TMP116_open(Board_TMP007_ROOMTEMP, i2cHandle, &tmp116Params);

    /* Check if the open is successful */
    if (tmp116Handle == NULL) {
       while(1);
    }

    /* Allow the sensor hardware to complete its first conversion */
    sleep(2);


    /* Get Die Temperature in Celsius */
    if (!TMP116_getTemp(tmp116Handle, TMP116_CELSIUS, &temp)) {
        //Display_print0(display, 0, 0, "TMP116 sensor read failed");
    }

    /* Begin infinite task loop */
    while (1) {

        if(0==sem_wait(&datatmp)){

            }

        if (!TMP116_getTemp(tmp116Handle, TMP116_CELSIUS, &temp)) {
        }
            

            datatosend =(uint16_t)(temp *100);

            sem_post(&datatmp);

         sleep(sampleTime);

    }
}





void maini2C(void)
{
   pthread_t           thread;
   pthread_attr_t      pAttrs;
   struct sched_param  priParam;
   int                 retc;
   int                 detachState;
   
    /* Call driver init functions */
  

    /* Set priority and stack size attributes */
    pthread_attr_init(&pAttrs);
    priParam.sched_priority = 1;

    detachState = PTHREAD_CREATE_DETACHED;
    retc = pthread_attr_setdetachstate(&pAttrs, detachState);
    if (retc != 0) {
        /* pthread_attr_setdetachstate() failed */
       while (1);
    }

    pthread_attr_setschedparam(&pAttrs, &priParam);

   retc |= pthread_attr_setstacksize(&pAttrs, THREADSTACKSIZE);
   if (retc != 0) {
        /* pthread_attr_setstacksize() failed */
       while (1);
    }

   retc = pthread_create(&thread, &pAttrs, mainThread, NULL);
   if (retc != 0) {
        /* pthread_create() failed */
       while (1);
    }

    /* destroy pthread attribute */    
    pthread_attr_destroy(&pAttrs);
    
    BIOS_start();
 
}



void sendorTask_AlertCB()
{
    static opto_sonde_data_t optosonde_data;

      /* Clear the ALERT interrupt source */
    scifClearAlertIntSource();


    if (scifGetAlertEvents() & (1 << SCIF_ADCMEAS_TASK_ID)){

        optosonde_data.reason = optosonde_reason_periodic;
        if(0!=sem_wait(&datatmp)){

        }

        optosonde_data.temp_deg_frac_8 = (int16_t)(temp *100);

        sem_post(&datatmp);

        
        
        while (!AONBatMonNewBatteryMeasureReady())
        {
            // Wait
            Task_sleep(100 * 100 / Clock_tickPeriod);
        }
        optosonde_data.bat_20mV = (AONBatMonBatteryVoltageGet() * 390625) / 2000000;
        AONBatMonDisable();

        if (PIN_getInputValue(IOID_8) == 0) {
            optosonde_data.reason = optosonde_reason_button;
        }

        // Init Tx task
        Task_Params_init(&txTaskParams);
        txTaskParams.stackSize = RFEASYLINKTX_TASK_STACK_SIZE;
        txTaskParams.priority = RFEASYLINKTX_TASK_PRIORITY + 1;
        txTaskParams.stack = &txTaskStack;
        txTaskParams.arg0 = (xdc_UArg) &optosonde_data;

        Task_construct(&txTask, rfEasyLinkTxFnx, &txTaskParams, NULL);
        }
    else
    {
        // Sensor failed
        sleepAndReset(10 * 60);
    }
    

    /* Acknowledge the alert event */
    scifAckAlertEvents();
    scifUninit();
}

void sensorTask_fn(UArg arg0, UArg arg1)
{
    AONBatMonEnable();

    scifOsalInit();
    scifOsalRegisterTaskAlertCallback(sendorTask_AlertCB);
    scifInit(&scifDriverSetup);
    scifExecuteTasksOnceNbl(1 << SCIF_ADCMEAS_TASK_ID);
}

void pinInt(PIN_Handle handle, PIN_Id pinId) {
    if (pinId == 8) {
        // Force reset to trigger measure and TX
        SysCtrlSystemReset();
    }
}

/*
 *  ======== main ========
 */
int opto_main(void)
{


    /* Call driver init functions. */
    //datatemp.Data=0.0;
   // datatemp.acces=true;
    Board_initGeneral();
    pin_handle = PIN_open(&pinState, pinTable);

    PIN_registerIntCb(pin_handle, pinInt);

    //if(0!=sem_init(&datatmp,0,0)){
        //while(1);
    //}
    
    // Sensor task
    Task_Params_init(&sensorTaskParams);
    txTaskParams.stackSize = RFEASYLINKTX_TASK_STACK_SIZE;
    txTaskParams.priority = RFEASYLINKTX_TASK_PRIORITY;
    txTaskParams.stack = &sensorTaskStack;
    txTaskParams.arg0 = 0;
    txTaskParams.arg1 = 0;

    Task_construct(&sensorTask, sensorTask_fn, &sensorTaskParams, NULL);
    maini2C();

    /* Start BIOS */

    return (0);
}
