austinbv / dino

Dino is a ruby gem that helps you bootstrap prototyping with an Arduino
MIT License
388 stars 84 forks source link

Safely remove hardware #73

Closed MinasMazar closed 6 years ago

MinasMazar commented 10 years ago

I've noticed if we close a script using dino without calling remove_[digital|analog]_hardware, dino.ino continue sending data over serial connection, even there is no one listening for it. Why not adding a "destructor" to Dino::Board that detach all digital and analog hardware?

vickash commented 10 years ago

Yes, currently you need to manually call Board#remove_digital_hardware or Board#remove_analog_hardware, or as of version 0.12, Board#remove_component, which replaces both.

Take a look at this line: https://github.com/austinbv/dino/blob/0.12.0-wip/examples/ssd/ssd.rb#L14

You could implement something like this in the TxRx::Base class. Trap the signal and send the reset command ("90\n" as of 0.12). Removing the components in Ruby will be unnecessary. When the thread dies, so will the board instance and all the component instances. Sending the reset command will reset the Arduino to defaults and stop it from writing to serial.

I have no idea how cross-platform compatible trapping "SIGINT" is. You might ned to play around.

MinasMazar commented 10 years ago

oh wait. I'have not already seen the revolutionary 0.12 full of beautiful refactoring and enhancement ;) the misbehaviour has disappeared with this new version. I think a trap feature could be implemented only by the user in application logic (the dino scripts).. but I've another potential bug issue: I edited Dino::TxRx::Base#handshake as follow:

def handshake
        puts "HANDSHAKE"
        flush_read
        10.times do
          write Dino::Message.encode(command: 90)
          line = gets(1)
          puts "Line: #{line}"
          if line && line.match(/ACK:/)
            flush_read
            return line.chop.split(/:/)[1]
          end
        end
end

And I get the corresponding output:

HANDSHAKE
Line: K:14
Line: 
Line: A
Line: CK:1
Line: 4
Line: AC
Line: K:14
Line: ACK
Line: :14
Line: ACK:

This happens with a low baud mode. (9600 in this case). Possible solutions are:

line = 3.times.map { gets(1) }.join

in this casse the ouput is matched at first attempt.

I have not followed previus issues of 0.12.0 so i don't know if this is in conflict with other requirements or bonds.

vickash commented 10 years ago

I just tried this about 10 times at 9600 baud with an UNO and then again with a Leonardo. No problem at all. What board, OS and ruby version are you using?

It looks like the call to gets on the serial port inside TxRx::Base#gets is timing out and returning a partial line.

MinasMazar commented 10 years ago

UNO board, linux 3.12.6 (Arch linux) and ruby 2.0.0 (despite travis.yml says..maybe the problem? ) When I build dino-0.12.0.gem I got:

WARNING:  open-ended dependency on serialport (>= 0) is not recommended
  if serialport is semantically versioned, use:
    add_runtime_dependency 'serialport', '~> 0'

serialport gem version used is 1.3.0. I repeated the test (incrementing gets attempts to 20.times ) and the result is the same, but now when the line match 'ACK:' Dino::Board#handshakedoes not return any value for Dino::Board@analog_zero

Line: 
Line: 
Line: A
Line: CK:1
Line: 4
Line: AC
Line: K:14
Line: 
Line: AC
Line: K:14
Line: ACK:
/home/minasmazar/workspace/dino/lib/dino/board.rb:108:in `analog_pin_to_i': undefined method `+' for nil:NilClass (NoMethodError)

This problem disappears with a baud rate >= 38400.

vickash commented 10 years ago

I'm on 2.0.0 as well. So that's not it.

Try replacing the single line in TxRx::Base#gets with this and see what happens:

IO.select([io], nil, nil, timeout) && io.gets("\n")
MinasMazar commented 10 years ago

It has no effect. I've tried different combination of timeouts for IO.select but nothing seems change..

vickash commented 6 years ago

As of 4b575c5 the read thread traps SIGINT and resets the board.