Source code for usb_iss.usb_iss

from . import defs
from .exceptions import UsbIssError
from .driver import Driver, DummyDriver
from .i2c import I2C
from .io import IO
from .spi import SPI
from .serial_ import Serial


[docs]class UsbIss(object): """ Main object used to interact with the USB_ISS device. Example: :: from usb_iss import UsbIss, defs # Configure I2C mode iss = UsbIss() iss.open("COM3") iss.setup_i2c() # Write and read back some data # NOTE: I2C methods use 7-bit device addresses (0x00 - 0x7F) iss.i2c.write(0x62, 0, [0, 1, 2]); data = iss.i2c.read(0x62, 0, 3) print(data) # [0, 1, 2] Args: dummy (bool): Use a dummy driver stub, for testing. verbose (bool): Print debug output to the console. Attributes: i2c (:class:`i2c.I2C`): Attribute to use for I2C access. See :class:`i2c.I2C` for the full set of I2C methods. io (:class:`io.IO`): Attribute to use for pin IO access. See :class:`io.IO` for the full set of IO methods. spi (:class:`spi.SPI`): Attribute to use for SPI access. See :class:`spi.SPI` for the full set of SPI methods. serial (:class:`serial_.Serial`): Attribute to use for Serial UART access. See :class:`serial_.Serial` for the full set of Serial methods. """ def __init__(self, dummy=False, verbose=False): self._drv = DummyDriver() if dummy else Driver(verbose) self.i2c = I2C(self._drv) self.io = IO(self._drv) self.spi = SPI(self._drv) self.serial = Serial(self._drv) self.current_io_type = 0xAA # Everything digital input by default
[docs] def open(self, port): """ Open the specified serial port for communication with the USB_ISS module. Args: port (str): Serial port to use for usb_iss communication. """ self._drv.open(port) return self
[docs] def close(self): """ Close the serial port. """ self._drv.close()
[docs] def setup_i2c(self, clock_khz=400, use_i2c_hardware=True, io1_type=None, io2_type=None): """ Issue an ISS_MODE command to set the operating mode to I2C + IO. Args: clock_khz (int): I2C clock rate in kHz. See https://www.robot-electronics.co.uk/htm/usb_iss_tech.htm for a list of valid values. use_i2c_hardware (bool): Use the USB_ISS module's hardware I2C controller. io1_type (defs.IOType): IO1 mode (or None for no change) io2_type (defs.IOType): IO2 mode (or None for no change) """ i2c_mode = self._get_i2c_mode(clock_khz, use_i2c_hardware) io_type = self._get_io_type(io1_type, io2_type, None, None) self._set_mode(i2c_mode, [io_type & 0x0F]) self.current_io_type = io_type
[docs] def setup_i2c_serial(self, clock_khz=400, use_i2c_hardware=True, baud_rate=9600): """ Issue an ISS_MODE command to set the operating mode to I2C + Serial. Args: clock_khz (int): I2C clock rate in kHz. See https://www.robot-electronics.co.uk/htm/usb_iss_tech.htm for a list of valid values. use_i2c_hardware (bool): Use the USB_ISS module's hardware I2C controller. baud_rate (int): Baud rate for the serial interface. """ i2c_mode = self._get_i2c_mode(clock_khz, use_i2c_hardware) divisor = self._get_serial_divisor(baud_rate) self._set_mode(i2c_mode | defs.Mode.SERIAL.value, divisor)
[docs] def setup_spi(self, spi_mode=defs.SPIMode.TX_ACTIVE_TO_IDLE_IDLE_LOW, clock_khz=500): """ Issue an ISS_MODE command to set the operating mode to SPI. Args: spi_mode (defs.SPIMode): SPI mode option to use. clock_khz (int): SPI clock rate in kHz. """ divisor = self._get_spi_divisor(clock_khz) self._set_mode(spi_mode.value, [divisor])
[docs] def setup_io(self, io1_type=None, io2_type=None, io3_type=None, io4_type=None): """ Issue an ISS_MODE command to set the operating mode to IO. Args: io1_type (defs.IOType): IO1 mode (or None for no change) io2_type (defs.IOType): IO2 mode (or None for no change) io3_type (defs.IOType): IO3 mode (or None for no change) io4_type (defs.IOType): IO4 mode (or None for no change) """ io_type = self._get_io_type(io1_type, io2_type, io3_type, io4_type) self._set_mode(defs.Mode.IO_MODE.value, [io_type]) self.current_io_type = io_type
[docs] def change_io(self, io1_type=None, io2_type=None, io3_type=None, io4_type=None): """ Issue an ISS_MODE command to change the current IO mode without affecting serial or I2C settings. Args: io1_type (defs.IOType): IO1 mode (or None for no change) io2_type (defs.IOType): IO2 mode (or None for no change) io3_type (defs.IOType): IO3 mode (or None for no change) io4_type (defs.IOType): IO4 mode (or None for no change) """ io_type = self._get_io_type(io1_type, io2_type, io3_type, io4_type) self._set_mode(defs.Mode.IO_CHANGE.value, [io_type]) self.current_io_type = io_type
[docs] def setup_serial(self, baud_rate=9600, io3_type=None, io4_type=None): """ Issue an ISS_MODE command to set the operating mode to Serial + IO. Args: baud_rate (int): Baud rate for the serial interface. io3_type (defs.IOType): IO3 mode (or None for no change) io4_type (defs.IOType): IO4 mode (or None for no change) """ divisor = self._get_serial_divisor(baud_rate) io_type = self._get_io_type(None, None, io3_type, io4_type) self._set_mode(defs.Mode.SERIAL.value, divisor + [io_type & 0xF0]) self.current_io_type = io_type
[docs] def read_module_id(self): """ Returns: int: The USB_ISS module ID (always 7). """ self._drv.write_cmd(defs.Command.USB_ISS.value, [defs.SubCommand.ISS_VERSION.value]) return self._drv.read(3)[0]
[docs] def read_fw_version(self): """ Returns: int: The USB_ISS firmware version. """ self._drv.write_cmd(defs.Command.USB_ISS.value, [defs.SubCommand.ISS_VERSION.value]) return self._drv.read(3)[1]
[docs] def read_iss_mode(self): """ Returns: defs.Mode: The current ISS_MODE operating mode. """ self._drv.write_cmd(defs.Command.USB_ISS.value, [defs.SubCommand.ISS_VERSION.value]) return defs.Mode(self._drv.read(3)[2])
[docs] def read_serial_number(self): """ Returns: str: The serial number of the attached USB_ISS module. """ self._drv.write_cmd(defs.Command.USB_ISS.value, [defs.SubCommand.GET_SER_NUM.value]) data = self._drv.read(8) return ''.join([chr(byte) for byte in data])
def _set_mode(self, mode_value, data): data = [defs.SubCommand.ISS_MODE.value, mode_value] + data self._drv.write_cmd(defs.Command.USB_ISS.value, data) self._drv.check_ack_error_code(defs.ModeError) def _get_io_type(self, io1_type, io2_type, io3_type, io4_type): new_io_type = self.current_io_type if io1_type is not None: new_io_type = (new_io_type & 0xFC) | (io1_type.value << 0) if io2_type is not None: new_io_type = (new_io_type & 0xF3) | (io2_type.value << 2) if io3_type is not None: new_io_type = (new_io_type & 0xCF) | (io3_type.value << 4) if io4_type is not None: new_io_type = (new_io_type & 0x3F) | (io4_type.value << 6) return new_io_type @staticmethod def _get_i2c_mode(clock_khz, use_i2c_hardware): if clock_khz == 20: assert not use_i2c_hardware, "I2C HW mode doesn't support 20kHz" return defs.Mode.I2C_S_20KHZ.value if clock_khz == 50: assert not use_i2c_hardware, "I2C HW mode doesn't support 50kHz" return defs.Mode.I2C_S_50KHZ.value if clock_khz == 100: return (defs.Mode.I2C_H_100KHZ.value if use_i2c_hardware else defs.Mode.I2C_S_100KHZ.value) if clock_khz == 400: return (defs.Mode.I2C_H_400KHZ.value if use_i2c_hardware else defs.Mode.I2C_S_400KHZ.value) if clock_khz == 1000: assert use_i2c_hardware, "I2C SW mode doesn't support 1000kHz" return defs.Mode.I2C_H_1000KHZ.value raise UsbIssError("Invalid clk_khz value") @staticmethod def _get_serial_divisor(baud_rate): divisor = (48000000 // (16 * baud_rate)) - 1 divisor = max(divisor, 0) divisor = min(divisor, 0xFFFF) return [divisor >> 8, divisor & 0xFF] @staticmethod def _get_spi_divisor(clock_khz): divisor = (6000 // clock_khz) - 1 divisor = max(divisor, 0) divisor = min(divisor, 0xFF) return divisor