-
Notifications
You must be signed in to change notification settings - Fork 24
samples: siwx917_ota: http/s OTAF application #111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
466273e to
6a581ad
Compare
569c7b4 to
dd7f3de
Compare
|
Please rebase this on the latest |
9c620ad to
7fe97ff
Compare
c3b2473 to
4bf41dc
Compare
jerome-pouiller
left a comment
There was a problem hiding this 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.
1b8ada9 to
a13421c
Compare
b2555db to
4ad0105
Compare
samples/siwx91x_ota/src/main.c
Outdated
| case OTA_STATE_SCAN: | ||
| /* Scan for networks and connect */ | ||
| ota_wifi_start_scan(ctx); | ||
| ret = ota_wifi_connect(ssid, pwd, ctx); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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)
4ad0105 to
8c6da5c
Compare
| break; | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
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]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed
ee3fcc1 to
ec8d3a0
Compare
This application demonstrates the support for OTA firmware upgrade. Signed-off-by: Devika Raju <[email protected]>
jerome-pouiller
left a comment
There was a problem hiding this 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.
samples/siwx91x_ota/src/main.c
Outdated
|
|
||
| ctx->ota_image_size = rsp->content_range.total; | ||
|
|
||
| if (rsp->body_frag_len > 0) { |
There was a problem hiding this comment.
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.
samples/siwx91x_ota/src/main.c
Outdated
| ctx->range_start, ctx->range_start + sizeof(ctx->flash_buffer) - 1); | ||
| return -EPROTO; | ||
| } | ||
| return ret; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed the comment
samples/siwx91x_ota/src/main.c
Outdated
| 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); |
There was a problem hiding this comment.
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).
samples/siwx91x_ota/src/main.c
Outdated
|
|
||
| status = sl_si91x_fwup_start(ctx->flash_buffer); | ||
| if (status != SL_STATUS_OK) { | ||
| printf("Failed to load firmware header (0x%x)\n", status); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto.
samples/siwx91x_ota/src/main.c
Outdated
| ret = ota_load_firmware(ctx); | ||
| if (ret < 0) { | ||
| goto out_reset; | ||
| } else { |
There was a problem hiding this comment.
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;
}
samples/siwx91x_ota/src/main.c
Outdated
| goto out_reset; | ||
| } | ||
| } | ||
| return ret; |
There was a problem hiding this comment.
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)
samples/siwx91x_ota/src/main.c
Outdated
| return ret; | ||
| out_reset: | ||
| ctx->range_start = 0; | ||
| return ret; |
There was a problem hiding this comment.
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; | ||
| } |
There was a problem hiding this comment.
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.
samples/siwx91x_ota/src/main.c
Outdated
| k_sleep(K_MSEC(1000)); | ||
| } | ||
| } | ||
| return (ret < 0) ? ret : 0; |
There was a problem hiding this comment.
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)
samples/siwx91x_ota/src/main.c
Outdated
| if (!ctx->connected) { | ||
| ota_wifi_start_scan(ctx); | ||
| ret = ota_wifi_connect(ctx); | ||
| if (ret) { |
There was a problem hiding this comment.
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...)
jerome-pouiller
left a comment
There was a problem hiding this 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.
samples/siwx91x_ota/src/main.c
Outdated
| static int ota_http_response_cb(struct http_response *rsp, enum http_final_call final_data, | ||
| void *user_data) | ||
| { | ||
| ARG_UNUSED(final_data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Useless.
samples/siwx91x_ota/src/main.c
Outdated
|
|
||
| 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); |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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()
There was a problem hiding this comment.
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.
samples/siwx91x_ota/src/main.c
Outdated
|
|
||
| if (ctx->image_size != ota_calc_image_size) { | ||
| printf("Image size mismatch - expected: %u, calculated: %u (file may be " | ||
| "corrupted)\n", |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
samples/siwx91x_ota/src/main.c
Outdated
|
|
||
| if (ctx->range_start >= (int)ctx->image_size) { | ||
| return -ENODATA; | ||
| } |
There was a problem hiding this comment.
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)
samples/siwx91x_ota/src/main.c
Outdated
| 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; |
There was a problem hiding this comment.
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.
samples/siwx91x_ota/src/main.c
Outdated
| 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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not addressed.
samples/siwx91x_ota/src/main.c
Outdated
| static int ota_download_firmware_chunk(struct app_ctx *ctx) | ||
| { | ||
| char range_header[64]; | ||
| const char *headers[2] = {range_header, NULL}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not addressed.
fc77cd2 to
5b70aa4
Compare
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.
samples/siwx91x_otasrc/main.c: Implements Wi‑Fi connect/scan, IP config handling, DNS logging, and an OTA state machine (scan → server connect → ranged download) usinghttp_clientwith TLS and Range headers; buffers chunks, validates image size, loads viasl_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 configurableCONFIG_OTA_WIFI_SSID,CONFIG_OTA_WIFI_PSK, andCONFIG_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 forsiwx917_rb4338a.Written by Cursor Bugbot for commit 8c6da5c. This will update automatically on new commits. Configure here.