<蓝牙BLE>cc2540主机获取数据包

转自大香瓜的博客。


一、简介

本篇以SimpleBLECentral工程为例,介绍CC2541作为主机时是如何获取从机广播包数据的。


二、实验平台

协议栈版本:BLE-CC254x-1.3.2

编译软件:IAR 8.20.2

硬件平台:smart RF开发板


三、简介广播包

广播包是从机端发出的数据包。

注:本篇中的“广播包”包含“广播包数据”和“扫描应答数据”。


1、SimpleBLEPeripheral工程中的广播数据包格式如下:

[cpp]  view plain copy
  1. // GAP - Advertisement data (max size = 31 bytes, though this is  
  2. // best kept short to conserve power while advertisting)  
  3. static uint8 advertData[] =  
  4. {  
  5.   // Flags; this sets the device to use limited discoverable  
  6.   // mode (advertises for 30 seconds at a time) instead of general  
  7.   // discoverable mode (advertises indefinitely)  
  8.   0x02,   // length of this data  
  9.   GAP_ADTYPE_FLAGS,  
  10.   DEFAULT_DISCOVERABLE_MODE | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED,  
  11.   
  12.   // service UUID, to notify central devices what services are included  
  13.   // in this peripheral  
  14.   0x03,   // length of this data  
  15.   GAP_ADTYPE_16BIT_MORE,      // some of the UUID's, but not all  
  16.   LO_UINT16( SIMPLEPROFILE_SERV_UUID ),  
  17.   HI_UINT16( SIMPLEPROFILE_SERV_UUID ),  
  18.   
  19. };  


2、SimpleBLEPeripheral工程中的扫描应答数据包格式如下:

[cpp]  view plain copy
  1. // GAP - SCAN RSP data (max size = 31 bytes)  
  2. static uint8 scanRspData[] =  
  3. {  
  4.   // complete name  
  5.   0x14,   // length of this data  
  6.   GAP_ADTYPE_LOCAL_NAME_COMPLETE,  
  7.   0x53,   // 'S'  
  8.   0x69,   // 'i'  
  9.   0x6d,   // 'm'  
  10.   0x70,   // 'p'  
  11.   0x6c,   // 'l'  
  12.   0x65,   // 'e'  
  13.   0x42,   // 'B'  
  14.   0x4c,   // 'L'  
  15.   0x45,   // 'E'  
  16.   0x50,   // 'P'  
  17.   0x65,   // 'e'  
  18.   0x72,   // 'r'  
  19.   0x69,   // 'i'  
  20.   0x70,   // 'p'  
  21.   0x68,   // 'h'  
  22.   0x65,   // 'e'  
  23.   0x72,   // 'r'  
  24.   0x61,   // 'a'  
  25.   0x6c,   // 'l'  
  26.   
  27.   // connection interval range  
  28.   0x05,   // length of this data  
  29.   GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE,  
  30.   LO_UINT16( DEFAULT_DESIRED_MIN_CONN_INTERVAL ),   // 100ms  
  31.   HI_UINT16( DEFAULT_DESIRED_MIN_CONN_INTERVAL ),  
  32.   LO_UINT16( DEFAULT_DESIRED_MAX_CONN_INTERVAL ),   // 1s  
  33.   HI_UINT16( DEFAULT_DESIRED_MAX_CONN_INTERVAL ),  
  34.   
  35.   // Tx power level  
  36.   0x02,   // length of this data  
  37.   GAP_ADTYPE_POWER_LEVEL,  
  38.   0       // 0dBm  
  39. };  

广播数据包和扫描应答数据包的数据格式,都是由多个“数据长度+数据类型+数据”组成。

因此,我们可以通过判断数据类型,来获取这个类型的数据。

四、代码修改(SimpleBLECentral.c)

1、定义一个获取广播数据段的函数Get_Adtype_Data

