3.4.1. APP - TRANSFER

3.4.1.1. 概述

  • 支持BLE蓝牙透传传输功能。BLE蓝牙使用自定义的profile协议,提供ATT的WRITE、WRITE_WITHOUT_RESPONSE,NOTIFY和INDICATE等属性传输收发数据。

  • 增加了ble2uart或者uart2ble功能,其中uart2ble功能需要不开低功耗去完成

3.4.1.2. 工程配置

  • 先配置板级board_config.h

#ifndef BOARD_CONFIG_H
#define BOARD_CONFIG_H

#define CONFIG_BOARD_AW31N_DEMO

#include "board_aw31n_demo_cfg.h"


#endif

(2)配置app选择:“app_config.h”

//apps example 选择,只能选1个,要配置对应的board_config.h
#define CONFIG_APP_LE_TRANS               1 // LE's slave
#define CONFIG_APP_MULTI                  0 //蓝牙LE多连 支持2.4g code
#define CONFIG_APP_NONCONN_24G            0 //2.4G 非连接收发
#define CONFIG_APP_IDLE                   0 // 空闲任务 todo
#define CONFIG_APP_DONGLE                 0 //usb + 蓝牙(ble 主机),PC hid设备  目前USB仅支持单设备 todo

(3)蓝牙的BLE配置,保护GATT和SM的配置

*//蓝牙BLE配置*
#define CONFIG_BT_GATT_COMMON_ENABLE       1 \ *//配置使用gatt公共模块*
#define CONFIG_BT_SM_SUPPORT_ENABLE        0 \ *//配置是否支持加密*
#define CONFIG_BT_GATT_CLIENT_NUM          0 \ *//配置主机client个数 (app not support)*
#define CONFIG_BT_GATT_SERVER_NUM          1 \ *//配置从机server个数*
#define CONFIG_BT_GATT_CONNECTION_NUM      (CONFIG_BT_GATT_SERVER_NUM + CONFIG_BT_GATT_CLIENT_NUM) \ *//配置连接个数*

3.4.1.3. 数据通信

  • 推荐使用手机测试工具:“nRF Connect”

  • 代码文件ble_trans.c

  • Profile生成的trans_profile_data数据表放在ble_trans_profile.h。用户可用工具make_gatt_services(sdk的tools目录下)按照“make_gatt_services工具说明.pdf”自定义修改,重新配置GATT服务和属性等。

//////////////////////////////////////////////////////
//
// 0x0001 PRIMARY_SERVICE  1800
//
//////////////////////////////////////////////////////
0x0a, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x28, 0x00, 0x18,

/* CHARACTERISTIC,  2a00, READ | WRITE | DYNAMIC, */
// 0x0002 CHARACTERISTIC 2a00 READ | WRITE | DYNAMIC

0x0d, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x28, 0x0a, 0x03, 0x00, 0x00, 0x2a,
// 0x0003 VALUE 2a00 READ | WRITE | DYNAMIC
0x08, 0x00, 0x0a, 0x01, 0x03, 0x00, 0x00, 0x2a,

//////////////////////////////////////////////////////
//
// 0x0004 PRIMARY_SERVICE  ae30
//
//////////////////////////////////////////////////////
0x0a, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x28, 0x30, 0xae,

/* CHARACTERISTIC,  ae01, WRITE_WITHOUT_RESPONSE | DYNAMIC, */
// 0x0005 CHARACTERISTIC ae01 WRITE_WITHOUT_RESPONSE | DYNAMIC
0x0d, 0x00, 0x02, 0x00, 0x05, 0x00, 0x03, 0x28, 0x04, 0x06, 0x00, 0x01, 0xae,
// 0x0006 VALUE ae01 WRITE_WITHOUT_RESPONSE | DYNAMIC
0x08, 0x00, 0x04, 0x01, 0x06, 0x00, 0x01, 0xae,
  • 接口说明:“ble_trans.c”

  • 配置广播ADV数据

static int trans_make_set_adv_data(void)
  • 配置广播RESPONE数据

static int trans_make_set_rsp_data(void)
  • 配置发送缓存大小

// ATT发送的包长,    note: 23 <=need >= MTU
#define ATT_LOCAL_MTU_SIZE        (64) /*一般是主机发起交换,如果主机没有发起,设备端也可以主动发起(ATT_MTU_REQUEST_ENALBE set 1)*/

//ATT缓存的buffer支持缓存数据包个数
#define ATT_PACKET_NUMS_MAX       (2)

