Skip to content

Conversation

@Devika-Raju-Z
Copy link

@Devika-Raju-Z Devika-Raju-Z commented Sep 16, 2025

Updating the SiWx917 device's firmware including NWP, M4, and the combined M4 + TA images using an HTTP or HTTPS server. It supports both secure and non-secure firmware updates for all three types: NWP, M4, and the combined image.


Note

Adds a new Zephyr sample for SiWx917 that performs HTTP/HTTPS OTA firmware updates over Wi‑Fi with ranged downloads and firmware flashing.

  • New sample: samples/siwx91x_ota
    • src/main.c: Implements Wi‑Fi connect/scan, IP config handling, DNS logging, and an OTA state machine (scan → server connect → ranged download) using http_client with TLS and Range headers; buffers chunks, validates image size, loads via sl_si91x_fwup_*, and reboots on success.
    • prj.conf: Enables networking, sockets, DHCPv4, HTTP client, URL parser, mbedTLS (TLS 1.2), DNS resolver, and SiWx91x firmware upgrade support.
    • Kconfig: Adds configurable CONFIG_OTA_WIFI_SSID, CONFIG_OTA_WIFI_PSK, and CONFIG_OTA_UPDATE_URL.
    • CMakeLists.txt: Sets up app build and sources.
    • README.rst: Documents purpose, configuration, build/run, and test steps.
    • sample.yaml: Registers sample and net test for siwx917_rb4338a.

Written by Cursor Bugbot for commit 8c6da5c. This will update automatically on new commits. Configure here.

@Devika-Raju-Z Devika-Raju-Z force-pushed the https_otaf branch 24 times, most recently from 569c7b4 to dd7f3de Compare September 25, 2025 17:03
@jhedberg jhedberg changed the title http/s otaf application samples: siwx917_ota: http/s OTAF application Sep 26, 2025
@jhedberg
Copy link
Contributor

Please rebase this on the latest main branch to see if the Compliance failure gets resolved

@Devika-Raju-Z Devika-Raju-Z force-pushed the https_otaf branch 5 times, most recently from 9c620ad to 7fe97ff Compare October 14, 2025 09:48
@Devika-Raju-Z Devika-Raju-Z force-pushed the https_otaf branch 5 times, most recently from c3b2473 to 4bf41dc Compare October 21, 2025 09:50
Copy link
Contributor

@jerome-pouiller jerome-pouiller left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I stop here for today.

@Devika-Raju-Z Devika-Raju-Z force-pushed the https_otaf branch 2 times, most recently from 1b8ada9 to a13421c Compare October 29, 2025 11:54
@Devika-Raju-Z Devika-Raju-Z force-pushed the https_otaf branch 2 times, most recently from b2555db to 4ad0105 Compare November 6, 2025 05:57
case OTA_STATE_SCAN:
/* Scan for networks and connect */
ota_wifi_start_scan(ctx);
ret = ota_wifi_connect(ssid, pwd, ctx);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Management of ctx->security is not correct:

  • The network can use hidden SSID. In this case, ctx->security won't be filled.
  • There is a race condition between the scan results and the wifi_connect.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have idea of how to handle the security for hidden SSID.
Do you have any suggestion?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably you could init security with WIFI_SECURITY_TYPE_PSK. So, it will try to connect using WPA2 (the most common case in 2025, I think) if the SSID is not found during the scan.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe error management for security field is still not properly managed (security is set during the first scan, but not reverted on error).

(note ipv4 and ipv6 status are correct because we receive the events from Zephyr in case of disconnection)

break;
}
}
}
Copy link
Contributor

@jerome-pouiller jerome-pouiller Nov 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With all the simplification we made, I start to see how error management should be done. Instead of calling ota_handle_retry() with various parameters, manage the error inline in the function. Thus, the error handling is transparent and easy to follow the error path:

    if (ret < 0) {
        ctx->state = OTA_STATE_SERVER_CONNECT;   
        goto out_close;
    }
    [...]
    if (ret < 0) {
        ctx->state = OTA_STATE_SERVER_CONNECT;   
        goto out_reset;
    }
    [...]
    return 0;

out_reset:
    ctx->range_start = 0;
    ctx->range_end = 1023;
out_close:
    zsock_close(ctx->sock);
    ctx->sock = -1;
out:
    return ret;

Ti work properly, the retry loop has be placed in main(). This change also allow to save one level on of indentation in ota_application_start() and change retry_count in a local variable. It also solve the issue with retry_count decremented even if operation success.

I also wonder if it make sense to break the loop on success. You could just fallback to the next state. Finally, we can see that the state OTA_STATE_SCAN is in fact the same than ctx->disconnected and OTA_STATE_SERVER_CONNECT is the same than ctx->sock < 0. Because the states were not properly updated, it blurries the global algorithm. At the end, this FSM is just a violation of the single source of trust principle. At the end, algorithm appear clearly if we remove the FSM:

if (ctx->disconnected /* OTA_STATE_SCAN */) {
    [manage wifi connection and goto out on error]
}
if (ctx->sock < 0 /* OTA_STATE_SERVER_CONNECT */) {
    [manage server connection and goto out on error]
}
[manage download and goto out_close on error]
[manage flash and goto out_reset on error]

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed

@Devika-Raju-Z Devika-Raju-Z force-pushed the https_otaf branch 2 times, most recently from ee3fcc1 to ec8d3a0 Compare November 20, 2025 12:37
This application demonstrates the support for OTA
firmware upgrade.

