
/***** Includes *****/
#include <DmNodeRadioTask.h>
#include <DmNodeTask.h>
#include <xdc/std.h>
#include <xdc/runtime/System.h>

#include <string.h>

#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Task.h>
#include <ti/sysbios/knl/Semaphore.h>
#include <ti/sysbios/knl/Event.h>
#include <ti/sysbios/knl/Clock.h>
#include <ti/drivers/PIN.h>
#include <ti/drivers/pin/PINCC26XX.h>
#include <ti/drivers/Power.h>
#include <ti/drivers/power/PowerCC26XX.h>
#include <ti/drivers/PWM.h>

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

#include "sensors/SensorI2C.h"
#include "sensors/SensorOpt3001.h"
#include "sensors/SensorBmp280.h"
#include "sensors/SensorHdc1000.h"
#include "sensors/SensorMpu9250.h"
#include "sensors/SensorTmp007.h"
#include "extflash/ExtFlash.h"

#include "MOB.h"

/***** Defines *****/
#define NODE_TASK_STACK_SIZE 1024
#define NODE_TASK_PRIORITY   3

#define NODE_EVENT_ALL                  0xFFFFFFFF
#define NODE_EVENT_MOB_UPDATE         (uint32_t)(1 << 0)


#define MOB_NODE_REPORTINTERVAL_S   7
#define MOB_NODE_SHUTDOWN_S         5
#define MOB_NODE_SHUTDOWN_SOUND_S   3

/***** Variable declarations *****/
static Task_Params nodeTaskParams;
Task_Struct nodeTask;    /* not static so you can see in ROV */
static uint8_t nodeTaskStack[NODE_TASK_STACK_SIZE];
Event_Struct nodeEvent;  /* not static so you can see in ROV */
static Event_Handle nodeEventHandle;

/* Clock for the report timeout */
Clock_Struct mobTimerClock;     /* not static so you can see in ROV */
static Clock_Handle mobTimerClockHandle;

/* Pin driver handle */
PIN_Handle pinHandle;
PIN_State pinState;
PIN_Handle buttonPinHandle;
PIN_State buttonPinState;

uint8_t nodeStatus;


/* Enable the 3.3V power domain*/
PIN_Config pinTable[] = {
    NODE_MOB_ACTIVITY_LED | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
    PIN_TERMINATE
};

PIN_Config buttonPinTable[] = {
    Board_PIN_BUTTON0  | PIN_INPUT_EN | PIN_PULLUP,
    Board_PIN_BUTTON1  | PIN_INPUT_EN | PIN_PULLUP,
    PIN_TERMINATE
};

PIN_Config ButtonTableWakeUp[] = {
    Board_PIN_BUTTON0     | PIN_INPUT_EN | PIN_PULLUP | PINCC26XX_WAKEUP_NEGEDGE,
    PIN_TERMINATE
};


uint8_t nodeAddress = 0xFF;

uint8_t buzzer=0;
PWM_Params params;
PWM_Handle pwm = NULL;

/***** Prototypes *****/
static void nodeTaskFunction(UArg arg0, UArg arg1);
void mobTimerCallback(UArg arg0);

/***** Function definitions *****/
void NodeTask_init(void)
{
    PIN_setOutputValue(pinHandle, NODE_MOB_ACTIVITY_LED,0);

    //Buzzer PWM
    PWM_init();
    PWM_Params_init(&params);
    params.dutyUnits = PWM_DUTY_US;
    params.dutyValue = 0;
    params.periodUnits = PWM_PERIOD_US;
    params.periodValue = BUZZER_PWM_PERIOD;
    pwm = PWM_open(Board_PWM2, &params);
    if (pwm == NULL) {
        System_abort("Error initializing BUZZER\n");
    }

    /* Create event used internally for state changes */
    Event_Params eventParam;
    Event_Params_init(&eventParam);
    Event_construct(&nodeEvent, &eventParam);
    nodeEventHandle = Event_handle(&nodeEvent);

    Clock_Params clkParams;
    clkParams.period = 200000 / Clock_tickPeriod; //200ms
    clkParams.startFlag = FALSE;
    Clock_construct(&mobTimerClock, mobTimerCallback, 1, &clkParams);
    mobTimerClockHandle = Clock_handle(&mobTimerClock);

    /* Create the node task */
    Task_Params_init(&nodeTaskParams);
    nodeTaskParams.stackSize = NODE_TASK_STACK_SIZE;
    nodeTaskParams.priority = NODE_TASK_PRIORITY;
    nodeTaskParams.stack = &nodeTaskStack;
    Task_construct(&nodeTask, nodeTaskFunction, &nodeTaskParams, NULL);
}

static void nodeTaskFunction(UArg arg0, UArg arg1)
{
    pinHandle = PIN_open(&pinState, pinTable);
    if (!pinHandle)
    {
        System_abort("Error initializing board 3.3V domain pins\n");
    }

    buttonPinHandle = PIN_open(&buttonPinState, buttonPinTable);
    if(!buttonPinHandle)
    {
        System_abort("Error initializing button pins\n");
    }

    if (SensorI2C_open())
    {
        // Put unused external sensors and flash into Sleep
        SensorBmp280_init();            // Pressure Sensor
        SensorBmp280_enable(false);
        SensorTmp007_init();            // Infrared Thermopile Sensor
        SensorTmp007_enable(false);
        SensorHdc1000_init();           // Humidity
        SensorMpu9250_init();           // Gyroscope and accelerometer
        SensorMpu9250_enable(false);
        SensorMpu9250_powerOff();
        SensorOpt3001_init();
        SensorOpt3001_enable(false);
        ExtFlash_open();
        ExtFlash_close();
    }
    else
    {
        System_abort("Error initializing sensors\n");
    }

    /* start MOB timer */
    Clock_setPeriod(mobTimerClockHandle, (200000 / Clock_tickPeriod)); //200ms
    Clock_start(mobTimerClockHandle);

    while (1)
    {
        /* Wait for event */
        uint32_t events = Event_pend(nodeEventHandle, 0, NODE_EVENT_ALL, BIOS_WAIT_FOREVER);

        /* Read the sensor and send the value */
        if (events & NODE_EVENT_MOB_UPDATE) {

            NodeRadioTask_sendData();
        }
    }

}

