// Copyright 2026 Shanling.
// HID固件升级头文件
// 改动原因：实现通过HID协议进行固件升级的功能，提供高效、稳定、安全的升级方案

#ifndef _DFU_UPGRADE_H_
#define _DFU_UPGRADE_H_

#include <stdint.h>

// 固件升级命令定义
#define FIRMWARE_UPGRADE_START      0xA7    // 开始固件升级
#define FIRMWARE_UPGRADE_DATA       0xA8    // 传输固件数据块
#define FIRMWARE_UPGRADE_END        0xA9    // 结束固件升级
#define FIRMWARE_UPGRADE_STATUS     0xAA    // 获取升级状态
#define FIRMWARE_UPGRADE_ABORT      0xAB    // 中止固件升级
#define FIRMWARE_UPGRADE_ERASE      0xAC    // 擦除现有升级镜像
#define DEVICE_REBOOT               0xAE    // 设备重启（通用命令，不仅限于固件升级）

// 升级状态定义
typedef enum {
    UPGRADE_IDLE = 0x00,            // 空闲状态，未开始升级
    UPGRADE_PREPARING = 0x01,       // 准备状态，已调用START
    UPGRADE_TRANSFERRING = 0x02,    // 传输状态，正在接收数据
    UPGRADE_COMPLETING = 0x03,      // 完成中，正在写入最后一页
    UPGRADE_COMPLETED = 0x04,       // 已完成，升级成功
    UPGRADE_ERROR = 0x05,           // 错误状态，升级失败
    UPGRADE_ABORTED = 0x06          // 已中止，升级被中止
} upgrade_state_t;

// 状态码定义
#define STATUS_SUCCESS              0x00    // 成功
#define STATUS_FAIL                 0x01    // 失败
#define STATUS_SPACE_INSUFFICIENT   0x02    // Flash空间不足
#define STATUS_SIZE_INVALID         0x03    // 大小无效
#define STATUS_BLOCK_NUM_ERROR      0x04    // 块序号错误
#define STATUS_CHECKSUM_ERROR       0x05    // Checksum错误
#define STATUS_DATA_INCOMPLETE      0x06    // 数据不完整
#define STATUS_VERSION_INVALID      0x08    // 版本号无效
#define STATUS_SIZE_MISMATCH        0x09    // 大小不匹配

// Flash参数
#define FLASH_PAGE_SIZE             256     // Flash页大小
// 改动原因：修正最大数据块大小，HID数据包63字节（不包括Report ID）
// 数据包格式：同步头(1) + 命令码(1) + 块序号(2) + 数据长度(1) + 数据(N) + Checksum(1)
// 所以最大数据长度 = 63 - 5(头部) - 1(Checksum) = 57字节
#define MAX_DATA_BLOCK_SIZE         57      // 最大数据块大小（63字节HID数据包 - 5字节头部 - 1字节Checksum）
#define FLASH_MAX_UPGRADE_SIZE      (2000 * 1024)  // 最大固件大小1400KB

// 页缓冲区结构
typedef struct {
    uint8_t buffer[FLASH_PAGE_SIZE];    // Flash页缓冲区
    uint16_t offset;                     // 当前偏移
    uint16_t total_pages;                // 总页数
    uint16_t written_pages;              // 已写入页数
} page_buffer_t;

// 升级状态结构
typedef struct {
    upgrade_state_t state;               // 当前状态
    uint32_t firmware_size;              // 固件总大小
    uint16_t total_blocks;               // 总块数
    uint16_t received_blocks;            // 已接收块数
    uint16_t expected_block_num;         // 期望的块序号
    // 改动原因：去掉固件版本号字段，不再存储版本号
    uint8_t error_code;                  // 错误码
    page_buffer_t page_buf;              // 页缓冲区
    uint8_t first_page_written;          // 第一页写命令是否已执行（0=未执行，1=已执行）
} upgrade_status_t;

// 固件升级主处理函数
// 改动原因：处理HID固件升级命令，支持START、DATA、END等命令
// 参数：
//   - data: HID数据包（63字节，不包括Report ID）
//   - len: 数据长度
// 返回值：0=成功，非0=失败
unsigned char process_firmware_upgrade_cmd(uint8_t data[], uint16_t len);

/* 改动原因：声明 DFU channel 转发函数，供 eq.c (process_send_params) 调用，
 * 将 HID 固件升级命令通过 streaming channel 转发到 uart_handler 处理。
 * 实现在 audiohw.xc 中。 */
void dfu_chan_forward(unsigned char data[], unsigned len);

// 各个固件升级命令的独立处理函数
// 改动原因：在eq.c中为每个命令添加独立处理，支持HID一条一条指令发送
// 参数：
//   - data: HID数据包（63字节，不包括Report ID）
//   - len: 数据长度
// 返回值：0=成功，非0=失败（状态码）
unsigned char handle_firmware_upgrade_start(uint8_t data[], uint16_t len);
unsigned char handle_firmware_upgrade_data(uint8_t data[], uint16_t len);
unsigned char handle_firmware_upgrade_end(uint8_t data[], uint16_t len);
unsigned char handle_firmware_upgrade_status(uint8_t data[], uint16_t len);
unsigned char handle_firmware_upgrade_abort(uint8_t data[], uint16_t len);
unsigned char handle_firmware_upgrade_erase(uint8_t data[], uint16_t len);

// 发送固件升级响应（主动上报）
// 改动原因：通过HID主动上报机制发送响应，与音量上报机制一致
// 参数：
//   - cmd: 命令码
//   - response_data: 响应数据
//   - data_len: 响应数据长度
void send_firmware_upgrade_response(uint8_t cmd, uint8_t *response_data, uint16_t data_len);

// 升级进行中标志（升级期间阻止其他HID主动上报）
extern unsigned g_in_fw_upgrade;

// 初始化固件升级模块
// 改动原因：初始化升级状态和缓冲区
void firmware_upgrade_init(void);

// 获取当前升级状态
// 改动原因：供外部查询当前升级状态
upgrade_state_t firmware_upgrade_get_state(void);

// 重置升级状态
// 改动原因：升级完成或中止后重置状态
void firmware_upgrade_reset(void);

// ====================== UART DFU 友好接口 ======================
// 改动原因：为 UART 串口升级提供不依赖 g_hid_pass_data 的接口，
// 内部仍然复用 HID DFU 的状态机和 Flash 写入流程。
//
// 这些函数只操作内部的 g_upgrade_status，并通过参数返回需要的字段，
// 方便 user_uart.xc 根据 UART 协议打包响应。

// UART 版 START：输入固件原始大小，返回对齐后的大小和总块数
unsigned char uart_firmware_upgrade_start(uint32_t firmware_size,
                                          uint32_t *aligned_size_out,
                                          uint16_t *total_blocks_out);

// UART 版 DATA：输入块号和数据，返回状态码和“确认的块号”（成功时等于块号，序号错误时为期望块号）
unsigned char uart_firmware_upgrade_data(uint16_t block_num,
                                         uint8_t data_len,
                                         const uint8_t *data,
                                         uint16_t *confirmed_block_out);

// UART 版 END：结束升级，写入最后一页并终止 Flash 写入
unsigned char uart_firmware_upgrade_end(uint32_t firmware_size);

// UART 版 STATUS：直接从 g_upgrade_status 中读取当前状态和进度
unsigned char uart_firmware_upgrade_status(uint8_t *state_out,
                                           uint16_t *received_blocks_out,
                                           uint16_t *total_blocks_out,
                                           uint16_t *written_pages_out,
                                           uint16_t *total_pages_out,
                                           uint32_t *bytes_transferred_out,
                                           uint32_t *firmware_size_out,
                                           uint8_t *error_code_out);

// UART 版 ABORT：中止升级，可选择是否擦除已写入数据
unsigned char uart_firmware_upgrade_abort(uint8_t erase_flag);

// UART 版 ERASE：擦除现有 upgrade image 并执行 begin_write 初始化
unsigned char uart_firmware_upgrade_erase(void);

#endif // _DFU_UPGRADE_H_
