jwhitehorn / pi_piper

Event driven Raspberry Pi GPIO programming in Ruby
BSD 2-Clause "Simplified" License
694 stars 71 forks source link

Trouble with Device or resource busy #30

Open robert2d opened 9 years ago

robert2d commented 9 years ago

Hi I am unable to get the pins to work on the latest version of noobs.

Running File.open("/sys/class/gpio/export", "w") { |f| f.write("7") }

Error Errno::EBUSY: Device or resource busy @ fptr_finalize - /sys/class/gpio/export

Using: https://github.com/robert2d/raspberry-pi-gpio-rails4-control

I have manually run the command via a rails console using rvmsudo bundle exec rails c. I have checked forums and other resources on google and cannot find a solution, so I was hoping somebody could point me(slash my pins :smile:) in the right direction.

Also: Running echo 7 >/sys/class/gpio/unexport seems to free up the pin again but re running the above twice causes the same error again.. (reference: http://squarism.com/2014/09/24/redis-595-timer-states/)

Thanks

bguest commented 9 years ago

Out of curiosity are you running into this problem when you are running the application on the pi or on your desktop / non-pi?

robert2d commented 9 years ago

lol on the Pi of course. I have investigated some more and found that I can get a pin and manipulate it when its stored in the rails console. But as soon as I flush the variable or try to get a new pin I run into the error above.

ClockVapor commented 9 years ago

I had this same issue. Seems like the only solution is to manually release each pin when you're done using it (echo GPIO_NUM > /sys/class/gpio/unexport). I've had no issues since I started doing that.

wrzasa commented 9 years ago

Clearly pi_piper does not clean up after itself, as it should.

I use this workaround:

pins.each do |pin|
  File.open("/sys/class/gpio/unexport", "w") { |f| f.write("#{pin}") }
end

but it obviously should be fixed in the gem.

github0013 commented 9 years ago

https://github.com/jwhitehorn/pi_piper/pull/31 This should fix. What do you guys think?

ClockVapor commented 9 years ago

@github0013 Looks good, but wouldn't it be better if Pin.release was private? I don't know if you should be able to manually release a pin that's allocated to a Pin object. You could get into trouble holding onto a Pin that's been released like that, I imagine.

wrzasa commented 9 years ago

If its private you cannot reliably release a pin. If you loose reference to a pin object you have this pin locked until GC removes the object. Am i right?

ClockVapor commented 9 years ago

Yeah, but there shouldn't be any reason to release a pin that's sensitive to how quickly the GC releases it. Or should there? Maybe I'm just nitpicking.

ClockVapor commented 9 years ago

Nevermind, you're right. There could be multiple programs trading off using the pins or something similar. Carry on, ignore me. :stuck_out_tongue:

github0013 commented 9 years ago

I think there aren't many cases you would use a pin for IN and OUT as your program go. So basically, you won't manually have to release any pins although it is a public method.

Once you set up a pin, you would use it as it is until the program ends. And normally you will be holding the pin object until your program ends (otherwise you can't control the pin). Since you hold on to it, GC won't run the unexport finalizer proc to release unexpectedly.

finalizer will at least release pins used at exit so that the next time you run any programs using the same pin, won't raise the busy exception.

If you have to have a pin IN then later OUT in a program, you can release it by PiPiper::Pin.release(pin_number) and switch it to IN or OUT.

wrzasa commented 9 years ago

I agree. Have only one doubt. Are you sure, that the finalizer will always be called? As I remember, in Java descructor was called only if an object was destroyed by GC, but not when it was destroyed when virtual machine was being shut down. Consequently, it might happen that descrutcor was never called and it was documented. Ruby docs say nothing about it. That leaves my with doubts rather then certainty.

ClockVapor commented 9 years ago

I wrote a test to check this. Seems to consistently clean everything up before exiting the program, but I don't know if anything could affect that.

wrzasa commented 9 years ago

Hard to tell, if doc says nothing...

github0013 commented 9 years ago

JA http://docs.ruby-lang.org/ja/1.9.3/method/ObjectSpace/m/define_finalizer.html EN http://ruby-doc.org/core-1.9.3/ObjectSpace.html#method-c-define_finalizer

EN doc doesn't really say much about define_finalizer whereas JA has more. translated: https://translate.google.co.jp/translate?sl=ja&tl=en&js=y&prev=_t&hl=ja&ie=UTF-8&u=http%3A%2F%2Fdocs.ruby-lang.org%2Fja%2F1.9.3%2Fmethod%2FObjectSpace%2Fm%2Fdefine_finalizer.html&edit-text=&act=url

JA doc talks about exiting or raising exceptions in the finalizer proc. It says they will be ignored. proc の呼び出しで発生した大域脱出(exitや例外)は無視されます。 my translation: global escapes (ex: exit or exceptions) that are called within this proc will be ignored

if you ask me "Are you sure, that the finalizer will always be called?", then I can interpret this as "since all finalizers will be called at least at the exit, bad things(exiting on the main exit or raising errors) need to be ignored."

github0013 commented 9 years ago

https://github.com/jwhitehorn/pi_piper/pull/32 I found at_exit in platform.rb.

If you use Gemfile to require this branch by bundle install --path vendor/bundle, and you cron a job, make sure that you add bundle exec ruby ... in your command.

ex:

yoru_ruby_file.rb

require 'bundler/setup'
require "pi_piper"
...
...

crontab

* * * * * /bin/bash -l -c 'cd  /full/path/to/; bundle exec ruby /full/path/to/yoru_ruby_file.rb'
wrzasa commented 9 years ago

EN doc doesn't really say much about define_finalizer whereas JA has more. translated:

So far for English as discussion language about Ruby...

Thanks for finding this page. It doesn't ensure that finalizer will be called, but giving tempfile as example using it reliably is quite convincing for me. Certainly sufficient for the case of pi_piper pins.

joecabezas commented 9 years ago

How can I make this to work using RVM?, everytime I load a ruby script with pi_piper says: bcm2835_init: Unable to open /dev/mem: Permission denied

wrzasa commented 9 years ago

run as root... I know it is lame but bcm2835 won't work without root privileges... and worse -- /sys interface to GPIO does not require root privileges, but bcm2835 is wiser and so it requires root... lame...

joshkinabrew commented 8 years ago

@joecabezas Try using rvmsudo

i.e. rvmsudo ruby ./my_script.rb

elmatou commented 8 years ago

Should be solved with V1.9.9 update the gem and see. If everything is ok please close the issue

kernelsmith commented 8 years ago

@wrzasa should your code be this? I'm not trying to be an ass, I'm just trying to make sure I'm thinking correctly:

pins.each do |pin| # changed led to pin
  File.open("/sys/class/gpio/unexport", "w") { |f| f.write("#{pin}") }
end

I've just started w/this gem and running a very simple example (which may be poorly written, by me) and I'm getting this error (among others) and googling brought me here. FWIW I am using v1.9.9 on a RPi, broadcom obviously, ruby v2.1.5p273 (2014-11-13)

elmatou commented 8 years ago

@kernelsmith, Still have this issue with 1.9.9 !? It would b possible if you used gpio outside PiPiper after the last boot.

try to reboot and test.

wrzasa commented 8 years ago

@kernelsmith Yes, you are correct: led in my code should be changed to pin. Just corrected this in my previous comment. Thanks!

kernelsmith commented 8 years ago

@wrzasa I'm still getting the error, haven't looked into it much, but as an example: https://gist.github.com/kernelsmith/c7beb8377e558cdb8f12

This is on a fresh install and having done nothing else to the gpio pins whatsoever

wrzasa commented 8 years ago

@kernelsmith There is something strange about the code you show. I don't know why the first usage of pin 22 ends up with the resource busy error if you didn't use the pin after last reboot. The second error is more strange because it shows incorrect path to export file. I don't have Pi running now, but AFAIR instead of: /sys/class/gpio/gpio/direction it should be /sys/class/gpio/direction. But it would not work anyway, because of the way pi_piper is designed: you cannot do more then once watch or after on a single pin... (yes it sucks!). If you want to react on different changes on a single pin you must put it all in a single watch/after/before block. And you cannot create Pin object for a pin you did a watch or after or you will get the 'resource busy' error. Thus the last error on watch would happen anyway if any of the previous usages of the pin succeeded.

Maybe you mixed Pin.new and watch/after calls on a single pin and that's why you get the resource busy error?

You can always monitor files in /sys/class/gpio and check when directories for pins appear. If a pin is already exported (directory for this pin is created in /sys/class/gpio) you will get 'resource busy' error trying to watch or Pin.new on this pin.

zsyed91 commented 8 years ago

@kernelsmith I just took a very quick glance at this.

I found out why /sys/class/gpio/gpio/direction is happening. It should be /sys/class/gpio/gpioPinNumber/direction but something is not setting PinNumber which is why the path look incorrect.

The other part is when calling after or watch, a pin object is automatically allocated. Did you already open pin 22?

I will look into this a bit more myself. I think maybe we can attempt to allow watch to be run multiple times.

zsyed91 commented 8 years ago

@kernelsmith Figured out why we have gpio/gpio/direction, you have a typo here: https://gist.github.com/kernelsmith/c7beb8377e558cdb8f12#file-pi_piper_error-L26

It should be pin: 22 not in: 22 :smile:

wrzasa commented 8 years ago

That's why people found out data validation... Not funny at all, Pin class should validate this in constructor and maybe watch should also do it...

kernelsmith commented 8 years ago

Thanks. Apologies, I'm overseas for a few days so I won't have any meaningful responses/feedback for a week or so

On Feb 20, 2016, at 11:34, Zshawn Syed notifications@github.com wrote:

@kernelsmith Figured out why we have gpio/gpio/direction, you have a typo here: https://gist.github.com/kernelsmith/c7beb8377e558cdb8f12#file-pi_piper_error-L26

It should be pin: 22 not in: 22

— Reply to this email directly or view it on GitHub.

zsyed91 commented 8 years ago

Alright I just tried this on my actual pi and was not able to reproduce your error. However I am using ruby 2.2.1. I know that isn't helpful but I am hoping to at least reproduce this bug somehow.

This is exactly what I tried:

$ rvmsudo irb
require 'pi_piper' # => 1.9.9
include PiPiper

pin4 = PiPiper::Pin.new(:pin => 4, :direction => :out)
#<PiPiper::Pin:0x18b58d8 @pin=4, @direction=:out, @invert=false, @trigger=:both, @pull=:off, @released=false, @last_value=nil, @value=0>

pin4.value
# => 0
pin4.on
# => 1
pin4.off
# => 1

after :pin => 22, :goes => :high do
  puts "pin 22 just went high"
end
#<Thread:0x5808c0@/home/pi/.rvm/gems/ruby-2.2.1/gems/pi_piper-1.9.9/lib/pi_piper.rb:14 sleep>
watsy0007 commented 8 years ago

thanks @joshkinabrew