From 1f51f6581662e635f9e1c54c2153a3662631a6b8 Mon Sep 17 00:00:00 2001 From: MaxineMuster <146550015+MaxineMuster@users.noreply.github.com> Date: Mon, 30 Dec 2024 23:20:21 +0100 Subject: [PATCH] OTA for W800 + "Simple OTA" w/o httpd (#1471) * OTA for W800 Removed unnecessary (and wasting resources) fetching of "index?status=1" on pages not using "state" div Added simple "internal OTA" (just POST-ing a file) Basic tests done - try avoiding other TCP connections to save memory Somtimes there are memory related messages in log like "Thread create HTTP Client - errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY". OTA working in most cases, somtimes device crashes during update. Device will immediatly reboot after OTA completion, even printfs after writing last bytes was not visible in console. * Add some more warnings Make file selector accepting images on extension for platform For Beken: Check magic "RBL" and future Platform name in header * Changed way to verify firmware files: must match OBK file structure for the platform As suggested by @NonPIayerCharacter added "NO_PLATFORM_OTA" in obk_config.h For platforms w/o OTA the page will be only showing a hint. * Fix page for non OTA devices * streamlined tests moved platform dependent #define for OTA extension to obk_config.h * Optimized JS code Only show hint for ".rbl" file on Beken platforms Added a #define OBK_OTA_NAME_EXTENSION, actually only for LN882H (here UART and OTA file are identicaly except an "_OTA" in the file name). Otherwise the UART file would also match the template (this file would not be flashed because of additional checks, but if we can prevent this ...) --- Makefile | 5 +- src/httpserver/http_fns.c | 23 +++++- src/httpserver/rest_interface.c | 139 +++++++++++++++++++++++++++++++- src/obk_config.h | 9 ++- 4 files changed, 171 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 53ea7dce3..eb7175433 100644 --- a/Makefile +++ b/Makefile @@ -193,7 +193,10 @@ sdk/OpenW600/tools/gcc-arm-none-eabi-4_9-2014q4/bin: submodules .PHONY: OpenW800 OpenW800: sdk/OpenW800/tools/w800/csky/bin sdk/OpenW800/sharedAppContainer/sharedApp prebuild_OpenW800 - $(MAKE) -C sdk/OpenW800 EXTRA_CCFLAGS=-DPLATFORM_W800 CONFIG_W800_USE_LIB=n CONFIG_W800_TOOLCHAIN_PATH="$(shell realpath sdk/OpenW800/tools/w800/csky/bin)/" + # if building new version, make sure "new_http.o" is deleted (it contains build time and version, so build time is set to actual time) + rm -rf sdk/OpenW800/bin/build/w800/obj/sharedAppContainer/sharedApp/src/httpserver/new_http.o + # define APP_Version so it's not "W800_Test" every time + $(MAKE) -C sdk/OpenW800 EXTRA_CCFLAGS="-DPLATFORM_W800 -DUSER_SW_VER=\\\"${APP_VERSION}\\\"" CONFIG_W800_USE_LIB=n CONFIG_W800_TOOLCHAIN_PATH="$(shell realpath sdk/OpenW800/tools/w800/csky/bin)/" mkdir -p output/$(APP_VERSION) cp sdk/OpenW800/bin/w800/w800.fls output/$(APP_VERSION)/OpenW800_$(APP_VERSION).fls cp sdk/OpenW800/bin/w800/w800_ota.img output/$(APP_VERSION)/OpenW800_$(APP_VERSION)_ota.img diff --git a/src/httpserver/http_fns.c b/src/httpserver/http_fns.c index a8889acac..12f918558 100644 --- a/src/httpserver/http_fns.c +++ b/src/httpserver/http_fns.c @@ -3011,11 +3011,30 @@ int http_fn_ota_exec(http_request_t* request) { int http_fn_ota(http_request_t* request) { http_setup(request, httpMimeTypeHTML); http_html_start(request, "OTA system"); - poststr(request, "

For a more user-friendly experience, it is recommended to use the OTA option in the Web Application, where you can easily drag and drop files without needing to set up a server. On Beken platforms, the .rbl file is used for OTA updates. In the OTA section below, paste the link to the .rbl file (an HTTP server is required).

"); - add_label_text_field(request, "URL for new bin file", "host", "", "
"); +#ifndef OBK_OTA_EXTENSION + poststr(request, "

Sorry, OTA update not implemented for " DEVICENAME_PREFIX_FULL "

"); +#else + poststr(request, "

It's recommended to use the OTA option in the Web Application, where you can easily drag and drop files.

If you have an HTTP server providing the OTA file, you may enter the URL below. " +#if PLATFORM_BEKEN + " On Beken platforms, the .rbl file is used for OTA updates." +#endif + "

"); + add_label_text_field(request, "URL for ota firmware file", "host", "", ""); poststr(request, "
\ \
"); + + const char htmlOTA[] = ""; + + poststr(request, "


Expert feature: Upload firmware OTA file.
If unsure, please use Web App!


"); + poststr(request, ""); + poststr(request, ""); + poststr(request, htmlOTA); +#endif poststr(request, htmlFooterReturnToCfgOrMainPage); http_html_end(request); poststr(request, NULL); diff --git a/src/httpserver/rest_interface.c b/src/httpserver/rest_interface.c index 54f593965..d93dc92ec 100644 --- a/src/httpserver/rest_interface.c +++ b/src/httpserver/rest_interface.c @@ -46,6 +46,9 @@ uint32_t flash_read(uint32_t flash, uint32_t addr, void* buf, uint32_t size); #elif PLATFORM_W800 +#include "wm_socket_fwup.h" +#include "wm_fwup.h" + #elif PLATFORM_LN882H #elif PLATFORM_ESPIDF @@ -242,6 +245,8 @@ static int http_rest_post(http_request_t* request) { return http_rest_post_flash(request, START_ADR_OF_BK_PARTITION_OTA, LFS_BLOCKS_END); #elif PLATFORM_W600 return http_rest_post_flash(request, -1, -1); +#elif PLATFORM_W800 + return http_rest_post_flash(request, -1, -1); #elif PLATFORM_BL602 return http_rest_post_flash(request, -1, -1); #elif PLATFORM_LN882H @@ -1421,7 +1426,7 @@ static int ota_verify_download(void) static int http_rest_post_flash(http_request_t* request, int startaddr, int maxaddr) { -#if PLATFORM_XR809 || PLATFORM_W800 || PLATFORM_TR6260 +#if PLATFORM_XR809 || PLATFORM_TR6260 return 0; //Operation not supported yet #endif @@ -1557,6 +1562,138 @@ static int http_rest_post_flash(http_request_t* request, int startaddr, int maxa } +#elif PLATFORM_W800 + int nRetCode = 0; + char error_message[256]; + + if(writelen < 0) + { + ADDLOG_DEBUG(LOG_FEATURE_OTA, "ABORTED: %d bytes to write", writelen); + return http_rest_error(request, -20, "writelen < 0"); + } + + struct pbuf* p; + + //The code below is based on W600 code and adopted to the differences in sdk\OpenW800\src\app\ota\wm_http_fwup.c + // fiexd crashing caused by not checking "writelen" before doing memcpy + // e.g. if more than 2 packets arrived before next loop, writelen could be > 2048 !! +#define FWUP_MSG_SIZE 3 +#define MAX_BUFF_SIZE 2048 + char* Buffer = (char*)os_malloc(MAX_BUFF_SIZE + FWUP_MSG_SIZE); + + if(request->contentLength >= 0) + { + towrite = request->contentLength; + } + + int recvLen = 0; + int totalLen = 0; + uint8_t counter = 0; + printf("\ntowrite %d writelen=%d\n", towrite, writelen); + + do + { + while(writelen > 0) + { + int actwrite = writelen < MAX_BUFF_SIZE ? writelen : MAX_BUFF_SIZE; // mustn't write more than Buffers size! Will crash else! + //bk_printf("Copying %d from writebuf to Buffer (writelen=%d) towrite=%d -- free_heap:%d\n", actwrite, writelen, towrite, xPortGetFreeHeapSize()); + memset(Buffer, 0, MAX_BUFF_SIZE + FWUP_MSG_SIZE); + memcpy(Buffer + FWUP_MSG_SIZE, writebuf, actwrite); + if(recvLen == 0) + { + IMAGE_HEADER_PARAM_ST *booter = (IMAGE_HEADER_PARAM_ST*)(Buffer + FWUP_MSG_SIZE); + bk_printf("magic_no=%u, img_type=%u, zip_type=%u, signature=%u\n", + booter->magic_no, booter->img_attr.b.img_type, booter->img_attr.b.zip_type, booter->img_attr.b.signature); + + if(TRUE == tls_fwup_img_header_check(booter)) + { + totalLen = booter->img_len + sizeof(IMAGE_HEADER_PARAM_ST); + if (booter->img_attr.b.signature) + { + totalLen += 128; + } + } + else + { + sprintf(error_message, "Image header check failed"); + nRetCode = -19; + break; + } + + nRetCode = socket_fwup_accept(0, ERR_OK); + if(nRetCode != ERR_OK) + { + sprintf(error_message, "Firmware update startup failed"); + break; + } + } + + p = pbuf_alloc(PBUF_TRANSPORT, actwrite + FWUP_MSG_SIZE, PBUF_REF); + if(!p) + { + sprintf(error_message, "Unable to allocate memory for buffer"); + nRetCode = -18; + break; + } + + if(recvLen == 0) + { + *Buffer = SOCKET_FWUP_START; + } + else if(recvLen == (totalLen - actwrite)) + { + *Buffer = SOCKET_FWUP_END; + } + else + { + *Buffer = SOCKET_FWUP_DATA; + } + + *(Buffer + 1) = (actwrite >> 8) & 0xFF; + *(Buffer + 2) = actwrite & 0xFF; + p->payload = Buffer; + p->len = p->tot_len = actwrite + FWUP_MSG_SIZE; + + nRetCode = socket_fwup_recv(0, p, ERR_OK); + if(nRetCode != ERR_OK) + { + sprintf(error_message, "Firmware data processing failed"); + break; + } + else + { + recvLen += actwrite; + } + + towrite -= actwrite; + writelen -= actwrite; // calculate, how much is left to write + writebuf += actwrite; // in case, we only wrote part of buffer, advance in buffer + } + + if(towrite > 0) + { + writebuf = request->received; + writelen = recv(request->fd, writebuf, request->receivedLenmax, 0); + if(writelen < 0) + { + sprintf(error_message, "recv returned %d - end of data - remaining %d", writelen, towrite); + nRetCode = -17; + } + } + if (counter++ % 5 == 0) bk_printf("Downloaded %d / %d\n", recvLen, totalLen); + rtos_delay_milliseconds(10); // give some time for flashing - will else increase used memory fast + } while((nRetCode == 0) && (towrite > 0) && (writelen >= 0)); + bk_printf("Download completed (%d / %d)\n", recvLen, totalLen); + tls_mem_free(Buffer); + + if(nRetCode != 0) + { + ADDLOG_ERROR(LOG_FEATURE_OTA, error_message); + socket_fwup_err(0, nRetCode); + return http_rest_error(request, nRetCode, error_message); + } + + #elif PLATFORM_BL602 int sockfd, i; int ret; diff --git a/src/obk_config.h b/src/obk_config.h index bfcc0b304..010f0584f 100644 --- a/src/obk_config.h +++ b/src/obk_config.h @@ -28,6 +28,7 @@ #define ENABLE_DRIVER_BL0937 1 #define ENABLE_DRIVER_DHT 1 #define ENABLE_TASMOTA_JSON 1 +#define OBK_OTA_EXTENSION ".img" #elif PLATFORM_W800 @@ -35,6 +36,7 @@ //#define OBK_DISABLE_ALL_DRIVERS 1 #define ENABLE_TASMOTA_JSON 1 #define ENABLE_DRIVER_DS1820 1 +#define OBK_OTA_EXTENSION ".img" #elif WINDOWS @@ -105,6 +107,8 @@ #define ENABLE_DRIVER_SSDP 1 #define ENABLE_DRIVER_CHT83XX 1 #define ENABLE_DRIVER_DS1820 1 +#define OBK_OTA_EXTENSION ".bin.xz.ota" + #elif PLATFORM_BEKEN @@ -156,8 +160,8 @@ #define ENABLE_DRIVER_IR2 0 #define ENABLE_DRIVER_DS1820 1 #define ENABLE_DRIVER_CHT83XX 1 - //#define ENABLE_DRIVER_OPENWEATHERMAP 1 +#define OBK_OTA_EXTENSION ".rbl" // ENABLE_I2C_ is a syntax for // our I2C system defines for drv_i2c_main.c @@ -182,6 +186,8 @@ //#define ENABLE_DRIVER_TMGN 1 #define ENABLE_TASMOTA_JSON 1 #define ENABLE_DRIVER_DS1820 1 +#define OBK_OTA_EXTENSION ".bin" +#define OBK_OTA_NAME_EXTENSION "_OTA" #elif PLATFORM_ESPIDF @@ -207,6 +213,7 @@ #define ENABLE_DRIVER_DDP 1 #define ENABLE_DRIVER_SSDP 1 #define ENABLE_DRIVER_CHT83XX 1 +#define OBK_OTA_EXTENSION ".img" #elif PLATFORM_TR6260