为什么我的有关 BLE 广告的代码在发送数据包之间需要大约 1 秒的时间

问题描述 投票:0回答:1

我在Python中使用BlueZ(v5.49)编写了一个程序。目标是发送广告包 (iBeacon),并使用嗅探器将其解包并保存主要、次要和 rssi(如果 UUID 正确)。主要和次要值是用于发送数据的广告通道。

首先,我使用两个模块Sena Parani-UD100。一个发送信息,另一个接收信息。接收器工作得很好,我用我的手机和一个发送广告包的应用程序对其进行了测试,它的速度非常快,并且在接收包裹方面达到了我的预期。

所以当我用其他模块发送信息时,问题就出现了,它每秒只发送一次广告包(更实际一点,大约1.3-1.4秒),我不知道问题出在哪里以及为什么需要这样做很多。

这是我的代码:


import sys
import argparse
import os
import signal
import time
import struct
import bluetooth._bluetooth as bluez
import blescan
import random
import re

# Configurable parameters
intervalm = 1000
intervalM = 1000
tx = -55

# HCI BLE CORE COMMANDS
LE_META_EVENT = 0x3e
LE_PUBLIC_ADDRESS=0x00
LE_RANDOM_ADDRESS=0x01
LE_SET_SCAN_PARAMETERS_CP_SIZE=7
OGF_LE_CTL=0x08
OCF_LE_SET_SCAN_PARAMETERS=0x000B
OCF_LE_SET_SCAN_ENABLE=0x000C
OCF_LE_CREATE_CONN=0x000D
OCF_LE_SET_ADVERTISING_PARAMETERS=0x0006
OCF_LE_SET_ADVERTISING_DATA=0x0008
OCF_LE_SET_ADVERTISE_ENABLE=0x000A
OCF_LE_SET_RANDOM_MAC=0x0005

LE_ROLE_MASTER = 0x00
LE_ROLE_SLAVE = 0x01

# these are actually subevents of LE_META_EVENT
EVT_LE_CONN_COMPLETE=0x01
EVT_LE_ADVERTISING_REPORT=0x02
EVT_LE_CONN_UPDATE_COMPLETE=0x03
EVT_LE_READ_REMOTE_USED_FEATURES_COMPLETE=0x04

# Advertisment event types
ADV_IND=0x00
ADV_DIRECT_IND=0x01
ADV_SCAN_IND=0x02
ADV_NONCONN_IND=0x03
ADV_SCAN_RSP=0x04


def randomMAC():
    return [ 0x1A, 0x3A, 0x3e,
        random.randint(0x00, 0x7f),
        random.randint(0x00, 0xff),
    random.randint(0x00, 0xff)]


def macCanal():
    return [0x11,0x11,0x11,0x11,0x11,0x11]


def printpacket(pkt):
    for c in pkt:
        sys.stdout.write("%02x " % struct.unpack("B",c)[0])


def hci_le_set_advertising_parameters(sock, interval_min, interval_max, canal):

    min1 = interval_min/0.625
    max1 = interval_max/0.625

    if canal == 37:
        advertising_channel_map = 0x01  # 0b00000001
    elif canal == 38:
        advertising_channel_map = 0x02  # 0b00000010
    elif canal == 39:
        advertising_channel_map = 0x04  # 0b00000100
    else:
        advertising_channel_map = 0x07  # Other channels

    cmd_pkt = struct.pack("<HHBBBBBB", int(min1), int(max1), ADV_NONCONN_IND, 0x00, 0x00, 0x00, advertising_channel_map, 0x00)
    bluez.hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_SET_ADVERTISING_PARAMETERS, cmd_pkt)


def hci_le_set_advertising_data(sock, minor, major, txpower):

    min = minor
    print("Minor:", min)
    maj = major
    print("major: ", maj)

    tx = txpower
    print("tx power: ", tx)
    #uu = uuid.uuid4().hex
    uu="11111111111111111111111111111002"
    print ("UUID: ", uu)
    uui = re.findall('.{1,2}', uu) 
    txp = struct.pack(">h", int(tx))
    txup = struct.unpack("<h", txp)
    cmd_pkt = struct.pack(">BBBBBBBBBBBBBBBBBBBBBBBBBBHHh", 0x1E, 0x02, 0x01, 0x1A, 0x1A, 0xFF, 0x4C, 0x00, 0x02, 0x15, int(uui[0], 16), int(uui[1], 16), int(uui[2], 16), int(uui[3], 16), int(uui[4], 16), int(uui[5], 16), int(uui[6], 16), int(uui[7], 16), int(uui[8], 16), int(uui[9], 16), int(uui[10], 16), int(uui[11], 16), int(uui[12], 16), int(uui[13], 16), int(uui[14], 16), int(uui[15], 16), int(min), int(maj), int(txup[0]))
    bluez.hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_SET_ADVERTISING_DATA, cmd_pkt)


def hci_enable_le_advertise(sock):
    hci_toggle_le_advertise(sock, 0x01)

def hci_disable_le_advertise(sock):
    hci_toggle_le_advertise(sock, 0x00)

def hci_toggle_le_advertise(sock, enable):
    cmd_pkt = struct.pack("<B", enable)
    bluez.hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_SET_ADVERTISE_ENABLE, cmd_pkt)

