mirror of
https://github.com/KevinMidboe/python-gpiozero.git
synced 2025-10-29 17:50:37 +00:00
Fix #459 - properly support remote SPI with pigpio
Sorry! Dave's messing around with the pin implementations again. Hopefully the last time. The pin_factory is now really a factory object which can be asked to produce individual pins or pin-based interfaces like SPI (which can be supported properly via pigpio).
This commit is contained in:
@@ -15,56 +15,28 @@ try:
|
||||
except ImportError:
|
||||
from ..compat import isclose
|
||||
|
||||
from . import Pin
|
||||
from .data import pi_info
|
||||
from ..exc import PinSetInput, PinPWMUnsupported, PinFixedPull
|
||||
from ..exc import PinPWMUnsupported, PinSetInput, PinFixedPull
|
||||
from ..devices import Device
|
||||
from .pi import PiPin
|
||||
from .local import LocalPiFactory
|
||||
|
||||
|
||||
PinState = namedtuple('PinState', ('timestamp', 'state'))
|
||||
|
||||
class MockPin(Pin):
|
||||
class MockPin(PiPin):
|
||||
"""
|
||||
A mock pin used primarily for testing. This class does *not* support PWM.
|
||||
"""
|
||||
|
||||
_PINS = {}
|
||||
|
||||
@classmethod
|
||||
def clear_pins(cls):
|
||||
cls._PINS.clear()
|
||||
|
||||
@classmethod
|
||||
def pi_info(cls):
|
||||
return pi_info('a21041') # Pretend we're a Pi 2B
|
||||
|
||||
def __new__(cls, number):
|
||||
if not (0 <= number < 54):
|
||||
raise ValueError('invalid pin %d specified (must be 0..53)' % number)
|
||||
try:
|
||||
old_pin = cls._PINS[number]
|
||||
except KeyError:
|
||||
self = super(MockPin, cls).__new__(cls)
|
||||
cls._PINS[number] = self
|
||||
self._number = number
|
||||
self._function = 'input'
|
||||
self._state = False
|
||||
self._pull = 'floating'
|
||||
self._bounce = None
|
||||
self._edges = 'both'
|
||||
self._when_changed = None
|
||||
self.clear_states()
|
||||
return self
|
||||
# Ensure the pin class expected supports PWM (or not)
|
||||
if issubclass(cls, MockPWMPin) != isinstance(old_pin, MockPWMPin):
|
||||
raise ValueError('pin %d is already in use as a %s' % (number, old_pin.__class__.__name__))
|
||||
return old_pin
|
||||
|
||||
def __repr__(self):
|
||||
return 'MOCK%d' % self._number
|
||||
|
||||
@property
|
||||
def number(self):
|
||||
return self._number
|
||||
def __init__(self, factory, number):
|
||||
super(MockPin, self).__init__(factory, number)
|
||||
self._function = 'input'
|
||||
self._state = False
|
||||
self._pull = 'floating'
|
||||
self._bounce = None
|
||||
self._edges = 'both'
|
||||
self._when_changed = None
|
||||
self.clear_states()
|
||||
|
||||
def close(self):
|
||||
self.when_changed = None
|
||||
@@ -186,8 +158,8 @@ class MockChargingPin(MockPin):
|
||||
(as if attached to, e.g. a typical circuit using an LDR and a capacitor
|
||||
to time the charging rate).
|
||||
"""
|
||||
def __init__(self, number):
|
||||
super(MockChargingPin, self).__init__()
|
||||
def __init__(self, factory, number):
|
||||
super(MockChargingPin, self).__init__(factory, number)
|
||||
self.charge_time = 0.01 # dark charging time
|
||||
self._charge_stop = Event()
|
||||
self._charge_thread = None
|
||||
@@ -225,8 +197,8 @@ class MockTriggerPin(MockPin):
|
||||
corresponding pin instance. When this pin is driven high it will trigger
|
||||
the echo pin to drive high for the echo time.
|
||||
"""
|
||||
def __init__(self, number):
|
||||
super(MockTriggerPin, self).__init__()
|
||||
def __init__(self, factory, number):
|
||||
super(MockTriggerPin, self).__init__(factory, number)
|
||||
self.echo_pin = None
|
||||
self.echo_time = 0.04 # longest echo time
|
||||
self._echo_thread = None
|
||||
@@ -250,8 +222,8 @@ class MockPWMPin(MockPin):
|
||||
"""
|
||||
This derivative of :class:`MockPin` adds PWM support.
|
||||
"""
|
||||
def __init__(self, number):
|
||||
super(MockPWMPin, self).__init__()
|
||||
def __init__(self, factory, number):
|
||||
super(MockPWMPin, self).__init__(factory, number)
|
||||
self._frequency = None
|
||||
|
||||
def close(self):
|
||||
@@ -283,8 +255,8 @@ class MockSPIClockPin(MockPin):
|
||||
rather, construct a :class:`MockSPIDevice` with various pin numbers, and
|
||||
this class will be used for the clock pin.
|
||||
"""
|
||||
def __init__(self, number):
|
||||
super(MockSPIClockPin, self).__init__()
|
||||
def __init__(self, factory, number):
|
||||
super(MockSPIClockPin, self).__init__(factory, number)
|
||||
if not hasattr(self, 'spi_devices'):
|
||||
self.spi_devices = []
|
||||
|
||||
@@ -301,8 +273,8 @@ class MockSPISelectPin(MockPin):
|
||||
tests; rather, construct a :class:`MockSPIDevice` with various pin numbers,
|
||||
and this class will be used for the select pin.
|
||||
"""
|
||||
def __init__(self, number):
|
||||
super(MockSPISelectPin, self).__init__()
|
||||
def __init__(self, factory, number):
|
||||
super(MockSPISelectPin, self).__init__(factory, number)
|
||||
if not hasattr(self, 'spi_device'):
|
||||
self.spi_device = None
|
||||
|
||||
@@ -314,13 +286,13 @@ class MockSPISelectPin(MockPin):
|
||||
|
||||
class MockSPIDevice(object):
|
||||
def __init__(
|
||||
self, clock_pin, mosi_pin, miso_pin, select_pin=None,
|
||||
self, clock_pin, mosi_pin=None, miso_pin=None, select_pin=None,
|
||||
clock_polarity=False, clock_phase=False, lsb_first=False,
|
||||
bits_per_word=8, select_high=False):
|
||||
self.clock_pin = MockSPIClockPin(clock_pin)
|
||||
self.mosi_pin = None if mosi_pin is None else MockPin(mosi_pin)
|
||||
self.miso_pin = None if miso_pin is None else MockPin(miso_pin)
|
||||
self.select_pin = None if select_pin is None else MockSPISelectPin(select_pin)
|
||||
self.clock_pin = Device._pin_factory.pin(clock_pin, pin_class=MockSPIClockPin)
|
||||
self.mosi_pin = None if mosi_pin is None else Device._pin_factory.pin(mosi_pin)
|
||||
self.miso_pin = None if miso_pin is None else Device._pin_factory.pin(miso_pin)
|
||||
self.select_pin = None if select_pin is None else Device._pin_factory.pin(select_pin, pin_class=MockSPISelectPin)
|
||||
self.clock_polarity = clock_polarity
|
||||
self.clock_phase = clock_phase
|
||||
self.lsb_first = lsb_first
|
||||
@@ -413,3 +385,34 @@ class MockSPIDevice(object):
|
||||
bits = reversed(bits)
|
||||
self.tx_buf.extend(bits)
|
||||
|
||||
|
||||
class MockFactory(LocalPiFactory):
|
||||
def __init__(self, revision='a21041', pin_class=MockPin):
|
||||
super(MockFactory, self).__init__()
|
||||
self._revision = revision
|
||||
self.pin_class = pin_class
|
||||
|
||||
def _get_address(self):
|
||||
return ('mock',)
|
||||
|
||||
def _get_revision(self):
|
||||
return self._revision
|
||||
|
||||
def reset(self):
|
||||
self.pins.clear()
|
||||
|
||||
def pin(self, spec, pin_class=None):
|
||||
if pin_class is None:
|
||||
pin_class = self.pin_class
|
||||
n = self._to_gpio(spec)
|
||||
try:
|
||||
pin = self.pins[n]
|
||||
except KeyError:
|
||||
pin = pin_class(self, n)
|
||||
self.pins[n] = pin
|
||||
else:
|
||||
# Ensure the pin class expected supports PWM (or not)
|
||||
if issubclass(pin_class, MockPWMPin) != isinstance(pin, MockPWMPin):
|
||||
raise ValueError('pin %d is already in use as a %s' % (n, pin.__class__.__name__))
|
||||
return pin
|
||||
|
||||
|
||||
Reference in New Issue
Block a user