3.4.2. APP - Bluetooth Multi connections
3.4.2.1. 概述
Note
ble多连例子,支持2.4g模式,支持状态形态如下:四主,三主一从,二主二从,三从一主,三从+scan,三主+adv…
3.4.2.2. 工程配置
app配置,在工程代码中找到对应的文件(apps/demo/transfer/include/app_config.h)进行APP选择,本案例中选择多连,其结果如下所示:
#define CONFIG_APP_LE_TRANS 0 // LE's slave
#define CONFIG_APP_MULTI 1 //BLE多机应用,支持2.4g code,支持4主,3主1从,2主2从...
#define CONFIG_APP_NONCONN_24G 0 //2.4G 非连接收发
#define CONFIG_APP_DONGLE 0 //usb + 蓝牙(ble 主机),PC hid设备, 使用需要配置板级board_aw31n_dongle.h
#define CONFIG_APP_AT_CHAR_COM 0 //AT com 字符串格式命令
#define CONFIG_APP_IDLE 0 // 空闲任务
apps/demo/transfer/include/app_config.h
如下代码段所示,配置宏解释如下
CONFIG_BLE_CONNECT_SLOT
:低时延配置,如果要使用这种方式需要主从双方都打开此配置,主机将默认使用1ms的interval的连接间隔发起连接CONFIG_BT_NOCONN_ADV_NUM
:多机状态机的非连接adv,最多打开一路CONFIG_BT_NOCONN_SCAN_NUM
:多机状态的非连接scan,最多打开一路CONFIG_BT_GATT_CLIENT_NUM
:主机连接链路数配置,最多打开四路CONFIG_BT_GATT_SERVER_NUM
主机连接链路配置,最多打开四路CFG_USE_24G_CODE_ID_ADV
:打开从机的2.4g功能CFG_USE_24G_CODE_ID_SCAN
:打开主机的2.4g功能
#define CONFIG_BLE_CONNECT_SLOT 0 //BLE高回报率设置, 支持私有协议,所有周期单位为us
#define CONFIG_BT_NOCONN_ADV_NUM 0 //range(0~1)
#define CONFIG_BT_NOCONN_SCAN_NUM 0 //range(0~1)
#define CONFIG_BT_GATT_CLIENT_NUM 1 //range(0~4)
#define CONFIG_BT_GATT_SERVER_NUM 0 //range(0~4)
......
//2.4G模式: 0---ble, 非0---2.4G配对码; !!!主从欲连接,需保持配对码一致
//!!!初始化之后任意非连接时刻修改配对码API:rf_set_conn_24g_coded
#define CFG_USE_24G_CODE_ID_ADV 0
#define CFG_USE_24G_CODE_ID_SCAN 0
#define CFG_RF_24G_CODE_ID_SCAN (0xAF9A9357) //<=24bits 主机扫描2.4G配对码, 可用void access_addr_generate(u8 *aa);生成
#define CFG_RF_24G_CODE_ID_ADV (0xAF9A9357) //<=24bits 从机广播2.4G配对码, 可用void access_addr_generate(u8 *aa);生成
#define CONFIG_BLE_HIGH_SPEED 0 //BLE提速模式: 使能DLE+2M, payload要匹配pdu的包长
由于ram和功能的限制,配置宏的冲突介绍如下:
Warning
CONFIG_BT_NOCONN_ADV_NUM和CONFIG_BT_GATT_SERVER_NUM不能同时配置(有了非链接adv就不要有从机的角色了)
CONFIG_BT_NOCONN_SCAN_NUM和CONFIG_BT_GATT_CLIENT_NUM不能同时配置(有了非连接scan就不要有主机的角色了)
由于ram限制,大于两台状态机就需要关闭低功耗功能(在board_aw32n_demo_cfg.h配置TCFG_LOWPOWER_LOWPOWER_SEL为LOWPOWER_CLOSE),并且目前最多支持四个状态机的存在(主机+从机+adv+scan <= 4)
部分配置例子如下,以此类推,用户可根据自己需要进行配置:
一主一从(产品需要与一台从机连接进行数据交互,并且需要被ble主机/手机连接)
#define CONFIG_BT_NOCONN_ADV_NUM 0 //range(0~1)
#define CONFIG_BT_NOCONN_SCAN_NUM 0 //range(0~1)
#define CONFIG_BT_GATT_CLIENT_NUM 1 //range(0~4)
#define CONFIG_BT_GATT_SERVER_NUM 1 //range(0~4)
一从+scan(产品需要被ble主机/手机连接,并且需要扫描附近的ble设备拿到广播数据)
#define CONFIG_BT_NOCONN_ADV_NUM 0 //range(0~1)
#define CONFIG_BT_NOCONN_SCAN_NUM 1 //range(0~1)
#define CONFIG_BT_GATT_CLIENT_NUM 0 //range(0~4)
#define CONFIG_BT_GATT_SERVER_NUM 1 //range(0~4)
二主二从(产品需要连接两台ble从机,并且需要被两台ble主机连接)
#define CONFIG_BT_NOCONN_ADV_NUM 0 //range(0~1)
#define CONFIG_BT_NOCONN_SCAN_NUM 0 //range(0~1)
#define CONFIG_BT_GATT_CLIENT_NUM 2 //range(0~4)
#define CONFIG_BT_GATT_SERVER_NUM 2 //range(0~4)
板级选择,接着在文件(apps/demo/transfer/board/bd47/board config.h)下进行对应的板级选择如下:
#define CONFIG_BOARD_AW31N_DEMO
#include "board_aw31n_demo_cfg.h"
3.4.2.3. 主要文件代码说明
LE公共处理 ble_multi_conn.c,配置Gatt common模块初始化,蓝牙初始化等操作
LE的GATT server实现 ble_multi_peripheral.c,配置Gatt Server端的广播、连接、事件处理等,和le_trans case工程功能类似,就不重点讲解
LE的GATT client 实现 ble_multi_central.c,配置Gatt Cleint端的搜索、连接、事件处理等
3.4.2.4. ble主机主要代码讲解(ble_multi_central.c)
配置主机连接参数
//连接周期
#if CONFIG_BLE_CONNECT_SLOT
#define BASE_INTERVAL_MIN (1000) // 最小的interval
#define SET_CONN_INTERVAL (BASE_INTERVAL_MIN) //(unit:us)
#else
#define BASE_INTERVAL_MIN (6)//最小的interval
#define SET_CONN_INTERVAL (BASE_INTERVAL_MIN*4) //(unit:1.25ms)
#endif
//连接latency
#define SET_CONN_LATENCY 0 //(unit:conn_interval)
//连接超时
#define SET_CONN_TIMEOUT 400 //(unit:10ms)
//建立连接超时
#define SET_CREAT_CONN_TIMEOUT 8000 //(unit:ms)
指定scan ble从机名字进行主动连接,以及指定的uuid控制,如下代码所示:
//指定搜索uuid
static const target_uuid_t multi_client_search_uuid_table[] = {
// for uuid16
// PRIMARY_SERVICE, ae30
// CHARACTERISTIC, ae01, WRITE_WITHOUT_RESPONSE | DYNAMIC,
// CHARACTERISTIC, ae02, NOTIFY,
{
.services_uuid16 = 0xae30,
.characteristic_uuid16 = 0xae01,
.opt_type = ATT_PROPERTY_WRITE_WITHOUT_RESPONSE,
},
{
.services_uuid16 = 0xae30,
.characteristic_uuid16 = 0xae02,
.opt_type = ATT_PROPERTY_NOTIFY,
},
//for uuid128,sample
// PRIMARY_SERVICE, 0000F530-1212-EFDE-1523-785FEABCD123
// CHARACTERISTIC, 0000F531-1212-EFDE-1523-785FEABCD123, NOTIFY,
// CHARACTERISTIC, 0000F532-1212-EFDE-1523-785FEABCD123, WRITE_WITHOUT_RESPONSE | DYNAMIC,
/*
{
.services_uuid16 = 0,
.services_uuid128 = {0x00,0x00,0xF5,0x30 ,0x12,0x12 ,0xEF, 0xDE ,0x15,0x23 ,0x78,0x5F,0xEA ,0xBC,0xD1,0x23} ,
.characteristic_uuid16 = 0,
.characteristic_uuid128 = {0x00,0x00,0xF5,0x31 ,0x12,0x12 ,0xEF, 0xDE ,0x15,0x23 ,0x78,0x5F,0xEA ,0xBC,0xD1,0x23},
.opt_type = ATT_PROPERTY_NOTIFY,
},
{
.services_uuid16 = 0,
.services_uuid128 = {0x00,0x00,0xF5,0x30 ,0x12,0x12 ,0xEF, 0xDE ,0x15,0x23 ,0x78,0x5F,0xEA ,0xBC,0xD1,0x23} ,
.characteristic_uuid16 = 0,
.characteristic_uuid128 = {0x00,0x00,0xF5,0x32 ,0x12,0x12 ,0xEF, 0xDE ,0x15,0x23 ,0x78,0x5F,0xEA ,0xBC,0xD1,0x23},
.opt_type = ATT_PROPERTY_WRITE_WITHOUT_RESPONSE,
},
*/
};
//配置多个扫描匹配设备
static const uint8_t multi_client_test_remoter_name1[] = "AW31N_BLE";
static const client_match_cfg_t multi_client_match_table[] = {
{
.create_conn_mode = BIT(CLI_CREAT_BY_NAME),
.compare_data_len = sizeof(multi_client_test_remoter_name1) - 1, //去结束符
.compare_data = multi_client_test_remoter_name1,
.filter_pdu_bitmap = 0,
},
};
//配置扫描匹配连接的设备,已经连上后搜索匹配的profile uuid
static const gatt_search_cfg_t multi_client_search_config = {
.match_devices = multi_client_match_table,
.match_devices_count = (sizeof(multi_client_match_table) / sizeof(client_match_cfg_t)),
.match_rssi_enable = 0,
.search_uuid_group = multi_client_search_uuid_table,
.search_uuid_count = (sizeof(multi_client_search_uuid_table) / sizeof(target_uuid_t)),
.auto_enable_ccc = 1,
};
//配置扫描匹配连接绑定后的设备
static gatt_search_cfg_t multi_client_bond_config = {
.match_devices = NULL,
.match_devices_count = 0,
.match_rssi_enable = 0,
.search_uuid_group = multi_client_search_uuid_table,
.search_uuid_count = (sizeof(multi_client_search_uuid_table) / sizeof(target_uuid_t)),
.auto_enable_ccc = 1,
};
在(ble_multi_central.c)中打开MULTI_TEST_WRITE_SEND_DATA使能(数据发送使能):
#define MULTI_TEST_WRITE_SEND_DATA 1 \ *//测试发数
连接从机之后,可以通过按键来发送ble数据来控制从机,下图为测试发送接口:
static void multi_client_write_data(uint8_t *data, uint16_t send_len)
{
#if MULTI_TEST_WRITE_SEND_DATA
int i, ret = 0;
uint16_t tmp_handle;
for (i = 0; i < SUPPORT_MAX_GATT_CLIENT; i++) {
tmp_handle = ble_comm_dev_get_handle(i, GATT_ROLE_CLIENT);
if (ble_comm_att_check_send(tmp_handle, send_len)) {
ret = ble_comm_att_send_data(tmp_handle, multi_client_write_handle, data, send_len, ATT_OP_WRITE_WITHOUT_RESPOND);
}
}
#endif
}
按键发送数据,搭配le_trans case ble从机测试,完成连接后,按键发送数据控制从机led灯亮灭(单击k1 led1亮,双击灭,单击k2 led3亮,双击灭)
void multi_client_key_test(uint8_t key_type, uint8_t key_value)
{
// ble主从通信test,
// k1单击亮led1,k1双击灭led1
// k2单机亮led2,k2双击灭led2
on_off_opcode_t on_off_opcode;
log_info(">>>>>>>>>>cetl_client_app key test");
on_off_opcode.led_opcode = LED_ON_OFF_OPCODE;
if (key_value == TCFG_ADKEY_VALUE0) {
on_off_opcode.led_num = LED1;
on_off_opcode.led_status = (key_type == KEY_EVENT_CLICK) ? LED_ON_STATUS : LED_OFF_STATUS;
} else if (key_value == TCFG_ADKEY_VALUE1) {
on_off_opcode.led_num = LED2;
on_off_opcode.led_status = (key_type == KEY_EVENT_CLICK) ? LED_ON_STATUS : LED_OFF_STATUS;
}
if (key_type == KEY_EVENT_DOUBLE_CLICK) {
on_off_opcode.led_status = LED_OFF_STATUS;
}
multi_client_write_data(&on_off_opcode, sizeof(on_off_opcode_t));
}
3.4.2.5. ble scan主要代码讲解
apps/demo/transfer/examples/multi_conn/ble_multi_scan.c
/*************************************************************************************************/
/*!
* \brief 扫描接收到的数据
*
* \param [in]
*
* \return
*
* \note
*/
/*************************************************************************************************/
static void multi_scan_data_handle(const uint8_t *data, uint16_t len)
{
log_info("rx_data: %d", len);
log_info_hexdump((uint8_t *)data, len);
}
/*************************************************************************************************/
/*!
* \brief 接收机数据处理回调
*
* \param [in]
*
* \return
*
* \note
*/
/*************************************************************************************************/
void multi_scan_report_handle(adv_report_t *report_pt, uint16_t len)
{
/* log_info("event_type,addr_type:%x,%x\n", report_pt->event_type, report_pt->address_type); */
/* log_info_hexdump(report_pt->address, 6); */
static uint32_t scan_packet_num = 0;//for test
/* r_printf("rx data:%d",report_pt->length); */
/* put_buf(report_pt->data,report_pt->length); */
if (report_pt == NULL) {
return;
}
if (0 == report_pt->length) {
return;
}
uint8_t data_len = report_pt->length - 1;
if (!data_len) {
return;
}
if (report_pt->data[0] == RSP_TX_HEAD) {
memcpy(&multi_scan_buffer[ADV_RSP_PACKET_MAX - 1], &report_pt->data[1], data_len);
log_info("long_packet =%d\n", multi_scan_len);
} else {
memcpy(multi_scan_buffer, &report_pt->data[1], data_len);
multi_scan_len = report_pt->data[0];
if (multi_scan_len > ADV_RSP_PACKET_MAX - 1) {
log_info("first_packet =%d,wait next packet\n", data_len);
return;
} else {
/* log_info("short_packet =%d\n", multi_scan_len); */
}
}
//for debug
#if MULTI_SCAN_LOG_ENABLE
log_info("rssi:%d,packet_num:%u\n", report_pt->rssi, ++scan_packet_num);
multi_scan_data_handle(multi_scan_buffer, multi_scan_len);
#endif
multi_scan_len = 0;
}
3.4.2.6. case默认应用资源(默认使用AW31N DEMO开发板)
Note
demo默认占用外设资源如下,具体可以查看board_aw31n_demo_cfg.h
I/O口占用情况
PA口 I/O |
默认占用情况 |
---|---|
PA3 |
默认打印UART0引脚 |
PA8 |
adkey检测引脚 |
PA9 |
LED控制引脚 |
硬件定时器占用情况
定时器 |
默认占用情况 |
---|---|
TIMER0 |
暂无使用 |
TIMER1 |
暂无使用 |
TIMER2 |
暂无使用 |
TIMER3 |
暂无使用 |
串口占用情况
串口 |
默认占用情况 |
---|---|
UART0 |
SDK打印 |
UART1 |
暂无使用 |
UART2 |
暂无使用 |
3.4.2.7. case默认应用功能现象
(默认使用AW31N DEMO开发板 LED1-PA9 LED2-PA10(开启LED2宏) ADKEY-PA8) 需与TRANSFER BLE从机联动功能测试 (默认ble主机功能即CONFIG_BT_GATT_CLIENT_NUM选择1)
操作 |
现象结果 |
---|---|
扫描scan功能,上电会自动连接上ble从机 |
能够连接并且进行ble数据传输 |
ble主从数据 传输led控制(见BLE从机应用UART功能) |
应用UART功能 |
K1按三下软关机 |
出现正确现象 |
K1单击:控制ble 从机LED1开(需要与BLE从机做功能联动) |
出现正确现象 |
K1双击:控制ble 从机LED1关(需要与BLE从机做功能联动) |
出现正确现象 |
K2单击:控制 对方LED2开(需要与BLE从机做功能联动) |
出现正确现象 |
K2双击:控制 对方LED2关(需要与BLE从机做功能联动) |
出现正确现象 |