void mobTimerCallback(UArg arg0)
{
    static int mobInterval=0;
    static int ledTimer=0;
    static int powerButtonTimer=MOB_NODE_SHUTDOWN_S*5;
    static int doubleButtonDebounce=3;

    if(mobInterval==0) {
        Event_post(nodeEventHandle, NODE_EVENT_MOB_UPDATE);
        mobInterval = MOB_NODE_REPORTINTERVAL_S*5;
    } else {
        mobInterval--;
    }


    /* Activity LED and BUZZER*/
    if( (nodeStatus&NODE_STATUS_FREQ_SELECTED)==0 || (nodeStatus&NODE_STATUS_SHUTDOWN)!=0)
    {
        PIN_setOutputValue(pinHandle, NODE_MOB_ACTIVITY_LED,1);
        buzzer=0;
        ledTimer=0;
    } else if( (nodeStatus&NODE_STATUS_MAIN_STATION_ALARM)!=0 ||
        (nodeStatus&NODE_STATUS_NODE_ALARM)!=0 ||
        (nodeStatus&NODE_STATUS_MAIN_STATION_LOST)!=0 )
    {
        PIN_setOutputValue(pinHandle, NODE_MOB_ACTIVITY_LED,1);
        buzzer=1;
        ledTimer=0;
    } else if ((nodeStatus&NODE_STATUS_MONITORED)==0) {
         PIN_setOutputValue(pinHandle, NODE_MOB_ACTIVITY_LED,0);
         buzzer=0;
         ledTimer=0;
    } else {
        //No alarm, node is monitored.
        buzzer=0;
        if (ledTimer==0) {
            PIN_setOutputValue(pinHandle, NODE_MOB_ACTIVITY_LED,1);
            ledTimer=MOB_NODE_REPORTINTERVAL_S*5;
        } else {
            PIN_setOutputValue(pinHandle, NODE_MOB_ACTIVITY_LED,0);
        }
        ledTimer--;
    }

    //*** Handle buttons:

    //Activate alarm when two buttons pressed:
    if(PIN_getInputValue(Board_PIN_BUTTON0) == 0 && PIN_getInputValue(Board_PIN_BUTTON1) == 0) {
        if(doubleButtonDebounce>0) {
            doubleButtonDebounce--;
        } else {
            nodeStatus|=NODE_STATUS_NODE_ALARM;
        }
    } else {
        doubleButtonDebounce=3;

        //Switch off the tag when power button pressed:
        if(PIN_getInputValue(Board_PIN_BUTTON0) == 0) {
                if(powerButtonTimer>0) {
                    powerButtonTimer--;
                    if(powerButtonTimer<MOB_NODE_SHUTDOWN_SOUND_S*5) {
                        nodeStatus&=(~((uint8_t)NODE_STATUS_NODE_ALARM));
                        nodeStatus&=(~((uint8_t)NODE_STATUS_MAIN_STATION_ALARM));
                        buzzer=2;
                    }
                } else {
                    buzzer=0; //Leave buzzer in the off state
                    PWM_setDuty(pwm, 0);
                    nodeStatus|=NODE_STATUS_SHUTDOWN;
                }
        } else {
            powerButtonTimer=MOB_NODE_SHUTDOWN_S*5;
        }
    }

    //Immediately shutdown if node is not monitored
    //or main station is not present (without informing the main station):
    if((nodeStatus&NODE_STATUS_SHUTDOWN)!=0 &&
       (((nodeStatus&NODE_STATUS_MONITORED)==0) || ((nodeStatus&NODE_STATUS_MAIN_STATION_LOST)!=0))) {
        //Wait while button is pressed
        static int debounce=5;
        if(PIN_getInputValue(Board_PIN_BUTTON0) == 0) {
            debounce=5;
        } else if(debounce>0) {
            debounce--;
        } else {
            PIN_setOutputValue(pinHandle, NODE_MOB_ACTIVITY_LED,0);

            /* Configure DIO for wake up from shutdown */
            PINCC26XX_setWakeup(ButtonTableWakeUp);
            /* Go to shutdown */
            Power_shutdown(0, 0);
        }
    }

    static int buzz=0;
    switch(buzzer) {
    default:
        PWM_setDuty(pwm, 0);
        PWM_stop(pwm);
        break;
    case 1:
        if(buzz==0) {
            PWM_setDuty(pwm, BUZZER_PWM_PERIOD/2);
            PWM_start(pwm);
            buzz=1;
        } else {
            PWM_setDuty(pwm, 0);
            PWM_stop(pwm);
            buzz=0;
        }
        break;
    case 2:
        PWM_setDuty(pwm, BUZZER_PWM_PERIOD/2);
        PWM_start(pwm);
        break;
    }
}




