/** **************************************************************************************** * * @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)