mirror of
https://github.com/KevinMidboe/python-gpiozero.git
synced 2025-10-29 17:50:37 +00:00
Fix #279 once and for all (ha! ;)
This implements the proposal discussed in the re-opened #279 to add a pin_factory argument at the device level and remove the ability to specify a pin instance to device constructors (they now only accept a pin specification). Note: there's still a couple of bits to tidy up (tests on "real" Pis, and pin_factory.release_all needs refinement) but the test suite is now at least capable of passing on a PC.
This commit is contained in:
@@ -11,7 +11,7 @@ import os
|
||||
import atexit
|
||||
import weakref
|
||||
import warnings
|
||||
from collections import namedtuple, defaultdict
|
||||
from collections import namedtuple
|
||||
from itertools import chain
|
||||
from types import FunctionType
|
||||
from threading import Lock
|
||||
@@ -194,77 +194,21 @@ class Device(ValuesMixin, GPIOBase):
|
||||
property, the :attr:`value` property, and the :meth:`close` method).
|
||||
"""
|
||||
pin_factory = None # instance of a Factory sub-class
|
||||
_reservations = defaultdict(list) # maps pin addresses to lists of devices
|
||||
_res_lock = Lock()
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
# Force pin_factory to be keyword-only, even in Python 2
|
||||
self.pin_factory = kwargs.pop('pin_factory', Device.pin_factory)
|
||||
if kwargs:
|
||||
raise TypeError("Device.__init__() got unexpected keyword "
|
||||
"argument '%s'" % kwargs.popitem()[0])
|
||||
super(Device, self).__init__()
|
||||
|
||||
def __repr__(self):
|
||||
return "<gpiozero.%s object>" % (self.__class__.__name__)
|
||||
|
||||
def _reserve_pins(self, *pins_or_addresses):
|
||||
"""
|
||||
Called to indicate that the device reserves the right to use the
|
||||
specified *pins_or_addresses*. This should be done during device
|
||||
construction. If pins are reserved, you must ensure that the
|
||||
reservation is released by eventually called :meth:`_release_pins`.
|
||||
|
||||
The *pins_or_addresses* can be actual :class:`Pin` instances or the
|
||||
addresses of pin instances (each address is a tuple of strings). The
|
||||
latter form is permitted to ensure that devices do not have to
|
||||
construct :class:`Pin` objects to reserve pins. This is important as
|
||||
constructing a pin often configures it (e.g. as an input) which
|
||||
conflicts with alternate pin functions like SPI.
|
||||
"""
|
||||
addresses = (
|
||||
p.address if isinstance(p, Pin) else p
|
||||
for p in pins_or_addresses
|
||||
)
|
||||
with Device._res_lock:
|
||||
for address in addresses:
|
||||
for device_ref in Device._reservations[address]:
|
||||
device = device_ref()
|
||||
if device is not None and self._conflicts_with(device):
|
||||
raise GPIOPinInUse(
|
||||
'pin %s is already in use by %r' % (
|
||||
'/'.join(address), device)
|
||||
)
|
||||
Device._reservations[address].append(weakref.ref(self))
|
||||
|
||||
def _release_pins(self, *pins_or_addresses):
|
||||
"""
|
||||
Releases the reservation of this device against *pins_or_addresses*.
|
||||
This is typically called during :meth:`close` to clean up reservations
|
||||
taken during construction. Releasing a reservation that is not
|
||||
currently held will be silently ignored (to permit clean-up after
|
||||
failed / partial construction).
|
||||
"""
|
||||
addresses = (
|
||||
p.address if isinstance(p, Pin) else p
|
||||
for p in pins_or_addresses
|
||||
)
|
||||
with Device._res_lock:
|
||||
for address in addresses:
|
||||
Device._reservations[address] = [
|
||||
ref for ref in Device._reservations[address]
|
||||
if ref() not in (self, None) # may as well clean up dead refs
|
||||
]
|
||||
|
||||
def _release_all(self):
|
||||
"""
|
||||
Releases all pin reservations taken out by this device. See
|
||||
:meth:`_release_pins` for further information).
|
||||
"""
|
||||
with Device._res_lock:
|
||||
Device._reservations = defaultdict(list, {
|
||||
address: [
|
||||
ref for ref in conflictors
|
||||
if ref() not in (self, None)
|
||||
]
|
||||
for address, conflictors in Device._reservations.items()
|
||||
})
|
||||
|
||||
def _conflicts_with(self, other):
|
||||
"""
|
||||
Called by :meth:`_reserve_pin` to test whether the *other*
|
||||
Called by :meth:`Factory.reserve_pins` to test whether the *other*
|
||||
:class:`Device` using a common pin conflicts with this device's intent
|
||||
to use it. The default is ``True`` indicating that all devices conflict
|
||||
with common pins. Sub-classes may override this to permit more nuanced
|
||||
@@ -315,6 +259,7 @@ class CompositeDevice(Device):
|
||||
self._named = frozendict({})
|
||||
self._namedtuple = None
|
||||
self._order = kwargs.pop('_order', None)
|
||||
pin_factory = kwargs.pop('pin_factory', None)
|
||||
try:
|
||||
if self._order is None:
|
||||
self._order = sorted(kwargs.keys())
|
||||
@@ -336,7 +281,8 @@ class CompositeDevice(Device):
|
||||
dev.close()
|
||||
raise
|
||||
self._all = args + tuple(kwargs[v] for v in self._order)
|
||||
super(CompositeDevice, self).__init__()
|
||||
kwargs = {'pin_factory': pin_factory} if pin_factory is not None else {}
|
||||
super(CompositeDevice, self).__init__(**kwargs)
|
||||
|
||||
def __getattr__(self, name):
|
||||
# if _named doesn't exist yet, pretend it's an empty dict
|
||||
@@ -412,20 +358,17 @@ class GPIODevice(Device):
|
||||
this is ``None``, :exc:`GPIOPinMissing` will be raised. If the pin is
|
||||
already in use by another device, :exc:`GPIOPinInUse` will be raised.
|
||||
"""
|
||||
def __init__(self, pin=None):
|
||||
super(GPIODevice, self).__init__()
|
||||
def __init__(self, pin=None, **kwargs):
|
||||
super(GPIODevice, self).__init__(**kwargs)
|
||||
# self._pin must be set before any possible exceptions can be raised
|
||||
# because it's accessed in __del__. However, it mustn't be given the
|
||||
# value of pin until we've verified that it isn't already allocated
|
||||
self._pin = None
|
||||
if pin is None:
|
||||
raise GPIOPinMissing('No pin given')
|
||||
if isinstance(pin, Pin):
|
||||
self._reserve_pins(pin)
|
||||
else:
|
||||
# Check you can reserve *before* constructing the pin
|
||||
self._reserve_pins(Device.pin_factory.pin_address(pin))
|
||||
pin = Device.pin_factory.pin(pin)
|
||||
# Check you can reserve *before* constructing the pin
|
||||
self.pin_factory.reserve_pins(self, pin)
|
||||
pin = self.pin_factory.pin(pin)
|
||||
self._pin = pin
|
||||
self._active_state = True
|
||||
self._inactive_state = False
|
||||
@@ -443,7 +386,7 @@ class GPIODevice(Device):
|
||||
def close(self):
|
||||
super(GPIODevice, self).close()
|
||||
if self._pin is not None:
|
||||
self._release_pins(self._pin)
|
||||
self.pin_factory.release_pins(self, self._pin.number)
|
||||
self._pin.close()
|
||||
self._pin = None
|
||||
|
||||
@@ -512,10 +455,10 @@ def _default_pin_factory(name=os.getenv('GPIOZERO_PIN_FACTORY', None)):
|
||||
|
||||
def _devices_shutdown():
|
||||
if Device.pin_factory:
|
||||
with Device._res_lock:
|
||||
with Device.pin_factory._res_lock:
|
||||
reserved_devices = {
|
||||
dev
|
||||
for ref_list in Device._reservations.values()
|
||||
for ref_list in Device.pin_factory._reservations.values()
|
||||
for ref in ref_list
|
||||
for dev in (ref(),)
|
||||
if dev is not None
|
||||
|
||||
@@ -8,6 +8,10 @@ from __future__ import (
|
||||
)
|
||||
str = type('')
|
||||
|
||||
from weakref import ref
|
||||
from collections import defaultdict
|
||||
from threading import Lock
|
||||
|
||||
from ..exc import (
|
||||
PinInvalidFunction,
|
||||
PinSetInput,
|
||||
@@ -20,6 +24,7 @@ from ..exc import (
|
||||
SPIFixedBitOrder,
|
||||
SPIFixedSelect,
|
||||
SPIFixedWordSize,
|
||||
GPIOPinInUse,
|
||||
)
|
||||
|
||||
|
||||
@@ -36,10 +41,61 @@ class Factory(object):
|
||||
applicable:
|
||||
|
||||
* :meth:`close`
|
||||
* :meth:`reserve_pins`
|
||||
* :meth:`release_pins`
|
||||
* :meth:`release_all`
|
||||
* :meth:`pin`
|
||||
* :meth:`spi`
|
||||
* :meth:`_get_pi_info`
|
||||
"""
|
||||
def __init__(self):
|
||||
self._reservations = defaultdict(list)
|
||||
self._res_lock = Lock()
|
||||
|
||||
def reserve_pins(self, requester, *pins):
|
||||
"""
|
||||
Called to indicate that the device reserves the right to use the
|
||||
specified *pins*. This should be done during device construction. If
|
||||
pins are reserved, you must ensure that the reservation is released by
|
||||
eventually called :meth:`release_pins`.
|
||||
"""
|
||||
with self._res_lock:
|
||||
for pin in pins:
|
||||
for reserver_ref in self._reservations[pin]:
|
||||
reserver = reserver_ref()
|
||||
if reserver is not None and requester._conflicts_with(reserver):
|
||||
raise GPIOPinInUse('pin %s is already in use by %r' %
|
||||
(pin, reserver))
|
||||
self._reservations[pin].append(ref(requester))
|
||||
|
||||
def release_pins(self, reserver, *pins):
|
||||
"""
|
||||
Releases the reservation of *reserver* against *pins*. This is
|
||||
typically called during :meth:`Device.close` to clean up reservations
|
||||
taken during construction. Releasing a reservation that is not currently
|
||||
held will be silently ignored (to permit clean-up after failed / partial
|
||||
construction).
|
||||
"""
|
||||
with self._res_lock:
|
||||
for pin in pins:
|
||||
self._reservations[pin] = [
|
||||
ref for ref in self._reservations[pin]
|
||||
if ref() not in (reserver, None) # may as well clean up dead refs
|
||||
]
|
||||
|
||||
def release_all(self, reserver):
|
||||
"""
|
||||
Releases all pin reservations taken out by *reserver*. See
|
||||
:meth:`release_pins` for further information).
|
||||
"""
|
||||
with self._res_lock:
|
||||
self._reservations = defaultdict(list, {
|
||||
pin: [
|
||||
ref for ref in conflictors
|
||||
if ref() not in (reserver, None)
|
||||
]
|
||||
for pin, conflictors in self._reservations.items()
|
||||
})
|
||||
|
||||
def close(self):
|
||||
"""
|
||||
@@ -63,19 +119,6 @@ class Factory(object):
|
||||
"""
|
||||
raise PinUnsupported("Individual pins are not supported by this pin factory")
|
||||
|
||||
def pin_address(self, spec):
|
||||
"""
|
||||
Returns the address that a pin *would* have if constructed from the
|
||||
given *spec*.
|
||||
|
||||
This unusual method is used by the pin reservation system to check
|
||||
for conflicts *prior* to pin construction; with most implementations,
|
||||
pin construction implicitly alters the state of the pin (e.g. setting
|
||||
it to an input). This allows pin reservation to take place without
|
||||
affecting the state of other components.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def spi(self, **spi_args):
|
||||
"""
|
||||
Returns an instance of an :class:`SPI` interface, for the specified SPI
|
||||
@@ -89,21 +132,6 @@ class Factory(object):
|
||||
def _get_address(self):
|
||||
raise NotImplementedError
|
||||
|
||||
address = property(
|
||||
lambda self: self._get_address(),
|
||||
doc="""\
|
||||
Returns a tuple of strings representing the address of the factory.
|
||||
For the Pi itself this is a tuple of one string representing the Pi's
|
||||
address (e.g. "localhost"). Expander chips can return a tuple appending
|
||||
whatever string they require to uniquely identify the expander chip
|
||||
amongst all factories in the system.
|
||||
|
||||
.. note::
|
||||
|
||||
This property *must* return an immutable object capable of being
|
||||
used as a dictionary key.
|
||||
""")
|
||||
|
||||
def _get_pi_info(self):
|
||||
return None
|
||||
|
||||
@@ -128,7 +156,6 @@ class Pin(object):
|
||||
represent the capabilities of pins. Descendents *must* override the
|
||||
following methods:
|
||||
|
||||
* :meth:`_get_address`
|
||||
* :meth:`_get_function`
|
||||
* :meth:`_set_function`
|
||||
* :meth:`_get_state`
|
||||
@@ -153,7 +180,7 @@ class Pin(object):
|
||||
"""
|
||||
|
||||
def __repr__(self):
|
||||
return self.address[-1]
|
||||
return "<Pin>"
|
||||
|
||||
def close(self):
|
||||
"""
|
||||
@@ -195,18 +222,6 @@ class Pin(object):
|
||||
self.function = 'input'
|
||||
self.pull = pull
|
||||
|
||||
def _get_address(self):
|
||||
raise NotImplementedError
|
||||
|
||||
address = property(
|
||||
lambda self: self._get_address(),
|
||||
doc="""\
|
||||
The address of the pin. This property is a tuple of strings constructed
|
||||
from the owning factory's address with the unique address of the pin
|
||||
appended to it. The tuple as a whole uniquely identifies the pin
|
||||
amongst all pins attached to the system.
|
||||
""")
|
||||
|
||||
def _get_function(self):
|
||||
return "input"
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ str = type('')
|
||||
|
||||
import io
|
||||
import warnings
|
||||
from collections import defaultdict
|
||||
from threading import Lock
|
||||
|
||||
try:
|
||||
from spidev import SpiDev
|
||||
@@ -31,6 +33,8 @@ class LocalPiFactory(PiFactory):
|
||||
:class:`~gpiozero.pins.native.NativePin`).
|
||||
"""
|
||||
pins = {}
|
||||
_reservations = defaultdict(list)
|
||||
_res_lock = Lock()
|
||||
|
||||
def __init__(self):
|
||||
super(LocalPiFactory, self).__init__()
|
||||
@@ -40,14 +44,13 @@ class LocalPiFactory(PiFactory):
|
||||
('software', 'exclusive'): LocalPiSoftwareSPI,
|
||||
('software', 'shared'): LocalPiSoftwareSPIShared,
|
||||
}
|
||||
# Override the pins dict to be this class' pins dict. This is a bit of
|
||||
# a dirty hack, but ensures that anyone evil enough to mix pin
|
||||
# implementations doesn't try and control the same pin with different
|
||||
# backends
|
||||
# Override the reservations and pins dict to be this class' attributes.
|
||||
# This is a bit of a dirty hack, but ensures that anyone evil enough to
|
||||
# mix pin implementations doesn't try and control the same pin with
|
||||
# different backends
|
||||
self.pins = LocalPiFactory.pins
|
||||
|
||||
def _get_address(self):
|
||||
return ('localhost',)
|
||||
self._reservations = LocalPiFactory._reservations
|
||||
self._res_lock = LocalPiFactory._res_lock
|
||||
|
||||
def _get_revision(self):
|
||||
# Cache the result as we can reasonably assume it won't change during
|
||||
@@ -74,19 +77,19 @@ class LocalPiPin(PiPin):
|
||||
|
||||
class LocalPiHardwareSPI(SPI, Device):
|
||||
def __init__(self, factory, port, device):
|
||||
if SpiDev is None:
|
||||
raise ImportError('failed to import spidev')
|
||||
self._port = port
|
||||
self._device = device
|
||||
self._interface = None
|
||||
self._address = factory.address + ('SPI(port=%d, device=%d)' % (port, device),)
|
||||
if SpiDev is None:
|
||||
raise ImportError('failed to import spidev')
|
||||
super(LocalPiHardwareSPI, self).__init__()
|
||||
pins = SPI_HARDWARE_PINS[port]
|
||||
self._reserve_pins(
|
||||
factory.pin_address(pins['clock']),
|
||||
factory.pin_address(pins['mosi']),
|
||||
factory.pin_address(pins['miso']),
|
||||
factory.pin_address(pins['select'][device])
|
||||
self.pin_factory.reserve_pins(
|
||||
self,
|
||||
pins['clock'],
|
||||
pins['mosi'],
|
||||
pins['miso'],
|
||||
pins['select'][device]
|
||||
)
|
||||
self._interface = SpiDev()
|
||||
self._interface.open(port, device)
|
||||
@@ -98,7 +101,7 @@ class LocalPiHardwareSPI(SPI, Device):
|
||||
self._interface.close()
|
||||
finally:
|
||||
self._interface = None
|
||||
self._release_all()
|
||||
self.pin_factory.release_all(self)
|
||||
super(LocalPiHardwareSPI, self).close()
|
||||
|
||||
@property
|
||||
@@ -148,10 +151,6 @@ class LocalPiHardwareSPI(SPI, Device):
|
||||
class LocalPiSoftwareSPI(SPI, OutputDevice):
|
||||
def __init__(self, factory, clock_pin, mosi_pin, miso_pin, select_pin):
|
||||
self._bus = None
|
||||
self._address = factory.address + (
|
||||
'SPI(clock_pin=%d, mosi_pin=%d, miso_pin=%d, select_pin=%d)' % (
|
||||
clock_pin, mosi_pin, miso_pin, select_pin),
|
||||
)
|
||||
super(LocalPiSoftwareSPI, self).__init__(select_pin, active_high=False)
|
||||
try:
|
||||
self._clock_phase = False
|
||||
@@ -163,6 +162,7 @@ class LocalPiSoftwareSPI(SPI, OutputDevice):
|
||||
raise
|
||||
|
||||
def _conflicts_with(self, other):
|
||||
# XXX Need to refine this
|
||||
return not (
|
||||
isinstance(other, LocalPiSoftwareSPI) and
|
||||
(self.pin.number != other.pin.number)
|
||||
|
||||
@@ -40,7 +40,7 @@ class MockPin(PiPin):
|
||||
def __init__(self, factory, number):
|
||||
super(MockPin, self).__init__(factory, number)
|
||||
self._function = 'input'
|
||||
self._pull = 'up' if factory.pi_info.pulled_up(self.address[-1]) else 'floating'
|
||||
self._pull = 'up' if factory.pi_info.pulled_up(repr(self)) else 'floating'
|
||||
self._state = self._pull == 'up'
|
||||
self._bounce = None
|
||||
self._edges = 'both'
|
||||
@@ -94,7 +94,7 @@ class MockPin(PiPin):
|
||||
def _set_pull(self, value):
|
||||
if self.function != 'input':
|
||||
raise PinFixedPull('cannot set pull on non-input pin %r' % self)
|
||||
if value != 'up' and self.factory.pi_info.pulled_up(self.address[-1]):
|
||||
if value != 'up' and self.factory.pi_info.pulled_up(repr(self)):
|
||||
raise PinFixedPull('%r has a physical pull-up resistor' % self)
|
||||
if value not in ('floating', 'up', 'down'):
|
||||
raise PinInvalidPull('pull must be floating, up, or down')
|
||||
@@ -423,14 +423,12 @@ class MockFactory(LocalPiFactory):
|
||||
pin_class = pkg_resources.load_entry_point(dist, group, pin_class.lower())
|
||||
self.pin_class = pin_class
|
||||
|
||||
def _get_address(self):
|
||||
return ('mock',)
|
||||
|
||||
def _get_revision(self):
|
||||
return self._revision
|
||||
|
||||
def reset(self):
|
||||
self.pins.clear()
|
||||
self._reservations.clear()
|
||||
|
||||
def pin(self, spec, pin_class=None, **kwargs):
|
||||
if pin_class is None:
|
||||
|
||||
@@ -228,7 +228,7 @@ class NativePin(LocalPiPin):
|
||||
self._change_thread = None
|
||||
self._change_event = Event()
|
||||
self.function = 'input'
|
||||
self.pull = 'up' if factory.pi_info.pulled_up(self.address[-1]) else 'floating'
|
||||
self.pull = 'up' if self.factory.pi_info.pulled_up(repr(self)) else 'floating'
|
||||
self.bounce = None
|
||||
self.edges = 'both'
|
||||
|
||||
@@ -236,7 +236,7 @@ class NativePin(LocalPiPin):
|
||||
self.frequency = None
|
||||
self.when_changed = None
|
||||
self.function = 'input'
|
||||
self.pull = 'up' if self.factory.pi_info.pulled_up(self.address[-1]) else 'floating'
|
||||
self.pull = 'up' if self.factory.pi_info.pulled_up(repr(self)) else 'floating'
|
||||
|
||||
def _get_function(self):
|
||||
return self.GPIO_FUNCTION_NAMES[(self.factory.mem[self._func_offset] >> self._func_shift) & 7]
|
||||
@@ -269,7 +269,7 @@ class NativePin(LocalPiPin):
|
||||
def _set_pull(self, value):
|
||||
if self.function != 'input':
|
||||
raise PinFixedPull('cannot set pull on non-input pin %r' % self)
|
||||
if value != 'up' and self.factory.pi_info.pulled_up(self.address[-1]):
|
||||
if value != 'up' and self.factory.pi_info.pulled_up(repr(self)):
|
||||
raise PinFixedPull('%r has a physical pull-up resistor' % self)
|
||||
try:
|
||||
value = self.GPIO_PULL_UPS[value]
|
||||
|
||||
@@ -7,8 +7,9 @@ from __future__ import (
|
||||
str = type('')
|
||||
|
||||
import io
|
||||
from threading import RLock
|
||||
from threading import RLock, Lock
|
||||
from types import MethodType
|
||||
from collections import defaultdict
|
||||
try:
|
||||
from weakref import ref, WeakMethod
|
||||
except ImportError:
|
||||
@@ -48,6 +49,7 @@ class PiFactory(Factory):
|
||||
forms the base of :class:`~gpiozero.pins.local.LocalPiFactory`.
|
||||
"""
|
||||
def __init__(self):
|
||||
super(PiFactory, self).__init__()
|
||||
self._info = None
|
||||
self.pins = {}
|
||||
self.pin_class = None
|
||||
@@ -72,10 +74,6 @@ class PiFactory(Factory):
|
||||
self.pins[n] = pin
|
||||
return pin
|
||||
|
||||
def pin_address(self, spec):
|
||||
n = self._to_gpio(spec)
|
||||
return self.address + ('GPIO%d' % n,)
|
||||
|
||||
def _to_gpio(self, spec):
|
||||
"""
|
||||
Converts the pin *spec* to a GPIO port number.
|
||||
@@ -240,23 +238,23 @@ class PiPin(Pin):
|
||||
self._when_changed = None
|
||||
self._number = number
|
||||
try:
|
||||
factory.pi_info.physical_pin(self.address[-1])
|
||||
factory.pi_info.physical_pin('GPIO%d' % self.number)
|
||||
except PinNoPins:
|
||||
warnings.warn(
|
||||
PinNonPhysical(
|
||||
'no physical pins exist for %s' % self.address[-1]))
|
||||
'no physical pins exist for GPIO%d' % self.number))
|
||||
|
||||
@property
|
||||
def number(self):
|
||||
return self._number
|
||||
|
||||
def __repr__(self):
|
||||
return 'GPIO%d' % self._number
|
||||
|
||||
@property
|
||||
def factory(self):
|
||||
return self._factory
|
||||
|
||||
def _get_address(self):
|
||||
return self.factory.address + ('GPIO%d' % self.number,)
|
||||
|
||||
def _call_when_changed(self):
|
||||
"""
|
||||
Called to fire the :attr:`when_changed` event handler; override this
|
||||
|
||||
@@ -7,7 +7,6 @@ from __future__ import (
|
||||
str = type('')
|
||||
|
||||
import os
|
||||
from weakref import proxy
|
||||
|
||||
import pigpio
|
||||
|
||||
@@ -126,9 +125,6 @@ class PiGPIOFactory(PiFactory):
|
||||
def _get_revision(self):
|
||||
return self.connection.get_hardware_revision()
|
||||
|
||||
def _get_address(self):
|
||||
return ("%s:%d" % (self.host, self.port),)
|
||||
|
||||
def spi(self, **spi_args):
|
||||
intf = super(PiGPIOFactory, self).spi(**spi_args)
|
||||
self._spis.append(intf)
|
||||
@@ -166,7 +162,7 @@ class PiGPIOPin(PiPin):
|
||||
|
||||
def __init__(self, factory, number):
|
||||
super(PiGPIOPin, self).__init__(factory, number)
|
||||
self._pull = 'up' if factory.pi_info.pulled_up(self.address[-1]) else 'floating'
|
||||
self._pull = 'up' if factory.pi_info.pulled_up(repr(self)) else 'floating'
|
||||
self._pwm = False
|
||||
self._bounce = None
|
||||
self._callback = None
|
||||
@@ -183,7 +179,7 @@ class PiGPIOPin(PiPin):
|
||||
self.frequency = None
|
||||
self.when_changed = None
|
||||
self.function = 'input'
|
||||
self.pull = 'up' if self.factory.pi_info.pulled_up(self.address[-1]) else 'floating'
|
||||
self.pull = 'up' if self.factory.pi_info.pulled_up(repr(self)) else 'floating'
|
||||
|
||||
def _get_function(self):
|
||||
return self.GPIO_FUNCTION_NAMES[self.factory.connection.get_mode(self.number)]
|
||||
@@ -225,7 +221,7 @@ class PiGPIOPin(PiPin):
|
||||
def _set_pull(self, value):
|
||||
if self.function != 'input':
|
||||
raise PinFixedPull('cannot set pull on non-input pin %r' % self)
|
||||
if value != 'up' and self.factory.pi_info.pulled_up(self.address[-1]):
|
||||
if value != 'up' and self.factory.pi_info.pulled_up(repr(self)):
|
||||
raise PinFixedPull('%r has a physical pull-up resistor' % self)
|
||||
try:
|
||||
self.factory.connection.set_pull_up_down(self.number, self.GPIO_PULL_UPS[value])
|
||||
@@ -296,19 +292,17 @@ class PiGPIOHardwareSPI(SPI, Device):
|
||||
def __init__(self, factory, port, device):
|
||||
self._port = port
|
||||
self._device = device
|
||||
self._factory = proxy(factory)
|
||||
self._factory = factory
|
||||
self._handle = None
|
||||
super(PiGPIOHardwareSPI, self).__init__()
|
||||
pins = SPI_HARDWARE_PINS[port]
|
||||
self._reserve_pins(*(
|
||||
factory.address + ('GPIO%d' % pin,)
|
||||
for pin in (
|
||||
pins['clock'],
|
||||
pins['mosi'],
|
||||
pins['miso'],
|
||||
pins['select'][device]
|
||||
)
|
||||
))
|
||||
self._factory.reserve_pins(
|
||||
self,
|
||||
pins['clock'],
|
||||
pins['mosi'],
|
||||
pins['miso'],
|
||||
pins['select'][device]
|
||||
)
|
||||
self._spi_flags = 8 << 16
|
||||
self._baud = 500000
|
||||
self._handle = self._factory.connection.spi_open(
|
||||
@@ -330,7 +324,7 @@ class PiGPIOHardwareSPI(SPI, Device):
|
||||
if not self.closed:
|
||||
self._factory.connection.spi_close(self._handle)
|
||||
self._handle = None
|
||||
self._release_all()
|
||||
self._factory.release_all(self)
|
||||
super(PiGPIOHardwareSPI, self).close()
|
||||
|
||||
@property
|
||||
@@ -397,13 +391,14 @@ class PiGPIOSoftwareSPI(SPI, Device):
|
||||
self._clock_pin = clock_pin
|
||||
self._mosi_pin = mosi_pin
|
||||
self._miso_pin = miso_pin
|
||||
self._factory = proxy(factory)
|
||||
self._factory = factory
|
||||
super(PiGPIOSoftwareSPI, self).__init__()
|
||||
self._reserve_pins(
|
||||
factory.pin_address(clock_pin),
|
||||
factory.pin_address(mosi_pin),
|
||||
factory.pin_address(miso_pin),
|
||||
factory.pin_address(select_pin),
|
||||
self._factory.reserve_pins(
|
||||
self,
|
||||
clock_pin,
|
||||
mosi_pin,
|
||||
miso_pin,
|
||||
select_pin,
|
||||
)
|
||||
self._spi_flags = 0
|
||||
self._baud = 100000
|
||||
@@ -434,7 +429,7 @@ class PiGPIOSoftwareSPI(SPI, Device):
|
||||
if not self.closed:
|
||||
self._closed = True
|
||||
self._factory.connection.bb_spi_close(self._select_pin)
|
||||
self._release_all()
|
||||
self.factory.release_all(self)
|
||||
super(PiGPIOSoftwareSPI, self).close()
|
||||
|
||||
@property
|
||||
|
||||
@@ -85,7 +85,7 @@ class RPiGPIOPin(LocalPiPin):
|
||||
|
||||
def __init__(self, factory, number):
|
||||
super(RPiGPIOPin, self).__init__(factory, number)
|
||||
self._pull = 'up' if factory.pi_info.pulled_up(self.address[-1]) else 'floating'
|
||||
self._pull = 'up' if self.factory.pi_info.pulled_up(self.address[-1]) else 'floating'
|
||||
self._pwm = None
|
||||
self._frequency = None
|
||||
self._duty_cycle = None
|
||||
|
||||
@@ -80,7 +80,7 @@ class RPIOPin(LocalPiPin):
|
||||
|
||||
def __init__(self, factory, number):
|
||||
super(RPIOPin, self).__init__(factory, number)
|
||||
self._pull = 'up' if factory.pi_info.pulled_up(self.address[-1]) else 'floating'
|
||||
self._pull = 'up' if self.factory.pi_info.pulled_up(self.address[-1]) else 'floating'
|
||||
self._pwm = False
|
||||
self._duty_cycle = None
|
||||
self._bounce = None
|
||||
|
||||
Reference in New Issue
Block a user