#include #include "app_ota.h" #include "httpclient.h" #include "makeimage.h" #include "crc32.h" #include "hlog.h" #define TAG "TAG_APPOTA" struct RangeUpgardeParam { int32_t offset; int32_t totallen; //ota file length int32_t progress; int32_t retry; }; enum upgradeStage { STAGE_HEADER = 0, STAGE_AW831, STAGE_SOUND, STAGE_MT7682, STAGE_DONE, }; enum upgradeRet { RET_FW_NOT_ENOUGH_DATA = -3, RET_FW_MAGIC_ERROR = -2, RET_FW_CRC_ERROR = -1, RET_FW_OK, RET_FW_NEED_MORE_DATA, RET_FW_NO_NEED_UPGRADE, }; typedef struct { char *url; onDownloadImageProgress listener; }Upgrade_config; //format: version,length,crc //setenv mt7682_ota_info 1,552996,1652930298 #define DEV_OTA_PARTITION "/dev/OTA" #define DOWNLOAD_TRY_TIMES 5 static enum upgradeStage sUpgradeStage = STAGE_HEADER; static iobuffer sDataBuffer = {NULL, 0, 0}; static struct FWPackHeader sFWHeader; static int32_t sUpgrading; //EKEN format typedef enum { PAYLOAD_TYPE_SET_WOW = 1, PAYLOAD_TYPE_KEEPALIVE, PAYLOAD_TYPE_GET_WIFI_DATA, PAYLOAD_TYPE_CHANGE_WIFI_CONNECT,//4 PAYLOAD_TYPE_SET_PIR, PAYLOAD_TYPE_REBOOT_T31, PAYLOAD_TYPE_GET_SOME_DATA, PAYLOAD_TYPE_OTA_START,//8 PAYLOAD_TYPE_OTA_ERASE, PAYLOAD_TYPE_OTA_ERASE_RET, PAYLOAD_TYPE_OTA_WRITE, PAYLOAD_TYPE_OTA_CRC_RET,//12 PAYLOAD_TYPE_OTA_STOP, PAYLOAD_TYPE_SET_DATETIME_TS, PAYLOAD_TYPE_SET_AP_SCAN, PAYLOAD_TYPE_GET_AP_SCAN_LIST,//16 PAYLOAD_TYPE_SET_AP_MODE, PAYLOAD_TYPE_SET_REBOOT_SYS, PAYLOAD_TYPE_SET_LED_STATE, PAYLOAD_TYPE_DHCP_OK,//20 PAYLOAD_TYPE_RING_KEY, PAYLOAD_TYPE_LOG_DATA, PAYLOAD_TYPE_SET_REG_DATA, PAYLOAD_TYPE_GET_REG_DATA, PAYLOAD_TYPE_TEST = 999, }_SPI_PAYLOAD_TYPE; typedef struct { uint32_t payload_type; uint32_t payload_len; } _SPI_DATA_HEADER; int32_t startOTAFromiobuffer(onDownloadImageProgress listener); static int32_t writeDatato7682(int32_t type, uint8_t *payload, uint32_t payloadsize) { _SPI_DATA_HEADER header = {type, payloadsize}; char *send_buf = (char *)hv_malloc(sizeof(header) + payloadsize); memcpy(send_buf, (unsigned char *)&header, sizeof(header)); if (payload) { memcpy(send_buf + sizeof(header), payload, payloadsize); } int32_t length = sizeof(header) + payloadsize; /*if (t31_device_transfer_mt7682(send_buf, length, NULL, 0) != 0) { hv_free(send_buf); hlogd("%s: t31_device_transfer_mt7682 failed", __FUNCTION__); return -1; }*/ hv_free(send_buf); return 0; } //VIA format static int32_t writeRAWSDIODatato7672(const char* data, int32_t len) { #if 0 SdioPacket* packet = PacketCreate(); putCmd(packet, UPGRADE_REQ); putData(packet, data, len); int32_t ret = sdio_writePacket(packet); hv_free(packet); return ret; #endif return 0; } void requestMT7682RebootandUpgrade() { hlogd("request MT7682 reboot to upgrade"); for (int32_t i = 0; i < 10; i++) { int32_t magic = 0x20207682; if (writeDatato7682(PAYLOAD_TYPE_OTA_START, (uint8_t*)&magic, sizeof(magic)) != 0) { sleep(1); } else { break; } } hlogd("FIXME: should not be here, 7682 should already reboot us"); } void dump(struct chipFWInfo *chipInfo) { hlogd("dump chipinfo: magic 0x%x chipid %d version %d offset %d length %d crc 0x%x", chipInfo->magic, chipInfo->chipID, chipInfo->version, chipInfo->offset, chipInfo->length, chipInfo->crc); } enum upgradeRet verifyFirmware(int32_t id) { struct chipFWInfo *chipInfo = &sFWHeader.FWInfo[id]; int32_t fwLen = chipInfo->length; if (chipInfo->magic == 0 && fwLen == 0) { hlogd("id %d no need upgrade", id); return RET_FW_NO_NEED_UPGRADE; } if (sDataBuffer.size < fwLen) { return RET_FW_NOT_ENOUGH_DATA; // return RET_FW_NEED_MORE_DATA; } if (chipInfo->magic != IMG_MAGIC || chipInfo->chipID != id) { dump(chipInfo); hlogd("verifyChipInfo: check id %d failed", id); return RET_FW_MAGIC_ERROR; } uint32_t crc = crc32(0, (const void *)sDataBuffer.iodata, fwLen); if (crc != chipInfo->crc) { int32_t *data = (int32_t *)sDataBuffer.iodata; hlogd("id %d fw crc error: 0x%x VS 0x%x, fwLen %d, fw data 0x%x 0x%x 0x%x 0x%x", id, crc, chipInfo->crc, fwLen, *(data), *(data + 1), *(data + 2), *(data + 3)); return RET_FW_CRC_ERROR; } hlogd("verifyChipInfo: id:%d check crc:0x%x", id, crc); return RET_FW_OK; } static int32_t parseHeader() { if (sDataBuffer.size < sizeof(struct FWPackHeader)) { return -1; } iobuffer_read(&sDataBuffer, &sFWHeader, sizeof(struct FWPackHeader)); sUpgradeStage++; hlogd("parse OTA package header OK"); for (int32_t i = 0; i < CHIP_MAX; i++) { struct chipFWInfo *info = &sFWHeader.FWInfo[i]; if (info->magic == IMG_MAGIC) { hlogd("FW id: %d version %d length %d offset %d crc 0x%x", i, info->version, info->length, info->offset, info->crc); } } return 0; } static int32_t upgradeModule(int32_t id, onDownloadImageProgress listener) { enum upgradeRet ret = verifyFirmware(id); if (ret < 0) return -2; if (ret == RET_FW_NO_NEED_UPGRADE) goto end; int32_t length = sFWHeader.FWInfo[id].length; if (id == MAIN) { hlogd("AW831 Firmware verify OK, start upgrade"); #if 0 if (aw_upgrade_slice("rtos", sDataBuffer.iodata, 0, length, 1)) { hloge("upgradeAW831 aw_upgrade_slice failed"); return -1; } if (aw_upgrade_end(0)) { hloge("upgradeAW831 aw_upgrade_end failed"); return -1; } #endif hlogd("upgradeModule V831 OK"); } else if (id == SOUND) { hlogd("SOUND Firmware verify OK, start upgrade"); #if 0 if (aw_upgrade_slice("/dev/SOUND", sDataBuffer.iodata, 0, length, 1)) { hloge("aw_upgrade_slice SOUND failed"); return -1; } #endif hlogd("SOUND Firmware upgrade done"); } else if (id == WIFI) { hlogd("MT7682 Firmware verify OK, start upgrade"); //hexdump -n 1024 /dev/OTA #if 0 if (aw_upgrade_slice(DEV_OTA_PARTITION, sDataBuffer.iodata, 0, length, 1)) { hloge("store7682Image aw_upgrade_slice failed"); return -1; } #endif hlogd("upgradeModule store MT7682 firmware OK"); } iobuffer_erase(&sDataBuffer, 0, length); end: sUpgradeStage++; return 0; } static int32_t rangeUpgrade(Upgrade_config *downcfg, struct RangeUpgardeParam *upgradeParam, onDownloadImageProgress listener){ httpclient_data_t client_data = {0}; httpclient_t client = {0}; static int32_t left_data = 0; int32_t ret = UPGRADING; sUpgradeStage = STAGE_HEADER; int32_t header_size = 1024; int32_t body_size = 32001; //one byte more for httpclient char *response_header = (char *)hv_malloc(header_size); char *response_body = (char *)hv_malloc(body_size); hlogd("%s: url %s", __FUNCTION__, downcfg->url); HTTPCLIENT_RESULT result = httpclient_connect(&client, downcfg->url); if (result != HTTPCLIENT_OK) { hlogd("httpclient_connect %s failed result %d", downcfg->url, result); listener(UPGRADING, 0); ret = UPGRADING; goto exit; } else { hlogd("httpclient_connect %s OK fd %d", downcfg->url, client.socket); } memset(&client_data, 0, sizeof(client_data)); client_data.header_buf = response_header; client_data.header_buf_len = header_size; client_data.response_buf = response_body; client_data.response_buf_len = body_size; client_data.range_enable = 1; client_data.range_begin = sDataBuffer.size; client_data.range_end = 0; listener(UPGRADING, 0); result = httpclient_send_request(&client, downcfg->url, HTTPCLIENT_GET, &client_data); if (result != HTTPCLIENT_OK) { hlogd("httpclient_send_request %s failed result %d", downcfg->url, result); listener(UPGRADING, 0); ret = UPGRADING; goto exit; } while (result >= HTTPCLIENT_OK) { result = httpclient_recv_response(&client, &client_data); if (result < 0) { hlogd("httpclient_recv_response %s failed result %d", downcfg->url, result); listener(UPGRADING, 0); ret = UPGRADING; goto exit; } if(upgradeParam->offset == 0) upgradeParam->retry = 0; if (upgradeParam->totallen == 0) { left_data = upgradeParam->totallen = client_data.response_content_len; hlogd("url %s size %d", downcfg->url, upgradeParam->totallen); } uint32_t data_len = left_data - client_data.retrieve_len; upgradeParam->offset += data_len; left_data -= data_len; hlogd("upgradeParam totallen %d offset %d leftLen %d", upgradeParam->totallen, upgradeParam->offset, client_data.retrieve_len); int32_t curProgress = upgradeParam->offset * 100 / upgradeParam->totallen; if(curProgress > upgradeParam->progress && curProgress != 100) { upgradeParam->progress = curProgress; listener(UPGRADING, curProgress); ret = UPGRADING; } if (data_len != 0) { iobuffer_appendData(&sDataBuffer, client_data.response_buf, data_len); } if (upgradeParam->offset == upgradeParam->totallen) { hlogd("firmware download done"); listener(UPGRADING, 100); listener(DOWNLOAD_OK, 0); ret = DOWNLOAD_OK; break; } } exit: hlogd("httpclient_close fd %d", client.socket); httpclient_close(&client); if (response_header) hv_free(response_header); if (response_body) hv_free(response_body); /* for compile if(ret == UPGRADING) rt_thread_mdelay(2000);*/ return ret; } static void upgradeTask(void *arg) { sUpgrading = 1; Upgrade_config *downcfg =(Upgrade_config *)arg; onDownloadImageProgress listener = downcfg->listener; //RT_ASSERT(listener); struct RangeUpgardeParam upgradeParam; memset(&upgradeParam, 0, sizeof(upgradeParam)); int32_t upgradeStatus = UPGRADING; //add_suspend(SUSPEND_UPGRADE, 8*60); iobuffer_init(&sDataBuffer); iobuffer_reserve(&sDataBuffer, 4*1024*1024); listener(READY, 0); while(strlen(downcfg->url) > 0){ hlogd("retried %d times rangeUpgrade", upgradeParam.retry); upgradeStatus = rangeUpgrade(downcfg, &upgradeParam, listener); if(upgradeStatus == DOWNLOAD_OK){ hlogd("rangeUpgrade download ok"); break; }else if(++upgradeParam.retry > DOWNLOAD_TRY_TIMES){ hlogd("retried %d times and still download fail !!!", upgradeParam.retry); upgradeStatus = DOWNLOAD_FAIL; listener(DOWNLOAD_FAIL, 0); break; } } if(upgradeStatus == DOWNLOAD_OK) startOTAFromiobuffer(listener); exit: sUpgrading = 0; if (STAGE_DONE != sUpgradeStage) { hlogd("upgradeTask error, current stage %d", sUpgradeStage); #if 0 goWow(__func__); #endif } else { hlogd("upgradeTask OK"); } hv_free(downcfg->url); hv_free(downcfg); return; } iobuffer* getOTAiobuffer() { return &sDataBuffer; } int32_t startOTAFromiobuffer(onDownloadImageProgress listener) { int32_t ret; int32_t upgraded7682 = 0; if(sDataBuffer.size == 0) { hlogd("sDataBuffer size is 0"); return -1; } listener(INSTALL_ING, 0); ret = parseHeader(); if(ret < 0) goto end; listener(UPGRADING, 10); ret = upgradeModule(MAIN, listener); if(ret < 0) goto end; listener(UPGRADING, 50); ret = upgradeModule(SOUND, listener); if(ret < 0) goto end; listener(UPGRADING, 80); ret = upgradeModule(WIFI, listener); if(ret < 0) goto end; else if(ret == RET_FW_OK){ upgraded7682 = 1; } listener(UPGRADING, 100); end: switch(ret){ case RET_FW_NOT_ENOUGH_DATA: case RET_FW_MAGIC_ERROR: listener(INSTALL_FAIL, 0); break; case RET_FW_CRC_ERROR: listener(CRC_FAIL, 0); break; default:// RET_FW_OK or RET_FW_NO_NEED_UPGRADE listener(UPGRADE_KERNEL, 0); listener(INSTALL_OK, 0); listener(UPGRADE_ALL, 0); break; } /*env_mutex_lock(); if(upgraded7682){ char info[32] = {0}; snprint32_tf(info, sizeof(info), "%d,%d,%d", sFWHeader.FWInfo[WIFI].version, sFWHeader.FWInfo[WIFI].length, sFWHeader.FWInfo[WIFI].crc); env_set_string(env_ota_info, info); } if(!is_adb_online()){//do not report version when update throught adb env_set_int32_t(env_need_report_version, 1); } env_save(); env_mutex_unlock();*/ if(upgraded7682){ requestMT7682RebootandUpgrade(); } return 0; } void createUpgradeTask(char *otaURL, onDownloadImageProgress listener) { if(sUpgrading){ hlogd("%s sUpgrading return",__func__); return; } hlogd("createUpgradeTask : %s", otaURL); Upgrade_config *p = (Upgrade_config*)hv_malloc(sizeof(Upgrade_config)); //RT_ASSERT(p); p->url = strdup(otaURL); p->listener = listener; /* rt_thread_t task_t = rt_thread_create("upgradeTask", upgradeTask, p, 10*1024, CONFIG_FINSH_THREAD_PRIORITY, 20); if(task_t == RT_NULL){ listener(READY_FAIL, 0); }else{ rt_thread_startup(task_t); }*/ } typedef struct { uint32_t m_magic; /* version of app */ uint32_t m_ver; /* app len*/ uint32_t m_body_len; uint32_t m_checkcrc; uint32_t m_bin_start_addr; uint32_t reserve[3]; } bl_sota_update_info_t; //32bytes int32_t isUpgrading(void){ return sUpgrading; } int32_t upgradeMT7682(void) { hlogd("%s start", __FUNCTION__); sUpgrading = 1; char *info = NULL;//env_get_string(env_ota_info, NULL); if (info == NULL) { hlogd("%s: can't find env env_ota_info", __FUNCTION__); return -1; } int32_t ret = -1; int32_t max_block_size = 1024; int32_t block_size = max_block_size; int32_t fwVersion = -1, fwSize = 0, fwCrc = 0; if (3 != sscanf(info, "%d,%d,%d", &fwVersion, &fwSize, &fwCrc)) { hlogd("%s: firmware info error: %s", __FUNCTION__, info); return -1; } int32_t otaFD = open(DEV_OTA_PARTITION, O_RDONLY); if (otaFD < 0) { hlogd("%s: open %s failed", __FUNCTION__, DEV_OTA_PARTITION); return -1; } char *buf = hv_malloc(block_size); if (!buf) { hlogd("%s: hv_malloc upgrade buffer %d error", __FUNCTION__, block_size); goto __ota_exit; } { //先发送一包数据表示固件的相关信息 bl_sota_update_info_t sota_header; sota_header.m_magic = 0x08317682; sota_header.m_ver = fwVersion; sota_header.m_body_len = fwSize; sota_header.m_checkcrc = fwCrc; hlogd("%s: start upgrade version %d length %d crc 0x%x", __FUNCTION__, sota_header.m_ver, sota_header.m_body_len, sota_header.m_checkcrc); if (writeRAWSDIODatato7672((const char *)&sota_header, sizeof(sota_header))) { hlogd("%s: write sota_header failed", __FUNCTION__); return -1; } hlogd("%s: write sota_header ok", __FUNCTION__); } int32_t leftSize = fwSize; do { block_size = leftSize > max_block_size ? max_block_size : leftSize; int32_t avail = read(otaFD, buf, block_size); if (avail == -1) { hlogd("read source failed"); goto __ota_exit; } leftSize -= avail; if (writeRAWSDIODatato7672((const char *)buf, avail) != 0) { hlogd("%s: write sota data failed", __FUNCTION__); goto __ota_exit; } hlogd("%s: write data %d ok", __FUNCTION__, avail); } while (leftSize); ret = 0; __ota_exit: if (buf) { hv_free(buf); } if (otaFD) { close(otaFD); } if (ret == 0) { hlogd("%s: done", __FUNCTION__); } else { hlogd("%s: failed", __FUNCTION__); } return ret; }