Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't Require Gem on RPi 4 #22

Open
aaronmiler opened this issue Aug 19, 2020 · 9 comments
Open

Can't Require Gem on RPi 4 #22

aaronmiler opened this issue Aug 19, 2020 · 9 comments

Comments

@aaronmiler
Copy link

I get a load error on a Raspberry Pi 4B for version 0.5.0. Version 0.4.0 loads without issue, here's the stack trace

I see the Readme mentions Ruby 2.0.0 as the highest version tested, but on the Pi4, 2.4 is the lowest version I could easily install with rbenv.

irb(main):001:0> require 'rpi_gpio'
LoadError: libruby.so.2.7: cannot open shared object file: No such file or directory - /home/pi/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rpi_gpio-0.5.0/lib/rpi_gpio/rpi_gpio.so
	from /home/pi/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rpi_gpio-0.5.0/lib/rpi_gpio.rb:1:in `require'
	from /home/pi/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rpi_gpio-0.5.0/lib/rpi_gpio.rb:1:in `<top (required)>'
	from (irb):1:in `require'
	from (irb):1
        [ bundler stack trace continues ]

lib/rpi_gpio/rpi_gpio.so does exist on my machine. I also tried using the code from #20, but get the RuntimeError: this gem can only be run on a Raspberry Pi.

Happy to perform any debugging steps on my machine

@mikekreuzer
Copy link

Same error, Pi Model 2B v1.1, Ruby 2.5 -- 2.5 being what I got with apt-get install ruby-full, and even that's in "security maintenance phase (will EOL soon!)"

@jamoore5
Copy link

Same on on Pi Model 3B+ with ruby 2.6.6

pi@raspberrypi:~ $ irb
irb(main):001:0> require 'rpi_gpio'
Traceback (most recent call last):
       10: from /home/pi/.rbenv/versions/2.6.6/bin/irb:23:in `<main>'
        9: from /home/pi/.rbenv/versions/2.6.6/bin/irb:23:in `load'
        8: from /home/pi/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
        7: from (irb):1
        6: from /home/pi/.rbenv/versions/2.6.6/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:34:in `require'
        5: from /home/pi/.rbenv/versions/2.6.6/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:130:in `rescue in require'
        4: from /home/pi/.rbenv/versions/2.6.6/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:130:in `require'
        3: from /home/pi/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rpi_gpio-0.5.0/lib/rpi_gpio.rb:1:in `<top (required)>'
        2: from /home/pi/.rbenv/versions/2.6.6/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
        1: from /home/pi/.rbenv/versions/2.6.6/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:54:in `require'
LoadError (libruby.so.2.7: cannot open shared object file: No such file or directory - /home/pi/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rpi_gpio-0.5.0/lib/rpi_gpio/rpi_gpio.so)

@mbegley
Copy link

mbegley commented Nov 30, 2020

I am seeing the same issue, and have a janky workaround. I'm going to try to improve on it but I'm putting it out there in case it might help someone immediately, and to move the conversation along.

Essentially, c_gpio.c, setup() sets up the memory map between the GPIO device and a block of memory. The function tries to set this up in two ways, the first if it has permissions to read from /dev/gpiomem, and the second if it does not.

I haven't been able to get get the first mapping working yet, because I don't have permission as a user to read from this device. I think I need to give ruby setuid root permissions to do this, and I haven't taken that step yet. Instead, I've gotten the second code path to work, which does require ruby to be run as root.

In this case, the IO memory base address, or peri_base, isn't getting determined properly by setup.c - the code is evaluating it to be zero and the code is bailing with this call:

   if (!peri_base)
      return SETUP_NOT_RPI_FAIL;

peri_base on the raspberry pi 4 needs to be 0xFE000000. So in the #define's I set this based on the CPU type:

#define BCM2711_PERI_BASE_DEFAULT   0xFE000000

Later on, there are two attempts to set peri_base, again, based on permissions. In the first attempt, it attempts to read from /proc/device-tree/soc/ranges and computes the value based on the contents of that device file. I don't yet understand the computation, so for now I've simply replaced the line that computes peri_base with one that sets peri_base to this value:

peri_base = BCM2711_PERI_BASE_DEFAULT;