//ATT缓存的buffer大小,  note: need >= 23,可修改
#define ATT_SEND_CBUF_SIZE        (ATT_PACKET_NUMS_MAX * (ATT_PACKET_HEAD_SIZE + ATT_LOCAL_MTU_SIZE))
  • 协议栈事件回调处理,主要是连接、断开等事件:“ble_trans.c”

/*************************************************************************************************/
/*!
*  \brief      处理gatt 返回的事件(hci && gatt)
*
*  \param      [in]
*
*  \return
*
*  \note
*/
/*************************************************************************************************/
static int trans_event_packet_handler(int event, uint8_t *packet, uint16_t size, uint8_t *ext_param)
{
        /* log_info("event: %02x,size= %d\n",event,size); */
        switch (event) {
        case GATT_COMM_EVENT_CAN_SEND_NOW:
                break;

        case GATT_COMM_EVENT_SERVER_INDICATION_COMPLETE:
                log_info("INDICATION_COMPLETE:con_handle= %04x,att_handle= %04x\n", \
                                little_endian_read_16(packet, 0), little_endian_read_16(packet, 2));
                break;


        case GATT_COMM_EVENT_CONNECTION_COMPLETE:
#if TCFG_LED_ENABLE
                led_set_connect_flag(1);
                // 完成连接灭灯
                led_operate(LED_CLOSE);
#endif
                trans_con_handle = little_endian_read_16(packet, 0);
                trans_connection_update_enable = 1;

                log_info("connection_handle:%04x\n", little_endian_read_16(packet, 0));
                log_info("connection_handle:%04x, rssi= %d\n", trans_con_handle, ble_vendor_get_peer_rssi(trans_con_handle));
                log_info("peer_address_info:");
                log_info_hexdump(&ext_param[7], 7);

                log_info("con_interval = %d\n", little_endian_read_16(ext_param, 14 + 0));
                log_info("con_latency = %d\n", little_endian_read_16(ext_param, 14 + 2));
                log_info("cnn_timeout = %d\n", little_endian_read_16(ext_param, 14 + 4));

#if ATT_MTU_REQUEST_ENALBE
                att_server_set_exchange_mtu(trans_con_handle);/*主动请求MTU长度交换*/
#endif

#if TCFG_COMMON_UART_ENABLE
                //注册串口传输数据回调,串口数据直通到蓝牙
                common_uart_regiest_receive_callback(trans_uart_rx_to_ble);
#endif

#if ATT_CHECK_REMOTE_REQUEST_ENALBE
                att_server_set_check_remote(trans_con_handle, trans_check_remote_result);
#endif
                break;

        case GATT_COMM_EVENT_DISCONNECT_COMPLETE:
#if TCFG_LED_ENABLE
                led_set_connect_flag(0);
                led_operate(LED_WAIT_CONNECT);
#endif
                log_info("disconnect_handle:%04x,reason= %02x\n", little_endian_read_16(packet, 0), packet[2]);
                if (trans_con_handle == little_endian_read_16(packet, 0)) {
#if CONFIG_BT_GATT_CLIENT_NUM
                        trans_client_search_remote_stop(trans_con_handle);
#endif
                        trans_con_handle = 0;
                }
                break;

        case GATT_COMM_EVENT_ENCRYPTION_CHANGE:
                log_info("ENCRYPTION_CHANGE:handle=%04x,state=%d,process =%d", little_endian_read_16(packet, 0), packet[2], packet[3]);
                if (packet[3] == LINK_ENCRYPTION_RECONNECT) {
                        trans_resume_all_ccc_enable(little_endian_read_16(packet, 0), 1);
                }
                break;

        case GATT_COMM_EVENT_CONNECTION_UPDATE_COMPLETE:
                log_info("conn_param update_complete:%04x\n", little_endian_read_16(packet, 0));
                log_info("update_interval = %d\n", little_endian_read_16(ext_param, 6 + 0));
                log_info("update_latency = %d\n", little_endian_read_16(ext_param, 6 + 2));
                log_info("update_timeout = %d\n", little_endian_read_16(ext_param, 6 + 4));
                break;

        case GATT_COMM_EVENT_CONNECTION_UPDATE_REQUEST_RESULT:
                break;

        case GATT_COMM_EVENT_MTU_EXCHANGE_COMPLETE:
                log_info("con_handle= %02x, ATT MTU = %u\n", little_endian_read_16(packet, 0), little_endian_read_16(packet, 2));
                break;

        case GATT_COMM_EVENT_SERVER_STATE:
                log_info("server_state: handle=%02x,%02x\n", little_endian_read_16(packet, 1), packet[0]);
                break;

        case GATT_COMM_EVENT_SM_PASSKEY_INPUT: {
                uint32_t key = little_endian_read_32(packet, 2);
                r_printf("input_key:%6u\n", key);
        }
        break;

        default:
                break;
        }
        return 0;
}
  • ATT读事件处理:“ble_trans.c”

