/*!
 * @file        Board.c
 *
 * @brief       This file provides firmware functions to manage Leds and key buttons
 *
 * @version     V1.0.0
 *
 * @date        2026-02-25
 *
 * @attention
 *
 *  Copyright (C) 2026 Geehy Semiconductor
 *
 *  You may not use this file except in compliance with the
 *  GEEHY COPYRIGHT NOTICE (Geehy Semiconductor Software License Agreement).
 *
 *  The program is only for reference, which is distributed in the hope
 *  that it will be useful and instructional for customers to develop
 *  their software. Unless required by applicable law or agreed to in
 *  writing, the program is distributed on an "AS IS" BASIS, WITHOUT
 *  ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the Geehy Semiconductor Software License Agreement for the governing permissions
 *  and limitations under the License.
 */

/* Includes */
#include "stdio.h"
#include "g32a10xx_gpio.h"
#include "g32a10xx_eint.h"
#include "g32a10xx_syscfg.h"
#include "g32a10xx_misc.h"
#include "Board.h"

/** @addtogroup Boards
  @{
*/

/** @addtogroup Board_G32A10xx_EVAL
  @{
*/

/** @defgroup G32A10xx_EVAL_Variables Variables
  @{
*/

GPIO_T* GPIO_PORT[LEDn] = {LED1_GPIO_PORT, LED2_GPIO_PORT, LED3_GPIO_PORT, LED4_GPIO_PORT};
const Gpio_PinType GPIO_PIN[LEDn] = {LED1_PIN,LED2_PIN,LED3_PIN,LED4_PIN};
const Rcm_AhbPeriphType GPIO_CLK[LEDn] = {LED1_GPIO_CLK, LED2_GPIO_CLK, LED3_GPIO_CLK, LED4_GPIO_CLK};

GPIO_T* BUTTON_PORT[BUTTONn] = {KEY1_BUTTON_GPIO_PORT, KEY2_BUTTON_GPIO_PORT, KEY3_BUTTON_GPIO_PORT, KEY4_BUTTON_GPIO_PORT};
const Gpio_PinType BUTTON_PIN[BUTTONn] = {KEY1_BUTTON_PIN, KEY2_BUTTON_PIN, KEY3_BUTTON_PIN, KEY4_BUTTON_PIN};
const Rcm_AhbPeriphType BUTTON_CLK[BUTTONn] = {KEY1_BUTTON_GPIO_CLK, KEY2_BUTTON_GPIO_CLK, KEY3_BUTTON_GPIO_CLK, KEY4_BUTTON_GPIO_CLK};
const Syscfg_PortTypes BUTTON_SYSCFG_PORT[BUTTONn] = {KEY1_BUTTON_SYSCFG_PORT, KEY2_BUTTON_SYSCFG_PORT, KEY3_BUTTON_SYSCFG_PORT, KEY4_BUTTON_SYSCFG_PORT};
const Syscfg_PinTypes BUTTON_SYSCFG_PIN[BUTTONn] = {KEY1_BUTTON_SYSCFG_PIN, KEY2_BUTTON_SYSCFG_PIN, KEY3_BUTTON_SYSCFG_PIN, KEY4_BUTTON_SYSCFG_PIN};

USART_T* COM_USART[COMn] = {EVAL_COM1, EVAL_COM2};
GPIO_T* COM_TX_PORT[COMn] = {EVAL_COM1_TX_GPIO_PORT, EVAL_COM2_TX_GPIO_PORT};
GPIO_T* COM_RX_PORT[COMn] = {EVAL_COM1_RX_GPIO_PORT, EVAL_COM2_RX_GPIO_PORT};
const Rcm_Apb2PeriphType COM_USART1_CLK[COMn] = {EVAL_COM1_CLK,RCM_APB2_PERIPH_SYSCFG};
const Rcm_Apb1PeriphType COM_USART2_CLK[COMn] = {RCM_APB1_PERIPH_TMR2,EVAL_COM2_CLK};

