/*
 * main.c
 *
 * Created: Mon Nov 08 2021 14:06:53
 *  Author Chris
 */

// ============================================================================================
// Includes
#include <stdio.h>
#include <string.h>

#include "pico/stdlib.h"

#include "Core1.h"
#include "Core1_LED_Enable.h"
#include "I2C_Master.h"

#include "Command.h"
#include "UI_Control.h"
#include "Mode_Manager.h"

#include "INA260.h"
#include "Switch.h"
#include "Screens.h"
#include "EEPROM_M24C64.h"
#include "Rotary_Encoder.h"

#include "Display.h"
#include "Display_SPI.h"
#include "Display_Image.h"
#include "Display_Default_Configurations.h"

#include "USB_Serial.h"
#include "Serial_Command.h"


// ============================================================================================
// Defines
#define LEDG_PIN 			12
#define LEDG_CONFIG      	gpio_init(LEDG_PIN); gpio_set_dir(LEDG_PIN, GPIO_OUT)
#define LEDG_ON 			gpio_put(LEDG_PIN, 0)
#define LEDG_OFF 			gpio_put(LEDG_PIN, 1)
#define LEDG_TOGGLE 		gpio_put(LEDG_PIN, !gpio_get(LEDG_PIN))
#define LEDG_ANIMATION_1	LEDG_ON; sleep_ms(100); LEDG_OFF; sleep_ms(100);
#define LEDG_ANIMATION_3	LEDG_ANIMATION_1; LEDG_ANIMATION_1; LEDG_ANIMATION_1

#define LEDR_PIN 			11
#define LEDR_CONFIG      	gpio_init(LEDR_PIN); gpio_set_dir(LEDR_PIN, GPIO_OUT)
#define LEDR_ON 			gpio_put(LEDR_PIN, 0)
#define LEDR_OFF 			gpio_put(LEDR_PIN, 1)
#define LEDR_TOGGLE 		gpio_put(LEDR_PIN, !gpio_get(LEDR_PIN))

#define TRIGGER_PIN			18
#define TRIGGER_CONFIG      gpio_init(TRIGGER_PIN); gpio_set_dir(TRIGGER_PIN, GPIO_OUT)
#define TRIGGER_ON 			gpio_put(TRIGGER_PIN, 1)
#define TRIGGER_OFF 		gpio_put(TRIGGER_PIN, 0)


// ============================================================================================
// Variables
static bool _Timer_Fired = false;
static struct repeating_timer _Timer;

extern uint16_t _Image_Power_Critical_32x32[];
extern uint16_t _Image_Power_Overvoltage_32x32[];
extern uint16_t _Image_Power_Undervoltage_32x32[];
extern uint16_t _Image_Power_Unplugged_32x32[];
extern uint16_t _Image_Overcurrent_32x32[];

static uint32_t _Idle_Counter;


// ============================================================================================
// Function Declarations
void Check_For_Serial_Input(void);
void Parse_Command(void);
void Serial_Send_Configuration_Text(void);
void Serial_Send_Configuration_Hex(void);
void Serial_Return_Ping(void);
void Serial_Write_Configuration_Byte(void);
void Serial_Save_To_EEPROM(void);
void Display_Start_Buffer_Readout(void);


/*******************************************************************
	Interrupt Service Routines
*******************************************************************/
bool ISR_Repeating_Timer(struct repeating_timer *t)
{
	LEDR_TOGGLE;
	_Timer_Fired = true;
    return true;
}


