From abaa9f2bfe7a398a36a6fcd16b7b89ad990a8177 Mon Sep 17 00:00:00 2001 From: Xu Si Yu Date: Tue, 11 Jul 2023 21:25:47 +0800 Subject: [PATCH] ci(openthread): Add a test case for openthread sleepy device --- .gitlab/ci/dependencies/dependencies.yml | 14 +++ .gitlab/ci/rules.yml | 29 +++++ .gitlab/ci/target-test.yml | 11 ++ components/esp_hw_support/sleep_modes.c | 6 +- conftest.py | 1 + examples/openthread/.build-test-rules.yml | 8 -- examples/openthread/ot_ci_function.py | 60 +++++++++-- .../light_sleep/main/esp_ot_sleepy_device.c | 35 ++++++ examples/openthread/pytest_otbr.py | 102 +++++++++++++++++- 9 files changed, 242 insertions(+), 24 deletions(-) diff --git a/.gitlab/ci/dependencies/dependencies.yml b/.gitlab/ci/dependencies/dependencies.yml index 31f538a479..e687a6472d 100644 --- a/.gitlab/ci/dependencies/dependencies.yml +++ b/.gitlab/ci/dependencies/dependencies.yml @@ -172,6 +172,20 @@ - "build:example_test" - build:target_test +# For openthread sleepy +"test:example_test-otsleepy": + patterns: + - "example_test-otsleepy" + - "target_test-i154" + labels: + - target_test + - example_test + included_in: + - "build:example_test-esp32c6" + - "build:example_test-esp32h2" + - "build:example_test" + - build:target_test + "test:host_test": labels: - host_test diff --git a/.gitlab/ci/rules.yml b/.gitlab/ci/rules.yml index 2ab1ebfe3f..e45236c53d 100644 --- a/.gitlab/ci/rules.yml +++ b/.gitlab/ci/rules.yml @@ -93,6 +93,13 @@ - "examples/common_components/iperf/**/*" - "examples/openthread/**/*" +.patterns-example_test-otsleepy: &patterns-example_test-otsleepy + - "components/esp_hw_support/**/*" + - "components/esp_netif/**/*" + - "components/lwip/**/*" + - "components/openthread/**/*" + - "examples/openthread/**/*" + .patterns-target_test-wifi: &patterns-target_test-wifi - "components/esp_netif/**/*" - "components/lwip/**/*" @@ -1120,6 +1127,8 @@ changes: *patterns-example_test-ethernet - <<: *if-dev-push changes: *patterns-example_test-i154 + - <<: *if-dev-push + changes: *patterns-example_test-otsleepy - <<: *if-dev-push changes: *patterns-example_test-sdio - <<: *if-dev-push @@ -1290,6 +1299,8 @@ changes: *patterns-example_test-ethernet - <<: *if-dev-push changes: *patterns-example_test-i154 + - <<: *if-dev-push + changes: *patterns-example_test-otsleepy - <<: *if-dev-push changes: *patterns-example_test-sdio - <<: *if-dev-push @@ -1332,6 +1343,8 @@ changes: *patterns-example_test-ethernet - <<: *if-dev-push changes: *patterns-example_test-i154 + - <<: *if-dev-push + changes: *patterns-example_test-otsleepy - <<: *if-dev-push changes: *patterns-example_test-sdio - <<: *if-dev-push @@ -1512,6 +1525,8 @@ changes: *patterns-example_test-ethernet - <<: *if-dev-push changes: *patterns-example_test-i154 + - <<: *if-dev-push + changes: *patterns-example_test-otsleepy - <<: *if-dev-push changes: *patterns-example_test-sdio - <<: *if-dev-push @@ -2633,6 +2648,20 @@ - <<: *if-dev-push changes: *patterns-target_test-i154 +.rules:test:example_test-otsleepy: + rules: + - <<: *if-revert-branch + when: never + - <<: *if-protected + - <<: *if-label-build-only + when: never + - <<: *if-label-example_test + - <<: *if-label-target_test + - <<: *if-dev-push + changes: *patterns-example_test-otsleepy + - <<: *if-dev-push + changes: *patterns-target_test-i154 + .rules:test:host_test: rules: - <<: *if-revert-branch diff --git a/.gitlab/ci/target-test.yml b/.gitlab/ci/target-test.yml index 2ccc054e23..ed46c8b98c 100644 --- a/.gitlab/ci/target-test.yml +++ b/.gitlab/ci/target-test.yml @@ -992,6 +992,17 @@ pytest_examples_openthread_br: - esp32c6 - openthread_br +pytest_examples_openthread_sleep: + extends: + - .pytest_examples_dir_template + - .rules:test:example_test-otsleepy + needs: + - build_pytest_examples_esp32c6 + - build_pytest_examples_esp32h2 + tags: + - esp32c6 + - openthread_sleep + pytest_components_esp32s3_usb_host: extends: - .pytest_components_dir_template diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 543c438c20..c43e3a6aa7 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -769,9 +769,9 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m result = ESP_ERR_SLEEP_REJECT; } else { #if CONFIG_ESP_SLEEP_DEBUG - if (s_sleep_ctx != NULL) { - s_sleep_ctx->wakeup_triggers = s_config.wakeup_triggers; - } + if (s_sleep_ctx != NULL) { + s_sleep_ctx->wakeup_triggers = s_config.wakeup_triggers; + } #endif if (deep_sleep) { #if !SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP diff --git a/conftest.py b/conftest.py index 145327b2b2..1d4c5a73aa 100644 --- a/conftest.py +++ b/conftest.py @@ -133,6 +133,7 @@ ENV_MARKERS = { # multi-dut markers 'ieee802154': 'ieee802154 related tests should run on ieee802154 runners.', 'openthread_br': 'tests should be used for openthread border router.', + 'openthread_sleep': 'tests should be used for openthread sleepy device.', 'wifi_two_dut': 'tests should be run on runners which has two wifi duts connected.', 'generic_multi_device': 'generic multiple devices whose corresponding gpio pins are connected to each other.', 'twai_network': 'multiple runners form a TWAI network.', diff --git a/examples/openthread/.build-test-rules.yml b/examples/openthread/.build-test-rules.yml index 7b8b09fe3b..49aa460e5c 100644 --- a/examples/openthread/.build-test-rules.yml +++ b/examples/openthread/.build-test-rules.yml @@ -13,10 +13,6 @@ examples/openthread/ot_br: examples/openthread/ot_cli: enable: - if: SOC_IEEE802154_SUPPORTED == 1 - disable_test: - - if: IDF_TARGET == "esp32c6" - temporary: true - reason: only test on esp32h2 examples/openthread/ot_rcp: enable: @@ -37,7 +33,3 @@ examples/openthread/ot_sleepy_device/deep_sleep: examples/openthread/ot_sleepy_device/light_sleep: enable: - if: SOC_IEEE802154_SUPPORTED == 1 - disable_test: - - if: SOC_IEEE802154_SUPPORTED == 1 - temporary: true - reason: Unsupport # TO-DO: TZ-134 diff --git a/examples/openthread/ot_ci_function.py b/examples/openthread/ot_ci_function.py index 6cd68793d1..346f991d42 100644 --- a/examples/openthread/ot_ci_function.py +++ b/examples/openthread/ot_ci_function.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Unlicense OR CC0-1.0 # !/usr/bin/env python3 # this file defines some functions for testing cli and br under pytest framework @@ -23,6 +23,26 @@ class thread_parameter: self.channel = channel self.exaddr = exaddr self.bbr = bbr + self.networkname = '' + self.panid = '' + self.extpanid = '' + self.networkkey = '' + self.pskc = '' + + def setnetworkname(self, networkname:str) -> None: + self.networkname = networkname + + def setpanid(self, panid:str) -> None: + self.panid = panid + + def setextpanid(self, extpanid:str) -> None: + self.extpanid = extpanid + + def setnetworkkey(self, networkkey:str) -> None: + self.networkkey = networkkey + + def setpskc(self, pskc:str) -> None: + self.pskc = pskc class wifi_parameter: @@ -34,23 +54,43 @@ class wifi_parameter: def joinThreadNetwork(dut:IdfDut, thread:thread_parameter) -> None: - if thread.dataset != '': + if thread.dataset: command = 'dataset set active ' + thread.dataset execute_command(dut, command) dut.expect('Done', timeout=5) else: execute_command(dut, 'dataset init new') dut.expect('Done', timeout=5) - execute_command(dut, 'dataset commit active') - dut.expect('Done', timeout=5) - if thread.channel != '': - command = 'channel ' + thread.channel + if thread.channel: + command = 'dataset channel ' + thread.channel execute_command(dut, command) dut.expect('Done', timeout=5) - if thread.exaddr != '': + if thread.exaddr: command = 'extaddr ' + thread.exaddr execute_command(dut, command) dut.expect('Done', timeout=5) + if thread.networkname: + command = 'dataset networkname ' + thread.networkname + execute_command(dut, command) + dut.expect('Done', timeout=5) + if thread.panid: + command = 'dataset panid ' + thread.panid + execute_command(dut, command) + dut.expect('Done', timeout=5) + if thread.extpanid: + command = 'dataset extpanid ' + thread.extpanid + execute_command(dut, command) + dut.expect('Done', timeout=5) + if thread.networkkey: + command = 'dataset networkkey ' + thread.networkkey + execute_command(dut, command) + dut.expect('Done', timeout=5) + if thread.pskc: + command = 'dataset pskc ' + thread.pskc + execute_command(dut, command) + dut.expect('Done', timeout=5) + execute_command(dut, 'dataset commit active') + dut.expect('Done', timeout=5) if thread.bbr: execute_command(dut, 'bbr enable') dut.expect('Done', timeout=5) @@ -109,9 +149,13 @@ def getDataset(dut:IdfDut) -> str: return str(dut_data) -def reset_thread(dut:IdfDut) -> None: +def init_thread(dut:IdfDut) -> None: dut.expect('>', timeout=10) wait(dut, 3) + reset_thread(dut) + + +def reset_thread(dut:IdfDut) -> None: clean_buffer(dut) execute_command(dut, 'factoryreset') dut.expect('OpenThread attached to netif', timeout=20) diff --git a/examples/openthread/ot_sleepy_device/light_sleep/main/esp_ot_sleepy_device.c b/examples/openthread/ot_sleepy_device/light_sleep/main/esp_ot_sleepy_device.c index 6d20b50ea5..95b5bc2e1d 100644 --- a/examples/openthread/ot_sleepy_device/light_sleep/main/esp_ot_sleepy_device.c +++ b/examples/openthread/ot_sleepy_device/light_sleep/main/esp_ot_sleepy_device.c @@ -28,6 +28,13 @@ #include "openthread/logging.h" #include "openthread/thread.h" +#if CONFIG_ESP_SLEEP_DEBUG +#include "esp_timer.h" +#include "esp_sleep.h" +#include "esp_private/esp_pmu.h" +#include "esp_private/esp_sleep_internal.h" +#endif + #ifdef CONFIG_PM_ENABLE #include "esp_pm.h" #endif @@ -68,6 +75,17 @@ static esp_netif_t *init_openthread_netif(const esp_openthread_platform_config_t return netif; } +#if CONFIG_ESP_SLEEP_DEBUG +static esp_sleep_context_t s_sleep_ctx; + +static void print_sleep_flag(void *arg) +{ + ESP_LOGD(TAG, "sleep_flags %lu", s_sleep_ctx.sleep_flags); + ESP_LOGD(TAG, "PMU_SLEEP_PD_TOP: %s", (s_sleep_ctx.sleep_flags & PMU_SLEEP_PD_TOP) ? "True":"False"); + ESP_LOGD(TAG, "PMU_SLEEP_PD_MODEM: %s", (s_sleep_ctx.sleep_flags & PMU_SLEEP_PD_MODEM) ? "True":"False"); +} +#endif + static void ot_task_worker(void *aContext) { esp_openthread_platform_config_t config = { @@ -90,6 +108,23 @@ static void ot_task_worker(void *aContext) create_config_network(esp_openthread_get_instance()); +#if CONFIG_ESP_SLEEP_DEBUG + esp_sleep_set_sleep_context(&s_sleep_ctx); + esp_log_level_set(TAG, ESP_LOG_DEBUG); + + // create a timer to print the status of sleepy device + int periods = 2000; + const esp_timer_create_args_t timer_args = { + .name = "print_sleep_flag", + .arg = NULL, + .callback = &print_sleep_flag, + .skip_unhandled_events = true, + }; + esp_timer_handle_t periodic_timer; + ESP_ERROR_CHECK(esp_timer_create(&timer_args, &periodic_timer)); + ESP_ERROR_CHECK(esp_timer_start_periodic(periodic_timer, periods * 1000)); +#endif + // Run the main loop esp_openthread_launch_mainloop(); diff --git a/examples/openthread/pytest_otbr.py b/examples/openthread/pytest_otbr.py index 06bb1bdcc0..95e146f7a9 100644 --- a/examples/openthread/pytest_otbr.py +++ b/examples/openthread/pytest_otbr.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Unlicense OR CC0-1.0 # !/usr/bin/env python3 @@ -91,9 +91,9 @@ def test_thread_connect(dut:Tuple[IdfDut, IdfDut, IdfDut]) -> None: cli_list = [cli_h2] router_extaddr_list = ['7766554433221101'] - ocf.reset_thread(br) + ocf.init_thread(br) for cli in cli_list: - ocf.reset_thread(cli) + ocf.init_thread(cli) br_ot_para = default_br_ot_para ocf.joinThreadNetwork(br, br_ot_para) cli_ot_para = default_cli_ot_para @@ -125,8 +125,8 @@ def test_thread_connect(dut:Tuple[IdfDut, IdfDut, IdfDut]) -> None: # / \ # Wi-FI_Host Thread_End_Device def formBasicWiFiThreadNetwork(br:IdfDut, cli:IdfDut) -> None: - ocf.reset_thread(br) - ocf.reset_thread(cli) + ocf.init_thread(br) + ocf.init_thread(cli) ocf.joinWiFiNetwork(br, default_br_wifi_para) ocf.joinThreadNetwork(br, default_br_ot_para) ot_para = default_cli_ot_para @@ -540,3 +540,95 @@ def test_TCP_NAT64(Init_interface:bool, dut: Tuple[IdfDut, IdfDut, IdfDut]) -> N ocf.execute_command(cli, 'factoryreset') time.sleep(3) assert b'hello' in mytcp.tcp_bytes + + +# Case 10: Sleepy device test +@pytest.mark.esp32h2 +@pytest.mark.esp32c6 +@pytest.mark.openthread_sleep +@pytest.mark.parametrize( + 'config, count, app_path, target', [ + ('cli_h2|sleepy_c6', 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, + 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'), + ], + indirect=True, +) +def test_ot_sleepy_device(dut: Tuple[IdfDut, IdfDut]) -> None: + leader = dut[0] + sleepy_device = dut[1] + fail_info = re.compile(r'Core\W*?\d\W*?register dump') + try: + ocf.init_thread(leader) + time.sleep(3) + leader_para = ocf.thread_parameter('leader', '', '12', '7766554433221100', False) + leader_para.setnetworkname('OpenThread-ESP') + leader_para.setpanid('0x1234') + leader_para.setextpanid('dead00beef00cafe') + leader_para.setnetworkkey('aabbccddeeff00112233445566778899') + leader_para.setpskc('104810e2315100afd6bc9215a6bfac53') + ocf.joinThreadNetwork(leader, leader_para) + ocf.wait(leader, 5) + output = sleepy_device.expect(pexpect.TIMEOUT, timeout=5) + assert not bool(fail_info.search(str(output))) + ocf.clean_buffer(sleepy_device) + sleepy_device.serial.hard_reset() + info = sleepy_device.expect(r'(.+)detached -> child', timeout=20)[1].decode(errors='replace') + assert not bool(fail_info.search(str(info))) + info = sleepy_device.expect(r'(.+)PMU_SLEEP_PD_TOP: True', timeout=10)[1].decode(errors='replace') + assert not bool(fail_info.search(str(info))) + info = sleepy_device.expect(r'(.+)PMU_SLEEP_PD_MODEM: True', timeout=20)[1].decode(errors='replace') + assert not bool(fail_info.search(str(info))) + output = sleepy_device.expect(pexpect.TIMEOUT, timeout=20) + assert not bool(fail_info.search(str(output))) + ocf.clean_buffer(sleepy_device) + ocf.execute_command(leader, 'factoryreset') + output = sleepy_device.expect(pexpect.TIMEOUT, timeout=5) + assert not bool(fail_info.search(str(output))) + finally: + ocf.execute_command(leader, 'factoryreset') + time.sleep(3) + + +# Case 11: Basic startup Test of BR +@pytest.mark.supported_targets +@pytest.mark.esp32h2 +@pytest.mark.esp32c6 +@pytest.mark.openthread_br +@pytest.mark.flaky(reruns=1, reruns_delay=1) +@pytest.mark.parametrize( + 'config, count, app_path, target', [ + ('rcp|br', 2, + f'{os.path.join(os.path.dirname(__file__), "ot_rcp")}' + f'|{os.path.join(os.path.dirname(__file__), "ot_br")}', + 'esp32c6|esp32s3'), + ], + indirect=True, +) +def test_basic_startup(dut: Tuple[IdfDut, IdfDut]) -> None: + br = dut[1] + dut[0].serial.stop_redirect_thread() + try: + ocf.init_thread(br) + time.sleep(3) + ocf.clean_buffer(br) + ocf.execute_command(br, 'ifconfig up') + br.expect('Done', timeout=5) + ocf.execute_command(br, 'thread start') + br.expect('Done', timeout=5) + assert ocf.wait_for_join(br, 'leader') + ocf.reset_thread(br) + ocf.joinWiFiNetwork(br, default_br_wifi_para) + ocf.execute_command(br, 'ifconfig up') + br.expect('Done', timeout=5) + ocf.execute_command(br, 'thread start') + br.expect('Done', timeout=5) + assert ocf.wait_for_join(br, 'leader') + finally: + ocf.execute_command(br, 'factoryreset') + time.sleep(3)