BLEの通信仕様
Bluetooth Low Energyの無線通信技術
この章は、組み込み機器開発およびiOSアプリケーション開発に必要な無線通信技術を要点をおさえて解説します。
Bluetooth Low Energy(以下、Bluetooth LE)の無線技術の知識は、独自のBluetooth LEデバイス設計に必要です。また、iOSアプリケーション開発に使うCoreBluetoothフレームワークのクラスや使い方そして振る舞いの理解に、役立ちます。
さらに詳細にBluetooth LEの無線通信技術を知りたいときは、Robin Heydon, Bluetooth Low Energy: The Developer’s Handbook, Prentice Hall, 2012、を参照してください。
Bluetooth4.0の仕様書は、PDF形式でだれでも無償で入手ができます。しかし、それは2000ページを超える膨大なものです。Bluetooth4.0の半導体やスタックを設計するのではないのですから、仕様書は読むものではなく、詳細な数値や記述を調べる辞書として利用します。
Bluetooth LEのアーキテクチャ
Bluetooth LEのアーキテクチャを階層表示したのが図<TBD BLEのアーキテクチャ>です。通信技術は異なる機種間でデータをやりとりする技術です。0/1のビット・データのやりとりにはじまり、接続管理やビット・データのかたまりの意味づけなど、いくつもの役割が組みあわさって、はじめて通信ができます。Bluetoothは、通信の手順やデータ構造をプロトコル、機器の振る舞いをプロファイル、と呼びます。
物理層からGATTまでの階層は、それぞれ下層の機能を使って、相手の同じ階層のプロトコルと通信します。ジェネリック・アクセス・プロファイルは、機器の振る舞いを定義します。機器の振る舞いは、物理層からGATTまでのレイヤそれぞれの役割を通じて実現されるので、ジェネリック・アクセス・プロファイルは、特定のレイヤのものではなく、物理層からGATTまでの全てのレイヤに影響を与えます。物理層からGATTまでの階層は、相手の同じ階層のプロトコルと通信します。レイヤの役割は以下のとおりです:
- Generic attribute profile (GATT, ジェネリック・アトリビュート・プロファイル)
- サービス/キャラクタリスティクスを提供。 -Attribute protocol(ATT, アトリビュート・プロトコル)
- アトリビュートという値をやりとりする
- Logical Link Control and Adaptation Protocol(L2CAP, ロジック・リンク・コントロール・アンド・アダプティブ・プロトコル)
- 論理チャンネルの提供
- Logic link(ロジックリンク)
- 近接デバイスの発見と接続、通信
- Physical layer(物理層、フィジカル・レイヤ)
- 無線通信
コントローラとホスト
Blueoothのアーキテクチャは、コントローラ、ホストそしてアプリケーションの3つに分けられます。コントローラは、電波の送受信、パケット通信、接続管理をおこないます。高周波回路とその制御回路、専用回路またマイクロコントローラで実行されるソフトウェア、で実装されます。ホストは、Bluetoothのプロトコルやプロファイルごとの通信の多重化など、Bluetoothの複雑な通信機能を提供します。アプリケーションは、ユーザが作るアプリケーションです。この2つはソフトウェアです。
ホスト・コントロール・インタフェース
コントローラとホストの間に、Host Control Interface (HCI)という、コマンドとデータの通信仕様があります。HCIはコントローラとホストを、論理的に、また物理的に分離します。ホストとコントローラを1つの半導体に実装する1チップ構成と、別々の半導体で実装する2チップ構成のいずれかがとれます。
1チップ構成は、半導体チップの中にあるマイクロコントローラで実行されるソフトウェアで、コントローラの制御部分とホストが実装されます。このときHCIは、2つのソフトウェアを接続する(ライブラリ呼び出しなどの)、論理的な接続仕様として使われます。1チップ構成では、チップ内部のマイクロコントローラはユーザのアプリケーションも実行します。
コントローラをモジュール化すると、2チップ構成になります。モジュールとは、半導体や高周波回路の素子などを小さな基板に実装して部品化したものです。電波を出力する機器は各国の電波法の承認を取得しなければなりません。この電波を出力するモジュールが承認を取得していれば、機器本体で承認を取る必要がなくなる、メリットがあります。ホストは別のプロセッサで実装されます。ホストはモジュールのコントローラと、シリアル端子やSPI、USBなどの物理インタフェースを通じて、HCIで通信します。
規格にHCIがあるので、2チップ構成でも、どのメーカのコントローラでも共通に使えるようになります。例えば、パソコンでは、ホストはBluetoothスタックと呼ばれるソフトウェアで提供されます。どのメーカのBluetooth USBドングルでも、USBを通してHCIで通信することで、同じように使えます。
どのようなチップ構成でも、ユーザのアプリケーションは、ホストと同じプロセッサで実行されます。ですから、HCIの場合と違い、ホストとユーザアプリケーションの間のインタフェースは、規格に定義がありません。メーカーやOSなどの提供側が決めるもので、開発環境に依存します。
どちらの構成をとるかは、状況によります。機能が単純な周辺機器ならば、製造コストを最小にするため1チップ構成をとるでしょう。機能が複雑だったり、既存設計にBluetooth LEの通信機能を追加するなどで、1チップ構成ではユーザアプリケーションを処理できないならば、2チップ構成を選びます。モバイル機器やパソコンなど、モジュールを採用すれば、おのずと2チップ構成になります。
Logic Link Control and Adaptation Protocol
ホストのLogical Link Control and Adaptation Protocol(L2CAP)は、通信の多重化を行うレイヤです。2つのデバイス間のデータ通信を提供するコントローラを通じて、プロトコルごとに、指定したチャネルごとの独立した通信を提供します。頭文字で略すとLLCAPですが、Lが2つ並ぶのを数字で表して、L2CAP、と表記します。
iOSデバイスのBLEアクセサリの設計指針は、 スレーブからマスターへの通信パラメータの伝送は、L2CAPの接続パラメータアップデートで伝えるべきとしています。この設定を要求するのは周辺機器のみです。 設定できるパラメータは、通信を行う周期を与えるコネクション・インターバル、接続が失われたと判定するスーパービジョン・タイムアウトなどです。
周辺機器は、通信頻度や電池消費量のバランスがとれるように、適切な場面で適切なパラメータを設定します。例えば、周辺機器がiPhoneに初めて接続したときに、まとまった量のデータを一気に送信したいならば、インターバルを短くして実効通信速度をあげて、短い時間でデータを送ります。接続したあと、電池消費量をおさえたいならば、インターバルを長くします。
Attribute Protocol(ATT)とGeneric Attribute Profile(GATT)
iOSアプリケーション開発者が実装で直接触れるのは、ホストの上位層にある、Attribute Protocol(ATT)とGeneric Attribute Profile(GATT)です。このレイヤは、Bluetooth LEのサービスおよびキャラクタリスティクスを定義しています。
Bluetooth LEの周辺機器は、サーバとして、センサの値、動作設定値、内部状態などを公開しています。Bluetooth LEは、ある機能をサービスという単位にまとめます。1つのサービスは複数のキャラクタリスティクスを持ちます。例えばエアコンであれば、室内温度というサービスを作り、そのなかに気温センサの値というキャラクタリスティクスをもたせる設計をしたりします。
ジェネリック・アクセス・プロファイル
ジェネリック・アクセス・プロファイル(Generic Access Profile, GAP)は、すべてのBluetoothデバイスが実装すべき、ベースプロファイルの実装です。GAPは、物理層からGATまでのレイヤをまたいだ、デバイスの振る舞いを提供します。
GAPは4つのデバイスの役割を定義します:
- ブロードキャスター
- オブザーバ
- ペリフェラル
- セントラル
Bluetoothデバイスは、コントローラが対応していれば、この4つのどの役割になれます。しかし、同時に2つ以上の役割になることはできません。
ブロードキャスターは、送信するだけのアプリケーションです。Bluetooth LEのアドバタイジングで、データをブロードキャストします。ブロードキャスターは送信機能のみが必要で、受信機能は必要ありません。またコネクションをサポートしません。オブザーバは、受信するだけのアプリケーションです。オブザーバには受信機能のみが必要で、送信機能とコネクションは不要です。
ペリフェラルは、単1の接続をサポートします。コントローラのスレーブのみをサポートします。セントラルは、すべてのペリフェラルとの接続を開始して、複数の接続を管理するものです。
役割により必要な機能が異なるので、必要な機能だけを実装することで、製造コストの削減などができます。例えばブロードキャスターであれば受信回路やその制御機能をすべて削除することもできます。しかし実施には、設計開発から販売管理までを含めたコストから、セントラルに対応したデバイスのみが販売されています。
隣接デバイスとの無線通信
コントローラの機能は、隣接するデバイスとの通信です。Bluetooth LEのコントローラは、電波を送受信する物理層、隣接するデバイスとの接続とパケット通信を管理するリンク・レイヤ、そしてホストのインタフェースHCIで構成されます。Bluetooth LEの物理層の特性を<TBD 表を参照>に示します。
項目 | 値 |
---|---|
周波数 | 2.400-2.4835 GHz |
物理層のビットレート | 1Mbps |
通信送信電力 | 10mW ~ 10μW |
伝達距離 | 150m (見通し) |
周波数帯
Bluetooth LEが利用する周波数は、クラシックBluetoothと同じ2.4GHz帯を使います。周波数帯が同じなので、クラシックBluetoothとBluetooth LEを両方搭載したものでも、同じアンテナや高周波回路を使えます。
この2.4GHz帯は、ISM (Industry-Science-Medical、アイエスエム) バンドと呼ばれるいくつかある周波数帯の1つです。ISMバンドは、産業、科学、医療、という名称が示すように、もともとは無線通信以外の産業・科学・医療に高周波エネルギー源として利用するために指定された周波数帯です。身近なものでは、電子レンジは加熱に2.45GHzの周波数を使います。
電波は公共の資源ですから、その周波数は区分されて利用目的が定められています。ですから、新しい無線機器を普及させて一般で使うには、周波数区分という資源の割り当てが必要です。また、国際展開のために、それが国際的に認められて各国が受け入れることも必要です。
新しい周波数区分の割り当ては、大変な手間と時間がかかります。そのため、Bluetoothに限らず無線LANなどの空中線電力の小さい高度な通信装置には、2.4GHz帯をはじめとするISMバンドの利用を認めてきました。
Bluetoothが利用する周波数帯はBluetooth専用ではありません。無線LANをはじめとする様々な通信装置や電子レンジも利用していますから、他の機器からの混信が常に生じうる、賑やかな周波数帯です。
Bluetooth LEは、同じ周波数帯を利用する無線機器があることを前提に設計されています。混信を与えないように、また通信が頻繁に切断しないように、80MHzの周波数帯を2MHz幅に分割したチャネルと、適応周波数ホッピング方式を導入しています。
変調方式
情報を送るために電波の波形を変化させることを変調と言います。変調は、送信する電波、情報を搬送する波なので搬送波と呼びます、の波の大きさ(振幅)または周波数および位相を時間変化させることです。この変調は0/1のデジタルデータを、四方八方に広がっていく電波にのせる技術です。
Bluetooth LEの変調方式は、<TBD 波形>に示すGaussian Frequency Shift Keying (ガウシアン周波数シフトキーイング、GFSK) という連続位相周波数偏移変調方式の1つです。周波数シフトキーイングは、0/1のビット・データごとに、一定の周期で周波数の遷移(シフト)量を切り替える(キーイング)変調方式です。
<TBD 波形>のように、250kHzの周波数偏移では、1マイクロ秒後に搬送波の位相が90度変化します。250kHzの周期は4マイクロ秒ですから、1マイクロ秒は1/4周期だからです。搬送波に比べればごく僅かな周波数遷移ですが、1マイクロ秒後たてば振幅の符号が正負に分かれるため、容易に情報を取り出せます。この1つの信号をシンボルと呼びます。Bluetooth LEのシンボル・レートは1Mbpsです。1シンボルは、振幅が正負どちらかにわかれる2状態なので、1シンボルで1ビットが伝送できます。ですからビット・レートは1Mbpsになります。
GFSKのガウシアンは、0/1の信号をガウスフィルタを通して滑らかにした波形で、周波数遷移をおこなうことから名づけられています。0/1の変化そのままで周波数遷移をすると、0/1の変化点で搬送波が急激に変化して、周波数占有幅が大きくなります。これは周波数帯域を効率よく使うための技術です。
物理層のビットレートは将来引き上げられるかもしれません。しかし、Bluetooth LEでは、ビットレートの向上は、より速い通信ではなく、さらなる低消費電力のためです。例えば、ビットレートが現在の1Mbpsから2倍の2Mbpsになれば、送受信回路の稼働時間が半分になります。半導体素子の電力の大部分が2.4GHzの高周波信号を送受信する回路で消費されますから、これは電池の稼働時間を大きく伸ばします。
チャンネル
電波での無線通信は、送信側と受信側がいること、それらが同じ時間に周波数を使っていること、で成り立ちます。また電波は四方八方に広がるので、自分たちの通信が他の通信の混信を引き起こしたり、逆に混信をうけます。
Bluetooth LEは、心拍センサや時計などの一般に普及する身に付けるデバイスで利用されます。そのために、公共の場所など、自分とその周囲の人たちが持つデバイスをあわせると、100や1000のデバイスが同時に通信をしている場面も生じます。さらに、Bluetooth LEを搭載するようなモバイル機器は無線LANも搭載しています。それらの無線通信との共存も必要です。
Bluetooth LEは、2.400 GHzから2.480GHzまでの80MHzの帯域を、2MHz幅で分割して、40のチャンネルとします。送信側と受信側が同じチャネルを使っていれば、同じ周波数をつかうことになります。また、あるチャンネルの通信は、周波数が十分離れていますから、隣接するチャンネルまたその他のチャンネルの通信に影響しません。ですから、違うチャンネルを利用すれば、複数の機器が同時に通信をしていても混信が生じません。
40のチャンネルには、それぞれ0から39までの番号が割り振られます。チャンネルは2種類にわけられます。チャンネル37からチャンネル39までの3チャンネルをアドバタイジング・チャンネル、チャンネル0からチャンネル36までの37チャンネルをデータ・チャンネルと呼びます。
アドバタイジング・チャンネルは、デバイスの発見と接続に使います。データ・チャンネルは、接続が完了したデバイス同士の通信に使います。アドバタイジング・チャンネルは、3つのうちどれか1つのチャンネルで通信ができるならば、機能します。データ・チャンネルは、適応周波数ホッピング方式と呼ばれる、通信につかうチャンネルを時間で次々に切り替えていく方式をつかうので、一部のチャンネルで混信をうけても通信は断絶しません。
Bluetooth LEを搭載するモバイル機器は、たいてい無線LANを搭載しています。そして、まずはデバイスを発見できなければ、通信がはじまりません。そのため、デバイスの発見に使うアドバタイジング・チャンネルには、無線LANと混信しにくいチャンネルが、3つ割り当てられています。
無線LANは、1チャンネルあたりの帯域が20MHz、14のチャネルを、5MHzづつずらして、隣接するチャンネルと帯域を重ねて配置されています。無線LANでよく使われるチャンネルは、1、6,および11で、それぞれの中心周波数は2.412 GHz、2.437 GHz、および2.462 GHzです。
これにBluetooth LEのチャンネルを重ねるとになります。 無線LANにかぎらず任意の無線通信の混信を避けるには、2.4GHzの帯域内の、なるべく離れたチャンネルを使うしかありません。チャンネル37 (2.402 GHz)とチャンネル39 (2.426 GHz)は、帯域の端に割り当ててあります。もう1つのチャンネル38 (2.480 GHz)は、帯域のなるべく中央で、かつ無線LANのチャンネルと重ならないものが選ばれています。
アドバタイジング・チャンネルの数が3よりも多ければ、より混信を避けられそうです。しかしそうすると、非接続時の周辺機器の電池消費量が、チャネル数分だけ増えてしまいます。周辺機器は、自分の存在を周囲に伝えるために、アドバタイズメント・パケットを送信します。アドバタイズメント・パケットは、一定の周期ごとに、3チャネルそれぞれで送信します。ですから、もしもアドバタイジング・チャネルを、2倍の6チャネルにすると、非接続時の周辺機器の電池消費量も単純に2倍になるでしょう。
パケット・フォーマット
通信でつかわれる、制御情報とデータを含む連続したビットのかたまりを、パケットと呼びます。Bluetooth LEのパケットのフォーマットはです。オクテットは8ビットの情報を表す単位です。通常使うバイトと同じ意味ですが、機種によっては8ビットではないバイトもありうるのです。そのため、通信では、曖昧さがない8を表すオクテットを使います。
パケットは、アクセス・アドレス、上位階層が送受信するデータであるプロトコル・データ・ユニット(Protocol Data Unit, PDU)とその誤り検出用の巡回検査符号(Cyclic Reundancy Check, CRC)の3つのエンティティで、構成されます。
パケットの長さは、80から376ビット(10 ~ 47オクテット)、ビット・レートが1Mbpsなので、80から376マイクロ秒の範囲になります。マイクロ(ギリシャ文字 μ と表記します)は10-6を示す接尾語です。1 / 1Mbpsで1マイクロ秒です。Bluetooth LEは、センサ値など少量のデータを決まったタイミングで通信するものなので、この最大376マイクロ秒の短いパケットのみで、通信がおこなわれます。
パケットは、エンティティごとに最下位ビットから最上位ビットの順に送出されます。バイトオーダは、リンクレイヤではなく、上位プロトコルによります。アドバタイジング・パケットは、最上位バイトから最下位バイトの順(ビッグエンディアン)に送出されます。デバイスとデータをやり取りするのに使うGATTプロファイルは、最下位バイトから最上位バイトの順(リトルエンディアン)に送出します。PDUを直接読み書きするときは、このネットワーク・バイトオーダーに注意します。
パケットの先頭のプリアンブルは、信号の強さと0/1のビットを読み取るタイミングの検出に使われます。
プリアンブルは、0/1が交互に続く8ビットの値 10101010b または 01010101b (接尾語 b は2進数表記を示す)です。2つの値のうち、末尾のビットが続くアクセス・アドレスの先頭ビットと異なるもの、境界に同じビット00bまたは11bが連続しないもの、が送出されます。
Bluetooth LEは、受信回路のダイナミック・レンジ(受信可能な最大の信号と最小信号の比)が80dBあります。つまり受信電力で8桁、電圧で4桁の範囲の信号を受信します。このダイナミック・レンジは、受信信号が信号の強さに応じて増幅率を自動で調整することで、実現されます。もしもプリアンブルがなければ、増幅率を調整している間に、データを含む信号が来てしまい、取りこぼしてしまいます。
プリアンブルは、信号の読み出しタイミングの同期に必要です。変調信号の0/1の変化し終わったタイミングがわかれば、シンボル・レートが1Mbpsとわかっているので、あとは1マイクロ秒ごとに値を読み出すだけです。プリアンブルの0/1を繰り返す波形で、読み出しタイミングを同期します。
アクセス・アドレスは、2つのデバイス間で接続ごとに割り振られるランダムな値です。アクセス・アドレスは、そのパケットがどの接続のものかを区別する識別子で、物理インタフェースとは無関係のランダムな値です。イーサネットにあるような、物理インタフェースに割り振られた唯一の固定のアドレスではありません。
アクセス・アドレスは32ビットありますが、実際に利用できるアドレスは31ビット分です。ですからピコネットの最大同時接続数は、アドレス数の制約からは、231になります。31ビットに制約されるのは、周波数変調信号の復調回路に、受信信号から自分の周波数のずれを自動調整する機能があるからです。000…0bや111…1bのように同じ値が連続すると、同じ周波数がずっと受信されます。すると、この自動調整機能の働きで、復調の基準とする周波数がずれていき、ただしい復調ができなくなります。これを避けるために、アクセス・アドレスは、32ビットの任意の6ビットをとりだしたとき、うち2ビットで0/1が変化している値を使います。
プロトコル・データ・ユニット(Protocol Data Unit, PDU)が、パケットが運ぶデータです。2オクテットから39オクテットの長さがあります。もしもPDUに連続する0/1があると、アクセス・アドレスとおなじ不都合が生じます。それを避けるために、PDUにはホワイトニングという、0/1を適当に変化させる変換処理がおこなわれます。これは送受信回路内部で処理されるので、アプリケーション側からは見えません。
CRC(Cyclic Redundancy Check, CRC)は、PDUのエラー検出のための巡回検査符号です。2および4ビットまたは奇数個のエラービットがあるとき、誤りだと検出できます。つまり、1,2,3,4,5,7,9… つのビット・エラーを検出できます。より強力な誤り検出が必要なときは、PDUの暗号化を使います。PDUが正しく暗号化されているかをチェックするためのメッセージ・インテグリティ・チェック(Message Integrity Check, MIC)が追加されます。
発見と接続
リンク層は、電波が届く範囲にある隣接デバイスの発見と、発見したデバイスとの接続および双方向通信を提供します。これらの仕組みと処理の流れを、通信制御の仕組み、やりとりするPDUのフォーマット、そしてパケットの送受信の手順とタイミング、の3点から述べます。
デバイスの発見とピコネットへの参加
デバイスの発見と接続の流れは、リンク層の状態遷移図<TBD 図表番号/>を使うとわかりやすくなります。リンク層には5つの状態:
- スタンドバイ(Standby)
- アドバタイジング(Acvertising)
- スキャニング(Scanning)
- イニシエーティング(Initiating)
- コネクション(Connection)
があります。スキャニングには、パッシブ・スキャン(Passive Scan)とアクティブ・スキャン(Active Scan)またコネクションには、マスター(Master)とスレーブ(Slave)のサブステートがあります。
スマートフォンが周辺機器に接続するまでの、状態遷移を見てみます。周辺機器がアドバタイジング・パケットを送信して、スマートフォンがそれを受信してデバイスを発見、そして接続をします。この時、スマートフォンの働きをするものをスキャナ(Scanner)、周辺機器の働きをするものをアドバタイザ(Advertiser)と呼びます。
スキャナとアドバタイザのリンク層は、どちらも最初はスタンドバイ状態にあります。スタンドバイ状態は、送受信を何もしません。
アドバタイザはアドバタイジング状態に遷移して、一定期間ごとにアドバタイジング・パケットを送信します。
スキャナはスキャニング状態に遷移してアドバタイジング・パケットを受信します。アドバタイジング・パケットを受信するだけなのが、パッシブ・スキャンです。アクティブ・スキャンは、アドバタイジング・パケットを受信したあとに、アドバタイザにリクエストを送り、さらなる情報を取得します。
スマートフォンがスキャンして得た情報から、接続先を決めます。スマートフォンはイニシエイティング状態に遷移します。この時のスマートフォンの役割をイニシエータと呼びます。イニシエータは、接続したいアドバタイザからのアドバタイジング・パケットを受信したあとに、接続要求を送信して、コネクション状態に遷移します。
ピコネットは、1つのマスターに複数のスレーブが接続するスター型のネットワークです。スレーブ同士が通信することはありません。接続が完了すると、イニシエータはマスター、アドバタイザはスレーブの役割になります。
状態遷移の経路から、スレーブには以下の制約があります:
- 同時にマスターかつスレーブには、なれない。
- スレーブは同時に2つ以上のマスターと接続しない。
スキャナやアドバタイザといった役割は、リンク層の制御機能で作られます。ですから、たいていのBluetooth LEの半導体では、ソフトウェアでどの役割をもたせるかが決められます。スマートフォンがアドバタイザになることも、また周辺機器がマスターでスマートフォンがスレーブになるピコネットを作ることもできます。
また、1つのコントローラが同時にスレーブかつマスターになることはできません。コネクション状態に遷移したスレイブはアドバタイジング・パケットを送出しませんから、スレーブは同時に2つ以上のマスターとは接続しません。スレーブは、かならず1つのピコネットに属します。
アドバタイジング・パケット
デバイスの発見のためにアドバタイザが送信するパケットが、アドバタイジング・パケットです。
周波数帯域は、チャネル37, 38, 39、の3チャネルを使います。デバイスが確実に発見されるように、3つのチャネルをすべて使うことが推奨されます。アドバタイジングに使うチャネルは、アドバタイザのファームウェアから設定できます。デバックで無線通信を傍受(スニッフィング)するときは、スニッフィングをしやすくするために、チャンネルをどれか1つに限定することがあります。
アドバタイジングでの通信は、非接続の同報通信です。リンク層のアクセス・アドレスは、固定値 10001110100010011011111011010110b (0x8E89BED6) が使われます。
アドバタイジング・パケットは、一定周期のアドバタイジング・イベントごとに送出されます<TBDアドバタイジングイベントのタイミング/>。アドバタイジング・イベントごとに、アドバタイジング・パケット(ADV_IND と表記している)が、チャンネルごとに送出されます。チャンネルごとのパケット送出時間は10ミリ秒以下です。
イベントの周期 T_advEvent は:
$$T_advEvent = advInterval + advDelay$$
と表されます。
advIntervalはアドバタイジングの周期です。20ミリ秒から10.24秒までの、0.625ミリ秒の整数倍の値を設定します。advIntervalが短いほど、デバイスは発見されやすくなりますが、電波を送信する分、電池の消費量が大きくなります。この値設定は、アドバタイザのファームウェア設計次第です。例えば、電源を入れて30秒間は、ユーザが接続をしようとしているだろうから20ミリ秒で、接続されないままならば、その後は徐々に周期を長くして、デバイス発見に少し時間はかかるが電池消費量は抑える、処理にします。
advDelayは0から10ミリ秒のランダムな値です。もしも、全く同じ開始タイミングで同じ周期のアドバタイジングをしているデバイスが2つあると混信しつづけます。そのような状況を避けるために、アドバタイジング・イベントをランダムにずらしています。
スキャン
アドバタイジング・パケットのペイロードは37オクテットの情報を送れます。しかしアドバタイザの情報は、たいてい、このペイロードだけでは不足します。アドバタイザからより多くのデバイス情報を引き出すのが、スキャンです。
<TBD 状態遷移図/>のスキャニングには、パッシブ・スキャンとアクティブ・スキャンがあります。パッシブ・スキャンはアドバタイザのパケットを受信するだけのスキャンです。アクティブ・スキャンは、アドバタイジング・パケットの終了から150マイクロ秒後に、SCAN_REQパケットを送信します。スキャン・リクエスト(SCAN_REQ)パケットを受信したアドバタイザは、アドバタイジング・パケットと同じ37オクテットのペイロードがあるスキャン・レスポンス(SCAN_RES)パケットを、150マイクロ秒後に返します。
アドバタイジング・パケットとSCAN_RESパケットは同じデータフォーマットに従います。ここで、アクティブ・スキャンは、パケットをやり取りする分だけ電力を消費します。そこでSCAN_RESパケットは、時間で変化しない情報を納めるものとします。スキャナが読み取ったSCAN_RESパケットをキャッシュすることで、スキャンは1度だけですむようにします。SCAN_RESパケットには、アドバタイザが持っている機能を表すサービスの識別子やデバイスの名称などが置かれます。
アドバタイザの周囲には複数のスキャナがいるときに、いくつかのスキャナが同時にSCAN_REQパケットを送信すると、パケットが衝突して、アドバタイザはパケットを正しく受信できなくなります。スキャナは、レスポンスが返ってこないときは、SCAN_RESパケットの送信を、ランダムな回数で間引いていきます。
ペイロードのフォーマット
アドバタイジング・パケットのPDUは、2オクテットのヘッダと6〜37オクテットのペイロードがあります<TBDパケットフォーマット/>。このヘッダの、PDU TypeはPDUの種類を示します。TxAdd, RxAddはPDU Typeにより異なる意味を持ちます。Lengthはペイロードの長さをオクテット単位で示します。
PDUタイプ | 役割 | 略語 |
---|---|---|
0000 | Connectable undirected advertising | ADV_IND |
0001 | Connectable directed advertising | ADV_DIRECT_IND |
0010 | Non connectable undirected advertising | ADV_NONCONN_IND |
0011 | Scan request | SCAN_REQ |
0100 | Scan response | SCAN_RSP |
0101 | Connection request | CONNECT_REQ |
0110 | Scannable undirected advertising | ADV_SCAN_IND |
ヘッダのPDU Typeは7タイプあります<TBD PDUタイプの表/>。このうち、アドバタイジングにつかうのは4タイプです。PDUタイプは、わかりやすく、短い略語であらわします。役割にあるConnectableは、接続要求ができることを、undirectedは不特定多数のデバイスへのアドバタイジング、directedは特定デバイスへのアドバタイジング、またScannnableは、のちに述べるスキャン要求ができること、を示しています。
PDUタイプ | 無向/有向 | スキャン要求 | 接続要求 |
---|---|---|---|
ADV_IND | 無向 | できる | できる |
ADV_DIRECT_IND | 有向 | できない | できる(特定デバイス) |
ADV_NONCONN_IND | 無向 | できない | できない |
ADV_SCAN_IND | 無向 | できる | できない |
PUDタイプごとの機能をまとめたものが<TBD PDUタイプと機能/>です。
ADV_INDとADV_DIRECT_INDは、接続を受け入れるタイプです。ADV_INDが、いわゆる通常のアドバタイジングです。不特定多数のデバイスにそのデバイスの存在をつたえて、接続要求があればそれを受け入れます。ADV_DIRECT_INDは、以前に接続したことのあるデバイスと高速に接続するためのタイプです。
ADV_NONCONN_IND と ADV_SCAN_IND は、接続要求を受け入れないタイプです。位置ビーコンのように、アドバタイジング・パケットのみで情報をブロードキャストするものに使います。
パブリック・デバイス・アドレスとランダム・デバイス・アドレス
ADV_INDタイプのペイロードは、6オクテットのアドバタイザのアドレスと、0から31オクテットのアドバタイジング・データとで構成されます<TBD ADV_INDPDUフォーマット/>。
パケットのアクセス・アドレスは、通信ごとにランダムな値です。ADV_INDのペイロードにある、この48ビットのアドレス AdvA は、デバイスを特定するアドレスです。このアドレスには、 パブリック・デバイス・アドレス(Public device address)とランダム・デバイス・アドレス(Random device address)の2種類があります。AdvAがいずれかは、ヘッダのTxAddの値で示します。TxAddrが0ならばパブリック・デバイス・アドレス、1ならばランダム・デバイス・アドレスです。
<TBD アドレスのビット構成/>の、パブリック・デバイス・アドレスは、Bluetooth SIGが企業ごとに発行した24ビットの識別子と、企業が製品1つづつに割り振る24ビットの識別子から構成されます。このアドレスは、製造時に書き込まれるデバイスに固有で唯一の値です。ランダム・デバイス・アドレスは、ハッシュ値とランダム値から構成されます。ランダム値は適当な一定時間ごとに変更されます。ハッシュ値は、デバイスが持っている128ビットのIRK(Identity Resolving Key)とランダム値から指定されたハッシュ関数で計算される値です。
ランダム・デバイス・アドレスはプライバシーを守るためにあります。パブリック・デバイス・アドレスは、デバイスそれぞれに割り振られた固有の値です。個人が持っているデバイスが、何かのきっかけでマスターとの接続が切断したとします。すると、デバイスは再接続をするためにアドバタイジングを始めます。このアドバタイジング・パケットは、誰でも傍受できます。ですから、アドバタイジング・パケットのアドレス AdvA から特定のデバイスの追跡が可能です。
ランダム・デバイス・アドレスを受信したスキャナは、事前にアドバタイザから受け取ったIRKを使い、ハッシュ値を計算します。このハッシュ値が、アドバタイジング・アドレスのハッシュ値と同じならば、それが目的のデバイスだとわかります。
アドバタイジング・データのフォーマット
Generic Access Profile(ジェネリック・アクセス・プロファイル、GAP)は、デバイスの発見と接続、そして通信データを暗号化するときは、鍵の交換をどのように行なうかを定義するものです。このGAPは、振る舞いを定義するものなので、リンク層から後に登場するGeneric Attribute Protocol(GATT)まで、層をまたいだ定義になります。次節のアドバタイジング・データのフォーマットは、GAPのシナリオから定義されています。
<TBD ADV_INDのフォーマット/>のAdv Dataのフォーマットは<TBD Adv Dataのフォーマット/>です。アドバタイジングの1つの情報をAD structureという単位で、それらの配列になっています。AD Structureは、1オクテットのLengthと、それに続く_Length_オクテットのDataです。Adv Datの長さは、1パケットのペイロードの制約で、31オクテットまでです。
AD structureのDataは、1オクテットのAD typeと_(Length-1)_オクテットのAd Dataで構成されます。AD typeは、いくつもありますが、知っておくべきものは次の5つです:
- Flags
- Local Name
- Manufacturer Specific Data
- TX Power Level
- Service UUIDs
Flags
デバイスがもつ発見や接続の機能を示すのがFlagsです<TBD Flagsのビット割り当て />。AD typeの値は0x01です。ビット0/1は、それぞれ論理値false/trueに対応します。Flagsは、アドバタイジング・パケットに1つだけ含めます。
AD type | ビット | 記述 |
---|---|---|
0x01 | 0 | LE Limited Discoverable Mode |
1 | LE General Discoverable Mode | |
2 | BR/EDR Not Supported | |
3 | Simultaneous LE and BR/EDR to Same Device Capable (Controller) | |
4 | Simultaneous LE and BR/EDR to Same Device Capable (Host) | |
5..7 | Reserved |
Bluetooth LEのみをサポートするシングルモード・デバイスは、BR/EDR Not Supported は'1’、Simultaneous LE and BR/EDR to Same Device Capable は、ホストとコントローラいずれも'0’になります。
Limited Discoverable Modeは、デバイスを発見できる時間制限があることを示します。接続が切れたからといって、不用意にアドバタイジングをさせたくない場合に使います。General Discoverable Modeは、常にデバイスが発見できるモードを示します。通常はこのモードを使います。
Local Name
Local name(ローカル ネーム)は、ユーザ・インタフェースの表示名などに使われる、ユーザが読めるデバイスの名称を示します。これはアドバタイジング・データかスキャン・データのいずれかに1つだけ含めます。文字列はUTF-8で符号化されます。C言語の’\0’のような、文字列の終端記号は必要ありません。
AD typeは、Shortened local name(ショーテンド ローカル ネーム)とComplete local name(コンプリート ローカル ネーム)の2つがあります<TBD ローカルネームのAD type/>。
AD type | 記述 |
---|---|
0x08 | Shortened local name |
0x09 | Complete local name |
Complete local nameは、デバイスの完全な名前です。しかしAdv Dataは最大31オクテットですから、ローカルネームが29バイトよりも大きいと、収まりません。この場合には、Shortened local nameを使います。これは完全なデバイス名の先頭部分を取り出したものです。例えば、完全なローカルネームが‘BT_Device_Name’ならば、短縮したローカルネームは、例えば‘BT_Dev’となります。人間が読んで意味がわかる区切りで切り出すとよいです。
Shortened local nameが使われた時、完全なローカルネームは、上位層のGATTを通して、Device name characteristic から読み出せます<TBD 節への参照/>。
Manufacturer Specific Data
Manufacturer Specific Data(マニュファクチャラ スペシフィック データ)は、それぞれの企業の任意データに使われます。AD type は 0xFFです。Ad Dataは、先頭2オクテットが Bluetooth SIGが企業に発行した識別子、そして任意長のバイナリ・データが続きます。企業の識別子はCompany Identifiers documentsにリストがあります。
位置ビーコンのような、非接続で周囲の不特定多数のBluetooth LEデバイスに同報するときに、データの格納に使えます。
Tx Power Level
送信電力を表します。AD typeは0x0Aで、Ad Dataは符号付きバイトの値のみがあります。値の単位はdBmで、-127 から +127dBm までの値を示します。
Tx Power Levelは、アドバタイザとの距離の推定に使います。この値と受信したパケットの受信信号強度(Received Signal Strength Indication, RSSI)から、伝搬損失(pass loss)は次の式で求められます:
$$ 伝搬損失 = Tx Power Level – RSSI $$
デバイス間の距離が離れるほど伝搬損失が大きくなりまが、残念ながら、電波の直接波と反射波の干渉で生じるフェーディング、アンテナの放射パターンなど、様々な要素により、伝搬損失は単純な距離の関数とはなりません。デバイスが近いか遠いかを推定する、ことには使えます。
Service UUIDs
Bluetooth LEのサービスは、機能を表します。例えば、エアコンであれば、温度設定といった制御値の入力機能、あるいは現在の室温といった計測機能が、それぞれ独立したサービスになります。機能の識別子にはUUID(Universally Unique Identifier)という128ビットの値が使われます。しかし128ビットそのままでは通信に時間がかかるので、Bluetooth SIGが承認したサービスには16ビットに短縮したUUIDが割り当てられています。
<TBD Service UUIDs のAd type/>のAD typeは、アドバタイザが持っているサービスのUUIDの配列を示します。31オクテットに収まる範囲で、主たる機能を表すサービスのリストを列挙します。
<TBD スキャンの様子、リアルで確認/>
値 | 概要 | 備考 |
---|---|---|
0x02 | 16-bit Service UUIDs | More 16-bit UUIDs available |
0x03 | 16-bit Service UUIDs | Complete list of 16-bit UUIDs available |
0x04 | 32-bit Service UUIDs | More 32-bit UUIDs available |
0x05 | 32-bit Service UUIDs | Complete list of 32-bit UUIDs available |
0x06 | 128-bit Service UUIDs | More 128-bit UUIDs available |
0x07 | 128-bit Service UUIDs | Complete list of 128-bit UUIDs available |
接続と通信
アドバタイザが送信したアドバタイジング・パケットに、イニシエータがコネクション・リクエスト・パケット(CONNECT_REQ)を返信すると、接続状態になります。接続した2つのデバイスの役割は、イニシエータがマスターに、アドバタイザがスレイブに、それぞれ切り替わり、接続状態(<TBD 状態遷移図/>のCONNECTED)に遷移します。
アドバタイジングはアドバタイザがパケットの送出タイミングを制御していました。接続後はマスターがタイミングを制御します。接続後、マスターは一定期間ごとに、スレイブにパケットを送信します。スレイブはマスターからのパケットに返信する形で、データを送ります。マスターは複数のスレイブと接続します。マスターがスレイブに最初に送るパケットの送信タイミングで、スレイブそれぞれとの通信タイミングが重ならないようにします。
通信のタイミング
く図<TBD 接続のパケット/>が接続確立と通信のタイミング図です。アドバタイジング・パケットの送信完了から150マイクロ秒後に、イニシエータはCONNECT_REQを送信します。イニシエータはアドバタイザがCONNECT_REQを受信できたかを、確認しません。もしもアドバタイザがCONNECT_REQを受信しておらず、接続状態に遷移していない場合は、マスターがしばらく通信できないので、接続が切断したと判断します。
CONNECT_REQパケットには、<TBD 表/>の接続パラメータが入っています。パラメータの複合語は、先頭は小文字につづく単語は先頭を大文字にして連結(CamelCase、キャメルケース)します。
transmitWindowOffset(transmit window offset、トランスミット・ウィンドウ・オフセット)は、CONNECT_REQを送信してから、次のtransmit window sizeが始まるまでの、オフセット時間を示します。
transmitWindowSize (transmit window size、トランスミット・ウィンドウ・サイズ)は、最初のデータ・パケットを送信できる期間を示します。
connInterval(connection interval、コネクション・インターバル)は、チャンネルをホップする周期を示します。
connSlaveLatency(connection slave latency、コネクション・スレイブ・レイテンシ)は、スレイブが送信するデータがなにもないときに、コネクション・イベントを無視出来る回数を示します。
connSupervisionTimeout(connection supversion timeout、コネクション・スーパービジョン・タイムアウト)は、接続が失われたと判断する、コネクション・イベントの失敗回数を示します。
名称 | 値の制約 | 値の範囲 |
---|---|---|
transmitWindowOffset | 1.25 ms 単位 | 0 ms 以上 connInterval 以下 |
transmitWindowSize | 1.25 ms 単位 | 1.25 ms 以上、10 msもしくは(connInterval - 1.25 ms) 以下 |
connInterval | 1.25ms 単位 | 7.5 ms 以上 4.0 s 以下 |
connSlaveLatency | 整数 | 0以上最大値以下 *1 |
connSupervisionTimeout | 10ms 単位 | 100ms 以上 32秒 以下 *2 |
1 最大値は ((connSupervisionTimeout / connInterval) - 1) かつ 500以下。 2 (1 + connSlaveLatency) * connInterval よりも大きいこと
マスターは、CONNECT_REQを送信してから、(1.25ミリ秒 + transmitWindowOffset)あと、transmitWindowSize の期間中に、最初のデータ・パケットを送信します。マスターは、この最初のデータ・パケットから、一定期間ごとに、スレイブにデータ・パケットを送信します。マスターは複数のスレイブと接続するので、他のスレイブと通信タイミングが重ならないように、この最初のデータ・パケットの送信タイミングで調整します。その調整幅が transmitWindowSize になります。
最初のデータ・パケットの送信タイミングから一定期間 connInterval ごとに、コネクション・イベントが発生します。マスターとスレイブは、ともに送信すべきデータがあり、送信するパケットがコネクション・インターバルに収まるかぎり、データ・パケットをやりとりします。
このコネクション・イベントで、マスターとスレーブで通信タイミングを同期することで、高周波回路の消費電力を必要最小限にしています。スレーブは、マスターがパケットを送信するタイミングにあわせて、受信回路を動かして、消費電力の大部分を占める高周波回路の駆動時間を必要最小限にします。
コネクション・イベントごとに、通信につかう周波数帯域、チャンネルを切り替えます。チャンネルの切り替えは、チャネル番号ごとに順番に1つづつ移動するのではありません。マスターとスレーブが接続時に交換するパラメータ、次の節で述べるLLDataのChM と Hop の2つの変数で計算したチャネルに、ホッピングしていきます。もしもあるチャンネルで通信ができなくても、そのチャンネルで再接続や再送処理をすることはありません。次のコネクション・イベントで、別のチャンネルに切り替えて、通信を継続します。
スレーブに送るべきデータができたときから、そのデータがマスターに送信されるまでの時間を、遅延時間 レイテンシ、と呼びます。コネクション・インターバル connInterval が20ミリ秒であれば、スレーブは20ミリ秒ごとにデータを送信する機会があるので、レイテンシは、最大が20ミリ秒、平均すれば10ミリ秒になります。connIntervalを短くするほどレイテンシは小さくなりますが、それだけ無線通信の電力消費量も大きくなります。小さいレイテンシと超低消費電力を両立させるための工夫が、コネクション・スレーブ・レイテンシです。
コネクション・スレーブ・レイテンシ connSlaveLatency は、スレイブがコネクション・イベントを無視できる回数を表します。スレーブに送信すべきデータがないとき、スレーブは connSlaveLatency までコネクション・イベントを無視できます。スレーブは送信すべきデータがなくても、(connSlave Latency + 1)回目のコネクション・イベントには返信をします。もしも(connSlave Latency + 1)回目のコネクタ・イベントで、スレーブがマスターからの返信を受け取れなかった場合は、通信が成立していないものとみなして、通信できるまで、その後のコネクション・イベントに返信をします。
例えば connInterval が20ミリ秒、connSlaveLatencyが 5 とします。スレーブに送信すべきデータがないならば、5回のコネクション・イベントを無視できます。そして6回目のコネクション・イベントに返信をします。つまり、レイテンシは20ミリ秒のままで、スレーブの無線通信頻度を100ミリ秒、1/5 の電力に抑えられます。
コネクション・スーパービジョン・タイムアウト connSupervisionTimeout は、通信が切断したと判断する時間です。マスターおよびスレーブはそれぞれ、通信をしない時間が コネクション・スーパービジョン・タイムアウト を超えたならば、通信が切断したと判断します。スレーブは、コネクション・スレーブ・レイテンシ だけパケットを無視できます。
コネクション・スーパビジョン・タイムアウトが最小値 $ (connSlaveLatency + 1 ) * 1.25ミリ秒 $ のとき、connSlaveLatencyだけパケットを無視したスレーブと、その次のコネクション・イベントで通信ミスが生じれば、直ちに切断してしまいます。頻繁な切断を避けるには、connSupervisionTimeout を目安として connSlaveLatency の6倍程度に設定します。例えば connSlaveLatency が5、connIntervalが20ミリ秒のとき、conSupervisionTimeout は ( 5 * 20ミリ秒 ) * 6 = 600ミリ秒 に設定します。
CONNECT_REQ PDUペイロード
イニシエータがアドバタイザに送るCONNECT_REQのPDUのフォーマットはです。InitAおよびAdvAは、それぞれイニシエータとアドバタイザのアクセス・アドレスです。アドバタイザはAdvAが自分宛であることを確認して、接続状態に遷移します。LLDataは22オクテットの接続パラメータです。
AA は、接続した後のデータ・パケットのアクセス・アドレスです。アドバタイジング・パケットのアクセス・アドレスは固定値でした。データ・パケットのアクセス・アドレスには、イニシエータがランダムに生成したアクセス・アドレスの制約条件を満たす値が使われます。
CRCInit はパケットのチェックサムを検査するシフトレジスタの初期値を指定します。CRCInitは、イニシエータがランダムに生成します。シフトレジスタは巡回検査符号を計算するためのハードウェアです。Bluetooth LEの巡回検査符号は、 多項式 $ x^24 +x^10 +x^9 +x^6 +x^4 +x^3 +x +1 $ を24個のシフトレジスタで実装した回路で計算されます。パケットの受信処理を開始する都度、これらのシフトレジスタは、CRCInitの値で初期化されます。ちなみに、アドバタイジングのときは、シフトレジスタは固定値 0x555555 で初期化されます。
WinSize、WinOffset、Interval、LatencyおよびTimeoutは、それぞれ前節のtransmitWindowSize、transmitWindowOffsetvalue、connInterval、connSlaveLatency、およびconnSupervisionTimeの値を表します。WinSizeなどの値は2オクテットの整数です。接続パラメータの物理値は、これらの整数値それぞれにの値の制約の単位をかけたものです。例えば、$ transmitWindowSize = WinSize * 1.25ミリ秒 $ です。
ChMは、チャネルマッピングを表します。コネクション・イベントでどのデータ・チャネルを使うかを指定します。WiFiなどの、干渉するとわかっている周波数帯域のデータ・チャンネルを使わないようにして、干渉を回避するのに使います。ChMは4オクテットの値で、それぞれのビットがチャンネルに対応します。最下位ビットがチャンネル0、下位から36ビット目がチャンネル36に対応します。チャンネルを指定するときは、チャンネル10とチャンネル11の間には、アドバタイジング・チャンネル38があり、データ・チャンネルだけをみると周波数帯域が1つ飛ぶことに、注意します。
hopIncrementは、データ・チャンネルの切り替え順番を指定します。あるコネクション・イベントでチャンネル A を使った時、次のコネクション・イベントで使うチャンネル B は $ B = (A + hopIncrement) mod 37 $ で求めます。この式の mod は剰余の演算子です。例えば、hopIncrementが5のとき、あるコネクション・イベントでチャンネル3を使っていれば、次のコネクション・イベントは、$ ( 3 + 5 ) % 37 = 8 $ から、チャンネル8をつかいます。もしもチャンネル・マッピングで利用不可のチャンネルが指定されている場合は、そのチャンネルは使いません。利用可能なチャンネルがでるまで、
hopIncrementの値が小さすぎると、周波数があまり離れていないチャンネルに移動します。もしもWiFiなどの混信があると、チャンネル・ホッピングとしても影響を受けやすくなります。また16よりも大きくしていっても、剰余演算なので、逆にホッピング先が近くなります。ですから、値を大きくする意味がありません。37は素数なので、5から16までのどの値をとっても、37のチャンネルを、いつかは選択することになります。
SCAはマスターのスリープ・クロックの精度を表します。これは、マスターがコネクション・イベントで送信するパケットを、スレーブが取りこぼさないために必要です。マスターもスレーブも、高精度の発振回路を搭載していますが、それでもppm(百万分の1)の桁のずれが生じています。スレーブは、発振回路のずれから生じるコネクション・イベントのパケット送信タイミングのずれ時間分だけ、受信回路の動作開始時刻を前にずらします。
通信
接続したマスターとスレーブのデータ・パケットのPDUののフォーマットはです。2オクテットのヘッダと、0~33オクテットのペイロード、そして通信を暗号化していてペイロードが0より大きいときは、4オクテットのMessage Integrity Check(MIC)がつきます。
データチャネルPDUの最大長さは、パケットフォーマット()のPDUの最大長さ39オクテットで制約されます。暗号化をしていないならば、MICの4オクテットをペイロードとして使えそうなものですが、暗号化の有無でバッファ長が変化しない設計になっています。
データ・チャネルPDUは、上位層 Logical Link Control and Adaptation Protocol (L2CAP)のパケットを分割送信します。
データ・チャネルPDUのヘッダは次の<TBD 表/>のフォーマットです。
フィールド名 | 記述 |
---|---|
LLID | ロジカル・リンクID (Logical Link Identifier) |
パケットの種類を示す。 | |
00b = Reserved | |
01b = LL Data PDU (Continuation) | |
10b = LL Data PDU (Start) | |
11b = LL Control PDU | |
NESN | Next Expected Sequence Number |
SN | シーケンス番号 (Sequence Number) |
MD | モア・データ (More Data) |
Length | ペイロードとMICのオクテット単位の長さ |
データチャンネルPDUは、LLIDの値で、ロジカル・リンク・データPDU(LL Data PDU)と、ロジカル・リンク・コントロールPDU(LL Control PDU)の2種類にわけられます。
ロジカル・リンク・データPDU
ロジカル・リンク・データPDUは、上位層(Bluetooth LEではL2CAP)のパケットの分割転送と受信時の再構築に使われます。
上位層(L2CAP)のパケット長がデータ・チャネルPDUのペイロードよりも長いとき、上位層からのパケットは複数のロジカル・リンク・データ PDUに分割して送信されます。一連のパケットの列は、最初のパケットのLLIDが 10b(Start、始めの) 、それに続くパケットの LLIDを 01b (Continuation、続きの)にして判別します。
上位層のパケット長がデータ・チャネルPDUのペイロードにおさまるときは、LLID 01bのパケット1つだけで、その後にLLID 01bのロジカル・リンク・データPDUは続きません。
ロジカル・リンク・データPDUに、上位層のパケット長を示すフィールドはありません。リンク層は、上位層からデータが来れば、順次それをStartとそれに続くContinuationのデータ・パケットに分割するだけです。ですから、リンク層は上位層のパケット長を事前に知る必要はありません。
Lengthはペイロードのオクテット長を示します。LLID 10b (Start)のデータPDUのLengthは0より大きい値、LLID 01b (Continuation)のLengthは0を含む値がとれます。LLIDが 01b (Continuation)でLengthが0のパケットを、エンプティ・パケット(Empty packet)と呼びます。
エンプティ・パケットは、フロー制御に使います。Continuationのパケットで<TBD パケット分割の図/> 送信すべきデータ揃っていないときは、エンプティ・パケットを埋め草として使います。またコネクション・イベントで、マスターからスレーブにパケットを送信するとき、マスターから送信すべきデータがないとき、また逆にスレーブがマスターにデータはないが接続を確認するために返信するときにも、エンプティ・パケットを使います。
Sequence number(シーケンス番号、SN)とNext expected sequence number(ネクスト・イクスペクテッド・シーケンス番号、NESN)は、信頼できるパケット通信とフロー制御に使われます。
SNとNESNは1ビットの値です。マスターとスレーブはコネクション状態<TBD 状態遷移の図/>に入るときに、SNとNESNをそれぞれ0に初期化します。SNは自分が送信するパケットのシーケンス番号を、NESNは相手に次に送ってほしいパケットのシーケンス番号を設定します。
マスターがコネクションイベントで、(SN = 0, NESN = 0)のデータ・チャネルPDUをスレーブに送ったとします。スレーブがこのパケットを受信して、次のパケットの送信を求めるならば、スレーブは NESN = 1 のデータ・チャネルPDUを送信します。マスターは、スレーブが NESN = 1 を送ってきたのをみて、直前に送信したSN=0のパケットをスレーブに送信できたと確認できます。マスターは次はSN = 1のパケットを送信します。
マスターが(SN = 0, NESN = 0)のデータ・チャネルPDUをスレーブに送った時、スレーブがパケットのビットエラーを検出したとします。スレーブは、マスターに SN = 0 のパケットを再送してもらうために、NESN = 0 のデータ・チャネルPDUを送信します。マスターは、スレーブがNESN = 0 を送ってきたのをみて、SN = 0 のパケットを再送します。
この仕組は、フロー制御にも使えます。例えば、スレーブの受信バッファがいっぱいで、パケットのペイロードを読み込めないときは、マスターにそのパケットの再送を要求します。
送信側から見て、送信先がパケットの受信に失敗する原因は、電波状態が悪いなどで、パケットにビットエラーが発生またはパケット自体を検出できていない場合と、先のフロー制御のように送信先の処理速度が追いつかない場合の2つがあります。送信側から見て送信先から返ってくる反応は、何も返ってこない、再送を要求するパケット(直前に送ったパケットのSNが NESN に設定されている)が返ってくる、および正常に受信できた(直前に送ったパケットのSNと違う値が NESN に設定されている)の3通りです。何も返ってこない場合は、次のコネクション・イベントで通信を再同期します。なにかしらパケットが返ってきた場合は、送信側は、再送もしくは次のパケットを送信します。
SNおよびNESNは1ビットの値です。マスターとスレーブはピコネット内で交互にパケットをやりとりします。ですから、パケット伝送の遅延時間が大きい場合にスループットを上げる目的で使われる、パケットの先送りがありません。ですから、SNおよびNESNは1ビットでよいのです。
MD(モア・データ、More Data)は、接続先デバイスに送信すべきデータがまだあることを示す1ビットの値です。MDが1ならデータが未だある、0ならば送信すべきデータはもうない、ことを示します。MDが1である限り、パケットのやり取りが継続します。もしもコネクション・インターバルの終わりになっても、MDが1ならば、そのコネクション・イベントは自動的に延長されて通信が継続します。逆にMDが0であれば、それ以上のデータはないとわかるので、直ちにスリープ状態に入るなどして省電力化ができます。
ロジカル・リンク・コントロールPDU
ロジカル・リンク・コントロールPDUは、リンク層の接続制御に用います。ロジカル・リンク・コントロールPDUのフォーマットは、1オクテットのopcode(オペコード)と0から22オクテットのCtrData(コントロール・データ、control data)で構成されます。<TBD 次の表/>は、オペコードの値とその意味です。
オペコード | コントロールPDU 名 |
---|---|
0x00 | LL_CONNECTION_UPDATE_REQ |
0x01 | LL_CHANNEL_MAP_REQ |
0x02 | LL_TERMINATE_IND |
0x03 | LL_ENC_REQ |
0x04 | LL_ENC_RSP |
0x05 | LL_START_ENC_REQ |
0x06 | LL_START_ENC_RSP |
0x07 | LL_UNKNOWN_RSP |
0x08 | LL_FEATURE_REQ |
0x09 | LL_FEATURE_RSP |
0x0A | LL_PAUSE_ENC_REQ |
0x0B | LL_PAUSE_ENC_RSP |
0x0C | LL_VERSION_IND |
0x0D | LL_REJECT_IND |
0x0E-0xFF | 将来のために予約 |
LL_CONNECTION_UPDATE_REQ と LL_CHANNEL_MAP_REQ は、コネクションのパラメータおよびチャンネル・マッピングを更新するオペコードです。やり取りするパラメータは、コネクション時のLL Data と同じものです。これらのオペコードは、マスターのみが使えます。それは、これらの接続パラメータの値を決められるのは、ピコネットの通信を制御しているマスターのみだからです。もしもスレーブが接続パラメータを更新したいときは、リンク層の上位層のL2CAPの、LE signaling channnel を使います。
LL_CONNECTION_UPDATE_REQ のCtrlDataのフォーマットの WinSize、WinOffset、Interval、Latency、および Timeout は、それぞれ の transmitWindowSize、transmitWindowOffset、connInterval、connSlaveLatency、および connSupervisionTimeout と同じ意味を持ちます。
Instant は、どのコネクション・イベントで、接続パラメータを更新するかを指定します。マスターとスレーブはそれぞれ、コネクション状態になってからのコネクション・イベントの数を connEventCount というカウンタで計測しています。Instantが示すコネクション・イベントのタイミングで、の接続開始時の処理を行い、アンカー・ポイントの再設定を行います。 LL_CHANNEL_MAP_REQ も、これと同様です。
オペコード 0x03 (LL_ENC_REQ) から0x0B (LL_PAUSE_ENC_RSP) は、パケットの暗号化のコマンド群です。LL_ENC_REQとLL_ENC_RSPは、暗号/復号処理に必要な情報をやり取りします。LL_START_ENC_REQ と LL_START_ENC_RSP は暗号化の開始を、LL_PAUSE_ENC_REQ と LL_PAUSE_ENC_RSP は暗号化の中断のコマンドです。
データ・チャネルPDU のヘッダのLengthフィールドは、ペイロードとMICを合わせた長さを示します。またパケットが暗号化されている/いないを示すフラグはありません。ですが、マスターとスレーブは、ロジカル・リンク・コントロールPDUで、今の通信が暗号化されている/いないがお互いにわかるので、暗号化を示すフラグは必要ありません。
LL_FEATURE_REQ および LL_FEATURE_RSP は、マスターおよびスレーブのリンク層の機能を示すデータをやりとりします。いまの規格は、暗号化サポートの1ビットのみを定めています。Bluetooth LEのリンク層の機能は、デフォルトですべての機能が有効になっています。接続時に、機能サポートを調べる必要はありません。もしも機能がサポートされていなければ、そのコマンドはリジェクトされます。そのエラー原因は、リジェクトで返される LL_REJECT_IND の、CtrDataにあるエラーコードから取得できます。
LL_VERSION_IND はコントローラのバージョン番号を示します。おもな用途は、接続時にトラブルが生じた時などの、デバックです。Bluetooth Controller の仕様番号、製造者番号、および実装番号が取得出来ます。仕様番号および製造者番号はBluetooth SIGが割り当てた値が使われます。
LL_UNKNOWN_RSP PDUは、LLコントロールPDUが予約されたオペコードや不正なCtrlDataを含むとき、そのレスポンスに使われます。
LL_REJECT_IND は、コマンドをリジェクトした時のエラーコードを返します。例えば、暗号化処理を要求したときに、相手先が暗号化処理を行えないときは、 ENCRYPTION MODE NOT ACCEPTABLE (0x25) が返されます。また、暗号化を必要とするGATTのキャラクタリスティクスへの読み書き等を、暗号化を開始せずに実行したときは、 INSUFFICIENT SECURITY (0x2F) が返されます。
Logic Link Control and Adptation Protocol
リンク層は接続デバイスとの通信路を提供します。Bluetoothには、この1本の通信路で様々なプロトコルやアプリケーションの通信を提供するために、Logic Link Control and Adptation Protocol (L2CAP、エルトゥーキャップ、頭文字のLが2続くのをL2と略している)があります。
L2CAPは、チャンネルという考え方で通信を多重化します。上位層のパケットの分割と統合、チャンネルごとのフロー制御とパケット再送制御、エラー・コントロールを提供します。Bluetoothでは、例えばヘッドセットなど一定のビットレートでストリーミングをするものや、ファイル転送など、大容量の情報を可能な限り高速で送信するものなど、アプリケーションごとに必要とするネットワークの特性が異なります。L2CAPは、必要とする特性にあわせた通信路を提供します。上位層のプロトコルおよびアプリケーションからみると、他のプロトコル/アプリケーションの通信状態にかかわらず、相手側のプロトコルおよびアプリケーションとの通信が確保されていると見えます。
クラシックBluetoothのL2CAPは、チャンネルを確立するときに、フロー制御などのパラメータをやりとりするために、複雑でまた処理時間もかかります。クラシックBluetoothは、一度接続すれば長時間接続しつづける用途に使われるので、接続時にかかる時間は許容されます。
しかしBluetooth LEは、コネクションを維持するものではありません。簡単に接続して、簡単に切断してしまうものです。これにL2CAPを対応させるために、Bluetooth LEのL2CAPは、固定されたチャンネルのみが提供されます。この固定チャンネルでは、接続時のパラメータのやりとりはありません。
Bluetooth LEのL2CAPのチャンネルは、の3つの固定チャンネルだけです。
Channel ID | 説明 |
---|---|
0x0004 | Attribute Protocol |
0x0005 | Low Energy L2CAP Signaling channel |
0x0006 | Security Manager Protocol |
パケット構造
L2CAPのパケット構造は、2バイトのLengthとChannel ID、それに0から65535バイトまでのinformation payloadが続きます。
チャンネルID 0x0005 のシグナリング・チャンネルのフォーマットは、1バイトのコードと識別子、2バイトの長さと任意長のデータが続きます。コードは次の3つだけです:
- Connection Parameters Update Request/ Response
- Command reject
シグナリング・チャンネルのIdentifierは、コマンドを発行した側が、0x00以外の値を設定します。コマンドを処理した側は、レスポンスにその識別子を設定して結果を返します。コマンド発行側は、複数のリクエストを同時に発行したときでも、この識別子の値から、どのコマンドに対する結果なのかがわかります。Bluetooth LEは、リクエストが1つですから、この処理はとても単純になります。
Connection Parameters Update Request/Responseは、スレーブからホストへの接続パラメータの変更要求に使われます。このConnection Parameters Update Requestは、スレーブはいつでもマスターに送信できます。マスターは送信できません。もしもサポートされていないコマンドを受信したり、データ長が期待した長さ(23バイト)ではない場合は、Command rejectが返されます。
このリクエストを受信したマスターは、その変更パラメータを受け付けるならば、レスポンスで受け付けること(accepted) を返してから、ロジカル・コントロールPDUから接続パラメータを更新します。変更パラメータを受け付けないならば、レスポンスで受付拒否(rejected)を返します。マスターには、その他のスレーブとの接続や、WiFiやクラシックBluetoothとの共存などの制約があります。スレーブは、変更パラメータの値の範囲をなるべく広くとって、マスターが受け入れられるパラメータを選べるようにすべきです。
スレーブからのコネクション・パラメータのアップデート要求は、通信速度と省電力の両立に利用できます。マスターは接続時にスレーブから、ATT/GATTのサービスおよびキャラクタリスティクスを読み出します。ですから接続直後に通信速度が高いパラメータを選択すれば、素早い接続処理ができます。接続が完了した後は、アプリケーションに応じた通信頻度で、より低消費電力のパラメータに切り替えることで、省電力化ができます。これらの、パラメータの設定や切り替えは、スレーブの設計次第です。コネクション・インターバルが小さい値でも、スレーブ・レイテンシが高くできるならば、パラメータの変更は必要ないかもしれません。
Attribute Protocol と Generic Attribute Profile
Attribute Protocol (アトリビュート・プロトコル、ATT)は、ATTはアドレスとラベルつきの値の集合をやりとりするプロトコルです。ATTは、L2CAPまでで確保された接続したデバイス間の通信を使い、Bluetooth LEの特徴的な通信の機能や振る舞いを提供しています。
ATTの上位層にGeneric Attribute Profile(ジェネリック・アトリビュート・プロファイル、GATT)があります。このATTとGATTは、Bluetoothに統合される以前の規格では1つの層でした。これが、規格に取り込む際に、通信の手順を表すプロトコル、ATT、と機器の振る舞いを表すプロファイル、GATT、の2つの層に分離されました。ATTは、ATT単体ではなく、Bluetooth LEの設計方針およびATTの上位層のとあわせて理解すると、Bluetooth LEでのATTの意味がよくわかります。
ATTとGATTの特徴
ATTとGATTの特徴は:
- すべてのアプリケーション使うシンプルな1つのプロトコル
- 通信と振る舞いを分離
- Bluetoothの認証の範囲で多種多様な周辺機器の開発を可能にする
です。
クラシックBluetoothは、メーカや機種を超えた相互運用を提供するために、通信プロトコルやデータ形式などの通信部分のみならず機器の振る舞いまでを含めたものを、プロファイルと定義します。例えばヘッドセットやファイル交換などの、アプリケーションごとにプロファイルが定義されます。Bluetooth SIGがプロファイルを定義していないアプリケーションの開発には、シリアル・ポート・プロファイルという、汎用通信のプロファイルを使います。この場合、通信プロトコルなどは、自ら開発しなければなりません。
Bluetooth LEでは、GATTの上層に、すべてのアプリケーションが作られます。GATTが通信の振る舞いを、アプリケーションが機器の振る舞いを、それぞれ担当するように層が分けられています。そして、Bluetooth LEでは、Bluetoothの認証範囲はGATTまでで、アプリケーションは含みません。したがって、Bluetooth LEは、Bluetoothのロゴ認証のもとで、多種多様なアプリケーション、つまり周辺機器、を一般に販売できます。
Bluetooth LEは、機器の振る舞いをプロファイルと呼びます。例えば心拍や血圧計など、メーカや機種を超えた相互運用が一般普及のために必要不可欠な分野があります。Bluetooth LEのプロファイルは、それぞれの分野で業界団体あるいは会社群がプロファイルを作成して、それをBluetooth SIGが承認することで成立します。GATTとアプリケーションが分かれているので、GATTというプロトコルはそのままで、分野ごとに多種多様なプロファイルが、必要になるたびに追加されます。
アトリビュート・プロトコル
Attribute Protocol(アトリビュート・プロトコル、ATT)は、アトリビュート・サーバ(ATTサーバ)とアトリビュート・クライアント(ATTクライアント)の通信プロトコルです。
ここで、アトリビュートは、アドレスとタイプでタグ付けされた値のことです。ATTサーバは、アトリビュートの集合を公開するものをいいます。ATTクライアントは、サーバが公開するアトリビュートを参照するものをいいます。サーバのアトリビュートは、クライアントから、発見、読み出し、書き込みができます。またサーバからクライアントに、インディケーション(indication)またはノーティフィケーション(notification)ができます。
アトリビュート
サーバが公開するアトリビュートの、サーバ内での論理表現は、アトリビュート・ハンドル (attribute handle)、アトリビュート・タイプ(attribute type)そしてアトリビュート・バリュー(attribute value)、アトリビュート・パーミッション(attribut permission)の4つで構成されます。
アトリビュート・ハンドルは、ATTクライアントがATTサーバのアトリビュートにアクセスするときに使われます。アトリビュート・ハンドルは、2オクテットの0x0001から0xffffまでの値です。
アトリビュート・タイプは、アトリビュートのデータの型を示します。これは128ビット(16オクテット)のUUID (Universally Unique IDentifier) RFC 4122です。しかし、128ビットのUUIDそのままを通信でやりとりすると、通信時間が長くなり電力を使います。そこで、Bluetooth SIGが、よく使うものには16ビット(2オクテット)のUUIDを割り当てています Assigned Numbers。この16ビットのUUIDは、次の128ビットのUUIDのxxxx部分を抜き出した短縮したUUIDです。
0000xxxx-0000-1000-8000-00805F9B34FB
16ビットのUUIDを128ビットのUUIDに戻すには、この128ビットのUUIDのxxxx部分を16ビットのUUIDで置き換えます。例えば 0x1801 ならば:
00001801-0000-1000-8000-00805F9B34FB
となります。
アトリビュート・バリューは0から512バイトまでの任意のバイト・データです。エンディアンは上位層の仕様が決めます。
アトリビュート・パーミッションは、アトリビュート・プロトコルで読み出すことはできません。上位層がどのアトリビュートが読み書きできるかを決めます。アトリビュート・プロトコルで、読み込みのみのアトリビュートに書き込みのリクエストをすれば、パーミッションがないので書き込めないとうエラー・レスポンスが返ってくるので、間接的にパーミッションを知ることができます。
リクエストとインディケーション
アトリビュート・プロトコルのアトリビュート・プロトコルPDU (Protocol Data Unit)のやりとりには、リクエスト、インディケーション、コマンド、そしてノーティフィケーションの4つがあります 図。たいていのアトリビュート・プロトコルPDUは、図 (a)の、シーケンシャルなリクエスト-レスポンス・プロトコルを使います。
クライアントからサーバにリクエストするときには、アトリビュート・リクエスト(ATTリクエスト)とアトリビュート・レスポンス(ATTレスポンス)のペアを、サーバからクライアントに通知するにはアトリビュート・インディケーション(ATTインディケーション)とアトリビュート・コンファメーション(ATTコンファメーション)のペアを使います。これらのやりとりをトランザクションと呼びます。
リクエストおよびインディケーションには、正常に処理できたならば、それぞれレスポンスもしくはコンファメーションが返されます。もしもエラーが生じた場合は、エラーメッセージが返されます。
トランザクションの期間は、ATTリクエストおよびATTレスポンスのペアでは、クライアントではリクエストの送信からサーバからのレスポンスを受信するまで、サーバではリクエストを受信してからレスポンスを送信し終えるまで、です。ATTインディケーションおよびコンファメーションのペアでは、サーバはインディケーションを送信してからコンファメーションを受信するまで、クライアントはインディケーションを受信してからコンファメーションを送信し終えるまで、です。
トランザクションが使えると、サーバとクライアントの間での処理要求や通知を確実に実行できます。ですが、トランザクションの排他処理や、トランザクションの失敗検出とその後処理をどうするのかを決める必要が生じます。
サーバおよびクライアントが実行するトランザクションは常に1つだけです。クライアントは、あるサーバにリクエストを送信したら、そのサーバからのレスポンスを受信するまで、同じサーバにリクエストは送りません。また、サーバがクライアントにインディケーションを送信した場合も、コンファメーションを受診するまで、インディケーションを送信しません。
リクエスト処理が完了するまでクライアントは待つので、フロー制御が得られます。また、サーバのリクエスト処理には、マイクロコントローラの計算時間や外部センサ回路を動かす処理などが必要かもしれません。もしもトランザクションが複数だと、資源の管理やロック機構が必須になります。トランザクションを1つにしているので、サーバにそのような仕組みを持たせずにすみます。
30秒以内にトランザクションが完了しないときは、タイムアウトとみなし、そのトランザクションは失敗とされます。上位層はトランザクション失敗を通知されます。トランザクションが失敗すると、それ以上アトリビュートPDUはやりとりされません。アトリビュートPDUのやりとりを再開するには、接続の切断と再接続をします。
トランザクションの途中で通信が切断した場合は、そのトランザクションは閉じられます。そのトランザクションがサーバの値を変更するものだった場合は、サーバの値がどうなるかは不定です。その時の振る舞いは、上位層の仕様で決めておきます。
サーバのアトリビュート・バリューのサイズは最大で512オクテットです。サイズが1つのアトリビュートPDUに収まらないアトリビュート・バリューの読み書きは、複数回のトランザクションで処理します。このために、アトリビュート・プロトコルには、オフセットを指定できるRead BlogリクエストとPrepare Writeリクエストが用意されています。もしも一連のトランザクションが、途中で失敗したり接続が切断した場合はサーバの値は不定になります。この時の振る舞いは、上位層の仕様で決めておきます。
コマンドとノーティフィケーション
アトリビュート・プロトコルには、クライアントからサーバへのアトリビュート・コマンド(ATTコマンド)、そしてサーバからクライアントへのアトリビュート・ノーティフィケーション(ATTノーティフィケーション)があります 図。これらはリクエスト/インディケーションと異なり、トランザクションもフロー制御もありません。トランザクションと無関係に、任意のタイミングで任意の回数の送信ができます。
例えば、クライアントがATTリクエストを送信して、まだレスポンスを受信していない時、トランザクションが終了していない時でも、クライアントはサーバにATTコマンドを送信できます。また、サーバも同様にトランザクションの途中でも、クライアントにATTノーティフィケーションを送信できます。
ATTコマンドとATTノーティフィケーションは、任意のタイミングに送信できるので、フロー制御はありません。リンク層の機能で、サーバおよびクライアントは、ATTコマンドおよびATTノーティフィケーションを確実に受信しますが、メモリ容量や計算時間が不足するなどした場合は、それらの処理を無視します。ATTコマンドおよびノーティフィケーションは、処理されるかが信頼できないもの、として扱います。
フロー制御がありませんから、例えば、クライアントから大量のコマンドがサーバに送りつけられるかもしれません。このようなことにならないように、上位層の仕様を決めておきます。
クライアントからのATTコマンドに対して、サーバが何かを返信したい場合、直ちに返信する必要はありません。トランザクションはないので、タイムアウトはありません。サーバは、ATTインディケーションかATTインディケーションノーティフィケーションで、そのうち通知をすればよいのです。
アトリビュートPDUフォーマット
アトリビュートPDFは、アトリビュート・オペコード(Attribute opcode)、アトリビュート・パラメータ、オーセンティケーション・シグネチャ(Authentication signature)が続きます <TBD 図/>。図のATT_MTUは、アトリビュートPDUの最大長 Maximum Transfer Unit(MTU)を表し、デフォルト値は23オクテットです。
アトリビュート・オペコードは、オーセンティケーション・シグネチャ・フラグ(Authentication signature flag)、コマンド・フラグ(Command flag)そしてメソッド(Method)から構成されます。コマンド・フラグが1ならば、そのPDUはコマンドです。6ビットのメソッドにより、アトリビュート・パラメータのフォーマットとその意味が決まります。
また、オーセンティケーション・シグネチャ・フラグが1ならば、オーセンティケーション・シグネチャがあります。
オーセンティケーション・シグネチャは、通信の暗号化は必要ではないが、サーバの状態を変化させてしまう書き込み処理は、信頼できるクライアントからのみ受け付けたい場合に、用います。リンク層の機能を使い、通信自体を暗号化すれば、スニッフィングも防止できますが、しかしパケットのオーバーヘッドの増加と暗号化処理が必要になります。サーバはシグネチャから、アトリビュートPDUが信頼できるクライアントが送信したものだと、確認ができます。
このような用途なので、オーセンティケーション・シグネチャ・フラグが1になるのは、Writeコマンドのみです。また、リンク層で暗号化をしているときは、必要がないので、オーセンティケーション・シグネチャ・フラグは1にはできません。
ロング・アトリビュートとその扱い
長さが(ATT_MTU–1)オクテットを超えるアトリビュート・バリューをもつアトリビュートを、ロング・アトリビュート(long attribute)と呼びます。サーバのアトリビュート・バリューの最大長は512バイトですが、ATT_MTUのデフォルト値は23オクテットです。たいていATT_MTUはデフォルト値がつかわれますから、23オクテット以上のアトリビュート・バリューはたいていロング・アトリビュートです。
アトリビュート・プロトコルで、トランザクションで送信できるアトリビュート・バリューの最大長は(ATT_MTU–1)オクテットです。アトリビュート・プロトコルのリード/ライト・リクエストは、ロング・アトリビュートであっても、それを自動で分割/再結合したりはしません。その場合は、冒頭(ATT_MTU–1)オクテットだけをやりとりします。
ロング・アトリビュートの読み書きに、オフセット値を指定できるRead Blogリクエスト、Prepare Write/Execute Writeリクエストがあります。上位層は、これらのリクエストを使って、ロング・アトリビュートを、(ATT_MTU-1)オクテット単位で複数回のトランザクションに分割して、扱います。
Exchange MTUリクエスト/レスポンス
アトリビュート・プロトコルのATT_MTUを変更するのが、Exchange MTU リクエスト/リスポンスです。このリクエストで、クライアントはサーバに、クライアントが扱えるATT_MTUを伝えます。サーバは、レスポンスで、サーバが扱えるATT_MTUを返します。このときのATT_MTUの値は、ATT_MTUのデフォルト値23以上の値です。
もしも、サーバにメモリが少ないマイクロコントローラが使われていると、ATT_MTUは大きく取れないかもしれません。サーバはその場合、ATT_MTUの最小値でもある、デフォルト値23を返すでしょう。
アトリビュートへのアクセス
サーバが公開しているアトリビュートには次の6つのアクセス方法があります。
- ファインド・リクエスト (Find request)
- リード・リクエスト (Read request)
- ライト・リクエスト (Write request)
- ライト・コマンド (Write command)
- インディケーション (Indication)
- ノーティフィケーション (Notification)
ファインド・リクエスト
ファインド・リクエストは、クライアントが、サーバのアトリビュートの集合から指定条件に一致するアトリビュート・ハンドルを取得するのに、使います。サーバのアトリビュートをすべて読み出そうとすると、通信に時間がかかります。条件を指定することで、必要なアトリビュートのハンドルのみを素早く取得できます。ファインド・リクエストは、Find InformationとFind By Type Valueの2つがあります:
- Find Information
- Find By Type Value
Find Informationでは、アトリビュート・ハンドルの範囲を指定して、アトリビュート・ハンドルとアトリビュート・タイプを読み出します。クライアントは、得られたアトリビュート・タイプの配列から、サーバのデータベースの構造を知ることができます。
クライアントがサーバに送るFind Information リクエストは、取得したいアトリビュート・ハンドルの開始値から終了値を指定します。サーバは、Find Informationレスポンスで、アトリビュート・ハンドルとアトリビュート・タイプの配列を返します。
例えば、クライアントがサーバのATTハンドルとATTタイプを全て読み出したい時は、ATTアトリビュートの範囲を0x0001から0xFFFFに設定したFind Informationリクエストを送ります。このとき、Find Informationレスポンスが、0x0001から0x0004までのアトリビュート・ハンドルを返してきたとします。まだ0x0005以降のアトリビュート・ハンドルがあるかもしれません。そこでクライアントは、アトリビュート・ハンドルの範囲を0x0005から0xFFFFに設定したFind Informationリクエストを送ります。クライアントは、これを繰り返して、すべてのアトリビュートを読み出します。該当するアトリビュートがなければ、サーバはクライアントに、エラー・コード Attribute not found のエラー・レスポンスを返します。
Find Informationレスポンスは、アトリビュート・タイプのUUIDが、16ビットか128ビットかを示すフラグと、アトリビュート・ハンドルとアトリビュート・タイプの組の配列を返します。1つのアトリビュート・ハンドルとアトリビュート・タイプの組は、アトリビュート・ハンドルは2オクテットなので、16ビットUUIDならば4オクテット、128ビットUUIDならば18オクテットを占めます。
Find Informationレスポンスは、16ビットと128ビットのアトリビュート・タイプを混在させることはできません。ハンドルとタイプの組の配列には、最大 (ATT_MTU -2) オクテットつかえます。ですから、 1つのFind Informationレスポンスで送れるハンドルとタイプの組は、ATT_MTUがデフォルト値23のとき、16ビットUUIDならば5つ ((23-2)/4 = 5.3)まで、128ビットUUIDならば1つ((23-2)/18=1.2)です。
Find By Type Valueは、使い方はFind Informationと同じで、アトリビュートのタイプおよびバリューが指定できる点が異なります。ただし、指定できるアトリビュート・タイプは16ビットのものだけで、アトリビュート・バリューの長さは(ATT_MTU -7)オクテットまでの制限があります。Find By Type Valueは、GATTのサービスおよびキャラクタリスティクスの素早い検索に役立ちます。
リード・リクエスト
クライアントがサーバのアトリビュートを読み出すリクエストは、6つあります。Readは1つのハンドルを指定する1つのアトリビュート・バリューの単純な読み込みを、Read Mutipleは複数のハンドルを指定しての読み込みを、Read Blobは長さが(ATT_MTU-1)を超えるアトリビュート・バリューの読み出しを行います。Read By TypeおよびRead By Group Typeは、アトリビュート・タイプを指定した読み出しです。
- Read
- Read Multiple
- Read Blob
- Read By Type
- Read By Group Type
クライアントが送信するアトリビュート・ハンドルを指定したReadリクエストに、サーバはReadレスポンスを返します。レスポンスのアトリビュート・バリューの長さは最大(ATT_MTU-1)、MTUがデフォルト値23のとき22オクテット、です。
Read Multipleリクエストは、複数のアトリビュート・ハンドルを指定して、1回のトランザクションで読み出します。サーバはアトリビュート・バリューを連結したものをレスポンスで返します。このアトリビュート・バリューの長さは最大で(ATT_MTU-1)オクテットです。もしもアトリビュート・バリューを連結したものが、この長さよりも長い場合は、先頭の(ATT_MTU-1)オクテットが返されます。またレスポンスには、それぞれのアトリビュート・バリューの境界を示さないので、Read Multipleリクエストはアトリビュート・バリューが固定長のものに限られます。ただし、最後の要素は可変長でもかまいません。
ReadリクエストおよびRead Multipleリクエストは、アトリビュート・バリューの長さが(ATT_MTU-1)オクテットよりも短いものを読み出せます。バリューが短いものをRead Multipleリクエストでまとめて読みだすことで、Readリクエストを使うよりも、リクエストの回数を小さくできます。
Read Blobリクエストは、(ATT_MTU-1)オクテットよりも長いアトリビュート・バリューの読み出しに使います。Readリクエストとの違いは、2オクテットのオフセット値を指定できることです。レスポンスは、オフセット位置から(ATT_MTU-1)オクテットまでのアトリビュート・バリューを返します。
Read By Type リクエストは、アトリビュート・ハンドルはわからないが、アトリビュート・タイプがわかっている場合の、読み出しに使います。動作は、Find By Type Valueリクエストでアトリビュート・ハンドルを取得してから、Readリクエストで読み出すことと同じです。
Read By Group Type リクエストは、Read By Typeリクエストとほぼ同じですが、グループ・タイプアトリビュートの一連のアトリビュートの末尾のアトリビュート・ハンドラを返す点が異なります。
上位層が提供する概念に、アトリビュートのグループ化があります。これは、例えばC言語の構造体のように、複数のアトリビュートを1つのグループにしてデータ構造をつくることです。このために上位層は、グループをあらわすアトリビュート・タイプ、グルーピング・タイプと呼びます、を定義しています。
Read By Group Type リクエストは、グルーピング・タイプの読み出しと、そのグループの範囲を読み出すために使われます。
ライト・リクエスト
クライアントがサーバにアトリビュート・バリューを書き込むリクエストは5つあります。Writeリクエストは、1つのハンドルを指定した単純な書き込みを、Prepare WriteとExecute Writeは、(ATT_MTU-1)オクテットよりも長いアトリビュート・バリューの書き込みをおこないます。
- Write
- Prepare Write
- Execute Write
- Write Command
- Signed Write Command
ライト・リクエストは、サーバの不揮発メモリに保存される設定情報など、サーバが確実に処理しなければならない書き込みに使います。ライト・リクエストが書き込めるアトリビュート・バリューの長さは最大(ATT_MTU–3)オクテット、ATT_MTUがデフォルト値23のとき20オクテット、です。
(ATT_MTU–3)オクテットよりも長いアトリビュート・バリューを書き込むときに、Prepareライト・リクエストとExecuteライト・リクエストを使います。
Prepareライト・リクエストで、クライアントはサーバに、オフセットとデータを送ります。この情報はサーバのキューに保持されます。Executeライト・コマンドで、クライアントがサーバに書き込みを支持すれば、キューにあるすべてのデータの書き込みが実行されます。Executeライト・コマンドを使って、クライアントはサーバのキューのクリア(書き込みのキャンセル)も指示できます。
ライト・コマンド(write command)は、リクエストではなくアトリビュート・プロトコルのコマンドです。読み込み処理は、クライアントが出した読み込みリクエストにサーバが値を返すので、必ずリクエストの形をとります。しかし書き込み処理は、サーバからリプライを返す必要はない場合があるので、コマンドが用意されています。
ライト・コマンドは、コントロール・ポイントへの書き込みに使われます。コントロール・ポイントは、サーバの装置等への動作指示を書き込むためのアトリビュートです。例えば、テレビのリモコンがクライアント、テレビ本体がサーバならば、リモコンのボタンを押してテレビに電源ONの指示を出す場合などに、ライト・コマンドが使われます。
Signeライト・コマンドは、シグネチャつきのライト・コマンドです。機器を動作させるような、重要な書き込みを、信頼できるクライアントのみに書き込みを許可したい場合に、使います。
インディケーションとノーティフィケーション
サーバからクライアントへの通知は、インディケーションまたはノーティフィケーションのいずれかを使います:
- Handle Value Indication
- Handle Value Notification
Handle Value Indicationはリクエスト/レスポンス、もHandle Value Notificationはコマンドである違いだけです。いずれも、アトリビュート・ハンドルと現在のアトリビュート・バリュー(長さは最大(ATT_MTU–3)オクテット)をクライアントに送ります。
ジェネリック・アトリビュート・プロファイル
ジェネリック・アトリビュート・プロファイル(Generic attribute profile, GATT)は、アトリビュート・プロトコルを使ったデータ交換の構造を与えます。その基礎構造は、サービスとキャラクタリスティクスという2つの要素で組み立てられます。
サービスは、機器の内部にある互いに独立した機能を表します。サービスというキャラクタリスティクスの集合です。キャラクタリスティクスは、外部センサー値や機器の内部状態および操作指示を読み書きするアトリビュートです。
GATTは、サービスとキャラクタリスティクスの発見、読み書き、そしてノーティフィケーションとインディケーションを提供します。
GATTは、サーバとクライアントの2つの役割を決めます。サーバは、アトリビュート・プロトコルのコマンドやリクエストを受けてレスポンスを返す役割です。クライアントは、アトリビュート・プロトコルのコマンドやリクエストを発行する役割です。このサーバとクライアントは、GATT層での役割です。リンク層のピコネットのマスターやスレーブなど、ATTTよりも下の層が決める役割とは、関係はありません。
サーバとクライアントの役割は物理的なデバイスに固定されるものではありません。ある機器がサーバになったりクライアントになることも、また同時にサーバかつクライアントになることも、利用場面次第であります。
サービスとキャラクタリスティクス
クラシックBluetoothでは、プロトコルは通信手順とデータ表現の仕様を、プロファイルは接続した機器の振る舞いの仕様を表します。Bluetoothのロゴがついていれば、製品やメーカを問わずに相互に接続できるのは、ヘッドフォンや着信通知といったアプリケーションごとに、機器の振る舞いまでを含めて仕様が決められて、規格認証の厳格な運用があるからです。
クラシックBluetoothには、オーディオのストリーミングや大容量のデータ・ファイル交換など、求められるネットワークの特性もデータ形式もまるで異なるアプリケーションがあります。そのために、プロトコルとプロファイルはアプリケーションごとに決められ、論理的通信チャンネルを提供するL2CAP層の上に作られます。
Bluetooth LEでは、すべてのアプリケーションはGATTの上に作られます。このGATTは、アトリビュート・プロトコルを使って、サービスとキャラクタリスティクスという仕組みを提供します。これがBluetooth LEで多種多様なアプリケーションが展開できる鍵になります。
GATTのサービスとは、アトリビュート・プロトコルのサーバが外部公開する、機能の単位です。例えば、ある機器がユーザに警告音を伝える機能、のように、機器の単1の機能を、サービス、という概念で扱います。サービスは、キャラクタリスティクスの集合です。キャラクタリスティクスとは、その機器の内部状態、操作指示、そして外部センサ値を読み書きするアトリビュートです。
GATTは、その機器の機能それぞれをサービスという単位で切り分けます。Bluetooth LEのサービスの概念は、ある機器の内部のハードウェアそれぞれの、互いに独立した機能の単位であり、けっして、ユーザやプロファイル(機器の使われ方)から見た個別機器の機能ではありません。例えばエアコンであれば、消費電力の計測、気温の検出、室温制御は、それぞれ個別に3つのサービスとして実装されるでしょう。ユーザ(プロファイル)からみると、これはエアコンという、1つのサービスにしそうです。しかし、Bluetooth LEのサービスは、その機器の内部にある互いに独立したハードウェアの機能、を指します。
このBluetooth LEのサービスが、機器の機能と、機器の使われ方を分離します。機器の使われ方、つまりプロファイルは、その機器のサービスの中から、必要なサービスを組み合わせて使います。
例えば、機器に音や振動でユーザにアラートを出す機能があるとします。この1つの機能が外部のクライアントにサービスとして公開されます。クライアントは、スマートフォンのアプリケーションなどでしょう。もしもそれが、スマートフォンの置き忘れ防止のアプリケーションならば、スマートフォンを置き忘れそうになったら、アプリケーションが機器にアラートを出させるでしょう。もしも、電話着信通知のアプリケーションであれば、電話着信を検出したら機器にアラートを出させるでしょう。サービスの利用方法は限定されていないので、アプリケーション側を作りサービスを組み合わせて、それまで考えられていなかった振る舞いでも、実現できます。
クラシックBluetoothと異なり、開発者が決めた任意のサービスおよびプロファイルを実装した機器を、Bluetoothの規格認証をうけてBluetoothロゴをつけて販売することができます。それは、Bluetooth LEの規格認証の範囲がGATT層までで、サービスやプロファイルはGATT層の上のアプリケーション層で作るからです。Bluetooth LEにも、クラシックBluetoothと同様に、メーカを超えた相互運用のために、Bluetooth SIGが承認したプロファイルおよびサービスの仕様があります。それらを実装するときは、それらの仕様に従います。
サービスとキャラクタリスティクスの例
懐中電灯を例にして、サービスとキャラクタリスティクスの使われ方を述べます。懐中電灯は、ライトのオンオフ状態などのデータを持っていますから、GATTでの役割はサーバになります。懐中電灯のサービスは、ライトの点灯状態の取得とそのオンオフ設定、そして明るさセンサーからの検出値の取得ができるものとします。
サーバ側のサービスとキャラクタリスティクス、そしてクライアントのプロファイルの設計するかは、Bluetooth SIGが定義しているものがあれば、それを使います。該当するものがない場合は、独自に設計します。該当するプロファイルがない場合でも、そのプロファイルに必要なサービスがBluetooth SIGで定義されていれば、その定義を利用すれば工程が少なくなる場合があります。
サービスに含まれるキャラクタリスティクスは次の3つのタイプに分類されます:
- 外部の値
- センサー値など、読み出すたびに値が変化するようなもの
- 機器内部の値
- デバイス内部の動作状態 (制御式の内部変数の値など)
- コントロールポイント
- 照明スイッチのOn/Offの操作など。
- このような操作を書き込むものは、readableではなく、writable/notifiableに設計する
このサービスには、ライトのスイッチ、ステータス、そして明るさ、の3つのキャラクタリスティクスがあります。それぞれのキャラクタリスティクスは、コントロール・ポイント、機器内部の値、そしてセンサー値を表します。
スイッチのキャラクタリスティクスは、外部からの操作を書き込むものですから、パーミッションは書き込みのみ読み出し不可に設定されているでしょう。ここにオン、オフに対応する値を書き込めば、サーバである懐中電灯がライトを制御します。オンオフを表す値をどうするかなどは、開発者が仕様を作り定義します。
ステータスのキャラクタリスティクスは、懐中電灯の制御プログラムの内部状態を表します。ライトの制御プログラムの動作は、状態遷移図で表現されます。スイッチの操作により、オンとオフの2状態を遷移します。このステータスは、スイッチのキャラクタリスティクスへの書き込み値で遷移するかもしれませんが、サーバの内部の変数の値ですから、このステータス自体が外部から書き込まれることは決してありません。ですから、パーミッションは読み出しのみに設定されます。
最後の明るさのキャラクタリスティクスは、実際のライトの明るさの検出値を表します。ライトの明るさは、ランプの劣化や乾電池の残量低下などで変化するでしょうから、実際の明るさを検出したくなるでしょう。検出値は読みだすだけで、書き込むものではありません。ですから、パーミッションは読み込みのみに設定されます。また、一定の時間間隔で、サーバからクライアントに通知(ノーティフィケーションまたはインディケーション)が必要かもしれません。GATTのキャラクタリスティクスには、クライアントに通知をする、しないを設定する機能があります。
ここまでの懐中電灯のサービスを定義したあとで、クライアントから乾電池の残量も知りたいと要求が出されたとします。このときに、懐中電灯のサービスにバッテリー残量を表すキャラクタリスティクスを追加する必要はありません。Bluetooth SIGには、バッテリー状態を公開するBattery Serviceが定義されていますから、このサービスを追加します。懐中電灯のサービスと、このバッテリー状態のサービスを組み合わせて使うことで、追加要求を満たすプロファイルが実現できます。
サービス
GATTのサービスは、データと関連付けられた機器の振る舞いや機能をあらわすものです。GATTのプロファイルはサービスの集合です <TBD サービスの構造/>。サービスの内容は、他のサービスへの参照とキャラクタリスティクスの集合です。サービスの定義は、サービスに必須のキャラクタリスティクスと、オプションのキャラクタリスティクスを定義します。
GATTのサービスとキャラクタリスティクスは、オブジェクト指向プログラミングのクラスとプロパティに例えられます。1つの独立した機能がクラスの定義です。アトリビュート・プロトコルのアトリビュートには、ちょうどプログラミングでいうメモリ・アドレスに相当する、ハンドルがあります。GATTは、サーバの複数のアトリビュートで、サービスの定義にしたがったサービスのインスタンスを公開しているようなものです。
サービスは、それぞれが独立した機能です。ですから異なる機器で、1つのサービスの定義を広く使えます。例えば、バッテリー状態を表すバッテリー・サービスが定義されています。このサービスは、電気車ならばその電池残量や容量、あるいは懐中電灯ならばその電池残量を表すでしょう。バッテリー・サービスはバッテリー・サービスとして振る舞うので、異なる機器でもプロファイルが求める機能が含まれていれば、利用ができます。サービスの使われ方、プロファイルは、クライアントの実装が決めます。
サービスは、他のサービスを参照して、そのサービスのキャラクタリスティクスを取り込むことができます。この参照されたサービスを included service と呼びます。他のサービスを取り込んだサービスは、included service自体の振る舞いを変更することは禁止されます。新しい値や振る舞いをキャラクタリスティクスとして追加することだけができます。included serviceの数や階層の深さに制約はありません。
このincluded serviceの仕組みは、サービスを継承して新しいサービスを作ること、後方互換性を保ちつつサービスを拡張することに使えます
例えば、バッテリー・サービスに、充電式電池に対応させるために電池の満充電容量の値を追加したいとします。この場合は、バッテリー・サービスを参照して、満充電容量の値のキャラクタリスティクスを追加した、新しいサービスBを定義できます。サービスBには対応していない更新されていないクライアントは、バッテリー・サービスを発見して、従来通りに動くでしょう。サービスBに対応した新しいクライアントは、拡張された満充電容量の値も読めるでしょう。
サービスには、プライマリ・サービスとセカンダリ・サービスの2タイプがあります。プライマリ・サービスは外部に公開されるサービスです。プライマリ・サービスは他のサービスのincluded serviceにもなれます。セカンダリ・サービスは外部に公開されず、他のサービスのincluded serviceとして使われるのみのサービスです。セカンダリ・サービスは、複数のサービスで定義を共有したいバリューをまとめるのに用いて、他のプライマリ・サービスから参照される使われ方をします。
アトリビュート・タイプ | アトリビュート・バリュー |
---|---|
0x2800, プライマリ・サービス | サービスのUUID(16もしくは128ビット) |
0x2801, セカンダリ・サービス | サービスのUUID(16もしくは128ビット) |
0x2802, Includedサービス | Included Service Attribute Handle |
End Group Handle | |
Service UUID (16ビットの場合のみ) |
アトリビュートをグループ化するサービスは、プライマリおよびセカンダリ・サービスの宣言から始まります。アトリビュート・ハンドルは任意の値が取れます。サービスの宣言は、バリューにそのサービスのUUIDを含みます。
そのサービスが他のサービスを参照している場合は、サービス宣言の次に、インクルード・ディフィニション(include definition)が続きます。インクルード・ディフィニションのバリューは、参照するサービス宣言のアトリビュート・ハンドル、それにそのサービス宣言の末尾を表すアトリビュート・ハンドルが続きます。もしも参照するサービスのUUIDが16ビットならば、そのUUIDが続きます。
キャラクタリスティクス
キャラクタリスティクスは、サーバの値や振る舞いの表現に使われます。キャラクタリスティクスの働きは、クライアントからサーバへの値の読み書きと、サーバからクライアントへの通知の2つです。キャラクタリスティクスの値とその読み書きの意図は、サーバで検出されたセンサなどの外部値、サーバの内部動作状態を表す値、そしてサーバへの動作指示、の3つに分類できます。
キャラクタリスティクスは、アトリビュート・ハンドルが連続する、アトリビュートの集合で表現されます。キャラクタリスティクスを構成するアトリビュートは、次の3つです:
- デクラレーション (Declaration)
- バリュー (Value)
- ディスクリプタ (Descriptor(s))
デスクリプションは、キャラクタリスティクスの読み書きなどの属性を制限します。バリューは、そのキャラクタリスティクスの値そのものを表します。ディスクリプタは、バリューの単位や表記を表します。
キャラクタリスティクス・デクラレーション
キャラクタリスティクス・デクラレーションは、アトリビュート・タイプ 0x2803 のアトリビュートで表します。アトリビュート・ハンドラは任意の値が取れます。アトリビュート・バリューは、キャラクタリスティクス・プロパティ、そのキャラクタリスティクスのバリューのアトリビュート・ハンドラ、およびキャラクタリスティクスのUUIDで構成されます。
アトリビュート・タイプ | アトリビュート・バリュー |
---|---|
0x2803 | Characteristic Properties |
Characteristic Value Attribute Handle | |
Characteristic UUID |
このプロパティは、キャラクタリスティクスのパーミションをビット・フィールドで表す1オクテットの値です。クライアントは、このプロパティから、キャラクタリスティクス・バリューに使える アトリビュート・プロトコルを知ることができます。
プロパティののBroadcastは、アトリビュート・プロパティにはないものです。もしもこのビットが1ならば、キャラクタリスティクス・デスクリプタに対応する値を書き込めば、キャラクタリスティクス・バリューがアドバタイズメント・データでブロードキャストされます。
プロパティ名 | 値 | 概要 |
---|---|---|
Broadcast | 0x01 | アドバタイズメントでのブロードキャスト |
Read | 0x02 | 読み出し可能 |
Write Without Response | 0x04 | レスポンスなしの書き込み |
Write | 0x08 | レスポンスありでの書き込み |
Notify | 0x10 | ノーティフィケーション |
Indicate | 0x20 | インディケーション |
Authenticated Signed Writes | 0x40 | シグネチャ付きの書き込み |
Extended Properties | 0x80 | プロパティの拡張定義 |
キャラクタリスティクス・バリュー・アトリビュート・ハンドルは、このキャラクタリスティクスのバリューを保持するアトリビュートのアトリビュート・ハンドラを示します。今のGATTの仕様では、キャラクタリスティクス・デクラレーションの次のアトリビュートが、キャラクタリスティクス・バリューになります。暗黙的なアトリビュートの並びに依存しないように、将来の実装が変更になっても対応できるように、このハンドラがあります。
キャラクタリスティクス・ディスクリプタ
キャラクタリスティクス・デスクリプタは、キャラクタリスティクス・バリューが文字列なのか数値なのかといった変数の型や単位等の情報の追加と、そのキャラクタリスティクス・バリューが変更された時にクライアントに通知する/しないといった振る舞いの指定に使います。
キャラクタリスティクス・バリューの値の説明や振る舞いは、サービスの仕様書に文章で記載されます。キャラクタリスティクス・デスクリプタは、そのサービスの仕様書にある内容をアトリビュートで表現します。キャラクタリスティクス・デスクリプタを読み出せば、もしもそのサービスの仕様を知らなくても、値の表示はできるはずです。
キャラクタリスティクス・デスクリプタは以下のとおりです:
- Characteristic Extended Properties
- Characteristic User Descriptor
- Client Characteristic Configuration
- Server Characteristic Configuration
- Characteristic Presentation Format
- Characteristic Aggregation Format
多くのデスクリプタがありますが、ほとんどはオプションです。
Characteristic Extended Properties
Characteristic Extended Properties は、キャラクタリスティクス・プロパティの追加定義を与えます。キャラクタリスティクス・デクラレーションのプロパティのExtended Propertiesが1の時に、現れます。このプロパティは、Reliable Write と Writable Auxiliaries の2つのフラグがあります。
Reliable Writeのビットが1ならば、キャラクタリスティクス・バリューの書き込みに、2段階の書き込み手順を使うことが許可されます。これは、 まずクライアントからサーバにアトリビュート・プロトコルのPrepare Write リクエスト/レスポンスでデータを送信します。次に、Execute write リクエスト/レスポンスで書き込みます。それぞれのリクエスト/レスポンスごとに、サーバはデータの正当性を確認して、エラーがあればそれをクライアントに通知できます。これにより、より信頼できるデータ書き込みができます。
Write Auxiliariesのビットが1ならば、Characteristic User デスクリプションのバリューへの書き込みが許可されます。
Characteristic User Descriptor
Characteristic User Descriptorは、キャラクタリスティクスを説明する人間に読める文字列です。Characteristic Extended Properties の Writable auxiliariesビットを1にして、ユーザに任意の文字列の書き込みを許可できます。
例えば、家の温度センサーなら、その温度がどの部屋のものかを表示したくなるでしょう。そのような場合に、キャラクタリスティクス・ユーザ・デスクリプタに部屋番号を記録しておけば、わかりやすくなります。
Client Characteristic Configuration
クライアント・キャラクタリスティクス・コンフィグレーションは、キャラクタリスティクスの振る舞いを設定するために、クライアントがサーバに書き込むものです。キャラクタリスティクスのプロパティの、notifiable もしくは indicatable が1ならば、必ずこのコンフィグレーションがあります。
クライアント・キャラクタリスティクス・コンフィグレーションは2ビットの値、1ビットがnotifications, もう1ビットがindications、を持ちます。クライアントがnotificationsに1を書き込めば、このキャラクタリスティクスのバリューが変更されたときに、サーバはクライアントにノーティフィケーションを送ります。indicationが1ならば、インディケーションを送ります。
クライアント・キャラクタリスティクス・コンフィグレーションは、クライアント固有の設定です。例えば、クライアントAとBの2つがサーバに接続している時、クライアントAがindicationを1にすれば、クライアントAにのみインディケーションが送信されます。またボンディングをしていないクライアントでは、接続時に全てのビットは初期値0に設定されます。
Server Characteristic Configuration
サーバ・キャラクタリスティクス・コンフィグレーションは、broadcastの1ビットの値だけを持ちます。このキャラクタリスティクスが含まれるサービスに関連した値が、アドバタイズメント・データでブロードキャストされます。どのようにブロードキャストされるかは、サービスの仕様が決めます。
ブロードキャストされるデータは、このサーバ・キャラクタリスティクス・コンフィグレーションを含むキャラクタリスティクス自体の値ではありません。このキャラクタリスティクスが含まれるサービスに関連するデータです。これは、値の意味や振る舞いを定義するのはサービスであって、キャラクタリスティクスそれ自体ではないからです。例えば、温度が20度、をブロードキャストしても意味がありません。例えば、室内が20度のように、ブロードキャストされたデータを説明するために、文脈が必要になります。
サーバ・キャラクタリスティクス・コンフィグレーションは、サーバ側の設定です。ですから、どのクライアントが設定しても、それはサーバの振る舞いを変更します。
Characteristic Presentation Format
キャラクタリスティクス・プレゼンテーション・フォーマットは、キャラクタリスティクスのバリューの変数型や表記フォーマットを表すのに使います。
サービスの仕様を知らない、キャラクタリスティクスを読み出すだけの汎用のクライアントでも、キャラクタリスティクス・プレゼンテーション・フォーマットを読み込むことで、その値がなにを意味するかを理解できなくても、人間が読める形でデータを表示できます。
このキャラクタリスティクスのフィールドは:
- Format
- Exponent
- Unit
- Namescape
- Description
で構成されます。
Formatは、変数の型を表します。次のような型があります:
- Boolean
- unsigned 2-bit / 4-bit
- unsigned/ signed 8 ~ 128 bit 整数
- IEEE-754 浮動小数点型
- 主に医療機器で使われる、2つの、固定サイズの固定小数点
- UTF-8 / UTF-16
Unitは単位を表す16ビットのUUIDです。この割当は、Bluetooth SIGのassigned numbersに列挙されています。