アルプスのセンサネットワークモジュールからモーションデータを取得するC# .NET Frameworkのコンソールアプリを作成します。なお、アルプスのセンサネットワークモジュールからのアドバタイズメントの受信については、「C# .NET Frameworkを使ったBluetoothLEデバイスの検出」を参照してください。

動作環境

  • Windows 10 Professional
  • Visual Studio 2019

センサネットワークモジュールの仕様説明

アルプスのセンサネットワークモジュールのアドレスは、「C# .NET Frameworkを使ったBluetoothLEデバイスの検出」で「44674167429270」ということがわかっています。モーションデータの取得するためのUUIDは、「Sensor Network Module 評価キット Application Note Command Guide」の6頁に次のように記述されています。

センサネットワークモジュールの仕様説明

センサネットワークモジュールモーションデータ取得プログラムの作成

Windows10のBLE周りのAPIはUWPアプリ専用のため、.NET Frameworkからは、WinRTのAPI「Microsoft.Windows.SDK.Contracts」を経由してアクセスする必要があります。WinRTのAPI「Microsoft.Windows.SDK.Contracts」のインストール方法については、「C# .NET Frameworkを使ったBluetoothLEデバイスの検出」を参照してください。

C# .NET Frameworkのコンソールアプリで作成したセンサネットワークモジュールモーションデータ取得プログラムを次に示します。

  • 23行目にはアルプスのセンサネットワークモジュールのアドレス、25-29行目にはアルプスのセンサネットワークモジュールのUUIDを設定します。
  • アルプスのセンサネットワークモジュールが検出されると、62行目に制御が移ります。
  • 78行目でCCCD への書き込みを行います。この設定によりNotifyでパソコンに通知(コールバック)されます。
  • 83行目で、データが変化したときに実行されるコールバック関数「Changed_data」を登録します。
  • 87-92行目で、アルプスのセンサネットワークモジュールの設定を「モーション(動き)検知 100ms間隔(モーション系センサのみ」とし、動きの計測を開始します。
  • 103行目のコールバック関数「Changed_data」では、受信したモーションデータを16進表示します。

SensorAlps\SensorNetwork\Program.cs

using System;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading;
using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.Advertisement;
using Windows.Devices.Bluetooth.GenericAttributeProfile;

namespace SensorAlps
{
    class Program
    {
        static void Main(string[] args)
        {
            SensorModule sensormodule = new SensorModule();
            sensormodule.Start();
        }
    }

    class SensorModule
    {
        //  address
        const ulong SENSOR_ADR = 44674167429270;
        // Bluetooth®サービス
        static Guid UUID_TEMP_SERV = new Guid("47FE55D8-447F-43EF-9AD9-FE6325E17C47");
        // 計測センサデータやモジュール内部ステータスをパソコンに通知
        static Guid UUID_TEMP_DATA = new Guid("686A9A3B-4C2C-4231-B871-9CFE92CC6B1E");
        // コマンド制御
        static Guid UUID_TEMP_CONF = new Guid("B962BDD1-5A77-4797-93A1-EDE8D0FF74BD");

        private BluetoothLEAdvertisementWatcher advWatcher;

        public void Start()
        {
            Console.WriteLine("Start");
            this.advWatcher = new BluetoothLEAdvertisementWatcher();
            this.advWatcher.ScanningMode = BluetoothLEScanningMode.Passive;

            this.advWatcher.Received += this.Watcher_Received;

            // スキャン開始
            this.advWatcher.Start();
            Thread.Sleep(60000);
            this.advWatcher.Stop();
            Console.WriteLine("Stop");
        }

        private void Watcher_Received(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args)
        {
            this.CheckArgs(args);
        }

        public async void CheckArgs(BluetoothLEAdvertisementReceivedEventArgs args)
        {
            Console.WriteLine("Received");

            if (args.BluetoothAddress == SENSOR_ADR)
            {
                // 検出
                try
                {
                    Console.WriteLine($"Service Find!");

                    // スキャンStop
                    this.advWatcher.Stop();

                    BluetoothLEDevice device = await BluetoothLEDevice.FromBluetoothAddressAsync(args.BluetoothAddress);

                    var services = await device.GetGattServicesForUuidAsync(UUID_TEMP_SERV);
                    var characteristics = await services.Services[0].GetCharacteristicsForUuidAsync(UUID_TEMP_DATA);
                    var characteristics1 = await services.Services[0].GetCharacteristicsForUuidAsync(UUID_TEMP_CONF);

                    if (characteristics.Status == GattCommunicationStatus.Success)
                    {
                        var gattCharacteristic = characteristics.Characteristics.First();

                        // CCCD への書き込みが必要。これがないとイベントハンドラが呼ばれない。
                        GattCommunicationStatus status
                            = await gattCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify);

                        if (status == GattCommunicationStatus.Success)
                        {
                            gattCharacteristic.ValueChanged += Changed_data;
                        }
                    }
                    // モーション(動き)検知 100ms間隔(モーション系センサのみ)
                    await characteristics1.Characteristics[0].WriteValueAsync(new byte[] { 0x2F, 0x03, 0x03 }.AsBuffer(), GattWriteOption.WriteWithoutResponse);
                    await characteristics1.Characteristics[0].WriteValueAsync(new byte[] { 0x01, 0x03, 0x03 }.AsBuffer(), GattWriteOption.WriteWithoutResponse);
                    await characteristics1.Characteristics[0].WriteValueAsync(new byte[] { 0x04, 0x03, 0x01 }.AsBuffer(), GattWriteOption.WriteWithoutResponse);
                    await characteristics1.Characteristics[0].WriteValueAsync(new byte[] { 0x06, 0x04, 0x64, 0x00 }.AsBuffer(), GattWriteOption.WriteWithoutResponse);  // 100msec
                    await characteristics1.Characteristics[0].WriteValueAsync(new byte[] { 0x2F, 0x03, 0x01 }.AsBuffer(), GattWriteOption.WriteWithoutResponse);
                    await characteristics1.Characteristics[0].WriteValueAsync(new byte[] { 0x20, 0x03, 0x01 }.AsBuffer(), GattWriteOption.WriteWithoutResponse);

                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Exception...{ex.Message})");
                }
            }

        }

        public void Changed_data(GattCharacteristic sender, GattValueChangedEventArgs eventArgs)
        {
            Console.WriteLine($"characteristicChanged...Length={eventArgs.CharacteristicValue.Length}");
            byte[] data = new byte[eventArgs.CharacteristicValue.Length];
            Windows.Storage.Streams.DataReader.FromBuffer(eventArgs.CharacteristicValue).ReadBytes(data);

            var tmp = BitConverter.ToString(data);
            Console.WriteLine($"characteristicChanged...{tmp}");

            return;
        }
    }
}


