diff --git a/Adafruit_BBIO/Encoder.py b/Adafruit_BBIO/Encoder.py index e978c90..0e94fa6 100644 --- a/Adafruit_BBIO/Encoder.py +++ b/Adafruit_BBIO/Encoder.py @@ -4,12 +4,26 @@ import os import logging import itertools +from .sysfs import Node +import platform +(major, minor, patch) = platform.release().split("-")[0].split(".") +if not (int(major) >= 4 and int(minor) >= 4): + raise ImportError( + 'The Encoder module requires Linux kernel version >= 4.4.x.\n' + 'Please upgrade your kernel to use this module.\n' + 'Your Linux kernel version is {}.'.format(platform.release())) + + +# eQEP module channel identifiers +# eQEP 2 and 2b are the same channel, exposed on two different sets of pins, +# which are mutually exclusive eQEP0 = 0 eQEP1 = 1 eQEP2 = 2 eQEP2b = 3 +# Definitions to initialize the eQEP modules _OCP_PATH = "/sys/devices/platform/ocp" _eQEP_DEFS = [ {'channel': 'eQEP0', 'pin_A': 'P9_92', 'pin_B': 'P9_27', @@ -33,7 +47,7 @@ def fromdict(cls, d): '''Creates a class instance from a dictionary''' allowed = ('channel', 'pin_A', 'pin_B', 'sys_path') - df = {k: v for k, v in d.iteritems() if k in allowed} + df = {k: v for k, v in d.items() if k in allowed} return cls(**df) def __init__(self, channel, pin_A, pin_B, sys_path): @@ -50,203 +64,236 @@ def __init__(self, channel, pin_A, pin_B, sys_path): rotary encoder sys_path (str): sys filesystem path to access the attributes of this eQEP module + node (str): sys filesystem device node that contains the + readable or writable attributes to control the QEP channel ''' self.channel = channel self.pin_A = pin_A self.pin_B = pin_B self.sys_path = sys_path + self.node = Node(sys_path) class RotaryEncoder(object): - - def _run_cmd(self, cmd): - '''Runs a command. If not successful (i.e. error code different than zero), - print the stderr output as a warning. + ''' + Rotary encoder class abstraction to control a given QEP channel. + + Constructor: + eqep_num: QEP object that determines which channel to control + + Properties: + position: current position of the encoder + frequency: frequency at which the encoder reports new positions + enabled: (read only) true if the module is enabled, false otherwise + mode: current mode of the encoder (absolute: 0, relative: 1) + + Methods: + enable: enable the QEP channel + disable: disable the QEP channel + setAbsolute: shortcut for setting the mode to absolute + setRelative: shortcut for setting the mode to relative + zero: shortcut for setting the position to 0 ''' - try: - output = check_output(cmd, stderr=STDOUT) - self._logger.info("_run_cmd(): cmd='{}' return code={} output={}".format( - " ".join(cmd), 0, output)) - except CalledProcessError as e: - self._logger.warning( - "_run_cmd(): cmd='{}' return code={} output={}".format( - " ".join(cmd), e.returncode, e.output)) + def _run_cmd(self, cmd): + '''Runs a command. If not successful (i.e. error code different than + zero), print the stderr output as a warning. - def config_pin(self, pin): - ''' - config_pin() - Config pin for QEP - ''' + ''' + try: + output = check_output(cmd, stderr=STDOUT) + self._logger.info( + "_run_cmd(): cmd='{}' return code={} output={}".format( + " ".join(cmd), 0, output)) + except CalledProcessError as e: + self._logger.warning( + "_run_cmd(): cmd='{}' return code={} output={}".format( + " ".join(cmd), e.returncode, e.output)) + + def _config_pin(self, pin): + '''Configures a pin in QEP mode using the `config-pin` binary''' + + self._run_cmd(["config-pin", pin, "qep"]) + + def __init__(self, eqep_num): + '''Creates an instance of the class RotaryEncoder. + + Arguments: + eqep_num: determines which eQEP pins are set up. + Allowed values: EQEP0, EQEP1, EQEP2 or EQEP2b, + based on which pins the physical rotary encoder + is connected to. - self._run_cmd(["config-pin", pin, "qep"]) + ''' + # nanoseconds factor to convert period to frequency and back + self._NS_FACTOR = 1000000000 - def cat_file(self, path): - ''' - cat_file() - Print contents of file - ''' + # Set up logging at the module level + self._logger = logging.getLogger(__name__) + self._logger.addHandler(logging.NullHandler()) - self._run_cmd(["cat", path]) + # Initialize the eQEP channel structures + self._eqep = eQEP.fromdict(_eQEP_DEFS[eqep_num]) + self._logger.info( + "Configuring: {}, pin A: {}, pin B: {}, sys path: {}".format( + self._eqep.channel, self._eqep.pin_A, self._eqep.pin_B, + self._eqep.sys_path)) - def __init__(self, eqep_num): - ''' - RotaryEncoder(eqep_num) - Creates an instance of the class RotaryEncoder. - eqep_num determines which eQEP pins are set up. - eqep_num can be: EQEP0, EQEP1, EQEP2 or EQEP2b based on which pins \ - the rotary encoder is connected to. - ''' + # Configure the pins for the given channel + self._config_pin(self._eqep.pin_A) + self._config_pin(self._eqep.pin_B) - self._logger = logging.getLogger(__name__) - self._logger.addHandler(logging.NullHandler()) + self._logger.debug( + "RotaryEncoder(): sys node: {0}".format(self._eqep.sys_path)) - # Configure eqep module - self._eqep = eQEP.fromdict(_eQEP_DEFS[eqep_num]) - self._logger.info( - "Configuring: {}, pin A: {}, pin B: {}, sys path: {}".format( - self._eqep.channel, self._eqep.pin_A, self._eqep.pin_B, - self._eqep.sys_path)) + # Enable the channel upon initialization + self.enable() - self.config_pin(self._eqep.pin_A) - self.config_pin(self._eqep.pin_B) + @property + def enabled(self): + '''Returns the enabled status of the module: - self.base_dir = self._eqep.sys_path - self._logger.debug( - "RotaryEncoder(): self.base_dir: {0}".format(self.base_dir)) + true: module is enabled + false: module is disabled + ''' + isEnabled = bool(int(self._eqep.node.enabled)) - self.enable() + return isEnabled - def enable(self): - ''' - enable() - Turns the eQEP hardware ON - ''' - enable_file = "%s/enabled" % self.base_dir - self._logger.debug("enable(): enable_file: {0}".format(enable_file)) - self._logger.warning( - "enable(): TODO: not implemented, write 1 to {}".format(enable_file)) - #return sysfs.kernelFileIO(enable_file, '1') + def _setEnable(self, enabled): + '''Turns the eQEP hardware ON or OFF - def disable(self): - ''' - disable() - Turns the eQEP hardware OFF - ''' - enable_file = "%s/enabled" % self.base_dir - self._logger.debug("disable(): enable_file: {0}".format(enable_file)) - self._logger.warning( - "disable(): TODO: not implemented, write 0 to {}".format(enable_file)) - #return sysfs.kernelFileIO(enable_file, '0') + value (int): 1 represents enabled, 0 is disabled - def setAbsolute(self): - ''' - setAbsolute() - Set mode as Absolute - The position starts at zero and is incremented or - decremented by the encoder's movement - ''' - mode_file = "%s/mode" % self.base_dir - self._logger.debug("setAbsolute(): mode_file: {0}".format(mode_file)) - self._logger.warning( - "setAbsolute(): TODO: not implemented, write 0 to {}".format(mode_file)) - #return sysfs.kernelFileIO(mode_file, '0') + ''' + enabled = int(enabled) + if enabled < 0 or enabled > 1: + raise ValueError( + 'The "enabled" attribute can only be set to 0 or 1. ' + 'You attempted to set it to {}.'.format(enabled)) - def setRelative(self): - ''' - setRelative() - Set mode as Relative - The position is reset when the unit timer overflows. - ''' - mode_file = "%s/mode" % self.base_dir - self._logger.debug("setRelative(): mode_file: {0}".format(mode_file)) - self._logger.warning( - "setRelative(): TODO: not implemented, write 1 to {}".format(mode_file)) - #return sysfs.kernelFileIO(mode_file, '1') + self._eqep.node.enabled = str(enabled) + self._logger.info("Channel: {}, enabled: {}".format( + self._eqep.channel, self._eqep.node.enabled)) - def getMode(self): - ''' - getMode() - Returns the mode the eQEP hardware is in. - ''' - mode_file = "%s/mode" % self.base_dir - self._logger.debug("getMode(): mode_file: {0}".format(mode_file)) - self._logger.warning("getMode(): TODO: read mode_file") - #return sysfs.kernelFileIO(mode_file) + def enable(self): + '''Turns the eQEP hardware ON''' - def getPosition(self): - ''' - getPosition() - Get the current position of the encoder. - In absolute mode, this attribute represents the current position - of the encoder. - In relative mode, this attribute represents the position of the - encoder at the last unit timer overflow. - ''' - self._logger.debug("Channel: {}".format(self._eqep.channel)) - position_file = "%s/position" % self.base_dir - self._logger.debug("getPosition(): position_file: {0}".format(position_file)) - position_handle = open(position_file, 'r') - self._logger.debug("getPosition(): position_handle: {0}".format(position_handle)) - position = position_handle.read() - self._logger.debug("getPosition(): position: {0}".format(position)) - #return sysfs.kernelFileIO(position_file) - - return position - - def setFrequency(self, freq): - ''' - setFrequency(freq) - Set the frequency in Hz at which the driver reports new positions. - ''' - period_file = "%s/period" % self.base_dir - self._logger.debug("setFrequency(): period_file: {0}".format(period_file)) - self._logger.debug("setFrequency(): freq: {0}".format(freq)) - self._logger.debug("setFrequency(): 1000000000/freq: {0}".format(1000000000/freq)) - self._logger.debug("setFrequency(): str(1000000000/freq)): {0}".format(str(1000000000/freq))) - self._logger.warning( - "setFrequency(): TODO: not implemented, set {} to {}".format( - period_file, str(1000000000/freq))) - #return sysfs.kernelFileIO(period_file, str(1000000000/freq)) - - def setPosition(self, val): - ''' - setPosition(value) - Give a new value to the current position - ''' - position_file = "%s/position" % self.base_dir - self._logger.warning( - "setPosition(): TODO: not implemented, write position to {}".format( - position_file)) - #return sysfs.kernelFileIO(position_file, str(val)) + self._setEnable(1) - def zero(self): - ''' - zero()s - Set the current position to 0 - ''' - return self.setPosition(0) - - -#""" -# encoder_test.py -# Rekha Seethamraju -# An example to demonstrate the use of the eQEP library -# for PyBBIO. -# This example program is in the public domain. -#""" -#from bbio import * -#from bbio.libraries.RotaryEncoder import RotaryEncoder -# -#encoder = RotaryEncoder(RotaryEncoder.EQEP2b) -# -#def setup(): -# encoder.setAbsolute() -# encoder.zero() -# -#def loop(): -# print("encoder position : "+encoder.getPosition()) -# delay(1000) -# -#run(setup, loop) + def disable(self): + '''Turns the eQEP hardware OFF''' + + self._setEnable(0) + + @property + def mode(self): + '''Returns the mode the eQEP hardware is in (absolute or relative). + + ''' + mode = int(self._eqep.node.mode) + + if mode == 0: + mode_name = "absolute" + elif mode == 1: + mode_name = "relative" + else: + mode_name = "invalid" + + self._logger.debug("getMode(): Channel {}, mode: {} ({})".format( + self._eqep.channel, mode, mode_name)) + + return mode + + @mode.setter + def mode(self, mode): + '''Sets the eQEP mode as absolute (0) or relative (1). + See the setAbsolute() and setRelative() methods for + more information. + + ''' + mode = int(mode) + if mode < 0 or mode > 1: + raise ValueError( + 'The "mode" attribute can only be set to 0 or 1. ' + 'You attempted to set it to {}.'.format(mode)) + + self._eqep.node.mode = str(mode) + self._logger.debug("Mode set to: {}".format( + self._eqep.node.mode)) + + def setAbsolute(self): + '''Sets the eQEP mode as Absolute: + The position starts at zero and is incremented or + decremented by the encoder's movement + + ''' + self.mode = 0 + + def setRelative(self): + '''Sets the eQEP mode as Relative: + The position is reset when the unit timer overflows. + + ''' + self.mode = 1 + + @property + def position(self): + '''Returns the current position of the encoder. + In absolute mode, this attribute represents the current position + of the encoder. + In relative mode, this attribute represents the position of the + encoder at the last unit timer overflow. + + ''' + position = self._eqep.node.position + + self._logger.debug("Get position: Channel {}, position: {}".format( + self._eqep.channel, position)) + + return int(position) + + @position.setter + def position(self, position): + '''Sets the current position to a new value''' + + position = int(position) + self._eqep.node.position = str(position) + + self._logger.debug("Set position: Channel {}, position: {}".format( + self._eqep.channel, position)) + + + @property + def frequency(self): + '''Sets the frequency in Hz at which the driver reports + new positions. + + ''' + frequency = self._eqep.node.period / self._NS_FACTOR + + self._logger.debug( + "Set frequency(): Channel {}, frequency: {} Hz, " + "period: {} ns".format( + self._eqep.channel, frequency, period)) + + return frequency + + @frequency.setter + def frequency(self, frequency): + '''Sets the frequency in Hz at which the driver reports + new positions. + + ''' + period = self._NS_FACTOR / frequency # Period in nanoseconds + self._eqep.node.period = str(period) + self._logger.debug( + "Set frequency(): Channel {}, frequency: {} Hz, " + "period: {} ns".format( + self._eqep.channel, frequency, period)) + + def zero(self): + '''Resets the current position to 0''' + + self.position = 0 diff --git a/Adafruit_BBIO/README.md b/Adafruit_BBIO/README.md index aa3642b..8bb4d7d 100644 --- a/Adafruit_BBIO/README.md +++ b/Adafruit_BBIO/README.md @@ -1,52 +1,72 @@ -# Adafruit_BBIO.Encoder module +# Adafruit_BBIO.Encoder -This module enables access to the Beaglebone Black enhanced Quadrature Encoder Pulse (eQEP) modules: eQEP0, eQEP1 and eQEP2. +This module enables access to the Beaglebone Black enhanced Quadrature Encoder Pulse (eQEP) modules: eQEP0, eQEP1 and eQEP2/eQEP2b. -Initially based on the [PyBBIO](https://github.com/graycatlabs/PyBBIO/bbio/libraries/RotaryEncoder/rotary_encoder.py) rotary encoder code. +## Usage -## Prerequisites +On a recent Beaglebone Debian image, access to the eQEP0 and eQEP2 channels should work out of the box: -These instructions are based on a 4.4.x Linux kernel. +```python +import Adafruit_BBIO.Encoder as Encoder -In order to use all eQEP pins the BeagleBone must boot with the [cape-universal](https://github.com/beagleboard/bb.org-overlays/tree/master/tools/beaglebone-universal-io) enabled, and load the cape-universal overlay +''' +Each channel can be accessed and initialized using its corresponding +channel name constants: -``` -enable_uboot_cape_universal=1 + Encoder.eQEP0 + Encoder.eQEP1 # Pins only available when video is disabled + Encoder.eQEP2 + Encoder.eQEP2b # Pins only available when video is disabled +''' + +# Instantiate the class to access channel eQEP2, and only initialize +# that channel +myEncoder = Encoder.RotaryEncoder(Encoder.eQEP2) ``` -Notes: -- It seems that the `cape-universal` cape _does only enable access to eQEP0 and eQEP2_. TBD: check how to load [`cape-universala`](https://github.com/cdsteinkuehler/beaglebone-universal-io/pull/30) -- An alternative option to the `cape-universal` overlay would be to load one of the [dedicated eQEP overlays](https://github.com/Teknoman117/beaglebot/tree/master/encoders/dts). +If you need to use further channels, read on the prerequisites in the following section. -### Install/upgrade the latest Device Tree overlays +## Prerequisites + +These instructions are based on: + +- Linux kernel: 4.4.x or later +- `bb-cape-overlays` package: version 4.4.20171120.0-0rcnee1~stretch+20171120 or later +- `bb-customizations` package: version 1.20171123-0rcnee0~stretch+20171123 or later + +It's recommended to run the following commands to ensure you have the latest required packages: ``` -sudo apt-get upgrade bb-cape-overlays +sudo apt update +sudo apt upgrade bb-cape-overlays bb-customizations ``` -### Load the universal cape +In order to use all eQEP pins the BeagleBone must boot with the [cape-universal](https://github.com/beagleboard/bb.org-overlays/tree/master/tools/beaglebone-universal-io) enabled, and load the `cape-universal` overlay. -If it doesn't already contain it, modify the `/boot/uEnv.txt` file to contain this line: +This is the default, thus **no further steps are initially required to use eQEP0 and eQEP2**. Simply double-check that the following line is present and not commented out on your `/boot/uEnv.txt` file: ``` enable_uboot_cape_universal=1 ``` -Notes: +Note: Some older documentation recommends using the `cmdline` and `cape_enable` options instead. They are meant to load deprecated kernel-based overlays and it's not recommended to use them. Use the new way of [loading overlays via uboot](https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#U-Boot_Overlays) instead, as instructed above. -- Some older documentation recommends using these two lines instead. They are meant to load deprecated kernel-based overlays and it's not recommended to use them. Use the new way of [loading overlays via uboot](https://elinux.org/Beagleboard:BeagleBoneBlack_Debian#U-Boot_Overlays) instead, as instructed above. +### Enabling additional eQEP modules - ``` - cmdline=cape_universal=enable # Plus some other options - ``` - ``` - cape_enable=bone_capemgr.enable_partno=cape-universala - ``` -- TBD: check the overlays that are currently loaded +The `cape-universal` overlay will enable access to the eQEP0 and eQEP2 modules. As it does not expose pins that are shared with the HDMI interface, eQEP1 and eQEP2b will **not** be available. + +To disable the HDMI interface and gain access to the pins and peripherals that share its pins, comment out the following line on the `/boot/uEnv.txt` file and reboot: + +``` +disable_uboot_overlay_video=1 +``` ## eQEP configuraton -Note: if either eQEP1 or eQEP2b are used on the Beaglebone Black, video must be disabled, as their pins are shared with the LCD_DATAx lines of the HDMI interface. +Notes: + +- If either eQEP1 or eQEP2b are used on the Beaglebone Black, video must be disabled, as their pins are shared with the LCD_DATAx lines of the HDMI interface. +- eQEP2 and eQEP2b are the same module, but with the alternative of accessing it via two sets of pins. These are mutually exclusive. ### eQEP0 @@ -91,7 +111,12 @@ $ config-pin P8.41 qep $ config-pin P8.42 qep $ cat /sys/devices/platform/ocp/48304000.epwmss/48304180.eqep/position ``` + +## Credits + +Initially based on the [PyBBIO](https://github.com/graycatlabs/PyBBIO/bbio/libraries/RotaryEncoder/rotary_encoder.py) rotary encoder code. + ## Further reading -- [Beaglebone encoder inputs](https://github.com/Teknoman117/beaglebot/tree/master/encoders) -- [Beaglebone eQEP overlays](https://github.com/Teknoman117/beaglebot/tree/master/encoders/dts) +1. [Beaglebone encoder inputs](https://github.com/Teknoman117/beaglebot/tree/master/encoders) +1. [Beaglebone eQEP overlays](https://github.com/Teknoman117/beaglebot/tree/master/encoders/dts) diff --git a/Adafruit_BBIO/sysfs.py b/Adafruit_BBIO/sysfs.py new file mode 100644 index 0000000..43fd078 --- /dev/null +++ b/Adafruit_BBIO/sysfs.py @@ -0,0 +1,118 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright (c) 2014 MIT OpenCourseWare +# Copyright (c) 2017 Adafruit Industries +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# +# Code originally published at http://stackoverflow.com/questions/4648792/ and +# subsequently forked at https://github.com/ponycloud/python-sysfs +# +# Original author: Benedikt Reinartz +# Contributors: +# - Jan Dvořák +# - Jonathon Reinhart https://github.com/JonathonReinhart +# - Ondřej Koch +# - David Planella + +""" +Simplistic Python SysFS interface. It enables access to the sys filesystem device +nodes and to get and set their exposed attributes. + +Usage examples:: + from sysfs import sys + + # Print all block devices in /sys, with their sizes + for block_dev in sys.block: + print block_dev, str(int(block_dev.size) / 1048576) + ' M' + + >>> import sysfs + >>> # Read/write Beaglebone Black's eQEP module attributes + >>> eqep0 = sysfs.Node("/sys/devices/platform/ocp/48300000.epwmss/48300180.eqep") + >>> # Read eqep attributes + >>> eqep0.enabled + '1' + >>> eqep0.mode + '0' + >>> eqep0.period + '1000000000' + >>> eqep0.position + '0' + >>> # Write eqep attributes. They should be strings. + >>> eqep0.position = str(2) + >>> eqep0.position + '2' +""" + +from os import listdir +from os.path import isdir, isfile, join, realpath, basename + +__all__ = ['sys', 'Node'] + + +class Node(object): + __slots__ = ['_path_', '__dict__'] + + def __init__(self, path='/sys'): + self._path_ = realpath(path) + if not self._path_.startswith('/sys/') and not '/sys' == self._path_: + raise RuntimeError('Using this on non-sysfs files is dangerous!') + + self.__dict__.update(dict.fromkeys(listdir(self._path_))) + + def __repr__(self): + return '' % self._path_ + + def __str__(self): + return basename(self._path_) + + def __setattr__(self, name, val): + if name.startswith('_'): + return object.__setattr__(self, name, val) + + path = realpath(join(self._path_, name)) + if isfile(path): + with open(path, 'w') as fp: + fp.write(val) + else: + raise RuntimeError('Cannot write to non-files.') + + def __getattribute__(self, name): + if name.startswith('_'): + return object.__getattribute__(self, name) + + path = realpath(join(self._path_, name)) + if isfile(path): + with open(path, 'r') as fp: + return fp.read().strip() + elif isdir(path): + return Node(path) + + def __setitem__(self, name, val): + return setattr(self, name, val) + + def __getitem__(self, name): + return getattr(self, name) + + def __iter__(self): + return iter(getattr(self, name) for name in listdir(self._path_)) + + +sys = Node() diff --git a/README.md b/README.md index 32da985..6445bcf 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,22 @@ sudo pip install --upgrade Adafruit_BBIO Using the library is very similar to the excellent RPi.GPIO library used on the Raspberry Pi. Below are some examples. +### Pin Numbers + +Please note that there is no '0' prefix for the pin numbers. For example, pin 7 on header P8 is `P8_7`. + +**Correct:** +``` +GPIO.setup("P8_7", OUT ) +``` + +**INCORRECT:** +``` +GPIO.setup("P8_07", OUT ) +``` + +Refer to `pins_t table[]` in [common.c](https://github.com/adafruit/adafruit-beaglebone-io-python/blob/master/source/common.c#L73) all the pin labels. + ### config-pin [config-pin](https://github.com/beagleboard/bb.org-overlays/tree/master/tools/beaglebone-universal-io) is now used on the official BeagleBoard.org Debian Jessie and Stretch images to control pin mode (e.g. pin mux). diff --git a/install_all_python_versions.sh b/install_all_python_versions.sh new file mode 100755 index 0000000..932c462 --- /dev/null +++ b/install_all_python_versions.sh @@ -0,0 +1,9 @@ +#!/bin/bash +# useful for testing changes against all versions of python +make clean +echo "Install Python 2.7" +python2.7 ./setup.py install +echo "Install Python 3.5" +python3.5 ./setup.py install +echo "Install Python 3.6" +python3.6 ./setup.py install diff --git a/pytest_all_versions.sh b/pytest_all_versions.sh new file mode 100755 index 0000000..dca6919 --- /dev/null +++ b/pytest_all_versions.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# useful for testing changes against all versions of python + +cd test +echo "Testing Python 2.7" +python2.7 -mpytest +echo "Testing Python 3.5" +python3.5 -mpytest +echo "Testing Python 3.6" +python3.6 -mpytest +cd .. diff --git a/source/py_pwm.c b/source/py_pwm.c index 49c539b..55f50f9 100644 --- a/source/py_pwm.c +++ b/source/py_pwm.c @@ -217,8 +217,8 @@ static const char moduledocstring[] = "PWM functionality of a BeagleBone using P PyMethodDef pwm_methods[] = { {"start", (PyCFunction)py_start_channel, METH_VARARGS | METH_KEYWORDS, "Set up and start the PWM channel. channel can be in the form of 'P8_10', or 'EHRPWM2A'"}, {"stop", (PyCFunction)py_stop_channel, METH_VARARGS | METH_KEYWORDS, "Stop the PWM channel. channel can be in the form of 'P8_10', or 'EHRPWM2A'"}, - { "set_duty_cycle", (PyCFunction)py_set_duty_cycle, METH_VARARGS, "Change the duty cycle\ndutycycle - between 0.0 and 100.0" }, - { "set_frequency", (PyCFunction)py_set_frequency, METH_VARARGS, "Change the frequency\nfrequency - frequency in Hz (freq > 0.0)" }, + { "set_duty_cycle", (PyCFunction)py_set_duty_cycle, METH_VARARGS | METH_KEYWORDS, "Change the duty cycle\ndutycycle - between 0.0 and 100.0" }, + { "set_frequency", (PyCFunction)py_set_frequency, METH_VARARGS | METH_KEYWORDS, "Change the frequency\nfrequency - frequency in Hz (freq > 0.0)" }, {"cleanup", py_cleanup, METH_VARARGS, "Clean up by resetting all GPIO channels that have been used by this program to INPUT with no pullup/pulldown and no event detection"}, //{"setwarnings", py_setwarnings, METH_VARARGS, "Enable or disable warning messages"}, {NULL, NULL, 0, NULL} diff --git a/test/test_rotary.py b/test/test_rotary.py deleted file mode 100755 index 2292cd0..0000000 --- a/test/test_rotary.py +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/python -# -# BeagleBone must boot with cape-universal enabled -# and load the cape-universala overlay in order to -# use all the eQEP pins -# -# Install the latest Device Tree overlays: -# ======================================== -# sudo apt-get upgrade bb-cape-overlays -# -# File: /boot/uEnv.txt -# ==================== -# uname_r=4.4.62-ti-r99 -# cmdline=coherent_pool=1M quiet cape_universal=enable -# cape_enable=bone_capemgr.enable_partno=cape-universala -# -# File: /sys/devices/platform/bone_capemgr/slots -# ============================================== -# 0: PF---- -1 -# 1: PF---- -1 -# 2: PF---- -1 -# 3: PF---- -1 -# 4: P-O-L- 0 Override Board Name,00A0,Override Manuf,cape-universala -# -# eqep0: P9_27, P9_92 -# =================== -# config-pin P9_27 qep -# config-pin P9_92 qep # alias for P9_42.1 -# cat /sys/devices/platform/ocp/48300000.epwmss/48300180.eqep/position -# -# eqep1: P8.33, P8.35 -# =================== -# config-pin P8.33 qep -# config-pin P8.35 qep -# cat /sys/devices/platform/ocp/48302000.epwmss/48302180.eqep/position -# -# eqep2: P8.11, P8.12 -# =================== -# config-pin P8.11 qep -# config-pin P8.12 qep -# cat /sys/devices/platform/ocp/48304000.epwmss/48304180.eqep/position -# -# alternate pins for eqep2 (mutually exclusive) -# eqep2b: P8.41, P8.42 -# ==================== -# config-pin P8.41 qep -# config-pin P8.42 qep -# cat /sys/devices/platform/ocp/48304000.epwmss/48304180.eqep/position -# -# -# How To Run This Test: -# debian@beaglebone:~/ssh/adafruit-beaglebone-io-python$ sudo python ./setup.py install &> /dev/null && sudo python ./test/test_rotary.py -# -# - -import Adafruit_BBIO.Encoder as Encoder - -qep = Encoder.RotaryEncoder(0) -print("qep.getPosition(): {0}".format(qep.getPosition())) - -qep = Encoder.RotaryEncoder(1) -print("qep.getPosition(): {0}".format(qep.getPosition())) - -qep = Encoder.RotaryEncoder(2) -print("qep.getPosition(): {0}".format(qep.getPosition())) - - -#qep.getMode() -#qep.setAbsolute() -#qep.setRelative() -#qep.setFrequency(5000) -#qep.setPosition(100) -#qep.disable() -#print("qep.enable(): {0}".format(qep.enable())) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy