#include "bsp_w25q.h"

#include "spi.h"

#include <string.h>

#include "app_leakage.h"
#include "bsp_W5500.h"

/* spi flash 片选引脚 - pb12 */
#define W25Q32_CS_LOW()    HAL_GPIO_WritePin(SPI2_CS_GPIO_Port, SPI2_CS_Pin, GPIO_PIN_RESET)
#define W25Q32_CS_HIGH()   HAL_GPIO_WritePin(SPI2_CS_GPIO_Port, SPI2_CS_Pin, GPIO_PIN_SET)

/* spi 传输函数 */
static void w25q32_spi_transmit(uint8_t *data, uint16_t size) {
    HAL_SPI_Transmit(&hspi2, data, size, HAL_MAX_DELAY);
}

static void w25q32_spi_receive(uint8_t *data, uint16_t size) {
    HAL_SPI_Receive(&hspi2, data, size, HAL_MAX_DELAY);
}

static uint8_t w25q32_spi_transmit_receive(uint8_t data) {
    uint8_t rx_data;
    HAL_SPI_TransmitReceive(&hspi2, &data, &rx_data, 1, HAL_MAX_DELAY);
    return rx_data;
}

/* 内部函数声明 */
static void w25q32_init(void);
static void w25q32_read(uint32_t addr, uint8_t *data, uint32_t len);
static void w25q32_write(uint32_t addr, uint8_t *data, uint32_t len);
static void w25q32_chip_erase(void);
static void w25q32_write_enable(void);
static void w25q32_write_disable(void);
static uint8_t w25q32_read_status_reg(void);
static void w25q32_wait_for_write_end(void);
static void w25q32_block_erase(uint32_t block_addr);
static void w25q32_page_write(uint32_t addr, uint8_t *data, uint16_t len);
static uint8_t w25q32_read_id(void);
static void w25q32_power_down(void);
static void w25q32_wake_up(void);

/* w25q32 对象实例 */
w25q32_t w25q32 = {
    .init = w25q32_init,
    .read = w25q32_read,
    .write = w25q32_write,
    .chip_erase = w25q32_chip_erase,
    .sector_erase = w25q32_sector_erase,
};


/* 从W25Q32读取设备信息到app_leakage */
static void gui_tjc_hmi_read_device_info_from_w25q(void)
{
    /* 创建一个临时缓冲区 */
    app_leakage_sub_device_flash_data_t temp_buffer[APP_LEAKAGE_SUB_DEVICE_NUM];
    
    /* 一次性读取所有设备信息 */
    w25q32.read(W25Q32_DEVICE_INFO_ADDR, 
               (uint8_t*)temp_buffer, 
               DEVICE_INFO_STORAGE_SIZE);
    
    /* 检查数据有效性 */
    uint8_t data_valid = 1;
    for(int i = 0; i < APP_LEAKAGE_SUB_DEVICE_NUM; i++)
    {
        /* 如果所有字段都是0xFF，说明是空数据 */
        if(temp_buffer[i].state == 0xFF && 
           temp_buffer[i].com == 0xFF &&
           temp_buffer[i].modbus_id == 0xFF)
        {
            data_valid = 0;
            break; 
        }
    }
    
    if(data_valid)
    {
        /* 复制到app_leakage结构体中 */
        for(int i = 0; i < APP_LEAKAGE_SUB_DEVICE_NUM; i++)
        {
            leakage.sub_device_data[i].flash_data = temp_buffer[i];
        }
    }
    else
    {
        /* Flash为空，初始化设备信息为默认值 */
        for(int i = 0; i < APP_LEAKAGE_SUB_DEVICE_NUM; i++)
        {
            memset(&leakage.sub_device_data[i].flash_data, 0, 
                   sizeof(app_leakage_sub_device_flash_data_t));
            leakage.sub_device_data[i].flash_data.state = DISABLE;
        }
    }  
}

static void gui_tjc_hmi_read_network_config_from_w25q(void)
{
    u16 i;
    network_config_t config;
    w25q32.read(W25Q32_NETWORK_CONFIG_ADDR, (uint8_t*)&config, sizeof(config));
    
    /* 检查数据有效性（判断第一个IP字节不是0xFF，表示有有效数据） */
    if (config.ip[0] != 0xFF && config.ip[0] != 0x00) {
        memcpy(W5500.IP_Addr, config.ip, 4);
        memcpy(W5500.Sub_Mask, config.mask, 4);
        memcpy(W5500.Gateway_IP, config.gateway, 4);
        
        for(i=0;i<NETWORK_PORT_NUM;i++)
        {
            W5500.W5500_Class[i].ConfigData.Port[0] = (config.port[i] >> 8) & 0xFF;
            W5500.W5500_Class[i].ConfigData.Port[1] = config.port[i] & 0xFF;
        }
    }
}

/* 初始化函数 */
static void w25q32_init(void) {
    W25Q32_CS_HIGH();  /* 初始时片选拉高 */
    w25q32_wake_up();   /* 唤醒芯片 */
    gui_tjc_hmi_read_device_info_from_w25q();
    gui_tjc_hmi_read_network_config_from_w25q();
}

/* 读取芯片id */
static uint8_t w25q32_read_id(void) {
    uint8_t id = 0;
    uint8_t cmd = W25Q32_JEDEC_ID;
    
    W25Q32_CS_LOW();
    w25q32_spi_transmit(&cmd, 1);
    w25q32_spi_receive(&id, 1);  /* 忽略前两个字节 */
    w25q32_spi_receive(&id, 1);
    w25q32_spi_receive(&id, 1);  /* 设备id在第三个字节 */
    W25Q32_CS_HIGH();
    
    return id;
}