センサネットワークモジュールモーションデータ取得プログラムの実行

センサネットワークモジュールモーションデータ取得プログラムを実行し、アルプスのセンサネットワークモジュールとペアリングできると、次のように受信されたモーションデータを16進表示します。データの最初のバイト「Event Code」が「E0」が ステータス通知、「F2」がデータパケット 1となります。モーションデータのデータ変換式については、「アルプスIoT Smart Moduleの加速度センサと地磁気センサの値をanyPiで取得/表示」を参照してください。

Start
Received
Service Find!
characteristicChanged...Length=20
characteristicChanged...E0-14-00-00-00-00-00-00-00-00-02-00-00-00-00-00-00-00-00-00
characteristicChanged...Length=20
characteristicChanged...E0-14-00-00-00-00-00-00-00-00-02-00-00-00-00-00-00-00-00-00
   ・・・・
characteristicChanged...F2-14-56-FF-96-FF-37-FF-4D-01-C9-0F-52-02-64-00-0A-00-00-00
characteristicChanged...Length=20
characteristicChanged...F2-14-56-FF-96-FF-37-FF-4D-01-C9-0F-52-02-64-00-0A-00-00-00
characteristicChanged...Length=20
characteristicChanged...F2-14-5A-FF-92-FF-3B-FF-47-01-A8-0F-E9-01-C8-00-0A-00-00-01
characteristicChanged...Length=20
characteristicChanged...F2-14-5A-FF-92-FF-3B-FF-47-01-A8-0F-E9-01-C8-00-0A-00-00-01

   ・・・・