const Rcm_AhbPeriphType COM_TX_PORT_CLK[COMn] = {EVAL_COM1_TX_GPIO_CLK, EVAL_COM2_TX_GPIO_CLK};

const Rcm_AhbPeriphType COM_RX_PORT_CLK[COMn] = {EVAL_COM1_RX_GPIO_CLK, EVAL_COM2_RX_GPIO_CLK};

const Gpio_PinType COM_TX_PIN[COMn] = {EVAL_COM1_TX_PIN, EVAL_COM2_TX_PIN};

const Gpio_PinType COM_RX_PIN[COMn] = {EVAL_COM1_RX_PIN, EVAL_COM2_RX_PIN};

const Gpio_PinSourceType COM_TX_PIN_SOURCE[COMn] = {EVAL_COM1_TX_SOURCE, EVAL_COM2_TX_SOURCE};

const Gpio_PinSourceType COM_RX_PIN_SOURCE[COMn] = {EVAL_COM1_RX_SOURCE, EVAL_COM2_RX_SOURCE};

const Gpio_AfType COM_TX_AF[COMn] = {EVAL_COM1_TX_AF, EVAL_COM2_TX_AF};

const Gpio_AfType COM_RX_AF[COMn] = {EVAL_COM1_RX_AF, EVAL_COM2_RX_AF};

/**@} end of group G32A10xx_EVAL_Variables */

/** @defgroup G32A10xx_EVAL_Functions Functions
  @{
  */

/*!
 * @brief       Configures LED GPIO.
 *
 * @param       Led: Specifies the Led to be configured.
 *              This parameter can be one of following parameters:
 *              @arg LED2
 *              @arg LED3
 *
 * @retval      None
 *
 * @note
 */
void Board_LedInit(Board_LedTypes Led)
{
    Gpio_ConfigType  gpioConfig;

    /* Enable the GPIO_LED Clock */
    Rcm_EnableAhbPeriphClock(GPIO_CLK[Led]);

    /* Configure the GPIO_LED pin */
    gpioConfig.pin = (uint16_t)GPIO_PIN[Led];
    gpioConfig.mode = GPIO_MODE_OUT;
    gpioConfig.outtype = GPIO_OUT_TYPE_PP;
    gpioConfig.speed = GPIO_SPEED_50MHz;
    gpioConfig.pupd = GPIO_PUPD_NO;

    Gpio_Config(GPIO_PORT[Led], &gpioConfig);

    GPIO_PORT[Led]->BSC_R.BSC = (uint32_t)GPIO_PIN[Led];
}

/*!
 * @brief       Turns selected LED On.
 *
 * @param       Led: Specifies the Led to be configured.
 *              This parameter can be one of following parameters:
 *              @arg LED2
 *              @arg LED3
 *
 * @retval      None
 *
 * @note
 */
void Board_LedOn(Board_LedTypes Led)
{
    GPIO_PORT[Led]->BR_R.BR = (uint32_t)GPIO_PIN[Led];
}

/*!
 * @brief       Turns selected LED Off.
 *
 * @param       Led: Specifies the Led to be configured.
 *              This parameter can be one of following parameters:
 *              @arg LED2
 *              @arg LED3
 *
 * @retval      None
 *
 * @note
 */
void Board_LedOff(Board_LedTypes Led)
{
    GPIO_PORT[Led]->BSC_R.BSC = (uint32_t)GPIO_PIN[Led];
}

/*!
 * @brief       Toggles the selected LED.
 *
 * @param       Led: Specifies the Led to be configured.
 *              This parameter can be one of following parameters:
 *              @arg LED2
 *              @arg LED3
 *
 * @retval      None
 *
 * @note
 */
void Board_LedToggle(Board_LedTypes Led)
{
    GPIO_PORT[Led]->ODATA_R.ODATA = GPIO_PORT[Led]->ODATA_R.ODATA ^ (uint32_t)GPIO_PIN[Led];
}