static uint16_t trans_att_read_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t offset, uint8_t *buffer, uint16_t buffer_size)
{
        uint16_t  att_value_len = 0;
        uint16_t handle = att_handle;

        log_info("read_callback,conn_handle =%04x, handle=%04x,buffer=%08x\n", connection_handle, handle, (uint32_t)buffer);

        switch (handle) {
        case ATT_CHARACTERISTIC_2a00_01_VALUE_HANDLE: {
                const char *gap_name = ble_comm_get_gap_name();
                att_value_len = strlen(gap_name);

                if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) {
                        break;
                }

                if (buffer) {
                        memcpy(buffer, &gap_name[offset], buffer_size);
                        att_value_len = buffer_size;
                        log_info("\n------read gap_name: %s\n", gap_name);
                }
        }
        break;

        case ATT_CHARACTERISTIC_ae10_01_VALUE_HANDLE:
                att_value_len = sizeof(trans_test_read_write_buf);
                if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) {
                        break;
                }

                if (buffer) {
                        memcpy(buffer, &trans_test_read_write_buf[offset], buffer_size);
                        att_value_len = buffer_size;
                }
                break;

        case ATT_CHARACTERISTIC_ae04_01_CLIENT_CONFIGURATION_HANDLE:
        case ATT_CHARACTERISTIC_ae02_01_CLIENT_CONFIGURATION_HANDLE:
        case ATT_CHARACTERISTIC_ae05_01_CLIENT_CONFIGURATION_HANDLE:
        case ATT_CHARACTERISTIC_ae3c_01_CLIENT_CONFIGURATION_HANDLE:
        case ATT_CHARACTERISTIC_2a05_01_CLIENT_CONFIGURATION_HANDLE:
                if (buffer) {
                        buffer[0] = ble_gatt_server_characteristic_ccc_get(connection_handle, handle);
                        buffer[1] = 0;
                }
                att_value_len = 2;
                break;

        case ATT_CHARACTERISTIC_2a50_01_VALUE_HANDLE:
                log_info("read PnP_ID\n");
                att_value_len = sizeof(trans_PNP_ID);
                if ((offset >= att_value_len) || (offset + buffer_size) > att_value_len) {
                        break;
                }
                if (buffer) {
                        memcpy(buffer, &trans_PNP_ID[offset], buffer_size);
                        att_value_len = buffer_size;
                }
                break;

        default:
                break;
        }

        log_info("att_value_len= %d\n", att_value_len);
        return att_value_len;
        }
  • ATT写事件处理:“ble_trans.c”

        static int trans_att_write_callback(hci_con_handle_t connection_handle, uint16_t att_handle, uint16_t transaction_mode, uint16_t offset, uint8_t *buffer, uint16_t buffer_size)
{
        int result = 0;
        uint16_t tmp16;
        uint16_t handle = att_handle;

#if !TEST_TRANS_CHANNEL_DATA
        log_info("write_callback,conn_handle =%04x, handle =%04x,size =%d\n", connection_handle, handle, buffer_size);
#endif

        switch (handle) {

        case ATT_CHARACTERISTIC_2a00_01_VALUE_HANDLE:
                break;

        case ATT_CHARACTERISTIC_ae02_01_CLIENT_CONFIGURATION_HANDLE:
        case ATT_CHARACTERISTIC_ae04_01_CLIENT_CONFIGURATION_HANDLE:
        case ATT_CHARACTERISTIC_ae05_01_CLIENT_CONFIGURATION_HANDLE:
        case ATT_CHARACTERISTIC_ae3c_01_CLIENT_CONFIGURATION_HANDLE:
        case ATT_CHARACTERISTIC_2a05_01_CLIENT_CONFIGURATION_HANDLE:
                trans_send_connetion_updata_deal(connection_handle);
                log_info("\n------write ccc:%04x,%02x\n", handle, buffer[0]);
                ble_gatt_server_characteristic_ccc_set(connection_handle, handle, buffer[0]);
                break;

        case ATT_CHARACTERISTIC_ae10_01_VALUE_HANDLE:
                tmp16 = sizeof(trans_test_read_write_buf);
                if ((offset >= tmp16) || (offset + buffer_size) > tmp16) {
                        break;
                }
                memcpy(&trans_test_read_write_buf[offset], buffer, buffer_size);
                log_info("\n-ae10_rx(%d):", buffer_size);
                log_info_hexdump(buffer, buffer_size);
                break;

        case ATT_CHARACTERISTIC_ae01_01_VALUE_HANDLE:

#if TEST_TRANS_CHANNEL_DATA
                /* putchar('R'); */
                trans_recieve_test_count += buffer_size;
                break;
#endif

                log_info("\n-ae01_rx(%d):", buffer_size);
                log_info_hexdump(buffer, buffer_size);

#if TCFG_COMMON_UART_ENABLE
                // ble数据直通串口
                common_uart_send_data(buffer, buffer_size);
#endif

                // test主从连接数据控制
#if BLE_SLAVE_CLIENT_LED_OP_EN
                on_off_opcode_t *op = (on_off_opcode_t *)buffer;
                led_onoff_op(op);
#endif

                /* // 收发测试,自动发送收到的数据;for test */
                /* if (ble_comm_att_check_send(connection_handle, buffer_size) && */
                /*         ble_gatt_server_characteristic_ccc_get(trans_con_handle, ATT_CHARACTERISTIC_ae02_01_CLIENT_CONFIGURATION_HANDLE)) { */
                /*     log_info("-loop send1\n"); */
                /*     ble_comm_att_send_data(connection_handle, ATT_CHARACTERISTIC_ae02_01_VALUE_HANDLE, buffer, buffer_size, ATT_OP_AUTO_READ_CCC); */
                /* } */
                break;

        case ATT_CHARACTERISTIC_ae03_01_VALUE_HANDLE:
                log_info("\n-ae03_rx(%d):", buffer_size);
                log_info_hexdump(buffer, buffer_size);

                //收发测试,自动发送收到的数据;for test
                if (ble_comm_att_check_send(connection_handle, buffer_size) && \
                        ble_gatt_server_characteristic_ccc_get(trans_con_handle, ATT_CHARACTERISTIC_ae05_01_CLIENT_CONFIGURATION_HANDLE)) {
                        log_info("-loop send2\n");
                        ble_comm_att_send_data(connection_handle, ATT_CHARACTERISTIC_ae05_01_VALUE_HANDLE, buffer, buffer_size, ATT_OP_AUTO_READ_CCC);
                }
                break;

#if RCSP_BTMATE_EN
        case ATT_CHARACTERISTIC_ae02_02_CLIENT_CONFIGURATION_HANDLE:
                ble_op_latency_skip(connection_handle, 0xffff); //
                ble_gatt_server_set_update_send(connection_handle, ATT_CHARACTERISTIC_ae02_02_VALUE_HANDLE, ATT_OP_AUTO_READ_CCC);
#endif
                /* trans_send_connetion_updata_deal(connection_handle); */
                log_info("------write ccc:%04x,%02x\n", handle, buffer[0]);
                ble_gatt_server_characteristic_ccc_set(connection_handle, handle, buffer[0]);
                break;

#if RCSP_BTMATE_EN
        case ATT_CHARACTERISTIC_ae01_02_VALUE_HANDLE:
                log_info("rcsp_read:%x\n", buffer_size);
                ble_gatt_server_receive_update_data(NULL, buffer, buffer_size);
                break;
#endif

        case ATT_CHARACTERISTIC_ae3b_01_VALUE_HANDLE:
                log_info("\n-ae3b_rx(%d):", buffer_size);
                log_info_hexdump(buffer, buffer_size);
                break;

        default:
                break;
        }
        return 0;
}
  • 检查是否可以往协议栈发送数据

