From fe4df278101dbf5de5fc19c948676c1150b0f23e Mon Sep 17 00:00:00 2001 From: Joel Savitz Date: Wed, 17 Jun 2020 00:03:56 -0400 Subject: [PATCH] Integrate a number of existing RPi.GPIO API examples and much more changes in this patch: .coveragerc: - report coverage information on RPi/core.py instead of RPi/_GPIO.py due to file name change Makefile: - %s/unit-cov/test-cov/g - removed an extraneous comment RPi/GPIO/__init__.py: RPi/GPIO_DEVEL/__init__.py: - Added header docstrings - formatted and sorted API imports RPi/_GPIO.py -> RPi/core.py: - File renamed to clarify purpose - convert header to docstring format - sort and organize functions and constants - fix documentation errors and gramatical mistakes - add automatic invokation of cleanup() at interpreter exit - add RPi.GPIO.{RPI_INFO, RPI_REVISION, VERSION} constants - fix various cases of mishandling of iterable channel and value lists - fix pwm thread never releasing lock if thread dies due to exception when the main thread revokes access, however I suspect that this actually be a surface fix for another bug, will look into further (#29) - small tweaks to improve modularity - add support for single value and iterable lists of values for RPi.GPIO.cleanup() - allow PwM to successfully start without explicitly setting up a channel as an output because this library has a more relaxed attitude about those things - add warn on invalid call to PWM.start() - fix board numbering mode being actually pretty broken due to inconsistent mishandling of channel inputs of various forms - fix line_get_value being actually very broken and not retuning anything and therefore always returning None - fix gpio_function() being actually entirely broken so it returns the current function representing what is going on on a GPIO channel as RPi.GPIO would, but this requires further testing (#30) - fix RPi.GPIO.PWM.start() not returning the truth of whether a PwM thread has been successfully started or not examples/callback2.py: - add shabang examples/flash18.py: - remove debuginfo output toggle examples/input_examples.py: examples/output_examples.py: examples/pwm2.py: examples/pwm_usage.py: examples/random_usage.py: examples/try_import.py: - copy example code from Ben Croston's RPi.GPIO wiki on sourceforge - see the files for the sources - ensure that the code works with this library. I found quite a few bugs integrating these files - fix a few mistakes in the code - fix style examples/morse.py: - update morse code to current API version - add basic input validation - fix style examples/pwm.py: - renamed to pwm1.py for consistency examples/pwm1.py: - add try except structure - this may be revelvant to (#29) examples/pwm3.py: examples/pwm4.py: - Copy example code from some forum - see the files for the sources non_root_permission.sh: - expand note on lack of persistence of effects post reboot requirements.txt: - update with latest output of pip freeze from my virtualenv, however this _may_ be bloat spec/spec.tex: - fix some typos - add entry for channel_valid_or_die - update some of the technical spec spec/spec.pdf: - regenerate document test-style.sh: - scan RPi/core.py instead of RPi/_GPIO.py due to name change - add scan of examples/morese.py since it is again working tests/test_gpio.py: - style tweaks - fix test_gpio_function by making it actually test for the feature that now is possibly implemented correctly - modify test_setdebug info to turn it off before the next call to Reset to avoid printing a lot of text to the terminal - extend test_cleanup to validate the new features of cleanup() tests/test_pwm.py: - more thoroughly test PWM.start() Signed-off-by: Joel Savitz --- .coveragerc | 2 +- Makefile | 9 +- RPi/GPIO/__init__.py | 56 ++- RPi/GPIO_DEVEL/__init__.py | 24 +- RPi/{_GPIO.py => core.py} | 866 ++++++++++++++++++++---------------- examples/callback2.py | 1 + examples/flash18.py | 2 - examples/input_examples.py | 75 ++++ examples/morse.py | 271 ++++++----- examples/output_examples.py | 46 ++ examples/pwm.py | 19 - examples/pwm1.py | 20 + examples/pwm2.py | 25 ++ examples/pwm3.py | 42 ++ examples/pwm4.py | 42 ++ examples/pwm_usage.py | 31 ++ examples/random_usage.py | 53 +++ examples/try_import.py | 17 + non_root_permission.sh | 4 + requirements.txt | 23 +- spec/spec.pdf | Bin 157754 -> 158471 bytes spec/spec.tex | 44 +- test-style.sh | 4 +- tests/test_gpio.py | 32 +- tests/test_pwm.py | 20 +- 25 files changed, 1171 insertions(+), 557 deletions(-) rename RPi/{_GPIO.py => core.py} (84%) create mode 100755 examples/input_examples.py create mode 100755 examples/output_examples.py delete mode 100755 examples/pwm.py create mode 100755 examples/pwm1.py create mode 100755 examples/pwm2.py create mode 100755 examples/pwm3.py create mode 100755 examples/pwm4.py create mode 100755 examples/pwm_usage.py create mode 100755 examples/random_usage.py create mode 100755 examples/try_import.py diff --git a/.coveragerc b/.coveragerc index 7006680..c05a228 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1,2 +1,2 @@ [report] -include = RPi/_GPIO.py +include = RPi/core.py diff --git a/Makefile b/Makefile index d6975b4..de60ce8 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,12 @@ +# Makefile to automate common testing procedures for python3-libgpiod-rpi +# By Joel Savitz +# This is free software, see LICENSE for details + all: test -test: unit-cov style -#@echo "MAKE TEST PASS" +test: test-cov style -unit-cov: +test-cov: @bash test-cov.sh -m && echo "FUNTIONAL PASS" || echo "FAILURE IN UNIT TEST" style: diff --git a/RPi/GPIO/__init__.py b/RPi/GPIO/__init__.py index 6e0178e..2383935 100644 --- a/RPi/GPIO/__init__.py +++ b/RPi/GPIO/__init__.py @@ -1,7 +1,49 @@ -# The extended RPi.GPIO API -from RPi._GPIO import setup, cleanup, output, input, setmode, getmode, add_event_detect, remove_event_detect, event_detected, \ - add_event_callback, wait_for_edge, gpio_function, setwarnings, \ - getbias, setbias, getdirection, setdirection, getactive_state, setactive_state, \ - channel_valid_or_die, \ - BCM, BOARD, UNKNOWN, IN, OUT, RISING, FALLING, BOTH, PUD_UP, PUD_DOWN, PUD_OFF, PUD_DISABLE, \ - HIGH, LOW, PWM, I2C, SPI, HARD_PWM, SERIAL +""" +The RPi.GPIO API +Originally created by Ben Croston +Reimplemented and extended by Joel Savitz and Fabrizio D'Angelo +This is free software, see LICENSE for details +""" + +from RPi.core import\ + BCM,\ + BOARD,\ + BOTH,\ + FALLING,\ + HARD_PWM,\ + HIGH,\ + I2C,\ + IN,\ + LOW,\ + OUT,\ + PUD_DISABLE,\ + PUD_DOWN,\ + PUD_OFF,\ + PUD_UP,\ + PWM,\ + RISING,\ + RPI_INFO,\ + RPI_REVISION,\ + SPI,\ + UNKNOWN,\ + VERSION,\ + add_event_callback,\ + add_event_detect,\ + channel_valid_or_die,\ + cleanup,\ + event_detected, \ + getactive_state,\ + getbias,\ + getdirection,\ + getmode,\ + gpio_function,\ + input,\ + output,\ + remove_event_detect,\ + setactive_state,\ + setbias,\ + setdirection,\ + setmode,\ + setup,\ + setwarnings,\ + wait_for_edge diff --git a/RPi/GPIO_DEVEL/__init__.py b/RPi/GPIO_DEVEL/__init__.py index 6df1e84..3455730 100644 --- a/RPi/GPIO_DEVEL/__init__.py +++ b/RPi/GPIO_DEVEL/__init__.py @@ -1,3 +1,21 @@ -# Development functions, not needed for normal use -from RPi._GPIO import Reset, State_Access, setdebuginfo, is_all_ints, is_all_bools_or_directions,\ - is_iterable, line_get_mode, line_set_mode, _line_mode_none, _line_mode_out, _line_mode_in +""" +The new RPi.GPIO_DEVEL development and debug API +By Joel Savitz and Fabrizio D'Angelo +This is free software, see LICENSE for details +""" + +# We have added functions and constants to this list as we have seen +# necesary but we are open to adding more if there is any interest + +from RPi.core import\ + is_all_bools_or_directions,\ + is_all_ints,\ + is_iterable,\ + Reset,\ + setdebuginfo,\ + State_Access,\ + line_get_mode,\ + line_set_mode,\ + _line_mode_in,\ + _line_mode_none,\ + _line_mode_out diff --git a/RPi/_GPIO.py b/RPi/core.py similarity index 84% rename from RPi/_GPIO.py rename to RPi/core.py index 9405f3a..3137b74 100644 --- a/RPi/_GPIO.py +++ b/RPi/core.py @@ -1,16 +1,18 @@ -# -# Core implementation of python3-libgpiod-rpi -# By Joel Savitz and Fabrizio D'Angelo -# This is free software, see LICENSE for details -# +""" +Core implementation of python3-libgpiod-rpi +By Joel Savitz and Fabrizio D'Angelo +This is free software, see LICENSE for details +""" + import gpiod from warnings import warn import os import sys import time from threading import Thread, Event, Lock +import atexit -# BCM to Board mode conversion table +# BCM to Board mode conversion table for Raspbery Pi 3 Model B pin_to_gpio_rev3 = [ -1, -1, -1, 2, -1, 3, -1, 4, 14, -1, # NOQA 15, 17, 18, 27, -1, 22, 23, -1, 24, 10, # NOQA @@ -18,23 +20,42 @@ -1, 6, 12, 13, -1, 19, 16, 26, 20, -1, 21 # NOQA ] + # === User Facing Data === # Exact values for constants taken from RPi.GPIO source code # file: source/common.h +# [API] RPi.GPIO API version (not python3-libgpiod-rpi version) +# NOTE: we currently only officially support the Raspbery Pi 3 Model B +# but we soon plan to implement support for the Raspbery Pi 4 Model B +# We are limited by the hardware available to the developers +VERSION = "0.7.0" + +# [API] Hardware information +RPI_INFO = { + "P1_REVISION": 3, + "REVISION": "a22082", + "TYPE": "Pi 3 Model B", + "MANUFACTURER": "Embest" + "PROCESSOR" "BCM2837", + "RAM": "1G", +} +# [API] Depcrecated source of hardware information +RPI_REVISION = RPI_INFO["P1_REVISION"] + # [API] Pin numbering modes UNKNOWN = -1 BCM = 11 BOARD = 10 -# [API] Random constants +# [API] Random constants defined but unused in the latest RPi.GPIO release SERIAL = 40 SPI = 41 I2C = 42 HARD_PWM = 43 -# Output modes +# [API] Output modes LOW = gpiod.Line.ACTIVE_LOW HIGH = gpiod.Line.ACTIVE_HIGH @@ -49,13 +70,13 @@ def active_flag(const): return _LINE_ACTIVE_STATE_COSNT_TO_FLAG[const] +# [API] Software pull up/pull down resistor modes # We map RPi.GPIO PUD modes to libgpiod PUD constants PUD_OFF = gpiod.Line.BIAS_AS_IS PUD_UP = gpiod.Line.BIAS_PULL_UP PUD_DOWN = gpiod.Line.BIAS_PULL_DOWN -# We extend RPi.GPIO with the ability to explicitly disable pull up/down -# behavior +# We extend RPi.GPIO with the ability to explicitly disable pull up/down behavior PUD_DISABLE = gpiod.Line.BIAS_DISABLE # libgpiod uses distinct flag values for each line bias constant returned by @@ -74,7 +95,7 @@ def bias_flag(const): return _LINE_BIAS_CONST_TO_FLAG[const] -# internal line modes +# Internal line modes _line_mode_none = 0 _line_mode_in = gpiod.LINE_REQ_DIR_IN _line_mode_out = gpiod.LINE_REQ_DIR_OUT @@ -86,7 +107,7 @@ def bias_flag(const): _line_mode_as_is = gpiod.LINE_REQ_DIR_AS_IS -# [API] Request types +# [API] Line event types FALLING = _line_mode_falling RISING = _line_mode_rising BOTH = _line_mode_both @@ -132,9 +153,9 @@ def __init__(self, channel, target_type, args): def kill(self): self.killswitch.set() - end_critical_section(self.channel, msg="drop lock and join poll thread") + end_critical_section(self.channel, msg="drop lock and join line thread") self.join() - begin_critical_section(self.channel, msg="poll thread dead so get lock") + begin_critical_section(self.channel, msg="line thread dead so get lock") class _Line: @@ -220,11 +241,6 @@ def DCprint(channel, *msgargs): Dprint("[{}]".format(channel), *msgargs) -# Mess with the internal state for development or recreational purposes -def State_Access(): - return _State - - # Reset internal state to default def Reset(): Dprint("Reset begins") @@ -246,23 +262,29 @@ def Reset(): Dprint("Reset commplete") -def is_all_ints(data): +def State_Access(): + # The purpose of this funtion is to allow the user to mess with the + # internal state of the library for development or recreational purposes + return _State + + +def is_all_bools_or_directions(data): if not is_iterable(data): data = [data] if len(data) < 1: return False - return all([isinstance(elem, int) for elem in data]) \ - if not isinstance(data, int)\ + return all([(isinstance(elem, bool) or elem in [HIGH, LOW]) for elem in data]) \ + if not (isinstance(data, bool) or data in [HIGH, LOW])\ else True -def is_all_bools_or_directions(data): +def is_all_ints(data): if not is_iterable(data): data = [data] if len(data) < 1: return False - return all([(isinstance(elem, bool) or elem in [HIGH, LOW]) for elem in data]) \ - if not (isinstance(data, bool) or data in [HIGH, LOW])\ + return all([isinstance(elem, int) for elem in data]) \ + if not isinstance(data, int)\ else True @@ -275,8 +297,29 @@ def is_iterable(data): return True +def setdebuginfo(value): + """Enable or disable debug messages""" + if not value: + Dprint("debuginfo output set to", _State.debuginfo) + _State.debuginfo = bool(value) + if value: + Dprint("debuginfo output set to", _State.debuginfo) + + +def wait_for_edge_validation(edge, bouncetime, timeout): + if edge not in [RISING, FALLING, BOTH]: + raise ValueError("The edge must be set to RISING, FALLING or BOTH") + + if bouncetime is not None and bouncetime <= 0: + raise ValueError("Bouncetime must be greater than 0") + + if timeout and timeout < 0: + # error semantics differ from RPi.GPIO + raise ValueError("Timeout must be greater than or equal to 0") + + def channel_fix_and_validate_bcm(channel): - if channel < 0 or channel > _State.chip.num_lines() - 1: + if channel < 0 or channel > chip_get_num_lines() - 1: raise ValueError("The channel sent is invalid on a Raspberry Pi") else: return channel @@ -312,16 +355,6 @@ def channel_fix_and_validate(channel_raw): return channel_fix_and_validate_board(channel_raw) -def channel_valid_or_die(channel): - """ - Validate a channel/pin number - Returns the pin number on success otherwise throws a ValueError - - channel - an integer to be validated as a channel - """ - channel_fix_and_validate(channel) - - def validate_gpio_dev_exists(): # This function only ever needs to be run once if validate_gpio_dev_exists.found: @@ -349,7 +382,7 @@ def chip_init(): try: _State.chip = gpiod.Chip("gpiochip0") except PermissionError: - print("Script or interpreter must be run as root") + print("Unable to access /dev/gpiochip0. Are you sure you have permission?") sys.exit() Dprint("state chip has value:", _State.chip) @@ -359,6 +392,10 @@ def chip_close(): _State.chip = None +def chip_is_open(): + return _State.chip is not None + + def chip_init_if_needed(): if _State.chip is None: chip_init() @@ -424,6 +461,10 @@ def line_get_active_state(channel): return _State.lines[channel].line.active_state() +def line_get_direction(channel): + return _LINE_MODE_TO_DIR_CONST[line_get_mode(channel)] + + def line_get_bias(channel): return _State.lines[channel].line.bias() @@ -476,20 +517,24 @@ def line_pwm_start(channel, dutycycle): if not line_is_pwm(channel) and \ line_pwm_get_frequency(channel) != -1: begin_critical_section(channel, msg="pwm start") + + # If you forgot to setup this channel as an output, we've got you + line_set_mode(channel, _line_mode_out) + line_pwm_set_dutycycle(channel, dutycycle) _State.lines[channel].thread_start(_line_thread_pwm, args=(channel,)) + end_critical_section(channel, msg="pwm start") return line_is_pwm(channel) + else: + warn("invalid call to pwm_start(). Did you call PWM.__init__() on this channel?") + return False + # If the line is already running a PwM thread # return True, but if there is no thread running # and the user tried to call PWM.start() before # calling PWM.__init__() somewhow, then # return False and tell them to call init. - if line_is_pwm(channel): - return True - else: - warn("invalid call to pwm_start(). Did you call PWM.__init__() on this channel?") - return False def line_pwm_stop(channel): @@ -550,220 +595,239 @@ def line_set_value(channel, value): def line_get_value(channel): - _State.lines[channel].line.get_value() + return _State.lines[channel].line.get_value() -# === Interface Functions === +def line_event_wait_lock(channel, bouncetime, timeout): + begin_critical_section(channel, msg="event wait") + ret = line_event_wait(channel, bouncetime, timeout) + end_critical_section(channel, msg="event wait") + return ret -def setmode(mode): - """ - Set up numbering mode to use for channels. - BOARD - Use Raspberry Pi board numbers - BCM - Use Broadcom GPIO 00..nn numbers - """ - if _State.mode != UNKNOWN: - raise ValueError("A different mode has already been set!") - if mode != BCM and mode != BOARD: - raise ValueError("An invalid mode was passed to setmode()") +# requires lock +def line_event_wait(channel, bouncetime, timeout): + # Split up timeout into appropriate parts + timeout_sec = int(int(timeout) / 1000) + timeout_nsec = (int(timeout) % 1000) * 1000 - _State.mode = mode + ret = None - chip_init_if_needed() + # We only care about bouncetime if it is explicitly speficied in the call to this function or if + # this is not the first call to wait_for_edge on the specified pin + if bouncetime and _State.lines[channel].timestamp and \ + time.time() - _State.lines[channel].timestamp < bouncetime: + pass + elif _State.lines[channel].line.event_wait(sec=timeout_sec, nsec=timeout_nsec): + _State.lines[channel].timestamp = time.time() + if channel not in _State.event_ls: + # Ensure no double appends. FIXME: should this be done outside of a poll thread? + _State.event_ls.append(channel) + event = _State.lines[channel].line.event_read() - Dprint("mode set to", _State.mode) + # A hack to clear the event buffer by reading a bunch of bytes + # from the underlying file representing the GPIO line + eventfd = _State.lines[channel].line.event_get_fd() + os.read(eventfd, 10000) + if event: + ret = channel + return ret -def setwarnings(value): - """Enable or disable warning messages""" - _State.warnings = bool(value) - Dprint("warning output set to", _State.warnings) +def line_add_callback(channel, callback): + begin_critical_section(channel, "add callback") + _State.lines[channel].callbacks.append(callback) + end_critical_section(channel, "add callback") -def setdebuginfo(value): - """Enable or disable debug messages""" - _State.debuginfo = bool(value) - Dprint("debuginfo output set to", _State.debuginfo) +def line_thread_should_die(channel): + return _State.lines[channel].thread.killswitch.is_set() -def setup(channel, direction, pull_up_down=PUD_OFF, initial=None): - """ - Set up a GPIO channel or list of channels with a direction and (optional) pull/up down control - channel - either board pin number or BCM number depending on which mode is set. - direction - IN or OUT - [pull_up_down] - PUD_OFF (default), PUD_UP or PUD_DOWN - [initial] - Initial value for an output channel - """ - # Channel must contain only integral data - if not is_all_ints(channel): - raise ValueError("Channel must be an integer or list/tuple of integers") +TEN_MILLISECONDS_IN_SECONDS = 0.0010 - # Direction must be valid - if direction != IN and direction != OUT: - raise ValueError("An invalid direction was passed to setup()") - if direction == OUT and pull_up_down != PUD_OFF: - raise ValueError("pull_up_down parameter is not valid for outputs") +def line_do_poll(channel, bouncetime, timeout): - if direction == IN and initial: - raise ValueError("initial parameter is not valid for inputs") + while True: + begin_critical_section(channel, msg="do poll") + if line_thread_should_die(channel): + end_critical_section(channel, msg="do poll exit") + break + if line_event_wait(channel, bouncetime, timeout): + callbacks = _State.lines[channel].callbacks + for fn in callbacks(): + fn() + end_critical_section(channel, msg="do poll") + time.sleep(TEN_MILLISECONDS_IN_SECONDS) - if pull_up_down not in [PUD_OFF, PUD_UP, PUD_DOWN, PUD_DISABLE]: - raise ValueError("Invalid value for pull_up_down - should be either PUD_OFF, PUD_UP, PUD_DOWN, or PUD_DISABLE") - # Make the channel data iterable by force - if not is_iterable(channel): - channel = [channel] +def poll_thread(channel, edge, callback, bouncetime): - # This implements BOARD mode - for pin in channel: - pin = channel_fix_and_validate(pin) + # FIXME: this is arbitrary + timeout = 10 # milliseconds + wait_for_edge_validation(edge, bouncetime, timeout) - request_flags = 0 - request_flags |= bias_flag(pull_up_down) + DCprint(channel, "launch poll thread") + line_do_poll(channel, bouncetime, timeout) + DCprint(channel, "terminate poll thread") - for pin in channel: - try: - line_set_mode(pin, direction, request_flags) - if initial is not None: - line_set_value(pin, initial) - except OSError: - warn("This channel is already in use, continuing anyway. Use GPIO.setwarnings(False) to disable warnings.\n \ - Further attemps to use channel {} will fail unless setup() is run again sucessfully".format(pin)) +# NOTE: RPi.GPIO specifies: +# Default to 1 kHz frequency 0.0% dutycycle +# but interface functions require explicit arguments +def pwm_thread(channel): + DCprint(channel, "begin PwM thread with dutycycle {}% and frequency {} Hz".format(_State.lines[channel].dutycycle, + _State.lines[channel].frequency)) + + # We wrap the loop with a try except so we can drop the lock and exit if + # access to the channel is suddenly revoked by the main thread + try: + while True: + begin_critical_section(channel, msg="do pwm") + if line_thread_should_die(channel): + end_critical_section(channel, msg="do pwm exit") + break + if _State.lines[channel].dutycycle > 0: + line_set_value(channel, True) + DCprint(channel, "PwM: ON") + # PwM calculation for high voltage part of period: + time.sleep(1 / _State.lines[channel].frequency * (_State.lines[channel].dutycycle / 100.0)) + if _State.lines[channel].dutycycle < 100: + line_set_value(channel, False) + DCprint(channel, "PwM: OFF") + # PwM calculation for low voltage part of period: + time.sleep(1 / _State.lines[channel].frequency * (1.0 - _State.lines[channel].dutycycle / 100.0)) + end_critical_section(channel, msg="do pwm") + time.sleep(TEN_MILLISECONDS_IN_SECONDS) + # arbitrary time to sleep without lock + # TODO: may interfere with overall timing of PwM but it's rough anyway + except (ValueError, PermissionError): + # If this thread suddenly fails to access a channel, exit gracefully + end_critical_section(channel, msg="do pwm sudden exit") + + +# === RPi.GPIO API entry points === -def output(channel, value): - """ - Output to a GPIO channel or list of channel - channel - either board pin number or BCM number depending on which mode is set. - value - 0/1 or False/True or LOW/HIGH - {compat} channel and value parameters may be lists or tuples of equal length +def add_event_callback(channel, callback): """ - if not is_all_ints(channel): - raise ValueError("Channel must be an integer or list/tuple of integers") + Add a callback for an event already defined using add_event_detect() + channel - either board pin number or BCM number depending on which mode is set. + callback - a callback function" - if not is_iterable(channel): - channel = [channel] + {compat} we do not require that the channel be setup as an input + """ # This implements BOARD mode - for chan in channel: - chan = channel_fix_and_validate(chan) - - if (not is_all_ints(value)) and (not is_all_bools_or_directions(value)): - raise ValueError("Value must be an integer/boolean or a list/tuple of integers/booleans") - - if not is_iterable(value): - value = [value] + channel = channel_fix_and_validate(channel) - # Normalize the value argument - for i in range(len(value)): - if value[i] == HIGH: - value[i] = True - if value[i] == LOW: - value[i] = False + if not line_is_poll(channel): + raise RuntimeError("Add event detection using add_event_detect first before adding a callback") - if len(channel) != len(value): - raise RuntimeError("Number of channel != number of value") + if not callable(callback): + raise TypeError("Parameter must be callable") - for chan, val in zip(channel, value): - if line_get_mode(chan) != _line_mode_out: - warn("The GPIO channel has not been set up as an OUTPUT\n\tSkipping channel {}".format(chan)) - else: - try: - line_set_value(chan, bool(val)) - except PermissionError: - warn("Unable to set value of channel {}, did you forget to run setup()? Or did setup() fail?".format(chan)) + line_add_callback(channel, callback) -def input(channel): +def add_event_detect(channel, edge, callback=None, bouncetime=None): """ - Input from a GPIO channel. Returns HIGH=1=True or LOW=0=False - # channel - either board pin number or BCM number depending on which mode is set. + Enable edge detection events for a particular GPIO channel. + channel - either board pin number or BCM number depending on which mode is set. + edge - RISING, FALLING or BOTH + [callback] - A callback function for the event (optional) + [bouncetime] - Switch bounce timeout in ms for callback + + {compat} we do not require that the channel be setup as an input as a prerequiste to running this function, + however the initial value on the channel is undefined """ # This implements BOARD mode channel = channel_fix_and_validate(channel) - # this does't really make sense but it matches rpi gpio source code logic - if getdirection(channel) not in [IN, OUT]: - raise RuntimeError("You must setup() the GPIO channel first") + valid_edges = [RISING, FALLING, BOTH] + if edge not in valid_edges: + raise ValueError("The edge must be set to RISING, FALLING or BOTH") - # TODO I feel like we should do more validation + if callback and not callable(callback): + raise TypeError("Parameter must be callable") - return line_get_value(channel) + if bouncetime and bouncetime <= 0: + raise ValueError("Bouncetime must be greater than 0") + line_set_mode(channel, edge) + line_poll_start(channel, edge, callback, bouncetime) -def getmode(): - """ - Get numbering mode used for channel numbers. - Returns BOARD, BCM or None - """ - return _State.mode if _State.mode else None - - -def getbias(channel): - """ - Get bias mode of an active channel - Returns PUD_OFF, PUD_DOWN, PUD_UP, or PUD disabled if the channel is - active or just PUD_OFF if the channel is not active. +def channel_valid_or_die(channel): """ + Validate a channel/pin number + Returns the pin number on success otherwise throws a ValueError - channel = channel_fix_and_validate(channel) - - if line_is_active(channel): - return line_get_bias(channel) - else: - return PUD_OFF + channel - an integer to be validated as a channel + """ + channel_fix_and_validate(channel) -def setbias(channel, bias): +def cleanup(channels=None): """ - Set bias of an active channel + Clean up by resetting all GPIO channels that have been used by this program to INPUT with no pullup/pulldown and no event detection + [channel] - individual channel or list/tuple of channels to clean up. + Default - clean every channel that has been used. + + {compat} Cleanup is mostly handled by libgpiod and the kernel, but we use this opportunity to kill any running callback poll threads + as well as close any open file descriptors """ - channel = channel_fix_and_validate(channel) + if not chip_is_open(): + chip_init_if_needed() + _State.lines = [_Line(channel) for channel in range(chip_get_num_lines())] - if bias not in [PUD_OFF, PUD_UP, PUD_DOWN, PUD_DISABLE]: - raise ValueError("An invalid bias was passed to setbias()") + destroy = False + if channels is None: + destroy = True + channels = [i for i in range(chip_get_num_lines())] - current = getbias(channel) - if bias != current: - flags = line_get_flags(channel) - flags &= ~bias_flag(getbias(channel)) - flags |= bias_flag(bias) - line_set_flags(channel, flags) + if not is_all_ints(channels): + raise ValueError("Channel must be an integer or list/tuple of integers") + elif isinstance(channels, tuple): + # Convert tuples to lists to make them writable for normalization of values + channels = [c for c in channels] + if not destroy: + Dprint("NOT DESTROY: iterable=", is_iterable(channels)) + if not is_iterable(channels): + channels = [channels] + for i in range(len(channels)): + # This implements BOARD mode + channels[i] = channel_fix_and_validate(channels[i]) -def getdirection(channel): - """ - Get direction of an active channel - Returns OUT if the channel is in an output mode, IN if the channel is in an input mode, - and -1 otherwise - """ + Dprint("cleanup {} lines".format(len(channels))) + if not destroy: + Dprint("channels:", channels) + for chan in channels: + line_set_mode(chan, _line_mode_none) - channel = channel_fix_and_validate(channel) - return _LINE_MODE_TO_DIR_CONST[line_get_mode(channel)] + if destroy: + chip_destroy() -def setdirection(channel, direction): +def event_detected(channel): """ - Set direction of an active channel + Returns True if an edge has occurred on a given GPIO. You need to enable edge detection using add_event_detect() first. + channel - either board pin number or BCM number depending on which mode is set." """ + # This implements BOARD mode channel = channel_fix_and_validate(channel) - if direction != IN and direction != OUT: - raise ValueError("An invalid direction was passed to setdirection()") - - current = getdirection(channel) - if current != -1: - if current == IN and direction == OUT: - line_set_mode(channel, _line_mode_out) - elif current == OUT and direction == IN: - line_set_mode(channel, _line_mode_in) + if channel in _State.event_ls: + _State.event_ls.remove(channel) + return True + else: + return False def getactive_state(channel): @@ -780,285 +844,312 @@ def getactive_state(channel): return -1 -def setactive_state(channel, active_state): +def getbias(channel): """ - Set the active_state of an active channel + Get bias mode of an active channel + Returns PUD_OFF, PUD_DOWN, PUD_UP, or PUD disabled if the channel is + active or just PUD_OFF if the channel is not active. """ channel = channel_fix_and_validate(channel) - if active_state not in [HIGH, LOW]: - raise ValueError("An active state was passed to setactive_state()") + if line_is_active(channel): + return line_get_bias(channel) + else: + return PUD_OFF - current = getactive_state(channel) - if active_state != current: - flags = line_get_flags(channel) - flags &= ~active_flag(getactive_state(channel)) - flags |= active_flag(active_state) - line_set_flags(channel, flags) +def getdirection(channel): + """ + Get direction of an active channel + Returns OUT if the channel is in an output mode, IN if the channel is in an input mode, + and -1 otherwise + """ -def wait_for_edge_validation(edge, bouncetime, timeout): - if edge not in [RISING, FALLING, BOTH]: - raise ValueError("The edge must be set to RISING, FALLING or BOTH") + channel = channel_fix_and_validate(channel) + return line_get_direction(channel) - if bouncetime is not None and bouncetime <= 0: - raise ValueError("Bouncetime must be greater than 0") - if timeout and timeout < 0: - # error semantics differ from RPi.GPIO - raise ValueError("Timeout must be greater than or equal to 0") +def getmode(): + """ + Get numbering mode used for channel numbers. + Returns BOARD, BCM or None + """ + return _State.mode if _State.mode else None -def wait_for_edge(channel, edge, bouncetime=None, timeout=0): - """ - Wait for an edge. Returns the channel number or None on timeout. - channel - either board pin number or BCM number depending on which mode is set. - edge - RISING, FALLING or BOTH - [bouncetime] - time allowed between calls to allow for switchbounce - [timeout] - timeout in ms - {compat} bouncetime units are in seconds. this is subject to change +def gpio_function(channel): """ + Return the current GPIO function (IN, OUT, PWM, SERIAL, I2C, SPI) + channel - either board pin number or BCM number depending on which mode is set. - # Running this function before setup is allowed but the initial pin value is undefined - # RPi.GPIO requires one to setup a pin as input before using it for event detection, - # while libgpiod provides an interface that keeps the two mutually exclusive. We get around - # this by not requiring it, though to maintain the same semantics as RPi.GPIO, we attempt - # to release the channel's handle as a an input value, and acquire a new handle for an - # event value. + {compat} This is a stateless function that will return a constant value for every pin + """ # This implements BOARD mode channel = channel_fix_and_validate(channel) - wait_for_edge_validation(edge, bouncetime, timeout) - - # ensure the line is in the right mode - # FIXME does this break input mode? - try: - line_set_mode(channel, edge) - except OSError: - raise RuntimeError("Channel is currently in use (Device or Resource Busy)") - - return line_event_wait_lock(channel, bouncetime, timeout) - + mode = line_get_mode(channel) -def line_event_wait_lock(channel, bouncetime, timeout): - begin_critical_section(channel, msg="event wait") - ret = line_event_wait(channel, bouncetime, timeout) - end_critical_section(channel, msg="event wait") - return ret + if mode == _line_mode_out: + return OUT + elif mode == _line_mode_in: + return IN + else: + return UNKNOWN + # We will provide support for other potential values of gpio_function + # when the underlying functions (SPI, SERIAL, I2C, HARD_PWM) are implemented. -# requires lock -def line_event_wait(channel, bouncetime, timeout): - # Split up timeout into appropriate parts - timeout_sec = int(int(timeout) / 1000) - timeout_nsec = (int(timeout) % 1000) * 1000 - # We only care about bouncetime if it is explicitly speficied in the call to this function or if - # this is not the first call to wait_for_edge on the specified pin - if bouncetime and _State.lines[channel].timestamp and \ - time.time() - _State.lines[channel].timestamp < bouncetime: - ret = None - elif _State.lines[channel].line.event_wait(sec=timeout_sec, nsec=timeout_nsec): - _State.lines[channel].timestamp = time.time() - if channel not in _State.event_ls: - # Ensure no double appends. FIXME: should this be done outside of a poll thread? - _State.event_ls.append(channel) - event = _State.lines[channel].line.event_read() +def input(channel): + """ + Input from a GPIO channel. Returns HIGH=1=True or LOW=0=False + # channel - either board pin number or BCM number depending on which mode is set. + """ - # A hack to clear the event buffer by reading a bunch of bytes - # from the underlying file representing the GPIO line - eventfd = _State.lines[channel].line.event_get_fd() - os.read(eventfd, 10000) - ret = event - else: - ret = None + # This implements BOARD mode + channel = channel_fix_and_validate(channel) - return ret + # this does't really make sense but it matches rpi gpio source code logic + if getdirection(channel) not in [IN, OUT]: + raise RuntimeError("You must setup() the GPIO channel first") + # TODO I feel like we should do more validation -def line_thread_should_die(channel): - return _State.lines[channel].thread.killswitch.is_set() + return line_get_value(channel) -TEN_MILLISECONDS_IN_SECONDS = 0.0010 +def output(channel, value): + """ + Output to a GPIO channel or list of channel + channel - either board pin number or BCM number depending on which mode is set. + value - 0/1 or False/True or LOW/HIGH + {compat} channel and value parameters may be lists or tuples of equal length + """ + if not is_all_ints(channel): + raise ValueError("Channel must be an integer or list/tuple of integers") -def line_do_poll(channel, bouncetime, timeout): + if not is_iterable(channel): + channel = [channel] - while True: - begin_critical_section(channel, msg="do poll") - if line_thread_should_die(channel): - end_critical_section(channel, msg="do poll exit") - break - if line_event_wait(channel, bouncetime, timeout): - callbacks = _State.lines[channel].callbacks - for fn in callbacks(): - fn() - end_critical_section(channel, msg="do poll") - time.sleep(TEN_MILLISECONDS_IN_SECONDS) + if (not is_all_ints(value)) and (not is_all_bools_or_directions(value)): + raise ValueError("Value must be an integer/boolean or a list/tuple of integers/booleans") + # Convert tuples to lists to make them writable for normalization of values + if isinstance(value, tuple): + value = [v for v in value] -def poll_thread(channel, edge, callback, bouncetime): + # If there is a single value provided, we set each channel to that value + if not is_iterable(value): + value = [value for i in range(len(channel))] - # FIXME: this is arbitrary - timeout = 10 # milliseconds - wait_for_edge_validation(edge, bouncetime, timeout) + # This implements BOARD mode for all input cases + for i in range(len(channel)): + channel[i] = channel_fix_and_validate(channel[i]) - DCprint(channel, "launch poll thread") - line_do_poll(channel, bouncetime, timeout) - DCprint(channel, "terminate poll thread") + # Normalize the value argument + for i in range(len(value)): + if value[i] == HIGH: + value[i] = True + if value[i] == LOW: + value[i] = False + Dprint("channel", channel, "value", value) + if len(channel) != len(value): + raise RuntimeError("Number of channel != number of value") -# NOTE: RPi.GPIO specifies: -# Default to 1 kHz frequency 0.0% dutycycle -# but interface functions require explicit arguments -def pwm_thread(channel): - DCprint(channel, "begin PwM thread with dutycycle {}% and frequency {} Hz".format(_State.lines[channel].dutycycle, - _State.lines[channel].frequency)) - while True: - begin_critical_section(channel, msg="do pwm") - if line_thread_should_die(channel): - end_critical_section(channel, msg="do pwm exit") - break - if _State.lines[channel].dutycycle > 0: - line_set_value(channel, True) - DCprint(channel, "PwM: ON") - # PwM calculation for high voltage part of period: - time.sleep(1 / _State.lines[channel].frequency * (_State.lines[channel].dutycycle / 100.0)) - if _State.lines[channel].dutycycle < 100: - line_set_value(channel, False) - DCprint(channel, "PwM: OFF") - # PwM calculation for low voltage part of period: - time.sleep(1 / _State.lines[channel].frequency * (1.0 - _State.lines[channel].dutycycle / 100.0)) - end_critical_section(channel, msg="do pwm") - time.sleep(TEN_MILLISECONDS_IN_SECONDS) - # arbitrary time to sleep without lock, TODO: may interfere with overall timing of PwM but it's rough anyway + for chan, val in zip(channel, value): + if line_get_mode(chan) != _line_mode_out: + warn("The GPIO channel has not been set up as an OUTPUT\n\tSkipping channel {}".format(chan)) + else: + try: + line_set_value(chan, bool(val)) + except PermissionError: + warn("Unable to set value of channel {}, did you forget to run setup()? Or did setup() fail?".format(chan)) -def add_event_detect(channel, edge, callback=None, bouncetime=None): +def remove_event_detect(channel): """ - Enable edge detection events for a particular GPIO channel. - channel - either board pin number or BCM number depending on which mode is set. - edge - RISING, FALLING or BOTH - [callback] - A callback function for the event (optional) - [bouncetime] - Switch bounce timeout in ms for callback - - {compat} we do not require that the channel be setup as an input as a prerequiste to running this function, - however the initial value on the channel is undefined + Remove edge detection for a particular GPIO channel + channel - either board pin number or BCM number depending on which mode is set. """ # This implements BOARD mode channel = channel_fix_and_validate(channel) - valid_edges = [RISING, FALLING, BOTH] - if edge not in valid_edges: - raise ValueError("The edge must be set to RISING, FALLING or BOTH") + if line_is_poll(channel): + line_kill_poll_lock(channel) + else: + raise ValueError("event detection not setup on channel {}".format(channel)) - if callback and not callable(callback): - raise TypeError("Parameter must be callable") - if bouncetime and bouncetime <= 0: - raise ValueError("Bouncetime must be greater than 0") +def setactive_state(channel, active_state): + """ + Set the active_state of an active channel + """ - line_set_mode(channel, edge) - line_poll_start(channel, edge, callback, bouncetime) + channel = channel_fix_and_validate(channel) + if active_state not in [HIGH, LOW]: + raise ValueError("An active state was passed to setactive_state()") -def add_event_callback(channel, callback): - """ - Add a callback for an event already defined using add_event_detect() - channel - either board pin number or BCM number depending on which mode is set. - callback - a callback function" + current = getactive_state(channel) + if active_state != current: + flags = line_get_flags(channel) + flags &= ~active_flag(getactive_state(channel)) + flags |= active_flag(active_state) + line_set_flags(channel, flags) - {compat} we do not require that the channel be setup as an input + +def setbias(channel, bias): + """ + Set bias of an active channel """ - # This implements BOARD mode channel = channel_fix_and_validate(channel) - if not line_is_poll(channel): - raise RuntimeError("Add event detection using add_event_detect first before adding a callback") + if bias not in [PUD_OFF, PUD_UP, PUD_DOWN, PUD_DISABLE]: + raise ValueError("An invalid bias was passed to setbias()") - if not callable(callback): - raise TypeError("Parameter must be callable") + current = getbias(channel) + if bias != current: + flags = line_get_flags(channel) + flags &= ~bias_flag(getbias(channel)) + flags |= bias_flag(bias) + line_set_flags(channel, flags) - line_add_callback(channel, callback) +def setdirection(channel, direction): + """ + Set direction of an active channel + """ -def line_add_callback(channel, callback): - begin_critical_section(channel, "add callback") - _State.lines[channel].callbacks.append(callback) - end_critical_section(channel, "add callback") + channel = channel_fix_and_validate(channel) + + if direction != IN and direction != OUT: + raise ValueError("An invalid direction was passed to setdirection()") + current = line_get_direction(channel) + if current != -1: + if current == IN and direction == OUT: + line_set_mode(channel, _line_mode_out) + elif current == OUT and direction == IN: + line_set_mode(channel, _line_mode_in) -def remove_event_detect(channel): + +def setmode(mode): """ - Remove edge detection for a particular GPIO channel - channel - either board pin number or BCM number depending on which mode is set. + Set up numbering mode to use for channels. + BOARD - Use Raspberry Pi board numbers + BCM - Use Broadcom GPIO 00..nn numbers """ + if _State.mode != UNKNOWN: + raise ValueError("A different mode has already been set!") - # This implements BOARD mode - channel = channel_fix_and_validate(channel) + if mode != BCM and mode != BOARD: + raise ValueError("An invalid mode was passed to setmode()") - if line_is_poll(channel): - line_kill_poll_lock(channel) - else: - raise ValueError("event detection not setup on channel {}".format(channel)) + _State.mode = mode + chip_init_if_needed() -def event_detected(channel): + Dprint("mode set to", _State.mode) + + +def setup(channel, direction, pull_up_down=PUD_OFF, initial=None): """ - Returns True if an edge has occurred on a given GPIO. You need to enable edge detection using add_event_detect() first. - channel - either board pin number or BCM number depending on which mode is set." + Set up a GPIO channel or list of channels with a direction and (optional) pull/up down control + channel - either board pin number or BCM number depending on which mode is set. + direction - IN or OUT + [pull_up_down] - PUD_OFF (default), PUD_UP or PUD_DOWN + [initial] - Initial value for an output channel """ - # This implements BOARD mode - channel = channel_fix_and_validate(channel) + # Channel must contain only integral data + if not is_all_ints(channel): + raise ValueError("Channel must be an integer or list/tuple of integers") - if channel in _State.event_ls: - _State.event_ls.remove(channel) - return True - else: - return False + # Direction must be valid + if direction != IN and direction != OUT: + raise ValueError("An invalid direction was passed to setup()") + + if direction == OUT and pull_up_down != PUD_OFF: + raise ValueError("pull_up_down parameter is not valid for outputs") + if direction == IN and initial: + raise ValueError("initial parameter is not valid for inputs") -def cleanup(): - """ - Clean up by resetting all GPIO channels that have been used by this program to INPUT with no pullup/pulldown and no event detection - [channel] - individual channel or list/tuple of channels to clean up. - Default - clean every channel that has been used. + if pull_up_down not in [PUD_OFF, PUD_UP, PUD_DOWN, PUD_DISABLE]: + raise ValueError("Invalid value for pull_up_down - should be either PUD_OFF, PUD_UP, PUD_DOWN, or PUD_DISABLE") - {compat} Cleanup is mostly handled by libgpiod and the kernel, but we use this opportunity to kill any running callback poll threads - as well as close any open file descriptors - """ + # Convert tuples to lists to make them writable for validations of channels + if isinstance(channel, tuple): + channel = [c for c in channel] + + # Make the channel data iterable by force + if not is_iterable(channel): + channel = [channel] - Dprint("cleanup {} lines".format(len(_State.lines))) - for channel in range(len(_State.lines)): - line_set_mode(channel, _line_mode_none) + # This implements BOARD mode + for i in range(len(channel)): + channel[i] = channel_fix_and_validate(channel[i]) - chip_destroy() + request_flags = 0 + request_flags |= bias_flag(pull_up_down) + for pin in channel: + try: + line_set_mode(pin, direction, request_flags) + if initial is not None: + line_set_value(pin, initial) + except OSError: + warn("This channel is already in use, continuing anyway. Use GPIO.setwarnings(False) to disable warnings.\n \ + Further attemps to use channel {} will fail unless setup() is run again sucessfully".format(pin)) -def get_gpio_number(channel): - return channel_fix_and_validate(channel) +def setwarnings(value): + """Enable or disable warning messages""" + _State.warnings = bool(value) + Dprint("warning output set to", _State.warnings) -def gpio_function(channel): + +def wait_for_edge(channel, edge, bouncetime=None, timeout=0): """ - Return the current GPIO function (IN, OUT, PWM, SERIAL, I2C, SPI) - channel - either board pin number or BCM number depending on which mode is set. + Wait for an edge. Returns the channel number or None on timeout. + channel - either board pin number or BCM number depending on which mode is set. + edge - RISING, FALLING or BOTH + [bouncetime] - time allowed between calls to allow for switchbounce + [timeout] - timeout in ms - {compat} This is a stateless function that will return a constant value for every pin + {compat} bouncetime units are in seconds. this is subject to change """ + # Running this function before setup is allowed but the initial pin value is undefined + # RPi.GPIO requires one to setup a pin as input before using it for event detection, + # while libgpiod provides an interface that keeps the two mutually exclusive. We get around + # this by not requiring it, though to maintain the same semantics as RPi.GPIO, we attempt + # to release the channel's handle as a an input value, and acquire a new handle for an + # event value. + # This implements BOARD mode channel = channel_fix_and_validate(channel) - # error handling is done in the called function - return get_gpio_number(channel) + wait_for_edge_validation(edge, bouncetime, timeout) + + # ensure the line is in the right mode + # FIXME does this break input mode? + try: + line_set_mode(channel, edge) + except OSError: + raise RuntimeError("Channel is currently in use (Device or Resource Busy)") + + return line_event_wait_lock(channel, bouncetime, timeout) + + +# === RPi.GPIO Pulse-width Modulation (PwM) class === class PWM: @@ -1085,7 +1176,7 @@ def start(self, dutycycle): if dutycycle < 0.0 or dutycycle > 100.0: raise ValueError("dutycycle must have a value from 0.0 to 100.0") - line_pwm_start(self.channel, dutycycle) + return line_pwm_start(self.channel, dutycycle) def stop(self): """ @@ -1115,11 +1206,18 @@ def ChangeFrequency(self, frequency): line_pwm_set_frequency(self.channel, frequency) +# === Library initialization === + + # Initialize the library with a reset Reset() + # line thead type to callable entry point mapping _LINE_THREAD_TYPE_TO_TARGET = { _line_thread_poll: poll_thread, _line_thread_pwm: pwm_thread, } + +# Run cleanup() when an interpreter using this module terminates +atexit.register(cleanup) diff --git a/examples/callback2.py b/examples/callback2.py index e7cc204..c46fd73 100755 --- a/examples/callback2.py +++ b/examples/callback2.py @@ -1,3 +1,4 @@ +#!/bin/python3 # Daniel's example (reproduced bug 6 until it was fixed) import RPi.GPIO as GPIO import time diff --git a/examples/flash18.py b/examples/flash18.py index 23baef6..25677e8 100755 --- a/examples/flash18.py +++ b/examples/flash18.py @@ -1,10 +1,8 @@ #!/bin/python3 import RPi.GPIO as GPIO -import RPi.GPIO_DEVEL as GPIO_DEVEL import time GPIO.setmode(GPIO.BCM) -GPIO_DEVEL.setdebuginfo(True) GPIO.setup(18, GPIO.OUT) for i in range(5): diff --git a/examples/input_examples.py b/examples/input_examples.py new file mode 100755 index 0000000..c79de9e --- /dev/null +++ b/examples/input_examples.py @@ -0,0 +1,75 @@ +#!/bin/python3 +# Input examples from Ben Croston +# source: https://sourceforge.net/p/raspberry-gpio-python/wiki/Inputs/ + +import RPi.GPIO as GPIO +import time + +GPIO.setmode(GPIO.BCM) + +channel = 18 + +GPIO.setup(channel, GPIO.IN, pull_up_down=GPIO.PUD_UP) +# or +GPIO.setup(channel, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) + +if GPIO.input(channel): + print('Input was HIGH') +else: + print('Input was LOW') + +# wait for button (real example doensn't have the "or False" at the end) +while GPIO.input(channel) == GPIO.LOW or False: + time.sleep(0.01) # wait 10 ms to give CPU chance to do other things + + +GPIO.wait_for_edge(channel, GPIO.RISING) + +# wait for up to 5 seconds for a rising edge (timeout is in milliseconds) +channel = GPIO.wait_for_edge(channel, GPIO.RISING, timeout=5000) +if channel is None: + print('Timeout occurred') +else: + print('Edge detected on channel', channel) + + +def do_something(): + print("running do_something()") + + +channel = 18 +GPIO.add_event_detect(channel, GPIO.RISING) # add rising edge detection on a channel +do_something() +if GPIO.event_detected(channel): + print('Button pressed') + + +def my_callback(channel): + print('This is a edge event callback function!') + print('Edge detected on channel %s' % channel) + print('This is run in a different thread to your main program') + + +GPIO.add_event_detect(channel, GPIO.RISING, callback=my_callback) # add rising edge detection on a channel +# ...the rest of your program... + + +def my_callback_one(channel): + print('Callback one') + + +def my_callback_two(channel): + print('Callback two') + + +GPIO.add_event_detect(channel, GPIO.RISING) +GPIO.add_event_callback(channel, my_callback_one) +GPIO.add_event_callback(channel, my_callback_two) + +# add rising edge detection on a channel, ignoring further edges for 200ms for switch bounce handling +GPIO.add_event_detect(channel, GPIO.RISING, callback=my_callback, bouncetime=200) + +# This example is on the linked webpage but it is wrong, I checked the RPi.GPIO source code +# GPIO.add_event_callback(channel, my_callback, bouncetime=200) + +GPIO.remove_event_detect(channel) diff --git a/examples/morse.py b/examples/morse.py index 384fcd3..5b425aa 100755 --- a/examples/morse.py +++ b/examples/morse.py @@ -1,121 +1,152 @@ #!/bin/env python3 -#import wrap as GPIO -#import sys -#from time import sleep -## Python program to implement Morse Code Translator - -# NOTE: this is broken - -#''' -#VARIABLE KEY -#'cipher' -> 'stores the morse translated form of the english string' -#'decipher' -> 'stores the english translated form of the morse string' -#'citext' -> 'stores morse code of a single character' -#'i' -> 'keeps count of the spaces between morse characters' -#'message' -> 'stores the string to be encoded or decoded' -#''' - -#pin=GPIO.Pin(25,GPIO.OUT) -#pin.value = 0 -## Dictionary representing the morse code chart -#MORSE_CODE_DICT = { -# 'A':'.-', 'B':'-...', -# 'C':'-.-.', 'D':'-..', 'E':'.', -# 'F':'..-.', 'G':'--.', 'H':'....', -# 'I':'..', 'J':'.---', 'K':'-.-', -# 'L':'.-..', 'M':'--', 'N':'-.', -# 'O':'---', 'P':'.--.', 'Q':'--.-', -# 'R':'.-.', 'S':'...', 'T':'-', -# 'U':'..-', 'V':'...-', 'W':'.--', -# 'X':'-..-', 'Y':'-.--', 'Z':'--..', -# '1':'.----', '2':'..---', '3':'...--', -# '4':'....-', '5':'.....', '6':'-....', -# '7':'--...', '8':'---..', '9':'----.', -# '0':'-----', ', ':'--..--', '.':'.-.-.-', -# '?':'..--..', '/':'-..-.', '-':'-....-', -# '(':'-.--.', ')':'-.--.-' -# } - -## Function to encrypt the string -## according to the morse code chart -#def encrypt(message): -# cipher = '' -# for letter in message: -# if letter != ' ': - -# # Looks up the dictionary and adds the -# # correspponding morse code -# # along with a space to separate -# # morse codes for different characters -# cipher += MORSE_CODE_DICT[letter] + ' ' -# else: -# # 1 space indicates different characters -# # and 2 indicates different words -# cipher += ' ' - -# return cipher - -## Function to decrypt the string -## from morse to english -#def decrypt(message): - -# # extra space added at the end to access the -# # last morse code -# message += ' ' - -# decipher = '' -# citext = '' -# for letter in message: - -# # checks for space -# if (letter != ' '): -# # counter to keep track of space -# i = 0 -# # storing morse code of a single character -# citext += letter -# # in case of space -# else: -# # if i = 1 that indicates a new character -# i += 1 -# # if i = 2 that indicates a new word -# if i == 2: -# # adding space to separate words -# decipher += ' ' -# else: -# # accessing the keys using their values (reverse of encryption) -# decipher += list(MORSE_CODE_DICT.keys())[list(MORSE_CODE_DICT -# .values()).index(citext)] -# citext = '' - -# return decipher - -## Hard-coded driver function to run the program -#def long(): -# pin.toggle() -# sleep(.4) -# pin.toggle() - -#def short(): -# pin.toggle() -# sleep(.2) -# pin.toggle() -#def main(): -# msg = sys.argv[1] -# result = encrypt(msg.upper()) -# for i in result: -# if i == "-": -# long() -# elif i == "." -# short() -# else: -# sleep(.5) -# sleep(.1) -# #print (result) - -# #message = "--. . . -.- ... -....- ..-. --- .-. -....- --. . . -.- ... " -# #result = decrypt(message) -# #print (result) - -## Executes the main function -#if __name__ == '__main__': -# main() +import RPi.GPIO as GPIO +import sys +from time import sleep + +# Python program to implement Morse Code Translator +# Modifed to interface with the RPi.GPIO API +# source: https://www.geeksforgeeks.org/morse-code-translator-python/ + +channel = 12 + +''' +VARIABLE KEY +'cipher' -> 'stores the morse translated form of the english string' +'decipher' -> 'stores the english translated form of the morse string' +'citext' -> 'stores morse code of a single character' +'i' -> 'keeps count of the spaces between morse characters' +'message' -> 'stores the string to be encoded or decoded' +''' + +# Dictionary representing the morse code chart +MORSE_CODE_DICT = { + 'A': '.-', + 'B': '-...', + 'C': '-.-.', + 'D': '-..', + 'E': '.', + 'F': '..-.', + 'G': '--.', + 'H': '....', + 'I': '..', + 'J': '.---', + 'K': '-.-', + 'L': '.-..', + 'M': '--', + 'N': '-.', + 'O': '---', + 'P': '.--.', + 'Q': '--.-', + 'R': '.-.', + 'S': '...', + 'T': '-', + 'U': '..-', + 'V': '...-', + 'W': '.--', + 'X': '-..-', + 'Y': '-.--', + 'Z': '--..', + '1': '.----', + '2': '..---', + '3': '...--', + '4': '....-', + '5': '.....', + '6': '-....', + '7': '--...', + '8': '---..', + '9': '----.', + '0': '-----', + ',': '--..--', + '.': '.-.-.-', + '?': '..--..', + '/': '-..-.', + '-': '-....-', + '(': '-.--.', + ')': '-.--.-', +} + + +# Function to encrypt the string according to the morse code chart +def encrypt(message): + cipher = '' + for letter in message: + if letter != ' ': + + # Looks up the dictionary and adds the correspponding morse code + # along with a space to separate morse codes for different characters + cipher += MORSE_CODE_DICT[letter] + ' ' + else: + # 1 space indicates different character and 2 indicates different words + cipher += ' ' + + return cipher + + +# Function to decrypt the string from morse to english +def decrypt(message): + + # extra space added at the end to access the last morse code + message += ' ' + + decipher = '' + citext = '' + for letter in message: + + # checks for space + if (letter != ' '): + # counter to keep track of space + i = 0 + # storing morse code of a single character + citext += letter + # in case of space + else: + # if i = 1 that indicates a new character + i += 1 + # if i = 2 that indicates a new word + if i == 2: + # adding space to separate words + decipher += ' ' + else: + # accessing the keys using their values (reverse of encryption) + decipher += list(MORSE_CODE_DICT.keys())[list(MORSE_CODE_DICT.values()).index(citext)] + citext = '' + + return decipher + + +def long_pulse(): + GPIO.output(channel, GPIO.HIGH) + sleep(.4) + GPIO.output(channel, GPIO.LOW) + + +def short_pulse(): + GPIO.output(channel, GPIO.HIGH) + sleep(.2) + GPIO.output(channel, GPIO.LOW) + + +def main(): + GPIO.setmode(GPIO.BOARD) + GPIO.setup(channel, GPIO.OUT) + + if len(sys.argv) > 1: + msg = sys.argv[1] + else: + msg = "hello world" + result = encrypt(msg.upper()) + + for i in result: + if i == "-": + long_pulse() + elif i == ".": + short_pulse() + else: + sleep(.5) + sleep(.1) + GPIO.cleanup() + + +# Executes the main function +if __name__ == '__main__': + main() diff --git a/examples/output_examples.py b/examples/output_examples.py new file mode 100755 index 0000000..e1d83c3 --- /dev/null +++ b/examples/output_examples.py @@ -0,0 +1,46 @@ +#!/bin/python3 +# Output and gpio_function examples from Ben Croston +# source: https://sourceforge.net/p/raspberry-gpio-python/wiki/Outputs/ +# source: https://sourceforge.net/p/raspberry-gpio-python/wiki/Checking%20function%20of%20GPIO%20channels/ + +import RPi.GPIO as GPIO + +GPIO.setmode(GPIO.BOARD) +GPIO.setup((11, 12), GPIO.OUT) + +GPIO.output(12, GPIO.HIGH) +# or +GPIO.output(12, 1) +# or +GPIO.output(12, True) + +GPIO.output(12, GPIO.LOW) +# or +GPIO.output(12, 0) +# or +GPIO.output(12, False) + + +chan_list = (11, 12) +GPIO.output(chan_list, GPIO.LOW) # all LOW +GPIO.output(chan_list, (GPIO.HIGH, GPIO.LOW)) # first LOW, second HIGH + +GPIO.setup(11, GPIO.IN) +GPIO.output(12, not GPIO.input(11)) + +GPIO.cleanup(12) + +func = GPIO.gpio_function(12) +print("is channel 12 GPIO.UNKNOWN?", func == GPIO.UNKNOWN) + +print("is channel 12 GPIO.OUT?:", func == GPIO.OUT) + +print("setting up channel 12 as output...") +GPIO.setup(12, GPIO.OUT) + +func = GPIO.gpio_function(12) +print("is channel 12 GPIO.UNKNOWN?", func == GPIO.UNKNOWN) + +print("is channel 12 GPIO.OUT?:", func == GPIO.OUT) + +GPIO.cleanup() diff --git a/examples/pwm.py b/examples/pwm.py deleted file mode 100755 index 060c556..0000000 --- a/examples/pwm.py +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/python3 -import RPi.GPIO as GPIO -import RPi.GPIO_DEVEL as GPIO_DEVEL -import time - -GPIO.setmode(GPIO.BCM) -# GPIO_DEVEL.setdebuginfo(True) -GPIO.setup(18, GPIO.OUT) -pwm = GPIO.PWM(18, 0.5) -pwm.start(50) - -time.sleep(10) - -for i in range(20): - pwm.ChangeFrequency(2 ** i) - print("set frequency to", 2 ** i) - time.sleep(3) - -pwm.stop() diff --git a/examples/pwm1.py b/examples/pwm1.py new file mode 100755 index 0000000..27b480b --- /dev/null +++ b/examples/pwm1.py @@ -0,0 +1,20 @@ +#!/bin/python3 +import RPi.GPIO as GPIO +import time + +GPIO.setmode(GPIO.BCM) +GPIO.setup(18, GPIO.OUT) +pwm = GPIO.PWM(18, 0.5) +pwm.start(50) + +time.sleep(10) + +try: + for i in range(20): + pwm.ChangeFrequency(2 ** i) + print("set frequency to", 2 ** i) + time.sleep(3) +except KeyboardInterrupt: + pass + +pwm.stop() diff --git a/examples/pwm2.py b/examples/pwm2.py new file mode 100755 index 0000000..b870289 --- /dev/null +++ b/examples/pwm2.py @@ -0,0 +1,25 @@ +#!/bin/python3 +# PWM demo from Ben Croston +# source: https://sourceforge.net/p/raspberry-gpio-python/wiki/PWM/ + +# It works out of the box with no changes! + +import time +import RPi.GPIO as GPIO +GPIO.setmode(GPIO.BOARD) +GPIO.setup(12, GPIO.OUT) + +p = GPIO.PWM(12, 50) # channel=12 frequency=50Hz +p.start(0) +try: + while 1: + for dc in range(0, 101, 5): + p.ChangeDutyCycle(dc) + time.sleep(0.1) + for dc in range(100, -1, -5): + p.ChangeDutyCycle(dc) + time.sleep(0.1) +except KeyboardInterrupt: + pass +p.stop() +GPIO.cleanup() diff --git a/examples/pwm3.py b/examples/pwm3.py new file mode 100755 index 0000000..a72e52f --- /dev/null +++ b/examples/pwm3.py @@ -0,0 +1,42 @@ +#!/bin/python3 +# Another example of PwM usage using the RPi.GPIO API +# By "alex" +# source: https://raspi.tv/2013/rpi-gpio-0-5-2a-now-has-software-pwm-how-to-use-it + +# Don't try to run this as a script or it will all be over very quickly +# it won't do any harm though. +# these are all the elements you need to control PWM on 'normal' GPIO ports +# with RPi.GPIO - requires RPi.GPIO 0.5.2a or higher + +# always needed with RPi.GPIO +import RPi.GPIO as GPIO + + +# choose BCM or BOARD numbering schemes. I use BCM +GPIO.setmode(GPIO.BCM) + +# set GPIO 25 as an output. You can use any GPIO port +GPIO.setup(25, GPIO.OUT) + +# create an object p for PWM on port 25 at 50 Hertz +# you can have more than one of these, but they need +# different names for each port +# e.g. p1, p2, motor, servo1 etc. +p = GPIO.PWM(25, 50) + +# start the PWM on 50 percent duty cycle +# duty cycle value can be 0.0 to 100.0%, floats are OK +p.start(50) + +# change the duty cycle to 90% +p.ChangeDutyCycle(90) + +# change the frequency to 100 Hz (floats also work) +# e.g. 100.5, 5.2 +p.ChangeFrequency(100) + +# stop the PWM output +p.stop() + +# when your program exits, tidy up after yourself +GPIO.cleanup() diff --git a/examples/pwm4.py b/examples/pwm4.py new file mode 100755 index 0000000..8667a50 --- /dev/null +++ b/examples/pwm4.py @@ -0,0 +1,42 @@ +#!/bin/python3 +# A random PwM script pulled from a comment section +# by "Nick" and improved by "AndrewS" (@lurch on GitHub) +# source: https://raspi.tv/2013/rpi-gpio-0-5-2a-now-has-software-pwm-how-to-use-it#comment-29887 +# source: https://raspi.tv/2013/rpi-gpio-0-5-2a-now-has-software-pwm-how-to-use-it#comment-30520 + +import RPi.GPIO as GPIO +import time + +# PWM frequency +HZ = 100 +FADESPEED = 0.002 + +GPIO.setmode(GPIO.BCM) + +gpioPinsList = [["r1", 18], ["g1", 23], ["b1", 25], ["r2", 17], ["g2", 22], ["b2", 24]] +gpioPinsObjs = [] + +# setup GPIO pins as outputs and create PWM objects for each +for i in range(len(gpioPinsList)): + GPIO.setup(gpioPinsList[i][1], GPIO.OUT) + gpioPinsObjs.append(GPIO.PWM(gpioPinsList[i][1], HZ)) + +try: + for pinObj in gpioPinsObjs: + pinObj.start(100) + time.sleep(FADESPEED) + while True: + #fade in + for i in range(101): + for pinObj in gpioPinsObjs: + pinObj.ChangeDutyCycle(0 + i) + time.sleep(FADESPEED) + + #fade out + for i in range(101): + for pinObj in gpioPinsObjs: + pinObj.ChangeDutyCycle(100 - i) + time.sleep(FADESPEED) +except KeyboardInterrupt: + GPIO.cleanup() + pass diff --git a/examples/pwm_usage.py b/examples/pwm_usage.py new file mode 100755 index 0000000..8a1f257 --- /dev/null +++ b/examples/pwm_usage.py @@ -0,0 +1,31 @@ +#!/bin/python3 +# PWM examples from Ben Croston +# source: https://sourceforge.net/p/raspberry-gpio-python/wiki/PWM/ +import RPi.GPIO as GPIO + +GPIO.setmode(GPIO.BOARD) +channel = 11 +frequency = 10 +freq = 100 +dc = 20 + +GPIO.setup(11, GPIO.OUT) + +p = GPIO.PWM(channel, frequency) + +p.start(dc) # where dc is the duty cycle (0.0 <= dc <= 100.0) + +p.ChangeFrequency(freq) # where freq is the new frequency in Hz + +dc = 30 +p.ChangeDutyCycle(dc) # where 0.0 <= dc <= 100.0 + +p.stop() + +GPIO.setup(12, GPIO.OUT) + +p = GPIO.PWM(12, 0.5) +p.start(1) +input('Press return to stop:') # use raw_input for Python 2 +p.stop() +GPIO.cleanup() diff --git a/examples/random_usage.py b/examples/random_usage.py new file mode 100755 index 0000000..a1a2ca3 --- /dev/null +++ b/examples/random_usage.py @@ -0,0 +1,53 @@ +#!/bin/python3 +# Random examples from Ben Croston +# source: https://sourceforge.net/p/raspberry-gpio-python/wiki/BasicUsage/ +import RPi.GPIO as GPIO +import RPi.GPIO_DEVEL as GPIO_DEVEL + +GPIO.setmode(GPIO.BOARD) + +GPIO_DEVEL.Reset() + +GPIO.setmode(GPIO.BCM) + +mode = GPIO.getmode() + +print("Is mode BCM:", mode == GPIO.BCM) + +GPIO.setwarnings(False) + +channel = 18 +GPIO.setup(channel, GPIO.IN) +GPIO.setup(channel, GPIO.OUT) +GPIO.setup(channel, GPIO.OUT, initial=GPIO.HIGH) + +# add as many channels as you want! +# you can tuples instead i.e.: +# chan_list = (11,12) +chan_list = [11, 12] +GPIO.setup(chan_list, GPIO.OUT) + +GPIO.setup(18, GPIO.OUT) + +GPIO.input(channel) + +chan_list = [11, 12] # also works with tuples +GPIO.output(chan_list, GPIO.LOW) # sets all to GPIO.LOW +GPIO.output(chan_list, (GPIO.HIGH, GPIO.LOW)) # sets first HIGH and second LOW + +GPIO.cleanup() + +channel = 18 +channel1 = 19 +channel2 = 21 + +GPIO.cleanup(channel) +GPIO.cleanup((channel1, channel2)) +GPIO.cleanup([channel1, channel2]) + +print("Some useful information:") +print("RPi.GPIO_INFO:", GPIO.RPI_INFO) +print("RPi.GPIO_INFO['P1_REVISION]':", GPIO.RPI_INFO['P1_REVISION']) +print("GPIO.RPI_REVISION", GPIO.RPI_REVISION) # (deprecated) + +print("RPi.GPIO.VERSION:", GPIO.VERSION) diff --git a/examples/try_import.py b/examples/try_import.py new file mode 100755 index 0000000..5894f8c --- /dev/null +++ b/examples/try_import.py @@ -0,0 +1,17 @@ +#!/bin/python3 +# An example of how one may import this library +# by Ben Croston +# Source: https://sourceforge.net/p/raspberry-gpio-python/wiki/BasicUsage/ + +try: + import RPi.GPIO as GPIO +except RuntimeError: + print("Error importing RPi.GPIO! \ + This is probably because you need superuser privileges. \ + You can achieve this by using 'sudo' to run your script") + + +# Note that one may use this library as a non-superuser +# by setting the Linux file group to a group such as gpi +# and adding a user to that group with a command +# like: `sudo usermod -aG gpio ` diff --git a/non_root_permission.sh b/non_root_permission.sh index 1c5d6fb..d34ba49 100755 --- a/non_root_permission.sh +++ b/non_root_permission.sh @@ -3,6 +3,10 @@ # Inspiration: https://forum.armbian.com/topic/8714-gpio-not-working-for-non-root/?do=findComment&comment=86295 # Run this script to enable all users in Linux user group gpio to access the gpio pins +# NOTE: the changes made by this script do _not_ persist after reboot. +# Until we provide an automated solution, we suggest that one +# place this snippet of code in a script that runs at system startup. + if [ "$UID" != "0" ] then echo "Script must be run as root! quitting..." diff --git a/requirements.txt b/requirements.txt index dce821f..c448acf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,20 @@ -pytest==5.2.2 -pytest-cov==2.8.1 -flake8==3.7.9 +bcrypt==3.1.6 +cffi==1.12.3 +coverage==4.5.4 +cryptography==2.6.1 +dbus-python==1.2.8 +gpg==1.13.1 +libcomps==0.1.15 +psutil==5.6.7 +pwquality==1.4.2 +pycairo==1.18.1 +PyGObject==3.34.0 +PyNaCl==1.3.0 +pyparted==3.11.2 +pyrsistent==0.16.0 +PyYAML==5.3.1 +-e git+https://github.com/underground-software/python3-libgpiod-rpi@00e7588bab1489cd81c1ee62349d4d4122d96e3d#egg=RPi.GPIO +rpm==4.15.1 +selinux==2.9 +setools==4.2.2 +systemd-python==234 diff --git a/spec/spec.pdf b/spec/spec.pdf index 46424d7a15c3d117ab2d8022b733ef9247dd37dd..51cb1228cdc49eb4e1f335812bf7184edc41f2c1 100644 GIT binary patch delta 43206 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

LdgMH~e`V-EC5RQab)=Nu>btbrS4Hhy9)&Uf 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 SBq<^XI~yW3wWP8X;(q{