当前位置: 首页 > news >正文

zephyr架构下扫描和解析Beacon数据

目录

概述

1.  软硬件环境

1.1 软件开发环境

1.2 硬件环境 

1.2.1 Beacon功能硬件环境

 1.2.2  Observer功能硬件环境

3 Beacon功能

3.1 广播数据定义

3.2 广播功能主函数

 3.3 编译运行代码

3 observer功能

3.1 使用的主要函数

3.2 功能实现

​3.4 编译和运行

3.5 Observer的源代码 


概述

本文主要介绍基于zephyr架构下的Bluetooth接口实现Beacon功能,同时实现了Observer用于解析Beacon的数据。

1.  软硬件环境

1.1 软件开发环境

nordic提供了基于zephyr平台sdk, 其提供了大量的demo可供开发者参考和使用,同时nordi还提供一个集成的软件库工具,方便开发者安装相应的SDK和编译工具链。集成环境同时包含了其他的一些软件,非常便于进行项目开发。

软件工具功能版本信息
nRF Connect SDK nordic提供基于zephyr的代码库v2.9.0 
nRF Connect SDK Toolchain代码编译工具v2.9.1
VS-CODE集成开发环境v1.99.3 
nRF Connect for Desktopnordic集成工具链v5.1.0
nRF Connect手机App

手机App下载地址:

https://nav.nordicsemi.com/search?query=nRF%20Connect

1.2 硬件环境 

1.2.1 Beacon功能硬件环境

本案例是在nRF52832开发板(nRF52-DK)上实现的,该开发板nRF52832的主要特点如下:

1)板载j-link调试接口

2)引出所有 IO接口,用户可根据实际应用,外载其他设备

3)支持4个LED

4)支持4路Key接口

5)板载UART调试接口,方便打印调试信息

 1.2.2  Observer功能硬件环境

使用nRF52840-DK开发作为Observer功能的硬件环境,该开发板的主要特点如下:

1)开发板上使用一颗nRF52840芯片

2)板载j-link调试接口

3)引出所有 IO接口,用户可根据实际应用,外载其他设备

4)支持4个LED

5)支持4路Key接口

6)板载UART调试接口,方便打印调试信息

3 Beacon功能

3.1 广播数据定义

 基于nrf52832-DK实现Beacon功能,其主要实现周期广播数据,其数据格式定义如下:

 定义广播的数据结构体:

3.2 广播功能主函数

代码102行: 调用bt_le_adv_start开始广播,

广播的类型为: BT_LE_ADV_NCONN_IDENTITY

代码116行: 获取当前Bluetooth的MAC

完整的程序代码如下:

/* main.c - Application main entry point *//** Copyright (c) 2015-2016 Intel Corporation** SPDX-License-Identifier: Apache-2.0*/#include <zephyr/types.h>
#include <stddef.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/util.h>#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/hci.h>
#include <zephyr/bluetooth/uuid.h>#include <zephyr/bluetooth/hci.h>#if 0
#define DEVICE_NAME CONFIG_BT_DEVICE_NAME
#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)static const struct bt_data ad[] = 
{BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_NO_BREDR),BT_DATA_BYTES(BT_DATA_UUID16_ALL, 0xaa, 0xfe),BT_DATA_BYTES(BT_DATA_SVC_DATA16,0xaa, 0xfe,       /* Eddystone UUID */0x10,             /* Eddystone-URL frame type */0x00,             /* Calibrated Tx power at 0m */0x00,             /* URL Scheme Prefix http://www. */'z', 'e', 'p', 'h', 'y', 'r','p', 'r', 'o', 'j', 'e', 'c', 't',0x08) /* .org */
};/* Set Scan Response data */
static const struct bt_data sd[] = {BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
};#elsestatic uint8_t user_manufacturer_data[] = 
{0x59, 0x20,	                             //  Company ID0xAA, 0x03, 0x11, 0x22, 0x33, 0x44,       // Mac address0x2a,                                     // status of device 0X21,                                     // voltage 0x00, 0x00, 0X10, 0,                      // steps of device0X20, 0X10,                               // Date time | Temperature 0x32                                      // POWER
};/***  blue tooth device name */
#define DEVICE_USER_NAME        "BEA"
#define DEVICE_NAME_LEN	       (sizeof(DEVICE_USER_NAME) - 1)
#define BT_UUID_USER_VAL       BT_UUID_128_ENCODE(0x25b556c5, 0xf081, 0x4506, 0x1bb7, 0x608eb1234345)static const struct bt_data ad[] = 
{BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),// MANUFACTURER BT_DATA(BT_DATA_MANUFACTURER_DATA, user_manufacturer_data, sizeof(user_manufacturer_data)),// DEVICE NAME BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_USER_NAME, DEVICE_NAME_LEN),
};/* Set Scan Response data */
static const struct bt_data sd[] = 
{BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_USER_VAL),
};  #endif void ble_interface_test( void );static void bt_ready(int err)
{char addr_s[BT_ADDR_LE_STR_LEN];bt_addr_le_t addr = {0};size_t count = 1;if (err) {printk("Bluetooth init failed (err %d)\n", err);return;}printk("Bluetooth initialized\n");/* Start advertising */err = bt_le_adv_start(BT_LE_ADV_NCONN_IDENTITY, ad, ARRAY_SIZE(ad),sd, ARRAY_SIZE(sd));if (err) {printk("Advertising failed to start (err %d)\n", err);return;}/* For connectable advertising you would use* bt_le_oob_get_local().  For non-connectable non-identity* advertising an non-resolvable private address is used;* there is no API to retrieve that.*/bt_id_get(&addr, &count);bt_addr_le_to_str(&addr, addr_s, sizeof(addr_s));printk("Beacon started, advertising as %s\n", addr_s);
}int main(void)
{int err;printk("Starting Beacon Demo\n");/* Initialize the Bluetooth Subsystem */err = bt_enable(bt_ready);if (err) {printk("Bluetooth init failed (err %d)\n", err);}ble_interface_test();return 0;
}/***   get tx power * /
/* Bits 7..0 : RADIO output power. */
// #define RADIO_TXPOWER_TXPOWER_Pos (0UL) /*!< Position of TXPOWER field. */
// #define RADIO_TXPOWER_TXPOWER_Msk (0xFFUL << RADIO_TXPOWER_TXPOWER_Pos) /*!< Bit mask of TXPOWER field. */
// #define RADIO_TXPOWER_TXPOWER_0dBm (0x00UL) /*!< 0 dBm */
// #define RADIO_TXPOWER_TXPOWER_Pos3dBm (0x03UL) /*!< +3 dBm */
// #define RADIO_TXPOWER_TXPOWER_Pos4dBm (0x04UL) /*!< +4 dBm */
// #define RADIO_TXPOWER_TXPOWER_Neg40dBm (0xD8UL) /*!< -40 dBm */
// #define RADIO_TXPOWER_TXPOWER_Neg20dBm (0xECUL) /*!< -20 dBm */
// #define RADIO_TXPOWER_TXPOWER_Neg16dBm (0xF0UL) /*!< -16 dBm */
// #define RADIO_TXPOWER_TXPOWER_Neg12dBm (0xF4UL) /*!< -12 dBm */
// #define RADIO_TXPOWER_TXPOWER_Neg8dBm (0xF8UL) /*!< -8 dBm */
// #define RADIO_TXPOWER_TXPOWER_Neg4dBm (0xFCUL) /*!< -4 dBm */
// #define RADIO_TXPOWER_TXPOWER_Neg30dBm (0xFFUL) /*!< Deprecated enumerator -  -40 dBm */#include <hal/nrf_radio.h>void get_radio_tx_power(void)
{// 获取当前无线电发射功率设置int8_t radio_power = nrf_radio_txpower_get(NRF_RADIO);// 转换为dBm值const char *power_str;switch(radio_power){case RADIO_TXPOWER_TXPOWER_Pos: power_str = "+8 dBm"; break;case RADIO_TXPOWER_TXPOWER_Pos3dBm: power_str = "+3 dBm"; break;case RADIO_TXPOWER_TXPOWER_Pos4dBm: power_str = "+4 dBm"; break;case RADIO_TXPOWER_TXPOWER_Neg40dBm: power_str = "-40 dBm"; break;case RADIO_TXPOWER_TXPOWER_Neg20dBm: power_str = "-20 dBm"; break;case RADIO_TXPOWER_TXPOWER_Neg16dBm: power_str = "-163 dBm"; break;case RADIO_TXPOWER_TXPOWER_Neg12dBm: power_str = "-12 dBm"; break;case RADIO_TXPOWER_TXPOWER_Neg8dBm: power_str = "-8 dBm"; break;case RADIO_TXPOWER_TXPOWER_Neg4dBm: power_str = "-4 dBm"; break;case RADIO_TXPOWER_TXPOWER_Neg30dBm:  power_str = "-30 dBm"; break;// 其他功率等级...default: power_str = "Unknown";}printk("Radio TX power: %s, %d\n", power_str, radio_power);
}void ble_interface_test( void )
{char addr_s[BT_ADDR_LE_STR_LEN];struct bt_le_ext_adv_info info;struct bt_le_ext_adv *adv;int8_t tx_power;int err;// 先获取扩展广播实例err = bt_le_ext_adv_get_info(adv, &info);if (!err) {tx_power = info.tx_power;bt_addr_le_to_str(&info.addr, addr_s, sizeof(addr_s));printk("Advertising TX power: %d dBm\n", tx_power);printk("Advertising address:  %s \n", addr_s);printk("Advertising ID:       %d \n", info.id);} else {printk("Failed to get advertising info (err %d)\n", err);}get_radio_tx_power();
}/* End of this file */

 3.3 编译运行代码