/*!
 * @brief       Configures Button GPIO and EINT Line.
 *
 * @param       Button: Specifies the Button to be configured.
 *              This parameter can be one of following parameters:
 *              @arg BUTTON_KEY1: Key1 Push Button
 *              @arg BUTTON_KEY2: Key2 Push Button
 * @param       Button_Mode: Specifies Button mode.
 *              This parameter can be one of following parameters:
 *              @arg BUTTON_MODE_GPIO: Button will be used as simple IO
 *              @arg BUTTON_MODE_EINT: Button will be connected to EINT line
 *                   with interrupt generation capability
 *
 * @retval      None
 *
 * @note
 */
void Board_ButtonInit(Board_ButtonTypes Button, Board_ButtonmodeTypes Button_Mode)
{
    Gpio_ConfigType gpioConfig;
    Eint_ConfigType eintConfig;
    
    if (Button <= BUTTON_KEY4)
    {
        /* Enable the BUTTON Clock */
        Rcm_EnableAhbPeriphClock(BUTTON_CLK[Button]);
        Rcm_EnableApb2PeriphClock(RCM_APB2_PERIPH_SYSCFG);

        /* Configure Button pin as input floating */
        gpioConfig.mode = GPIO_MODE_IN;
        gpioConfig.pupd = GPIO_PUPD_PU;
        gpioConfig.pin = (uint16_t)BUTTON_PIN[Button];
        Gpio_Config(BUTTON_PORT[Button], &gpioConfig);

        if (Button_Mode == BUTTON_MODE_EINT)
        {
            /* Configure GPIO pin used as EINT Line */
            Syscfg_EintLine(BUTTON_SYSCFG_PORT[Button], BUTTON_SYSCFG_PIN[Button]);

            /* Configure EINT0 line */
            if (Button == BUTTON_KEY1)
            {
                eintConfig.line    =  (uint32_t)EINT_LINE0;
                eintConfig.lineCmd =  ENABLE;
                eintConfig.mode    =  EINT_MODE_INTERRUPT;
                eintConfig.trigger =  EINT_TRIGGER_FALLING;
                Eint_Config(&eintConfig);
            }
            /* Configure EINT1 line */
            else if (Button == BUTTON_KEY2)
            {
                eintConfig.line    =  (uint32_t)EINT_LINE1;
                eintConfig.lineCmd =  ENABLE;
                eintConfig.mode    =  EINT_MODE_INTERRUPT;
                eintConfig.trigger =  EINT_TRIGGER_FALLING;
                Eint_Config(&eintConfig);
            }
            /* Configure EINT2 line */
            else if (Button == BUTTON_KEY3)
            {
                eintConfig.line    =  (uint32_t)EINT_LINE2;
                eintConfig.lineCmd =  ENABLE;
                eintConfig.mode    =  EINT_MODE_INTERRUPT;
                eintConfig.trigger =  EINT_TRIGGER_FALLING;
                Eint_Config(&eintConfig);
            }
            /* Configure EINT3 line */
            else
            {
                eintConfig.line    =  (uint32_t)EINT_LINE3;
                eintConfig.lineCmd =  ENABLE;
                eintConfig.mode    =  EINT_MODE_INTERRUPT;
                eintConfig.trigger =  EINT_TRIGGER_FALLING;
                Eint_Config(&eintConfig);
            }

            /* Enable and set EINTx Interrupt to the lowest priority */
            Nvic_EnableIrqRequest(EINT0_1_IRQn, 0x0f);
            Nvic_EnableIrqRequest(EINT2_3_IRQn, 0x0f);
        }
        else
        {
            /*  nothing */
        }
    }
    else
    {
        /*  nothing */
    }
}

