微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 无线和射频 > TI无线射频设计 > Peripheral如何将数据发送给Central?

Peripheral如何将数据发送给Central?

时间:12-23 整理:3721RD 点击:

各位大神,你们好!

        我从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

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top