/*-------------------------------------------------------------------------------------------------
--
-- File Name    : main.c



-- Description  : This module replicates the CoaXPress Host functionality.




-- Targeted device : Microchip FPGAs
-- Author          : India Solutions Team




--
-- COPYRIGHT 2023 BY MICROCHIP
-- THE INFORMATION CONTAINED IN THIS DOCUMENT IS SUBJECT TO LICENSING RESTRICTIONS
-- FROM MICROCHIP CORP.  IF YOU ARE NOT IN POSSESSION OF WRITTEN AUTHORIZATION FROM
-- MICROCHIP FOR USE OF THIS FILE, THEN THE FILE SHOULD BE IMMEDIATELY DESTROYED AND
-- NO BACK-UP OF THE FILE SHOULD BE MADE.
--



-------------------------------------------------------------------------------------------------*/


#include <stdio.h>
#include "hal/hal.h"
#include "miv_rv32_hal/miv_rv32_hal.h"
#include "drivers/fpga_ip/CoreGPIO/core_gpio.h"

#include "drivers/fpga_ip/CoaXPressHost/coaxpressXcvrSpeed.h"
#include "drivers/fpga_ip/CoaXPressHost/coaxpressHost.h"
#include "coaxpressHostGUI.h"

#define LED1 GPIO_0
#define LED2 GPIO_1
#define LED3 GPIO_2
#define LED4 GPIO_3

volatile  uint32_t counter;
uint8_t state;

volatile uint8_t irq_flag_device = 0;
volatile uint8_t irq_flag_gui = 0;

void delay();
void GPIO_settings();
void gui_handler();

/*-----------------------------------------------------------------------------
 * GPIO instance data.
 */
gpio_instance_t g_gpio_out;
volatile uint32_t DIP_SW_status;

volatile uint32_t g_10ms_count;
volatile uint32_t timerdone = 0;
volatile uint32_t g_10ms_count1;
volatile uint32_t g_ms_count;
/*-----------------------------------------------------------------------------
 * Interrupt handlers.
 * Weakly linked default versions of all the interrupt handlers are defined
 * in miv_rv32_stubs.c.
 */
void Software_IRQHandler()
{
    MRV_clear_soft_irq();
}

void SysTick_Handler1(void)
{
    static volatile uint32_t val = 0u;
    val ^= 0xFu;
    GPIO_set_outputs(&g_gpio_out, val);
    //printf("\r\nInternal System Timer Interrupt");
}

void SysTick_Handler(void)
{
    if(timerdone == 1)
    {
        g_10ms_count += 1;
        if(g_ms_count <= g_10ms_count)
            timerdone = 0;
    }
}
void External_IRQHandler()
{
    irq_flag_device = 1;
}

void MSYS_EI0_IRQHandler(void)
{
    irq_flag_gui = 1 ;
}

/*-------------------------------------------------------------------------//**
  main() function.
 */
