diff -Nru python-periphery-2.1.0/CHANGELOG.md python-periphery-2.3.0/CHANGELOG.md --- python-periphery-2.1.0/CHANGELOG.md 2020-05-29 06:27:44.000000000 +0000 +++ python-periphery-2.3.0/CHANGELOG.md 2021-02-15 04:38:06.000000000 +0000 @@ -1,3 +1,31 @@ +* v2.3.0 - 02/14/2021 + * GPIO + * Add kernel version check for line bias support. + * Fix docstring for `close()`. + * SPI + * Add kernel version check for 32-bit mode support. + * MMIO + * Fix duplicate transactions in integral read and write methods. + * Fix memory offset of `pointer` property. + * Contributors + * Michael Murton, @CrazyIvan359 - 9c1a4f3 + * @paul-demo - b318a6a + +* v2.2.0 - 12/16/2020 + * MMIO + * Add `path` keyword argument to constructor for use with alternate + memory character devices (e.g. `/dev/gpiomem`). + * SPI + * Add support for 32-bit flags to `extra_flags` property and + constructor. + +* v2.1.1 - 11/19/2020 + * GPIO + * Add direction checks for improved error reporting to `write()`, + `read_event()`, and `poll()` for character device GPIOs. + * Contributors + * Michael Murton, @CrazyIvan359 - 69bd36e + * v2.1.0 - 05/29/2020 * GPIO * Add `poll_multiple()` static method. diff -Nru python-periphery-2.1.0/debian/changelog python-periphery-2.3.0/debian/changelog --- python-periphery-2.1.0/debian/changelog 2020-06-30 14:52:43.000000000 +0000 +++ python-periphery-2.3.0/debian/changelog 2021-08-29 16:48:48.000000000 +0000 @@ -1,3 +1,19 @@ +python-periphery (2.3.0-1) unstable; urgency=low + + [ Ondřej Nový ] + * d/control: Update Maintainer field with new Debian Python Team + contact address. + * d/control: Update Vcs-* fields with new Debian Python Team Salsa + layout. + + [ Michael Fladischer ] + * New upstream release. + * Update d/watch to work with github again. + * Bump Standards-Version to 4.6.0. + * Use uscan version 4. + + -- Michael Fladischer Sun, 29 Aug 2021 16:48:48 +0000 + python-periphery (2.1.0-1) unstable; urgency=low * New upstream release. diff -Nru python-periphery-2.1.0/debian/control python-periphery-2.3.0/debian/control --- python-periphery-2.1.0/debian/control 2020-06-30 14:52:43.000000000 +0000 +++ python-periphery-2.3.0/debian/control 2021-08-29 16:48:48.000000000 +0000 @@ -1,7 +1,7 @@ Source: python-periphery Section: python Priority: optional -Maintainer: Debian Python Modules Team +Maintainer: Debian Python Team Uploaders: Michael Fladischer Build-Depends: debhelper-compat (= 13), @@ -10,10 +10,10 @@ python3-setuptools, python3-sphinx, python3-sphinx-rtd-theme, -Standards-Version: 4.5.0 +Standards-Version: 4.6.0 Homepage: https://github.com/vsergeev/python-periphery/ -Vcs-Browser: https://salsa.debian.org/python-team/modules/python-periphery -Vcs-Git: https://salsa.debian.org/python-team/modules/python-periphery.git +Vcs-Browser: https://salsa.debian.org/python-team/packages/python-periphery +Vcs-Git: https://salsa.debian.org/python-team/packages/python-periphery.git Testsuite: autopkgtest-pkg-python Rules-Requires-Root: no diff -Nru python-periphery-2.1.0/debian/watch python-periphery-2.3.0/debian/watch --- python-periphery-2.1.0/debian/watch 2020-06-30 14:52:43.000000000 +0000 +++ python-periphery-2.3.0/debian/watch 2021-08-29 16:48:48.000000000 +0000 @@ -1,4 +1,4 @@ -version=3 +version=4 opts=filenamemangle=s/.*\/v([\d\.]+.*)$/python-periphery-$1/ \ https://github.com/vsergeev/python-periphery/releases \ -/vsergeev/python-periphery/archive/v([\d\.]+)\.tar\.gz +/vsergeev/python-periphery/archive/refs/tags/v([\d\.]+)\.tar\.gz diff -Nru python-periphery-2.1.0/docs/conf.py python-periphery-2.3.0/docs/conf.py --- python-periphery-2.1.0/docs/conf.py 2020-05-29 06:27:44.000000000 +0000 +++ python-periphery-2.3.0/docs/conf.py 2021-02-15 04:38:06.000000000 +0000 @@ -17,11 +17,11 @@ # -- Project information ----------------------------------------------------- project = u'python-periphery' -copyright = u'2015-2020, vsergeev / Ivan (Vanya) A. Sergeev' +copyright = u'2015-2021, vsergeev / Ivan (Vanya) A. Sergeev' author = u'Vanya A. Sergeev' # The short X.Y version. -version = '2.1.0' +version = '2.3.0' # The full version, including alpha/beta/rc tags. release = version diff -Nru python-periphery-2.1.0/LICENSE python-periphery-2.3.0/LICENSE --- python-periphery-2.1.0/LICENSE 2020-05-29 06:27:44.000000000 +0000 +++ python-periphery-2.3.0/LICENSE 2021-02-15 04:38:06.000000000 +0000 @@ -1,4 +1,4 @@ - Copyright (c) 2015-2020 vsergeev / Ivan (Vanya) A. Sergeev + Copyright (c) 2015-2021 vsergeev / Ivan (Vanya) A. Sergeev Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff -Nru python-periphery-2.1.0/periphery/gpio.py python-periphery-2.3.0/periphery/gpio.py --- python-periphery-2.1.0/periphery/gpio.py 2020-05-29 06:27:44.000000000 +0000 +++ python-periphery-2.3.0/periphery/gpio.py 2021-02-15 04:38:06.000000000 +0000 @@ -4,10 +4,17 @@ import fcntl import os import os.path +import platform import select import time +try: + KERNEL_VERSION = tuple([int(s) for s in platform.release().split(".")[:2]]) +except ValueError: + KERNEL_VERSION = (0, 0) + + class GPIOError(IOError): """Base class for GPIO errors.""" pass @@ -175,7 +182,7 @@ return results def close(self): - """Close the sysfs GPIO. + """Close the GPIO. Raises: GPIOError: if an I/O or OS error occurs. @@ -439,6 +446,8 @@ _GPIOEVENT_EVENT_RISING_EDGE = 0x1 _GPIOEVENT_EVENT_FALLING_EDGE = 0x2 + _SUPPORTS_LINE_BIAS = KERNEL_VERSION >= (5, 5) + def __init__(self, path, line, direction, edge="none", bias="default", drive="default", inverted=False, label=None): """**Character device GPIO** @@ -498,22 +507,22 @@ if not isinstance(direction, str): raise TypeError("Invalid direction type, should be string.") - elif direction.lower() not in ["in", "out", "high", "low"]: + elif direction not in ["in", "out", "high", "low"]: raise ValueError("Invalid direction, can be: \"in\", \"out\", \"high\", \"low\".") if not isinstance(edge, str): raise TypeError("Invalid edge type, should be string.") - elif edge.lower() not in ["none", "rising", "falling", "both"]: + elif edge not in ["none", "rising", "falling", "both"]: raise ValueError("Invalid edge, can be: \"none\", \"rising\", \"falling\", \"both\".") if not isinstance(bias, str): raise TypeError("Invalid bias type, should be string.") - elif bias.lower() not in ["default", "pull_up", "pull_down", "disable"]: + elif bias not in ["default", "pull_up", "pull_down", "disable"]: raise ValueError("Invalid bias, can be: \"default\", \"pull_up\", \"pull_down\", \"disable\".") if not isinstance(drive, str): raise TypeError("Invalid drive type, should be string.") - elif drive.lower() not in ["default", "open_drain", "open_source"]: + elif drive not in ["default", "open_drain", "open_source"]: raise ValueError("Invalid drive, can be: \"default\", \"open_drain\", \"open_source\".") if not isinstance(inverted, bool): @@ -540,7 +549,9 @@ def _reopen(self, direction, edge, bias, drive, inverted): flags = 0 - if bias == "pull_up": + if bias != "default" and not CdevGPIO._SUPPORTS_LINE_BIAS: + raise GPIOError(None, "Line bias configuration not supported by kernel version {}.{}.".format(*KERNEL_VERSION)) + elif bias == "pull_up": flags |= CdevGPIO._GPIOHANDLE_REQUEST_BIAS_PULL_UP elif bias == "pull_down": flags |= CdevGPIO._GPIOHANDLE_REQUEST_BIAS_PULL_DOWN @@ -674,6 +685,8 @@ def write(self, value): if not isinstance(value, bool): raise TypeError("Invalid value type, should be bool.") + elif self._direction != "out": + raise GPIOError(None, "Invalid operation: cannot write to input GPIO") data = _CGpiohandleData() @@ -687,6 +700,8 @@ def poll(self, timeout=None): if not isinstance(timeout, (int, float, type(None))): raise TypeError("Invalid timeout type, should be integer, float, or None.") + elif self._direction != "in": + raise GPIOError(None, "Invalid operation: cannot poll output GPIO") # Setup poll p = select.poll() @@ -702,7 +717,9 @@ return len(events) > 0 def read_event(self): - if self._edge == "none": + if self._direction != "in": + raise GPIOError(None, "Invalid operation: cannot read event of output GPIO") + elif self._edge == "none": raise GPIOError(None, "Invalid operation: GPIO edge not set") try: @@ -814,7 +831,7 @@ def _set_direction(self, direction): if not isinstance(direction, str): raise TypeError("Invalid direction type, should be string.") - if direction.lower() not in ["in", "out", "high", "low"]: + if direction not in ["in", "out", "high", "low"]: raise ValueError("Invalid direction, can be: \"in\", \"out\", \"high\", \"low\".") if self._direction == direction: @@ -830,7 +847,7 @@ def _set_edge(self, edge): if not isinstance(edge, str): raise TypeError("Invalid edge type, should be string.") - if edge.lower() not in ["none", "rising", "falling", "both"]: + if edge not in ["none", "rising", "falling", "both"]: raise ValueError("Invalid edge, can be: \"none\", \"rising\", \"falling\", \"both\".") if self._direction != "in": @@ -849,7 +866,7 @@ def _set_bias(self, bias): if not isinstance(bias, str): raise TypeError("Invalid bias type, should be string.") - if bias.lower() not in ["default", "pull_up", "pull_down", "disable"]: + if bias not in ["default", "pull_up", "pull_down", "disable"]: raise ValueError("Invalid bias, can be: \"default\", \"pull_up\", \"pull_down\", \"disable\".") if self._bias == bias: @@ -865,7 +882,7 @@ def _set_drive(self, drive): if not isinstance(drive, str): raise TypeError("Invalid drive type, should be string.") - if drive.lower() not in ["default", "open_drain", "open_source"]: + if drive not in ["default", "open_drain", "open_source"]: raise ValueError("Invalid drive, can be: \"default\", \"open_drain\", \"open_source\".") if self._direction != "out" and drive != "default": diff -Nru python-periphery-2.1.0/periphery/__init__.py python-periphery-2.3.0/periphery/__init__.py --- python-periphery-2.1.0/periphery/__init__.py 2020-05-29 06:27:44.000000000 +0000 +++ python-periphery-2.3.0/periphery/__init__.py 2021-02-15 04:38:06.000000000 +0000 @@ -1,9 +1,9 @@ import time -__version__ = "2.1.0" +__version__ = "2.3.0" "Module version string." -version = (2, 1, 0) +version = (2, 3, 0) "Module version tuple." diff -Nru python-periphery-2.1.0/periphery/mmio.py python-periphery-2.3.0/periphery/mmio.py --- python-periphery-2.1.0/periphery/mmio.py 2020-05-29 06:27:44.000000000 +0000 +++ python-periphery-2.3.0/periphery/mmio.py 2021-02-15 04:38:06.000000000 +0000 @@ -16,13 +16,17 @@ class MMIO(object): - def __init__(self, physaddr, size): + def __init__(self, physaddr, size, path="/dev/mem"): """Instantiate an MMIO object and map the region of physical memory - specified by the address base `physaddr` and size `size` in bytes. + specified by the `physaddr` base physical address and `size` size in + bytes. The default memory character device "/dev/mem" can be overridden + with the keyword argument `path`, for use with sandboxed memory + character devices, e.g. "/dev/gpiomem". Args: physaddr (int, long): base physical address of memory region. size (int, long): size of memory region. + path (str): memory character device path. Returns: MMIO: MMIO object. @@ -33,7 +37,7 @@ """ self.mapping = None - self._open(physaddr, size) + self._open(physaddr, size, path) def __del__(self): self.close() @@ -44,7 +48,7 @@ def __exit__(self, t, value, traceback): self.close() - def _open(self, physaddr, size): + def _open(self, physaddr, size, path): if not isinstance(physaddr, (int, long)): raise TypeError("Invalid physaddr type, should be integer.") if not isinstance(size, (int, long)): @@ -58,19 +62,19 @@ self._aligned_size = size + (physaddr - self._aligned_physaddr) try: - fd = os.open("/dev/mem", os.O_RDWR | os.O_SYNC) + fd = os.open(path, os.O_RDWR | os.O_SYNC) except OSError as e: - raise MMIOError(e.errno, "Opening /dev/mem: " + e.strerror) + raise MMIOError(e.errno, "Opening {:s}: {:s}".format(path, e.strerror)) try: self.mapping = mmap.mmap(fd, self._aligned_size, flags=mmap.MAP_SHARED, prot=(mmap.PROT_READ | mmap.PROT_WRITE), offset=self._aligned_physaddr) except OSError as e: - raise MMIOError(e.errno, "Mapping /dev/mem: " + e.strerror) + raise MMIOError(e.errno, "Mapping {:s}: {:s}".format(path, e.strerror)) try: os.close(fd) except OSError as e: - raise MMIOError(e.errno, "Closing /dev/mem: " + e.strerror) + raise MMIOError(e.errno, "Closing {:s}: {:s}".format(path, e.strerror)) # Methods @@ -101,7 +105,7 @@ offset = self._adjust_offset(offset) self._validate_offset(offset, 4) - return struct.unpack("=L", self.mapping[offset:offset + 4])[0] + return ctypes.c_uint32.from_buffer(self.mapping, offset).value def read16(self, offset): """Read 16-bits from the specified `offset` in bytes, relative to the @@ -123,7 +127,7 @@ offset = self._adjust_offset(offset) self._validate_offset(offset, 2) - return struct.unpack("=H", self.mapping[offset:offset + 2])[0] + return ctypes.c_uint16.from_buffer(self.mapping, offset).value def read8(self, offset): """Read 8-bits from the specified `offset` in bytes, relative to the @@ -145,7 +149,7 @@ offset = self._adjust_offset(offset) self._validate_offset(offset, 1) - return struct.unpack("B", self.mapping[offset:offset + 1])[0] + return ctypes.c_uint8.from_buffer(self.mapping, offset).value def read(self, offset, length): """Read a string of bytes from the specified `offset` in bytes, @@ -192,7 +196,7 @@ offset = self._adjust_offset(offset) self._validate_offset(offset, 4) - self.mapping[offset:offset + 4] = struct.pack("=L", value) + ctypes.c_uint32.from_buffer(self.mapping, offset).value = value def write16(self, offset, value): """Write 16-bits to the specified `offset` in bytes, relative to the @@ -216,7 +220,7 @@ offset = self._adjust_offset(offset) self._validate_offset(offset, 2) - self.mapping[offset:offset + 2] = struct.pack("=H", value) + ctypes.c_uint16.from_buffer(self.mapping, offset).value = value def write8(self, offset, value): """Write 8-bits to the specified `offset` in bytes, relative to the @@ -240,7 +244,7 @@ offset = self._adjust_offset(offset) self._validate_offset(offset, 1) - self.mapping[offset:offset + 1] = struct.pack("B", value) + ctypes.c_uint8.from_buffer(self.mapping, offset).value = value def write(self, offset, data): """Write a string of bytes to the specified `offset` in bytes, relative @@ -301,7 +305,7 @@ :type: ctypes.c_void_p """ - return ctypes.cast(ctypes.pointer(ctypes.c_uint8.from_buffer(self.mapping, 0)), ctypes.c_void_p) + return ctypes.cast(ctypes.pointer(ctypes.c_uint8.from_buffer(self.mapping, self._adjust_offset(0))), ctypes.c_void_p) # String representation diff -Nru python-periphery-2.1.0/periphery/spi.py python-periphery-2.3.0/periphery/spi.py --- python-periphery-2.1.0/periphery/spi.py 2020-05-29 06:27:44.000000000 +0000 +++ python-periphery-2.3.0/periphery/spi.py 2021-02-15 04:38:06.000000000 +0000 @@ -2,6 +2,13 @@ import fcntl import array import ctypes +import platform + + +try: + KERNEL_VERSION = tuple([int(s) for s in platform.release().split(".")[:2]]) +except ValueError: + KERNEL_VERSION = (0, 0) class SPIError(IOError): @@ -31,12 +38,16 @@ _SPI_LSB_FIRST = 0x8 _SPI_IOC_WR_MODE = 0x40016b01 _SPI_IOC_RD_MODE = 0x80016b01 + _SPI_IOC_WR_MODE32 = 0x40046b05 + _SPI_IOC_RD_MODE32 = 0x80046b05 _SPI_IOC_WR_MAX_SPEED_HZ = 0x40046b04 _SPI_IOC_RD_MAX_SPEED_HZ = 0x80046b04 _SPI_IOC_WR_BITS_PER_WORD = 0x40016b03 _SPI_IOC_RD_BITS_PER_WORD = 0x80016b03 _SPI_IOC_MESSAGE_1 = 0x40206b00 + _SUPPORTS_MODE32 = KERNEL_VERSION >= (3, 15) + def __init__(self, devpath, mode, max_speed, bit_order="msb", bits_per_word=8, extra_flags=0): """Instantiate a SPI object and open the spidev device at the specified path with the specified SPI mode, max speed in hertz, and the defaults @@ -92,8 +103,6 @@ raise ValueError("Invalid bit_order, can be \"msb\" or \"lsb\".") elif bits_per_word < 0 or bits_per_word > 255: raise ValueError("Invalid bits_per_word, must be 0-255.") - elif extra_flags < 0 or extra_flags > 255: - raise ValueError("Invalid extra_flags, must be 0-255.") # Open spidev try: @@ -106,11 +115,23 @@ bit_order = bit_order.lower() # Set mode, bit order, extra flags - buf = array.array("B", [mode | (SPI._SPI_LSB_FIRST if bit_order == "lsb" else 0) | extra_flags]) - try: - fcntl.ioctl(self._fd, SPI._SPI_IOC_WR_MODE, buf, False) - except (OSError, IOError) as e: - raise SPIError(e.errno, "Setting SPI mode: " + e.strerror) + if extra_flags > 0xff: + if not SPI._SUPPORTS_MODE32: + raise SPIError(None, "32-bit mode configuration not supported by kernel version {}.{}.".format(*KERNEL_VERSION)) + + # Use 32-bit mode if extra flags is wider than 8-bits + buf = array.array("I", [mode | (SPI._SPI_LSB_FIRST if bit_order == "lsb" else 0) | extra_flags]) + try: + fcntl.ioctl(self._fd, SPI._SPI_IOC_WR_MODE32, buf, False) + except (OSError, IOError) as e: + raise SPIError(e.errno, "Setting SPI mode: " + e.strerror) + else: + # Prefer 8-bit mode for compatibility with older kernels + buf = array.array("B", [mode | (SPI._SPI_LSB_FIRST if bit_order == "lsb" else 0) | extra_flags]) + try: + fcntl.ioctl(self._fd, SPI._SPI_IOC_WR_MODE, buf, False) + except (OSError, IOError) as e: + raise SPIError(e.errno, "Setting SPI mode: " + e.strerror) # Set max speed buf = array.array("I", [int(max_speed)]) @@ -370,10 +391,15 @@ """ def _get_extra_flags(self): - # Get mode - buf = array.array('B', [0]) + if SPI._SUPPORTS_MODE32: + buf = array.array('I', [0]) + rd_cmd = SPI._SPI_IOC_RD_MODE32 + else: + buf = array.array('B', [0]) + rd_cmd = SPI._SPI_IOC_RD_MODE + try: - fcntl.ioctl(self._fd, SPI._SPI_IOC_RD_MODE, buf, True) + fcntl.ioctl(self._fd, rd_cmd, buf, True) except (OSError, IOError) as e: raise SPIError(e.errno, "Getting SPI mode: " + e.strerror) @@ -382,15 +408,24 @@ def _set_extra_flags(self, extra_flags): if not isinstance(extra_flags, int): raise TypeError("Invalid extra_flags type, should be integer.") - if extra_flags < 0 or extra_flags > 255: - raise ValueError("Invalid extra_flags, must be 0-255.") # Read-modify-write mode, because the mode contains bits for other settings + if extra_flags > 0xff: + if not SPI._SUPPORTS_MODE32: + raise SPIError(None, "32-bit mode configuration not supported by kernel version {}.{}.".format(*KERNEL_VERSION)) + + buf = array.array('I', [0]) + rd_cmd = SPI._SPI_IOC_RD_MODE32 + wr_cmd = SPI._SPI_IOC_WR_MODE32 + else: + buf = array.array('B', [0]) + rd_cmd = SPI._SPI_IOC_RD_MODE + wr_cmd = SPI._SPI_IOC_WR_MODE + # Get mode - buf = array.array('B', [0]) try: - fcntl.ioctl(self._fd, SPI._SPI_IOC_RD_MODE, buf, True) + fcntl.ioctl(self._fd, rd_cmd, buf, True) except (OSError, IOError) as e: raise SPIError(e.errno, "Getting SPI mode: " + e.strerror) @@ -398,7 +433,7 @@ # Set mode try: - fcntl.ioctl(self._fd, SPI._SPI_IOC_WR_MODE, buf, False) + fcntl.ioctl(self._fd, wr_cmd, buf, False) except (OSError, IOError) as e: raise SPIError(e.errno, "Setting SPI mode: " + e.strerror) @@ -416,5 +451,5 @@ # String representation def __str__(self): - return "SPI (device={:s}, fd={:d}, mode={:d}, max_speed={:d}, bit_order={:s}, bits_per_word={:d}, extra_flags=0x{:02x})" \ + return "SPI (device={:s}, fd={:d}, mode={:d}, max_speed={:d}, bit_order={:s}, bits_per_word={:d}, extra_flags=0x{:08x})" \ .format(self.devpath, self.fd, self.mode, self.max_speed, self.bit_order, self.bits_per_word, self.extra_flags) diff -Nru python-periphery-2.1.0/README.md python-periphery-2.3.0/README.md --- python-periphery-2.1.0/README.md 2020-05-29 06:27:44.000000000 +0000 +++ python-periphery-2.3.0/README.md 2021-02-15 04:38:06.000000000 +0000 @@ -46,7 +46,7 @@ gpio_out.close() ``` -[Go to GPIO documentation.](http://python-periphery.readthedocs.org/en/latest/gpio.html) +[Go to GPIO documentation.](https://python-periphery.readthedocs.io/en/latest/gpio.html) ### LED @@ -68,7 +68,7 @@ led1.close() ``` -[Go to LED documentation.](http://python-periphery.readthedocs.org/en/latest/led.html) +[Go to LED documentation.](https://python-periphery.readthedocs.io/en/latest/led.html) ### PWM @@ -91,7 +91,7 @@ pwm.close() ``` -[Go to PWM documentation.](http://python-periphery.readthedocs.org/en/latest/pwm.html) +[Go to PWM documentation.](https://python-periphery.readthedocs.io/en/latest/pwm.html) ### SPI @@ -110,7 +110,7 @@ spi.close() ``` -[Go to SPI documentation.](http://python-periphery.readthedocs.org/en/latest/spi.html) +[Go to SPI documentation.](https://python-periphery.readthedocs.io/en/latest/spi.html) ### I2C @@ -128,7 +128,7 @@ i2c.close() ``` -[Go to I2C documentation.](http://python-periphery.readthedocs.org/en/latest/i2c.html) +[Go to I2C documentation.](https://python-periphery.readthedocs.io/en/latest/i2c.html) ### MMIO @@ -159,7 +159,7 @@ ctrl_mmio.close() ``` -[Go to MMIO documentation.](http://python-periphery.readthedocs.org/en/latest/mmio.html) +[Go to MMIO documentation.](https://python-periphery.readthedocs.io/en/latest/mmio.html) ### Serial @@ -178,11 +178,11 @@ serial.close() ``` -[Go to Serial documentation.](http://python-periphery.readthedocs.org/en/latest/serial.html) +[Go to Serial documentation.](https://python-periphery.readthedocs.io/en/latest/serial.html) ## Documentation -Documentation is hosted at [http://python-periphery.readthedocs.org/](http://python-periphery.readthedocs.org/). +Documentation is hosted at [https://python-periphery.readthedocs.io](https://python-periphery.readthedocs.io). To build documentation locally with Sphinx, run: diff -Nru python-periphery-2.1.0/setup.py python-periphery-2.3.0/setup.py --- python-periphery-2.1.0/setup.py 2020-05-29 06:27:44.000000000 +0000 +++ python-periphery-2.3.0/setup.py 2021-02-15 04:38:06.000000000 +0000 @@ -5,7 +5,7 @@ setup( name='python-periphery', - version='2.1.0', + version='2.3.0', description='A pure Python 2/3 library for peripheral I/O (GPIO, LED, PWM, SPI, I2C, MMIO, Serial) in Linux.', author='vsergeev', author_email='v@sergeev.io', diff -Nru python-periphery-2.1.0/tests/test_spi.py python-periphery-2.3.0/tests/test_spi.py --- python-periphery-2.1.0/tests/test_spi.py 2020-05-29 06:27:44.000000000 +0000 +++ python-periphery-2.3.0/tests/test_spi.py 2021-02-15 04:38:06.000000000 +0000 @@ -34,7 +34,6 @@ passert("max speed is 100000", spi.max_speed == 100000) passert("default bit_order is msb", spi.bit_order == "msb") passert("default bits_per_word is 8", spi.bits_per_word == 8) - passert("default extra_flags is 0", spi.extra_flags == 0) # Not going to try different bit order or bits per word, because not # all SPI controllers support them