问题描述
我找到了调整BLE扫描窗口大小的解决方案:BLE Scan Interval Windows 10
但是,它不起作用。 扫描时会丢失许多信标。
using System;
using System.Linq;
using Windows.Devices.Bluetooth.Advertisement;
using Windows.Storage.Streams;
namespace BeaconExample
{
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
class BetterScanner
{
static Task task;
/// <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 UInt32 unkNown1;
internal UInt32 scanType;
internal UInt32 unkNown2;
internal UInt16 scanInterval;
internal UInt16 scanWindow;
internal UInt32[] unkNown3;
}
*/
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(UInt32 scanType,UInt16 scanInterval,UInt16 scanWindow)
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
{
unkNown1 = 0,scanType = scanType,unkNown2 = 0,scanInterval = scanInterval,scanWindow = scanWindow,unkNown3 = new UInt32[2] {0,0}
};
*/
LE_SCAN_REQUEST req = new LE_SCAN_REQUEST
{
scanType = scanType,};
bool ret = DeviceIoControl(handle,0x41118c,ref req,8,IntPtr.Zero,out outsize,IntPtr.Zero);
Console.WriteLine("DeviceControl ret=" + ret);
if(ret == false)
{
var error = Marshal.GetLastWin32Error();
Console.WriteLine("The last Win32 Error was: " + error);
}
};
task = new Task(action,"nothing");
task.Start();
}
public static void StopScanner()
{
Console.WriteLine("BetterScanner Stop");
task.Wait();
}
}
class Program
{
const String UUID = "44790ba4-7eb3-4095-9e14-4b43ae67512b";
const ushort MAJOR = 40033;
const short RSSI = -40;
private class BeaconData
{
public Guid Uuid { get; set; }
public ushort Major { get; set; }
public ushort Minor { get; set; }
public byte Battery { get; set; }
public static BeaconData FromBytes(byte[] bytes)
{
//if (bytes[0] != 0x02) { throw new ArgumentException("First byte in array was exptected to be 0x02","bytes"); }
//if (bytes[1] != 0x15) { throw new ArgumentException("Second byte in array was expected to be 0x15","bytes"); }
//if (bytes.Length != 23) { throw new ArgumentException("Byte array length was expected to be 23","bytes"); }
return new BeaconData
{
Uuid = new Guid(
BitConverter.ToInt32(bytes.Skip(2).Take(4).Reverse().ToArray(),0),BitConverter.ToInt16(bytes.Skip(6).Take(2).Reverse().ToArray(),BitConverter.ToInt16(bytes.Skip(8).Take(2).Reverse().ToArray(),bytes.Skip(10).Take(8).ToArray()),Major = BitConverter.ToUInt16(bytes.Skip(18).Take(2).Reverse().ToArray(),Minor = BitConverter.ToUInt16(bytes.Skip(20).Take(2).Reverse().ToArray(),Battery = (byte)((byte)bytes[23] & (byte)0x7F)
};
}
public static BeaconData FromBuffer(IBuffer buffer)
{
var bytes = new byte[buffer.Length];
if(bytes.Length !=24)
{
return null;
}
using (var reader = DataReader.FromBuffer(buffer))
{
reader.ReadBytes(bytes);
}
return BeaconData.FromBytes(bytes);
}
}
static void Main(string[] args)
{
var watcher = new bluetoothleadvertisementwatcher();
watcher.Received += Watcher_Received;
//watcher.SignalStrengthFilter.InRangeThresholdindBm = RSSI;
//watcher.SignalStrengthFilter.OutOfRangeThresholdindBm = RSSI-10;
watcher.SignalStrengthFilter.SamplingInterval = TimeSpan.FromMilliseconds(100);
watcher.ScanningMode = BluetoothLEScanningMode.Passive;
BetterScanner.StartScanner(0,29);
watcher.Start();
Console.WriteLine("Bluetooth LE Advertisement Watcher Started (Press ESC to exit)");
while (Console.ReadKey().Key != ConsoleKey.Escape)
{
}
watcher.Stop();
BetterScanner.StopScanner();
Console.WriteLine("Bluetooth LE Advertisement Watcher Stopped");
}
private static void Watcher_Received(bluetoothleadvertisementwatcher sender,BluetoothLEAdvertisementReceivedEventArgs args)
{
const ushort AppleCompanyId = 0x004C;
Int16 RSSi = args.RawSignalStrengthInDBm;
foreach (var adv in args.Advertisement.ManufacturerData.Where(x => x.CompanyId == AppleCompanyId))
{
var beaconData = BeaconData.FromBuffer(adv.Data);
if(beaconData == null)
{
continue;
}
if (beaconData.Uuid.ToString() == UUID && beaconData.Major == MAJOR)
{
if (RSSi < RSSI)
{
Console.WriteLine("RSSI=" + RSSi+ ","+beaconData.Uuid+"_"+ beaconData.Major + "_" + beaconData.Minor);
continue;
}
Console.WriteLine(
"UUID={0},Major={1},Minor={2},Battery={3},RSSi={4}",beaconData.Uuid,beaconData.Major,beaconData.Minor,beaconData.Battery,args.RawSignalStrengthInDBm);
}
}
}
}
}
DeviceControl返回false,但最后一个错误代码为0,并且仍然进行延迟扫描。
DeviceControl ret=False
Bluetooth LE Advertisement Watcher Started (Press ESC to exit)
The last Win32 Error was: 0
RSSI=-50,44790ba4-7eb3-4095-9e14-4b43ae67512b_40033_6
RSSI=-50,44790ba4-7eb3-4095-9e14-4b43ae67512b_40033_6
RSSI=-51,44790ba4-7eb3-4095-9e14-4b43ae67512b_40033_6
RSSI=-73,44790ba4-7eb3-4095-9e14-4b43ae67512b_40033_9
RSSI=-50,44790ba4-7eb3-4095-9e14-4b43ae67512b_40033_6
RSSI=-70,44790ba4-7eb3-4095-9e14-4b43ae67512b_40033_18
RSSI=-50,44790ba4-7eb3-4095-9e14-4b43ae67512b_40033_6
RSSI=-74,44790ba4-7eb3-4095-9e14-4b43ae67512b_40033_9
RSSI=-48,44790ba4-7eb3-4095-9e14-4b43ae67512b_40033_6
RSSI=-64,44790ba4-7eb3-4095-9e14-4b43ae67512b_40033_18
RSSI=-75,44790ba4-7eb3-4095-9e14-4b43ae67512b_40033_9
RSSI=-76,44790ba4-7eb3-4095-9e14-4b43ae67512b_40033_9
RSSI=-67,44790ba4-7eb3-4095-9e14-4b43ae67512b_40033_9
RSSI=-78,44790ba4-7eb3-4095-9e14-4b43ae67512b_40033_9
RSSI=-87,44790ba4-7eb3-4095-9e14-4b43ae67512b_40033_9
有40033_1、3、6、9、18个信标,但是某些信标在一段时间内未扫描。
广告间隔为700毫秒。
我应该检查什么?
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)