简介
上一篇 【WB2蓝牙学习-1】蓝牙数据广播 主要展示了蓝牙从机模式被蓝牙调试助手链接后,蓝牙助手显示的信息。
这篇还是围绕蓝牙从机模式的代码。研究一下手机与蓝牙之间的通信在代码中是如何实现的。还是一样的本文不讲解蓝牙低功耗的协议,因为我也一知半解。不敢误导大家;
启动流程

如上图所示,蓝牙设备的初始化主要流程:
1、协议栈初始化;
2、slave 设备初始化;
3、注册最大传输单元变更回调函数;
4、注册一系列链接相关回调函数;
途中也标出了在不同阶段注册的回调函数。正是这些回调函数实现了蓝牙设备跟手机的通信;接下来逐个研究;
回调函数
bt_enable_cb
这个函数是在协议栈初始化最后使能蓝牙时调用的。
这个函数在安信可的SDK文档中有描述:

回调函数的具体实现:
static void bt_enable_cb(int err)
{
if (!err)
{
bt_addr_le_t bt_addr;
bt_get_local_public_address(&bt_addr);
bt_addr.a.val[5] = 0x88;
bt_addr.a.val[4] = 0x88;
bt_addr.a.val[3] = 0x88;
bt_addr.a.val[2] = 0x88;
bt_addr.a.val[1] = 0x88;
bt_addr.a.val[0] = 0x88;
printf("BD_ADDR:(MSB)%02x:%02x:%02x:%02x:%02x:%02x(LSB) \r\n",
bt_addr.a.val[5], bt_addr.a.val[4], bt_addr.a.val[3], bt_addr.a.val[2], bt_addr.a.val[1], bt_addr.a.val[0]);
}
}
这里我有点不理解,这是写了默认值吗?
在不修改代码的情况下尝试一下:

尝试修改代码删除设置默认值:

可以看到真实的地址了;
这个回调函数是在使能蓝牙设备后被调用。
ble_salve_conn_cb
& ble_salve_conn_cb
这两个函数是在slave 初始化部分注册的,但是注册回调函数的实现仅仅是设置了两个全局变量。这两个函数实际使用是在后边的提到的回调函数中使用。
这样做可以理解为这两个函数是对回调函数的增强,因为在后边的两个回调函数的实现中可以发现在判断存在的情况下会首先使用这两个回调函数,因此这里暂时不看;
_connected
& _disconnected
这两个回调函数是在蓝牙启动代码中最后注册的。 安信可的SDK文档中也有简单的说明:

不过参数描述没看明白;也不影响理解,就是注册了链接相关的回调函数。
首先 _connected 的具体实现如下:
static void _connected(struct bt_conn *conn, u8_t err)
{
if (conn_cb)
{
if (conn_cb(conn, err) != 0)
{
return;
}
}
if (conn->type != BT_CONN_TYPE_LE)
{
return;
}
conn_cur = conn;
printf("[BLE] connected \r\n");
BleSetMtu();
return;
}
可以看到,这里就用到了上边提到的其中一个回调函数。使用手机的蓝牙调试助手链接,然后查看串口日志:

这里打印了三条信息:
第一行是 _connected
这个回调函数打印的;
第二行是
_connected 这个回调函数中 BleSetMtu
这个函数导致的。
第三行是 _le_param_updated
这个函数输出的,参数更新的回调;
_disconnected
回调函数:
static void _disconnected(struct bt_conn *conn, u8_t reason)
{
if (disconn_cb)
{
if (disconn_cb(conn, reason) != 0)
{
return;
}
}
if (conn->type != BT_CONN_TYPE_LE)
{
return;
}
conn_cur = NULL;
printf("[BLE] disconnected, reason:%d \r\n", reason);
}
蓝牙调式助手断开蓝牙串口打印信息:

第一行提示重新广播失败,是 _disconnected中调用的之前提到的 ble_salve_disconn_cb 中尝试重新广播;
第二行则是 _disconnected 回调函数中调用的。
_ble_mtu_changed_cb
这个函数的具体实现如下:
static void _ble_mtu_changed_cb(struct bt_conn *conn, int mtu)
{
printf("[BLE] mtu updated:%d \r\n", mtu);
}
从打印的日志内容可以看到是 mtu(最大传输单元)发生了变化;
总结
正是通过注册的这些回调函数实现了蓝牙设备主机和从机的通信。 同时可以看出这些回调函数只是在启动过成功起到作用,因此如果应用程序希望在链接过程中做一些事情的话就可以在这些回调函数中实现自己的逻辑。比如使能设备成功回调函数中可以让模组的等闪烁。链接成功后停止闪烁。 断开链接后再重新闪烁。下一次在研究下链接成功后设备的通信;