hirax.net::inside out::2009年11月11日

最新記事(inside out)へ  |   年と月を指定して記事を読む(クリック!)

2009年10月 を読む << 2009年11月 を読む >> 2009年12月 を読む

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でも使って何かしてみることにしましょうか。