Source code for philander.shiftreg_spi

"""Module to control a shift register by means of an SPI bus.
"""
__author__ = "Oliver Maye"
__version__ = "0.1"
__all__ = ["ShiftRegSPI"]

import logging

from .serialbus import SerialBusDevice, SerialBusType
from .shiftreg import ShiftReg
from .systypes import ErrorCode


[docs] class ShiftRegSPI( ShiftReg ): """Driver class for a shift register device using SPI. """ def __init__(self): """Initialize the instance with defaults. Also see: :meth:`.Params_init`, :meth:`.ShiftReg.Params_init` """ ShiftReg.__init__(self) self.serbusdev = None # # Module API #
[docs] @classmethod def Params_init(cls, paramDict): """Initializes configuration parameters with defaults. General or global GPIO adjustments or defaults can be set using the `shiftreg.gpio.*` keys. They can be pin-wise overridden by specific e.g. `shiftreg.ena.gpio.*` settings. The following settings are supported: ================================== ===================================================================== Key name Value type, meaning and default ================================== ===================================================================== shiftreg.* Shift register configuration; See :meth:`.ShiftReg.Params_init`. shiftreg.SerialBusDevice.* Serial bus device config; See :meth:`.SerialBusDevice.Params_init`. shiftreg.SerialBus.* Serial bus configuration; See :meth:`.SerialBus.Params_init`. ========================================================================================================== Also see: :meth:`.Module.Params_init`, :meth:`.ShiftReg.Params_init`, :meth:`.SerialBusDevice.Params_init`. :param dict(str, object) paramDict: Dictionary of configuration settings. :return: none :rtype: None """ # Remove GPIO definitions for DIN and DCLK, if present paramDict.pop( "shiftreg.din.gpio.pinDesignator", None) paramDict.pop( "shiftreg.dclk.gpio.pinDesignator", None) # Base class settings ShiftReg.Params_init( paramDict ) # Driver defaults serialDefaults = {} serialDefaults["SerialBus.type"] = SerialBusType.SPI SerialBusDevice.Params_init( serialDefaults ) # Mandatory settings itemKey = ShiftReg.MODULE_PARAM_PREFIX + "." + "SerialBus.type" paramDict[itemKey] = SerialBusType.SPI # Add missing values by setting defaults for key, value in serialDefaults.items(): itemKey = ShiftReg.MODULE_PARAM_PREFIX + "." + key if not( itemKey in paramDict): paramDict[itemKey] = value return None
[docs] def open(self, paramDict): ret = ErrorCode.errOk if self.serbusdev: ret = ErrorCode.errResourceConflict if ret.isOk(): self.Params_init( paramDict ) prefixMod = ShiftReg.MODULE_PARAM_PREFIX + "." prefixSub1 = prefixMod + "SerialBus." prefixSub2 = prefixMod + "SerialBusDevice." # Extract serial bus parameters serialParams = dict( [(k.replace(prefixMod, ""),v) \ for k,v in paramDict.items() \ if k.startswith(prefixSub1) or k.startswith(prefixSub2)] ) self.serbusdev = SerialBusDevice() ret = self.serbusdev.open(serialParams) if not ret.isOk(): logging.debug("ShiftRegSPI couldn't open serial bus device, error: %s.", ret) self.serbusdev = None if ret.isOk(): ret = super().open( paramDict ) if not ret.isOk(): self.serbusdev.close() self.serbusdev = None logging.debug('ShiftRegSPI.open() returns: %s.', ret) return ret
[docs] def close(self): ret = ErrorCode.errOk if self.serbusdev: ret = self.serbusdev.close() self.serbusdev = None err = super().close() if ret.isOk(): ret = err logging.debug('ShiftReg closed, return: %s.', ret) return ret
# # Module specific API #
[docs] def write(self, data, numBits=8, autoLatch=True): """Feed data into the shift register. As the underlying mechanism is SPI, only full bytes can be written to the register. So, 'numBits' must be a multiple of 8. At maximum, four bytes can be written at once, so numBits must be one of `numBits={8 | 16 | 24 | 32}`. The highest-significant byte selected is written first. If, for example, `data = 0xa4b3c2d1` and `numBits=24`, the sequence shifted into the register is `b3-c2-d1`. If `autoLatch` is `True` and depending on the underlying hardware, the resulting content of the shift register is latched into the buffer. :param int data: The data to send to the shift register. :param int numBits: Non-negative number of least-significant \ bits in 'data' to shift-in. One of `{8 | 16 | 24 | 32}`. :param bool autoLatch: Whether to automatically latch the result into the buffer. :return: An error code indicating either success or the reason of failure. :rtype: ErrorCode """ ret = ErrorCode.errOk if not self.serbusdev: ret = ErrorCode.errNotInited elif not isinstance( data, int ) or \ not isinstance( numBits, int ) or (numBits not in [0,8,16,24,32]): ret = ErrorCode.errInvalidParameter elif numBits == 0: # Do nothing ret = ErrorCode.errOk else: buf = [] while numBits > 0: numBits -= 8 buf.append( (data >> numBits) & 0xFF ) ret = self.serbusdev.writeBuffer(buf) if( ret.isOk() and autoLatch ): self.latch() logging.debug('ShiftReg write(data=%02x, numBits=%d), return: %s.', data, numBits, ret) return ret