以官方的串口BLE 为例:
int main(void)
{
leds_init(); //非必须,只是该例子中用到了
timers_init(); //非必须,只是该例子中用到了
buttons_init(); //非必须,只是该例子中用到了
uart_init(); //非必须,只是该例子中用到了串口
ble_stack_init(); //必须
gap_params_init(); //必须
services_init(); //跟自己创建的服务相关,不同的服务细节不同但大体建立
//过程基本一致,通常在直接使用官 方的例子修改一些参数即可
advertising_init(); //广播数据初始化,必须
conn_params_init(); //是情况而定,如果连接后不需要连接参数的协商,该初始化也 //可不要
sec_params_init(); //安全参数初始化,如果没用到配对绑定相关这个也可以不初始化
advertising_start(); //开启广播,必须
// Enter main loop
for (;;)
{
power_manage(); //进入睡眠
}
}
比如uart的demo中dispatch派发函数
static void ble_evt_dispatch(ble_evt_t * p_ble_evt)
{
ble_conn_params_on_ble_evt(p_ble_evt);
ble_nus_on_ble_evt(&m_nus, p_ble_evt);
on_ble_evt(p_ble_evt);
}
在任何与BLE相关的事件被协议栈上抛上来给app时,ble_evt_dispatch就会被调用。从而将事件抛给各个服务函数或处理模块,这里是将事件抛给了
voidble_nus_on_ble_evt(ble_nus_t * p_nus, ble_evt_t * p_ble_evt)
{
if ((p_nus == NULL) || (p_ble_evt == NULL))
{
return;
}
switch (p_ble_evt->header.evt_id)
{
caseBLE_GAP_EVT_CONNECTED:
on_connect(p_nus, p_ble_evt);
break;
caseBLE_GAP_EVT_DISCONNECTED:
on_disconnect(p_nus, p_ble_evt);
break;
caseBLE_GATTS_EVT_WRITE:
on_write(p_nus, p_ble_evt);
break;
default:
// No implementation needed.
break;
}
}
也就是说完成一个完整的服务建立函数其实只要sd_ble_gatts_service_add()和sd_ble_gatts_characteristic_add ()这两个核心函数。
通常建立服务并不需要自己去从头写过。而是直接赋值官方的这个services_init()函数,然后做一些小改动就可以。比如修改一下uuid, 修改一下读/写属性,多添加一个特征值等。要修改的其实很少。
下面解决最后两个问题:手机发送来的数据在哪里?我怎么发送数据给手机?
要搞清楚这两个问题,先来看一下群里常问的几个与上面相关的问题:
问:手机发给51822设备的数据在哪个函数里出来的?
答:
没有函数
协议栈会抛上来一个事件结构体
收到的数据在结构体中
问:蓝牙上传函数,与下发函数都是一样的吗?都是服务API函数?
答:
只有上传函数 是服务器用来将数据传给客户端的。
下发数据 是蓝牙芯片收到数据后,协议栈会拋上来一个有数据的事件结 构体。具体参看示例代码中的 dispatch派发程序中各个事件处理函数对各 种事件的数据。
问:sd_ble_gatts_hvx()这个函数是 蓝牙的发送函数,有知道蓝牙的接收函数 ?
答:
蓝牙没有接收函数,蓝牙的数据接收在底层,接收完后会返回事件给上层的 ble_evt_dispatch 分发函数,它将事件分发给各个服务或者事件处理函数。 服 务或处理函数会捕获是否存在写事件case BLE_GATTS_EVT_WRITE: 存在就做 相应的处理。收到的数据都在返回的事件结构体里
其实看完这三个问题基本上上面的问题其实已经解决差不多了。作为从设备,BLE的发送数据给手机是有API接口的,就是上面问到的sd_ble_gatts_hvx(),可以通过参数来设置是以通知方式发送还是指示方式发送(通知不需要回复确认,指示需要)。但是手机发过来数据却是没有接收函数,为什么?因为协议栈是基于事件驱动的!所以收到数据后协议栈会给上层app一个写事件(指示对端设备写数据过来了),而写过来的数据时在这个事件结构体中。我们只要提取出来就行了。所以没有接收函数API。
从另一方面也可以解释为什么没有接收数据函数。因为发送数据时”同步的”,是主动调用的,在往想发送数据的时候。但是接收数据时”异步的”,数据可能随时到来,总不来一直调用一个函数然后原地等待数据到来吧,如果数据不来岂不是什么事都干不了了。所以接收是基于事件驱动的。有数据来再转过去处理。
用个图来解释下:
如果还是觉得有点抽象,回到前面看看协议栈运作讲解部分。应该更能体会所谓的事件驱动。
http://blog.chinaunix.net/uid-28852942-id-5335038.html