/*!
 * @brief       Returns the selected Button state.
 *
 * @param       Button: Specifies the Button to be configured.
 *              This parameter can be one of following parameters:
 *              @arg BUTTON_KEY1: Key1 Push Button
 *              @arg BUTTON_KEY2: Key2 Push Button
 *
 * @retval      The Button GPIO pin value.
 *
 * @note
 */
uint32_t Board_GetButtonState(Board_ButtonTypes Button)
{
    return Gpio_ReadInputBit(BUTTON_PORT[Button], (uint16_t)BUTTON_PIN[Button]);
}

/*!
 * @brief       Configures COM port.
 *
 * @param       COM: Specifies the COM port to be configured.
 *              This parameter can be one of following parameters:
 *              @arg COM1
 *              @arg COM2
 *
 * @retval      None
 *
 * @note
 */
void Board_ComInit(Board_ComTypes COM)
{
    Gpio_ConfigType gpioConfig;
    Usart_ConfigType usartConfigStruct;
    /* Enable GPIO clock */
    Rcm_EnableAhbPeriphClock(COM_TX_PORT_CLK[COM]);
    Rcm_EnableAhbPeriphClock(COM_RX_PORT_CLK[COM]);
    
    /* Enable COM1 or COM2 clock */
    if (COM == COM1)
    {
        Rcm_EnableApb2PeriphClock(COM_USART1_CLK[COM]);
    }
    else
    {
        Rcm_EnableApb1PeriphClock(COM_USART2_CLK[COM]);
    }

    /* Connect PXx to USARTx_Tx */
    Gpio_ConfigPinAF(COM_TX_PORT[COM], COM_TX_PIN_SOURCE[COM], COM_TX_AF[COM]);

    /* Connect PXx to USARTx_Rx */
    Gpio_ConfigPinAF(COM_RX_PORT[COM], COM_RX_PIN_SOURCE[COM], COM_RX_AF[COM]);

    /* Configure USART Tx as alternate function push-pull */
    gpioConfig.mode = GPIO_MODE_AF;
    gpioConfig.pin = (uint16_t)COM_TX_PIN[COM];
    gpioConfig.speed = GPIO_SPEED_50MHz;
    gpioConfig.outtype = GPIO_OUT_TYPE_PP;
    gpioConfig.pupd = GPIO_PUPD_PU;
    Gpio_Config(COM_TX_PORT[COM], &gpioConfig);

    /* Configure USART Rx as input floating */
    gpioConfig.pin = (uint16_t)COM_RX_PIN[COM];
    Gpio_Config(COM_RX_PORT[COM], &gpioConfig);

    /* EVAL_USARTs configured as follow:
    - BaudRate = 115200 baud
    - Word Length = 8 Bits
    - One Stop Bit
    - No parity
    - Hardware flow control disabled (RTS and CTS signals)
    - Receive and transmit enabled
    */

    usartConfigStruct.baudRate = 115200;
    usartConfigStruct.mode     = USART_MODE_TX_RX;
    usartConfigStruct.hardwareFlowCtrl = USART_FLOW_CTRL_NONE;
    usartConfigStruct.parity   = USART_PARITY_NONE;
    usartConfigStruct.stopBits =  USART_STOP_BIT_1;
    usartConfigStruct.wordLength = USART_WORD_LEN_8B;
    Usart_Config(COM_USART[COM], &usartConfigStruct);

    /* Enable USART_Interrupt_RXBNEIE */
    Usart_EnableInterrupt(COM_USART[COM], USART_INT_RXBNEIE);

    if (COM_USART[COM] == USART1)
    {
        Nvic_EnableIrqRequest(USART1_IRQn, 2);
    }
    else if (COM_USART[COM] == USART2)
    {
        Nvic_EnableIrqRequest(USART2_IRQn, 3);
    }
    else
    {
        /*  nothing */
    }

    /* Enable USART */
    Usart_Enable(COM_USART[COM]);
}

/**@} end of group G32A10xx_EVAL_Functions */
/**@} end of group Board_G32A10xx_EVAL */
/**@} end of group Boards */
