# -*- coding: utf-8 -*-
# Copyright (c) 2020-2023 Richard Hull and contributors
# See LICENSE.rst for details.
"""
Encapsulates sending commands and data over a parallel-bus interface.
"""
from time import sleep
from luma.core import lib
__all__ = ["bitbang_6800"]
"""
Default amount of time to wait for a pulse to complete if the device the
interface is connected to requires a pin to be 'pulsed' from low to high to
low for it to accept data or a command
"""
PULSE_TIME = 1e-6 * 50
[docs]
@lib.rpi_gpio
class bitbang_6800(object):
"""
Implements a 6800 style parallel-bus interface that provides :py:func:`data`
and :py:func:`command` methods. The default pin assignments provided are
from `Adafruit <https://learn.adafruit.com/drive-a-16x2-lcd-directly-with-a-raspberry-pi/wiring>`_.
:param gpio: GPIO interface (must be compatible with
`RPi.GPIO <https://pypi.org/project/RPi.GPIO>`__)
:param pulse_time: length of time in seconds that the enable line should be
held high during a data or command transfer
:type pulse_time: float
:param RS: The GPIO pin register select (RS) line (low for command, high
for data). Default: 22
:type RS: int
:param E: The GPIO pin to connect the enable (E) line to. Default: 17
:type E: int
:param PINS: The GPIO pins that form the data bus (a list of 4 or 8 pins
depending upon implementation ordered from LSD to MSD). Default: ``[25, 24, 23, 18]``
:type PINS: list[int]
.. versionadded:: 1.16.2
"""
def __init__(self, gpio=None, pulse_time=PULSE_TIME, **kwargs):
self._managed = gpio is None
self._gpio = gpio or self.__rpi_gpio__()
self._gpio.setwarnings(False)
self._pulse_time = pulse_time
self._RS = self._configure(kwargs.get("RS", 22))
self._E = self._configure(kwargs.get("E", 17))
self._PINS = self._configure(kwargs.get('PINS', [25, 24, 23, 18]))
self._datalines = len(self._PINS)
assert self._datalines in (4, 8), f'You\'ve provided {len(self._PINS)} pins but a bus must contain either four or eight pins'
self._bitmode = self._datalines # Used by device to autoset its own bitmode
self._cmd_mode = self._gpio.LOW # Command mode = Hold low
self._data_mode = self._gpio.HIGH # Data mode = Pull high
def _configure(self, pin):
pins = pin if type(pin) is list else [pin] if pin else []
for p in pins:
self._gpio.setup(p, self._gpio.OUT)
return pin
[docs]
def command(self, *cmd):
"""
Sends a command or sequence of commands through the bus.
If the bus is in 4-bit mode, only the lowest 4 bits of the data
value will be sent.
This means that the device needs to send high and low bits separately
if the device is operating using a 4-bit bus; to send a ``0x32`` in
4-bit mode the device would use: ``command(0x03, 0x02)``
:param cmd: A spread of commands.
:type cmd: int
"""
self._write(list(cmd), self._cmd_mode)
[docs]
def data(self, data):
"""
Sends a data byte or sequence of data bytes through to the bus.
If the bus is in 4-bit mode, only the lowest 4 bits of the data
value will be sent.
This means that the device needs to send high and low bits separately
if the device is operating using a 4-bit bus; to send a ``0x32`` in
4-bit mode the device would use: ``data([0x03, 0x02])``
:param data: A data sequence.
:type data: list, bytearray
"""
self._write(data, self._data_mode)
def _write(self, data, mode):
gpio = self._gpio
gpio.output(self._RS, mode)
gpio.output(self._E, gpio.LOW)
for value in data:
for i in range(self._datalines):
gpio.output(self._PINS[i], (value >> i) & 0x01)
gpio.output(self._E, gpio.HIGH)
sleep(self._pulse_time)
gpio.output(self._E, gpio.LOW)
[docs]
def cleanup(self):
"""
Clean up GPIO resources.
"""
if self._managed:
self._gpio.cleanup([self._RS, self._E, *self._PINS])