/*
 * Copyright 2020-2021 NXP
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include "FreeRTOS.h"
#include "task.h"

#include "fsl_debug_console.h"
#include "littlevgl_support.h"
#include "pin_mux.h"
#include "board.h"
#include "lvgl.h"
#include "gui_guider.h"
#include "events_init.h"
#include "custom.h"
#include "fsl_snvs_hp.h"
#include "semphr.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/
#define PERIOD_TICK_ONE_SECOND  1000U

#ifndef SECONDS_IN_A_DAY
#define SECONDS_IN_A_DAY    (86400U)
#endif
#ifndef SECONDS_IN_A_HOUR
#define SECONDS_IN_A_HOUR   (3600U)
#endif
#ifndef SECONDS_IN_A_MINUTE
#define SECONDS_IN_A_MINUTE (60U)
#endif
#ifndef DAYS_IN_A_YEAR
#define DAYS_IN_A_YEAR      (365U)
#endif
#ifndef YEAR_RANGE_START
#define YEAR_RANGE_START    (1970U)
#endif
#ifndef YEAR_RANGE_END
#define YEAR_RANGE_END      (2099U)
#endif

/*******************************************************************************
 * Variables
 ******************************************************************************/
static volatile uint32_t s_tick        = 0U;

extern uint8_t g_ckActive;
extern uint8_t g_blendActive;

extern uint32_t pourAnimation_Delay;
extern bool animationDelayActive;

volatile uint32_t currTime_s, alarmTime;
snvs_hp_rtc_datetime_t currTime_datetime;
volatile uint32_t updateOvenCk;
volatile uint32_t updateBlenderTime;

static volatile bool s_lvgl_initialized = false;
lv_ui guider_ui;

SemaphoreHandle_t xGuiSemaphore;

/*******************************************************************************
 * Prototypes
 ******************************************************************************/
uint32_t DEMO_ConvertDatetimeToSeconds(snvs_hp_rtc_datetime_t *datetime);
void DEMO_ConvertSecondsToDatetime(uint32_t seconds, snvs_hp_rtc_datetime_t *datetime);

/*******************************************************************************
 * Code
 ******************************************************************************/
static void AppTask(void *param)
{
	xGuiSemaphore = xSemaphoreCreateBinary();

	if (xGuiSemaphore == NULL) {
		while(1) {
			// Something went wrong if the code ends up here
		}
		return;
	}

	updateOvenCk = 0;
	updateBlenderTime = 0;

    lv_port_pre_init();
    lv_init();
    lv_port_disp_init();
    lv_port_indev_init();

    s_lvgl_initialized = true;

    setup_ui(&guider_ui);
    events_init(&guider_ui);
    custom_init(&guider_ui);

    xSemaphoreGive(xGuiSemaphore);

    for (;;)
    {
    	vTaskDelay(5);
    	lv_task_handler();


    	if(updateOvenCk) {
    		ovenCk_cb();
    		updateOvenCk = 0;
    	}

    	if(updateBlenderTime) {
    		blendActive_cb();
    		updateBlenderTime = 0;
    	}
    }
}

/*!
 * @brief Main function
 */
int main(void)
{
    BaseType_t stat;

    /* Init board hardware. */
    /* Set the eLCDIF read_qos priority high, to make sure eLCDIF
     * can fetch data in time when PXP is used.
     */
    *((volatile uint32_t *)0x41044100) = 5;

    BOARD_ConfigMPU();
    BOARD_InitPins();
    BOARD_InitI2C1Pins();
    BOARD_InitSemcPins();
    BOARD_BootClockRUN();
    BOARD_InitDebugConsole();

    stat = xTaskCreate(AppTask, "littlevgl", configMINIMAL_STACK_SIZE + 800, NULL, tskIDLE_PRIORITY + 2, NULL);

    if (pdPASS != stat)
    {
        PRINTF("Failed to create littlevgl task");
        while (1)
            ;
    }

    vTaskStartScheduler();

    for (;;)
    {
    } /* should never get here */
}

/*!
 * @brief Malloc failed hook.
 */
void vApplicationMallocFailedHook(void)
{
    for (;;)
        ;
}

/*!
 * @brief FreeRTOS tick hook.
 */
void vApplicationTickHook(void)
{
    if (s_lvgl_initialized)
    {
    	s_tick++;
        lv_tick_inc(1);

        // Service Oven time
        if ((s_tick % PERIOD_TICK_ONE_SECOND) == 0U) {
        	currTime_s++;

            if(g_ckActive == true) {
            	updateOvenCk = 1;
            }

            if(g_blendActive == true) {
            	updateBlenderTime = 1;
            }
        }
    }
}

/*!
 * @brief Stack overflow hook.
 */
void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTaskName)
{
    (void)pcTaskName;
    (void)xTask;

    for (;;)
        ;
}


uint32_t DEMO_ConvertDatetimeToSeconds(snvs_hp_rtc_datetime_t *datetime)
{
    assert(datetime);

    /* Number of days from begin of the non Leap-year*/
    /* Number of days from begin of the non Leap-year*/
    uint16_t monthDays[] = {0U, 0U, 31U, 59U, 90U, 120U, 151U, 181U, 212U, 243U, 273U, 304U, 334U};
    uint32_t seconds;

    /* Compute number of days from 1970 till given year*/
    seconds = ((uint32_t)datetime->year - 1970U) * DAYS_IN_A_YEAR;
    /* Add leap year days */
    seconds += (((uint32_t)datetime->year / 4U) - (1970U / 4U));
    /* Add number of days till given month*/
    seconds += monthDays[datetime->month];
    /* Add days in given month. We subtract the current day as it is
     * represented in the hours, minutes and seconds field*/
    seconds += ((uint32_t)datetime->day - 1U);
    /* For leap year if month less than or equal to Febraury, decrement day counter*/
    if (((datetime->year & 3U) == 0x00U) && (datetime->month <= 2U))
    {
        seconds--;
    }

    seconds = (seconds * SECONDS_IN_A_DAY) + (datetime->hour * SECONDS_IN_A_HOUR) +
              (datetime->minute * SECONDS_IN_A_MINUTE) + datetime->second;

    return seconds;
}

void DEMO_ConvertSecondsToDatetime(uint32_t seconds, snvs_hp_rtc_datetime_t *datetime)
{
    assert(datetime);

    uint8_t i;
    uint16_t daysInYear;
    uint32_t secondsRemaining;
    uint32_t days;
    /* Table of days in a month for a non leap year. First entry in the table is not used,
     * valid months start from 1
     */
    uint8_t daysPerMonth[] = {0U, 31U, 28U, 31U, 30U, 31U, 30U, 31U, 31U, 30U, 31U, 30U, 31U};

    /* Start with the seconds value that is passed in to be converted to date time format */
    secondsRemaining = seconds;

    /* Calcuate the number of days, we add 1 for the current day which is represented in the
     * hours and seconds field
     */
    days = secondsRemaining / SECONDS_IN_A_DAY + 1U;

    /* Update seconds left*/
    secondsRemaining = secondsRemaining % SECONDS_IN_A_DAY;

    /* Calculate the datetime hour, minute and second fields */
    datetime->hour   = (uint8_t)(secondsRemaining / SECONDS_IN_A_HOUR);
    secondsRemaining = secondsRemaining % SECONDS_IN_A_HOUR;
    datetime->minute = (uint8_t)(secondsRemaining / 60U);
    datetime->second = (uint8_t)(secondsRemaining % SECONDS_IN_A_MINUTE);

    /* Calculate year */
    daysInYear     = DAYS_IN_A_YEAR;
    datetime->year = YEAR_RANGE_START;
    while (days > daysInYear)
    {
        /* Decrease day count by a year and increment year by 1 */
        days -= daysInYear;
        datetime->year++;

        /* Adjust the number of days for a leap year */
        if ((datetime->year & 3U) != 0x00U)
        {
            daysInYear = DAYS_IN_A_YEAR;
        }
        else
        {
            daysInYear = DAYS_IN_A_YEAR + 1U;
        }
    }

    /* Adjust the days in February for a leap year */
    if ((datetime->year & 3U) == 0x00U)
    {
        daysPerMonth[2] = 29U;
    }

    for (i = 1U; i <= 12U; i++)
    {
        if (days <= daysPerMonth[i])
        {
            datetime->month = i;
            break;
        }
        else
        {
            days -= daysPerMonth[i];
        }
    }

    datetime->day = (uint8_t)days;
}
