#ifndef __OTA_H__
#define __OTA_H__
#include <stdint.h>
#include <stdbool.h>

#define WBJW    0x57424A57

#define MAX_BIN_SIZE        (256*1024)      //单个bin文件最大值；
#define MAX_OLDFILES_NUM    8	            //旧bin文件的个数的最大值；
#define BLOCK_MAX           8	            //块数量的最大值；
#define NEW_EP              (0X80000000)	//入口地址；

#define MAX_PATH 8


/**************************** 以下为结构体定义*****************************/

//升级固件类型
#define FIRMTYPE_BT     1
#define FIRMTYPE_PT     2
#define FIRMTYPE_APP    3

#define DF_PKG  1   //差分包
#define FS_PKG  2   //原始包
//升级信息
typedef struct _ota_info_t
{
    uint8_t firmware_type;              //固件类型
    uint32_t old_ver;                   //旧版本号
    uint32_t old_size;                  //旧字节数
    uint32_t old_crc32;                 //旧crc32
    uint8_t pkg_type;                   //升级包类型
    uint8_t update_enum;                //固件标记
    uint8_t tail_flag;                  //是否包含尾部20字节
    uint8_t erase_app1;                 //是否已擦除app1
}ota_info_t;
extern ota_info_t ota_info;


//升级过程结果
enum {
    OTA_RET_SUCCESS         = 0x00,     //执行成功
    OTA_RET_APP3_CRC_ERR    = 0x31,     //APP3校验错误
    OTA_RET_NO_BLK_ERR,                 //没找到对应的块
    OTA_RET_NEWSIZE_ERR,                //升级后的字节数错误
    OTA_RET_NEWCRC_ERR,                 //升级后的crc错误
    OTA_RET_OLDSIZE_ERR,                //旧固件的字节数错误
    OTA_RET_OLDCRC_ERR,                 //旧固件的crc错误
    OTA_RET_FIRMWARE_ERR,               //固件类型错误
};


typedef struct{
    bool ok;
    char* path;
    char drive[MAX_PATH];
    char dir[MAX_PATH];
    char filename[MAX_PATH];
    char ext[MAX_PATH];
    uint8_t* addr;
    uint32_t size;
    uint32_t app_ver;
    uint16_t dev_type;
    uint32_t crc32;
}bin_file_t;


#pragma pack(1)                     // 1字节对齐
// 下载包，结构体
typedef struct{
    uint8_t* pkg_addr;              // 下载包的首地址；

    uint32_t pkg_size;              // 下载包的大小,完整的；从数据包里解析出来的原始字段值
    uint32_t pkg_crc32;             // 下载包的crc32；从数据包里解析出来的原始字段值
    uint32_t calc_pkg_size;             // 下载包的大小,完整的；经过计算的值 calc_size == pkg_size
    uint32_t calc_pkg_crc32;            // 下载包的crc32；经过计算的值 calc_crc32 = crc32(pkg_addr,calc_size - 4)
}DFOTA_pkg_t;

// 下载包，头，结构体，
// header_size = sizeof(DFOTA_pkg_header_t)
typedef struct{
    uint8_t  pkg_magic[16];         // ="DFOTA_PK_V002"; 魔数，差分升级标记，整个下载包的起始标记
    uint32_t pkg_time;              // 打包的时间戳；
    uint32_t pkg_size;              // 从数据包里解析出来的原始字段值
}DFOTA_pkg_header_t;

// 块，结构体
// DFOTA_blk_t block[BLOCK_MAX]     // 数组定义
typedef struct{
    uint8_t* blk_addr;              // 第n个块的首地址；

    uint32_t blk_size;              // 第n个块的大小,完整的；从数据包里解析出来的原始字段值
    uint32_t blk_crc32;             // 第n个块的crc32；从数据包里解析出来的原始字段值

    uint32_t calc_blk_size;             // 第n个块的大小,完整的；经过计算的值 calc_size == blk_size
    uint32_t calc_blk_crc32;            // 第n个块的crc32；经过计算的值 calc_crc32 = crc32(blk_addr,calc_size - 4)

    uint8_t* payload_addr;          // 载荷的首地址；
    uint32_t payload_size;          // 载荷的大小,完整的

}DFOTA_blk_t;

//块，头，结构体，header_size = sizeof(DFOTA_pkg_header_t)
typedef struct{
    uint8_t  blk_magic[4];          // ="BLOK"//魔数，块标记
    uint32_t blk_size;              // 此字段之后crc32之前的字节数
    uint8_t  d_flag;                // 差分算法标记
    uint8_t  z_flag;                // 压缩算法标记
    uint16_t reserve;               // 预留
    uint32_t old_ver;               // 旧固件[old.bin]的版本号
    uint32_t old_size;              // 旧固件[old.bin]的字节数
    uint32_t old_crc32;             // 旧固件[old.bin]的crc32
    uint32_t new_ver;               // 新固件[new.bin]的版本号
    uint32_t new_size;              // 新固件[new.bin]的字节数
    uint32_t new_crc32;             // 新固件[new.bin]的crc32
    uint32_t new_ep;                // 新固件[new.bin]的入口地址
    uint32_t pad_size;              // block尾部填充字节数
}DFOTA_blk_header_t;

// 载荷，结构体
typedef struct{
    uint8_t* diff_header_addr;      // 差分头首地址
    uint8_t* compr_header_addr;     // 压缩头首地址

    uint8_t* data_addr;             // data首地址
    uint32_t data_size;             // data的大小；
}DFOTA_payload_t;

// 差分，头，结构体，header_size = sizeof(DFOTA_bsdiff_header_t)
typedef struct{
    uint8_t  diff_magic[16];        // ="ENDSLEY/BSDIFF43"
    uint32_t new_size;              // new file size in Byte(s)（new.bin的字节数）
}DFOTA_bsdiff_header_t;

// 压缩，头，结构体，header_size = sizeof(DFOTA_lzma_header_t)
typedef struct{
    uint8_t  props;                 // Special LZMA properties (lc,lp, pb in encoded form)
    uint32_t dic;                   // Dictionary size (little endian)
    uint64_t raw_size;              // 没压缩时的字节数diff_raw.bin的字节数)
}DFOTA_lzma_header_t;

// DFOTA设备相关参数结构体定义
typedef struct{
    uint32_t current_ver;           // 当前版本
    uint32_t current_size;          // 当前版本
    uint32_t current_crc32;         // 当前版本

    uint32_t blk_sum;               // 实际解析到的块的个数
    uint32_t blk_match_index;       // 索引到的匹配的块下标

    //.....
}DFOTA_dev_t;


#pragma pack()                      // 取消1字节对齐，恢复为默认4字节对齐

#define PKG_HEADER_LEN  sizeof(DFOTA_pkg_header_t)  //24字节
#define BLK_HEADER_LEN  sizeof(DFOTA_blk_header_t)  //44字节


uint8_t firmware_tail_check(uint32_t part, uint32_t *firm_len);
uint8_t ota_process(void);
uint8_t blk_check(uint32_t addr, uint32_t *len);
void myiap_task(void);

#endif // ! 
