【BLE】CC2541之发现多个特征值句柄

本篇博文最后修改时间:2017年01月21日,13:52。


一、简介

本文介绍在主机端如何发现从机的多个特征值句柄。

注意:有群友反馈char3和char5应该要能读到特征值句柄的,本文实验中没有读到,因此我有时间时再看看是怎么回事。有人知道的话麻烦告诉我一声~谢谢


二、实验平台

协议栈版本:BLE-CC254x-1.4.0

编译软件:IAR 8.20.2

硬件平台:Smart RF开发板(主芯片CC2541)


版权声明

博主:甜甜的大香瓜

声明:喝水不忘挖井人,转载请注明出处。

原文地址:http://blog.csdn.NET/feilusia

联系方式:897503845@qq.com

香瓜BLE之CC2541群:127442605

香瓜BLE之CC2640群:557278427

香瓜BLE之Android群:541462902

香瓜单片机之STM8/STM32群:164311667
甜甜的大香瓜的小店(淘宝店):https://shop217632629.taobao.com/?spm=2013.1.1000126.d21.hd2o8i

四、 实验前提
1、在进行本文步骤前,请先 阅读 以下博文:
暂无

2、在进行本文步骤前,请先 实现以下博文:
暂无


五、基础知识

1、本文发现多个特征值句柄的思路是怎么样的?

答:

主机通过“从机服务的UUID”发现从机相对应的服务,再通过分别发送“特征值的UUID”依次获取到特征值句柄。

由于有些特征值句柄是获取不到的,所以本篇只获取char1、char2、char4(需要修改从机)和char6(从机要有char6)的特征值句柄。


2、无法通过主动获取的方式获得特征值句柄,那该怎么办?

答:例如char3的特征值句柄获取不到,我们可以通过获取到char1的特征值句柄,再进行偏移计算获得char3的特征值句柄。

假设char1的特征值句柄是0x25,通过查询属性表可知char1的value位置与char3的value位置相差6,则char3的特征值句柄=0x25+6=0x2B。


六、实验步骤

1、增加多个特征值状态的宏(sImpleBLECentral.c中)

// Discovery states
enum
{
  BLE_DISC_STATE_IDLE,                // Idle
  BLE_DISC_STATE_SVC,                 // Service discovery
  BLE_DISC_STATE_CHAR1,               // Characteristic discovery 1
  BLE_DISC_STATE_CHAR2,               // Characteristic discovery 2
  BLE_DISC_STATE_CHAR3,               // Characteristic discovery 3
  BLE_DISC_STATE_CHAR4,               // Characteristic discovery 4
  BLE_DISC_STATE_CHAR5,               // Characteristic discovery 5  
  BLE_DISC_STATE_CHAR6                // Characteristic discovery 6
};
默认的特征值状态的宏只有BLE_DISC_STATE_CHAR,因此在这里修改为6个。(具体要看从机有几个可读特征值)


2、定义一个自己存放特征句柄的数组(sImpleBLECentral.c中)

// Discovered characteristic handle
static uint16 simpleBLECharHdl = 0;
static uint16 GUA_charHdl[6] = {0};     //6个特征值句柄保存位置

当然也可以直接修改为simpleBLECharHdl[6],但这样需要修改代码中其他用到simpleBLECharHdl的地方。

为了省事,很懒的我自己定义一个GUA_charHdl[6]。


3、修改发现事件的处理函数simpleBLEGATTDiscoveryEvent(sImpleBLECentral.c中)

/*********************************************************************
 * @fn      simpleBLEGATTDiscoveryEvent
 *
 * @brief   Process GATT discovery event
 *
 * @return  none
 */
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_CHAR1;
        
        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_CHAR1 )        //发现char1
  {
    //读出char1的handle并保存到GUA_charHdl
    if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&                
         pMsg->msg.readByTypeRsp.numPairs > 0 )
    {
      GUA_charHdl[0] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
                                       pMsg->msg.readByTypeRsp.dataList[1] );


      simpleBLEProcedureInProgress = TRUE;                     //此时仍在进程中
    }


    //发送命令读取下一个特征值的句柄      
    else{                                                      //注意这里一定要else,当numPairs=0时才能再读下一个,下同    
      simpleBLEDiscState = BLE_DISC_STATE_CHAR2;
          
      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 )        //发现char2
  {
    //读出char2的handle并保存到GUA_charHdl
    if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&                
         pMsg->msg.readByTypeRsp.numPairs > 0 )
    {
      GUA_charHdl[1] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
                                       pMsg->msg.readByTypeRsp.dataList[1] );


      simpleBLEProcedureInProgress = TRUE;                     //此时仍在进程中
    }


    //发送命令读取下一个特征值的句柄      
    else{                                                           
      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_CHAR3 )        //发现char3
  {
    //读出char3的handle并保存到GUA_charHdl
    if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&                
         pMsg->msg.readByTypeRsp.numPairs > 0 )
    {
      GUA_charHdl[2] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
                                       pMsg->msg.readByTypeRsp.dataList[1] );


      simpleBLEProcedureInProgress = TRUE;                     //此时仍在进程中
    }


    //发送命令读取下一个特征值的句柄    
    else{                                                          
      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 )        //发现char4
  {
    //读出char3的handle并保存到GUA_charHdl
    if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&                
         pMsg->msg.readByTypeRsp.numPairs > 0 )
    {
      GUA_charHdl[3] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
                                       pMsg->msg.readByTypeRsp.dataList[1] );


      simpleBLEProcedureInProgress = TRUE;                     //此时仍在进程中
    }
    
    //发送命令读取下一个特征值的句柄    
    else{                                                         
      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 ); 
    }
  } 
