初めに
RFCOMMはどの様な場合に使うのが良いかを考えたときに、①ホストで働くRS232C用のアプリケーション・プログラムを持っているが、それをそのまま使いたい場合と②ホストがRFCOMMにしか対応していない場合であると思います。以下のようにRFCOMMをPICに実装するのは大変な作業です。上記2つの場合以外はBluetooth-HIDプロファイルを検討されるのが良いと、個人的には思っています。もちろん、ホストがBluetooth-HIDプロファイルに対応していないといけませんが。
RFCOMM接続概要
RFCOMM接続を実現するためには、大まかに3つの作業が必要になります。
1. 接続作業(制御用通信路の確保、接続認証、パラメタ交渉、データ用通信路の確保、ポート状態情報の交換、ポート交渉、データ受信可能情報の受信)
2. データの入出力作業
3. 切断作業
rfcomm5.zip(不安定ですので、実際にはrfcomm7_4.zipをご使用ください。)とRsTest.zipの組み合わせで得たログファイルrfcommlog.txtに基づいて1つづつ説明してゆきますが、まだ理解できていないところがあります。なお、RFCOMMはGSM TS 07.10の基づいて作られています。以下、***節と書いた時には、マニュアルGSM TS 07.10での節を表すものとします。ところで、以下使用する日本語の用語は私が勝手に訳したもので、普通使われているものとは異なっていると思います。
RFCOMMで用いる データ・パケットはL2CAP データ・パケットですが、そのL2CAPデータ列(RFCOMMフレームと言います)がさらに構造化されています。
RFCOMMフレーム(L2CAPデータ列)
=アドレス、コントロール、データ長、(クレジット)、インフォメーション、FCS
なお、フレームの種類は
①SABM(Set Asynchronous Balanced Mode:命令)
②UA(Unnumbered Acknowledgement:応答)
③DISC(Disconnect Command:命令)
④UIH(Unnumbered Information with Header check:命令/応答)
の4種類です。以下、PCから接続要求を出してPIC基板と接続することを前提としていますので、PCがホスト、PIC基板がスレーブとなります。
アドレス:
アドレスは1バイトです。その上位6ビットはDLCI(Data Link Connection identifier、すなわち制御通信路(チャンネル)の番号を表しています。下位2ビットは上位から順番にC/RビットとEAビットです。まずEA(Extend Address)ビットですが、これが1の場合、アドレスに関するデータがこのバイトで終わりであることを表しています。EAが0の場合には、次のバイトもアドレスに関するデータであるという意味になりますが、アドレスは必ず1バイトですから、常にEA=1となります。
次にC/R(command/response)ビットですが、これが複雑です。SABM、UA、DISCでは、命令を発信するものがホストの場合C/R=1で、この命令に対するスレーブからの応答もC/R=1とします。逆に、命令を発信するものがスレーブの場合C/R=0で、この命令に対するホストの応答もC/R=0とします。一方、UIHフレームの場合、ホストが発信元である場合C/R=1で、スレーブが発信元である場合C/R=0とします。命令か応答であるか関係ありません。面倒なので、アドレス値を以下の表に示します。チャンネルが0と2の場合しか書いてありませんが、それ以外のチャンネルに対するアドレスもすぐ求まると思います。
チャンネル | SABM、UA、DISC | UIH | アドレス |
命令の発信元*1) | 命令/応答の発信元*2) | ||
0 | PC(ホスト) | 0x03 | |
PIC(スレーブ) | 0x01 | ||
2 | PC(ホスト) | 0x0B | |
PIC(スレーブ) | 0x09 |
*1)アドレスは命令の発信元できまる。命令に対する応答は、命令のアドレスと同じものを用いる。
*2)アドレスは命令でも応答でもその発信元で決まる。
なお、表中のアドレス値はチャンネルを4倍して1(C/R=0、EA=1)を足すか3(C/R=1、EA=1)を足すかの値になっています。
コントロール:
コントロールは1バイトです。コントロールの上位から4ビット目は、P/F(Poll/Final)ビットと呼ばれています。SABM、UA、DISCフレームでは必ずP/F=1とします。P/F=0とするとフレーム自体が破棄されます。UIHフレームでは、P/F=1は「クレジットに基づくフロー制御」(credit based flow controle)でのクレジットを追加する場合で、P/F=0は追加しない場合です。前者の場合、RFCOMMフレームでの(クレジット)なる1バイトが余計に入ります。これも面倒なので以下のように表にしました。なお、「クレジットに基づくフロー制御」については後ほど説明します。
表2
フレームの種類 | コントロール |
SABM | 0x3F (P/F=1) |
UA | 0x73 (P/F=1) |
DISC | 0x53 (P/F=1) |
UIH | 0xEF (P/F=0) or 0xFF (P/F=1) |
データ長:
データ長は1バイトか2バイトでインフォーメーションの長さの情報を持ちます。最下位ビットはEAビットです。
インフォーメーション:
インフォーメーションは可変長でフレームが運ぶデータです。
(クレジット):
クレジット・バイトは有ったり無かったりしますので、括弧で括っています。クレジットを追加する場合必要となります。
FCS:
FCS(frame check sequence)は、送受信するRFCOMMフレームがきちんと転送されているかを(有る程度)チェックするための1バイトのデータです。FCSはFCS算出用プログラムで算出できます。SABM、UA、DISCフレームでは、アドレス、コントロール、データ長の3バイトから、またUIHフレームではアドレスとコントロールの2バイトから、ある数式にしたがって求めます。
制御用通信路(0番チャンネル)の確保
まず初めに、制御メッセージを送受信するための専用通信路、すなわちチャンネル0番を確保する必要があります。概念的には制御メッセージと単なるデータの通信路(チャンネル0番以外)を区別しようというものです。USBで、EP0と(EP1、EP2、・・・)などとを区別することに似ています。この時使用するRFCOMMフレームはSABM(Set Asynchronous balanced Mode)フレームと呼ばれます。
ログファイルの最初の部分は次の通りです。
RFCOMM_SABM03_READ
2B 20 08 00 04 00 45 00 03 3F 01 1C
2B 20 08 00 04 00 41 00 03 73 01 D7
これらは、L2CAP データ・パケットなので、RFCOMMフレームだけを取り出すと、
① 03 3F 01 1C
② 03 73 01 D7
となります。
① 制御用通信路の確保要求
03 3F 01 1C
これは、ホスト(PC)からスレーブ(PIC)へ送られて来たフレームです。
03 3F: 2バイト目は0x3Fですから、このフレームはSABMフレームであるこが分かります。さらに、1バイト目が0x03(チャンネル0番)ですから、これはPC(ホスト)からの命令で、チャンネル0番を開けよという命令です。
01: 上位7ビットだけがデータ長を表します。今の場合データ長は0となります。また、EA=1(最下位ビット)ですからデータ長の情報は、本バイトだけで終わりです。
1C: FCSです。
接続認証(初回)
接続認証はRFCOMMプロトコルに1部なので、避けようがないようです。さて、ホストとスレーブ間でHCIレーヤで接続(リンク)承認をおこないます。まず、初回の接続時の承認過程です。ホスト側でPINコード(パスキー)の入力が求められ、ホストはこれを記憶しておきます。スレーブは、ホスト側で入力したPINコードと同じコードをホストに返します。ホストは自分が記憶しているPINコードとスレーブから送られて来たPINコードが同じであれば接続を承認します。承認が済むとホストからリンクキー(ホストとスレーブの間だけで分かる16バイトの数値)がスレーブに送られてきます。次回の以降は、このリンクキーとホストのBluetoothアドレスをスレーブ側で記憶させておき、これらを使って自動で接続が行われます。HCIレーヤで接続承認が行われるので、ここでは、すべてのデータを省略せずに書き出します。
① HCI_CMD_WAIT_PIN_CODE: 16 06 0A 6F FE 33 24 00
② HCL: 0D 04 17 0A 6F FE 33 24 00 04 30 30 30 30 00 00 00 00 00 00 00 00 00 00 00 00
RFCOMM_PN_READ
③ 2B 20 0C 00 08 00 01 00 02 FC 04 00 01 00 42 00
④ HCI: 18 17 0A 6F FE 33 24 00 83 E1 CF 56 25 70 D7 E4 36 F8 00 1F D8 16 FF 93 00
① ホストからのPINコードの要求
16 06 0A 6F FE 33 24 00
16: HCIイベントでPIN Code Request Eventを意味します。
06: これ以降のデータの長さ、つまり6バイト
0A 6F FE 33 24 00: ホストのBluetoothアドレス。
② PINコード応答
0D 04 17 0A 6F FE 33 24 00 04 30 30 30 30 00 00 00 00 00 00 00 00 00 00 00 00
0D 04: HCI命令でPIN Code Request Reply Commandを意味します。
17: これ以降のデータの長さ、つまり23バイト
0A 6F FE 33 24 00: ホストのBluetoothアドレス。
04: PINコードの長さ=4;最大16です。
30 30 30 30: PINコードで、アスキー文字で"0000"
これ以降の0x00は意味がありません。
③はMicrosoftのBluetoothプロトコルスタックのバグで意味がありません。
④ ホストからのリンクキー通知
18 17 0A 6F FE 33 24 00 83 E1 CF 56 25 70 D7 E4 36 F8 00 1F D8 16 FF 93 00
18: HCIイベントでLink Key Notification Eventを意味します。
17: これ以降のデータの長さ、つまり23バイト
0A 6F FE 33 24 00: ホストのBluetoothアドレス。
83 E1 CF 56 25 70 D7 E4 36 F8 00 1F D8 16 FF 93: 16バイト長のリンクキー
00: Key_Typeですが通常のペアリングであることを意味しています。
なお、リンクキーは、PINコード、Bluetoothアドレス、発生させた乱数から自動的に作られます。
接続認証(2回目以降)
2回目以降の承認過程です。ホストからのリンクキー要求が来て、これに適切に応答すると自動接続が可能となります。
① HCI_CMD_WAIT_PIN_CODE: 17 06 0A 6F FE 33 24 00
② HCL: 0B 04 16 0A 6F FE 33 24 00 83 E1 CF 56 25 70 D7 E4 36 F8 00 1F D8 16 FF 93 00
① ホストからのリンクキー要求
17 06 0A 6F FE 33 24 00
16: HCIイベントLink Key Request Eventを意味します。ホストからリンクキーが要求されます。
06: これ以降のデータの長さ、つまり6バイト
0A 6F FE 33 24 00: ホストのBluetoothアドレス。
② リンクキー応答
0B 04 16 0A 6F FE 33 24 00 83 E1 CF 56 25 70 D7 E4 36 F8 00 1F D8 16 FF 93
0B 04: HCI命令でLink Key Request Reply Commandを意味します。
16: これ以降のデータの長さ、つまり22バイト
0A 6F FE 33 24 00: ホストのBluetoothアドレス。
83 E1 CF 56 25 70 D7 E4 36 F8 00 1F D8 16 FF 93: 16バイト長のリンクキー
マルチプレクサ制御命令(Multiplexer Control Command)
パラメタ交渉の説明の前に、マルチプレクサ(多重化装置)制御命令について記述します。1つの伝送路にデータ用通信路(データ用チャンネル)を多数作ろうという話だと思いますが、きちんとは理解していません。マルチプレクサ制御命令はチャンネル0番(制御用通信路)を行き来するUIHフレームです。RFCOMMフレームのインフォメーションがさらに次のように構造化されています。
インフォメーション=タイプ(型)、メッセージ長、メッセージ
タイプとUIHデータ長はそれぞれ1バイトです。UIHフレーム(マルチプレクサ制御命令)全体では、その構成が
L2CAPデータ列(フレーム)
=アドレス、コントロール、データ長、(クレジット)、タイプ(型)、メッセージ長、メッセージ、FCS
となります。
アドレス:
関係するチャンネルは0番です。
タイプ(型):
タイプは1バイトで、その上位6ビットでタイプが決まります。下位2ビットは、上位からC/RとEAです。EAは常に1です。ここでのC/Rも今までのものと意味が違います。命令の場合C/R=1で、応答の場合C/R=0です。命令や応答の発信元には依りません。これまでC/Rの定義が3つ出てきましたので混乱しそうです。混乱するといけないので、以下のように表にまとめました。
表3
タイプ | 命令 | 応答 |
PN | 0x83 | 0x81 |
MSC | 0xE3 | 0xE1 |
RPN | 0x93 | 0x91 |
PN(Prameter Negotiation Command)、MSC(Modem Status Command)、RPN(Remote Port Negotiation Command)
パラメタ交渉
パラメタ交渉にはPN(Prameter Negotiation Command)型のマルチプレクサ制御命令が使用されます。データ用通信路(チャンネル0番とは異なるチャンネル)を確保するために、事前に必要なパラメタ(parameter)に関する交渉(negotiation)をホスト・スレーブ間でチャンネル0番を通して行います。これ以下、「L2CAPレーヤにおける切断」なる箇所まで、RFCOMMフレームだけを取り出しての説明になります。
RFCOMM_PN_READ1
① 03 EF 15 83 11 02 F0 07 00 F3 03 00 07 70
② 01 EF 15 81 11 02 E0 07 00 F3 03 00 07 AA
① パラメタ交渉(0番チャンネルを使ったUIHフレームによるホストからのパラメタ設定要求)
03 EF 15 83 11 02 F0 07 00 F3 03 00 07 70
03 EF: チャンネル0番で、ホストから送られてきたUIHフレーム
15: データ長が10バイト
83: PN命令(表3)
11: メッセージ長が8バイト
02: 上位3バイトは0で固定。下位5バイトはDLCI(チャンネル番号)で、今の場合2です。チャンネル番号2を開ける準備のパラメタ交渉になります。
F0: データ用チャンネルが開く前には、「クレジットに基づくフロー制御」をする場合上位4ビットは0xfとします。なお、下位4ビットは0x0で固定です。今の場合、「クレジットに基づくフロー制御」をすることになります。
07: プライオリティ(優先度)で、0から63までの値をとれますが、値が大きいほどチャンネル優先度が高くなります。
00: 常に0とします。
F3 03: 最大フレーム長を指定します。
00: 常に0とします。
07: 上位5ビットは0で固定。下位3ビットには、「クレジットに基づくフロー制御」をする場合にはクレジットの値(今の場合は7クレジット)を、それ以外の場合は0を入れる。
70: FCS
データ用通信路の確保
RFCOMM_SABM0b_READ
① 0B 3F 01 59
② 0B 73 01 92
② ①に対する承認応答(2番チャンネルの確保要求に対する承認応答)
0B 73 01 D7
03: ①に対する応答ですから同じアドレスにします。
73: UAフレームで承認応答がなされます。(表2)
01: データ長は0
92: FCS
ポート状態の通知(その1)
ポート状態の通知にはMSC(Modem Status Command)が使用されます。この命令はいつホスト・スレーブ間で行き来するのかが分かりませんので(例えば、PCがデータを受け取る準備ができた旨をPICに伝えるために、MSCを発信したとします。しかし、いつ準備ができるかはPC次第です。)、ホストでもスレーブでも
ログでは
RFCOMM_MSC_READ1
① 03 EF 0B E3 07 0B 8C 01 70
② 01 EF 09 E3 05 0B 8D AA
RFCOMM_MSC_READ2
③ 03 EF 09 E1 05 0B 8D 70
④ 09 FF 01 7F 9C
⑤ 01 EF 09 E1 05 0B 8D AA
RFCOMM_MSC_READ3
⑥ 03 EF 0B E3 07 0B 8D 00 70
⑦ 01 EF 09 E1 05 0B 8D AA
となっていますが、ホスト(PC)からの命令とスレーブ(PC)への命令が錯綜しているので分かり易いように並べ変えると
① 03 EF 0B E3 07 0B 8C 01 70
⑤ 01 EF 09 E1 05 0B 8D AA
② 01 EF 09 E3 05 0B 8D AA
③ 03 EF 09 E1 05 0B 8D 70
⑥ 03 EF 0B E3 07 0B 8D 00 70
⑦ 01 EF 09 E1 05 0B 8D AA
となります。ただ、上の様な順番で通信をしないとRFCOMMでの接続はできません。なお、④は不必要なことが分かりました。
1バイト目は0x03か0x01です。前者がホストからスレーブへ、後者がスレーブからホストへ、チャンネル0番を通して送られるデータを意味します。2バイト目はすべて0xEFですので、これらのフレームはUIHフレームです。しかもチャンネル0番を通ってきますので、マルチプレクサ制御命令になります。3イト目はフレーム長です。また、4バイト目は0xE1か0xE3ですので、フレームタイプがMSC(Modem Status Command)であることも分かります。なお、0xE1と0xE3の違いは、前者が応答で、後者が命令という違いです(表3)。5バイト目はメッセージ長です。6バイト目はすべて0x0Bです。これは、「チャンネル2に関する情報」(7バイト目以降のデータ)を伝えるという意味です。
ところで、第1バイトと第4バイト目に着目すると。①はホストからスレーブへ来る命令で、⑤はそれに対するホストへの応答、②はスレーブからホストへの命令で、③はそれに対するホストからの応答で、⑥はホストからスレーブへ来る命令で、⑦はそれに対するホストへの応答に相当します。
以下、7バイト目以降のデータだけを取り出して説明します。
① ホストの着信ポート(?)の準備完了通知
8C 01 70
8C: 2進で書くと、1000 1100 です。ここでは、この1バイトのデータの最上位ビットから1、5、6、8ビット目だけを説明します。その他のビットは0であると仮定します(詳しくは5.4.6.3.7節)。1ビット目はデータが正しいものでであることを示すので、1となっています。5ビット目はRTR(Ready To Receive)で、6ビット目はRTC(Ready To Communicate)で、このフレームを送って来る方の機器がデータを受け取る準備と機器の準備ができたことを、それぞれ知らせています。8ビット目(最下位ビット)はEAで、これが0ですから以降にまだ続くデータがあることを示します。
01: マニュアルに依れば、最下位ビットがEA=1ですから、これ以降にデータはないことを示すことになります。以下、憶測で、全く理解していません。このバイトはどうもMicrosoft社が別途定義したものであるように思えます。つまり、同社のBluetoothプロトコルスタックでは、仮想COMポートとして発信と着信の2つのポートを利用しています。この2つのポートを区別するために、このバイトが使われているように思われます。そのうちの着信ポートを、ここでのバイト0x01に対応していると推測します。
70: FCS
⑤ ①に対する応答
8D AA
8D: マニュアルに依れば、MSCの応答は、通知と同じデータを送り返せば良いのですが、ここではそうはなっていません。①での0x01に対するものがありません。また、このバイト0x8Dは①での0x8Cに対する応答で、最後のビットEAが1になっており、以後のデータは無いことになっています。①での0x01が無視されているようです。これでもきちんと応答はできていますので、やはり、①での0x01はMicrosoft社が別途定義したものと考えるのがよさそうです。
AA: FCS
② スレーブからホストへの通知
8D AA
⑤と同じ意味です。ただ、スレーブからホストへの通知です。
⑥ ホストの発信ポート(?)の準備完了
8D 00 70
8D: これは⑤と同じ意味です。マニュアルに依れば、0x8Dの最下位ビットはEA=1を意味しますので、これ以降データは無いはずですが、0x00が存在します。①では、これに対応するものが0x01でしたので、やはり2つのCOMポートのうち①でのものとは違うポート(すなわち発信ポート)において、データを受け取る準備とデータをやり取りする準備ができたこと知らせてくる通達と考えるのが自然だと思いますが、これも規格外なのではっきりしたことは分かりません。
00: 発信ポートと推測されます。
AA: FCS
⑦ ⑥への応答
8D AA
⑤と全く同じ意味です。
ポート交渉
RFCOMM_RPN_READ1
① 03 EF 15 93 11 0B 03 00 00 00 00 01 00 70
② 01 EF 15 91 11 0B 03 00 00 00 00 01 00 AA
RFCOMM_RPN_READ2
③ 03 EF 15 93 11 0B 03 00 00 00 00 01 00 70
④ 01 EF 15 91 11 0B 03 00 00 00 00 01 00 AA
RsTest.exeにおいて、RS232Cの初期化を行っていますが、その情報がポート交渉でホストから送られてくるポート交渉のパラメタとして反映されています。上記の4つのRFCOMMフレームを見ると、全く同じ2組(①、②組と③、④組)のポート交渉が行われています。これも推測ですが、Microsoft社のBluetoothプロトコルスタックでは、仮想COMポートとして発信と着信の2つのポートを利用しているために、このような2組のポート交渉が行われるものと思われます。以下、①と②だけについて書きますが、どうも理解を超えており間違った説明となるかも知れません。なお、パラメタの詳しい説明は5.4.6.3.9節を参照ください。
① ポート交渉(着信/発信ポートのため?)
② ①への応答
01 EF 15 91 11 0B 03 00 00 00 00 01 00 AA
03 EF: 表1、2からスレーブ発信のUIHフレームでチャンネル0番を使っています。したがってマルチプレクサ制御命令です。
15: データ長
91: 表3からRPN(Remote Port Negotiation Command)命令に対する応答であることが分かります。
11 0B 03 00 00 00 00: ①と同じ
01: ボーレートだけ承認。
00: フロー制御は承認できない。
AA: FCS
ポート状態情報の通知(その2)
RFCOMM_MSC_READ4
① 03 EF 0B E3 07 0B 09 00 70
② 01 EF 09 E1 05 0B 09 AA
① ホストの発信ポート(?)の準備完了通知
09 00 70
09: 2進で書くと、0000 1001 です。ここでは、この1バイトのデータの最上位ビットから1、5、6、8ビット目だけを説明します。その他のビットは0であると仮定します(詳しくは5.4.6.3.7節)。1ビット目はデータが正しいものでであることを示すので、必ず1となっているはずなのですが、0です。理由が分かりません。5ビット目はRTR(Ready To Receive)で、6ビット目はRTC(Ready To Communicate)で、このフレームを送って来る方の機器がデータを受け取る準備とデータをやり取りする準備ができたことを、それぞれ知らせています。8ビット目(最下位ビット)はEAで、これが0ですから以降にまだ続くデータがあることを示します。
00: 発信ポートを表しているように思えます。
70: FCS
⑤ ①に対する応答
0B 09 AA
09: MSCの応答としてマニュアル通り、通知と同じデータを送り返しています。
AA: FCS
データの入出力
以上の作業で、やっとPCとPIC基板の間でデータの入出力が可能となります。
RFCOMM_DATA
① 0B FF 07 19 31 32 33 86
② 09 FF 01 1A 5C
③ 09 EF 07 32 32 33 40
① データの受信
0B FF 07 19 31 32 33 86
0B FF: チャンネル2番(データ用チャンネル)を通って来たホストからのUIHフレームであることが分かります。また0xFFはP/F=1でクレジットがあります。
07: データ長 3バイト (0x07の最後のビットはEA=1を意味します)
19: クレジット0x19を追加します。
31 32 33: 3バイトのデータで、アスキー文字で"123"です。
86: FCS
② クレジットの送信
09 FF 01 1A 5C
09 FF: チャンネル2番(データ用チャンネル)を通してホストに送るUIHフレームであることが分かります。また0xFFはP/F=1でクレジットがあります。
01: データ長 0バイト
1A: クレジット0x1Aを追加します。
5C: FCS
③ データの送信
09 EF 07 32 32 33 40
09 EF: チャンネル2番(データ用チャンネル)を通してホストに送るUIHフレームであることが分かります。また0xEFはP/F=0でクレジットがありません。
07: データ長 3バイト
32 32 33: 3バイトのデータで、アスキー文字で"223"です。
40: FCS
切断
切断作業は3段階になります。
1.RFCOMMレーヤにおける切断
RFCOMM_DATA
① 0B 53 01 B8
② 0B 73 01 92
③ 01 53 01 9C
RRFCOMM_END1_RESP
④ 03 53 01 FD
⑤ 03 73 01 D7
RRFCOMM_END3_RESP
⑥ 01 73 01 B6
① チャンネル2の切断命令
0B 53 01 B8
0B: 表1からチャンネル2を通してホストから来た命令であることが分かります。
53: 表2からDISCフレームで、(チャンネル2の)切断命令です。
01: データ長=0
70: FCS
② 切断承認応答
0B 73 01 92
0B: チャンネル2を通してホストから来た命令に対する応答なので①と同じアドレスを用います。表1を参照。
73: 表2からUACフレームで、切断承認応答になります。
01: データ長=0
92: FCS
③はスレーブから発信したチャンネル0番に対する切断命令で、⑥がそれへの応答(アドレスが同じで0x01)です。一方、④はホストから発信したチャンネル0番に対する切断命令で、⑤がそれへの応答(アドレスが同じで0x03)です。
2.L2CAPレーヤにおける切断
L2CAP_END1
① 2B 20 0C 00 08 00 01 00 06 FD 04 00 45 00 41 00
② 2B 20 0C 00 08 00 01 00 06 FD 04 00 41 00 45 00
③ 2B 20 0C 00 08 00 01 00 07 FD 04 00 45 00 41 00
L2CAP_END_REQ_RESP
④ 2B 20 0C 00 08 00 01 00 07 FD 04 00 41 00 45 00
上記のL2CAP データ・パケットの7、8バイト目を見ると0x0001となり、制御用チャンネルを使用していることが分かります。また9バイト目は0x06か0x07ですが、それぞれ切断(disconnection)要求とそれに対する応答を表しています。それぞれのパケットの最後の4バイトは、ソースとディスティネーションのチャンネル番号であることを考慮に入れれば、①はホストからの切断命令で④がそれに対する応答、また、②はスレーブからの切断命令で③がそれに対する応答であることが分かります。
3.HCIレーヤにおける切断HCI_CMD_DISCONECT:06 04 03 2B 00 00
06 04: Disconnect CommandでHCIレーヤにおける切断命令
03: データ長 3バイト
2B 00: 接続ハンドル
00: 理由で、0x00はエラーでないことを意味します。
クレジットに基づくフロー制御
スレーブが受け取ることができるRFCOMMフレームの数(スレーブのメモリ容量による)をホストに知らせるために、スレーブがホストにクレジットと呼ばれる1バイトの数値を送ります。ホストはスレーブにRFCOMMフレームを1フレーム送るごとに、このクレジットを1つづつ小さくして行き、クレジットが0になると、ホストはRFCOMMフレームの送信を止めます。スレーブが新たにクレジットを送ってくると、この送信は再開されます。クレジットは銀行預金の預金のようなもので貯められます(クレジットは常に加算される)。預金の引き出しは、RFCOMMフレームの送信時に執行されます。