RubyでIOを使いたい(シリアルポート編)

さて、先日の
http://d.hatena.ne.jp/xibbar/20110405#1302101791
の記事はソースはCで作ったのですが、
Rubyでやりたくなりますよね。
だって、irbでIOの制御とかかっこよすぎです。(ホントか?)
というわけで、Rubyで書いてみました。
まず、/usr/include/asm-generic/ioctls.h の
定数がいくつか重要なので、メモっておきます。

#define TIOCM_LE        0x001
#define TIOCM_DTR       0x002
#define TIOCM_RTS       0x004
#define TIOCM_ST        0x008
#define TIOCM_SR        0x010
#define TIOCM_CTS       0x020
#define TIOCM_CAR       0x040
#define TIOCM_RNG       0x080
#define TIOCM_DSR       0x100
#define TIOCM_CD        TIOCM_CAR
#define TIOCM_RI        TIOCM_RNG

こんな感じで定義されています。
あと、ioctlのTIOCMGETも必要ですね。
/usr/include/asm-generic/ioctls.h
で定義されています。

#define TIOCMGET	0x5415

これらを全部Rubyの中に書いちゃいましょう。

#!/usr/bin/env ruby
TIOCM_LE =0x001
TIOCM_DTR=0x002
TIOCM_RTS=0x004
TIOCM_ST =0x008
TIOCM_SR =0x010
TIOCM_CTS=0x020
TIOCM_CAR=0x040
TIOCM_RNG=0x080
TIOCM_DSR=0x100
TIOCM_CD =TIOCM_CAR
TIOCM_RI =TIOCM_RNG
TIOCMGET =0x5415
DEVICE="/dev/ttyUSB0"
fh=open(DEVICE,"r")
ret=""
loop do
  fh.ioctl(TIOCMGET,ret)
  lsstat=ret.unpack("S")[0]
  print (lsstat & TIOCM_CTS >0) ? " CTS on  " : " CTS off "
  print (lsstat & TIOCM_CD  >0) ? " DCD on  " : " DCD off "
  print (lsstat & TIOCM_DSR >0) ? " DSR on  " : " DSR off "
  puts  (lsstat & TIOCM_RI  >0) ? " RI  on  " : " RI  off "
  sleep(3);
end

sudo ruby serial_test.rb
とかってやって実行してみると、

$ sudo ruby serial_test.rb 
 CTS on   DCD on   DSR on   RI  on  
 CTS on   DCD on   DSR on   RI  on  
 CTS on   DCD on   DSR off  RI  on  
 CTS on   DCD off  DSR off  RI  on  
 CTS on   DCD off  DSR off  RI  off 
 CTS off  DCD off  DSR off  RI  off 

こんな感じに値が得られます。
Cのソースとの長さの違いには驚きますが、
まあいいでしょう。用途が全然違いますし。
とりあえず、入力を取ることはできたのですが、
電源を別に用意しなければならないのは超めんどくさいです。
電池でもなんでもいいんですけど、
別で用意するのは面倒です。
USBは5V電源が入っているので、
これを流用できたらレギュレータで3.3Vぐらいに落として
使えるのになぁと思いました。