漫談LiteOS-Huawei_IoT_Link_SDK_OTA 開發指導


1概述

在應用升級過程中,無線下載更新(OTA)是一種常用,且方便的升級方式。Liteos采用的OTA升級方案基於LwM2M協議,實現了固件升級(FOTA)和軟件升級(SOTA)兩種升級方案。用戶可根據自己的開發環境選擇合適的升級方式。 OTA功能代碼結構如下圖:

2升級文件二進制文件結構

如圖所示,升級壓縮包中二進制文件如下圖所示,FOTA與SOTA采用相同的固件格式。

 

  •  簽名校驗值:長度256字節,對剩余文件進行hash計算后,並進行sha256加密后得到的簽名密文。

  •  二進制信息:預留長度32字節,升級文件是全量升級文件或增量升級文件等信息。

  •  升級文件內容:經壓縮后的升級文件,升級文件使用hdiffpatch算法對新、舊鏡像進行運算生成的差分包,並使用lzma算法進行壓縮。

3 存儲器接口

存儲器結構代碼位於iot_link/sotrage目錄下。存儲器結構被划分為兩部分,分別定義為存儲設備(storage.c)與設備分區(partition.c)。 存儲設備定義的是系統中使用的不同類型存儲器及接口,如內部flash,spi flash 或 nandflash等,所使用結構體如下:

typedef struct {
  int id;
  char *name;
  uint32_t size;
 
  void (*init)();
  int (*read)(void *buf, int32_t len, uint32_t offset);
  int (*write)(const uint8_t *buf, int32_t len, uint32_t offset);
  int (*erase)(uint32_t offset, int32_t len);
  int (*erase_write)(const void *buf, int32_t len, uint32_t offset);
}storage_device;

設備分區定義了用戶划分的分區信息,如下所示:

typedef struct _partition {
  uint8_t dev_id;
  char *name;
  uint32_t start_addr;
  uint32_t size;
}storage_partition;

設備分區定義了一組外部使用的接口,系統中可以使用這組接口進行相應的讀寫等操作。

int ota_storage_bin_read(int offset, void *buf, int len);
int ota_storage_bin_write(int offset, void *msg, int len);
int ota_storage_flag_read(ota_flag_t *flag);
int ota_storage_flag_write(ota_flag_t *flag);

4 OTA管理接口

系統中的OTA接口分為三個部分,OTA鏡像接口、OTA包管理接口,OTA簽名校驗接口。

4.1 OTA鏡像接口

OTA鏡像接口包括了OTA標志鏡像和OTA二進制鏡像。其中OTA標志存儲了升級版本號、升級文件大小、當前OTA狀態及OTA升級結果等信息,其結構如下:

#pragma pack(1)
typedef struct
{
    uint8_t  ver[CN_OTA_VERSION_LEN];
    uint32_t ver_code;
    uint32_t file_size;   ///< the new bin file size
    uint32_t blk_size;    ///< the new bin block size
    uint32_t blk_num;     ///< the new bin block num
    uint32_t blk_cur;
    uint32_t file_off;    ///< the current offet to write
    uint32_t cur_state;   ///< defined by en_ota_status_t
    uint32_t ret_upgrade; ///< the upgrade,filled by the loader
    uint32_t updater;     ///< fota or sota
    uint32_t crc;         ///< all the ota information computed
}ota_flag_t;
#pragma pack()

在loader和app中維護的同一份OTA標志,APP中會根據下載進度更改cur_state值,在loader中完成升級后會重置cur_state值並填充升級結果到ret_upgrade中,在進入app后將該結果上報至服務器。 外部可調用以下接口進行OTA鏡像讀寫操作:

int storage_partition_read(int part_id, uint8_t *buf, uint32_t len, uint32_t offset);
int storage_partition_write(int part_id, uint8_t *buf, uint32_t len, uint32_t offset);
int storage_partition_erase_write(int part_id, uint8_t *buf, uint32_t len, uint32_t offset);
int storage_partition_erase(int part_id, uint32_t offset, uint32_t len);

4.2 OTA包管理接口

ota_pack實現對接FOTA功能的接口封裝。該文件內實現了以下接口:

struct pack_storage_device_api_tag_s { 
    int (*write_software)(pack_storage_device_api_s *thi, uint32_t offset, const uint8_t *buffer, uint32_t len); 
    int (*write_software_end)(pack_storage_device_api_s *thi, pack_download_result_e result, uint32_t total_len); 
    int (*active_software)(pack_storage_device_api_s *thi); 
};

4.3 OTA簽名校驗接口

Ota_checksum實現了升級包簽名驗證接口。系統中可調用下面接口獲取簽名校驗結果:

int ota_pack_get_signature_verify_result(int sign_len, int file_len);

