【BLE】CC2541之主机端获取广播包数据

一、简介

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


二、实验平台

协议栈版本:BLE-CC254x-1.3.2

编译软件:IAR 8.20.2

硬件平台:smart RF开发板


三、版权声明

博主:甜甜的大香瓜

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

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

联系方式:[email protected]

技术交流QQ群:127442605


四、简介广播包

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

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


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

// GAP - Advertisement data (max size = 31 bytes, though this is
// best kept short to conserve power while advertisting)
static uint8 advertData[] =
{
  // Flags; this sets the device to use limited discoverable
  // mode (advertises for 30 seconds at a time) instead of general
  // discoverable mode (advertises indefinitely)
  0x02,   // length of this data
  GAP_ADTYPE_FLAGS,
  DEFAULT_DISCOVERABLE_MODE | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED,

  // service UUID, to notify central devices what services are included
  // in this peripheral
  0x03,   // length of this data
  GAP_ADTYPE_16BIT_MORE,      // some of the UUID's, but not all
  LO_UINT16( SIMPLEPROFILE_SERV_UUID ),
  HI_UINT16( SIMPLEPROFILE_SERV_UUID ),

};


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

// GAP - SCAN RSP data (max size = 31 bytes)
static uint8 scanRspData[] =
{
  // complete name
  0x14,   // length of this data
  GAP_ADTYPE_LOCAL_NAME_COMPLETE,
  0x53,   // 'S'
  0x69,   // 'i'
  0x6d,   // 'm'
  0x70,   // 'p'
  0x6c,   // 'l'
  0x65,   // 'e'
  0x42,   // 'B'
  0x4c,   // 'L'
  0x45,   // 'E'
  0x50,   // 'P'
  0x65,   // 'e'
  0x72,   // 'r'
  0x69,   // 'i'
  0x70,   // 'p'
  0x68,   // 'h'
  0x65,   // 'e'
  0x72,   // 'r'
  0x61,   // 'a'
  0x6c,   // 'l'

  // connection interval range
  0x05,   // length of this data
  GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE,
  LO_UINT16( DEFAULT_DESIRED_MIN_CONN_INTERVAL ),   // 100ms
  HI_UINT16( DEFAULT_DESIRED_MIN_CONN_INTERVAL ),
  LO_UINT16( DEFAULT_DESIRED_MAX_CONN_INTERVAL ),   // 1s
  HI_UINT16( DEFAULT_DESIRED_MAX_CONN_INTERVAL ),

  // Tx power level
  0x02,   // length of this data
  GAP_ADTYPE_POWER_LEVEL,
  0       // 0dBm
};

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

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

五、代码修改(SimpleBLECentral.c)

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

//******************************************************************************
//name:		        Get_Adtype_Data

//introduce:            获取广播数据或扫描应答数据中adType对应的数据

//input parameter:      adType:数据类型
//                      pData:广播包或扫描应答包
//                      dataLen:广播包或扫描应答包的数据长度

//output parameter:     adTypeData_index:对应的adType类型数据的偏移值
//                      adTypeData_len:对应的adType类型数据的长度

//return:	        TRUE:找到adType类型的数据
//                      FALSE:没找到adType类型的数据
//******************************************************************************
static bool Get_Adtype_Data( uint8 adType, uint8 *pData, uint8 dataLen, uint8 *adTypeData_index, uint8 *adTypeData_len)
{  
  (void)adTypeData_index;       //防止编译报错
  (void)adTypeData_len;         //防止编译报错
  
  uint8 adLen;                  //对应数据段的长度
  uint8 *pCurrent;              //当前位置的指针
  uint8 *pEnd;                  //尾指针
    
  pEnd = pData + dataLen - 1;   //指向包尾
    
  pCurrent = pData;             //当前指针指向包头
  
  while ( pCurrent < pEnd )     //判断当前指针是否还未到包尾
  {
    adLen = *pCurrent++;        //获取本段数据段的长度
    
    if ( adLen > 0 )
    {      
      if ( adType == *pCurrent )                        //如果找到了adType
      {        
        *adTypeData_index = (pCurrent + 1) - pData;     //数据段在数据包中的偏移值
        *adTypeData_len = adLen - 1;                    //数据段长度
        
        return TRUE;                                    //返回TRUE
      }
      else                                              //没找到adType则指向下一个数据段
      {
        pCurrent += adLen;
      }
    }
  } 
  
  return FALSE;         //本数据串中没有找到adType
}

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


2、声明函数Get_Adtype_Data

static bool Get_Adtype_Data( uint8 adType, uint8 *pData, uint8 dataLen, uint8 *adTypeData_index, uint8 *adTypeData_len);

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

//**************************************************  
//name:         Hex_To_Str  
//input:        十六进制进制转字符串  
//return:       修改后的字符串  
//**************************************************  
char* Hex_To_Str( uint8 *pHex )  
{   
  char        hex[] = "0123456789ABCDEF";  
  static char str[100];  
  char        *pStr = str;  
  
  for ( uint8 i = 0; i < sizeof(pHex); i++ )  
  {  
    *pStr++ = hex[*pHex >> 4];  
    *pStr++ = hex[*pHex++ & 0x0F];  
  }  
  
  return str;  
}  
这里字符串大小我定了100个字节,也就是最多只能转50个十六进制。将就用吧。