*//收发测试,自动发送收到的数据;for test*
if (ble_comm_att_check_send(connection_handle, buffer_size)) {
xxx
}
  • 发送完成回调,表示可以继续往协议栈发数,用来触发继续发数

    case GATT_COMM_EVENT_CAN_SEND_NOW:
#if TEST_AUDIO_DATA_UPLOAD
        trans_test_send_audio_data(0);
#endif
        break;
  • 收发测试:“ble_trans.c”

  • 使用手机NRF软件,连接设备后;使能notify和indicate的UUID (AE02 和 AE05) 的通知功能后;可以通过向write的UUID (AE01 或 AE03) 发送数据;测试UUID (AE02 或 AE05)是否收到数据。

case ATT_CHARACTERISTIC_ae01_01_VALUE_HANDLE:
    log_info("\n-ae01_rx(%d):", buffer_size);
    put_buf(buffer, buffer_size);
    *//收发测试,自动发送收到的数据;for test*
    if (ble_comm_att_check_send(connection_handle, buffer_size)) {
        log_info("-loop send1\n");
        ble_comm_att_send_data(connection_handle, ATT_CHARACTERISTIC_ae02_01_VALUE_HANDLE, buffer, buffer_size, ATT_OP_AUTO_READ_CCC);
    }
        break;

