FOTA Developer guide - XradioTech/XR871-OLD GitHub Wiki


目录


OTA Update Introduce

FOTA(Firmware Over The Air,空中固件升级,以下简称OTA)是从服务器上下载软件到本地,由本地完成软件版本的升级。SDK中的OTA方案通过对两个Image区域进行乒乓操作实现对固件的升级,两个Image区域如下图所示 OTA-image 两个Image区域大小相同,均为Image size。Image size应该大于或等于实际固件的大小。此外,Image区域应该与Flash可擦除块对齐。Image区域一的数据与实际固件数据相同,前Boot size大小的区域为Bootloader。Image区域二的前Boot size大小的区域为Boot config。Boot size之后区域的数据与实际固件数据相同(即Image区域二中没有Bootloader,对应位置为Boot config)。因此OTA升级时,Bootloader不变,始终加载Image区域一的Bootloader。Bootloader之后的数据将会在每次OTA升级成功后交替加载两个区域的固件数据。 系统启动时,加载Image区域一的Bootloader,Bootloader根据Boot config的记录,判断后续加载哪个Image区域的固件数据。 OTA升级固件时,系统根据Boot config的记录,判断本次更新哪个Image区域的固件。固件更新成功并校验通过后,更新Boot config,并重启系统。系统重启后会根据更新后的Boot config加载最新的固件数据。如果固件更新或校验失败,则不修改Boot config,系统下次启动仍然加载OTA升级前的固件数据。

  • Boot config 系统启动时,从Boot config获取加载哪个Image区域固件的信息。Boot config中主要存储结构体类型ota_cfg_t的数据,结构体类型ota_cfg_t的两个成员类型分别为ota_image_t和ota_state_t。上述3个类型数据在image.h中定义如下:

    typedef enum ota_image {
    	OTA_IMAGE_1ST = 1,
    	OTA_IMAGE_2ND = 2,
    } ota_image_t;
    
    typedef enum ota_state {
    	OTA_STATE_UNVERIFIED	= 0,
    	OTA_STATE_VERIFIED		= 1,
    } ota_state_t;
    
    typedef struct ota_cfg {
    	ota_image_t	image;
    	ota_state_t	state;
    } ota_cfg_t;
    
  • ota_image_t是Image区域的序号,OTA_IMAGE_1ST表示Image区域一,OTA_IMAGE_2ND表示Image区域二

  • ota_state_t是固件校验状态,OTA_STATE_UNVERIFIED表示固件校验失败,OTA_STATE_VERIFIED表示固件校验成功。

  • 从Boot config读取到ota_cfg_t类型数据后,其两个成员ota_image_t和ota_state_t的值组合如下:

  1. OTA_IMAGE_1ST和OTA_STATE_VERIFIED:最新已校验通过的固件位于Image区域一,则系统启动从Image区域一加载固件,OTA升级更新Image区域二的固件。
  2. OTA_IMAGE_1ST和OTA_STATE_UNVERIFIED:Image区域一的固件未校验通过,则系统启动从Image区域二加载固件,OTA升级更新Image区域一的固件。
  3. OTA_IMAGE_2ND和OTA_STATE_VERIFIED:最新已校验通过的固件位于Image区域二,则系统启动从Image区域二加载固件,OTA升级更新Image区域一的固件。
  4. OTA_IMAGE_2ND和OTA_STATE_UNVERIFIED:Image区域二的固件未校验通过,则系统启动从Image区域一加载固件,OTA升级更新Image区域二的固件。
  • OTA protocol OTA protocol表示OTA升级时下载固件的协议。 当前SDK中支持通过Http和File两种协议下载固件。 其在image.h中定义如下:

    typedef enum ota_protocol {
      OTA_PROTOCOL_FILE	= 0,
      OTA_PROTOCOL_HTTP	= 1,
    } ota_protocol_t;
    
  • OTA verify OTA verify表示对下载完固件的校验算法。为保证固件在OTA下载和烧写Flash过程中不出错,可采用CRC32、MD5、SHA1或SHA256算法对固件进行校验。

    typedef enum ota_verify {
      OTA_VERIFY_NONE		= 0,
      OTA_VERIFY_CRC32		= 1,
      OTA_VERIFY_MD5		= 2,
      OTA_VERIFY_SHA1		= 3,
      OTA_VERIFY_SHA256	= 4,
    } ota_verify_t;
    

API Detail

