/*
* Copyright (C) 2004 TES Electronic Solutions GmbH,
* All Rights Reserved.
* This source code and any compilation or derivative thereof is the
* proprietary information of TES Electronic Solutions GmbH
* and is confidential in nature.
* Under no circumstances is this software to be exposed to or placed
* under an Open Source License of any type without the expressed
* written permission of TES Electronic Solutions GmbH
*
*############################################################
*/

/* Dependencies */
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>


#include "r_cpg_drv_api.h"
#include "r_ostm_drv_api.h"
#include "r_startup_config.h"
#include "r_os_abstraction_api.h"
#include "r_task_priority.h"
#include "r_octabus_lld_rza2m_api.h"

#include "freertos.h"
#include "task.h"
#include "semphr.h"

#include "iodefine.h"
#include "compiler_settings.h"

#include "m13_rza2m_ek_lcd.h"
#include "m13_rza2m_ek_button.h"
#include "m13_rza2m_ek_led.h"
#include "m13_rza2m_ek_acc.h"
#include "m13_rza2m_ek_vcom.h"
#include "m13_rza2m_ek_status.h"
#include "m13_rza2m_ek_i2c.h"
#include "m13_rza2m_ek_touch.h"
#include "m13_rza2m_ek_octaram.h"
#include "m13_rza2m_ek_sdram.h"
#include "m13_rza2m_ek_eeprom.h"

#define MAIN_PRV_LED_ON        (1)
#define MAIN_PRV_LED_OFF       (0)

extern void GuilianiStart(void);

void vApplicationStackOverflowHook(xTaskHandle pxTask, char *pcTaskName)
{
    (void) pcTaskName;
    (void) pxTask;

    taskDISABLE_INTERRUPTS();
    while(1)
    {
        ;
    }
}

/* explcit function for cache-access */
unsigned int ClearDataCache(void* ptr, uint32_t size)
{
    return R_CACHE_L1DataCleanLine(ptr, size);
}

static void prvGuilianiTask( void *pvParameters )
{
    /* Remove compiler warning about unused parameter. */
    ( void ) pvParameters;

    GuilianiStart();
}

//----------------------------------
#define TP_TOUCHNUM_MAX 5

typedef enum {
    TPEVT_ENTRY_NONE    = 0x0000,      /*!< None */
    TPEVT_ENTRY_UP      = 0x0001,      /*!< Up */
    TPEVT_ENTRY_DOWN    = 0x0002,      /*!< Down */
    TPEVT_ENTRY_MOVE    = 0x0004,      /*!< Move */

    TPEVT_ENTRY_ALL     = 0x0007,      /*!< All */

    TPEVT_ENTRY_UNKNOWN = 0x8000       /*!< internal event state */
} TpEvt_EntryType ;

typedef struct {
    TpEvt_EntryType     eState;
    uint16_t            unPosX;
    uint16_t            unPosY;
} TP_TouchFinger_st;

typedef struct {
    TP_TouchFinger_st   sFinger[TP_TOUCHNUM_MAX];
} TP_TouchEvent_st;

typedef struct {
    int32_t x ;        /*!< x-coordinate [pixel] */
    int32_t y ;        /*!< y-coordinate [pixel] */
} TPEVT_COORDINATES ;
//----------------------------------

int16_t ax;
int16_t ay;
int16_t az;
int8_t  ay_toggle = 0;
uint8_t touch_status;
uint8_t touch_data[31];

extern uint16_t background_color;
extern int32_t touch_read_request;

static uint32_t gs_main_led_flg;
static SemaphoreHandle_t i2c3_event = NULL;

// Private global functions
void lcd_task(void *parameters);
void lcd_task_start(void);
void touch_task(void *parameters);
void touch_task_start(void);

extern void touchevent_callback(int_t nId, TP_TouchEvent_st* psTouchEvt);

