CC2541 SensorTagから温度データを取得するC# .NET Frameworkのコンソールアプリを作成します。なお、CC2541 SensorTagからのアドバタイズメントの受信については、「C# .NET Frameworkを使ったBluetoothLEデバイスの検出」を参照してください。

動作環境

  • Windows 10 Professional
  • Visual Studio 2019

SensorTagの仕様説明

CC2541 SensorTagのアドレスは、「C# .NET Frameworkを使ったBluetoothLEデバイスの検出」で「198570504670687」ということがわかっています。温度データの取得するためのUUIDは、
Bluetooth® Low Energy Sensor Tag Hands On 」に示すハンズオンの13頁に次のように記述されています。なお、CC2541 SensorTagのベースUUIDは「F000xxxx-0451-4000-B000-000000000000」で「xxxx」の部分が対応する機能によって設定されます。

  • サービスUUID : F000AA00-0451-4000-B000-000000000000
  • データUUID : F000AA01-0451-4000-B000-000000000000
  • 通知UUID : F000AA02-0451-4000-B000-000000000000

SensorTagの仕様説明

SensorTag温度データ取得プログラムの作成

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のコンソールアプリで作成したSensorTag温度データ取得プログラムを次に示します。

  • 23行目にはCC2541 SensorTagのアドレス、25-30行目にはCC2541 SensorTagのUUIDを設定します。
  • CC2541 SensorTagが検出されると、63行目に制御が移ります。
  • 79行目でCCCD への書き込みを行います。この設定によりNotifyでパソコンに通知(コールバック)されます。
  • 84行目で、データが変化したときに実行されるコールバック関数「Changed_data」を登録します。
  • 89行目で、CC2541 SensorTagの温度計測を開始します。
  • 99行目のコールバック関数「Changed_data」では、受信した温度データを16進表示します。
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 SensorNetwork
{
    class Program
    {
        static void Main(string[] args)
        {
            SensorModule sensormodule = new SensorModule();
            sensormodule.Start();
        }
    }

    class SensorModule
    {
        // CC2541 Sensor Tag address
        const ulong SENSOR_ADR = 198570504670687;
        // Temperature Service
        static Guid UUID_TEMP_SERV = new Guid("F000AA00-0451-4000-B000-000000000000");
        // TEMPERATURE_DATA_UUID 00:00:00:00 (4 bytes)
        static Guid UUID_TEMP_DATA = new Guid("F000AA01-0451-4000-B000-000000000000");
        // TEMPERATURE_CONF_UUID (1 byte) Write "01" to start Sensor and Measurements,
        // "00" to put to sleep
        static Guid UUID_TEMP_CONF = new Guid("F000AA02-0451-4000-B000-000000000000");

        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;
                        }
                    }

                    characteristics.Characteristics[0].ValueChanged += Changed_data;
                    await characteristics1.Characteristics[0].WriteValueAsync(new byte[] { 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;
        }
    }
}

SensorTag温度データ取得プログラムの実行

SensorTag温度データ取得プログラムを実行を実行し、CC2541 SensorTagとペアリングできると、次のように受信された温度データを16進表示します。温度センサーデータのデータ変換式については、「SensorTagの IR温度センサー「TI TMP006」」を参照してください。

Start
Received
Service Find!
characteristicChanged...Length=4
characteristicChanged...BE-FE-68-0B
characteristicChanged...Length=4
characteristicChanged...BE-FE-68-0B
characteristicChanged...Length=4
characteristicChanged...C7-FE-68-0B
   ・・・・