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关 |
出现正确现象 |