2014年 07月 25日

自作 USB CW キーイングデバイスを作る

去年AVR で USB 接続の PC キーヤーを作るということをやったのだけど、結局ちゃんと形にはせず放置してしまっていた。最近なんとなく自分の中で PC キーイングの機運が高まってきたので、まじめに安定したものを作ろうと頑張って、ある程度成果がでてきた。

当然似たようなデバイスは既にあるので、改めて作る必要はないんだけど、自分で作れそうなものは、一回ぐらい自分で作りたいものですね。

ハードウェア

安定して動くように試行錯誤した結果、USB のデータラインに 100pF のパスコン (ノイズ対策)、リセットピンを外部プルアップ (USB のデータラインに電流が多く流れて、リセットされやすくなるので)、USB ラインのツェナーダイオードをちゃんと計ってから使う、18MHz の水晶 (CRCチェック用) とかになった。あとはもともとと同じだと思う。

ファームウェア

USB まわりを割と丁寧に実装しなおした。UI との整合性をとるため、機能をちょいちょい足している。usbFunctionWrite で -1 を返すと STALL の意味になるとか、V-USB のドキュメントをよく読んだほうがいい。

ソフトウェア

ドライバをカーネルレベルで書くのはデバッグが大変で嫌なので、最初から libusb 関係のものを使うことしか考えてなかった。最初は Chrome App から直接 chrome.usb で扱おうとしたのだが、いろいろあってやめて、ruby + libusb + em-websocket で WebSocket サーバを書いて中継している。

libusb の同期的インターフェイスは、実際のところ非同期インターフェイスのラッパーになっており、マルチスレッド環境で使うとレースコンディションが発生することがある。libusb のドキュメントにいろいろ書いてあるが、面倒なので ruby 側で mutex のロックをかけるようにしたら解決したので深く追ってない。

また、ホットプラグ対応もなんか刺さったりしてつらいのでやめて、デバイスが接続されていないときは定期的にポーリングするというクソっぽいけど正確に動く実装にした。

インターフェイス

そして WebSocket で通信するページをペライチで作って試してている。全部込みで動画にしてみた。

今後

まずは無闇にストールしたり、刺さったりしないという基本的な部分で安定することを目指して頑張った。「もう無理では……」と思ったこともあったけど、いつのまにか結構安定した。ただ、実際の運用まで行ってないので、インターフェアにどれぐらい耐性があるかはわかってない。試験電波を出してオシロで信号ラインを見た感じだと大丈夫そうだけど、よくわからない。

手持ちのユニバーサル基板に組んだので、作ってみたらケースを含めちょっと大きくなってしまった。内容的にはたいしたことがないので、フリスクケースに収まるような基板を作ってみたい。

あとは、ログツールとの連携をしたいと思っているけど、ログツールを作りなおしているので、まだまだ先になりそう。

MorseRunner

ただ聴くだけのモールス練習に若干飽きてきて、MorseRunner というのを試してみたら、おもしろかった。Mac でも homebrew の wine で普通に動いてくれる。

コンテストを想定した練習ソフトみたいな感じになっていて、F1 で CQ を出して、呼んでくる局のコールサインを聴きとって入力し、RET を押すと、自動的に相手局にコンテストナンバーが送られ、相手局が返してくるコンテストナンバーを聴きとって入力したら1局終わり。

聴きとれないときは F7 押したりするともう一度打ってくれたりする。結構実際に交信しているみたいで楽しい。

以下の画像は HST モードで1時間やってみたもの。ぶっちゃけ15分ぐらいから辛くて早く終わってほしい感じになる。普段は 10分のシングルコールかパイルアップで遊んでる。シングルコールはあんまり頭使わないので、だんだん眠くなるけど、聴きとれるというのが楽しい。パイルアップは、とにかく2文字とって訊き返すというのが大事でおもしろい。

シングルコールがただ聴くだけだから一番局数は稼げる?と思うけど、自分の場合 30wpm でやると、だいたい10分で30局超えたらいいみたいな感じだった。しかし S と H の区別がはっきりつけられないので厳しい気持ちになることがある。

デジタル一眼レフ (EOS) をウェブカメラ的にとして使う

スクリーンキャストとカメラの同時録画 の動画を撮ったときは Mac 内蔵のカメラを使ったので、自由にカメラを動かせず難儀した。ウェブカメラが欲しいなーと思ったけど、よく考えたら優秀なカメラが既にあるので、利用できないかと考えた。

結論からいうと、直接ウェブカメラとして使うことは簡単にはできない。なので、

  • EOS Utility でライブビュー撮影モードにする (PC にカメラの画像がリアルタイムに反映される)
  • それをスクリーンキャスト用のツールでカメラデバイスにする

という方法をとる必要がある。


スクリーンキャストとカメラの同時録画をしたいというだけなら、単に EOS Utility のウィンドウを直接録画したらいいので、簡単。ただ、どうしてもちょっと映像が遅れるので、それを許容できる場合にだけ使える。

ハルロック (1)

ハルロック(1) (モーニング KC) - 西餅

西餅

5.0 / 5.0

うっかりウェブに公開されているやつを読んでしまったら面白かったので買ってしまった。最近電子工作にハマってるのでタイムリーだった。

題材が電子工作で、そこらかしこに流行りワードがちらばっているけど、そういうのよりは主人公の女子大生が狂ってるのを楽しむ感じで、ゲラゲラ笑える。


