diff --git a/components/openthread/CMakeLists.txt b/components/openthread/CMakeLists.txt index cf30571107..6e03dbea2f 100644 --- a/components/openthread/CMakeLists.txt +++ b/components/openthread/CMakeLists.txt @@ -272,7 +272,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 5b525e4808..df26b9a869 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 95236cd3d4..fe987c1cae 100644 --- a/examples/openthread/.build-test-rules.yml +++ b/examples/openthread/.build-test-rules.yml @@ -60,4 +60,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)