/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : hal_stm32f4_gpio.c
  * @brief          : STM32F4 specific GPIO HAL implementation
  ******************************************************************************
  */
/* USER CODE END Header */

#include "hal.h"
#include "hal_gpio.h"
#include "stm32f4xx_hal.h"

/**
 * @brief Convert HAL GPIO port to STM32 GPIO port
 * @param port: HAL GPIO port
 * @retval STM32 GPIO port
 */
static GPIO_TypeDef* hal_gpio_port_to_stm32(hal_gpio_port_t port) {
    switch (port) {
        case HAL_GPIO_PORT_A: return GPIOA;
        case HAL_GPIO_PORT_B: return GPIOB;
        case HAL_GPIO_PORT_C: return GPIOC;
        case HAL_GPIO_PORT_D: return GPIOD;
        case HAL_GPIO_PORT_E: return GPIOE;
        case HAL_GPIO_PORT_F: return GPIOF;
        case HAL_GPIO_PORT_G: return GPIOG;
        case HAL_GPIO_PORT_H: return GPIOH;
        case HAL_GPIO_PORT_I: return GPIOI;
        // case HAL_GPIO_PORT_J: return GPIOJ;
        // case HAL_GPIO_PORT_K: return GPIOK;
        default: return NULL;
    }
}

/**
 * @brief Convert HAL GPIO pin to STM32 GPIO pin
 * @param pin: HAL GPIO pin
 * @retval STM32 GPIO pin
 */
static uint16_t hal_gpio_pin_to_stm32(hal_gpio_pin_t pin) {
    return (1U << pin);
}

/**
 * @brief Convert HAL GPIO state to STM32 GPIO state
 * @param state: HAL GPIO state
 * @retval STM32 GPIO state
 */
static GPIO_PinState hal_gpio_state_to_stm32(hal_gpio_pin_state_t state) {
    return (state == HAL_GPIO_PIN_SET) ? GPIO_PIN_SET : GPIO_PIN_RESET;
}

/**
 * @brief STM32F4 specific GPIO initialization
 */
void hal_stm32f4_gpio_init(void) {
    /* GPIO initialization is handled by BSP layer */
}

/**
 * @brief STM32F4 specific GPIO write pin implementation
 */
void hal_stm32f4_gpio_write_pin(hal_gpio_port_t port, hal_gpio_pin_t pin, hal_gpio_pin_state_t state) {
    GPIO_TypeDef* stm32_port = hal_gpio_port_to_stm32(port);
    if (stm32_port == NULL) {
        return;
    }
    uint16_t stm32_pin = hal_gpio_pin_to_stm32(pin);
    GPIO_PinState stm32_state = hal_gpio_state_to_stm32(state);
    HAL_GPIO_WritePin(stm32_port, stm32_pin, stm32_state);
}

/**
 * @brief STM32F4 specific GPIO toggle pin implementation
 */
void hal_stm32f4_gpio_toggle_pin(hal_gpio_port_t port, hal_gpio_pin_t pin) {
    GPIO_TypeDef* stm32_port = hal_gpio_port_to_stm32(port);
    if (stm32_port == NULL) {
        return;
    }
    uint16_t stm32_pin = hal_gpio_pin_to_stm32(pin);
    HAL_GPIO_TogglePin(stm32_port, stm32_pin);
}

/**
 * @brief STM32F4 specific GPIO read pin implementation
 */
hal_gpio_pin_state_t hal_stm32f4_gpio_read_pin(hal_gpio_port_t port, hal_gpio_pin_t pin) {
    GPIO_TypeDef* stm32_port = hal_gpio_port_to_stm32(port);
    if (stm32_port == NULL) {
        return HAL_GPIO_PIN_RESET;
    }
    uint16_t stm32_pin = hal_gpio_pin_to_stm32(pin);
    GPIO_PinState stm32_state = HAL_GPIO_ReadPin(stm32_port, stm32_pin);
    return (stm32_state == GPIO_PIN_SET) ? HAL_GPIO_PIN_SET : HAL_GPIO_PIN_RESET;
}

/**
 * @brief STM32F4 specific GPIO configure pin implementation
 */
void hal_stm32f4_gpio_configure_pin(const hal_gpio_config_t *config) {
    if (config == NULL) {
        return;
    }
    
    GPIO_TypeDef* stm32_port = hal_gpio_port_to_stm32(config->port);
    if (stm32_port == NULL) {
        return;
    }
    
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    /* Enable GPIO clock */
    switch (config->port) {
        case HAL_GPIO_PORT_A: __HAL_RCC_GPIOA_CLK_ENABLE(); break;
        case HAL_GPIO_PORT_B: __HAL_RCC_GPIOB_CLK_ENABLE(); break;
        case HAL_GPIO_PORT_C: __HAL_RCC_GPIOC_CLK_ENABLE(); break;
        case HAL_GPIO_PORT_D: __HAL_RCC_GPIOD_CLK_ENABLE(); break;
        case HAL_GPIO_PORT_E: __HAL_RCC_GPIOE_CLK_ENABLE(); break;
        case HAL_GPIO_PORT_F: __HAL_RCC_GPIOF_CLK_ENABLE(); break;
        case HAL_GPIO_PORT_G: __HAL_RCC_GPIOG_CLK_ENABLE(); break;
        case HAL_GPIO_PORT_H: __HAL_RCC_GPIOH_CLK_ENABLE(); break;
        case HAL_GPIO_PORT_I: __HAL_RCC_GPIOI_CLK_ENABLE(); break;
        default: break;
    }
    
    /* Configure GPIO parameters */
    GPIO_InitStruct.Pin = hal_gpio_pin_to_stm32(config->pin);
    
    /* Convert HAL GPIO mode to STM32 GPIO mode */
    switch (config->mode) {
        case HAL_GPIO_MODE_INPUT: GPIO_InitStruct.Mode = GPIO_MODE_INPUT; break;
        case HAL_GPIO_MODE_OUTPUT_PP: GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; break;
        case HAL_GPIO_MODE_OUTPUT_OD: GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; break;
        case HAL_GPIO_MODE_AF_PP: GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; break;
        case HAL_GPIO_MODE_AF_OD: GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; break;
        case HAL_GPIO_MODE_ANALOG: GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; break;
        case HAL_GPIO_MODE_IT_RISING: GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; break;
        case HAL_GPIO_MODE_IT_FALLING: GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; break;
        case HAL_GPIO_MODE_IT_RISING_FALLING: GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING; break;
        default: GPIO_InitStruct.Mode = GPIO_MODE_INPUT; break;
    }
    
    /* Convert HAL GPIO pull to STM32 GPIO pull */
    switch (config->pull) {
        case HAL_GPIO_PULL_NO: GPIO_InitStruct.Pull = GPIO_NOPULL; break;
        case HAL_GPIO_PULL_UP: GPIO_InitStruct.Pull = GPIO_PULLUP; break;
        case HAL_GPIO_PULL_DOWN: GPIO_InitStruct.Pull = GPIO_PULLDOWN; break;
        default: GPIO_InitStruct.Pull = GPIO_NOPULL; break;
    }
    
    /* Convert HAL GPIO speed to STM32 GPIO speed */
    switch (config->speed) {
        case HAL_GPIO_SPEED_LOW: GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; break;
        case HAL_GPIO_SPEED_MEDIUM: GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM; break;
        case HAL_GPIO_SPEED_HIGH: GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; break;
        case HAL_GPIO_SPEED_VERY_HIGH: GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; break;
        default: GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; break;
    }
    
    /* Initialize GPIO */
    HAL_GPIO_Init(stm32_port, &GPIO_InitStruct);
}
