[[← 1 節に戻る|Palm OS Programmer's Companion Volume II/6-1]] [[↑6 章トップへ|Palm OS Programmer's Companion Volume II/6]] [[3 節に進む →|Palm OS Programmer's Companion Volume II/6-3]] ---- !!! 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 ライブラリを開いて利用する用意ができます。ライブラリを参照するために、{{span style='color:blue;font-family:monospace;',btLibRefNum}} 値を使います。 !!Bluetooth ライブラリの概要 プログラマの見通しから、Bluetoothライブラリの関数は 4 つの領域になります。マネージメント・ソケット・セキュリティ・ユーティリティです。 *マネージメント関数は、Bluetooth 仕様における無線とベースバンドの部分を扱います。近くにあるデバイスの発見やACLリンクの確立で使用します。 *ソケット関数は、L2CAP・RFCOMM・SDPとの通信を可能にします。 *セキュリティ関数は、信頼されたデバイス(ハンドヘルドと安全な接続を生成するときに証明を必要としないデバイス)を管理します。 *ユーティリティ関数は、有用なデータ変換を行ないます。 !!マネージメント Bluetoothアプリケーションに共通する 3 つの基本的なマネージメントタスクは、範囲内の Bluetooth デバイスの検索、ACL リンクの確立、Piconet での活動、です。しかし、これらの操作を行なう関数をコード内で使用するためには、マネージメントコールバック関数を生成する必要があります。 !マネージメントコールバック関数 多くのマネージメントコールは非同期です。言い換えると、それらは操作を開始し、操作が実際に完了する前に戻ります。操作が完了したときに、Bluetooth ライブラリはコールバック関数によってアプリケーションに通知します。そのような通知は'''マネージメントイベント'''と呼ばれます。 マネージメント関数は非同期操作の開始前に失敗する場合があります。この場合、コールバック関数はコールされません。マネージメント関数のリターンコードを見ることで、コールバック関数がコールされるのかどうかを知ることができます。  {{span style='color:blue;font-family:monospace;',btLibErrNoError}}   操作は完了しました。コールバック関数はコールされないでしょう。  {{span style='color:blue;font-family:monospace;',btLibErrPending}}   操作は開始されました。コールバック関数がコールされるでしょう。  {{span style='color:blue;font-family:monospace;',any other error code}}   操作は失敗しました。コールバック関数はコールされないでしょう。 マネージメントコールバック関数は 2 つのパラメータを持ちます。マネージメントイベント構造体(発生したイベントに関する全ての情報を含む)と、参照コンテクスト(イベントのコンテクストを確立するために使用できるオプションの {{span style='color:blue;font-family:monospace;',UInt32}} 値)です。コールバック関数は、あなたが行なう操作の結果として発生するイベントをハンドルするコードが提供されることを必要とします。 コールバック関数は高負荷なプロセスを行なうべきではありません。そうすると、Bluetooth スタックが実行から妨害されます。コールバック関数におけるカスタムシステムイベントの生成およびイベントをハンドルするコードによるイベントへの反応によって、プロセスを延期することができます。プロセスを延期するべき操作もあります。例えば、コールバック関数は {{span style='color:blue;font-family:monospace;',btLibManagementEventAclDisconnect}} イベントへの反応として Bluetoothライブラリを閉じることができません。 単純な例として、近くにあるデバイスを探すというタスクを考えます。このタスクは次のセクションで説明します。コールバック関数は 4 つのイベントに反応するべきです。それは{{span style='color:blue;font-family:monospace;',btLibManagementEventInquiryResult}}、 {{span style='color:blue;font-family:monospace;',btLibManagementEventInquiryComplete}}、{{span style='color:blue;font-family:monospace;',btLibManagementEventInquiryCanceled}}、{{span style='color:blue;font-family:monospace;',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 ライブラリに伝えるには、{{span style='color:blue;font-family:monospace;',BtLibRegisterManagementNotification}}をコールします。Bluetoothライブラリを閉じる前には常に、コールバックを解放するべきです。 マネージメントイベントの一覧は、第 82 章 「Bluetooth ライブラリ: マネージメント」の「マネージメントコールバックイベント」を参照して下さい。 !ライブラリを開く Bluetooth ライブラリを開くには、{{span style='color:blue;font-family:monospace;',btLibManagementEventRadioState}} イベントを {{span style='color:blue;font-family:monospace;',btLibErrRadioInitialized}} の状態で使用します。無線を含むあらゆる Bluetooth ライブラリ関数をコールする前に正しく完了するために、初期化を待たなければいけません。 このルールの例外は、探索関数 {{span style='color:blue;font-family:monospace;',BtLibDiscoverSingleDevice}} です。それは無線初期化イベントを自動的にハンドルし、Bluetooth ライブラリが開かれた後に直接コールされることができます。 !近くにあるデバイスを探す 範囲内にある Bluetooth デバイスを探すには 2 つの方法があります。 *近くにあるデバイスを探すために{{span style='color:blue;font-family:monospace;',BtLibDiscoverSingleDevice}}関数を使用します。これらの関数は、ユーザが1つ以上のデバイスを選択できるようにするユーザインターフェイスを起動します。 *{{span style='color:blue;font-family:monospace;',BtLibStartInquiry}} を使ってデバイス問い合わせを行ないます。これは探索関数の 1 つを使用するよりも難しいですが、より柔軟です。 {{span style='color:blue;font-family:monospace;',btLibManagementEventInquiryCanceled}} をコールしたとき、キャンセルが成功すればイベントは生成されます。 !ACL リンクの生成 一度リモートデバイスのデバイスアドレスを取得したなら、生成された {{span style='color:blue;font-family:monospace;',btLibManagementEventAclConnectOutbound}} イベントを使ってリモートデバイスとの ACL リンクの生成を試行することができます。また、そのイベントに含まれるステータスコードはリンクが正しく確立したかどうかを示しています。 リンクを切断するには、生成された {{span style='color:blue;font-family:monospace;',btLibManagementEventAclDisconnect}} イベントを使います。リモートデバイスが切断を初期化するときと同じイベントが生成されることに注意して下さい。 プログラムは {{span style='color:blue;font-family:monospace;',BtLibLinkDisconnect}} 関数にも反応するべきです。 !Piconet での活動 Bluetooth は Piconet において 7 つまでのスレーブをサポートします。Bluetooth ライブラリは、Piconet を生成もしくは破棄するための単純な API を提供します。 Bluetooth1.1 仕様は、新しい接続が確立されたときにホールドまたはパークモード中に上位のソフトウェアレイヤがスレーブ状態になることを提案している、ということに注意して下さい。これは仕様において充分に定義されたものではありません。また、タイミングの関係でそのようにするのは困難です。Bluetooth ライブラリは、無線ベースバンドが Piconet のタイミングを扱うことを期待しています。 Piconet を生成するには、「マスタ」が {{span style='color:blue;font-family:monospace;',BtLibPiconetCreate}} をコールします。そしてスレーブはマスタを探索し Piconet に参加することができます。もしくはマスタがスレーブを探索し接続することができます。マスタは、7 つのスレーブの限界に達すると広報を停止します。どのデバイスもスレーブとして振る舞うことができるということに注意して下さい。 更にスレーブが参加することを防ぐために Piconet をロックすることができます。しかし、それでもマスタはスレーブを探索および追加することができます。ロックされた Piconet では、およそ 10 % 程度の帯域改善があります。 Bluetooth ライブラリでは、以下の関数が Piconet の管理をサポートします。 *{{span style='color:blue;font-family:monospace;',BtLibPiconetCreate}} : Piconet の作成または既存 Piconet の再設定を行ない、ローカルデバイスがマスタになります。 *{{span style='color:blue;font-family:monospace;',BtLibPiconetDestroy}} : 全てのデバイスとのリンクを切断することにより、Piconet を破棄します。また、ローカルデバイスがマスタかスレーブかに関わらず全ての制限を取り除きます。 *{{span style='color:blue;font-family:monospace;',BtLibPiconetLockInbound}} : リモートデバイスが Piconet 内に ACL リンクを作成することを防ぎます。 *{{span style='color:blue;font-family:monospace;',BtLibPiconetUnlockInbound}} : 追加のスレーブが Piconet 内に ACL リンクを作成することを許可します。 Piconet の以下の制限を忘れないで下さい。スレーブからスレーブへの通信は許可されません。マスタはスレーブに対して「ブロードキャスト」することはできません。 !!ソケット Bluetooth ライブラリは、Bluetooth デバイスとの通信を管理するためにソケットのコンセプトを使用しています。ソケットはリモートデバイスに対する双方向のパケットベースリンクを表現します。ソケットは ACL 接続の上で動作します。Bluetoothライブラリは、16 までの同時ソケットに対応します。 Bluetooth ライブラリでは 3 種類のソケットがサポートされます。L2CAP および RFCOMM ソケットは、データチャネルを確立し、そのチャネルを通して随意のデータを送受信します。SDP ソケットによって、リモートデバイスに対してそのデバイスが提供するサービスについて問い合わせることができるようになります。 データパケットを L2CAP もしくは RFCOMM ソケットで送信するには、{{span style='color:blue;font-family:monospace;',btLibSocketEventSendComplete}} イベントを使用します。各ソケットについて一つの目立ったjパケットのみを持つことができます。 {{span style='color:blue;font-family:monospace;',btLibSocketEventData}} イベントはデータが受信されたことを示します。 !L2CAP L2CAP ソケットはフローコントロールを許可しません。 '''インバウンド L2CAP 接続の確立''' インバウンド L2CAP 接続をセットアップするには、以下のコールを行ないます。 +{{span style='color:blue;font-family:monospace;',BtLibSocketCreate}}:L2CAP ソケットを生成します。 +{{span style='color:blue;font-family:monospace;',BtLibSocketListen}}:L2CAP ソケットをリスナとしてセットアップします。 +{{span style='color:blue;font-family:monospace;',BtLibSdpServiceRecordCreate}}:SDP サービスレコードを示すメモリチャンクをアロケートします。 +{{span style='color:blue;font-family:monospace;',BtLibSdpServiceRecordSetAttributesForSocket}}:SDP メモリレコードを初期化し、そしてそれは新しく生成された L2CAP リスナソケットをサービスとして示します。 +{{span style='color:blue;font-family:monospace;',BtLibSdpServiceRecordStartAdvertising}}:SDP メモリレコードを、リモートデバイスから見えるローカル SDP サービスレコードとして示します。 {{span style='color:blue;font-family:monospace;',btLibSocketEventConnectedInbound}}イベントをインバウンドソケットで取得したとき、データが送信または受信されます。 待機中のソケットは開き続け、接続が試行されることを通知します。言い換えると、単一の L2CAP 待機ソケットを使ってインバウンドソケットを複数生成することができます。そのインバウンドソケットを閉じるまで待機ソケットは閉じることができません。 '''アウトバウンド L2CAP 接続の確立''' アウトバウンド L2CAP 接続を確立するために、まずリモートデバイスとの ACL リンクを確立します。以下のようにコールします。 +{{span style='color:blue;font-family:monospace;',BtLibSocketCreate}}:SDP ソケットを生成します。 +{{span style='color:blue;font-family:monospace;',BtLibSdpGetPSMByUuid}}:SDP を使って利用可能な L2CAP PSM を取得します。 +{{span style='color:blue;font-family:monospace;',BtLibSocketClose}}:SDP ソケットを閉じます。 +{{span style='color:blue;font-family:monospace;',BtLibSocketCreate}}:L2CAP ソケットを生成します。 +{{span style='color:blue;font-family:monospace;',BtLibSocketConnect}}:アウトバウンド L2CAP 接続を生成します。 !RFCOMM RFCOMM はシリアル接続をエミュレートします。それは、Bluetooth仮想シリアルドライバと Bluetooth 交換ライブラリで使用されます。 RFCOMM を使用するとき、待機ソケットごとに一つのインバウンド接続だけを持つことができます。フローコントロールは「信用」システムを使用します。つまり、データパケットを受け取るはるか前に信用を提出する必要があります。 RFCOMM は '''サーバ'''と'''クライアント'''の概念を定義します。サーバは、その存在を広報するために SDP を使用し、インバウンド接続を待機します。クライアントはアウトバウンド RFCOMM 接続をサーバに対して生成します。 '''インバウンド RFCOMM 接続の確立''' インバウンド RFCOMM 接続をセットアップするには、以下のようにコールします。 +{{span style='color:blue;font-family:monospace;',BtLibSocketCreate}}:RFCOMM ソケットを生成します。 +{{span style='color:blue;font-family:monospace;',BtLibSocketListen}}:RFCOMM ソケットをリスナとしてセットアップします。 +{{span style='color:blue;font-family:monospace;',BtLibSdpServiceRecordCreate}}:SDP サービスレコードを示すメモリチャンクを割り当てます。 +{{span style='color:blue;font-family:monospace;',BtLibSdpServiceRecordSetAttributesForSocket}}:SDP メモリレコードを初期化します。そして、それは新しく生成されたサービスとしての RFCOMM リスナソケットを示すことができます。 +{{span style='color:blue;font-family:monospace;',BtLibSdpServiceRecordStartAdvertising}}:ローカル SDP サービスレコードを示す SDP メモリレコードがリモートデバイスから見えるようにします。 {{span style='color:blue;font-family:monospace;',btLibSocketEventData}}イベントを取得したなら、データが受信されたということです。 待機中のソケットはそれ以上の接続試行を通知しません。言い換えると、単一の RFCOMM 待機ソケットは単一のインバウンド RFCOMM ソケットを生み出すだけです。インバウンドソケットを閉じるまで待機ソケットを閉じることはできません。 '''アウトバウンド RFCOMM 接続の確立''' アウトバウンド RFCOMM 接続を確立するには、まずリモートデバイスとの ACL リンクを確立します。以下のコールをします。 +{{span style='color:blue;font-family:monospace;',BtLibSocketCreate}}:SDP ソケットを生成します。 +{{span style='color:blue;font-family:monospace;',BtLibSdpGetServerChannelByUuid}}:SDP を使って利用可能な RFCOMM サーバチャネルを取得します。 +{{span style='color:blue;font-family:monospace;',BtLibSocketCreate}}:RFCOMM ソケットを生成します。 +{{span style='color:blue;font-family:monospace;',BtLibSocketConnect}}:アウトバウンド RFCOMM 接続を生成します。   ---- [[← 1 節に戻る|Palm OS Programmer's Companion Volume II/6-1]] [[↑6 章トップへ|Palm OS Programmer's Companion Volume II/6]] [[3 節に進む →|Palm OS Programmer's Companion Volume II/6-3]]