diff options
Diffstat (limited to 'Adafruit_Python_GPIO/Adafruit_GPIO/PCA95xx.py')
-rw-r--r-- | Adafruit_Python_GPIO/Adafruit_GPIO/PCA95xx.py | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/Adafruit_Python_GPIO/Adafruit_GPIO/PCA95xx.py b/Adafruit_Python_GPIO/Adafruit_GPIO/PCA95xx.py new file mode 100644 index 0000000..2a3b406 --- /dev/null +++ b/Adafruit_Python_GPIO/Adafruit_GPIO/PCA95xx.py @@ -0,0 +1,121 @@ +''' +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 |