/* 写使能 */
static void w25q32_write_enable(void) {
    uint8_t cmd = W25Q32_WRITE_ENABLE;
    
    W25Q32_CS_LOW();
    w25q32_spi_transmit(&cmd, 1);
    W25Q32_CS_HIGH();
}

/* 写禁止 */
static void w25q32_write_disable(void) {
    uint8_t cmd = W25Q32_WRITE_DISABLE;
    
    W25Q32_CS_LOW();
    w25q32_spi_transmit(&cmd, 1);
    W25Q32_CS_HIGH();
}

/* 读取状态寄存器 */
static uint8_t w25q32_read_status_reg(void) {
    uint8_t status;
    uint8_t cmd = W25Q32_READ_STATUS_REG1;
    
    W25Q32_CS_LOW();
    w25q32_spi_transmit(&cmd, 1);
    status = w25q32_spi_transmit_receive(0x00);
    W25Q32_CS_HIGH();
    
    return status;
}

/* 等待写入完成 */
static void w25q32_wait_for_write_end(void) {
    while (w25q32_read_status_reg() & W25Q32_STATUS_BUSY) {
        /* 可添加延时或看门狗喂狗 */
    }
}

/* 扇区擦除 (4kb) */
void w25q32_sector_erase(uint32_t sector_addr) 
{
    uint8_t cmd[4];
    
    /* 确保地址是4k对齐 */
    sector_addr &= ~(W25Q32_SECTOR_SIZE - 1);
    
    w25q32_write_enable();
    
    cmd[0] = W25Q32_SECTOR_ERASE;
    cmd[1] = (sector_addr >> 16) & 0xFF;
    cmd[2] = (sector_addr >> 8) & 0xFF;
    cmd[3] = sector_addr & 0xFF;
    
    W25Q32_CS_LOW();
    w25q32_spi_transmit(cmd, 4);
    W25Q32_CS_HIGH();
    
    w25q32_wait_for_write_end();
}

/* 块擦除 (64kb) */
static void w25q32_block_erase(uint32_t block_addr) {
    uint8_t cmd[4];
    
    /* 确保地址是64k对齐 */
    block_addr &= ~(W25Q32_BLOCK_SIZE - 1);
    
    w25q32_write_enable();
    
    cmd[0] = W25Q32_BLOCK_ERASE_64K;
    cmd[1] = (block_addr >> 16) & 0xFF;
    cmd[2] = (block_addr >> 8) & 0xFF;
    cmd[3] = block_addr & 0xFF;
    
    W25Q32_CS_LOW();
    w25q32_spi_transmit(cmd, 4);
    W25Q32_CS_HIGH();
    
    w25q32_wait_for_write_end();
}

/* 整片擦除 */
static void w25q32_chip_erase(void) {
    uint8_t cmd = W25Q32_CHIP_ERASE;  
    
    w25q32_write_enable();
    
    W25Q32_CS_LOW();
    w25q32_spi_transmit(&cmd, 1);  
    W25Q32_CS_HIGH();
    
    w25q32_wait_for_write_end();
}

/* 页写入 (最大256字节) */
static void w25q32_page_write(uint32_t addr, uint8_t *data, uint16_t len) {
    uint8_t cmd[4];
    
    if (len > W25Q32_PAGE_SIZE) {
        len = W25Q32_PAGE_SIZE;
    }
    
    w25q32_write_enable();
    
    cmd[0] = W25Q32_PAGE_PROGRAM;
    cmd[1] = (addr >> 16) & 0xFF;
    cmd[2] = (addr >> 8) & 0xFF;
    cmd[3] = addr & 0xFF;
    
    W25Q32_CS_LOW();
    w25q32_spi_transmit(cmd, 4);
    w25q32_spi_transmit(data, len);
    W25Q32_CS_HIGH();
    
    w25q32_wait_for_write_end();
}

/* 任意长度写入 */
static void w25q32_write(uint32_t addr, uint8_t *data, uint32_t len) {
    uint32_t page_remaining;
    uint32_t offset = 0;
    
    while (len > 0) {
        /* 计算当前页剩余字节数 */
        page_remaining = W25Q32_PAGE_SIZE - (addr % W25Q32_PAGE_SIZE);
        
        /* 本次写入的长度 */
        uint32_t write_len = (len < page_remaining) ? len : page_remaining;
        
        /* 写入一页数据 */
        w25q32_page_write(addr, &data[offset], write_len);
        
        /* 更新地址和偏移 */
        addr += write_len;
        offset += write_len;
        len -= write_len;
    }
}

/* 读取数据 */
static void w25q32_read(uint32_t addr, uint8_t *data, uint32_t len) {
    uint8_t cmd[4];
    
    cmd[0] = W25Q32_READ_DATA;
    cmd[1] = (addr >> 16) & 0xFF;
    cmd[2] = (addr >> 8) & 0xFF;
    cmd[3] = addr & 0xFF;
    
    W25Q32_CS_LOW();
    w25q32_spi_transmit(cmd, 4);
    w25q32_spi_receive(data, len);
    W25Q32_CS_HIGH();
}

/* 进入掉电模式 */
static void w25q32_power_down(void) {
    uint8_t cmd = W25Q32_POWER_DOWN;
    
    W25Q32_CS_LOW();
    w25q32_spi_transmit(&cmd, 1);
    W25Q32_CS_HIGH();
}

/* 唤醒芯片 */
static void w25q32_wake_up(void) {
    uint8_t cmd = W25Q32_RELEASE_POWER_DOWN;
    
    W25Q32_CS_LOW();
    w25q32_spi_transmit(&cmd, 1);
    W25Q32_CS_HIGH();
    HAL_Delay(5);  /* 等待芯片唤醒 */
}

