微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 无线和射频 > TI蓝牙设计交流 > 关于simpleGATTprofile的Characteristic

关于simpleGATTprofile的Characteristic

时间:10-02 整理:3721RD 点击:

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,让我等待,是不是蓝牙协议的一些流程我不熟悉导致的?

你好:

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

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

网站地图

Top