/*
  else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR5 )        //发现char5
  {
    //读出char3的handle并保存到GUA_charHdl
    if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&                
         pMsg->msg.readByTypeRsp.numPairs > 0 )
    {
      GUA_charHdl[4] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
                                       pMsg->msg.readByTypeRsp.dataList[1] );


      simpleBLEProcedureInProgress = TRUE;                     //此时仍在进程中
    }
    
    
    //发送命令读取下一个特征值的句柄    
    else{                                                          
      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 ); 
    }   
  } 
*/  
  else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR6 )        //发现char6
  {
    // Characteristic found, store handle
    if ( pMsg->method == ATT_READ_BY_TYPE_RSP && 
         pMsg->msg.readByTypeRsp.numPairs > 0 )
    {
      GUA_charHdl[5] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],
                                       pMsg->msg.readByTypeRsp.dataList[1] );
      
      LCD_WRITE_STRING( "Char5 Found", HAL_LCD_LINE_6 );
      simpleBLEProcedureInProgress = FALSE;                     //注意最后一个特征值时需要赋值
    }
    
    simpleBLEDiscState = BLE_DISC_STATE_IDLE;                   //读完最后的char6,就可以返回闲置模式了


    
  }    
}
注意:

1)主机端只能获得“特征值属性为读、通知,并且属性表中为可读”的特征值句柄。

说的通俗一点,就是特征值的属性要为GATT_PROP_READ或GATT_PROP_NOTIFY,且属性表中对应的值的属性要为GATT_PERMIT_READ,主机端才能获取到它的特征值句柄。

例子一:

SimpleBLEPeripheral工程的char1的属性是可读可写(满足条件)

// Simple Profile Characteristic 1 Properties
static uint8 simpleProfileChar1Props = GATT_PROP_READ | GATT_PROP_WRITE;


属性表中的属性是GATT_PERMIT_READ(满足条件)

      // Characteristic Value 1
      { 
        { ATT_BT_UUID_SIZE, simpleProfilechar1UUID },
        GATT_PERMIT_READ | GATT_PERMIT_WRITE, 
        0, 
        &simpleProfileChar1 
      },
因此,主机端可获取到同时满足两个条件的char1的特征值句柄。


例子二:

SimpleBLEPeripheral工程的char3的属性是可写,不可读(不满足条件)

// Simple Profile Characteristic 3 Properties
static uint8 simpleProfileChar3Props = GATT_PROP_WRITE;

并且属性表中的属性也是GATT_PERMIT_WRITE(不满足条件)

      // Characteristic Value 3
      { 
        { ATT_BT_UUID_SIZE, simpleProfilechar3UUID },
        GATT_PERMIT_WRITE, 
        0, 
        &simpleProfileChar3 
      },
因此,主机端不能获取char3的特征值句柄。(如果想获取,需要char3修改为GATT_PROP_READ和GATT_PERMIT_READ)


例子三:

SimpleBLEPeripheral工程的char4的属性是通知(满足条件)

// Simple Profile Characteristic 4 Properties
static uint8 simpleProfileChar4Props = GATT_PROP_NOTIFY;

但是属性表中的属性是0,即不可读不可写(不满足条件)
      // Characteristic Value 4
      { 
        { ATT_BT_UUID_SIZE, simpleProfilechar4UUID },
        0, 
        0, 
        &simpleProfileChar4 
      },
因此,主机端不能获取char4的特征值句柄。(如果想获取,需要char4的属性表修改为GATT_PERMIT_READ)

2)连续读取特征值句柄时,如果中间某个特征值句柄读取失败,则会导致后续的特征值也读取不到。

3)char5的属性表的值的属性是GATT_PERMIT_AUTHEN_READ,似乎是加密的,我不熟,就暂时不考虑啦。会用的朋友可以告诉我。


七、注意事项

暂无


八、实验结果

注:char3和char5的特征值我没有去读,而char4则是修改了从机的属性表为GATT_PERMIT_READ才可读到。


九、本文仍存在的问题

1、从char1一直读到char6时,由于char3不能读,导致后面几个也读不到了。而屏蔽了char3,后面的就可以读了。

答:

目前的解决办法:屏蔽不能读的char3和char5,跳过问题。

待验证的解决方案:用GATT_DiscCharsByUUID函数获取特征值句柄。


  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值