タイムアウト処理


RS232Cのエラー
この間、装置が暴走してしまった。その原因はまだはっきりしないが、一番状況を説明できるのが、RS232Cの読み取りで止まってしまったという可能性だ。GPIBなどでは、長い間読み取りできないと、タイムアウトエラーになるので、そのエラートラップをかけておけばよいが、RS232Cにはデフォルトではタイムアウトがない。また、パリティーぐらいしかチェックしていないので、通信ミスでうまく命令が伝わらなくても、それに気づかないで、読み取ろうとしていつまでもデータが戻ってこない。そうなると、その部分でずっとプログラムが止まってしまう。 それを防止するために、RS232Cでもtime outができるように、読み込みのmethodをこんなふうにしてみた。

def read()
  @rs.write(sprintf("L\x0d\x0a"))
  t=Thread::start{@v=@rs.gets("\x0d\x0a").to_f}
  t0=Time::now
  while Time::now < t0+1
    return @v unless t.alive?
    sleep 0.01
  end
  t.kill
  print "rs232c timeout!\n"
  @v=-1.0
  return @v
end

もっとシンプルに書ける気がするが、読み取りはスレッドにまかせて、それが終了していたらその値を返して、それがいつまでも終わらなかったら、スレッドを殺すという感じである。 これで、RS232Cのエラーは無くなるはずだが、これが本当の原因なのかはまだはっきりしないので、他の部分も調べないと。

2008/11/30追記 timeoutのライブラリもあるようで、

require 'timeout'
def read()
  @rs.write(sprintf("L\x0d\x0a"))
  timeout(1){
    return @rs.gets("\x0d\x0a").to_f
  }
  rescue TimeoutError
    return -1.0
  end
end

てな感じで良いのかも。