Browse Source

Merge branch 'feature/add_sleep_test_for_ot_ci' into 'master'

OpenThread CI: add a test case of sleepy device

See merge request espressif/esp-idf!24715
Xu Si Yu 2 năm trước cách đây
mục cha
commit
36511a3005

+ 9 - 0
.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

+ 6 - 0
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"

+ 8 - 0
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

+ 1 - 0
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.',

+ 12 - 21
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]

+ 51 - 7
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)

+ 6 - 0
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

+ 6 - 0
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

+ 87 - 4
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)