📡

BLE Characteristic Presentation Format Descriptionの使い方

に公開

BLEの基本

Bluetooth Low Energy(BLE)ではiPhoneなどのcentral deviceがIoTセンサなどのperipheral deviceに接続して,データを取得します.このとき,central deviceはseriveを介してcharacteristic内のセンサの値(value)を読み取ります.この値(Byte値)が何を表す値なのかであったり,どう読むべきかなのかを示したものがdescrptorになります.

Descriptorにはいくつかの種類があります.一番有名なのは,おそらくUser Description Descriptorで,これは文字列でCharactoristicのラベルを付けるときに使えます.ArduinoのBLEのサンプルではここで終わっているものがほとんどです.しかし,これだけではCharacteristicに入っているデータがintなのかfloatなのか,mgなのかkgなのかは分かりません.読み取り側のソフトも専用で設計して,読み取り方法や単位をcentral device側で設定すれば読み取れますが,汎用性がありません.

Presentation Format Descriptorとは

このデータ型や単位を指定するものがPresentation Format Descriptorです.

残念ながら,Presentation Format Descriptorの解説記事は非常に少ないです.ここではその少ない情報から読み取ったものをまとめます.詳細は,BLE v5の仕様書のp2241に書かれています.ここからはPresentation Format DescriptorをPFDと呼びます.

PFDはformat, exponent, unit, namespace, descriptionを指定したバイト列のデータを持ちます.データは次のように並んでいます.2列目はデータサイズ(Bytes)です.

// format | exponent |unit| namespace| description
// 1      | 1        | 2  | 1        | 2

それぞれの値の役割は次のようになっています.

  • format: characteristic valueの型(uint8, float, strなど)
  • exponent: characteristic valueの指数(-3ならm(ミリ),+3ならk(キロ)など)
  • unit: データの単位(g,V,mなど)
  • namespace: 不明
  • description: 不明

formatとunitはそれぞれBLEの規格で定められている対応表があるので,それに合わせた値を入れます.assigned numbers sheetの中で,p16のGATT Format Typesやp73の3.5 Unitsのセクションを参考にしてください.
なお,このデータはlittle-endianで保存しなければいけません.

ArduinoBLE Example

ArduinoBLEの場合は,次のような形でPresentation Formatを設定することができます.

class MyService : public BLEService {
  private:
  // characteristics
  BLEUnsignedLongCharacteristic timer_char_;

  const uint8_t msec_format_[7] = {
      BLE_GATT_CPF_FORMAT_UINT64,              // 0x0A
      0b11111101,                              // exp, milli, -3
      (u_int8_t)BLE_GATT_CPF_UNIT_SEC,         // 0x13
      (u_int8_t)(BLE_GATT_CPF_UNIT_SEC >> 8),  // 0x27
      0x01, // namespace
      0x00, // description
      0x00};// description
  public:
  MyService(/* args */);
  ~MyService();
};

MyService::MyService(/* args */)
    : BLEService("ABF0E000-B599-4BE0-B869-6054B7ED0CE3"),
      timer_char_("ABF0E001-B599-4BE0-B869-6054B7ED0CE3", BLERead | BLENotify){
  // add characteristics to service
  this->addCharacteristic(this->timer_char_);
  
  // User Description
  BLEDescriptor timer_descriptor("2901", "timer_ms");
  this->timer_char_.addDescriptor(timer_descriptor);
  
  // Presentation Format
  BLEDescriptor millisec_descriptor("2904", this->msec_format_, 7);
  this->timer_char_.addDescriptor(millisec_descriptor);
}

Web BLE App(おまけ)

私の開発したBLE AppではPresentation Format Descriptorを読み取ることで,汎用的なBLEデバイスの読み書きができるようにしています.

Discussion