一,背景
1,基于Window开发蓝牙的需求较为迫切,且需要基于Windows的蓝牙能力应用于生产,工控设备控制以及设备交互等。
2,基于Windows开发蓝牙存在很多弊端以及门槛,相对于上位机开发工程师而言,嵌入式软件工程师长期与蓝牙设备开发打交道,对蓝牙较为熟悉,所以衍生出来通过嵌入式开发底层接口,上位机开发UI等实现方式。
二、设计思路
1,模型框图
2,具体设计
硬件设计方案来自:Nordic52832
三、具体代码分析
如上设计,具体代码分为三部分:设备端固件、Windows PC Host驱动库、Windows应用逻辑(对上为库)
1,设备端固件
设备采用的是:Nordic52832小板,裸模块+串口CH340串口
参考设备驱动固件源码为NRF SDK15.3 + 适配PATCH(nRF5_SDK_15.3.0_connectivity.patch)
SDK源码可在官网获取,这里附上PATCH地址:https://github.com/NordicSemiconductor/pc-ble-driver/tree/master/hex
1.1,本地RAM设定
由于需要打一部分log,把设备端应用程序的ram拉大了,这里如果非调式阶段,可以把应用程序RAM设定小一点,尽可能把RAMA给协议栈使用。(例如:RAM_START=0x2000ab20;RAM_SIZE=0x54e0)
1.2,源码分析
中间层映射表:
这里仅仅需关心使用的那部分,毕竟接口太多,感兴趣可以深入了解。
1.3,编译固件
1. Apply PATCH:
git apply nRF5_SDK_15.3.0_connectivity.patch --ignore-whitespace
2. Compile the \nRF5_SDK_15.3.0_59ac345\examples\connectivity\ble_connectivity\pca10040\ser_s132v3_hci\ with armgcc or ses — NRF52832 DK
编译结果:(这里做了ram分配,协议栈可使用更大)
2,Windows PC Host驱动库
2.1 涉及源码部分
之所以用Microsoft Visual Studio,便于可视化编译Windows依赖库以及避免繁琐的脚本工具安装。
大致源码如下:
注:这里需要注意添加宏定义,否则编译会过不了。
// 宏定义:
NRF_SD_BLE_API_VERSION=6
_CRT_SECURE_NO_WARNINGS
ASIO_STANDALONE
SD_RPC_EXPORTS
HCI_LINK_CONTROL
_WIN32_WINNT=0x0501
如果编译部分存在疑惑可在我的资源部分下载,放到pc-ble-driver源码中+重新添加你所需的头文件地址即可。
2.2 部分源码分析
设定COM口以及波特率:
底层用C++实现逻辑,具体编解码部分没啥深入意义,不做详述。
这里需要注意一个关键点:open rpc module的时候需要注册ble事件,类似于添加一个observer,当前可添加一个,如需多个observer,需自定义在函数内控制。(可控)
3,Windows应用逻辑(向上为静态库,属协议部分)
目前可提供ble slave以及ble master多设备控制,slave较为简单,我们以ble master深入应用
3.1 初始化注意事项
这里需要注意一个非常关键的点:设定最大对端设备数量,否则无法多设备连接以及控制。
// 设定最大对端设备连接数量由BLE_CONN_CFG_GAP控制
// 设定最大对端设备GATT PDU由BLE_CONN_CFG_GATT控制
// 注:这里的ram start是虚的,没意义
memset(&ble_cfg, 0x00, sizeof(ble_cfg));
ble_cfg.conn_cfg.conn_cfg_tag = conn_cfg_tag;
ble_cfg.conn_cfg.params.gap_conn_cfg.conn_count = MAX_PEER_COUNT; // 4
ble_cfg.conn_cfg.params.gap_conn_cfg.event_length = BLE_GAP_EVENT_LENGTH_DEFAULT;
error_code = sd_ble_cfg_set(ble_port_adapter, BLE_CONN_CFG_GAP, &ble_cfg, ram_start);
if (error_code != NRF_SUCCESS)
{
printf("sd_ble_cfg_set() failed when attempting to set BLE_CONN_CFG_GAP. Error code: 0x%02X\n", error_code);
return error_code;
}
memset(&ble_cfg, 0x00, sizeof(ble_cfg));
ble_cfg.conn_cfg.conn_cfg_tag = conn_cfg_tag;
ble_cfg.conn_cfg.params.gatt_conn_cfg.att_mtu = 247; // This is CFG_GATT configuration
error_code = sd_ble_cfg_set(ble_port_adapter, BLE_CONN_CFG_GATT, &ble_cfg, ram_start);
if (error_code != NRF_SUCCESS)
{
printf("sd_ble_cfg_set() returned %s when attempting to set BLE_CONN_CFG_GATT.",
error_code);
}
3.2 扫描注意事项
如果需要接收扫描scan response,需要使能对应扫描标志,否则你接收的到永远都是adv data,没有rsp data:
同时注意接收端判定adv or rsp的标志:
3.2 设备连接注意事项
由于这里会对不同service uuid的设备进行连接,故每次连接成功后我们需要检索对应uuid:
同样的获取对应特征值的handle也需要多次判断:
最后便是cccd handle了,一个service下对应一个,这个没必要多次检索了
3.4 设备透传
if(ble_conn_state_status(m_tuya_ble_c[i].conn_handle) != BLE_CONN_STATUS_CONNECTED) {
printf("Current Device status: %d\n", ble_conn_state_status(m_ble_c[i].conn_handle));
return -2;
}
ble_gattc_write_params_t write_params;
write_params.handle = m_tuya_ble_c[i].tuya_tx_handle;
write_params.len = data_len;
write_params.p_value = p_data;
write_params.write_op = BLE_GATT_OP_WRITE_CMD;
write_params.flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE,
write_params.offset = 0;
err_code = sd_ble_gattc_write(ble_port_adapter, m_tuya_ble_c[i].conn_handle, &write_params);
四、实现效果
1, 验证扫描结果
2, 连接多设备并透传
主动连接设备:
数据发送以及接收:
断开设备: