/**
 * @file digital_outputs_driver.c
 * @brief Simplified Driver implementation for 8 independent open-drain digital outputs
 *         on STM32F103C8T6 using global static state.
 */

#include "digital_outputs_driver.h"

/**
 * @brief Internal structure to track pin hardware mapping
 */
typedef struct {
    GPIO_TypeDef* port;
    uint16_t      pin;
} pin_map_t;

/**
 * @brief Static configuration of pins (Hardware Abstraction Layer)
 */
static const pin_map_t output_pins[OUTPUT_PINS_COUNT] = {
    {GPIOB, GPIO_PIN_0},  // Index 0
    {GPIOB, GPIO_PIN_1},  // Index 1
    {GPIOB, GPIO_PIN_2},  // Index 2
    {GPIOB, GPIO_PIN_8},  // Index 3
    {GPIOB, GPIO_PIN_9},  // Index 4
    {GPIOC, GPIO_PIN_13}, // Index 5
    {GPIOC, GPIO_PIN_14}, // Index 6
    {GPIOC, GPIO_PIN_15}  // Index 7
};

/**
 * @brief Static array to track current software state of pins
 */
static uint8_t pin_states[OUTPUT_PINS_COUNT] = {0};

/**
 * @brief Initializes the GPIO hardware and sets initial states.
 * @note This function replaces the handle-based init.
 * @retval None
 */
void digital_outputs_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    for (int i = 0; i < OUTPUT_PINS_COUNT; i++) {
        GPIO_InitStruct.Pin   = output_pins[i].pin;
        GPIO_InitStruct.Mode  = GPIO_MODE_OUTPUT_OD; // Open-drain
        GPIO_InitStruct.Pull  = GPIO_NOPULL;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

        HAL_GPIO_Init(output_pins[i].port, &GPIO_InitStruct);

        // Force initial state to LOW (Reset)
        HAL_GPIO_WritePin(output_pins[i].port, output_pins[i].pin, GPIO_PIN_SET);
        pin_states[i] = 0;
    }
}

/**
 * @brief Sets the state of a specific output pin.
 * @param pin Index of the pin (0 to OUTPUT_PINS_COUNT-1)
 * @param state Desired state (0 = LOW, 1 = HIGH)
 * @retval None
 */
void digital_outputs_set_state(digital_output_pin_t pin, uint8_t state)
{
    if (pin >= OUTPUT_PINS_COUNT) {
        return; // Simple boundary protection
    }

    GPIO_TypeDef* port = output_pins[pin].port;
    uint16_t pin_mask  = output_pins[pin].pin;

    if (state) {
        HAL_GPIO_WritePin(port, pin_mask, GPIO_PIN_RESET);
        pin_states[pin] = 1;
    } else {
        HAL_GPIO_WritePin(port, pin_mask, GPIO_PIN_SET);
        pin_states[pin] = 0;
    }
}

/**
 * @brief Gets the current state of a specific output pin.
 * @param pin Index of the pin
 * @param p_state Pointer to a variable where the state will be stored
 * @retval None
 */
void digital_outputs_get_state(digital_output_pin_t pin, uint8_t* p_state)
{
    if ((pin < OUTPUT_PINS_COUNT) && (p_state != NULL)) {
        *p_state = pin_states[pin];
    }
}

/**
 * @brief Toggles the state of a specific output pin.
 * @param pin Index of the pin
 * @retval None
 */
void digital_outputs_toggle(digital_output_pin_t pin)
{
    if (pin < OUTPUT_PINS_COUNT) {
        // Simple toggle logic using the internal state array
        uint8_t new_state = !pin_states[pin];
        digital_outputs_set_state(pin, new_state);
    }
}

/**
 * @brief Resets all outputs to LOW.
 * @retval None
 */
void digital_outputs_reset_all(void)
{
    for (int i = 0; i < OUTPUT_PINS_COUNT; i++) {
        digital_outputs_set_state(i, 0);
    }
}
