Skip to content

Commit

Permalink
OTA for W800 + "Simple OTA" w/o httpd (#1471)
Browse files Browse the repository at this point in the history
* 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 ...)
  • Loading branch information
MaxineMuster authored Dec 30, 2024
1 parent 3331f72 commit 1f51f65
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 5 deletions.
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
23 changes: 21 additions & 2 deletions src/httpserver/http_fns.c
Original file line number Diff line number Diff line change
Expand Up @@ -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, "<p>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).</p>");
add_label_text_field(request, "URL for new bin file", "host", "", "<form action=\"/ota_exec\">");
#ifndef OBK_OTA_EXTENSION
poststr(request, "<h3>Sorry, OTA update not implemented for " DEVICENAME_PREFIX_FULL " </h3>");
#else
poststr(request, "<p>It's recommended to use the OTA option in the Web Application, where you can easily drag and drop files.<br><br>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
"</p>");
add_label_text_field(request, "URL for ota firmware file", "host", "", "<form action=\"/ota_exec\">");
poststr(request, "<br>\
<input type=\"submit\" value=\"Submit\" onclick=\"return confirm('Are you sure?')\">\
</form>");

const char htmlOTA[] = "<script>var o=document.getElementById('otafile'),d=document.querySelector('dialog'),h=document.getElementById('hint'),D='OTA started! Please wait ',R=/" DEVICENAME_PREFIX_FULL "_.*"
#ifdef OBK_OTA_NAME_EXTENSION
OBK_OTA_NAME_EXTENSION
#endif
OBK_OTA_EXTENSION "/,SR=R.source,mr=(e)=>e.name.match(R);doota=()=>{f=o.files[0];if(f&&(f)){d.showModal();var t=30;setTimeout(()=>{d.close(),location.href='/'},1e3*t),setInterval(()=>d.innerHTML=D+t--+' secs',1e3),fetch('/api/ota',{method:'POST',body:f}).then((e)=>{e.ok&&fetch('/index?restart=1')})}else alert(f?'filename invalid':'no file selected')};d.innerHTML=D,o.addEventListener('change',((e)=>{const t=e.target.files[0];if(!t)return;h.innerHTML=mr(t)?'':'Selected file does <b>not</b> match reqired format '+SR+'!'}))</script>";

poststr(request, "<br><br><br>Expert feature: Upload firmware OTA file.<br>If unsure, please use Web App!<br><span id='hint' style='color: yellow;'></span><br><br>");
poststr(request, "<input id='otafile' type='file' accept='" OBK_OTA_EXTENSION "'>");
poststr(request, "<input type='button' class='bred' onclick='doota();' value='START OTA - No file check - will reboot after OTA'><dialog></dialog>");
poststr(request, htmlOTA);
#endif
poststr(request, htmlFooterReturnToCfgOrMainPage);
http_html_end(request);
poststr(request, NULL);
Expand Down
139 changes: 138 additions & 1 deletion src/httpserver/rest_interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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;
Expand Down
9 changes: 8 additions & 1 deletion src/obk_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@
#define ENABLE_DRIVER_BL0937 1
#define ENABLE_DRIVER_DHT 1
#define ENABLE_TASMOTA_JSON 1
#define OBK_OTA_EXTENSION ".img"

#elif PLATFORM_W800

// try enabling drivers - e.g. to access charts
//#define OBK_DISABLE_ALL_DRIVERS 1
#define ENABLE_TASMOTA_JSON 1
#define ENABLE_DRIVER_DS1820 1
#define OBK_OTA_EXTENSION ".img"


#elif WINDOWS
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand All @@ -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

Expand All @@ -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

Expand Down

0 comments on commit 1f51f65

Please sign in to comment.