273 lines
8.2 KiB
C
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);
|
|
}
|
|
}
|