ライブラリがビルドできたら、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