Files
banban/ql-application/threadx/interface/custom_app/ota_fullfota2.c
T

273 lines
8.2 KiB
C

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ql_fota.h"
#include "ql_fs.h"
#include "ql_power.h"
#include "ql_rtos.h"
#include "webclient.h"
#include "ota_baseline.h"
#include "ota_fullfota2.h"
#define BANBAN_FULLOTA2_PACKAGE_PATH "U:/FotaFile.bin"
#define BANBAN_FULLOTA2_URL_MAX 256U
#define BANBAN_FULLOTA2_READ_BUFFER_SIZE 4096U
#define BANBAN_FULLOTA2_TASK_STACK_SIZE (12U * 1024U)
#define BANBAN_FULLOTA2_TASK_PRIORITY 100U
#define BANBAN_FULLOTA2_HTTP_TIMEOUT_MS 30000
#define BANBAN_FULLOTA2_FBF_OVERHEAD 8192U
typedef struct {
char url[BANBAN_FULLOTA2_URL_MAX];
banban_fullfota2_finished_cb_t finished_cb;
} banban_fullfota2_request_t;
static ql_task_t g_fullfota2_task = NULL;
static volatile int g_fullfota2_running = 0;
static banban_fullfota2_request_t g_fullfota2_request;
static void banban_fullfota2_finish(int result,
struct webclient_session *session,
uint8_t *buffer,
qlFotaImgProcCtxPtr fota)
{
banban_fullfota2_finished_cb_t finished_cb =
g_fullfota2_request.finished_cb;
if (session != NULL) {
webclient_close(session);
}
if (buffer != NULL) {
web_free(buffer);
}
if (fota != NULL) {
ql_fota_deinit(fota);
}
if (result != BANBAN_FULLOTA2_OK) {
ql_fota_fixed_internal_flash_upgrade(0);
if (ql_access(BANBAN_FULLOTA2_PACKAGE_PATH, 0) == 0) {
ql_remove(BANBAN_FULLOTA2_PACKAGE_PATH);
}
}
memset(&g_fullfota2_request, 0, sizeof(g_fullfota2_request));
g_fullfota2_running = 0;
g_fullfota2_task = NULL;
if (finished_cb != NULL) {
finished_cb(result);
}
}
static void banban_fullfota2_task(void *argument)
{
struct webclient_session *session = NULL;
qlFotaImgProcCtxPtr fota = NULL;
uint8_t *buffer = NULL;
int status;
int content_length;
int free_size;
int read_length;
int written = 0;
int next_progress = 10;
int result = BANBAN_FULLOTA2_ERR_HTTP;
struct lfs_info staged_info;
(void)argument;
printf("[FULLOTA2] start url=%s path=%s\r\n",
g_fullfota2_request.url,
BANBAN_FULLOTA2_PACKAGE_PATH);
if (ql_access(BANBAN_FULLOTA2_PACKAGE_PATH, 0) == 0) {
ql_remove(BANBAN_FULLOTA2_PACKAGE_PATH);
}
session = webclient_session_create(2048);
if (session == NULL) {
result = BANBAN_FULLOTA2_ERR_HTTP;
goto failed;
}
webclient_set_timeout(session, BANBAN_FULLOTA2_HTTP_TIMEOUT_MS);
status = webclient_get(session, g_fullfota2_request.url);
if (status != 200) {
printf("[FULLOTA2] HTTP GET failed status=%d\r\n", status);
result = BANBAN_FULLOTA2_ERR_HTTP;
goto failed;
}
content_length = session->content_length;
if (content_length <= (int)BANBAN_FULLOTA2_FBF_OVERHEAD ||
content_length > (int)BANBAN_OTA_APP_PARTITION_SIZE) {
printf("[FULLOTA2] invalid Content-Length=%d\r\n", content_length);
result = BANBAN_FULLOTA2_ERR_LENGTH;
goto failed;
}
free_size = ql_fs_free_size('U');
if (free_size < 0 ||
(uint32_t)free_size <
(uint32_t)content_length + BANBAN_OTA_STAGING_RESERVE_BYTES) {
printf("[FULLOTA2] insufficient space free=%d required=%lu\r\n",
free_size,
(unsigned long)((uint32_t)content_length +
BANBAN_OTA_STAGING_RESERVE_BYTES));
result = BANBAN_FULLOTA2_ERR_SPACE;
goto failed;
}
ql_fota_fixed_internal_flash_upgrade(1);
if (ql_fota_set_package_path(BANBAN_FULLOTA2_PACKAGE_PATH) != 0) {
printf("[FULLOTA2] set package path failed\r\n");
result = BANBAN_FULLOTA2_ERR_INIT;
goto failed;
}
fota = ql_fota_init();
if (fota == NULL) {
printf("[FULLOTA2] ql_fota_init failed\r\n");
result = BANBAN_FULLOTA2_ERR_INIT;
goto failed;
}
buffer = web_malloc(BANBAN_FULLOTA2_READ_BUFFER_SIZE);
if (buffer == NULL) {
printf("[FULLOTA2] allocate read buffer failed\r\n");
result = BANBAN_FULLOTA2_ERR_INIT;
goto failed;
}
while (written < content_length) {
int request_length = content_length - written;
int progress;
if (request_length > (int)BANBAN_FULLOTA2_READ_BUFFER_SIZE) {
request_length = BANBAN_FULLOTA2_READ_BUFFER_SIZE;
}
read_length = webclient_read(session, buffer, request_length);
if (read_length <= 0) {
printf("[FULLOTA2] body read failed ret=%d received=%d expected=%d\r\n",
read_length, written, content_length);
result = BANBAN_FULLOTA2_ERR_HTTP;
goto failed;
}
if (ql_fota_image_write(fota, buffer, read_length) != 0) {
printf("[FULLOTA2] image write failed received=%d chunk=%d\r\n",
written, read_length);
result = BANBAN_FULLOTA2_ERR_WRITE;
goto failed;
}
written += read_length;
progress = (written * 100) / content_length;
if (progress >= next_progress || written == content_length) {
printf("[FULLOTA2] download progress=%d%% bytes=%d/%d\r\n",
progress, written, content_length);
while (next_progress <= progress) {
next_progress += 10;
}
}
}
if (written != content_length) {
result = BANBAN_FULLOTA2_ERR_LENGTH;
goto failed;
}
if (ql_fota_image_flush(fota) != 0) {
printf("[FULLOTA2] image flush failed\r\n");
result = BANBAN_FULLOTA2_ERR_FLUSH;
goto failed;
}
memset(&staged_info, 0, sizeof(staged_info));
if (ql_stat(BANBAN_FULLOTA2_PACKAGE_PATH, &staged_info) != 0 ||
staged_info.size != (uint32_t)content_length) {
printf("[FULLOTA2] staged length mismatch file=%lu expected=%d\r\n",
(unsigned long)staged_info.size, content_length);
result = BANBAN_FULLOTA2_ERR_LENGTH;
goto failed;
}
if (ql_fota_image_verify(fota) != 0) {
printf("[FULLOTA2] FBF verify/setflag failed\r\n");
result = BANBAN_FULLOTA2_ERR_VERIFY;
goto failed;
}
printf("[FULLOTA2] package verified; rebooting into updater\r\n");
banban_fullfota2_finish(BANBAN_FULLOTA2_OK, session, buffer, fota);
ql_rtos_task_sleep_ms(200);
ql_power_reset();
/* ql_power_reset() is not expected to return. Keep the task quiesced if it does. */
while (1) {
ql_rtos_task_sleep_s(60);
}
failed:
printf("[FULLOTA2] failed result=%d\r\n", result);
banban_fullfota2_finish(result, session, buffer, fota);
ql_rtos_task_delete(NULL);
}
int banban_fullfota2_start(const char *url,
banban_fullfota2_finished_cb_t finished_cb)
{
int ret;
size_t url_length;
if (url == NULL || url[0] == '\0') {
return BANBAN_FULLOTA2_ERR_ARGUMENT;
}
url_length = strlen(url);
if (url_length >= sizeof(g_fullfota2_request.url)) {
return BANBAN_FULLOTA2_ERR_ARGUMENT;
}
if (g_fullfota2_running) {
return BANBAN_FULLOTA2_ERR_BUSY;
}
memset(&g_fullfota2_request, 0, sizeof(g_fullfota2_request));
memcpy(g_fullfota2_request.url, url, url_length + 1);
g_fullfota2_request.finished_cb = finished_cb;
g_fullfota2_running = 1;
ret = ql_rtos_task_create(&g_fullfota2_task,
BANBAN_FULLOTA2_TASK_STACK_SIZE,
BANBAN_FULLOTA2_TASK_PRIORITY,
"ota_fullfota2",
banban_fullfota2_task,
NULL);
if (ret != 0) {
memset(&g_fullfota2_request, 0, sizeof(g_fullfota2_request));
g_fullfota2_running = 0;
g_fullfota2_task = NULL;
return BANBAN_FULLOTA2_ERR_TASK;
}
return BANBAN_FULLOTA2_OK;
}
int banban_fullfota2_is_running(void)
{
return g_fullfota2_running ? 1 : 0;
}
void banban_fullfota2_discard_staged_package(void)
{
if (!g_fullfota2_running &&
ql_access(BANBAN_FULLOTA2_PACKAGE_PATH, 0) == 0) {
ql_remove(BANBAN_FULLOTA2_PACKAGE_PATH);
}
}