diff --git a/examples/bluetooth/.build-test-rules.yml b/examples/bluetooth/.build-test-rules.yml index 4917e5c5fc..020efec256 100644 --- a/examples/bluetooth/.build-test-rules.yml +++ b/examples/bluetooth/.build-test-rules.yml @@ -205,6 +205,22 @@ examples/bluetooth/nimble/ble_phy: depends_filepatterns: - examples/bluetooth/nimble/common/**/* +examples/bluetooth/nimble/blecent: + <<: *bt_default_depends + disable: + - if: SOC_BLE_SUPPORTED != 1 + depends_components: + - bt + - esp_phy + - esp_event + - esp_coex + - esp_pm + depends_filepatterns: + - examples/bluetooth/nimble/common/**/* + - examples/bluetooth/nimble/blecent/**/* + - examples/bluetooth/nimble/power_save/**/* + - examples/bluetooth/nimble/pytest_nimble_test.py + examples/bluetooth/nimble/blemesh: <<: *bt_default_depends enable: @@ -249,6 +265,9 @@ examples/bluetooth/nimble/power_save: - esp_pm depends_filepatterns: - examples/bluetooth/nimble/common/**/* + - examples/bluetooth/nimble/blecent/**/* + - examples/bluetooth/nimble/power_save/**/* + - examples/bluetooth/nimble/pytest_nimble_test.py examples/bluetooth/nimble/throughput_app: <<: *bt_default_depends diff --git a/examples/bluetooth/nimble/blecent/main/Kconfig.projbuild b/examples/bluetooth/nimble/blecent/main/Kconfig.projbuild index b5f044b14a..23e88bae48 100644 --- a/examples/bluetooth/nimble/blecent/main/Kconfig.projbuild +++ b/examples/bluetooth/nimble/blecent/main/Kconfig.projbuild @@ -28,4 +28,12 @@ menu "Example Configuration" prompt "Enable Link Encryption" help This enables bonding and encryption after connection has been established. + + config EXAMPLE_USE_CI_ADDRESS + bool + default n + prompt "Advertise using Test address(Internal Test ONLY)" + help + Used for internal test ONLY. + Use this option to advertise in a specific random address. endmenu diff --git a/examples/bluetooth/nimble/blecent/main/main.c b/examples/bluetooth/nimble/blecent/main/main.c index edee64bb06..8e7222b913 100644 --- a/examples/bluetooth/nimble/blecent/main/main.c +++ b/examples/bluetooth/nimble/blecent/main/main.c @@ -455,17 +455,26 @@ ext_blecent_should_connect(const struct ble_gap_ext_disc_desc *disc) { int offset = 0; int ad_struct_len = 0; +#if CONFIG_EXAMPLE_USE_CI_ADDRESS + uint32_t *addr_offset; +#endif // CONFIG_EXAMPLE_USE_CI_ADDRESS if (disc->legacy_event_type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND && disc->legacy_event_type != BLE_HCI_ADV_RPT_EVTYPE_DIR_IND) { return 0; } if (strlen(CONFIG_EXAMPLE_PEER_ADDR) && (strncmp(CONFIG_EXAMPLE_PEER_ADDR, "ADDR_ANY", strlen ("ADDR_ANY")) != 0)) { +#if !CONFIG_EXAMPLE_USE_CI_ADDRESS ESP_LOGI(tag, "Peer address from menuconfig: %s", CONFIG_EXAMPLE_PEER_ADDR); /* Convert string to address */ sscanf(CONFIG_EXAMPLE_PEER_ADDR, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &peer_addr[5], &peer_addr[4], &peer_addr[3], &peer_addr[2], &peer_addr[1], &peer_addr[0]); +#else + addr_offset = (uint32_t *)&peer_addr[1]; + *addr_offset = atoi(CONFIG_EXAMPLE_PEER_ADDR); + peer_addr[5] = 0xC3; +#endif // !CONFIG_EXAMPLE_USE_CI_ADDRESS if (memcmp(peer_addr, disc->addr.val, sizeof(disc->addr.val)) != 0) { return 0; } @@ -501,6 +510,9 @@ blecent_should_connect(const struct ble_gap_disc_desc *disc) struct ble_hs_adv_fields fields; int rc; int i; +#if CONFIG_EXAMPLE_USE_CI_ADDRESS + uint32_t *addr_offset; +#endif // CONFIG_EXAMPLE_USE_CI_ADDRESS /* The device has to be advertising connectability. */ if (disc->event_type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND && @@ -516,10 +528,16 @@ blecent_should_connect(const struct ble_gap_disc_desc *disc) if (strlen(CONFIG_EXAMPLE_PEER_ADDR) && (strncmp(CONFIG_EXAMPLE_PEER_ADDR, "ADDR_ANY", strlen("ADDR_ANY")) != 0)) { ESP_LOGI(tag, "Peer address from menuconfig: %s", CONFIG_EXAMPLE_PEER_ADDR); +#if !CONFIG_EXAMPLE_USE_CI_ADDRESS /* Convert string to address */ sscanf(CONFIG_EXAMPLE_PEER_ADDR, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &peer_addr[5], &peer_addr[4], &peer_addr[3], &peer_addr[2], &peer_addr[1], &peer_addr[0]); +#else + addr_offset = (uint32_t *)&peer_addr[1]; + *addr_offset = atoi(CONFIG_EXAMPLE_PEER_ADDR); + peer_addr[5] = 0xC3; +#endif // !CONFIG_EXAMPLE_USE_CI_ADDRESS if (memcmp(peer_addr, disc->addr.val, sizeof(disc->addr.val)) != 0) { return 0; } diff --git a/examples/bluetooth/nimble/blecent/sdkconfig.ci b/examples/bluetooth/nimble/blecent/sdkconfig.ci new file mode 100644 index 0000000000..ac6390187d --- /dev/null +++ b/examples/bluetooth/nimble/blecent/sdkconfig.ci @@ -0,0 +1,2 @@ +CONFIG_EXAMPLE_USE_CI_ADDRESS=y +CONFIG_EXAMPLE_PEER_ADDR="${CI_JOB_ID}" diff --git a/examples/bluetooth/nimble/blecent/sdkconfig.ci.esp32c2_xtal26m b/examples/bluetooth/nimble/blecent/sdkconfig.ci.esp32c2_xtal26m new file mode 100644 index 0000000000..c82bb24692 --- /dev/null +++ b/examples/bluetooth/nimble/blecent/sdkconfig.ci.esp32c2_xtal26m @@ -0,0 +1,4 @@ +CONFIG_IDF_TARGET="esp32c2" +CONFIG_XTAL_FREQ_26=y +CONFIG_EXAMPLE_USE_CI_ADDRESS=y +CONFIG_EXAMPLE_PEER_ADDR="${CI_JOB_ID}" diff --git a/examples/bluetooth/nimble/power_save/main/Kconfig.projbuild b/examples/bluetooth/nimble/power_save/main/Kconfig.projbuild index b734208ba9..9fb8e73231 100644 --- a/examples/bluetooth/nimble/power_save/main/Kconfig.projbuild +++ b/examples/bluetooth/nimble/power_save/main/Kconfig.projbuild @@ -156,4 +156,19 @@ menu "Example Configuration" help Use this option to enable resolving peer's address. + config EXAMPLE_USE_CI_ADDRESS + bool + default n + prompt "Advertise using Test address(Internal Test ONLY)" + help + Used for internal test ONLY. + Use this option to advertise in a specific random address. + + config EXAMPLE_CI_ADDRESS_OFFSET + string + prompt "Advertise using Test address(Internal Test ONLY)" + depends on EXAMPLE_USE_CI_ADDRESS + help + Used for internal test ONLY. + Use this option to advertise in a specific random address. endmenu diff --git a/examples/bluetooth/nimble/power_save/main/main.c b/examples/bluetooth/nimble/power_save/main/main.c index 183bbb0055..422a0a092d 100644 --- a/examples/bluetooth/nimble/power_save/main/main.c +++ b/examples/bluetooth/nimble/power_save/main/main.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -28,7 +28,7 @@ static uint8_t ext_adv_pattern_1[] = { static const char *tag = "NimBLE_BLE_PRPH"; static int bleprph_gap_event(struct ble_gap_event *event, void *arg); -#if CONFIG_EXAMPLE_RANDOM_ADDR +#if CONFIG_EXAMPLE_RANDOM_ADDR || CONFIG_EXAMPLE_USE_CI_ADDRESS static uint8_t own_addr_type = BLE_OWN_ADDR_RANDOM; #else static uint8_t own_addr_type; @@ -93,7 +93,7 @@ ext_bleprph_advertise(void) params.connectable = 1; /* advertise using random addr */ - params.own_addr_type = BLE_OWN_ADDR_PUBLIC; + params.own_addr_type = own_addr_type; params.primary_phy = BLE_HCI_LE_PHY_1M; params.secondary_phy = BLE_HCI_LE_PHY_2M; @@ -462,14 +462,26 @@ bleprph_on_sync(void) ble_app_set_addr(); #endif +#if CONFIG_EXAMPLE_USE_CI_ADDRESS + if (strlen(CONFIG_EXAMPLE_CI_ADDRESS_OFFSET)) { + uint8_t addr[6] = {0}; + uint32_t *offset = (uint32_t *)&addr[1]; + *offset = atoi(CONFIG_EXAMPLE_CI_ADDRESS_OFFSET); + addr[5] = 0xC3; + rc = ble_hs_id_set_rnd(addr); + assert(rc == 0); + } +#endif // CONFIG_EXAMPLE_USE_CI_ADDRESS + /* Make sure we have proper identity address set (public preferred) */ -#if CONFIG_EXAMPLE_RANDOM_ADDR +#if CONFIG_EXAMPLE_RANDOM_ADDR || CONFIG_EXAMPLE_USE_CI_ADDRESS rc = ble_hs_util_ensure_addr(1); #else rc = ble_hs_util_ensure_addr(0); #endif assert(rc == 0); + /* Figure out address to use while advertising (no privacy for now) */ rc = ble_hs_id_infer_auto(0, &own_addr_type); if (rc != 0) { diff --git a/examples/bluetooth/nimble/power_save/sdkconfig.ci b/examples/bluetooth/nimble/power_save/sdkconfig.ci new file mode 100644 index 0000000000..a466b75320 --- /dev/null +++ b/examples/bluetooth/nimble/power_save/sdkconfig.ci @@ -0,0 +1,5 @@ +# +# Test Config +# +CONFIG_EXAMPLE_USE_CI_ADDRESS=y +CONFIG_EXAMPLE_CI_ADDRESS_OFFSET="${CI_JOB_ID}" diff --git a/examples/bluetooth/nimble/power_save/sdkconfig.ci.esp32c2_xtal26m b/examples/bluetooth/nimble/power_save/sdkconfig.ci.esp32c2_xtal26m new file mode 100644 index 0000000000..69cdde9cd5 --- /dev/null +++ b/examples/bluetooth/nimble/power_save/sdkconfig.ci.esp32c2_xtal26m @@ -0,0 +1,7 @@ +CONFIG_IDF_TARGET="esp32c2" +CONFIG_XTAL_FREQ_26=y +# +# Test Config +# +CONFIG_EXAMPLE_USE_CI_ADDRESS=y +CONFIG_EXAMPLE_CI_ADDRESS_OFFSET="${CI_JOB_ID}" diff --git a/examples/bluetooth/nimble/pytest_nimble_test.py b/examples/bluetooth/nimble/pytest_nimble_test.py new file mode 100644 index 0000000000..da3c89756e --- /dev/null +++ b/examples/bluetooth/nimble/pytest_nimble_test.py @@ -0,0 +1,63 @@ +# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: CC0-1.0 + +import os.path +from typing import Tuple + +import pexpect +import pytest +from pytest_embedded_idf.dut import IdfDut + + +# Case 1: BLE power save test +@pytest.mark.esp32c6 +@pytest.mark.esp32h2 +@pytest.mark.esp32c3 +@pytest.mark.esp32s3 +@pytest.mark.esp32 +@pytest.mark.wifi_two_dut +@pytest.mark.parametrize( + 'count, app_path', [ + (2, + f'{os.path.join(os.path.dirname(__file__), "power_save")}|{os.path.join(os.path.dirname(__file__), "blecent")}'), + ], + indirect=True, +) +def test_power_save_conn(app_path: str, dut: Tuple[IdfDut, IdfDut]) -> None: + peripheral = dut[0] + central = dut[1] + + peripheral.expect('NimBLE_BLE_PRPH: BLE Host Task Started', timeout=30) + central.expect('NimBLE_BLE_CENT: BLE Host Task Started', timeout=30) + peripheral.expect('Returned from app_main()', timeout=30) + central.expect('Returned from app_main()', timeout=30) + central.expect('Connection established', timeout=30) + peripheral.expect('connection established; status=0', timeout=30) + output = peripheral.expect(pexpect.TIMEOUT, timeout=30) + assert 'rst:' not in str(output) and 'boot:' not in str(output) + + +# Case 2: BLE power save test for ESP32C2 +@pytest.mark.esp32c2 +@pytest.mark.wifi_two_dut +@pytest.mark.xtal_26mhz +@pytest.mark.parametrize( + 'config, count, app_path, baud', [ + ('esp32c2_xtal26m', 2, + f'{os.path.join(os.path.dirname(__file__), "power_save")}|{os.path.join(os.path.dirname(__file__), "blecent")}', + '74880'), + ], + indirect=True, +) +def test_power_save_conn_esp32c2_26mhz(dut: Tuple[IdfDut, IdfDut]) -> None: + peripheral = dut[0] + central = dut[1] + + peripheral.expect('NimBLE_BLE_PRPH: BLE Host Task Started', timeout=5) + central.expect('NimBLE_BLE_CENT: BLE Host Task Started', timeout=5) + peripheral.expect('Returned from app_main()', timeout=5) + central.expect('Returned from app_main()', timeout=5) + central.expect('Connection established', timeout=30) + peripheral.expect('connection established; status=0', timeout=30) + output = peripheral.expect(pexpect.TIMEOUT, timeout=30) + assert 'rst:' not in str(output) and 'boot:' not in str(output)