mirror of
https://github.com/KevinMidboe/python-gpiozero.git
synced 2025-10-29 09:40:36 +00:00
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.
198 lines
7.8 KiB
Python
198 lines
7.8 KiB
Python
from __future__ import (
|
|
unicode_literals,
|
|
absolute_import,
|
|
print_function,
|
|
division,
|
|
)
|
|
nstr = str
|
|
str = type('')
|
|
|
|
|
|
import sys
|
|
import pytest
|
|
from array import array
|
|
from mock import patch
|
|
from collections import namedtuple
|
|
|
|
from gpiozero.pins.native import NativeFactory
|
|
from gpiozero.pins.local import (
|
|
LocalPiHardwareSPI,
|
|
LocalPiSoftwareSPI,
|
|
LocalPiHardwareSPIShared,
|
|
LocalPiSoftwareSPIShared,
|
|
)
|
|
from gpiozero.pins.mock import MockSPIDevice
|
|
from gpiozero import *
|
|
|
|
|
|
def teardown_function(function):
|
|
Device.pin_factory.reset()
|
|
|
|
|
|
def test_spi_hardware_params():
|
|
with patch('os.open'), patch('mmap.mmap') as mmap_mmap, patch('io.open') as io_open:
|
|
mmap_mmap.return_value = array(nstr('B'), (0,) * 4096)
|
|
io_open.return_value.__enter__.return_value = ['Revision: a21042']
|
|
factory = NativeFactory()
|
|
with patch('gpiozero.pins.local.SpiDev'):
|
|
with factory.spi() as device:
|
|
assert isinstance(device, LocalPiHardwareSPI)
|
|
with factory.spi(port=0, device=0) as device:
|
|
assert isinstance(device, LocalPiHardwareSPI)
|
|
with factory.spi(port=0, device=1) as device:
|
|
assert isinstance(device, LocalPiHardwareSPI)
|
|
with factory.spi(clock_pin=11) as device:
|
|
assert isinstance(device, LocalPiHardwareSPI)
|
|
with factory.spi(clock_pin=11, mosi_pin=10, select_pin=8) as device:
|
|
assert isinstance(device, LocalPiHardwareSPI)
|
|
with factory.spi(clock_pin=11, mosi_pin=10, select_pin=7) as device:
|
|
assert isinstance(device, LocalPiHardwareSPI)
|
|
with factory.spi(shared=True) as device:
|
|
assert isinstance(device, LocalPiHardwareSPIShared)
|
|
with pytest.raises(ValueError):
|
|
factory.spi(port=1)
|
|
with pytest.raises(ValueError):
|
|
factory.spi(device=2)
|
|
with pytest.raises(ValueError):
|
|
factory.spi(port=0, clock_pin=12)
|
|
with pytest.raises(ValueError):
|
|
factory.spi(foo='bar')
|
|
|
|
def test_spi_software_params():
|
|
with patch('os.open'), patch('mmap.mmap') as mmap_mmap, patch('io.open') as io_open:
|
|
mmap_mmap.return_value = array(nstr('B'), (0,) * 4096)
|
|
io_open.return_value.__enter__.return_value = ['Revision: a21042']
|
|
factory = NativeFactory()
|
|
with patch('gpiozero.pins.local.SpiDev'):
|
|
with factory.spi(select_pin=6) as device:
|
|
assert isinstance(device, LocalPiSoftwareSPI)
|
|
with factory.spi(clock_pin=11, mosi_pin=9, miso_pin=10) as device:
|
|
assert isinstance(device, LocalPiSoftwareSPI)
|
|
with factory.spi(select_pin=6, shared=True) as device:
|
|
assert isinstance(device, LocalPiSoftwareSPIShared)
|
|
with patch('gpiozero.pins.local.SpiDev', None):
|
|
# Clear out the old factory's caches (this is only necessary because
|
|
# we're being naughty switching out patches)
|
|
factory.pins.clear()
|
|
factory._reservations.clear()
|
|
# Ensure software fallback works when SpiDev isn't present
|
|
with factory.spi() as device:
|
|
assert isinstance(device, LocalPiSoftwareSPI)
|
|
|
|
def test_spi_hardware_conflict():
|
|
with patch('gpiozero.pins.local.SpiDev') as spidev:
|
|
with LED(11) as led:
|
|
with pytest.raises(GPIOPinInUse):
|
|
Device.pin_factory.spi(port=0, device=0)
|
|
with patch('gpiozero.pins.local.SpiDev') as spidev:
|
|
with Device.pin_factory.spi(port=0, device=0) as spi:
|
|
with pytest.raises(GPIOPinInUse):
|
|
LED(11)
|
|
|
|
def test_spi_hardware_read():
|
|
with patch('gpiozero.pins.local.SpiDev') as spidev:
|
|
spidev.return_value.xfer2.side_effect = lambda data: list(range(10))[:len(data)]
|
|
with Device.pin_factory.spi() as device:
|
|
assert device.read(3) == [0, 1, 2]
|
|
assert device.read(6) == list(range(6))
|
|
|
|
def test_spi_hardware_write():
|
|
with patch('gpiozero.pins.local.SpiDev') as spidev:
|
|
spidev.return_value.xfer2.side_effect = lambda data: list(range(10))[:len(data)]
|
|
with Device.pin_factory.spi() as device:
|
|
assert device.write([0, 1, 2]) == 3
|
|
assert spidev.return_value.xfer2.called_with([0, 1, 2])
|
|
assert device.write(list(range(6))) == 6
|
|
assert spidev.return_value.xfer2.called_with(list(range(6)))
|
|
|
|
def test_spi_hardware_modes():
|
|
with patch('gpiozero.pins.local.SpiDev') as spidev:
|
|
spidev.return_value.mode = 0
|
|
spidev.return_value.lsbfirst = False
|
|
spidev.return_value.cshigh = True
|
|
spidev.return_value.bits_per_word = 8
|
|
with Device.pin_factory.spi() as device:
|
|
assert device.clock_mode == 0
|
|
assert not device.clock_polarity
|
|
assert not device.clock_phase
|
|
device.clock_polarity = False
|
|
assert device.clock_mode == 0
|
|
device.clock_polarity = True
|
|
assert device.clock_mode == 2
|
|
device.clock_phase = True
|
|
assert device.clock_mode == 3
|
|
assert not device.lsb_first
|
|
assert device.select_high
|
|
assert device.bits_per_word == 8
|
|
device.select_high = False
|
|
device.lsb_first = True
|
|
device.bits_per_word = 12
|
|
assert not spidev.return_value.cshigh
|
|
assert spidev.return_value.lsbfirst
|
|
assert spidev.return_value.bits_per_word == 12
|
|
|
|
def test_spi_software_read():
|
|
class SPISlave(MockSPIDevice):
|
|
def on_start(self):
|
|
super(SPISlave, self).on_start()
|
|
for i in range(10):
|
|
self.tx_word(i)
|
|
with patch('gpiozero.pins.local.SpiDev', None), \
|
|
SPISlave(11, 10, 9, 8) as slave, \
|
|
Device.pin_factory.spi() as master:
|
|
assert master.read(3) == [0, 1, 2]
|
|
assert master.read(6) == [0, 1, 2, 3, 4, 5]
|
|
slave.clock_phase = True
|
|
master.clock_phase = True
|
|
assert master.read(3) == [0, 1, 2]
|
|
assert master.read(6) == [0, 1, 2, 3, 4, 5]
|
|
|
|
def test_spi_software_write():
|
|
with patch('gpiozero.pins.local.SpiDev', None), \
|
|
MockSPIDevice(11, 10, 9, 8) as test_device, \
|
|
Device.pin_factory.spi() as master:
|
|
master.write([0])
|
|
assert test_device.rx_word() == 0
|
|
master.write([2, 0])
|
|
assert test_device.rx_word() == 512
|
|
master.write([0, 1, 1])
|
|
assert test_device.rx_word() == 257
|
|
|
|
def test_spi_software_clock_mode():
|
|
with patch('gpiozero.pins.local.SpiDev', None), \
|
|
Device.pin_factory.spi() as master:
|
|
assert master.clock_mode == 0
|
|
assert not master.clock_polarity
|
|
assert not master.clock_phase
|
|
master.clock_polarity = False
|
|
assert master.clock_mode == 0
|
|
master.clock_polarity = True
|
|
assert master.clock_mode == 2
|
|
master.clock_phase = True
|
|
assert master.clock_mode == 3
|
|
master.clock_mode = 0
|
|
assert not master.clock_polarity
|
|
assert not master.clock_phase
|
|
with pytest.raises(ValueError):
|
|
master.clock_mode = 5
|
|
|
|
def test_spi_software_attr():
|
|
with patch('gpiozero.pins.local.SpiDev', None), \
|
|
Device.pin_factory.spi() as master:
|
|
assert not master.lsb_first
|
|
assert not master.select_high
|
|
assert master.bits_per_word == 8
|
|
master.bits_per_word = 12
|
|
assert master.bits_per_word == 12
|
|
master.lsb_first = True
|
|
assert master.lsb_first
|
|
master.select_high = True
|
|
assert master.select_high
|
|
with pytest.raises(ValueError):
|
|
master.bits_per_word = 0
|
|
|
|
|
|
# XXX Test two simultaneous SPI devices sharing clock, MOSI, and MISO, with
|
|
# separate select pins (including threaded tests which attempt simultaneous
|
|
# reading/writing)
|