Example of Classic Bluetooth Device and Service Discovery.
This is the example of using APIs to perform inquiry to search for a target device with a Major device type "Phone" or "Audio/Video" in the CoD (Class of Device) field and then performing a search via SDP (Service Discovery Protocol).
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
These `includes` are required for the FreeRTOS and underlying system components to run, including the logging functionality and a library to store data in non-volatile flash memory. We are interested in `bt.h`, `esp_bt_main.h`, `esp_bt_device.h` and `esp_gap_bt_api.h`, which expose the Classic Bluetooth APIs required to implement this example.
*`bt.h`: configures the Bluetooth controller and VHCI from the host side.
*`esp_bt_main.h`: initializes and enables the Bluedroid stack.
*`esp_gap_bt_api.h`: implements the GAP configuration, such as Classic Bluetooth device and service discovery.
*`esp_bt_device.h`: implements the device configuration, such as device address and device name.
## Main Entry Point
The program’s entry point is the `app_main()` function.
### Non-volatile Storage Library Initialization
The main function starts by initializing the non-volatile storage library. This library allows to store PHY calibration data and save key-value pairs in flash memory.
```c
esp_err_t 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 );
```
### Release The Controller Memory
Then the main function releases the controller memory for unused modes. It releases the BLE (Bluetooth Low Energy) memory in the controller via:
The controller memory should be released only before initializing Bluetooth controller or after deinitializing Bluetooth controller.
Note that once Bluetooth controller memory is released, the process cannot be reversed. It means you cannot use the Bluetooth mode which you have released by this function.
The main function also initializes the Bluetooth controller by first creating the controller configuration structure named `esp_bt_controller_config_t` with default settings generated by the `BT_CONTROLLER_INIT_CONFIG_DEFAULT()` macro. The Bluetooth controller implements the Host Controller Interface (HCI) on the controller side, the Link Layer (LL), and the Physical Layer (PHY). The Bluetooth Controller is invisible to the user applications and deals with the lower layers of the Bluetooth stack. The controller configuration includes setting the Bluetooth controller stack size, priority, and HCI baud rate. With the settings created, the Bluetooth controller is initialized and enabled with the `esp_bt_controller_init()` function:
> If you want to use the dual mode (BLE + Bluetooth Classic), the controller should be enabled in `ESP_BT_MODE_BTDM`, and should not releases the BLE memory in the controller.
There are four Bluetooth modes supported:
1.`ESP_BT_MODE_IDLE`: Bluetooth not running
2.`ESP_BT_MODE_BLE`: BLE mode
3.`ESP_BT_MODE_CLASSIC_BT`: Bluetooth Classic mode
4.`ESP_BT_MODE_BTDM`: Dual mode (BLE + Bluetooth Classic)
After the initialization of the Bluetooth controller, the Bluedroid stack, which includes the common definitions and APIs for both Bluetooth Classic and BLE, is initialized and enabled by using:
The GAP event handlers are the functions used to catch the events generated by the Bluetooth stack and execute functions to configure parameters of the application.
The functions `bt_app_gap_cb` handle all the events generated by the Bluetooth stack.
The application function then sets the device name and sets it as discoverable and connectable. After this, this device can be discovered and connected.
After device discovery gets started the state will change to `ESP_BT_GAP_DISCOVERY_STARTED`, and `bt_app_gap_cb` will be called with `ESP_BT_GAP_DISC_STATE_CHANGED_EVT`.
If nearby Bluetooth devices are discovered `bt_app_gap_cb` will be called with `ESP_BT_GAP_DISC_RES_EVT`, to post the result to users.
```c
case ESP_BT_GAP_DISC_RES_EVT: {
update_device_info(param);
break;
}
```
### Search For A Target Device
Function `update_device_info` gets the CoD (Class of Device), RSSI (Received Signal Strength Indication), name, EIR (Extended Inquiry Result) from the discovery result.
```c
for (int i = 0; i <param->disc_res.num_prop; i++) {
p = param->disc_res.prop + i;
switch (p->type) {
case ESP_BT_GAP_DEV_PROP_COD:
cod = *(uint32_t *)(p->val);
ESP_LOGI(GAP_TAG, "--Class of Device: 0x%x", cod);
Then, function `update_device_info` searches for a device with Major device type "Phone" or "Audio/Video" according to COD. For more information on COD, check [Bluetooth specifications](https://www.bluetooth.com/specifications/assigned-numbers/).
After device discovery stops the state will change to `ESP_BT_GAP_DISCOVERY_STOPPED` and `bt_app_gap_cb` will be called with `ESP_BT_GAP_DISC_STATE_CHANGED_EVT`.
Then it performs service discovery targeting at this device.
```c
p_dev->state = APP_GAP_STATE_SERVICE_DISCOVERING;
ESP_LOGI(GAP_TAG, "Discover services ...");
esp_bt_gap_get_remote_services(p_dev->bda);
```
Then `bt_app_gap_cb` will be called with `ESP_BT_GAP_RMT_SRVCS_EVT` to post the service discovery result to users including the service UUID. For more information on the service UUID, you can check [Bluetooth specifications](https://www.bluetooth.com/specifications/assigned-numbers/).
```c
for (int i = 0; i <param->rmt_srvcs.num_uuids; i++) {
We have reviewed the Bluetooth discovery example code. This example searches for nearby devices. When the device of interest is found, the example searches for the services of this device. We can get the device discovery result and service discovery result from the GAP callback, which is registered in advance.