在peripheral.c中
GAPRole_Init(taskID++);进行了初始化设置
还有有以下函数bStatus_tGAPRole_SetParameter(uint16param,uint8len,void*pValue)
GAPRole_GetParameter(…..)可以调用进行设置。
2)scanning
1)被动扫描:
扫描者监听广播频道的广播包,收到后将其上传到host层
2)主动扫描:
扫描者监听广播频道的广播包,当收到广播包后扫描者发送一个scanRequest包,广播设备回应一个scanreponse包
3)Connection
在扫描设备扫描到一个可连接的广播消息后,扫描设备可以通过发送connectionreequst包给广播设备从而成为连接的发起者
Connectionresqust包含从机链路层一系列的参数,这些参数声明连接时的通道及时序要求。
建立连接
GAPCentralRole_EstablishLink(DEFAULT_LINK_HIGH_DUTY_CYCLE,
DEFAULT_LINK_WHITE_LIST,
addrType,peerAddr);
广播设备接收了连接请求,就进入了连接状态,发起者成了主机,广播设备成了从机。
两个已连接的设备的所有通信发生在连接事件中,连接事件周期性的发生,周期由连接间隔参数决定。
连接间隔:
使用调频的间隔;两个连接事件之间的时间间隔,蓝牙传数据是在一个频段发送数据后,然后跳到另一个频段再传数据,从一个频道另一个频段的时间间隔就是连接间隔;即使没有数据发送,也要调频切换测试包是否连接断开;所以,连接间隔是定时的存在;可以认为是一个固定的时序;每隔一段时间就自动调到另一个频道的去建立连接;这个时间中,是很少功耗的,基本没有;
单位是1.25毫秒;范围是6----3200个单位;也就是1.25ms到4s的范围
不同的应用时间间隔不一样,
时间间隔长,功耗就低,传输数据慢;
时间间隔短,功耗就高,传输数据就快。
从机延时:
从机如果没有数据发送,可以跳过连接间隔,不用频繁的定时去建立连接,从而过一段较长时间再去建立连接;这个时间就是从机延时时间;从而功耗降低很多;单位是和连接间隔一样;范围是0---499
管理超时超过这个时间,还没有建立连接,则认为是连接丢失,断开。
回到未连接状态;
单位是10ms,范围是10(100ms)-----3200(32s)。
超时值必须比有效连接间隔大;有效连接间隔=连接间隔×(1+从机延时)
如果从机不想使用当前的连接参数,可以向主机发送连接更新请求,从机设备可以在任何时候发送连接更新请求,使得从机可以动态的调整连接参数。
GAPCentralRole_UpdateLink(simpleBLEConnHandle,
DEFAULT_UPDATE_MIN_CONN_INTERVAL,
DEFAULT_UPDATE_MAX_CONN_INTERVAL,
DEFAULT_UPDATE_SLAVE_LATENCY,
DEFAULT_UPDATE_CONN_TIMEOUT);
无论主机还是从机,都可以无条件的终止当前连接,一方请求终止,另一方必须在断开连接状态之前响应。
连接还可以由超时而终止。
超时时间小于32s,大于有效连接间隔(连接间隔×(1+从机延时))
终止连接函数:
GAPCentralRole_TerminateLink(simpleBLEConnHandle);
主机和从机保存各自的超时计时器,每次收到数据包就清零,一旦达到超时数值,就认为连接已经丢失就会断开连接。
连接超时判断,终止连接在程序中还没找到。
2.BLE中的GAP和GATT
GAP个人认为就是监控上图中的交互状态,比如从广播变成连接,到配对等。
GATT通俗理解为用于主从机之间的客户端和服务器端的数据交互,以AttributeTable来体现。
GAPRoleProfile:
在GAP所处的4个角色:
广播Advertise,主机central,从机Peripheral,观察者Observer。
GATTAttribute:
通用属性配置文件。
GAP作为PeripheralRole需要设置的核心参数如下
GAPROLE_ADVERT_ENABLED:
广播使能。
GAPROLE_ADVERT_DATA:
广播时的参数,
GAPROLE_SCAN_RSP_DATA:
从机扫描响应,返回的数据包
GAPROLE_MIN_CONN_INTERVAL:
处于连接状态后的设备,都会有个hop,一段时间内进行数据交互,以保证两者是连接的。
当前后两次交互时,需要等待的最小间隔时间
GAPROLE_MAX_CONN_INTERVAL:
...需要等待的最大间隔时间
GAPROLE_SLAVE_LATENCY:
处于连接后,从机可以做出不响应连接请求的间隔数目,即跳过n个交互的连接。
GAPROLE_TIMEOUT_MULTIPLIER:
从上次成功连接到这次连接成功的最大允许延时。
如果规定时间内未成功则认为本次连接失败,丢弃。
该值必须比有效连接的间隔大。
GAPROLE_PARAM_UPDATE_ENABLE:
请求主机更新参数,主机可以接受也可以拒绝。
.GATTServer的相关设置函数。
//InitializeGATTattributes
GGS_AddService(GATT_ALL_SERVICES); //GAPService
GATTServApp_AddService(GATT_ALL_SERVICES); //GATTattributes
DevInfo_AddService(); //DeviceInformationService
SimpleProfile_AddService(GATT_ALL_SERVICES); //SimpleGATTProfile
通常一个GATT中GAPserver和GATTserver是必须强制存在的,还有设备信息服务以及自己设计的profileserver.
SimpleProfile_AddService就是添加自己设计的profileserver
在SimpleProfile_AddService函数中调用了如下函数
GATTServApp_RegisterService(simpleProfileAttrTbl,GATT_NUM_ATTRS(simpleProfileAttrTbl),&simpleProfileCBs);}
simpleProfileCBs的函数定义如下:
CONSTgattServiceCBs_tsimpleProfileCBs=
{simpleProfile_ReadAttrCB,//Readcallbackfunctionpointer
simpleProfile_WriteAttrCB,//Writecallbackfunctionpointer
NULL//Authorizationcallbackfunctionpointer
};
实际上就是底层读写数据的函数,主机读数据时从机会调用simpleProfile_ReadAttrCB函数,写数据时从机会调用simpleProfile_WriteAttrCB函数。
这两个函数在simpleGaatprofile.c中实现。
注意在simpleProfile_WriteAttrCB,函数中有如下语句
if((notifyApp!
=0xFF)&&simpleProfile_AppCBs&&simpleProfile_AppCBs->pfnSimpleProfileChange)
{
simpleProfile_AppCBs->pfnSimpleProfileChange(notifyApp);
}
注意函数指针的用法,实际是在接收到主机数据发过来的数据后调用simpleProfileChangeCB函数来处理接收到的数据。
这个函数在初始化时注册,下面会讲到。
作为GATT的server和client,主要通过Attribute来进行交互,当client请求server读取数据时,通过如下注册的回调函数来进行访问。
//RegistercallbackwithSimpleGATTprofile
VOIDSimpleProfile_RegisterAppCBs(&simpleBLEPeripheral_SimpleProfileCBs);//给应用注册回调函数,这个函数非常重要
在回调函数中对数据做出处理。
staticsimpleProfileCBs_tsimpleBLEPeripheral_SimpleProfileCBs=
{
simpleProfileChangeCB//Charactersiticvaluechangecallback
};
在SimpleProfile_RegisterAppCBs函数中赋值。
simpleProfile_AppCBs=simpleProfileChangeCB
在simpleProfileChangeCB函数中可以启动定时器来给主机发送Notification数据
发送数据函数为GATT_Notification(noti_cHandle,&pReport,FALSE);
如下:
{ staticattHandleValueNoti_tpReport;//声明attHandleValueNoti_t这个结构体
uint16noti_cHandle;//存放handle
pReport.handle=simpleProfileAttrTbl[11].handle;//读取notification对应的handle
GAPRole_GetParameter(0x30E,¬i_cHandle);//获取ConnectionHandle
pReport.len=1;//数据长度
pReport.value[0]=0x03;//赋值
GATT_Notification(noti_cHandle,&pReport,FALSE);
}
主机使能Notification:
这个handle应该是相应的characteristicvalue的handle的后面一个,就是characteristicvalue的handle加1.
例子:
{
attWriteReq_twriteReq;
writeReq.handle=;
writeReq.len=2;
writeReq.value[0]=LO_UINT16(GATT_CLIENT_CFG_NOTIFY); 这里是0x01
writeReq.value[1]=HI_UINT16(GATT_CLIENT_CFG_NOTIFY); 这里是0x00
writeReq.sig=0;
writeReq.cmd=0;
GATT_WriteCharValue(simpleBLEConnHandle,&writeReq,simpleBLETaskId);
}
这两个值目的是打开Notification功能.CCC的参数有两个,一个Notification,一个indication. value[0]就是打开关闭notification, value[1]是打开关闭indication.
主机数据处理:
simpleBLECentral.c这个文件,里面有个函数:
simpleBLECentralProcessGATTMsg()
这个函数就是处理各种从peripheral过来的数据.
但是在示例代码中并没有加入通知,就是notification的接收,所以你得自己添加代码.
很简单,类似 if((pMsg->method==ATT_READ_RSP)||........), 添加 elseif((pMsg->method==ATT_HANDLE_VALUE_NOTI ) ||......)
就可以处理从机Notification的数据。
value被写的时候首先 simpleProfile_WriteAttrCB()会被调到.
最后才会调用 simpleProfileChangeCB()
GAP通过在启动设备事件的任务处理中启动设备,其实主要是向GAP中注册回调函数,让系统在发现自身运行状态变化时,调用该函数,方便应用层进行相关操作。
if(events&SBP_START_DEVICE_EVT)
{
//StarttheDevice
VOIDGAPRole_StartDevice(&simpleBLEPeripheral_PeripheralCBs);
//启动设备,注册回调函数,用于监督设备的状态变化:
广播、连接、配对、绑定等。
//StartBondManager
VOIDGAPBondMgr_Register(&simpleBLEPeripheral_BondMgrCBs);
}
simpleBLEPeripheral_PeripheralCBs函数定义如下
staticgapRolesCBs_tsimpleBLEPeripheral_PeripheralCBs=
{
peripheralStateNotificationCB,//ProfileStateChangeCallbacks
NULL//WhenavalidRSSIisreadfromcontroller(notusedbyapplication)
};
staticvoidperipheralStateNotificationCB(gaprole_States_tnewState)//传入参数由GPA自己输入,内部调用回调函数给用户,处理连接状态的改变
simpleBLEPeripheral_BondMgrCBs函数定义如下:
staticgapBondCBs_tsimpleBLEPeripheral_BondMgrCBs=
{
ProcessPasscodeCB,//生成配对密码,发送给主机
ProcessPairStateCB//主机密码的校验处理。
配对状态管理
};
一、修改广播功率
{
#defineLL_EXT_TX_POWER_MINUS_23_DBM0//-23dbm功率最小
#defineLL_EXT_TX_POWER_MINUS_6_DBM1//-6dbm
#defineLL_EXT_TX_POWER_0_DBM2//0dbm
#defineLL_EXT_TX_POWER_4_DBM3//+dbm功率最大
HCI_EXT_SetTxPowerCmd(gTxPower);
更新广播内容
GAP_UpdateAdvertisingData(simpleBLEPeripheral_TaskID,TRUE,sizeof(advertData_Ex),advertData_Ex);
}
二、数据加密解密
{
uint8key[16]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
//需要加密的数据
uint8plaintextData[16]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
//加密后数据存放区
uint8encryptedData[16];
//解密后数据存放区
uint8deccryptedData[16];
//开始加密
LL_Encrypt(key,plaintextData,encryptedData);
//开始解密
LL_EXT_Decrypt(key,encryptedData,deccryptedData);
}
三、设置从机广播时间
1)、广播模式必须是LimitedDiscoverablemode
在advertData 中加入此ADstring:
0x02,
GAP_ADTYPE_FLAGS,
GAP_ADTYPE_FLAGS_LIMITED|GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED
2)、设置时间
//Maximumtimetoremainadvertising,wheninLimitedDiscoverablemode.unitisseconds
#defineUSER_DEF_ADV_TIMEOUT 30
GAP_SetParamValue(TGAP_LIM_ADV_TIMEOUT,USER_DEF_ADV_TIMEOUT);