2#if defined(USE_OPENTHREAD) && defined(USE_NRF52)
3#include <openthread/dataset.h>
4#include <openthread/thread.h>
5#include <openthread/logging.h>
8#include <zephyr/net/openthread.h>
10static const char *
const TAG =
"openthread";
14static void on_thread_state_changed(otChangedFlags
flags,
struct openthread_context *ot_context,
void *user_data) {
19 if (
flags & OT_CHANGED_THREAD_ROLE) {
20 otDeviceRole role = otThreadGetDeviceRole(ot_context->instance);
21 ESP_LOGI(TAG,
"Thread role changed to %s", otThreadDeviceRoleToString(role));
23 if (
flags & OT_CHANGED_THREAD_NETDATA) {
24 ESP_LOGI(TAG,
"Thread network data updated");
26 if (
flags & (OT_CHANGED_THREAD_ROLE | OT_CHANGED_THREAD_NETDATA)) {
27 char buf[NET_IPV6_ADDR_LEN];
28 for (
const otNetifAddress *addr = otIp6GetUnicastAddresses(ot_context->instance); addr !=
nullptr;
30 ESP_LOGI(TAG,
" Address: %s", net_addr_ntop(AF_INET6, &addr->mAddress, buf,
sizeof(buf)));
35static struct openthread_state_changed_cb ot_state_changed_cb = {.state_changed_cb = on_thread_state_changed};
38 struct openthread_context *context = openthread_get_default_context();
40 otOperationalDatasetTlvs dataset = {};
42#ifndef USE_OPENTHREAD_FORCE_DATASET
43 otError error = otDatasetGetActiveTlvs(context->instance, &dataset);
44 if (error != OT_ERROR_NONE) {
47 ESP_LOGI(TAG,
"Found existing dataset, ignoring config (force_dataset: true to override)");
51#ifdef USE_OPENTHREAD_TLVS
52 if (dataset.mLength == 0) {
53 const size_t tlv_chars =
sizeof(USE_OPENTHREAD_TLVS) - 1;
54 if ((tlv_chars % 2) != 0) {
55 ESP_LOGE(TAG,
"Invalid OpenThread TLV hex string length (must be even, got %zu)", tlv_chars);
60 size_t len = tlv_chars / 2;
61 if (
len >
sizeof(dataset.mTlvs)) {
62 ESP_LOGE(TAG,
"OpenThread TLV too long (max %zu bytes, got %zu bytes)",
sizeof(dataset.mTlvs),
len);
67 size_t parsed =
parse_hex(USE_OPENTHREAD_TLVS, tlv_chars, dataset.mTlvs,
len);
68 if (parsed != tlv_chars) {
69 ESP_LOGE(TAG,
"Invalid OpenThread TLV hex string (expected %zu hex chars, got %zu)", tlv_chars, parsed);
73 dataset.mLength =
len;
76 if (dataset.mLength > 0) {
77 otError error = otDatasetSetActiveTlvs(context->instance, &dataset);
78 if (error != OT_ERROR_NONE) {
79 ESP_LOGE(TAG,
"Failed to set active dataset: %s", otThreadErrorToString(error));
84 openthread_state_changed_cb_register(context, &ot_state_changed_cb);
85 openthread_start(context);
103 size_t addr_count = 0;
104 for (
const otNetifAddress *addr = otIp6GetUnicastAddresses(openthread_get_default_instance());
105 addr !=
nullptr && addr_count + 1 < addresses.size(); addr = addr->mNext) {
107 memcpy(&ip6, addr->mAddress.mFields.m8,
sizeof(ip6));
108 addresses[addr_count + 1] = network::IPAddress(&ip6);
118 struct openthread_context *ot_context = openthread_get_default_context();
119 if (k_mutex_lock(&ot_context->api_lock, K_MSEC(
delay)) == 0) {
126 struct openthread_context *ot_context = openthread_get_default_context();
127 k_mutex_lock(&ot_context->api_lock, K_FOREVER);
135 struct openthread_context *ot_context = openthread_get_default_context();
136 k_mutex_unlock(&ot_context->api_lock);
void mark_failed()
Mark this component as failed.
static InstanceLock try_acquire(int delay)
otInstance * get_instance()
static InstanceLock acquire()
InstanceLock(const InstanceLock &)=delete
network::IPAddresses get_ip_addresses()
std::atomic< bool > lock_initialized_
otInstance * get_openthread_instance_()
static void on_state_changed(otChangedFlags flags, void *context)
bool is_lock_initialized() const
Returns true once esp_openthread_init() has completed and the OT lock is usable.
std::array< IPAddress, 5 > IPAddresses
OpenThreadComponent * global_openthread_component
size_t parse_hex(const char *str, size_t length, uint8_t *data, size_t count)
Parse bytes from a hex-encoded string into a byte array.
void HOT delay(uint32_t ms)