PQI Air Card から UDP で Yo と答えさせてデバイス検出する試み
WiFi 内蔵 SD カードである PQI Air Card[1] には WiFi の子機として繋ぐモードで動かすことができる。 WiFi AP が DHCP などで動的な IP 割り当てをしているときに、 PQI Air Card がどの IP アドレスで繋がっているかわからない。 しかしながら、PQI Air Card のほとんどの設定はブラウザからアクセスする必要があって、 これには IP アドレスがわからないと繋ぐことができない[4]。 そこで、PQI Air Card を探すために Yo と話しかけられたら Yo と返す 極めて簡素なプロトコルを設計し、これで簡易なデバイス検出(device discovery)をすることを試みた。 そのために PQI Air Card に乗っけるプログラムの作成と、 簡易デバイス検出クライアントを作成し検証した。
背景
WiFi 内蔵 SD カードを親機(WiFi AP)とする使い方はネットワーク接続が簡単ではあるが、 子機として繋げている機器からはインターネット接続ができなくなるなど不便である。 インターネット接続を維持する場合は、SD カードを子機として共通の WiFi AP に繋げる必要がある[4]。 PQI Air Card はどちらの方法でも使えることができる。 本エントリでは前者をステーション動作、後者をホットスポット動作と呼ぶこととする。
ステーション動作のときは PQI Air Card の IP アドレスは明らかであり、 子機のデフォルトゲートウェイとおなじになる。 一方で、ホットスポット動作のときは IP アドレスは環境ごとに変わりうる。 というのも親機(WiFi AP)によって IP アドレスが割り当てられるからである。
ホットスポット動作のときの IP アドレスを判断する方法はいくつか提案されている。 もっとも根本的な解決策は PQI Air Card (の MAC アドレス) に対して、 固定 IP を割り当てることである。 これは親機(WiFi AP)における機能によって解決する方法である。 これ以外の方法は公式的には PQI Air Card には存在しないと思われる。
他の WiFi 内蔵 SD カードでのこの問題の解決策としては、 SD カード側が NetBIOS 名や Bonjour 名を広告して Windows 機(samba クライアント)や Mac から見れる ようにしている事例(Flash Air)[2]、 外部サーバにそのままファイルを同期アップロードすることによって SD カード側の IP アドレスを知る必要性をほとんどなくしてしまった事例(Eye-Fi)[3] がみられる。
いっぽうで PQI Air Card の中では Linux が動いているが、
SD カードのルートに autorun.sh
という名前のシェルスクリプトのファイルを置くと
任意の動作をさせることができる[6]。
これを利用して親機(WiFi AP)に繋がった時点で twitter の Mention で伝えるという
解決策も提示されている[4]。
外部のネットワーク (e.g. twitter) を使わずに、 WiFi AP を安っすい固定割り当てができないものでも使えるようにし、 そして Flash Air などを使わずになんとかしたいと思ったので、 簡易デバイス検出の仕組みを作成し検証した次第である。
プロトコル Yo
本目的で使えそうなプロトコルとしては下記が上げられる。 これらのいくつかは “Simple” と謳っており、 実際確かにシンプルなものもあるのだが、 いずれも私が求めるシンプルさよりも遥かに複雑であった。
- NetBIOS Name service
- Simple Network Management Protocol (SNMP)
- Multicast DNS (mDNS), DNS-based service discovery (DNS-SD)
- Simple Service Discovery Protocol (SSDP), Universal Plug and Play (UPnP)
- Service Location Protocol (SLP)
そこで、極めて実装が簡単なプロトコルを設計した。 設計したといえない程の簡単なやりとりである。
- UDPを使い、機器(サービス)側のポート番号は既知とする。
- あるクライアントから機器(サービス)に UDP で
REQUEST-MESSAGE
を送信したとき、 機器(サービス)はそのクライアントに対してRESPONSE-MESSAGE
を送信する - クライアント→機器(サービス)はユニキャスト・ブロードキャストのいずれでもよい
- 機器(サービス)→クライアントはユニキャストである
- データ構造
REQUEST-MESSAGE: "Yo" CLIENT-ARBITARY-TEXT
RESPONSE-MESSAGE: REQUEST-MESSAGE CR-LF "Yo" SERVICE-ARBITARY-TEXT
CLIENT-ARBITARY-TEXT
,SERVICE-ARBITARY-TEXT
: 改行を含まない任意のテキストCR-LF: "\r\n"
要するに、下記の通り “Yo” をやりとりしてるだけの話である。
|Client side Service side| | | | "Yo from laptop" | |----------------------------------------->| | | | "Yo from laptop\r\nYo from PQI_AIR_CARD" | |<-----------------------------------------| | |
リクエストメッセージの送信をUDPブロードキャストにすることで、 クライアントは所望の “Yo” が戻ってきたアドレスを確認することで PQI Air Card の IP アドレスがわかる。
PQI Air Card への Yo サービスの導入
下記のとおり C 言語で書いた:
これを PQI Air Card 向けにコンパイルをした。 商用であるが無料で使える Sourcery CodeBench Lite という のでコンパイルした(クロスコンパイル環境によるコンパイル)。 なお、ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV) のバイナリを生成する コンパイラならどれをつかってもかまわないはずであるし、 PC上でデバッグ検証をするのならば普通に x86_64 の gcc などでコンパイルして 動作検証すればよい。
% arm-none-linux-gnueabi-gcc -o yo_service yo_service.c -O2 -Wall -static % arm-none-linux-gnueabi-strip -s yo_service
この yo_service
をSDカードの任意の場所に置く。
(/path/to/yo_service
に置いたものとする)
そしてSDカードのルートのautorun.sh
には下記を記述する(または追記する)。
あとはカメラの電源を入れたときに yo_service
が起動し常駐するようになる。
使用
機器(サービス)側の実装とデプロイで疲れてしまったので、 クライアント側は下記のような適当な ruby コードで確認した。
カメラに電源を入れた後しばらく待って (PQI Air Card の WiFi が確立する時間) 下記実行したらきちんと “Yo” が帰ってきた。
% ruby yo_send_test.rb "Yo from laptop\r\nYo from PQI_AIR_CARD" ["AF_INET", 10091, "192.168.1.3", "192.168.1.3"]
なお、ファイアウォールを導入している場合は、 UDPの受信ポートを開放しないと動作しないようだ。 上に示した ruby コードの例では 20091 版ポートを開放する必要がある模様。
これで PQI Air Card は 192.168.1.3 であることがわかるので、 PQI Air Card にブラウザなり FTP なり telnet なりで接続ができる。
% telnet 192.168.1.3 Trying 192.168.1.3... Connected to 192.168.1.3. Escape character is '^]'. #
ただしこの ruby コードはかなり雑であり、 PQI Air Card の WiFi が確立する前だったりの原因で “Yo” が帰ってこなかった場合の考慮が抜けているので、 その場合は Ctrl+C をするなど対策が必要だ。
UDP のパケット欠落や、その他複数の “Yo” を返す機器(サービス)がある場合については、 クライアント側のアプリの改良は当然ながら必要である。 UDP は TCP と違って再送などがないのでそれもプログラムとして組み込む必要があるが、 実際に何回か試した所、1m 程度の範囲内ならばエラーなしで届いているので UDP の再送他はなくてもどうにかなってしまっている。
まとめ
PQI Air Card を探すために Yo と話しかけられたら Yo と返す 極めて簡素なプロトコルを設計、実装をし、検証をした。
その結果、200 行未満の機器(サービス)側のコードと やっつけなクライアント側のコードでそれなりに満足のできる結果がえられた。
今後の課題として、 UDP のパケット欠落や、その他複数の “Yo” を返す機器(サービス)の検討が必要だが、 これでそれなりに満足してしまったのと、 NetBIOS 等が入っていない(or 導入が困難)かつ自作プログラムを送り込めるガジェット なんてそんなにないだろうから、 クライアント側のアプリの改良はすることはないだろう。
特記事項
“Yo”というキーワードはSNSのYoにインスパイヤされた。
参考文献
- [1] PQI Air Card, PQI Group
- [2] FlashAir Developers - ドキュメント - APIガイド - CONFIG,
APPNAME
- [3] Eyefi (アイファイ)クラウド - 安全なクラウドで便利に同期, Eyefi Japan
- [4] 竹内義晴 「これはいい!PQI Air Cardの2つの不満を解決する方法」, 「竹内義晴の、しごとのみらい」, 2013-04-02
- [5] あきみち Linuxネットワークプログラミング, Geekなぺーじ
- [6] moyashi, 「デジカメ内部でRubyを動かす狂気!無線LAN内蔵SDカードアダプタPQI Air Cardの間違った使い方」, ひとりぶろぐ, 2012-11-02
- [7] とんすけ, 「FlucardでプログラムとかCGIとか」, とんすけぶろぐ, 2012-04-03