ライブラリがビルドできたら、LEDを点灯させるサンプルを実行してみましょう。
以下のように、cdでサンプルのディレクトリに移動し、makeでビルド、make runで実行します。
cd examples/firststep/
make
make run
以下のようなhipcdumpの出力が表示されれば、実行は成功です。環境によっては標準エラー出力(RまたはLの行)が複数の行に分割されているかもしれませんが、問題はありません。 HIPCの本来の目的は、マイコンのサーバーとパソコンのクライアントの間で通信を行うことですが、 ここではサーバーとクライアントの両方がパソコンで実行されています。
09:24:45.156584 < HELLO[07 ff 00 3a] 43 46 47 6c 65 64 3b 32 30 31 35 2d 30 36
2d 32 33 54 30 39 3a 32 34 3a 33 39 2b 30 39 3a 30 30 3b 61 30 61 33 30 64 66
37 3b 6d 79 75 38 6a 56 47 4c 75 35 4a 48 73 4b 58 42 |CFGled;2015-06-23T09
:24:39+09:00;a0a30df7;myu8jVGLu5JHsKXB|
09:24:45.156744 > SYS[02 6c 00 01] 01 |.|
09:24:45.156744 > SYS[02 00 01 01] 00 |.|
09:24:45.156744 > SYS[02 00 02 01] 01 |.|
09:24:45.156945 < GET[04 00 00 01]
09:24:45.157076 > SUCCESS[01 00 00 01] 00 |.|
09:24:45.157246 R STRUprm.led: 0
09:24:45.157342 < PUT[05 00 00 01] 01 |.|
09:24:45.157460 L led:1
09:24:45.157474 > SUCCESS[01 ff 00 00]
09:24:45.157569 < BYE[06 ff 00 00]
09:24:45.157662 > QUIT[00 ff 00 00]
09:24:45.157776 L end
09:24:45.158076 R end
HIPCコンフィギュレーションファイルはhipccfg/CFGled.ymlです。 unsigned char型でledという名前のメンバーを持つ構造体型STRUprmを定義しています。
なお、ここで、フィギュレーションファイル名にCFG、構造体型名にSTRUを付けているのは、設定ファイルで指定した名前が他の場所でどのように使われるかを分かりやすくするためです。CFGやSTRUは必須ではありません。
クライアントのソースコードは、client/client.cです。
hipcOpen()は、セッションを開くための関数です。引数にあるHIPCUD_CFGled_CCFGは、コンフィギュレーションファイルから自動生成されています。hipcPosixReadMsgとhipcPosixWriteMsgはHIPCメッセージをファイルディスクリプタから読む関数とファイルディスクリプタへ書く関数で、共にhipc/posix/clientutils.hで宣言されています。このサンプルでは、標準入力と標準出力を使うので、fdrとfdwという変数にSTDIN_FILENOとSTDOUT_FILENOを代入して、hipcOpen()へそれら変数のアドレスを引数として渡しています。
HIPC_ERRCHECK()は、エラーが起きていないことを確認するためのマクロです。もし、エラーが起きていた場合は、エラーの情報を表示した後、プログラムはHIPC_ERRCHECK()の行で終了します。
hipcGet()は、GETメッセージを送って、サーバーからデータを得ます。ここではSTRUprm.ledの値を要求していて、送られてきたデータはローカル変数prmにセットされます。
hipcPut()は、PUTメッセージを使って、サーバーへデータを送ります。ここではローカル変数prmの中から、メンバーであるledの値だけ送っています。
hipcClose()を呼ぶと、セッションが閉じられます。hipcOpen()でセッションを開いたら、hipcClose()で必ず閉じるようにして下さい。
サーバーのソースコードはserver/server.cです。
main関数では、hipcPosixUsocInit()で通信に使うユニバーサルソケットを初期化しています。STDIN_FILENOとSTDOUT_FILENOは、それぞれ標準入力と標準出力のファイルディスクリプタなので、この例ではサーバーは標準入出力を使ってクライアントを通信を行います。
この後hipcMain()が呼ばれます。 hipcMain()ではhipcUsocAcceptSimple()で、HELLOメッセージを待ち受けます。 適切なHELLOメッセージを受け取ると、hipcUsocAcceptSimple()はHIPC_SUCCESSを返しますので、hipcsvsLedRun()を呼んでCFGled構成におけるメッセージ処理へ移っています。
hipcsvsLedRun()では、クライアントからの要求を待って、これが来たら返答を返すという処理を繰り返します。実装としては、for文のすぐ下のhipcUsocRead()で、要求となるメッセージのヘッダのみをまず読み込んでいます。続いてhipcMsgdType()で、メッセージタイプを見て、それによって処理を分岐させています。
要求がGETメッセージだったときは、hipcGenmdSuccessToGet()で、返答としてmdSをデータ付きSUCCESSメッセージに初期化しています。引数として変数prmのアドレスを渡しているので、このSUCCESSメッセージのボディは、要求のあった範囲のprmの値となります。 なお、GETメッセージにはメッセージボディが無いため、その読み込み処理もありません。
要求がPUTメッセージだったときは、hipcMsgdSetBdyForPut()で、クライアントから来たデータの読み込み先をprmの適切な位置に設定し、hipcUsocRead()で実際にデータを読み込んでいます。 この読み込みは、メッセージボディの読み込みであると同時に、prmへの書き込みにもなっています。 続いてhipcGenmdSuccess()で、mdSをデータ無し(ボディサイズが0)のSUCCESSメッセージとして初期化しています。 さらに続いてhipcsvsLedUpdate()を呼んでいます。 hipcsvsLedUpdate()は、hipcsvsLedRun()のすぐ上で定義していて、標準エラー出力にprmに書き込まれた値を出力しています。先ほど見たhipcdumpの "R STRUprm.led: 0" という出力はこの出力です。
GETかPUTメッセージを受信した場合は、breakでswitch文を抜けた直後にhipcUsocWriteMsgd()で、返答となるメッセージmdSをクライアントに送ります。そして、ループの先頭に戻ってクライアントからの次のメッセージの処理に移ります。
BYEメッセージが来たときは、これは正常なセッション終了の要求なので、HIPC_SUCCESSを戻り値にしてreturnしています。
hipcsvsLedRun()の中でエラーが起きたときは、エラー値を戻り値にしてretrunしています。
セッションの終了はエラーか否かにかかわらず、必ずQUITメッセージとなります。 そこで、hipcMain()では、hipcsvsLedRun()から戻ったあと、この戻り値をhipcGenmdQuit()に渡してmdSを初期化し、通信エラーが起きていなければこれをクライアントへ送っています。
以上のセッションの開始から終了までの流れを図に表すと、以下のようなります。 なお、セッションやメッセージのより詳しい内容はプロトコル仕様に記述されています。
Last modified: 2015/07/27 08:00:59 +09:00