调试终端看见如下log:

 使用手机App扫描设备,得到如下信息,说明Beacon功能以及实现了

3 observer功能

3.1 使用的主要函数

1) bt_le_scan_start

该函数是 Zephyr RTOS 蓝牙协议栈中的一个重要函数,用于启动低功耗蓝牙(BLE)扫描。

函数原型

int bt_le_scan_start(const struct bt_le_scan_param *param, bt_le_scan_cb_t cb);

参数说明

  1. param: 指向扫描参数结构体的指针

    • 类型: struct bt_le_scan_param

    • 包含扫描类型、间隔、窗口等配置

  2. cb: 扫描回调函数

    • 类型: bt_le_scan_cb_t

    • 当发现设备时调用的回调函数

2) bt_le_scan_cb_register() 函数

bt_le_scan_cb_register() 是 Zephyr RTOS 蓝牙协议栈中的一个函数,用于注册或注销低功耗蓝牙(BLE)扫描回调函数。

函数原型

void bt_le_scan_cb_register(struct bt_le_scan_cb *cb);


参数说明

  • cb: 指向扫描回调结构体的指针

    • 类型: struct bt_le_scan_cb

    • 包含回调函数指针和其他相关信息

    • 如果传入 NULL,则表示注销所有已注册的回调

3.2 功能实现

1) device_found函数

扫描设备的回调函数,在该函数中根据BT_DATA_NAME_COMPLETE获取name数据,并解析对应的数据

2)回调函数和主要函数

代码127行:实现回调函数引用

代码142行: 注册回调函数

代码146行: 开始扫描设备,发现设备后,在device_found函数中解析Beacon数据

 3.4 编译和运行

编译代码,并运作nRF52840-DK板卡上,log中已经能够解析Beacon的数据包。

3.5 Observer的源代码 

