hybridgroup / rubyserial

FFI Ruby library for RS-232 serial port communication
https://rubygems.org/gems/rubyserial
Other
154 stars 27 forks source link

Serial doesn't play nice with File on Win8 #21

Closed bfoz closed 9 years ago

bfoz commented 9 years ago

I'm working on a simple script to send a data file to a microcontroller and then display whatever the micro sends back. The current test-firmware simply echoes every byte that it gets over the UART, but ultimately it's supposed to process the bytes and return the results.

It seems that if I open the serial port before opening the data file, the port gets hung up. But, if I read the file into memory, and close it, before opening the port, everything works fine.

I'm probably doing something wrong here, but I'm not seeing it. Any ideas?

This is the script that doesn't work...

require 'rubyserial'

puts "Hello world"

serialport = Serial.new 'COM4', 125000

Thread.new do
    loop { printf("%c", serialport.read(1)) }
end

File.open('data/sim-data-01.txt') {|f|}

5.times { serialport.write('a') }   # This should be echoed by the micro

loop do 
end

But, this version works just fine...

require 'rubyserial'

puts "Hello world"

File.open('data/sim-data-01.txt') {|f|}

serialport = Serial.new 'COM4', 125000

Thread.new do
    loop { printf("%c", serialport.read(1)) }
end

5.times { serialport.write('a') }   # This should be echoed by the micro

loop do
end

The only difference between the two is the location of the call to File.open.

Here's the output of ruby -v: ruby 2.1.5p273 (2014-11-13 revision 48405) [x64-mingw32]

zankich commented 9 years ago

@bfoz That's strange behavior, the only thing I can think of is the

Thread.new do
    loop { printf("%c", serialport.read(1)) }
end

is spinning out of control and locking up the ruby thread. Maybe you can add a sleep for a few milliseconds and that will fix it?

bfoz commented 9 years ago

You might be right, because this works...

require 'rubyserial'
require 'pp'

puts "Hello world"

serialport = Serial.new 'COM4', 1250000

File.open('data/sim-data-01.txt') {|f|}

5.times { serialport.write('a') }   # This should be echoed by the micro
pp serialport.read(5)

loop do
end

Is there any way to do a blocking read?

zankich commented 9 years ago

@bfoz You could do something like this

l = 5
data = ""
while l > 0 do
  ret = serialport.read(l)
  data += ret
  l -= ret.length
end

That will guarantee that you read 5 bytes and keep trying until you get it

bfoz commented 9 years ago

Thanks. That's essentially what I've done, but I was hoping for something less reliant on polling.

zankich commented 9 years ago

@bfoz yeah currently the implementation is very much centered around having non blocking io operations. Blocking io behavior could be something to add in the future.