最近需要透過 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:從零開始的軟體開發生活」
請大家繼續支持 ^_^

