2009-11-11[n年前へ]
■Rubyシリアル通信用スレッドクラスで簡単なバイナリ受信処理をしてみよう
以前、Rubyでシリアルポート通信(いわゆるRS-232C)を楽に行うためのクラス"ComThread"を作りました(ここが関連ファイルの置き場です)。そのcomThread.rbを使えば、たとえば、COM3で受信した内容をコンソールに出力するだけであれば、このようなコードで動く、というようなものです。
require 'comThread' receiveComThread=ComThread.new({:icomno=>3}) receiveComThread.start({:receive=>true, :receiveMonitor=>true}) sleep 60 receiveComThread.stopこれは、「シリアルポートを使って簡単に各種機器からの情報を取得したり、あるいは操作したりするためのクラス」です。もうひとつ例を挙げれば、「シリアルポートで受信した内容を最前面アプリにキー送信するアプリケーション」くらいであれば、以前書いたように十行程度のコードを書けば「はい、できあがり」という具合に(少なくとも私が良く見るシチュエーションにおいては)割に使いやすいクラスです。
ところで、シリアルポートで送受信を行う機器は多いですが、ものによってはASCII(アスキー)コードでなく、バイナリでデータを送ってくるものもあります。小型の計測器などでは、そんな風にシリアルポート(見かけ上はUSB接続で)経由で出力をバイナリ送信するものも多いかもしれません(もちろん、テキスト送信するものも多いです)。そんな場合でも、簡単なものであれば、comThread.rb でも普通に処理を行うことができます(データが頻繁に大量に送られてくるようなものは扱えません)。
そこで、バイナリデータをシリアルポートに送りつけてくる機器に対応するスクリプトを書いてみましょう。それは、たとえばこんな具合です。
require 'comThread' class Comport def receive(size) rcv=@com.receive ret=nil if rcv!=nil if rcv.length==size aHigh=rcv[0] & 0b00001111 aLow=rcv[1] re+=(aHigh*255+aLow).to_s end end ret end end period=ARGV[0] # time(seconds) Waint 10 # waint to activate teraterm receiveComThread=ComThread.new( {:icomno=>4, :ibaud=>57600}) receiveComThread.start( {:receive=>true, :receiveMonitor=>true, :delimeter=>4}) sleep period receiveComThread.stopこれは「4バイトのデータ列を定期的に出力する機器のデータを(COM4に57600bpsで受信し)パース処理した上で、その結果をテキストに変換しコンソール出力する」というスクリプト例です。
バイナリデータとしては、1バイト目のがハイバイトで、2バイト目がローバイトからなるデータ構成になっていて、さらに、ハイバイトは下位4ビットのみが使われる、というような処理がなされています。
サンプル用に書いたので、本来なら書くべき処理をはしょっています。それでも、数バイト程度のデータが、数秒の時間間隔で送信されるような機器のデータ加工程度の用途であれば、(たまにデータを処理しないで無視してしまうこともあるでしょうが)こんなものでも、(プロトタイピング用途としては)十分使うことができることもあるのではないでしょうか。
ところで、comThread.rbを少し手直ししました。そのため、(今日段階で置いてある)zipファイルは以前作ったものとサンプルソース類となっていて、comThread.rbの方は、今日少し作りなおしたものとなっています。異なるのは、ComThread.start の部分に、delimeter指定が入っていること・メンテナンスがしやすいように内部で使う関数の引数をHash(ハッシュ)で渡すようにした、ということくらいです。とはいえ、そのまま上位互換で使うことができるのではないか、(多分)と思います。動かない場合があれば、メールして頂ければ、時間を作って直しておきます。
ふと気付くと、最近Perlを触っていないような気がします。来週あたりは、Perlでも使って何かしてみることにしましょうか。