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

  1. CONFIG_BT_NOCONN_ADV_NUM和CONFIG_BT_GATT_SERVER_NUM不能同时配置(有了非链接adv就不要有从机的角色了)

  2. CONFIG_BT_NOCONN_SCAN_NUM和CONFIG_BT_GATT_CLIENT_NUM不能同时配置(有了非连接scan就不要有主机的角色了)

  3. 由于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从机做功能联动)

出现正确现象