GATTServApp_ProcessCharCfg和 GATT_NOTIFICATION()区别
大神们:
GATTServApp_ProcessCharCfg( )和GATT_Notification俩接口函数 流程是什么样子?
GATT_Notification:是直接将数据发送给master?
GATTServApp_ProcessCharCfg:最终会导致master那边调用一个read请求, 然后调用到keyfob这边的sk_ReadAttrCB()?
请指教。
Hi mac,
你说的正确.
你想用Notification的话最好用GATT_Notification(), 这个直接发送Notification, 不会像GATTServApp_ProcessCharCfg再会让master向slave去发送一个读的请求.
Yan
我刚刚开始看CC2540相关的内容,假如我使用GATT_Notification()这个函数的话,我循环发送数据,在BTOOL上怎样才能看到效果呢?
hi rivers,
你会在BTool的接收窗口间隔性的看到收到的数据.
Hi Yan,
Notification 是用GATT_Notofication()发送的?
simpleBLEperipheral例子程序里是用SimpleProfile_SetParameter( SIMPLEPROFILE_CHAR4, sizeof(uint8), &valueToCopy);这个函数吗?在周期函数里,每隔5秒发送notification啊?我找了一下没有找到用GATT_Notification()发送SIMPLEPROFILE_CHAR4啊?这是为什么呢?
谢谢!
hi xie,
请看 simpleGATTProfile.c,
里面有个SimpleProfile_SetParameter(), 这个就是间隔性被调用的函数.
里面有 case SIMPLEPROFILE_CHAR4:
调用 GATTServApp_ProcessCharCfg(...........................), 这个函数内部最终会回调到simpleProfile_ReadAttrCB(),
里面的下面代码会设置CHAR4的值.
case SIMPLEPROFILE_CHAR4_UUID:
*pLen = 1;
pValue[0] = *pAttr->pValue;
break;
最后, 如果notification是打开的, GATTServApp_ProcessCharCfg(...........................)内部会调用GATT_Notification().
都在内部封装好了, 所以你看不到, 但是过程是很清楚在那里的.
清楚了?
Hi Yan,
非常感谢!我清楚了。隐藏的太深,哈哈。流程有点复杂,我使用的时候可以直接调用GATT_Notification();发送Notification吗?而不走那么复杂的流程呢?谢谢!
xie,
可以, 直接用GATT_Notification()可以.
你好YAN,我也出现了这个问题,我不知道Notification中的handle应该是哪个handle?我就是想使用CHAR4这个UUID。
attHandleValueNoti_t noti;
noti.handle = simpleProfileAttrTbl[11].handle;
noti.len = 7;
noti.value[0] = "hello";
GATT_Notification( pLinkItem->connectionHandle, ¬i, FALSE );
就是这个高亮这个应该怎么写呢?keyfob中发现是个连接的结构体,在Peripheral中有这中结构体吗?
还有就是value的值我可以这样赋值吗? 麻烦您了。。。
static void performPeriodicTask( void )
{
if (gapProfileState == GAPROLE_CONNECTED)
{
if ( GATT_CLIENT_CFG_NOTIFY )
{
attHandleValueNoti_t noti;
noti.handle = simpleProfileAttrTbl[11].handle;
noti.len = 7;
noti.value[0] = "hello";
GATT_Notification( pLinkItem->connectionHandle, ¬i, FALSE );
}
}
}
这是我的代码,麻烦你了,看看可行不行。
lele,
pLinkItem->connectionHandle 是指连接的Handle, 你跟对方设备连上以后会产生一个Handle. 这个Handle在连接建立成功的事件中可以找到, 你仔细看一下代码.
value的默认值是一个字节的, 你要这样赋值的话得改一下, 改成数组.
simpleProfileAttrTbl, 的位置12 是CHAR4 的Client Characteristic Configuration, 记得发Notification 之前, 通过master设备把这个值设置成 0x0001, 打开notification.
hi leleli: 我之前也在找这handle来至于哪里。如果你看的是从机代码可以在:
static void peripheralStateNotificationCB( gaprole_States_t newState )函数中
case GAPROLE_CONNECTED:
{ #if (defined HAL_LCD) && (HAL_LCD == TRUE)
GAPRole_GetParameter( GAPROLE_CONNHANDLE, &gapConnHandle );
HalLcdWriteString( "Connected", HAL_LCD_LINE_3 );
#endif // (defined HAL_LCD) && (HAL_LCD == TRUE) } break;
标红色字体地方获取handle
Hi Yan:
打扰一下,再问一个关于此的基础性问题,如果在slave端采用GATT_Notification,master端会直接收到Notification的数据包,如果slave端采用GATTServApp_ProcessCharCfg,则需要把simpleProfileChar4Config写成0x0001,master端才会收到Notification的数据包。这里收到的数据包是指通过sniffer监控到的数据包,如下图:
现在的问题是,我在simpleBLECentralProcessGATTMsg中添加如下蓝色代码:
else if ( ( pMsg->method == ATT_WRITE_RSP ) ||
( ( pMsg->method == ATT_ERROR_RSP ) &&
( pMsg->msg.errorRsp.reqOpcode == ATT_WRITE_REQ ) ) )
{
if ( pMsg->method == ATT_ERROR_RSP == ATT_ERROR_RSP )
{
uint8 status = pMsg->msg.errorRsp.errCode;
LCD_WRITE_STRING_VALUE( "Write Error", status, 10, HAL_LCD_LINE_1 );
}
else
{
// After a succesful write, display the value that was written and increment value
LCD_WRITE_STRING_VALUE( "Write sent:", simpleBLECharVal++, 10, HAL_LCD_LINE_1 );
}
simpleBLEProcedureInProgress = FALSE;
}
else if ( pMsg->method == ATT_HANDLE_VALUE_NOTI )
{
HalUARTWrite(HAL_UART_PORT_0,"noti",5);
}
没有执行HalUARTWrite,HalUARTWrite本身没有问题,在该工程其他地方执行是正确的,请问可能的原因是?谢谢!
hey peng,
首先, 不管GATT_Notification() 还是GATTServApp_ProcessCharCfg(), 本质上都是notification, 都需要master 那边先打开slave 这边的notification 功能.
你这段代码加的是正确的. 我看不出有什么问题.
是否你其他地方还有问题? 请再仔细看一下代码.
另外你在salve 端是怎么发送notification 的? 一次发了5个字节?
Hi Yan,
程序功能还没正常, 所以目前在使用sniffer配合调试。我的想法是这样的,连接成功后,slave自动发送notification给master。
现在发现如果在slave端采用GATT_Notification
attHandleValueNoti_t noti;
noti.handle = 0x002E;
noti.len = 1;
noti.value[0] = 0x01;
GATT_Notification( 0x0000, ¬i, FALSE );
连接成功后sniffer就可监控到数据长度为1的那个notify数据包。
另外我想试一下GATTServApp_ProcessCharCfg函数,自己修改了simpleGATTprofile.c,定义了1个4个字节的数据包,该部分已经通过BTOOL验证功能正常(使用BTOOL写入0x0001到对应地址可以收到4字节的notify数据包)。
把master工程模板切换成BLEcentral,连接成功后sniffer还是只能监控到GATT_Notification的数据包,只有在central中加入:
attWriteReq_t writeReq;
writeReq.handle = 0x002F;
writeReq.len = 2;
writeReq.value[0] = LO_UINT16(GATT_CLIENT_CFG_NOTIFY);
writeReq.value[1] = HI_UINT16(GATT_CLIENT_CFG_NOTIFY);
writeReq.sig = 0;
writeReq.cmd = 0;
GATT_WriteCharValue( 0x0000, &writeReq, simpleBLETaskId );
才能监控到那个4个字节的数据包。sniffer虽然监控到这两个数据包了,但central的程序好像没有执行到函数simpleBLECentralProcessGATTMsg中。刚刚在central中试了一下GATT_ReadCharValue,额,好像也没跳转进去,正在看代码中......
hi peng,
从空中的包看, notification 是肯定发送过去了, simpleBLECentralProcessGATTMsg 也应该别调用到了.
只是默认central 工程没有在这个函数里面定义如何去处理收到的notification 事件, 请参考下面这个帖子, 有你要的答案:
http://www.deyisupport.com/question_answer/analog/wireless_connectivity/f/45/p/23013/77181.aspx#77181
Hi Yan
谢谢你的帮助,问题已经解决,是自己在一主多从的模式下误操作了simpleBLEState。非常感谢!
您好Yan:
我刚刚做了个关于GATTServApp_ProcessCharCfg和GATT_NOTIFICATION 的实验。
1.当使用GATTServApp_ProcessCharCfg时master必须向SIMPLEPROFILE_CHAR4发送命令(向handle 4 写0x0001),即进入了程序
case SIMPLEPROFILE_CHAR4:
if ( len == sizeof ( uint8 ) )
{
simpleProfileChar4 = *((uint8*)value);
// See if Notification has been enabled
// GATTServApp_ProcessCharCfg( simpleProfileChar4Config, &simpleProfileChar4, FALSE,
// simpleProfileAttrTbl, GATT_NUM_ATTRS( simpleProfileAttrTbl ),
// INVALID_TASK_ID );
GATTServApp_ProcessCharCfg( simpleProfileChar4Config, &simpleProfileChar4, FALSE,
simpleProfileAttrTbl, GATT_NUM_ATTRS( simpleProfileAttrTbl ),
INVALID_TASK_ID );
}中,进行判断正确后,在上位机端BTool软件中,每隔5秒接收一次数据。
2.当使用GATT_NOTIFICATION 时我发现,只要dongle和keyfob建立连接后,上位机BTool就一直接收数据。
关于这两个函数的使用我感觉还算是清楚,但是我有一点搞不明白:
就是我使用GATT_NOTIFICATION 函数时,是在总体程序的随便一个地方添加的,添加的前面还有判断条件,但是运行的时候好像程序没有管这些判断条件就直接向后运行了,这是怎么回事,恩~ 我想问下关于GATT_NOTIFICATION 函数的具体一个调用方法(是类似中断么?)。
这是我的程序
else if( len == 12)//len长度都没有输入判断就直接进入了
{
temp = (uint8*)value;
attHandleValueNoti_t noti;
noti.handle = 0x002E;
noti.len = 12;
noti.value[0] = *temp++;
noti.value[1] = *temp++;
noti.value[2] = *temp++;
noti.value[3] = *temp++;
noti.value[4] = *temp++;
noti.value[5] = *temp++;
noti.value[6] = *temp++;
noti.value[7] = *temp++;
noti.value[8] = *temp++;
noti.value[9] = *temp++;
noti.value[10] = *temp++;
noti.value[11] = *temp++;
GATT_Notification( 0x0000, ¬i, FALSE );
}
不清楚你的意思.
len的长度没判断, 貌似是代码的逻辑问题?
Notification 是Master和slave 通信的一种方式, 开关由Master 来控制, master打开slave 的某个 Notification 开关后, slave 就可以发送数据.
这是双方的一种通信协议, 以起到同步信息以及状态的作用.
请问notification在程序的那个地方打开?
hi yan,
问您个问题,我设置好了notification,本来默认的是一个字节,我5秒发一次,后来我修改代码改成了每次发送8个字节,还是5秒发一次,但是程序执行起来不到一秒就发一次,定时器都跟着出问题了,请问我改了什么东西还会产生这种效果?
SimpleProfile_SetParameter()为什么调用simpleProfile_ReadAttrCB()呢,不应该是simpleProfile_WriteAttrCB()吗?
嗨Yan,你不是说
调用 GATTServApp_ProcessCharCfg(...........................), 该函数处理客户端特征改变(来自BLE官方html文档)
这个函数内部最终会回调到simpleProfile_ReadAttrCB(),里面的下面代码会设置CHAR4的值.
case SIMPLEPROFILE_CHAR4_UUID:
*pLen = 1;
pValue[0] = *pAttr->pValue;
break;
最后, 如果notification是打开的, GATTServApp_ProcessCharCfg(...........................)
内部会调用GATT_Notification().
这里完全就没有master什么事啊?那你为什么说调用这个 GATTServApp_ProcessCharCfg函数会引起主机master发出一个Read请求。再说Notification在主机方面没有Read的权限啊!你说不是吗?
我是较真的啊。
Hi Yan!
我用串口助手扫描出某个透传模块的特征值为:FFF1可通知,FFF2可写。请问从“FFF1可通知”这一点是否可以看出该模块数据传输采用哪种方式?是否为GATT_Indication方式?
谢谢!