diff --git a/components/bt/test_apps/.build-test-rules.yml b/components/bt/test_apps/.build-test-rules.yml index 72899ce198..9b43473633 100644 --- a/components/bt/test_apps/.build-test-rules.yml +++ b/components/bt/test_apps/.build-test-rules.yml @@ -6,3 +6,12 @@ components/bt/test_apps/basic_unit_test: reason: Sufficient to run the tests on one chip of each architecture depends_components: - bt + +components/bt/test_apps/memory_release: + disable: + - if: IDF_TARGET not in ["esp32", "esp32c2"] + - if: CONFIG_NAME == "iram" and IDF_TARGET != "esp32c2" + - if: CONFIG_NAME == "psram" and SOC_SPIRAM_SUPPORTED != 1 + reason: Sufficient to run the tests on one chip of each architecture + depends_components: + - bt diff --git a/components/bt/test_apps/memory_release/CMakeLists.txt b/components/bt/test_apps/memory_release/CMakeLists.txt new file mode 100644 index 0000000000..f3d75bb435 --- /dev/null +++ b/components/bt/test_apps/memory_release/CMakeLists.txt @@ -0,0 +1,5 @@ +# This is the project CMakeLists.txt file for the test subproject +cmake_minimum_required(VERSION 3.16) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(test_bt_memory_release) diff --git a/components/bt/test_apps/memory_release/README.md b/components/bt/test_apps/memory_release/README.md new file mode 100644 index 0000000000..2975ce8f21 --- /dev/null +++ b/components/bt/test_apps/memory_release/README.md @@ -0,0 +1,4 @@ +| Supported Targets | ESP32 | ESP32-C2 | +| ----------------- | ----- | -------- | + +This test app is used to test esp_bt_memory_release function diff --git a/components/bt/test_apps/memory_release/main/CMakeLists.txt b/components/bt/test_apps/memory_release/main/CMakeLists.txt new file mode 100644 index 0000000000..660eb5875d --- /dev/null +++ b/components/bt/test_apps/memory_release/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "test_app_main.c" + INCLUDE_DIRS "." + PRIV_REQUIRES bt nvs_flash) diff --git a/components/bt/test_apps/memory_release/main/test_app_main.c b/components/bt/test_apps/memory_release/main/test_app_main.c new file mode 100644 index 0000000000..562d1d97dd --- /dev/null +++ b/components/bt/test_apps/memory_release/main/test_app_main.c @@ -0,0 +1,131 @@ +/* + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include + +#include "esp_log.h" +#include "nvs_flash.h" + +#include "multi_heap.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "esp_bt.h" +#include "nimble/nimble_port.h" +#include "nimble/nimble_port_freertos.h" +#include "host/ble_hs.h" +#include "host/util/util.h" +#include "services/gap/ble_svc_gap.h" + +#define FAIL() do { printf("FAILURE\n"); return; } while(0) + +extern uint8_t _bt_bss_start; +extern uint8_t _bt_bss_end; +extern uint8_t _bt_controller_bss_start; +extern uint8_t _bt_controller_bss_end; + +extern void ble_store_config_init(void); + +static const char *tag = "MEM_RELEASE_APP"; + +static void nimble_host_on_reset(int reason) +{ + ESP_LOGI(tag, "Resetting state; reason=%d", reason); +} + +static void nimble_host_on_sync(void) +{ + ESP_LOGI(tag, "NimBLE host synchronized"); +} + +static void nimble_host_task_fn(void *param) +{ + ESP_LOGI(tag, "BLE Host Task Started"); + /* This function will return only when nimble_port_stop() is executed */ + nimble_port_run(); + + nimble_port_freertos_deinit(); +} + +static void bt_stack_init(void) +{ + esp_err_t ret = nimble_port_init(); + ESP_ERROR_CHECK(ret); + + /* Initialize the NimBLE host configuration. */ + ble_hs_cfg.reset_cb = nimble_host_on_reset; + ble_hs_cfg.sync_cb = nimble_host_on_sync; + ble_hs_cfg.store_status_cb = ble_store_util_status_rr; + + /* Set the default device name. */ + int rc = ble_svc_gap_device_name_set(tag); + assert(rc == 0); + + /* XXX Need to have template for store */ + ble_store_config_init(); + + nimble_port_freertos_init(nimble_host_task_fn); +} + +static void bt_stack_deinit(void) +{ + int rc = nimble_port_stop(); + assert(rc == 0); + + nimble_port_deinit(); + ESP_LOGI(tag, "BLE Host Task Stopped"); +} + +void app_main(void) +{ + esp_err_t ret = ESP_OK; + + /* Initialize NVS — it is used to store PHY calibration data */ + ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + /* initialize and then deinitialize bluetooth stack */ + bt_stack_init(); + + vTaskDelay(pdMS_TO_TICKS(200)); + + bt_stack_deinit(); + + /* Get the size of heap located in external RAM */ + const uint32_t free_before = heap_caps_get_free_size(MALLOC_CAP_DEFAULT); + ESP_LOGI(tag, "Free size in external RAM heap: %"PRIu32, free_before); + + /* Make sure at least one of the Bluetooth BSS section that can be used as a heap */ + const uint32_t heap_size = sizeof(multi_heap_info_t); + const uint32_t bt_bss_size = &_bt_bss_end - &_bt_bss_start; + const uint32_t bt_ctrl_bss_size = &_bt_controller_bss_end - &_bt_controller_bss_start; + + ESP_LOGI(tag, "bt_bss_size %"PRIu32", bt_ctrl_bss_size %"PRIu32, bt_bss_size, bt_ctrl_bss_size); + if (bt_bss_size < heap_size && bt_ctrl_bss_size < heap_size) + { + ESP_LOGW(tag, "Bluetooth BSS sections are too small!"); + FAIL(); + } + + /* Release the BSS sections to use them as heap */ + ret = esp_bt_mem_release(ESP_BT_MODE_BTDM); + ESP_ERROR_CHECK(ret); + + /* Check that we have more available memory in the external RAM heap */ + const uint32_t free_after = heap_caps_get_free_size(MALLOC_CAP_DEFAULT); + ESP_LOGI(tag, "Free size in external RAM after releasing: %"PRIu32, free_after); + if (free_after <= free_before) { + FAIL(); + } + ESP_LOGI(tag, "Free heap size increased by %"PRIu32" bytes", free_after - free_before); + + ESP_LOGI(tag, "SUCCESS"); +} diff --git a/components/bt/test_apps/memory_release/pytest_memory_release.py b/components/bt/test_apps/memory_release/pytest_memory_release.py new file mode 100644 index 0000000000..dbefc908a6 --- /dev/null +++ b/components/bt/test_apps/memory_release/pytest_memory_release.py @@ -0,0 +1,15 @@ +# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Apache-2.0 +import pytest +from pytest_embedded import Dut + + +@pytest.mark.parametrize('config', [ + pytest.param('default', marks=[pytest.mark.esp32, pytest.mark.esp32c2, pytest.mark.generic]), + pytest.param('iram', marks=[pytest.mark.esp32c2, pytest.mark.generic]), + pytest.param('psram', marks=[pytest.mark.esp32, pytest.mark.psram]), +], indirect=True) +def test_bt_memory_release(dut: Dut) -> None: + dut.expect_exact('BLE Host Task Started', timeout=6) + dut.expect_exact('BLE Host Task Stopped', timeout=8) + dut.expect_exact('SUCCESS', timeout=10) diff --git a/components/bt/test_apps/memory_release/sdkconfig.ci.iram b/components/bt/test_apps/memory_release/sdkconfig.ci.iram new file mode 100644 index 0000000000..36e7ceb92a --- /dev/null +++ b/components/bt/test_apps/memory_release/sdkconfig.ci.iram @@ -0,0 +1,2 @@ +CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT=n +CONFIG_BT_RELEASE_IRAM=y diff --git a/components/bt/test_apps/memory_release/sdkconfig.ci.psram b/components/bt/test_apps/memory_release/sdkconfig.ci.psram new file mode 100644 index 0000000000..4090a49eaf --- /dev/null +++ b/components/bt/test_apps/memory_release/sdkconfig.ci.psram @@ -0,0 +1,2 @@ +CONFIG_SPIRAM=y +CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y diff --git a/components/bt/test_apps/memory_release/sdkconfig.defaults b/components/bt/test_apps/memory_release/sdkconfig.defaults new file mode 100644 index 0000000000..a22d8109d7 --- /dev/null +++ b/components/bt/test_apps/memory_release/sdkconfig.defaults @@ -0,0 +1,2 @@ +CONFIG_BT_ENABLED=y +CONFIG_BT_NIMBLE_ENABLED=y