570 lines
13 KiB
C
570 lines
13 KiB
C
#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
|