Skip to content

Conversation

Devika-Raju-Z
Copy link

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.

cmake_minimum_required(VERSION 3.20.0)

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(siwx917_tcp_client)
Copy link
Contributor

Choose a reason for hiding this comment

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

OTA already mean Over The Air, so we don't need to specify https. I suggest to rename this sample in siwx91x_ota.

Align the name of the sample with the name of the project.

zephyr_code_relocate(FILES ${WISECONNECT_DIR}/components/device/silabs/si91x/wireless/ahb_interface/inc/sli_siwx917_soc.h LOCATION RAM)
zephyr_code_relocate(FILES ${WISECONNECT_DIR}/components/sli_si91x_wifi_event_handler/src/sli_si91x_wifi_event_handler.c LOCATION RAM)
zephyr_code_relocate(FILES ${WISECONNECT_DIR}/components/sli_wifi_command_engine/src/sli_wifi_command_engine.c LOCATION RAM)
zephyr_code_relocate(FILES ${SERVICE_DIR}/sleeptimer/src/sl_sleeptimer.c LOCATION RAM) No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

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

Wow, this is very unexpected. Can you explain why it's required? I assume the iea is to relocate in memory all the code reached by the ISR? In this case, these relocations are not sufficient.

Copy link
Author

Choose a reason for hiding this comment

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

Keeping this frequently used files in RAM to improve the performance. We can keep this in flash, but the performance will be low

Copy link
Contributor

Choose a reason for hiding this comment

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

What performance degradation do you get? If this kind of hack is required to get sane performance, we have raise the issue and address it.

Copy link
Author

Choose a reason for hiding this comment

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

When we relocated the code to RAM for TCP transmit throughput analysis, we observed an improvement of approximately 0.5 Mbps in throughput.

Copy link
Contributor

Choose a reason for hiding this comment

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

I assume we can consider it is still sane.

Overview
********

Application demonstrates how to perform HTTP/HTTPS OTA firmware updates on the SiWx917 platform using Zephyr RTOS. It connects to a Wi-Fi network, establishes a secure HTTPS connection using a CA certificate, and downloads firmware updates from a remote server. The application showcases secure connectivity and OTA update mechanisms for IoT devices.
Copy link
Contributor

Choose a reason for hiding this comment

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

Warp you line at 80 columns.

************

* SiWx917 development board with Wi-Fi support.
* Windows PC to run HTTP server python script.
Copy link
Contributor

Choose a reason for hiding this comment

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

Which python script? It does not work with standard file sharing?

Copy link
Author

Choose a reason for hiding this comment

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

This application is verified with HTTP server python script

Copy link
Contributor

Choose a reason for hiding this comment

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

It is not clear. Can this application run with another http server? If no, why? If yes, why do we require a specific server?

* For non-secure updates (SECURED_IMAGE_UPDATE=0), the possible values to set HTTP_URL are:
* M4_RPS_FILE - M4 image file
* TA_RPS_FILE - TA image file
* COMBINED_RPS_FILE - Combined image file
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you can replace app_config.h by Kconfig.

int ret;

ret = setup_socket(family, server, port, sock, addr, addr_len);
if (ret < 0 || *sock < 0) {
Copy link
Contributor

Choose a reason for hiding this comment

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

You will simplify your code if you adopt a more Posix way to design setup_socket(). I suggest to return the socket file descriptor (>= 0) on success and -errno on error.

Ditto for http_connect_socket().

BTW, does it make sense to have setup_socket() and http_connect_socket(). Shouldn't we merge them?

printf("\r\nWLAN_SCAN_STATE\r\n");
struct wifi_scan_params params = { 0 };
params.dwell_time_active = 99;
if (net_mgmt(NET_REQUEST_WIFI_SCAN, iface, &params, sizeof(params))) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid large blocks of code inside switch .. case.

}break;
}
}
}
Copy link
Contributor

@jerome-pouiller jerome-pouiller Sep 16, 2025

Choose a reason for hiding this comment

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

I have no clue of what you are doing in this function. I believe the way to manage the state machine is wrong. I believe you can get rid of the states and make the nominal case clearer:

void app_try_ota()
{
    ret = wait_for_network();
    if (ret)
        return;
    http_connect_socket();
    ret = wait_for_server();
    if (ret)
        return;
    while (end < ota_image_size - 1) {
        ret = handle_http_packet(msg_c.buffer, msg_c.length);
        if (ret)
            return;
    }
    sl_si91x_soc_nvic_reset();
}

