moved a bunch of garbage (things that have nothing to do in root) to _trash
This commit is contained in:
parent
d094982b2c
commit
3226ed29ec
2610 changed files with 0 additions and 0 deletions
|
@ -1,404 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2020 Melissa LeBlanc-Williams for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
"""
|
||||
`Adafruit_PureIO.spi`
|
||||
================================================================================
|
||||
|
||||
Pure python (i.e. no native extensions) access to Linux IO SPI interface that is
|
||||
similar to the SpiDev API. Based heavily on https://github.com/tomstokes/python-spi/.
|
||||
|
||||
* Author(s): Tom Stokes, Melissa LeBlanc-Williams
|
||||
|
||||
Implementation Notes
|
||||
--------------------
|
||||
|
||||
**Software and Dependencies:**
|
||||
|
||||
* Linux and Python 3.5 or Higher
|
||||
|
||||
"""
|
||||
|
||||
# imports
|
||||
from ctypes import create_string_buffer, string_at, addressof
|
||||
from fcntl import ioctl
|
||||
import struct
|
||||
import platform
|
||||
import os.path
|
||||
from os import environ
|
||||
import array
|
||||
|
||||
__version__ = "1.1.11"
|
||||
__repo__ = "https://github.com/adafruit/Adafruit_Python_PureIO.git"
|
||||
|
||||
# SPI C API constants (from linux kernel headers)
|
||||
SPI_CPHA = 0x01
|
||||
SPI_CPOL = 0x02
|
||||
SPI_CS_HIGH = 0x04
|
||||
SPI_LSB_FIRST = 0x08
|
||||
SPI_THREE_WIRE = 0x10
|
||||
SPI_LOOP = 0x20
|
||||
SPI_NO_CS = 0x40
|
||||
SPI_READY = 0x80
|
||||
SPI_TX_DUAL = 0x100
|
||||
SPI_TX_QUAD = 0x200
|
||||
SPI_RX_DUAL = 0x400
|
||||
SPI_RX_QUAD = 0x800
|
||||
|
||||
SPI_MODE_0 = 0
|
||||
SPI_MODE_1 = SPI_CPHA
|
||||
SPI_MODE_2 = SPI_CPOL
|
||||
SPI_MODE_3 = SPI_CPHA | SPI_CPOL
|
||||
|
||||
SPI_DEFAULT_CHUNK_SIZE = 4096
|
||||
|
||||
|
||||
def _ioc_encode(direction, number, structure):
|
||||
"""
|
||||
ioctl command encoding helper function
|
||||
Calculates the appropriate spidev ioctl op argument given the direction,
|
||||
command number, and argument structure in python's struct.pack format.
|
||||
Returns a tuple of the calculated op and the struct.pack format
|
||||
See Linux kernel source file /include/uapi/asm/ioctl.h
|
||||
"""
|
||||
ioc_magic = ord("k")
|
||||
ioc_nrbits = 8
|
||||
ioc_typebits = 8
|
||||
if platform.machine() == "mips":
|
||||
ioc_sizebits = 13
|
||||
else:
|
||||
ioc_sizebits = 14
|
||||
|
||||
ioc_nrshift = 0
|
||||
ioc_typeshift = ioc_nrshift + ioc_nrbits
|
||||
ioc_sizeshift = ioc_typeshift + ioc_typebits
|
||||
ioc_dirshift = ioc_sizeshift + ioc_sizebits
|
||||
|
||||
size = struct.calcsize(structure)
|
||||
|
||||
operation = (
|
||||
(direction << ioc_dirshift)
|
||||
| (ioc_magic << ioc_typeshift)
|
||||
| (number << ioc_nrshift)
|
||||
| (size << ioc_sizeshift)
|
||||
)
|
||||
|
||||
return direction, operation, structure
|
||||
|
||||
|
||||
# pylint: disable=too-many-instance-attributes, too-many-branches
|
||||
class SPI:
|
||||
"""
|
||||
This class is similar to SpiDev, but instead of opening and closing
|
||||
for each call, it is set up on initialization making it fast.
|
||||
"""
|
||||
|
||||
_IOC_TRANSFER_FORMAT = "QQIIHBBBBH"
|
||||
|
||||
if platform.machine() == "mips":
|
||||
# Direction is 3 bits
|
||||
_IOC_READ = 2
|
||||
_IOC_WRITE = 4
|
||||
else:
|
||||
# Direction is 2 bits
|
||||
_IOC_WRITE = 1
|
||||
_IOC_READ = 2
|
||||
|
||||
# _IOC_MESSAGE is a special case, so we ony need the ioctl operation
|
||||
_IOC_MESSAGE = _ioc_encode(_IOC_WRITE, 0, _IOC_TRANSFER_FORMAT)[1]
|
||||
|
||||
_IOC_RD_MODE = _ioc_encode(_IOC_READ, 1, "B")
|
||||
_IOC_WR_MODE = _ioc_encode(_IOC_WRITE, 1, "B")
|
||||
|
||||
_IOC_RD_LSB_FIRST = _ioc_encode(_IOC_READ, 2, "B")
|
||||
_IOC_WR_LSB_FIRST = _ioc_encode(_IOC_WRITE, 2, "B")
|
||||
|
||||
_IOC_RD_BITS_PER_WORD = _ioc_encode(_IOC_READ, 3, "B")
|
||||
_IOC_WR_BITS_PER_WORD = _ioc_encode(_IOC_WRITE, 3, "B")
|
||||
|
||||
_IOC_RD_MAX_SPEED_HZ = _ioc_encode(_IOC_READ, 4, "I")
|
||||
_IOC_WR_MAX_SPEED_HZ = _ioc_encode(_IOC_WRITE, 4, "I")
|
||||
|
||||
_IOC_RD_MODE32 = _ioc_encode(_IOC_READ, 5, "I")
|
||||
_IOC_WR_MODE32 = _ioc_encode(_IOC_WRITE, 5, "I")
|
||||
# pylint: disable=too-many-arguments
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
device,
|
||||
max_speed_hz=None,
|
||||
bits_per_word=None,
|
||||
phase=None,
|
||||
polarity=None,
|
||||
cs_high=None,
|
||||
lsb_first=None,
|
||||
three_wire=None,
|
||||
loop=None,
|
||||
no_cs=None,
|
||||
ready=None,
|
||||
):
|
||||
"""
|
||||
Create spidev interface object.
|
||||
"""
|
||||
if isinstance(device, tuple):
|
||||
(bus, dev) = device
|
||||
device = f"/dev/spidev{bus:d}.{dev:d}"
|
||||
|
||||
if not os.path.exists(device):
|
||||
raise IOError(f"{device} does not exist")
|
||||
|
||||
self.handle = os.open(device, os.O_RDWR)
|
||||
|
||||
self.chunk_size = SPI_DEFAULT_CHUNK_SIZE
|
||||
if environ.get("SPI_BUFSIZE") is not None:
|
||||
try:
|
||||
self.chunk_size = int(os.environ.get("SPI_BUFSIZE"))
|
||||
except ValueError:
|
||||
self.chunk_size = SPI_DEFAULT_CHUNK_SIZE
|
||||
|
||||
if max_speed_hz is not None:
|
||||
self.max_speed_hz = max_speed_hz
|
||||
|
||||
if bits_per_word is not None:
|
||||
self.bits_per_word = bits_per_word
|
||||
|
||||
if phase is not None:
|
||||
self.phase = phase
|
||||
|
||||
if polarity is not None:
|
||||
self.polarity = polarity
|
||||
|
||||
if cs_high is not None:
|
||||
self.cs_high = cs_high
|
||||
|
||||
if lsb_first is not None:
|
||||
self.lsb_first = lsb_first
|
||||
|
||||
if three_wire is not None:
|
||||
self.three_wire = three_wire
|
||||
|
||||
if loop is not None:
|
||||
self.loop = loop
|
||||
|
||||
if no_cs is not None:
|
||||
self.no_cs = no_cs
|
||||
|
||||
if ready is not None:
|
||||
self.ready = ready
|
||||
|
||||
# pylint: enable=too-many-arguments
|
||||
|
||||
def _ioctl(self, ioctl_data, data=None):
|
||||
"""
|
||||
ioctl helper function.
|
||||
|
||||
Performs an ioctl on self.handle. If the ioctl is an SPI read type
|
||||
ioctl, returns the result value.
|
||||
"""
|
||||
(direction, ioctl_bytes, structure) = ioctl_data
|
||||
if direction == SPI._IOC_READ:
|
||||
arg = array.array(structure, [0])
|
||||
ioctl(self.handle, ioctl_bytes, arg, True)
|
||||
return arg[0]
|
||||
|
||||
arg = struct.pack("=" + structure, data)
|
||||
ioctl(self.handle, ioctl_bytes, arg)
|
||||
return None
|
||||
|
||||
def _get_mode_field(self, field):
|
||||
"""Helper function to get specific spidev mode bits"""
|
||||
return bool(self._ioctl(SPI._IOC_RD_MODE) & field)
|
||||
|
||||
def _set_mode_field(self, field, value):
|
||||
"""Helper function to set a spidev mode bit"""
|
||||
mode = self._ioctl(SPI._IOC_RD_MODE)
|
||||
if value:
|
||||
mode |= field
|
||||
else:
|
||||
mode &= ~field
|
||||
self._ioctl(SPI._IOC_WR_MODE, mode)
|
||||
|
||||
@property
|
||||
def phase(self):
|
||||
"""SPI clock phase bit"""
|
||||
return self._get_mode_field(SPI_CPHA)
|
||||
|
||||
@phase.setter
|
||||
def phase(self, phase):
|
||||
self._set_mode_field(SPI_CPHA, phase)
|
||||
|
||||
@property
|
||||
def polarity(self):
|
||||
"""SPI polarity bit"""
|
||||
return self._get_mode_field(SPI_CPOL)
|
||||
|
||||
@polarity.setter
|
||||
def polarity(self, polarity):
|
||||
self._set_mode_field(SPI_CPOL, polarity)
|
||||
|
||||
@property
|
||||
def cs_high(self):
|
||||
"""SPI chip select active level"""
|
||||
return self._get_mode_field(SPI_CS_HIGH)
|
||||
|
||||
@cs_high.setter
|
||||
def cs_high(self, cs_high):
|
||||
self._set_mode_field(SPI_CS_HIGH, cs_high)
|
||||
|
||||
@property
|
||||
def lsb_first(self):
|
||||
"""Bit order of SPI word transfers"""
|
||||
return self._get_mode_field(SPI_LSB_FIRST)
|
||||
|
||||
@lsb_first.setter
|
||||
def lsb_first(self, lsb_first):
|
||||
self._set_mode_field(SPI_LSB_FIRST, lsb_first)
|
||||
|
||||
@property
|
||||
def three_wire(self):
|
||||
"""SPI 3-wire mode"""
|
||||
return self._get_mode_field(SPI_THREE_WIRE)
|
||||
|
||||
@three_wire.setter
|
||||
def three_wire(self, three_wire):
|
||||
self._set_mode_field(SPI_THREE_WIRE, three_wire)
|
||||
|
||||
@property
|
||||
def loop(self):
|
||||
"""SPI loopback mode"""
|
||||
return self._get_mode_field(SPI_LOOP)
|
||||
|
||||
@loop.setter
|
||||
def loop(self, loop):
|
||||
self._set_mode_field(SPI_LOOP, loop)
|
||||
|
||||
@property
|
||||
def no_cs(self):
|
||||
"""No chipselect. Single device on bus."""
|
||||
return self._get_mode_field(SPI_NO_CS)
|
||||
|
||||
@no_cs.setter
|
||||
def no_cs(self, no_cs):
|
||||
self._set_mode_field(SPI_NO_CS, no_cs)
|
||||
|
||||
@property
|
||||
def ready(self):
|
||||
"""Slave pulls low to pause"""
|
||||
return self._get_mode_field(SPI_READY)
|
||||
|
||||
@ready.setter
|
||||
def ready(self, ready):
|
||||
self._set_mode_field(SPI_READY, ready)
|
||||
|
||||
@property
|
||||
def max_speed_hz(self):
|
||||
"""Maximum SPI transfer speed in Hz.
|
||||
|
||||
Note that the controller cannot necessarily assign the requested
|
||||
speed.
|
||||
"""
|
||||
return self._ioctl(SPI._IOC_RD_MAX_SPEED_HZ)
|
||||
|
||||
@max_speed_hz.setter
|
||||
def max_speed_hz(self, max_speed_hz):
|
||||
self._ioctl(SPI._IOC_WR_MAX_SPEED_HZ, max_speed_hz)
|
||||
|
||||
@property
|
||||
def bits_per_word(self):
|
||||
"""Number of bits per word of SPI transfer.
|
||||
|
||||
A value of 0 is equivalent to 8 bits per word
|
||||
"""
|
||||
return self._ioctl(SPI._IOC_RD_BITS_PER_WORD)
|
||||
|
||||
@bits_per_word.setter
|
||||
def bits_per_word(self, bits_per_word):
|
||||
self._ioctl(SPI._IOC_WR_BITS_PER_WORD, bits_per_word)
|
||||
|
||||
@property
|
||||
def mode(self):
|
||||
"""Mode that SPI is currently running in"""
|
||||
return self._ioctl(SPI._IOC_RD_MODE)
|
||||
|
||||
@mode.setter
|
||||
def mode(self, mode):
|
||||
self._ioctl(SPI._IOC_WR_MODE, mode)
|
||||
|
||||
def writebytes(self, data, max_speed_hz=0, bits_per_word=0, delay=0):
|
||||
"""Perform half-duplex SPI write."""
|
||||
data = array.array("B", data).tobytes()
|
||||
# length = len(data)
|
||||
chunks = [
|
||||
data[i : i + self.chunk_size] for i in range(0, len(data), self.chunk_size)
|
||||
]
|
||||
for chunk in chunks:
|
||||
length = len(chunk)
|
||||
transmit_buffer = create_string_buffer(chunk)
|
||||
spi_ioc_transfer = struct.pack(
|
||||
SPI._IOC_TRANSFER_FORMAT,
|
||||
addressof(transmit_buffer),
|
||||
0,
|
||||
length,
|
||||
max_speed_hz,
|
||||
delay,
|
||||
bits_per_word,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
try:
|
||||
ioctl(self.handle, SPI._IOC_MESSAGE, spi_ioc_transfer)
|
||||
except TimeoutError as err:
|
||||
raise Exception( # pylint: disable=broad-exception-raised
|
||||
"ioctl timeout. Please try a different SPI frequency or less data."
|
||||
) from err
|
||||
|
||||
def readbytes(self, length, max_speed_hz=0, bits_per_word=0, delay=0):
|
||||
"""Perform half-duplex SPI read as a binary string"""
|
||||
receive_buffer = create_string_buffer(length)
|
||||
spi_ioc_transfer = struct.pack(
|
||||
SPI._IOC_TRANSFER_FORMAT,
|
||||
0,
|
||||
addressof(receive_buffer),
|
||||
length,
|
||||
max_speed_hz,
|
||||
delay,
|
||||
bits_per_word,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
ioctl(self.handle, SPI._IOC_MESSAGE, spi_ioc_transfer)
|
||||
return string_at(receive_buffer, length)
|
||||
|
||||
def transfer(self, data, max_speed_hz=0, bits_per_word=0, delay=0):
|
||||
"""Perform full-duplex SPI transfer"""
|
||||
data = array.array("B", data).tobytes()
|
||||
receive_data = []
|
||||
|
||||
chunks = [
|
||||
data[i : i + self.chunk_size] for i in range(0, len(data), self.chunk_size)
|
||||
]
|
||||
for chunk in chunks:
|
||||
length = len(chunk)
|
||||
receive_buffer = create_string_buffer(length)
|
||||
transmit_buffer = create_string_buffer(chunk)
|
||||
spi_ioc_transfer = struct.pack(
|
||||
SPI._IOC_TRANSFER_FORMAT,
|
||||
addressof(transmit_buffer),
|
||||
addressof(receive_buffer),
|
||||
length,
|
||||
max_speed_hz,
|
||||
delay,
|
||||
bits_per_word,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
ioctl(self.handle, SPI._IOC_MESSAGE, spi_ioc_transfer)
|
||||
receive_data += string_at(receive_buffer, length)
|
||||
return receive_data
|
Loading…
Add table
Add a link
Reference in a new issue