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
|
@ -0,0 +1,3 @@
|
|||
# SPDX-FileCopyrightText: 2020 Melissa LeBlanc-Williams for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
386
_trash/lib/python3.11/site-packages/Adafruit_PureIO/smbus.py
Normal file
386
_trash/lib/python3.11/site-packages/Adafruit_PureIO/smbus.py
Normal file
|
@ -0,0 +1,386 @@
|
|||
# SPDX-FileCopyrightText: 2016 Tony DiCola for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
"""
|
||||
`Adafruit_PureIO.smbus`
|
||||
================================================================================
|
||||
|
||||
Pure python (i.e. no native extensions) access to Linux IO I2C interface that mimics the
|
||||
Python SMBus API.
|
||||
|
||||
* Author(s): Tony DiCola, Lady Ada, Melissa LeBlanc-Williams
|
||||
|
||||
Implementation Notes
|
||||
--------------------
|
||||
|
||||
**Software and Dependencies:**
|
||||
|
||||
* Linux and Python 3.5 or Higher
|
||||
|
||||
"""
|
||||
|
||||
from ctypes import c_uint8, c_uint16, c_uint32, cast, pointer, POINTER
|
||||
from ctypes import create_string_buffer, Structure
|
||||
from fcntl import ioctl
|
||||
import struct
|
||||
|
||||
# pylint: disable=fixme
|
||||
|
||||
# I2C C API constants (from linux kernel headers)
|
||||
I2C_M_TEN = 0x0010 # this is a ten bit chip address
|
||||
I2C_M_RD = 0x0001 # read data, from slave to master
|
||||
I2C_M_STOP = 0x8000 # if I2C_FUNC_PROTOCOL_MANGLING
|
||||
I2C_M_NOSTART = 0x4000 # if I2C_FUNC_NOSTART
|
||||
I2C_M_REV_DIR_ADDR = 0x2000 # if I2C_FUNC_PROTOCOL_MANGLING
|
||||
I2C_M_IGNORE_NAK = 0x1000 # if I2C_FUNC_PROTOCOL_MANGLING
|
||||
I2C_M_NO_RD_ACK = 0x0800 # if I2C_FUNC_PROTOCOL_MANGLING
|
||||
I2C_M_RECV_LEN = 0x0400 # length will be first received byte
|
||||
|
||||
I2C_SLAVE = 0x0703 # Use this slave address
|
||||
I2C_SLAVE_FORCE = 0x0706 # Use this slave address, even if
|
||||
# is already in use by a driver!
|
||||
I2C_TENBIT = 0x0704 # 0 for 7 bit addrs, != 0 for 10 bit
|
||||
I2C_FUNCS = 0x0705 # Get the adapter functionality mask
|
||||
I2C_RDWR = 0x0707 # Combined R/W transfer (one STOP only)
|
||||
I2C_PEC = 0x0708 # != 0 to use PEC with SMBus
|
||||
I2C_SMBUS = 0x0720 # SMBus transfer
|
||||
|
||||
|
||||
# ctypes versions of I2C structs defined by kernel.
|
||||
# Tone down pylint for the Python classes that mirror C structs.
|
||||
# pylint: disable=invalid-name,too-few-public-methods
|
||||
class i2c_msg(Structure):
|
||||
"""Linux i2c_msg struct."""
|
||||
|
||||
_fields_ = [
|
||||
("addr", c_uint16),
|
||||
("flags", c_uint16),
|
||||
("len", c_uint16),
|
||||
("buf", POINTER(c_uint8)),
|
||||
]
|
||||
|
||||
|
||||
class i2c_rdwr_ioctl_data(Structure): # pylint: disable=invalid-name
|
||||
"""Linux i2c data struct."""
|
||||
|
||||
_fields_ = [("msgs", POINTER(i2c_msg)), ("nmsgs", c_uint32)]
|
||||
|
||||
|
||||
# pylint: enable=invalid-name,too-few-public-methods
|
||||
|
||||
|
||||
# pylint: disable=attribute-defined-outside-init
|
||||
def make_i2c_rdwr_data(messages):
|
||||
"""Utility function to create and return an i2c_rdwr_ioctl_data structure
|
||||
populated with a list of specified I2C messages. The messages parameter
|
||||
should be a list of tuples which represent the individual I2C messages to
|
||||
send in this transaction. Tuples should contain 4 elements: address value,
|
||||
flags value, buffer length, ctypes c_uint8 pointer to buffer.
|
||||
"""
|
||||
# Create message array and populate with provided data.
|
||||
msg_data_type = i2c_msg * len(messages)
|
||||
msg_data = msg_data_type()
|
||||
for i, message in enumerate(messages):
|
||||
msg_data[i].addr = message[0] & 0x7F
|
||||
msg_data[i].flags = message[1]
|
||||
msg_data[i].len = message[2]
|
||||
msg_data[i].buf = message[3]
|
||||
# Now build the data structure.
|
||||
data = i2c_rdwr_ioctl_data()
|
||||
data.msgs = msg_data
|
||||
data.nmsgs = len(messages)
|
||||
return data
|
||||
|
||||
|
||||
# pylint: enable=attribute-defined-outside-init
|
||||
|
||||
|
||||
# Create an interface that mimics the Python SMBus API.
|
||||
class SMBus:
|
||||
"""I2C interface that mimics the Python SMBus API but is implemented with
|
||||
pure Python calls to ioctl and direct /dev/i2c device access.
|
||||
"""
|
||||
|
||||
def __init__(self, bus=None):
|
||||
"""Create a new smbus instance. Bus is an optional parameter that
|
||||
specifies the I2C bus number to use, for example 1 would use device
|
||||
/dev/i2c-1. If bus is not specified then the open function should be
|
||||
called to open the bus.
|
||||
"""
|
||||
self._device = None
|
||||
if bus is not None:
|
||||
self.open(bus)
|
||||
|
||||
def __del__(self):
|
||||
"""Clean up any resources used by the SMBus instance."""
|
||||
self.close()
|
||||
|
||||
def __enter__(self):
|
||||
"""Context manager enter function."""
|
||||
# Just return this object so it can be used in a with statement, like
|
||||
# with SMBus(1) as bus:
|
||||
# # do stuff!
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
"""Context manager exit function, ensures resources are cleaned up."""
|
||||
self.close()
|
||||
return False # Don't suppress exceptions.
|
||||
|
||||
def open(self, bus):
|
||||
"""Open the smbus interface on the specified bus."""
|
||||
# Close the device if it's already open.
|
||||
if self._device is not None:
|
||||
self.close()
|
||||
# Try to open the file for the specified bus. Must turn off buffering
|
||||
# or else Python 3 fails (see: https://bugs.python.org/issue20074)
|
||||
# pylint: disable=consider-using-with
|
||||
self._device = open(f"/dev/i2c-{bus}", "r+b", buffering=0)
|
||||
# pylint: enable=consider-using-with
|
||||
# TODO: Catch IOError and throw a better error message that describes
|
||||
# what's wrong (i.e. I2C may not be enabled or the bus doesn't exist).
|
||||
|
||||
def close(self):
|
||||
"""Close the smbus connection. You cannot make any other function
|
||||
calls on the bus unless open is called!"""
|
||||
if self._device is not None:
|
||||
self._device.close()
|
||||
self._device = None
|
||||
|
||||
def _select_device(self, addr):
|
||||
"""Set the address of the device to communicate with on the I2C bus."""
|
||||
ioctl(self._device.fileno(), I2C_SLAVE, addr & 0x7F)
|
||||
|
||||
def read_byte(self, addr):
|
||||
"""Read a single byte from the specified device."""
|
||||
assert (
|
||||
self._device is not None
|
||||
), "Bus must be opened before operations are made against it!"
|
||||
self._select_device(addr)
|
||||
return ord(self._device.read(1))
|
||||
|
||||
def read_bytes(self, addr, number):
|
||||
"""Read many bytes from the specified device."""
|
||||
assert (
|
||||
self._device is not None
|
||||
), "Bus must be opened before operations are made against it!"
|
||||
self._select_device(addr)
|
||||
return self._device.read(number)
|
||||
|
||||
def read_byte_data(self, addr, cmd):
|
||||
"""Read a single byte from the specified cmd register of the device."""
|
||||
assert (
|
||||
self._device is not None
|
||||
), "Bus must be opened before operations are made against it!"
|
||||
# Build ctypes values to marshall between ioctl and Python.
|
||||
reg = c_uint8(cmd)
|
||||
result = c_uint8()
|
||||
# Build ioctl request.
|
||||
request = make_i2c_rdwr_data(
|
||||
[
|
||||
(addr, 0, 1, pointer(reg)), # Write cmd register.
|
||||
(addr, I2C_M_RD, 1, pointer(result)), # Read 1 byte as result.
|
||||
]
|
||||
)
|
||||
# Make ioctl call and return result data.
|
||||
ioctl(self._device.fileno(), I2C_RDWR, request)
|
||||
return result.value
|
||||
|
||||
def read_word_data(self, addr, cmd):
|
||||
"""Read a word (2 bytes) from the specified cmd register of the device.
|
||||
Note that this will interpret data using the endianness of the processor
|
||||
running Python (typically little endian)!
|
||||
"""
|
||||
assert (
|
||||
self._device is not None
|
||||
), "Bus must be opened before operations are made against it!"
|
||||
# Build ctypes values to marshall between ioctl and Python.
|
||||
reg = c_uint8(cmd)
|
||||
result = c_uint16()
|
||||
# Build ioctl request.
|
||||
request = make_i2c_rdwr_data(
|
||||
[
|
||||
(addr, 0, 1, pointer(reg)), # Write cmd register.
|
||||
(
|
||||
addr,
|
||||
I2C_M_RD,
|
||||
2,
|
||||
cast(pointer(result), POINTER(c_uint8)),
|
||||
), # Read word (2 bytes).
|
||||
]
|
||||
)
|
||||
# Make ioctl call and return result data.
|
||||
ioctl(self._device.fileno(), I2C_RDWR, request)
|
||||
return result.value
|
||||
|
||||
def read_block_data(self, addr, cmd):
|
||||
"""Perform a block read from the specified cmd register of the device.
|
||||
The amount of data read is determined by the first byte send back by
|
||||
the device. Data is returned as a bytearray.
|
||||
"""
|
||||
# TODO: Unfortunately this will require calling the low level I2C
|
||||
# access ioctl to trigger a proper read_block_data. The amount of data
|
||||
# returned isn't known until the device starts responding so an I2C_RDWR
|
||||
# ioctl won't work.
|
||||
raise NotImplementedError()
|
||||
|
||||
def read_i2c_block_data(self, addr, cmd, length=32):
|
||||
"""Perform a read from the specified cmd register of device. Length number
|
||||
of bytes (default of 32) will be read and returned as a bytearray.
|
||||
"""
|
||||
assert (
|
||||
self._device is not None
|
||||
), "Bus must be opened before operations are made against it!"
|
||||
# Build ctypes values to marshall between ioctl and Python.
|
||||
|
||||
# convert register into bytearray
|
||||
if not isinstance(cmd, (bytes, bytearray)):
|
||||
reg = cmd # backup
|
||||
cmd = bytearray(1)
|
||||
cmd[0] = reg
|
||||
|
||||
cmdstring = create_string_buffer(len(cmd))
|
||||
for i, val in enumerate(cmd):
|
||||
cmdstring[i] = val
|
||||
|
||||
result = create_string_buffer(length)
|
||||
|
||||
# Build ioctl request.
|
||||
request = make_i2c_rdwr_data(
|
||||
[
|
||||
(
|
||||
addr,
|
||||
0,
|
||||
len(cmd),
|
||||
cast(cmdstring, POINTER(c_uint8)),
|
||||
), # Write cmd register.
|
||||
(addr, I2C_M_RD, length, cast(result, POINTER(c_uint8))), # Read data.
|
||||
]
|
||||
)
|
||||
|
||||
# Make ioctl call and return result data.
|
||||
ioctl(self._device.fileno(), I2C_RDWR, request)
|
||||
return bytearray(
|
||||
result.raw
|
||||
) # Use .raw instead of .value which will stop at a null byte!
|
||||
|
||||
def write_quick(self, addr):
|
||||
"""Write a single byte to the specified device."""
|
||||
# What a strange function, from the python-smbus source this appears to
|
||||
# just write a single byte that initiates a write to the specified device
|
||||
# address (but writes no data!). The functionality is duplicated below
|
||||
# but the actual use case for this is unknown.
|
||||
assert (
|
||||
self._device is not None
|
||||
), "Bus must be opened before operations are made against it!"
|
||||
# Build ioctl request.
|
||||
request = make_i2c_rdwr_data(
|
||||
[
|
||||
(addr, 0, 0, None),
|
||||
]
|
||||
) # Write with no data.
|
||||
# Make ioctl call and return result data.
|
||||
ioctl(self._device.fileno(), I2C_RDWR, request)
|
||||
|
||||
def write_byte(self, addr, val):
|
||||
"""Write a single byte to the specified device."""
|
||||
assert (
|
||||
self._device is not None
|
||||
), "Bus must be opened before operations are made against it!"
|
||||
self._select_device(addr)
|
||||
data = bytearray(1)
|
||||
data[0] = val & 0xFF
|
||||
self._device.write(data)
|
||||
|
||||
def write_bytes(self, addr, buf):
|
||||
"""Write many bytes to the specified device. buf is a bytearray"""
|
||||
assert (
|
||||
self._device is not None
|
||||
), "Bus must be opened before operations are made against it!"
|
||||
self._select_device(addr)
|
||||
self._device.write(buf)
|
||||
|
||||
def write_byte_data(self, addr, cmd, val):
|
||||
"""Write a byte of data to the specified cmd register of the device."""
|
||||
assert (
|
||||
self._device is not None
|
||||
), "Bus must be opened before operations are made against it!"
|
||||
# Construct a string of data to send with the command register and byte value.
|
||||
data = bytearray(2)
|
||||
data[0] = cmd & 0xFF
|
||||
data[1] = val & 0xFF
|
||||
# Send the data to the device.
|
||||
self._select_device(addr)
|
||||
self._device.write(data)
|
||||
|
||||
def write_word_data(self, addr, cmd, val):
|
||||
"""Write a word (2 bytes) of data to the specified cmd register of the
|
||||
device. Note that this will write the data in the endianness of the
|
||||
processor running Python (typically little endian)!
|
||||
"""
|
||||
assert (
|
||||
self._device is not None
|
||||
), "Bus must be opened before operations are made against it!"
|
||||
# Construct a string of data to send with the command register and word value.
|
||||
data = struct.pack("=BH", cmd & 0xFF, val & 0xFFFF)
|
||||
# Send the data to the device.
|
||||
self._select_device(addr)
|
||||
self._device.write(data)
|
||||
|
||||
def write_block_data(self, addr, cmd, vals):
|
||||
"""Write a block of data to the specified cmd register of the device.
|
||||
The amount of data to write should be the first byte inside the vals
|
||||
string/bytearray and that count of bytes of data to write should follow
|
||||
it.
|
||||
"""
|
||||
# Just use the I2C block data write to write the provided values and
|
||||
# their length as the first byte.
|
||||
data = bytearray(len(vals) + 1)
|
||||
data[0] = len(vals) & 0xFF
|
||||
data[1:] = vals[0:]
|
||||
self.write_i2c_block_data(addr, cmd, data)
|
||||
|
||||
def write_i2c_block_data(self, addr, cmd, vals):
|
||||
"""Write a buffer of data to the specified cmd register of the device."""
|
||||
assert (
|
||||
self._device is not None
|
||||
), "Bus must be opened before operations are made against it!"
|
||||
# Construct a string of data to send, including room for the command register.
|
||||
data = bytearray(len(vals) + 1)
|
||||
data[0] = cmd & 0xFF # Command register at the start.
|
||||
data[1:] = vals[0:] # Copy in the block data (ugly but necessary to ensure
|
||||
# the entire write happens in one transaction).
|
||||
# Send the data to the device.
|
||||
self._select_device(addr)
|
||||
self._device.write(data)
|
||||
|
||||
def process_call(self, addr, cmd, val):
|
||||
"""Perform a smbus process call by writing a word (2 byte) value to
|
||||
the specified register of the device, and then reading a word of response
|
||||
data (which is returned).
|
||||
"""
|
||||
assert (
|
||||
self._device is not None
|
||||
), "Bus must be opened before operations are made against it!"
|
||||
# Build ctypes values to marshall between ioctl and Python.
|
||||
data = create_string_buffer(struct.pack("=BH", cmd, val))
|
||||
result = c_uint16()
|
||||
# Build ioctl request.
|
||||
request = make_i2c_rdwr_data(
|
||||
[
|
||||
(addr, 0, 3, cast(pointer(data), POINTER(c_uint8))), # Write data.
|
||||
(
|
||||
addr,
|
||||
I2C_M_RD,
|
||||
2,
|
||||
cast(pointer(result), POINTER(c_uint8)),
|
||||
), # Read word (2 bytes).
|
||||
]
|
||||
)
|
||||
# Make ioctl call and return result data.
|
||||
ioctl(self._device.fileno(), I2C_RDWR, request)
|
||||
# Note the python-smbus code appears to have a rather serious bug and
|
||||
# does not return the result value! This is fixed below by returning it.
|
||||
return result.value
|
404
_trash/lib/python3.11/site-packages/Adafruit_PureIO/spi.py
Normal file
404
_trash/lib/python3.11/site-packages/Adafruit_PureIO/spi.py
Normal file
|
@ -0,0 +1,404 @@
|
|||
# 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