int main()
{
    ...
    while (1) {
        // app_try_ota() does not return in case of success
        app_try_ota();
    }
}

Copy link
Author

Choose a reason for hiding this comment

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

Using a state machine approach can be effective for managing error conditions. If an error occurs in a particular state, we can handle by transitioning back to the appropriate state.

Copy link
Contributor

Choose a reason for hiding this comment

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

For now this code is unmaintainable. Unless you know what you are doing, I suggest to change this design.

However, of course, if you are able to present this code properly, I am fine to approve it.

} break;
}
return status;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Same comment here. Rewrite this function.

Copy link
Author

Choose a reason for hiding this comment

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

Using a state machine approach can be effective for managing error conditions. If an error occurs in a particular state, we can handle by transitioning back to the appropriate state.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ditto

#endif
uint32_t status = 0;
uint8_t otaf_header_size = 0;
switch(otaf_state)
Copy link
Contributor

Choose a reason for hiding this comment

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

Add a blank line between variable declarations and the first statement.

zephyr_code_relocate(FILES ${WISECONNECT_DIR}/components/device/silabs/si91x/wireless/ahb_interface/inc/sli_siwx917_soc.h LOCATION RAM)
zephyr_code_relocate(FILES ${WISECONNECT_DIR}/components/sli_si91x_wifi_event_handler/src/sli_si91x_wifi_event_handler.c LOCATION RAM)
zephyr_code_relocate(FILES ${WISECONNECT_DIR}/components/sli_wifi_command_engine/src/sli_wifi_command_engine.c LOCATION RAM)
zephyr_code_relocate(FILES ${SERVICE_DIR}/sleeptimer/src/sl_sleeptimer.c LOCATION RAM) No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

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

What performance degradation do you get? If this kind of hack is required to get sane performance, we have raise the issue and address it.

************

* SiWx917 development board with Wi-Fi support.
* Windows PC to run HTTP server python script.
Copy link
Contributor

Choose a reason for hiding this comment

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

It is not clear. Can this application run with another http server? If no, why? If yes, why do we require a specific server?

# Memory and Threading
CONFIG_MAIN_STACK_SIZE=2048
CONFIG_INIT_STACKS=y
CONFIG_HEAP_MEM_POOL_SIZE=16384
Copy link
Contributor

Choose a reason for hiding this comment

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

Where this allocation happens? If want to increase the space available for malloc(), this is not the correct option (this option in fact make the memory unavailable for malloc()). This mem pool is normally used for kernel object allocation. Unless you have specific reason, you should have to change it.


# WiFi Configuration
CONFIG_WIFI=y
CONFIG_WIFI_SILABS_SIWX91X_NET_STACK_NATIVE=y
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 this the default and you don't need to specify this option.

Copy link
Author

Choose a reason for hiding this comment

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

I believe this option is to differentiate between native or offload stack. The files siwx91x_wifi.c, siwx91x_wifi_ap.c, and siwx91x_wifi_sta.c contain code that conditionally executes based on the CONFIG_WIFI_SILABS_SIWX91X_NET_STACK_NATIVE macro

Copy link
Contributor

Choose a reason for hiding this comment

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

Indeed, but CONFIG_WIFI_SILABS_SIWX91X_NET_STACK_NATIVE set by default if you enable Wifi. You don't need to specify it.

Copy link
Author

Choose a reason for hiding this comment

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

ok

dhcpv6_params.request_addr = true;
dhcpv6_params.request_prefix = false;
printf("\r\ndhcpv6 start\r\n");
net_dhcpv6_start(iface, &dhcpv6_params);
Copy link
Contributor

Choose a reason for hiding this comment

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

I think Zephyr support SLAAC for configuration. Then, I don't think you need DHCPv6.

CONFIG_MBEDTLS_ENABLE_HEAP=y
CONFIG_MBEDTLS_HEAP_SIZE=60000
CONFIG_TLS_CREDENTIALS=y
CONFIG_NET_SOCKETS_SOCKOPT_TLS=y
Copy link
Contributor

Choose a reason for hiding this comment

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

I may miss things, but the following config should be very close of what you need ():