[cpp]  view plain copy
  1. //******************************************************************************  
  2. //name:             Get_Adtype_Data  
  3.   
  4. //introduce:            获取广播数据或扫描应答数据中adType对应的数据  
  5.   
  6. //input parameter:      adType:数据类型  
  7. //                      pData:广播包或扫描应答包  
  8. //                      dataLen:广播包或扫描应答包的数据长度  
  9.   
  10. //output parameter:     adTypeData_index:对应的adType类型数据的偏移值  
  11. //                      adTypeData_len:对应的adType类型数据的长度  
  12.   
  13. //return:           TRUE:找到adType类型的数据  
  14. //                      FALSE:没找到adType类型的数据  
  15. //******************************************************************************  
  16. static bool Get_Adtype_Data( uint8 adType, uint8 *pData, uint8 dataLen, uint8 *adTypeData_index, uint8 *adTypeData_len)  
  17. {    
  18.   (void)adTypeData_index;       //防止编译报错  
  19.   (void)adTypeData_len;         //防止编译报错  
  20.     
  21.   uint8 adLen;                  //对应数据段的长度  
  22.   uint8 *pCurrent;              //当前位置的指针  
  23.   uint8 *pEnd;                  //尾指针  
  24.       
  25.   pEnd = pData + dataLen - 1;   //指向包尾  
  26.       
  27.   pCurrent = pData;             //当前指针指向包头  
  28.     
  29.   while ( pCurrent < pEnd )     //判断当前指针是否还未到包尾  
  30.   {  
  31.     adLen = *pCurrent++;        //获取本段数据段的长度  
  32.       
  33.     if ( adLen > 0 )  
  34.     {        
  35.       if ( adType == *pCurrent )                        //如果找到了adType  
  36.       {          
  37.         *adTypeData_index = (pCurrent + 1) - pData;     //数据段在数据包中的偏移值  
  38.         *adTypeData_len = adLen - 1;                    //数据段长度  
  39.           
  40.         return TRUE;                                    //返回TRUE  
  41.       }  
  42.       else                                              //没找到adType则指向下一个数据段  
  43.       {  
  44.         pCurrent += adLen;  
  45.       }  
  46.     }  
  47.   }   
  48.     
  49.   return FALSE;         //本数据串中没有找到adType  
  50. }  

该函数是我参考simpleBLEFindSvcUuid写出来的,通过这个函数可以找出某个类型的数据段位置。


2、声明函数Get_Adtype_Data

[cpp]  view plain copy
  1. static bool Get_Adtype_Data( uint8 adType, uint8 *pData, uint8 dataLen, uint8 *adTypeData_index, uint8 *adTypeData_len);  

3、定义一个十六进制转字符串的函数Hex_To_Str

[cpp]  view plain copy
  1. //**************************************************    
  2. //name:         Hex_To_Str    
  3. //input:        十六进制进制转字符串    
  4. //return:       修改后的字符串    
  5. //**************************************************    
  6. char* Hex_To_Str( uint8 *pHex )    
  7. {     
  8.   char        hex[] = "0123456789ABCDEF";    
  9.   static char str[100];    
  10.   char        *pStr = str;    
  11.     
  12.   for ( uint8 i = 0; i < sizeof(pHex); i++ )    
  13.   {    
  14.     *pStr++ = hex[*pHex >> 4];    
  15.     *pStr++ = hex[*pHex++ & 0x0F];    
  16.   }    
  17.     
  18.   return str;    
  19. }    
这里字符串大小我定了100个字节,也就是最多只能转50个十六进制。将就用吧。


4、声明函数Hex_To_Str

[cpp]  view plain copy
  1. char *Hex_To_Str( uint8 *pHex );  

5、使用举例一——获取广播数据

代码修改:

[cpp]  view plain copy
  1. case GAP_DEVICE_INFO_EVENT:  
  2.   {                  
  3.     // if filtering device discovery results based on service UUID  
  4.     if ( DEFAULT_DEV_DISC_BY_SVC_UUID == TRUE )  
  5.     {  
  6.       if ( simpleBLEFindSvcUuid( SIMPLEPROFILE_SERV_UUID,  
  7.                                  pEvent->deviceInfo.pEvtData,  
  8.                                  pEvent->deviceInfo.dataLen ) )  
  9.       {  
  10.         simpleBLEAddDeviceInfo( pEvent->deviceInfo.addr, pEvent->deviceInfo.addrType );  
  11.   
  12.         {  
  13.           //读广播包或扫描应答包的某个数据段  
  14.           uint8 adType = GAP_ADTYPE_FLAGS;  //需要扫描的类型数据  
  15.           uint8 adTypeData_index = 0;       //数据段在数据包中的偏移值  
  16.           uint8 adTypeData_len = 0;         //数据段的长度  
  17.           bool status = FALSE;  
  18.             
  19.           status = Get_Adtype_Data( adType,   
  20.                                     pEvent->deviceInfo.pEvtData,  
  21.                                     pEvent->deviceInfo.dataLen,  
  22.                                     &adTypeData_index,  
  23.                                     &adTypeData_len);  
  24.           if(status == TRUE)  
  25.           {  
  26.             NPI_PrintString("GAP_ADTYPE_FLAGS:");     
  27.             NPI_WriteTransport((uint8 *)(Hex_To_Str(pEvent->deviceInfo.pEvtData + adTypeData_index)),  
  28.                                          adTypeData_len*2);           
  29.             NPI_PrintString("\r\n");              
  30.             NPI_PrintValue("size:", adTypeData_len, 10);              
  31.             NPI_PrintString("\r\n");  
  32.           }  
  33.         }   
  34.   
  35.          {  
  36.           //读广播包或扫描应答包的某个数据段  
  37.           uint8 adType = GAP_ADTYPE_16BIT_MORE;  //需要扫描的类型数据  
  38.           uint8 adTypeData_index = 0;       //数据段在数据包中的偏移值  
  39.           uint8 adTypeData_len = 0;         //数据段的长度  
  40.           bool status = FALSE;  
  41.             
  42.           status = Get_Adtype_Data( adType,   
  43.                                     pEvent->deviceInfo.pEvtData,  
  44.                                     pEvent->deviceInfo.dataLen,  
  45.                                     &adTypeData_index,  
  46.                                     &adTypeData_len);  
  47.           if(status == TRUE)  
  48.           {  
  49.             NPI_PrintString("GAP_ADTYPE_16BIT_MORE:");     
  50.             NPI_WriteTransport((uint8 *)(Hex_To_Str(pEvent->deviceInfo.pEvtData + adTypeData_index)),  
  51.                                          adTypeData_len*2);           
  52.             NPI_PrintString("\r\n");              
  53.             NPI_PrintValue("size:", adTypeData_len, 10);              
  54.             NPI_PrintString("\r\n");  
  55.           }  
  56.         }  */           
  57.       }  
  58.     }  
  59.       
  60.   
  61.   
  62.   }  
  63.   break;  


