RTAI入門(8)どう書くか?その2
この記事からの続きです。
とにかくテンプレートのように、コピペしてすぐ使える!という形式を目指しています。新たにRTAIアプリを組む時は、今回からの記事から必要な部分だけコピペして下さい。
なお、ここで使用するサンプルコードはすべてこちらの記事で構築した環境にて確かめています。
今回の記事で出来るようになる事は、次の通りです。
- メールボックス
- FIFO
- セマフォ
- Net_RPC
メールボックス
メールボックスを作成するには、
- メールボックスを作成する
- メールボックスにデータを送信する
- メールボックスからデータを取り出す
という手順が必要です。
よりくわしい情報は、<RTAIのソース>\doc\generated\html\api\group__msg.html を参照して下さい。
メールボックスについてざっくりお知りになりたい方は、こちらの記事を参照してください。
メールボックスを作成する
mbx = rt_typed_named_mbx_init("MYMBX1", 32, FIFO_Q ); if( NULL == mbx ) { printf("Failed to initialize mbx\n"); return( 0 ); }
メールボックスを作成するには、rt_typed_named_mbx_init 関数を使用します。
第一引数: メールボックス名 6文字以下の文字列で指定します
第二引数: メールボックスのデータサイズ
第三引数: メールボックスにアクセスするタスクの順番。 FIFO_Qなら早い者勝ち。PRIO_Qなら優先順位の高いもの勝ち。RES_Qというのもありますが、これは良く分かりません・・・
メールボックスにデータを送信する
char buf[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; MBX* mbx = (MBX*)rt_get_adr( nam2num("MYMBX1") ); rt_mbx_send( mbx, buf, sizeof(buf) );
ここで、rt_get_adr に渡している MYBMX1 は、メールボックスの名前を指定します。この名前は、rt_typed_named_mbx_init に渡したものと同じです。
rt_mbx_send関数には、次の引数を与えます。
第二引数:データを格納してあるバッファ
第三引数:データサイズ
メールボックスからデータを受信する
char buf2[64]; MBX* mbx = (MBX*)rt_get_adr( nam2num("MYMBX1") ); rt_mbx_receive( mbx, buf2, 16 );
ここで、rt_mbx_receive関数には、次の引数を与えます。
第二引数: データを格納したいバッファ
第三引数: 受信したいデータサイズ
メールボックスを削除する
rt_mbx_delete( mbx );
メールボックスを使い終わったら、かならず削除して下さい。
メールボックスを削除しないままアプリを終了したとしても、メールボックスはまだ生き残っています。そのため、必ず明示的にメールボックスを削除してやる必要があります。
FIFO
メールボックスと同様に、FIFOを使ったデータのやり取りも可能です。
より詳しい情報は、<RTAIのソース>\doc\generated\html\api\group__fifos__ipc.html を参照してください。
FIFOに関する概要は、こちらの記事を参照してください。
FIFOを作成する
FIFOを作成するには、あらかじめ
mknod /dev/rtf<x> c 150 <x>
というコマンドを実行しておく必要があります。<x>は0~63の数値です。
FIFOを開く
ユーザースペースにてFIFOを開くには、次のようにします
int fid = rtf_open_sized( "/dev/rtf0", O_RDWR, 1024 );
ここで、第一引数はFIFOデバイスファイル名です。
第二引数は、O_RDWR, O_RDONLY, O_WRONLY などのモードを渡します。
第三引数は、使用したいFIFOのサイズです。
FIFOに書き込む
ユーザースペースにてFIFOに書き込むには、次のようにします
char buf[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; write( fid, buf, sizeof(buf) );
これはファイルへの書き込みとまったく同様です。
FIFOから読み込む
ユーザースペースにてFIFOから読み込むには、次のようにします
char buf[16]; read( fid, buf, 16 );
これはファイルからの読み込みとまったく同様です。
セマフォ
FIFOの /dev/rtf<x> にはセマフォ機能も付いています。/dev/rtf0 ~ /dev/rtf63 の合計64個のセマフォを使う事が出来ます。
より詳しい情報は、<RTAIのソース>\doc\generated\html\api\group__fifos__sem.html を参照してください。
セマフォの概要については、こちらの記事を参照してください。
セマフォを初期化する
/* Initialize semaphore */ int fid = open("/dev/rtf0", O_RDWR ); rtf_sem_init( fid /* semaphore */, 0 /* initial value. 0 or 1 */ );
open の第一引数が、セマフォ名です。/dev/rtf0 から /dev/rtf63 の間で指定します。
rtf_sem_initの第二引数は、セマフォの初期値です。0か1で指定しておきます。
初期値を0にしておくと、最初に wait した時にブロックしてしまいます。
初期値を1にしておくと、最初に wait した時、すでにカンバンが1つだけあるため、ブロックしません。
セマフォを wait する
int fid = open( "/dev/rtf0", O_RDWR ); rtf_sem_wait( fid /* semaphore */ );
open の第一引数が、セマフォ名です。/dev/rtf0 から /dev/rtf63 の間で指定します。
セマフォを post する
int fid = open( "/dev/rtf0", O_RDWR ); rtf_sem_post( fid /* semaphore */ );
open の第一引数が、セマフォ名です。/dev/rtf0 から /dev/rtf63 の間で指定します。
Net RPC
Net RPCを使用する事で、リモートマシン上のタスクやメールボックスを操作する事が出来ます。
Net RPCについては doc\generated には説明がありません。
概要については、こちらの記事をご覧ください。
ポートを取得する
Net RPCを使用するために、まずポートを取得します。
struct sockaddr_in addr; inet_aton("192.168.0.155" /* address */ ,&addr.sin_addr ); unsigned long node = addr.sin_addr.s_addr; long port = rt_request_hard_port( node );
このコードは、IPアドレス(192.168.0.155)からポートを取得するためのコードです。
ここで取得した、node, port の2つの変数が重要です。これらの変数でもって、Net RPCを使用します。
リモートのメールボックスからデータを読み込む
MBX* mbx = (MBX*)RT_get_adr( node, port, "MBX4"); if( NULL == mbx ) { printf("Failed to connect to MBX4"); } else { unsigned char buf[64]; memset( buf, 0, sizeof(buf) ); RT_mbx_receive( node, port, mbx, buf, 16 ); for( int i = 0 ; i < 16 ; ++i ) { printf("%02X ", buf[ i ] ); } printf("\n"); } rt_release_port( node, port );
このコードでは、取得したポートを元にリモートマシンのメールボックス MBX4 にアクセスしています。
そして、そのメールボックスから16バイトのデータを読み込もうとしています。
ここで、RT_get_adr や、 RT_mbx_receive などの関数名に着目します。
ローカルマシン内で、メールボックスのアドレスを取得するのは rt_get_adr です。
同様に、ローカルマシン内でメールボックスから受信するのは rt_mbx_receive です。
ところが、ここでは RT という大文字で始まっています。実は、これがポイントです。
Net RPCを使用するには、RT で始まる関数を使用します。そして、第一引数に node, 第二引数に port を与えます。
この、「RTで始まる」「node, port を引数に与える」という所以外は、すべてローカルの関数と同様に扱えます。
メールボックス読み込みに限らず、メールボックス書き込み、メッセージ送信、メッセージ受信、なども、すべて RTで始まり、node, port を与えるようにすれば実現可能です。
サンプルプログラム
次回
次回はいよいよ最終回、割り込みの方法です。
今さらかもしれませんが…ご参考までにコメントします。
FIFO, セマフォを使用するとき、mknod /dev/rtf c 150 をあらかじめ実行する必要があるとの記事内容ですが、rtai4.0 で行ってみたところ rtai_fifos.ko を起動時にloadしておくと、自動的に0~63までの/dev/rtfが作成されており、File exists エラーとなります。
セマフォについてはそのままで動作することを確認しました。