Palm Programmer's Laboratory
Palm OS Programmer's Companion Volume II/6-2
6-2 Bluetooth 利用可能なアプリケーションの開発
Palm OS は複数のインターフェイスを通して Bluetooth を公開するので、手元のタスクに適したインターフェイスを選択することができます。Bluetooth 開発は、仮想シリアルドライバを使ったシリアルマネージャを通してサポートされます。それについては「Bluetooth Exchange ライブラリサポート?」で述べています。オブジェクト転送は Bluetooth 交換ライブラリを使って Exchange マネージャーを通してサポートされます。それについては「Bluetooth 仮想シリアルドライバ?」で述べています。最後に、BluetoothライブラリAPIで直接プログラムすることができます。これがこのセクションの主題です。
どのアプローチを取るにせよ、Bluetooth API を使用する前にハンドヘルドで Bluetooth システムが動いているかどうかを確認すべきです。そのためには、以下のコードを使用します。
UInt32 btVersion; // Make sure Bluetooth components are installed // This check also ensures Palm OS 4.0 or greater if (FtrGet(btLibFeatureCreator, btLibFeatureVersion, &btVersion) != errNone) { // Alert the user if it's the active application if ((launchFlags & sysAppLaunchFlagNewGlobals) && (launchFlags & sysAppLaunchFlagUIApp)) FrmAlert (MissingBtComponentsAlert); return sysErrRomIncompatible; }
Bluetooth サポートが利用可能であることをアプリケーションが一度決定したなら、Bluetoothライブラリをロードする必要があります。これは以下のようなコードで実行することができます。
UInt16 btLibRefNum; Err error = errNone; if (SysLibFind(btLibName, &btLibRefNum)) { error = SysLibLoad(sysFileTLibrary, sysFileCBtLib, &btLibRefNum); }
そしてアプリケーションは Bluetooth ライブラリを開いて利用する用意ができます。ライブラリを参照するために、btLibRefNum 値を使います。
Bluetooth ライブラリの概要
プログラマの見通しから、Bluetoothライブラリの関数は 4 つの領域になります。マネージメント・ソケット・セキュリティ・ユーティリティです。
- マネージメント関数は、Bluetooth 仕様における無線とベースバンドの部分を扱います。近くにあるデバイスの発見やACLリンクの確立で使用します。
- ソケット関数は、L2CAP・RFCOMM・SDPとの通信を可能にします。
- セキュリティ関数は、信頼されたデバイス(ハンドヘルドと安全な接続を生成するときに証明を必要としないデバイス)を管理します。
- ユーティリティ関数は、有用なデータ変換を行ないます。
マネージメント
Bluetoothアプリケーションに共通する 3 つの基本的なマネージメントタスクは、範囲内の Bluetooth デバイスの検索、ACL リンクの確立、Piconet での活動、です。しかし、これらの操作を行なう関数をコード内で使用するためには、マネージメントコールバック関数を生成する必要があります。
マネージメントコールバック関数
多くのマネージメントコールは非同期です。言い換えると、それらは操作を開始し、操作が実際に完了する前に戻ります。操作が完了したときに、Bluetooth ライブラリはコールバック関数によってアプリケーションに通知します。そのような通知はマネージメントイベントと呼ばれます。
マネージメント関数は非同期操作の開始前に失敗する場合があります。この場合、コールバック関数はコールされません。マネージメント関数のリターンコードを見ることで、コールバック関数がコールされるのかどうかを知ることができます。
btLibErrNoError
操作は完了しました。コールバック関数はコールされないでしょう。
btLibErrPending
操作は開始されました。コールバック関数がコールされるでしょう。
any other error code
操作は失敗しました。コールバック関数はコールされないでしょう。
マネージメントコールバック関数は 2 つのパラメータを持ちます。マネージメントイベント構造体(発生したイベントに関する全ての情報を含む)と、参照コンテクスト(イベントのコンテクストを確立するために使用できるオプションの UInt32 値)です。コールバック関数は、あなたが行なう操作の結果として発生するイベントをハンドルするコードが提供されることを必要とします。
コールバック関数は高負荷なプロセスを行なうべきではありません。そうすると、Bluetooth スタックが実行から妨害されます。コールバック関数におけるカスタムシステムイベントの生成およびイベントをハンドルするコードによるイベントへの反応によって、プロセスを延期することができます。プロセスを延期するべき操作もあります。例えば、コールバック関数は btLibManagementEventAclDisconnect イベントへの反応として Bluetoothライブラリを閉じることができません。
単純な例として、近くにあるデバイスを探すというタスクを考えます。このタスクは次のセクションで説明します。コールバック関数は 4 つのイベントに反応するべきです。それはbtLibManagementEventInquiryResult、 btLibManagementEventInquiryComplete、btLibManagementEventInquiryCanceled、btLibManagementEventRadioStateです。以下のコードは、あなたが必要とするコールバック関数の骨組みです。
void MyManagementCallback (BtLibManagementEventType *eventP, UInt32 refcon) { switch (eventP->event) { case btLibManagementEventInquiryResult : // A device has been found. Save it in a list break; case btLibManagementEventInquiryComplete : // The inquiry has finished break; case btLibManagementEventInquiryCanceled : // The inquiry has been canceled break; case btLibManagementEventRadioState : // The radio state has changed break; default : // Unknown event break; }
コールバック関数を使用することを Bluetooth ライブラリに伝えるには、BtLibRegisterManagementNotificationをコールします。Bluetoothライブラリを閉じる前には常に、コールバックを解放するべきです。
マネージメントイベントの一覧は、第 82 章 「Bluetooth ライブラリ: マネージメント」の「マネージメントコールバックイベント」を参照して下さい。
ライブラリを開く
Bluetooth ライブラリを開くには、btLibManagementEventRadioState イベントを btLibErrRadioInitialized の状態で使用します。無線を含むあらゆる Bluetooth ライブラリ関数をコールする前に正しく完了するために、初期化を待たなければいけません。
このルールの例外は、探索関数 BtLibDiscoverSingleDevice です。それは無線初期化イベントを自動的にハンドルし、Bluetooth ライブラリが開かれた後に直接コールされることができます。
近くにあるデバイスを探す
範囲内にある Bluetooth デバイスを探すには 2 つの方法があります。
- 近くにあるデバイスを探すためにBtLibDiscoverSingleDevice関数を使用します。これらの関数は、ユーザが1つ以上のデバイスを選択できるようにするユーザインターフェイスを起動します。
- BtLibStartInquiry を使ってデバイス問い合わせを行ないます。これは探索関数の 1 つを使用するよりも難しいですが、より柔軟です。
btLibManagementEventInquiryCanceled をコールしたとき、キャンセルが成功すればイベントは生成されます。
ACL リンクの生成
一度リモートデバイスのデバイスアドレスを取得したなら、生成された btLibManagementEventAclConnectOutbound イベントを使ってリモートデバイスとの ACL リンクの生成を試行することができます。また、そのイベントに含まれるステータスコードはリンクが正しく確立したかどうかを示しています。
リンクを切断するには、生成された btLibManagementEventAclDisconnect イベントを使います。リモートデバイスが切断を初期化するときと同じイベントが生成されることに注意して下さい。
プログラムは BtLibLinkDisconnect 関数にも反応するべきです。
Piconet での活動
Bluetooth は Piconet において 7 つまでのスレーブをサポートします。Bluetooth ライブラリは、Piconet を生成もしくは破棄するための単純な API を提供します。
Bluetooth1.1 仕様は、新しい接続が確立されたときにホールドまたはパークモード中に上位のソフトウェアレイヤがスレーブ状態になることを提案している、ということに注意して下さい。これは仕様において充分に定義されたものではありません。また、タイミングの関係でそのようにするのは困難です。Bluetooth ライブラリは、無線ベースバンドが Piconet のタイミングを扱うことを期待しています。
Piconet を生成するには、「マスタ」が BtLibPiconetCreate をコールします。そしてスレーブはマスタを探索し Piconet に参加することができます。もしくはマスタがスレーブを探索し接続することができます。マスタは、7 つのスレーブの限界に達すると広報を停止します。どのデバイスもスレーブとして振る舞うことができるということに注意して下さい。
更にスレーブが参加することを防ぐために Piconet をロックすることができます。しかし、それでもマスタはスレーブを探索および追加することができます。ロックされた Piconet では、およそ 10 % 程度の帯域改善があります。
Bluetooth ライブラリでは、以下の関数が Piconet の管理をサポートします。
- BtLibPiconetCreate : Piconet の作成または既存 Piconet の再設定を行ない、ローカルデバイスがマスタになります。
- BtLibPiconetDestroy : 全てのデバイスとのリンクを切断することにより、Piconet を破棄します。また、ローカルデバイスがマスタかスレーブかに関わらず全ての制限を取り除きます。
- BtLibPiconetLockInbound : リモートデバイスが Piconet 内に ACL リンクを作成することを防ぎます。
- BtLibPiconetUnlockInbound : 追加のスレーブが Piconet 内に ACL リンクを作成することを許可します。
Piconet の以下の制限を忘れないで下さい。スレーブからスレーブへの通信は許可されません。マスタはスレーブに対して「ブロードキャスト」することはできません。
ソケット
Bluetooth ライブラリは、Bluetooth デバイスとの通信を管理するためにソケットのコンセプトを使用しています。ソケットはリモートデバイスに対する双方向のパケットベースリンクを表現します。ソケットは ACL 接続の上で動作します。Bluetoothライブラリは、16 までの同時ソケットに対応します。
Bluetooth ライブラリでは 3 種類のソケットがサポートされます。L2CAP および RFCOMM ソケットは、データチャネルを確立し、そのチャネルを通して随意のデータを送受信します。SDP ソケットによって、リモートデバイスに対してそのデバイスが提供するサービスについて問い合わせることができるようになります。
データパケットを L2CAP もしくは RFCOMM ソケットで送信するには、btLibSocketEventSendComplete イベントを使用します。各ソケットについて一つの目立ったjパケットのみを持つことができます。
btLibSocketEventData イベントはデータが受信されたことを示します。
L2CAP
L2CAP ソケットはフローコントロールを許可しません。
インバウンド L2CAP 接続の確立
インバウンド L2CAP 接続をセットアップするには、以下のコールを行ないます。
- BtLibSocketCreate:L2CAP ソケットを生成します。
- BtLibSocketListen:L2CAP ソケットをリスナとしてセットアップします。
- BtLibSdpServiceRecordCreate:SDP サービスレコードを示すメモリチャンクをアロケートします。
- BtLibSdpServiceRecordSetAttributesForSocket:SDP メモリレコードを初期化し、そしてそれは新しく生成された L2CAP リスナソケットをサービスとして示します。
- BtLibSdpServiceRecordStartAdvertising:SDP メモリレコードを、リモートデバイスから見えるローカル SDP サービスレコードとして示します。
btLibSocketEventConnectedInboundイベントをインバウンドソケットで取得したとき、データが送信または受信されます。
待機中のソケットは開き続け、接続が試行されることを通知します。言い換えると、単一の L2CAP 待機ソケットを使ってインバウンドソケットを複数生成することができます。そのインバウンドソケットを閉じるまで待機ソケットは閉じることができません。
アウトバウンド L2CAP 接続の確立
アウトバウンド L2CAP 接続を確立するために、まずリモートデバイスとの ACL リンクを確立します。以下のようにコールします。
- BtLibSocketCreate:SDP ソケットを生成します。
- BtLibSdpGetPSMByUuid:SDP を使って利用可能な L2CAP PSM を取得します。
- BtLibSocketClose:SDP ソケットを閉じます。
- BtLibSocketCreate:L2CAP ソケットを生成します。
- BtLibSocketConnect:アウトバウンド L2CAP 接続を生成します。
RFCOMM
RFCOMM はシリアル接続をエミュレートします。それは、Bluetooth仮想シリアルドライバと Bluetooth 交換ライブラリで使用されます。
RFCOMM を使用するとき、待機ソケットごとに一つのインバウンド接続だけを持つことができます。フローコントロールは「信用」システムを使用します。つまり、データパケットを受け取るはるか前に信用を提出する必要があります。
RFCOMM は サーバとクライアントの概念を定義します。サーバは、その存在を広報するために SDP を使用し、インバウンド接続を待機します。クライアントはアウトバウンド RFCOMM 接続をサーバに対して生成します。
インバウンド RFCOMM 接続の確立
インバウンド RFCOMM 接続をセットアップするには、以下のようにコールします。
- BtLibSocketCreate:RFCOMM ソケットを生成します。
- BtLibSocketListen:RFCOMM ソケットをリスナとしてセットアップします。
- BtLibSdpServiceRecordCreate:SDP サービスレコードを示すメモリチャンクを割り当てます。
- BtLibSdpServiceRecordSetAttributesForSocket:SDP メモリレコードを初期化します。そして、それは新しく生成されたサービスとしての RFCOMM リスナソケットを示すことができます。
- BtLibSdpServiceRecordStartAdvertising:ローカル SDP サービスレコードを示す SDP メモリレコードがリモートデバイスから見えるようにします。
btLibSocketEventDataイベントを取得したなら、データが受信されたということです。
待機中のソケットはそれ以上の接続試行を通知しません。言い換えると、単一の RFCOMM 待機ソケットは単一のインバウンド RFCOMM ソケットを生み出すだけです。インバウンドソケットを閉じるまで待機ソケットを閉じることはできません。
アウトバウンド RFCOMM 接続の確立
アウトバウンド RFCOMM 接続を確立するには、まずリモートデバイスとの ACL リンクを確立します。以下のコールをします。
- BtLibSocketCreate:SDP ソケットを生成します。
- BtLibSdpGetServerChannelByUuid:SDP を使って利用可能な RFCOMM サーバチャネルを取得します。
- BtLibSocketCreate:RFCOMM ソケットを生成します。
- BtLibSocketConnect:アウトバウンド RFCOMM 接続を生成します。