/** Copyright (c) 2022 Nordic Semiconductor ASA* Copyright (c) 2015-2016 Intel Corporation** SPDX-License-Identifier: Apache-2.0*/#include <zephyr/sys/printk.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/hci.h>#define NAME_LEN 30static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,struct net_buf_simple *ad)
{char addr_str[BT_ADDR_LE_STR_LEN];bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));//  printk("Device found: %s (RSSI %d), type %u, AD data len %u\n",//          addr_str, rssi, type, ad->len);int len =  ad->len;if( ad->data[len-3] == 'B' && ad->data[len-2] == 'E'  && ad->data[len-1] == 'A' )   {printk("\r\n"); for(int i = 0; i < ad->len; i++ ){printk(" %02x ", ad->data[i]);}  printk("\r\n");     }        
}#if defined(CONFIG_BT_EXT_ADV)
static bool data_cb(struct bt_data *data, void *user_data)
{char *name = user_data;uint8_t len;switch (data->type) {case BT_DATA_NAME_SHORTENED:case BT_DATA_NAME_COMPLETE:len = MIN(data->data_len, NAME_LEN - 1);(void)memcpy(name, data->data, len);name[len] = '\0';// printk("step-1: BT_DATA_NAME_COMPLETE \r\n");// for(int i = 0; i < data->data_len; i++ )// {//     printk(" %02x ", data->data[i]);// }  // printk("\r\n");    return false;case BT_DATA_MANUFACTURER_DATA:    //  printk(" step-2: BT_DATA_MANUFACTURER_DATA \r\n");// for(int i = 0; i < data->data_len; i++ )// {//     printk(" %02x ", data->data[i]);// }   // printk("\r\n");         return true;default:return true;}
}static const char *phy2str(uint8_t phy)
{switch (phy) {case BT_GAP_LE_PHY_NONE: return "No packets";case BT_GAP_LE_PHY_1M: return "LE 1M";case BT_GAP_LE_PHY_2M: return "LE 2M";case BT_GAP_LE_PHY_CODED: return "LE Coded";default: return "Unknown";}
}static void scan_recv(const struct bt_le_scan_recv_info *info,struct net_buf_simple *buf)
{char le_addr[BT_ADDR_LE_STR_LEN];char name[NAME_LEN];uint8_t data_status;uint16_t data_len;(void)memset(name, 0, sizeof(name));data_len = buf->len;bt_data_parse(buf, data_cb, name);data_status = BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS(info->adv_props);bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));if( memcmp(name, "BEA",3) == 0 ){// printk("[DEVICE]: %s, AD evt type %u, Tx Pwr: %i, RSSI %i "//        "Data status: %u, AD data len: %u Name: %s "//        "C:%u S:%u D:%u SR:%u E:%u Pri PHY: %s, Sec PHY: %s, "//        "Interval: 0x%04x (%u ms), SID: %u\n",//        le_addr, info->adv_type, info->tx_power, info->rssi,//        data_status, data_len, name,//        (info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) != 0,//        (info->adv_props & BT_GAP_ADV_PROP_SCANNABLE) != 0,//        (info->adv_props & BT_GAP_ADV_PROP_DIRECTED) != 0,//        (info->adv_props & BT_GAP_ADV_PROP_SCAN_RESPONSE) != 0,//        (info->adv_props & BT_GAP_ADV_PROP_EXT_ADV) != 0,//        phy2str(info->primary_phy), phy2str(info->secondary_phy),//        info->interval, info->interval * 5 / 4, info->sid);printk("\r\n");printk( " Name: %s, [DEVICE]: %s AD evt type %u Tx Pwr: %i, RSSI %i \r\n" , name, le_addr, info->adv_type, info->tx_power, info->rssi);  }// printk(" LOG DATA: \r\n");    // for(int i = 0; i < buf->len; i++ )// {//     printk(" %02x ", buf->data[i]);// }    // printk("\r\n");  
}static struct bt_le_scan_cb scan_callbacks = {.recv = scan_recv,
};
#endif /* CONFIG_BT_EXT_ADV */int observer_start(void)
{struct bt_le_scan_param scan_param = {.type       = BT_LE_SCAN_TYPE_PASSIVE,.options    = BT_LE_SCAN_OPT_FILTER_DUPLICATE,.interval   = BT_GAP_SCAN_FAST_INTERVAL,.window     = BT_GAP_SCAN_FAST_WINDOW,};int err;#if defined(CONFIG_BT_EXT_ADV)bt_le_scan_cb_register(&scan_callbacks);printk("Registered scan callbacks\n");
#endif /* CONFIG_BT_EXT_ADV */err = bt_le_scan_start(&scan_param, device_found);if (err) {printk("Start scanning failed (err %d)\n", err);return err;}printk("Started scanning...\n");return 0;
}

相关文章:

  • 安川机器人常见故障报警及解决办法
  • react有哪些生命周期
  • 基于开源AI智能名片链动2+1模式S2B2C商城小程序的IP开发泡沫破局与价值重构研究
  • Spring 提供了多种依赖注入的方式
  • 短视频矩阵系统:源码搭建与定制化开发的深度剖析
  • 怪物猎人:世界-冰原10000+mod整合包5月最新更新!
  • 【c++】【STL】stack详解
  • 游戏引擎学习第253天:重新启用更多调试界面
  • 高并发场景下的MySQL生存指南
  • MERGE存储引擎(介绍,操作),FEDERATED存储引擎(介绍,操作),不同存储引擎的特性图
  • Qt进阶开发:QSS常用的语法介绍和使用
  • 猜数字游戏:从数学原理到交互体验的完整设计指南
  • [更新完毕]2025五一杯A题五一杯数学建模思路代码文章教学:支路车流量推测问题
  • RuoYi-Vue+WuJie整合傻瓜式教程-解决keepAlive问题
  • 2025五一杯数学建模A题:支路车流量推测问题,思路分析+模型代码
  • 【FreeRTOS-列表和列表项】
  • 机器学习Day15 LightGBM算法
  • 基于机器学习的舆情分析算法研究
  • python如何word转pdf
  • 机器学习实战,天猫双十一销量与中国人寿保费预测,使用多项式回归,梯度下降,EDA数据探索,弹性网络等技术
  • 美国第一季度经济环比萎缩0.3%,特朗普:怪拜登,与关税无关
  • 乌副总理:乌美签署矿产协议
  • 中央网信办部署开展“清朗·整治AI技术滥用”专项行动
  • 澎湃回声丨23岁小伙“被精神病8年”续:今日将被移出“重精”管理系统
  • 海口市政协党组成员、秘书长、机关党组书记汪娟被查
  • 结婚这件事,年轻人到底怎么想的?