vsergeev / python-periphery

A pure Python 2/3 library for peripheral I/O (GPIO, LED, PWM, SPI, I2C, MMIO, Serial) in Linux.
MIT License
519 stars 139 forks source link

PWM doesn't wait for udev to apply permissions after export #35

Closed jonasl closed 4 years ago

jonasl commented 4 years ago

After exporting PWM udev will trigger and if rules are set up correctly non-root permissions will be applied. This process isn't synchronous, i.e. it will take some time after export until the sysfs node can be used by non-root users.

gpio.py has retry logic to account for this: https://github.com/vsergeev/python-periphery/blob/master/periphery/gpio.py#L723

pwm.py however does not. The following test case shows this

from periphery import PWM
import time

# Exports the PWM, this succeeds because udev set permissions correctly.
pwm = PWM(0, 0)

# Tries to write to /sys/class/pwm/pwmchip0/pwm0/period
# This fails with:
# "PermissionError: [Errno 13] Permission denied: '/sys/class/pwm/pwmchip0/pwm0/period'"
# even if udev have set permissions correctly.
try:
    pwm.frequency = 1e3
    print('test1: frequency set')
except Exception as e:
    print('test1: failed to set frequency', e)
pwm.close()

# Now add a small delay and try again.
pwm = PWM(0, 0)
time.sleep(0.1)
pwm.frequency = 1e3
print('test2: frequency set')

time.sleep(5)
pwm.close()

Output as non-root:

test1: failed to set frequency [Errno 13] Permission denied: '/sys/class/pwm/pwmchip0/pwm0/period'
test2: frequency set

With suggested fix:

test1: frequency set
test2: frequency set

If, with the suggested fix, there's a real issue with permissions the following is raised in PWM._open:

periphery.pwm.PWMError: [Errno 13] Permission denied: /sys/class/pwm/pwmchip0/pwm0/period