2021-11-24 00:21:13 -05:00
|
|
|
/*
|
2024-07-18 00:06:02 -04:00
|
|
|
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
2021-11-24 00:21:13 -05:00
|
|
|
*
|
2021-12-06 01:59:55 -05:00
|
|
|
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
2021-11-24 00:21:13 -05:00
|
|
|
*/
|
2017-04-12 04:42:14 -04:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <string.h>
|
2022-12-08 23:23:36 -05:00
|
|
|
#include <inttypes.h>
|
2017-04-12 04:42:14 -04:00
|
|
|
#include "freertos/FreeRTOS.h"
|
|
|
|
#include "freertos/task.h"
|
|
|
|
#include "nvs.h"
|
|
|
|
#include "nvs_flash.h"
|
|
|
|
#include "esp_system.h"
|
|
|
|
#include "esp_log.h"
|
|
|
|
|
2017-12-07 08:48:27 -05:00
|
|
|
#include "esp_bt.h"
|
2017-04-12 04:42:14 -04:00
|
|
|
#include "bt_app_core.h"
|
|
|
|
#include "bt_app_av.h"
|
|
|
|
#include "esp_bt_main.h"
|
|
|
|
#include "esp_bt_device.h"
|
|
|
|
#include "esp_gap_bt_api.h"
|
|
|
|
#include "esp_a2dp_api.h"
|
|
|
|
#include "esp_avrc_api.h"
|
|
|
|
|
2021-12-23 08:05:18 -05:00
|
|
|
/* device name */
|
|
|
|
#define LOCAL_DEVICE_NAME "ESP_SPEAKER"
|
|
|
|
|
|
|
|
/* event for stack up */
|
2017-04-12 04:42:14 -04:00
|
|
|
enum {
|
|
|
|
BT_APP_EVT_STACK_UP = 0,
|
|
|
|
};
|
|
|
|
|
2021-12-23 08:05:18 -05:00
|
|
|
/********************************
|
|
|
|
* STATIC FUNCTION DECLARATIONS
|
|
|
|
*******************************/
|
|
|
|
|
2023-12-05 01:07:53 -05:00
|
|
|
/* Device callback function */
|
|
|
|
static void bt_app_dev_cb(esp_bt_dev_cb_event_t event, esp_bt_dev_cb_param_t *param);
|
2021-12-23 08:05:18 -05:00
|
|
|
/* GAP callback function */
|
|
|
|
static void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param);
|
2017-04-12 04:42:14 -04:00
|
|
|
/* handler for bluetooth stack enabled events */
|
|
|
|
static void bt_av_hdl_stack_evt(uint16_t event, void *p_param);
|
|
|
|
|
2021-12-23 08:05:18 -05:00
|
|
|
/*******************************
|
|
|
|
* STATIC FUNCTION DEFINITIONS
|
|
|
|
******************************/
|
2024-07-18 00:06:02 -04:00
|
|
|
static char *bda2str(uint8_t * bda, char *str, size_t size)
|
|
|
|
{
|
|
|
|
if (bda == NULL || str == NULL || size < 18) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t *p = bda;
|
|
|
|
sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
|
|
|
|
p[0], p[1], p[2], p[3], p[4], p[5]);
|
|
|
|
return str;
|
|
|
|
}
|
2017-04-12 04:42:14 -04:00
|
|
|
|
2023-12-05 01:07:53 -05:00
|
|
|
static void bt_app_dev_cb(esp_bt_dev_cb_event_t event, esp_bt_dev_cb_param_t *param)
|
|
|
|
{
|
|
|
|
switch (event) {
|
|
|
|
case ESP_BT_DEV_NAME_RES_EVT: {
|
|
|
|
if (param->name_res.status == ESP_BT_STATUS_SUCCESS) {
|
|
|
|
ESP_LOGI(BT_AV_TAG, "Get local device name success: %s", param->name_res.name);
|
|
|
|
} else {
|
|
|
|
ESP_LOGE(BT_AV_TAG, "Get local device name failed, status: %d", param->name_res.status);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default: {
|
|
|
|
ESP_LOGI(BT_AV_TAG, "event: %d", event);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-23 08:05:18 -05:00
|
|
|
static void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
|
2018-07-09 23:18:52 -04:00
|
|
|
{
|
2022-08-23 22:56:57 -04:00
|
|
|
uint8_t *bda = NULL;
|
|
|
|
|
2018-07-09 23:18:52 -04:00
|
|
|
switch (event) {
|
2021-12-23 08:05:18 -05:00
|
|
|
/* when authentication completed, this event comes */
|
2018-09-04 09:11:03 -04:00
|
|
|
case ESP_BT_GAP_AUTH_CMPL_EVT: {
|
2018-07-09 23:18:52 -04:00
|
|
|
if (param->auth_cmpl.stat == ESP_BT_STATUS_SUCCESS) {
|
|
|
|
ESP_LOGI(BT_AV_TAG, "authentication success: %s", param->auth_cmpl.device_name);
|
2024-05-01 08:26:15 -04:00
|
|
|
ESP_LOG_BUFFER_HEX(BT_AV_TAG, param->auth_cmpl.bda, ESP_BD_ADDR_LEN);
|
2018-07-09 23:18:52 -04:00
|
|
|
} else {
|
2021-12-23 08:05:18 -05:00
|
|
|
ESP_LOGE(BT_AV_TAG, "authentication failed, status: %d", param->auth_cmpl.stat);
|
2018-07-09 23:18:52 -04:00
|
|
|
}
|
2023-12-28 22:35:53 -05:00
|
|
|
ESP_LOGI(BT_AV_TAG, "link key type of current link is: %d", param->auth_cmpl.lk_type);
|
2018-07-09 23:18:52 -04:00
|
|
|
break;
|
|
|
|
}
|
2023-12-29 03:01:41 -05:00
|
|
|
case ESP_BT_GAP_ENC_CHG_EVT: {
|
|
|
|
char *str_enc[3] = {"OFF", "E0", "AES"};
|
|
|
|
bda = (uint8_t *)param->enc_chg.bda;
|
|
|
|
ESP_LOGI(BT_AV_TAG, "Encryption mode to [%02x:%02x:%02x:%02x:%02x:%02x] changed to %s",
|
|
|
|
bda[0], bda[1], bda[2], bda[3], bda[4], bda[5], str_enc[param->enc_chg.enc_mode]);
|
|
|
|
break;
|
|
|
|
}
|
2018-12-07 01:19:47 -05:00
|
|
|
|
2023-08-29 04:49:49 -04:00
|
|
|
#if (CONFIG_EXAMPLE_A2DP_SINK_SSP_ENABLED == true)
|
2021-12-23 08:05:18 -05:00
|
|
|
/* when Security Simple Pairing user confirmation requested, this event comes */
|
2018-07-09 23:18:52 -04:00
|
|
|
case ESP_BT_GAP_CFM_REQ_EVT:
|
2022-12-08 23:23:36 -05:00
|
|
|
ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_CFM_REQ_EVT Please compare the numeric value: %"PRIu32, param->cfm_req.num_val);
|
2018-07-09 23:18:52 -04:00
|
|
|
esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, true);
|
|
|
|
break;
|
2021-12-23 08:05:18 -05:00
|
|
|
/* when Security Simple Pairing passkey notified, this event comes */
|
2018-07-09 23:18:52 -04:00
|
|
|
case ESP_BT_GAP_KEY_NOTIF_EVT:
|
2022-12-08 23:23:36 -05:00
|
|
|
ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_KEY_NOTIF_EVT passkey: %"PRIu32, param->key_notif.passkey);
|
2018-07-09 23:18:52 -04:00
|
|
|
break;
|
2021-12-23 08:05:18 -05:00
|
|
|
/* when Security Simple Pairing passkey requested, this event comes */
|
2018-07-09 23:18:52 -04:00
|
|
|
case ESP_BT_GAP_KEY_REQ_EVT:
|
|
|
|
ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_KEY_REQ_EVT Please enter passkey!");
|
|
|
|
break;
|
2018-12-07 01:19:47 -05:00
|
|
|
#endif
|
|
|
|
|
2021-12-23 08:05:18 -05:00
|
|
|
/* when GAP mode changed, this event comes */
|
2020-07-21 06:11:11 -04:00
|
|
|
case ESP_BT_GAP_MODE_CHG_EVT:
|
2021-12-23 08:05:18 -05:00
|
|
|
ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_MODE_CHG_EVT mode: %d", param->mode_chg.mode);
|
2020-07-21 06:11:11 -04:00
|
|
|
break;
|
2022-08-23 22:56:57 -04:00
|
|
|
/* when ACL connection completed, this event comes */
|
|
|
|
case ESP_BT_GAP_ACL_CONN_CMPL_STAT_EVT:
|
|
|
|
bda = (uint8_t *)param->acl_conn_cmpl_stat.bda;
|
|
|
|
ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_ACL_CONN_CMPL_STAT_EVT Connected to [%02x:%02x:%02x:%02x:%02x:%02x], status: 0x%x",
|
|
|
|
bda[0], bda[1], bda[2], bda[3], bda[4], bda[5], param->acl_conn_cmpl_stat.stat);
|
|
|
|
break;
|
|
|
|
/* when ACL disconnection completed, this event comes */
|
|
|
|
case ESP_BT_GAP_ACL_DISCONN_CMPL_STAT_EVT:
|
|
|
|
bda = (uint8_t *)param->acl_disconn_cmpl_stat.bda;
|
|
|
|
ESP_LOGI(BT_AV_TAG, "ESP_BT_GAP_ACL_DISC_CMPL_STAT_EVT Disconnected from [%02x:%02x:%02x:%02x:%02x:%02x], reason: 0x%x",
|
|
|
|
bda[0], bda[1], bda[2], bda[3], bda[4], bda[5], param->acl_disconn_cmpl_stat.reason);
|
|
|
|
break;
|
2021-12-23 08:05:18 -05:00
|
|
|
/* others */
|
2018-07-09 23:18:52 -04:00
|
|
|
default: {
|
|
|
|
ESP_LOGI(BT_AV_TAG, "event: %d", event);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-12-23 08:05:18 -05:00
|
|
|
|
2017-04-12 04:42:14 -04:00
|
|
|
static void bt_av_hdl_stack_evt(uint16_t event, void *p_param)
|
|
|
|
{
|
2021-12-23 08:05:18 -05:00
|
|
|
ESP_LOGD(BT_AV_TAG, "%s event: %d", __func__, event);
|
|
|
|
|
2017-04-12 04:42:14 -04:00
|
|
|
switch (event) {
|
2021-12-23 08:05:18 -05:00
|
|
|
/* when do the stack up, this event comes */
|
2017-04-12 04:42:14 -04:00
|
|
|
case BT_APP_EVT_STACK_UP: {
|
2024-04-02 23:53:08 -04:00
|
|
|
esp_bt_gap_set_device_name(LOCAL_DEVICE_NAME);
|
2023-12-05 01:07:53 -05:00
|
|
|
esp_bt_dev_register_callback(bt_app_dev_cb);
|
2018-07-09 23:18:52 -04:00
|
|
|
esp_bt_gap_register_callback(bt_app_gap_cb);
|
2017-04-12 04:42:14 -04:00
|
|
|
|
2021-12-23 08:05:18 -05:00
|
|
|
assert(esp_avrc_ct_init() == ESP_OK);
|
2017-04-12 04:42:14 -04:00
|
|
|
esp_avrc_ct_register_callback(bt_app_rc_ct_cb);
|
2021-12-23 08:05:18 -05:00
|
|
|
assert(esp_avrc_tg_init() == ESP_OK);
|
component/bt: implement AVRCP Target APIs
1. Add more notification events to the enum according to the event list in AVRCP specification.
2. Add API and callback events for basic AVRCP target functionalities to do init, deinit, callback-registration, connection status indication.
3. Implement API to set/get supported PASSTHROUGH command on local AVRCP TG, implement callback events for remote passthrough command indication.
4. Implement API to set/get supported notification eventIDs on local AVRCP TG, implement API to send event notifications to remote CT. \
Currently supported event in TG only includes ESP_AVRC_RN_VOLUME_CHANGE(0xd), which can be extended in later commits.
5. Implement callback events for SetAbsoluteVolume command indication on TG.
6. Add limitation of event_ids supported in RegisterNotification command in CT. The supported event_ids include: \
ESP_AVRC_RN_PLAY_STATUS_CHANGE(0x1), ESP_AVRC_RN_TRACK_CHANGE(0x2), ESP_AVRC_RN_PLAY_POS_CHANGE(0x5), ESP_AVRC_RN_VOLUME_CHANGE(0xd).
7. Add feature bit mask in parameter of callback event ESP_AVRC_CT_REMOTE_FEATURES_EVT for peer feature information got from SDP.
8. Add API and callback event to AVRCP CT to retrieve remote TG's supported notification event capabilities.
9. Modify data type for parameter of callback event ESP_AVRC_CT_CHANGE_NOTIFY_EVT.
10. Change AVRCP version from 1.3 to 1.4 for compatibility cause in using AbsoluteVolume feature.
11. Modify local AVRCP device to be category 1 as CT and category 2 as TG that applies to bluetooth headphones or speakers.
12. Update the use of AVRCP APIs and events in the two examples: a2dp_sink and a2dp_gatts_coex, which include the demo of volume control and notification.
2018-12-21 04:04:21 -05:00
|
|
|
esp_avrc_tg_register_callback(bt_app_rc_tg_cb);
|
|
|
|
|
|
|
|
esp_avrc_rn_evt_cap_mask_t evt_set = {0};
|
|
|
|
esp_avrc_rn_evt_bit_mask_operation(ESP_AVRC_BIT_MASK_OP_SET, &evt_set, ESP_AVRC_RN_VOLUME_CHANGE);
|
|
|
|
assert(esp_avrc_tg_set_rn_evt_cap(&evt_set) == ESP_OK);
|
|
|
|
|
2021-12-23 08:05:18 -05:00
|
|
|
assert(esp_a2d_sink_init() == ESP_OK);
|
component/bt: implement AVRCP Target APIs
1. Add more notification events to the enum according to the event list in AVRCP specification.
2. Add API and callback events for basic AVRCP target functionalities to do init, deinit, callback-registration, connection status indication.
3. Implement API to set/get supported PASSTHROUGH command on local AVRCP TG, implement callback events for remote passthrough command indication.
4. Implement API to set/get supported notification eventIDs on local AVRCP TG, implement API to send event notifications to remote CT. \
Currently supported event in TG only includes ESP_AVRC_RN_VOLUME_CHANGE(0xd), which can be extended in later commits.
5. Implement callback events for SetAbsoluteVolume command indication on TG.
6. Add limitation of event_ids supported in RegisterNotification command in CT. The supported event_ids include: \
ESP_AVRC_RN_PLAY_STATUS_CHANGE(0x1), ESP_AVRC_RN_TRACK_CHANGE(0x2), ESP_AVRC_RN_PLAY_POS_CHANGE(0x5), ESP_AVRC_RN_VOLUME_CHANGE(0xd).
7. Add feature bit mask in parameter of callback event ESP_AVRC_CT_REMOTE_FEATURES_EVT for peer feature information got from SDP.
8. Add API and callback event to AVRCP CT to retrieve remote TG's supported notification event capabilities.
9. Modify data type for parameter of callback event ESP_AVRC_CT_CHANGE_NOTIFY_EVT.
10. Change AVRCP version from 1.3 to 1.4 for compatibility cause in using AbsoluteVolume feature.
11. Modify local AVRCP device to be category 1 as CT and category 2 as TG that applies to bluetooth headphones or speakers.
12. Update the use of AVRCP APIs and events in the two examples: a2dp_sink and a2dp_gatts_coex, which include the demo of volume control and notification.
2018-12-21 04:04:21 -05:00
|
|
|
esp_a2d_register_callback(&bt_app_a2d_cb);
|
|
|
|
esp_a2d_sink_register_data_callback(bt_app_a2d_data_cb);
|
2017-04-12 04:42:14 -04:00
|
|
|
|
2022-03-30 04:29:36 -04:00
|
|
|
/* Get the default value of the delay value */
|
|
|
|
esp_a2d_sink_get_delay_value();
|
2023-12-05 01:07:53 -05:00
|
|
|
/* Get local device name */
|
2024-04-02 23:53:08 -04:00
|
|
|
esp_bt_gap_get_device_name();
|
2022-03-30 04:29:36 -04:00
|
|
|
|
2017-04-12 04:42:14 -04:00
|
|
|
/* set discoverable and connectable mode, wait to be connected */
|
2018-04-09 06:30:48 -04:00
|
|
|
esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
|
2017-04-12 04:42:14 -04:00
|
|
|
break;
|
|
|
|
}
|
2021-12-23 08:05:18 -05:00
|
|
|
/* others */
|
2017-04-12 04:42:14 -04:00
|
|
|
default:
|
2021-12-23 08:05:18 -05:00
|
|
|
ESP_LOGE(BT_AV_TAG, "%s unhandled event: %d", __func__, event);
|
2017-04-12 04:42:14 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2021-12-23 08:05:18 -05:00
|
|
|
|
|
|
|
/*******************************
|
|
|
|
* MAIN ENTRY POINT
|
|
|
|
******************************/
|
|
|
|
|
|
|
|
void app_main(void)
|
|
|
|
{
|
2024-07-18 00:06:02 -04:00
|
|
|
char bda_str[18] = {0};
|
2021-12-23 08:05:18 -05:00
|
|
|
/* initialize NVS — it is used to store PHY calibration data */
|
|
|
|
esp_err_t err = nvs_flash_init();
|
|
|
|
if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
|
|
|
ESP_ERROR_CHECK(nvs_flash_erase());
|
|
|
|
err = nvs_flash_init();
|
|
|
|
}
|
|
|
|
ESP_ERROR_CHECK(err);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This example only uses the functions of Classical Bluetooth.
|
|
|
|
* So release the controller memory for Bluetooth Low Energy.
|
|
|
|
*/
|
|
|
|
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BLE));
|
|
|
|
|
|
|
|
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
|
|
|
if ((err = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
|
2023-06-08 14:56:11 -04:00
|
|
|
ESP_LOGE(BT_AV_TAG, "%s initialize controller failed: %s", __func__, esp_err_to_name(err));
|
2021-12-23 08:05:18 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ((err = esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT)) != ESP_OK) {
|
2023-06-08 14:56:11 -04:00
|
|
|
ESP_LOGE(BT_AV_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(err));
|
2021-12-23 08:05:18 -05:00
|
|
|
return;
|
|
|
|
}
|
2023-08-29 04:49:49 -04:00
|
|
|
|
|
|
|
esp_bluedroid_config_t bluedroid_cfg = BT_BLUEDROID_INIT_CONFIG_DEFAULT();
|
|
|
|
#if (CONFIG_EXAMPLE_A2DP_SINK_SSP_ENABLED == false)
|
|
|
|
bluedroid_cfg.ssp_en = false;
|
|
|
|
#endif
|
|
|
|
if ((err = esp_bluedroid_init_with_cfg(&bluedroid_cfg)) != ESP_OK) {
|
2023-06-08 14:56:11 -04:00
|
|
|
ESP_LOGE(BT_AV_TAG, "%s initialize bluedroid failed: %s", __func__, esp_err_to_name(err));
|
2021-12-23 08:05:18 -05:00
|
|
|
return;
|
|
|
|
}
|
2023-08-29 04:49:49 -04:00
|
|
|
|
2021-12-23 08:05:18 -05:00
|
|
|
if ((err = esp_bluedroid_enable()) != ESP_OK) {
|
2023-06-08 14:56:11 -04:00
|
|
|
ESP_LOGE(BT_AV_TAG, "%s enable bluedroid failed: %s", __func__, esp_err_to_name(err));
|
2021-12-23 08:05:18 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-08-29 04:49:49 -04:00
|
|
|
#if (CONFIG_EXAMPLE_A2DP_SINK_SSP_ENABLED == true)
|
2021-12-23 08:05:18 -05:00
|
|
|
/* set default parameters for Secure Simple Pairing */
|
|
|
|
esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
|
|
|
|
esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_IO;
|
|
|
|
esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* set default parameters for Legacy Pairing (use fixed pin code 1234) */
|
|
|
|
esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_FIXED;
|
|
|
|
esp_bt_pin_code_t pin_code;
|
|
|
|
pin_code[0] = '1';
|
|
|
|
pin_code[1] = '2';
|
|
|
|
pin_code[2] = '3';
|
|
|
|
pin_code[3] = '4';
|
|
|
|
esp_bt_gap_set_pin(pin_type, 4, pin_code);
|
|
|
|
|
2024-07-18 00:06:02 -04:00
|
|
|
ESP_LOGI(BT_AV_TAG, "Own address:[%s]", bda2str((uint8_t *)esp_bt_dev_get_address(), bda_str, sizeof(bda_str)));
|
2021-12-23 08:05:18 -05:00
|
|
|
bt_app_task_start_up();
|
|
|
|
/* bluetooth device name, connection mode and profile set up */
|
|
|
|
bt_app_work_dispatch(bt_av_hdl_stack_evt, BT_APP_EVT_STACK_UP, NULL, 0, NULL);
|
|
|
|
}
|