CONFIG_NETWORKING=y
CONFIG_WIFI=y

CONFIG_NET_IPV6=y
CONFIG_NET_IPV4=y
CONFIG_NET_DHCPV4=y
CONFIG_NET_TCP=y
CONFIG_NET_SOCKETS=y
CONFIG_NET_SOCKETS_SOCKOPT_TLS=y
CONFIG_HTTP_CLIENT=y

CONFIG_MAIN_STACK_SIZE=2048

You may improve compatibility with TLS servers by adding the snippet below, but I think this is not strictly required.

CONFIG_MBEDTLS_CIPHER_ALL_ENABLED=y
CONFIG_MBEDTLS_POLY1305=y

Also note I suggest to use the zsock_*() function so you won't depends on CONFIG_POSIX_API.

#else
#define SSID "<AP-SSID>"
#define PSK "<AP-PASSPHRASE>"
#define HTTP_SERVER_ADDR "<SERVER-ADDR>"
Copy link
Contributor

Choose a reason for hiding this comment

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

hmm... indeed, I see your workaround with TLS_HOSTNAME = NULL. Probably we want to keep that. I suggest to add note explaining this does not for production and how to properly check the FQDN.

Anyway, FQDN will be usual case and we have to accept an hostname instead of an an IP (zsock_getaddrinfo() also accept raw IP address anyway).

#include "sl_si91x_hal_soc_soft_reset.h"

/* Event masks */
#define L4_EVENT_MASK (NET_EVENT_L4_IPV6_CONNECTED)
Copy link
Contributor

Choose a reason for hiding this comment

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

You can just use:

	net_mgmt_init_event_callback(&l4_cb, l4_event_handler, NET_EVENT_L4_IPV6_CONNECTED);

L4_EVENT_MASK just make the code more difficult to understand.

int end = (CHUNK_SIZE - 1);
int otaf_state = START_IMAGE;
uint16_t http_sts_code = 0;
osMessageQueueId_t http_data_q;
Copy link
Contributor

Choose a reason for hiding this comment

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

osMessageQueueId_t is not a Zephyr native structure. It provided by the CMSIS-RTOS interface to simplify portability of existing applications.

char link_local[NET_IPV6_ADDR_LEN] = {0};
char ipv6_address[NET_IPV6_ADDR_LEN] = {0};
static struct net_mgmt_event_callback l4_cb;
#endif
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid global variables.

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

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

@jhedberg
Copy link
Collaborator

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

Nevermind. Rerunning the workflow was sufficient, since it does a rebase itself. The check is passing now.

OTA_STATE_SERVER_CONNECT, /**< Connect to OTA server */
OTA_STATE_DOWNLOAD, /**< Download firmware image */
OTA_STATE_PROCESS, /**< Process downloaded firmware */
};
Copy link
Contributor

Choose a reason for hiding this comment

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

This symbol doesn't need to be exported. You can move it to main.c (then app_config.h will be useless)

Copy link
Author

Choose a reason for hiding this comment

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

ok

char resolved_addr_str[(CONFIG_OTA_IP_PROTOCOL_SELECTION == 0) ? INET_ADDRSTRLEN
: INET6_ADDRSTRLEN];
static bool ipv6_addr_config_done;
volatile enum ota_state state = OTA_STATE_INIT;
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid global variables. You can probably move them to struct app_ctx (or even better, change them in local variables).

static struct net_mgmt_event_callback l4_cb;
struct app_ctx app_ctx = {.wlan_sem = Z_SEM_INITIALIZER(app_ctx.wlan_sem, 0, 1),
.ota_sem = Z_SEM_INITIALIZER(app_ctx.ota_sem, 0, 1),
.dhcp_sem = Z_SEM_INITIALIZER(app_ctx.dhcp_sem, 0, 1)};
Copy link
Contributor

Choose a reason for hiding this comment

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

Add new lines after opening brace and before closing braces:

	struct app_ctx app_ctx = {
		.wlan_sem = Z_SEM_INITIALIZER(app_ctx.wlan_sem, 0, 1),
		.ota_sem = Z_SEM_INITIALIZER(app_ctx.ota_sem, 0, 1),
		.dhcp_sem = Z_SEM_INITIALIZER(app_ctx.dhcp_sem, 0, 1)
	};


