520 lines
17 KiB
C
520 lines
17 KiB
C
|
||
/**
|
||
****************************************************************************************
|
||
*
|
||
* @file ota_m4.c
|
||
*
|
||
* @brief
|
||
*
|
||
* Copyright (c) 2022 - 2025, XinChip
|
||
* All rights reserved.p
|
||
*
|
||
****************************************************************************************
|
||
*/
|
||
|
||
#include "rwip_config.h"
|
||
|
||
#if (BLE_APP_PRESENT)
|
||
|
||
#include "ota_flash_interface.h"
|
||
#include "ota_protocol.h"
|
||
#include "ota_server.h"
|
||
#include "xc_drv_wdt.h"
|
||
uint8_t ota_flag = 0;
|
||
extern struct app_env_tag app_env;
|
||
static struct fotas_write_env fotas_write_env;
|
||
__RAM_EM struct fotas_env fota_env;
|
||
struct fotas_flag fotas_status = {1, 1, TRUES, FALSE, 0, 0, 0, 1, 0};
|
||
|
||
uint8_t *get_fota_env_addr(uint16_t len)
|
||
{
|
||
if (len > FOTA_PAGE_NUM * FLASH_PAGE_SIZE + 20) {
|
||
// LOGI(" len error\n ");
|
||
return NULL;
|
||
}
|
||
return &fota_env;
|
||
}
|
||
void xc_ota_wdt_init(WDT_InitCfg_t *wdt_cfg)
|
||
{
|
||
cpr_ctlapbclken_grctl__wdt_pclk_en__setf(ENABLE);
|
||
cpr_rstctl_ctlapb_sw__wdt_rstn__setf(RSTCTL_ENABLE);
|
||
cpr_rstctl_ctlapb_sw__wdt_rstn__setf(RSTCTL_DISABLE);
|
||
|
||
cpr_rstctl_wdtrst_mask_set(
|
||
(WDT_SYS_RSTN_MASK_DISABLE | WDT_M0_RSTN_MASK_ENABLE));
|
||
cpr_lp_ctl__wdt_pclk_sel__setf(DISABLE);
|
||
cpr_lp_ctl__wdt_tclk_en__setf(ENABLE);
|
||
|
||
wdt_cr__wdt_rmod__setf(wdt_cfg->WorkMode);
|
||
wdt_torr__wdt_top__setf(wdt_cfg->ReloadValue);
|
||
}
|
||
void wdt_reset_system(void)
|
||
{
|
||
|
||
WDT_InitCfg_t wdt_cfg;
|
||
|
||
NVIC_EnableIRQ(WDT_IRQn);
|
||
|
||
wdt_cfg.WorkMode = WDT_WORK_MODE0;
|
||
|
||
wdt_cfg.ReloadValue = WDT_ReloadValue_0xFFFF;
|
||
|
||
xc_ota_wdt_init(&wdt_cfg);
|
||
xc_wdt_start();
|
||
}
|
||
|
||
static void fota_status_set(uint8_t status) { fota_env.status = status; }
|
||
|
||
static uint8_t fota_status_get(void) { return fota_env.status; }
|
||
|
||
// DEV->APP RSP OR CMD
|
||
void xc_fota_dev_ack_cmd(uint16_t sn, uint8_t cmd,
|
||
uint8_t data_or_atype, // data or ack type
|
||
uint16_t fnum_or_para) // frame num or parameter
|
||
{
|
||
fota_env.ack.sn = sn;
|
||
fota_env.ack.cmd = cmd;
|
||
fota_env.ack.data_or_atype = data_or_atype;
|
||
fota_env.ack.fnum_or_para = fnum_or_para;
|
||
FOTAS_NOTIFY((uint8_t *)&fota_env.ack, sizeof(fota_env.ack),
|
||
OTA_SVC_TX_CHAR_VAL);
|
||
}
|
||
|
||
// The sector CRC check and write data to flash.
|
||
static void xc_fotas_flash_write()
|
||
{
|
||
// only 1 time
|
||
if (fotas_status.first_pack_write_flag) {
|
||
fotas_status.first_pack_write_flag = FALSE;
|
||
fotas_status.sector_erase_flag = 1;
|
||
for (int j = 0; j < 256; j++) {
|
||
fotas_write_env.para_buf[j] = fota_env.sector_buf[0][j];
|
||
}
|
||
|
||
// 0x1b000
|
||
fotas_write_env.erase_addr = (fotas_write_env.para_buf[27] << 24) +
|
||
(fotas_write_env.para_buf[26] << 16) +
|
||
(fotas_write_env.para_buf[25] << 8) +
|
||
(fotas_write_env.para_buf[24]); // data
|
||
fotas_write_env.write_addr =
|
||
(fotas_write_env.para_buf[27] << 24) +
|
||
(fotas_write_env.para_buf[26] << 16) +
|
||
(fotas_write_env.para_buf[25] << 8) +
|
||
(fotas_write_env.para_buf[24]); // start para
|
||
LOGI(" ota parameter fotas_write_env.write_addr=%x "
|
||
"fotas_write_env.erase_addr=%x\n ",
|
||
fotas_write_env.write_addr, fotas_write_env.erase_addr);
|
||
|
||
FLASH_SECTOR_ERASE(fotas_write_env.erase_addr);
|
||
fotas_status.wtite_flag = 1;
|
||
} else // second sector
|
||
{
|
||
ble_flash_later_write_page(fota_env.sector_buf[0],
|
||
fotas_write_env.write_addr);
|
||
|
||
fotas_status.wtite_flag = 1;
|
||
fotas_write_env.write_addr += 256;
|
||
}
|
||
fotas_write_env.erase_addr +=
|
||
256; // The erase address needs to be aligned to 4096
|
||
|
||
LOGI(".");
|
||
|
||
fotas_write_env.cur_num = 0;
|
||
}
|
||
|
||
// first sector, 15 page
|
||
void ota_write_flash()
|
||
{
|
||
// LOGI("yes %x
|
||
// %d\n",fotas_write_env.write_addr,fotas_status.wtitten_page_num);
|
||
ble_flash_later_write_page(
|
||
fota_env.sector_buf[fotas_status.wtitten_page_num],
|
||
fotas_write_env.write_addr);
|
||
fotas_write_env.write_addr += 256;
|
||
fotas_status.wtitten_page_num += 1;
|
||
fotas_write_env.erase_addr += 256;
|
||
}
|
||
// OTA data handler.
|
||
|
||
void xc_fota_write_data_handle(uint8_t *buffer, uint8_t cmd2)
|
||
{
|
||
uint16_t pid;
|
||
struct img_hdr_t *img;
|
||
struct fota_data *fota_data1;
|
||
struct fota_data_att *data_att;
|
||
uint16_t sn;
|
||
uint8_t cmd;
|
||
uint16_t len;
|
||
uint16_t sw_ver;
|
||
uint16_t rom_ver;
|
||
|
||
(void)sn;
|
||
(void)cmd;
|
||
(void)len;
|
||
|
||
if (fota_status_get() == FOTAS_DEV_READY) {
|
||
switch (cmd2) {
|
||
// FOTAS_STA_CMD = 1
|
||
case FOTAS_STA_CMD: // 1.3 App->Dev, ota start req
|
||
LOGI("line=%d, app->dev 1.3, ver same dev->app 2.1, ver diff "
|
||
"dev->app 1.4\n",
|
||
__LINE__);
|
||
img = (struct img_hdr_t *)buffer;
|
||
sn = img->sn;
|
||
cmd = img->cmd;
|
||
len = img->len;
|
||
sw_ver = img->sw_ver;
|
||
rom_ver = img->rom_ver;
|
||
fota_env.crc = img->crc;
|
||
fota_env.bin_size = img->bin_size;
|
||
fota_env.pack_num = img->pack_num;
|
||
|
||
fota_status_set(FOTAS_DEV_READY);
|
||
xc_fota_dev_ack_cmd(FOTAS_RSP, FOTAS_CMD, FOTAS_TRANS_SUC,
|
||
1); // 1 means fnum
|
||
break;
|
||
// FOTAS_INFO_CMD = 3
|
||
case FOTAS_INFO_CMD: // 3.3 App->Dev, ota current info packet
|
||
LOGI("line=%d,current info packet, 3.3 app->dev, 4.1 dev->app \n",
|
||
__LINE__);
|
||
if (fotas_status.sector_erase_flag &&
|
||
(fotas_write_env.erase_addr % 4096 == 0)) {
|
||
ble_flash_later_sector_erase(fotas_write_env.erase_addr);
|
||
LOGI("addr:%x\n", fotas_write_env.erase_addr);
|
||
}
|
||
|
||
data_att = (struct fota_data_att *)buffer;
|
||
fota_env.data_att.sn = data_att->sn;
|
||
fota_env.data_att.len = data_att->len;
|
||
fota_env.data_att.cmd = data_att->cmd;
|
||
fota_env.data_att.segment_id = data_att->segment_id;
|
||
fota_env.data_att.sector_size = data_att->sector_size; // 4096
|
||
fota_env.data_att.crc = data_att->crc;
|
||
|
||
xc_fota_dev_ack_cmd(FOTAS_RSP, FOTAS_CMD, FOTAS_TRANS_SUC, 1);
|
||
break;
|
||
// FOTAS_DATA_CMD = 5
|
||
case FOTAS_DATA_CMD: // 5.3 App->Dev
|
||
LOGI("line=%d, 5.3 ota current data packet\n", __LINE__);
|
||
fota_data1 = (struct fota_data *)buffer;
|
||
pid = fota_data1->sn;
|
||
fotas_write_env.cur_num += 1;
|
||
memcpy((uint8_t *)fota_env.sector_buf +
|
||
(pid - 1) * fotas_write_env.old_length,
|
||
fota_data1->data, fotas_write_env.length);
|
||
fotas_write_env.old_length = fotas_write_env.length;
|
||
LOGI("fotas_write_env.cur_num=%x fotas_write_env.all_fnum=%x\n",
|
||
fotas_write_env.cur_num, fotas_write_env.all_fnum);
|
||
if (fotas_write_env.cur_num != fotas_write_env.all_fnum) {
|
||
xc_fota_dev_ack_cmd(FOTAS_RSP, FOTAS_ACK, FOTAS_TANS_LOSE, 0);
|
||
} else {
|
||
xc_fota_dev_ack_cmd(FOTAS_RSP, FOTAS_CMD, FOTAS_TRANS_SUC, 0);
|
||
|
||
uint16_t last_sector_size = fota_env.data_att.sector_size %
|
||
(FOTA_PAGE_NUM * FLASH_PAGE_SIZE);
|
||
|
||
if (last_sector_size) {
|
||
memset(
|
||
(uint8_t *)fota_env.sector_buf + last_sector_size, 0xff,
|
||
(FOTA_PAGE_NUM * FLASH_PAGE_SIZE) - last_sector_size);
|
||
}
|
||
|
||
fota_status_set(FOTAS_DEV_BUSY);
|
||
|
||
xc_fotas_flash_write();
|
||
}
|
||
break;
|
||
// FOTAS_DATA_CMD = 6
|
||
case FOTAS_COM_CMD:
|
||
LOGI("line=%d, 7.3 ota over\n", __LINE__);
|
||
ble_flash_later_write_page(fotas_write_env.para_buf,
|
||
OTA_PARAM_ADDR);
|
||
xc_fota_dev_ack_cmd(FOTAS_RSP, FOTAS_CMD, FOTAS_SUCCEES, 1);
|
||
|
||
fotas_status.rsp_stat = 0;
|
||
fotas_status.ack_idx = 0;
|
||
|
||
fota_status_set(FOTAS_TRANS_SUC);
|
||
fotas_status.ota_succ_flag = 1;
|
||
break;
|
||
|
||
default:
|
||
LOGI("err cmd\n");
|
||
break;
|
||
}
|
||
} else {
|
||
xc_fota_dev_ack_cmd(FOTAS_RSP, FOTAS_CMD, FOTAS_DEV_BUSY, 0);
|
||
}
|
||
}
|
||
void fota_disconnect_reset()
|
||
{
|
||
fotas_status.rsp_stat = 0;
|
||
fotas_status.ack_idx = 0;
|
||
fotas_status.fir_rsp_stat = 1;
|
||
fotas_status.first_pack_write_flag = TRUES;
|
||
}
|
||
|
||
void ota_clear_status()
|
||
{
|
||
fotas_status.ota_succ_flag = 0;
|
||
fotas_status.rsp_stat = 0;
|
||
fotas_status.ack_idx = 0;
|
||
fotas_write_env.cur_num = 0;
|
||
fotas_status.fir_rsp_stat = 1;
|
||
fotas_status.first_pack_write_flag = TRUES;
|
||
fotas_status.sector_erase_flag = 0;
|
||
fotas_status.wtitten_page_num = 1;
|
||
fotas_status.wtite_flag = 0; // Only when the valid data of the bin file is
|
||
// received, it will be set to 1
|
||
fota_status_set(FOTAS_DEV_BUSY);
|
||
}
|
||
|
||
uint16_t trans_size_cmd_ack(uint8_t num_page)
|
||
{
|
||
uint16_t size = 0;
|
||
switch (num_page) {
|
||
case 16: {
|
||
size = 0x0001; // 4096
|
||
} break;
|
||
case 8: {
|
||
size = 0x0101; // 2048
|
||
} break;
|
||
case 4: {
|
||
size = 0x0201; // 1024
|
||
} break;
|
||
case 2: {
|
||
size = 0x0301; // 512
|
||
} break;
|
||
case 1: {
|
||
size = 0x0401; // 256
|
||
} break;
|
||
defult:
|
||
LOGI("not support size = %d\n", num_page * 256);
|
||
}
|
||
return size;
|
||
}
|
||
|
||
// CMD and RSP handler.
|
||
void xc_fota_cmd_rsp_handle(struct opencode_or_ack *wr_req)
|
||
{
|
||
uint8_t cmd = wr_req->cmd;
|
||
uint8_t type = wr_req->data_or_atype;
|
||
uint16_t fnum = wr_req->fnum_or_para;
|
||
|
||
// Each stage of ota will perform an empty packet interaction before
|
||
// starting data interaction
|
||
if (cmd == FOTAS_CMD) {
|
||
if (type == 0) // type is transmission
|
||
{
|
||
// ���յ���ǰ����Ϣ�� FOTAS_INFO_CMD ʱ�� fotas_status.rsp_stat = 1
|
||
// ���յ� 2.2 app ������ack, �� fotas_status.ack_idx = 0 ʱ��rsp_stat
|
||
// += 1
|
||
|
||
switch (fotas_status.rsp_stat) {
|
||
|
||
// FOTAS_RSP_READY = 0
|
||
case FOTAS_RSP_READY:
|
||
LOGI("line=%d, [1.1 app->dev, 1.2 dev->app]\n", __LINE__);
|
||
|
||
ble_flash_later_page_erase(OTA_PARAM_ADDR);
|
||
|
||
// xc_fota_dev_ack_cmd(FOTAS_RSP, FOTAS_ACK, FOTAS_TRANS_SUC,
|
||
// 0x0001);
|
||
xc_fota_dev_ack_cmd(FOTAS_RSP, FOTAS_ACK, FOTAS_TRANS_SUC,
|
||
trans_size_cmd_ack(FOTA_PAGE_NUM));
|
||
fota_status_set(FOTAS_DEV_READY);
|
||
break;
|
||
|
||
// FOTAS_RCV_SECT_START = 1
|
||
case FOTAS_RCV_SECT_START:
|
||
// �˴��յ���Ϣ2.4 App->Dev, ����û��2.5�������Ϣ�Ƿ���Ҫ�豸�˻ظ�
|
||
//
|
||
LOGI("line=%d, [2.4,3.1 app->dev 3.2 dev->app] or [4.4,5.1 "
|
||
"app->dev 5.2 dev->app ]\n",
|
||
__LINE__);
|
||
// start recv data
|
||
fotas_write_env.all_fnum = fnum;
|
||
xc_fota_dev_ack_cmd(FOTAS_RSP, FOTAS_ACK, FOTAS_TRANS_SUC, 1);
|
||
fota_status_set(FOTAS_DEV_READY);
|
||
|
||
// when default =1, disconnect=1, ota over=1,
|
||
// fotas_status.fir_ack_idx = 1
|
||
|
||
fotas_status.ack_idx = FOTAS_RECV_START;
|
||
|
||
break;
|
||
|
||
case FOTAS_RCV_SECT_CANCEL: // no use, maybe use in the future
|
||
LOGI("FOTAS_RCV_SECT_CANCEL\n");
|
||
break;
|
||
|
||
default:
|
||
LOGI("err fotas_status.rsp_stat:%d\n", fotas_status.rsp_stat);
|
||
}
|
||
}
|
||
} else if (cmd == FOTAS_ACK) // type is ack, app -> dev, ������Ҫ dev ����
|
||
// app һ����
|
||
{
|
||
if (fnum == 1) {
|
||
// fotas_status.ack_idx = 1, When fotas_status.ack_idx=1, it means
|
||
// that the ota data packet has been delivered
|
||
switch (
|
||
fotas_status
|
||
.ack_idx) // ��Ϊ app
|
||
// ����ָ��һ���������豸�ص�ָ�һ��
|
||
{
|
||
// FOTAS_RSP_START = 0
|
||
case FOTAS_RSP_START:
|
||
LOGI("line=%d, sn=0, app->dev ack 2.2, dev->app 2.3 \n",
|
||
__LINE__);
|
||
|
||
fotas_status.rsp_stat = FOTAS_RCV_SECT_START;
|
||
|
||
fota_env.send_buf.sn = FOTAS_SENT;
|
||
fota_env.send_buf.len = 3;
|
||
|
||
if (fotas_status.ota_succ_flag) {
|
||
fota_env.send_buf.cmd =
|
||
7; // 8.3 Dev->App (ota upgrade result)
|
||
} else {
|
||
fota_env.send_buf.cmd = 2; // 2.3 Dev->App (ota start rsp)
|
||
}
|
||
fota_env.send_buf.status = fota_status_get();
|
||
FOTAS_NOTIFY((uint8_t *)&fota_env.send_buf,
|
||
sizeof(fota_env.send_buf), OTA_SVC_TX_CHAR_VAL);
|
||
break;
|
||
|
||
// FOTAS_RSP_START = 1
|
||
case FOTAS_RSP_CMD:
|
||
// 4.3 Dev->App (ota current packet rsp)
|
||
LOGI("line=%d,ota current packet rsp, app->dev 4.2 ack, "
|
||
"dev->app 4.3 req\n",
|
||
__LINE__);
|
||
fota_status_set(FOTAS_DEV_READY);
|
||
fota_env.send_buf.sn = FOTAS_SENT;
|
||
fota_env.send_buf.len = 3;
|
||
fota_env.send_buf.cmd = 4;
|
||
fota_env.send_buf.status = fota_status_get();
|
||
FOTAS_NOTIFY((uint8_t *)&fota_env.send_buf,
|
||
sizeof(fota_env.send_buf), OTA_SVC_TX_CHAR_VAL);
|
||
break;
|
||
|
||
// FOTAS_RECV_START = 2
|
||
case FOTAS_RECV_START:
|
||
LOGI("line=%d, 4.3 ota current packet rsp \n", __LINE__);
|
||
fota_status_set(FOTAS_DEV_READY);
|
||
fota_env.send_buf.sn = FOTAS_SENT;
|
||
fota_env.send_buf.len = 3;
|
||
fota_env.send_buf.cmd = 4;
|
||
fota_env.send_buf.status = fota_status_get();
|
||
FOTAS_NOTIFY((uint8_t *)&fota_env.send_buf,
|
||
sizeof(fota_env.send_buf), OTA_SVC_TX_CHAR_VAL);
|
||
break;
|
||
|
||
default:
|
||
LOGI("fotas_status.ack_idx:%d\n", fotas_status.ack_idx);
|
||
break;
|
||
}
|
||
} else if (fnum == 0) {
|
||
switch (fotas_status.ack_idx) {
|
||
case FOTAS_RSP_START:
|
||
if (fotas_status.ota_succ_flag) {
|
||
LOGI("\r\n");
|
||
LOGI("fotas_status.ota_succ_flag\n");
|
||
xc_ble_disconnect(app_env.slave_conidx, 0x16);
|
||
wdt_reset_system();
|
||
} else {
|
||
// LOGI("ota start rsp succeed 2.4\n");
|
||
}
|
||
break;
|
||
|
||
case FOTAS_RECV_START:
|
||
LOGI("line=%d, ota start recv data 4.4 \n", __LINE__);
|
||
fota_status_set(FOTAS_DEV_READY);
|
||
fotas_status.ack_idx = 1;
|
||
break;
|
||
|
||
default:
|
||
// LOGI(" fnum:%d
|
||
//fotas_status.ack_idx:%d\n",fnum,fotas_status.ack_idx);
|
||
break;
|
||
}
|
||
}
|
||
} else {
|
||
LOGI("error!!!!rsp\n");
|
||
}
|
||
}
|
||
typedef void (*iapfun)(void); // 定义一个函数类型的参数.
|
||
iapfun jump2app;
|
||
__asm void MSR_MSP(uint32_t addr) // 设置栈顶地址 addr:栈顶地址
|
||
{
|
||
MSR MSP, r0 // set Main Stack value
|
||
BX r14
|
||
}
|
||
void enter_ota_mode()
|
||
{
|
||
#define OTA_ADDR 0x1100F000
|
||
|
||
uint32_t pes=OTA_ADDR;
|
||
typedef void (*iapfun)(void); // 定义一个函数类型的参数static iapfun jump2app;
|
||
jump2app = (iapfun) * (uint32_t *)(pes + 4);
|
||
MSR_MSP(*(uint32_t *) (pes));
|
||
jump2app ();
|
||
|
||
while(1);
|
||
}
|
||
// uint8_t flash_size;
|
||
void xc_fota_server_write_ind(uint8_t *buffer, uint16_t buff_size)
|
||
{
|
||
struct opencode_or_ack *wr_req = (struct opencode_or_ack *)buffer;
|
||
uint16_t sn = wr_req->sn;
|
||
#if SINGLE_OTA
|
||
enter_ota_mode();
|
||
#endif
|
||
if (buff_size >= 3) {
|
||
fotas_write_env.length = buff_size - 3;
|
||
} else {
|
||
fotas_write_env.length = buff_size;
|
||
LOGI("err buff_size=%d\n", buff_size);
|
||
}
|
||
ota_flag = 1;
|
||
LOGI("debug: sn = %x \n", sn);
|
||
switch (sn) {
|
||
case FOTAS_RSP:
|
||
LOGI("FOTAS_RSP\n");
|
||
xc_fota_cmd_rsp_handle(wr_req);
|
||
break;
|
||
|
||
default:
|
||
LOGI("FOTAS_DATA\n");
|
||
xc_fota_write_data_handle(buffer, wr_req->cmd);
|
||
break;
|
||
}
|
||
}
|
||
|
||
void xc_ota_schedule()
|
||
{
|
||
ble_flash_handle();
|
||
|
||
if(fotas_status.wtite_flag)
|
||
{
|
||
if(op_flash.op_state == OP_IDEL)
|
||
{
|
||
if(fotas_status.wtitten_page_num == FOTA_PAGE_NUM)
|
||
{
|
||
fotas_status.wtitten_page_num = 1;
|
||
fotas_status.wtite_flag = 0;
|
||
LOGI("func=%s,line=%d\n",__func__,__LINE__);
|
||
xc_fota_dev_ack_cmd(0, 1, 0, 0);
|
||
}
|
||
else
|
||
{
|
||
//LOGI("func=%s,line=%d\n",__func__,__LINE__);
|
||
ota_write_flash();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
#endif // (BLE_APP_PRESENT)
|