openpdu-libs/usr/lib/python2.7/site-packages/oled/serial.py

174 lines
5.4 KiB
Python

# -*- coding: utf-8 -*-
# Copyright (c) 2016 Richard Hull and contributors
# See LICENSE.rst for details.
import errno
import oled.error
class i2c(object):
"""
Wrap an `I2C <https://en.wikipedia.org/wiki/I%C2%B2C>`_ interface to
provide data and command methods.
:param bus: I2C bus instance.
:type bus:
:param port: I2C port number.
:type port: int
:param address: I2C address.
:type address:
:raises oled.error.DeviceAddressError: I2C device address is invalid.
:raises oled.error.DeviceNotFoundError: I2C device could not be found.
:raises oled.error.DevicePermissionError: Permission to access I2C device
denied.
.. note::
1. Only one of ``bus`` OR ``port`` arguments should be supplied;
if both are, then ``bus`` takes precedence.
2. If ``bus`` is provided, there is an implicit expectation
that it has already been opened.
"""
def __init__(self, bus=None, port=1, address=0x3C):
import smbus2
self._cmd_mode = 0x00
self._data_mode = 0x40
try:
self._addr = int(str(address), 0)
except ValueError:
raise oled.error.DeviceAddressError(
'I2C device address invalid: {}'.format(address))
try:
self._bus = bus or smbus2.SMBus(port)
except (IOError, OSError) as e:
if e.errno == errno.ENOENT:
# FileNotFoundError
raise oled.error.DeviceNotFoundError(
'I2C device not found: {}'.format(e.filename))
elif e.errno == errno.EPERM or e.errno == errno.EACCES:
# PermissionError
raise oled.error.DevicePermissionError(
'I2C device permission denied: {}'.format(e.filename))
else:
raise
def command(self, *cmd):
"""
Sends a command or sequence of commands through to the I2C address
- maximum allowed is 32 bytes in one go.
"""
assert(len(cmd) <= 32)
self._bus.write_i2c_block_data(self._addr, self._cmd_mode, list(cmd))
def data(self, data):
"""
Sends a data byte or sequence of data bytes through to the I2C
address - maximum allowed in one transaction is 32 bytes, so if
data is larger than this, it is sent in chunks.
"""
i = 0
n = len(data)
write = self._bus.write_i2c_block_data
while i < n:
write(self._addr, self._data_mode, list(data[i:i + 32]))
i += 32
def cleanup(self):
"""
Clean up I2C resources
"""
self._bus.close()
class spi(object):
"""
Wraps an `SPI <https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus>`_
interface to provide data and command methods.
* The DC pin (Data/Command select) defaults to GPIO 24 (BCM).
* The RST pin (Reset) defaults to GPIO 25 (BCM).
:raises oled.error.DeviceNotFoundError: SPI device could not be found.
"""
def __init__(self, spi=None, gpio=None, port=0, device=0,
bus_speed_hz=8000000, bcm_DC=24, bcm_RST=25):
self._gpio = gpio or self.__rpi_gpio__()
self._spi = spi or self.__spidev__()
try:
self._spi.open(port, device)
except (IOError, OSError) as e:
if e.errno == errno.ENOENT:
# FileNotFoundError
raise oled.error.DeviceNotFoundError('SPI device not found')
else:
raise
self._spi.max_speed_hz = bus_speed_hz
self._bcm_DC = bcm_DC
self._bcm_RST = bcm_RST
self._cmd_mode = self._gpio.LOW # Command mode = Hold low
self._data_mode = self._gpio.HIGH # Data mode = Pull high
self._gpio.setmode(self._gpio.BCM)
self._gpio.setup(self._bcm_DC, self._gpio.OUT)
self._gpio.setup(self._bcm_RST, self._gpio.OUT)
self._gpio.output(self._bcm_RST, self._gpio.HIGH) # Keep RESET pulled high
def __rpi_gpio__(self):
# RPi.GPIO _really_ doesn't like being run on anything other than
# a Raspberry Pi... this is imported here so we can swap out the
# implementation for a mock
import RPi.GPIO
return RPi.GPIO
def __spidev__(self):
# spidev cant compile on macOS, so use a similar technique to
# initialize (mainly so the tests run unhindered)
import spidev
return spidev.SpiDev()
def command(self, *cmd):
"""
Sends a command or sequence of commands through to the SPI device.
"""
self._gpio.output(self._bcm_DC, self._cmd_mode)
self._spi.xfer2(list(cmd))
def data(self, data):
"""
Sends a data byte or sequence of data bytes through to the SPI device.
If the data is more than 4Kb in size, it is sent in chunks.
"""
self._gpio.output(self._bcm_DC, self._data_mode)
i = 0
n = len(data)
write = self._spi.xfer2
while i < n:
write(data[i:i + 4096])
i += 4096
def cleanup(self):
"""
Clean up SPI & GPIO resources
"""
self._spi.close()
self._gpio.cleanup()
class noop(object):
"""
Does nothing, used for pseudo-devices / emulators, which dont have a serial
interface.
"""
def command(self, *cmd):
pass
def data(self, data):
pass
def cleanup(self):
pass