なんともいえないのは、最初おじさん先生から PIC が出てくるんだけど、卒業すると登場するのが Arduino やら Raspberry Pi やら AVR になっていくので愉快な感じ。

自分も主人公ほどではないにせよ、小さいときに分解魔だったので (分解したからといって原理がわかるわけではない) そのへんも共感できた。

2014年 07月 19日

Mac で外部カメラとスクリーン録画を同時にやる (カメラ+スクリーンキャスト)

前までできなかったと思うんだけど、比較的簡単にできるようになっていた。

QuickTime Player に「ファイル」→「新規画面収録」というのがあり、これを使うと音声入力を含めてスクリーンキャストを録画できる。

外部カメラも同時にとる場合は「ファイル」→「新規ムービー収録」を選択するとカメラの状態が画面にでるようになる。この状態でも「新規画面収録」を行うことができ、カメラとスクリーンを同時に録画可能になっている。

収録しおわったら「編集」→「トリム」で不要な前後も簡単に削除できるので、あせって録画する必要はない。

試しに録画したもの


一つ欠点があって、できるあがるファイルが .mov なので、どっかにアップロードするなら

ffmpeg -i input.mov output.mp4

とか適当にしたほうがいいっぽい。

2014年 07月 17日

結論: chrome.usb は使えない

直近の Mac OS X Mavericks アップデートの直後あたりから (これが直接の原因かはわからないけど)、例え HID デバイスではなくても chrome.usb を単体で動かすことができなくなった。

今まではデバイス接続後に Chrome 全体を再起動することで openDevice が成功するという挙動だったのだが、今ではデバイス接続後に他の libusb を使ったプログラムを走らせて一旦 device を OS に認識させ、そのプログラムを終了し Chrome を起動する、という手順が必要になった。

つまり単体で再起動を繰替えしたりしてなんとか動かすということが不可能になり外部プログラムへ依存が必要になった。Chrome はどのようなコンテキストでも外部プログラムを実行することはできないので、打つ手はなくなった。

chromium のイシュートラッカーを usb 関係で検索してみると


あたりが関係していそう。 Canary を入れたくないので 35.0.1916.153 でしか試してない。stable で動かないものは「ない」と同じ。


このほか以下のようなバグがありそう

  • コントロール転送で8バイト未満をデバイスから返すと、データが化ける (こちらから送ったリクエストのバイナリ列になってしまう。謎)
  • インタラプト転送でずっとレスポンスしないでいると、デバイスにアクセスできなくなる。定期的に必ずなにか返答しないとだめ。

それとバグではないが、コントロール転送を out する場合、何も data を送りたくなくても、data : new ArrayBuffer(0) を渡さないと実行されない。罠。

2014年 07月 14日

秩父





関連エントリー (画像)

2014年 07月 12日

Chrome App で USB デバイス (AVR V-USB) にアクセスする

Chrome App は、chrome.usb という API を通じて低レベルなUSBデバイスドライバをJavaScriptで書くことが可能になっている。chrome.usb は libusb 相当の API を提供している。

つまり、自分で作った USB デバイスと通信して、ブラウザ(といっても App だけど)からそれのI/Oを操作でき、LED を HTML+CSS+JS で UI を作って操作したり、ミサイルも JavaScript で飛ばせる。

そこで、AVR (200円ぐらいのワンチップマイコン) とその上で動くソフトウェアUSB実装である V-USB でカスタムデバイスを作成し、Chrome App から呼んでみた。

デバイス側

だいぶ前に実験した結果、Mac OS においては HID デバイスとしてUSBデバイスを作ると OS の管理下におかれ、libusb などからアクセスする手段が殆どなくなってしまうことがわかっていた。libhid 的なものがあればいいのだけれど、すくなくともまともにメンテされているのは当時見当らなかったので諦めた。

今回は教訓をいかして最初からHIDではないカスタムクラスのUSBデバイスにすることとした。

デバイス側の実装及び V-USB の設定ファイルは以下の通り

AVR ATmega168、16MHz で動かして試している。

HID にしなくともデバイス側の実装はあまり大差ない。

USB_CFG_DEVICE_CLASS と USB_CFG_INTERFACE_CLASS を 0xff (vendor) にしておかないと claim_interface に失敗したので忘れずに変えておく必要がありそう。

ホスト側

ホスト側では、まず libusb + ruby における実装を書いて試した。

interrupt_transfer はブロックをとれるみたいなのだが、うまく呼ばれなかったので深追いせず普通に呼んでいる。

libusb を使うにしても USB のプロトコルの知識が必要になるのが面倒


そして Chrome App の実装も書いた。主な実装箇所は以下

最初どうしても openDevice が成功せず途方にくれていたが、Chrome 自体を再起動することで成功するようになった。諦めなくてよかった。

ちなみに公式?にある usb のサンプルは API が最新に追従していないので参考にしないほうがいい。

USB プロトコルまわり

知っておかなければいけないこと

  • USB は基本的に片方向の通信
    • CONTROL 転送は1度のトランザクションが双方向で Stop-and-wait ARQ みたいな感じになってる
    • 必ずホストから先に通信が始まる (つまりデバイス側からデータを push することはできない)
  • USB には転送方法がいくつかある・それぞれ再送があったりなかったりするので必要に応じて使う
    • CONTROL 転送
    • ISOCHRONOUS 転送
    • BULK 転送
    • INTERRUPT 転送


参照