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

14 25 sysfs permissions #26

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 16 additions & 7 deletions gpio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
__version__ = '1.0.0'

from threading import Lock
from time import sleep, time
try:
from collections.abc import Iterable
except ImportError:
Expand All @@ -16,7 +17,9 @@
GPIO_ROOT = '/sys/class/gpio'
GPIO_EXPORT = os.path.join(GPIO_ROOT, 'export')
GPIO_UNEXPORT = os.path.join(GPIO_ROOT, 'unexport')
FMODE = 'w+' # w+ overwrites and truncates existing files
FMODE_STR_WO = 'w' # /sys/class/gpio/export is not readable, even by root
FMODE_STR_RW = 'w+' # w+ overwrites and truncates existing files
FMODE_BIN_RW = 'wb+' # Using unbuffered binary IO is ~ 3x faster than text
IN, OUT = 'in', 'out'
LOW, HIGH = 0, 1

Expand Down Expand Up @@ -46,12 +49,18 @@ def __init__(self, pin, direction=None, initial=LOW, active_low=None):

if not os.path.exists(self.root):
with _export_lock:
with open(GPIO_EXPORT, FMODE) as f:
with open(GPIO_EXPORT, FMODE_STR_WO) as f:
f.write(str(self.pin))
f.flush()
gpio_gid = os.stat(GPIO_ROOT).st_gid
value_path = os.path.join(self.root, 'value')
start = time()
# give udev a moment to update the group of newly created files
while os.stat(value_path).st_gid != gpio_gid and time() - start < .5:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should you throw some kind of error if this ISN'T true after the loop?

sleep(.01)

# Using unbuffered binary IO is ~ 3x faster than text
self.value = open(os.path.join(self.root, 'value'), 'wb+', buffering=0)
self.value = open(os.path.join(self.root, 'value'), FMODE_BIN_RW, buffering=0)

# I hate manually calling .setup()!
self.setup(direction, initial, active_low)
Expand Down Expand Up @@ -100,7 +109,7 @@ def get_direction(self):
Returns:
str: "in" or "out"
'''
with open(os.path.join(self.root, 'direction'), FMODE) as f:
with open(os.path.join(self.root, 'direction'), FMODE_STR_RW) as f:
return f.read().strip()

def set_direction(self, mode):
Expand All @@ -112,7 +121,7 @@ def set_direction(self, mode):
if mode not in (IN, OUT, LOW, HIGH):
raise ValueError("Unsupported pin mode {}".format(mode))

with open(os.path.join(self.root, 'direction'), FMODE) as f:
with open(os.path.join(self.root, 'direction'), FMODE_STR_RW) as f:
f.write(str(mode))
f.flush()

Expand All @@ -125,7 +134,7 @@ def set_active_low(self, active_low):
if not isinstance(active_low, bool):
raise ValueError("active_low must be True or False")

with open(os.path.join(self.root, 'active_low'), FMODE) as f:
with open(os.path.join(self.root, 'active_low'), FMODE_STR_RW) as f:
f.write('1' if active_low else '0')
f.flush()

Expand Down Expand Up @@ -168,7 +177,7 @@ def cleanup(self):

if os.path.exists(self.root):
with _export_lock:
with open(GPIO_UNEXPORT, FMODE) as f:
with open(GPIO_UNEXPORT, FMODE_STR_WO) as f:
f.write(str(self.pin))
f.flush()

Expand Down