/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : w25qxx.h
  * @brief          : W25QXX flash memory driver header file
  ******************************************************************************
  */
/* USER CODE END Header */

#ifndef __W25QXX_H__
#define __W25QXX_H__

#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>

/**
 * @brief W25QXX command definitions
 */
#define W25QXX_CMD_WRITE_ENABLE           0x06
#define W25QXX_CMD_WRITE_DISABLE          0x04
#define W25QXX_CMD_READ_STATUS_REG1       0x05
#define W25QXX_CMD_READ_STATUS_REG2       0x35
#define W25QXX_CMD_WRITE_STATUS_REG       0x01
#define W25QXX_CMD_PAGE_PROGRAM           0x02
#define W25QXX_CMD_QUAD_PAGE_PROGRAM      0x32
#define W25QXX_CMD_BLOCK_ERASE_4KB        0x20
#define W25QXX_CMD_BLOCK_ERASE_32KB       0x52
#define W25QXX_CMD_BLOCK_ERASE_64KB       0xD8
#define W25QXX_CMD_CHIP_ERASE             0xC7
#define W25QXX_CMD_ERASE_SECURITY_REG     0x44
#define W25QXX_CMD_PROGRAM_SECURITY_REG   0x42
#define W25QXX_CMD_READ_SECURITY_REG      0x48
#define W25QXX_CMD_RDID                   0x9F
#define W25QXX_CMD_REMS                   0x90
#define W25QXX_CMD_REMS_DUAL              0xAB
#define W25QXX_CMD_REMS_QUAD              0xAF
#define W25QXX_CMD_READ                   0x03
#define W25QXX_CMD_FAST_READ              0x0B
#define W25QXX_CMD_FAST_READ_DUAL         0x3B
#define W25QXX_CMD_FAST_READ_QUAD         0x6B
#define W25QXX_CMD_WORD_READ_QUAD         0x9B
#define W25QXX_CMD_OCTAL_WORD_READ        0xEB
#define W25QXX_CMD_RESET_ENABLE           0x66
#define W25QXX_CMD_RESET                  0x99
#define W25QXX_CMD_RELEASE_POWER_DOWN     0xAB
#define W25QXX_CMD_POWER_DOWN             0xB9
#define W25QXX_CMD_SET_BURST_WRAP         0x77
#define W25QXX_CMD_ENABLE_QPI             0x38
#define W25QXX_CMD_DISABLE_QPI            0xFF

/**
 * @brief W25QXX status register bits
 */
#define W25QXX_STATUS_BUSY_BIT            0x01
#define W25QXX_STATUS_WEL_BIT             0x02
#define W25QXX_STATUS_BP0_BIT             0x04
#define W25QXX_STATUS_BP1_BIT             0x08
#define W25QXX_STATUS_BP2_BIT             0x10
#define W25QXX_STATUS_BP3_BIT             0x20
#define W25QXX_STATUS_QE_BIT              0x40
#define W25QXX_STATUS_SR1_BIT             0x80

/**
 * @brief W25QXX device information structure
 */
typedef struct {
    uint8_t manufacturer_id;   /* Manufacturer ID */
    uint16_t device_id;        /* Device ID */
    uint32_t capacity;         /* Total capacity in bytes */
    uint16_t page_size;        /* Page size in bytes */
    uint32_t sector_size;      /* Sector size in bytes */
    uint32_t block_size;       /* Block size in bytes */
} w25qxx_device_info_t;

/**
 * @brief W25QXX SPI communication interface
 */
typedef struct {
    /**
     * @brief Send SPI data
     * @param data Pointer to data buffer to send
     * @param size Size of data to send
     * @return true if successful, false otherwise
     */
    bool (*spi_send)(const uint8_t *data, uint16_t size);
    
    /**
     * @brief Receive SPI data
     * @param data Pointer to data buffer to receive
     * @param size Size of data to receive
     * @return true if successful, false otherwise
     */
    bool (*spi_receive)(uint8_t *data, uint16_t size);
    
    /**
     * @brief Send and receive SPI data
     * @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
     */
    bool (*spi_transceive)(const uint8_t *tx_data, uint8_t *rx_data, uint16_t size);
    
    /**
     * @brief Set chip select pin state
     * @param state true for selected, false for deselected
     */
    void (*cs_set)(bool state);
    
    /**
     * @brief Delay in milliseconds
     * @param ms Delay time in milliseconds
     */
    void (*delay_ms)(uint32_t ms);
} w25qxx_spi_interface_t;

/**
 * @brief Initialize W25QXX flash memory
 * @param interface SPI communication interface
 * @return true if initialization is successful, false otherwise
 */
bool w25qxx_init(const w25qxx_spi_interface_t *interface);

/**
 * @brief Get W25QXX device information
 * @param info Pointer to device information structure to fill
 * @return true if successful, false otherwise
 */
bool w25qxx_get_device_info(w25qxx_device_info_t *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
 * @return true if read is successful, false otherwise
 */
bool w25qxx_read(uint32_t address, uint8_t *data, uint32_t 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
 * @return true if write is successful, false otherwise
 */
bool w25qxx_write(uint32_t address, const uint8_t *data, uint32_t size);

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

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

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

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

/**
 * @brief Read status register 1
 * @return Status register 1 value
 */
uint8_t w25qxx_read_status_reg1(void);

/**
 * @brief Read status register 2
 * @return Status register 2 value
 */
uint8_t w25qxx_read_status_reg2(void);

/**
 * @brief Write status register
 * @param reg1 Status register 1 value
 * @param reg2 Status register 2 value
 * @return true if write is successful, false otherwise
 */
bool w25qxx_write_status_reg(uint8_t reg1, uint8_t reg2);

/**
 * @brief Put W25QXX into power down mode
 * @return true if successful, false otherwise
 */
bool w25qxx_power_down(void);

/**
 * @brief Release W25QXX from power down mode
 * @return true if successful, false otherwise
 */
bool w25qxx_release_power_down(void);

#endif /* __W25QXX_H__ */