diff options
Diffstat (limited to 'Adafruit_Python_GPIO/Adafruit_GPIO')
-rw-r--r-- | Adafruit_Python_GPIO/Adafruit_GPIO/FT232H.py | 816 | ||||
-rw-r--r-- | Adafruit_Python_GPIO/Adafruit_GPIO/GPIO.py | 426 | ||||
-rw-r--r-- | Adafruit_Python_GPIO/Adafruit_GPIO/I2C.py | 202 | ||||
-rw-r--r-- | Adafruit_Python_GPIO/Adafruit_GPIO/MCP230xx.py | 165 | ||||
-rw-r--r-- | Adafruit_Python_GPIO/Adafruit_GPIO/PCA95xx.py | 121 | ||||
-rw-r--r-- | Adafruit_Python_GPIO/Adafruit_GPIO/PCF8574.py | 94 | ||||
-rw-r--r-- | Adafruit_Python_GPIO/Adafruit_GPIO/PWM.py | 128 | ||||
-rw-r--r-- | Adafruit_Python_GPIO/Adafruit_GPIO/Platform.py | 110 | ||||
-rw-r--r-- | Adafruit_Python_GPIO/Adafruit_GPIO/SPI.py | 328 | ||||
-rw-r--r-- | Adafruit_Python_GPIO/Adafruit_GPIO/__init__.py | 3 |
10 files changed, 0 insertions, 2393 deletions
diff --git a/Adafruit_Python_GPIO/Adafruit_GPIO/FT232H.py b/Adafruit_Python_GPIO/Adafruit_GPIO/FT232H.py deleted file mode 100644 index 1874272..0000000 --- a/Adafruit_Python_GPIO/Adafruit_GPIO/FT232H.py +++ /dev/null @@ -1,816 +0,0 @@ -# Copyright (c) 2014 Adafruit Industries -# Author: Tony DiCola -# -# 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. - -import atexit -import logging -import math -import os -import subprocess -import sys -import time - -import ftdi1 as ftdi - -import Adafruit_GPIO.GPIO as GPIO - - -logger = logging.getLogger(__name__) - -FT232H_VID = 0x0403 # Default FTDI FT232H vendor ID -FT232H_PID = 0x6014 # Default FTDI FT232H product ID - -MSBFIRST = 0 -LSBFIRST = 1 - -_REPEAT_DELAY = 4 - - -def _check_running_as_root(): - # NOTE: Checking for root with user ID 0 isn't very portable, perhaps - # there's a better alternative? - if os.geteuid() != 0: - raise RuntimeError('Expected to be run by root user! Try running with sudo.') - -def disable_FTDI_driver(): - """Disable the FTDI drivers for the current platform. This is necessary - because they will conflict with libftdi and accessing the FT232H. Note you - can enable the FTDI drivers again by calling enable_FTDI_driver. - """ - logger.debug('Disabling FTDI driver.') - if sys.platform == 'darwin': - logger.debug('Detected Mac OSX') - # Mac OS commands to disable FTDI driver. - _check_running_as_root() - subprocess.call('kextunload -b com.apple.driver.AppleUSBFTDI', shell=True) - subprocess.call('kextunload /System/Library/Extensions/FTDIUSBSerialDriver.kext', shell=True) - elif sys.platform.startswith('linux'): - logger.debug('Detected Linux') - # Linux commands to disable FTDI driver. - _check_running_as_root() - subprocess.call('modprobe -r -q ftdi_sio', shell=True) - subprocess.call('modprobe -r -q usbserial', shell=True) - # Note there is no need to disable FTDI drivers on Windows! - -def enable_FTDI_driver(): - """Re-enable the FTDI drivers for the current platform.""" - logger.debug('Enabling FTDI driver.') - if sys.platform == 'darwin': - logger.debug('Detected Mac OSX') - # Mac OS commands to enable FTDI driver. - _check_running_as_root() - subprocess.check_call('kextload -b com.apple.driver.AppleUSBFTDI', shell=True) - subprocess.check_call('kextload /System/Library/Extensions/FTDIUSBSerialDriver.kext', shell=True) - elif sys.platform.startswith('linux'): - logger.debug('Detected Linux') - # Linux commands to enable FTDI driver. - _check_running_as_root() - subprocess.check_call('modprobe -q ftdi_sio', shell=True) - subprocess.check_call('modprobe -q usbserial', shell=True) - -def use_FT232H(): - """Disable any built in FTDI drivers which will conflict and cause problems - with libftdi (which is used to communicate with the FT232H). Will register - an exit function so the drivers are re-enabled on program exit. - """ - disable_FTDI_driver() - atexit.register(enable_FTDI_driver) - -def enumerate_device_serials(vid=FT232H_VID, pid=FT232H_PID): - """Return a list of all FT232H device serial numbers connected to the - machine. You can use these serial numbers to open a specific FT232H device - by passing it to the FT232H initializer's serial parameter. - """ - try: - # Create a libftdi context. - ctx = None - ctx = ftdi.new() - # Enumerate FTDI devices. - device_list = None - count, device_list = ftdi.usb_find_all(ctx, vid, pid) - if count < 0: - raise RuntimeError('ftdi_usb_find_all returned error {0}: {1}'.format(count, ftdi.get_error_string(self._ctx))) - # Walk through list of devices and assemble list of serial numbers. - devices = [] - while device_list is not None: - # Get USB device strings and add serial to list of devices. - ret, manufacturer, description, serial = ftdi.usb_get_strings(ctx, device_list.dev, 256, 256, 256) - if serial is not None: - devices.append(serial) - device_list = device_list.next - return devices - finally: - # Make sure to clean up list and context when done. - if device_list is not None: - ftdi.list_free(device_list) - if ctx is not None: - ftdi.free(ctx) - - -class FT232H(GPIO.BaseGPIO): - # Make GPIO constants that match main GPIO class for compatibility. - HIGH = GPIO.HIGH - LOW = GPIO.LOW - IN = GPIO.IN - OUT = GPIO.OUT - - def __init__(self, vid=FT232H_VID, pid=FT232H_PID, serial=None): - """Create a FT232H object. Will search for the first available FT232H - device with the specified USB vendor ID and product ID (defaults to - FT232H default VID & PID). Can also specify an optional serial number - string to open an explicit FT232H device given its serial number. See - the FT232H.enumerate_device_serials() function to see how to list all - connected device serial numbers. - """ - # Initialize FTDI device connection. - self._ctx = ftdi.new() - if self._ctx == 0: - raise RuntimeError('ftdi_new failed! Is libftdi1 installed?') - # Register handler to close and cleanup FTDI context on program exit. - atexit.register(self.close) - if serial is None: - # Open USB connection for specified VID and PID if no serial is specified. - self._check(ftdi.usb_open, vid, pid) - else: - # Open USB connection for VID, PID, serial. - self._check(ftdi.usb_open_string, 's:{0}:{1}:{2}'.format(vid, pid, serial)) - # Reset device. - self._check(ftdi.usb_reset) - # Disable flow control. Commented out because it is unclear if this is necessary. - #self._check(ftdi.setflowctrl, ftdi.SIO_DISABLE_FLOW_CTRL) - # Change read & write buffers to maximum size, 65535 bytes. - self._check(ftdi.read_data_set_chunksize, 65535) - self._check(ftdi.write_data_set_chunksize, 65535) - # Clear pending read data & write buffers. - self._check(ftdi.usb_purge_buffers) - # Enable MPSSE and syncronize communication with device. - self._mpsse_enable() - self._mpsse_sync() - # Initialize all GPIO as inputs. - self._write('\x80\x00\x00\x82\x00\x00') - self._direction = 0x0000 - self._level = 0x0000 - - def close(self): - """Close the FTDI device. Will be automatically called when the program ends.""" - if self._ctx is not None: - ftdi.free(self._ctx) - self._ctx = None - - def _write(self, string): - """Helper function to call write_data on the provided FTDI device and - verify it succeeds. - """ - # Get modem status. Useful to enable for debugging. - #ret, status = ftdi.poll_modem_status(self._ctx) - #if ret == 0: - # logger.debug('Modem status {0:02X}'.format(status)) - #else: - # logger.debug('Modem status error {0}'.format(ret)) - length = len(string) - ret = ftdi.write_data(self._ctx, string, length) - # Log the string that was written in a python hex string format using a very - # ugly one-liner list comprehension for brevity. - #logger.debug('Wrote {0}'.format(''.join(['\\x{0:02X}'.format(ord(x)) for x in string]))) - if ret < 0: - raise RuntimeError('ftdi_write_data failed with error {0}: {1}'.format(ret, ftdi.get_error_string(self._ctx))) - if ret != length: - raise RuntimeError('ftdi_write_data expected to write {0} bytes but actually wrote {1}!'.format(length, ret)) - - def _check(self, command, *args): - """Helper function to call the provided command on the FTDI device and - verify the response matches the expected value. - """ - ret = command(self._ctx, *args) - logger.debug('Called ftdi_{0} and got response {1}.'.format(command.__name__, ret)) - if ret != 0: - raise RuntimeError('ftdi_{0} failed with error {1}: {2}'.format(command.__name__, ret, ftdi.get_error_string(self._ctx))) - - def _poll_read(self, expected, timeout_s=5.0): - """Helper function to continuously poll reads on the FTDI device until an - expected number of bytes are returned. Will throw a timeout error if no - data is received within the specified number of timeout seconds. Returns - the read data as a string if successful, otherwise raises an execption. - """ - start = time.time() - # Start with an empty response buffer. - response = bytearray(expected) - index = 0 - # Loop calling read until the response buffer is full or a timeout occurs. - while time.time() - start <= timeout_s: - ret, data = ftdi.read_data(self._ctx, expected - index) - # Fail if there was an error reading data. - if ret < 0: - raise RuntimeError('ftdi_read_data failed with error code {0}.'.format(ret)) - # Add returned data to the buffer. - response[index:index+ret] = data[:ret] - index += ret - # Buffer is full, return the result data. - if index >= expected: - return str(response) - time.sleep(0.01) - raise RuntimeError('Timeout while polling ftdi_read_data for {0} bytes!'.format(expected)) - - def _mpsse_enable(self): - """Enable MPSSE mode on the FTDI device.""" - # Reset MPSSE by sending mask = 0 and mode = 0 - self._check(ftdi.set_bitmode, 0, 0) - # Enable MPSSE by sending mask = 0 and mode = 2 - self._check(ftdi.set_bitmode, 0, 2) - - def _mpsse_sync(self, max_retries=10): - """Synchronize buffers with MPSSE by sending bad opcode and reading expected - error response. Should be called once after enabling MPSSE.""" - # Send a bad/unknown command (0xAB), then read buffer until bad command - # response is found. - self._write('\xAB') - # Keep reading until bad command response (0xFA 0xAB) is returned. - # Fail if too many read attempts are made to prevent sticking in a loop. - tries = 0 - sync = False - while not sync: - data = self._poll_read(2) - if data == '\xFA\xAB': - sync = True - tries += 1 - if tries >= max_retries: - raise RuntimeError('Could not synchronize with FT232H!') - - def mpsse_set_clock(self, clock_hz, adaptive=False, three_phase=False): - """Set the clock speed of the MPSSE engine. Can be any value from 450hz - to 30mhz and will pick that speed or the closest speed below it. - """ - # Disable clock divisor by 5 to enable faster speeds on FT232H. - self._write('\x8A') - # Turn on/off adaptive clocking. - if adaptive: - self._write('\x96') - else: - self._write('\x97') - # Turn on/off three phase clock (needed for I2C). - # Also adjust the frequency for three-phase clocking as specified in section 2.2.4 - # of this document: - # http://www.ftdichip.com/Support/Documents/AppNotes/AN_255_USB%20to%20I2C%20Example%20using%20the%20FT232H%20and%20FT201X%20devices.pdf - if three_phase: - self._write('\x8C') - else: - self._write('\x8D') - # Compute divisor for requested clock. - # Use equation from section 3.8.1 of: - # http://www.ftdichip.com/Support/Documents/AppNotes/AN_108_Command_Processor_for_MPSSE_and_MCU_Host_Bus_Emulation_Modes.pdf - # Note equation is using 60mhz master clock instead of 12mhz. - divisor = int(math.ceil((30000000.0-float(clock_hz))/float(clock_hz))) & 0xFFFF - if three_phase: - divisor = int(divisor*(2.0/3.0)) - logger.debug('Setting clockspeed with divisor value {0}'.format(divisor)) - # Send command to set divisor from low and high byte values. - self._write(str(bytearray((0x86, divisor & 0xFF, (divisor >> 8) & 0xFF)))) - - def mpsse_read_gpio(self): - """Read both GPIO bus states and return a 16 bit value with their state. - D0-D7 are the lower 8 bits and C0-C7 are the upper 8 bits. - """ - # Send command to read low byte and high byte. - self._write('\x81\x83') - # Wait for 2 byte response. - data = self._poll_read(2) - # Assemble response into 16 bit value. - low_byte = ord(data[0]) - high_byte = ord(data[1]) - logger.debug('Read MPSSE GPIO low byte = {0:02X} and high byte = {1:02X}'.format(low_byte, high_byte)) - return (high_byte << 8) | low_byte - - def mpsse_gpio(self): - """Return command to update the MPSSE GPIO state to the current direction - and level. - """ - level_low = chr(self._level & 0xFF) - level_high = chr((self._level >> 8) & 0xFF) - dir_low = chr(self._direction & 0xFF) - dir_high = chr((self._direction >> 8) & 0xFF) - return str(bytearray((0x80, level_low, dir_low, 0x82, level_high, dir_high))) - - def mpsse_write_gpio(self): - """Write the current MPSSE GPIO state to the FT232H chip.""" - self._write(self.mpsse_gpio()) - - def get_i2c_device(self, address, **kwargs): - """Return an I2CDevice instance using this FT232H object and the provided - I2C address. Meant to be passed as the i2c_provider parameter to objects - which use the Adafruit_Python_GPIO library for I2C. - """ - return I2CDevice(self, address, **kwargs) - - # GPIO functions below: - - def _setup_pin(self, pin, mode): - if pin < 0 or pin > 15: - raise ValueError('Pin must be between 0 and 15 (inclusive).') - if mode not in (GPIO.IN, GPIO.OUT): - raise ValueError('Mode must be GPIO.IN or GPIO.OUT.') - if mode == GPIO.IN: - # Set the direction and level of the pin to 0. - self._direction &= ~(1 << pin) & 0xFFFF - self._level &= ~(1 << pin) & 0xFFFF - else: - # Set the direction of the pin to 1. - self._direction |= (1 << pin) & 0xFFFF - - def setup(self, pin, mode): - """Set the input or output mode for a specified pin. Mode should be - either OUT or IN.""" - self._setup_pin(pin, mode) - self.mpsse_write_gpio() - - def setup_pins(self, pins, values={}, write=True): - """Setup multiple pins as inputs or outputs at once. Pins should be a - dict of pin name to pin mode (IN or OUT). Optional starting values of - pins can be provided in the values dict (with pin name to pin value). - """ - # General implementation that can be improved by subclasses. - for pin, mode in iter(pins.items()): - self._setup_pin(pin, mode) - for pin, value in iter(values.items()): - self._output_pin(pin, value) - if write: - self.mpsse_write_gpio() - - def _output_pin(self, pin, value): - if value: - self._level |= (1 << pin) & 0xFFFF - else: - self._level &= ~(1 << pin) & 0xFFFF - - def output(self, pin, value): - """Set the specified pin the provided high/low value. Value should be - either HIGH/LOW or a boolean (true = high).""" - if pin < 0 or pin > 15: - raise ValueError('Pin must be between 0 and 15 (inclusive).') - self._output_pin(pin, value) - self.mpsse_write_gpio() - - def output_pins(self, pins, write=True): - """Set multiple pins high or low at once. Pins should be a dict of pin - name to pin value (HIGH/True for 1, LOW/False for 0). All provided pins - will be set to the given values. - """ - for pin, value in iter(pins.items()): - self._output_pin(pin, value) - if write: - self.mpsse_write_gpio() - - def input(self, pin): - """Read the specified pin and return HIGH/true if the pin is pulled high, - or LOW/false if pulled low.""" - return self.input_pins([pin])[0] - - def input_pins(self, pins): - """Read multiple pins specified in the given list and return list of pin values - GPIO.HIGH/True if the pin is pulled high, or GPIO.LOW/False if pulled low.""" - if [pin for pin in pins if pin < 0 or pin > 15]: - raise ValueError('Pin must be between 0 and 15 (inclusive).') - _pins = self.mpsse_read_gpio() - return [((_pins >> pin) & 0x0001) == 1 for pin in pins] - - -class SPI(object): - def __init__(self, ft232h, cs=None, max_speed_hz=1000000, mode=0, bitorder=MSBFIRST): - self._ft232h = ft232h - # Initialize chip select pin if provided to output high. - if cs is not None: - ft232h.setup(cs, GPIO.OUT) - ft232h.set_high(cs) - self._cs = cs - # Initialize clock, mode, and bit order. - self.set_clock_hz(max_speed_hz) - self.set_mode(mode) - self.set_bit_order(bitorder) - - def _assert_cs(self): - if self._cs is not None: - self._ft232h.set_low(self._cs) - - def _deassert_cs(self): - if self._cs is not None: - self._ft232h.set_high(self._cs) - - def set_clock_hz(self, hz): - """Set the speed of the SPI clock in hertz. Note that not all speeds - are supported and a lower speed might be chosen by the hardware. - """ - self._ft232h.mpsse_set_clock(hz) - - def set_mode(self, mode): - """Set SPI mode which controls clock polarity and phase. Should be a - numeric value 0, 1, 2, or 3. See wikipedia page for details on meaning: - http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus - """ - if mode < 0 or mode > 3: - raise ValueError('Mode must be a value 0, 1, 2, or 3.') - if mode == 0: - # Mode 0 captures on rising clock, propagates on falling clock - self.write_clock_ve = 1 - self.read_clock_ve = 0 - # Clock base is low. - clock_base = GPIO.LOW - elif mode == 1: - # Mode 1 capture of falling edge, propagate on rising clock - self.write_clock_ve = 0 - self.read_clock_ve = 1 - # Clock base is low. - clock_base = GPIO.LOW - elif mode == 2: - # Mode 2 capture on rising clock, propagate on falling clock - self.write_clock_ve = 1 - self.read_clock_ve = 0 - # Clock base is high. - clock_base = GPIO.HIGH - elif mode == 3: - # Mode 3 capture on falling edge, propagage on rising clock - self.write_clock_ve = 0 - self.read_clock_ve = 1 - # Clock base is high. - clock_base = GPIO.HIGH - # Set clock and DO as output, DI as input. Also start clock at its base value. - self._ft232h.setup_pins({0: GPIO.OUT, 1: GPIO.OUT, 2: GPIO.IN}, {0: clock_base}) - - def set_bit_order(self, order): - """Set order of bits to be read/written over serial lines. Should be - either MSBFIRST for most-significant first, or LSBFIRST for - least-signifcant first. - """ - if order == MSBFIRST: - self.lsbfirst = 0 - elif order == LSBFIRST: - self.lsbfirst = 1 - else: - raise ValueError('Order must be MSBFIRST or LSBFIRST.') - - def write(self, data): - """Half-duplex SPI write. The specified array of bytes will be clocked - out the MOSI line. - """ - # Build command to write SPI data. - command = 0x10 | (self.lsbfirst << 3) | self.write_clock_ve - logger.debug('SPI write with command {0:2X}.'.format(command)) - # Compute length low and high bytes. - # NOTE: Must actually send length minus one because the MPSSE engine - # considers 0 a length of 1 and FFFF a length of 65536 - length = len(data)-1 - len_low = length & 0xFF - len_high = (length >> 8) & 0xFF - self._assert_cs() - # Send command and length. - self._ft232h._write(str(bytearray((command, len_low, len_high)))) - # Send data. - self._ft232h._write(str(bytearray(data))) - self._deassert_cs() - - def read(self, length): - """Half-duplex SPI read. The specified length of bytes will be clocked - in the MISO line and returned as a bytearray object. - """ - # Build command to read SPI data. - command = 0x20 | (self.lsbfirst << 3) | (self.read_clock_ve << 2) - logger.debug('SPI read with command {0:2X}.'.format(command)) - # Compute length low and high bytes. - # NOTE: Must actually send length minus one because the MPSSE engine - # considers 0 a length of 1 and FFFF a length of 65536 - len_low = (length-1) & 0xFF - len_high = ((length-1) >> 8) & 0xFF - self._assert_cs() - # Send command and length. - self._ft232h._write(str(bytearray((command, len_low, len_high, 0x87)))) - self._deassert_cs() - # Read response bytes. - return bytearray(self._ft232h._poll_read(length)) - - def transfer(self, data): - """Full-duplex SPI read and write. The specified array of bytes will be - clocked out the MOSI line, while simultaneously bytes will be read from - the MISO line. Read bytes will be returned as a bytearray object. - """ - # Build command to read and write SPI data. - command = 0x30 | (self.lsbfirst << 3) | (self.read_clock_ve << 2) | self.write_clock_ve - logger.debug('SPI transfer with command {0:2X}.'.format(command)) - # Compute length low and high bytes. - # NOTE: Must actually send length minus one because the MPSSE engine - # considers 0 a length of 1 and FFFF a length of 65536 - length = len(data) - len_low = (length-1) & 0xFF - len_high = ((length-1) >> 8) & 0xFF - # Send command and length. - self._assert_cs() - self._ft232h._write(str(bytearray((command, len_low, len_high)))) - self._ft232h._write(str(bytearray(data))) - self._ft232h._write('\x87') - self._deassert_cs() - # Read response bytes. - return bytearray(self._ft232h._poll_read(length)) - - -class I2CDevice(object): - """Class for communicating with an I2C device using the smbus library. - Allows reading and writing 8-bit, 16-bit, and byte array values to registers - on the device.""" - # Note that most of the functions in this code are adapted from this app note: - # http://www.ftdichip.com/Support/Documents/AppNotes/AN_255_USB%20to%20I2C%20Example%20using%20the%20FT232H%20and%20FT201X%20devices.pdf - def __init__(self, ft232h, address, clock_hz=100000): - """Create an instance of the I2C device at the specified address on the - specified I2C bus number.""" - self._address = address - self._ft232h = ft232h - # Enable clock with three phases for I2C. - self._ft232h.mpsse_set_clock(clock_hz, three_phase=True) - # Enable drive-zero mode to drive outputs low on 0 and tri-state on 1. - # This matches the protocol for I2C communication so multiple devices can - # share the I2C bus. - self._ft232h._write('\x9E\x07\x00') - self._idle() - - def _idle(self): - """Put I2C lines into idle state.""" - # Put the I2C lines into an idle state with SCL and SDA high. - self._ft232h.setup_pins({0: GPIO.OUT, 1: GPIO.OUT, 2: GPIO.IN}, - {0: GPIO.HIGH, 1: GPIO.HIGH}) - - def _transaction_start(self): - """Start I2C transaction.""" - # Clear command buffer and expected response bytes. - self._command = [] - self._expected = 0 - - def _transaction_end(self): - """End I2C transaction and get response bytes, including ACKs.""" - # Ask to return response bytes immediately. - self._command.append('\x87') - # Send the entire command to the MPSSE. - self._ft232h._write(''.join(self._command)) - # Read response bytes and return them. - return bytearray(self._ft232h._poll_read(self._expected)) - - def _i2c_start(self): - """Send I2C start signal. Must be called within a transaction start/end. - """ - # Set SCL high and SDA low, repeat 4 times to stay in this state for a - # short period of time. - self._ft232h.output_pins({0: GPIO.HIGH, 1: GPIO.LOW}, write=False) - self._command.append(self._ft232h.mpsse_gpio() * _REPEAT_DELAY) - # Now drop SCL to low (again repeat 4 times for short delay). - self._ft232h.output_pins({0: GPIO.LOW, 1: GPIO.LOW}, write=False) - self._command.append(self._ft232h.mpsse_gpio() * _REPEAT_DELAY) - - def _i2c_idle(self): - """Set I2C signals to idle state with SCL and SDA at a high value. Must - be called within a transaction start/end. - """ - self._ft232h.output_pins({0: GPIO.HIGH, 1: GPIO.HIGH}, write=False) - self._command.append(self._ft232h.mpsse_gpio() * _REPEAT_DELAY) - - def _i2c_stop(self): - """Send I2C stop signal. Must be called within a transaction start/end. - """ - # Set SCL low and SDA low for a short period. - self._ft232h.output_pins({0: GPIO.LOW, 1: GPIO.LOW}, write=False) - self._command.append(self._ft232h.mpsse_gpio() * _REPEAT_DELAY) - # Set SCL high and SDA low for a short period. - self._ft232h.output_pins({0: GPIO.HIGH, 1: GPIO.LOW}, write=False) - self._command.append(self._ft232h.mpsse_gpio() * _REPEAT_DELAY) - # Finally set SCL high and SDA high for a short period. - self._ft232h.output_pins({0: GPIO.HIGH, 1: GPIO.HIGH}, write=False) - self._command.append(self._ft232h.mpsse_gpio() * _REPEAT_DELAY) - - def _i2c_read_bytes(self, length=1): - """Read the specified number of bytes from the I2C bus. Length is the - number of bytes to read (must be 1 or more). - """ - for i in range(length-1): - # Read a byte and send ACK. - self._command.append('\x20\x00\x00\x13\x00\x00') - # Make sure pins are back in idle state with clock low and data high. - self._ft232h.output_pins({0: GPIO.LOW, 1: GPIO.HIGH}, write=False) - self._command.append(self._ft232h.mpsse_gpio()) - # Read last byte and send NAK. - self._command.append('\x20\x00\x00\x13\x00\xFF') - # Make sure pins are back in idle state with clock low and data high. - self._ft232h.output_pins({0: GPIO.LOW, 1: GPIO.HIGH}, write=False) - self._command.append(self._ft232h.mpsse_gpio()) - # Increase expected number of bytes. - self._expected += length - - def _i2c_write_bytes(self, data): - """Write the specified number of bytes to the chip.""" - for byte in data: - # Write byte. - self._command.append(str(bytearray((0x11, 0x00, 0x00, byte)))) - # Make sure pins are back in idle state with clock low and data high. - self._ft232h.output_pins({0: GPIO.LOW, 1: GPIO.HIGH}, write=False) - self._command.append(self._ft232h.mpsse_gpio() * _REPEAT_DELAY) - # Read bit for ACK/NAK. - self._command.append('\x22\x00') - # Increase expected response bytes. - self._expected += len(data) - - def _address_byte(self, read=True): - """Return the address byte with the specified R/W bit set. If read is - True the R/W bit will be 1, otherwise the R/W bit will be 0. - """ - if read: - return (self._address << 1) | 0x01 - else: - return self._address << 1 - - def _verify_acks(self, response): - """Check all the specified bytes have the ACK bit set. Throws a - RuntimeError exception if not all the ACKs are set. - """ - for byte in response: - if byte & 0x01 != 0x00: - raise RuntimeError('Failed to find expected I2C ACK!') - - def ping(self): - """Attempt to detect if a device at this address is present on the I2C - bus. Will send out the device's address for writing and verify an ACK - is received. Returns true if the ACK is received, and false if not. - """ - self._idle() - self._transaction_start() - self._i2c_start() - self._i2c_write_bytes([self._address_byte(False)]) - self._i2c_stop() - response = self._transaction_end() - if len(response) != 1: - raise RuntimeError('Expected 1 response byte but received {0} byte(s).'.format(len(response))) - return ((response[0] & 0x01) == 0x00) - - def writeRaw8(self, value): - """Write an 8-bit value on the bus (without register).""" - value = value & 0xFF - self._idle() - self._transaction_start() - self._i2c_start() - self._i2c_write_bytes([self._address_byte(False), value]) - self._i2c_stop() - response = self._transaction_end() - self._verify_acks(response) - - def write8(self, register, value): - """Write an 8-bit value to the specified register.""" - value = value & 0xFF - self._idle() - self._transaction_start() - self._i2c_start() - self._i2c_write_bytes([self._address_byte(False), register, value]) - self._i2c_stop() - response = self._transaction_end() - self._verify_acks(response) - - def write16(self, register, value, little_endian=True): - """Write a 16-bit value to the specified register.""" - value = value & 0xFFFF - value_low = value & 0xFF - value_high = (value >> 8) & 0xFF - if not little_endian: - value_low, value_high = value_high, value_low - self._idle() - self._transaction_start() - self._i2c_start() - self._i2c_write_bytes([self._address_byte(False), register, value_low, - value_high]) - self._i2c_stop() - response = self._transaction_end() - self._verify_acks(response) - - def writeList(self, register, data): - """Write bytes to the specified register.""" - self._idle() - self._transaction_start() - self._i2c_start() - self._i2c_write_bytes([self._address_byte(False), register] + data) - self._i2c_stop() - response = self._transaction_end() - self._verify_acks(response) - - def readList(self, register, length): - """Read a length number of bytes from the specified register. Results - will be returned as a bytearray.""" - if length <= 0: - raise ValueError("Length must be at least 1 byte.") - self._idle() - self._transaction_start() - self._i2c_start() - self._i2c_write_bytes([self._address_byte(True), register]) - self._i2c_stop() - self._i2c_idle() - self._i2c_start() - self._i2c_read_bytes(length) - self._i2c_stop() - response = self._transaction_end() - self._verify_acks(response[:-length]) - return response[-length:] - - def readRaw8(self): - """Read an 8-bit value on the bus (without register).""" - self._idle() - self._transaction_start() - self._i2c_start() - self._i2c_write_bytes([self._address_byte(False)]) - self._i2c_stop() - self._i2c_idle() - self._i2c_start() - self._i2c_write_bytes([self._address_byte(True)]) - self._i2c_read_bytes(1) - self._i2c_stop() - response = self._transaction_end() - self._verify_acks(response[:-1]) - return response[-1] - - def readU8(self, register): - """Read an unsigned byte from the specified register.""" - self._idle() - self._transaction_start() - self._i2c_start() - self._i2c_write_bytes([self._address_byte(False), register]) - self._i2c_stop() - self._i2c_idle() - self._i2c_start() - self._i2c_write_bytes([self._address_byte(True)]) - self._i2c_read_bytes(1) - self._i2c_stop() - response = self._transaction_end() - self._verify_acks(response[:-1]) - return response[-1] - - def readS8(self, register): - """Read a signed byte from the specified register.""" - result = self.readU8(register) - if result > 127: - result -= 256 - return result - - def readU16(self, register, little_endian=True): - """Read an unsigned 16-bit value from the specified register, with the - specified endianness (default little endian, or least significant byte - first).""" - self._idle() - self._transaction_start() - self._i2c_start() - self._i2c_write_bytes([self._address_byte(False), register]) - self._i2c_stop() - self._i2c_idle() - self._i2c_start() - self._i2c_write_bytes([self._address_byte(True)]) - self._i2c_read_bytes(2) - self._i2c_stop() - response = self._transaction_end() - self._verify_acks(response[:-2]) - if little_endian: - return (response[-1] << 8) | response[-2] - else: - return (response[-2] << 8) | response[-1] - - def readS16(self, register, little_endian=True): - """Read a signed 16-bit value from the specified register, with the - specified endianness (default little endian, or least significant byte - first).""" - result = self.readU16(register, little_endian) - if result > 32767: - result -= 65536 - return result - - def readU16LE(self, register): - """Read an unsigned 16-bit value from the specified register, in little - endian byte order.""" - return self.readU16(register, little_endian=True) - - def readU16BE(self, register): - """Read an unsigned 16-bit value from the specified register, in big - endian byte order.""" - return self.readU16(register, little_endian=False) - - def readS16LE(self, register): - """Read a signed 16-bit value from the specified register, in little - endian byte order.""" - return self.readS16(register, little_endian=True) - - def readS16BE(self, register): - """Read a signed 16-bit value from the specified register, in big - endian byte order.""" - return self.readS16(register, little_endian=False) diff --git a/Adafruit_Python_GPIO/Adafruit_GPIO/GPIO.py b/Adafruit_Python_GPIO/Adafruit_GPIO/GPIO.py deleted file mode 100644 index 08e99c6..0000000 --- a/Adafruit_Python_GPIO/Adafruit_GPIO/GPIO.py +++ /dev/null @@ -1,426 +0,0 @@ -# Copyright (c) 2014 Adafruit Industries -# Author: Tony DiCola -# -# 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. - -import Adafruit_GPIO.Platform as Platform - - -OUT = 0 -IN = 1 -HIGH = True -LOW = False - -RISING = 1 -FALLING = 2 -BOTH = 3 - -PUD_OFF = 0 -PUD_DOWN = 1 -PUD_UP = 2 - -class BaseGPIO(object): - """Base class for implementing simple digital IO for a platform. - Implementors are expected to subclass from this and provide an implementation - of the setup, output, and input functions.""" - - def setup(self, pin, mode, pull_up_down=PUD_OFF): - """Set the input or output mode for a specified pin. Mode should be - either OUT or IN.""" - raise NotImplementedError - - def output(self, pin, value): - """Set the specified pin the provided high/low value. Value should be - either HIGH/LOW or a boolean (true = high).""" - raise NotImplementedError - - def input(self, pin): - """Read the specified pin and return HIGH/true if the pin is pulled high, - or LOW/false if pulled low.""" - raise NotImplementedError - - def set_high(self, pin): - """Set the specified pin HIGH.""" - self.output(pin, HIGH) - - def set_low(self, pin): - """Set the specified pin LOW.""" - self.output(pin, LOW) - - def is_high(self, pin): - """Return true if the specified pin is pulled high.""" - return self.input(pin) == HIGH - - def is_low(self, pin): - """Return true if the specified pin is pulled low.""" - return self.input(pin) == LOW - - -# Basic implementation of multiple pin methods just loops through pins and -# processes each one individually. This is not optimal, but derived classes can -# provide a more optimal implementation that deals with groups of pins -# simultaneously. -# See MCP230xx or PCF8574 classes for examples of optimized implementations. - - def output_pins(self, pins): - """Set multiple pins high or low at once. Pins should be a dict of pin - name to pin value (HIGH/True for 1, LOW/False for 0). All provided pins - will be set to the given values. - """ - # General implementation just loops through pins and writes them out - # manually. This is not optimized, but subclasses can choose to implement - # a more optimal batch output implementation. See the MCP230xx class for - # example of optimized implementation. - for pin, value in iter(pins.items()): - self.output(pin, value) - - def setup_pins(self, pins): - """Setup multiple pins as inputs or outputs at once. Pins should be a - dict of pin name to pin type (IN or OUT). - """ - # General implementation that can be optimized by derived classes. - for pin, value in iter(pins.items()): - self.setup(pin, value) - - def input_pins(self, pins): - """Read multiple pins specified in the given list and return list of pin values - GPIO.HIGH/True if the pin is pulled high, or GPIO.LOW/False if pulled low. - """ - # General implementation that can be optimized by derived classes. - return [self.input(pin) for pin in pins] - - - def add_event_detect(self, pin, edge): - """Enable edge detection events for a particular GPIO channel. Pin - should be type IN. Edge must be RISING, FALLING or BOTH. - """ - raise NotImplementedError - - def remove_event_detect(self, pin): - """Remove edge detection for a particular GPIO channel. Pin should be - type IN. - """ - raise NotImplementedError - - def add_event_callback(self, pin, callback): - """Add a callback for an event already defined using add_event_detect(). - Pin should be type IN. - """ - raise NotImplementedError - - def event_detected(self, pin): - """Returns True if an edge has occured on a given GPIO. You need to - enable edge detection using add_event_detect() first. Pin should be - type IN. - """ - raise NotImplementedError - - def wait_for_edge(self, pin, edge): - """Wait for an edge. Pin should be type IN. Edge must be RISING, - FALLING or BOTH.""" - raise NotImplementedError - - def cleanup(self, pin=None): - """Clean up GPIO event detection for specific pin, or all pins if none - is specified. - """ - raise NotImplementedError - - -# helper functions useful to derived classes - - def _validate_pin(self, pin): - # Raise an exception if pin is outside the range of allowed values. - if pin < 0 or pin >= self.NUM_GPIO: - raise ValueError('Invalid GPIO value, must be between 0 and {0}.'.format(self.NUM_GPIO)) - - def _bit2(self, src, bit, val): - bit = 1 << bit - return (src | bit) if val else (src & ~bit) - - -class RPiGPIOAdapter(BaseGPIO): - """GPIO implementation for the Raspberry Pi using the RPi.GPIO library.""" - - def __init__(self, rpi_gpio, mode=None): - self.rpi_gpio = rpi_gpio - # Suppress warnings about GPIO in use. - rpi_gpio.setwarnings(False) - # Setup board pin mode. - if mode == rpi_gpio.BOARD or mode == rpi_gpio.BCM: - rpi_gpio.setmode(mode) - elif mode is not None: - raise ValueError('Unexpected value for mode. Must be BOARD or BCM.') - else: - # Default to BCM numbering if not told otherwise. - rpi_gpio.setmode(rpi_gpio.BCM) - # Define mapping of Adafruit GPIO library constants to RPi.GPIO constants. - self._dir_mapping = { OUT: rpi_gpio.OUT, - IN: rpi_gpio.IN } - self._pud_mapping = { PUD_OFF: rpi_gpio.PUD_OFF, - PUD_DOWN: rpi_gpio.PUD_DOWN, - PUD_UP: rpi_gpio.PUD_UP } - self._edge_mapping = { RISING: rpi_gpio.RISING, - FALLING: rpi_gpio.FALLING, - BOTH: rpi_gpio.BOTH } - - def setup(self, pin, mode, pull_up_down=PUD_OFF): - """Set the input or output mode for a specified pin. Mode should be - either OUTPUT or INPUT. - """ - self.rpi_gpio.setup(pin, self._dir_mapping[mode], - pull_up_down=self._pud_mapping[pull_up_down]) - - def output(self, pin, value): - """Set the specified pin the provided high/low value. Value should be - either HIGH/LOW or a boolean (true = high). - """ - self.rpi_gpio.output(pin, value) - - def input(self, pin): - """Read the specified pin and return HIGH/true if the pin is pulled high, - or LOW/false if pulled low. - """ - return self.rpi_gpio.input(pin) - - def input_pins(self, pins): - """Read multiple pins specified in the given list and return list of pin values - GPIO.HIGH/True if the pin is pulled high, or GPIO.LOW/False if pulled low. - """ - # maybe rpi has a mass read... it would be more efficient to use it if it exists - return [self.rpi_gpio.input(pin) for pin in pins] - - def add_event_detect(self, pin, edge, callback=None, bouncetime=-1): - """Enable edge detection events for a particular GPIO channel. Pin - should be type IN. Edge must be RISING, FALLING or BOTH. Callback is a - function for the event. Bouncetime is switch bounce timeout in ms for - callback - """ - kwargs = {} - if callback: - kwargs['callback']=callback - if bouncetime > 0: - kwargs['bouncetime']=bouncetime - self.rpi_gpio.add_event_detect(pin, self._edge_mapping[edge], **kwargs) - - def remove_event_detect(self, pin): - """Remove edge detection for a particular GPIO channel. Pin should be - type IN. - """ - self.rpi_gpio.remove_event_detect(pin) - - def add_event_callback(self, pin, callback): - """Add a callback for an event already defined using add_event_detect(). - Pin should be type IN. - """ - self.rpi_gpio.add_event_callback(pin, callback) - - def event_detected(self, pin): - """Returns True if an edge has occured on a given GPIO. You need to - enable edge detection using add_event_detect() first. Pin should be - type IN. - """ - return self.rpi_gpio.event_detected(pin) - - def wait_for_edge(self, pin, edge): - """Wait for an edge. Pin should be type IN. Edge must be RISING, - FALLING or BOTH. - """ - self.rpi_gpio.wait_for_edge(pin, self._edge_mapping[edge]) - - def cleanup(self, pin=None): - """Clean up GPIO event detection for specific pin, or all pins if none - is specified. - """ - if pin is None: - self.rpi_gpio.cleanup() - else: - self.rpi_gpio.cleanup(pin) - -class AdafruitBBIOAdapter(BaseGPIO): - """GPIO implementation for the Beaglebone Black using the Adafruit_BBIO - library. - """ - - def __init__(self, bbio_gpio): - self.bbio_gpio = bbio_gpio - # Define mapping of Adafruit GPIO library constants to RPi.GPIO constants. - self._dir_mapping = { OUT: bbio_gpio.OUT, - IN: bbio_gpio.IN } - self._pud_mapping = { PUD_OFF: bbio_gpio.PUD_OFF, - PUD_DOWN: bbio_gpio.PUD_DOWN, - PUD_UP: bbio_gpio.PUD_UP } - self._edge_mapping = { RISING: bbio_gpio.RISING, - FALLING: bbio_gpio.FALLING, - BOTH: bbio_gpio.BOTH } - - def setup(self, pin, mode, pull_up_down=PUD_OFF): - """Set the input or output mode for a specified pin. Mode should be - either OUTPUT or INPUT. - """ - self.bbio_gpio.setup(pin, self._dir_mapping[mode], - pull_up_down=self._pud_mapping[pull_up_down]) - - def output(self, pin, value): - """Set the specified pin the provided high/low value. Value should be - either HIGH/LOW or a boolean (true = high). - """ - self.bbio_gpio.output(pin, value) - - def input(self, pin): - """Read the specified pin and return HIGH/true if the pin is pulled high, - or LOW/false if pulled low. - """ - return self.bbio_gpio.input(pin) - - def input_pins(self, pins): - """Read multiple pins specified in the given list and return list of pin values - GPIO.HIGH/True if the pin is pulled high, or GPIO.LOW/False if pulled low. - """ - # maybe bbb has a mass read... it would be more efficient to use it if it exists - return [self.bbio_gpio.input(pin) for pin in pins] - - def add_event_detect(self, pin, edge, callback=None, bouncetime=-1): - """Enable edge detection events for a particular GPIO channel. Pin - should be type IN. Edge must be RISING, FALLING or BOTH. Callback is a - function for the event. Bouncetime is switch bounce timeout in ms for - callback - """ - kwargs = {} - if callback: - kwargs['callback']=callback - if bouncetime > 0: - kwargs['bouncetime']=bouncetime - self.bbio_gpio.add_event_detect(pin, self._edge_mapping[edge], **kwargs) - - def remove_event_detect(self, pin): - """Remove edge detection for a particular GPIO channel. Pin should be - type IN. - """ - self.bbio_gpio.remove_event_detect(pin) - - def add_event_callback(self, pin, callback, bouncetime=-1): - """Add a callback for an event already defined using add_event_detect(). - Pin should be type IN. Bouncetime is switch bounce timeout in ms for - callback - """ - kwargs = {} - if bouncetime > 0: - kwargs['bouncetime']=bouncetime - self.bbio_gpio.add_event_callback(pin, callback, **kwargs) - - def event_detected(self, pin): - """Returns True if an edge has occured on a given GPIO. You need to - enable edge detection using add_event_detect() first. Pin should be - type IN. - """ - return self.bbio_gpio.event_detected(pin) - - def wait_for_edge(self, pin, edge): - """Wait for an edge. Pin should be type IN. Edge must be RISING, - FALLING or BOTH. - """ - self.bbio_gpio.wait_for_edge(pin, self._edge_mapping[edge]) - - def cleanup(self, pin=None): - """Clean up GPIO event detection for specific pin, or all pins if none - is specified. - """ - if pin is None: - self.bbio_gpio.cleanup() - else: - self.bbio_gpio.cleanup(pin) - -class AdafruitMinnowAdapter(BaseGPIO): - """GPIO implementation for the Minnowboard + MAX using the mraa library""" - - def __init__(self,mraa_gpio): - self.mraa_gpio = mraa_gpio - # Define mapping of Adafruit GPIO library constants to mraa constants - self._dir_mapping = { OUT: self.mraa_gpio.DIR_OUT, - IN: self.mraa_gpio.DIR_IN } - self._pud_mapping = { PUD_OFF: self.mraa_gpio.MODE_STRONG, - PUD_UP: self.mraa_gpio.MODE_HIZ, - PUD_DOWN: self.mraa_gpio.MODE_PULLDOWN } - self._edge_mapping = { RISING: self.mraa_gpio.EDGE_RISING, - FALLING: self.mraa_gpio.EDGE_FALLING, - BOTH: self.mraa_gpio.EDGE_BOTH } - - def setup(self,pin,mode): - """Set the input or output mode for a specified pin. Mode should be - either DIR_IN or DIR_OUT. - """ - self.mraa_gpio.Gpio.dir(self.mraa_gpio.Gpio(pin),self._dir_mapping[mode]) - - def output(self,pin,value): - """Set the specified pin the provided high/low value. Value should be - either 1 (ON or HIGH), or 0 (OFF or LOW) or a boolean. - """ - self.mraa_gpio.Gpio.write(self.mraa_gpio.Gpio(pin), value) - - def input(self,pin): - """Read the specified pin and return HIGH/true if the pin is pulled high, - or LOW/false if pulled low. - """ - return self.mraa_gpio.Gpio.read(self.mraa_gpio.Gpio(pin)) - - def add_event_detect(self, pin, edge, callback=None, bouncetime=-1): - """Enable edge detection events for a particular GPIO channel. Pin - should be type IN. Edge must be RISING, FALLING or BOTH. Callback is a - function for the event. Bouncetime is switch bounce timeout in ms for - callback - """ - kwargs = {} - if callback: - kwargs['callback']=callback - if bouncetime > 0: - kwargs['bouncetime']=bouncetime - self.mraa_gpio.Gpio.isr(self.mraa_gpio.Gpio(pin), self._edge_mapping[edge], **kwargs) - - def remove_event_detect(self, pin): - """Remove edge detection for a particular GPIO channel. Pin should be - type IN. - """ - self.mraa_gpio.Gpio.isrExit(self.mraa_gpio.Gpio(pin)) - - def wait_for_edge(self, pin, edge): - """Wait for an edge. Pin should be type IN. Edge must be RISING, - FALLING or BOTH. - """ - self.bbio_gpio.wait_for_edge(self.mraa_gpio.Gpio(pin), self._edge_mapping[edge]) - -def get_platform_gpio(**keywords): - """Attempt to return a GPIO instance for the platform which the code is being - executed on. Currently supports only the Raspberry Pi using the RPi.GPIO - library and Beaglebone Black using the Adafruit_BBIO library. Will throw an - exception if a GPIO instance can't be created for the current platform. The - returned GPIO object is an instance of BaseGPIO. - """ - plat = Platform.platform_detect() - if plat == Platform.RASPBERRY_PI: - import RPi.GPIO - return RPiGPIOAdapter(RPi.GPIO, **keywords) - elif plat == Platform.BEAGLEBONE_BLACK: - import Adafruit_BBIO.GPIO - return AdafruitBBIOAdapter(Adafruit_BBIO.GPIO, **keywords) - elif plat == Platform.MINNOWBOARD: - import mraa - return AdafruitMinnowAdapter(mraa, **keywords) - elif plat == Platform.UNKNOWN: - raise RuntimeError('Could not determine platform.') diff --git a/Adafruit_Python_GPIO/Adafruit_GPIO/I2C.py b/Adafruit_Python_GPIO/Adafruit_GPIO/I2C.py deleted file mode 100644 index 765ed82..0000000 --- a/Adafruit_Python_GPIO/Adafruit_GPIO/I2C.py +++ /dev/null @@ -1,202 +0,0 @@ -# Copyright (c) 2014 Adafruit Industries -# Author: Tony DiCola -# Based on Adafruit_I2C.py created by Kevin Townsend. -# -# 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. -import logging -import os -import subprocess - -import Adafruit_GPIO.Platform as Platform - - -def reverseByteOrder(data): - """DEPRECATED: See https://github.com/adafruit/Adafruit_Python_GPIO/issues/48""" - # # Courtesy Vishal Sapre - # byteCount = len(hex(data)[2:].replace('L','')[::2]) - # val = 0 - # for i in range(byteCount): - # val = (val << 8) | (data & 0xff) - # data >>= 8 - # return val - raise RuntimeError('reverseByteOrder is deprecated! See: https://github.com/adafruit/Adafruit_Python_GPIO/issues/48') - -def get_default_bus(): - """Return the default bus number based on the device platform. For a - Raspberry Pi either bus 0 or 1 (based on the Pi revision) will be returned. - For a Beaglebone Black the first user accessible bus, 1, will be returned. - """ - plat = Platform.platform_detect() - if plat == Platform.RASPBERRY_PI: - if Platform.pi_revision() == 1: - # Revision 1 Pi uses I2C bus 0. - return 0 - else: - # Revision 2 Pi uses I2C bus 1. - return 1 - elif plat == Platform.BEAGLEBONE_BLACK: - # Beaglebone Black has multiple I2C buses, default to 1 (P9_19 and P9_20). - return 1 - else: - raise RuntimeError('Could not determine default I2C bus for platform.') - -def get_i2c_device(address, busnum=None, i2c_interface=None, **kwargs): - """Return an I2C device for the specified address and on the specified bus. - If busnum isn't specified, the default I2C bus for the platform will attempt - to be detected. - """ - if busnum is None: - busnum = get_default_bus() - return Device(address, busnum, i2c_interface, **kwargs) - -def require_repeated_start(): - """Enable repeated start conditions for I2C register reads. This is the - normal behavior for I2C, however on some platforms like the Raspberry Pi - there are bugs which disable repeated starts unless explicitly enabled with - this function. See this thread for more details: - http://www.raspberrypi.org/forums/viewtopic.php?f=44&t=15840 - """ - plat = Platform.platform_detect() - if plat == Platform.RASPBERRY_PI and os.path.exists('/sys/module/i2c_bcm2708/parameters/combined'): - # On the Raspberry Pi there is a bug where register reads don't send a - # repeated start condition like the kernel smbus I2C driver functions - # define. As a workaround this bit in the BCM2708 driver sysfs tree can - # be changed to enable I2C repeated starts. - subprocess.check_call('chmod 666 /sys/module/i2c_bcm2708/parameters/combined', shell=True) - subprocess.check_call('echo -n 1 > /sys/module/i2c_bcm2708/parameters/combined', shell=True) - # Other platforms are a no-op because they (presumably) have the correct - # behavior and send repeated starts. - - -class Device(object): - """Class for communicating with an I2C device using the adafruit-pureio pure - python smbus library, or other smbus compatible I2C interface. Allows reading - and writing 8-bit, 16-bit, and byte array values to registers - on the device.""" - def __init__(self, address, busnum, i2c_interface=None): - """Create an instance of the I2C device at the specified address on the - specified I2C bus number.""" - self._address = address - if i2c_interface is None: - # Use pure python I2C interface if none is specified. - import Adafruit_PureIO.smbus - self._bus = Adafruit_PureIO.smbus.SMBus(busnum) - else: - # Otherwise use the provided class to create an smbus interface. - self._bus = i2c_interface(busnum) - self._logger = logging.getLogger('Adafruit_I2C.Device.Bus.{0}.Address.{1:#0X}' \ - .format(busnum, address)) - - def writeRaw8(self, value): - """Write an 8-bit value on the bus (without register).""" - value = value & 0xFF - self._bus.write_byte(self._address, value) - self._logger.debug("Wrote 0x%02X", - value) - - def write8(self, register, value): - """Write an 8-bit value to the specified register.""" - value = value & 0xFF - self._bus.write_byte_data(self._address, register, value) - self._logger.debug("Wrote 0x%02X to register 0x%02X", - value, register) - - def write16(self, register, value): - """Write a 16-bit value to the specified register.""" - value = value & 0xFFFF - self._bus.write_word_data(self._address, register, value) - self._logger.debug("Wrote 0x%04X to register pair 0x%02X, 0x%02X", - value, register, register+1) - - def writeList(self, register, data): - """Write bytes to the specified register.""" - self._bus.write_i2c_block_data(self._address, register, data) - self._logger.debug("Wrote to register 0x%02X: %s", - register, data) - - def readList(self, register, length): - """Read a length number of bytes from the specified register. Results - will be returned as a bytearray.""" - results = self._bus.read_i2c_block_data(self._address, register, length) - self._logger.debug("Read the following from register 0x%02X: %s", - register, results) - return results - - def readRaw8(self): - """Read an 8-bit value on the bus (without register).""" - result = self._bus.read_byte(self._address) & 0xFF - self._logger.debug("Read 0x%02X", - result) - return result - - def readU8(self, register): - """Read an unsigned byte from the specified register.""" - result = self._bus.read_byte_data(self._address, register) & 0xFF - self._logger.debug("Read 0x%02X from register 0x%02X", - result, register) - return result - - def readS8(self, register): - """Read a signed byte from the specified register.""" - result = self.readU8(register) - if result > 127: - result -= 256 - return result - - def readU16(self, register, little_endian=True): - """Read an unsigned 16-bit value from the specified register, with the - specified endianness (default little endian, or least significant byte - first).""" - result = self._bus.read_word_data(self._address,register) & 0xFFFF - self._logger.debug("Read 0x%04X from register pair 0x%02X, 0x%02X", - result, register, register+1) - # Swap bytes if using big endian because read_word_data assumes little - # endian on ARM (little endian) systems. - if not little_endian: - result = ((result << 8) & 0xFF00) + (result >> 8) - return result - - def readS16(self, register, little_endian=True): - """Read a signed 16-bit value from the specified register, with the - specified endianness (default little endian, or least significant byte - first).""" - result = self.readU16(register, little_endian) - if result > 32767: - result -= 65536 - return result - - def readU16LE(self, register): - """Read an unsigned 16-bit value from the specified register, in little - endian byte order.""" - return self.readU16(register, little_endian=True) - - def readU16BE(self, register): - """Read an unsigned 16-bit value from the specified register, in big - endian byte order.""" - return self.readU16(register, little_endian=False) - - def readS16LE(self, register): - """Read a signed 16-bit value from the specified register, in little - endian byte order.""" - return self.readS16(register, little_endian=True) - - def readS16BE(self, register): - """Read a signed 16-bit value from the specified register, in big - endian byte order.""" - return self.readS16(register, little_endian=False) diff --git a/Adafruit_Python_GPIO/Adafruit_GPIO/MCP230xx.py b/Adafruit_Python_GPIO/Adafruit_GPIO/MCP230xx.py deleted file mode 100644 index 3ba8b5f..0000000 --- a/Adafruit_Python_GPIO/Adafruit_GPIO/MCP230xx.py +++ /dev/null @@ -1,165 +0,0 @@ -# Copyright (c) 2014 Adafruit Industries -# Author: Tony DiCola -# -# 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. -import math - -import Adafruit_GPIO as GPIO -import Adafruit_GPIO.I2C as I2C - - -class MCP230xxBase(GPIO.BaseGPIO): - """Base class to represent an MCP230xx series GPIO extender. Is compatible - with the Adafruit_GPIO BaseGPIO class so it can be used as a custom GPIO - class for interacting with device. - """ - - def __init__(self, address, i2c=None, **kwargs): - """Initialize MCP230xx at specified I2C address and bus number. If bus - is not specified it will default to the appropriate platform detected bus. - """ - # Create I2C device. - if i2c is None: - import Adafruit_GPIO.I2C as I2C - i2c = I2C - self._device = i2c.get_i2c_device(address, **kwargs) - # Assume starting in ICON.BANK = 0 mode (sequential access). - # Compute how many bytes are needed to store count of GPIO. - self.gpio_bytes = int(math.ceil(self.NUM_GPIO/8.0)) - # Buffer register values so they can be changed without reading. - self.iodir = [0xFF]*self.gpio_bytes # Default direction to all inputs. - self.gppu = [0x00]*self.gpio_bytes # Default to pullups disabled. - self.gpio = [0x00]*self.gpio_bytes - # Write current direction and pullup buffer state. - self.write_iodir() - self.write_gppu() - - - def setup(self, pin, value): - """Set the input or output mode for a specified pin. Mode should be - either GPIO.OUT or GPIO.IN. - """ - self._validate_pin(pin) - # Set bit to 1 for input or 0 for output. - if value == GPIO.IN: - self.iodir[int(pin/8)] |= 1 << (int(pin%8)) - elif value == GPIO.OUT: - self.iodir[int(pin/8)] &= ~(1 << (int(pin%8))) - else: - raise ValueError('Unexpected value. Must be GPIO.IN or GPIO.OUT.') - self.write_iodir() - - - def output(self, pin, value): - """Set the specified pin the provided high/low value. Value should be - either GPIO.HIGH/GPIO.LOW or a boolean (True = HIGH). - """ - self.output_pins({pin: value}) - - def output_pins(self, pins): - """Set multiple pins high or low at once. Pins should be a dict of pin - name to pin value (HIGH/True for 1, LOW/False for 0). All provided pins - will be set to the given values. - """ - [self._validate_pin(pin) for pin in pins.keys()] - # Set each changed pin's bit. - for pin, value in iter(pins.items()): - if value: - self.gpio[int(pin/8)] |= 1 << (int(pin%8)) - else: - self.gpio[int(pin/8)] &= ~(1 << (int(pin%8))) - # Write GPIO state. - self.write_gpio() - - - def input(self, pin): - """Read the specified pin and return GPIO.HIGH/True if the pin is pulled - high, or GPIO.LOW/False if pulled low. - """ - return self.input_pins([pin])[0] - - def input_pins(self, pins): - """Read multiple pins specified in the given list and return list of pin values - GPIO.HIGH/True if the pin is pulled high, or GPIO.LOW/False if pulled low. - """ - [self._validate_pin(pin) for pin in pins] - # Get GPIO state. - self.gpio = self._device.readList(self.GPIO, self.gpio_bytes) - # Return True if pin's bit is set. - return [(self.gpio[int(pin/8)] & 1 << (int(pin%8))) > 0 for pin in pins] - - - def pullup(self, pin, enabled): - """Turn on the pull-up resistor for the specified pin if enabled is True, - otherwise turn off the pull-up resistor. - """ - self._validate_pin(pin) - if enabled: - self.gppu[int(pin/8)] |= 1 << (int(pin%8)) - else: - self.gppu[int(pin/8)] &= ~(1 << (int(pin%8))) - self.write_gppu() - - def write_gpio(self, gpio=None): - """Write the specified byte value to the GPIO registor. If no value - specified the current buffered value will be written. - """ - if gpio is not None: - self.gpio = gpio - self._device.writeList(self.GPIO, self.gpio) - - def write_iodir(self, iodir=None): - """Write the specified byte value to the IODIR registor. If no value - specified the current buffered value will be written. - """ - if iodir is not None: - self.iodir = iodir - self._device.writeList(self.IODIR, self.iodir) - - def write_gppu(self, gppu=None): - """Write the specified byte value to the GPPU registor. If no value - specified the current buffered value will be written. - """ - if gppu is not None: - self.gppu = gppu - self._device.writeList(self.GPPU, self.gppu) - - -class MCP23017(MCP230xxBase): - """MCP23017-based GPIO class with 16 GPIO pins.""" - # Define number of pins and registor addresses. - NUM_GPIO = 16 - IODIR = 0x00 - GPIO = 0x12 - GPPU = 0x0C - - def __init__(self, address=0x20, **kwargs): - super(MCP23017, self).__init__(address, **kwargs) - - -class MCP23008(MCP230xxBase): - """MCP23008-based GPIO class with 8 GPIO pins.""" - # Define number of pins and registor addresses. - NUM_GPIO = 8 - IODIR = 0x00 - GPIO = 0x09 - GPPU = 0x06 - - def __init__(self, address=0x20, **kwargs): - super(MCP23008, self).__init__(address, **kwargs) diff --git a/Adafruit_Python_GPIO/Adafruit_GPIO/PCA95xx.py b/Adafruit_Python_GPIO/Adafruit_GPIO/PCA95xx.py deleted file mode 100644 index 2a3b406..0000000 --- a/Adafruit_Python_GPIO/Adafruit_GPIO/PCA95xx.py +++ /dev/null @@ -1,121 +0,0 @@ -''' -Adafruit compatible using BaseGPIO class to represent a PCA9555 IO expander -Copyright (C) 2016 Matias Vidal -Ported from: https://github.com/dberlin/PCA95XX - -# Copyright 2012 Daniel Berlin - -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.''' - -import Adafruit_GPIO as GPIO -import Adafruit_GPIO.I2C as I2C - -# For the PCA 953X and 955X series, the chips with 8 GPIO's have these port numbers -# The chips with 16 GPIO's have the first port for each type at double these numbers -# IE The first config port is 6 - -INPUT_PORT = 0 -OUTPUT_PORT = 1 -POLARITY_PORT = 2 -CONFIG_PORT = 3 - -IN = GPIO.IN -OUT = GPIO.OUT -HIGH = GPIO.HIGH -LOW = GPIO.LOW - - -class PCA9555(GPIO.BaseGPIO): - """Class to represent a PCA9555 GPIO extender. Compatible - with the Adafruit_GPIO BaseGPIO class so it can be used as a custom GPIO - class for interacting with device. - """ - NUM_GPIO = 16 - - def __init__(self, address=0x20, busnum=None, i2c=None, num_gpios=16, **kwargs): - address = int(address) - self.__name__ = "PCA955" - # Create I2C device. - i2c = i2c or I2C - busnum = busnum or i2c.get_default_bus() - self._device = i2c.get_i2c_device(address, busnum, **kwargs) - self.num_gpios = num_gpios - - if self.num_gpios <= 8: - self.iodir = self._device.readU8(CONFIG_PORT) - self.outputvalue = self._device.readU8(OUTPUT_PORT) - - elif self.num_gpios > 8 and self.num_gpios <= 16: - self.iodir = self._device.readU16(CONFIG_PORT<< 1) - self.outputvalue = self._device.readU16(OUTPUT_PORT << 1) - - def _changebit(self, bitmap, bit, value): - assert value == 1 or value == 0, "Value is %s must be 1 or 0" % value - if value == 0: - return bitmap & ~(1 << bit) - elif value == 1: - return bitmap | (1 << bit) - - # Change the value of bit PIN on port PORT to VALUE. If the - # current pin state for the port is passed in as PORTSTATE, we - # will avoid doing a read to get it. The port pin state must be - # complete if passed in (IE it should not just be the value of the - # single pin we are trying to change) - def _readandchangepin(self, port, pin, value, portstate = None): - assert pin >= 0 and pin < self.num_gpios, "Pin number %s is invalid, only 0-%s are valid" % (pin, self.num_gpios) - if not portstate: - if self.num_gpios <= 8: - portstate = self._device.readU8(port) - elif self.num_gpios > 8 and self.num_gpios <= 16: - portstate = self._device.readU16(port << 1) - newstate = self._changebit(portstate, pin, value) - if self.num_gpios <= 8: - self._device.write8(port, newstate) - else: - self._device.write16(port << 1, newstate) - return newstate - - # Polarity inversion - def polarity(self, pin, value): - return self._readandchangepin(POLARITY_PORT, pin, value) - - # Pin direction - def config(self, pin, mode): - self.iodir = self._readandchangepin(CONFIG_PORT, pin, mode, self.iodir) - return self.iodir - - def output(self, pin, value): - assert self.iodir & (1 << pin) == 0, "Pin %s not set to output" % pin - self.outputvalue = self._readandchangepin(OUTPUT_PORT, pin, value, self.outputvalue) - return self.outputvalue - - def input(self, pin): - assert self.iodir & (1 << pin) != 0, "Pin %s not set to input" % pin - if self.num_gpios <= 8: - value = self._device.readU8(INPUT_PORT) - elif self.num_gpios > 8 and self.num_gpios <= 16: - value = self._device.readU16(INPUT_PORT << 1) - return value & (1 << pin) - - def setup(self, pin, mode): - self.config(pin, mode) - - def cleanup(self, pin=None): - # nothing to cleanup - pass diff --git a/Adafruit_Python_GPIO/Adafruit_GPIO/PCF8574.py b/Adafruit_Python_GPIO/Adafruit_GPIO/PCF8574.py deleted file mode 100644 index 02919d1..0000000 --- a/Adafruit_Python_GPIO/Adafruit_GPIO/PCF8574.py +++ /dev/null @@ -1,94 +0,0 @@ -''' -Adafruit compatible using BaseGPIO class to represent a PCF8574/A IO expander -Copyright (C) 2015 Sylvan Butler - -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.''' - -import Adafruit_GPIO as GPIO -import Adafruit_GPIO.I2C as I2C - - - -IN = GPIO.IN -OUT = GPIO.OUT -HIGH = GPIO.HIGH -LOW = GPIO.LOW - - -class PCF8574(GPIO.BaseGPIO): - """Class to represent a PCF8574 or PCF8574A GPIO extender. Compatible - with the Adafruit_GPIO BaseGPIO class so it can be used as a custom GPIO - class for interacting with device. - """ - - NUM_GPIO = 8 - - def __init__(self, address=0x27, busnum=None, i2c=None, **kwargs): - address = int(address) - self.__name__ = \ - "PCF8574" if address in range(0x20, 0x28) else \ - "PCF8574A" if address in range(0x38, 0x40) else \ - "Bad address for PCF8574(A): 0x%02X not in range [0x20..0x27, 0x38..0x3F]" % address - if self.__name__[0] != 'P': - raise ValueError(self.__name__) - # Create I2C device. - i2c = i2c or I2C - busnum = busnum or i2c.get_default_bus() - self._device = i2c.get_i2c_device(address, busnum, **kwargs) - # Buffer register values so they can be changed without reading. - self.iodir = 0xFF # Default direction to all inputs is in - self.gpio = 0x00 - self._write_pins() - - - def _write_pins(self): - self._device.writeRaw8(self.gpio | self.iodir) - - def _read_pins(self): - return self._device.readRaw8() & self.iodir - - - def setup(self, pin, mode): - self.setup_pins({pin: mode}) - - def setup_pins(self, pins): - if False in [y for x,y in [(self._validate_pin(pin),mode in (IN,OUT)) for pin,mode in pins.items()]]: - raise ValueError('Invalid MODE, IN or OUT') - for pin,mode in pins.items(): - self.iodir = self._bit2(self.iodir, pin, mode) - self._write_pins() - - - def output(self, pin, value): - self.output_pins({pin: value}) - - def output_pins(self, pins): - [self._validate_pin(pin) for pin in pins.keys()] - for pin,value in pins.items(): - self.gpio = self._bit2(self.gpio, pin, bool(value)) - self._write_pins() - - - def input(self, pin): - return self.input_pins([pin])[0] - - def input_pins(self, pins): - [self._validate_pin(pin) for pin in pins] - inp = self._read_pins() - return [bool(inp & (1<<pin)) for pin in pins] diff --git a/Adafruit_Python_GPIO/Adafruit_GPIO/PWM.py b/Adafruit_Python_GPIO/Adafruit_GPIO/PWM.py deleted file mode 100644 index 1e1717a..0000000 --- a/Adafruit_Python_GPIO/Adafruit_GPIO/PWM.py +++ /dev/null @@ -1,128 +0,0 @@ -# Copyright (c) 2014 Adafruit Industries -# Author: Tony DiCola -# -# 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. -import Adafruit_GPIO.Platform as Platform - - -class RPi_PWM_Adapter(object): - """PWM implementation for the Raspberry Pi using the RPi.GPIO PWM library.""" - - def __init__(self, rpi_gpio, mode=None): - self.rpi_gpio = rpi_gpio - # Suppress warnings about GPIO in use. - rpi_gpio.setwarnings(False) - # Set board or BCM pin numbering. - if mode == rpi_gpio.BOARD or mode == rpi_gpio.BCM: - rpi_gpio.setmode(mode) - elif mode is not None: - raise ValueError('Unexpected value for mode. Must be BOARD or BCM.') - else: - # Default to BCM numbering if not told otherwise. - rpi_gpio.setmode(rpi_gpio.BCM) - # Store reference to each created PWM instance. - self.pwm = {} - - def start(self, pin, dutycycle, frequency_hz=2000): - """Enable PWM output on specified pin. Set to intiial percent duty cycle - value (0.0 to 100.0) and frequency (in Hz). - """ - if dutycycle < 0.0 or dutycycle > 100.0: - raise ValueError('Invalid duty cycle value, must be between 0.0 to 100.0 (inclusive).') - # Make pin an output. - self.rpi_gpio.setup(pin, self.rpi_gpio.OUT) - # Create PWM instance and save a reference for later access. - self.pwm[pin] = self.rpi_gpio.PWM(pin, frequency_hz) - # Start the PWM at the specified duty cycle. - self.pwm[pin].start(dutycycle) - - def set_duty_cycle(self, pin, dutycycle): - """Set percent duty cycle of PWM output on specified pin. Duty cycle must - be a value 0.0 to 100.0 (inclusive). - """ - if dutycycle < 0.0 or dutycycle > 100.0: - raise ValueError('Invalid duty cycle value, must be between 0.0 to 100.0 (inclusive).') - if pin not in self.pwm: - raise ValueError('Pin {0} is not configured as a PWM. Make sure to first call start for the pin.'.format(pin)) - self.pwm[pin].ChangeDutyCycle(dutycycle) - - def set_frequency(self, pin, frequency_hz): - """Set frequency (in Hz) of PWM output on specified pin.""" - if pin not in self.pwm: - raise ValueError('Pin {0} is not configured as a PWM. Make sure to first call start for the pin.'.format(pin)) - self.pwm[pin].ChangeFrequency(frequency_hz) - - def stop(self, pin): - """Stop PWM output on specified pin.""" - if pin not in self.pwm: - raise ValueError('Pin {0} is not configured as a PWM. Make sure to first call start for the pin.'.format(pin)) - self.pwm[pin].stop() - del self.pwm[pin] - - -class BBIO_PWM_Adapter(object): - """PWM implementation for the BeagleBone Black using the Adafruit_BBIO.PWM - library. - """ - - def __init__(self, bbio_pwm): - self.bbio_pwm = bbio_pwm - - def start(self, pin, dutycycle, frequency_hz=2000): - """Enable PWM output on specified pin. Set to intiial percent duty cycle - value (0.0 to 100.0) and frequency (in Hz). - """ - if dutycycle < 0.0 or dutycycle > 100.0: - raise ValueError('Invalid duty cycle value, must be between 0.0 to 100.0 (inclusive).') - self.bbio_pwm.start(pin, dutycycle, frequency_hz) - - def set_duty_cycle(self, pin, dutycycle): - """Set percent duty cycle of PWM output on specified pin. Duty cycle must - be a value 0.0 to 100.0 (inclusive). - """ - if dutycycle < 0.0 or dutycycle > 100.0: - raise ValueError('Invalid duty cycle value, must be between 0.0 to 100.0 (inclusive).') - self.bbio_pwm.set_duty_cycle(pin, dutycycle) - - def set_frequency(self, pin, frequency_hz): - """Set frequency (in Hz) of PWM output on specified pin.""" - self.bbio_pwm.set_frequency(pin, frequency_hz) - - def stop(self, pin): - """Stop PWM output on specified pin.""" - self.bbio_pwm.stop(pin) - - -def get_platform_pwm(**keywords): - """Attempt to return a PWM instance for the platform which the code is being - executed on. Currently supports only the Raspberry Pi using the RPi.GPIO - library and Beaglebone Black using the Adafruit_BBIO library. Will throw an - exception if a PWM instance can't be created for the current platform. The - returned PWM object has the same interface as the RPi_PWM_Adapter and - BBIO_PWM_Adapter classes. - """ - plat = Platform.platform_detect() - if plat == Platform.RASPBERRY_PI: - import RPi.GPIO - return RPi_PWM_Adapter(RPi.GPIO, **keywords) - elif plat == Platform.BEAGLEBONE_BLACK: - import Adafruit_BBIO.PWM - return BBIO_PWM_Adapter(Adafruit_BBIO.PWM, **keywords) - elif plat == Platform.UNKNOWN: - raise RuntimeError('Could not determine platform.') diff --git a/Adafruit_Python_GPIO/Adafruit_GPIO/Platform.py b/Adafruit_Python_GPIO/Adafruit_GPIO/Platform.py deleted file mode 100644 index 2c041a8..0000000 --- a/Adafruit_Python_GPIO/Adafruit_GPIO/Platform.py +++ /dev/null @@ -1,110 +0,0 @@ -# Copyright (c) 2014 Adafruit Industries -# Author: Tony DiCola - -# 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. -import platform -import re - -# Platform identification constants. -UNKNOWN = 0 -RASPBERRY_PI = 1 -BEAGLEBONE_BLACK = 2 -MINNOWBOARD = 3 - -def platform_detect(): - """Detect if running on the Raspberry Pi or Beaglebone Black and return the - platform type. Will return RASPBERRY_PI, BEAGLEBONE_BLACK, or UNKNOWN.""" - # Handle Raspberry Pi - pi = pi_version() - if pi is not None: - return RASPBERRY_PI - - # Handle Beaglebone Black - # TODO: Check the Beaglebone Black /proc/cpuinfo value instead of reading - # the platform. - plat = platform.platform() - if plat.lower().find('armv7l-with-debian') > -1: - return BEAGLEBONE_BLACK - elif plat.lower().find('armv7l-with-ubuntu') > -1: - return BEAGLEBONE_BLACK - elif plat.lower().find('armv7l-with-glibc2.4') > -1: - return BEAGLEBONE_BLACK - - # Handle Minnowboard - # Assumption is that mraa is installed - try: - import mraa - if mraa.getPlatformName()=='MinnowBoard MAX': - return MINNOWBOARD - except ImportError: - pass - - # Couldn't figure out the platform, just return unknown. - return UNKNOWN - - -def pi_revision(): - """Detect the revision number of a Raspberry Pi, useful for changing - functionality like default I2C bus based on revision.""" - # Revision list available at: http://elinux.org/RPi_HardwareHistory#Board_Revision_History - with open('/proc/cpuinfo', 'r') as infile: - for line in infile: - # Match a line of the form "Revision : 0002" while ignoring extra - # info in front of the revsion (like 1000 when the Pi was over-volted). - match = re.match('Revision\s+:\s+.*(\w{4})$', line, flags=re.IGNORECASE) - if match and match.group(1) in ['0000', '0002', '0003']: - # Return revision 1 if revision ends with 0000, 0002 or 0003. - return 1 - elif match: - # Assume revision 2 if revision ends with any other 4 chars. - return 2 - # Couldn't find the revision, throw an exception. - raise RuntimeError('Could not determine Raspberry Pi revision.') - - -def pi_version(): - """Detect the version of the Raspberry Pi. Returns either 1, 2 or - None depending on if it's a Raspberry Pi 1 (model A, B, A+, B+), - Raspberry Pi 2 (model B+), or not a Raspberry Pi. - """ - # Check /proc/cpuinfo for the Hardware field value. - # 2708 is pi 1 - # 2709 is pi 2 - # 2835 is pi 3 on 4.9.x kernel - # Anything else is not a pi. - with open('/proc/cpuinfo', 'r') as infile: - cpuinfo = infile.read() - # Match a line like 'Hardware : BCM2709' - match = re.search('^Hardware\s+:\s+(\w+)$', cpuinfo, - flags=re.MULTILINE | re.IGNORECASE) - if not match: - # Couldn't find the hardware, assume it isn't a pi. - return None - if match.group(1) == 'BCM2708': - # Pi 1 - return 1 - elif match.group(1) == 'BCM2709': - # Pi 2 - return 2 - elif match.group(1) == 'BCM2835': - # Pi 3 / Pi on 4.9.x kernel - return 3 - else: - # Something else, not a pi. - return None diff --git a/Adafruit_Python_GPIO/Adafruit_GPIO/SPI.py b/Adafruit_Python_GPIO/Adafruit_GPIO/SPI.py deleted file mode 100644 index c20a32c..0000000 --- a/Adafruit_Python_GPIO/Adafruit_GPIO/SPI.py +++ /dev/null @@ -1,328 +0,0 @@ -# Copyright (c) 2014 Adafruit Industries -# Author: Tony DiCola -# -# 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. - -import operator -import time - -import Adafruit_GPIO as GPIO - - -MSBFIRST = 0 -LSBFIRST = 1 - - -class SpiDev(object): - """Hardware-based SPI implementation using the spidev interface.""" - - def __init__(self, port, device, max_speed_hz=500000): - """Initialize an SPI device using the SPIdev interface. Port and device - identify the device, for example the device /dev/spidev1.0 would be port - 1 and device 0. - """ - import spidev - self._device = spidev.SpiDev() - self._device.open(port, device) - self._device.max_speed_hz=max_speed_hz - # Default to mode 0, and make sure CS is active low. - self._device.mode = 0 - self._device.cshigh = False - - def set_clock_hz(self, hz): - """Set the speed of the SPI clock in hertz. Note that not all speeds - are supported and a lower speed might be chosen by the hardware. - """ - self._device.max_speed_hz=hz - - def set_mode(self, mode): - """Set SPI mode which controls clock polarity and phase. Should be a - numeric value 0, 1, 2, or 3. See wikipedia page for details on meaning: - http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus - """ - if mode < 0 or mode > 3: - raise ValueError('Mode must be a value 0, 1, 2, or 3.') - self._device.mode = mode - - def set_bit_order(self, order): - """Set order of bits to be read/written over serial lines. Should be - either MSBFIRST for most-significant first, or LSBFIRST for - least-signifcant first. - """ - if order == MSBFIRST: - self._device.lsbfirst = False - elif order == LSBFIRST: - self._device.lsbfirst = True - else: - raise ValueError('Order must be MSBFIRST or LSBFIRST.') - - def close(self): - """Close communication with the SPI device.""" - self._device.close() - - def write(self, data): - """Half-duplex SPI write. The specified array of bytes will be clocked - out the MOSI line. - """ - self._device.writebytes(data) - - def read(self, length): - """Half-duplex SPI read. The specified length of bytes will be clocked - in the MISO line and returned as a bytearray object. - """ - return bytearray(self._device.readbytes(length)) - - def transfer(self, data): - """Full-duplex SPI read and write. The specified array of bytes will be - clocked out the MOSI line, while simultaneously bytes will be read from - the MISO line. Read bytes will be returned as a bytearray object. - """ - return bytearray(self._device.xfer2(data)) - -class SpiDevMraa(object): - """Hardware SPI implementation with the mraa library on Minnowboard""" - def __init__(self, port, device, max_speed_hz=500000): - import mraa - self._device = mraa.Spi(0) - self._device.mode(0) - - def set_clock_hz(self, hz): - """Set the speed of the SPI clock in hertz. Note that not all speeds - are supported and a lower speed might be chosen by the hardware. - """ - self._device.frequency(hz) - - def set_mode(self,mode): - """Set SPI mode which controls clock polarity and phase. Should be a - numeric value 0, 1, 2, or 3. See wikipedia page for details on meaning: - http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus - """ - if mode < 0 or mode > 3: - raise ValueError('Mode must be a value 0, 1, 2, or 3.') - self._device.mode(mode) - - def set_bit_order(self, order): - """Set order of bits to be read/written over serial lines. Should be - either MSBFIRST for most-significant first, or LSBFIRST for - least-signifcant first. - """ - if order == MSBFIRST: - self._device.lsbmode(False) - elif order == LSBFIRST: - self._device.lsbmode(True) - else: - raise ValueError('Order must be MSBFIRST or LSBFIRST.') - - def close(self): - """Close communication with the SPI device.""" - self._device.Spi() - - def write(self, data): - """Half-duplex SPI write. The specified array of bytes will be clocked - out the MOSI line. - """ - self._device.write(bytearray(data)) - -class BitBang(object): - """Software-based implementation of the SPI protocol over GPIO pins.""" - - def __init__(self, gpio, sclk, mosi=None, miso=None, ss=None): - """Initialize bit bang (or software) based SPI. Must provide a BaseGPIO - class, the SPI clock, and optionally MOSI, MISO, and SS (slave select) - pin numbers. If MOSI is set to None then writes will be disabled and fail - with an error, likewise for MISO reads will be disabled. If SS is set to - None then SS will not be asserted high/low by the library when - transfering data. - """ - self._gpio = gpio - self._sclk = sclk - self._mosi = mosi - self._miso = miso - self._ss = ss - # Set pins as outputs/inputs. - gpio.setup(sclk, GPIO.OUT) - if mosi is not None: - gpio.setup(mosi, GPIO.OUT) - if miso is not None: - gpio.setup(miso, GPIO.IN) - if ss is not None: - gpio.setup(ss, GPIO.OUT) - # Assert SS high to start with device communication off. - gpio.set_high(ss) - # Assume mode 0. - self.set_mode(0) - # Assume most significant bit first order. - self.set_bit_order(MSBFIRST) - - def set_clock_hz(self, hz): - """Set the speed of the SPI clock. This is unsupported with the bit - bang SPI class and will be ignored. - """ - pass - - def set_mode(self, mode): - """Set SPI mode which controls clock polarity and phase. Should be a - numeric value 0, 1, 2, or 3. See wikipedia page for details on meaning: - http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus - """ - if mode < 0 or mode > 3: - raise ValueError('Mode must be a value 0, 1, 2, or 3.') - if mode & 0x02: - # Clock is normally high in mode 2 and 3. - self._clock_base = GPIO.HIGH - else: - # Clock is normally low in mode 0 and 1. - self._clock_base = GPIO.LOW - if mode & 0x01: - # Read on trailing edge in mode 1 and 3. - self._read_leading = False - else: - # Read on leading edge in mode 0 and 2. - self._read_leading = True - # Put clock into its base state. - self._gpio.output(self._sclk, self._clock_base) - - def set_bit_order(self, order): - """Set order of bits to be read/written over serial lines. Should be - either MSBFIRST for most-significant first, or LSBFIRST for - least-signifcant first. - """ - # Set self._mask to the bitmask which points at the appropriate bit to - # read or write, and appropriate left/right shift operator function for - # reading/writing. - if order == MSBFIRST: - self._mask = 0x80 - self._write_shift = operator.lshift - self._read_shift = operator.rshift - elif order == LSBFIRST: - self._mask = 0x01 - self._write_shift = operator.rshift - self._read_shift = operator.lshift - else: - raise ValueError('Order must be MSBFIRST or LSBFIRST.') - - def close(self): - """Close the SPI connection. Unused in the bit bang implementation.""" - pass - - def write(self, data, assert_ss=True, deassert_ss=True): - """Half-duplex SPI write. If assert_ss is True, the SS line will be - asserted low, the specified bytes will be clocked out the MOSI line, and - if deassert_ss is True the SS line be put back high. - """ - # Fail MOSI is not specified. - if self._mosi is None: - raise RuntimeError('Write attempted with no MOSI pin specified.') - if assert_ss and self._ss is not None: - self._gpio.set_low(self._ss) - for byte in data: - for i in range(8): - # Write bit to MOSI. - if self._write_shift(byte, i) & self._mask: - self._gpio.set_high(self._mosi) - else: - self._gpio.set_low(self._mosi) - # Flip clock off base. - self._gpio.output(self._sclk, not self._clock_base) - # Return clock to base. - self._gpio.output(self._sclk, self._clock_base) - if deassert_ss and self._ss is not None: - self._gpio.set_high(self._ss) - - def read(self, length, assert_ss=True, deassert_ss=True): - """Half-duplex SPI read. If assert_ss is true, the SS line will be - asserted low, the specified length of bytes will be clocked in the MISO - line, and if deassert_ss is true the SS line will be put back high. - Bytes which are read will be returned as a bytearray object. - """ - if self._miso is None: - raise RuntimeError('Read attempted with no MISO pin specified.') - if assert_ss and self._ss is not None: - self._gpio.set_low(self._ss) - result = bytearray(length) - for i in range(length): - for j in range(8): - # Flip clock off base. - self._gpio.output(self._sclk, not self._clock_base) - # Handle read on leading edge of clock. - if self._read_leading: - if self._gpio.is_high(self._miso): - # Set bit to 1 at appropriate location. - result[i] |= self._read_shift(self._mask, j) - else: - # Set bit to 0 at appropriate location. - result[i] &= ~self._read_shift(self._mask, j) - # Return clock to base. - self._gpio.output(self._sclk, self._clock_base) - # Handle read on trailing edge of clock. - if not self._read_leading: - if self._gpio.is_high(self._miso): - # Set bit to 1 at appropriate location. - result[i] |= self._read_shift(self._mask, j) - else: - # Set bit to 0 at appropriate location. - result[i] &= ~self._read_shift(self._mask, j) - if deassert_ss and self._ss is not None: - self._gpio.set_high(self._ss) - return result - - def transfer(self, data, assert_ss=True, deassert_ss=True): - """Full-duplex SPI read and write. If assert_ss is true, the SS line - will be asserted low, the specified bytes will be clocked out the MOSI - line while bytes will also be read from the MISO line, and if - deassert_ss is true the SS line will be put back high. Bytes which are - read will be returned as a bytearray object. - """ - if self._mosi is None: - raise RuntimeError('Write attempted with no MOSI pin specified.') - if self._mosi is None: - raise RuntimeError('Read attempted with no MISO pin specified.') - if assert_ss and self._ss is not None: - self._gpio.set_low(self._ss) - result = bytearray(len(data)) - for i in range(len(data)): - for j in range(8): - # Write bit to MOSI. - if self._write_shift(data[i], j) & self._mask: - self._gpio.set_high(self._mosi) - else: - self._gpio.set_low(self._mosi) - # Flip clock off base. - self._gpio.output(self._sclk, not self._clock_base) - # Handle read on leading edge of clock. - if self._read_leading: - if self._gpio.is_high(self._miso): - # Set bit to 1 at appropriate location. - result[i] |= self._read_shift(self._mask, j) - else: - # Set bit to 0 at appropriate location. - result[i] &= ~self._read_shift(self._mask, j) - # Return clock to base. - self._gpio.output(self._sclk, self._clock_base) - # Handle read on trailing edge of clock. - if not self._read_leading: - if self._gpio.is_high(self._miso): - # Set bit to 1 at appropriate location. - result[i] |= self._read_shift(self._mask, j) - else: - # Set bit to 0 at appropriate location. - result[i] &= ~self._read_shift(self._mask, j) - if deassert_ss and self._ss is not None: - self._gpio.set_high(self._ss) - return result diff --git a/Adafruit_Python_GPIO/Adafruit_GPIO/__init__.py b/Adafruit_Python_GPIO/Adafruit_GPIO/__init__.py deleted file mode 100644 index 7e99604..0000000 --- a/Adafruit_Python_GPIO/Adafruit_GPIO/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from __future__ import absolute_import - -from Adafruit_GPIO.GPIO import * |