2
votes

I have a GPIO pin, that value of which is represented in the sysfs node /sys/class/gpio/gpioXXXX/value) and I want to detect a change to the value of this GPIO pin. According to the sysfs documentation you should use poll(2) or select(2) for this.

However, both poll and message only seems to be available as a system calls and not from bash. Is there some way to use to get triggered by a state change of the GPIO pin functionality from a bash script?

My intention is to not have (semi-)busy waiting or userland polling. I would also like to simply do this from bash without having to dip into another language. I don't plan to stick with bash throughout the project, but I do want to use it for this very first version. Writing a simple C program to be called from bash for just this is a possibility, but before doing that, I would like to know if I'm not missing something.

1
Short form: You're not missing something; poll() isn't directly available without using external software (or writing a loadable module for bash adding an additional built-in command).Charles Duffy
...that said, if performance is a primary goal, I might suggest that you might consider dropping bash. It's certainly possible to write much more efficient shell scripts than most people do (and there are certainly much faster shells than bash), but there's still an upper limit on how performant they'll ever be, and that upper limit is still waaaay below the point where worrying about what kind of interrupt is in use is relevant.Charles Duffy
I don't have advice on how to use poll(), but if this gpio value is visible at the filesystem level, might tail -F send the change to stdout? If so, a super simple solution like this might do.ghoti
If what you want is "a way to monitor a file for changes" that isn't specific to gpio, then what you get is a completely different answer focused around inotify-tools. Is the question gpio-specific, or is it not?Charles Duffy
Absolutely does make a difference. Even poll() doesn't work for GPIO without non-default flags.Charles Duffy

1 Answers

3
votes

Yes, you'll need a C or Python helper -- and you might think about abandoning bash for this project entirely.

See this gist for an implementation of such a helper (named "wfi", "watch-for-interrupt", modified from a Raspberry Pi StackExchange question's answer.


That said:

If you want to (semi-)efficiently have a shell script monitor for a GPIO signal change, you'll want to have a C helper that uses poll() and writes to stdout whenever a noteworthy change occurs. Given that, you can then write a shell loop akin to the following:

while IFS= read -r event; do
  echo "Processing $event"
done < <(wfi /sys/class/gpio/gpioXXXX/value)

Using process substitution in this way ensures that the startup cost for your monitor-gpio-signal helper is paid only once. Note some caveats:

  • Particularly if anything inside the body of your loop calls an external command (rather than relying on shell builtins alone), this is still going to be much slower than using a program written in C, Go or even an otherwise-relatively-slow language such as Python.

  • If the shell script isn't ready to receive a write, that write may block for an indefinite amount of time. A tool such as pv may be useful to add a buffer to your pipeline:

    done < <(wfi "name" | pv -q -B 1M)
    

    ...for instance, will establish a 1MB buffer.