/*
 * 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 */
#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

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];

TMP116_Handle  tmp116Handle ;
I2C_Handle     AppI2cHandle   ;
I2C_Transaction  i2cTransaction;
I2C_Params      AppI2cParams;
TMP116_Params  tmp116Params;

sem_t tmp116Sem;

float temp ;



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
};

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


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();
}


void *tmp116AlertTask(void *arg0)
{
    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);

        }
    }
}

static void rfEasyLinkTxFnx(UArg arg0, UArg arg1)
{

    opto_sonde_data_t* optosonde_data = (opto_sonde_data_t*) arg0;
//    rtc_cmd_t* rtc_cmd = arg1;

//    EasyLink_init(EasyLink_Phy_625bpsLrm);
//    EasyLink_init(EasyLink_Phy_5kbpsSlLr);
    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 * 3600;
#endif

    sleepAndReset(sleep_time_s);
}

void sendorTask_AlertCB()
{
    static opto_sonde_data_t optosonde_data;

    /* Callback for ALERT event */



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

    /* Only handle the periodic event alert */
    if (scifGetAlertEvents() & (1 << SCIF_ADCMEAS_TASK_ID))
    {
        optosonde_data.reason = optosonde_reason_periodic;

        //if(AppI2cHandle == NULL){
            /* Error opening I2C */
            //while (1);
        //}



        if (!TMP116_getTemp(tmp116Handle, TMP116_CELSIUS, &temp))
            //temp =0x30;

        optosonde_data.temp_deg_frac_8 =(int16_t) temp;


        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. */
    Board_initGeneral();



    pin_handle = PIN_open(&pinState, pinTable);
    PIN_registerIntCb(pin_handle, pinInt);

    I2C_init();
    TMP116_init();

    // GPIO_write(Board_TMP116_PWR, Board_TMP116_ON);
    I2C_Params_init(&AppI2cParams);
    AppI2cParams.transferMode = I2C_MODE_BLOCKING;
    AppI2cParams.transferCallbackFxn = NULL;
    AppI2cParams.bitRate = I2C_400kHz;
    AppI2cHandle = I2C_open(Board_I2C_TMP, &AppI2cParams);

    if(0 != sem_init(&tmp116Sem,0,0))
    {

        while (1);
    }

    TMP116_Params_init(&tmp116Params);
    /* Open TMP116 sensor with custom Params */
    /* Callback for ALERT event */
    tmp116Params.callback = &tmp116Callback;
    tmp116Handle = TMP116_open(Board_TMP007_ROOMTEMP, AppI2cHandle, &tmp116Params);
    /* Allow the sensor hardware to complete its first conversion */
    sleep(2);


    //if (tmp116Handle == NULL)
    //{
        //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);


    /* Start BIOS */
    BIOS_start();


    return (0);
}
