Merge branch 'backport/openthread_154_related_feature_v52' into 'release/v5.2'

Backport some openthread and IEEE802154 related feature(Backport v5.2)

See merge request espressif/esp-idf!34273
This commit is contained in:
Shu Chen 2024-10-28 12:13:26 +08:00
commit 9ce3654357
43 changed files with 1014 additions and 102 deletions

View File

@ -469,11 +469,10 @@ static IRAM_ATTR void isr_handle_ack_rx_done(void)
NEEDS_NEXT_OPT(true);
}
static IRAM_ATTR void isr_handle_rx_phase_rx_abort(void)
static IRAM_ATTR void isr_handle_rx_phase_rx_abort(ieee802154_ll_rx_abort_reason_t rx_abort_reason)
{
event_end_process();
uint32_t rx_status = ieee802154_ll_get_rx_status();
ieee802154_ll_rx_abort_reason_t rx_abort_reason = ieee802154_ll_get_rx_abort_reason();
switch (rx_abort_reason) {
case IEEE802154_RX_ABORT_BY_RX_STOP:
case IEEE802154_RX_ABORT_BY_TX_ACK_STOP:
@ -508,13 +507,12 @@ static IRAM_ATTR void isr_handle_rx_phase_rx_abort(void)
NEEDS_NEXT_OPT(true);
}
static IRAM_ATTR void isr_handle_tx_ack_phase_rx_abort(void)
static IRAM_ATTR void isr_handle_tx_ack_phase_rx_abort(ieee802154_ll_rx_abort_reason_t rx_abort_reason)
{
event_end_process();
#if CONFIG_IEEE802154_TEST
uint32_t rx_status = ieee802154_ll_get_rx_status();
#endif
ieee802154_ll_rx_abort_reason_t rx_abort_reason = ieee802154_ll_get_rx_abort_reason();
switch (rx_abort_reason) {
case IEEE802154_RX_ABORT_BY_RX_STOP:
case IEEE802154_RX_ABORT_BY_TX_ACK_STOP:
@ -553,10 +551,9 @@ static IRAM_ATTR void isr_handle_tx_ack_phase_rx_abort(void)
NEEDS_NEXT_OPT(true);
}
static IRAM_ATTR void isr_handle_tx_abort(void)
static IRAM_ATTR void isr_handle_tx_abort(ieee802154_ll_tx_abort_reason_t tx_abort_reason)
{
event_end_process();
ieee802154_ll_tx_abort_reason_t tx_abort_reason = ieee802154_ll_get_tx_abort_reason();
switch (tx_abort_reason) {
case IEEE802154_TX_ABORT_BY_RX_ACK_STOP:
case IEEE802154_TX_ABORT_BY_TX_STOP:
@ -636,6 +633,8 @@ static void ieee802154_isr(void *arg)
{
ieee802154_enter_critical();
ieee802154_ll_events events = ieee802154_ll_get_events();
ieee802154_ll_rx_abort_reason_t rx_abort_reason = ieee802154_ll_get_rx_abort_reason();
ieee802154_ll_tx_abort_reason_t tx_abort_reason = ieee802154_ll_get_tx_abort_reason();
IEEE802154_PROBE(events);
@ -643,7 +642,7 @@ static void ieee802154_isr(void *arg)
if (events & IEEE802154_EVENT_RX_ABORT) {
// First phase rx abort process, will clear RX_ABORT event in second.
isr_handle_rx_phase_rx_abort();
isr_handle_rx_phase_rx_abort(rx_abort_reason);
}
if (events & IEEE802154_EVENT_RX_SFD_DONE) {
@ -701,12 +700,12 @@ static void ieee802154_isr(void *arg)
if (events & IEEE802154_EVENT_RX_ABORT) {
// Second phase rx abort process, clears RX_ABORT event.
isr_handle_tx_ack_phase_rx_abort();
isr_handle_tx_ack_phase_rx_abort(rx_abort_reason);
events &= (uint16_t)(~IEEE802154_EVENT_RX_ABORT);
}
if (events & IEEE802154_EVENT_TX_ABORT) {
isr_handle_tx_abort();
isr_handle_tx_abort(tx_abort_reason);
events &= (uint16_t)(~IEEE802154_EVENT_TX_ABORT);
}
@ -773,7 +772,7 @@ esp_err_t ieee802154_mac_init(void)
ieee802154_ll_enable_rx_abort_events(BIT(IEEE802154_RX_ABORT_BY_TX_ACK_TIMEOUT - 1) | BIT(IEEE802154_RX_ABORT_BY_TX_ACK_COEX_BREAK - 1));
ieee802154_ll_set_ed_sample_mode(IEEE802154_ED_SAMPLE_AVG);
#if !CONFIG_IEEE802154_TEST && CONFIG_ESP_COEX_SW_COEXIST_ENABLE || CONFIG_EXTERNAL_COEX_ENABLE
#if !CONFIG_IEEE802154_TEST && (CONFIG_ESP_COEX_SW_COEXIST_ENABLE || CONFIG_EXTERNAL_COEX_ENABLE)
esp_coex_ieee802154_ack_pti_set(IEEE802154_MIDDLE);
IEEE802154_SET_TXRX_PTI(IEEE802154_SCENE_IDLE);
#else

View File

@ -309,7 +309,7 @@ uint8_t IEEE802154_INLINE ieee802154_frame_get_version(const uint8_t *frame)
bool IEEE802154_INLINE ieee802154_frame_is_ack_required(const uint8_t *frame)
{
return frame[IEEE802154_FRAME_AR_OFFSET] & IEEE802154_FRAME_AR_BIT;
return (is_suported_frame_type(ieee802154_frame_get_type(frame))) && (frame[IEEE802154_FRAME_AR_OFFSET] & IEEE802154_FRAME_AR_BIT);
}
uint8_t ieee802154_frame_get_dst_addr(const uint8_t *frame, uint8_t *addr)

View File

@ -21,7 +21,7 @@ uint8_t ieee802154_channel_to_freq(uint8_t channel)
return (channel - 11) * 5 + 3;
}
#if !CONFIG_IEEE802154_TEST && CONFIG_ESP_COEX_SW_COEXIST_ENABLE || CONFIG_EXTERNAL_COEX_ENABLE
#if !CONFIG_IEEE802154_TEST && (CONFIG_ESP_COEX_SW_COEXIST_ENABLE || CONFIG_EXTERNAL_COEX_ENABLE)
void ieee802154_set_txrx_pti(ieee802154_txrx_scene_t txrx_scene)
{

View File

@ -265,7 +265,7 @@ typedef enum {
IEEE802154_SCENE_RX_AT, /*!< IEEE802154 radio coexistence scene RX AT */
} ieee802154_txrx_scene_t;
#if !CONFIG_IEEE802154_TEST && CONFIG_ESP_COEX_SW_COEXIST_ENABLE || CONFIG_EXTERNAL_COEX_ENABLE
#if !CONFIG_IEEE802154_TEST && (CONFIG_ESP_COEX_SW_COEXIST_ENABLE || CONFIG_EXTERNAL_COEX_ENABLE)
/**
* @brief Set the IEEE802154 radio coexistence scene during transmitting or receiving.

View File

@ -15,7 +15,6 @@ if(CONFIG_OPENTHREAD_ENABLED)
set(private_include_dirs
"openthread/examples/platforms"
"openthread/include/openthread"
"openthread/src"
"openthread/src/core"
"openthread/src/lib"
@ -140,6 +139,19 @@ if(CONFIG_OPENTHREAD_ENABLED)
list(APPEND exclude_srcs
"src/port/esp_openthread_radio.c"
"src/port/esp_openthread_sleep.c")
elseif(CONFIG_OPENTHREAD_RADIO_154_NONE)
list(APPEND exclude_srcs
"src/port/esp_openthread_radio_spinel.cpp"
"src/port/esp_spi_spinel_interface.cpp"
"src/port/esp_uart_spinel_interface.cpp"
"src/port/esp_openthread_radio.c"
"src/port/esp_openthread_sleep.c"
)
endif()
if(NOT CONFIG_OPENTHREAD_RADIO_TREL)
list(APPEND exclude_srcs
"src/port/esp_openthread_trel.c")
endif()
if(CONFIG_OPENTHREAD_BORDER_ROUTER)
@ -156,6 +168,13 @@ if(CONFIG_OPENTHREAD_ENABLED)
if(CONFIG_OPENTHREAD_NCP_VENDOR_HOOK)
list(APPEND src_dirs
"src/ncp")
if(CONFIG_OPENTHREAD_RCP_UART)
list(APPEND exclude_srcs
"src/ncp/esp_openthread_ncp_spi.cpp")
elseif(CONFIG_OPENTHREAD_RCP_SPI)
list(APPEND exclude_srcs
"src/ncp/esp_openthread_ncp_hdlc.cpp")
endif()
endif()
if(NOT CONFIG_OPENTHREAD_DNS64_CLIENT)
@ -252,6 +271,10 @@ idf_component_register(SRC_DIRS "${src_dirs}"
PRIV_REQUIRES console esp_event esp_partition esp_timer
ieee802154 mbedtls nvs_flash)
if(CONFIG_OPENTHREAD_RADIO_TREL)
idf_component_optional_requires(PRIVATE espressif__mdns)
endif()
if(CONFIG_OPENTHREAD_ENABLED OR CONFIG_OPENTHREAD_SPINEL_ONLY)
if(CONFIG_OPENTHREAD_RADIO)
set(CONFIG_FILE_TYPE "radio")

View File

@ -101,7 +101,7 @@ menu "OpenThread"
default 5 if OPENTHREAD_LOG_LEVEL_DEBG
choice OPENTHREAD_RADIO_TYPE
prompt "Config the Thread radio type"
prompt "Config the Thread radio type with 15.4 link"
depends on OPENTHREAD_ENABLED
default OPENTHREAD_RADIO_NATIVE if SOC_IEEE802154_SUPPORTED
default OPENTHREAD_RADIO_SPINEL_UART
@ -124,8 +124,26 @@ menu "OpenThread"
help
Select this to connect to a Radio Co-Processor via SPI.
config OPENTHREAD_RADIO_154_NONE
bool "Disable the Thread radio based on 15.4 link"
help
Select this to disable the Thread radio based on 15.4 link.
endchoice
config OPENTHREAD_RADIO_TREL
bool "Enable Thread Radio Encapsulation Link (TREL)"
depends on EXAMPLE_CONNECT_WIFI || EXAMPLE_CONNECT_ETHERNET
default n
help
Select this option to enable Thread Radio Encapsulation Link.
config OPENTHREAD_TREL_PORT
int "The port of openthread trel service"
depends on OPENTHREAD_RADIO_TREL
default 12390
help
Configure the port number of TREL service.
choice OPENTHREAD_DEVICE_TYPE
prompt "Config the Thread device type"
depends on OPENTHREAD_ENABLED

View File

@ -117,6 +117,7 @@ typedef enum {
RADIO_MODE_NATIVE = 0x0, /*!< Use the native 15.4 radio */
RADIO_MODE_UART_RCP, /*!< UART connection to a 15.4 capable radio co-processor (RCP) */
RADIO_MODE_SPI_RCP, /*!< SPI connection to a 15.4 capable radio co-processor (RCP) */
RADIO_MODE_TREL, /*!< Use the Thread Radio Encapsulation Link (TREL) */
RADIO_MODE_MAX, /*!< Using for parameter check */
} esp_openthread_radio_mode_t;

View File

@ -203,16 +203,6 @@
#define OPENTHREAD_CONFIG_DNSSD_SERVER_ENABLE 1
#endif
/**
* @def OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
*
* Set to 1 to enable support for Thread Radio Encapsulation Link (TREL).
*
*/
#ifndef OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
#define OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE 0
#endif
/**
* @def OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
*
@ -225,6 +215,28 @@
#endif // CONFIG_OPENTHREAD_BORDER_ROUTER
/**
* @def OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
*
* Set to 1 to enable support for Thread Radio Encapsulation Link (TREL).
*
*/
#if CONFIG_OPENTHREAD_RADIO_TREL
#define OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE 1
#endif // CONFIG_OPENTHREAD_RADIO_TREL
/**
* @def OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
*
* Set to 1 to enable support for IEEE802.15.4 radio link.
*
*/
#if !CONFIG_OPENTHREAD_RADIO_154_NONE
#define OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE 1
#else
#define OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE 0
#endif
#if !CONFIG_OPENTHREAD_RADIO_NATIVE
/**
* @def OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT

View File

@ -94,14 +94,18 @@ static esp_err_t esp_openthread_host_interface_init(const esp_openthread_platfor
{
esp_openthread_host_connection_mode_t host_mode = get_host_connection_mode();
switch (host_mode) {
#if CONFIG_OPENTHREAD_RCP_SPI
case HOST_CONNECTION_MODE_RCP_SPI:
ESP_RETURN_ON_ERROR(esp_openthread_host_rcp_spi_init(config), OT_PLAT_LOG_TAG,
"esp_openthread_host_rcp_spi_init failed");
break;
#endif
#if CONFIG_OPENTHREAD_RCP_UART
case HOST_CONNECTION_MODE_RCP_UART:
ESP_RETURN_ON_ERROR(esp_openthread_host_rcp_uart_init(config), OT_PLAT_LOG_TAG,
"esp_openthread_host_rcp_uart_init failed");
break;
#endif
#if CONFIG_OPENTHREAD_CONSOLE_TYPE_UART
case HOST_CONNECTION_MODE_CLI_UART:
ESP_RETURN_ON_ERROR(esp_openthread_host_cli_uart_init(config), OT_PLAT_LOG_TAG,

View File

@ -4,12 +4,11 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "sdkconfig.h"
#include "esp_ieee802154.h"
#include "esp_openthread_ncp.h"
#include "ncp_base.hpp"
#if OPENTHREAD_ENABLE_NCP_VENDOR_HOOK
#if CONFIG_OPENTHREAD_RCP_UART
#include "utils/uart.h"
#endif
@ -107,5 +106,3 @@ otError NcpBase::VendorSetPropertyHandler(spinel_prop_key_t aPropKey)
} // namespace Ncp
} // namespace ot
#endif // #if OPENTHREAD_ENABLE_NCP_VENDOR_HOOK

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -7,8 +7,6 @@
#include "common/new.hpp"
#include "ncp_hdlc.hpp"
#if OPENTHREAD_ENABLE_NCP_VENDOR_HOOK
namespace ot {
namespace Ncp {
@ -29,5 +27,3 @@ extern "C" void otNcpHdlcInit(otInstance *aInstance, otNcpHdlcSendCallback aSend
} // namespace Ncp
} // namespace ot
#endif // #if OPENTHREAD_ENABLE_NCP_VENDOR_HOOK

View File

@ -0,0 +1,29 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "common/new.hpp"
#include "ncp_spi.hpp"
namespace ot {
namespace Ncp {
static OT_DEFINE_ALIGNED_VAR(sNcpRaw, sizeof(NcpSpi), uint64_t);
extern "C" void otNcpSpiInit(otInstance *aInstance)
{
NcpSpi *ncpSpi = nullptr;
Instance *instance = static_cast<Instance *>(aInstance);
ncpSpi = new (&sNcpRaw) NcpSpi(instance);
if (ncpSpi == nullptr || ncpSpi != NcpBase::GetNcpInstance())
{
OT_ASSERT(false);
}
}
} // namespace Ncp
} // namespace ot

View File

@ -7,7 +7,6 @@
#include <stdatomic.h>
#include "esp_openthread_radio.h"
#include "error.h"
#include "esp_err.h"
#include "sdkconfig.h"
#include "esp_check.h"
@ -25,6 +24,7 @@
#include "rom/ets_sys.h"
#include "openthread-core-config.h"
#include "openthread/error.h"
#include "openthread/link.h"
#include "openthread/platform/diag.h"
#include "openthread/platform/radio.h"

View File

@ -6,7 +6,6 @@
#include "esp_openthread_radio.h"
#include "link_raw.h"
#include "sdkconfig.h"
#include "esp_check.h"
#include "esp_err.h"

View File

@ -25,7 +25,6 @@
#include <string.h>
#include "driver/gpio.h"
#include "driver/spi_slave.h"
#include "esp_private/cache_utils.h"
#include "esp_private/spi_slave_internal.h"
#include "ncp/ncp_config.h"
#include "openthread/error.h"

View File

@ -0,0 +1,352 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_err.h"
#include "esp_netif_types.h"
#include "lwip/ip6_addr.h"
#include "sdkconfig.h"
#include "common/code_utils.hpp"
#include "openthread/error.h"
#include "esp_check.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "mdns.h"
#include "esp_netif_ip_addr.h"
#include "esp_openthread.h"
#include "esp_openthread_border_router.h"
#include "esp_openthread_common_macro.h"
#include "esp_openthread_lock.h"
#include "esp_openthread_radio.h"
#include "esp_openthread_task_queue.h"
#include "lwip/pbuf.h"
#include "lwip/tcpip.h"
#include "lwip/udp.h"
#include "openthread/trel.h"
#include "openthread/platform/diag.h"
static esp_netif_t *s_trel_netif = NULL;
static otPlatTrelCounters s_trel_counters;
#define TREL_MDNS_TYPE "_trel"
#define TREL_MDNS_PROTO "_udp"
typedef struct {
uint16_t port;
struct udp_pcb *trel_pcb;
} ot_trel_t;
typedef struct {
struct pbuf *p;
} ot_trel_recv_task_t;
typedef struct {
struct udp_pcb *pcb;
const uint8_t *payload;
uint16_t length;
ip_addr_t peer_addr;
uint16_t peer_port;
} ot_trel_send_task_t;
static ot_trel_t s_ot_trel = {CONFIG_OPENTHREAD_TREL_PORT, NULL};
static bool s_is_service_registered = false;
static void trel_browse_notifier(mdns_result_t *result)
{
while (result) {
if (result->addr && result->addr->addr.type == IPADDR_TYPE_V6) {
otPlatTrelPeerInfo info;
uint8_t trel_txt[1024] = {0};
uint16_t trel_txt_len = 0;
size_t index = 0;
while (index < result->txt_count) {
trel_txt[trel_txt_len++] = strlen(result->txt[index].key) + result->txt_value_len[index] + 1;
memcpy((trel_txt + trel_txt_len), (void *)result->txt[index].key, strlen(result->txt[index].key));
trel_txt_len += (strlen(result->txt[index].key));
trel_txt[trel_txt_len++] = '=';
memcpy((trel_txt + trel_txt_len), (void *)result->txt[index].value, result->txt_value_len[index]);
trel_txt_len += result->txt_value_len[index];
index++;
}
if (!s_trel_netif) {
s_trel_netif = result->esp_netif;
}
info.mTxtData = trel_txt;
info.mTxtLength = trel_txt_len;
info.mSockAddr.mPort = result->port;
memcpy(info.mSockAddr.mAddress.mFields.m32, result->addr->addr.u_addr.ip6.addr, OT_IP6_ADDRESS_SIZE);
info.mRemoved = (result->ttl == 0);
ESP_LOGI(OT_PLAT_LOG_TAG, "%s TREL peer: address: %s, port:%d", info.mRemoved ? "Remove" : "Found", ip6addr_ntoa(((ip6_addr_t*)(&result->addr->addr.u_addr.ip6))), info.mSockAddr.mPort);
esp_openthread_task_switching_lock_acquire(portMAX_DELAY);
otPlatTrelHandleDiscoveredPeerInfo(esp_openthread_get_instance(), &info);
esp_openthread_task_switching_lock_release();
}
result = result->next;
}
}
static void trel_recv_task(void *ctx)
{
struct pbuf *recv_buf = (struct pbuf *)ctx;
uint8_t *data_buf = (uint8_t *)recv_buf->payload;
uint8_t *data_buf_to_free = NULL;
uint16_t length = recv_buf->len;
if (recv_buf->next != NULL) {
data_buf = (uint8_t *)malloc(recv_buf->tot_len);
if (data_buf != NULL) {
length = recv_buf->tot_len;
data_buf_to_free = data_buf;
pbuf_copy_partial(recv_buf, data_buf, recv_buf->tot_len, 0);
} else {
ESP_LOGE(OT_PLAT_LOG_TAG, "Failed to allocate data buf when receiving Thread TREL message");
ExitNow();
}
}
otPlatTrelHandleReceived(esp_openthread_get_instance(), data_buf, length);
exit:
if (data_buf_to_free) {
free(data_buf_to_free);
}
pbuf_free(recv_buf);
}
static void handle_trel_udp_recv(void *ctx, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, uint16_t port)
{
ESP_LOGD(OT_PLAT_LOG_TAG, "Receive from %s:%d", ip6addr_ntoa(&(addr->u_addr.ip6)), port);
if (esp_openthread_task_queue_post(trel_recv_task, p) != ESP_OK) {
ESP_LOGE(OT_PLAT_LOG_TAG, "Failed to receive OpenThread TREL message");
}
}
static esp_err_t ot_new_trel(void *ctx)
{
ot_trel_t *task = (ot_trel_t *)ctx;
task->trel_pcb = udp_new();
ESP_RETURN_ON_FALSE(task->trel_pcb != NULL, ESP_ERR_NO_MEM, OT_PLAT_LOG_TAG, "Failed to create a new UDP pcb");
udp_bind(task->trel_pcb, IP6_ADDR_ANY, task->port);
udp_recv(task->trel_pcb, handle_trel_udp_recv, NULL);
return ESP_OK;
}
void otPlatTrelEnable(otInstance *aInstance, uint16_t *aUdpPort)
{
*aUdpPort = s_ot_trel.port;
esp_openthread_task_switching_lock_release();
esp_err_t err = esp_netif_tcpip_exec(ot_new_trel, &s_ot_trel);
if (err != ESP_OK) {
ESP_LOGE(OT_PLAT_LOG_TAG, "Fail to create trel udp");
}
mdns_browse_new(TREL_MDNS_TYPE, TREL_MDNS_PROTO, trel_browse_notifier);
esp_openthread_task_switching_lock_acquire(portMAX_DELAY);
}
static void trel_send_task(void *ctx)
{
err_t err = ERR_OK;
struct pbuf *send_buf = NULL;
ot_trel_send_task_t *task = (ot_trel_send_task_t *)ctx;
task->pcb = s_ot_trel.trel_pcb;
task->pcb->ttl = UDP_TTL;
task->pcb->netif_idx = esp_netif_get_netif_impl_index(s_trel_netif);
task->peer_addr.u_addr.ip6.zone = 0;
task->peer_addr.type = IPADDR_TYPE_V6;
task->pcb->flags = (task->pcb->flags & (~UDP_FLAGS_MULTICAST_LOOP));
task->pcb->local_port = s_ot_trel.port;
send_buf = pbuf_alloc(PBUF_TRANSPORT, task->length, PBUF_RAM);
if (send_buf == NULL) {
ESP_LOGE(OT_PLAT_LOG_TAG, "Failed to allocate data buf when sending Thread TREL message");
ExitNow();
}
memcpy(send_buf->payload, task->payload, task->length);
err = udp_sendto_if(task->pcb, send_buf, &task->peer_addr, task->peer_port, netif_get_by_index(task->pcb->netif_idx));
if(err != ERR_OK) {
ESP_LOGE(OT_PLAT_LOG_TAG, "Fail to send trel msg to %s:%d %d (%d)", ip6addr_ntoa(&(task->peer_addr.u_addr.ip6)), task->peer_port, task->pcb->netif_idx, err);
}
exit:
pbuf_free(send_buf);
free(task);
}
void otPlatTrelSend(otInstance *aInstance,
const uint8_t *aUdpPayload,
uint16_t aUdpPayloadLen,
const otSockAddr *aDestSockAddr)
{
if (!s_trel_netif) {
ESP_LOGE(OT_PLAT_LOG_TAG, "None Thread TREL interface");
return;
}
ot_trel_send_task_t *task = (ot_trel_send_task_t *)malloc(sizeof(ot_trel_send_task_t));
if (task == NULL) {
ESP_LOGE(OT_PLAT_LOG_TAG, "Failed to allocate buf for Thread TREL");
return;
}
memcpy(task->peer_addr.u_addr.ip6.addr, aDestSockAddr->mAddress.mFields.m32, OT_IP6_ADDRESS_SIZE);
task->peer_port = aDestSockAddr->mPort;
ESP_LOGD(OT_PLAT_LOG_TAG, "send trel msg to %s:%d", ip6addr_ntoa(&(task->peer_addr.u_addr.ip6)), task->peer_port);
task->payload = aUdpPayload;
task->length = aUdpPayloadLen;
esp_openthread_task_switching_lock_release();
tcpip_callback(trel_send_task, task);
esp_openthread_task_switching_lock_acquire(portMAX_DELAY);
}
void otPlatTrelRegisterService(otInstance *aInstance, uint16_t aPort, const uint8_t *aTxtData, uint8_t aTxtLength)
{
esp_err_t ret = ESP_OK;
esp_openthread_task_switching_lock_release();
if (s_is_service_registered) {
mdns_service_remove(TREL_MDNS_TYPE, TREL_MDNS_PROTO);
}
mdns_service_add(NULL, TREL_MDNS_TYPE, TREL_MDNS_PROTO, aPort, NULL, 0);
s_is_service_registered = true;
uint16_t index = 0;
while (index < aTxtLength) {
const uint8_t *item_header = aTxtData + index + 1;
uint8_t item_len = aTxtData[index];
char key[UINT8_MAX + 1];
for (uint16_t i = 0; i < item_len; i++) {
if (item_header[i] == '=') {
ESP_GOTO_ON_FALSE(i != 0, ESP_FAIL, exit, OT_PLAT_LOG_TAG, "Wrong format of _trel._udp txt key");
key[i] = '\0';
uint16_t value_len = item_len - i - 1;
ESP_GOTO_ON_FALSE(value_len != 0, ESP_FAIL, exit, OT_PLAT_LOG_TAG, "Wrong format of _trel._udp txt value");
mdns_service_txt_item_set_with_explicit_value_len(TREL_MDNS_TYPE, TREL_MDNS_PROTO, key, (const char *)item_header + i + 1, value_len);
break;
}
key[i] = item_header[i];
}
index += item_len + 1;
}
exit:
if (ret != ESP_OK) {
ESP_LOGE(OT_PLAT_LOG_TAG, "Registered TREL service with some errors");
}
esp_openthread_task_switching_lock_acquire(portMAX_DELAY);
}
void otPlatTrelResetCounters(otInstance *aInstance)
{
memset(&s_trel_counters, 0, sizeof(otPlatTrelCounters));
}
static void trel_disable_task(void *ctx)
{
struct udp_pcb *pcb = (struct udp_pcb *)ctx;
udp_remove(pcb);
}
void otPlatTrelDisable(otInstance *aInstance)
{
esp_openthread_task_switching_lock_release();
if (s_ot_trel.trel_pcb) {
tcpip_callback(trel_disable_task, s_ot_trel.trel_pcb);
}
mdns_service_remove(TREL_MDNS_TYPE, TREL_MDNS_PROTO);
s_is_service_registered = false;
mdns_browse_delete(TREL_MDNS_TYPE, TREL_MDNS_PROTO);
esp_openthread_task_switching_lock_acquire(portMAX_DELAY);
s_ot_trel.trel_pcb = NULL;
}
const otPlatTrelCounters *otPlatTrelGetCounters(otInstance *aInstance)
{
return &s_trel_counters;
}
// TODO: TZ-1169
OT_TOOL_WEAK otError otPlatRadioSetTransmitPower(otInstance *aInstance, int8_t aPower)
{
ESP_LOGD(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatRadioSetTransmitPower`");
return OT_ERROR_NOT_IMPLEMENTED;
}
OT_TOOL_WEAK otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower)
{
ESP_LOGD(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatRadioGetTransmitPower`");
return OT_ERROR_NOT_IMPLEMENTED;
}
OT_TOOL_WEAK bool otPlatRadioGetPromiscuous(otInstance *aInstance)
{
ESP_LOGD(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatRadioGetPromiscuous`");
return false;
}
OT_TOOL_WEAK otError otPlatRadioSetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t aThreshold)
{
ESP_LOGD(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatRadioSetCcaEnergyDetectThreshold`");
return OT_ERROR_NOT_IMPLEMENTED;
}
OT_TOOL_WEAK otError otPlatRadioGetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t *aThreshold)
{
ESP_LOGD(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatRadioGetCcaEnergyDetectThreshold`");
return OT_ERROR_NOT_IMPLEMENTED;
}
OT_TOOL_WEAK void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeeeEui64)
{
ESP_LOGD(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatRadioGetIeeeEui64`");
}
OT_TOOL_WEAK otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance)
{
ESP_LOGD(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatRadioGetTransmitBuffer`");
return NULL;
}
#if CONFIG_OPENTHREAD_DIAG
OT_TOOL_WEAK void otPlatDiagSetOutputCallback(otInstance *aInstance, otPlatDiagOutputCallback aCallback, void *aContext)
{
ESP_LOGD(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatDiagSetOutputCallback`");
}
OT_TOOL_WEAK void otPlatDiagModeSet(bool mode)
{
ESP_LOGD(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatDiagModeSet`");
}
OT_TOOL_WEAK bool otPlatDiagModeGet(void)
{
ESP_LOGD(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatDiagModeGet`");
return false;
}
OT_TOOL_WEAK void otPlatDiagTxPowerSet(int8_t tx_power)
{
ESP_LOGD(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatDiagTxPowerSet`");
}
OT_TOOL_WEAK void otPlatDiagChannelSet(uint8_t channel)
{
ESP_LOGD(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatDiagChannelSet`");
}
OT_TOOL_WEAK void otPlatDiagAlarmCallback(otInstance *aInstance)
{
ESP_LOGD(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatDiagAlarmCallback`");
}
#endif // CONFIG_OPENTHREAD_DIAG
OT_TOOL_WEAK esp_err_t esp_openthread_radio_init(const esp_openthread_platform_config_t *config)
{
ESP_LOGI(OT_PLAT_LOG_TAG, "Running in TREL mode");
return ESP_OK;
}
OT_TOOL_WEAK void esp_openthread_radio_deinit(void)
{
ESP_LOGI(OT_PLAT_LOG_TAG, "Running in TREL mode");
}

View File

@ -6,7 +6,7 @@
#include "esp_spi_spinel_interface.hpp"
#include "error.h"
#include "openthread/error.h"
#include "esp_check.h"
#include "esp_openthread_common_macro.h"
#include "esp_rom_sys.h"

View File

@ -40,9 +40,8 @@ examples/openthread/ot_rcp:
enable:
- if: SOC_IEEE802154_SUPPORTED == 1
disable_test:
- if: IDF_TARGET == "esp32h2"
temporary: true
reason: only test on esp32c6
- if: IDF_TARGET not in ["esp32h2", "esp32c6"]
reason: only test on esp32h2 and esp32c6
<<: *openthread_dependencies
examples/openthread/ot_sleepy_device/deep_sleep:
@ -57,3 +56,11 @@ examples/openthread/ot_sleepy_device/light_sleep:
enable:
- if: SOC_IEEE802154_SUPPORTED == 1
<<: [*openthread_dependencies, *openthread_sleep_dependencies]
examples/openthread/ot_trel:
enable:
- if: SOC_WIFI_SUPPORTED == 1
disable_test:
- if: IDF_TARGET not in ["esp32c6", "esp32s3"]
reason: only test on esp32c6 and esp32s3
<<: *openthread_dependencies

View File

@ -48,6 +48,16 @@
#include "ot_led_strip.h"
#endif
#if CONFIG_OPENTHREAD_BR_AUTO_START
#include "example_common_private.h"
#include "protocol_examples_common.h"
#endif
#if !CONFIG_OPENTHREAD_BR_AUTO_START && CONFIG_EXAMPLE_CONNECT_ETHERNET
// TZ-1109: Add a menchanism for connecting ETH manually.
#error Currently we do not support a manual way to connect ETH, if you want to use ETH, please enable OPENTHREAD_BR_AUTO_START.
#endif
#define TAG "esp_ot_br"
#if CONFIG_EXTERNAL_COEX_ENABLE
@ -93,47 +103,62 @@ static void ot_task_worker(void *aContext)
void ot_br_init(void *ctx)
{
#if CONFIG_EXAMPLE_CONNECT_WIFI
#if CONFIG_OPENTHREAD_CLI_WIFI
ESP_ERROR_CHECK(esp_ot_wifi_config_init());
#endif
#if CONFIG_OPENTHREAD_BR_AUTO_START
ESP_ERROR_CHECK(example_connect());
ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_MAX_MODEM));
#if CONFIG_ESP_COEX_SW_COEXIST_ENABLE && CONFIG_OPENTHREAD_RADIO_NATIVE
ESP_ERROR_CHECK(esp_coex_wifi_i154_enable());
#if CONFIG_EXAMPLE_CONNECT_WIFI || CONFIG_EXAMPLE_CONNECT_ETHERNET
bool wifi_or_ethernet_connected = false;
#else
#error No backbone netif!
#endif
#if CONFIG_EXAMPLE_CONNECT_WIFI
char wifi_ssid[32] = "";
char wifi_password[64] = "";
if (esp_ot_wifi_config_get_ssid(wifi_ssid) == ESP_OK) {
ESP_LOGI(TAG, "use the Wi-Fi config from NVS");
esp_ot_wifi_config_get_password(wifi_password);
} else {
ESP_LOGI(TAG, "use the Wi-Fi config from Kconfig");
strcpy(wifi_ssid, CONFIG_EXAMPLE_WIFI_SSID);
strcpy(wifi_password, CONFIG_EXAMPLE_WIFI_PASSWORD);
}
if (esp_ot_wifi_connect(wifi_ssid, wifi_password) == ESP_OK) {
wifi_or_ethernet_connected = true;
} else {
ESP_LOGE(TAG, "Fail to connect to Wi-Fi, please try again manually");
}
#endif
#if CONFIG_EXAMPLE_CONNECT_ETHERNET
ESP_ERROR_CHECK(example_ethernet_connect());
wifi_or_ethernet_connected = true;
#endif
#endif // CONFIG_OPENTHREAD_BR_AUTO_START
#if CONFIG_EXTERNAL_COEX_ENABLE
ot_br_external_coexist_init();
#endif // CONFIG_EXTERNAL_COEX_ENABLE
#endif
esp_openthread_set_backbone_netif(get_example_netif());
#else
esp_ot_wifi_netif_init();
esp_openthread_set_backbone_netif(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"));
#endif // CONFIG_OPENTHREAD_BR_AUTO_START
#elif CONFIG_EXAMPLE_CONNECT_ETHERNET
ESP_ERROR_CHECK(example_connect());
esp_openthread_set_backbone_netif(get_example_netif());
#else
ESP_LOGE(TAG, "ESP-Openthread has not set backbone netif");
#endif // CONFIG_EXAMPLE_CONNECT_WIFI
ESP_ERROR_CHECK(mdns_init());
ESP_ERROR_CHECK(mdns_hostname_set("esp-ot-br"));
// Initialize border routing features
esp_openthread_lock_acquire(portMAX_DELAY);
#if CONFIG_OPENTHREAD_STATE_INDICATOR_ENABLE
ESP_ERROR_CHECK(esp_openthread_state_indicator_init(esp_openthread_get_instance()));
#endif
#if CONFIG_OPENTHREAD_BR_AUTO_START
ESP_ERROR_CHECK(esp_openthread_border_router_init());
otOperationalDatasetTlvs dataset;
otError error = otDatasetGetActiveTlvs(esp_openthread_get_instance(), &dataset);
ESP_ERROR_CHECK(esp_openthread_auto_start((error == OT_ERROR_NONE) ? &dataset : NULL));
if (wifi_or_ethernet_connected) {
esp_openthread_set_backbone_netif(get_example_netif());
ESP_ERROR_CHECK(esp_openthread_border_router_init());
#if CONFIG_EXAMPLE_CONNECT_WIFI
esp_ot_wifi_border_router_init_flag_set(true);
#endif
otOperationalDatasetTlvs dataset;
otError error = otDatasetGetActiveTlvs(esp_openthread_get_instance(), &dataset);
ESP_ERROR_CHECK(esp_openthread_auto_start((error == OT_ERROR_NONE) ? &dataset : NULL));
} else {
ESP_LOGE(TAG, "Auto-start mode failed, please try to start manually");
}
#endif // CONFIG_OPENTHREAD_BR_AUTO_START
esp_openthread_lock_release();
vTaskDelete(NULL);
}

View File

@ -1,7 +1,7 @@
## IDF Component Manager Manifest File
dependencies:
espressif/esp_ot_cli_extension:
version: "~1.1.0"
version: "~1.2.0"
espressif/mdns: "^1.0.3"
## Required IDF version
idf:

View File

@ -0,0 +1 @@
CONFIG_OPENTHREAD_RADIO_SPINEL_SPI=y

View File

@ -1,7 +1,7 @@
## IDF Component Manager Manifest File
dependencies:
espressif/esp_ot_cli_extension:
version: "~1.1.0"
version: "~1.2.0"
idf:
version: ">=4.1.0"
ot_led:

View File

@ -1,2 +0,0 @@
CONFIG_IDF_TARGET="esp32c6"
CONFIG_IDF_TARGET_ESP32C6=y

View File

@ -1,2 +0,0 @@
CONFIG_IDF_TARGET="esp32h2"
CONFIG_IDF_TARGET_ESP32H2=y

View File

@ -1,4 +1,2 @@
CONFIG_IDF_TARGET="esp32h2"
CONFIG_IDF_TARGET_ESP32H2=y
CONFIG_OPENTHREAD_CLI=n
CONFIG_OPENTHREAD_CLI_ESP_EXTENSION=n

View File

@ -0,0 +1 @@
CONFIG_OPENTHREAD_RCP_SPI=y

View File

@ -1,5 +1,3 @@
CONFIG_IDF_TARGET="esp32c6"
CONFIG_IDF_TARGET_ESP32C6=y
CONFIG_OPENTHREAD_NETWORK_CHANNEL=12
CONFIG_OPENTHREAD_NETWORK_MASTERKEY="aabbccddeeff00112233445566778899"
CONFIG_ESP_SLEEP_DEBUG=y

View File

@ -1,7 +0,0 @@
CONFIG_IDF_TARGET="esp32h2"
CONFIG_IDF_TARGET_ESP32H2=y
CONFIG_OPENTHREAD_NETWORK_CHANNEL=12
CONFIG_OPENTHREAD_NETWORK_MASTERKEY="aabbccddeeff00112233445566778899"
CONFIG_ESP_SLEEP_DEBUG=y
CONFIG_LOG_MAXIMUM_LEVEL_DEBUG=y
CONFIG_ESP_SLEEP_CACHE_SAFE_ASSERTION=y

View File

@ -1,5 +1,3 @@
CONFIG_IDF_TARGET="esp32c6"
#
# Sleep Config
#

View File

@ -1 +0,0 @@
CONFIG_IDF_TARGET="esp32h2"

View File

@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(esp_ot_cli)

View File

@ -0,0 +1,133 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- |
# Thread Radio Encapsulation Link Example
This example demonstrates a Thread Radio Encapsulation Link (TREL) Example.
## How to use example
### Hardware Required
To run this example, a board with Wi-Fi module (for example ESP32-S3) is required.
### Configure the project
```
idf.py menuconfig
```
The Wi-Fi ssid and password should be set through the menuconfig:
```
Component config → → Example Connection Configuration → → WiFi SSID
Component config → → Example Connection Configuration → → WiFi Password
```
The example can run with the default configuration. OpenThread Command Line is enabled with UART as the default interface. Additionally, USB JTAG is also supported and can be activated through the menuconfig:
```
Component config → ESP System Settings → Channel for console output → USB Serial/JTAG Controller
```
### Build, Flash, and Run
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py build
idf.py -p PORT erase-flash flash monitor
```
Now you'll get an OpenThread command line shell.
### Example Output
The `help` command will print all of the supported commands.
```bash
> help
I(7058) OPENTHREAD:[INFO]-CLI-----: execute command: help
bbr
bufferinfo
ccathreshold
channel
child
childip
childmax
childsupervision
childtimeout
coap
contextreusedelay
counters
dataset
delaytimermin
diag
discover
dns
domainname
eidcache
eui64
extaddr
extpanid
factoryreset
...
```
## Set Up Network
To run this example, at least two ESP32-S3 boards flashed with this ot_trel example are required. And they must connect to the same wifi AP.
On the first device, run the following commands:
```bash
> factoryreset
... # the device will reboot
> dataset init new
Done
> dataset commit active
Done
> ifconfig up
Done
> thread start
Done
# After some seconds
> state
leader
Done
```
Now the first device has formed a Thread network as a leader. Get some information which will be used in next steps:
```bash
> ipaddr
fdde:ad00:beef:0:0:ff:fe00:fc00
fdde:ad00:beef:0:0:ff:fe00:8000
fdde:ad00:beef:0:a7c6:6311:9c8c:271b
fe80:0:0:0:5c27:a723:7115:c8f8
# Get the Active Dataset
> dataset active -x
0e080000000000010000000300001835060004001fffe00208fe7bb701f5f1125d0708fd75cbde7c6647bd0510b3914792d44f45b6c7d76eb9306eec94030f4f70656e5468726561642d35383332010258320410e35c581af5029b054fc904a24c2b27700c0402a0fff8
```
On the second device, set the active dataset from leader, and start Thread interface:
```bash
> factoryreset
... # the device will reboot
> dataset set active 0e080000000000010000000300001835060004001fffe00208fe7bb701f5f1125d0708fd75cbde7c6647bd0510b3914792d44f45b6c7d76eb9306eec94030f4f70656e5468726561642d35383332010258320410e35c581af5029b054fc904a24c2b27700c0402a0fff8
> ifconfig up
Done
> thread start
Done
# After some seconds
> state
router # child is also a valid state
Done
```
The second device has joined the Thread network as a router (or a child).
## Extension commands
You can refer to the [extension command](https://github.com/espressif/esp-thread-br/blob/main/components/esp_ot_cli_extension/README.md) about the extension commands.

View File

@ -0,0 +1,2 @@
idf_component_register(SRCS "esp_ot_trel.c"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,9 @@
menu "OpenThread TREL Example"
config OPENTHREAD_AUTO_START
bool 'Enable the automatic start mode.'
default False
help
If enabled, the Openthread Device will create or connect to thread network with pre-configured
network parameters automatically. Otherwise, user need to configure Thread via CLI command manually.
endmenu

View File

@ -0,0 +1,58 @@
/*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*
* OpenThread Command Line Example
*
* This example code is in the Public Domain (or CC0 licensed, at your option.)
*
* Unless required by applicable law or agreed to in writing, this
* software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied.
*/
#pragma once
#include "sdkconfig.h"
#include "esp_openthread_types.h"
#define ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG() \
{ \
.radio_mode = RADIO_MODE_TREL, \
}
#if CONFIG_OPENTHREAD_CONSOLE_TYPE_UART
#define ESP_OPENTHREAD_DEFAULT_HOST_CONFIG() \
{ \
.host_connection_mode = HOST_CONNECTION_MODE_CLI_UART, \
.host_uart_config = { \
.port = 0, \
.uart_config = \
{ \
.baud_rate = 115200, \
.data_bits = UART_DATA_8_BITS, \
.parity = UART_PARITY_DISABLE, \
.stop_bits = UART_STOP_BITS_1, \
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE, \
.rx_flow_ctrl_thresh = 0, \
.source_clk = UART_SCLK_DEFAULT, \
}, \
.rx_pin = UART_PIN_NO_CHANGE, \
.tx_pin = UART_PIN_NO_CHANGE, \
}, \
}
#elif CONFIG_OPENTHREAD_CONSOLE_TYPE_USB_SERIAL_JTAG
#define ESP_OPENTHREAD_DEFAULT_HOST_CONFIG() \
{ \
.host_connection_mode = HOST_CONNECTION_MODE_CLI_USB, \
.host_usb_config = USB_SERIAL_JTAG_DRIVER_CONFIG_DEFAULT(), \
}
#endif
#define ESP_OPENTHREAD_DEFAULT_PORT_CONFIG() \
{ \
.storage_partition_name = "nvs", \
.netif_queue_size = 10, \
.task_queue_size = 10, \
}

View File

@ -0,0 +1,139 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*
* OpenThread Command Line Example
*
* This example code is in the Public Domain (or CC0 licensed, at your option.)
*
* Unless required by applicable law or agreed to in writing, this
* software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "esp_netif_types.h"
#include "esp_openthread.h"
#include "esp_openthread_cli.h"
#include "esp_openthread_lock.h"
#include "esp_openthread_netif_glue.h"
#include "esp_openthread_types.h"
#include "esp_ot_config.h"
#include "esp_vfs_eventfd.h"
#include "driver/uart.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "hal/uart_types.h"
#include "nvs_flash.h"
#include "openthread/cli.h"
#include "openthread/instance.h"
#include "openthread/logging.h"
#include "openthread/tasklet.h"
#include "protocol_examples_common.h"
#include "mdns.h"
#if !CONFIG_EXAMPLE_CONNECT_WIFI && !CONFIG_EXAMPLE_CONNECT_ETHERNET
#error No netif for TREL!
#endif
#if CONFIG_OPENTHREAD_STATE_INDICATOR_ENABLE
#include "ot_led_strip.h"
#endif
#if CONFIG_OPENTHREAD_CLI_ESP_EXTENSION
#include "esp_ot_cli_extension.h"
#endif // CONFIG_OPENTHREAD_CLI_ESP_EXTENSION
#define TAG "ot_esp_trel"
static esp_netif_t *init_openthread_netif(const esp_openthread_platform_config_t *config)
{
esp_netif_config_t cfg = ESP_NETIF_DEFAULT_OPENTHREAD();
esp_netif_t *netif = esp_netif_new(&cfg);
assert(netif != NULL);
ESP_ERROR_CHECK(esp_netif_attach(netif, esp_openthread_netif_glue_init(config)));
return netif;
}
static void ot_task_worker(void *aContext)
{
esp_openthread_platform_config_t config = {
.radio_config = ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG(),
.host_config = ESP_OPENTHREAD_DEFAULT_HOST_CONFIG(),
.port_config = ESP_OPENTHREAD_DEFAULT_PORT_CONFIG(),
};
ESP_ERROR_CHECK(example_connect());
// Initialize the OpenThread stack
ESP_ERROR_CHECK(esp_openthread_init(&config));
#if CONFIG_OPENTHREAD_STATE_INDICATOR_ENABLE
ESP_ERROR_CHECK(esp_openthread_state_indicator_init(esp_openthread_get_instance()));
#endif
#if CONFIG_OPENTHREAD_LOG_LEVEL_DYNAMIC
// The OpenThread log level directly matches ESP log level
(void)otLoggingSetLevel(CONFIG_LOG_DEFAULT_LEVEL);
#endif
// Initialize the OpenThread cli
#if CONFIG_OPENTHREAD_CLI
esp_openthread_cli_init();
#endif
esp_netif_t *openthread_netif;
// Initialize the esp_netif bindings
openthread_netif = init_openthread_netif(&config);
esp_netif_set_default_netif(openthread_netif);
#if CONFIG_OPENTHREAD_CLI_ESP_EXTENSION
esp_cli_custom_command_init();
#endif // CONFIG_OPENTHREAD_CLI_ESP_EXTENSION
// Run the main loop
#if CONFIG_OPENTHREAD_CLI
esp_openthread_cli_create_task();
#endif
#if CONFIG_OPENTHREAD_AUTO_START
otOperationalDatasetTlvs dataset;
otError error = otDatasetGetActiveTlvs(esp_openthread_get_instance(), &dataset);
ESP_ERROR_CHECK(esp_openthread_auto_start((error == OT_ERROR_NONE) ? &dataset : NULL));
#endif
esp_openthread_launch_mainloop();
// Clean up
esp_openthread_netif_glue_deinit();
esp_netif_destroy(openthread_netif);
esp_vfs_eventfd_unregister();
vTaskDelete(NULL);
}
void app_main(void)
{
// Used eventfds:
// * netif
// * ot task queue
esp_vfs_eventfd_config_t eventfd_config = {
.max_fds = 2,
};
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_vfs_eventfd_register(&eventfd_config));
ESP_ERROR_CHECK(mdns_init());
ESP_ERROR_CHECK(mdns_hostname_set("esp-ot-trel"));
xTaskCreate(ot_task_worker, "ot_trel_main", 8192, xTaskGetCurrentTaskHandle(), 5, NULL);
}

View File

@ -0,0 +1,11 @@
## IDF Component Manager Manifest File
dependencies:
espressif/esp_ot_cli_extension:
version: "~1.2.0"
espressif/mdns: "^1.0.3"
idf:
version: ">=4.1.0"
protocol_examples_common:
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
ot_led:
path: ${IDF_PATH}/examples/openthread/ot_common_components/ot_led

View File

@ -0,0 +1,5 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 0x170000,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000,
5 factory, app, factory, 0x10000, 0x170000,

View File

@ -0,0 +1,3 @@
CONFIG_EXAMPLE_CONNECT_WIFI=y
CONFIG_EXAMPLE_WIFI_SSID="OTCITE"
CONFIG_EXAMPLE_WIFI_PASSWORD="otcitest888"

View File

@ -0,0 +1,43 @@
#
# Partition Table
#
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_OFFSET=0x8000
CONFIG_PARTITION_TABLE_MD5=y
# end of Partition Table
#
# mbedTLS
#
CONFIG_MBEDTLS_CMAC_C=y
CONFIG_MBEDTLS_SSL_PROTO_DTLS=y
CONFIG_MBEDTLS_KEY_EXCHANGE_ECJPAKE=y
CONFIG_MBEDTLS_ECJPAKE_C=y
# end of mbedTLS
#
# OpenThread
#
CONFIG_OPENTHREAD_ENABLED=y
CONFIG_OPENTHREAD_BORDER_ROUTER=n
CONFIG_OPENTHREAD_DNS64_CLIENT=y
CONFIG_OPENTHREAD_RADIO_154_NONE=y
CONFIG_OPENTHREAD_RADIO_TREL=y
# end of OpenThread
#
# lwIP
#
CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=4096
CONFIG_LWIP_IPV6_NUM_ADDRESSES=8
CONFIG_LWIP_MULTICAST_PING=y
CONFIG_LWIP_HOOK_IP6_SELECT_SRC_ADDR_CUSTOM=y
CONFIG_LWIP_IPV6_AUTOCONFIG=y
# end of lwIP
#
# Configurations for optimizing the size of firmware
#
CONFIG_COMPILER_OPTIMIZATION_SIZE=y

View File

@ -59,6 +59,9 @@ from pytest_embedded_idf.dut import IdfDut
# Case 14: Curl a website over HTTPS via DNS and NAT64
# A border router joins a Wi-Fi network and forms a Thread network, a Thread devices attached to it and curl a https website.
# Case 15: Thread network formation and attaching with TREL
# A TREL device forms a Thread network, other TREL devices attach to it, then test ping connection between them.
@pytest.fixture(scope='module', name='Init_avahi')
def fixture_Init_avahi() -> bool:
@ -91,11 +94,16 @@ default_cli_ot_para = ocf.thread_parameter('router', '', '', '', False)
@pytest.mark.flaky(reruns=1, reruns_delay=1)
@pytest.mark.parametrize(
'config, count, app_path, target', [
('rcp|cli_h2|br', 3,
('rcp_uart|cli|br', 3,
f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}'
f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}'
f'|{os.path.join(os.path.dirname(__file__), "ot_br")}',
'esp32c6|esp32h2|esp32s3'),
('rcp_spi|cli|br_spi', 3,
f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}'
f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}'
f'|{os.path.join(os.path.dirname(__file__), "ot_br")}',
'esp32h2|esp32c6|esp32s3'),
],
indirect=True,
)
@ -161,7 +169,7 @@ def formBasicWiFiThreadNetwork(br:IdfDut, cli:IdfDut) -> None:
@pytest.mark.flaky(reruns=1, reruns_delay=1)
@pytest.mark.parametrize(
'config, count, app_path, target', [
('rcp|cli_h2|br', 3,
('rcp_uart|cli|br', 3,
f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}'
f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}'
f'|{os.path.join(os.path.dirname(__file__), "ot_br")}',
@ -210,7 +218,7 @@ def test_Bidirectional_IPv6_connectivity(Init_interface:bool, dut: Tuple[IdfDut,
@pytest.mark.flaky(reruns=1, reruns_delay=1)
@pytest.mark.parametrize(
'config, count, app_path, target', [
('rcp|cli_h2|br', 3,
('rcp_uart|cli|br', 3,
f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}'
f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}'
f'|{os.path.join(os.path.dirname(__file__), "ot_br")}',
@ -260,7 +268,7 @@ def test_multicast_forwarding_A(Init_interface:bool, dut: Tuple[IdfDut, IdfDut,
@pytest.mark.flaky(reruns=1, reruns_delay=1)
@pytest.mark.parametrize(
'config, count, app_path, target', [
('rcp|cli_h2|br', 3,
('rcp_uart|cli|br', 3,
f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}'
f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}'
f'|{os.path.join(os.path.dirname(__file__), "ot_br")}',
@ -311,7 +319,7 @@ def test_multicast_forwarding_B(Init_interface:bool, dut: Tuple[IdfDut, IdfDut,
@pytest.mark.flaky(reruns=1, reruns_delay=1)
@pytest.mark.parametrize(
'config, count, app_path, target', [
('rcp|cli_h2|br', 3,
('rcp_uart|cli|br', 3,
f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}'
f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}'
f'|{os.path.join(os.path.dirname(__file__), "ot_br")}',
@ -367,7 +375,7 @@ def test_service_discovery_of_Thread_device(Init_interface:bool, Init_avahi:bool
@pytest.mark.flaky(reruns=1, reruns_delay=1)
@pytest.mark.parametrize(
'config, count, app_path, target', [
('rcp|cli_h2|br', 3,
('rcp_uart|cli|br', 3,
f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}'
f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}'
f'|{os.path.join(os.path.dirname(__file__), "ot_br")}',
@ -430,7 +438,7 @@ def test_service_discovery_of_WiFi_device(Init_interface:bool, Init_avahi:bool,
@pytest.mark.flaky(reruns=1, reruns_delay=1)
@pytest.mark.parametrize(
'config, count, app_path, target', [
('rcp|cli_h2|br', 3,
('rcp_uart|cli|br', 3,
f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}'
f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}'
f'|{os.path.join(os.path.dirname(__file__), "ot_br")}',
@ -465,7 +473,7 @@ def test_ICMP_NAT64(Init_interface:bool, dut: Tuple[IdfDut, IdfDut, IdfDut]) ->
@pytest.mark.flaky(reruns=1, reruns_delay=1)
@pytest.mark.parametrize(
'config, count, app_path, target', [
('rcp|cli_h2|br', 3,
('rcp_uart|cli|br', 3,
f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}'
f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}'
f'|{os.path.join(os.path.dirname(__file__), "ot_br")}',
@ -518,7 +526,7 @@ def test_UDP_NAT64(Init_interface:bool, dut: Tuple[IdfDut, IdfDut, IdfDut]) -> N
@pytest.mark.flaky(reruns=1, reruns_delay=1)
@pytest.mark.parametrize(
'config, count, app_path, target', [
('rcp|cli_h2|br', 3,
('rcp_uart|cli|br', 3,
f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}'
f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}'
f'|{os.path.join(os.path.dirname(__file__), "ot_br")}',
@ -575,11 +583,11 @@ def test_TCP_NAT64(Init_interface:bool, dut: Tuple[IdfDut, IdfDut, IdfDut]) -> N
@pytest.mark.openthread_sleep
@pytest.mark.parametrize(
'config, count, app_path, target', [
('cli_h2|sleepy_c6', 2,
('cli|sleepy', 2,
f'{os.path.join(os.path.dirname(__file__), "ot_cli")}'
f'|{os.path.join(os.path.dirname(__file__), "ot_sleepy_device/light_sleep")}',
'esp32h2|esp32c6'),
('cli_c6|sleepy_h2', 2,
('cli|sleepy', 2,
f'{os.path.join(os.path.dirname(__file__), "ot_cli")}'
f'|{os.path.join(os.path.dirname(__file__), "ot_sleepy_device/light_sleep")}',
'esp32c6|esp32h2'),
@ -627,7 +635,7 @@ def test_ot_sleepy_device(dut: Tuple[IdfDut, IdfDut]) -> None:
@pytest.mark.flaky(reruns=1, reruns_delay=1)
@pytest.mark.parametrize(
'config, count, app_path, target', [
('rcp|br', 2,
('rcp_uart|br', 2,
f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}'
f'|{os.path.join(os.path.dirname(__file__), "ot_br")}',
'esp32c6|esp32s3'),
@ -666,7 +674,7 @@ def test_basic_startup(dut: Tuple[IdfDut, IdfDut]) -> None:
@pytest.mark.flaky(reruns=1, reruns_delay=1)
@pytest.mark.parametrize(
'config, count, app_path, target', [
('rcp|cli_h2|br', 3,
('rcp_uart|cli|br', 3,
f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}'
f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}'
f'|{os.path.join(os.path.dirname(__file__), "ot_br")}',
@ -703,7 +711,7 @@ def test_NAT64_DNS(Init_interface:bool, dut: Tuple[IdfDut, IdfDut, IdfDut]) -> N
@pytest.mark.flaky(reruns=1, reruns_delay=1)
@pytest.mark.parametrize(
'config, count, app_path, target', [
('rcp|br', 2,
('rcp_uart|br', 2,
f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}'
f'|{os.path.join(os.path.dirname(__file__), "ot_br")}',
'esp32c6|esp32s3'),
@ -761,7 +769,7 @@ def test_br_meshcop(Init_interface:bool, Init_avahi:bool, dut: Tuple[IdfDut, Idf
@pytest.mark.flaky(reruns=1, reruns_delay=1)
@pytest.mark.parametrize(
'config, count, app_path, target', [
('rcp|cli_h2|br', 3,
('rcp_uart|cli|br', 3,
f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}'
f'|{os.path.join(os.path.dirname(__file__), "ot_cli")}'
f'|{os.path.join(os.path.dirname(__file__), "ot_br")}',
@ -787,3 +795,53 @@ def test_https_NAT64_DNS(Init_interface:bool, dut: Tuple[IdfDut, IdfDut, IdfDut]
ocf.execute_command(br, 'factoryreset')
ocf.execute_command(cli, 'factoryreset')
time.sleep(3)
# Case 15: Thread network formation and attaching with TREL
@pytest.mark.supported_targets
@pytest.mark.esp32c6
@pytest.mark.openthread_br
@pytest.mark.flaky(reruns=1, reruns_delay=1)
@pytest.mark.parametrize(
'config, count, app_path, target', [
('trel|trel', 2,
f'{os.path.join(os.path.dirname(__file__), "ot_trel")}'
f'|{os.path.join(os.path.dirname(__file__), "ot_trel")}',
'esp32c6|esp32s3'),
],
indirect=True,
)
def test_trel_connect(dut: Tuple[IdfDut, IdfDut]) -> None:
trel_s3 = dut[1]
trel_c6 = dut[0]
trel_list = [trel_c6]
router_extaddr_list = ['7766554433221101']
trel_s3.expect('IPv4 address:', timeout=10)
trel_c6.expect('IPv4 address:', timeout=10)
ocf.init_thread(trel_s3)
for trel in trel_list:
ocf.init_thread(trel)
trel_leader_para = copy.copy(default_br_ot_para)
trel_leader_para.bbr = False
ocf.joinThreadNetwork(trel_s3, trel_leader_para)
trel_para = copy.copy(default_cli_ot_para)
trel_para.dataset = ocf.getDataset(trel_s3)
try:
order = 0
for trel in trel_list:
trel_para.exaddr = router_extaddr_list[order]
order = order + 1
ocf.joinThreadNetwork(trel, trel_para)
for trel in trel_list:
trel_mleid_addr = ocf.get_mleid_addr(trel)
trel_s3_mleid_addr = ocf.get_mleid_addr(trel_s3)
rx_nums = ocf.ot_ping(trel, trel_s3_mleid_addr, 5)[1]
assert rx_nums == 5
rx_nums = ocf.ot_ping(trel_s3, trel_mleid_addr, 5)[1]
assert rx_nums == 5
finally:
ocf.execute_command(trel_s3, 'factoryreset')
for trel in trel_list:
ocf.execute_command(trel, 'factoryreset')
time.sleep(3)