brian-armstrong / gpio

Go library to do GPIO on systems with /sys/class/gpio (sysfs)
BSD 3-Clause "New" or "Revised" License
140 stars 50 forks source link

Issues on Pi Zero W #14

Open ghost opened 5 years ago

ghost commented 5 years ago

Hi Brian,

to start, I would like to thank you for providing this library, your work is much appreciated! The approach of using the GPIO sysfs interface and a blocking select() call seems more appropriate to me than polling, as it is done in other GPIO implementations.

I use your lib in a private project, in which I am building an audio box, controllable via web app and also physical buttons, running on a Raspberry Pi Zero W.

However, I experience issues when adding new Pins to a button upon a fresh reboot or with unexported pins (via AddPin() with watcher receiver). The behaviour is reproducible. By extending the error printing in function exportGPIO() for debugging purposes, I could see that writing into the direction file is not working, when the issue occurs:

failed to open gpio 2 direction file for writing open /sys/class/gpio/gpio2/direction: permission denied

Restarting the application again the same way as before, the pin can then be added properly. The same goes for additional subsequent starts of the application. (I ruled out any actual permission issues of the user running the application).

Eventually I figured out that the duration of 10ms between calling exportGPIO() and setDirection() seems to be too short for a Pi Zero. Increasing this duration to 100ms, the issue does not occur anymore. So, I suppose that the Pi Zero is simply too slow in order to prepare the GPIO sysfs interface after exporting the pin and subsequently creating the direction file with proper permissions. So the main issue can be described as a race condition.

My actual issue with the described behaviour is that setDirection() calls os.Exit(1) when os.OpenFile() returns an error. I don't want my service to Exit(1), when the direction can't be set. I would rather handle the error and retry adding the pin. I use supervisord to restart my application a few times until all Pins are added and proper configured, however this seems as an ugly workaround for me.

I propose two possible solutions for the issue.

1.) Quick and dirty: Increase sleep duration between exportGPIO() and setDirection() to 100ms (?). Another approach but in the same direction could be providing the option in the lib to give the desired waiting duration externally via parameter to AddPin().

2.) More elaborate: Remove os.Exit(1) call from setDirection() (and ideally the whole lib) and return the error upstream to the exported function (in this case from setDirection() via exportGPIO() and NewInput() to AddPin(), in order to handle the error in the calling application. In case AddPin() fails, the application can then handle the error properly, i .e. retry adding in this case.

If you need more info, just let me know.

Best regards,

Jens