2.6. DEMO_EDR工程说明
概述
本工程展示了使用蓝牙EDR进行播歌和通话测试的使用示例。
1.实现蓝牙EDR播歌中暂停播放、上下曲、音量增减等功能。
2.实现蓝牙EDR通话中接听和挂断电话,音量增减等功能。
3.实现蓝牙发射功能。
4.实现spp数据传输功能。
具体的示例工程代码详见 apps/demo/demo_edr
。
2.6.1. 工程配置说明
apps/demo/demo_edr/app_config
#define CONFIG_POWER_ON_ENABLE_BT 1 //开机自动打开经典蓝牙
#define TCFG_USER_BT_CLASSIC_ENABLE 1 //经典蓝牙功能
#define TCFG_USER_BLE_ENABLE 0 //BLE功能使能
#define TCFG_USER_EMITTER_ENABLE 1 //蓝牙发射功能
修改蓝牙初始名称user_cfg.c:
可修改bt_get_local_name()中edr_name:JL-AC79XX。
在bt_get_pin_code()函数修改设备返回的pin code。
如有特殊需求,可在bt_get_mac_addr()函数修改设备的蓝牙mac地址。
const char *bt_get_local_name(void)
{
#ifndef CONFIG_RF_TEST_ENABLE
const u8 *mac_addr;
mac_addr = bt_get_mac_addr();
sprintf(edr_name, "JL-AC79XX-%02X%02X", mac_addr[4], mac_addr[5]);//修改edr_name
#endif
return edr_name;
}
const char *bt_get_pin_code(void)
{
return pincode;
}
const u8 *bt_get_mac_addr(void)
{
static u8 mac_addr[6];
#if defined CONFIG_WIFI_ENABLE && !defined CONFIG_RF_TEST_ENABLE
wifi_get_mac(mac_addr);
if (bytecmp(mac_addr, 0, 6)) {
return mac_addr;
} else
#endif
{
if (syscfg_read(CFG_BT_MAC_ADDR, mac_addr, 6) == 6) {
return mac_addr;
}
u8 flash_uid[16];
memcpy(flash_uid, get_norflash_uuid(), 16);
do {
u32 crc32 = rand32()^CRC32(flash_uid, sizeof(flash_uid));
u16 crc16 = rand32()^CRC16(flash_uid, sizeof(flash_uid));
memcpy(mac_addr, &crc32, sizeof(crc32));
memcpy(&mac_addr[4], &crc16, sizeof(crc16));
} while (!bytecmp(mac_addr, 0, 6));
//此处用户可自行修改为本地生成mac地址的算法
mac_addr[0] &= ~((1 << 0) | (1 << 1));
syscfg_write(CFG_BT_MAC_ADDR, mac_addr, 6);
return mac_addr;
}
}
2.6.2. 操作说明:
按键功能:查看bt_music.c中bt_music_key_event_handler()
1.播歌模式
A ) 暂停或播放:KEY_OK按键。B ) 音量增大:短按KEY_VOLUME_INC按键。C ) 音量减小:短按KEY_VOLUME_DEC按键。D ) 播放上一首:长按KEY_VOLUME_DEC按键。E ) 播放下一首:长按KEY_VOLUME_INC按键。
2.通话模式
A ) 接听或挂断电话:KEY_OK按键。B ) 音量增大:短按KEY_VOLUME_INC按键。C ) 音量减小:短按KEY_VOLUME_DEC按键。
3.发射模式
长按KEY_MODE按键切换到蓝牙发射模式,进行设备搜索并根据过滤规则连接指定设备。
4.通过spp数传app进行开发板与手机之间的数据传输。发送间隔2ms,sent_len长度660,速率最快150Kbytes。底层限制了每次发送的最大长度,当sent_len超过660时受限制。
5.关闭或打开蓝牙,短按KEY_MODE按键。切换蓝牙到发射或者接收模式,长按KEY_MODE按键。
2.6.3. 代码流程
1.app_main(),调用bt_ble_module_init()进行蓝牙BR协议栈初始化
//app_main.c
/*
* 应用程序主函数
*/
void app_main()
{
puts("------------- demo_edr app main-------------\n");
extern void bt_ble_module_init(void);
bt_ble_module_init();
}
2.bt_ble_module_init()
A ) 调用bt_function_select_init()函数进行经典蓝牙功能配置,包括音量是否同步、是否连接自动播放、是否定时更新电量、回连搜索超时、蓝牙加密等级和蓝牙设备类型等功能。B ) 调用bredr_handle_register()函数进行协议栈回调函数注册,包括SPP数传数据回调、蓝牙音量同步接口回调、电量显示获取电量的接口、被测试盒链接上进入快速测试回调、样机进入dut被测试仪器链接上回调、获取远端设备蓝牙名字回调、获取歌曲信息回调、发射器设置回调等。C ) 调用btstack_init()函数进行蓝牙协议栈初始化。D ) 调用sys_auto_sniff_controle()函数进行自动进入sniff低功耗模式,空闲5s之后进入sniff模式。E ) bt_connction_status_event_handler()函数负责处理协议栈连接、加密、媒体播放、通话等各种状态的回调。F ) bt_hci_event_handler()函数负责处理协议栈各种HCI事件的回调。
void bt_ble_module_init(void)
{
bt_function_select_init();
bredr_handle_register();
btstack_init();
}
static void bt_function_select_init(void)
{
__this->media_volume = INIT_VOLUME_VALUE;
__this->call_volume = INIT_VOLUME_VALUE;
__set_a2dp_auto_play_flag(1); /* 连接高级音频后自动播放歌曲 */
__set_support_msbc_flag(1);
#if TCFG_BT_SUPPORT_AAC
__set_support_aac_flag(1);
#endif
#if BT_SUPPORT_DISPLAY_BAT
__bt_set_update_battery_time(60);
#else
__bt_set_update_battery_time(0);
#endif
__set_page_timeout_value(8000); /*回连搜索时间长度设置,可使用该函数注册使用,ms单位,u16*/
__set_super_timeout_value(8000); /*回连时超时参数设置。ms单位。做主机有效*/
__set_simple_pair_flag(1); //是否打开简易配对功能,打开后不需要输入pincode
////设置蓝牙加密的level
//io_capabilities ; /*0: Display only 1: Display YesNo 2: KeyboardOnly 3: NoInputNoOutput*/
//authentication_requirements: 0:not protect 1 :protect
__set_simple_pair_param(3, 0, 2);
#if (USER_SUPPORT_PROFILE_PBAP==1)
////设置蓝牙设备类型
__change_hci_class_type(BD_CLASS_CAR_AUDIO);
#endif
#if (TCFG_BT_SNIFF_ENABLE == 0)
void lmp_set_sniff_disable(void);
lmp_set_sniff_disable();
#endif
}
static void bredr_handle_register(void)
{
#if USER_SUPPORT_PROFILE_SPP
extern void user_spp_data_handler(u8 packet_type, u16 ch, u8 * packet, u16 size);
spp_data_deal_handle_register(user_spp_data_handler);
#endif
#if BT_SUPPORT_MUSIC_VOL_SYNC
///蓝牙音乐和通话音量同步
music_vol_change_handle_register(bt_set_music_device_volume, phone_get_device_vol);
#endif
#if BT_SUPPORT_DISPLAY_BAT
///电量显示获取电量的接口
get_battery_value_register(bt_get_battery_value); /*电量显示获取电量的接口*/
#endif
///被测试盒链接上进入快速测试回调
/* bt_fast_test_handle_register(bt_fast_test_api); */
///样机进入dut被测试仪器链接上回调
bt_dut_test_handle_register(bt_dut_api);
///获取远端设备蓝牙名字回调
read_remote_name_handle_register(bt_read_remote_name);
////获取歌曲信息回调
/* bt_music_info_handle_register(user_get_bt_music_info); */
#if TCFG_USER_EMITTER_ENABLE
////发射器设置回调等
inquiry_result_handle_register(emitter_search_result);
#endif
}
3.transport_spp_init()函数,初始化spp传输初始化
//bt_music.c
static int bt_connction_status_event_handler(struct bt_event *bt)
{
log_i("-----------------------bt_connction_status_event_handler %d\n", bt->event);
switch (bt->event) {
case BT_STATUS_INIT_OK:
/*
* 蓝牙初始化完成
*/
log_i("===================BT_STATUS_INIT_OK\n");
#if SPP_TRANS_DATA_EN
extern void transport_spp_init(void);
transport_spp_init();
#endif
bt_connection_enable();
break;
4.蓝牙发射功能(bt_emitter.c):蓝牙发射搜索结果回调处理,根据过滤规则可以做名字过滤、地址过滤、自定义过滤和无限制规则,也可以保存搜索到的所有设备再选择一个进行连接。
提供按键切换发射器或者接收器功能:2:发射 1:接收 0: 关闭。发射器设置回调包括设备名字name、设备名字长度len、设备类型class和设备信号强度rssi等。
//bt_music.c的bt_music_key_event_handler()长按KEY_MODE切换发射器和接收器
case KEY_MODE:
#if TCFG_USER_EMITTER_ENABLE
//发射器或者接收器切换
if (__this->enable) {
if (__this->emitter) {
bt_emitter_disable();
} else {
key_event_disable();
bt_connection_disable();
sys_timeout_add(NULL, bt_emitter_enable, 1000);
}
}
#endif
break;
//bt_emitter.c
#define SEARCH_BD_ADDR_LIMITED 0 //搜索蓝牙地址过滤
#define SEARCH_BD_NAME_LIMITED 1 //搜索蓝牙名称过滤
#define SEARCH_CUSTOM_LIMITED 2 //自定义搜索
#define SEARCH_NULL_LIMITED 3 //没有指定限制,则搜到什么就连接什么
#define SEARCH_LIMITED_MODE SEARCH_BD_NAME_LIMITED
//地址过滤
#if (SEARCH_LIMITED_MODE == SEARCH_BD_ADDR_LIMITED)
static const u8 bd_addr_filt[][6] = {
{0x8E, 0xA7, 0xCA, 0x0A, 0x5E, 0xC8}, /*S10_H*/
{0xA7, 0xDD, 0x05, 0xDD, 0x1F, 0x00}, /*ST-001*/
{0xE9, 0x73, 0x13, 0xC0, 0x1F, 0x00}, /*HBS 730*/
{0x38, 0x7C, 0x78, 0x1C, 0xFC, 0x02}, /*Bluetooth*/
};
/*----------------------------------------------------------------------------*/
/**@brief 蓝牙发射搜索通过地址过滤
@param 无
@return 无
@note
*/
/*----------------------------------------------------------------------------*/
static u8 search_bd_addr_filt(const u8 *addr)
{
log_i("bd_addr:");
put_buf(addr, 6);
for (u8 i = 0; i < (sizeof(bd_addr_filt) / sizeof(bd_addr_filt[0])); i++) {
if (memcmp(addr, bd_addr_filt[i], 6) == 0) {
/* printf("bd_addr match:%d\n", i); */
return TRUE;
}
}
/*log_i("bd_addr not match\n"); */
return FALSE;
}
#endif
//名称过滤
#if (SEARCH_LIMITED_MODE == SEARCH_BD_NAME_LIMITED)
#if 0
static const u8 bd_name_filt[][32] = {
"BeMine",
"EDIFIER CSR8635",/*CSR*/
"JL-BT-SDK",/*Realtek*/
"I7-TWS",/*ZKLX*/
"TWS-i7",/*ZKLX*/
"I9",/*ZKLX*/
"小米小钢炮蓝牙音箱",/*XiaoMi*/
"小米蓝牙音箱",/*XiaoMi*/
"XMFHZ02",/*XiaoMi*/
"JBL GO 2",
"i7mini",/*JL tws AC690x*/
"S08U",
"AI8006B_TWS00",
"S046",/*BK*/
"AirPods",
"CSD-TWS-01",
"AC692X_wh",
"JBL GO 2",
"JBL Flip 4",
"BT Speaker",
"CSC608",
"QCY-QY19",
"Newmine",
"HT1+",
"S-35",
"T12-JL",
"Redmi AirDots_R",
"Redmi AirDots_L",
"AC69_Bluetooth",
"FlyPods 3",
"MNS",
"Jam Heavy Metal",
"Bluedio",
"HR-686",
"BT MUSIC",
"BW-USB-DONGLE",
"S530",
"XPDQ7",
"MICGEEK Q9S",
"S10_H",
"S10",/*JL AC690x*/
"S11",/*JL AC460x*/
"HBS-730",
"SPORT-S9",
"Q5",
"IAEB25",
"T5-JL",
"MS-808",
"LG HBS-730",
"NG-BT07"
};
#else
static const u8 bd_name_filt[][30] = {
"JL-AC79XX-AF0B",
"JL-AC79XX-AAFF",
};
#endif
/*----------------------------------------------------------------------------*/
/**@brief 蓝牙发射搜索通过名字过滤
@param 无
@return 无
@note
*/
/*----------------------------------------------------------------------------*/
u8 search_bd_name_filt(const char *data, u8 len, u32 dev_class, char rssi)
{
char bd_name[64] = {0};
if ((len > (sizeof(bd_name))) || (len == 0)) {
return FALSE;
}
memcpy(bd_name, data, len);
log_i("name:%s,len:%d,class %x ,rssi %d\n", bd_name, len, dev_class, rssi);
for (u8 i = 0; i < (sizeof(bd_name_filt) / sizeof(bd_name_filt[0])); i++) {
if (memcmp(data, bd_name_filt[i], len) == 0) {
log_i("\n*****find dev ok******\n");
return TRUE;
}
}
return FALSE;
}
#endif
/*----------------------------------------------------------------------------*/
/**@brief 蓝牙发射搜索结果回调处理
@param name : 设备名字
name_len: 设备名字长度
addr: 设备地址
dev_class: 设备类型
rssi: 设备信号强度
@return 无
@note
蓝牙设备搜索结果,可以做名字/地址过滤,也可以保存搜到的所有设备
在选择一个进行连接,获取其他你想要的操作。
返回TRUE,表示搜到指定的想要的设备,搜索结束,直接连接当前设备
返回FALSE,则继续搜索,直到搜索完成或者超时
*/
/*----------------------------------------------------------------------------*/
u8 emitter_search_result(char *name, u8 name_len, u8 *addr, u32 dev_class, char rssi)
{
if (emitter_or_receiver != BT_EMITTER_EN) {
return 0;
}
#if (SEARCH_LIMITED_MODE == SEARCH_BD_NAME_LIMITED)
if (name == NULL) {
struct inquiry_noname_remote *remote = zalloc(sizeof(struct inquiry_noname_remote));
remote->match = 0;
remote->class = dev_class;
remote->rssi = rssi;
memcpy(remote->addr, addr, 6);
os_mutex_pend(&mutex, 0);
list_add_tail(&remote->entry, &inquiry_noname_list);
if (read_name_start == 0) {
read_name_start = 1;
user_send_cmd_prepare(USER_CTRL_READ_REMOTE_NAME, 6, addr);
}
os_mutex_post(&mutex);
}
#endif
#if (SEARCH_LIMITED_MODE == SEARCH_BD_NAME_LIMITED)
return search_bd_name_filt(name, name_len, dev_class, rssi);
#endif
#if (SEARCH_LIMITED_MODE == SEARCH_BD_ADDR_LIMITED)
return search_bd_addr_filt(addr);
#endif
#if (SEARCH_LIMITED_MODE == SEARCH_CUSTOM_LIMITED)
/*以下为搜索结果自定义处理*/
char bt_name[63] = {0};
u8 len;
if (name_len == 0) {
log_i("No_eir\n");
} else {
len = (name_len > 63) ? 63 : name_len;
/* display bd_name */
memcpy(bt_name, name, len);
log_i("name:%s,len:%d,class %x ,rssi %d\n", bt_name, name_len, dev_class, rssi);
}
/* display bd_addr */
put_buf(addr, 6);
/* You can connect the specified bd_addr by below api */
//user_send_cmd_prepare(USER_CTRL_START_CONNEC_VIA_ADDR,6,addr);
return FALSE;
#endif
#if (SEARCH_LIMITED_MODE == SEARCH_NULL_LIMITED)
/*没有指定限制,则搜到什么就连接什么*/
return TRUE;
#endif
}