Ruby + Windows + Timeouts + SerialPorts won't

2019-07-19 17:03发布

问题:

I am developing a multiplatform Ruby program that is supposed to connect via USB to a serial device. First I was using the serialport gem (1.0.4), but then I ran into some strange problems and had to drop it. I then proceeded to communicate via Ruby's IO class, as follows:

@port = IO.new IO.sysopen(path, mode), mode

Communication via syswrite and sysread is perfect both in Linux as Windows.

With the communication done, I tried setting up timeouts so that the program won't hang if any desync occurs. All done on the Linux side with timeout.rb, but Windows won't get me control of the interpreter again after calling any IO read method (sysread, getc, gets, getbyte... I tried them all!).

I experimented with Terminator, but it wouldn't even run, throwing argument exceptions instead of timing out -- even in Linux!:

require 'terminator'
  Terminator.terminate 2 do
  sleep 4
end

produces:

/var/lib/gems/1.9.1/gems/terminator-0.4.4/lib/terminator.rb:164: Use RbConfig instead of obsolete and deprecated Config.
ArgumentError: wrong number of arguments (1 for 0)
from /var/lib/gems/1.9.1/gems/terminator-0.4.4/lib/terminator.rb:127:in `block in terminate'
from (irb):12:in `call'
from (irb):12:in `sleep'
from (irb):12:in `block in irb_binding'
from /var/lib/gems/1.9.1/gems/terminator-0.4.4/lib/terminator.rb:134:in `call'
from /var/lib/gems/1.9.1/gems/terminator-0.4.4/lib/terminator.rb:134:in `terminate'
from (irb):11
from /usr/bin/irb:12:in `<main>'

As SystemTimer relies on UNIX signals and doesn't work on Windows (it simply wraps timeout.rb), I am stuck with a multiplatform program that would just eternally hang when running on Windows, although just fine on Linux.

Is there any way I could set timeouts on serial port reading on Windows? Perhaps a win32api call?

Thank you for your time. :)

Edit:

I believe I found a way around the problem, although it really stinks.

instead of

Timeout::timeout 0.5 do
  gets
end

I tried

begin
  Timeout::timeout 0.5 do
    Thread.new do
      gets
    end.join
  end
rescue
  "Expired :)"
end

and it seems to be fine on IRB.

I'm going to implement and test it and then I'll post the results here. :)

However, any prettier solution is most than welcome!