Optimize OTA information structure and flash_write function

This commit is contained in:
wgzAIIT
2023-04-23 16:33:22 +08:00
parent 6074b2b147
commit cfadebc3e8
4 changed files with 118 additions and 107 deletions
@@ -369,17 +369,35 @@ struct InitSequenceDesc _board_init[] =
#ifdef BSP_USING_OTA #ifdef BSP_USING_OTA
static void OtaCmd(void) static void OtaCmd(void)
{ {
int32_t Size; int32_t size;
ota_info_t ota_info;
FLASH_Init(); FLASH_Init();
UartConfig(); UartConfig();
UpdateOTAStatus(OTA_STATUS_DOWNLOADING);
Size = SerialDownload(DOWN_FLAH_ADDRESS); memcpy(&ota_info, (const void *)FLAG_FLAH_ADDRESS,sizeof(ota_info_t));
UpdateOTAStatus(OTA_STATUS_DOWNLOADED); ota_info.status = OTA_STATUS_DOWNLOADING;
if(Size > 0) UpdateOTAFlag(&ota_info);
size = SerialDownload(DOWN_FLAH_ADDRESS);
ota_info.status = OTA_STATUS_DOWNLOADED;
UpdateOTAFlag(&ota_info);
if(size > 0)
{ {
UpdateOTAFlag(Size, 0x11223344, OTA_STATUS_READY, "OTA Test!","No error!"); ota_info.down.size = size;
ota_info.down.crc32= calculate_crc32(DOWN_FLAH_ADDRESS, size);
ota_info.down.version = 0x11223344;
strncpy(ota_info.down.description, "OTA Test!",sizeof(ota_info.down.description));
ota_info.status = OTA_STATUS_READY;
strncpy(ota_info.error_message, "Download the firmware to the download partition successfully!",sizeof(ota_info.error_message));
UpdateOTAFlag(&ota_info);
} }
else
{
ota_info.status = OTA_STATUS_ERROR;
strncpy(ota_info.error_message, "Failed to download firmware to download partition!",sizeof(ota_info.error_message));
UpdateOTAFlag(&ota_info);
}
FLASH_DeInit(); FLASH_DeInit();
__set_FAULTMASK(1); __set_FAULTMASK(1);
@@ -437,4 +455,10 @@ void InitBoardHardware()
} }
KPrintf("board init done.\n"); KPrintf("board init done.\n");
KPrintf("start kernel...\n"); KPrintf("start kernel...\n");
#ifdef BSP_USING_OTA
FLASH_Init();
//跳转成功将对应跳转失败标志清零
FLASH_DeInit();
#endif
} }
@@ -684,7 +684,7 @@ status_t FLASH_Read(uint32_t addr, uint32_t *buf, uint32_t len)
* 功能描述: 擦除Flash指定长度的空间 * 功能描述: 擦除Flash指定长度的空间
* 形 参: addr:擦除区域起始地址 * 形 参: addr:擦除区域起始地址
byte_cnt:要擦除的字节数,以4k字节为最小擦除单位 byte_cnt:要擦除的字节数,以4k字节为最小擦除单位
* 返 回 值: None * 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码
* 注 释: 不满4k字节的,也需要擦除掉4k字节 * 注 释: 不满4k字节的,也需要擦除掉4k字节
*******************************************************************************/ *******************************************************************************/
status_t flash_erase(uint32_t start_addr, uint32_t byte_cnt) status_t flash_erase(uint32_t start_addr, uint32_t byte_cnt)
@@ -708,16 +708,30 @@ status_t flash_erase(uint32_t start_addr, uint32_t byte_cnt)
/******************************************************************************* /*******************************************************************************
* 函 数 名: flash_write * 函 数 名: flash_write
* 功能描述: 与FLASH_WritePage功能相同,写Flash一个页 * 功能描述: 在指定的flash起始地址写入指定长度的数据
* 形 参: addr:写入区域起始地址 * 形 参: addr:写入区域起始地址
buf:数据存储区 buf:数据存储区
len:要写入的字节数(最大256) byte_cnt:要写入的字节数
* 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码 * 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码
* 注 释: 在指定地址开始写入最大256字节的数据
*******************************************************************************/ *******************************************************************************/
status_t flash_write(uint32_t start_addr, uint8_t *buf, uint32_t byte_cnt) status_t flash_write(uint32_t start_addr, uint8_t *buf, uint32_t byte_cnt)
{ {
return FLASH_WritePage(start_addr, (void *)buf, byte_cnt); uint32_t size;
status_t status;
while(byte_cnt > 0)
{
size = byte_cnt > FLASH_PAGE_SIZE ? FLASH_PAGE_SIZE : byte_cnt;
status = FLASH_WritePage(start_addr, (void *)buf, size);
if(status != kStatus_Success)
{
return status;
}
start_addr += size;
buf += size;
byte_cnt -= size;
}
return kStatus_Success;
} }
@@ -100,7 +100,7 @@ static const uint32_t crc32tab[] = {
len:表示需要计算CRC32的数据长度 len:表示需要计算CRC32的数据长度
* 返 回 值: 计算得到的CRC32值 * 返 回 值: 计算得到的CRC32值
*******************************************************************************/ *******************************************************************************/
static uint32_t calculate_crc32(uint32_t addr, uint32_t len) uint32_t calculate_crc32(uint32_t addr, uint32_t len)
{ {
uint32_t crc = 0xFFFFFFFF; uint32_t crc = 0xFFFFFFFF;
uint8_t byte = 0xFF; uint8_t byte = 0xFF;
@@ -114,52 +114,26 @@ static uint32_t calculate_crc32(uint32_t addr, uint32_t len)
} }
/*******************************************************************************
* 函 数 名: UpdateOTAStatus
* 功能描述: 更新OTA的状态信息
* 形 参: status:将要更改的状态值
* 返 回 值: 无
*******************************************************************************/
void UpdateOTAStatus(ota_status_t status)
{
ota_info_t ota_info;
//从Flash中读取OTA信息
memcpy(&ota_info, (const void *)FLAG_FLAH_ADDRESS,sizeof(ota_info_t));
ota_info.status = status;
flash_erase(FLAG_FLAH_ADDRESS,sizeof(ota_info_t));
flash_write(FLAG_FLAH_ADDRESS,(void *)&ota_info,sizeof(ota_info_t));
}
/******************************************************************************* /*******************************************************************************
* 函 数 名: UpdateOTAFlag * 函 数 名: UpdateOTAFlag
* 功能描述: 更新OTA Flag区域的信息,版本完成下载后在app里进行调用 * 功能描述: 更新OTA Flag区域的信息,版本完成下载后在app里进行调用
* 形 参: app_size:新的固件的大小,单位字节 * 形 参: ptr:ota_info_t结构体指针,描述OTA升级相关信息
version:新的固件的版本 * 返 回 值: 如果函数执行成功,状态值为 kStatus_Success,否则状态值为其他错误码
status:OTA的状态信息
description:新版本的固件描述
error_message:更新过程中存储的错误信息
* 返 回 值: 无
*******************************************************************************/ *******************************************************************************/
void UpdateOTAFlag(uint32_t app_size, uint32_t version, uint32_t status, uint8_t* description, uint8_t* error_message) status_t UpdateOTAFlag(ota_info_t *ptr)
{ {
ota_info_t ota_info; // 定义OTA信息结构体 status_t status;
// 从Flash中读取OTA信息 status = flash_erase(FLAG_FLAH_ADDRESS,sizeof(ota_info_t));
memcpy(&ota_info, (const void *)FLAG_FLAH_ADDRESS,sizeof(ota_info_t)); if(status != kStatus_Success)
ota_info.app_size = app_size; {
ota_info.crc = calculate_crc32(DOWN_FLAH_ADDRESS, app_size); return status;
ota_info.version = version; }
strncpy(ota_info.description, description,sizeof(ota_info.description)); status = flash_write(FLAG_FLAH_ADDRESS,(void *)ptr,sizeof(ota_info_t));
ota_info.status = status;
strncpy(ota_info.error_message, error_message,sizeof(ota_info.error_message));
flash_erase(FLAG_FLAH_ADDRESS,sizeof(ota_info_t)); return status;
flash_write(FLAG_FLAH_ADDRESS,(void *)&ota_info,sizeof(ota_info_t));
} }
/******************************************************************************* /*******************************************************************************
* 函 数 名: UpdateApplication * 函 数 名: UpdateApplication
* 功能描述: 在bootloader里进行调用,根据Flash中Flag分区中的信息决定是否进行版本更新 * 功能描述: 在bootloader里进行调用,根据Flash中Flag分区中的信息决定是否进行版本更新
@@ -179,61 +153,44 @@ void UpdateApplication(void)
if(ota_info.status == OTA_STATUS_READY) if(ota_info.status == OTA_STATUS_READY)
{ {
Serial_PutString("\r\n------Start to update the app!------\r\n"); Serial_PutString("\r\n------Start to update the app!------\r\n");
// 校验固件CRC // 校验downlad分区固件CRC
if(calculate_crc32(DOWN_FLAH_ADDRESS, ota_info.app_size) == ota_info.crc) if(calculate_crc32(DOWN_FLAH_ADDRESS, ota_info.down.size) == ota_info.down.crc32)
{ {
// 如果CRC校验通过,开始升级,逐字节搬移 ota_info.status = OTA_STATUS_UPDATING;
UpdateOTAStatus(OTA_STATUS_UPDATING); UpdateOTAFlag(&ota_info);
status = flash_copy(XIUOS_FLAH_ADDRESS,BAKUP_FLAH_ADDRESS,ota_info.app_size);
if(status != kStatus_Success)
{
Serial_PutString("------Backup app failed!------\r\n");
goto finish;
}
status = flash_copy(DOWN_FLAH_ADDRESS,XIUOS_FLAH_ADDRESS,ota_info.app_size);
if(status != kStatus_Success)
{
Serial_PutString("------Firmware partition copy failed!------\r\n");
goto finish;
}
// 校验搬移后的固件CRC // 拷贝download分区到XiUOS System分区
if(calculate_crc32(XIUOS_FLAH_ADDRESS, ota_info.app_size) == ota_info.crc) status = flash_copy(DOWN_FLAH_ADDRESS, XIUOS_FLAH_ADDRESS, ota_info.down.size);
if((status == kStatus_Success) &&(calculate_crc32(XIUOS_FLAH_ADDRESS, ota_info.down.size) == ota_info.down.crc32))
{ {
ota_info.status = OTA_STATUS_IDLE; // 将OTA升级状态设置为IDLE Serial_PutString("\r\n------The download partition is copied successfully!------\r\n");
memset(ota_info.error_message,0,sizeof(ota_info.error_message)); // 清空错误信息
// 将更新后的OTA信息写入Flash中 ota_info.os.size = ota_info.down.size;
flash_erase(FLAG_FLAH_ADDRESS,sizeof(ota_info_t)); ota_info.os.crc32 = ota_info.down.crc32;
flash_write(FLAG_FLAH_ADDRESS,(void *)&ota_info,sizeof(ota_info_t)); ota_info.os.version = ota_info.down.version;
Serial_PutString("\r\n------Update completed!------\r\n"); strncpy(ota_info.os.description, ota_info.down.description, sizeof(ota_info.down.description));
goto finish; ota_info.status == OTA_STATUS_IDLE; // 拷贝download分区到XiUOS System分区成功,将OTA升级状态设置为IDLE
UpdateOTAFlag(&ota_info);
} }
else else
{ {
// 如果搬移后的固件CRC校验失败,升级失败 Serial_PutString("\r\n------The download partition copy failed!------\r\n");
ota_info.status = OTA_STATUS_ERROR; // 将OTA升级状态设置为ERROR ota_info.status = OTA_STATUS_ERROR;
memset(ota_info.error_message,0,sizeof(ota_info.error_message)); strncpy(ota_info.error_message, "The download partition copy failed!",sizeof(ota_info.error_message));
snprintf((char *)ota_info.error_message, sizeof(ota_info.error_message), "APP Firmware CRC check failed!"); // 记录错误信息 UpdateOTAFlag(&ota_info);
// 将更新后的OTA信息写入Flash中
flash_erase(FLAG_FLAH_ADDRESS,sizeof(ota_info_t));
flash_write(FLAG_FLAH_ADDRESS,(void *)&ota_info,sizeof(ota_info_t));
Serial_PutString("\r\n------APP Firmware CRC check failed!------\r\n");
goto finish; goto finish;
} }
Serial_PutString("\r\n------Update completed!------\r\n");
goto finish;
} }
else else
{ {
// 如果CRC校验失败,升级失败 // 如果download分区CRC校验失败,升级失败
ota_info.status = OTA_STATUS_ERROR; // 将OTA升级状态设置为ERROR
memset(ota_info.error_message,0,sizeof(ota_info.error_message));
snprintf((char *)ota_info.error_message, sizeof(ota_info.error_message), "Download Firmware CRC check failed"); // 记录错误信息
// 将更新后的OTA信息写入Flash中
flash_erase(FLAG_FLAH_ADDRESS,sizeof(ota_info_t));
flash_write(FLAG_FLAH_ADDRESS,(void *)&ota_info,sizeof(ota_info_t));
Serial_PutString("\r\n------Download Firmware CRC check failed!------\r\n"); Serial_PutString("\r\n------Download Firmware CRC check failed!------\r\n");
ota_info.status = OTA_STATUS_ERROR;
strncpy(ota_info.error_message, "Download Firmware CRC check failed!",sizeof(ota_info.error_message));
UpdateOTAFlag(&ota_info);
goto finish; goto finish;
} }
} }
@@ -26,27 +26,43 @@
#include "flash.h" #include "flash.h"
#include "ymodem.h" #include "ymodem.h"
/* OTA升级过程中的状态描述 */
typedef enum { typedef enum {
OTA_STATUS_IDLE = 0, // 空闲状态,没有进行OTA升级 OTA_STATUS_IDLE = 0, // 空闲状态,没有进行OTA升级
OTA_STATUS_READY, // 准备状态,可以进行OTA升级 OTA_STATUS_READY, // 准备状态,可以进行OTA升级
OTA_STATUS_DOWNLOADING, // 正在下载固件 OTA_STATUS_DOWNLOADING, // 正在下载固件
OTA_STATUS_DOWNLOADED, // 固件下载完成,可以进行升级 OTA_STATUS_DOWNLOADED, // 固件下载完成,可以进行升级
OTA_STATUS_UPDATING, // 正在进行OTA升级 OTA_STATUS_UPDATING, // 正在进行OTA升级
OTA_STATUS_ERROR, // 出现错误,升级失败 OTA_STATUS_ERROR, // 出现错误,升级失败
} ota_status_t; } ota_status_t;
/* Flash分区中保存固件的属性描述 */
typedef struct { typedef struct {
uint32_t app_size; // 应用程序大小 uint32_t size; // 应用程序大小,记录分区固件的大小
uint32_t crc; // 应用程序CRC校验 uint32_t crc32; // 应用程序CRC32校验值,记录分区固件的crc32
uint32_t version; // 应用程序版本号 uint32_t version; // 应用程序版本号,记录分区固件的版本号
uint32_t status; // 升级状态 uint32_t reserve; // 保留字段
uint8_t description[64]; // 应用程序升级说明,最多64个字符 uint8_t description[128]; // 固件的描述信息,最多128个字符
uint8_t error_message[64]; // 错误信息,最多64个字符 } firmware_t;
/* OTA升级过程中的信息结构体 */
typedef struct {
firmware_t os; // XiUOS System分区属性信息
firmware_t bak; // Bakup分区属性信息
firmware_t down; // Download分区属性信息
uint32_t status; // 升级状态,取值来自于ota_status_t类型
uint32_t initversion; // 恢复出厂设置的标志,0xFFFFFFFF代表未烧写过,烧写过以后设置为0x12345678
uint32_t jumpfailed; // bootloaer跳转失败的标志,bootloader里置0xabababab,跳转成功后置0x00000000
uint32_t reserve; // 保留字段
uint8_t error_message[128]; // 错误信息,最多128个字符
} ota_info_t; } ota_info_t;
void UpdateOTAStatus(ota_status_t status); uint32_t calculate_crc32(uint32_t addr, uint32_t len);
void UpdateOTAFlag(uint32_t app_size, uint32_t version, uint32_t status, uint8_t* description, uint8_t* error_message); status_t UpdateOTAFlag(ota_info_t *ptr);
void UpdateApplication(void); void UpdateApplication(void);
#endif #endif