<蓝牙BLE>cc2540发现多个特征值句柄

转自大香瓜的博客。


一、简介

本篇在《CC2541的SimpleBLECentral发现服务与特征值过程》的基础上,进一步讲述主机端如何发现从机的多个特征值句柄。


二、实验平台

协议栈版本:BLE-CC254x-1.3.2

编译软件:IAR 8.20.2


三、思路

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

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


四、实现过程

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

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


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

[cpp]  view plain copy
  1. // Discovered characteristic handle  
  2. static uint16 simpleBLECharHdl = 0;  
  3. static uint16 GUA_charHdl[6] = {0};     //6个特征值句柄保存位置  

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

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


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

[cpp]  view plain copy
  1. /********************************************************************* 
  2.  * @fn      simpleBLEGATTDiscoveryEvent 
  3.  * 
  4.  * @brief   Process GATT discovery event 
  5.  * 
  6.  * @return  none 
  7.  */  
  8. static void simpleBLEGATTDiscoveryEvent( gattMsgEvent_t *pMsg )  
  9. {  
  10.   attReadByTypeReq_t req;  
  11.     
  12.   if ( simpleBLEDiscState == BLE_DISC_STATE_SVC )  
  13.   {  
  14.     // Service found, store handles  
  15.     if ( pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP &&  
  16.          pMsg->msg.findByTypeValueRsp.numInfo > 0 )  
  17.     {  
  18.       simpleBLESvcStartHdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].handle;  
  19.       simpleBLESvcEndHdl = pMsg->msg.findByTypeValueRsp.handlesInfo[0].grpEndHandle;  
  20.     }  
  21.       
  22.     // If procedure complete  
  23.     if ( ( pMsg->method == ATT_FIND_BY_TYPE_VALUE_RSP  &&   
  24.            pMsg->hdr.status == bleProcedureComplete ) ||  
  25.          ( pMsg->method == ATT_ERROR_RSP ) )  
  26.     {  
  27.       if ( simpleBLESvcStartHdl != 0 )  
  28.       {  
  29.         // Discover characteristic  
  30.         simpleBLEDiscState = BLE_DISC_STATE_CHAR1;  
  31.           
  32.         req.startHandle = simpleBLESvcStartHdl;  
  33.         req.endHandle = simpleBLESvcEndHdl;  
  34.         req.type.len = ATT_BT_UUID_SIZE;  
  35.         req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR1_UUID);  
  36.         req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR1_UUID);  
  37.   
  38.   
  39.         GATT_ReadUsingCharUUID( simpleBLEConnHandle, &req, simpleBLETaskId );  
  40.       }  
  41.     }  
  42.   }  
  43.     
  44.   else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR1 )        //发现char1  
  45.   {  
  46.     //读出char1的handle并保存到GUA_charHdl  
  47.     if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&                  
  48.          pMsg->msg.readByTypeRsp.numPairs > 0 )  
  49.     {  
  50.       GUA_charHdl[0] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],  
  51.                                        pMsg->msg.readByTypeRsp.dataList[1] );  
  52.   
  53.   
  54.       simpleBLEProcedureInProgress = TRUE;                     //此时仍在进程中  
  55.     }  
  56.   
  57.   
  58.     //发送命令读取下一个特征值的句柄        
  59.     else{                                                      //注意这里一定要else,当numPairs=0时才能再读下一个,下同      
  60.       simpleBLEDiscState = BLE_DISC_STATE_CHAR2;  
  61.             
  62.       req.startHandle = simpleBLESvcStartHdl;  
  63.       req.endHandle = simpleBLESvcEndHdl;  
  64.       req.type.len = ATT_BT_UUID_SIZE;  
  65.       req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR2_UUID);  
  66.       req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR2_UUID);  
  67.   
  68.   
  69.       GATT_ReadUsingCharUUID( simpleBLEConnHandle, &req, simpleBLETaskId );  
  70.     }  
  71.   }    
  72.     
  73.   else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR2 )        //发现char2  
  74.   {  
  75.     //读出char2的handle并保存到GUA_charHdl  
  76.     if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&                  
  77.          pMsg->msg.readByTypeRsp.numPairs > 0 )  
  78.     {  
  79.       GUA_charHdl[1] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],  
  80.                                        pMsg->msg.readByTypeRsp.dataList[1] );  
  81.   
  82.   
  83.       simpleBLEProcedureInProgress = TRUE;                     //此时仍在进程中  
  84.     }  
  85.   
  86.   
  87.     //发送命令读取下一个特征值的句柄        
  88.     else{                                                             
  89.       simpleBLEDiscState = BLE_DISC_STATE_CHAR4;  
  90.             
  91.       req.startHandle = simpleBLESvcStartHdl;  
  92.       req.endHandle = simpleBLESvcEndHdl;  
  93.       req.type.len = ATT_BT_UUID_SIZE;  
  94.       req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR4_UUID);  
  95.       req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR4_UUID);  
  96.   
  97.   
  98.       GATT_ReadUsingCharUUID( simpleBLEConnHandle, &req, simpleBLETaskId );      
  99.     }  
  100.   }    
  101. /*     
  102.   else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR3 )        //发现char3 
  103.   { 
  104.     //读出char3的handle并保存到GUA_charHdl 
  105.     if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&                 
  106.          pMsg->msg.readByTypeRsp.numPairs > 0 ) 
  107.     { 
  108.       GUA_charHdl[2] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0], 
  109.                                        pMsg->msg.readByTypeRsp.dataList[1] ); 
  110.  
  111.  
  112.       simpleBLEProcedureInProgress = TRUE;                     //此时仍在进程中 
  113.     } 
  114.  
  115.  
  116.     //发送命令读取下一个特征值的句柄     
  117.     else{                                                           
  118.       simpleBLEDiscState = BLE_DISC_STATE_CHAR4; 
  119.            
  120.       req.startHandle = simpleBLESvcStartHdl; 
  121.       req.endHandle = simpleBLESvcEndHdl; 
  122.       req.type.len = ATT_BT_UUID_SIZE; 
  123.       req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR4_UUID); 
  124.       req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR4_UUID); 
  125.  
  126.  
  127.       GATT_ReadUsingCharUUID( simpleBLEConnHandle, &req, simpleBLETaskId );  
  128.     } 
  129.   }     
  130. */  
  131.   else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR4 )        //发现char4  
  132.   {  
  133.     //读出char3的handle并保存到GUA_charHdl  
  134.     if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&                  
  135.          pMsg->msg.readByTypeRsp.numPairs > 0 )  
  136.     {  
  137.       GUA_charHdl[3] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],  
  138.                                        pMsg->msg.readByTypeRsp.dataList[1] );  
  139.   
  140.   
  141.       simpleBLEProcedureInProgress = TRUE;                     //此时仍在进程中  
  142.     }  
  143.       
  144.     //发送命令读取下一个特征值的句柄      
  145.     else{                                                           
  146.       simpleBLEDiscState = BLE_DISC_STATE_CHAR6;  
  147.             
  148.       req.startHandle = simpleBLESvcStartHdl;  
  149.       req.endHandle = simpleBLESvcEndHdl;  
  150.       req.type.len = ATT_BT_UUID_SIZE;  
  151.       req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR6_UUID);  
  152.       req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR6_UUID);  
  153.   
  154.   
  155.       GATT_ReadUsingCharUUID( simpleBLEConnHandle, &req, simpleBLETaskId );   
  156.     }  
  157.   }   
  158. /* 
  159.   else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR5 )        //发现char5 
  160.   { 
  161.     //读出char3的handle并保存到GUA_charHdl 
  162.     if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&                 
  163.          pMsg->msg.readByTypeRsp.numPairs > 0 ) 
  164.     { 
  165.       GUA_charHdl[4] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0], 
  166.                                        pMsg->msg.readByTypeRsp.dataList[1] ); 
  167.  
  168.  
  169.       simpleBLEProcedureInProgress = TRUE;                     //此时仍在进程中 
  170.     } 
  171.      
  172.      
  173.     //发送命令读取下一个特征值的句柄     
  174.     else{                                                           
  175.       simpleBLEDiscState = BLE_DISC_STATE_CHAR6; 
  176.            
  177.       req.startHandle = simpleBLESvcStartHdl; 
  178.       req.endHandle = simpleBLESvcEndHdl; 
  179.       req.type.len = ATT_BT_UUID_SIZE; 
  180.       req.type.uuid[0] = LO_UINT16(SIMPLEPROFILE_CHAR6_UUID); 
  181.       req.type.uuid[1] = HI_UINT16(SIMPLEPROFILE_CHAR6_UUID); 
  182.  
  183.  
  184.       GATT_ReadUsingCharUUID( simpleBLEConnHandle, &req, simpleBLETaskId );  
  185.     }    
  186.   }  
  187. */    
  188.   else if ( simpleBLEDiscState == BLE_DISC_STATE_CHAR6 )        //发现char6  
  189.   {  
  190.     // Characteristic found, store handle  
  191.     if ( pMsg->method == ATT_READ_BY_TYPE_RSP &&   
  192.          pMsg->msg.readByTypeRsp.numPairs > 0 )  
  193.     {  
  194.       GUA_charHdl[5] = BUILD_UINT16( pMsg->msg.readByTypeRsp.dataList[0],  
  195.                                        pMsg->msg.readByTypeRsp.dataList[1] );  
  196.         
  197.       LCD_WRITE_STRING( "Char5 Found", HAL_LCD_LINE_6 );  
  198.       simpleBLEProcedureInProgress = FALSE;                     //注意最后一个特征值时需要赋值  
  199.     }  
  200.       
  201.     simpleBLEDiscState = BLE_DISC_STATE_IDLE;                   //读完最后的char6,就可以返回闲置模式了  
  202.   
  203.   
  204.       
  205.   }      
  206. }  
