当前位置:   article > 正文

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

ble 主机例程获取广播包数据

本篇博文最后修改时间:2017年01月06日,11:06。


一、简介

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

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


二、实验平台

协议栈版本: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、广播包是什么?

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


2、广播包的格式是如何的?

答:

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

  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. // service UUID, to notify central devices what services are included
  12. // in this peripheral
  13. 0x03, // length of this data
  14. GAP_ADTYPE_16BIT_MORE, // some of the UUID's, but not all
  15. LO_UINT16( SIMPLEPROFILE_SERV_UUID ),
  16. HI_UINT16( SIMPLEPROFILE_SERV_UUID ),
  17. };


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

  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. // connection interval range
  27. 0x05, // length of this data
  28. GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE,
  29. LO_UINT16( DEFAULT_DESIRED_MIN_CONN_INTERVAL ), // 100ms
  30. HI_UINT16( DEFAULT_DESIRED_MIN_CONN_INTERVAL ),
  31. LO_UINT16( DEFAULT_DESIRED_MAX_CONN_INTERVAL ), // 1s
  32. HI_UINT16( DEFAULT_DESIRED_MAX_CONN_INTERVAL ),
  33. // Tx power level
  34. 0x02, // length of this data
  35. GAP_ADTYPE_POWER_LEVEL,
  36. 0 // 0dBm
  37. };

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

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

六、实验步骤

1、添加一个获取广播数据段的函数Get_Adtype_Data

1)定义一个获取广播数据段的函数Get_Adtype_Data(SimpleBLECentral.c中)

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

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


2)声明函数Get_Adtype_Data(SimpleBLECentral.c中)

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

2、定义一个十六进制转字符串的函数Hex_To_Str(SimpleBLECentral.c中)

  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. for ( uint8 i = 0; i < sizeof(pHex); i++ )
  12. {
  13. *pStr++ = hex[*pHex >> 4];
  14. *pStr++ = hex[*pHex++ & 0x0F];
  15. }
  16. return str;
  17. }
这里字符串大小我定了100个字节,也就是最多只能转50个十六进制。将就用吧。


3、声明函数Hex_To_Str(SimpleBLECentral.c中)

char *Hex_To_Str( uint8 *pHex );

4、分别获取广播数据与扫描应答数据的举例

1)使用举例一——获取广播数据中的数据段

①代码修改(SimpleBLECentral.c中)

  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. uint8 adType = GAP_ADTYPE_FLAGS; //需要扫描的类型数据
  14. uint8 adTypeData_index = 0; //数据段在数据包中的偏移值
  15. uint8 adTypeData_len = 0; //数据段的长度
  16. bool status = FALSE;
  17. status = Get_Adtype_Data( adType,
  18. pEvent->deviceInfo.pEvtData,
  19. pEvent->deviceInfo.dataLen,
  20. &adTypeData_index,
  21. &adTypeData_len);
  22. if(status == TRUE)
  23. {
  24. NPI_PrintString("GAP_ADTYPE_FLAGS:");
  25. NPI_WriteTransport((uint8 *)(Hex_To_Str(pEvent->deviceInfo.pEvtData + adTypeData_index)),
  26. adTypeData_len*2);
  27. NPI_PrintString("\r\n");
  28. NPI_PrintValue("size:", adTypeData_len, 10);
  29. NPI_PrintString("\r\n");
  30. }
  31. }
  32. /*
  33. {
  34. //读广播包或扫描应答包的某个数据段
  35. uint8 adType = GAP_ADTYPE_16BIT_MORE; //需要扫描的类型数据
  36. uint8 adTypeData_index = 0; //数据段在数据包中的偏移值
  37. uint8 adTypeData_len = 0; //数据段的长度
  38. bool status = FALSE;
  39. status = Get_Adtype_Data( adType,
  40. pEvent->deviceInfo.pEvtData,
  41. pEvent->deviceInfo.dataLen,
  42. &adTypeData_index,
  43. &adTypeData_len);
  44. if(status == TRUE)
  45. {
  46. NPI_PrintString("GAP_ADTYPE_16BIT_MORE:");
  47. NPI_WriteTransport((uint8 *)(Hex_To_Str(pEvent->deviceInfo.pEvtData + adTypeData_index)),
  48. adTypeData_len*2);
  49. NPI_PrintString("\r\n");
  50. NPI_PrintValue("size:", adTypeData_len, 10);
  51. NPI_PrintString("\r\n");
  52. }
  53. } */
  54. }
  55. }
  56. }
  57. break;

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

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

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


②实验结果

其中,GAP_ADTYPE_FLAGS数据段获取结果


其中,GAP_ADTYPE_16BIT_MORE数据段获取结果



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

①代码修改(SimpleBLECentral.c中)

  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. status = Get_Adtype_Data( adType,
  10. pEvent->deviceInfo.pEvtData,
  11. pEvent->deviceInfo.dataLen,
  12. &adTypeData_index,
  13. &adTypeData_len);
  14. if(status == TRUE)
  15. {
  16. //NPI_PrintValue("GAP_ADTYPE_FLAGS:", *p_adTypedata, 10);
  17. NPI_PrintString("GAP_ADTYPE_LOCAL_NAME_COMPLETE:");
  18. NPI_WriteTransport((uint8 *)(Hex_To_Str(pEvent->deviceInfo.pEvtData + adTypeData_index)),
  19. adTypeData_len*2);
  20. NPI_PrintString("\r\n");
  21. NPI_PrintValue("size:", adTypeData_len, 10);
  22. NPI_PrintString("\r\n");
  23. }
  24. }

②实验结果


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

(群友指出上面只显示2个字节的原因是:16进制转字符串的函数中,“sizeof(pHex)”只是取指针大小,因为指针是2字节大小,所以只输出了2个字节)。


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


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

  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'


因此,实验成功。


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/933275
推荐阅读
相关标签
  

闽ICP备14008679号