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