def __init__(self, address=0xc, **kwargs): """Initialise the AD5321 device. :param address: address of the AD5321 on the I2C bus :param kwargs: keyword arguments to be passed to the underlying I2CDevice """ # Initialise the I2CDevice superclass instance I2CDevice.__init__(self, address, **kwargs)
def test_change_default_bus(self, test_i2c_device): default_i2c_bus = 0 I2CDevice.set_default_i2c_bus(default_i2c_bus) new_device = I2CDevice(test_i2c_device.device_address, debug=test_i2c_device.device_debug) assert default_i2c_bus == new_device.busnum
def __init__(self, address, **kwargs): I2CDevice.__init__(self, address, **kwargs) self.address = address #addresses of the 4 DACs self.dacs = [0x01, 0x02, 0x04, 0x08] #store dac values to minimise i2c traffic self.dac_values = [0x00, 0x00, 0x00, 0x00] #store self.dac_mult = [0.0004, 0.1, 0.1, 0.00002]
def __init__(self, address=0x20, **kwargs): """Initialise the AD7998 device. :param address: address of the AD7998 device on the I2C bus :param kwargs: keyword arguments to be passed to the underlying I2CDevice """ # Initialise the I2CDevice superclass instance I2CDevice.__init__(self, address, **kwargs) # Set cycle register to fastest conversion mode self.write8(3, 1)
def __init__(self, address=0x68, **kwargs): """ Initialise the SI5324 device. :param address: The address of the SI5324 is determined by pins A[2:0] as follows: 0b1101[A2][A1][A0]. """ I2CDevice.__init__(self, address, **kwargs) logger.info( "Created new si5324 instance with address 0x{:02X}.".format( address)) self.iCAL_required = True # An iCAL is required at least once before run
def __init__(self, address=0x20, **kwargs): """Initialise the MCP23008 device. :param address: address of the MCP23008 deviceon the I2C bus :param kwargs: keyword arguments to be passed to the underlying I2CDevice """ # Initialise the I2CDevice superclass instance I2CDevice.__init__(self, address, **kwargs) # Synchronise local buffered register values with state of device self.__iodir = self.readU8(self.IODIR) self.__gppu = self.readU8(self.GPPU) self.__gpio = self.readU8(self.GPIO)
def __init__(self, address=0x50, **kwargs): """Initialise the TPL0102 device. :param address: The address of the TPL0102 default: 0x50 """ I2CDevice.__init__(self, address, **kwargs) #Read back current wiper settings self.__wiper_pos = [self.readU8(0), self.readU8(1)] self.__tot_resistance = 100.0 self.__low_pd = [0.0, 0.0] self.__high_pd = [3.3, 3.3] self.disable_shutdown(True) self.set_non_volatile(False)
def __init__(self, address=0x70, allowMultiple=True, **kwargs): """Initialise the the TCA9548 device. :param address: address of TCA9548 on the I2C bus :param kwargs: keyword arguments to be passed to underlying I2CDevice """ # Initialise the I2CDevice superclass instance I2CDevice.__init__(self, address, **kwargs) # Clear attached devices and currently enabled channel self._attached_devices = {} self._selected_channel = None # Disable any already enabled devices by clearing output bus selection self.write8(0, 0)
def _init_select(self, chosen_address): """ Set up the FireFly to respond on a chosen address, and to use the select line correctly when when the _select_device() functions are used. """ # Set up device to respond on chosen address with _select_device() functions if self._select_line is None: # If no selectL line is provided, it must be assumed that it is being pulled low # externally, or setup cannot be completed. It must also be the only device pulled low # on the bus. self._log.warning( "Select Line not specified. " "This MUST be the only device with selectL pulled low on the bus" ) # Apply extra address-specific measures if chosen_address in [0x00, 0x7F]: # Revert to default behaviour, where address is 0x50 when selectL pulled low self._base_address = 0x50 return if 0x40 < chosen_address < 0x7E and chosen_address is not 0x50: # Addresses in this range will ignore selectL, so disable it (if not already None) # Note that 0x50 is a special case as the default, since it is responded to with # address register set to 0x00, and so not in this range... self._select_line = None # Write address field with initial settings for select line self._tx_device = I2CDevice( 0x50) # Temporarily assign the tx_device to default address self.write_field(self.FLD_I2C_Address, [chosen_address]) self._base_address = chosen_address self._tx_device = None # Will be properly assigned later
def _init_select(self, chosen_address): """ Set up the FireFly to respond on a chosen address, and to use the select line correctly when when the _select_device() functions are used. """ # Set up device to respond on chosen address with _select_device() functions if self._select_line is None: # If no selectL line is provided, it must be assumed that it is being pulled low # externally, or setup cannot be completed. It must also be the only device pulled low # on the bus. self._log.warning( "Select Line not specified. " "This MUST be the only device with selectL pulled low on the bus" ) # Apply extra address-specific measures if chosen_address == 0x00 or 0x7F < chosen_address < 0xFF: # Revert to default behaviour, where address is 0x50 when selectL pulled low self._log.warning( "Device will be responding to 0x50, not {}".format( chosen_address)) self._address = 0x50 return # Write address field with initial settings for select line self._device = I2CDevice( 0x50) # Temporarily assign the tx_device to default address self.write_field(self.FLD_I2C_Address, [chosen_address]) self._address = chosen_address self._device = None # Will be properly assigned later
def __init__(self): self.device_busnum = 1 self.device_address = 0x70 self.device_debug = True self.device = I2CDevice(self.device_address, self.device_busnum, self.device_debug) self.device.pre_access = Mock()
def __init__(self, loggername, base_address=0x00, select_line=None): """ Configure the two I2C device drivers, and set up the FireFly device to a specified address if requried. Also initiate use of the GPIO selection line. """ _FireFly_Interface.__init__(self, 0, loggername) # Channels start at 00 # Set up select line use for the given address self._select_line = select_line self._base_address = base_address self._init_select(base_address) # May modify _base_address # CXP uses seperate 'devices' for Tx/Rx operations self._tx_device = I2CDevice(self._base_address) self._rx_device = I2CDevice(self._base_address + 4)
def test_remove_missing_device(self, test_i2c_container): device = I2CDevice(0x24) assert_message = 'Device %s was not attached to this I2CContainer' % device with pytest.raises(I2CException) as excinfo: test_i2c_container.container.remove_device(device) assert assert_message in excinfo.value
def test_remove_missing_device(self, test_tca9548_driver): device_not_attached = I2CDevice(0x20) exc_message = 'Device %s is not attached to this TCA' % device_not_attached with pytest.raises(I2CException) as excinfo: test_tca9548_driver.tca.remove_device(device_not_attached) assert exc_message in excinfo.value
def __init__(self, address=0x55, model=SI570_C, **kwargs): """Initialise the SI570 and determine the crystal frequency. This resets the device to the factory programmed frequency. """ I2CDevice.__init__(self, address, **kwargs) # Registers used are dependant on the device model self.__register = 13 if model == self.SI570_C else 7 # Reset device to 156.25MHz and calculate fXTAL self.write8(135, 1 << 7) while self.readU8(135) & 1: continue # Device is reset, read initial register configurations data = self.readList(self.__register, 6) self.__hs_div, self.__n1, self.__rfreq = self.__calculate_params(data) self.__fxtal = (156250000 * self.__hs_div * self.__n1) / self.__rfreq / 1000000 self.__fout = (self.__fxtal * self.__rfreq) / (self.__n1 * self.__hs_div)
def test_field_read(self, test_firefly): # These functions have been tested indirectly already, but these are to double-check # any untested functionality. The superfunction will be tested, which will sidestep the # page selection logic. tmp_mock_readList = MagicMock() with \ patch.object(I2CDevice, 'readList') as tmp_mock_readList: test_generic_interface = _FireFly_Interface(0, None) test_i2cdevice = I2CDevice(0x50) # Check that reading a byte works normally tmp_mock_readList.side_effect = lambda reg, num: [0xAA] tmp_field = _Field(register=0x00, startbit=7, length=8) assert (test_generic_interface.read_field( tmp_field, test_i2cdevice) == [0xAA]) # Check that reading a subsection of a byte works normally tmp_mock_readList.side_effect = lambda reg, num: [0xAA] tmp_field.startbit = 6 tmp_field.length = 3 result = test_generic_interface.read_field(tmp_field, test_i2cdevice) print(result) assert (result == [0b010]) # 0b10101010 bits 6-4 are 0b010 # Check that reading a selection of bits over a byte boundary works tmp_mock_readList.side_effect = lambda reg, num: [ 0b00000111, 0b11100000 ] tmp_field.startbit = 11 tmp_field.length = 8 result = test_generic_interface.read_field(tmp_field, test_i2cdevice) assert (result == [0b01111110]) # Check that if the I2CDevice returns nothing, an error is raised tmp_mock_readList.side_effect = None with pytest.raises(I2CException, match=".*Failed to read byte.*"): result = test_generic_interface.read_field( tmp_field, test_i2cdevice) # Check that if the number of full bytes returned is not as expected, an error is raised tmp_mock_readList.side_effect = lambda reg, num: [1, 2] tmp_field.startbit = 2 tmp_field.length = 1 with pytest.raises( I2CException, match= ".*Number of bytes read incorrect.*Expected 1, got 2.*"): result = test_generic_interface.read_field( tmp_field, test_i2cdevice)
def __init__(self, address=0x2F, **kwargs): #Initialise the AD5272 device. #:param address: The address of the AD5272 default: 0x2F when ADDR=0, 2E when ADD= FLOAT (see schematics) # I2CDevice.__init__(self, address, **kwargs) self.write8(0x1C, 0x02) # enable the update of wiper position by default #Read back current wiper settings self.write8( 0x08, 0x00) # Have to write code 0x0800 to initiate a read of the wiper tmp = self.readU16(0) # read the result into tmp variable self.__wiper_pos = ((tmp & 0x03) << 8) + ( (tmp & 0xFF00) >> 8 ) #mask off lower 8 bits and shift down 8, mask off upper 8 bits and bits 7-2 & shift up 8 #read the contents of the control register #0x1 = 50-TP program enable 0 = default, dissable #0x2 = RDAC register write protect 0 = default, wiper position frozen, 1 = allow update via i2c #0x4 = Resistance performance enable 0 = default = enabled, 1 = dissbale #0x8 = 50-TP memory program success bit 0 = default = unsuccessful, 1 = successful #send the command to read the contents of the control register self.write8( 0x20, 0x00 ) #send the command to read the contents of the control register # when read, byte swap to get register contents self.__control_reg = (self.readU16(0) & 0xF00 >> 8) #Internal variable settings depending on device / voltage connections self.__num_wiper_pos = 1024 self.__tot_resistance = 100.0 self.__low_pd = 0.0 self.__high_pd = 3.3
def __init__(self, loggername, address=0x00, select_line=None): """ Configure the two I2C device drivers, and set up the FireFly device to a specified address if requried. Also initiate use of the GPIO selection line. """ _FireFly_Interface.__init__( self, 1, loggername) # Channels start at 1 for some reason... # Set up select line use for the given address self._select_line = select_line self._address = address self._init_select(address) # May modify _address self._device = I2CDevice(self._address) self._device.enable_exceptions() #TODO remove
def __init__(self, use_spi=True, bus=0, device=0): """Initialise the BME280 device. :param use_spi: bool to specify device type for bme to use. Default True = SPI will be used, False = I2C. :param bus: bus number for SPI/I2C device. Default: 0 :param device: device number for SPI device. Default: 0 Device settings can be adjusted with the functions in the respective device class. """ self.use_spi = use_spi if self.use_spi: # using SPI self.device = SPIDevice(bus=bus, device=device) # This device is compatible with SPI modes 0 and 2 (00, 11). self.device.set_mode(0) # Longest transaction is 24 bytes read, one written. self.device.set_buffer_length(25) else: self.device = I2CDevice(address=_BME280_ADDRESS, busnum=bus) # Check device ID. chip_id = self._read_byte(_BME280_REGISTER_CHIPID) print("Chip ID: 0x%x" % int(chip_id)) if _BME280_CHIPID != chip_id: raise RuntimeError('Failed to find BME280! Chip ID 0x%x' % chip_id) # Reasonable defaults. self._iir_filter = IIR_FILTER_DISABLE self._overscan_humidity = OVERSCAN_X1 self._overscan_temperature = OVERSCAN_X1 self._overscan_pressure = OVERSCAN_X16 self._t_standby = STANDBY_TC_125 self._mode = MODE_SLEEP self._reset() self._read_coefficients() self._write_ctrl_meas() self._write_config() # Pressure in hPa at sea level. Used to calibrate altitude. self_t_fine = None
def test_attach_existing_device(self, test_i2c_container): device = I2CDevice(0x21) test_i2c_container.container.attach_device(device) assert device in test_i2c_container.container._attached_devices
def test_field_write(self, test_firefly): # These functions have been tested indirectly already, but these are to double-check # any untested functionality. The superfunction will be tested, which will sidestep the # page selection logic. tmp_mock_readList = MagicMock() tmp_mock_writeList = MagicMock() with \ patch.object(I2CDevice, 'writeList') as tmp_mock_writeList, \ patch.object(I2CDevice, 'readList') as tmp_mock_readList: pass test_generic_interface = _FireFly_Interface(0, None) test_i2cdevice = I2CDevice(0x50) # Check that writing a byte works tmp_mock_writeList.reset_mock() tmp_mock_readList.side_effect = lambda reg, ln: [ 0x00 ] # Used when reading old value tmp_field = _Field(register=0x00, startbit=7, length=8) test_generic_interface.write_field(tmp_field, [0xAA], test_i2cdevice) tmp_mock_writeList.assert_called_with(0x00, [0xAA]) # Check that writing a subsection of a byte works tmp_mock_writeList.reset_mock() tmp_field = _Field(register=0x00, startbit=6, length=3) tmp_mock_readList.side_effect = lambda reg, ln: [ 0x00 ] # Initial value 0 test_generic_interface.write_field(tmp_field, [0b101], test_i2cdevice) tmp_mock_writeList.assert_called_with(0x00, [0b01010000]) # Check that writing a selection of bits over a byte boundary works tmp_mock_writeList.reset_mock() tmp_field = _Field(register=0x00, startbit=11, length=8) tmp_mock_readList.side_effect = lambda reg, ln: [ 0x00, 0x00 ] # Initial values 0 test_generic_interface.write_field(tmp_field, [0b10101010], test_i2cdevice) tmp_mock_writeList.assert_called_with(0x00, [0b00001010, 0b10100000]) # Check that if the value does not fit inside the specified field an error is raised tmp_mock_writeList.reset_mock() tmp_field = _Field(register=0x00, startbit=3, length=4) tmp_mock_readList.side_effect = lambda reg, ln: [ 0x00 ] # Initial value 0 with pytest.raises(I2CException, match=".*Value 255 does not fit.*length 4.*"): test_generic_interface.write_field(tmp_field, [0b11111111], test_i2cdevice) # Check that the verify passes on success tmp_mock_writeList.reset_mock() tmp_mock_readList.side_effect = lambda reg, ln: [ 0xAA ] # Readback will return 0xAA tmp_field = _Field(register=0x00, startbit=7, length=8) test_generic_interface.write_field(tmp_field, [0xAA], test_i2cdevice, verify=True) # Check that the verify raises an error on failure tmp_mock_writeList.reset_mock() tmp_mock_readList.side_effect = lambda reg, ln: [ 0x00 ] # Readback will return 0x00 tmp_field = _Field(register=0x00, startbit=7, length=8) with pytest.raises( I2CException, match=".*Value.*was not successfully written.*"): test_generic_interface.write_field(tmp_field, [0xAA], test_i2cdevice, verify=True)
def test_device_info_report_pn(self, test_firefly): with \ patch.object(I2CDevice, 'write8') as mock_I2C_write8, \ patch.object(I2CDevice, 'readU8') as mock_I2C_readU8, \ patch.object(I2CDevice, 'writeList') as mock_I2C_writeList, \ patch.object(I2CDevice, 'readList') as mock_I2C_readList: # Set up the mocks mock_I2C_readList.side_effect = model_I2C_readList mock_I2C_writeList.side_effect = model_I2C_writeList mock_I2C_write8.side_effect = model_I2C_write8 mock_I2C_readU8.side_effect = model_I2C_readU8 mock_registers_reset() # reset the register systems, PS is 0 mock_I2C_SwitchDeviceQSFP() # Model a QSFP device valid_part_number = 'B0425xxx0x1xxx ' input_vendor_name = 'PRETEND MANUFAC ' I2CDevice.writeList(168, [ord(x) for x in valid_part_number]) # Insert info I2CDevice.writeList(148, [ord(x) for x in input_vendor_name]) # Insert info test_firefly = FireFly() # Check fields returned ret_pn, ret_vn, ret_oui = test_firefly.get_device_info() assert (valid_part_number == ret_pn) assert (input_vendor_name == ret_vn) # (OUI is already set to Samtec's one, or init will fail) # Check part number parts assert (test_firefly.data_rate_Gbps == 25) assert (test_firefly.num_channels == 4) # Check that an unsupported num of channels raises an error pn_unsupported_channels = 'B0625xxx0x1xxx ' # 6-channel (not real) I2CDevice.writeList( 168, [ord(x) for x in pn_unsupported_channels]) # Insert info with pytest.raises(Exception, match=".*Unsupported number of channels: 06.*"): test_firefly = FireFly() # Check that an invalid direction raises an error pn_invalid_direction = 'P0425xxx0x1xxx ' # 'P' direction (not real) I2CDevice.writeList(168, [ord(x) for x in pn_invalid_direction]) # Insert info with pytest.raises( Exception, match= ".*Data direction P in part number field not recognised.*" ): test_firefly = FireFly() # Check that invalid static padding fields raise an error (these never change) pn_invalid_static_bits = 'B0425xxx1x0xxx ' # Static bits 0, 1 swapped I2CDevice.writeList( 168, [ord(x) for x in pn_invalid_static_bits]) # Insert info with pytest.raises(Exception, match=".*Invalid PN static field.*"): test_firefly = FireFly()
def _get_interface(select_line, default_address, log_instance=None): """ Attempt to automatically determine the interface type (QSFP+ or CXP) that is being used by the FireFly device at a given I2C address, using a given select line (if used). :param select_line: gpiod Line being used for CS. Provide with gpio_bus or gpiod. :param default_address: The address to use when attempting to communicate. Most likely this is the default (0x50) since the device has not been configured. :param log_instance: Because this is a static method, the self._log must be passed in for logging to work. :return: Interface type (FireFly.INTERFACE_*) or None if it could not be determined automatically. """ # Assuming the device is currently on the default address, and OUI is 0x40C880 tempdevice = I2CDevice(default_address) if select_line is not None: # Check GPIO control is available if not _GPIO_AVAIL: raise I2CException( "GPIO control is not available, cannot use CS line") # Check select_line is valid try: if not select_line.is_requested(): raise I2CException( "GPIO Line supplied is not requested by user") except AttributeError: raise I2CException( "Supplied line was not a valid object. Use gpiod or odin_devices.gpio_bus" ) # GPIO select line low select_line.set_value(0) # Force the page to 0x00 tempdevice.write8(127, 0x00) # Read bytes 168, 169, 170 cxp_oui = tempdevice.readList(168, 3) # Read bytes 165, 166, 167 qsfp_oui = tempdevice.readList(165, 3) if select_line is not None: # GPIO select line high select_line.set_value(1) if log_instance is not None: log_instance.debug( "Reading OUI fields from device at {}: CXP OUI {}, QSFP OUI {}" .format(default_address, cxp_oui, qsfp_oui)) if cxp_oui == [0x04, 0xC8, 0x80]: # OUI found correctly, must be CXP device return FireFly.INTERFACE_CXP elif qsfp_oui == [0x04, 0xC8, 0x80]: # OUI found correctly, must be QSFP interface return FireFly.INTERFACE_QSFP else: if log_instance is not None: log_instance.critical( "OUI not found during automatic detection") return None