
/*
 * Copyright (c) 2018, 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.
 */

/*
 *    ======== i2ctmp116.c ========
 */
#include <stdint.h>
#include <stddef.h>
#include <unistd.h>

/* POSIX Header files */
#include <pthread.h>
#include <semaphore.h>

/* Driver Header files */
#include <ti/drivers/GPIO.h>
#include <ti/drivers/I2C.h>
#include <ti/display/Display.h>

/* Module Header */
#include <ti/sail/tmp116/tmp116.h>

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

#define THREADSTACKSIZE    1024

extern Display_Handle dispHandle;

#define SAMPLE_TIME     10        /*In seconds*/
#define HIGH_LIMIT      30.0F
#define LOW_LIMIT       20.0F

#define TMP_TASK_STACK_SIZE   768

TMP116_Handle  tmp116Handle = NULL;
I2C_Handle     i2cHandle    = NULL;

sem_t tmp116Sem;


/* Global values which may be accessed from GUI Composer App */
float temp;

/* Global sample rate which may be accessed and set from GUI Composer App */
volatile uint16_t sampleTime;

/*
 *  ======== tmp116Callback ========
 *  When an ALERTing condition is met on the TMP116 hardware, the ALERT pin
 *  is asserted generating an interrupt. This callback function serves as
 *  an ISR for a single TMP116 sensor.
 */
void tmp116Callback(uint_least8_t index)
{
    sem_post(&tmp116Sem);
}

/*
 *  ======== tmp116AlertTask ========
 *  This task is unblocked when the ALERT pin is asserted and generates an
 *  interrupt. When the TMP116 is in INTERRUPT mode, the status register must
 *  be read to clear the ALERT pin.
 */
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);

            /* Check Object Temperature High Flag */
            if (data & TMP116_STAT_ALR_HI) {
                Display_print0(dispHandle, 6, 0, "ALERT: Object Temperature High\n");
            }

            /* Check Object Temperature Low Flag */
            if (data & TMP116_STAT_ALR_LO) {
                Display_print0(dispHandle, 6, 0, "ALERT: Object Temperature Low\n");
            }

        }
    }
}

/*
 *  ======== sailThread ========
 */
void *sailThread(void *arg0)
{
    I2C_Handle      i2cHandle;
    I2C_Params      i2cParams;
    int             retc;
    pthread_t alertTask;
    pthread_attr_t       pAttrs;
    float hiLim = HIGH_LIMIT;
    float loLim = LOW_LIMIT;
    sampleTime = SAMPLE_TIME;
    struct sched_param  priParam;

    TMP116_Params  tmp116Params;

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

    /* Turn on user LED and TMP116 Sensor */
    GPIO_write(Board_GPIO_LED0, Board_GPIO_LED_ON);
    GPIO_write(Board_TMP116_PWR, Board_TMP116_ON);

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

    i2cParams.bitRate = I2C_400kHz;

    i2cHandle = I2C_open(Board_I2C_TMP, &i2cParams);
    if (i2cHandle == NULL) {
        Display_print0(dispHandle, 6, 0, "Error Initializing I2C\n");
        while (1);
    }

    if(0 != sem_init(&tmp116Sem,0,0))
    {
        /* sem_init() failed */
        Display_print0(dispHandle, 6, 0, "tmp116Sem Semaphore creation failed\n");
        while (1);
    }

    pthread_attr_init(&pAttrs);

    priParam.sched_priority = 1;
    pthread_attr_setschedparam(&pAttrs, &priParam);

    pthread_attr_setstacksize(&pAttrs, TMP_TASK_STACK_SIZE);
    retc = pthread_create(&alertTask, &pAttrs, tmp116AlertTask, NULL);
    if (retc != 0) {
        /* pthread_create() failed */
        Display_print0(dispHandle, 6, 0, "Alert Task creation failed\n");
        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_TMP116, i2cHandle, &tmp116Params);

    /* Check if the open is successful */
    if (tmp116Handle == NULL) {
        Display_print0(dispHandle, 6, 0, "TMP116_ROOMTEMP0 Open Failed!\n");
        while(1);
    }

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

    /* Set Object Temperature Alert Limits */
    if (!TMP116_setTempLimit(tmp116Handle, TMP116_CELSIUS, hiLim, loLim)) {
        Display_print0(dispHandle, 6, 0, "Setting Object Temperature Limits Failed!\n");
    }

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

    Display_print1(dispHandle, 6, 0, "Temperature: %d (C)\n", (int32_t) temp);

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

        /* Get Die and Object Temperatures */
        if (!TMP116_getTemp(tmp116Handle, TMP116_CELSIUS, &temp)) {
            Display_print0(dispHandle, 6, 0, "TMP116 sensor read failed\n");

        }

        Display_print1(dispHandle, 6, 0, "Temp: %d (C)\n\n", (int32_t) temp);

        sleep(sampleTime);
    }
}

void sailThread_create(void) {
     pthread_t           thread;
    pthread_attr_t      pAttrs;
    struct sched_param  priParam;
    int                 retc;

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

    /* Initialize the attributes structure with default values */
    pthread_attr_init(&pAttrs);

    /* Set priority, detach state, and stack size attributes */
    priParam.sched_priority = 1;
    retc = pthread_attr_setschedparam(&pAttrs, &priParam);
    retc |= pthread_attr_setdetachstate(&pAttrs, PTHREAD_CREATE_DETACHED);
    retc |= pthread_attr_setstacksize(&pAttrs, THREADSTACKSIZE);
    if (retc != 0) {
        /* failed to set attributes */
        while (1) {}
    }

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