美文网首页物联网loT从业者物联网相关技术研究
CC2640R2F学习笔记(18)——主机端不连接获取从机数据

CC2640R2F学习笔记(18)——主机端不连接获取从机数据

作者: Leung_ManWah | 来源:发表于2019-04-25 18:29 被阅读2次

    一、背景

    链路层(LL)控制设备的射频状态,有五个设备状态:待机、广播、扫描、初始化和连接。

    广播 为广播数据包,而 扫描 则是监听广播。

    GAP通信中角色,中心设备(Central - 主机)用来扫描和连接 外围设备(Peripheral - 从机)

    大部分情况下外围设备通过广播自己来让中心设备发现自己,并建立 GATT 连接,从而进行更多的数据交换。

    也有些情况是不需要连接的,只要外设广播自己的数据即可,用这种方式主要目的是让外围设备,把自己的信息发送给多个中心设备。

    1.1 不连接方式获取从机信息的意义

    不连接的方式下,从机的广播信息可发给无数台主机。
    比如从机是 ibeacon 且被放置于商场的厕所,周边的人只需要使用 app 等蓝牙主机进行扫描
    ibeacon,即可导向至厕所。

    1.2 主机可以获取的从机信息

    • addr - 6字节MAC地址
    • rssi - 信号强度,可用于测距、定位
    • *pEvtData - 该数据为广播包或者扫描应答包取决于当前主机收到数据包的类型

    二、添加文件和程序

    2.1 添加头文件

    #include <stdlib.h>
    #include <string.h>
    

    2.2 添加获取广播数据或扫描应答的函数

    /**
     @brief 获取广播数据或扫描应答数据中adType对应的数据函数
     @param adType 数据类型
     @param pData 广播包或扫描应答包
     @param pAdTypeData_index 对应的adType类型数据的偏移值
     @param pAdTypeData_len 对应的adType类型数据的长度
     @return TRUE - 成功;FALSE - 失败
    */
    static bool getAdtypeData(uint8 adType, uint8 *pData, uint8 dataLen, uint8 *pAdTypeData_index, uint8 *pAdTypeData_len)
    {
        (void)pAdTypeData_index;                                        // 防止编译报错
        (void)pAdTypeData_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
                {
                    *pAdTypeData_index = (pCurrent + 1) - pData;        // 数据段在数据包中的偏移值
                    *pAdTypeData_len = adLen - 1;                       // 数据段长度
    
                    return TRUE;
                }
                else                                                    // 没找到adType则指向下一个数据段
                {
                    pCurrent += adLen;
                }
            }
        }
    
        return FALSE;                                                   // 本数据串中没有找到adType
    }
    

    2.3 添加十六进制转字符串的函数

    /**
     @brief 十六进制数组转字符串
     @param pHexArr 十六进制数组
     @param hexArrLen 数组长度
     @return 字符串数组
    */
    char *HexArr2Str(uint8 *pHexArr, uint8 hexArrLen)
    {
        char hexStr[] = "0123456789ABCDEF";
        char destStr[hexArrLen * 2];
        char *pDestStr = destStr;
    
        for(uint8 i = hexArrLen; i > 0; i--)
        {
            *pDestStr++ = hexStr[*pHexArr >> 4];
            *pDestStr++ = hexStr[*pHexArr++ & 0x0F];
        }
    
        return destStr;
    }
    

    三、使用方法

    3.1 获取MAC地址和RSSI

    以SDK2.4 multi_role工程为例,在 multi_role_processRoleEvent()函数的GAP_DEVICE_INFO_EVENT扫描过滤部分

    case GAP_DEVICE_INFO_EVENT:
    {
      if(ENABLE_UNLIMITED_SCAN_RES == FALSE)
      {
        multi_role_addDeviceInfo(pEvent->deviceInfo.addr,
                                  pEvent->deviceInfo.addrType);
    
        uint8 deviceAddr[6] = {0};
        uint8 currDevRssi = 0;
    
        // MAC地址
        deviceAddr[0] = pEvent->deviceInfo.addr[5];
        deviceAddr[1] = pEvent->deviceInfo.addr[4];
        deviceAddr[2] = pEvent->deviceInfo.addr[3];
        deviceAddr[3] = pEvent->deviceInfo.addr[2];
        deviceAddr[4] = pEvent->deviceInfo.addr[1];
        deviceAddr[5] = pEvent->deviceInfo.addr[0];
        // RSSI
        pEvent->deviceInfo.rssi = pEvent->deviceInfo.rssi + 128;
        currDevRssi = pEvent->deviceInfo.rssi;
        
        // 显示MAC地址
        UART_Send("found device:", 13);
        UART_Send(HexArr2Str(deviceAddr, 6));
        UART_Send("\r\n", 2);
        // 显示RSSI
        char rssi[10] = {0};
        sprintf(rssi, "rssi:%d\r\n", (int)currDevRssi);
        UART_Send((uint8 *)rssi, strlen(rssi));
    }
    

    3.2 获取名称字段数据

    以SDK2.4 multi_role工程为例,在 multi_role_processRoleEvent()函数的GAP_DEVICE_INFO_EVENT扫描过滤部分

    case GAP_DEVICE_INFO_EVENT:
    {
      if(ENABLE_UNLIMITED_SCAN_RES == FALSE)
      {
        multi_role_addDeviceInfo(pEvent->deviceInfo.addr,
                                  pEvent->deviceInfo.addrType);
    
        uint8 nameAdType = GAP_ADTYPE_LOCAL_NAME_COMPLETE;  // 名称字段
        uint8 nameAdTypeData_index = 0;                     // 名称字段在数据包中的偏移值
        uint8 nameAdTypeData_len = 0;                       // 名称字段的长度
        char *pFiltering_Name1 = "Y11";
    
        // 获取名称字段数据
        if(getAdtypeData(nameAdType, pEvent->deviceInfo.pEvtData,
                          pEvent->deviceInfo.dataLen, &nameAdTypeData_index, 
                          &nameAdTypeData_len))
        {
          // 自定义处理,如根据名称1进行过滤
          if(memcmp((pEvent->deviceInfo.pEvtData+nameAdTypeData_index), pFiltering_Name1, 3) == 0)
          {
            ···
          }
        }
      }
    }
    

    3.3 获取自定义FF段数据

    以SDK2.4 multi_role工程为例,在 multi_role_processRoleEvent()函数的GAP_DEVICE_INFO_EVENT扫描过滤部分

    case GAP_DEVICE_INFO_EVENT:
    {
      if(ENABLE_UNLIMITED_SCAN_RES == FALSE)
      {
        multi_role_addDeviceInfo(pEvent->deviceInfo.addr,
                                  pEvent->deviceInfo.addrType);
    
        uint8 customAdType = GAP_ADTYPE_MANUFACTURER_SPECIFIC;  // 自定义FF字段
        uint8 customAdTypeData_index = 0;                       // 自定义FF字段在数据包中的偏移值
        uint8 customAdTypeData_len = 0;                         // 自定义FF字段的长度
    
        // 获取自定义FF段数据
        if(getAdtypeData(customAdType, pEvent->deviceInfo.pEvtData,
                          pEvent->deviceInfo.dataLen, &customAdTypeData_index,
                          &customAdTypeData_len))
        {
          // 自定义处理,如拷贝FF段数据前4字节
          uint8 cacheValue[4] = {0};
          memcpy(cacheValue, (pEvent->deviceInfo.pEvtData + customAdTypeData_index), 4);
        }
      }
    }
    

    • 由 Leung 写于 2019 年 4 月 25 日

    • 参考:【BLE-CC2640】CC2640之主机端获取广播包数据

    相关文章

      网友评论

        本文标题:CC2640R2F学习笔记(18)——主机端不连接获取从机数据

        本文链接:https://www.haomeiwen.com/subject/nxmagqtx.html