fotobox/.venv/lib/python3.7/site-packages/gpiozero/pins/spi.py

105 lines
3.5 KiB
Python

# vim: set fileencoding=utf-8:
#
# GPIO Zero: a library for controlling the Raspberry Pi's GPIO pins
#
# Copyright (c) 2016-2021 Dave Jones <dave@waveform.org.uk>
#
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import (
unicode_literals,
print_function,
absolute_import,
division,
)
str = type('')
import operator
from threading import RLock
from ..devices import Device, SharedMixin
from ..input_devices import InputDevice
from ..output_devices import OutputDevice
class SPISoftwareBus(SharedMixin, Device):
def __init__(self, clock_pin, mosi_pin, miso_pin):
self.lock = None
self.clock = None
self.mosi = None
self.miso = None
super(SPISoftwareBus, self).__init__()
self.lock = RLock()
try:
self.clock = OutputDevice(clock_pin, active_high=True)
if mosi_pin is not None:
self.mosi = OutputDevice(mosi_pin)
if miso_pin is not None:
self.miso = InputDevice(miso_pin)
except:
self.close()
raise
def close(self):
super(SPISoftwareBus, self).close()
if getattr(self, 'lock', None):
with self.lock:
if self.miso is not None:
self.miso.close()
self.miso = None
if self.mosi is not None:
self.mosi.close()
self.mosi = None
if self.clock is not None:
self.clock.close()
self.clock = None
self.lock = None
@property
def closed(self):
return self.lock is None
@classmethod
def _shared_key(cls, clock_pin, mosi_pin, miso_pin):
return (clock_pin, mosi_pin, miso_pin)
def transfer(self, data, clock_phase=False, lsb_first=False, bits_per_word=8):
"""
Writes data (a list of integer words where each word is assumed to have
:attr:`bits_per_word` bits or less) to the SPI interface, and reads an
equivalent number of words, returning them as a list of integers.
"""
result = []
with self.lock:
# See https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus
# (specifically the section "Example of bit-banging the master
# protocol") for a simpler C implementation of this which ignores
# clock polarity, phase, variable word-size, and multiple input
# words
if lsb_first:
shift = operator.lshift
init_mask = 1
else:
shift = operator.rshift
init_mask = 1 << (bits_per_word - 1)
for write_word in data:
mask = init_mask
read_word = 0
for _ in range(bits_per_word):
if self.mosi is not None:
self.mosi.value = bool(write_word & mask)
# read bit on clock activation
self.clock.on()
if not clock_phase:
if self.miso is not None and self.miso.value:
read_word |= mask
# read bit on clock deactivation
self.clock.off()
if clock_phase:
if self.miso is not None and self.miso.value:
read_word |= mask
mask = shift(mask, 1)
result.append(read_word)
return result