iface = net_if_get_first_wifi();
net_mgmt_init_event_callback(&app_ctx.wlan_mgmt_cb, wifi_mgmt_event_handler,
(WIFI_SHELL_MGMT_EVENTS_COMMON));
Copy link
Contributor

Choose a reason for hiding this comment

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

Parentheses around WIFI_SHELL_MGMT_EVENTS_COMMON are probably useless.


case OTA_STATE_IP_CONFIG:
ret = configure_ip(app_ctx_st);
state = (ret == 0) ? OTA_STATE_SERVER_CONNECT : OTA_STATE_IP_CONFIG;
Copy link
Contributor

Choose a reason for hiding this comment

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

Ditto.

Copy link
Author

Choose a reason for hiding this comment

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

I am not updating the next state in the dhcp callback.

int firmware_status = 0;
char *ssid = CONFIG_OTA_WIFI_SSID;
char *pwd = CONFIG_OTA_WIFI_PSK;
sl_wifi_firmware_version_t version = {0};
Copy link
Contributor

Choose a reason for hiding this comment

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

sl_wifi_firmware_version_t version = { }; is sufficient.

} else {
printf("Failed to get firmware version: 0x%x\n", ret);
}
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.

This state is only used one. You can simplify your FSM by placing this code outside of the loop. (BTW, since version is only used for this part, I suggest to create a function for that task).

break;
case NET_EVENT_WIFI_DISCONNECT_RESULT:
handle_wifi_disconnect_result(cb);
break;
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, the purpose of these callbacks are only to provide info to the user. In this case, why do they need semaphore? Globally, since the call back only change the state, I am not sure any the semaphore are useful (we only have to ensure state is accessed atomically).

Copy link
Author

@Devika-Raju-Z Devika-Raju-Z Sep 27, 2025

Choose a reason for hiding this comment

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

Timeout for receiving the response is implemented using semaphore. If we didn't receive the callback within timeout, status setting as error and retrying.

}
/* Purge any remaining messages */
k_msgq_purge(&http_data_q);
return;
Copy link
Contributor

Choose a reason for hiding this comment

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

Give an opportunity to the FSM to be useful. Catch the error and repair it. (ditto for wifi disconnection)

@Devika-Raju-Z Devika-Raju-Z force-pushed the https_otaf branch 5 times, most recently from 32f6693 to 053214b Compare September 30, 2025 10:57
char *full_url = CONFIG_OTA_UPDATE_URL;
size_t data_len;

memset(&parser, 0, sizeof(parser));
Copy link
Contributor

Choose a reason for hiding this comment

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

Redundant with http_parser_url_init().

int ret = http_parser_parse_url(full_url, strlen(full_url), 0, &parser);
if (ret) {
printf("Failed to parse URL: %s\n", full_url);
return -EINVAL;
Copy link
Contributor

Choose a reason for hiding this comment

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

Considering:

  • this is a fatal error you can't recover
  • this is sample (pedagogic) code

You can use __ASSERT(). Same comment in case host, path or schema is not specified.

BTW, you need to retrieve the schema to know if TLS is enabled or not.
You also need to set a default value for the port if it is not specified.

return -errno;
}

if (IS_ENABLED(CONFIG_OTA_HTTPS_SUPPORT)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

CONFIG_OTA_HTTPS_SUPPORT is not required, you can look at the schema of the URL. You may __ASSERT(IS_ENABLED(CONFIG_NET_SOCKETS_SOCKOPT_TLS), "Application was built without support for TLS");.

addr_ptr = &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
}
zsock_inet_ntop(res->ai_family, addr_ptr, addr_str, sizeof(addr_str));
printf("Connected to %s:%s\n", addr_str, http_parse_data_st.port);
Copy link
Contributor

Choose a reason for hiding this comment

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

Just print http_parse_data_st.host. So you won't have to do the conversion above.

struct dns_resolve_context *dnsctx;

dnsctx = dns_resolve_get_default();
ret = dns_resolve_reconfigure(dnsctx, dns_servers, NULL, DNS_SOURCE_MANUAL);
Copy link
Contributor

Choose a reason for hiding this comment

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

In Ipv6 DNS is provided by RDNS field of the Router Advertisements. You don't have to manage manually.
You have to add the symbol CONFIG_NET_IPV6_RA_RDNSS in prj.conf.