Signed-off-by: Devika Raju <[email protected]>
Copy link
Contributor

@jerome-pouiller jerome-pouiller left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have not yet finish my review, but the things start to have a good shape.


ctx->ota_image_size = rsp->content_range.total;

if (rsp->body_frag_len > 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe you can remove the condition without changing the behavior of the code, but it is not a big deal.

ctx->range_start, ctx->range_start + sizeof(ctx->flash_buffer) - 1);
return -EPROTO;
}
return ret;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return 0;. Not a big deal.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed the comment

buf_offset = sizeof(sl_si91x_firmware_header_t);
status = sl_wifi_get_firmware_size((void *)ctx->flash_buffer, &ota_calc_image_size);
if (status != SL_STATUS_OK) {
printf("Unable to fetch firmware size. Status: 0x%x\n", status);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally, we pad the hexadecimal numbers on 2, 4 or 8 characters (0x%08x).


status = sl_si91x_fwup_start(ctx->flash_buffer);
if (status != SL_STATUS_OK) {
printf("Failed to load firmware header (0x%x)\n", status);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

ret = ota_load_firmware(ctx);
if (ret < 0) {
goto out_reset;
} else {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This else statement is useless. The idea is to use early return to keep the nominal case linear:

    ret = fn1();
    if (ret < 0) {
        goto early_return1;
    }
    ret = fn2();
    if (ret < 0) {
        goto early_return2;
    }

goto out_reset;
}
}
return ret;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does not change the behavior, but return 0; is easier to understand.

(for the coding style, keep a blank between normal return and error management)

return ret;
out_reset:
ctx->range_start = 0;
return ret;
Copy link
Contributor

@jerome-pouiller jerome-pouiller Nov 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we reset, don't we want to reconnect? The idea is to use fallbacks between the label to reset the various state (as you would do with an exception in python).

ret = ota_connect_to_server(ctx);
if (ret < 0) {
goto out_close;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ota_connect_to_server() is well written. It does not change the context in case of error. You don't have to close the socket. return ret; is sufficient.

k_sleep(K_MSEC(1000));
}
}
return (ret < 0) ? ret : 0;
Copy link
Contributor

@jerome-pouiller jerome-pouiller Nov 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure you need a suche complex code for a such simple thing?

while (retry_count < 3) {
    ret = ota_application_start(&app_ctx);
    if (ret < 0) {
          retry_count++;
          k_sleep(K_MSEC(1000));
    }
}
printf("Maximum retries exceeded, aborting OTA\n");
return -EIO;

(Note the detailed errors are already displayed in the earlier functions, having yet another error message here has little benefit).

(It would be even easier if ota_application_start() would take care of the download loop and only returned in case of error)

if (!ctx->connected) {
ota_wifi_start_scan(ctx);
ret = ota_wifi_connect(ctx);
if (ret) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ret < 0 (not a big deal, but the other check in the function test against minus values, so for uniformity...)

Copy link
Contributor

@jerome-pouiller jerome-pouiller left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have finished the review.

static int ota_http_response_cb(struct http_response *rsp, enum http_final_call final_data,
void *user_data)
{
ARG_UNUSED(final_data);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Useless.


if (ctx->range_start == 0) {
buf_offset = sizeof(sl_si91x_firmware_header_t);
status = sl_wifi_get_firmware_size((void *)ctx->flash_buffer, &ota_calc_image_size);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure you need to cast the pointer?

zsock_close(ctx->sock);
ctx->sock = -1;
ctx->flash_buffer_len = 0;
ctx->http_status_code = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand right, flash_buffer_len and http_status_code are reset each time you call ota_download_firmware_chunk()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are resetting the flash_buffer_len, but not the http_status_code. We will reset that as well.


if (ctx->image_size != ota_calc_image_size) {
printf("Image size mismatch - expected: %u, calculated: %u (file may be "
"corrupted)\n",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some user may understand file may be corrupted means the device is now corrupted. I suggest (corrupted payload?) (or Corrupted payload (image size mismatch: %d bytes != %d bytes)\n)


/* Prepare headers */
snprintf(range_header, sizeof(range_header), "Range: bytes=%d-%d\r\n", ctx->range_start,
ctx->range_start + sizeof(ctx->flash_buffer) - 1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you confirm the HTTP server is fine when we request range_end beyond image_size?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HTTP server returns 416 http status code when we request range_end beyond image_size

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this code is not correct, that's it?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once HTTP server responds 416 error code, application closes the connection


if (ctx->range_start >= (int)ctx->image_size) {
return -ENODATA;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO, this error is directly related to the http download and it make more send to handle it in ota_download_firmware_chunk().

(Then this function will be only one line, and maybe you will prefer to inline it)

if (ret != 0) {
printf("Cannot resolve %s:%s: %s\n", ctx->http_parse_info.host,
ctx->http_parse_info.port, zsock_gai_strerror(ret));
return ret;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, so you can't return ret. You have to return -EINVAL or something like this.

if (!ctx->ipv4_addr_config_done || !ctx->ipv6_addr_config_done ||
ctx->disconnected) {
ota_handle_retry(ctx, "network connection", true);
ctx->state = OTA_STATE_SCAN;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not addressed.

static int ota_download_firmware_chunk(struct app_ctx *ctx)
{
char range_header[64];
const char *headers[2] = {range_header, NULL};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not addressed.

@Devika-Raju-Z Devika-Raju-Z force-pushed the https_otaf branch 2 times, most recently from fc77cd2 to 5b70aa4 Compare November 24, 2025 15:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants