[UWP]透過 BluetoothLEAdvertisementReceivedEventArgs 取得 Beacon 的資訊

最近需要透過 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}");
}

參考資料

WinBeacon

Hi, 

亂馬客Blog已移到了 「亂馬客​ : Re:從零開始的軟體開發生活

請大家繼續支持 ^_^