This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Peripheral如何将数据发送给Central?

Other Parts Discussed in Thread: BLE-STACK

各位大神,你们好!

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