case ATT_CHARACTERISTIC_ae03_01_VALUE_HANDLE:
        log_info("\n-ae_rx(%d):", buffer_size);
        put_buf(buffer, buffer_size);

        *//收发测试,自动发送收到的数据;for test*
        if (ble_comm_att_check_send(connection_handle, buffer_size)) {
                log_info("-loop send2\n");
                ble_comm_att_send_data(connection_handle, ATT_CHARACTERISTIC_ae05_01_VALUE_HANDLE, buffer, buffer_size, ATT_OP_AUTO_READ_CCC);
        }
        break;
  • ble2uart功能,uart2ble功能(需要打开TCFG_COMMON_UART_ENABLE宏)

    • 通用串口初始化(app_trans.c)

    // 配置一个通用串口做ble2uart or uart2ble
    #if TCFG_COMMON_UART_ENABLE
            common_uart_init(TCFG_COMMON_UART_BAUDRATE, COMMON_UART_TX_PIN, COMMON_UART_RX_PIN);
    #endif
    
    • 串口数据回调注册(ble_trans.c) uart2ble

    #if TCFG_COMMON_UART_ENABLE
            //注册串口传输数据回调,串口数据直通到蓝牙,串口内部调用
            common_uart_regiest_receive_callback(trans_uart_rx_to_ble);
    #endif
    
    • ble数据直通串口(ble_trans.c) ble2uart

    #if TCFG_COMMON_UART_ENABLE
            // ble数据直通串口
            common_uart_send_data(buffer, buffer_size);
    #endif
    

3.4.1.4. case默认应用资源(默认使用AW31N DEMO开发板)

Note

demo默认占用外设资源如下,具体可以查看board_aw31n_demo_cfg.h

I/O口占用情况

PA口 I/O

默认占用情况

PA3

默认打印UART0引脚

PA6

ble转串口功能引脚(如果开启)

PA8

adkey检测引脚

PA9

LED控制引脚

硬件定时器占用情况

定时器

默认占用情况

TIMER0

暂无使用

TIMER1

暂无使用

TIMER2

暂无使用

TIMER3

暂无使用

串口占用情况

串口

默认占用情况

UART0

SDK打印

UART1

BLE转串口功能引脚(如果开启)

UART2

暂无使用

3.4.1.5. case默认应用功能现象

(默认使用AW31N DEMO开发板 LED1-PA9 LED2-PA10(开启LED2宏) ADKEY-PA8)

操作

现象结果

连接,使用nrf连接 搜索,name为AW31N,进行连接操作

nrf能 够成功扫描到广播并成功连接不断开

k1三击:软关机,进入 软关机后任意按键从软关机唤醒设备

正确进入软关机

ble未连接闪亮

出现正确现象

ble连上后灭

出现正确现象

有按键按下闪亮后灭

出现正确现象

低 电连续快速闪亮(250ms),50s后进 入软关机(和应用电源功能相对应)

出现正确灯现象,正确进入软关机

BLE转UART功能 ,NRF连接从机,PA6接强制升级工具 RX引脚,打开串口软件(波特率100 0000),选择0xAE30服务,使用0xAE 01特性发送数据,串口助手软件能够 正确的接收到手机nrf发送的ble数据

串口助手软件能够 正确的接收到手机nrf收到的ble数据

UATR转BLE功能功能 (需要与BLE主机做功能联动),PA6 接强制升级工具TX引脚,使用串口软 件发送灯控数据(波特率1000000) (需ble从机不开低功耗版本测试) 1. 发送660101控制ble主机led1开 2. 发送660100控制ble主机led1关 3. 发送660201控制ble主机led2开 4. 发送660200控制ble主机led2关

出现正确现象