Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
892e18a
Add empty OTA sample
roberthusak Feb 25, 2026
b5ffcac
Add OTA Kconfig
roberthusak Feb 25, 2026
6abcbbf
Remove unnecessary option selection from OTA Kconfig
roberthusak Feb 26, 2026
205dc0b
Add subscription to OTA topic and update message parsing
roberthusak Feb 26, 2026
ce148a5
Clean up conditional compilation to make logging to cloud optional
roberthusak Feb 26, 2026
56ba263
Fix OTA compilation
roberthusak Feb 26, 2026
2bfb51b
Add FRDM-RW612 specific configuration to OTA sample
roberthusak Feb 26, 2026
b6dba31
Add initial implementation of OTA download
roberthusak Feb 27, 2026
1396cb5
Tune configuration to make HTTPS work
roberthusak Mar 2, 2026
cdb8dfa
Add image confirmation to OTA sample
roberthusak Mar 4, 2026
2ca2811
Make TLS for OTA work by updating sample prj.conf
roberthusak Mar 4, 2026
a19f19f
Fix missing image slot erasing
roberthusak Mar 24, 2026
b2c9385
Select IMG_ERASE_PROGRESSIVELY in Kconfig
roberthusak Mar 30, 2026
da611b8
Set necessary MBEDTLS_SSL_MAX_CONTENT_LEN in Kconfig
roberthusak Mar 30, 2026
a9ce22a
Fix formatting
roberthusak Mar 31, 2026
2a15606
Move Mbed TLS heap size configuration to Kconfig
roberthusak Apr 1, 2026
65b8cbb
Move OTA downloading and URL parsing logic to separate files
roberthusak Apr 1, 2026
02d277f
Remove s_ prefix from static global variables
roberthusak Apr 1, 2026
822b5e9
Fix race condition of image URL for download
roberthusak Apr 1, 2026
2b13b4a
Enable logging and reboot metrics in OTA sample
roberthusak Apr 2, 2026
628b9f3
Add TEST_FIRMWARE_UPGRADE to reboot reasons
roberthusak Apr 2, 2026
23afe77
Simplify if defined() to ifdef
roberthusak Apr 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions zephyr/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ add_subdirectory(src/net)
add_subdirectory(src/config)
add_subdirectory(src/coredumps)
add_subdirectory(src/metrics)
add_subdirectory(src/ota)

