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 ...)
This commit is contained in:
MaxineMuster
2024-12-30 23:20:21 +01:00
committed by GitHub
parent 3331f721b0
commit 1f51f65816
4 changed files with 171 additions and 5 deletions

View File

@@ -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);

View File

@@ -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;