OS X用GigE Visionカメラドライバ - その8 [OS X用GigE Vision]
こないだからやってるGigE Vison準拠カメラをOS Xで動かすためのおさらい。前回まででUDPを使って通信するんだあ、ネットワーク上のカメラを探すのにUDPのブロードキャストを使うんだあ、あとはカメラのレジスタに書き込むことで動作を起動することができるんだあ、画像データはやっぱりUDPのパケットで送られてくるんだあ、ということまではわかった。
概要を追いかけているだけでは退屈してきた。あんまり仕様をちまちま追いかけていてもわかった気にならないので、実際にコードを書いていこうと思う。まずカメラ探索....
僕のいつものパターンだとコードを書くのはぎりぎりになってからなんだけど(でないとすぐスパゲティで嫌になって投げ出すことになる)、今回の場合アルゴリズムも糞もない。こういうのは実際に書いて試してみるしかない。
デバイス探索は
このサイトにもあるようにまず
socketを作る上のコードでは、まずAF_INETというのはIPv4インターネットを使いますよ、SOCK_DGRAMはUDPを使いますよ、ということを設定してる。socket()の3番目の引数はプロトコルを指定するはずでIPPROTO_UDPが正しいけど、どのみちSOCK_DGRAMにはひとつしかプロトコルは定義されていないので0(デフォルトのプロトコルを使うという指定)でOK。
このあと、socketがブロードキャストできるようにオプションを設定する必要がある。
その次に送り先のアドレスを設定する。
これを送り先にしてさっき作ったsocketからデータを送り出す。
sendto()の4つ目の引数はフラグで、OS Xでは
このsendto()では送り出されたバイト数が返る。負の値が返ってきたときは失敗したということになる。
sendto()が成功したとしても単にUDPパケットが送り出された、というだけで相手に届く保証は無い。とりあえず成功すればまず
ところで、なんのかんの言ってもコード書いてるほうがやっぱり楽しい。僕もまだ若いな.....
概要を追いかけているだけでは退屈してきた。あんまり仕様をちまちま追いかけていてもわかった気にならないので、実際にコードを書いていこうと思う。まずカメラ探索....
4 デバイス探索のコード
まず最初に必要になるのはデバイス探索。UDPのブロードキャストを放って、その応答を捕まえる。僕のいつものパターンだとコードを書くのはぎりぎりになってからなんだけど(でないとすぐスパゲティで嫌になって投げ出すことになる)、今回の場合アルゴリズムも糞もない。こういうのは実際に書いて試してみるしかない。
デバイス探索は
- socketをUDP用に作る
- ブロードキャストアドレスを設定し、ポートをGVCP専用ポート番号にする
- デバイス探索のコマンドフレームのデータを作る
- socketを通じてデータをブロードキャストする
- 応答を受け取る
4.1 UDPブロードキャスト
ということでsocketのブロードキャストってどうだったっけ?というのを整理する。僕が書くまでもなく専門家のサイトがあるのでそちらを参考にしてもらいたい。このサイトではLinuxでのコードを紹介しているけどOS Xでも全く同じコードが動く。このサイトにもあるようにまず
int sock; sock = socket(AF_INET, SOCK_DGRAM, 0);でUDP用のsocketを作る。socketなにそれ?百ボルトでビリビリくるの?という人はどこかで勉強してきてほしい。僕よりもずっと親切で丁寧でわかりやすいサイトがいっぱいある。
socketを作る上のコードでは、まずAF_INETというのはIPv4インターネットを使いますよ、SOCK_DGRAMはUDPを使いますよ、ということを設定してる。socket()の3番目の引数はプロトコルを指定するはずでIPPROTO_UDPが正しいけど、どのみちSOCK_DGRAMにはひとつしかプロトコルは定義されていないので0(デフォルトのプロトコルを使うという指定)でOK。
このあと、socketがブロードキャストできるようにオプションを設定する必要がある。
int option = 1; setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&option, sizeof(option));これを設定しないとブロードキャストは失敗する。僕はこれを忘れてなんでブロードキャストが通らないのか、とずいぶん悩んだ。しょうもない悩みだった。でもなんのためにこんな設定をする必要があるのかよくわからない。どのみち1行設定するだけなので、ブロードキャストの濫用防止にはならないと思うんだけど。
その次に送り先のアドレスを設定する。
struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(3956); addr.sin_addr.s_addr = inet_addr("255.255.255.255");socketで指定したのにまたAF_INETを指定しないといけないのか、というと構造体の形がアドレスファミリごとに違っているからである。3956というポート番号はGVCPを通すためのポート番号で、GigE Vision規格の中で決まっている固定した値である。アドレスはIPv4のブロードキャストアドレスである。ちなみにTCPにはブロードキャストはないし、IPv6のブロードキャストはマルチキャストに格下げされている。
これを送り先にしてさっき作ったsocketからデータを送り出す。
char *buffer; size_t bufferLength; ssize_t length; length = sendto(sock, buffer, bufferLength, 0, (struct sockaddr *)&addr, sizeof(addr));これはsocketを経由してaddrで示した宛先にbufferの内容を送る、というシステムコールである。このbufferにはデバイス探索のコマンドフレームが書き込まれてあるとしている。具体的なコマンドフレームの内容はまたあとでまとめる。
sendto()の4つ目の引数はフラグで、OS Xでは
#define MSG_OOB 0x1 /* process out-of-band data */ #define MSG_DONTROUTE 0x4 /* bypass routing, use direct interface */のふたつだけが定義されている。詳細はmanページを参照してほしい。
このsendto()では送り出されたバイト数が返る。負の値が返ってきたときは失敗したということになる。
sendto()が成功したとしても単にUDPパケットが送り出された、というだけで相手に届く保証は無い。とりあえず成功すればまず
option = 0; setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&option, sizeof(option));で、ブロードキャストをデフォルトに戻しておくのが一応の作法である(が、このあとsocketを破棄してしまえば関係ない)。
ところで、なんのかんの言ってもコード書いてるほうがやっぱり楽しい。僕もまだ若いな.....
2014-10-26 17:47
nice!(0)
コメント(0)
トラックバック(0)
コメント 0