zephyr_include_directories(
src
Expand Down
14 changes: 12 additions & 2 deletions zephyr/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,12 @@ menuconfig SPOTFLOW

if SPOTFLOW

rsource "src/config/Kconfig"
rsource "src/logging/KConfig"
rsource "src/coredumps/KConfig"
rsource "src/metrics/Kconfig"
rsource "src/metrics/system/Kconfig"

rsource "src/ota/Kconfig"

config SPOTFLOW_GENERATE_BUILD_ID
bool "Generate build ID"
Expand All @@ -47,7 +48,10 @@ config SPOTFLOW_GENERATE_BUILD_ID
Build ID allows to match core dumps with the original .elf file.

configdefault MBEDTLS_SSL_MAX_CONTENT_LEN
default 4096 if SPOTFLOW
# TODO: Remove if we manage to support max_fragment_length in the CDN
# (and reflect that in MBEDTLS_HEAP_SIZE as well)
default 16384 if SPOTFLOW_OTA
default 4096

if NRF_SECURITY
configdefault MBEDTLS_MPI_MAX_SIZE
Expand All @@ -69,9 +73,15 @@ if MBEDTLS_ENABLE_HEAP
# recommended size for mbedtls heap is 32kB
# to be able to verify whole Lets Encrypt certificate chain
configdefault MBEDTLS_HEAP_SIZE
default 98304 if SPOTFLOW_OTA
default 32768
endif # MBEDTLS_ENABLE_HEAP

if SPOTFLOW_OTA
configdefault NET_SOCKETS_TLS_MAX_CONTEXTS
default 2
endif # SPOTFLOW_OTA

config SPOTFLOW_SERVER_HOSTNAME
string "Hostname of Spotflow observability platform"
depends on SPOTFLOW
Expand Down
17 changes: 17 additions & 0 deletions zephyr/samples/ota/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
cmake_minimum_required(VERSION 3.20.0)

if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/credentials.conf")
list(APPEND EXTRA_CONF_FILE "${CMAKE_CURRENT_SOURCE_DIR}/credentials.conf")
endif()

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(ota)

# Verify that this sample is built through sysbuild to ensure MCUboot is used
test_sysbuild()

add_subdirectory(../net-common ${CMAKE_CURRENT_BINARY_DIR}/net-common)

target_sources(app PRIVATE
src/main.c
)
3 changes: 3 additions & 0 deletions zephyr/samples/ota/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
rsource "../net-common/Kconfig"

source "Kconfig.zephyr"
2 changes: 2 additions & 0 deletions zephyr/samples/ota/boards/frdm_mcxn947_mcxn947_cpu0.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# TODO: Copied from RW612, test if needed
CONFIG_NET_BUF_DATA_SIZE=256
9 changes: 9 additions & 0 deletions zephyr/samples/ota/boards/frdm_rw612.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# These configs are automatically enabled for FRDM-RW612 board from kconfig
#WIFI_NXP
#NXP_WIFI_TX_RX_ZERO_COPY
#NET_IF_MAX_IPV4_COUNT=2

# Fix buffer size for RW612 on Zephyr 4.1.0+
CONFIG_NET_BUF_DATA_SIZE=256

CONFIG_NXP_WIFI_SOFTAP_SUPPORT=n
44 changes: 44 additions & 0 deletions zephyr/samples/ota/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Boards that support both Wi-Fi and Ethernet use Wi-Fi by default.
# If you want to use Ethernet instead, please use the following option:
# CONFIG_SPOTFLOW_USE_ETH=y

# Enable Spotflow logging and OTA updates
CONFIG_SPOTFLOW=y
CONFIG_SPOTFLOW_OTA=y

# Enable Spotflow reboot metrics, disable others
CONFIG_SPOTFLOW_METRICS=y
CONFIG_SPOTFLOW_METRICS_SYSTEM=y
CONFIG_SPOTFLOW_METRICS_SYSTEM_HEAP=n
CONFIG_SPOTFLOW_METRICS_SYSTEM_NETWORK=n
CONFIG_SPOTFLOW_METRICS_SYSTEM_CPU=n
CONFIG_SPOTFLOW_METRICS_SYSTEM_CONNECTION=n
CONFIG_SPOTFLOW_METRICS_SYSTEM_RESET_CAUSE=y
CONFIG_SPOTFLOW_METRICS_SYSTEM_STACK=n

# Enable logging
CONFIG_LOG=y

# Show function names in the logs
CONFIG_LOG_FUNC_NAME_PREFIX_INF=y
CONFIG_LOG_FUNC_NAME_PREFIX_WRN=y
CONFIG_LOG_FUNC_NAME_PREFIX_ERR=y

# Log Spotflow module details for debugging
CONFIG_SPOTFLOW_MODULE_DEFAULT_LOG_LEVEL=4

# Satisfy networking dependencies of Spotflow
CONFIG_NETWORKING=y
CONFIG_NET_MGMT=y
CONFIG_NET_MGMT_EVENT=y
CONFIG_NET_MGMT_EVENT_INFO=y
CONFIG_NET_CONFIG_AUTO_INIT=n
CONFIG_NET_CONNECTION_MANAGER=y
CONFIG_NET_DHCPV4=y
CONFIG_NET_IPV4=y
CONFIG_NET_IPV6=n
CONFIG_NET_TCP=y
CONFIG_NET_UDP=y

# Increase main stack size for the sample
CONFIG_MAIN_STACK_SIZE=4096
37 changes: 37 additions & 0 deletions zephyr/samples/ota/src/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include <zephyr/logging/log.h>
#include <zephyr/dfu/mcuboot.h>

#include "net.h"

LOG_MODULE_REGISTER(ota_sample, LOG_LEVEL_INF);

int main(void)
{
/* TODO: Add a Kconfig option and instructions to README */
/* Uncomment for versions to be downloaded */
// LOG_INF("I was downloaded from the web!");

LOG_INF("Starting Spotflow OTA example");

if (boot_is_img_confirmed()) {
LOG_INF("Current image is confirmed");
} else {
LOG_INF("Current image is NOT confirmed (test mode)");
LOG_INF("Confirming current image...");
int ret = boot_write_img_confirmed();
if (ret) {
LOG_ERR("ERROR: Failed to confirm image: %d", ret);
} else {
LOG_INF("Image confirmed successfully");
}
}

/* Wait for the initialization of network device */
k_sleep(K_SECONDS(1));

spotflow_sample_net_init();

LOG_INF("Ready to receive OTA updates");

return 0;
}
1 change: 1 addition & 0 deletions zephyr/samples/ota/sysbuild.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SB_CONFIG_BOOTLOADER_MCUBOOT=y
1 change: 1 addition & 0 deletions zephyr/samples/ota/sysbuild/mcuboot.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CONFIG_MCUBOOT_LOG_LEVEL_DBG=y
3 changes: 1 addition & 2 deletions zephyr/src/config/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
zephyr_library_sources_ifdef(CONFIG_SPOTFLOW_LOG_BACKEND
zephyr_library_sources_ifdef(CONFIG_SPOTFLOW_CONFIG
spotflow_config.c
spotflow_config_cbor.c
spotflow_config_options.c
spotflow_config_net.c
spotflow_config_persistence.c
)

7 changes: 7 additions & 0 deletions zephyr/src/config/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
config SPOTFLOW_CONFIG
bool
default y if SPOTFLOW_LOG_BACKEND
default n
help
Spotflow configuration is enabled automatically when needed by any other part of the SDK
(currently only by the logging backend).
51 changes: 41 additions & 10 deletions zephyr/src/metrics/system/spotflow_reset_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
#include "metrics/spotflow_metrics_backend.h"
#include "zephyr/logging/log.h"

#if defined(CONFIG_MCUBOOT_IMG_MANAGER)
#include <zephyr/dfu/mcuboot.h>
#endif
#include <zephyr/drivers/hwinfo.h>
#include <stdio.h>

Expand Down Expand Up @@ -32,7 +35,12 @@ static const struct {

#define RESET_CAUSE_COUNT ARRAY_SIZE(reset_cause_map)

void reset_cause_to_string(uint32_t cause, char* buf, size_t buf_len);
static void reset_cause_to_string(uint32_t cause, char* buf, size_t buf_len);

static bool is_test_firmware_upgrade(void);

static bool append_cause_name(char* buf, size_t buf_len, size_t* used, bool* first,
const char* name);

void spotflow_report_reboot_reason(void)
{
Expand Down Expand Up @@ -69,33 +77,56 @@ void spotflow_report_reboot_reason(void)
hwinfo_clear_reset_cause();
}

void reset_cause_to_string(uint32_t cause, char* buf, size_t buf_len)
static void reset_cause_to_string(uint32_t cause, char* buf, size_t buf_len)
{
size_t used = 0;
bool first = true;
bool test_firmware_upgrade = is_test_firmware_upgrade();

if (buf_len == 0) {
return;
}

buf[0] = '\0';

if (cause == 0U) {
if (cause == 0U && !test_firmware_upgrade) {
snprintk(buf, buf_len, "UNKNOWN");
return;
}

for (size_t i = 0; i < RESET_CAUSE_COUNT; i++) {
if (cause & reset_cause_map[i].flag) {
int n = snprintk(buf + used, buf_len - used, "%s%s", first ? "" : " | ",
reset_cause_map[i].name);

if (n < 0 || (size_t)n >= buf_len - used) {
if (!append_cause_name(buf, buf_len, &used, &first,
reset_cause_map[i].name)) {
return; /* truncated safely */
}

used += n;
first = false;
}
}

if (test_firmware_upgrade) {
(void)append_cause_name(buf, buf_len, &used, &first, "TEST_FIRMWARE_UPGRADE");
}
}

static bool is_test_firmware_upgrade(void)
{
#ifdef CONFIG_MCUBOOT_IMG_MANAGER
return !boot_is_img_confirmed();
#else
return false;
#endif
}

static bool append_cause_name(char* buf, size_t buf_len, size_t* used, bool* first,
const char* name)
{
int n = snprintk(buf + *used, buf_len - *used, "%s%s", *first ? "" : " | ", name);

if (n < 0 || (size_t)n >= buf_len - *used) {
return false;
}

*used += n;
*first = false;
return true;
}
18 changes: 8 additions & 10 deletions zephyr/src/net/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
zephyr_library_sources_ifdef(CONFIG_SPOTFLOW_LOG_BACKEND
zephyr_library_sources(
spotflow_processor.c
spotflow_connection_helper.c
spotflow_device_id.c
Expand All @@ -9,13 +9,11 @@

zephyr_library_link_libraries(mbedTLS)

if (CONFIG_SPOTFLOW_LOG_BACKEND)
if (NOT CONFIG_SPOTFLOW_DEVICE_ID)
message(FATAL_ERROR "CONFIG_SPOTFLOW_DEVICE_ID must be specified
if CONFIG_SPOTFLOW_LOG_BACKEND enabled")
endif ()
if (NOT CONFIG_SPOTFLOW_INGEST_KEY)
message(FATAL_ERROR "CONFIG_SPOTFLOW_INGEST_KEY
must be specified if CONFIG_SPOTFLOW_LOG_BACKEND enabled")
endif()
if (NOT CONFIG_SPOTFLOW_DEVICE_ID)
message(FATAL_ERROR
"CONFIG_SPOTFLOW_DEVICE_ID must be specified if CONFIG_SPOTFLOW is enabled")
endif ()
if (NOT CONFIG_SPOTFLOW_INGEST_KEY)
message(FATAL_ERROR
"CONFIG_SPOTFLOW_INGEST_KEY must be specified if CONFIG_SPOTFLOW is enabled")
endif()
Loading
Loading