下面对OTA模块提供的接口进行简要说明:

  1. 初始化OTA模块。 输入参数param为初始化参数结构体指针,初始化参数可通过Image模块提供的接口image_get_ota_param()获得。 参数主要包括两个Image区域的位置、大小以及Bootloader区域大小等信息。 执行成功,返回OTA_STATUS_OK; 执行失败,返回OTA_STATUS_ERROR。

    ota_status_t ota_init(image_ota_param_t *param);
    
  2. 反初始化OTA模块。

    void ota_deinit(void);
    
  3. 读取Boot config信息,系统启动时和固件升级时根据Boot config信息选择Image区域。 输入参数为config的指针。 执行成功,返回OTA_STATUS_OK; 执行失败,返回OTA_STATUS_ERROR。

    ota_status_t ota_read_cfg(ota_cfg_t *cfg);
    
  4. 写入Boot config信息,完成对下载固件的校验后更新Boot config信息。 输入参数为config的指针。 执行成功,返回OTA_STATUS_OK; 执行失败,返回OTA_STATUS_ERROR。

    ota_status_t ota_write_cfg(ota_cfg_t *cfg);
    
  5. 通过指定协议下载固件。 输入参数protocol为所选择的下载固件的协议。 输入参数url为固件统一资源定位符。 下载成功,返回OTA_STATUS_OK; 下载失败,返回OTA_STATUS_ERROR。

    ota_status_t ota_get_image(ota_protocol_t protocol, void *url);
    
  6. 通过指定算法校验下载的固件,并根据校验结果更新Boot config信息。 即使不采用其他校验算法也应该调用该接口来更新Boot config信息(详情参见示例)。 输入参数verify为指定的校验算法。 输入参数value为正确固件通过指定校验算法得到的校验值。 执行成功(指函数执行成功,不等价于校验通过),返回OTA_STATUS_OK; 执行失败(指函数执行失败,不等价于校验不通过),返回OTA_STATUS_ERROR。

    ota_status_t ota_verify_image(ota_verify_t verify, uint32_t *value);
    
  7. 重启系统。

    void ota_reboot(void);
    

Usage Example

  • 系统启动 下面是系统启动时Bootloader中调用OTA模块接口的例子:
//初始化OTA模块,参数param通过接口image_get_ota_param()获得
ota_init(&param);

//读Boot config信息
if (ota_read_cfg(&cfg) != OTA_STATUS_OK) {
	……									//出错处理
}

//根据Boot config信息选择Image区域
if (((cfg.image == OTA_IMAGE_1ST) && (cfg.state == OTA_STATE_VERIFIED))
	|| ((cfg.image == OTA_IMAGE_2ND) && (cfg.state == OTA_STATE_UNVERIFIED))) {
	*image_seq = IMAGE_SEQ_1ST; 		//选择Image区域一
} else if (((cfg.image == OTA_IMAGE_2ND) && (cfg.state == OTA_STATE_VERIFIED))
		  ||((cfg.image == OTA_IMAGE_1ST) && (cfg.state == OTA_STATE_UNVERIFIED))) {
	*image_seq = IMAGE_SEQ_2ND; 		//选择Image区域二
} else {
	……									//出错处理
}
char url[] = "http://192.168.1.100/OTA/xr_system.img";

//通过Http协议下载固件
if (ota_get_image(OTA_PROTOCOL_HTTP, url) != OTA_STATUS_OK) {
	……						//出错处理
}

//校验固件,此处选择不进行其他校验算法校验,调用该接口将更新Boot config信息
if (ota_verify_image(OTA_VERIFY_NONE, NULL)  != OTA_STATUS_OK) {
	……						//出错处理
}

//重启系统
ota_reboot();
  • 协议扩展 OTA模块已提供Http和File两种协议下载固件,此外还支持扩展其他协议。扩展协议的方式为:
  1. 在文件ota.h中将扩展的协议补充到数据类型ota_protocol_t。

    typedef enum ota_protocol {
      OTA_PROTOCOL_FILE	= 0,
      OTA_PROTOCOL_HTTP	= 1,
      OTA_PROTOCOL_XXXX	= 2,
    } ota_protocol_t;
    
  2. 实现扩展协议下载固件的两个回调函数,回调函数类型在文件ota_i.h中定义如下。可参考Http协议和File协议对两个回调函数的实现(ota_http.h、ota_http.c、ota_file.h、ota_file.c)。

    typedef ota_status_t (*ota_update_init_t)(void *url);
    typedef ota_status_t (*ota_update_get_t)(uint8_t *buf, uint32_t buf_size,
      									uint32_t *recv_size, uint8_t *eof_flag);
    
  3. 将扩展协议的两个回调函数注册到文件ota.c的函数ota_get_image()中。

    case OTA_PROTOCOL_FILE:
      return ota_update_image(url, ota_update_file_init, ota_update_file_get);
    case OTA_PROTOCOL_HTTP:
      return ota_update_image(url, ota_update_http_init, ota_update_http_get);
    case OTA_PROTOCOL_XXXX:
      return ota_update_image(url, ota_update_xxxx_init, ota_update_xxxx_get);
    

XR871 OTA Reference Documents