4、声明函数Hex_To_Str

char *Hex_To_Str( uint8 *pHex );

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

代码修改:

    case GAP_DEVICE_INFO_EVENT:
      {                
        // if filtering device discovery results based on service UUID
        if ( DEFAULT_DEV_DISC_BY_SVC_UUID == TRUE )
        {
          if ( simpleBLEFindSvcUuid( SIMPLEPROFILE_SERV_UUID,
                                     pEvent->deviceInfo.pEvtData,
                                     pEvent->deviceInfo.dataLen ) )
          {
            simpleBLEAddDeviceInfo( pEvent->deviceInfo.addr, pEvent->deviceInfo.addrType );

            {
              //读广播包或扫描应答包的某个数据段
              uint8 adType = GAP_ADTYPE_FLAGS;  //需要扫描的类型数据
              uint8 adTypeData_index = 0;       //数据段在数据包中的偏移值
              uint8 adTypeData_len = 0;         //数据段的长度
              bool status = FALSE;
              
              status = Get_Adtype_Data( adType, 
                                        pEvent->deviceInfo.pEvtData,
                                        pEvent->deviceInfo.dataLen,
                                        &adTypeData_index,
                                        &adTypeData_len);
              if(status == TRUE)
              {
                NPI_PrintString("GAP_ADTYPE_FLAGS:");   
                NPI_WriteTransport((uint8 *)(Hex_To_Str(pEvent->deviceInfo.pEvtData + adTypeData_index)),
                                             adTypeData_len*2);         
                NPI_PrintString("\r\n");            
                NPI_PrintValue("size:", adTypeData_len, 10);            
                NPI_PrintString("\r\n");
              }
            } 
/* 
             {
              //读广播包或扫描应答包的某个数据段
              uint8 adType = GAP_ADTYPE_16BIT_MORE;  //需要扫描的类型数据
              uint8 adTypeData_index = 0;       //数据段在数据包中的偏移值
              uint8 adTypeData_len = 0;         //数据段的长度
              bool status = FALSE;
              
              status = Get_Adtype_Data( adType, 
                                        pEvent->deviceInfo.pEvtData,
                                        pEvent->deviceInfo.dataLen,
                                        &adTypeData_index,
                                        &adTypeData_len);
              if(status == TRUE)
              {
                NPI_PrintString("GAP_ADTYPE_16BIT_MORE:");   
                NPI_WriteTransport((uint8 *)(Hex_To_Str(pEvent->deviceInfo.pEvtData + adTypeData_index)),
                                             adTypeData_len*2);         
                NPI_PrintString("\r\n");            
                NPI_PrintValue("size:", adTypeData_len, 10);            
                NPI_PrintString("\r\n");
              }
            }  */         
          }
        }
        


      }
      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】CC2541之主机端获取广播包数据_第1张图片


2)GAP_ADTYPE_16BIT_MORE数据段获取结果

【BLE】CC2541之主机端获取广播包数据_第2张图片


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

代码修改:

    case GAP_DEVICE_INFO_EVENT:
      { 
            {
              //读广播包或扫描应答包的某个数据段
              uint8 adType = GAP_ADTYPE_LOCAL_NAME_COMPLETE;  //需要扫描的类型数据
              uint8 adTypeData_index = 0;       //数据段在数据包中的偏移值
              uint8 adTypeData_len = 0;         //数据段的长度
              bool status = FALSE;
              
              status = Get_Adtype_Data( adType, 
                                        pEvent->deviceInfo.pEvtData,
                                        pEvent->deviceInfo.dataLen,
                                        &adTypeData_index,
                                        &adTypeData_len);
              if(status == TRUE)
              {
                //NPI_PrintValue("GAP_ADTYPE_FLAGS:", *p_adTypedata, 10);
                NPI_PrintString("GAP_ADTYPE_LOCAL_NAME_COMPLETE:");   
                NPI_WriteTransport((uint8 *)(Hex_To_Str(pEvent->deviceInfo.pEvtData + adTypeData_index)),
                                             adTypeData_len*2);         
                NPI_PrintString("\r\n");            
                NPI_PrintValue("size:", adTypeData_len, 10);            
                NPI_PrintString("\r\n");
              }
            }  

实验结果:

【BLE】CC2541之主机端获取广播包数据_第3张图片

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

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

【BLE】CC2541之主机端获取广播包数据_第4张图片

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

  0x53,   // 'S'
  0x69,   // 'i'
  0x6d,   // 'm'
  0x70,   // 'p'
  0x6c,   // 'l'
  0x65,   // 'e'
  0x42,   // 'B'
  0x4c,   // 'L'
  0x45,   // 'E'
  0x50,   // 'P'
  0x65,   // 'e'
  0x72,   // 'r'
  0x69,   // 'i'
  0x70,   // 'p'
  0x68,   // 'h'
  0x65,   // 'e'
  0x72,   // 'r'
  0x61,   // 'a'
  0x6c,   // 'l'

你可能感兴趣的:(【BLE】CC2541之主机端获取广播包数据)