From 3e04a4a4f6af99c372d1985414b47e7fcbad664c Mon Sep 17 00:00:00 2001 From: Arkadiusz Balys Date: Fri, 25 Apr 2025 14:13:16 +0200 Subject: [PATCH 1/6] modules: openthread: Synchronize openthread platform with Zephyr Updated modules/openthread/platform after latest changes in Zephyr. Aligned openthread implementation to the new approach. Signed-off-by: Arkadiusz Balys --- modules/openthread/CMakeLists.txt | 7 + modules/openthread/openthread.c | 483 +++++++++++++++++++++ modules/openthread/platform/CMakeLists.txt | 1 - modules/openthread/{platform => }/shell.c | 4 +- 4 files changed, 492 insertions(+), 3 deletions(-) create mode 100644 modules/openthread/openthread.c rename modules/openthread/{platform => }/shell.c (93%) diff --git a/modules/openthread/CMakeLists.txt b/modules/openthread/CMakeLists.txt index a8c73335bce2..3678bedd1f44 100644 --- a/modules/openthread/CMakeLists.txt +++ b/modules/openthread/CMakeLists.txt @@ -274,6 +274,13 @@ target_link_libraries(zephyr PRIVATE ${ot_libs}) endif() +# Create a library for the OpenThread Zephyr utils +zephyr_library_named(openthread_utils) +zephyr_library_sources( + openthread.c +) +zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_SHELL shell.c) + add_subdirectory(platform) endif() diff --git a/modules/openthread/openthread.c b/modules/openthread/openthread.c new file mode 100644 index 000000000000..908f96e815d5 --- /dev/null +++ b/modules/openthread/openthread.c @@ -0,0 +1,483 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * This file implements the OpenThread module initialization and state change handling. + * + */ + +#include +LOG_MODULE_REGISTER(net_openthread_platform, CONFIG_OPENTHREAD_PLATFORM_LOG_LEVEL); + +#include +#include +#include +#include +#include + +#include "platform-zephyr.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_OPENTHREAD_NAT64_TRANSLATOR) +#include +#endif /* CONFIG_OPENTHREAD_NAT64_TRANSLATOR */ + +#define OT_STACK_SIZE (CONFIG_OPENTHREAD_THREAD_STACK_SIZE) + +#if defined(CONFIG_OPENTHREAD_THREAD_PREEMPTIVE) +#define OT_PRIORITY K_PRIO_PREEMPT(CONFIG_OPENTHREAD_THREAD_PRIORITY) +#else +#define OT_PRIORITY K_PRIO_COOP(CONFIG_OPENTHREAD_THREAD_PRIORITY) +#endif + +#if defined(CONFIG_OPENTHREAD_NETWORK_NAME) +#define OT_NETWORK_NAME CONFIG_OPENTHREAD_NETWORK_NAME +#else +#define OT_NETWORK_NAME "" +#endif + +#if defined(CONFIG_OPENTHREAD_CHANNEL) +#define OT_CHANNEL CONFIG_OPENTHREAD_CHANNEL +#else +#define OT_CHANNEL 0 +#endif + +#if defined(CONFIG_OPENTHREAD_PANID) +#define OT_PANID CONFIG_OPENTHREAD_PANID +#else +#define OT_PANID 0 +#endif + +#if defined(CONFIG_OPENTHREAD_XPANID) +#define OT_XPANID CONFIG_OPENTHREAD_XPANID +#else +#define OT_XPANID "" +#endif + +#if defined(CONFIG_OPENTHREAD_NETWORKKEY) +#define OT_NETWORKKEY CONFIG_OPENTHREAD_NETWORKKEY +#else +#define OT_NETWORKKEY "" +#endif + +#if defined(CONFIG_OPENTHREAD_JOINER_PSKD) +#define OT_JOINER_PSKD CONFIG_OPENTHREAD_JOINER_PSKD +#else +#define OT_JOINER_PSKD "" +#endif + +#if defined(CONFIG_OPENTHREAD_PLATFORM_INFO) +#define OT_PLATFORM_INFO CONFIG_OPENTHREAD_PLATFORM_INFO +#else +#define OT_PLATFORM_INFO "" +#endif + +#if defined(CONFIG_OPENTHREAD_POLL_PERIOD) +#define OT_POLL_PERIOD CONFIG_OPENTHREAD_POLL_PERIOD +#else +#define OT_POLL_PERIOD 0 +#endif + +#define ZEPHYR_PACKAGE_NAME "Zephyr" +#define PACKAGE_VERSION KERNEL_VERSION_STRING + +static void openthread_process(struct k_work *work); + +/* Global variables to store the OpenThread module context */ +static otInstance *openthread_instance; +static sys_slist_t openthread_state_change_cbs = SYS_SLIST_STATIC_INIT(openthread_state_change_cbs); +static struct k_work_q openthread_work_q; + +static K_WORK_DEFINE(openthread_work, openthread_process); +static K_MUTEX_DEFINE(openthread_lock); +K_KERNEL_STACK_DEFINE(ot_stack_area, OT_STACK_SIZE); + +k_tid_t openthread_thread_id_get(void) +{ + return (k_tid_t)&openthread_work_q.thread; +} + +static int ncp_hdlc_send(const uint8_t *buf, uint16_t len) +{ + otError err = OT_ERROR_NONE; + + err = otPlatUartSend(buf, len); + if (err != OT_ERROR_NONE) { + return 0; + } + + return len; +} + +static void openthread_process(struct k_work *work) +{ + ARG_UNUSED(work); + + openthread_mutex_lock(); + + while (otTaskletsArePending(openthread_instance)) { + otTaskletsProcess(openthread_instance); + } + + otSysProcessDrivers(openthread_instance); + + openthread_mutex_unlock(); +} + +static void ot_joiner_start_handler(otError error, void *context) +{ + ARG_UNUSED(context); + + if (error != OT_ERROR_NONE) { + LOG_ERR("Join failed [%d]", error); + } else { + LOG_INF("Join success"); + error = otThreadSetEnabled(openthread_instance, true); + if (error != OT_ERROR_NONE) { + LOG_ERR("Failed to start the OpenThread network [%d]", error); + } + } +} + +static bool ot_setup_default_configuration(void) +{ + otExtendedPanId xpanid = {0}; + otNetworkKey networkKey = {0}; + otError error = OT_ERROR_NONE; + + error = otThreadSetNetworkName(openthread_instance, OT_NETWORK_NAME); + if (error != OT_ERROR_NONE) { + LOG_ERR("Failed to set %s [%d]", "network name", error); + return false; + } + + error = otLinkSetChannel(openthread_instance, OT_CHANNEL); + if (error != OT_ERROR_NONE) { + LOG_ERR("Failed to set %s [%d]", "channel", error); + return false; + } + + error = otLinkSetPanId(openthread_instance, OT_PANID); + if (error != OT_ERROR_NONE) { + LOG_ERR("Failed to set %s [%d]", "PAN ID", error); + return false; + } + + net_bytes_from_str(xpanid.m8, 8, (char *)OT_XPANID); + error = otThreadSetExtendedPanId(openthread_instance, &xpanid); + if (error != OT_ERROR_NONE) { + LOG_ERR("Failed to set %s [%d]", "ext PAN ID", error); + return false; + } + + if (strlen(OT_NETWORKKEY)) { + net_bytes_from_str(networkKey.m8, OT_NETWORK_KEY_SIZE, (char *)OT_NETWORKKEY); + error = otThreadSetNetworkKey(openthread_instance, &networkKey); + if (error != OT_ERROR_NONE) { + LOG_ERR("Failed to set %s [%d]", "network key", error); + return false; + } + } + + return true; +} + +static void ot_state_changed_handler(uint32_t flags, void *context) +{ + ARG_UNUSED(context); + + struct openthread_state_changed_callback *entry, *next; + + bool is_up = otIp6IsEnabled(openthread_instance); + + LOG_INF("State changed! Flags: 0x%08" PRIx32 " Current role: %s Ip6: %s", flags, + otThreadDeviceRoleToString(otThreadGetDeviceRole(openthread_instance)), + (is_up ? "up" : "down")); + + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&openthread_state_change_cbs, entry, next, node) { + if (entry->otCallback != NULL) { + entry->otCallback(flags, entry->user_data); + } + } +} + +void otTaskletsSignalPending(otInstance *instance) +{ + ARG_UNUSED(instance); + + int error = k_work_submit_to_queue(&openthread_work_q, &openthread_work); + if (error < 0) { + LOG_ERR("Failed to submit work to queue, error: %d", error); + } +} + +void otSysEventSignalPending(void) +{ + otTaskletsSignalPending(NULL); +} + +int openthread_state_changed_callback_register(struct openthread_state_changed_callback *cb) +{ + CHECKIF(cb == NULL || cb->otCallback == NULL) { + return -EINVAL; + } + + openthread_mutex_lock(); + sys_slist_append(&openthread_state_change_cbs, &cb->node); + openthread_mutex_unlock(); + + return 0; +} + +int openthread_state_changed_callback_unregister(struct openthread_state_changed_callback *cb) +{ + bool removed = false; + + CHECKIF(cb == NULL) { + return -EINVAL; + } + + openthread_mutex_lock(); + removed = sys_slist_find_and_remove(&openthread_state_change_cbs, &cb->node); + openthread_mutex_unlock(); + + if (!removed) { + return -EALREADY; + } + + return 0; +} + +struct otInstance *openthread_get_default_instance(void) +{ + __ASSERT(openthread_instance, "OT instance is not initialized"); + return openthread_instance; +} + +int openthread_init(void) +{ + struct k_work_queue_config q_cfg = { + .name = "openthread", + .no_yield = true, + }; + otError error = OT_ERROR_NONE; + + /* Prevent multiple initializations */ + if (openthread_instance) { + return 0; + } + + openthread_mutex_lock(); + + otSysInit(0, NULL); + openthread_instance = otInstanceInitSingle(); + + __ASSERT(openthread_instance, "OT instance initialization failed"); + + if (IS_ENABLED(CONFIG_OPENTHREAD_SHELL)) { + platformShellInit(openthread_instance); + } + + if (IS_ENABLED(CONFIG_OPENTHREAD_COPROCESSOR)) { + error = otPlatUartEnable(); + if (error != OT_ERROR_NONE) { + LOG_ERR("Failed to enable UART: [%d]", error); + } + + otNcpHdlcInit(openthread_instance, ncp_hdlc_send); + } else { + otIp6SetReceiveFilterEnabled(openthread_instance, true); + +#if defined(CONFIG_OPENTHREAD_NAT64_TRANSLATOR) + + otIp4Cidr nat64_cidr; + + if (otIp4CidrFromString(CONFIG_OPENTHREAD_NAT64_CIDR, &nat64_cidr) == + OT_ERROR_NONE) { + if (otNat64SetIp4Cidr(openthread_instance, &nat64_cidr) != OT_ERROR_NONE) { + LOG_ERR("Incorrect NAT64 CIDR"); + return -EIO; + } + } else { + LOG_ERR("Failed to parse NAT64 CIDR"); + return -EIO; + } +#endif /* CONFIG_OPENTHREAD_NAT64_TRANSLATOR */ + + error = otSetStateChangedCallback(openthread_instance, &ot_state_changed_handler, + NULL); + if (error != OT_ERROR_NONE) { + LOG_ERR("Could not set state changed callback: %d", error); + return -EIO; + } + } + + openthread_mutex_unlock(); + + /* Start work queue for the OpenThread module */ + k_work_queue_start(&openthread_work_q, ot_stack_area, K_KERNEL_STACK_SIZEOF(ot_stack_area), + OT_PRIORITY, &q_cfg); + + (void)k_work_submit_to_queue(&openthread_work_q, &openthread_work); + + return error == OT_ERROR_NONE ? 0 : -EIO; +} + +int openthread_run(void) +{ + openthread_mutex_lock(); + otError error = OT_ERROR_NONE; + + LOG_INF("OpenThread version: %s", otGetVersionString()); + + if (IS_ENABLED(CONFIG_OPENTHREAD_COPROCESSOR)) { + LOG_DBG("OpenThread co-processor."); + goto exit; + } + + error = otIp6SetEnabled(openthread_instance, true); + if (error != OT_ERROR_NONE) { + LOG_ERR("Failed to set %s [%d]", "IPv6 support", error); + goto exit; + } + + /* Sleepy End Device specific configuration. */ + if (IS_ENABLED(CONFIG_OPENTHREAD_MTD_SED)) { + otLinkModeConfig ot_mode = otThreadGetLinkMode(openthread_instance); + + /* A SED should always attach the network as a SED to indicate + * increased buffer requirement to a parent. + */ + ot_mode.mRxOnWhenIdle = false; + + error = otThreadSetLinkMode(openthread_instance, ot_mode); + if (error != OT_ERROR_NONE) { + LOG_ERR("Failed to set %s [%d]", "link mode", error); + goto exit; + } + + error = otLinkSetPollPeriod(openthread_instance, OT_POLL_PERIOD); + if (error != OT_ERROR_NONE) { + LOG_ERR("Failed to set %s [%d]", "poll period", error); + goto exit; + } + } + + /* Configure Child Supervision and MLE Child timeouts. */ + otChildSupervisionSetInterval(openthread_instance, + CONFIG_OPENTHREAD_CHILD_SUPERVISION_INTERVAL); + otChildSupervisionSetCheckTimeout(openthread_instance, + CONFIG_OPENTHREAD_CHILD_SUPERVISION_CHECK_TIMEOUT); + otThreadSetChildTimeout(openthread_instance, CONFIG_OPENTHREAD_MLE_CHILD_TIMEOUT); + + if (otDatasetIsCommissioned(openthread_instance)) { + /* OpenThread already has dataset stored - skip the + * configuration. + */ + LOG_DBG("OpenThread already commissioned."); + } else if (IS_ENABLED(CONFIG_OPENTHREAD_JOINER_AUTOSTART)) { + /* No dataset - initiate network join procedure. */ + LOG_DBG("Starting OpenThread join procedure."); + + error = otJoinerStart(openthread_instance, OT_JOINER_PSKD, NULL, + ZEPHYR_PACKAGE_NAME, OT_PLATFORM_INFO, PACKAGE_VERSION, NULL, + &ot_joiner_start_handler, NULL); + + if (error != OT_ERROR_NONE) { + LOG_ERR("Failed to start joiner [%d]", error); + } + + goto exit; + } else { + /* No dataset - load the default configuration. */ + LOG_DBG("Loading OpenThread default configuration."); + + if (!ot_setup_default_configuration()) { + goto exit; + } + } + + LOG_INF("Network name: %s", otThreadGetNetworkName(openthread_instance)); + + /* Start the network. */ + error = otThreadSetEnabled(openthread_instance, true); + if (error != OT_ERROR_NONE) { + LOG_ERR("Failed to start the OpenThread network [%d]", error); + } + +exit: + + openthread_mutex_unlock(); + + return error == OT_ERROR_NONE ? 0 : -EIO; +} + +int openthread_stop(void) +{ + otError error = OT_ERROR_NONE; + + if (IS_ENABLED(CONFIG_OPENTHREAD_COPROCESSOR)) { + return 0; + } + + openthread_mutex_lock(); + + error = otThreadSetEnabled(openthread_instance, false); + if (error == OT_ERROR_INVALID_STATE) { + LOG_DBG("Openthread interface was not up [%d]", error); + } + + openthread_mutex_unlock(); + + return 0; +} + +void openthread_set_receive_cb(openthread_receive_cb cb, void *context) +{ + __ASSERT(cb != NULL, "Receive callback is not set"); + __ASSERT(openthread_instance != NULL, "OpenThread instance is not initialized"); + + if (!IS_ENABLED(CONFIG_OPENTHREAD_COPROCESSOR)) { + openthread_mutex_lock(); + otIp6SetReceiveCallback(openthread_instance, cb, context); + +#if defined(CONFIG_OPENTHREAD_NAT64_TRANSLATOR) + otNat64SetReceiveIp4Callback(openthread_instance, cb, context); +#endif /* CONFIG_OPENTHREAD_NAT64_TRANSLATOR */ + + openthread_mutex_unlock(); + } +} + +void openthread_mutex_lock(void) +{ + (void)k_mutex_lock(&openthread_lock, K_FOREVER); +} + +int openthread_mutex_try_lock(void) +{ + return k_mutex_lock(&openthread_lock, K_NO_WAIT); +} + +void openthread_mutex_unlock(void) +{ + (void)k_mutex_unlock(&openthread_lock); +} diff --git a/modules/openthread/platform/CMakeLists.txt b/modules/openthread/platform/CMakeLists.txt index d67fe96e8fed..f4e67af59ca7 100644 --- a/modules/openthread/platform/CMakeLists.txt +++ b/modules/openthread/platform/CMakeLists.txt @@ -15,7 +15,6 @@ zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_BLE_TCAT ble.c) zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_DIAG diag.c) zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_COPROCESSOR uart.c) zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_CRYPTO_PSA crypto_psa.c) -zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_SHELL shell.c) zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_EXTERNAL_HEAP memory.c) zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_PLATFORM_MESSAGE_MANAGEMENT messagepool.c) zephyr_library_sources_ifdef(CONFIG_SETTINGS settings.c) diff --git a/modules/openthread/platform/shell.c b/modules/openthread/shell.c similarity index 93% rename from modules/openthread/platform/shell.c rename to modules/openthread/shell.c index 22f11d31f3eb..00de8d1e0dfe 100644 --- a/modules/openthread/platform/shell.c +++ b/modules/openthread/shell.c @@ -74,9 +74,9 @@ static int ot_cmd(const struct shell *sh, size_t argc, char *argv[]) shell_p = sh; - openthread_api_mutex_lock(openthread_get_default_context()); + openthread_mutex_lock(); otCliInputLine(rx_buffer); - openthread_api_mutex_unlock(openthread_get_default_context()); + openthread_mutex_unlock(); return 0; } From 3c0a54dde7072dfc5a8e6ed5b0f0b3c22a361a86 Mon Sep 17 00:00:00 2001 From: Arkadiusz Balys Date: Mon, 5 May 2025 10:48:11 +0200 Subject: [PATCH 2/6] modules: openthread: change log level to PLATFORM Stop using L2 log level in platform files. Signed-off-by: Arkadiusz Balys --- modules/openthread/platform/entropy.c | 2 +- modules/openthread/platform/radio.c | 2 +- modules/openthread/platform/settings.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/openthread/platform/entropy.c b/modules/openthread/platform/entropy.c index a52f885e3063..843d6a533d0b 100644 --- a/modules/openthread/platform/entropy.c +++ b/modules/openthread/platform/entropy.c @@ -10,7 +10,7 @@ #include -LOG_MODULE_REGISTER(net_otPlat_entropy, CONFIG_OPENTHREAD_L2_LOG_LEVEL); +LOG_MODULE_REGISTER(net_otPlat_entropy, CONFIG_OPENTHREAD_PLATFORM_LOG_LEVEL); #if !defined(CONFIG_CSPRNG_ENABLED) #error OpenThread requires an entropy source for a TRNG diff --git a/modules/openthread/platform/radio.c b/modules/openthread/platform/radio.c index 80673f65e64e..e2bdebed33fa 100644 --- a/modules/openthread/platform/radio.c +++ b/modules/openthread/platform/radio.c @@ -15,7 +15,7 @@ #define LOG_MODULE_NAME net_otPlat_radio #include -LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_OPENTHREAD_L2_LOG_LEVEL); +LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_OPENTHREAD_PLATFORM_LOG_LEVEL); #include #include diff --git a/modules/openthread/platform/settings.c b/modules/openthread/platform/settings.c index ce5fefde0c8d..4fdb77c6f9f0 100644 --- a/modules/openthread/platform/settings.c +++ b/modules/openthread/platform/settings.c @@ -11,7 +11,7 @@ #include -LOG_MODULE_REGISTER(net_otPlat_settings, CONFIG_OPENTHREAD_L2_LOG_LEVEL); +LOG_MODULE_REGISTER(net_otPlat_settings, CONFIG_OPENTHREAD_PLATFORM_LOG_LEVEL); #define OT_SETTINGS_ROOT_KEY "ot" #define OT_SETTINGS_MAX_PATH_LEN 32 From 4750b87c502dedeae70c56b2ec3ca797335f1a36 Mon Sep 17 00:00:00 2001 From: Arkadiusz Balys Date: Tue, 6 May 2025 14:37:07 +0200 Subject: [PATCH 3/6] openthread: Add possibility to initialize OpenThread in POST_KERNEL The new CONFIG_OPENTHREAD_SYS_INIT Kconfig option allows OpenThread to be automatically initialised during the Zephyr POST_KERNEL initialisation stage. If Zephyr's L2 layer OpenThread implementation is enabled, the IEEE802.15.4 shim layer initialises OpenThread in the POST_KERNEL phase. However, since Openthread may work without Zephyr's L2 layer, in this case, no object can initialise it automatically. This new Kconfig option may help start OpenThread automatically if the L2 Layer is disabled. Signed-off-by: Arkadiusz Balys Signed-off-by: Adrian Gielniewski --- modules/openthread/Kconfig | 15 +++++++++++++++ modules/openthread/openthread.c | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/modules/openthread/Kconfig b/modules/openthread/Kconfig index 3297a346a8f0..b5a856b72fcb 100644 --- a/modules/openthread/Kconfig +++ b/modules/openthread/Kconfig @@ -19,6 +19,21 @@ config OPENTHREAD if OPENTHREAD +config OPENTHREAD_SYS_INIT + bool "Initialize OpenThread stack during system initialization" + default y + depends on !NET_L2_OPENTHREAD + help + This option initializes the OpenThread automatically by calling the openthread_init() + function during system initialization. + +config OPENTHREAD_SYS_INIT_PRIORITY + int "OpenThread system initialization priority" + default 40 + depends on OPENTHREAD_SYS_INIT + help + This option sets the priority of the OpenThread system initialization. + choice OPENTHREAD_IMPLEMENTATION prompt "OpenThread origin selection" help diff --git a/modules/openthread/openthread.c b/modules/openthread/openthread.c index 908f96e815d5..60e198c50edd 100644 --- a/modules/openthread/openthread.c +++ b/modules/openthread/openthread.c @@ -481,3 +481,7 @@ void openthread_mutex_unlock(void) { (void)k_mutex_unlock(&openthread_lock); } + +#ifdef CONFIG_OPENTHREAD_SYS_INIT +SYS_INIT(openthread_init, POST_KERNEL, CONFIG_OPENTHREAD_SYS_INIT_PRIORITY); +#endif /* CONFIG_OPENTHREAD_SYS_INIT */ From 231e9968d9c750382f5e1e9a591074bbc5b733a2 Mon Sep 17 00:00:00 2001 From: Adrian Gielniewski Date: Thu, 29 May 2025 21:22:44 +0200 Subject: [PATCH 4/6] openthread: Add header for OpenThread module * Add header with public API of OpenThread module. * Add module include directory to Zephyr include directories. * Use new header in platform implementation. Signed-off-by: Adrian Gielniewski --- modules/openthread/CMakeLists.txt | 1 + modules/openthread/include/openthread.h | 163 ++++++++++++++++++++++++ modules/openthread/openthread.c | 3 +- modules/openthread/platform/ble.c | 7 +- modules/openthread/shell.c | 3 +- 5 files changed, 171 insertions(+), 6 deletions(-) create mode 100644 modules/openthread/include/openthread.h diff --git a/modules/openthread/CMakeLists.txt b/modules/openthread/CMakeLists.txt index 3678bedd1f44..b3b5bbc5f258 100644 --- a/modules/openthread/CMakeLists.txt +++ b/modules/openthread/CMakeLists.txt @@ -280,6 +280,7 @@ zephyr_library_sources( openthread.c ) zephyr_library_sources_ifdef(CONFIG_OPENTHREAD_SHELL shell.c) +zephyr_include_directories(include) add_subdirectory(platform) diff --git a/modules/openthread/include/openthread.h b/modules/openthread/include/openthread.h new file mode 100644 index 000000000000..36706e5cb125 --- /dev/null +++ b/modules/openthread/include/openthread.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_MODULES_OPENTHREAD_OPENTHREAD_H_ +#define ZEPHYR_MODULES_OPENTHREAD_OPENTHREAD_H_ + +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief The common callback type for receiving IPv4 (translated by NAT64) and IPv6 datagrams. + * + * This callback is called when a datagram is received. + * + * @param message The message to receive. + * @param context The context to pass to the callback. + */ +typedef void (*openthread_receive_cb)(struct otMessage *message, void *context); + +/** OpenThread state change callback */ + +/** + * @brief OpenThread state change callback structure + * + * Used to register a callback in the callback list. As many + * callbacks as needed can be added as long as each of them + * are unique pointers of struct openthread_state_changed_callback. + * + * @note You may destroy the object only after it is unregistered from the callback list. + */ +struct openthread_state_changed_callback { + /** + * @brief Callback for notifying configuration or state changes. + * + * @param otCallback OpenThread callback to register. + * See https://openthread.io/reference/group/api-instance#otstatechangedcallback for + * details. + */ + otStateChangedCallback otCallback; + + /** User data if required */ + void *user_data; + + /** + * Internally used field for list handling + * - user must not directly modify + */ + sys_snode_t node; +}; + +/** + * @brief Register callbacks that will be called when a certain configuration + * or state changes occur within OpenThread. + * + * @param cb Callback struct to register. + */ +int openthread_state_changed_callback_register(struct openthread_state_changed_callback *cb); + +/** + * @brief Unregister OpenThread configuration or state changed callbacks. + * + * @param cb Callback struct to unregister. + */ +int openthread_state_changed_callback_unregister(struct openthread_state_changed_callback *cb); + +/** + * @brief Get OpenThread thread identification. + */ +k_tid_t openthread_thread_id_get(void); + +/** + * @brief Get pointer to default OpenThread instance. + * + * @retval !NULL On success. + * @retval NULL On failure. + */ +struct otInstance *openthread_get_default_instance(void); + +/** + * @brief Initialize the OpenThread module. + * + * This function: + * - Initializes the OpenThread module. + * - Creates an OpenThread single instance. + * - Starts the shell. + * - Enables the UART and NCP HDLC for coprocessor purposes. + * - Initializes the NAT64 translator. + * - Creates a work queue for the OpenThread module. + * + * @note This function is automatically called by Zephyr's networking layer. + * If you want to initialize the OpenThread independently, call this function + * in your application init code. + * + * @retval 0 On success. + * @retval -EIO On failure. + */ +int openthread_init(void); + +/** + * @brief Run the OpenThread network. + * + * @details Prepares the OpenThread network and enables it. + * Depends on active settings: it uses the stored network configuration, + * starts the joining procedure or uses the default network configuration. + * Additionally, when the device is MTD, it sets the SED mode to properly + * attach the network. + */ +int openthread_run(void); + +/** + * @brief Disable the OpenThread network. + */ +int openthread_stop(void); + +/** + * @brief Set the additional callback for receiving packets. + * + * @details This callback is called once a packet is received and can be + * used to inject packets into the Zephyr networking stack. + * Setting this callback is optional. + * + * @param cb Callback to set. + * @param context Context to pass to the callback. + */ +void openthread_set_receive_cb(openthread_receive_cb cb, void *context); + +/** + * @brief Lock internal mutex before accessing OpenThread API. + * + * @details OpenThread API is not thread-safe. Therefore, before accessing any + * API function, you need to lock the internal mutex, to prevent the + * OpenThread thread from pre-empting the API call. + */ +void openthread_mutex_lock(void); + +/** + * @brief Try to lock internal mutex before accessing OpenThread API. + * + * @details This function behaves like openthread_mutex_lock(), provided that + * the internal mutex is unlocked. Otherwise, it returns a negative value without + * waiting. + */ +int openthread_mutex_try_lock(void); + +/** + * @brief Unlock internal mutex after accessing OpenThread API. + */ +void openthread_mutex_unlock(void); + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_MODULES_OPENTHREAD_OPENTHREAD_H_ */ diff --git a/modules/openthread/openthread.c b/modules/openthread/openthread.c index 60e198c50edd..03bd66bc4f3d 100644 --- a/modules/openthread/openthread.c +++ b/modules/openthread/openthread.c @@ -17,10 +17,11 @@ LOG_MODULE_REGISTER(net_openthread_platform, CONFIG_OPENTHREAD_PLATFORM_LOG_LEVE #include #include #include -#include #include "platform-zephyr.h" +#include + #include #include #include diff --git a/modules/openthread/platform/ble.c b/modules/openthread/platform/ble.c index ca40ae117be9..ea5427abc4b3 100644 --- a/modules/openthread/platform/ble.c +++ b/modules/openthread/platform/ble.c @@ -19,8 +19,7 @@ #include #include -/* Zephyr OpenThread integration Library */ -#include +#include /* OpenThread BLE driver API */ #include @@ -163,7 +162,7 @@ static void ot_plat_ble_thread(void *unused1, void *unused2, void *unused3) ring_buf_get(&ot_plat_ble_ring_buf, ot_plat_ble_msg_buf, len); } - openthread_api_mutex_lock(openthread_get_default_context()); + openthread_mutex_lock(); if (len <= PLAT_BLE_MSG_DATA_MAX) { /* The packet parameter in otPlatBleGattServerOnWriteRequest is not const. @@ -178,7 +177,7 @@ static void ot_plat_ble_thread(void *unused1, void *unused2, void *unused3) } else if (len == PLAT_BLE_MSG_DISCONNECT) { otPlatBleGapOnDisconnected(ble_openthread_instance, 0); } - openthread_api_mutex_unlock(openthread_get_default_context()); + openthread_mutex_unlock(); } } diff --git a/modules/openthread/shell.c b/modules/openthread/shell.c index 00de8d1e0dfe..f82e0b77c55c 100644 --- a/modules/openthread/shell.c +++ b/modules/openthread/shell.c @@ -6,7 +6,6 @@ #include #include -#include #include #include #include @@ -16,6 +15,8 @@ #include "platform-zephyr.h" +#include + #define OT_SHELL_BUFFER_SIZE CONFIG_SHELL_CMD_BUFF_SIZE static char rx_buffer[OT_SHELL_BUFFER_SIZE]; From bb5382b7775a2b0379d62aa7e15ebced74e7a90f Mon Sep 17 00:00:00 2001 From: Adrian Gielniewski Date: Wed, 28 May 2025 10:21:16 +0200 Subject: [PATCH 5/6] openthread: Remove usage of deprecated API Use new API from OpenThread module header. Signed-off-by: Adrian Gielniewski --- samples/openthread/cli/src/low_power.c | 16 +++--- .../coap_client/src/coap_client_utils.c | 30 +++++------ .../openthread/coap_server/src/coap_server.c | 14 ++--- samples/wifi/thread_coex/src/ot_utils.c | 53 +++++++++---------- subsys/caf/modules/net_state_ot.c | 26 +++++---- .../rpc/common/ot_rpc_lock_net_l2.c | 6 +-- .../net/openthread/rpc/server/CMakeLists.txt | 1 + .../rpc/server/src/instance_suite.c | 2 +- .../net/openthread/rpc/server/src/mocks.c | 8 ++- 9 files changed, 73 insertions(+), 83 deletions(-) diff --git a/samples/openthread/cli/src/low_power.c b/samples/openthread/cli/src/low_power.c index 35fd08ac31eb..eb177373fa49 100644 --- a/samples/openthread/cli/src/low_power.c +++ b/samples/openthread/cli/src/low_power.c @@ -4,8 +4,8 @@ * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause */ +#include #include -#include #include #include #if defined(CONFIG_RAM_POWER_DOWN_LIBRARY) @@ -14,11 +14,12 @@ #include "low_power.h" -static void on_thread_state_changed(otChangedFlags flags, struct openthread_context *ot_context, - void *user_data) +static void on_thread_state_changed(otChangedFlags flags, void *user_data) { + struct otInstance *instance = openthread_get_default_instance(); + if (flags & OT_CHANGED_THREAD_ROLE) { - if (otThreadGetDeviceRole(ot_context->instance) == OT_DEVICE_ROLE_CHILD) { + if (otThreadGetDeviceRole(instance) == OT_DEVICE_ROLE_CHILD) { const struct device *cons = DEVICE_DT_GET(DT_CHOSEN(zephyr_console)); if (!device_is_ready(cons)) { @@ -33,11 +34,10 @@ static void on_thread_state_changed(otChangedFlags flags, struct openthread_cont } } -static struct openthread_state_changed_cb ot_state_chaged_cb = { - .state_changed_cb = on_thread_state_changed -}; +static struct openthread_state_changed_callback ot_state_chaged_cb = { + .otCallback = on_thread_state_changed}; void low_power_enable(void) { - openthread_state_changed_cb_register(openthread_get_default_context(), &ot_state_chaged_cb); + openthread_state_changed_callback_register(&ot_state_chaged_cb); } diff --git a/samples/openthread/coap_client/src/coap_client_utils.c b/samples/openthread/coap_client/src/coap_client_utils.c index 79d4522edd84..e05d1997678c 100644 --- a/samples/openthread/coap_client/src/coap_client_utils.c +++ b/samples/openthread/coap_client/src/coap_client_utils.c @@ -8,8 +8,8 @@ #include #include #include -#include #include +#include #include #include "coap_client_utils.h" @@ -195,15 +195,13 @@ static void toggle_minimal_sleepy_end_device(struct k_work *item) { otError error; otLinkModeConfig mode; - struct openthread_context *context = openthread_get_default_context(); - - __ASSERT_NO_MSG(context != NULL); + struct otInstance *instance = openthread_get_default_instance(); - openthread_api_mutex_lock(context); - mode = otThreadGetLinkMode(context->instance); + openthread_mutex_lock(); + mode = otThreadGetLinkMode(instance); mode.mRxOnWhenIdle = !mode.mRxOnWhenIdle; - error = otThreadSetLinkMode(context->instance, mode); - openthread_api_mutex_unlock(context); + error = otThreadSetLinkMode(instance, mode); + openthread_mutex_unlock(); if (error != OT_ERROR_NONE) { LOG_ERR("Failed to set MLE link mode configuration"); @@ -219,11 +217,12 @@ static void update_device_state(void) on_mtd_mode_toggle(mode.mRxOnWhenIdle); } -static void on_thread_state_changed(otChangedFlags flags, struct openthread_context *ot_context, - void *user_data) +static void on_thread_state_changed(otChangedFlags flags, void *user_data) { + struct otInstance *instance = openthread_get_default_instance(); + if (flags & OT_CHANGED_THREAD_ROLE) { - switch (otThreadGetDeviceRole(ot_context->instance)) { + switch (otThreadGetDeviceRole(instance)) { case OT_DEVICE_ROLE_CHILD: case OT_DEVICE_ROLE_ROUTER: case OT_DEVICE_ROLE_LEADER: @@ -240,9 +239,8 @@ static void on_thread_state_changed(otChangedFlags flags, struct openthread_cont } } } -static struct openthread_state_changed_cb ot_state_chaged_cb = { - .state_changed_cb = on_thread_state_changed -}; +static struct openthread_state_changed_callback ot_state_chaged_cb = { + .otCallback = on_thread_state_changed}; static void submit_work_if_connected(struct k_work *work) { @@ -274,8 +272,8 @@ void coap_client_utils_init(ot_connection_cb_t on_connect, k_work_init(&multicast_light_work, toggle_mesh_lights); k_work_init(&provisioning_work, send_provisioning_request); - openthread_state_changed_cb_register(openthread_get_default_context(), &ot_state_chaged_cb); - openthread_start(openthread_get_default_context()); + openthread_state_changed_callback_register(&ot_state_chaged_cb); + openthread_run(); if (IS_ENABLED(CONFIG_OPENTHREAD_MTD_SED)) { k_work_init(&toggle_MTD_SED_work, diff --git a/samples/openthread/coap_server/src/coap_server.c b/samples/openthread/coap_server/src/coap_server.c index 249d6940d5ea..5b5ba9af8f29 100644 --- a/samples/openthread/coap_server/src/coap_server.c +++ b/samples/openthread/coap_server/src/coap_server.c @@ -110,11 +110,10 @@ static void on_button_changed(uint32_t button_state, uint32_t has_changed) } } -static void on_thread_state_changed(otChangedFlags flags, struct openthread_context *ot_context, - void *user_data) +static void on_thread_state_changed(otChangedFlags flags, void *user_data) { if (flags & OT_CHANGED_THREAD_ROLE) { - switch (otThreadGetDeviceRole(ot_context->instance)) { + switch (otThreadGetDeviceRole(openthread_get_default_instance())) { case OT_DEVICE_ROLE_CHILD: case OT_DEVICE_ROLE_ROUTER: case OT_DEVICE_ROLE_LEADER: @@ -130,8 +129,9 @@ static void on_thread_state_changed(otChangedFlags flags, struct openthread_cont } } } -static struct openthread_state_changed_cb ot_state_chaged_cb = { .state_changed_cb = - on_thread_state_changed }; + +static struct openthread_state_changed_callback ot_state_chaged_cb = { + .otCallback = on_thread_state_changed}; int main(void) { @@ -166,8 +166,8 @@ int main(void) goto end; } - openthread_state_changed_cb_register(openthread_get_default_context(), &ot_state_chaged_cb); - openthread_start(openthread_get_default_context()); + openthread_state_changed_callback_register(&ot_state_chaged_cb); + openthread_run(); end: return 0; diff --git a/samples/wifi/thread_coex/src/ot_utils.c b/samples/wifi/thread_coex/src/ot_utils.c index fbf24654bcd2..cf9d4303f4ed 100644 --- a/samples/wifi/thread_coex/src/ot_utils.c +++ b/samples/wifi/thread_coex/src/ot_utils.c @@ -51,34 +51,34 @@ static void ot_device_dettached(void *ptr) static void ot_commissioner_state_changed(otCommissionerState aState, void *aContext) { + struct otInstance *instance = openthread_get_default_instance(); + LOG_INF("OT commissioner state changed"); if (aState == OT_COMMISSIONER_STATE_ACTIVE) { LOG_INF("ot commissioner joiner add * FEDCBA9876543210 2000"); - otCommissionerAddJoiner(openthread_get_default_instance(), NULL, - "FEDCBA9876543210", 2000); + otCommissionerAddJoiner(instance, NULL, "FEDCBA9876543210", 2000); LOG_INF("\n\nRun thread application on client\n\n"); } } -static void ot_thread_state_changed(otChangedFlags flags, struct openthread_context *ot_context, - void *user_data) +static void ot_thread_state_changed(otChangedFlags flags, void *user_data) { + struct otInstance *instance = openthread_get_default_instance(); + LOG_INF("OT device state changed"); if (flags & OT_CHANGED_THREAD_ROLE) { - otDeviceRole ot_role = otThreadGetDeviceRole(ot_context->instance); + otDeviceRole ot_role = otThreadGetDeviceRole(instance); if (ot_role != OT_DEVICE_ROLE_DETACHED && ot_role != OT_DEVICE_ROLE_DISABLED) { /* ot commissioner start */ LOG_INF("ot commissioner start"); - otCommissionerStart(ot_context->instance, &ot_commissioner_state_changed, - NULL, NULL); + otCommissionerStart(instance, &ot_commissioner_state_changed, NULL, NULL); } } } -static struct openthread_state_changed_cb ot_state_chaged_cb = { - .state_changed_cb = ot_thread_state_changed -}; +static struct openthread_state_changed_callback ot_state_chaged_cb = { + .otCallback = ot_thread_state_changed}; /* call back Thread device joiner */ static void ot_joiner_start_handler(otError error, void *context) @@ -100,31 +100,30 @@ int ot_throughput_client_init(void) { otError err = 0; uint32_t ot_role_non_child = 0; + struct otInstance *instance = openthread_get_default_instance(); ot_start_joiner("FEDCBA9876543210"); err = k_sem_take(&connected_sem, WAIT_TIME_FOR_OT_CON); - struct openthread_context *context = openthread_get_default_context(); LOG_INF("Starting openthread."); - openthread_api_mutex_lock(context); + openthread_mutex_lock(); /* ot thread start */ - err = otThreadSetEnabled(openthread_get_default_instance(), true); + err = otThreadSetEnabled(instance, true); if (err != OT_ERROR_NONE) { LOG_ERR("Starting openthread: %d (%s)", err, otThreadErrorToString(err)); } - otDeviceRole current_role = - otThreadGetDeviceRole(openthread_get_default_instance()); - openthread_api_mutex_unlock(context); + otDeviceRole current_role = otThreadGetDeviceRole(instance); + openthread_mutex_unlock(); LOG_INF("Current role: %s. Waiting to get child role", otThreadDeviceRoleToString(current_role)); while (current_role != OT_DEVICE_ROLE_CHILD) { k_sleep(K_MSEC(CHECK_OT_ROLE_WAIT_TIME)); - openthread_api_mutex_lock(context); - current_role = otThreadGetDeviceRole(openthread_get_default_instance()); - openthread_api_mutex_unlock(context); + openthread_mutex_lock(); + current_role = otThreadGetDeviceRole(instance); + openthread_mutex_unlock(); /* Avoid infinite waiting if the device role is not child */ if (current_role == OT_DEVICE_ROLE_ROUTER) { ot_role_non_child = 1; @@ -160,9 +159,8 @@ void ot_start_joiner(const char *pskd) LOG_INF("Starting joiner"); otInstance *instance = openthread_get_default_instance(); - struct openthread_context *context = openthread_get_default_context(); - openthread_api_mutex_lock(context); + openthread_mutex_lock(); /** Step1: Set null network key i.e, * ot networkkey 00000000000000000000000000000000 @@ -179,7 +177,7 @@ void ot_start_joiner(const char *pskd) "Zephyr", "Zephyr", KERNEL_VERSION_STRING, NULL, &ot_joiner_start_handler, NULL); - openthread_api_mutex_unlock(context); + openthread_mutex_unlock(); /* LOG_INF("Thread start joiner Done."); */ } @@ -196,8 +194,7 @@ int ot_throughput_test_init(bool is_ot_client, bool is_ot_zperf_udp) } if (!is_ot_client) { /* for server */ ot_initialization(); - openthread_state_changed_cb_register(openthread_get_default_context(), - &ot_state_chaged_cb); + openthread_state_changed_callback_register(&ot_state_chaged_cb); LOG_INF("Starting zperf server"); ot_start_zperf_test_recv(is_ot_zperf_udp); @@ -281,14 +278,12 @@ void ot_setNetworkConfiguration(otInstance *aInstance) int ot_initialization(void) { - struct openthread_context *context = openthread_get_default_context(); - otInstance *instance = openthread_get_default_instance(); /* LOG_INF("Updating thread parameters"); */ ot_setNetworkConfiguration(instance); /* LOG_INF("Enabling thread"); */ - otError err = openthread_start(context); /* 'ifconfig up && thread start' */ + otError err = openthread_run(); /* 'ifconfig up && thread start' */ if (err != OT_ERROR_NONE) { LOG_ERR("Starting openthread: %d (%s)", err, otThreadErrorToString(err)); @@ -325,10 +320,10 @@ void ot_get_peer_address(uint64_t timeout_ms) memset(&config, 0, sizeof(config)); config.mReplyCallback = ot_handle_ping_reply; - openthread_api_mutex_lock(openthread_get_default_context()); + openthread_mutex_lock(); otIp6AddressFromString(dest, &config.mDestination); otPingSenderPing(openthread_get_default_instance(), &config); - openthread_api_mutex_unlock(openthread_get_default_context()); + openthread_mutex_unlock(); start_time = k_uptime_get(); while (!peer_address_info.address_found && k_uptime_get() < start_time + timeout_ms) { diff --git a/subsys/caf/modules/net_state_ot.c b/subsys/caf/modules/net_state_ot.c index ec6196bb8e4f..a0e1d3fba5d2 100644 --- a/subsys/caf/modules/net_state_ot.c +++ b/subsys/caf/modules/net_state_ot.c @@ -144,19 +144,19 @@ static void set_net_state(enum net_state state) send_net_state_event(state); } -static void on_thread_state_changed(otChangedFlags flags, struct openthread_context *ot_context, - void *user_data) +static void on_thread_state_changed(otChangedFlags flags, void *user_data) { static bool has_role; + struct otInstance *instance = openthread_get_default_instance(); - bool has_neighbors = check_neighbors(ot_context->instance); - bool route_available = check_routes(ot_context->instance); + bool has_neighbors = check_neighbors(instance); + bool route_available = check_routes(instance); LOG_INF("state: 0x%.8x has_neighbours:%s route_available:%s", flags, (has_neighbors)?("yes"):("no"), (route_available)?("yes"):("no")); if (flags & OT_CHANGED_THREAD_ROLE) { - switch (otThreadGetDeviceRole(ot_context->instance)) { + switch (otThreadGetDeviceRole(instance)) { case OT_DEVICE_ROLE_LEADER: LOG_INF("Leader role set"); has_role = true; @@ -187,14 +187,13 @@ static void on_thread_state_changed(otChangedFlags flags, struct openthread_cont set_net_state(NET_STATE_DISCONNECTED); } } -static struct openthread_state_changed_cb ot_state_chaged_cb = { - .state_changed_cb = on_thread_state_changed -}; +static struct openthread_state_changed_callback ot_state_chaged_cb = { + .otCallback = on_thread_state_changed}; static void connect_ot(void) { - openthread_state_changed_cb_register(openthread_get_default_context(), &ot_state_chaged_cb); - openthread_start(openthread_get_default_context()); + openthread_state_changed_callback_register(&ot_state_chaged_cb); + openthread_run(); LOG_INF("OT connection requested"); } @@ -222,16 +221,15 @@ static bool handle_state_event(const struct module_state_event *event) static bool handle_reset_event(void) { - struct openthread_context *ot_context = openthread_get_default_context(); otError err; /* This event has to apear before initialization */ __ASSERT_NO_MSG(!initialized); LOG_WRN("Storage reset requested"); - openthread_api_mutex_lock(ot_context); - err = otInstanceErasePersistentInfo(ot_context->instance); - openthread_api_mutex_unlock(ot_context); + openthread_mutex_lock(); + err = otInstanceErasePersistentInfo(openthread_get_default_instance()); + openthread_mutex_unlock(); /* It can fail only if called with OpenThread stack enabled. * This event should not appear after the OpenThread is started. * If it does - there is some huge coding error. diff --git a/subsys/net/openthread/rpc/common/ot_rpc_lock_net_l2.c b/subsys/net/openthread/rpc/common/ot_rpc_lock_net_l2.c index 4ac05c8893de..8ac98fdac627 100644 --- a/subsys/net/openthread/rpc/common/ot_rpc_lock_net_l2.c +++ b/subsys/net/openthread/rpc/common/ot_rpc_lock_net_l2.c @@ -6,14 +6,14 @@ #include "ot_rpc_lock.h" -#include +#include void ot_rpc_mutex_lock(void) { - openthread_api_mutex_lock(openthread_get_default_context()); + openthread_mutex_lock(); } void ot_rpc_mutex_unlock(void) { - openthread_api_mutex_unlock(openthread_get_default_context()); + openthread_mutex_unlock(); } diff --git a/tests/subsys/net/openthread/rpc/server/CMakeLists.txt b/tests/subsys/net/openthread/rpc/server/CMakeLists.txt index 92ba379120e4..968f81eb5031 100644 --- a/tests/subsys/net/openthread/rpc/server/CMakeLists.txt +++ b/tests/subsys/net/openthread/rpc/server/CMakeLists.txt @@ -25,6 +25,7 @@ target_sources(app PRIVATE # Fill the gaps due to not setting NET_L2_OPENTHREAD. zephyr_include_directories( ${ZEPHYR_OPENTHREAD_MODULE_DIR}/include + ${ZEPHYR_BASE}/modules/openthread/include ) zephyr_compile_definitions( diff --git a/tests/subsys/net/openthread/rpc/server/src/instance_suite.c b/tests/subsys/net/openthread/rpc/server/src/instance_suite.c index 1061f38dc760..f1d6355d9fb3 100644 --- a/tests/subsys/net/openthread/rpc/server/src/instance_suite.c +++ b/tests/subsys/net/openthread/rpc/server/src/instance_suite.c @@ -10,9 +10,9 @@ #include #include -#include #include +#include #include /* Fake functions */ diff --git a/tests/subsys/net/openthread/rpc/server/src/mocks.c b/tests/subsys/net/openthread/rpc/server/src/mocks.c index e732b6e1eb6e..66fe617ac5a2 100644 --- a/tests/subsys/net/openthread/rpc/server/src/mocks.c +++ b/tests/subsys/net/openthread/rpc/server/src/mocks.c @@ -11,21 +11,19 @@ #include -#include +#include -static struct openthread_context ot_context; +static int dummy; struct otInstance *openthread_get_default_instance(void) { - return ot_context.instance; + return (struct otInstance *)&dummy; } void ot_rpc_mutex_lock(void) { - (void)k_mutex_lock(&ot_context.api_lock, K_FOREVER); } void ot_rpc_mutex_unlock(void) { - (void)k_mutex_unlock(&ot_context.api_lock); } From 70dda378376d3e11f4ef788a08fc5055140c55f7 Mon Sep 17 00:00:00 2001 From: Adrian Gielniewski Date: Thu, 29 May 2025 21:12:19 +0200 Subject: [PATCH 6/6] openthread: Add Kconfigs for packet TX time and carrier functions Add new Kconfig options to enable platform-specific features in OpenThread: - CONFIG_OPENTHREAD_PLATFORM_PKT_TXTIME enables support for packet TX time when CONFIG_NET_PKT_TXTIME is selected. - CONFIG_OPENTHREAD_PLATFORM_CARRIER_FUNCTIONS enables modulated and continuous carrier functions when CONFIG_OPENTHREAD_DIAG and CONFIG_IEEE802154_CARRIER_FUNCTIONS are enabled. Update preprocessor conditionals to use the new options instead of relying directly on CONFIG_NET_PKT_TXTIME and CONFIG_IEEE802154_CARRIER_FUNCTIONS. This change improves configurability and allows to reuse the platform implementation when not using Zephyr networking. Upstream PR #: 90737 Signed-off-by: Adrian Gielniewski --- modules/openthread/Kconfig | 13 +++++++++++++ modules/openthread/platform/alarm.c | 2 +- modules/openthread/platform/diag.c | 15 +++++++++------ modules/openthread/platform/platform-zephyr.h | 8 ++++---- modules/openthread/platform/radio.c | 14 +++++++------- 5 files changed, 34 insertions(+), 18 deletions(-) diff --git a/modules/openthread/Kconfig b/modules/openthread/Kconfig index b5a856b72fcb..5b25721bdf7b 100644 --- a/modules/openthread/Kconfig +++ b/modules/openthread/Kconfig @@ -334,6 +334,19 @@ config OPENTHREAD_INTERFACE_EARLY_UP Otherwise, OpenThread interface will be marked operational UP only after the device joins a Thread network. +config OPENTHREAD_PLATFORM_PKT_TXTIME + bool + default y if NET_PKT_TXTIME + help + Enable packet TX time support. This is needed for when the application + wants to set the exact time when the packet should be sent. + +config OPENTHREAD_PLATFORM_CARRIER_FUNCTIONS + bool + default y if OPENTHREAD_DIAG && IEEE802154_CARRIER_FUNCTIONS + help + Enable support for functions such as modulated carrier and continuous carrier. + menu "OpenThread stack features" rsource "Kconfig.features" endmenu diff --git a/modules/openthread/platform/alarm.c b/modules/openthread/platform/alarm.c index 13f3f9110478..fa8bac9eaa40 100644 --- a/modules/openthread/platform/alarm.c +++ b/modules/openthread/platform/alarm.c @@ -50,7 +50,7 @@ K_TIMER_DEFINE(ot_us_timer, ot_timer_us_fired, NULL); void platformAlarmInit(void) { -#if defined(CONFIG_NET_PKT_TXTIME) +#if defined(CONFIG_OPENTHREAD_PLATFORM_PKT_TXTIME) time_offset_us = (int32_t)((int64_t)otPlatAlarmMicroGetNow() - (uint32_t)otPlatRadioGetNow(NULL)); time_offset_ms = time_offset_us / 1000; diff --git a/modules/openthread/platform/diag.c b/modules/openthread/platform/diag.c index 3bd4b549536b..74781cad4a1d 100644 --- a/modules/openthread/platform/diag.c +++ b/modules/openthread/platform/diag.c @@ -37,7 +37,10 @@ static uint32_t sTxPeriod = 1; static int32_t sTxCount; static int32_t sTxRequestedCount = 1; +#if defined(CONFIG_OPENTHREAD_PLATFORM_CARRIER_FUNCTIONS) static otError startModCarrier(otInstance *aInstance, uint8_t aArgsLength, char *aArgs[]); +#endif /* CONFIG_OPENTHREAD_PLATFORM_CARRIER_FUNCTIONS */ + static otError processTransmit(otInstance *aInstance, uint8_t aArgsLength, char *aArgs[]); static otError parse_long(char *aArgs, long *aValue) @@ -72,11 +75,11 @@ void otPlatDiagSetOutputCallback(otInstance *aInstance, otError otPlatDiagProcess(otInstance *aInstance, uint8_t aArgsLength, char *aArgs[]) { -#if defined(CONFIG_IEEE802154_CARRIER_FUNCTIONS) +#if defined(CONFIG_OPENTHREAD_PLATFORM_CARRIER_FUNCTIONS) if (strcmp(aArgs[0], "modcarrier") == 0) { return startModCarrier(aInstance, aArgsLength - 1, aArgs + 1); } -#endif +#endif /* CONFIG_OPENTHREAD_PLATFORM_CARRIER_FUNCTIONS */ if (strcmp(aArgs[0], "transmit") == 0) { return processTransmit(aInstance, aArgsLength - 1, aArgs + 1); @@ -128,7 +131,7 @@ void otPlatDiagRadioReceived(otInstance *aInstance, ARG_UNUSED(aError); } -#if defined(CONFIG_IEEE802154_CARRIER_FUNCTIONS) +#if defined(CONFIG_OPENTHREAD_PLATFORM_CARRIER_FUNCTIONS) otError otPlatDiagRadioTransmitCarrier(otInstance *aInstance, bool aEnable) { if (sTransmitMode != DIAG_TRANSMIT_MODE_IDLE && @@ -144,7 +147,7 @@ otError otPlatDiagRadioTransmitCarrier(otInstance *aInstance, bool aEnable) return platformRadioTransmitCarrier(aInstance, aEnable); } -#endif /* CONFIG_IEEE802154_CARRIER_FUNCTIONS */ +#endif /* CONFIG_OPENTHREAD_PLATFORM_CARRIER_FUNCTIONS */ /* * To enable gpio diag commands, in Devicetree create `openthread` node in `/options/` path @@ -317,7 +320,7 @@ otError otPlatDiagGpioGetMode(uint32_t aGpio, otGpioMode *aMode) * DT_NODE_HAS_PROP(DT_COMPAT_GET_ANY_STATUS_OKAY(openthread_config), diag_gpios) */ -#if defined(CONFIG_IEEE802154_CARRIER_FUNCTIONS) +#if defined(CONFIG_OPENTHREAD_PLATFORM_CARRIER_FUNCTIONS) static otError startModCarrier(otInstance *aInstance, uint8_t aArgsLength, char *aArgs[]) { @@ -346,7 +349,7 @@ static otError startModCarrier(otInstance *aInstance, uint8_t aArgsLength, char return platformRadioTransmitModulatedCarrier(aInstance, enable, data); } -#endif +#endif /* CONFIG_OPENTHREAD_PLATFORM_CARRIER_FUNCTIONS */ void otPlatDiagAlarmCallback(otInstance *aInstance) { diff --git a/modules/openthread/platform/platform-zephyr.h b/modules/openthread/platform/platform-zephyr.h index d6dd26adea04..4d61197b2b42 100644 --- a/modules/openthread/platform/platform-zephyr.h +++ b/modules/openthread/platform/platform-zephyr.h @@ -80,20 +80,20 @@ uint16_t platformRadioChannelGet(otInstance *aInstance); void platformRadioChannelSet(uint8_t aChannel); #endif /* CONFIG_OPENTHREAD_DIAG */ -#if defined(CONFIG_IEEE802154_CARRIER_FUNCTIONS) +#if defined(CONFIG_OPENTHREAD_PLATFORM_CARRIER_FUNCTIONS) /** * Start/stop continuous carrier wave transmission. */ otError platformRadioTransmitCarrier(otInstance *aInstance, bool aEnable); -#endif /* CONFIG_IEEE802154_CARRIER_FUNCTIONS */ +#endif /* CONFIG_OPENTHREAD_PLATFORM_CARRIER_FUNCTIONS */ -#if defined(CONFIG_IEEE802154_CARRIER_FUNCTIONS) +#if defined(CONFIG_OPENTHREAD_PLATFORM_CARRIER_FUNCTIONS ) /** * Start/stop modulated carrier wave transmission. */ otError platformRadioTransmitModulatedCarrier(otInstance *aInstance, bool aEnable, const uint8_t *aData); -#endif +#endif /* CONFIG_OPENTHREAD_PLATFORM_CARRIER_FUNCTIONS */ /** * This function initializes the random number service used by OpenThread. diff --git a/modules/openthread/platform/radio.c b/modules/openthread/platform/radio.c index e2bdebed33fa..e9516d452b22 100644 --- a/modules/openthread/platform/radio.c +++ b/modules/openthread/platform/radio.c @@ -244,7 +244,7 @@ void handle_radio_event(const struct device *dev, enum ieee802154_event evt, } } -#if defined(CONFIG_NET_PKT_TXTIME) || defined(CONFIG_OPENTHREAD_CSL_RECEIVER) +#if defined(CONFIG_OPENTHREAD_PLATFORM_PKT_TXTIME) || defined(CONFIG_OPENTHREAD_CSL_RECEIVER) /** * @brief Convert 32-bit (potentially wrapped) OpenThread microsecond timestamps * to 64-bit Zephyr network subsystem nanosecond timestamps. @@ -320,7 +320,7 @@ static net_time_t convert_32bit_us_wrapped_to_64bit_ns(uint32_t target_time_us_w __ASSERT_NO_MSG(result <= INT64_MAX / NSEC_PER_USEC); return (net_time_t)result * NSEC_PER_USEC; } -#endif /* CONFIG_NET_PKT_TXTIME || CONFIG_OPENTHREAD_CSL_RECEIVER */ +#endif /* CONFIG_OPENTHREAD_PLATFORM_PKT_TXTIME || CONFIG_OPENTHREAD_CSL_RECEIVER */ static void dataInit(void) { @@ -416,7 +416,7 @@ void transmit_message(struct k_work *tx_job) if ((radio_caps & IEEE802154_HW_TXTIME) && (sTransmitFrame.mInfo.mTxInfo.mTxDelay != 0)) { -#if defined(CONFIG_NET_PKT_TXTIME) +#if defined(CONFIG_OPENTHREAD_PLATFORM_PKT_TXTIME) uint32_t tx_at = sTransmitFrame.mInfo.mTxInfo.mTxDelayBaseTime + sTransmitFrame.mInfo.mTxInfo.mTxDelay; net_pkt_set_timestamp_ns(tx_pkt, convert_32bit_us_wrapped_to_64bit_ns(tx_at)); @@ -834,7 +834,7 @@ otError otPlatRadioReceiveAt(otInstance *aInstance, uint8_t aChannel, } #endif -#if defined(CONFIG_IEEE802154_CARRIER_FUNCTIONS) +#if defined(CONFIG_OPENTHREAD_PLATFORM_CARRIER_FUNCTIONS) otError platformRadioTransmitCarrier(otInstance *aInstance, bool aEnable) { if (radio_api->continuous_carrier == NULL) { @@ -885,7 +885,7 @@ otError platformRadioTransmitModulatedCarrier(otInstance *aInstance, bool aEnabl return OT_ERROR_NONE; } -#endif /* CONFIG_IEEE802154_CARRIER_FUNCTIONS */ +#endif /* CONFIG_OPENTHREAD_PLATFORM_CARRIER_FUNCTIONS */ otRadioState otPlatRadioGetState(otInstance *aInstance) { @@ -1000,7 +1000,7 @@ otRadioCaps otPlatRadioGetCaps(otInstance *aInstance) } #endif -#if defined(CONFIG_NET_PKT_TXTIME) +#if defined(CONFIG_OPENTHREAD_PLATFORM_PKT_TXTIME) if (radio_caps & IEEE802154_HW_TXTIME) { caps |= OT_RADIO_CAPS_TRANSMIT_TIMING; } @@ -1265,7 +1265,7 @@ uint64_t otPlatTimeGet(void) } } -#if defined(CONFIG_NET_PKT_TXTIME) +#if defined(CONFIG_OPENTHREAD_PLATFORM_PKT_TXTIME) uint64_t otPlatRadioGetNow(otInstance *aInstance) { ARG_UNUSED(aInstance);