void lcd_display_test_screen(void)
{
    // clear screen with background color
    bsp_lcd_clear(LCD_DEFAULT_BACKGROUND_COLOR);

    // Set font and color for default texts
    bsp_lcd_set_text_color(LCD_COLOR_BLACK);
    bsp_lcd_set_font(&font_22x29);

    // Display default texts
    bsp_lcd_display_string(301, 60, "M13DESIGN");
    bsp_lcd_display_string(268, 150, "M13-RZA2M-EK");
    bsp_lcd_display_string(312, 300, "BSP DEMO");
    bsp_lcd_draw_rect(250, 292, 300, 40, LCD_COLOR_BLACK);

    // Set font and color for coords. text
    bsp_lcd_set_text_color(LCD_COLOR_BLUE);
    bsp_lcd_set_font(&font_14x19);

    // Display corner's coordinates
    bsp_lcd_display_string(1, 5, "(0,0)");
    bsp_lcd_display_string(702, 5, "(800,0)");
    bsp_lcd_display_string(1, 461, "(0,480)");
    bsp_lcd_display_string(674, 461, "(800,480)");
}

void touch_task(void *parameters)
{
    uint8_t touch_status;
    uint8_t touch_data[31];

    uint16_t x_pos[5];
    uint16_t y_pos[5];

    //----------------------------------
    TP_TouchEvent_st    sTouchEvt;
    TPEVT_COORDINATES   sLastCoords[TP_TOUCHNUM_MAX];
    int                 sLastState[TP_TOUCHNUM_MAX];

    memset(&sTouchEvt, 0x00, sizeof(sTouchEvt));
    memset(sLastCoords, 0x00, sizeof(sLastCoords));
    memset(sLastState, 0x00, sizeof(sLastState));
    //----------------------------------

    // clear touch data
    memset(touch_data, 0x00, sizeof(touch_data) );

    while(1)
    {
        //Wait for an event
        xSemaphoreTake(i2c3_event, portMAX_DELAY);

        if(touch_read_request > 0)
        {
            bsp_touch_get_status(&touch_status);

            if(touch_status >= 1 && touch_status <= 5)
            {
                bsp_touch_get_data(touch_data, sizeof(touch_data));
            }
            // Reset irq flag
            touch_read_request = 0;
        }

        // Release semaphore
        xSemaphoreGive(i2c3_event);

        //----------------------------------
        int send_event = 0;

        // check for new positions
        if (touch_status >= 1 && touch_status <= 5)
        {
            // Retrieve and form finger position data
            for(uint8_t i = 0; i < touch_status; i++)
            {
                bsp_touch_get_position(touch_data, ID_FINGER(i), &x_pos[i], &y_pos[i]);

                if ((sLastState[i] == TPEVT_ENTRY_NONE) || (sLastState[i] == TPEVT_ENTRY_UP))
                {
                	sTouchEvt.sFinger[i].eState = TPEVT_ENTRY_DOWN;
            		sTouchEvt.sFinger[i].unPosX = x_pos[i];
            		sTouchEvt.sFinger[i].unPosY = y_pos[i];
                	send_event = 1;
                }
                else if ((sLastState[i] == TPEVT_ENTRY_DOWN) || (sLastState[i] == TPEVT_ENTRY_MOVE))
                {
                	// check for delta
                	if (
						(abs(sLastCoords[i].x - x_pos[i]) > 2) ||
						(abs(sLastCoords[i].y - y_pos[i]) > 2)
						)
                	{
						sTouchEvt.sFinger[i].eState = TPEVT_ENTRY_MOVE;
						sTouchEvt.sFinger[i].unPosX = x_pos[i];
						sTouchEvt.sFinger[i].unPosY = y_pos[i];
						send_event = 1;
                	}
                }

                // new state
                sLastState[i] = sTouchEvt.sFinger[i].eState;
                sLastCoords[i].x = x_pos[i];
                sLastCoords[i].y = y_pos[i];
            }
        }
        else
        {
            for (uint8_t i = 0; i < TP_TOUCHNUM_MAX; i++)
            {
            	if (sTouchEvt.sFinger[i].eState != TPEVT_ENTRY_UP)
            	{
            		sTouchEvt.sFinger[i].eState = TPEVT_ENTRY_UP;
            		sTouchEvt.sFinger[i].unPosX = sLastCoords[i].x;
            		sTouchEvt.sFinger[i].unPosY = sLastCoords[i].y;
            		send_event = 1;
            	}

                // new state
                sLastState[i] = sTouchEvt.sFinger[i].eState;
			}
        }

        if (send_event)
        {
        	//PRINTF_INFO("send event: %i s: %i x: %i y: %i\r\n", touch_status, sTouchEvt.sFinger[0].eState, sTouchEvt.sFinger[0].unPosX, sTouchEvt.sFinger[0].unPosY);
        	touchevent_callback(0, &sTouchEvt);
        }

        vTaskDelay(2 / portTICK_PERIOD_MS);
        //----------------------------------
    }
}

