1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
|
# 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>
# Copyright (c) 2019 Andrew Scheller <github@loowis.durge.org>
#
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import (
unicode_literals,
absolute_import,
print_function,
division,
)
nstr = str
str = type('')
import io
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 test_spi_hardware_params(mock_factory):
with patch('gpiozero.pins.local.SpiDev'):
with mock_factory.spi() as device:
assert isinstance(device, LocalPiHardwareSPI)
assert repr(device) == 'SPI(port=0, device=0)'
device.close()
assert device.closed
assert repr(device) == 'SPI(closed)'
with mock_factory.spi(port=0, device=0) as device:
assert isinstance(device, LocalPiHardwareSPI)
with mock_factory.spi(port=0, device=1) as device:
assert isinstance(device, LocalPiHardwareSPI)
with mock_factory.spi(clock_pin=11) as device:
assert isinstance(device, LocalPiHardwareSPI)
with mock_factory.spi(clock_pin=11, mosi_pin=10, select_pin=8) as device:
assert isinstance(device, LocalPiHardwareSPI)
with mock_factory.spi(clock_pin=11, mosi_pin=10, select_pin=7) as device:
assert isinstance(device, LocalPiHardwareSPI)
# Ensure we support "partial" SPI where we don't reserve a pin because
# the device wants it for general IO (see SPI screens which use a pin
# for data/commands)
with mock_factory.spi(clock_pin=11, mosi_pin=10, miso_pin=None, select_pin=7) as device:
assert isinstance(device, LocalPiHardwareSPI)
with mock_factory.spi(clock_pin=11, mosi_pin=None, miso_pin=9, select_pin=7) as device:
assert isinstance(device, LocalPiHardwareSPI)
with mock_factory.spi(shared=True) as device:
assert isinstance(device, LocalPiHardwareSPIShared)
with pytest.raises(ValueError):
mock_factory.spi(port=1)
with pytest.raises(ValueError):
mock_factory.spi(device=2)
with pytest.raises(ValueError):
mock_factory.spi(port=0, clock_pin=12)
with pytest.raises(ValueError):
mock_factory.spi(foo='bar')
def test_spi_software_params(mock_factory):
with patch('gpiozero.pins.local.SpiDev'):
with mock_factory.spi(select_pin=6) as device:
assert isinstance(device, LocalPiSoftwareSPI)
assert repr(device) == 'SPI(clock_pin=11, mosi_pin=10, miso_pin=9, select_pin=6)'
device.close()
assert device.closed
assert repr(device) == 'SPI(closed)'
with mock_factory.spi(clock_pin=11, mosi_pin=9, miso_pin=10) as device:
assert isinstance(device, LocalPiSoftwareSPI)
device._bus.close()
assert device._bus.closed
device.close()
assert device.closed
with mock_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)
mock_factory.pins.clear()
mock_factory._reservations.clear()
# Ensure software fallback works when SpiDev isn't present
with mock_factory.spi() as device:
assert isinstance(device, LocalPiSoftwareSPI)
def test_spi_hardware_conflict(mock_factory):
with patch('gpiozero.pins.local.SpiDev') as spidev:
with LED(11) as led:
with pytest.raises(GPIOPinInUse):
mock_factory.spi(port=0, device=0)
with patch('gpiozero.pins.local.SpiDev') as spidev:
with mock_factory.spi(port=0, device=0) as spi:
with pytest.raises(GPIOPinInUse):
LED(11)
def test_spi_software_same_bus(mock_factory):
with patch('gpiozero.pins.local.SpiDev'):
with mock_factory.spi(select_pin=6) as device:
with pytest.raises(GPIOPinInUse):
mock_factory.spi(select_pin=6)
with mock_factory.spi(select_pin=5) as another_device:
assert device._bus is another_device._bus
def test_spi_software_shared_bus(mock_factory):
with patch('gpiozero.pins.local.SpiDev'):
with mock_factory.spi(select_pin=6, shared=True) as device:
with mock_factory.spi(select_pin=6, shared=True) as another_device:
assert device is another_device
def test_spi_hardware_read(mock_factory):
with patch('gpiozero.pins.local.SpiDev') as spidev:
spidev.return_value.xfer2.side_effect = lambda data: list(range(10))[:len(data)]
with mock_factory.spi() as device:
assert device.read(3) == [0, 1, 2]
assert device.read(6) == list(range(6))
def test_spi_hardware_write(mock_factory):
with patch('gpiozero.pins.local.SpiDev') as spidev:
spidev.return_value.xfer2.side_effect = lambda data: list(range(10))[:len(data)]
with mock_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(mock_factory):
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 mock_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
device.rate = 1000000
assert device.rate == 1000000
device.rate = 500000
assert device.rate == 500000
def test_spi_software_read(mock_factory):
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, \
mock_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(mock_factory):
with patch('gpiozero.pins.local.SpiDev', None), \
MockSPIDevice(11, 10, 9, 8) as test_device, \
mock_factory.spi() as master:
master.write([0])
assert test_device.rx_word() == 0
master.write([2, 0])
# 0b 0000_0010 0000_0000
assert test_device.rx_word() == 512
master.write([0, 1, 1])
# 0b 0000_0000 0000_0001 0000_0001
assert test_device.rx_word() == 257
def test_spi_software_write_lsb_first(mock_factory):
with patch('gpiozero.pins.local.SpiDev', None), \
MockSPIDevice(11, 10, 9, 8, lsb_first=True) as test_device, \
mock_factory.spi() as master:
# lsb_first means the bit-strings above get reversed
master.write([0])
assert test_device.rx_word() == 0
master.write([2, 0])
# 0b 0000_0000 0100_0000
assert test_device.rx_word() == 64
master.write([0, 1, 1])
# 0b 1000_0000 1000_0000 0000_0000
assert test_device.rx_word() == 8421376
def test_spi_software_clock_mode(mock_factory):
with patch('gpiozero.pins.local.SpiDev', None), \
mock_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(mock_factory):
with patch('gpiozero.pins.local.SpiDev', None), \
mock_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)
|