In the second attempt, which tries to determine peri_base based on the cpu type by reading /proc/cpuinfo, I've added an elseif based on the CPU type BCM2711:

    else if (strcmp(hardware, "BCM2711")) {
        // pi 4 hardware
        peri_base = BCM2711_PERI_BASE_DEFAULT;
        found = 1;

Now, if I build this code and copy the resulting shared library into place, and run my test code as root, I'm able to read and write to the GPIO pins.

With this code deployed on my Paspberry Pi 4, I'm able to toggle an LED connected to board pin 11 with this bit of ruby:

require 'rpi_gpio'

RPi::GPIO.set_numbering :board
RPi::GPIO.setup 11, :as => :output

while true do
  RPi::GPIO.set_low 11
  sleep 1
  RPi::GPIO.set_high 11
  sleep 1
end

Anyway, I've attached my modified c_gpio.c (as a txt file) for anyone interested to copy into their source tree. I doubt it'll work on anything but a pi 4 right now, but it's a start.

c_gpio.c.txt

@1cf2
Copy link

1cf2 commented Feb 10, 2021

Any update?
I have exactly same issue on pi4 and I don't know how to rebuild the gem locally with the updated c_gpio.c.txt. Thanks @mbegley

@repent
Copy link

repent commented Feb 20, 2021

Same issue on a Pi 3B, with Ruby 3.0.0 and 2.5.1. Before finding this thread I'd tried rbenv, RVM and a clean install of Raspbian.

@mbegley
Copy link

mbegley commented Feb 20, 2021

Any update?
I have exactly same issue on pi4 and I don't know how to rebuild the gem locally with the updated c_gpio.c.txt. Thanks @mbegley

These may not be comprehensive instructions, but they may be enough to muddle through:

  1. clone down a copy of the rpi_gpio github repo
  2. in the repo directory tree, navigate to ./ext/rpi_gpio/
  3. in that directory, make a copy of the file c_gpio.c so you can easily roll back.
  4. edit g_gpio using your favorite editor, as described above. Assuming the code hasn't been updated since I made this port, youcan likely substitute in the contents of c_gpio.c.text that's attached to my earlier comment.
  5. if you don't have a Makefile yet, generate it by running: ruby extconf.rb
  6. build the shared library my typing: make
  7. If the build completes successfully, then it will have created a new shared library: 'rpi_gpio.so'. You should be able to copy the new shared library into place so your system can use it. Be sure to make a copy of the original shared library before you move it, again, for easier rollback if there are problems.

I updated it in two places:

/usr/local/lib/ruby/gems/2.7.0/gems/rpi_gpio-0.5.0/lib/rpi_gpio
and
~/.rvm/gems/ruby-2.7.2/gems/rpi_gpio-0.5.0/lib/rpi_gpio/

Now, check to see if your system works and you're able to talk to the GPIO!

Anyway, this is the steps I followed a couple months ago, based on memory. I hope it's clear (and accurate) enough - let me know if you have any issues or need clarifications.

Obviously, this should only be done on an as-needed basis, and should be considered a particularly ugly bandaid. I hope it can help someone out until a proper fix can be rolled out.

@repent
Copy link

repent commented Feb 24, 2021

@mbegley "I haven't been able to get get the first mapping working yet, because I don't have permission as a user to read from this device. I think I need to give ruby setuid root permissions to do this, and I haven't taken that step yet. Instead, I've gotten the second code path to work, which does require ruby to be run as root."

Sorry if this is a dumb suggestion, but your user is a member of the gpio group, right?

@mbegley
Copy link

mbegley commented Feb 24, 2021

Not a dumb suggestion, because the user wasn't a member of the group. I just added it, and I still get an error unless I'm running as root. :-/

I'm probably doing something dumb.

EDIT - Still not working, but when I su to the user pi (which is also in the gpio group, I'm able to read from /dev/gpiomem, but when I try that from my user account even after I added it to the gpio group it still fails.

So there's probably something I need to figure out with regards to group membership & permissions, once I have a moment this evening.

@rojosinalma
Copy link

rojosinalma commented Mar 11, 2021

The problem itself is that the library Ruby expects should be in lib/rpi_gpio/rpi_gpio.so and for some reason is not there.

This file is created at gem installation time (or when manual compilation happens), for some reason, your compilation process either has an error or the file is just not being created, that's why Ruby then complains that it can't find it.

I'm not sure the solution is indeed updating the start values for any given BCM, but the fact that your current BCM (i.e: Pi4) is not supported could be the issue. I highly doubt this is the main reason, but since I haven't really tested it I'm leaving it as an option.

I did checkout to the only open PR right now (#20). Recompiled the lib and replaced the whole gem folder where it was installed.

If all of this sounds weird to you, the tl;dr is:

  1. Clone this repo
  2. Checkout to the PR Update to raspberry-gpio-python version 0.7. #20
  3. Try recompiling the library:
    you need to manually install rake and rake-compiler
rake clean
rake compile
  1. Place the rpi_gpio.so inside the lib/rpi_gpio of where your gem is installed. (That will change depending if you use rvm, rbenv, asdf, etc)

The compile process should output a fiile: lib/rpi_gpio/rpi_gpio.so. If this file doesn't exist, then you need to debug why the compilation fails, that I leave to you.

If you solve that or manage by any other means to get that library there, this problem should be gone.

Note: You may also just cd into the folder where your gem is already installed, but since a lot of people use different version managers, I think the generic way is to just clone the repo. Anyway, if you know your version manager and where it install the gems, you can skip the cloning step.

To know where any given gem is installed use gem which <gem_name>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants