MAX_CARLINK_A270S/MXC_A27-PCB4.5-270T/ArkmicroFiles/libboard-amt630hv100/source/ota_update.c

716 lines
19 KiB
C
Raw Permalink Normal View History

2025-01-21 16:49:37 +08:00
#include <stdlib.h>
#include <unistd.h>
#include "FreeRTOS.h"
#include "board.h"
#include "chip.h"
#include "sfud.h"
#include "romfile.h"
#include "updatefile.h"
#include "animation.h"
#include "sysinfo.h"
#include "mmcsd_core.h"
#include "ff_stdio.h"
#include "source/crc32.h"
#if DEVICE_TYPE_SELECT != EMMC_FLASH
#include "ff_sfdisk.h"
#endif
#ifdef OTA_UPDATE_SUPPORT
#include "ota_update.h"
/* 获取已升级文件位置, toburn不为0时获取升级文件要烧录的位置 */
static unsigned int get_upfile_offset(int filetype, int toburn)
{
SysInfo *sysinfo = GetSysInfo();
if (filetype == UPFILE_TYPE_WHOLE) {
if (!toburn) return sysinfo->image_offset;
if (sysinfo->image_offset == UPDATEFILE_MEDIA_OFFSET)
return UPDATEFILE_MEDIA_B_OFFSET;
else
return UPDATEFILE_MEDIA_OFFSET;
} else if (filetype == UPFILE_TYPE_FIRSTLDR) {
#if DEVICE_TYPE_SELECT == EMMC_FLASH
if (!toburn) return sysinfo->loader_offset;
if (sysinfo->loader_offset == LOADER_OFFSET)
return LOADERB_OFFSET;
else
return LOADER_OFFSET;
#else
return LOADER_OFFSET;
#endif
} else if (filetype == UPFILE_TYPE_STEPLDR) {
if (!toburn) return sysinfo->stepldr_offset;
if (sysinfo->stepldr_offset == STEPLDRA_OFFSET)
return STEPLDRB_OFFSET;
else
return STEPLDRA_OFFSET;
} else if (filetype == UPFILE_TYPE_LNCHEMMC) {
return 0;
} else {
uint8_t buf[512];
UpFileHeader *header;
UpFileInfo *appfile;
unsigned int image_offset;
int i;
if (toburn) {
if (sysinfo->image_offset == UPDATEFILE_MEDIA_OFFSET)
image_offset = UPDATEFILE_MEDIA_B_OFFSET;
else
image_offset = UPDATEFILE_MEDIA_OFFSET;
} else {
image_offset = sysinfo->image_offset;
}
#if DEVICE_TYPE_SELECT == EMMC_FLASH
emmc_read(image_offset, 512, buf);
#else
sfud_flash *sflash = sfud_get_device(0);
sfud_read(sflash, image_offset, 512, buf);
#endif
header = (UpFileHeader *)buf;
if (header->magic != MKTAG('U', 'P', 'D', 'F')) {
printf("update file isn't found, can't support module update.\n");
return 0xffffffff;
}
for (i = 0; i < header->filenum; i++) {
appfile = &header->files[i];
if ((appfile->magic == UPFILE_APP_MAGIC && filetype == UPFILE_TYPE_APP) ||
(appfile->magic == MKTAG('R', 'O', 'M', 'A') && filetype == UPFILE_TYPE_RESOURCE) ||
(appfile->magic == MKTAG('B', 'A', 'N', 'I') && filetype == UPFILE_TYPE_ANIMATION)) {
if (appfile->offset & (64 - 1)) {
printf("offset isn't align to sector erase size, can't support module update.\n");
return 0xffffffff;
}
return appfile->offset + image_offset;
}
}
}
return 0xffffffff;
}
static void set_upfile_offset(SysInfo *sysinfo, int filetype, uint32_t offset)
{
if (filetype == UPFILE_TYPE_WHOLE) {
sysinfo->image_offset = offset;
} else if (filetype == UPFILE_TYPE_FIRSTLDR) {
#if DEVICE_TYPE_SELECT == EMMC_FLASH
sysinfo->loader_offset = offset;
#endif
} else if (filetype == UPFILE_TYPE_STEPLDR) {
sysinfo->stepldr_offset = offset;
}
}
static unsigned int get_upfile_size(int filetype)
{
SysInfo *sysinfo = GetSysInfo();
uint32_t offset;
uint8_t buf[512];
if (filetype <= UPFILE_TYPE_ANIMATION) {
offset = get_upfile_offset(filetype, 0);
#if DEVICE_TYPE_SELECT == EMMC_FLASH
emmc_read(offset, 512, buf);
#else
sfud_flash *sflash = sfud_get_device(0);
sfud_read(sflash, offset, 512, buf);
#endif
if (filetype == UPFILE_TYPE_WHOLE) {
UpFileHeader *header = (UpFileHeader *)buf;
return header->size;
} else if (filetype == UPFILE_TYPE_RESOURCE) {
RomHeader *header = (RomHeader *)buf;
return header->romsize;
} else if (filetype == UPFILE_TYPE_ANIMATION) {
BANIHEADER *header = (BANIHEADER *)buf;
return header->aniSize;
}
} else if (filetype >= UPFILE_TYPE_APP) {
return sysinfo->app_size;
} else if (filetype == UPFILE_TYPE_FIRSTLDR) {
return sysinfo->loader_size;
} else if (filetype == UPFILE_TYPE_STEPLDR) {
return sysinfo->stepldr_size;
}
return 0;
}
/* 获取已升级文件校验和
filesize 0:
toburn 0: 1:
checkmode 0: 1:0 2:, */
static uint32_t get_upfile_checksum(int filetype, size_t filesize, int checkmode, int toburn)
{
uint32_t checksum, calc_checksum = 0xffffffff;
uint8_t *buf;
sfud_flash *sflash = sfud_get_device(0);
uint32_t fileoffset;
int off, size, leftsize;
buf = pvPortMalloc(IMAGE_RW_SIZE);
if (!buf) {
printf("%s %d malloc %d bytes fail.\n", __FUNCTION__, __LINE__, IMAGE_RW_SIZE);
return 0;
}
if (!filesize) {
filesize = get_upfile_size(filetype);
if (!filesize) {
if (!checkmode) {
filesize = IMAGE_RW_SIZE;
} else {
printf("Error, filesize is zero when needing chekced.\n");
return 0;
}
}
}
fileoffset = get_upfile_offset(filetype, toburn);
size = filesize > IMAGE_RW_SIZE ? IMAGE_RW_SIZE : filesize;
#if DEVICE_TYPE_SELECT == EMMC_FLASH
if (filetype == UPFILE_TYPE_LNCHEMMC) {
if (!sflash->init_ok)
sfud_init();
sfud_read(sflash, fileoffset, size, buf);
} else emmc_read(fileoffset, size, buf);
#else
sfud_read(sflash, fileoffset, size, buf);
#endif
if (filetype == UPFILE_TYPE_WHOLE) {
UpFileHeader *header = (UpFileHeader *)buf;
checksum = header->checksum;
header->checksum = 0;
if (checkmode)
calc_checksum = xcrc32(buf, size, calc_checksum);
} else if (filetype == UPFILE_TYPE_RESOURCE) {
RomHeader *header = (RomHeader *)buf;
checksum = header->checksum;
header->checksum = 0;
if (checkmode)
calc_checksum = xcrc32(buf, size, calc_checksum);
} else if (filetype == UPFILE_TYPE_ANIMATION) {
BANIHEADER *header = (BANIHEADER *)buf;
checksum = header->checksum;
header->checksum = 0;
if (checkmode)
calc_checksum = xcrc32(buf, size, calc_checksum);
} else if (filetype >= UPFILE_TYPE_APP) {
checksum = *(uint32_t*)(buf + APPLDR_CHECKSUM_OFFSET);
*(uint32_t*)(buf + APPLDR_CHECKSUM_OFFSET) = 0;
if (checkmode)
calc_checksum = xcrc32(buf, size, calc_checksum);
}
if (!checkmode) {
vPortFree(buf);
return checksum;
}
off = fileoffset + IMAGE_RW_SIZE;
leftsize = filesize - size;
while (leftsize > 0) {
size = leftsize > IMAGE_RW_SIZE ? IMAGE_RW_SIZE : leftsize;
#if DEVICE_TYPE_SELECT == EMMC_FLASH
if (filetype == UPFILE_TYPE_LNCHEMMC)
sfud_read(sflash, off, size, buf);
else
emmc_read(off, size, buf);
#else
sfud_read(sflash, off, size, buf);
#endif
calc_checksum = xcrc32(buf, size, calc_checksum);
off += size;
leftsize -= size;
}
vPortFree(buf);
if (calc_checksum == checksum || checkmode > 1)
return calc_checksum;
else
return 0;
}
/* 获取升级文件的校验和bchecked不为0时表示需要校验校验错误返回0 */
static uint32_t get_mediafile_checksum(const char *ufile, int filetype, int bchecked)
{
uint32_t checksum, calc_checksum = 0xffffffff;
FF_FILE *fp;
uint8_t *buf;
int rlen;
fp = ff_fopen(ufile, "rb");
if (!fp) {
printf("open %s fail.\n", ufile);
return 0;
}
buf = pvPortMalloc(IMAGE_RW_SIZE);
if (!buf) {
printf("%s %d malloc %d bytes fail.\n", __FUNCTION__, __LINE__, IMAGE_RW_SIZE);
ff_fclose(fp);
return 0;
}
rlen = ff_fread(buf, 1, IMAGE_RW_SIZE, fp);
if (rlen <= 0) {
printf("read %s data fail.\n", ufile);
ff_fclose(fp);
vPortFree(buf);
return 0;
}
if (filetype == UPFILE_TYPE_WHOLE) {
UpFileHeader *header = (UpFileHeader *)buf;
checksum = header->checksum;
header->checksum = 0;
if (bchecked)
calc_checksum = xcrc32(buf, rlen, calc_checksum);
} else if (filetype == UPFILE_TYPE_RESOURCE) {
RomHeader *header = (RomHeader *)buf;
checksum = header->checksum;
header->checksum = 0;
if (bchecked)
calc_checksum = xcrc32(buf, rlen, calc_checksum);
} else if (filetype == UPFILE_TYPE_ANIMATION) {
BANIHEADER *header = (BANIHEADER *)buf;
checksum = header->checksum;
header->checksum = 0;
if (bchecked)
calc_checksum = xcrc32(buf, rlen, calc_checksum);
} else if (filetype >= UPFILE_TYPE_APP) {
checksum = *(uint32_t*)(buf + APPLDR_CHECKSUM_OFFSET);
*(uint32_t*)(buf + APPLDR_CHECKSUM_OFFSET) = 0;
if (bchecked)
calc_checksum = xcrc32(buf, rlen, calc_checksum);
}
if (!bchecked) {
ff_fclose(fp);
vPortFree(buf);
return checksum;
}
while ((rlen = ff_fread(buf, 1, IMAGE_RW_SIZE, fp)) > 0)
calc_checksum = xcrc32(buf, rlen, calc_checksum);
ff_fclose(fp);
vPortFree(buf);
if (calc_checksum == checksum)
return checksum;
else
return 0;
}
static int backup_whole_image(void)
{
uint8_t *buf;
SysInfo *sysinfo = GetSysInfo();
uint32_t imagechecksum, imagesize, imageoff, roff, woff;
UpFileHeader *header = NULL;
int leftsize, rwsize;
int retimes = 3;
#if DEVICE_TYPE_SELECT != EMMC_FLASH
sfud_flash *sflash = sfud_get_device(0);
#endif
buf = pvPortMalloc(IMAGE_RW_SIZE);
if (!buf) {
printf("%s %d malloc %d bytes fail.\n", __FUNCTION__, __LINE__, IMAGE_RW_SIZE);
return -1;
}
if (sysinfo->image_offset == UPDATEFILE_MEDIA_OFFSET)
imageoff = UPDATEFILE_MEDIA_B_OFFSET;
else
imageoff = UPDATEFILE_MEDIA_OFFSET;
#if DEVICE_TYPE_SELECT == EMMC_FLASH
emmc_read(imageoff, IMAGE_RW_SIZE, buf);
#else
sfud_read(sflash, imageoff, IMAGE_RW_SIZE, buf);
#endif
header = (UpFileHeader*)buf;
if (header->checksum == sysinfo->app_checksum) {
if (get_upfile_checksum(UPFILE_TYPE_WHOLE, header->size, 1, 1) == sysinfo->app_checksum) {
printf("the whole images are same, no need to backup.\n");
vPortFree(buf);
return 0;
}
} else if (sysinfo->app_checksum == 0) {
uint32_t checksum = get_upfile_checksum(UPFILE_TYPE_WHOLE, header->size, 2, 1);
if (checksum && checksum == get_upfile_checksum(UPFILE_TYPE_WHOLE, header->size, 2, 0)) {
printf("the whole images are same, no need to backup.\n");
vPortFree(buf);
return 0;
}
}
printf("start backup the whole image...\n");
rewrite:
#if DEVICE_TYPE_SELECT == EMMC_FLASH
emmc_read(sysinfo->image_offset, IMAGE_RW_SIZE, buf);
emmc_write(imageoff, IMAGE_RW_SIZE, buf);
#else
sfud_read(sflash, sysinfo->image_offset, IMAGE_RW_SIZE, buf);
sfud_erase_write(sflash, imageoff, IMAGE_RW_SIZE, buf);
#endif
imagesize = header->size;
leftsize = imagesize - IMAGE_RW_SIZE;
woff = imageoff + IMAGE_RW_SIZE;
roff = sysinfo->image_offset + IMAGE_RW_SIZE;
/* 如果串口单独升级过update.bin内某一种文件的话可能导致header->checksum并不是真实的校验和 */
header->checksum = 0;
imagechecksum = xcrc32(buf, IMAGE_RW_SIZE, 0xffffffff);
while (leftsize > 0) {
rwsize = leftsize > IMAGE_RW_SIZE ? IMAGE_RW_SIZE : leftsize;
#if DEVICE_TYPE_SELECT == EMMC_FLASH
emmc_read(roff, rwsize, buf);
emmc_write(woff, rwsize, buf);
#else
sfud_read(sflash, roff, rwsize, buf);
sfud_erase_write(sflash, woff, rwsize, buf);
#endif
leftsize -= rwsize;
roff += rwsize;
woff += rwsize;
imagechecksum = xcrc32(buf, rwsize, imagechecksum);
}
#if DEVICE_TYPE_SELECT == EMMC_FLASH
emmc_read(sysinfo->image_offset, IMAGE_RW_SIZE, buf);
header->checksum = imagechecksum;
emmc_write(imageoff, IMAGE_RW_SIZE, buf);
#else
sfud_read(sflash, sysinfo->image_offset, IMAGE_RW_SIZE, buf);
header->checksum = imagechecksum;
sfud_erase_write(sflash, imageoff, IMAGE_RW_SIZE, buf);
#endif
printf("checksum after backup...\n");
if (get_upfile_checksum(UPFILE_TYPE_WHOLE, imagesize, 1, 1) == imagechecksum) {
printf("backup the whole image ok.\n");
vPortFree(buf);
return 0;
} else if (retimes-- > 0) {
printf("checksum fail, retry...\n");
goto rewrite;
} else {
printf("backup the whole image fail.\n");
}
vPortFree(buf);
return -1;
}
/* 获取app, resource, rom升级文件单独升级时能支持的最大文件大小 */
static unsigned int get_subfile_maxsize(int filetype)
{
uint8_t buf[512];
UpFileHeader *header;
UpFileInfo *appfile;
SysInfo *sysinfo = GetSysInfo();
int i;
if (filetype < UPFILE_TYPE_RESOURCE || filetype > UPFILE_TYPE_APP)
return 0;
#if DEVICE_TYPE_SELECT == EMMC_FLASH
emmc_read(sysinfo->image_offset, 512, buf);
#else
sfud_flash *sflash = sfud_get_device(0);
sfud_read(sflash, sysinfo->image_offset, 512, buf);
#endif
header = (UpFileHeader *)buf;
if (header->magic != MKTAG('U', 'P', 'D', 'F'))
return 0;
for (i = 0; i < header->filenum; i++) {
appfile = &header->files[i];
if ((appfile->magic == UPFILE_APP_MAGIC && filetype == UPFILE_TYPE_APP) ||
(appfile->magic == MKTAG('R', 'O', 'M', 'A') && filetype == UPFILE_TYPE_RESOURCE) ||
(appfile->magic == MKTAG('B', 'A', 'N', 'I') && filetype == UPFILE_TYPE_ANIMATION)) {
if (i < header->filenum - 1) {
UpFileInfo *nextfile = &header->files[i + 1];
return nextfile->offset - appfile->offset;
} else {
return UPDATEFILE_MAX_SIZE - appfile->offset;
}
}
}
return 0;
}
int update_from_media(char *mpath, int filetype)
{
char update_file[32];
FF_FILE *fp;
size_t filesize;
uint8_t *buf;
size_t file_offset;
SysInfo *sysinfo = GetSysInfo();
sfud_flash *sflash = sfud_get_device(0);
int leftsize, rwoffset, rwsize;
int rlen;
uint32_t checksum;
SysInfo bak_sysinfo;
memcpy(&bak_sysinfo, sysinfo, sizeof(SysInfo));
strcpy(update_file, mpath);
strcat(update_file, "/");
strcat(update_file, g_upfilename[filetype]);
printf("%s checksum...\n", update_file);
if (!(checksum = get_mediafile_checksum(update_file, filetype, 1))) {
printf("checksum fail, don't update.\n");
return 0;
}
if (checksum == get_upfile_checksum(filetype, 0, 0, 0)) {
if (!(filetype == UPFILE_TYPE_WHOLE && sysinfo->app_checksum == 0)) {
printf("checksum is the same as now, don't update.\n");
return 0;
}
}
fp = ff_fopen(update_file, "rb");
if (!fp) {
printf("open %s fail.\n", update_file);
return -1;
}
filesize = ff_filelength(fp);
buf = pvPortMalloc(IMAGE_RW_SIZE);
if (!buf) {
printf("%s %d malloc %d bytes fail.\n", __FUNCTION__, __LINE__, IMAGE_RW_SIZE);
ff_fclose(fp);
return -1;
}
rlen = ff_fread(buf, 1, IMAGE_RW_SIZE, fp);
if (rlen <= 0) {
printf("read %s data fail.\n", update_file);
goto end;
}
if (filetype == UPFILE_TYPE_WHOLE) {
UpFileHeader *header = (UpFileHeader *)buf;
bak_sysinfo.app_checksum = header->checksum;
bak_sysinfo.app_size = header->files[0].size;
} else if (filetype == UPFILE_TYPE_APP) {
bak_sysinfo.app_size = filesize;
} else if (filetype == UPFILE_TYPE_FIRSTLDR) {
bak_sysinfo.loader_size = filesize;
} else if (filetype == UPFILE_TYPE_STEPLDR) {
bak_sysinfo.stepldr_size = filesize;
} else if (filetype == UPFILE_TYPE_LNCHEMMC) {
if (!sflash->init_ok)
sfud_init();
}
/* 这三种文件没有备份需要先备份整个update.bin镜像再升级备份区域 */
if (filetype >= UPFILE_TYPE_RESOURCE && filetype <= UPFILE_TYPE_APP) {
if (filesize > get_subfile_maxsize(filetype)) {
printf("Not have enough space to update subfile %s.\n", update_file);
goto end;
}
if (backup_whole_image()) {
printf("backup_whole_image fail.\n");
goto end;
}
if (sysinfo->image_offset == UPDATEFILE_MEDIA_OFFSET)
bak_sysinfo.image_offset = UPDATEFILE_MEDIA_B_OFFSET;
else
bak_sysinfo.image_offset = UPDATEFILE_MEDIA_OFFSET;
}
file_offset = get_upfile_offset(filetype, 1);
if (file_offset == 0xffffffff) {
printf("get_upfile_offset fail.\n");
goto end;
}
leftsize = filesize;
rwoffset = file_offset;
while (leftsize > 0) {
rwsize = leftsize > rlen ? rlen : leftsize;
#if DEVICE_TYPE_SELECT == EMMC_FLASH
if (filetype == UPFILE_TYPE_LNCHEMMC) {
if (sfud_erase_write(sflash, rwoffset, rwsize, buf) != SFUD_SUCCESS)
{
printf("burn %s data fail.\n", update_file);
goto end;
}
} else {
if (emmc_write(rwoffset, rwsize, buf))
#else
if (sfud_erase_write(sflash, rwoffset, rwsize, buf) != SFUD_SUCCESS)
#endif
{
printf("burn %s data fail.\n", update_file);
goto end;
}
#if DEVICE_TYPE_SELECT == EMMC_FLASH
}
#endif
rwoffset += rwsize;
leftsize -= rwsize;
printf("burn %d/%d.\n", filesize - leftsize, filesize);
rlen = ff_fread(buf, 1, IMAGE_RW_SIZE, fp);
if (rlen < 0) {
printf("read %s data fail.\n", update_file);
goto end;
}
}
printf("checksum after burn...\n");
if (checksum == get_upfile_checksum(filetype, filesize, 1, 1)) {
/* 升级这三个文件app_checksum后不准确不能再用来判断版本 */
if (filetype >= UPFILE_TYPE_RESOURCE && filetype <= UPFILE_TYPE_APP)
bak_sysinfo.app_checksum = 0;
set_upfile_offset(&bak_sysinfo, filetype, file_offset);
memcpy(sysinfo, &bak_sysinfo, sizeof(SysInfo));
SaveSysInfo();
ff_fclose(fp);
vPortFree(buf);
printf("burn %s ok.\n", update_file);
return 0;
} else {
printf("checksum after burn fail.\n");
}
end:
ff_fclose(fp);
vPortFree(buf);
return -1;
}
int save_file_to_ota(int filetype)
{
char update_file[32];
char ota_file[32];
FF_FILE *fp, *fota;
size_t filesize;
int leftsize;
uint8_t *buf = NULL;
size_t readlen;
strcpy(update_file,"/usb/");
strcat(update_file, g_upfilename[filetype]);
strcpy(ota_file, OTA_MOUNT_PATH "/");
strcat(ota_file, g_upfilename[filetype]);
if (get_mediafile_checksum(update_file, filetype, 0) ==
get_mediafile_checksum(ota_file, filetype, 0)) {
if (get_mediafile_checksum(ota_file, filetype, 1)) {
printf("%s is same with ota, not save.\n", g_upfilename[filetype]);
return 0;
}
}
fp = ff_fopen(update_file, "rb");
if (!fp) {
printf("open %s fail.\n", update_file);
return -1;
}
filesize = ff_filelength(fp);
fota = ff_fopen(ota_file, "wb");
if (!fota) {
printf("create %s in ota partition fail.\n", ota_file);
ff_fclose(fp);
return -1;
}
buf = pvPortMalloc(IMAGE_RW_SIZE);
if (!buf) {
printf("malloc IMAGE_RW_SIZE fail.\n");
ff_fclose(fota);
ff_fclose(fp);
return -1;
}
leftsize = filesize;
while (leftsize > 0) {
if (readlen = ff_fread(buf, 1, IMAGE_RW_SIZE, fp)) {
if (ff_fwrite(buf, 1, readlen, fota) != readlen) {
printf("write ota data fail.\n");
break;
} else {
printf("write ota data %d/%d.\n", filesize - leftsize + readlen, filesize);
}
} else {
break;
}
leftsize -= readlen;
}
ff_fclose(fota);
ff_fclose(fp);
vPortFree(buf);
if (leftsize == 0) {
printf("save file ok.\n");
return 0;
}
return -1;
}
#ifdef WIFI_UPDATE_SUPPORT
#define USB_DEV_PLUGED 0
#define USB_DEV_UNPLUGED 1
extern int usb_wait_stor_dev_pluged(uint32_t timeout);
extern void hub_usb_dev_reset(void);
/* 用从usb读取数据来模拟wifi接收升级数据真实的wifi接收升级文件
app适配 */
static void wifi_update_demo_thread(void *para)
{
#if DEVICE_TYPE_SELECT != EMMC_FLASH
FF_Disk_t *sfdisk = FF_SFDiskInit(SF_MOUNT_PATH);
if (sfdisk)
#endif
{
unsigned int status;
int filetype;
for (;;) {
status = usb_wait_stor_dev_pluged(portMAX_DELAY);
if (status == USB_DEV_PLUGED) {
printf("usb dev inserted.\n");
for (filetype = UPFILE_TYPE_WHOLE; filetype <= UPFILE_TYPE_LNCHEMMC; filetype++) {
if (save_file_to_ota(filetype)) {
printf("save_file_to_ota fail.\n");
} else {
printf("start to update from ota...\n");
update_from_media(OTA_MOUNT_PATH, filetype);
}
}
} else {
printf("usb removed.\n");
}
}
}
for (;;)
vTaskDelay(portMAX_DELAY);
}
void wifi_update_demo(void)
{
if (xTaskCreate(wifi_update_demo_thread, "wifiupdate", configMINIMAL_STACK_SIZE * 16, NULL,
1, NULL) != pdPASS) {
printf("create wifi update demo task fail.\n");
}
}
#endif
#endif