这年头协议栈开源的太多了,掌握基础蓝牙协议栈作为嵌入式软件工程师的进阶技能。如果有了解并应用的市面上大部分蓝牙芯片,不妨看看如下内容,对于理解并提升蓝牙协议了解有一定帮助。
本次文章主要说明如何去学习蓝牙Host协议栈,controller协议栈仅做参考。(conrtoller涉及PHY层,除非原厂深入,一般我们仅作了解)
上官方链接:https://mynewt.apache.org/
上Github链接:https://github.com/apache/mynewt-nimble
Apache Mynewt是一个开源项目,其中Mynewt Nimble是开源5.1蓝牙协议栈,包含host&controller协议栈,可完全替代nordic softdevice(跟zephyr一样的)。
网上开源协议栈很多,诸如:btstack,bluez,zephyr等等,但是Nimble属轻量级LE Host协议栈,对于初次了解协议栈的朋友非常友好。
官方介绍:
NimBLE complies with Bluetooth Core Specification 5.0 which makes it an ideal wireless technology for the Internet of Things (IoT).
LE Advertising Extensions
2Msym/s PHY for higher throughput
Coded PHY for LE Long Range
High Duty Cycle Non-Connectable Advertising
Channel Selection Algorithm #2 to utilize channels in more efficient way.
LE Privacy 1.2 for frequent changes to the device address to make it difficult to track for outsiders
LE Secure Connections featuring FIPS-compliant algorithms.
LE Data Length Extension for higher throughput
Coming Soon: Assigning an Internet Protocol (IP) address (compliant with the IPv6 or 6LoWPAN standard) to a Bluetooth device through Internet Protocol Support Profile (IPSP)
The Bluetooth 5 is backward compatible with previous Bluetooth version 4.2 which is also supported by Apache Mynewt.
本次主要验证如何跑通Host协议栈以及对应源码的简单介绍。
关于Host的支持项如下:
Host
Logical Link Control and Adaptation Protocol (L2CAP): provides logical channels, named L2CAP channels, which are multiplexed over one or more logical links to provide packet segmentation and reassembly, flow control, error control, streaming, QoS etc.
Security Manager (SM): uses Security Manager Protocol (SMP) for pairing and transport specific key distribution for securing radio communication
Attribute protocol (ATT): allows a device (Server) to expose certain pieces of data, known as Attributes, to another device (Client)
Generic Attribute Profile (GATT): a framework for using the ATT protocol to exchange attributes encapsulated as Characteristics or Services
Generic Access Profile (GAP): a base profile which all Bluetooth devices implement, which in the case of LE, defines the Physical Layer, Link Layer, L2CAP, Security Manager, Attribute Protocol and Generic Attribute Profile.
Host Controller Interface (HCI): the interface between the host and controller either through software API or by a hardware interface such as SPI, UART or USB.
对于一个Linux子设备,如IPC或者网关蓝牙配网提供wifi ssid/token等等,一份简单的host协议栈即可满足需求。(且可配置无需依赖linux kernel)
(1)下载源码:
git clone https://github.com/apache/mynewt-nimble
(2)编译源码:
root@ubuntu:/home/timcheng/project/mynewt-nimble-latest# cd porting/examples/linux/
// 默认工具链为GCC,本次编译环境为Ubuntu 16.04
root@ubuntu:/home/timcheng/project/mynewt-nimble-latest/porting/examples/linux# make
// 生成一个nimble-linux的可执行文件
root@ubuntu:/home/timcheng/project/mynewt-nimble-latest/porting/examples/linux# ls
ble.c ble.o include main.c main.o Makefile nimble-linux README.md
// 直接执行即可。
// 需说明:由于采用的是HCI SOCKET形式与设备交互,所以如果没有安装驱动需单独安装驱动。
//如果采用市面上的realtk dongle直插,需重新加载驱动,具体如何安装驱动以及驱动程序在我的附件中。
(3)关于蓝牙服务说明:
默认服务还是蛮多的,如果需要添加自己的vendor service,可按照任意一个的服务初始化添加即可,比较简单。同时需注释掉如下服务。
(4)关于HCI Socket说明:
索引地址:nimble\transport\socket\src\ble_hci_socket.c
由于直接在ubuntu上编译且不依赖Apache Mynewt框架,所以可以选择性浏览一些代码。hci实现形式非常多,对于前期理解可先易后难。
协议栈分层已经是基础了,我们剖析中间每一层去理解更为深刻。Apache Mynewt Nimble完全按照L2CAP->ATT/SM->GATT Server/Client以及GAP分层。注重说明GATT与GAP源码。
索引地址:nimble\Host\src\ble_gap.c
// 着重注意GAT Event,每一个GAP Event将会通过回调机制返回状态。
static int gap_event_cb(struct ble_gap_event *event, void *arg)
// 具体包含如下GAP Event事件
#define BLE_GAP_EVENT_CONNECT 0
#define BLE_GAP_EVENT_DISCONNECT 1
/* Reserved 2 */
#define BLE_GAP_EVENT_CONN_UPDATE 3
...
#define BLE_GAP_EVENT_PERIODIC_SYNC_LOST 22
#define BLE_GAP_EVENT_SCAN_REQ_RCVD 23
#define BLE_GAP_EVENT_PERIODIC_TRANSFER 24
// 关于GAP接口可参考文件内信息,着重说明如下几个常用接口
// 开启广播
int ble_gap_adv_start(uint8_t own_addr_type, const ble_addr_t *direct_addr,
int32_t duration_ms,
const struct ble_gap_adv_params *adv_params,
ble_gap_event_fn *cb, void *cb_arg);
// 关闭广播
int ble_gap_adv_stop(void);
// 设置广播信息
int ble_gap_adv_set_data(const uint8_t *data, int data_len);
int ble_gap_adv_rsp_set_data(const uint8_t *data, int data_len);
// 连接子设备
int ble_gap_connect(uint8_t own_addr_type, const ble_addr_t *peer_addr,
int32_t duration_ms,
const struct ble_gap_conn_params *params,
ble_gap_event_fn *cb, void *cb_arg);
// 开启扫描
int ble_gap_disc(uint8_t own_addr_type, int32_t duration_ms,
const struct ble_gap_disc_params *disc_params,
ble_gap_event_fn *cb, void *cb_arg);
// 关闭扫描
int ble_gap_disc_cancel(void);
Server索引地址:nimble\Host\src\ble_gatts.c
Client索引地址:nimble\Host\src\ble_gatts.c
// 常用读写notify接口
int ble_gattc_write_no_rsp(uint16_t conn_handle, uint16_t attr_handle,
struct os_mbuf *om);
int ble_gattc_write(uint16_t conn_handle, uint16_t attr_handle,
struct os_mbuf *om,
ble_gatt_attr_fn *cb, void *cb_arg);
int ble_gattc_notify_custom(uint16_t conn_handle, uint16_t att_handle,
struct os_mbuf *om);
int ble_gattc_indicate_custom(uint16_t conn_handle, uint16_t chr_val_handle, struct os_mbuf *txom);
int ble_gattc_read_by_uuid(uint16_t conn_handle, uint16_t start_handle,
uint16_t end_handle, const ble_uuid_t *uuid,
ble_gatt_attr_fn *cb, void *cb_arg);
// 常用Client端发现服务等接口
int ble_gattc_disc_all_svcs(uint16_t conn_handle,
ble_gatt_disc_svc_fn *cb, void *cb_arg);
int ble_gattc_disc_svc_by_uuid(uint16_t conn_handle, const ble_uuid_t *uuid, ble_gatt_disc_svc_fn *cb, void *cb_arg);
int ble_gattc_find_inc_svcs(uint16_t conn_handle, uint16_t start_handle,
uint16_t end_handle, ble_gatt_disc_svc_fn *cb, void *cb_arg);
int ble_gattc_disc_all_chrs(uint16_t conn_handle, uint16_t start_handle,
uint16_t end_handle, ble_gatt_chr_fn *cb, void *cb_arg);
int ble_gattc_disc_chrs_by_uuid(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle, const ble_uuid_t *uuid,
ble_gatt_chr_fn *cb, void *cb_arg);
int ble_gattc_disc_all_dscs(uint16_t conn_handle, uint16_t start_handle,
uint16_t end_handle, ble_gatt_dsc_fn *cb, void *cb_arg);
// 决定了你发送数据/广播/新增服务等的buffer大小
MYNEWT_VAL_MSYS_1_BLOCK_COUNT
// 决定了你接收数据的buffer大小
MYNEWT_VAL_BLE_ACL_BUF_COUNT
// 决定了你接收的hci事件的buffer大小,如果包含扫描,务必设定较大。
MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT
MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT
开源协议栈框架仅仅是作为一个基础模型,真正做产品还是需要多加打磨的。无论是协议交互还是内存管理,都需要深度理解,才能打造好的产品。
关于如何制作Controller与驱动以及协议栈内存管理分配,可参考另外篇幅。
如果有相关需求,可以联系本人(vx:timcheng93)。可有偿提供整套协议栈服务。