Peripheral如何将数据发送给Central?
各位大神,你们好!
我从Central向Peripheral发送数据,并从串口将数据打印出来,已经实现。但是如何从Peripheral向Central发送数据呢?找了好多TI的例层,但是没找到,希望大家指教。
hi Qin,
可以通过central 向peripheral 发送读请求, peripheral回复,
或者peripheral 发送notification, 或indication 给central 实现.
具体请参考central 和 peripheral 代码.
Peripheral 每5秒执行performPeriodicTask( void )函数,通过SimpleProfile_SetParameter( SIMPLEPROFILE_CHAR4, sizeof(uint8), &valueToCopy);向Central发送数据。但是SimpleProfile_SetParameter( SIMPLEPROFILE_CHAR4, sizeof(uint8), &valueToCopy)-> simpleProfile_ProcessCharCfg( simpleProfileChar4Config, &simpleProfileChar4, FALSE )->simpleProfile_ProcessCharCfg()->GATT_Notification(),但是GATT_Notification()这个函数更本就没调用。 simpleProfile_ProcessCharCfg函数中
if ( ( pItem->connHandle != INVALID_CONNHANDLE ) && ( pItem->value != GATT_CFG_NO_OPERATION ) )
条件就没法成立。
bStatus_t SimpleProfile_AddService( uint32 services ) {
uint8 status = SUCCESS;
// Initialize Client Characteristic Configuration attributes
for ( uint8 i = 0; i < GATT_MAX_NUM_CONN; i++ ) {
simpleProfileChar4Config[i].connHandle = INVALID_CONNHANDLE; /'/不知道这里为什么都填为INVALID_CONNHANDLE?
simpleProfileChar4Config[i].value = GATT_CFG_NO_OPERATION;
}
// Register with Link DB to receive link status change callback
VOID linkDB_Register( simpleProfile_HandleConnStatusCB );
if ( services & SIMPLEPROFILE_SERVICE ) {
// Register GATT attribute list and CBs with GATT Server App
status = GATTServApp_RegisterService( simpleProfileAttrTbl, GATT_NUM_ATTRS( simpleProfileAttrTbl ),
simpleProfile_ReadAttrCB, simpleProfile_WriteAttrCB, NULL );
}
return ( status );
}
能给一下指导吗?
TI的工程师怎么也不给个回应呢!
hi qin,
simpleProfile_ProcessCharCfg() 是什么? 你自己加的代码? 为什么没有用 GATTServApp_ProcessCharCfg() ?
请麻烦你再把你的具体情况说清楚一点, 是否自己加了代码.
GATTServApp_ProcessCharCfg() 会调用GATT_Notification().
请参考以下这个帖子:http://www.deyisupport.com/question_answer/analog/wireless_connectivity/f/45/t/23478.aspx
有时候你问的问题可能已经在论坛里面有人解答过了, 所以有可能的话请在提问前在论坛里面搜索一下 :)
INVALID_CONNHANDLE , 这是表示蓝牙连接的handle.
你初始化的时候根本没有设备给你连上, 当然默认全都是invalid.
你这个代码也不是TI 的源码, 被人改过的. 请去官网下载正宗的协议栈对比一下:
http://www.ti.com/tool/ble-stack?DCMP=wbu-blestack&HQS=blestack
我之前用的是BLE-CC254X-1.1版本的。现在换了BLE-CC254x-1.3版本了。
我的问题是,Central和Peripheral建立连接后,Peripheral给Central的发送数据,主机接收不到数据,且没任何反应。
现在两个Central和Peripheral能建立连接。因为主机打印了Connected,还打印了从机地址0xE0C79D60DEC6。
GATTServApp_ProcessCharCfg( simpleProfileChar4Config, &simpleProfileChar4, FALSE, simpleProfileAttrTbl, GATT_NUM_ATTRS( simpleProfileAttrTbl ), INVALID_TASK_ID );是周期性地调用,但是,主机没任何反应。
Hi Qin,
请确认主机已经把从机的CHAR4 的 notification enable打开.
怎样做,主机才能把从机的CHAR4 的 notification enable打开呢?我之前在其他坛子也看到了你这句话,但是一直没明白。是在主机和从机连接完成后吗,还是连接过程中呢?
Hi Qin,
这是在连接完成后进行操作的.
具体的话, 你先看simpleGATTProfile.c 中, CHAR4 的定义里, 有个
// Characteristic 4 configuration
{
{ ATT_BT_UUID_SIZE, clientCharCfgUUID },
GATT_PERMIT_READ | GATT_PERMIT_WRITE,
0,
(uint8 *)simpleProfileChar4Config
},
simpleProfileChar4Config 这个值负责的就是notification 和 indication 的打开关闭.
连接成功后, master 端用 write 的方式把这个值写成 0x0001, 就把notification 打开了.
是在连接成功时,Central发送数据告诉Peripheral打开notification 和 indication 吗?
case GAP_LINK_ESTABLISHED_EVENT:
{
if ( pEvent->gap.hdr.status == SUCCESS ) {
simpleBLEState = BLE_STATE_CONNECTED;
simpleBLEConnHandle = pEvent->linkCmpl.connectionHandle;
simpleBLEProcedureInProgress = TRUE;
// If service discovery not performed initiate service discovery
if ( simpleBLECharHdl == 0 )
{
osal_start_timerEx( simpleBLETaskId, START_DISCOVERY_EVT, DEFAULT_SVC_DISCOVERY_DELAY );
}
LCD_WRITE_STRING( "Connected", HAL_LCD_LINE_1 );
LCD_WRITE_STRING( bdAddr2Str( pEvent->linkCmpl.devAddr ), HAL_LCD_LINE_2 );
attWriteReq_t req;
req.handle = simpleBLEConnHandle;
req.len = 2;
//req.value[0] = simpleBLECharVal;
req.value[0] = LO_UINT16(0);
req.value[1] = HI_UINT16(GATT_CLIENT_CFG_NOTIFY);
req.sig = 0;
req.cmd = 0;
GATT_WriteCharValue( simpleBLEConnHandle, &req, simpleBLETaskId );
。。。 。。。
Peripheral接收到数据后,将simpleProfileChar4Config值改为0x0001吗?
req.handle = simpleBLEConnHandle;
这个不对, 不是连接的handle, 这里需要的是characteristic 的handle.
其他的基本正确.
其实论坛里面有类似问题也能给你答案的:
http://www.deyisupport.com/question_answer/analog/wireless_connectivity/f/45/p/23013/77927.aspx#77927
req.handle = simpleBLECharHdl; ?
req.handle = simpleBLECharHdl;
req.len = 2;
//req.value[0] = simpleBLECharVal;
req.value[0] = LO_UINT16(0);
req.value[1] = HI_UINT16(GATT_CLIENT_CFG_NOTIFY);
req.sig = 0;
req.cmd = 0;
GATT_WriteCharValue( simpleBLEConnHandle, &req, simpleBLETaskId );
但是从机的simpleProfileChangeCB函数没有被调用
连接完成后,从机发送数据,主机还是接收不到。主机的simpleBLECentralProcessGATTMsg函数就没被调用。
Yan Engineer,
能再点指导吗?
“master 端用 write 的方式把这个值写成 0x0001”,是指Central端通过如下的写方法:
req.handle = simpleBLECharHdl;
req.value[0] = LO_UINT16(GATT_CLIENT_CFG_NOTIFY);
req.value[1] = HI_UINT16(GATT_CLIENT_CFG_NOTIFY);
req.sig = 0;
req.cmd = 0;
GATT_WriteCharValue( simpleBLEConnHandle, &req, simpleBLETaskId );
从机接到该数据后,就给这个simpleProfileChar4Config变量进行如下方式的赋值是吗?
*((uint16*)simpleProfileChar4Config)= 0x0001;
这样就把从机(server端)的notification打开了是吗?
Qin,
value 被写的时候首先 simpleProfile_WriteAttrCB() 会被调到.
函数内:
switch ( uuid )
{
case SIMPLEPROFILE_CHAR1_UUID:
case SIMPLEPROFILE_CHAR3_UUID:
加上 case SIMPLEPROFILE_CHAR3_UUID:
再
往
下
//Write the value
if ( status == SUCCESS )
{
uint8 *pCurValue = (uint8 *)pAttr->pValue;
*pCurValue = pValue[0];
if( pAttr->pValue == &simpleProfileChar1 ) // 这里你自己去加对 char4 的判断. 注意好好看一下代码.
{
notifyApp = SIMPLEPROFILE_CHAR1;
}
else
{
notifyApp = SIMPLEPROFILE_CHAR3;
}
}
最后才会调用你的 simpleProfileChangeCB()
Qin
是的, 只要你的simpleBLECharHdl 正确, 必须是对应的simpleProfileChar4Config 的handle.
Qin,
value 被写的时候首先 simpleProfile_WriteAttrCB() 会被调到.
函数内:
switch ( uuid )
{
case SIMPLEPROFILE_CHAR1_UUID:
case SIMPLEPROFILE_CHAR3_UUID:
加上 case SIMPLEPROFILE_CHAR3_UUID:
再
往
下
//Write the value
if ( status == SUCCESS )
{
uint8 *pCurValue = (uint8 *)pAttr->pValue;
*pCurValue = pValue[0];
if( pAttr->pValue == &simpleProfileChar1 ) // 这里你自己去加对 char4 的判断. 注意好好看一下代码.
{
notifyApp = SIMPLEPROFILE_CHAR1;
}
else
{
notifyApp = SIMPLEPROFILE_CHAR3;
}
}
最后才会调用你的 simpleProfileChangeCB()
这个函数现在只能获取CHAR1的handle是吗?我怎么才能获取CHAR4的句柄呢?我真的不知道怎么才能同时获取CHAR1和CHAR4的句柄。
Hi Qin,
如果你只是想单独获取CHAR4 的句柄, 只要把这段代码里面的SIMPLEPROFILE_CHAR1_UUID 改成SIMPLEPROFILE_CHAR4_UUID 就行.
如果你想同时获取, 你得稍微修改一下状态机,
我随便举个例子, 代码不敢保证百分百正确, 思路就是这样的, 你自己去修改试一下吧.
在 simpleBLECentral.c 里面,
// Discovery states
enum
{
BLE_DISC_STATE_IDLE, // Idle
BLE_DISC_STATE_SVC, // Service discovery
BLE_DISC_STATE_CHAR, // Characteristic discovery
再加一个 BLE_DISC_STATE_CHAR4
};
然后在 simpleBLEGATTDiscoveryEvent()
else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR )
{
// Characteristic found, store handle
if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&
pMsg->msg.readByTypeRsp.numPairs > 0 )
{
simpleBLECharHdl = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
pMsg->msg.readByTypeRsp.dataList[1] );
LCD_WRITE_STRING( "Simple Svc Found", HAL_LCD_LINE_1 );
simpleBLEProcedureInProgress = TRUE;
}
修改 //simpleBLEDiscState = BLE_DISC_STATE_IDLE;
simpleBLEDiscState = BLE_DISC_STATE_CHAR4;
添加如下, 去查找CHAR4
req.startHandle = simpleBLESvcStartHdl;
req.endHandle = simpleBLESvcEndHdl;
req.type.len = ATT_BT_UUID_SIZE;
req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR4_UUID);
req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR4_UUID);
GATT_ReadUsingCharUUID( simpleBLEConnHandle, &req, simpleBLETaskId );
}
再加如下, 因为找到CHAR4 以后会到这里来
else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR4 )
{
保存char4 handle
simpleBLEChar4Hdl = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
pMsg->msg.readByTypeRsp.dataList[1] );
LCD_WRITE_STRING( "Simple Svc Found", HAL_LCD_LINE_1 );
simpleBLEProcedureInProgress = FALSE;
}
simpleBLEDiscState = BLE_DISC_STATE_IDLE;
}
static void simpleBLEGATTDiscoveryEvent( gattMsgEvent_t *pMsg )
{
attReadByTypeReq_t req;
if ( simpleBLEDiscState == BLE_DISC_STATE_SVC ) {
// Service found, store handles
if ( pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
pMsg->msg.findByTypeValueRsp.numInfo > 0 )
{
simpleBLESvcStartHdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].handle;
simpleBLESvcEndHdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].grpEndHandle;
}
// If procedure complete
if ( ( pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
pMsg->hdr.status == bleProcedureComplete ) ||
( pMsg->method == ATT_ERROR_RSP ) )
{
if ( simpleBLESvcStartHdl != 0 )
{
// Discover characteristic
simpleBLEDiscState = BLE_DISC_STATE_CHAR;
req.startHandle = simpleBLESvcStartHdl;
req.endHandle = simpleBLESvcEndHdl;
req.type.len = ATT_BT_UUID_SIZE;
req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR1_UUID);
req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR1_UUID);
GATT_ReadUsingCharUUID( simpleBLEConnHandle, &req, simpleBLETaskId );
}
}
}
else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR )
{
// Characteristic found, store handle
if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&
pMsg->msg.readByTypeRsp.numPairs > 0 )
{
simpleBLECharHdl[0] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
pMsg->msg.readByTypeRsp.dataList[1] );
LCD_WRITE_STRING( "Simple Svc Found", HAL_LCD_LINE_1 );
simpleBLEProcedureInProgress = TRUE;
//simpleBLEProcedureInProgress = FALSE;
}
simpleBLEDiscState = BLE_DISC_STATE_CHAR2;
//simpleBLEDiscState = BLE_DISC_STATE_IDLE;
req.startHandle = simpleBLESvcStartHdl;
req.endHandle = simpleBLESvcEndHdl;
req.type.len = ATT_BT_UUID_SIZE;
req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR2_UUID);
req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR2_UUID);
GATT_ReadUsingCharUUID( simpleBLEConnHandle, &req, simpleBLETaskId );
}
else if (simpleBLEDiscState == BLE_DISC_STATE_CHAR2)
{ // Characteristic found, store handle
//if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&
// pMsg->msg.readByTypeRsp.numPairs > 0 )
//{
simpleBLECharHdl[1] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
pMsg->msg.readByTypeRsp.dataList[1] );
LCD_WRITE_STRING( "Simple Svc Found", HAL_LCD_LINE_1 );
simpleBLEProcedureInProgress = FALSE;
// }
simpleBLEDiscState = BLE_DISC_STATE_IDLE;
}
}
这样改后,Central能不断的读到Peripheral Char1的数据,但是读不到Char2的数据, simpleBLECharHdl[1]句柄的值一直为0。
在连接成功后,通过下面方式请求读取Peripheral的前两个Char的值
for(int i = 0; i < 2; i++)
{
attReadReq_t req;
if(simpleBLECharHdl[i] != 0)
{
req.handle = simpleBLECharHdl[i];
status = GATT_ReadCharValue( simpleBLEConnHandle, &req, simpleBLETaskId );
if ( status == SUCCESS )
{
simpleBLEProcedureInProgress = TRUE;
//simpleBLEDoWrite = !simpleBLEDoWrite;
}
}
但是没有办法同时读取Peripheral的前两个Char的值。我现在只想Central能够通过定时查询的方式,读取Peripheral的Char1和Char2的值。
现在Peripheral Char1是可读可写,Char2是只读的。
如果单独定时去读的话,Char1和Char2的值能读出来。
你试一下下面的代码, 注意红色部分:
static void simpleBLEGATTDiscoveryEvent( gattMsgEvent_t *pMsg )
{
attReadByTypeReq_t req;
if ( simpleBLEDiscState == BLE_DISC_STATE_SVC )
{
// Service found, store handles
if ( pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
pMsg->msg.findByTypeValueRsp.numInfo > 0 )
{
simpleBLESvcStartHdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].handle;
simpleBLESvcEndHdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].grpEndHandle;
}
// If procedure complete
if ( ( pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&
pMsg->hdr.status == bleProcedureComplete ) ||
( pMsg->method == ATT_ERROR_RSP ) )
{
if ( simpleBLESvcStartHdl != 0 )
{
// Discover characteristic
simpleBLEDiscState = BLE_DISC_STATE_CHAR;
req.startHandle = simpleBLESvcStartHdl;
req.endHandle = simpleBLESvcEndHdl;
req.type.len = ATT_BT_UUID_SIZE;
req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR1_UUID);
req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR1_UUID);
GATT_ReadUsingCharUUID( simpleBLEConnHandle, &req, simpleBLETaskId );
}
}
}
else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR )
{
// Characteristic found, store handle
if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&
pMsg->msg.readByTypeRsp.numPairs > 0 )
{
simpleBLECharHdl[0] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
pMsg->msg.readByTypeRsp.dataList[1] );
//LCD_WRITE_STRING( "Simple Svc Found", HAL_LCD_LINE_1 );
simpleBLEProcedureInProgress = TRUE;
//simpleBLEProcedureInProgress = FALSE;
}
// . 这里加"else", 目的为了判断pMsg->msg.readByTypeRsp.numPairs 是否为 0. 因为client 会一直查找到返回handle 为0 为止, 有可能因为设计需要, 同一个
service 里面会有两个以上相同的characteristic 定义. 只有等 char1 被查完了, 你再去发起查找char2 的流程.
else
{
simpleBLEDiscState = BLE_DISC_STATE_CHAR2;
//simpleBLEDiscState = BLE_DISC_STATE_IDLE;
req.startHandle = simpleBLESvcStartHdl;
req.endHandle = simpleBLESvcEndHdl;
req.type.len = ATT_BT_UUID_SIZE;
req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR2_UUID);
req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR2_UUID);
GATT_ReadUsingCharUUID( simpleBLEConnHandle, &req, simpleBLETaskId );
}
}
else if (simpleBLEDiscState == BLE_DISC_STATE_CHAR2)
{ // Characteristic found, store handle
// 这个判断打开, 理由同上.
if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&
pMsg->msg.readByTypeRsp.numPairs > 0 )
{
simpleBLECharHdl[1] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
pMsg->msg.readByTypeRsp.dataList[1] );
//LCD_WRITE_STRING( "Simple Svc Found", HAL_LCD_LINE_1 );
simpleBLEProcedureInProgress = FALSE;
}
simpleBLEDiscState = BLE_DISC_STATE_IDLE;
}
至少我这边用这样是没问题, 两个handle 都能得到.
主机用GATT_WriteCharValue( simpleBLEConnHandle, &req, simpleBLETaskId )给从机发送多个字节数据,提示Write Error 13,请问是什么问题?
从Central向Peripheral发送数据的经验能分享一下吗,期待哥们的回复,邮箱:zhanshijack@qq.com.
Daohong:
你好!你能把Central向Peripheral发送数据的经验分享一下吗,希望你能回我一个邮件zhanshijack@qq.com.谢谢了。
你好
请问有没有peripheral给central发送数据 已经写好的程序 自己不会写 有的话 能发送一份给我吗 邮箱382862415@qq.com
qin daohong 我想做主机从机通信 ,要先请确认主机是否把从机的CHAR4 的 notification enable打开. 这里一定要CHAR4吗 是否可以改其他char。我在从机把char4从一个字节改为多个字节了. 另外能否把in的主从机通信代码发给我参考学习 wanghgsz@163.com
我也想要参考学习能发代码参考吗? yaocing_pccu@hotmail.com