Files
python-gpiozero/tests/test_spi.py
Dave Jones a99e0746c3 Fix #279
Permit replacement of pin_factory without closing old factory. However,
continue closing devices associated with extant pin factory at script
termination.
2017-06-22 22:45:00 +01:00

198 lines
8.1 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']
with patch('gpiozero.devices.Device.pin_factory', NativeFactory()), \
patch('gpiozero.pins.local.SpiDev'):
with Device.pin_factory.spi() as device:
assert isinstance(device, LocalPiHardwareSPI)
with Device.pin_factory.spi(port=0, device=0) as device:
assert isinstance(device, LocalPiHardwareSPI)
with Device.pin_factory.spi(port=0, device=1) as device:
assert isinstance(device, LocalPiHardwareSPI)
with Device.pin_factory.spi(clock_pin=11) as device:
assert isinstance(device, LocalPiHardwareSPI)
with Device.pin_factory.spi(clock_pin=11, mosi_pin=10, select_pin=8) as device:
assert isinstance(device, LocalPiHardwareSPI)
with Device.pin_factory.spi(clock_pin=11, mosi_pin=10, select_pin=7) as device:
assert isinstance(device, LocalPiHardwareSPI)
with Device.pin_factory.spi(shared=True) as device:
assert isinstance(device, LocalPiHardwareSPIShared)
with pytest.raises(ValueError):
Device.pin_factory.spi(port=1)
with pytest.raises(ValueError):
Device.pin_factory.spi(device=2)
with pytest.raises(ValueError):
Device.pin_factory.spi(port=0, clock_pin=12)
with pytest.raises(ValueError):
Device.pin_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']
with patch('gpiozero.devices.Device.pin_factory', NativeFactory()), \
patch('gpiozero.pins.local.SpiDev'):
with Device.pin_factory.spi(select_pin=6) as device:
assert isinstance(device, LocalPiSoftwareSPI)
with Device.pin_factory.spi(clock_pin=11, mosi_pin=9, miso_pin=10) as device:
assert isinstance(device, LocalPiSoftwareSPI)
with Device.pin_factory.spi(select_pin=6, shared=True) as device:
assert isinstance(device, LocalPiSoftwareSPIShared)
with patch('gpiozero.devices.Device.pin_factory', NativeFactory()), \
patch('gpiozero.pins.local.SpiDev', None):
# Clear out the old factory's pins cache (this is only necessary
# because we're being very naughty switching out pin factories)
Device.pin_factory.pins.clear()
# Ensure software fallback works when SpiDev isn't present
with Device.pin_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)