The user may enable CONFIG_DNS_SERVER_IP_ADDRESSES=y if his network does not support RDNS.

void *addr_ptr;
struct zsock_addrinfo hints = {
.ai_family = (CONFIG_OTA_IP_PROTOCOL_SELECTION == 0) ? AF_INET : AF_INET6,
.ai_socktype = SOCK_STREAM};
Copy link
Contributor

Choose a reason for hiding this comment

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

Hints is not really required. Zephyr will already automatically selects the right IP version.

printf("Failed to set TLS_HOSTNAME option (%d)\n", -errno);
zsock_close(*sock_ptr);
zsock_freeaddrinfo(res);
return -errno;
Copy link
Contributor

Choose a reason for hiding this comment

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

I suggest to manage the errors of this function using a label and goto.

BTW, "Connection failed is definitely something we want to report. But, the others (Failed to create TLS socket, Failed to set TLS secure option, etc...) should really not happen. Since it is a pedagogic code, I am not sure it make sense to clutter the code with such debug traces.

.protocol = "HTTP/1.1",
.response = ota_http_response_cb,
.recv_buf = app_ctx_st->http_recv_buf,
.recv_buf_len = sizeof(app_ctx_st->http_recv_buf)};
Copy link
Contributor

Choose a reason for hiding this comment

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

Prefer this format:

	struct http_request req = {
		.method = HTTP_GET,
		.url = app_ctx_st->http_parse_data_st.path,
		.header_fields = headers,
		.host = app_ctx_st->http_parse_data_st.host,
		.protocol = "HTTP/1.1",
		.response = ota_http_response_cb,
		.recv_buf = app_ctx_st->http_recv_buf,
		.recv_buf_len = sizeof(app_ctx_st->http_recv_buf)
	};

{
int ret = 0;
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.

Add space after { and before }.

0x31, 0xee, 0x2a, 0x3b, 0x7b, 0xf0, 0x2c, 0x9e, 0x6f, 0xe9, 0xc4, 0x07, 0x81, 0x24, 0xda,
0x05, 0x70, 0x4d, 0xdd, 0x09, 0xae, 0x9e, 0x72, 0xb8, 0x21, 0x0e, 0x8c, 0xb2, 0xab, 0xaa,
0x4c, 0x49, 0x10, 0xf7, 0x76, 0xf9, 0xb5, 0x0d, 0x6c, 0x20, 0xd3, 0xdf, 0x7a, 0x06, 0x32,
0x8d, 0x29, 0x1f, 0x28, 0x1d, 0x8d, 0x26, 0x33};
Copy link
Contributor

Choose a reason for hiding this comment

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

The original code with the conversion was fine. Why did you change it?

Copy link
Author

Choose a reason for hiding this comment

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

With .pem format, the client is closing the connection after the TCP handshake. I was unable to connect with server. I checked by enabling the CONFIG_MBEDTLS_PEM_CERTIFICATE_FORMAT, but it didn't work

if (final_data && staging_len > 0) {
msg_p.length = staging_len;
memcpy(msg_p.buffer, staging_buf, staging_len);
if (k_msgq_put(&app_ctx_st->http_data_q, &msg_p, K_NO_WAIT)) {
Copy link
Contributor

@jerome-pouiller jerome-pouiller Sep 30, 2025

Choose a reason for hiding this comment

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

I am not sure you need this callback. This is only required to process the data on the fly. But in your case, you can wait the request terminate. I believe you just have to process req->recv_buf / req->data_len after the call to http_client_req().

BTW, I believe http_data_q is also useless since we store only one buffer at time and we don't do any new request while the previous one is not finished.

BTW, can you place this function close to download_firmware_chunk(), so the code is easier to read.

Copy link
Author

Choose a reason for hiding this comment

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

We can't use the http_client_req API without passing callback. If we pass callback as NULL, it gives invalid argument error while executing

@Devika-Raju-Z Devika-Raju-Z force-pushed the https_otaf branch 5 times, most recently from b8b78eb to 9a126e8 Compare October 1, 2025 08:01
This application demonstrates the support for OTA
firmware upgrade.

Signed-off-by: Devika Raju <[email protected]>
@Devika-Raju-Z Devika-Raju-Z force-pushed the https_otaf branch 3 times, most recently from 6025ad2 to 8cc35e9 Compare October 1, 2025 09:07
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.

3 participants