2021年2月2日火曜日

Windows10でEddyStone Beaconを受信する その3 イベントハンドラ編

実行中のEddyStone受信プログラム
 今回は前の続きでEddyStoneを受信するWindowsのコマンドラインプログラム。その中のイベントハンドラについて解説する。なお、前々回の投稿以後、プログラムを少し変更してある。
 イベントハンドラは、以下のような形。
private static void WatcherReceived(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args) {
	ulong MyBtAddress = 0xF5E5E7BD08AE; // Your MicroBit Bleutooth Address
    if (args.BluetoothAddress != MyBtAddress) { return; }
    BluetoothLEAdvertisementDataSection x = args.Advertisement.GetSectionsByType(22)[0];
    var dataReader = Windows.Storage.Streams.DataReader.FromBuffer(x.Data);
    var r = new Byte[x.Data.Length];
    var MyInstaceID = new Byte[8];
    var MyNameSpace = new Byte[10];
    dataReader.ReadBytes(r);
    for (var i = 0; i < 10; i++) { MyNameSpace[i] = r[i + 4]; }
    Console.WriteLine($"MicroBit NameSpace:{BitConverter.ToInt32(MyNameSpace, 6):X8}");
    for (var i = 0; i < 6; i++) { MyInstaceID[i] = r[14 + i]; }
    Array.Reverse(MyInstaceID);
    Console.WriteLine($"        InstanceID:{BitConverter.ToUInt64(MyInstaceID, 0) / 0x10000:X8}\n");
}

 定義は、MSDNのここ。重要なのは、2つめの引数argだ。このargさえ得られれば、アドバタイズパケットの処理は終わったも同然といえる。BluetoothLEAdvertisementReceivedEventArgs Classは、前記定義ページにあるように、複数のプロパティを持っており、たとえば、パケットの送信元のBluetoothアドレスなら、BluetoothAddressプロパティを読み出せばよい。また、信号強度を調べるならRawSignalStrengthInDBmプロパティ、イベントの受信日時ならTimestampプロパティだ。重要なのは、Advertisementプロパティで、これは、 BluetoothLEAdvertisement Classを返す。ここには、アドバタイズパケットそのものが入っているほか、そこから解釈したデータがプロパティとして含まれている。

  イベントハンドラが呼び出されたらmicro:bit v2のものかどうかをBtアドレスで判定して、違うなら戻る。フィルターをかけているので、EddyStoneのアドバタイズパケットのときだけ、イベントハンドラーが呼び出される。不要ならBtアドレスによる判定はなくてもよい。

ulong MyBtAddress = 0x000000000000; //Your Microbit Bluetooth Address
if (args.BluetoothAddress != MyBtAddress) { return; }

 アドバタイズパケットのデータは、args.Advertisement.DataSectionsの中にある(複数形に注意)。これがパケットデータそのもので、複数のDataSetion(こっちは単数形)から構成されている(DataSectionsは、DataSectionのList)。実データはパケット内で1バイトのDataSize、DataTypeとペイロード(複数バイト)から構成されているが、DataSectionは、DataTypeとDataになっていて、DataのLengthが実データの先頭にあるDataSizeになる。Dataは、バイトの配列で、これを必要に応じて解釈する必要がある。

 EddyStoneの場合には、DataTypeが22(0x16)のデータが含まれる。この中にmicro:bitの「Buletooth UUIDアドバタイズ」に設定する「Name Space」と「Instance ID」が入っている。

 これを取り出すのが、.GetSectionsByType(22)[0]である(4行目)。GetSectionsByTypeメソッドは、引数で指定されたDataTypeを取り出す。ただし、複数のDataSectionが対応する可能性があるのでListとしてかえされるが、EditStoneでは1つだけなので「[0]」として先頭のものだけを取り出している。最初のバージョンでは、これを使わず、foreachですべてのDataSectionsをスキャンして、DataTypeが22のものだけをifで見付けて処理していた。しかし、.GetSectionsByTypeメソッドを使えば、1行で目的のDataSectionを取り出せる。

 バイト列を読み込むには“ Windows.Storage.Streams.DataReader.FromBuffer”を使う(5行目)。あらかじめバイト配列(var r = new Byte[x.Data.Length];)を用意しておき、「dataReader.ReadBytes(r);」で読み込む(9行目)。

 EddyStone(micro:bitのBluetoothアドバタイズ)のNameSpaceは、読み込んだバイト列の4バイト目から10バイト分(10行目)、InstanceIDは、14バイト目からの5バイトになる(12行目)。ただしInstanceIDは逆順で入っているので、ひっくり返す必要がある(13行目)。

0 件のコメント:

コメントを投稿