diff --git a/.gitlab/ci/target-test.yml b/.gitlab/ci/target-test.yml index fb3230e9ed..ae550fa405 100644 --- a/.gitlab/ci/target-test.yml +++ b/.gitlab/ci/target-test.yml @@ -1077,6 +1077,15 @@ pytest_examples_openthread_br: - esp32c6 - openthread_br +pytest_examples_openthread_sleep: + extends: + - .pytest_examples_dir_template + - .rules:test:example_test-esp32h2 + needs: + - build_pytest_examples_esp32c6 + - build_pytest_examples_esp32h2 + tags: [ esp32c6, openthread_sleep ] + pytest_examples_zigbee: extends: - .pytest_examples_dir_template diff --git a/components/esp_hw_support/Kconfig b/components/esp_hw_support/Kconfig index 759cc09bf6..4a9b2d226b 100644 --- a/components/esp_hw_support/Kconfig +++ b/components/esp_hw_support/Kconfig @@ -164,6 +164,12 @@ menu "Hardware Settings" only for code quality inspection. Enabling it will increase the time overhead of entering and exiting sleep. It is not recommended to enable it in the release version. + config ESP_SLEEP_DEBUG + bool "esp sleep debug" + default n + help + Enable esp sleep debug. + endmenu menu "ESP_SLEEP_WORKAROUND" diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index b7fa3a99fa..236d512309 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -579,6 +579,14 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m bool deep_sleep = (mode == ESP_SLEEP_MODE_DEEP_SLEEP); bool should_skip_sleep = false; +#if CONFIG_ESP_SLEEP_DEBUG + // The following three logs are used to confirm whether the digital domain and modem are powered off. + // Some CI tests depend on these three logs and it is best not to modify them. + ESP_EARLY_LOGD(TAG, "pd_lags %lu", pd_flags); + ESP_EARLY_LOGD(TAG, "PMU_SLEEP_PD_TOP: %s", (pd_flags & PMU_SLEEP_PD_TOP) ? "True":"False"); + ESP_EARLY_LOGD(TAG, "PMU_SLEEP_PD_MODEM: %s", (pd_flags & PMU_SLEEP_PD_MODEM) ? "True":"False"); +#endif + int64_t sleep_duration = (int64_t) s_config.sleep_duration - (int64_t) s_config.sleep_time_adjustment; #if SOC_RTC_SLOW_CLK_SUPPORT_RC_FAST_D256 diff --git a/conftest.py b/conftest.py index 9682a5986c..53af0db382 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.', 'zigbee_multi_dut': 'zigbee runner which have multiple duts.', '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.', diff --git a/examples/openthread/.build-test-rules.yml b/examples/openthread/.build-test-rules.yml index 708b984373..eb59f014aa 100644 --- a/examples/openthread/.build-test-rules.yml +++ b/examples/openthread/.build-test-rules.yml @@ -3,24 +3,23 @@ # TODO: Modify the configuration after the files matching rules are changed # Or delete TODO without modifying the configuration if it is sure that current rules are correct. .openthread_dependencies: &openthread_dependencies + depends_components: + - esp_coex + - esp_netif + - esp_phy + - ieee802154 + - lwip + - openthread depends_filepatterns: - - components/esp_coex/* - - components/esp_coex/**/* - - components/esp_netif/* - - components/esp_netif/**/* - - components/esp_phy/* - - components/esp_phy/**/* - - components/ieee802154/* - - components/ieee802154/**/* - - components/lwip/* - - components/lwip/**/* - - components/openthread/* - - components/openthread/**/* - examples/common_components/iperf/* - examples/common_components/iperf/**/* - examples/openthread/* - examples/openthread/**/* +.openthread_sleep_dependencies: &openthread_sleep_dependencies + depends_components: + - esp_hw_support + examples/openthread/ot_br: disable: - if: IDF_TARGET in ["esp32h2"] @@ -35,10 +34,6 @@ examples/openthread/ot_br: examples/openthread/ot_cli: enable: - if: IDF_TARGET in ["esp32h2", "esp32c6"] - disable_test: - - if: IDF_TARGET == "esp32c6" - temporary: true - reason: only test on esp32h2 <<: *openthread_dependencies examples/openthread/ot_rcp: @@ -53,8 +48,4 @@ examples/openthread/ot_rcp: examples/openthread/ot_sleepy_device: enable: - if: IDF_TARGET in ["esp32h2", "esp32c6"] - disable_test: - - if: IDF_TARGET in ["esp32h2", "esp32c6"] - temporary: true - reason: No support # TO-DO: TZ-134 - <<: *openthread_dependencies + <<: [*openthread_dependencies, *openthread_sleep_dependencies] diff --git a/examples/openthread/ot_ci_function.py b/examples/openthread/ot_ci_function.py index 6cd68793d1..48db7e60e5 100644 --- a/examples/openthread/ot_ci_function.py +++ b/examples/openthread/ot_ci_function.py @@ -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/sdkconfig.ci.sleepy_c6 b/examples/openthread/ot_sleepy_device/sdkconfig.ci.sleepy_c6 new file mode 100644 index 0000000000..80eea90801 --- /dev/null +++ b/examples/openthread/ot_sleepy_device/sdkconfig.ci.sleepy_c6 @@ -0,0 +1,6 @@ +CONFIG_IDF_TARGET="esp32c6" +CONFIG_IDF_TARGET_ESP32C6=y +CONFIG_OPENTHREAD_NETWORK_CHANNEL=12 +CONFIG_OPENTHREAD_NETWORK_MASTERKEY="aabbccddeeff00112233445566778899" +CONFIG_ESP_SLEEP_DEBUG=y +CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y diff --git a/examples/openthread/ot_sleepy_device/sdkconfig.ci.sleepy_h2 b/examples/openthread/ot_sleepy_device/sdkconfig.ci.sleepy_h2 new file mode 100644 index 0000000000..43b8d650b8 --- /dev/null +++ b/examples/openthread/ot_sleepy_device/sdkconfig.ci.sleepy_h2 @@ -0,0 +1,6 @@ +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_DEFAULT_LEVEL_DEBUG=y diff --git a/examples/openthread/pytest_otbr.py b/examples/openthread/pytest_otbr.py index b90ed95e42..2ae516518b 100644 --- a/examples/openthread/pytest_otbr.py +++ b/examples/openthread/pytest_otbr.py @@ -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,86 @@ 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")}', + '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")}', + 'esp32c6|esp32h2'), + ], + indirect=True, +) +def test_ot_sleepy_device(dut: Tuple[IdfDut, IdfDut]) -> None: + leader = dut[0] + sleepy_device = dut[1] + 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.clean_buffer(sleepy_device) + ocf.joinThreadNetwork(leader, leader_para) + ocf.clean_buffer(sleepy_device) + sleepy_device.serial.hard_reset() + sleepy_device.expect('detached -> child', timeout=20) + sleepy_device.expect('PMU_SLEEP_PD_TOP: True', timeout=10) + sleepy_device.expect('PMU_SLEEP_PD_MODEM: True', timeout=20) + ocf.clean_buffer(sleepy_device) + output = sleepy_device.expect(pexpect.TIMEOUT, timeout=5) + assert 'rst:' not in str(output) and 'boot:' not in 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)