注意:

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

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

例子一:

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

[cpp]  view plain copy
  1. // Simple Profile Characteristic 1 Properties  
  2. static uint8 simpleProfileChar1Props = GATT_PROP_READ | GATT_PROP_WRITE;  


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

[cpp]  view plain copy
  1. // Characteristic Value 1  
  2. {   
  3.   { ATT_BT_UUID_SIZE, simpleProfilechar1UUID },  
  4.   GATT_PERMIT_READ | GATT_PERMIT_WRITE,   
  5.   0,   
  6.   &simpleProfileChar1   
  7. },  
因此,主机端可获取到同时满足两个条件的char1的特征值句柄。


例子二:

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

[cpp]  view plain copy
  1. // Simple Profile Characteristic 3 Properties  
  2. static uint8 simpleProfileChar3Props = GATT_PROP_WRITE;  

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

[cpp]  view plain copy
  1. // Characteristic Value 3  
  2. {   
  3.   { ATT_BT_UUID_SIZE, simpleProfilechar3UUID },  
  4.   GATT_PERMIT_WRITE,   
  5.   0,   
  6.   &simpleProfileChar3   
  7. },  
因此,主机端不能获取char3的特征值句柄。(如果想获取,需要char3修改为GATT_PROP_READ和GATT_PERMIT_READ)


例子三:

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

[cpp]  view plain copy
  1. // Simple Profile Characteristic 4 Properties  
  2. static uint8 simpleProfileChar4Props = GATT_PROP_NOTIFY;  

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

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

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


五、实验结果

<蓝牙BLE>cc2540发现多个特征值句柄_第1张图片

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


六、此方法存在的问题

实验中发现:从char1一直读到char6时,由于char3不能读,导致后面几个也读不到了。而屏蔽了char3,后面的就可以读了。

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

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


你可能感兴趣的:(蓝牙,特征值,BLE)