在GAP_DEVICE_INFO_EVENT事件中会有广播数据包和扫描应答数据包进来,因此本段代码先判断了UUID来确认此数据包是“广播数据包”。

然后再通过Get_adType_Data去获取GAP_ADTYPE_FLAGS数据段的数据。

注:注释部分是获取GAP_ADTYPE_16BIT_MORE数据段的代码,由于串口同一时间打印太多会不好使,所以我分开来编译GAP_ADTYPE_FLAGS数据段和GAP_ADTYPE_16BIT_MORE数据段的代码。


实验结果:

1)GAP_ADTYPE_FLAGS数据段获取结果

<蓝牙BLE>cc2540主机获取数据包_第1张图片


2)GAP_ADTYPE_16BIT_MORE数据段获取结果

<蓝牙BLE>cc2540主机获取数据包_第2张图片


6、使用举例二——获取扫描应答数据包的设备名称段

代码修改:

[cpp]  view plain copy
  1. case GAP_DEVICE_INFO_EVENT:  
  2.   {   
  3.         {  
  4.           //读广播包或扫描应答包的某个数据段  
  5.           uint8 adType = GAP_ADTYPE_LOCAL_NAME_COMPLETE;  //需要扫描的类型数据  
  6.           uint8 adTypeData_index = 0;       //数据段在数据包中的偏移值  
  7.           uint8 adTypeData_len = 0;         //数据段的长度  
  8.           bool status = FALSE;  
  9.             
  10.           status = Get_Adtype_Data( adType,   
  11.                                     pEvent->deviceInfo.pEvtData,  
  12.                                     pEvent->deviceInfo.dataLen,  
  13.                                     &adTypeData_index,  
  14.                                     &adTypeData_len);  
  15.           if(status == TRUE)  
  16.           {  
  17.             //NPI_PrintValue("GAP_ADTYPE_FLAGS:", *p_adTypedata, 10);  
  18.             NPI_PrintString("GAP_ADTYPE_LOCAL_NAME_COMPLETE:");     
  19.             NPI_WriteTransport((uint8 *)(Hex_To_Str(pEvent->deviceInfo.pEvtData + adTypeData_index)),  
  20.                                          adTypeData_len*2);           
  21.             NPI_PrintString("\r\n");              
  22.             NPI_PrintValue("size:", adTypeData_len, 10);              
  23.             NPI_PrintString("\r\n");  
  24.           }  
  25.         }    

实验结果:

<蓝牙BLE>cc2540主机获取数据包_第3张图片

串口输出结果不太好用,只输出了设备名的前两个字节“0x53(S)”和“0x69(i)”。

所以在仿真中直接查看设备名是否有被获取到:

<蓝牙BLE>cc2540主机获取数据包_第4张图片

对照下面这个设备名,可见设备名已经存在于pEvent->deviceInfo.pEvtData中了,并且首地址是“pEvent->deviceInfo.pEvtData + adTypeData_index”,长度是adTypeData_len的0x13个(19个)。

[cpp]  view plain copy
  1. 0x53,   // 'S'  
  2. 0x69,   // 'i'  
  3. 0x6d,   // 'm'  
  4. 0x70,   // 'p'  
  5. 0x6c,   // 'l'  
  6. 0x65,   // 'e'  
  7. 0x42,   // 'B'  
  8. 0x4c,   // 'L'  
  9. 0x45,   // 'E'  
  10. 0x50,   // 'P'  
  11. 0x65,   // 'e'  
  12. 0x72,   // 'r'  
  13. 0x69,   // 'i'  
  14. 0x70,   // 'p'  
  15. 0x68,   // 'h'  
  16. 0x65,   // 'e'  
  17. 0x72,   // 'r'  
  18. 0x61,   // 'a'  
  19. 0x6c,   // 'l'  

你可能感兴趣的:(蓝牙,数据包,BLE)