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.

关于simpleGATTprofile的Characteristic

simpleGATTprofile中有5个Characteristic,第4个需要启用通知才能收到,在simpleBLECentral工程中,当启用通知后,是在哪里收到数据?

求各位大神指教。

  • Hi x,

    如果你看simpleBLECentral.c 这个文件, 里面有个函数:simpleBLECentralProcessGATTMsg()

    这个函数就是处理各种从peripheral过来的数据.

    但是在示例代码中并没有加入通知, 就是notification的接收, 所以你得自己添加代码.

    很简单, 类似  if ( ( pMsg->method == ATT_READ_RSP ) || ........),  你添加  else if ( ( pMsg->method == ATT_HANDLE_VALUE_NOTI ) ||......)

  • 使能通知是向handle为0x002f写入0x0001

    gattPrepareWriteReq_t req;                

    req.handle = 0x002f;        

    req.len = 2;        

    req.pValue[0] = 0x00;        

    req.pValue[1] = 0x01;        

     req.offset = 0;        

    GATT_WriteLongCharValue( simpleBLEConnHandle, &req, simpleBLETaskId );

    但还是无法收到?

  • Hi x, 

    首先请确定你找的handle是正确的. 这个handle应该是相应的characteristic value的handle的后面一个, 就是characteristic valude的handle加 1 .

    另外, 你的 req.pValue 填错了, 上下两个请反一下.

    最后, 这里不要用write long, 用一般的写就行, 就两个字节的内容.

    下面是个例子:


    attWriteReq_t writeReq;

    writeReq.handle = 0x002f;

    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 );


  • Hi Yan,

    notification发送和接收都是在第四通道channel 4吗?

    在simpleBLEcenter例子程序里有个按键触发读写的代码:     

     // Do a read or write as long as no other read or write is in progress
          if ( simpleBLEDoWrite )
          {
            // Do a write
            attWriteReq_t req;
           
            req.handle = simpleBLECharHdl;
            req.len = 1;
            req.value[0] = simpleBLECharVal;
            req.sig = 0;
            req.cmd = 0;
            status = GATT_WriteCharValue( simpleBLEConnHandle, &req, simpleBLETaskId );        
          }

     simpleBLECharHdl 应该是第一通道 channel 1的句柄吧。

     req.value[0] = simpleBLECharVal应该是要发送的值。

    跟踪发现句柄获得,其中句柄simpleBLECharHdl = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
                                           pMsg->msg.readByTypeRsp.dataList[1] );

    那我该如何获得第四通道数据的句柄?

    还有你上面notification的例子怎么是

    writeReq.value[0] = LO_UINT16(GATT_CLIENT_CFG_NOTIFY);        这里是 0x01

    writeReq.value[1] = HI_UINT16(GATT_CLIENT_CFG_NOTIFY);          这里是 0x00

    notification的要发送的值写在哪里呢?比如我要发送一个数值0xFF,我该怎么用notification发送?

    谢谢!

  • Hi xie,

    你说的channel是什么? 第四个channel说的是第四个characteristic?

    simpleBLECharHdl这里必须是你对应的characteristic的CCC的那个句柄. CCC指的是Client Characteristic Configuration 的这个descriptor.

    CCC句柄一般是在characteristic value的句柄后面.

    句柄的顺序是characteristic declaration, characteristic  value, 然后是 CCC.

    你这个0xFF的value就填写在simpleBLECharVal里面啊.

  • Hi Yan,

    我还是不懂,我说的channel是指

    // Profile Parameters
    #define SIMPLEPROFILE_CHAR1                   0  // RW uint8 - Profile Characteristic 1 value
    #define SIMPLEPROFILE_CHAR2                   1  // RW uint8 - Profile Characteristic 2 value
    #define SIMPLEPROFILE_CHAR3                   2  // RW uint8 - Profile Characteristic 3 value
    #define SIMPLEPROFILE_CHAR4                   3  // RW uint8 - Profile Characteristic 4 value
    #define SIMPLEPROFILE_CHAR5                   4  // RW uint8 - Profile Characteristic 4 value

    第四个SIMPLEPROFILE_CHAR4 是GATT profile的第四个值,他是一个可以通过通知发送给GATT客户端设备。

    在simpleBLEcenter例子程序中有一段按键读写第一个SIMPLEPROFILE_CHAR1的值的代码,如下:

    // Do a read or write as long as no other read or write is in progress
          if ( simpleBLEDoWrite )
          {
            // Do a write
            attWriteReq_t req;
           
            req.handle = simpleBLECharHdl;
            req.len = 1;
            req.value[0] = simpleBLECharVal;
            req.sig = 0;
            req.cmd = 0;
            status = GATT_WriteCharValue( simpleBLEConnHandle, &req, simpleBLETaskId );        
          }
          else
          {
            // Do a read
            attReadReq_t req;
           
            req.handle = simpleBLECharHdl;
            status = GATT_ReadCharValue( simpleBLEConnHandle, &req, simpleBLETaskId );
          }

    这段代码很好理解,SIMPLEPROFILE_CHAR1的句柄和value值都在代码中体现了。

    但是notification的代码我就很难理解,句柄和value值还有0x01和0x00(

    writeReq.value[0] = LO_UINT16(GATT_CLIENT_CFG_NOTIFY);        这里是 0x01

    writeReq.value[1] = HI_UINT16(GATT_CLIENT_CFG_NOTIFY);          这里是 0x00

    )

    不明白什么意思。

  • writeReq.value[0] = LO_UINT16(GATT_CLIENT_CFG_NOTIFY);        这里是 0x01

    writeReq.value[1] = HI_UINT16(GATT_CLIENT_CFG_NOTIFY);          这里是 0x00

    我之前解释可能有误, 没给你讲清楚.

    这两个值目的是打开Notification功能. CCC的参数有两个, 一个Notification, 一个indication. value[0]就是打开关闭notification, value[1]是打开关闭indication.

    至于接下来notification发的值是什么, 其实就是对应的characteristic value. 

    你有空最好去看一下协议栈对spec的定义, 我这样告诉你也只是很少的比较片面的协议栈定义里面的一些内容, 如果你要更好地理解, 最好去看一下spec.

    你也可以看上面的教学视频, 也可以看上面的深度培训文档,

    最好是可以去blueooth sig 官网上下载spec:

    https://www.bluetooth.org/en-us/specification/adopted-specifications

    其中第三章 volume 3  Core System Package 里面的 part G: GENERIC ATTRIBUTE PROFILE (GATT) 里面的第三章 3 SERVICE INTEROPERABILITY REQUIREMENTS, 这里面有很详细的介绍 service, characteristic 定义的内容.

    里面的 3.3.3.3, 就是Client Characteristic Configuration 

  • 好的,非常感谢!

    我还想问一下,simpleBLEcenter例子程序中,有个simpleBLECharHdl 句柄的获得,这个句柄应该是SIMPLEPROFILE_CHAR1的句柄吧             

    simpleBLECharHdl = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
                                           pMsg->msg.readByTypeRsp.dataList[1] );

    这段什么意思呢?dataList[0],dataList[1]代表什么?假如我想获得其他SIMPLEPROFILE_CHAR的句柄该如何获得呢?比如SIMPLEPROFILE_CHAR2、SIMPLEPROFILE_CHAR3等。

    谢谢!

  • 是的.

    如果你仔细看代码, 就应该不难看出, 这里有个状态机.

    前面的状态里面的代码:

    req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR1_UUID);
    req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR1_UUID);

    GATT_ReadUsingCharUUID( simpleBLEConnHandle, &req, simpleBLETaskId );

    就是用来查找SIMPLEPROFILE_CHAR1的句柄的.

    你贴的代码就是状态机进入到找到这个句柄后的状态.

    dagaList, 你如果也仔细看代码的话, 这个就是peripheral那边回复过来的具体数据, 这里就是句柄.

    如果你要查找SIMPLEPROFILE_CHAR2,或者SIMPLEPROFILE_CHAR3, 你可以简单替换掉前面状态机里面(就是我上面贴的代码)的查找参数.

    更好的方法是你在原先的状态机里面多添加几个状态, 在查找玩CHAR1之后添加查找CHAR2, CHAR3, 等等. 也很方便, 不难.

  • 在收到CHAR1的handle后立刻查找其他特征值的handle,会找不到

    else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR )

    {

    。。。

    //simpleBLEDiscState = BLE_DISC_STATE_IDLE;

    接着查找

    if ( simpleBLESvcStartHdl != 0 )      

     {        

    // Discover characteristic         simpleBLEDiscState = BLE_DISC_STATE_CHAR6;                

     req.startHandle = simpleBLESvcStartHdl;        

    req.endHandle = simpleBLESvcEndHdl;        

    req.type.len = ATT_BT_UUID_SIZE;        

    req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR6_UUID);        

    req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR6_UUID);

    GATT_ReadUsingCharUUID( simpleBLEConnHandle, &req, simpleBLETaskId );                

    LCD_WRITE_STRING( "Finding", HAL_LCD_LINE_1 );      

    }

    }

    else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR6 )  

     {    

     // Characteristic found, store handle    

    if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&          pMsg->msg.readByTypeRsp.numPairs > 0 )    

    {      

     simpleBLECharHd6 = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],                                       

    pMsg->msg.readByTypeRsp.dataList[1] );            

    LCD_WRITE_STRING( "CHAR6 Found", HAL_LCD_LINE_1 );          

     }    

    simpleBLEDiscState = BLE_DISC_STATE_IDLE;  

    }

    如果不马上查找就可以,请问是哪里有问题?

     

     

  • 在没有收到上一个查找请求的回复之前, 再次发送查找命令, 协议栈规定不予理睬.

    这是个顺序执行的过程.

  • Hi Yan,

    你的意思是查找多个句柄的时候,应该收到上一个查找请求的回复之后才能再次发送查找命令吗?在例程中,查找请求回复是在哪个地方?能不能给我讲解一下查找多个句柄时的完整流程是怎么样的?

    谢谢!

  • Hi lv,

    你说:“在收到CHAR1的handle后立刻查找其他特征值的handle,会找不到;如果不马上查找就可以”。当我发现CHAR1的句柄之后再查找其他特征值,该如何做?接下来该怎么样再次发送查找句柄命令(函数)?

    谢谢!

  • Hi Yan,

    我尝试了几次,然后用这种方法再次查找,终于发现了CHAR4的句柄,如下红色部分:

    static void simpleBLECentralProcessGATTMsg( gattMsgEvent_t *pMsg )
    {

    ……

      else if ( simpleBLEDiscState != BLE_DISC_STATE_IDLE )
      {
        simpleBLEGATTDiscoveryEvent( pMsg );
    /*=====================================================*/
        simpleBLEGATTDiscoveryEvent( pMsg );   //再次执行
    /*=====================================================*/
      } 
    }

    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 = 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;
      //}
     /*================================================================================*/
        if ( simpleBLESvcStartHdl != 0 )
        {
            // Discover characteristic
          simpleBLEDiscState = BLE_DISC_STATE_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 );
        }
      }
      else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR4 )
      {
        // Characteristic found, store handle
        if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&
                pMsg->msg.readByTypeRsp.numPairs > 0 )
        {
           simpleBLECharHd4 = 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;   
       
      }
    /*================================================================================*/
    }

    在线调试可以看到CHAR4的句柄:simpleBLECharHd4 =0x0025;

    但是我感觉这样写的程序比较纠结、不顺眼,如下:

      else if ( simpleBLEDiscState != BLE_DISC_STATE_IDLE )
      {

        simpleBLEGATTDiscoveryEvent( pMsg );
    /*=====================================================*/
        simpleBLEGATTDiscoveryEvent( pMsg );   //再次执行
    /*=====================================================*/

    }

    执行一次,再执行一次一样的函数,感觉非常的2,还有没有更好的方法?

    谢谢!

  • Hi Yan:

    请问在Central程序中,第四个Characteristic是在哪里启动的呢?我GATT_notification()==success;成立的是不是代表底层通讯已经成功了?需要做的就是主机端的数据读取。

  • 兄弟,你太厉害了。我都调了好长时间都没找到CHAR4的句柄。

  • 你确定你或的这个句柄对吗?我感觉获得的这个句柄还是CHAR1的句柄吧

  • 好像还真是,晕。不知道怎么弄,你调出来了吗?

  • 我是哪里出了问题呢?明明用的是CHAR4的UUID。怎么变成CHAR1的句柄呢?

  • 没有,我以为你调出来了呢,然后我也试了以下,发现得到的不是CHAR4的句柄,还是CHAR1的句柄。

    我看不懂TI工程师说的那个状态机。

  • 我也是看的一头雾水。我猜我那代码应该是接着发现特征值时,函数调用出问题了,调用早了,里面存的还是CHAR1的句柄,没等发现CHAR4的句柄。

  • 其实咱俩的问题是同一个问题。就是能不能同时获得Peripheral提供的5个CHAR的句柄。只有的得到这些句柄,Central和Peripheral才能更方便地相互传递数据。

  • Hi Yan,

    关于CHAR4句柄获得问题,我将例程中static void simpleBLEGATTDiscoveryEvent( gattMsgEvent_t *pMsg )函数中的SIMPLEPROFILE_CHAR1_UUID替换为SIMPLEPROFILE_CHAR4_UUID,但是下载到开发板上,设备根本无法发现服务,无法获得CHAR4的UUID. 问题出在哪呢?代码如下,红色部分是被我修改的地方。

    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);
            req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR4_UUID);
            req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR4_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 = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
                                           pMsg->msg.readByTypeRsp.dataList[1] );*/
          simpleBLECharHd4 = 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;

       
      }   
    }

  • 经过实验:

    SIMPLEPROFILE_CHAR3_UUID,

    SIMPLEPROFILE_CHAR4_UUID,

    SIMPLEPROFILE_CHAR5_UUID.

    这三个UUID的句柄都无法被单独发现。只有SIMPLEPROFILE_CHAR1_UUID和SIMPLEPROFILE_CHAR2_UUID可以。

  • Hi xie,

    不好意思, 要读这几个char 还有几个地方要改.

    GATT_ReadUsingCharUUID() 需要read 属性支持. 加上read

    // Simple Profile Characteristic 3 Properties
    static uint8 simpleProfileChar3Props = GATT_PROP_WRITE;                           //只有write, 没有read

    // Simple Profile Characteristic 4 Properties

    static uint8 simpleProfileChar4Props = GATT_PROP_NOTIFY;                          //只有notiry, 没有read

    char 5 则是因为被定义为 需要鉴权参能读它

    // Characteristic Value 5
    {
    { ATT_BT_UUID_SIZE, simpleProfilechar5UUID },
    GATT_PERMIT_AUTHEN_READ,
    0,
    simpleProfileChar5
    },


  • Hi Yan,

    我这几天想了一下,也猜到是这个原因。但是我想问:像notification的句柄该如何去发现呢,因为当我们要使能notification的时候必须先知道它的句柄啊。

  • Hi xie,

    每个service 都有个表格, 以simpleBLEPripheral 为例, 有 simpleProfileAttrTbl[], 是个数组.

    以其中的char4 为例, 你可以用类似 simpleProfileAttrTbl[ char4_val_idx ]. handle 来得到hanle 的值. char4_val_idx 你可以在表格里面数一下, 就是attribute 在表格中的位置.

  • Hi Yan,

    我发现这个simpleProfileAttrTbl[]数组只在simpleBLEPeripheral例程中有定义。那么当我们在simpleBLEcenter里要用到CHAR4的句柄时,我们是不是只能间接获得CHAR4的句柄?比如在线调试simpleBLEPeripheral程序在IAR里面通过 simpleProfileAttrTbl[ char4_val_idx ]. handle 来得到hanle 的值,或者通过BTool获得CHAR4的句柄,然后再用到simpleBLEcenter程序中使能notification吗?

  • Hi,

        我如何才能找到正确的handle,本人刚接触BLE不久。

  • 请问各种消息响应从peripheral传过来后就直接调用simpleBLECentralProcessGATTMsg()函数么?还是要在Central中写入请求

  • HI ,前面的大神, 请问你们有调通notification吗??

    我当前是在central端的simpleBLECentralProcessGATTMsg函数中写了关于notification的处理,但是从消息获取的method是response error

    请大神们指点下

  • 感觉怪怪的,怎么你的char4 的句柄跟char1 的一样啊

    我的char4一直没找到,按照你的方法找出来的是

    0x0025

    但我一执行一次查找Char 1 和char 2

    Char1 Handler 0x0025

    Char2 Handler 0x0028

  • 哦哦,没看后面的,感谢了,对上面哪位兄弟说声抱歉了,我没看后面的帖子。不好意思了

  • Hi Yan

        恕我愚笨,我在simpleBLEGATTDiscoveryEvent用以下程序获得Char4的Handler(实际上没反应)

    static void simpleBLEGATTDiscoveryEvent( gattMsgEvent_t *pMsg )
    {
        attReadByTypeReq_t req;
        uint16 IWantSerchUUID=0;
        /*
        Serch_CharNum
        7                 6-0
        EnableSerch       SercherNum
        */
        switch(Serch_CharNum&0x7f)
        {
        case 0 :IWantSerchUUID=SIMPLEPROFILE_CHAR1_UUID;
        break;
        case 1 :IWantSerchUUID=SIMPLEPROFILE_CHAR3_UUID;
        break;
        default:
          simpleBLEProcedureInProgress = FALSE;
          break;
        }
        
        if ( simpleBLEDiscState == BLE_DISC_STATE_SVC )
        {
          if(!(Serch_CharNum&0x80))
          {
            // 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 )
            {
              Serch_CharNum|=0x80;
            }
          } 
          if((Serch_CharNum&0x80))
          {
              // 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(IWantSerchUUID);
              req.type.uuid[1] = HI_UINT16(IWantSerchUUID);
      
              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[(Serch_CharNum&0x7f)] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
                                             pMsg->msg.readByTypeRsp.dataList[1] );
            //simpleBLEProcedureInProgress = TRUE;
            Serch_CharNum++;
            simpleBLEDiscState=BLE_DISC_STATE_SVC;
          }else if((pMsg->method == ATT_ERROR_RSP))
          {
            SerialPrintString("Not Find The Handle");
            SerialPrintValue("Read Error", pMsg->msg.errorRsp.errCode, 10);SerialPrintString("\r\n");
            simpleBLEDiscState = BLE_DISC_STATE_IDLE;
          }
            
        }
        
        if(simpleBLEProcedureInProgress == FALSE )
        {
          SerialPrintValue("simpleBLECharHdl[0]:",simpleBLECharHdl[0],16);
          SerialPrintString("\r\n");
          SerialPrintValue("simpleBLECharHdl[1]:",simpleBLECharHdl[1],16);
          SerialPrintString("\r\n");
          SerialPrintString("Simple Svc Found\r\n");
        }
    }

    但现在还是读不到Handle啊

    读 Char2的还是找得到

  • 相应的characteristic value的handle,这个handle怎样确定???

  • 哥们,你已经可以读连续两个handle了??

  • 没有,我刚接触,不是很了解,为什么要读取handle?为了主从机之间的通信?

  • 那你可以先看下TI官网的资料,https://www.bluetooth.org/en-us/specification/adopted-specifications

    里面对profile的定义啊 挺详细的

  • 对,我的目的就是读两个handler,方便对比,但现在差不多解决了

    首先是从机里面就先定义好了读写的规范,

    然后如果能读写,读写的服务程序也必不可少,

    我之前吧这些属性该了,但没发现自己读写的程序中没读的服务程序

    所以才一直没读出来的

  • 工程师,你好!

              我按照你的方法, 把 Characteristic 4 添加了读的权限,但是客户端还是读不到句柄,

    GATT_PROP_READ 以及GATT_PERMIT_AUTHEN_READ

    // Simple Profile Characteristic 4 Properties

     static uint8 simpleProfileChar4Props =  GATT_PROP_READ | GATT_PROP_NOTIFY; 

    你有测试过吗?帮忙指点一下,谢谢

  • 原来我漏掉了一个权限,把这个加上就可以读出CHAR 4的特征值的地址了。

    // Characteristic Value 4
    {
    { ATT_BT_UUID_SIZE, simpleProfilechar4UUID },
    GATT_PERMIT_READ | GATT_PERMIT_WRITE, //本来是0的,自己加上读写权限
    0,
    &simpleProfileChar4
    },

    要想读出CHAR 4需要设置两个地方的权限:

    1、

    // Simple Profile Characteristic 4 Properties

     static uint8 simpleProfileChar4Props =  GATT_PROP_READ | GATT_PROP_NOTIFY; //增加GATT_PROP_READ

    2、属性表中

    // Characteristic Value 4

    { ATT_BT_UUID_SIZE, simpleProfilechar4UUID },
    GATT_PERMIT_READ | GATT_PERMIT_WRITE, //本来是0的,自己加上读写权限
    0, 
    &simpleProfileChar4 
    },

    论坛给我了指导,也希望能够帮助大家

  • hi sizao

     

    大神,你是一次性同时获取多个handle吗?在主机里面是调用simpleBLEGATTDiscoveryEvent( gattMsgEvent_t *pMsg )这个函数发现handle吗?

    你有测试过GATT_DiscCharsByUUID( uint16 connHandle, attReadByTypeReq_t *pReq, uint8 taskId );这个函数吗?

  • Hi Yan

    GATT_WriteCharValue()参数中有个simpleBLEConnHandle,这个参数是simpleBLECentral.c文件中的本文件全局变量,我一直都是不太明白这个参数的含义。谢谢关注。CQ_JIMI

  • 嗨 Yan,首先我是自己建立另外一个特征值char8,长度15;我按着你这个例程对特征值通知开通了,主机中开通通知代码如下

    if( keys & HAL_KEY_SW_1 )
      {
        //使能char8通知
        attWriteReq_t attReq;
        uint8 pValue[2];
        attReq.handle = 0x0040;    //这里我用的是btool软件Read/Write功能发现特征值功能,发现char8的句柄是0x003f,然后handle+1 =0x0040
        attReq.len = 2;
        attReq.sig = 0;
        attReq.cmd = 0;
        pValue[0] = LO_UINT16( GATT_CLIENT_CFG_NOTIFY );   //0X01
        pValue[1] = HI_UINT16( GATT_CLIENT_CFG_NOTIFY );   //0X00
        osal_memcpy( attReq.value, pValue, 2 );
        GATT_WriteCharValue( simpleBLEConnHandle, &attReq, simpleBLETaskId );
        NPI_WriteTransport( "Notification enabled", osal_strlen("Notification enabled") );
        
      }

    但是我并不知道从机是否相应的给我开通了通知;然后我从peripheral串口助手发送一串字符,在串口回调函数中对从串口接收到的数据更新特征值8的值,

    从机中串口代码如下

    static void NpiSerialCallback(uint8 port ,uint8 events )
    {
      (void)port;
      uint8 numBytes=0;
      uint8 buf[128];
      if(events & HAL_UART_RX_TIMEOUT)  //串口有数据,
      {
        numBytes=NPI_RxBufLen();  //读出串口有多少数据
        if(numBytes)
        {
          if(numBytes >= SIMPLEPROFILE_CHAR8_LEN )
            buf[0] =  SIMPLEPROFILE_CHAR8_LEN -1;
          else
            buf[0] = numBytes;
          
          //从串口缓冲区读出nuBytes个字节数据
          NPI_ReadTransport( &buf[1], buf[0] );
          SimpleProfile_SetParameter(SIMPLEPROFILE_CHAR8, SIMPLEPROFILE_CHAR8_LEN, buf);
          //把接收到的数据在打印出来
          //NPI_WriteTransport(buf,numBytes);
          
        }
      }
    }

    现在的问题是,我从串口发送一串字符过去,主机那边不能进入这个simpleBLECentralProcessGATTMsg消息处理函数中。

    其中我对通知的处理代码如下:

     else if( pMsg->method == ATT_HANDLE_VALUE_NOTI )
      {
        //串口打印char8通知,由从机通知过来char8的值
        if(pMsg->msg.handleValueNoti.handle == 0x003F )
        {
          if( pMsg->msg.handleValueNoti.value[0] >= 15 )
          {
            NPI_WriteTransport( &pMsg->msg.handleValueNoti.value[1], 14 );
            NPI_WriteTransport("....\n", 5);
          }
          else
          {
            NPI_WriteTransport( &pMsg->msg.handleValueNoti.value[1], pMsg->msg.handleValueNoti.value[0] );
    
          }
        }
        
      }

    谢谢Yan的关注,我叫CQ_JIMI

  • 你为什么不用attHandleValueNoti_t?

  • CQ_JIMI 

    你的问题解决了么? 我现在和你一模一样卡在了这里,无法获得从机的特征值句柄,我跟踪了一下,在CCCD位写入使能01 00 后返回一个0x16的数值,我查了一下,这个数值是 waiting的意思,应该是没有读取到 所以我就不确定自己写入的01 00 是否真的到达了从机。困扰一个星期了,希望你能帮我一下

  • 我是直接从表里读的:pReport.handle =  simpleProfileAttrTbl[11].handle;//读取notification对应的handle

  • 你好:

           我用GATT_ReadUsingCharUUID获取的conhandle为0x25,是char1的句柄,然后用GATT_ReadCharValue获取特征值,返回值为0x16,让我等待,是不是蓝牙协议的一些流程我不熟悉导致的?

  • 你好:

          请问你问题解决了吗?我遇到了