Files
TencentOS-tiny/components/ota/recovery/ota_recovery.c
daishengdong 5b51d50ade add ota algorithm for device
1. effective "Differential Upgrade" patch algorithm with high compression rate
2. effective recovery algorithm support recovery firmware in blocks which has low memory consumption and wear-leveling strategies, especially suitable for embeded devices with low RAM.
3. add sample ota bootloader project, see:
board\TencentOS_tiny_EVB_MX_Plus\KEIL\ota\ota_bootloader_recovery
4. add sample application project for download firmware through http, see:
board\TencentOS_tiny_EVB_MX_Plus\KEIL\ota\ota_application_download_through_http
5. add sample application project for download firmware through qcloud explorer console, see:
board\TencentOS_tiny_EVB_MX_Plus\KEIL\ota\ota_application_download_through_qcloud_iot_explorer
6. an OTA markdown document is pending
2020-06-02 15:03:42 +08:00

194 lines
5.4 KiB
C

/*----------------------------------------------------------------------------
* Tencent is pleased to support the open source community by making TencentOS
* available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* If you have downloaded a copy of the TencentOS binary from Tencent, please
* note that the TencentOS binary is licensed under the BSD 3-Clause License.
*
* If you have downloaded a copy of the TencentOS source code from Tencent,
* please note that TencentOS source code is licensed under the BSD 3-Clause
* License, except for the third-party components listed below which are
* subject to different license terms. Your integration of TencentOS into your
* own projects may require compliance with the BSD 3-Clause License, as well
* as the other licenses applicable to the third-party components included
* within TencentOS.
*---------------------------------------------------------------------------*/
#include "tos_k.h"
#include "tos_kv.h"
#include "crc8.h"
#include "ota_flash.h"
#include "ota_partition.h"
#include "ota_image.h"
#include "ota_info.h"
#include "ota_env.h"
#include "lzma_uncompress.h"
#include "ota_recovery.h"
#define MIN(a, b) ((a) < (b) ? (a) : (b))
static int patch_verify(ota_img_hdr_t *img_hdr)
{
#define BUF_SIZE 128
static uint8_t buf[BUF_SIZE];
uint8_t crc = 0;
ota_img_vs_t new_version;
ota_img_vs_t cur_version;
size_t version_len, remain_len, read_len;
uint32_t active_app_start = ota_partition_start(OTA_PARTITION_ACTIVE_APP);
uint32_t patch_start = ota_partition_start(OTA_PARTITION_OTA);
/* drag the ota_img_hdr out of the flash */
if (ota_flash_read(patch_start, img_hdr, sizeof(ota_img_hdr_t)) < 0) {
return -1;
}
/* 1. check whether new version patch downloaded */
if (tos_kv_get("new_version", &new_version, sizeof(ota_img_vs_t), &version_len) != KV_ERR_NONE) {
return -1;
}
if (new_version.major != img_hdr->new_version.major ||
new_version.minor != img_hdr->new_version.minor) {
return -1;
}
/* 2. verify magic */
if (img_hdr->magic != OTA_IMAGE_MAGIC) {
return -1;
}
/* 3. is this patch for current version? */
cur_version = ota_info_curr_version();
if (cur_version.major != img_hdr->old_version.major ||
cur_version.minor != img_hdr->old_version.minor) {
return -1;
}
/* 4. verify the patch crc checksum */
remain_len = img_hdr->patch_size;
crc = ota_img_hdr_crc(img_hdr);
patch_start += sizeof(ota_img_hdr_t);
while (remain_len > 0) {
read_len = MIN(sizeof(buf), remain_len);
if (ota_flash_read(patch_start, buf, read_len) < 0) {
return -1;
}
crc = crc8(crc, buf, read_len);
remain_len -= read_len;
patch_start += read_len;
}
if (crc != img_hdr->patch_crc) {
return -1;
}
/* 5. verify the old crc checksum */
remain_len = img_hdr->old_size;
crc = 0;
while (remain_len > 0) {
read_len = MIN(sizeof(buf), remain_len);
if (ota_flash_read(active_app_start, buf, read_len) < 0) {
return -1;
}
crc = crc8(crc, buf, read_len);
remain_len -= read_len;
active_app_start += read_len;
}
if (crc != img_hdr->old_crc) {
return -1;
}
return 0;
}
static int do_recovery(ota_img_hdr_t *hdr)
{
uint32_t patch = ota_partition_start(OTA_PARTITION_OTA) + sizeof(ota_img_hdr_t);
return ota_patch(patch, hdr->patch_size - sizeof(ota_img_hdr_t), hdr->patch_size);
}
static int app_copy(uint32_t dst, uint32_t dst_size, uint32_t src, uint32_t src_size)
{
#define BUF_SIZE 128
static uint8_t buf[BUF_SIZE];
size_t read_len = 0;
size_t remain_len = src_size;
uint32_t r_addr = src, w_addr = dst;
if (src_size != dst_size) {
return -1;
}
/* make flash ready */
if (ota_flash_erase_blocks(dst, dst_size) < 0) {
return -1;
}
while (remain_len > 0) {
read_len = MIN(sizeof(buf), remain_len);
if (ota_flash_read(r_addr, buf, read_len) < 0) {
return -1;
}
if (ota_flash_write(w_addr, (void *)buf, ota_flash_write_size_aligned_get(read_len)) < 0) {
return -1;
}
w_addr += read_len;
r_addr += read_len;
remain_len -= read_len;
}
return 0;
}
int ota_recovery(void)
{
ota_img_hdr_t img_hdr;
if (patch_verify(&img_hdr)) {
return -1;
}
/* backup */
if (ota_partition_is_pingpong() &&
app_copy(ota_partition_start(OTA_PARTITION_BACKUP_APP),
ota_partition_size(OTA_PARTITION_BACKUP_APP),
ota_partition_start(OTA_PARTITION_ACTIVE_APP),
ota_partition_size(OTA_PARTITION_ACTIVE_APP)) < 0) {
return -1;
}
if (do_recovery(&img_hdr) != 0) {
printf("recovery failed\n");
/* restore */
if (ota_partition_is_pingpong()) {
app_copy(ota_partition_start(OTA_PARTITION_ACTIVE_APP),
ota_partition_size(OTA_PARTITION_ACTIVE_APP),
ota_partition_start(OTA_PARTITION_BACKUP_APP),
ota_partition_size(OTA_PARTITION_BACKUP_APP));
}
return -1;
}
if (ota_info_update(img_hdr.new_version) != 0) {
return -1;
}
return 0;
}