/**
 * @name       mems_task_start
 * @brief      Task creation for mems_task
 * @param[in]  None
 * @return     None
 */
void touch_task_start(void)
{
    portBASE_TYPE status;
    xTaskHandle task = NULL;

    status = xTaskCreate(touch_task, "Touch Task", 2000, NULL, 1, &task);

    //Failed to create the task?
    if(task == BSP_INVALID_HANDLE)
    {
        //Debug message
    }
}

int os_main_task_t( void )
{
    // Initialize led
    bsp_led_init();

    // Configure and Initialize switch pins
    bsp_button_init();

    // Initialize VCOM
    bsp_vcom_init();

    // Initialize the LCD
    bsp_lcd_init();
    bsp_lcd_clear(LCD_COLOR_BLACK);
    bsp_lcd_set_text_background_color(LCD_DEFAULT_BACKGROUND_COLOR);
    bsp_lcd_set_text_color(LCD_DEFAULT_TEXT_COLOR);
    bsp_lcd_set_font(&font_22x29);
    bsp_lcd_display_on();

    // Initialize I2C channel 3
    bsp_i2c_init(BSP_I2C_CHANNEL_3);

    // Configure and start touch
    bsp_touch_init();

    // Create Mutex for I2C3 events
    i2c3_event = xSemaphoreCreateMutex();

    // Init SDRAM
    bsp_sdram_init();

    // Launch all the tasks
    touch_task_start();

    bsp_lcd_enable_double_buffer();

    bsp_lcd_swap_buffer();

    os_task_t *p_os_task;
    p_os_task = R_OS_TaskCreate("Guiliani", prvGuilianiTask, NULL, GUILIANI_TASK_STACK_SIZE, 1);

    /* Failed to create the task? */
    if (R_OS_ABSTRACTION_INVALID_HANDLE == (int)p_os_task)
    {
        /* Debug message */
        printf("Failed to create task!\r\n");
    }

    /* NULL signifies that no task was created by R_OS_CreateTask */
    if (NULL == p_os_task)
    {
        /* Debug message */
        printf("Failed to create task!\r\n");
    }

    /* Need to determine system state is running */
    if (R_OS_TasksGetNumber())
    {
        while (1)
        {
            R_OS_TaskSleep(10000);
        }
    }

    // todo
    /* Shut down all system resources */


    /* This function should never return */
    while (1)
    {
        R_COMPILER_Nop();
    }

    return 0;
}

/******************************************************************************
* Function Name: main
* Description  : C Entry point
*              : opens and configures cpg driver
*              : starts the freertos kernel
* Arguments    : none
* Return Value : 0
******************************************************************************/
int_t main(void)
{
    int_t cpg_handle;

    /* Initialize the devlink layer */
    R_DEVLINK_Init();

    /* Initialize CPG */
    cpg_handle = direct_open("cpg", 0);
    if(cpg_handle < 0)
    {
        /* stop execute */
        while(1)
        {
            ;
        }
    }

    /* Can close handle if no need to change clock after here */
    direct_close(cpg_handle);

    /* Start FreeRTOS */
    /* R_OS_InitKernel should never return */
    R_OS_KernelInit();
}
/******************************************************************************
* End of function main
******************************************************************************/
