Browse Source

constructor: added args to select SPI bus & chip select line

Fabian Peter Hammerle 3 years ago
parent
commit
8765270c74
4 changed files with 37 additions and 8 deletions
  1. 1 0
      CHANGELOG.md
  2. 11 2
      README.md
  3. 10 6
      cc1101/__init__.py
  4. 15 0
      tests/test_spi.py

+ 1 - 0
CHANGELOG.md

@@ -6,6 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## [Unreleased]
 ### Added
+- select arbitrary device via `CC1101(spi_bus=?, spi_chip_select=?)`
 - added explanation to `PermissionError` on `SpiDev.open()`
 
 ## [2.1.0] - 2020-12-04

+ 11 - 2
README.md

@@ -21,7 +21,7 @@ $ sudo apt-get install --no-install-recommends python3-spidev
 
 ### Wiring Raspberry Pi
 
-Directly connect the following pins:
+Connect the following pins directly:
 
 |C1101|Raspberry Pi        |
 |-----|--------------------|
@@ -29,9 +29,14 @@ Directly connect the following pins:
 |SI   | MOSI (Pin 19)      |
 |SO   | MISO (Pin 21)      |
 |CSn  | CE0 (Pin 24)       |
-|SCLK | SCLK (Pin 23)      | 
+|SCLK | SCLK (Pin 23)      |
 |GND  | Ground             |
 
+If these pins are already in use,
+select a different SPI bus or chip select:
+https://www.raspberrypi.org/documentation/hardware/raspberrypi/spi/README.md
+([permalink](https://github.com/raspberrypi/documentation/blob/d41d69f8efa3667b1a8b01a669238b8bd113edc1/hardware/raspberrypi/spi/README.md#hardware))
+
 No resistors required. GDO0 & GDO2 are currently unused.
 
 Raspberry Pi GPIO docs: https://www.raspberrypi.org/documentation/usage/gpio/
@@ -49,6 +54,10 @@ with cc1101.CC1101() as transceiver:
     transceiver.transmit(b"\x01\xff\x00 message")
 ```
 
+In case CC1101 is connected to a different SPI bus or chip select line
+than `/dev/spidev0.0`,
+use `CC1101(spi_bus=?, spi_chip_select=?)`.
+
 In case a `PermissionError` gets raised,
 check the permissions of `/dev/spidev*`.
 You'll probably need `sudo usermod -a -G spi $USER`,

+ 10 - 6
cc1101/__init__.py

@@ -137,15 +137,21 @@ class CC1101:
     # > f_carrier = f_XOSC / 2**16 * (FREQ + CHAN * ((256 + CHANSPC_M) * 2**CHANSPC_E-2))
     _FREQUENCY_CONTROL_WORD_HERTZ_FACTOR = _CRYSTAL_OSCILLATOR_FREQUENCY_HERTZ / 2 ** 16
 
-    def __init__(self) -> None:
+    def __init__(self, spi_bus: int = 0, spi_chip_select: int = 0) -> None:
         self._spi = spidev.SpiDev()
-        self._spi_bus = 0
+        self._spi_bus = int(spi_bus)
         # > The BCM2835 core common to all Raspberry Pi devices has 3 SPI Controllers:
         # > SPI0, with two hardware chip selects, [...]
         # > SPI1, with three hardware chip selects, [...]
         # > SPI2, also with three hardware chip selects, is only usable on a Compute Module [...]
+        # https://github.com/raspberrypi/documentation/blob/d41d69f8efa3667b1a8b01a669238b8bd113edc1/hardware/raspberrypi/spi/README.md#hardware
         # https://www.raspberrypi.org/documentation/hardware/raspberrypi/spi/README.md
-        self._spi_chip_select = 0
+        self._spi_chip_select = int(spi_chip_select)
+
+    @property
+    def _spi_device_path(self) -> str:
+        # https://github.com/doceme/py-spidev/blob/v3.4/spidev_module.c#L1286
+        return "/dev/spidev{}.{}".format(self._spi_bus, self._spi_chip_select)
 
     @staticmethod
     def _log_chip_status_byte(chip_status: int) -> None:
@@ -443,9 +449,7 @@ class CC1101:
             self._spi.open(self._spi_bus, self._spi_chip_select)
         except PermissionError as exc:
             raise PermissionError(
-                "Could not access /dev/spidev{}.{}".format(
-                    self._spi_bus, self._spi_chip_select
-                )
+                "Could not access {}".format(self._spi_device_path)
                 + "\nVerify that the current user has both read and write access."
                 + "\nOn some devices, like Raspberry Pis,"
                 + "\n\tsudo usermod -a -G spi $USER"

+ 15 - 0
tests/test_spi.py

@@ -26,6 +26,21 @@ import cc1101.options
 # pylint: disable=protected-access
 
 
+@pytest.mark.parametrize("bus", [0, 1])
+@pytest.mark.parametrize("chip_select", [0, 2])
+def test___init__select_device(bus, chip_select):
+    with unittest.mock.patch("spidev.SpiDev"):
+        transceiver = cc1101.CC1101(spi_bus=bus, spi_chip_select=chip_select)
+    assert transceiver._spi_bus == bus
+    assert transceiver._spi_chip_select == chip_select
+    assert transceiver._spi_device_path == "/dev/spidev{}.{}".format(bus, chip_select)
+    transceiver._spi.open.side_effect = SystemExit
+    with pytest.raises(SystemExit):
+        with transceiver:
+            pass
+    transceiver._spi.open.assert_called_once_with(bus, chip_select)
+
+
 def test__read_status_register(transceiver):
     transceiver._spi.xfer.return_value = [0, 20]
     transceiver._read_status_register(cc1101.addresses.StatusRegisterAddress.VERSION)