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
This commit is contained in:
55
components/ota/tools/diff/Makefile
Normal file
55
components/ota/tools/diff/Makefile
Normal file
@@ -0,0 +1,55 @@
|
||||
TARGET ?= diff
|
||||
|
||||
CC := gcc
|
||||
LD := ld
|
||||
|
||||
OUT_ROOT := out
|
||||
OBJ_DIR := obj
|
||||
LIB_DIR := lib
|
||||
TARGET_DIR := target
|
||||
OUT_DIR := $(OUT_ROOT)/$(OBJ_DIR) $(OUT_ROOT)/$(LIB_DIR) $(OUT_ROOT)/$(TARGET_DIR)
|
||||
|
||||
NOECHO := @
|
||||
|
||||
INCDIRS := \
|
||||
../../common/image \
|
||||
../../common/lzma/3rdparty \
|
||||
../../common/lzma/wrapper \
|
||||
../../common/crc \
|
||||
../../common/diff
|
||||
|
||||
SRCDIRS := \
|
||||
../../common/image \
|
||||
../../common/lzma/3rdparty \
|
||||
../../common/lzma/wrapper \
|
||||
../../common/crc \
|
||||
../../common/diff \
|
||||
src
|
||||
|
||||
INCLUDE := $(patsubst %, -I %, $(INCDIRS))
|
||||
|
||||
CFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))
|
||||
|
||||
CFILENDIR := $(notdir $(CFILES))
|
||||
|
||||
COBJS := $(patsubst %, $(OUT_ROOT)/$(OBJ_DIR)/%, $(CFILENDIR:.c=.o))
|
||||
OBJS := $(COBJS)
|
||||
|
||||
VPATH := $(SRCDIRS)
|
||||
|
||||
.PHONY: clean $(OUT_DIR)
|
||||
|
||||
$(TARGET): $(OUT_DIR) $(OBJS)
|
||||
@echo "LD $(TARGET)"
|
||||
$(NOECHO)$(CC) -o $(OUT_ROOT)/$(TARGET_DIR)/$(TARGET) $(OBJS)
|
||||
|
||||
$(OUT_DIR) :
|
||||
@mkdir -p $@
|
||||
|
||||
$(COBJS) : $(OUT_ROOT)/$(OBJ_DIR)/%.o : %.c
|
||||
@echo "CC $(notdir $<)"
|
||||
$(NOECHO)$(CC) -Wall -c -O2 $(INCLUDE) -o $@ $<
|
||||
|
||||
clean:
|
||||
@rm -rf $(OUT_ROOT)
|
||||
|
308
components/ota/tools/diff/src/main.c
Normal file
308
components/ota/tools/diff/src/main.c
Normal file
@@ -0,0 +1,308 @@
|
||||
#include "stdio.h"
|
||||
#include "stdint.h"
|
||||
#include "stdlib.h"
|
||||
#include "stdarg.h"
|
||||
#include "string.h"
|
||||
|
||||
#include "unistd.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "crc8.h"
|
||||
#include "ota_diff.h"
|
||||
#include "lzma_compress.h"
|
||||
#include "ota_image.h"
|
||||
|
||||
#define ERROR(msg) \
|
||||
printf("ERROR: line number[%d], function[%s] msg[%s]\n", __LINE__, __FUNCTION__, msg); \
|
||||
rc = -1; \
|
||||
goto OUT;
|
||||
|
||||
typedef struct args_param_st {
|
||||
int is_verbose;
|
||||
int is_safe_ignored;
|
||||
} args_param_t;
|
||||
|
||||
typedef struct diff_param_st {
|
||||
uint16_t block_len;
|
||||
ota_img_vs_t new_version;
|
||||
ota_img_vs_t old_version;
|
||||
} diff_param_t;
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: diff [-h] [-v] [-s] -b block_len -n new_version -o old_version old_image new_image patch_image\n"
|
||||
" -h help\n"
|
||||
" -v more information\n"
|
||||
" -s ingnore the safe block\n"
|
||||
" -b set block size\n"
|
||||
" -n version of new_image. format: two number separated by dot, {version_major.version_minor}\n"
|
||||
" -o version of old_image. format: two number separated by dot, {version_major.version_minor}\n"
|
||||
);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
static void panic(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
static char buffer[128];
|
||||
|
||||
va_start(args, format);
|
||||
vsnprintf(buffer, sizeof(buffer), format, args);
|
||||
va_end(args);
|
||||
|
||||
fprintf(stderr, buffer);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
static int str2int(char *p)
|
||||
{
|
||||
long int v;
|
||||
v = strtoll(p, &p, 0);
|
||||
switch (*p) {
|
||||
case 0:
|
||||
if (v < -(1 << 30)) {
|
||||
v = -(1 << 30);
|
||||
}
|
||||
if (v > (1 << 30)) {
|
||||
v = (1 << 30);
|
||||
}
|
||||
break;
|
||||
case 'k':
|
||||
case 'K':
|
||||
if (v < -(1 << 20)) {
|
||||
v = -(1 << 20);
|
||||
}
|
||||
if (v > (1 << 20)) {
|
||||
v = (1 << 20);
|
||||
}
|
||||
v *= 1024;
|
||||
break;
|
||||
case 'm':
|
||||
case 'M':
|
||||
if (v < -(1 << 10)) {
|
||||
v = -(1 << 10);
|
||||
}
|
||||
if (v > (1 << 10)) {
|
||||
v = (1 << 10);
|
||||
}
|
||||
v *= 1024 * 1024;
|
||||
break;
|
||||
case 'g':
|
||||
case 'G':
|
||||
if (v < -1) {
|
||||
v = -1;
|
||||
}
|
||||
if (v > 1) {
|
||||
v = 1;
|
||||
}
|
||||
v *= 1024 * 1024 * 1024;
|
||||
break;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
static void process_command_line(int argc, char **argv, diff_param_t *param, args_param_t *args_param)
|
||||
{
|
||||
int c, v;
|
||||
uint32_t version_major, version_minor;
|
||||
|
||||
param->block_len = 0;
|
||||
|
||||
while ((c = getopt(argc, argv, "vhb:n:o:")) != -1) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
usage();
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
args_param->is_verbose = 1;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
args_param->is_safe_ignored = 1;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
v = str2int(optarg);
|
||||
if (v < 64 || v > (1 << 20) || (v & (v - 1))) {
|
||||
panic("invalid block_len %s\n", optarg);
|
||||
}
|
||||
param->block_len = v;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
if (sscanf(optarg, "%u.%u", &version_major, &version_minor) < 2) {
|
||||
panic("invalid new_version format %s\n", optarg);
|
||||
}
|
||||
|
||||
if (version_major > (uint8_t)-1 || version_minor > (uint8_t)-1) {
|
||||
panic("invalid version number: %d %d\n", version_major, version_minor);
|
||||
}
|
||||
|
||||
param->new_version.major = version_major;
|
||||
param->new_version.minor = version_minor;
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
if (sscanf(optarg, "%u.%u", &version_major, &version_minor) < 2) {
|
||||
panic("invalid new_version format %s\n", optarg);
|
||||
}
|
||||
|
||||
if (version_major > (uint8_t)-1 || version_minor > (uint8_t)-1) {
|
||||
panic("invalid version number: %d %d\n", version_major, version_minor);
|
||||
}
|
||||
|
||||
param->old_version.major = version_major;
|
||||
param->old_version.minor = version_minor;
|
||||
break;
|
||||
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t img_crc(uint8_t *img, size_t img_size, ota_img_hdr_t *img_hdr)
|
||||
{
|
||||
uint8_t crc = 0;
|
||||
|
||||
crc = crc8(crc, (uint8_t *)&img_hdr->magic, sizeof(uint16_t));
|
||||
crc = crc8(crc, (uint8_t *)&img_hdr->new_version, sizeof(ota_img_vs_t));
|
||||
crc = crc8(crc, (uint8_t *)&img_hdr->old_version, sizeof(ota_img_vs_t));
|
||||
|
||||
crc = crc8(crc, (uint8_t *)&img_hdr->new_crc, sizeof(uint8_t));
|
||||
crc = crc8(crc, (uint8_t *)&img_hdr->new_size, sizeof(uint32_t));
|
||||
|
||||
crc = crc8(crc, (uint8_t *)&img_hdr->old_crc, sizeof(uint8_t));
|
||||
crc = crc8(crc, (uint8_t *)&img_hdr->old_size, sizeof(uint32_t));
|
||||
|
||||
crc = crc8(crc, (uint8_t *)&img_hdr->patch_size, sizeof(uint32_t));
|
||||
crc = crc8(crc, img, img_size);
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
int make_patch(uint8_t *new, size_t new_size,
|
||||
uint8_t *old, size_t old_size,
|
||||
diff_param_t *diff_param,
|
||||
args_param_t *args_param,
|
||||
FILE *patch_file)
|
||||
{
|
||||
int rc = 0;
|
||||
ota_img_hdr_t img_hdr;
|
||||
uint8_t *patch = NULL;
|
||||
size_t patch_size;
|
||||
|
||||
if (ota_diff(old, old_size, new, new_size, diff_param->block_len, args_param->is_safe_ignored, args_param->is_verbose, &patch, &patch_size) != 0) {
|
||||
ERROR("ota_diff failed\n");
|
||||
}
|
||||
|
||||
img_hdr.magic = OTA_IMAGE_MAGIC;
|
||||
img_hdr.new_version = diff_param->new_version;
|
||||
img_hdr.old_version = diff_param->old_version;
|
||||
|
||||
img_hdr.new_size = new_size;
|
||||
img_hdr.new_crc = crc8(0, new, new_size);
|
||||
|
||||
img_hdr.old_size = old_size;
|
||||
img_hdr.old_crc = crc8(0, old, old_size);
|
||||
|
||||
img_hdr.patch_size = patch_size;
|
||||
img_hdr.patch_crc = img_crc(patch, patch_size, &img_hdr);
|
||||
|
||||
if (fwrite(&img_hdr, 1, sizeof(ota_img_hdr_t), patch_file) != sizeof(ota_img_hdr_t)) {
|
||||
ERROR("write header failed\n");
|
||||
}
|
||||
|
||||
if (fwrite(patch, 1, patch_size, patch_file) != patch_size) {
|
||||
ERROR("write patch failed\n");
|
||||
}
|
||||
|
||||
OUT:
|
||||
if (patch) {
|
||||
free(patch);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
size_t new_size, old_size;
|
||||
uint8_t *new = NULL, *old = NULL;
|
||||
char *new_path, *old_path, *patch_path;
|
||||
args_param_t args_param = { 0 };
|
||||
diff_param_t diff_param = { 0 };
|
||||
|
||||
memset(&args_param, 0, sizeof(args_param_t));
|
||||
memset(&diff_param, 0, sizeof(diff_param_t));
|
||||
|
||||
process_command_line(argc, argv, &diff_param, &args_param);
|
||||
|
||||
if (optind + 3 != argc) {
|
||||
usage();
|
||||
}
|
||||
|
||||
old_path = argv[optind];
|
||||
new_path = argv[optind + 1];
|
||||
patch_path = argv[optind + 2];
|
||||
|
||||
if (((fp = fopen(new_path, "rb")) == NULL) ||
|
||||
(fseek(fp, 0, SEEK_END) == -1) ||
|
||||
((new_size = ftell(fp)) == -1) ||
|
||||
((new = malloc(new_size + 1)) == NULL) ||
|
||||
(fseek(fp, 0, SEEK_SET) != 0) ||
|
||||
(fread(new, 1, new_size, fp) != new_size) ||
|
||||
(fclose(fp) == -1)) {
|
||||
printf("failed to open: %s\n", new_path);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (((fp = fopen(old_path, "rb")) == NULL) ||
|
||||
(fseek(fp, 0, SEEK_END) == -1) ||
|
||||
((old_size = ftell(fp)) == -1) ||
|
||||
((old = malloc(old_size + 1)) == NULL) ||
|
||||
(fseek(fp, 0, SEEK_SET) != 0) ||
|
||||
(fread(old, 1, old_size, fp) != old_size) ||
|
||||
(fclose(fp) == -1)) {
|
||||
printf("failed to open: %s\n", old_path);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Create the patch file */
|
||||
if ((fp = fopen(patch_path, "wb")) == NULL) {
|
||||
printf("failed to open: %s\n", patch_path);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (make_patch(new, new_size,
|
||||
old, old_size,
|
||||
&diff_param,
|
||||
&args_param,
|
||||
fp) != 0) {
|
||||
printf("make patch failed\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
errout:
|
||||
if (fp) {
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
if (new) {
|
||||
free(new);
|
||||
}
|
||||
|
||||
if (old) {
|
||||
free(old);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
50
components/ota/tools/partition_table/Makefile
Normal file
50
components/ota/tools/partition_table/Makefile
Normal file
@@ -0,0 +1,50 @@
|
||||
TARGET ?= ptbl
|
||||
|
||||
CC := gcc
|
||||
LD := ld
|
||||
|
||||
OUT_ROOT := out
|
||||
OBJ_DIR := obj
|
||||
LIB_DIR := lib
|
||||
TARGET_DIR := target
|
||||
OUT_DIR := $(OUT_ROOT)/$(OBJ_DIR) $(OUT_ROOT)/$(LIB_DIR) $(OUT_ROOT)/$(TARGET_DIR)
|
||||
|
||||
NOECHO := @
|
||||
|
||||
INCDIRS := \
|
||||
../../common/image \
|
||||
../../common/crc \
|
||||
../../common/partition
|
||||
|
||||
SRCDIRS := \
|
||||
../../common/image \
|
||||
../../common/crc \
|
||||
src
|
||||
|
||||
INCLUDE := $(patsubst %, -I %, $(INCDIRS))
|
||||
|
||||
CFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))
|
||||
|
||||
CFILENDIR := $(notdir $(CFILES))
|
||||
|
||||
COBJS := $(patsubst %, $(OUT_ROOT)/$(OBJ_DIR)/%, $(CFILENDIR:.c=.o))
|
||||
OBJS := $(COBJS)
|
||||
|
||||
VPATH := $(SRCDIRS)
|
||||
|
||||
.PHONY: clean $(OUT_DIR)
|
||||
|
||||
$(TARGET): $(OUT_DIR) $(OBJS)
|
||||
@echo "LD $(TARGET)"
|
||||
$(NOECHO)$(CC) -o $(OUT_ROOT)/$(TARGET_DIR)/$(TARGET) $(OBJS)
|
||||
|
||||
$(OUT_DIR) :
|
||||
@mkdir -p $@
|
||||
|
||||
$(COBJS) : $(OUT_ROOT)/$(OBJ_DIR)/%.o : %.c
|
||||
@echo "CC $(notdir $<)"
|
||||
$(NOECHO)$(CC) -Wall -c -O2 $(INCLUDE) -o $@ $<
|
||||
|
||||
clean:
|
||||
@rm -rf $(OUT_ROOT)
|
||||
|
254
components/ota/tools/partition_table/src/main.c
Normal file
254
components/ota/tools/partition_table/src/main.c
Normal file
@@ -0,0 +1,254 @@
|
||||
#include "stdio.h"
|
||||
#include "stdint.h"
|
||||
#include "stdlib.h"
|
||||
#include "stdarg.h"
|
||||
#include "string.h"
|
||||
|
||||
#include "unistd.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "crc8.h"
|
||||
#include "ota_partition.h"
|
||||
|
||||
typedef struct partition_param_st {
|
||||
ota_updt_type_t updt_type;
|
||||
|
||||
ota_img_vs_t version;
|
||||
ota_pts_t pts;
|
||||
} partition_param_t;
|
||||
|
||||
static int partitions_verify(ota_pt_t *pts, int n)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (pts[i].start == 0 || pts[i].start == (uint32_t)-1 ||
|
||||
pts[i].end == 0 || pts[i].end == (uint32_t)-1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pts[i].start >= pts[i].end) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: ptbl [-h] -p option -a active_app_pt [-b backup_app_pt] -o ota_pt -k kv_pt -v version pt_tbl_image\n"
|
||||
" -h help\n"
|
||||
" -p option[ip or pp]\n"
|
||||
" if option is ip, using in-position update stragety\n"
|
||||
" in this situation, MUST no backup_app_pt is supplied\n"
|
||||
" if option is pp, using ping-pong update stragety\n"
|
||||
" in this situation, MUST ONE backup_app_pt is supplied\n"
|
||||
" -a active application partition, format: pt_start,pt_end\n"
|
||||
" -b backup application partition, format: pt_start,pt_end\n"
|
||||
" -o ota partition, format: pt_start,pt_end\n"
|
||||
" -k kv partition, format pt_start,pt_end\n"
|
||||
" -v version of the initial application, format: two number separated by dot\n"
|
||||
);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
static void panic(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
static char buffer[128];
|
||||
|
||||
va_start(args, format);
|
||||
vsnprintf(buffer, sizeof(buffer), format, args);
|
||||
va_end(args);
|
||||
|
||||
fprintf(stderr, buffer);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
static void process_command_line(int argc, char **argv, partition_param_t *param)
|
||||
{
|
||||
int c;
|
||||
uint32_t start, end;
|
||||
uint32_t version_major, version_minor;
|
||||
|
||||
while ((c = getopt(argc, argv, "hp:a:b:o:k:v:")) != -1) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
usage();
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
if (strncmp("ip", optarg, 2) == 0) {
|
||||
param->updt_type = OTA_UPDATE_IN_POSITION;
|
||||
} else if (strncmp("pp", optarg, 2) == 0) {
|
||||
param->updt_type = OTA_UPDATE_PING_PONG;
|
||||
} else {
|
||||
usage();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
if (sscanf(optarg, "%x,%x", &start, &end) < 2) {
|
||||
panic("invalid partition %s\n", optarg);
|
||||
}
|
||||
|
||||
if (param->updt_type == OTA_UPDATE_IN_POSITION) {
|
||||
param->pts.ip.ip_pts.active_app.start = start;
|
||||
param->pts.ip.ip_pts.active_app.end = end;
|
||||
} else if (param->updt_type == OTA_UPDATE_PING_PONG) {
|
||||
param->pts.pp.pp_pts.active_app.start = start;
|
||||
param->pts.pp.pp_pts.active_app.end = end;
|
||||
} else {
|
||||
usage();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
if (sscanf(optarg, "%x,%x", &start, &end) < 2) {
|
||||
panic("invalid partition %s\n", optarg);
|
||||
}
|
||||
|
||||
if (param->updt_type == OTA_UPDATE_PING_PONG) {
|
||||
param->pts.pp.pp_pts.backup_app.start = start;
|
||||
param->pts.pp.pp_pts.backup_app.end = end;
|
||||
} else {
|
||||
usage();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
if (sscanf(optarg, "%x,%x", &start, &end) < 2) {
|
||||
panic("invalid partition %s\n", optarg);
|
||||
}
|
||||
|
||||
if (param->updt_type == OTA_UPDATE_IN_POSITION) {
|
||||
param->pts.ip.ip_pts.ota.start = start;
|
||||
param->pts.ip.ip_pts.ota.end = end;
|
||||
} else if (param->updt_type == OTA_UPDATE_PING_PONG) {
|
||||
param->pts.pp.pp_pts.ota.start = start;
|
||||
param->pts.pp.pp_pts.ota.end = end;
|
||||
} else {
|
||||
usage();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
if (sscanf(optarg, "%x,%x", &start, &end) < 2) {
|
||||
panic("invalid partition %s\n", optarg);
|
||||
}
|
||||
|
||||
if (param->updt_type == OTA_UPDATE_IN_POSITION) {
|
||||
param->pts.ip.ip_pts.kv.start = start;
|
||||
param->pts.ip.ip_pts.kv.end = end;
|
||||
} else if (param->updt_type == OTA_UPDATE_PING_PONG) {
|
||||
param->pts.pp.pp_pts.kv.start = start;
|
||||
param->pts.pp.pp_pts.kv.end = end;
|
||||
} else {
|
||||
usage();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
if (sscanf(optarg, "%u.%u", &version_major, &version_minor) < 2) {
|
||||
panic("invalid version format %s\n", optarg);
|
||||
}
|
||||
|
||||
if (version_major > (uint8_t)-1 || version_minor > (uint8_t)-1) {
|
||||
panic("invalid version number: %d %d\n", version_major, version_minor);
|
||||
}
|
||||
|
||||
param->version.major = version_major;
|
||||
param->version.minor = version_minor;
|
||||
break;
|
||||
|
||||
default:
|
||||
usage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void write_partition(partition_param_t *param, FILE *fp)
|
||||
{
|
||||
uint8_t crc = 0;
|
||||
ota_pt_hdr_t hdr;
|
||||
|
||||
hdr.magic = OTA_PARTITION_MAGIC;
|
||||
hdr.version = param->version;
|
||||
|
||||
crc = partition_hdr_crc(&hdr);
|
||||
|
||||
if (param->updt_type == OTA_UPDATE_IN_POSITION) {
|
||||
if (partitions_verify(¶m->pts.ip.pts[0], sizeof(param->pts.ip.pts) / sizeof(ota_pt_t)) != 0) {
|
||||
panic("invalid partitions\n");
|
||||
}
|
||||
|
||||
crc = partitions_crc(crc, ¶m->pts.ip.pts[0], sizeof(param->pts.ip.pts) / sizeof(ota_pt_t));
|
||||
} else if (param->updt_type == OTA_UPDATE_PING_PONG) {
|
||||
if (partitions_verify(¶m->pts.pp.pts[0], sizeof(param->pts.pp.pts) / sizeof(ota_pt_t)) != 0) {
|
||||
panic("invalid partitions\n");
|
||||
}
|
||||
|
||||
crc = partitions_crc(crc, ¶m->pts.pp.pts[0], sizeof(param->pts.pp.pts) / sizeof(ota_pt_t));
|
||||
} else {
|
||||
panic("invalid partitions\n");
|
||||
}
|
||||
|
||||
hdr.crc = crc;
|
||||
|
||||
if (fwrite(&hdr, 1, sizeof(ota_pt_hdr_t), fp) != sizeof(ota_pt_hdr_t)) {
|
||||
fclose(fp);
|
||||
panic("failed to write partition header\n");
|
||||
}
|
||||
|
||||
if (param->updt_type == OTA_UPDATE_IN_POSITION) {
|
||||
if (fwrite(¶m->pts.ip.pts[0], 1, sizeof(param->pts.ip.pts), fp) != sizeof(param->pts.ip.pts)) {
|
||||
fclose(fp);
|
||||
panic("failed to write partitions\n");
|
||||
}
|
||||
} else if (param->updt_type == OTA_UPDATE_PING_PONG) {
|
||||
if (fwrite(¶m->pts.pp.pts[0], 1, sizeof(param->pts.pp.pts), fp) != sizeof(param->pts.pp.pts)) {
|
||||
fclose(fp);
|
||||
panic("failed to write partitions\n");
|
||||
}
|
||||
} else {
|
||||
panic("invalid partitions\n");
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
char *pt_tbl_path = NULL;
|
||||
partition_param_t param = { 0 };
|
||||
|
||||
memset(¶m, 0, sizeof(partition_param_t));
|
||||
|
||||
process_command_line(argc, argv, ¶m);
|
||||
|
||||
if (optind + 1 != argc) {
|
||||
usage();
|
||||
}
|
||||
|
||||
pt_tbl_path = argv[optind];
|
||||
|
||||
if ((fp = fopen(pt_tbl_path, "wb")) == NULL) {
|
||||
panic("failed to open: %s\n", pt_tbl_path);
|
||||
}
|
||||
|
||||
write_partition(¶m, fp);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user