#include "include.h" #include "bt_fota.h" #if FOT_EN #define FOT_DEBUG_EN 0 #if FOT_DEBUG_EN #define FOT_DEBUG(...) printf(__VA_ARGS__) #define FOT_DEBUG_R(...) print_r(__VA_ARGS__) #else #define FOT_DEBUG(...) #define FOT_DEBUG_R(...) #endif /**********************************************/ #define FOT_STA_INIT BIT(0) #define FOT_STA_START BIT(1) #define FOT_STA_PAUSE BIT(2) /**********************************************/ #define FOT_FLAG_UPDATE_OK BIT(0) #define FOT_FLAG_SYS_RESET BIT(1) #define FOT_FLAG_ROLE_SWITCH BIT(2) #define FOT_FLAG_APP_CONNECT BIT(3) #define FOT_FLAG_CLK_SET BIT(4) #define FOT_FLAG_UPDATE_EXIT BIT(5) /**********************************************/ #define FOT_NOTIFY_STA 0x90 #define FOT_GET_INFO 0x91 #define FOT_GET_INFO_TLV 0x92 #define FOT_OUT_DATA_START 0xA0 #define FOT_OUT_DATA_CONTINUE 0x20 /**********************************************/ #define FOT_CMD_POS 0 #define FOT_SEQ_POS 1 #define FOT_ADDR_POS 2 #define FOT_DATA_LEN_POS 6 #define DATA_START_POS 10 #define DATA_CONTINUE_POS 2 /**********************************************/ #define FOT_BLOCK_LEN 1024 //压缩升级必须是512的倍数,目前只做了512倍数的处理 extern bool ble_fot_send_packet(u8 *buf, u16 len); extern u16 get_spp_mtu_size(void); u16 dev_version = 0x0001; //设备版本号 AT(.com_text.const) static const u8 fot_auth_data[] = {0xCC, 0xAA, 0x55, 0xEE, 0x12, 0x19, 0xE4}; typedef enum{ INFO_DEV_VER = 1, INFO_UPDATE_REQ, INFO_DEV_FEATURE, INFO_DEV_CONNECT_STA, INFO_EDR_ADDR, INFO_DEV_CHANNEL, }DEV_INFO_E; typedef struct __attribute__((packed)){ u16 remote_ver; u32 total_len; u32 remain_len; u32 hash; u16 data_pos; u8 fot_recv_ok; u32 addr; u32 tick; u8 type; u8 sys_clk; }fot_s; fot_s fot_var; static u8 fot_data[FOT_BLOCK_LEN] AT(.fot_data.buf); static u8 fot_seq = 0; static u8 fot_remote_seq = 0; static u8 fot_sta = 0; static u8 fot_flag = 0; static u16 fot_connect_sta = 0; u8 is_fot_update_en(void) { return 1; } void app_fota_pack_write(void *buf, u32 len) { u32 total_use_len = 0; while (len && (ota_pack_get_err() == FOT_ERR_OK)) { ota_pack_write(buf + total_use_len); len -= 512; total_use_len += 512; } } AT(.text.fot.cache) void app_fota_write(void *buf, u32 addr, u32 len) { app_fota_pack_write(buf, len); } AT(.text.fot.cache) u8 app_fota_get_err(void) { return ota_pack_get_err(); } AT(.text.fot.cache) void app_fota_verify(void) { ota_pack_verify(); } bool app_fota_breakpoint_info_read(void) { return ota_pack_breakpoint_info_read(); } void app_fota_init(void) { ota_pack_init(); load_code_fota(); } u32 app_fota_get_curaddr(void) { return ota_pack_get_curaddr(); } void app_fota_update_done(void) { ota_pack_done(); } bool app_fota_is_write_done(void) { return ota_pack_is_write_done(); } AT(.text.fot.cache) static void fot_sent_proc(u8 *buf,u8 len) { if((fot_flag & FOT_FLAG_APP_CONNECT) == 0){ return; } FOT_DEBUG("fot tx:"); FOT_DEBUG_R(buf,len); #if FOT_EN if(ble_is_connect()){ ble_fot_send_packet(buf,len); } #endif } AT(.text.fot.update) static void fot_reply_info_tlv(u8 *buf,u8 len) { u8 read_offset = 0; u8 write_offset = 0; u8 rsp[32]; u8 val_len = 0; if((buf == NULL) || (len == 0)){ return; } rsp[write_offset++] = FOT_GET_INFO_TLV; rsp[write_offset++] = fot_seq++; while(read_offset < len){ switch(buf[read_offset]){ case INFO_DEV_VER: FOT_DEBUG("INFO_DEV_VER\n"); val_len = buf[read_offset + 1]; rsp[write_offset++] = INFO_DEV_VER; rsp[write_offset++] = 2; rsp[write_offset++] = dev_version & 0xff; rsp[write_offset++] = (dev_version >> 8) & 0xff; break; case INFO_DEV_FEATURE: FOT_DEBUG("INFO_DEV_FEATURE\n"); { u16 dev_ability = 0; val_len = buf[read_offset + 1]; rsp[write_offset++] = INFO_DEV_FEATURE; rsp[write_offset++] = 2; rsp[write_offset++] = dev_ability & 0xff; rsp[write_offset++] = (dev_ability >> 8) & 0xff; } break; case INFO_DEV_CONNECT_STA: FOT_DEBUG("INFO_DEV_CONNECT_STA\n"); val_len = buf[read_offset + 1]; rsp[write_offset++] = INFO_DEV_CONNECT_STA; rsp[write_offset++] = 2; rsp[write_offset++] = fot_connect_sta & 0xff; rsp[write_offset++] = (fot_connect_sta >> 8) & 0xff; break; default: val_len = buf[read_offset + 1]; break; } read_offset += (2 + val_len); } if(write_offset > sizeof(rsp)){ FOT_DEBUG("fot:rsp buf overflow!!!\n"); while(1); } fot_sent_proc(rsp,write_offset); } AT(.text.fot.update) static void fot_reply_dev_version(void) { u8 data[5]; data[0] = FOT_GET_INFO; data[1] = fot_seq++; data[2] = INFO_DEV_VER; memcpy(&data[3],&dev_version,2); fot_sent_proc(data,5); } AT(.text.fot.cache) static void fot_dev_notify_sta(u8 sta) { u8 buf[3]; buf[0] = FOT_NOTIFY_STA; buf[1] = fot_seq++; buf[2] = sta; fot_sent_proc(buf,3); } AT(.text.fot.update) u8 is_fot_start(void) { return (fot_sta & FOT_STA_START) ? 1:0; } AT(.text.fot.update) void bsp_fot_init(void) { u8 dev_version_str[] = SW_VERSION; u16 version_temp = 0; memset(&fot_var,0,sizeof(fot_var)); dev_version = 0x00; version_temp = dev_version_str[1]-'0'; version_temp <<= 12; dev_version |= version_temp; version_temp = dev_version_str[3]-'0'; version_temp <<= 8; dev_version |= version_temp; version_temp = dev_version_str[5]-'0'; version_temp <<= 4; dev_version |= version_temp; fot_sta = FOT_STA_INIT; } void bsp_fot_exit(void) { fot_sta = 0; fot_seq = 0; fot_remote_seq = 0; fot_flag &= ~FOT_FLAG_APP_CONNECT; if(fot_var.sys_clk){ sys_clk_set(fot_var.sys_clk); } unlock_code_fota(); } void fot_update_pause(void) { if(fot_sta & FOT_STA_START){ fot_sta = FOT_STA_PAUSE; fot_dev_notify_sta(FOT_UPDATE_PAUSE); } } void fot_update_continue(void) { if(fot_sta & FOT_STA_PAUSE){ bsp_fot_init(); fot_dev_notify_sta(FOT_UPDATE_CONTINUE); } } u16 bsp_fot_mtu_get(void) { u16 packet_len = 0; #if FOT_EN if(ble_is_connect()){ packet_len = ble_get_gatt_mtu(); } #endif return packet_len; } AT(.text.fot.update) static void fot_reply_update_request(void) { u16 flash_remote_ver; u32 hash; u32 addr = 0; u32 block_len = FOT_BLOCK_LEN; u16 packet_len = 0; u8 data[14]; u8 need_update = 1; if(bt_get_status() >= BT_STA_INCOMING){ need_update = 0; fot_flag |= FOT_FLAG_UPDATE_EXIT; goto fot_req_reply; } #if FOT_EN if(ble_is_connect()){ ble_update_conn_param(16,0,400); } #endif packet_len = bsp_fot_mtu_get(); FOT_DEBUG("fot_packet_len:%d\n",packet_len); app_fota_init(); fot_flag |= FOT_FLAG_CLK_SET; fot_sta |= FOT_STA_START; FOT_DEBUG("hash_val:0x%x\n",fot_var.hash); param_fot_remote_ver_read((u8*)&flash_remote_ver); param_fot_hash_read((u8*)&hash); FOT_DEBUG("flash hash val:0x%x\n",hash); if((fot_var.hash != 0xFFFFFFFF) && (flash_remote_ver == fot_var.remote_ver) && (hash == fot_var.hash)){ param_fot_type_read(&fot_var.type); if(app_fota_breakpoint_info_read() == true){ addr = app_fota_get_curaddr(); } } fot_req_reply: data[0] = FOT_GET_INFO; data[1] = fot_seq++; data[2] = INFO_UPDATE_REQ; memcpy(&data[3],&addr,4); memcpy(&data[7],&block_len,4); memcpy(&data[11],&packet_len,2); data[13] = need_update; fot_sent_proc(data,14); } #if FOT_EN void fot_ble_disconnect_callback(void) { FOT_DEBUG("--->fot_ble_disconnect_callback\n"); bsp_fot_exit(); } void fot_ble_connect_callback(void) { FOT_DEBUG("--->fot_ble_connect_callback\n"); } #endif void fot_spp_connect_callback(void) { FOT_DEBUG("--->fot_spp_connect_callback\n"); } void fot_spp_disconnect_callback(void) { FOT_DEBUG("--->fot_spp_disconnect_callback\n"); bsp_fot_exit(); } AT(.text.fot.cache) void fot_recv_proc(u8 *buf, u16 len) { u32 addr; u32 recv_data_len; u8 cmd; if(fot_remote_seq != buf[FOT_SEQ_POS]){ if(memcmp(fot_auth_data, buf, 7)){ //接入码先过掉 FOT_DEBUG("remote seq err:%d,%d\n",fot_remote_seq,buf[FOT_SEQ_POS]); fot_dev_notify_sta(FOT_ERR_SEQ); fot_flag |= FOT_FLAG_UPDATE_EXIT; } return; } fot_remote_seq++; if((fot_sta & FOT_STA_INIT) == 0){ return; } cmd = buf[FOT_CMD_POS]; switch(cmd){ case FOT_GET_INFO_TLV: fot_reply_info_tlv(&buf[2],len-2); break; case FOT_GET_INFO: if(buf[2] == INFO_DEV_VER){ fot_reply_dev_version(); }else if(buf[2] == INFO_UPDATE_REQ){ memcpy(&fot_var.remote_ver,&buf[3],2); memcpy(&fot_var.hash,&buf[5],4); fot_reply_update_request(); } break; case FOT_OUT_DATA_START: if(fot_var.remain_len){ FOT_DEBUG("--->len err:%d\n",fot_var.remain_len); fot_dev_notify_sta(FOT_ERR_DATA_LEN); fot_flag |= FOT_FLAG_UPDATE_EXIT; return; } recv_data_len = len-DATA_START_POS; memcpy(&fot_var.total_len,&buf[FOT_DATA_LEN_POS],4); fot_var.remain_len = fot_var.total_len - recv_data_len; memcpy(&addr,&buf[FOT_ADDR_POS],4); memcpy(&fot_data[fot_var.data_pos],&buf[DATA_START_POS],recv_data_len); fot_var.data_pos += recv_data_len; if(fot_var.remain_len == 0){ fot_var.fot_recv_ok = 1; fot_var.data_pos = 0; } break; case FOT_OUT_DATA_CONTINUE: recv_data_len = len-DATA_CONTINUE_POS; if(fot_var.remain_len < recv_data_len){ recv_data_len = fot_var.remain_len; } fot_var.remain_len -= recv_data_len; memcpy(&fot_data[fot_var.data_pos],&buf[DATA_CONTINUE_POS],recv_data_len); fot_var.data_pos += recv_data_len; if(fot_var.remain_len == 0){ fot_var.fot_recv_ok = 1; fot_var.data_pos = 0; } break; } } AT(.text.fot.cache) void bsp_fot_process(void) { if(fot_sta & FOT_STA_START){ if(fot_var.fot_recv_ok){ fot_var.fot_recv_ok = 0; app_fota_write(fot_data, app_fota_get_curaddr(), fot_var.total_len); if(app_fota_is_write_done()){ app_fota_verify(); if(app_fota_get_err()){ fot_dev_notify_sta(app_fota_get_err()); fot_flag |= FOT_FLAG_UPDATE_EXIT; }else{ FOT_DEBUG("--->fot update success\n"); app_fota_update_done(); fot_flag |= (FOT_FLAG_UPDATE_OK | FOT_FLAG_SYS_RESET); fot_var.tick = tick_get(); fot_dev_notify_sta(FOT_UPDATE_DONE); } }else{ fot_dev_notify_sta(app_fota_get_err()); if(app_fota_get_err()){ fot_flag |= FOT_FLAG_UPDATE_EXIT; } } } } if(fot_flag & FOT_FLAG_SYS_RESET){ if(tick_check_expire(fot_var.tick,3000)){ fot_flag &= ~FOT_FLAG_SYS_RESET; FOT_DEBUG("-->fota update ok,sys reset\n"); WDT_RST(); } } if(fot_flag & FOT_FLAG_CLK_SET){ FOT_DEBUG("--->FOT_FLAG_CLK_SET\n"); fot_var.sys_clk = sys_clk_get_cur(); //主时钟192M切换132M会复位 if (fot_var.sys_clk < SYS_192M) { sys_clk_set(SYS_132M); } fot_flag &= ~FOT_FLAG_CLK_SET; } if(fot_flag & FOT_FLAG_UPDATE_EXIT){ FOT_DEBUG("-->FOT_FLAG_UPDATE_EXIT"); bsp_fot_exit(); fot_flag &= ~FOT_FLAG_UPDATE_EXIT; } } AT(.com_text.fot) u8 fot_app_connect_auth(uint8_t *packet, uint16_t size) { if(!fot_sta){ if(size == 7 && !memcmp(fot_auth_data, packet, 7)){ //sizeof(fot_auth_data) fot_flag |= FOT_FLAG_APP_CONNECT; bsp_fot_init(); } } return fot_sta; } AT(.com_text.fot) bool bsp_fot_is_connect(void) { return (fot_sta>0); } #else WEAK void fot_update_pause(void) { } WEAK void fot_update_continue(void) { } #endif //FOT_EN