若用戶使用自己的公私鑰對,可在此處更改prv_public_key為對應的公鑰key值。

5 簽名驗證

OTA升級包簽名驗證在下載完成后,發送執行升級命令階段時執行。

收到執行命令后,系統首先將調用簽名校驗接口進行二進制文件簽名校驗,只有在驗簽通過后,才會執行后續的升級流程,否則會退出升級流程並上報升級失敗到服務器。

SOTA在接收到EN_PCP_MSG_EXCUTEUPDATE命令后,位於pcp.c文件中pcp_handle_msg函數。 FOTA流程的簽名校驗放在了ota_pack_man_software_write_end函數中。

6 Loader

進入Loader后會在ota_detection函數中讀取OTA標志,檢測當前OTA狀態。若為UPDATING狀態,則執行升級,否則跳轉至APP。

增量升級過程首先會讀取升級文件內容並解析出新、舊鏡像大小及所使用的壓縮插件等信息。

隨后調用以下接口:

hpatch_BOOL patch_decompress_with_cache(const hpatch_TStreamOutput* out_newData,
    const hpatch_TStreamInput*  oldData,const hpatch_TStreamInput*  compressedDiff,
    hpatch_TDecompress* decompressPlugin,TByte* temp_cache,TByte* temp_cache_end)

執行還原差分鏡像。 其中接口參數out_newData、oldData、compressedDiff,需要由用戶定義並實現對應的鏡像讀寫接口。

7 FOTA / SOTA

FOTA和SOTA都是基於LwM2M協議實現的升級方案,區別是基於不同的對象。

FOTA使用的是協議中定義的固件對象升級方案,基於對象5實現。

SOTA使用自定義對象19,並使用了PCP協議作為數據傳輸協議。因此,在使用SOTA時需要將config.mk中的CONFIG_PCP_ENABLE選項使能並使用oc_lwm2m_ota_demo。

8 編譯

實現OTA功能需要編譯Loader鏡像和App鏡像。需要對編譯選項進行修改:

  •  Loader和App鏡像大小定義在鏈接腳本中,當定義的鏡像空間不足以容納生成的鏡像時,需要適當的調整其大小。Loader和app的鏈接腳本分別是os_loader.ld和os_loader.ld,在其中更改MEMORY中的FLASH大小,即可調節對應鏡像空間。

  • 在Makefile文件中,將cfg_seperate_load_mode值改為yes,使編譯系統通過鏈接腳本構建目標文件。

  •   Config.mk中,需要修改以下值:

CONFIG_MQTT_ENABLE := n // config中默認使用的時mqtt,需將其關閉 
CONFIG_LWM2M_ENABLE := y // 使能lwm2m 
CONFIG_LWM2M_TYPE := "wakaama_raw" //選擇使用的lwm2m實現類型 
CONFIG_OC_LWM2M_ENABLE := y // 使能lwm2m的oc接口 
CONFIG_OC_LWM2M_TYPE := "atiny_lwm2m_raw" CONFIG_OTA_ENABLE := y 
CONFIG_PCP_ENABLE := y // 若使用SOTA,需使能該選項 
CONFIG_DEMO_TYPE := "oc_lwm2m_ota_demo" // 並使用該DEMO進行SOTA功能驗證
  • 編譯loader:在GCC目錄下的config.mk文件中,將CONFIG_LOADER_ENABLE和CONFIG_OTA_ENABLE的值改為y,進行loader鏡像編譯。

  • 編譯APP:在config.mk文件中,將CONFIG_LOADER_ENABLE值改為n,同時需要使能CONFIG_PCP_ENABLE和CONFIG_OTA_ENABLE選項,進行App鏡像編譯。

9 新平台適配

若用戶需要在新平台上使用OTA升級功能,需要完成以下工作:

  •  完成存儲器的定義。

用戶需定義所使用的存儲器類型接口及分區信息,並使用以下接口將其注冊到系統中:

int storage_dev_install(storage_device *dev, uint32_t max_num);
int storage_partition_init(storage_partition *part, int32_t max_num);
  •   完成OTA鏡像接口的定義。

用戶需定義ota_storage_t中flag鏡像與bin鏡像的讀寫接口,並通過下面接口進行注冊:

int ota_storage_install(const ota_storage_t *device);

對於FOTA系統,需要同時適配hal_get_ota_opt函數,填充並返回ota_opt_s的read_flash和write_flash接口。

  • 對於loader,需完成ota_detection函數,實現ota狀態檢查及鏡像的升級功能。

  • 在config.mk中定義CONFIG_LOADER_ENABLE值為y,進行Loader鏡像的編譯。將改值改為n,進行APP鏡像的編譯。

  • 在Makefile文件中將cfg_seperate_load_mode賦值為yes,以使用對應的鏈接腳本來構建對應的執行文件。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM