HCIプロトコル

  Bluetooth USB ドングル(一般的にコントローラと呼ばれます)をPICやPC(一般にホストと呼ばれます)で制御するため、この間を取り持つ方法(一般的にインターフェースと呼ばれます)に関する規約(プロトコル)が、HCI(Host Controller Interface)プロトコルです。 HCIプロトコルを用いて行うことは、ドングルを初期化することと、通信相手のbluetooth機器と接続し、結果的にHCI ACL データ・パケットを送受信できるようにすることです。

以下、コントローラ(bluetooth USB ドングル)を簡単にドングルと呼び、ホストはドングル・ホストと呼ぶことにします。

以下の図をご覧ください。ドングル・ホストはドングルに対して、HCI命令・パケットの送信や、HCI ACL データ・パケットの送受信を行います。そして、ドングル・ホストはその応答をHCIイベント・パケットとしてドングルから受け取ります。

1.HCI命令・パケットは、ドングル・ホストからドングルへ、エンドポイント0x00を通して送るのですが、クラス・リクエストとして送らなければいけません。
2.HCIイベント・パケットは、ドングルからドングル・ホストへエンドポイント0x81を通して、インターラプト転送で送られます。
3.HCI ACL データ・パケットは、ドングル・ホストからドングルへエンドポイント0x02を通して、また、ドングルからドングル・ホストへはエンドポイント0x82を通して、バルク転送で送られます。

ところで、 HCIプロトコルでは複数バイトの整数を表すときにリトルエンディアン(little endian)方式を用います。複数バイトの整数を1バイトづつに分けるのですが、最下位バイトから最上位バイトへと並べて行く方式です。例えば、0x1234(0xは16進数表現であることを示します)の最上位バイトは0x12で、最下位バイトは0x34です。リトルエンディアン方式では、0x34  0x12と並べることになります。

以下、マニュアルと書いたときには、bluetoothのマニュアル Core v2.1 + EDR.pdf のVolume2のPartE(HOST CONTROLLER INTERFACE FUNCTIONAL SPECIFICATION)を意味します。


HCI命令パケット(HCI Command Packet)

パケットはデータの塊のことを意味しており、HCI命令パケットは、
      OpCode(オペコード)、パラメタ数、パラメタ列
の形式をとります。

①  オペコード(2バイト幅)
HCI命令は、次のように大くくりでOpCode Group(オペコード・グループ)で分類されています。
        Link Control commands: 0x01
        Link Policy Commands: 0x02
        HCI Control and Baseband Commands: 0x03
        Informational Parameters Commands: 0x04
        Status and baseband: 0x05
        Testing Commands: 0x06
そして、これらそれぞれの分類の中で、HCI命令がOpCode Command(オペコード命令:0x01からの数値で区別される)によって整理されています。上に書いてあるように、オペコードは16ビット(2バイト)幅です。最上位から6ビットがOpCode Group Filed (OGF:オペコード・グループが入る場所)で、残り10ビットがOpCode Command Filed (OCF:オペコード命令が入る場所)です。

たとえばRead BD_ADDR Commandの場合、オペコード・グループが0x04でオペコード命令が0x09なので、これらをならべて、2進数で書くと
        000100   0000001001
となります。これを16進数で表すと、0x1009となります。ただし、2バイト整数は、リトルエンディアン方式を使うので、0x09  0x10  という順番で並べたものがオペコードとなります。

なお、普通使うオペコード命令は0xFFより小さいので、オペコード命令の後にオペコード・グループを4倍した(2回左シフトした)値を並べたものがオペコードとなります。上の例では、オペコード命令0x09の後に、オペコード・グループを4倍した0x04×4=0x10を並べたものがオペコードとなります。逆に、オペコードが0x09  0x10となって場合には、オペコード命令は0x09で、オペコード・グループは0x10を4で割って(2回右シフトして)、0x04であると判断できます。

②  パラメタ数(1バイト幅)
この数の後に続くパラメタのバイト数です。パラメタがない場合には00とします。これを忘れないことが重要です。結局、HCI命令は、かならず3バイト以上で構成されます。

③  パラメタ(バイト幅は変化する)
それぞれのオペコードによって変わりますので、マニュアルをご覧ください。

○  HCI命令パケットの例
例として、ファームウェアの最初の部分を見てみます。
        case HCI_CMD_RESET:
                buf1[0]=0x03;
                buf1[1]=0x0c;
                buf1[2]=0;
                data_size=3;
                DemoState = BT_STATE_WRITE_CLASS;  (クラスリクエスト)
                HciState = HCI_CMD_RESET_END;
                break;

  ここでは、PICから16進数表記で03 0c 00 というHCI命令パケットをクラスリクエストとしてドングルに送っています。

03 0c: オペコード命令が0x03でオペコード・グループが0x03(0x0cを4で割る)であることから、マニュアルからReset Commandであると分かります。ドングルをリセットする命令です。
00:この数値に続くパラメタがゼロであることを示しています。上に書いたように、これは必須ですので省略してはいけません。


HCIイベント・パケット(HCI Event Packet)

HCIイベント・パケット
      EventCode(イベントコード)、パラメタ数、パラメタ列
の形式をとります。

①  イベントコード(1バイト幅)
イベントの種類を表す数値です。マニュアルの7.7節を参照ください。

②  パラメタ数(1バイト幅)
この数の後に続くパラメタのバイト数です。

③  パラメタ(バイト幅は変化する)
それぞれのイベントコードによって変わりますので、マニュアルをご覧ください。

○  HCIイベント・パケットの例
HCIイベントパケットの例として、接続完了イベント・パケットを取り上げます。 例えば、16進数列で

          03 0B 00 2A 00 B7 7A 95 CE 4E E8 01 00
となります。

03:Connection Complete Eventを表します。
0B:この数値以下に続くパラメタのバイト数です。
00: ステータスで、00は正常に接続ができたことを示しています。
2A 00: Connection Handle(接続ハンドル)と呼ばれるもので、bluetooth機器の間で通信する場合、この数値を用いて通信をします。
B7 7A 95 CE 4E E8:接続相手の機器(例えばPC)のbluethooth(ドングル)に付けられた一意的な番号、すなわちBluetooth Device Addressを表しています。
01:リンクの型で、01は以下に記述するACLを示しています。
00:リンクレベルでの暗号化に関する情報だと思いますが、理解していません。00は、暗号化していないという意味だと思います。

ここで大事なのはConnection Handle(接続ハンドル)の値です。接続ハンドルは、HCI ACL データ・パケットを2つのbluetooth機器の間でやりとりする場合、いつも必要になります。なお、2A 00はリトルエンディアンですので、0x002Aなる数値を表していまが、最上位4ビットは意味がありません。つまり0x02A(12ビット)が接続ハンドルの値となります。


HCI ACL データ・パケット(HCI ACL Data Packets)

bluetooth機器の間で、接続が可能となると、両機器の間でHCI ACL データ・パケットが交換可能になります(HCI SCO Data Packetsというものもありますが、ここでは説明しません)。ACLはAsynchronous Connection-Lessの略です。データ送信に際して、非同期(Asynchronous)で、かつ接続関係を確立しない(Connection-Less)ということです。非同期型通信とは、定期的でないという意味で、クロック信号のタイミングに合わせず、任意のタイミングでデータを送信する通信です。また、コネクションレス型通信とは、通信相手がデータを受け取れるかどうか確認しないで、勝手にデータを送信する通信のことを意味します。

HCI ACL データ・パケットは、
      (Connection Handle+PB Flag+BC Flag)、ACLデータ長、ACLデータ列
の形式を持ちます。

例えば16進数列で    2A 20 0C 00 08 00 01 00 02 01 04 00 01 00 40 00    の様です。

①  Connection Handle+PB Flag+BC Flag(2バイト幅)
2バイトの中で、最上位から2ビットがBroadcast_Flag、次の2ビットがPacket_Boundary_Flag、そして残り12ビットが接続ハンドルです。

Broadcast_Flag:いくつものbluetooth機器にむけてデータを送る場合、ブロードキャスト送信といいますが、ここでは相手にするbluetooth機器は1つとしていますので、2進数で00とします。

Packet_Boundary_Flag:送信データが短い場合、1つのパケットで送ることができます。しかし、送信データが長い場合、パケットの長さ制限から、いくつかのパケットに分けて送る必要があります。どちらの場合でも、最初に送るパケットでは、Packet_Boundary_Flagを2進数で10とします。パケットが分割されていて、最初に送ったパケットの続きのパケット(2番目以降のパケット)である場合、Packet_Boundary_Flagを2進数で01とします。

ここで、BC Flag=00の場合で、接続ハンドルが0x02Aで、最初に送るパケットの場合、(Connection Handle+PB Flag+BC Flag)を2進数で書くと
        00  10  000000101010
となります。これを16進数で表すと、0x202Aとなります。実際にパケットとして送り出す場合は、リトルエンディアンとして0x2Aの後に0x20が並ぶことになります。また、1つのデータを幾つかのパケットに分けて送る場合で、2番目以降のパケット場合には、0x2Aの後に0x10が並ぶことになります。BC Flag=00の場合、以上のことを図示すると次のようになります。

②  ACLデータ長(2バイト幅)
データの長さを表すバイト数です。リトルエンディアンなので注意しましょう。
例えば、この値が上の例のように  0C 00  となっていたの場合、実際のデータ長さは0x000C  (12バイト)です。逆に実際のデータ長さが0x000Cである場合、パケット上では  0C 00  の順番となります。

③  ACLデータ列  (バイト幅は変化する)
送信するデータ(08 00 01 00 02 01 04 00 01 00 40 00)を、ここに列挙します。


戻る