def hci_set_random_mac(sock, canal):
    mac = macCanal() #BREAKPOINT#################
    if canal == 37:
        print(canal)
        cmd_pkt = struct.pack("<BBBBBB", 55, mac[4], mac[3], mac[2], mac[1], mac[0])
        bluez.hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_SET_RANDOM_MAC, cmd_pkt)
    elif canal == 38:
        print(canal)
        cmd_pkt = struct.pack("<BBBBBB", 56, mac[4], mac[3], mac[2], mac[1], mac[0])
        bluez.hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_SET_RANDOM_MAC, cmd_pkt)
    elif canal == 39:
        print(canal)
        cmd_pkt = struct.pack("<BBBBBB", 57, mac[4], mac[3], mac[2], mac[1], mac[0])
        bluez.hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_SET_RANDOM_MAC, cmd_pkt)
    else:
        print("Tres canales")
        cmd_pkt = struct.pack("<BBBBBB", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0])
        bluez.hci_send_cmd(sock, OGF_LE_CTL, OCF_LE_SET_RANDOM_MAC, cmd_pkt)

########################################################################################################################


def showAdapters():
    os.system("sudo hcitool dev")


def signal_handler(signal, frame):
    print("You pressed Ctrl+C")
    blescan.hci_disable_le_advertise(sock)
    sys.exit(0)


signal.signal(signal.SIGINT, signal_handler)
parser = argparse.ArgumentParser()
parser.add_argument("-i","--id", type=int, help="device id")
parser.add_argument("-d", "--devices", action="store_true", help="Show devices")
parser.add_argument("-t","--tx", type=int, help="Tx power")
parser.add_argument("-u","--intervalm", type=int, help="Interval min")
parser.add_argument("-U","--intervalM", type=int, help="Interval max")
parser.add_argument("-s","--sleep", type=int, help="Sleep time")
args = parser.parse_args()


if args.sleep == None:
    sleep = 1
else:
    sleep = args.sleep

if args.intervalm == None:
    intervalm = intervalm
else:
    intervalm = args.intervalm

if args.intervalM == None:
        intervalM = intervalM
else:
        intervalM = args.intervalM

if intervalM < intervalm:
    print("Max interval is smaller than min interval.")
    sys.exit(2)

if args.tx == None:
        tx = tx
else:
        tx = args.tx

if args.id == None:
    args.id = 1

if args.devices:
    showAdapters()
    sys.exit(2)


try:
    sock = bluez.hci_open_dev(args.id)
    print("ble thread started")
except:
    print("error accessing bluetooth device")
    sys.exit(1)


channel = 37  # First advertisement channel
while True:
    blescan.hci_set_random_mac(sock, channel)
    blescan.hci_le_set_advertising_parameters(sock, int(intervalm), int(intervalM), channel)
    blescan.hci_le_set_advertising_data(sock, channel, channel, int(tx))
    blescan.hci_enable_le_advertise(sock)
    time.sleep(1)
    if channel == 39:
        channel = 37
        blescan.hci_disable_le_advertise(sock)
    else:
        channel = channel + 1
        blescan.hci_disable_le_advertise(sock)

请注意,当我在启用广告后让程序进入睡眠状态时,此时必须发送很多包,但它只发送一个。

我尝试每秒发送多个包,就像 BLE 中的常规广告过程一样,但它每秒只发送一个包,因此我尝试优化代码并尝试修改包以及接收器中的过滤器,认为问题出在接收器,但这些都不起作用。经过多次研究,我最终得出结论,问题出在发射器上,对我来说,代码没问题。而且 HCI 命令的功能也如此,所以我不知道问题出在哪里。

python-3.x bluetooth-lowenergy ibeacon bluez
1个回答
0
投票

问题可能出在发射器侧。您可以使用 BlueZ HCI 命令来尝试提高广告率,如我的回答here所示(带有 hcitool 命令的 shell 脚本,抱歉,但您应该能够将其应用到 Python)。

sudo hcitool -i hci0 cmd 0x08 0x0006 A0 00 A0 00 03 00 00 00 00 00 00 00 00 07 00

hcitool 命令 (0x08 0x0006) 是“LE 设置广告 参数。前两个字节 A0 00 是“最小间隔”。这 第二个字节 A0 00 是“最大间隔”。在这个例子中,它 将广告之间的时间设置为 100 毫秒。这个的粒度 设置为 0.625ms,因此将间隔设置为 01 00 设置 每 0.625 毫秒播放一次广告。将其设置为 A0 00 设置 每 0xA0*0.625ms = 100ms 播放一次广告。

不同的 BLE 平台支持不同的广告速率(1 Hz、10 Hz 或更高),因此您可能会受到硬件方面的限制。要对此进行测试,同时消除接收器的任何问题,最简单的方法是使用移动应用程序来测量接收率。我会推荐我的 Android BeaconScope 应用程序,它提供了这些统计数据。 (还有一个 iOS 版本,但 iOS 无法测量 iBeacon 的数据包接收率,因为 API 将检测限制为每秒一次。)

© www.soinside.com 2019 - 2024. All rights reserved.