最近需要透過 RPi 上透過 Bluetooth 去掃 Beacon 的資訊,
而透過 BluetoothLEAdvertisementWatcher 掃到的資料是 Byte Array,
而我們需要的是將那些 Byte Array 的資料,
轉成 Beacon 的資訊,例如 UUID, Major, Miner, TxPower
在 WinBeacon 中已有寫了一些轉換,
我們可以封裝它,讀取 BluetoothLEAdvertisementReceivedEventArgs ,
然後傳出 Beacon 物件,如下,
private const byte SecondBeaconDataSectionDataType = 0xFF;
private const int SecondBeaconDataSectionMinimumLengthInBytes = 25;
private const string HexStringSeparator = "-";
private const string UUIDFormat = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
public static object ParseBeaconFromReceivedEventArgs(BluetoothLEAdvertisementReceivedEventArgs args)
{
dynamic beacon = null;
const int beaconDataSectionMinimumLengthInBytes = 25;
if (args != null && args.Advertisement != null)
{
var dataSections = args.Advertisement.DataSections;
if (dataSections != null && dataSections.Count > 0)
{
foreach (BluetoothLEAdvertisementDataSection dataSection in dataSections)
{
if (dataSection != null)
{
if (dataSection.Data != null
&& dataSection.DataType == SecondBeaconDataSectionDataType)
{
//using System.Runtime.InteropServices.WindowsRuntime;
byte[] data = dataSection.Data.ToArray();
/// Byte(s) Name
/// --------------------------
/// 0-1 Manufacturer ID (16-bit unsigned integer, big endian)
/// 2-3 Beacon code (two 8-bit unsigned integers, but can be considered as one 16-bit unsigned integer in little endian)
/// 4-19 ID1 (UUID)
/// 20-21 ID2 (16-bit unsigned integer, big endian)
/// 22-23 ID3 (16-bit unsigned integer, big endian)
/// 24 Measured Power (signed 8-bit integer)
/// 25 Additional information byte (optional)
if (data.Length >= beaconDataSectionMinimumLengthInBytes)
{
var payload = new Queue<byte>(data);
byte[] companyBytes = BitConverter.GetBytes((ushort)((payload.Dequeue() << 8) + payload.Dequeue()));
var companyId = ToLittleEndianFormattedString(companyBytes);
var b0advInd = payload.Dequeue();
var b1advInd = payload.Dequeue();
var uuid = ToLittleEndianFormattedUuidString(payload.Dequeue(16));
var major = (ushort)((payload.Dequeue() << 8) + payload.Dequeue());
var minor = (ushort)((payload.Dequeue() << 8) + payload.Dequeue());
var txPower = (sbyte)payload.Dequeue();
// The received signal strength indicator (RSSI)
var rssi = args.RawSignalStrengthInDBm;
var bleAddress = args.BluetoothAddress.ToString("X");
beacon = new JObject();
beacon.CompanyId = companyId;
beacon.UUID = uuid;
beacon.Major = major;
beacon.Minor = minor;
beacon.TxPower = txPower;
beacon.RSSI = rssi;
beacon.BluetoothAddress = bleAddress;
break;
}
}
}
}
}
}
return beacon;
}
//轉成 UUID
static string ToLittleEndianFormattedUuidString(byte[] data)
{
return ToLittleEndianFormattedString(data, UUIDFormat);
}
static string ToLittleEndianFormattedString(byte[] data)
{
return ToLittleEndianFormattedString(data, string.Empty);
}
static string ToLittleEndianFormattedString(byte[] data, string format)
{
var digits = new Queue<char>(BitConverter.ToString(data).Replace("-", "").ToLower());
if(string.IsNullOrEmpty(format))
format = new String('x', digits.Count);
return new string((from c in format
select c == '-' ? '-' : digits.Dequeue()).ToArray());
}
在 BluetoothLEAdvertisementWatcher 的 Received 事件中,呼叫那個 Method,如下,
dynamic beacon = ParseBeaconFromReceivedEventArgs(eventArgs);
if (beacon != null)
{
Debug.WriteLine($"companyId:{beacon.companyId}, uuid:{ beacon.uuid}, major:{ beacon.major}, major:{ beacon.major}, rrsi:{ beacon.rssi}, txPower:{ beacon.txPower}");
}
參考資料
Hi,
亂馬客Blog已移到了 「亂馬客 : Re:從零開始的軟體開發生活」
請大家繼續支持 ^_^