if ( events & START_DEVICE_EVT )
// Start the Device
VOID GAPCentralRole_StartDevice( (gapCentralRoleCB_t *) &simpleBLERoleCB );
// Register with bond manager after starting device
GAPBondMgr_Register( (gapBondCBs_t *) &simpleBLEBondCB );
return ( events ^ START_DEVICE_EVT );
2、GAP_DEVICE_INFO_EVENT(设备信息事件)
在发现设备过程中,如果有设备被发现,就会执行该事件。
注意,进到该事件时,主机已经获得了某个从机的UUID和MAC地址,而且一个设备会先后进两次本事件,一次是广播数据、一次是扫描应答数据。
举个例子,
有个从机地址的UUID是0xFFF0、MAC地址是0xB4994C621B09。
当主机进到GAP_DEVICE_INFO_EVENT事件时,已经获取到了0xFFF0(广播数据中)和0xB4994C621B09(广播数据和扫描应答数据中都没有发现,应该是在底层的交互数据中)。第一次进GAP_DEVICE_INFO_EVENT事件时pEvent->deviceInfo.pEvtData指向的是广播数据,第二次进GAP_DEVICE_INFO_EVENT事件时pEvent->deviceInfo.pEvtData指向的是扫描应答数据。
来看看simpleBLEFindSvcUuid函数是怎么实现的:
static bool simpleBLEFindSvcUuid( uint16 uuid, uint8 *pData, uint8 dataLen )
uint8 adLen;
uint8 adType;
uint8 *pEnd;
pEnd = pData + dataLen - 1;
// While end of data not reached
while ( pData < pEnd )
// Get length of next AD item
adLen = *pData++;
if ( adLen > 0 )
adType = *pData;
// If AD type is for 16-bit service UUID
if ( adType == GAP_ADTYPE_16BIT_MORE || adType == GAP_ADTYPE_16BIT_COMPLETE )
pData++;
adLen--;
// For each UUID in list
while ( adLen >= 2 && pData < pEnd )
// Check for match
if ( pData[0] == LO_UINT16(uuid) && pData[1] == HI_UINT16(uuid) )
// Match found
return TRUE;
// Go to next
pData += 2;
adLen -= 2;
// Handle possible erroneous extra byte in UUID list
if ( adLen == 1 )
pData++;
// Go to next item
pData += adLen;
// Match not found
return FALSE;
}
上面这段代码实现过程:先接收“数据长度”,判断“数据长度”后面一个字节的“数据类型”,如果是GAP_ADTYPE_16BIT_MORE或GAP_ADTYPE_16BIT_COMPLETE则说明该数据段是UUID,则保存下来。
对比看看下图的广播数据就比较清楚了。
再看看simpleBLEAddDeviceInfo是如何添加MAC地址到列表的。
3、GAP_DEVICE_DISCOVERY_EVENT(发现设备完成事件)
GAP_DEVICE_INFO_EVENT事件是发现设备过程中,发现一个设备即进一次事件。
GAP_DEVICE_DISCOVERY_EVENT事件则是发现结束后产生的事件。
4、GAP_LINK_ESTABLISHED_EVENT(连接结束事件)
5、GAP_LINK_TERMINATED_EVENT(断开完成事件)
6、GAP_LINK_PARAM_UPDATE_EVENT(参数更新)
case GAP_LINK_PARAM_UPDATE_EVENT:
LCD_WRITE_STRING( "Param Update", HAL_LCD_LINE_1 );
break;
GAP_LINK_PARAM_UPDATE_EVENT事件是在GAPCentralRole_UpdateLink被调用后而执行的:
if ( keys & HAL_KEY_RIGHT )
// Connection update
if ( simpleBLEState == BLE_STATE_CONNECTED )
GAPCentralRole_UpdateLink( simpleBLEConnHandle,
DEFAULT_UPDATE_MIN_CONN_INTERVAL,
DEFAULT_UPDATE_MAX_CONN_INTERVAL,
DEFAULT_UPDATE_SLAVE_LATENCY,
DEFAULT_UPDATE_CONN_TIMEOUT );
/*BLE中的GAP和GATT
GATT通俗理解为用于主从机之间的客户端和服务器端的数据交互,以Attribute Table来体现。
//*GATT层:是一个服务框架定义了对ATT应用的子程序。GATT指定了profile的结构。
//*在BLE中,由profile或者是服务所使用的所有类型的数据都称为characteristic。发生于两个设备间通过BLE连接进行交换的数据都需经过GATT子程
BLE协议栈Central 工程中与广播连接建立的事件
最近在改写BLE协议栈,需要实现实时发现周边从设备,并建立连接,获取RSSI的功能,没什么难度,但着实将各个事件好好看了一遍。曾经看到一位大神说相同的任务使用事件触发方式,不同的任务使用消息传递方式。冥冥之中突然来了感觉~
BLE进行广播和建立连接的事件主要实现是在simpleBLECentralEventC
首先要明确:连接参数是由主机端确定的,从机端可以发起更新连接参数的请求。主机端可以直接下发连接参数,而从机端则只能是发起更新请求并附带想要的连接参数范围。
在初始化中将想要的连接参数设置进osal( 在和iOS设备连接时需要注意一些规则,在前面有提到 ):
GAPRole_SetParameter( GAPROLE_PARAM_UPDATE_ENABLE, sizeof( uint8 ), &
【1】主机、从机 代码主要区别。有无profile。
主机:无 profile
从机:有 profile (从机里包含了一个叫做profile的相关代码,这个profile决定了从机的功能。例如防丢器、血压仪、心率计等均是蓝牙组织规定的profile。)
【2】主机、从机 读写函数的区别
主机(Client客户端): GATT_WriteCharValue(?); 或者 GATT