BLE 扫描间隔 Windows 10
Posted
技术标签:
【中文标题】BLE 扫描间隔 Windows 10【英文标题】:BLE Scan Interval Windows 10 【发布时间】:2016-05-18 18:17:49 【问题描述】:在 Windows 10 上使用Windows.Devices.Bluetooth.Advertisement.BluetoothLEAdvertisementWatcher
时,有什么方法可以调整 BLE 广告扫描间隔?在 android 上扫描时,我每 100 毫秒看到一次广告,但在使用 C# 的 Windows 10 上,我每 700 毫秒只会收到一个 BluetoothLEAdvertisementWatcher.Received
事件。
【问题讨论】:
【参考方案1】:我猜不是。
扫描参数被硬编码为 118.125 ms 的扫描间隔和 18.125 ms 的扫描窗口。
这就是为什么您只能获得所有数据包的 1/7(因为 18.125 / 118.125 约为 1/7)。
但是,您可以使用 DeviceIoControl 来执行更底层的操作。这是一个例子。您必须与您的 BluetoothLEAdvertisementWatcher 并行运行它(例如 BetterScanner.StartScanner(0, 29, 29)
)。如果两个扫描仪同时处于活动状态,Windows 似乎总是选择“最佳”参数。
DeviceIoControl 永远不会返回,所以我在单独的线程中运行它。如果您需要能够取消扫描,则必须使用重叠 io 才能执行 CancelIoEx。此代码不会检查错误,因此请注意。
using System;
using System.Runtime.InteropServices;
using System.Threading;
class BetterScanner
/// <summary>
/// The BLUETOOTH_FIND_RADIO_PARAMS structure facilitates enumerating installed Bluetooth radios.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
private struct BLUETOOTH_FIND_RADIO_PARAM
internal UInt32 dwSize;
internal void Initialize()
this.dwSize = (UInt32)Marshal.SizeOf(typeof(BLUETOOTH_FIND_RADIO_PARAM));
/// <summary>
/// Closes an open object handle.
/// </summary>
/// <param name="handle">[In] A valid handle to an open object.</param>
/// <returns>If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error information, call GetLastError.</returns>
[DllImport("Kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr handle);
/// <summary>
/// Finds the first bluetooth radio present in device manager
/// </summary>
/// <param name="pbtfrp">Pointer to a BLUETOOTH_FIND_RADIO_PARAMS structure</param>
/// <param name="phRadio">Pointer to where the first enumerated radio handle will be returned. When no longer needed, this handle must be closed via CloseHandle.</param>
/// <returns>In addition to the handle indicated by phRadio, calling this function will also create a HBLUETOOTH_RADIO_FIND handle for use with the BluetoothFindNextRadio function.
/// When this handle is no longer needed, it must be closed via the BluetoothFindRadioClose.
/// Returns NULL upon failure. Call the GetLastError function for more information on the error. The following table describe common errors:</returns>
[DllImport("irprops.cpl", SetLastError = true)]
static extern IntPtr BluetoothFindFirstRadio(ref BLUETOOTH_FIND_RADIO_PARAM pbtfrp, out IntPtr phRadio);
[StructLayout(LayoutKind.Sequential)]
private struct LE_SCAN_REQUEST
internal int scanType;
internal ushort scanInterval;
internal ushort scanWindow;
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)]
static extern bool DeviceIoControl(IntPtr hDevice, uint dwIoControlCode,
ref LE_SCAN_REQUEST lpInBuffer, uint nInBufferSize,
IntPtr lpOutBuffer, uint nOutBufferSize,
out uint lpBytesReturned, IntPtr lpOverlapped);
/// <summary>
/// Starts scanning for LE devices.
/// Example: BetterScanner.StartScanner(0, 29, 29)
/// </summary>
/// <param name="scanType">0 = Passive, 1 = Active</param>
/// <param name="scanInterval">Interval in 0.625 ms units</param>
/// <param name="scanWindow">Window in 0.625 ms units</param>
public static void StartScanner(int scanType, ushort scanInterval, ushort scanWindow)
var thread = new Thread(() =>
BLUETOOTH_FIND_RADIO_PARAM param = new BLUETOOTH_FIND_RADIO_PARAM();
param.Initialize();
IntPtr handle;
BluetoothFindFirstRadio(ref param, out handle);
uint outsize;
LE_SCAN_REQUEST req = new LE_SCAN_REQUEST scanType = scanType, scanInterval = scanInterval, scanWindow = scanWindow ;
DeviceIoControl(handle, 0x41118c, ref req, 8, IntPtr.Zero, 0, out outsize, IntPtr.Zero);
);
thread.Start();
【讨论】:
对此进行了测试,效果非常好!现在拿起所有的广告。 谢谢,它似乎确实有效。我不确定如何停止线程,因为 DeviceIoControl 永远不会返回,也没有办法触发它返回。你认为它需要使用 Overlapped IO 来实现异步吗?当涉及到设备驱动程序时,我已经脱离了我的元素。另外,您从哪里获得传递给 DeviceIoControl 的值 0x41118c? 我只在 C 中做过这个,所以如果你使用 C#,你需要使用一些 P/Invokes。您需要创建一个 OVERLAPPED 结构,其中包含一个由 CreateEvent(NULL, FALSE, FALSE, NULL) 分配的事件对象。在 DeviceIoControl 的最后一个参数中传递一个指向该结构的指针。如果一切正常,它将返回 false 和 GetLastError() == ERROR_IO_PENDING。当你想取消时,使用相同的句柄和重叠结构调用 CancelIoEx。在使用 bWait=TRUE 调用 GetOverlappedResult 之后立即。然后你需要在事件上调用 CloseHandle (或者干脆保存它并在下次重复使用)。 有ioctl可以改变发布间隔吗?似乎不是一成不变的。有时使用 BluetoothLEAdvertisementPublisher 会每 100 毫秒发出一次,有时它会每 5-6 秒发出一些广告。 为我工作!但我很想知道您从哪里获得该值 (0x41118c)?【参考方案2】:如果您设置 SamplingInterval,SignalStrengthFilter 的频率可能会改变。试试这个:
BluetoothLEAdvertisementWatcher watcher=new BluetoothLEAdvertisementWatcher();
watcher.SignalStrengthFilter.SamplingInterval = 100;
【讨论】:
这对我不起作用。仍然收到 700 毫秒的响应。【参考方案3】:对于 Windows 通用应用程序,请尝试将 StartScanner 更改如下:
public static void StartScanner(int scanType, ushort scanInterval, ushort scanWindow)
Action<object> action = (object obj) =>
BLUETOOTH_FIND_RADIO_PARAM param = new BLUETOOTH_FIND_RADIO_PARAM();
param.Initialize();
IntPtr handle;
BluetoothFindFirstRadio(ref param, out handle);
uint outsize;
LE_SCAN_REQUEST req = new LE_SCAN_REQUEST
scanType = scanType,
scanInterval = scanInterval,
scanWindow = scanWindow
;
DeviceIoControl(handle, 0x41118c, ref req, 8, IntPtr.Zero, 0, out outsize, IntPtr.Zero);
;
Task task = new Task(action,"nothing");
task.Start();
【讨论】:
以上是关于BLE 扫描间隔 Windows 10的主要内容,如果未能解决你的问题,请参考以下文章