/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : bsp_w25qxx.c
  * @brief          : BSP layer for W25QXX flash memory
  ******************************************************************************
  */
/* USER CODE END Header */

#include "bsp_w25qxx.h"
#include "delay.h"

/**
 * @brief SPI send function for W25QXX
 * @param data Pointer to data buffer to send
 * @param size Size of data to send
 * @return true if successful, false otherwise
 */
static bool w25qxx_spi_send(const uint8_t *data, uint16_t size) {
    return hal_spi_transmit(W25QXX_SPI_INSTANCE, data, size) == HAL_RET_OK;
}

/**
 * @brief SPI receive function for W25QXX
 * @param data Pointer to data buffer to receive
 * @param size Size of data to receive
 * @return true if successful, false otherwise
 */
static bool w25qxx_spi_receive(uint8_t *data, uint16_t size) {
    return hal_spi_receive(W25QXX_SPI_INSTANCE, data, size) == HAL_RET_OK;
}

/**
 * @brief SPI transmit and receive function for W25QXX
 * @param tx_data Pointer to transmit data buffer
 * @param rx_data Pointer to receive data buffer
 * @param size Size of data to transfer
 * @return true if successful, false otherwise
 */
static bool w25qxx_spi_transceive(const uint8_t *tx_data, uint8_t *rx_data, uint16_t size) {
    return hal_spi_transmit_receive(W25QXX_SPI_INSTANCE, tx_data, rx_data, size) == HAL_RET_OK;
}

/**
 * @brief Chip select function for W25QXX
 * @param state true for selected, false for deselected
 */
static void w25qxx_cs_set(bool state) {
    hal_gpio_write_pin(W25QXX_CS_PORT, W25QXX_CS_PIN, state ? HAL_GPIO_PIN_RESET : HAL_GPIO_PIN_SET);
}

/**
 * @brief Delay function for W25QXX
 * @param ms Delay time in milliseconds
 */
static void w25qxx_delay_ms(uint32_t ms) {
    delay_ms(ms);
}

/**
 * @brief W25QXX SPI interface structure
 */
static w25qxx_spi_interface_t w25qxx_spi_interface = {
    .spi_send = w25qxx_spi_send,
    .spi_receive = w25qxx_spi_receive,
    .spi_transceive = w25qxx_spi_transceive,
    .cs_set = w25qxx_cs_set,
    .delay_ms = w25qxx_delay_ms
};

/**
 * @brief Initialize W25QXX flash memory
 * @retval true if initialization is successful, false otherwise
 */
bool bsp_w25qxx_init(void) {
    /* Initialize CS pin */
    hal_gpio_config_t gpio_config = {
        .port = W25QXX_CS_PORT,
        .pin = W25QXX_CS_PIN,
        .mode = HAL_GPIO_MODE_OUTPUT_PP,
        .speed = HAL_GPIO_SPEED_HIGH,
        .pull = HAL_GPIO_PULL_NO
    };
    hal_gpio_configure_pin(&gpio_config);
    
    /* Deselect chip initially */
    w25qxx_cs_set(false);
    
    /* Initialize SPI */
    hal_spi_config_t spi_config = {
        .instance = W25QXX_SPI_INSTANCE,
        .mode = HAL_SPI_MODE_MASTER,
        .baudrate = 1000000, /* 1 MHz */
        .polarity = HAL_SPI_POLARITY_LOW,
        .phase = HAL_SPI_PHASE_1EDGE,
        .databits = HAL_SPI_DATABITS_8
    };
    
    if (hal_spi_init(W25QXX_SPI_INSTANCE, &spi_config) != HAL_RET_OK) {
        return false;
    }
    
    /* Initialize W25QXX driver */
    return w25qxx_init(&w25qxx_spi_interface);
}

/**
 * @brief Get W25QXX device information
 * @param info Pointer to device information structure to fill
 * @retval true if successful, false otherwise
 */
bool bsp_w25qxx_get_device_info(w25qxx_device_info_t *info) {
    return w25qxx_get_device_info(info);
}

/**
 * @brief Read data from W25QXX flash memory
 * @param address Starting address to read from
 * @param data Pointer to data buffer to store read data
 * @param size Size of data to read
 * @retval true if read is successful, false otherwise
 */
bool bsp_w25qxx_read(uint32_t address, uint8_t *data, uint32_t size) {
    return w25qxx_read(address, data, size);
}

/**
 * @brief Write data to W25QXX flash memory
 * @param address Starting address to write to
 * @param data Pointer to data buffer to write
 * @param size Size of data to write
 * @retval true if write is successful, false otherwise
 */
bool bsp_w25qxx_write(uint32_t address, const uint8_t *data, uint32_t size) {
    return w25qxx_write(address, data, size);
}

/**
 * @brief Erase 4KB block
 * @param address Address within the block to erase
 * @retval true if erase is successful, false otherwise
 */
bool bsp_w25qxx_erase_block_4kb(uint32_t address) {
    return w25qxx_erase_block_4kb(address);
}

/**
 * @brief Erase 32KB block
 * @param address Address within the block to erase
 * @retval true if erase is successful, false otherwise
 */
bool bsp_w25qxx_erase_block_32kb(uint32_t address) {
    return w25qxx_erase_block_32kb(address);
}

/**
 * @brief Erase 64KB block
 * @param address Address within the block to erase
 * @retval true if erase is successful, false otherwise
 */
bool bsp_w25qxx_erase_block_64kb(uint32_t address) {
    return w25qxx_erase_block_64kb(address);
}

/**
 * @brief Erase entire chip
 * @retval true if erase is successful, false otherwise
 */
bool bsp_w25qxx_erase_chip(void) {
    return w25qxx_erase_chip();
}