From 38f024681c3c3704bcedb6c87a5a63c7b0b4edea Mon Sep 17 00:00:00 2001 From: Xu Si Yu Date: Tue, 24 Sep 2024 10:35:54 +0800 Subject: [PATCH 1/7] feat(openthread): support vendor hook for rcp spi --- components/openthread/CMakeLists.txt | 7 ++++ .../openthread/src/ncp/esp_openthread_ncp.cpp | 5 +-- .../src/ncp/esp_openthread_ncp_hdlc.cpp | 6 +--- .../src/ncp/esp_openthread_ncp_spi.cpp | 29 +++++++++++++++ examples/openthread/.build-test-rules.yml | 5 ++- examples/openthread/ot_br/sdkconfig.ci.br_spi | 1 + examples/openthread/ot_cli/sdkconfig.ci.cli | 0 .../openthread/ot_cli/sdkconfig.ci.cli_c6 | 2 -- .../openthread/ot_cli/sdkconfig.ci.cli_h2 | 2 -- .../ot_cli/sdkconfig.ci.disable_cli | 2 -- .../openthread/ot_rcp/sdkconfig.ci.rcp_spi | 1 + ...sdkconfig.ci.rcp => sdkconfig.ci.rcp_uart} | 0 ...onfig.ci.sleepy_c6 => sdkconfig.ci.sleepy} | 2 -- .../light_sleep/sdkconfig.ci.sleepy_h2 | 7 ---- .../light_sleep/sdkconfig.defaults.esp32c6 | 2 -- .../light_sleep/sdkconfig.defaults.esp32h2 | 1 - examples/openthread/pytest_otbr.py | 35 +++++++++++-------- 17 files changed, 62 insertions(+), 45 deletions(-) create mode 100644 components/openthread/src/ncp/esp_openthread_ncp_spi.cpp create mode 100644 examples/openthread/ot_br/sdkconfig.ci.br_spi create mode 100644 examples/openthread/ot_cli/sdkconfig.ci.cli delete mode 100644 examples/openthread/ot_cli/sdkconfig.ci.cli_c6 delete mode 100644 examples/openthread/ot_cli/sdkconfig.ci.cli_h2 create mode 100644 examples/openthread/ot_rcp/sdkconfig.ci.rcp_spi rename examples/openthread/ot_rcp/{sdkconfig.ci.rcp => sdkconfig.ci.rcp_uart} (100%) rename examples/openthread/ot_sleepy_device/light_sleep/{sdkconfig.ci.sleepy_c6 => sdkconfig.ci.sleepy} (78%) delete mode 100644 examples/openthread/ot_sleepy_device/light_sleep/sdkconfig.ci.sleepy_h2 delete mode 100644 examples/openthread/ot_sleepy_device/light_sleep/sdkconfig.defaults.esp32h2 diff --git a/components/openthread/CMakeLists.txt b/components/openthread/CMakeLists.txt index a457955602..fa52dc7a95 100644 --- a/components/openthread/CMakeLists.txt +++ b/components/openthread/CMakeLists.txt @@ -154,6 +154,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) diff --git a/components/openthread/src/ncp/esp_openthread_ncp.cpp b/components/openthread/src/ncp/esp_openthread_ncp.cpp index 7e5127f869..eefeda5017 100644 --- a/components/openthread/src/ncp/esp_openthread_ncp.cpp +++ b/components/openthread/src/ncp/esp_openthread_ncp.cpp @@ -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 diff --git a/components/openthread/src/ncp/esp_openthread_ncp_hdlc.cpp b/components/openthread/src/ncp/esp_openthread_ncp_hdlc.cpp index 0e8a3dbb88..6b86b6d935 100644 --- a/components/openthread/src/ncp/esp_openthread_ncp_hdlc.cpp +++ b/components/openthread/src/ncp/esp_openthread_ncp_hdlc.cpp @@ -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 diff --git a/components/openthread/src/ncp/esp_openthread_ncp_spi.cpp b/components/openthread/src/ncp/esp_openthread_ncp_spi.cpp new file mode 100644 index 0000000000..d85c918aad --- /dev/null +++ b/components/openthread/src/ncp/esp_openthread_ncp_spi.cpp @@ -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(aInstance); + + ncpSpi = new (&sNcpRaw) NcpSpi(instance); + + if (ncpSpi == nullptr || ncpSpi != NcpBase::GetNcpInstance()) + { + OT_ASSERT(false); + } +} + +} // namespace Ncp +} // namespace ot diff --git a/examples/openthread/.build-test-rules.yml b/examples/openthread/.build-test-rules.yml index d431fd6861..bec9ecfcbf 100644 --- a/examples/openthread/.build-test-rules.yml +++ b/examples/openthread/.build-test-rules.yml @@ -36,9 +36,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: diff --git a/examples/openthread/ot_br/sdkconfig.ci.br_spi b/examples/openthread/ot_br/sdkconfig.ci.br_spi new file mode 100644 index 0000000000..1778799eb7 --- /dev/null +++ b/examples/openthread/ot_br/sdkconfig.ci.br_spi @@ -0,0 +1 @@ +CONFIG_OPENTHREAD_RADIO_SPINEL_SPI=y diff --git a/examples/openthread/ot_cli/sdkconfig.ci.cli b/examples/openthread/ot_cli/sdkconfig.ci.cli new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/openthread/ot_cli/sdkconfig.ci.cli_c6 b/examples/openthread/ot_cli/sdkconfig.ci.cli_c6 deleted file mode 100644 index a7f4dfb822..0000000000 --- a/examples/openthread/ot_cli/sdkconfig.ci.cli_c6 +++ /dev/null @@ -1,2 +0,0 @@ -CONFIG_IDF_TARGET="esp32c6" -CONFIG_IDF_TARGET_ESP32C6=y diff --git a/examples/openthread/ot_cli/sdkconfig.ci.cli_h2 b/examples/openthread/ot_cli/sdkconfig.ci.cli_h2 deleted file mode 100644 index 485c06eac5..0000000000 --- a/examples/openthread/ot_cli/sdkconfig.ci.cli_h2 +++ /dev/null @@ -1,2 +0,0 @@ -CONFIG_IDF_TARGET="esp32h2" -CONFIG_IDF_TARGET_ESP32H2=y diff --git a/examples/openthread/ot_cli/sdkconfig.ci.disable_cli b/examples/openthread/ot_cli/sdkconfig.ci.disable_cli index 51c321da5e..a281edc22b 100644 --- a/examples/openthread/ot_cli/sdkconfig.ci.disable_cli +++ b/examples/openthread/ot_cli/sdkconfig.ci.disable_cli @@ -1,4 +1,2 @@ -CONFIG_IDF_TARGET="esp32h2" -CONFIG_IDF_TARGET_ESP32H2=y CONFIG_OPENTHREAD_CLI=n CONFIG_OPENTHREAD_CLI_ESP_EXTENSION=n diff --git a/examples/openthread/ot_rcp/sdkconfig.ci.rcp_spi b/examples/openthread/ot_rcp/sdkconfig.ci.rcp_spi new file mode 100644 index 0000000000..87b895575b --- /dev/null +++ b/examples/openthread/ot_rcp/sdkconfig.ci.rcp_spi @@ -0,0 +1 @@ +CONFIG_OPENTHREAD_RCP_SPI=y diff --git a/examples/openthread/ot_rcp/sdkconfig.ci.rcp b/examples/openthread/ot_rcp/sdkconfig.ci.rcp_uart similarity index 100% rename from examples/openthread/ot_rcp/sdkconfig.ci.rcp rename to examples/openthread/ot_rcp/sdkconfig.ci.rcp_uart diff --git a/examples/openthread/ot_sleepy_device/light_sleep/sdkconfig.ci.sleepy_c6 b/examples/openthread/ot_sleepy_device/light_sleep/sdkconfig.ci.sleepy similarity index 78% rename from examples/openthread/ot_sleepy_device/light_sleep/sdkconfig.ci.sleepy_c6 rename to examples/openthread/ot_sleepy_device/light_sleep/sdkconfig.ci.sleepy index c4abd6d670..9f3ddc2c93 100644 --- a/examples/openthread/ot_sleepy_device/light_sleep/sdkconfig.ci.sleepy_c6 +++ b/examples/openthread/ot_sleepy_device/light_sleep/sdkconfig.ci.sleepy @@ -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 diff --git a/examples/openthread/ot_sleepy_device/light_sleep/sdkconfig.ci.sleepy_h2 b/examples/openthread/ot_sleepy_device/light_sleep/sdkconfig.ci.sleepy_h2 deleted file mode 100644 index b7fa32376f..0000000000 --- a/examples/openthread/ot_sleepy_device/light_sleep/sdkconfig.ci.sleepy_h2 +++ /dev/null @@ -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 diff --git a/examples/openthread/ot_sleepy_device/light_sleep/sdkconfig.defaults.esp32c6 b/examples/openthread/ot_sleepy_device/light_sleep/sdkconfig.defaults.esp32c6 index 2c90c3e7ee..229cb8cc6b 100644 --- a/examples/openthread/ot_sleepy_device/light_sleep/sdkconfig.defaults.esp32c6 +++ b/examples/openthread/ot_sleepy_device/light_sleep/sdkconfig.defaults.esp32c6 @@ -1,5 +1,3 @@ -CONFIG_IDF_TARGET="esp32c6" - # # Sleep Config # diff --git a/examples/openthread/ot_sleepy_device/light_sleep/sdkconfig.defaults.esp32h2 b/examples/openthread/ot_sleepy_device/light_sleep/sdkconfig.defaults.esp32h2 deleted file mode 100644 index ba2980822c..0000000000 --- a/examples/openthread/ot_sleepy_device/light_sleep/sdkconfig.defaults.esp32h2 +++ /dev/null @@ -1 +0,0 @@ -CONFIG_IDF_TARGET="esp32h2" diff --git a/examples/openthread/pytest_otbr.py b/examples/openthread/pytest_otbr.py index ea9dc3353d..604862d8d3 100644 --- a/examples/openthread/pytest_otbr.py +++ b/examples/openthread/pytest_otbr.py @@ -91,11 +91,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 +166,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 +215,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 +265,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 +316,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 +372,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 +435,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 +470,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 +523,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 +580,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 +632,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 +671,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 +708,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 +766,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")}', From 64dc7ebbc3b3a0040e4bd978fa93393685fd7072 Mon Sep 17 00:00:00 2001 From: Xu Si Yu Date: Thu, 26 Sep 2024 14:29:51 +0800 Subject: [PATCH 2/7] fix(openthread): add macro for rcp init --- components/openthread/src/esp_openthread_platform.cpp | 4 ++++ components/openthread/src/port/esp_openthread_spi_slave.c | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/components/openthread/src/esp_openthread_platform.cpp b/components/openthread/src/esp_openthread_platform.cpp index 3e73ef362a..8beb8143dc 100644 --- a/components/openthread/src/esp_openthread_platform.cpp +++ b/components/openthread/src/esp_openthread_platform.cpp @@ -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, diff --git a/components/openthread/src/port/esp_openthread_spi_slave.c b/components/openthread/src/port/esp_openthread_spi_slave.c index 979e6067e7..754300e5c9 100644 --- a/components/openthread/src/port/esp_openthread_spi_slave.c +++ b/components/openthread/src/port/esp_openthread_spi_slave.c @@ -25,7 +25,6 @@ #include #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" From 77ce639292e2c8726bbd5e86fecad15e01d93a99 Mon Sep 17 00:00:00 2001 From: zwx Date: Mon, 23 Sep 2024 16:55:41 +0800 Subject: [PATCH 3/7] feat(ieee802154): add frame type checking for hw autoack feature --- components/ieee802154/driver/esp_ieee802154_frame.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/ieee802154/driver/esp_ieee802154_frame.c b/components/ieee802154/driver/esp_ieee802154_frame.c index e32e338ae0..c5cc1e907c 100644 --- a/components/ieee802154/driver/esp_ieee802154_frame.c +++ b/components/ieee802154/driver/esp_ieee802154_frame.c @@ -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) From 6e1bc899451c93088844988cb58fb11bdc45a214 Mon Sep 17 00:00:00 2001 From: Xu Si Yu Date: Tue, 24 Sep 2024 14:17:21 +0800 Subject: [PATCH 4/7] fix(ieee802154): fix a bug in the usage of a macro --- components/ieee802154/driver/esp_ieee802154_dev.c | 2 +- components/ieee802154/driver/esp_ieee802154_util.c | 2 +- components/ieee802154/private_include/esp_ieee802154_util.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/ieee802154/driver/esp_ieee802154_dev.c b/components/ieee802154/driver/esp_ieee802154_dev.c index d893cceef6..e6efdddb2d 100644 --- a/components/ieee802154/driver/esp_ieee802154_dev.c +++ b/components/ieee802154/driver/esp_ieee802154_dev.c @@ -773,7 +773,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 diff --git a/components/ieee802154/driver/esp_ieee802154_util.c b/components/ieee802154/driver/esp_ieee802154_util.c index bb486fdea9..c3ffed0a94 100644 --- a/components/ieee802154/driver/esp_ieee802154_util.c +++ b/components/ieee802154/driver/esp_ieee802154_util.c @@ -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) { diff --git a/components/ieee802154/private_include/esp_ieee802154_util.h b/components/ieee802154/private_include/esp_ieee802154_util.h index 7949e5286d..c1e843055a 100644 --- a/components/ieee802154/private_include/esp_ieee802154_util.h +++ b/components/ieee802154/private_include/esp_ieee802154_util.h @@ -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. From 064ac29b416df33a2a372e6edb40dd77330963f4 Mon Sep 17 00:00:00 2001 From: zwx Date: Thu, 26 Sep 2024 12:15:58 +0800 Subject: [PATCH 5/7] fix(802154): pass hardware abort reason into processing function --- .../ieee802154/driver/esp_ieee802154_dev.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/components/ieee802154/driver/esp_ieee802154_dev.c b/components/ieee802154/driver/esp_ieee802154_dev.c index e6efdddb2d..05a3df7442 100644 --- a/components/ieee802154/driver/esp_ieee802154_dev.c +++ b/components/ieee802154/driver/esp_ieee802154_dev.c @@ -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); } From f6591b773e096b93223aadbb4700d285c7b24d63 Mon Sep 17 00:00:00 2001 From: Xu Si Yu Date: Wed, 17 Jul 2024 12:27:56 +0800 Subject: [PATCH 6/7] feat(openthread): support trel feature --- components/openthread/CMakeLists.txt | 18 +- components/openthread/Kconfig | 20 +- .../openthread/include/esp_openthread_trel.h | 38 ++ .../openthread/include/esp_openthread_types.h | 1 + .../openthread-core-esp32x-ftd-config.h | 32 +- .../src/port/esp_openthread_radio.c | 2 +- .../src/port/esp_openthread_radio_spinel.cpp | 1 - .../openthread/src/port/esp_openthread_trel.c | 374 ++++++++++++++++++ .../src/port/esp_spi_spinel_interface.cpp | 2 +- examples/openthread/.build-test-rules.yml | 5 + examples/openthread/ot_trel/CMakeLists.txt | 6 + examples/openthread/ot_trel/README.md | 132 +++++++ .../openthread/ot_trel/main/CMakeLists.txt | 2 + .../openthread/ot_trel/main/Kconfig.projbuild | 9 + .../openthread/ot_trel/main/esp_ot_config.h | 58 +++ .../openthread/ot_trel/main/esp_ot_trel.c | 141 +++++++ .../openthread/ot_trel/main/idf_component.yml | 11 + examples/openthread/ot_trel/partitions.csv | 5 + .../openthread/ot_trel/sdkconfig.defaults | 42 ++ 19 files changed, 884 insertions(+), 15 deletions(-) create mode 100644 components/openthread/include/esp_openthread_trel.h create mode 100644 components/openthread/src/port/esp_openthread_trel.c create mode 100644 examples/openthread/ot_trel/CMakeLists.txt create mode 100644 examples/openthread/ot_trel/README.md create mode 100644 examples/openthread/ot_trel/main/CMakeLists.txt create mode 100644 examples/openthread/ot_trel/main/Kconfig.projbuild create mode 100644 examples/openthread/ot_trel/main/esp_ot_config.h create mode 100644 examples/openthread/ot_trel/main/esp_ot_trel.c create mode 100644 examples/openthread/ot_trel/main/idf_component.yml create mode 100644 examples/openthread/ot_trel/partitions.csv create mode 100644 examples/openthread/ot_trel/sdkconfig.defaults diff --git a/components/openthread/CMakeLists.txt b/components/openthread/CMakeLists.txt index fa52dc7a95..4b0b3d2320 100644 --- a/components/openthread/CMakeLists.txt +++ b/components/openthread/CMakeLists.txt @@ -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" @@ -138,6 +137,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) @@ -257,6 +269,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") diff --git a/components/openthread/Kconfig b/components/openthread/Kconfig index 160084fbcb..9ae0a6c63b 100644 --- a/components/openthread/Kconfig +++ b/components/openthread/Kconfig @@ -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 SOC_WIFI_SUPPORTED + 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 diff --git a/components/openthread/include/esp_openthread_trel.h b/components/openthread/include/esp_openthread_trel.h new file mode 100644 index 0000000000..c2dc8c58b4 --- /dev/null +++ b/components/openthread/include/esp_openthread_trel.h @@ -0,0 +1,38 @@ +/* + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "sdkconfig.h" +#include "esp_netif.h" +#include "esp_netif_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Sets the interface used for trel feature. + * + * @note This function must be called after connect to wifi/ethernet + * + * @param[in] trel_netif The network interface (WiFi or ethernet) + * + */ +void esp_openthread_set_trel_netif(esp_netif_t *trel_netif); + +/** + * @brief Gets the trel interface of OpenThread device. + * + * @return + * The trel interface or NULL if trel not initialized. + * + */ +esp_netif_t *esp_openthread_get_trel_netif(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/openthread/include/esp_openthread_types.h b/components/openthread/include/esp_openthread_types.h index 0309594019..e046c4606f 100644 --- a/components/openthread/include/esp_openthread_types.h +++ b/components/openthread/include/esp_openthread_types.h @@ -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; diff --git a/components/openthread/private_include/openthread-core-esp32x-ftd-config.h b/components/openthread/private_include/openthread-core-esp32x-ftd-config.h index aa8882f234..0cd3542a91 100644 --- a/components/openthread/private_include/openthread-core-esp32x-ftd-config.h +++ b/components/openthread/private_include/openthread-core-esp32x-ftd-config.h @@ -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_NATIVE || CONFIG_OPENTHREAD_RADIO_SPINEL_UART || CONFIG_OPENTHREAD_RADIO_SPINEL_SPI +#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 diff --git a/components/openthread/src/port/esp_openthread_radio.c b/components/openthread/src/port/esp_openthread_radio.c index 4276809c52..aac760c260 100644 --- a/components/openthread/src/port/esp_openthread_radio.c +++ b/components/openthread/src/port/esp_openthread_radio.c @@ -7,7 +7,7 @@ #include #include "esp_openthread_radio.h" -#include "error.h" +#include "openthread/error.h" #include "esp_err.h" #include "sdkconfig.h" #include "esp_check.h" diff --git a/components/openthread/src/port/esp_openthread_radio_spinel.cpp b/components/openthread/src/port/esp_openthread_radio_spinel.cpp index 34eccebc8a..4cbe63a845 100644 --- a/components/openthread/src/port/esp_openthread_radio_spinel.cpp +++ b/components/openthread/src/port/esp_openthread_radio_spinel.cpp @@ -6,7 +6,6 @@ #include "esp_openthread_radio.h" -#include "link_raw.h" #include "sdkconfig.h" #include "esp_check.h" #include "esp_err.h" diff --git a/components/openthread/src/port/esp_openthread_trel.c b/components/openthread/src/port/esp_openthread_trel.c new file mode 100644 index 0000000000..69c43f00ec --- /dev/null +++ b/components/openthread/src/port/esp_openthread_trel.c @@ -0,0 +1,374 @@ +/* + * 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_common_macro.h" +#include "esp_openthread_lock.h" +#include "esp_openthread_radio.h" +#include "esp_openthread_task_queue.h" +#include "esp_openthread_trel.h" +#include "lwip/pbuf.h" +#include "lwip/tcpip.h" +#include "lwip/udp.h" +#include "openthread/trel.h" +#include "openthread/platform/diag.h" + +#if CONFIG_OPENTHREAD_BORDER_ROUTER +#include "esp_openthread_border_router.h" +#endif + +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->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++; + } + + 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, "Found TREL peer: address: %s, port:%d", 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_bind_netif(task->trel_pcb, netif_get_by_index(esp_netif_get_netif_impl_index(s_trel_netif))); + 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; + if (s_trel_netif == NULL) { + ESP_LOGE(OT_PLAT_LOG_TAG, "netif for trel is not set"); + assert(false); + } + + 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) +{ + 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; +} + +void esp_openthread_set_trel_netif(esp_netif_t *trel_netif) +{ + s_trel_netif = trel_netif; +} + +esp_netif_t *esp_openthread_get_trel_netif(void) +{ + return s_trel_netif; +} + +OT_TOOL_WEAK otError otPlatRadioSetTransmitPower(otInstance *aInstance, int8_t aPower) +{ + ESP_LOGW(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatRadioSetTransmitPower`"); + return OT_ERROR_NONE; +} + +OT_TOOL_WEAK otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower) +{ + ESP_LOGW(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatRadioGetTransmitPower`"); + return OT_ERROR_NONE; +} + +OT_TOOL_WEAK bool otPlatRadioGetPromiscuous(otInstance *aInstance) +{ + ESP_LOGW(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_LOGW(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatRadioSetCcaEnergyDetectThreshold`"); + return OT_ERROR_NONE; +} + +OT_TOOL_WEAK otError otPlatRadioGetCcaEnergyDetectThreshold(otInstance *aInstance, int8_t *aThreshold) +{ + ESP_LOGW(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatRadioGetCcaEnergyDetectThreshold`"); + return OT_ERROR_NONE; +} + +OT_TOOL_WEAK void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeeeEui64) +{ + ESP_LOGW(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatRadioGetIeeeEui64`"); +} + +OT_TOOL_WEAK otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance) +{ + return NULL; +} + +#if CONFIG_OPENTHREAD_DIAG + +OT_TOOL_WEAK void otPlatDiagSetOutputCallback(otInstance *aInstance, otPlatDiagOutputCallback aCallback, void *aContext) +{ + OT_UNUSED_VARIABLE(aInstance); + OT_UNUSED_VARIABLE(aCallback); + OT_UNUSED_VARIABLE(aContext); +} + +OT_TOOL_WEAK void otPlatDiagModeSet(bool mode) +{ + ESP_LOGW(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatDiagModeSet`"); +} + +OT_TOOL_WEAK bool otPlatDiagModeGet(void) +{ + return false; +} + +OT_TOOL_WEAK void otPlatDiagTxPowerSet(int8_t tx_power) +{ + ESP_LOGW(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatDiagTxPowerSet`"); +} + +OT_TOOL_WEAK void otPlatDiagChannelSet(uint8_t channel) +{ + ESP_LOGW(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatDiagChannelSet`"); +} + +OT_TOOL_WEAK void otPlatDiagAlarmCallback(otInstance *aInstance) +{ + ESP_LOGW(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"); +} diff --git a/components/openthread/src/port/esp_spi_spinel_interface.cpp b/components/openthread/src/port/esp_spi_spinel_interface.cpp index e19acd9152..61d6cfab2f 100644 --- a/components/openthread/src/port/esp_spi_spinel_interface.cpp +++ b/components/openthread/src/port/esp_spi_spinel_interface.cpp @@ -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" diff --git a/examples/openthread/.build-test-rules.yml b/examples/openthread/.build-test-rules.yml index bec9ecfcbf..52ca33d873 100644 --- a/examples/openthread/.build-test-rules.yml +++ b/examples/openthread/.build-test-rules.yml @@ -49,3 +49,8 @@ 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 + <<: *openthread_dependencies diff --git a/examples/openthread/ot_trel/CMakeLists.txt b/examples/openthread/ot_trel/CMakeLists.txt new file mode 100644 index 0000000000..b12d49bfa3 --- /dev/null +++ b/examples/openthread/ot_trel/CMakeLists.txt @@ -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) diff --git a/examples/openthread/ot_trel/README.md b/examples/openthread/ot_trel/README.md new file mode 100644 index 0000000000..ca6e9942d5 --- /dev/null +++ b/examples/openthread/ot_trel/README.md @@ -0,0 +1,132 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | 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 -p PORT build 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. diff --git a/examples/openthread/ot_trel/main/CMakeLists.txt b/examples/openthread/ot_trel/main/CMakeLists.txt new file mode 100644 index 0000000000..cea684e5f9 --- /dev/null +++ b/examples/openthread/ot_trel/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "esp_ot_trel.c" + INCLUDE_DIRS ".") diff --git a/examples/openthread/ot_trel/main/Kconfig.projbuild b/examples/openthread/ot_trel/main/Kconfig.projbuild new file mode 100644 index 0000000000..32146234e0 --- /dev/null +++ b/examples/openthread/ot_trel/main/Kconfig.projbuild @@ -0,0 +1,9 @@ +menu "OpenThread CLI 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 diff --git a/examples/openthread/ot_trel/main/esp_ot_config.h b/examples/openthread/ot_trel/main/esp_ot_config.h new file mode 100644 index 0000000000..be8eff0e21 --- /dev/null +++ b/examples/openthread/ot_trel/main/esp_ot_config.h @@ -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, \ + } diff --git a/examples/openthread/ot_trel/main/esp_ot_trel.c b/examples/openthread/ot_trel/main/esp_ot_trel.c new file mode 100644 index 0000000000..94c5079985 --- /dev/null +++ b/examples/openthread/ot_trel/main/esp_ot_trel.c @@ -0,0 +1,141 @@ +/* + * 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 +#include +#include + +#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 "esp_openthread_trel.h" +#include "protocol_examples_common.h" +#include "mdns.h" + +#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(), + }; + +#if !CONFIG_EXAMPLE_CONNECT_WIFI && !CONFIG_EXAMPLE_CONNECT_ETHERNET +#error No netif for TREL! +#endif + ESP_ERROR_CHECK(example_connect()); + assert(esp_openthread_get_trel_netif() == NULL); + esp_openthread_set_trel_netif(get_example_netif()); + + // 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); +} diff --git a/examples/openthread/ot_trel/main/idf_component.yml b/examples/openthread/ot_trel/main/idf_component.yml new file mode 100644 index 0000000000..68d7abc65b --- /dev/null +++ b/examples/openthread/ot_trel/main/idf_component.yml @@ -0,0 +1,11 @@ +## IDF Component Manager Manifest File +dependencies: + espressif/esp_ot_cli_extension: + version: "~1.1.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 diff --git a/examples/openthread/ot_trel/partitions.csv b/examples/openthread/ot_trel/partitions.csv new file mode 100644 index 0000000000..641bcc9afc --- /dev/null +++ b/examples/openthread/ot_trel/partitions.csv @@ -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, diff --git a/examples/openthread/ot_trel/sdkconfig.defaults b/examples/openthread/ot_trel/sdkconfig.defaults new file mode 100644 index 0000000000..0e7a865be6 --- /dev/null +++ b/examples/openthread/ot_trel/sdkconfig.defaults @@ -0,0 +1,42 @@ +# +# 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 +# end of lwIP + +# +# Configurations for optimizing the size of firmware +# +CONFIG_COMPILER_OPTIMIZATION_SIZE=y From e84a7e651d658725aab134465b3a7429d5407383 Mon Sep 17 00:00:00 2001 From: Xu Si Yu Date: Wed, 11 Sep 2024 22:00:59 +0800 Subject: [PATCH 7/7] feat(openthread): allow enabling trel before getting interface --- components/openthread/CMakeLists.txt | 2 +- components/openthread/Kconfig | 2 +- .../openthread/include/esp_openthread_trel.h | 38 --------- .../openthread-core-esp32x-ftd-config.h | 2 +- .../src/port/esp_openthread_radio.c | 2 +- .../openthread/src/port/esp_openthread_trel.c | 80 +++++++------------ examples/openthread/.build-test-rules.yml | 3 + examples/openthread/ot_trel/README.md | 7 +- .../openthread/ot_trel/main/Kconfig.projbuild | 2 +- .../openthread/ot_trel/main/esp_ot_trel.c | 10 +-- .../openthread/ot_trel/main/idf_component.yml | 2 +- examples/openthread/ot_trel/sdkconfig.ci.trel | 3 + .../openthread/ot_trel/sdkconfig.defaults | 1 + examples/openthread/pytest_otbr.py | 53 ++++++++++++ 14 files changed, 103 insertions(+), 104 deletions(-) delete mode 100644 components/openthread/include/esp_openthread_trel.h create mode 100644 examples/openthread/ot_trel/sdkconfig.ci.trel diff --git a/components/openthread/CMakeLists.txt b/components/openthread/CMakeLists.txt index 4b0b3d2320..d32ad89398 100644 --- a/components/openthread/CMakeLists.txt +++ b/components/openthread/CMakeLists.txt @@ -270,7 +270,7 @@ idf_component_register(SRC_DIRS "${src_dirs}" ieee802154 mbedtls nvs_flash) if(CONFIG_OPENTHREAD_RADIO_TREL) -idf_component_optional_requires(PRIVATE espressif__mdns) + idf_component_optional_requires(PRIVATE espressif__mdns) endif() if(CONFIG_OPENTHREAD_ENABLED OR CONFIG_OPENTHREAD_SPINEL_ONLY) diff --git a/components/openthread/Kconfig b/components/openthread/Kconfig index 9ae0a6c63b..d344f59615 100644 --- a/components/openthread/Kconfig +++ b/components/openthread/Kconfig @@ -132,7 +132,7 @@ menu "OpenThread" config OPENTHREAD_RADIO_TREL bool "Enable Thread Radio Encapsulation Link (TREL)" - depends on SOC_WIFI_SUPPORTED + depends on EXAMPLE_CONNECT_WIFI || EXAMPLE_CONNECT_ETHERNET default n help Select this option to enable Thread Radio Encapsulation Link. diff --git a/components/openthread/include/esp_openthread_trel.h b/components/openthread/include/esp_openthread_trel.h deleted file mode 100644 index c2dc8c58b4..0000000000 --- a/components/openthread/include/esp_openthread_trel.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include "sdkconfig.h" -#include "esp_netif.h" -#include "esp_netif_types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Sets the interface used for trel feature. - * - * @note This function must be called after connect to wifi/ethernet - * - * @param[in] trel_netif The network interface (WiFi or ethernet) - * - */ -void esp_openthread_set_trel_netif(esp_netif_t *trel_netif); - -/** - * @brief Gets the trel interface of OpenThread device. - * - * @return - * The trel interface or NULL if trel not initialized. - * - */ -esp_netif_t *esp_openthread_get_trel_netif(void); - -#ifdef __cplusplus -} -#endif diff --git a/components/openthread/private_include/openthread-core-esp32x-ftd-config.h b/components/openthread/private_include/openthread-core-esp32x-ftd-config.h index 0cd3542a91..ec94801505 100644 --- a/components/openthread/private_include/openthread-core-esp32x-ftd-config.h +++ b/components/openthread/private_include/openthread-core-esp32x-ftd-config.h @@ -231,7 +231,7 @@ * Set to 1 to enable support for IEEE802.15.4 radio link. * */ -#if CONFIG_OPENTHREAD_RADIO_NATIVE || CONFIG_OPENTHREAD_RADIO_SPINEL_UART || CONFIG_OPENTHREAD_RADIO_SPINEL_SPI +#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 diff --git a/components/openthread/src/port/esp_openthread_radio.c b/components/openthread/src/port/esp_openthread_radio.c index aac760c260..3e0f4286fe 100644 --- a/components/openthread/src/port/esp_openthread_radio.c +++ b/components/openthread/src/port/esp_openthread_radio.c @@ -7,7 +7,6 @@ #include #include "esp_openthread_radio.h" -#include "openthread/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" diff --git a/components/openthread/src/port/esp_openthread_trel.c b/components/openthread/src/port/esp_openthread_trel.c index 69c43f00ec..8424a7631d 100644 --- a/components/openthread/src/port/esp_openthread_trel.c +++ b/components/openthread/src/port/esp_openthread_trel.c @@ -17,21 +17,17 @@ #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 "esp_openthread_trel.h" #include "lwip/pbuf.h" #include "lwip/tcpip.h" #include "lwip/udp.h" #include "openthread/trel.h" #include "openthread/platform/diag.h" -#if CONFIG_OPENTHREAD_BORDER_ROUTER -#include "esp_openthread_border_router.h" -#endif - static esp_netif_t *s_trel_netif = NULL; static otPlatTrelCounters s_trel_counters; @@ -61,8 +57,7 @@ static bool s_is_service_registered = false; static void trel_browse_notifier(mdns_result_t *result) { while (result) { - - if (result->addr->addr.type == IPADDR_TYPE_V6) { + if (result->addr && result->addr->addr.type == IPADDR_TYPE_V6) { otPlatTrelPeerInfo info; uint8_t trel_txt[1024] = {0}; uint16_t trel_txt_len = 0; @@ -76,21 +71,19 @@ static void trel_browse_notifier(mdns_result_t *result) 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, "Found TREL peer: address: %s, port:%d", ip6addr_ntoa(((ip6_addr_t*)(&result->addr->addr.u_addr.ip6))), info.mSockAddr.mPort); - + 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; } } @@ -125,7 +118,6 @@ exit: 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"); } @@ -138,7 +130,6 @@ static esp_err_t ot_new_trel(void *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_bind_netif(task->trel_pcb, netif_get_by_index(esp_netif_get_netif_impl_index(s_trel_netif))); udp_recv(task->trel_pcb, handle_trel_udp_recv, NULL); return ESP_OK; } @@ -146,11 +137,6 @@ static esp_err_t ot_new_trel(void *ctx) void otPlatTrelEnable(otInstance *aInstance, uint16_t *aUdpPort) { *aUdpPort = s_ot_trel.port; - if (s_trel_netif == NULL) { - ESP_LOGE(OT_PLAT_LOG_TAG, "netif for trel is not set"); - assert(false); - } - esp_openthread_task_switching_lock_release(); esp_err_t err = esp_netif_tcpip_exec(ot_new_trel, &s_ot_trel); if (err != ESP_OK) { @@ -179,12 +165,10 @@ static void trel_send_task(void *ctx) 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); @@ -195,6 +179,10 @@ void otPlatTrelSend(otInstance *aInstance, 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"); @@ -205,7 +193,6 @@ void otPlatTrelSend(otInstance *aInstance, 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); @@ -214,11 +201,11 @@ void otPlatTrelSend(otInstance *aInstance, 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; @@ -276,53 +263,45 @@ const otPlatTrelCounters *otPlatTrelGetCounters(otInstance *aInstance) return &s_trel_counters; } -void esp_openthread_set_trel_netif(esp_netif_t *trel_netif) -{ - s_trel_netif = trel_netif; -} - -esp_netif_t *esp_openthread_get_trel_netif(void) -{ - return s_trel_netif; -} - +// TODO: TZ-1169 OT_TOOL_WEAK otError otPlatRadioSetTransmitPower(otInstance *aInstance, int8_t aPower) { - ESP_LOGW(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatRadioSetTransmitPower`"); - return OT_ERROR_NONE; + 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_LOGW(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatRadioGetTransmitPower`"); - return OT_ERROR_NONE; + 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_LOGW(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatRadioGetPromiscuous`"); + 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_LOGW(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatRadioSetCcaEnergyDetectThreshold`"); - return OT_ERROR_NONE; + 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_LOGW(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatRadioGetCcaEnergyDetectThreshold`"); - return OT_ERROR_NONE; + 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_LOGW(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatRadioGetIeeeEui64`"); + 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; } @@ -330,34 +309,33 @@ OT_TOOL_WEAK otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance) OT_TOOL_WEAK void otPlatDiagSetOutputCallback(otInstance *aInstance, otPlatDiagOutputCallback aCallback, void *aContext) { - OT_UNUSED_VARIABLE(aInstance); - OT_UNUSED_VARIABLE(aCallback); - OT_UNUSED_VARIABLE(aContext); + ESP_LOGD(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatDiagSetOutputCallback`"); } OT_TOOL_WEAK void otPlatDiagModeSet(bool mode) { - ESP_LOGW(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatDiagModeSet`"); + 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_LOGW(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatDiagTxPowerSet`"); + ESP_LOGD(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatDiagTxPowerSet`"); } OT_TOOL_WEAK void otPlatDiagChannelSet(uint8_t channel) { - ESP_LOGW(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatDiagChannelSet`"); + ESP_LOGD(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatDiagChannelSet`"); } OT_TOOL_WEAK void otPlatDiagAlarmCallback(otInstance *aInstance) { - ESP_LOGW(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatDiagAlarmCallback`"); + ESP_LOGD(OT_PLAT_LOG_TAG, "Running in TREL mode and not support `otPlatDiagAlarmCallback`"); } #endif // CONFIG_OPENTHREAD_DIAG diff --git a/examples/openthread/.build-test-rules.yml b/examples/openthread/.build-test-rules.yml index 52ca33d873..47f4df4949 100644 --- a/examples/openthread/.build-test-rules.yml +++ b/examples/openthread/.build-test-rules.yml @@ -53,4 +53,7 @@ examples/openthread/ot_sleepy_device/light_sleep: 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 diff --git a/examples/openthread/ot_trel/README.md b/examples/openthread/ot_trel/README.md index ca6e9942d5..63af9ea2bd 100644 --- a/examples/openthread/ot_trel/README.md +++ b/examples/openthread/ot_trel/README.md @@ -1,5 +1,5 @@ -| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-S2 | ESP32-S3 | -| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | # Thread Radio Encapsulation Link Example @@ -34,7 +34,8 @@ Component config → ESP System Settings → Channel for console output → USB Build the project and flash it to the board, then run monitor tool to view serial output: ``` -idf.py -p PORT build flash monitor +idf.py build +idf.py -p PORT erase-flash flash monitor ``` Now you'll get an OpenThread command line shell. diff --git a/examples/openthread/ot_trel/main/Kconfig.projbuild b/examples/openthread/ot_trel/main/Kconfig.projbuild index 32146234e0..7a37072f94 100644 --- a/examples/openthread/ot_trel/main/Kconfig.projbuild +++ b/examples/openthread/ot_trel/main/Kconfig.projbuild @@ -1,4 +1,4 @@ -menu "OpenThread CLI Example" +menu "OpenThread TREL Example" config OPENTHREAD_AUTO_START bool 'Enable the automatic start mode.' diff --git a/examples/openthread/ot_trel/main/esp_ot_trel.c b/examples/openthread/ot_trel/main/esp_ot_trel.c index 94c5079985..05b7251da4 100644 --- a/examples/openthread/ot_trel/main/esp_ot_trel.c +++ b/examples/openthread/ot_trel/main/esp_ot_trel.c @@ -38,10 +38,13 @@ #include "openthread/instance.h" #include "openthread/logging.h" #include "openthread/tasklet.h" -#include "esp_openthread_trel.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 @@ -71,12 +74,7 @@ static void ot_task_worker(void *aContext) .port_config = ESP_OPENTHREAD_DEFAULT_PORT_CONFIG(), }; -#if !CONFIG_EXAMPLE_CONNECT_WIFI && !CONFIG_EXAMPLE_CONNECT_ETHERNET -#error No netif for TREL! -#endif ESP_ERROR_CHECK(example_connect()); - assert(esp_openthread_get_trel_netif() == NULL); - esp_openthread_set_trel_netif(get_example_netif()); // Initialize the OpenThread stack ESP_ERROR_CHECK(esp_openthread_init(&config)); diff --git a/examples/openthread/ot_trel/main/idf_component.yml b/examples/openthread/ot_trel/main/idf_component.yml index 68d7abc65b..a52a17085f 100644 --- a/examples/openthread/ot_trel/main/idf_component.yml +++ b/examples/openthread/ot_trel/main/idf_component.yml @@ -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" idf: version: ">=4.1.0" diff --git a/examples/openthread/ot_trel/sdkconfig.ci.trel b/examples/openthread/ot_trel/sdkconfig.ci.trel new file mode 100644 index 0000000000..994413fa4f --- /dev/null +++ b/examples/openthread/ot_trel/sdkconfig.ci.trel @@ -0,0 +1,3 @@ +CONFIG_EXAMPLE_CONNECT_WIFI=y +CONFIG_EXAMPLE_WIFI_SSID="OTCITE" +CONFIG_EXAMPLE_WIFI_PASSWORD="otcitest888" diff --git a/examples/openthread/ot_trel/sdkconfig.defaults b/examples/openthread/ot_trel/sdkconfig.defaults index 0e7a865be6..99f65081b9 100644 --- a/examples/openthread/ot_trel/sdkconfig.defaults +++ b/examples/openthread/ot_trel/sdkconfig.defaults @@ -34,6 +34,7 @@ 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 # diff --git a/examples/openthread/pytest_otbr.py b/examples/openthread/pytest_otbr.py index 604862d8d3..2abb6e4cb9 100644 --- a/examples/openthread/pytest_otbr.py +++ b/examples/openthread/pytest_otbr.py @@ -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: @@ -792,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)