Reputation: 1
I have found the solution that adjust BLE scan window size: BLE Scan Interval Windows 10
But, it's not working. Many beacons are missed while scanning.
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,
scanInterval = scanInterval,
scanWindow = scanWindow,
};
bool ret = DeviceIoControl(handle, 0x41118c, ref req, 8, IntPtr.Zero, 0, 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(), 0),
BitConverter.ToInt16(bytes.Skip(8).Take(2).Reverse().ToArray(), 0),
bytes.Skip(10).Take(8).ToArray()),
Major = BitConverter.ToUInt16(bytes.Skip(18).Take(2).Reverse().ToArray(), 0),
Minor = BitConverter.ToUInt16(bytes.Skip(20).Take(2).Reverse().ToArray(), 0),
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, 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 returns false but last error code is 0 and still do lazy scanning.
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=-50, 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=-50, 44790ba4-7eb3-4095-9e14-4b43ae67512b_40033_6
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=-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=-74, 44790ba4-7eb3-4095-9e14-4b43ae67512b_40033_18
RSSI=-50, 44790ba4-7eb3-4095-9e14-4b43ae67512b_40033_6
RSSI=-51, 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_18
RSSI=-75, 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
There are 40033_1, 3, 6, 9, 18 beacons but some beacons are not scanned some periods of time.
Advertising interval is 700 ms.
What should I have to check?
Upvotes: 0
Views: 653