int main(void)
{
    GPIO_settings();

    MRV_enable_local_irq(MRV32_EXT_IRQn);
    MRV_enable_local_irq(MRV32_MSYS_EIE0_IRQn);

    /* This must be done for all Mi-V cores to enable interrupts globally. */
    HAL_enable_interrupts();

    //MRV_systick_config(SYS_CLK_FREQ);
    DIP_SW_status = GPIO_get_inputs(&g_gpio_out);

    update_hdmi_xcvr_speed(DIP_SW_status);

    GPIO_set_output(&g_gpio_out, GPIO_4, 1); //display controller reset

    GPIO_set_output(&g_gpio_out, LED2, 0);

    update_cxp_xcvr_uplink_speed(RATE_3DOT125G);

    wait_for_pll_lock();
    delay();

    device_reset();
    delay();

    start_video_stream();
    delay();

    wait_for_pll_lock();
    delay();

    GPIO_config(&g_gpio_out, LED1, GPIO_OUTPUT_MODE);
    GPIO_set_output(&g_gpio_out, LED1, 1);

    counter = 0;
    state = 0;

    do {

            if(10000u == counter)
            {
                counter = 0;
                state = !state;
                GPIO_set_output(&g_gpio_out, LED1, state);
            }
            else
            {
                counter = counter + 1;
            }

            if(irq_flag_gui == 1)
            {
                CoaxpressHostGUIMain();
                GPIO_set_output(&g_gpio_out, LED3, 1);
            }

            if(irq_flag_device == 1)
            {
                CoaxpressDeviceToHostMain();
                GPIO_set_output(&g_gpio_out, LED3, 0);
            }

            gui_handler();

            if(reset_en == 1)
            {
                reset_en = 0;
                update_cxp_xcvr_uplink_speed(RATE_3DOT125G);

                wait_for_pll_lock();
                delay();

                device_reset();
                start_video_stream();
                wait_for_pll_lock();
                delay();
            }
#if 0
            if(device_to_host_connection_test_en == 1)
            {
                device_to_host_connection_test_en = 0;
                coaxpress_device_to_host_connection_test();
            }

            if(host_to_device_connection_test_en == 1)
            {
                host_to_device_connection_test_en = 0;
                coaxpress_host_to_device_connection_test();
            }
#endif
        } while (1);

    return 0;
}


void GPIO_settings()
{
    GPIO_init(&g_gpio_out, COREGPIO_OUT_BASE_ADDR, GPIO_APB_32_BITS_BUS);
    GPIO_config(&g_gpio_out, GPIO_0, GPIO_INOUT_MODE);
    GPIO_config(&g_gpio_out, GPIO_1, GPIO_OUTPUT_MODE);
    GPIO_config(&g_gpio_out, GPIO_2, GPIO_OUTPUT_MODE);
    GPIO_config(&g_gpio_out, GPIO_3, GPIO_OUTPUT_MODE);
    GPIO_config(&g_gpio_out, GPIO_4, GPIO_OUTPUT_MODE);
    GPIO_set_output(&g_gpio_out, GPIO_4, 0);

    /* set the output value */
    GPIO_set_outputs(&g_gpio_out, 0x0u);
    GPIO_set_outputs(&g_gpio_out, 0xFFu);
}


#define R_GAIN_ADDR         0x70001020
#define G_GAIN_ADDR         0x70001024
#define B_GAIN_ADDR         0x70001028
#define CONTRAST_ADDR       0x70001030
#define BRIGHTNESS_ADDR     0x70001034
#define ALPHA_ADDR          0x70001000

#define R_CONST_ADDR        0x70001004
#define G_CONST_ADDR        0x70001008
#define B_CONST_ADDR        0x7000100C
#define SECOND_CONST_ADDR   0x70001010

uint16_t contrast;
uint16_t brightness;
uint16_t r_gain, b_gain, g_gain;
uint16_t r_const, b_const, g_const;
uint32_t second_const,contrast_scl;

void gui_handler()
{
    r_gain = (uint16_t)(*(volatile int*) R_GAIN_ADDR);
    g_gain = (uint16_t)(*(volatile int*) G_GAIN_ADDR);
    b_gain = (uint16_t)(*(volatile int*) B_GAIN_ADDR);
    contrast = *(volatile int*) CONTRAST_ADDR;//8;//Range 3 - 30 (divided by 10 in later steps)
    brightness = *(volatile int*) BRIGHTNESS_ADDR;

    contrast_scl = (325*(contrast+128) / (387 - contrast))>>5u;
    r_const = (r_gain * contrast_scl)/10;
    b_const = (b_gain * contrast_scl)/10;
    g_const = (g_gain * contrast_scl/10);
    second_const = 128 * (brightness - ((128*contrast_scl)/10));

    *(volatile int*) R_CONST_ADDR = r_const;
    *(volatile int*) G_CONST_ADDR = g_const;
    *(volatile int*) B_CONST_ADDR = b_const;
    *(volatile int*) SECOND_CONST_ADDR = second_const;
}

