ruby-serialport icon indicating copy to clipboard operation
ruby-serialport copied to clipboard

#read_timeout= problem

Open atimin opened this issue 14 years ago • 7 comments

Very strange behavior:

irb(main):003:0> sp.read_timeout => 0 irb(main):004:0> sp.read_timeout = 5 => 5 irb(main):005:0> sp.read_timeout => -1 irb(main):006:0> sp.read_timeout = 100 => 100 irb(main):007:0> sp.read_timeout => 100 irb(main):008:0> sp.read_timeout = 101 => 101 irb(main):009:0> sp.read_timeout => 0 Ubuntu 10.04 Ruby 1.8.7

atimin avatar Jul 17 '10 07:07 atimin

flipback: Very strange. Are you just running through a loop? Can someone confirm on another POSIX system, e.g. Mac OS X, and Windows? HGP

hparra avatar Jul 17 '10 21:07 hparra

Could you send me a functional test to duplicate this? Just a small file where I pass in the port address should be fine.

hparra avatar Jul 18 '10 02:07 hparra

confirmed on OS X 10.6.4 w/ 1.0.4

sp = SerialPort.new '/dev/tty.usbserial'

=> #SerialPort:0x10053f7e0

sp.read_timeout

=> 0

sp.read_timeout = 4

=> 4

sp.read_timeout

=> -1

sp.read_timeout= 4

=> 4

sp.read_timeout

=> -1

sp.read_timeout=7

=> 7

sp.read_timeout

=> -1

zeeed avatar Nov 17 '10 23:11 zeeed

I think I see what's happening here. Poor design. Please confirm.

The documentation specifies that you can pass a millisecond value, but the truth is the underlying structure (POSIX anyway) can only receive tenths of a second (deciseconds), so there is some poor arithmetic done internally (strange magic number included). You need to pass in a value >= 100. The value that the ruby method returns is the same exact one you passed in, so it doesn't really tell you anything.

So to document flipback's output...

irb(main):003:0> sp.read_timeout => 0 # default value of timeout, VMIN = 1 & VTIME = 0

irb(main):004:0> sp.read_timeout = 5 => 5 # VMIN = 0 but VTIME = 0 due to poor arithmetic so ... irb(main):005:0> sp.read_timeout => -1 # timeout = -1

irb(main):006:0> sp.read_timeout = 100 => 100 # 100 / 100 = 1 tenth of a second irb(main):007:0> sp.read_timeout => 100 # so it works...

irb(main):008:0> sp.read_timeout = 101 => 101 # ... but ... irb(main):009:0> sp.read_timeout => 0 # I can't explain this!!!

I see AT LEAST two corrections here:

  • read_timeout should return the value that underlying system is actually set to (not what was just passed in)
  • there should be some default behavior for an invalid timeout (exception, retain old value, set lowest valid timeout), but what it's doing now is very wrong IMO.

Open to suggestions since changing either or both these things has the potential to break systems out there.

hparra avatar Nov 18 '10 00:11 hparra

I'm interested in the Windows behavior as well. If anyone can check I would appreciate it, but in looking at the code the millisecond value is passed straight to Windows, so it will be responsible for default behaviors.

hparra avatar Nov 18 '10 00:11 hparra

I can confirm your observations. The value appears to get rounded to deciseconds indeed. I do see a different outcome with my adapter when attempting to set a 101ms timeout.

OS X:

sp = SerialPort.new '/dev/tty.usbserial'
=> #<0x1010004e0>

<0x41bafa0>

zeeed avatar Nov 18 '10 01:11 zeeed

Yes, the magic number with internal arithmetic was 50 - used to round up to the nearest whole decisecond, so 150-249 ms became 200ms. I'm not sure how I feel about this, but changing the return value of the method to be the actual timeout value set would make even more sense because of it.

I'm curious why termios works this way. Seems like a legacy boo boo, or it unrealistic to set such precise timeouts?

hparra avatar Nov 18 '10 23:11 hparra