Palm Programmer's Laboratory
Palm OS Programmer's Companion Volume II/5-7
5-7 シリアルリンクマネージャ
シリアルリンクマネージャは、シリアルリンクプロトコルの Palm OS 実装です。
シリアルリンクマネージャは複数のクライアントソケット、パケット送信、同期/非同期のパケット受信、を管理するメカニズムを提供します。また、リモートデバッガまたはリモートプロシージャコール( Remote Procedure Calls : RPC )のサポートも提供します。
シリアルリンクマネージャの利用
アプリケーションがシリアルリンクマネージャのサービスを利用する前に、アプリケーションは SlkOpen をコールしてマネージャを開かなければいけません。エラーコードがゼロまたは slkErrAlreadyOpen であれば、成功です。戻り値 slkErrAlreadyOpen は、シリアルリンクマネージャが既に(たいていは他のタスクによって)開いていることを示します。他のエラーコードは失敗を示します。
シリアルリンクマネージャの利用が終わったら、SlkOpen をコールしてゼロまたは slkErrAlreadyOpen が戻されます。開く数がゼロに達したら、SlkOpen によってアロケートされたリソースを SlkCloseが解放します。
シリアルリンクマネージャのソケットサービスを利用するには、「ソケットIDの割り当て」?をコールしてシリアルリンクソケットを開きます。
シリアルリンクソケットを使い終わったら、SlkCloseSocket をコールしてそれを閉じます。これは、シリアルリンクマネージャによってこのソケットにアロケートされたシステムリソースを解放します。
特定のソケットのために通信ライブラリの参照値を得るには、SlkSocketRefNum をコールします。そのソケットは既に開いている必要があります。ソケットのためにポート ID を得るには、もしシリアルマネージャを使っているなら、SlkSocketPortID をコールします。
特定のソケットのためにバイト内パケットの受信タイムアウトを設定するには、SlkSocketSetTimeout をコールします。
特定のソケットのために受信ストリームをフラッシュするには、ソケットの値とそのバイト内タイムアウトを渡して SlkFlushSocket をコールします。
特定のソケットのためにソケットリスナを登録するには、開いたソケットのソケット値と SlkSocketListenType 構造体へのポインタを渡して SlkSetSocketListener をコールします。シリアルリンクマネージャは SlkSocketListenType 構造体をコピーしませんが、代わりに渡されたポインタを保存します。そのため、その構造体は自動変数(つまりスタックにアロケートされるもの)にはなりません。SlkSocketListenType 構造体はアプリケーションのグローバル変数かもしれませんし、またはダイナミックヒープからアロケートされたロックされたチャンクかもしれません。SlkSocketListenType 構造体はソケットリスナプロシージャへのポインタとこのソケットに向いたディスパッチ中のパケットのためのデータバッファを指定します。2 つのバッファへのポインタは指定されるべきです。
- パケットヘッダバッファ( SlkPktHeaderTypeのサイズ)
- パケットボディバッファ。これは、予想されるクライアントデータサイズよりも充分に大きくなければいけません。
両バッファはアプリケーションのグローバル変数かもしれませんし、またはダイナミックヒープからアロケートされたロックされたチャンクかもしれません。
ソケットリスナプロシージャは、有効なパケットがソケットに受信されたときにコールされます。パケットヘッダバッファとパケットボディバッファへのポインタは、ソケットリスナプロシージャのパラメータとして渡されます。シリアルリンクマネージャは、ソケットが閉じるときに SlkSocketListenType 構造体やバッファを解放しません。つまり、それらの解放はアプリケーションの責任で行なうものです。この関数のメカニズムにより、定期的に SlkReceivePacket をコールすることによるシリアルリンクマネージャ受信者を「運用する」責任を引き受けるためにはいくつかのタスクが要求されます。
パケットを送信するには、このセクションで説明したプロセスを取り入れた Listing 5.12 をコールします。
Listing 5.12 シリアルリンクパケットの送信
Err err; //serial link packet header SlkPktHeaderType sendHdr; //serial link write data segments SlkWriteDataType writeList[2]; //packet body(example packet body) UInt8 body[20]; // Initialize packet body ... // Compose the packet header. Let Serial Link Manager // set the transId. sendHdr.dest = slkSocketDLP; sendHdr.src = slkSocketDLP; sendHdr.type = slkPktTypeSystem; sendHdr.transId = 0; // Specify packet body writeList[0].size = sizeof(body); //first data block size writeList[0].dataP = body; //first data block pointer writeList[1].size = 0; //no more data blocks // Send the packet err = SlkSendPacket( &sendHdr, writeList ); ... }
Listing 5.13 新しいトランザクション ID の生成
// // Example: Generating a new transaction ID given the // previous transaction ID. Can start with any seed value. // UInt8 NextTransactionID (UInt8 previousTransactionID) { UInt8 nextTransactionID; // Generate a new transaction id, avoid the // reserved values (0x00 and 0xFF) if ( previousTransactionID >= (UInt8)0xFE ) nextTransactionID = 1; // wrap around else nextTransactionID = previousTransactionID + 1; // increment return nextTransactionID; }
パケットを受信するには、SlkReceivePacket をコールします。渡されたソケットIDのためだけにパケットを要求するかもしれませんし、もしくはソケットリスナを持たない開いたソケットのためかもしれません。パケットヘッダとクライアントデータとタイムアウトのためのバッファをパラメータで指定します。タイムアウトは、タイムアウトする前に到達を開始するために、受信側がどの程度パケットを待たなければいけないか、を示します。-1 のタイムアウト値は「永久に待つ」を意味します。もし登録されたソケットリスナを持つソケットのためにパケットが受信されるなら、パケットはそのソケットリスナプロシージャを経由してディスパッチされます。