/*******************************************************************
	Main Routine
*******************************************************************/
int main(void)
{
	// LED			=================================================
	LEDG_CONFIG;
	LEDR_CONFIG;	LEDR_OFF;
	LEDG_ANIMATION_3;

	// Trigger		=================================================
	TRIGGER_CONFIG;
	TRIGGER_OFF;

    // Serial Command	=============================================
    Serial_Command_Init();

	// USB Serial	=================================================
	USB_Serial_Init();
	
	// I2C Master		=============================================
	I2CM_Init(I2C_NO_INTERNAL_PULLUP);

	// EEPROM		=================================================
	EEPROM_Init();

	// INA 260		=================================================
	INA260_Init();

	// Core 1		=================================================
	multicore_launch_core1(Core1_Main);

	// Command		=================================================
	Command_Init();

	// UI Control	=================================================
	UI_Control_Init();

	// Display 		=================================================
	Display_Init(DISPLAY_COLOR_BLACK, true, false);
	Screen_Setup_Loading();
	// Screen_Setup_Menu_Main(TRANSITION_NONE, TRANSITION_NONE, LINEAR, 0, false, 3);
	
	// Rotary Encoder	=============================================
	Rotary_Encoder_Init();
	
	// Switch		=================================================
	Switch_Init(SWITCH_NO_INTERNAL_PULLUP);

	// Mode Manager		=============================================
	Mode_Manager_Init();

	// Repeating Timer	=============================================
	add_repeating_timer_ms(40, ISR_Repeating_Timer, NULL, &_Timer);

    _Idle_Counter = 0;
	
    while (1)
	{
		if (_Timer_Fired == true)
		{
			_Timer_Fired = false;

			Display_Send_Buffer();
			Display_Inc_Frame_Counter();

			Display_Screen_Transition_Tick();
			_Screen_Tick();

			UI_Control_Acceleration_Update(CURRENT_TIME_ms);

			INA260_Update_Current_Threshold();
            INA260_Read_BusVoltage();
			INA260_Read_Current();
			Command_Issue_Set_Request(MULTICORE_COMMAND_SET_INA260_BUSVOLTAGE, 0, INA260_Get_BusVoltage_mV());

            if(_EEPROM_Content.Device_Configuration.Screen_Timeout > 0)
			{
				if(_Idle_Counter >= _EEPROM_Content.Device_Configuration.Screen_Timeout * (1000 / 40))
				{
					if(_Screen_Idle_Active != true)
					{
						Screen_Setup_Idle(TRANSITION_UP, TRANSITION_UP, SCREEN_TRANSITION_DEFAULT_EASING, SCREEN_TRANSITION_DEFAULT_FRAMES);
					}
				}
				else if(_Screen_Idle_Counter_Disable == false)
				{
					_Idle_Counter++;
				}
				else if(_Screen_Idle_Counter_Disable == true)
				{
					_Idle_Counter = 0;
				}
			}
		}

		// Add functions here to execute during the DMA Transfer
		if(Display_SPI_DMA_Transfer_Ongoing())
		{
					
		}

		if(Display_Send_Buffer_Completed())
		{	
			TRIGGER_ON;
            Mode_Manager_Tick();
            EEPROM_Tick();

			Command_Issue_Get_Request(MULTICORE_COMMAND_GET_LED_POWER_ERROR, 0);
			Display_Render_Objects();
			LED_Power_Error Error = Command_Get_Request_Response_By_Command_Only(MULTICORE_COMMAND_GET_LED_POWER_ERROR, 100);

			uint16_t *Image = NULL;

			switch (Error)
			{
			case BUS_NO_SUPPLY:				Image = _Image_Power_Unplugged_32x32;		break;
			case BUS_UNDERVOLTAGE:			Image = _Image_Power_Undervoltage_32x32;	break;
			case BUS_OVERVOLTAGE:			Image = _Image_Power_Overvoltage_32x32;		break;
			case BUS_VOLTAGE_MEASUREMENT:	Image = _Image_Power_Critical_32x32;		break;
			case OVERCURRENT:	            Image = _Image_Overcurrent_32x32;		    break;
			}

			if(Image != NULL && Display_Screen_Transition_Ongoing() == false) {
				Display_Image_Draw_Color(DISPLAY_X_CENTER + 50, 30, Image);
			}
			TRIGGER_OFF;
		}
		else
		{
        	Serial_Command_Check_For_Input();

			if(Rotary_Encoder_Rotation_CW_Occurred()) {
                _Idle_Counter = 0;
				Display_Action_CW();
			}

			if(Rotary_Encoder_Rotation_CCW_Occurred()) {
                _Idle_Counter = 0;
				Display_Action_CCW();
			}

			if(Rotary_Encoder_Switch_Press_Occurred()) {
                _Idle_Counter = 0;
				Display_Action_SW();
			}

            if(Switch_Press_Occurred()) {
                if(_Screen_Idle_Active == false) {
                    _Idle_Counter = 0;
                }
				Mode_Manager_Cycle_Mode();
			}
		}	
    }
}


