Esempio n. 1
0
def test_read_conversion(patch_pigpio_i2c, mock_i2c_hardware, ads1x15, seed):
    """_________________________________________________________________________________________________________TEST #10
    Tests that the proper cfg is generated and written to the config register given kwargs, and tests that the
        conversion register is properly read & converted to signed int
    """
    random.seed(seed)
    kwargs = {
        "MUX": random.choice(ads1x15._CONFIG_VALUES[1]),
        "PGA": random.choice(ads1x15._CONFIG_VALUES[2]),
        "MODE": random.choice(ads1x15._CONFIG_VALUES[3]),
        "DR": random.choice(ads1x15._CONFIG_VALUES[4])
    }
    conversion_bytes = token_bytes(2)
    expected_val = int.from_bytes(conversion_bytes, 'big',
                                  signed=True) * kwargs['PGA'] / 32767
    mock = mock_i2c_hardware(i2c_bus=1,
                             i2c_address=ads1x15._DEFAULT_ADDRESS,
                             n_registers=4,
                             reg_values=[conversion_bytes, b'\x85\x83'])
    pig = PigpioConnection()
    pig.add_mock_hardware(mock['device'], mock['i2c_address'], mock['i2c_bus'])
    ads = ads1x15(pig=pig)

    expected_default_config = ads.config.unpack(0xC3E3)
    expected_config = ads.config.unpack(ads.config.pack(0xC3E3, **kwargs))
    assert ads.print_config() == expected_default_config
    result = ads.read_conversion(**kwargs)
    assert ads.print_config() == expected_config
    assert result == expected_val
    """__________________________________________________________________________________________________________
def test_analog_sensor_average_read(patch_pigpio_i2c, mock_i2c_hardware, ads1x15, seed):
    """__________________________________________________________________________________________________________TEST #6
    Performs a several updates before averaging AnalogSensor.data to determine if the result matches expectations
        - Data loaded into the conversion register is gaussian normal about the expected value
    """
    random.seed(seed)
    pga = random.choice(ads1x15._CONFIG_VALUES[2])

    kwargs = {
        "MUX": random.choice(ads1x15._CONFIG_VALUES[1]),
        "PGA": pga,
        "MODE": random.choice(ads1x15._CONFIG_VALUES[3]),
        "DR": random.choice(ads1x15._CONFIG_VALUES[4]),
        'offset_voltage': round(random.uniform(-0.35, 0.35) * pga, 2),
        'output_span': round(random.uniform(.75, 1.0) * pga, 2),
        'conversion_factor': round(random.choice([-1, 1]) * random.uniform(1, 10), 2)
    }

    mock = mock_i2c_hardware(
        i2c_bus=1,
        i2c_address=ads1x15._DEFAULT_ADDRESS,
        n_registers=4,
        reg_values=[b'\x00\x00', b'\x85\x83']
    )

    def voltage(bytes_value):
        val = int.from_bytes(bytes_value, 'big', signed=True)
        result = val*kwargs['PGA'] / 32767
        return result

    def gaussian_bytes(mu):
        def _gauss():
            val = random.gauss(mu, mu/1000)
            result = int(round(val)).to_bytes(2, 'big')
            return result
        return _gauss

    n_iter = 1000
    target = random.randint(1000, 20000)

    pig = PigpioConnection()
    pig.add_mock_hardware(mock['device'], mock['i2c_address'], mock['i2c_bus'])
    ads = ads1x15(pig=pig)
    a_sensor = AnalogSensor(ads, **kwargs)
    a_sensor.maxlen_data = n_iter
    gauss_cannon = gaussian_bytes(target)
    bytes_data = [gauss_cannon() for _ in range(n_iter)]
    avg_voltage = np.mean([voltage(byt) for byt in bytes_data])
    expected_value = kwargs['conversion_factor'] * (avg_voltage - kwargs['offset_voltage']) / kwargs['output_span']

    for i in range(n_iter):
        pig.mock_i2c[1][mock['i2c_address']].write_mock_hardware_register(0, bytes_data[i])
        a_sensor.update()
    data = a_sensor.data
    result_0 = a_sensor.get(average=True)
    result_1 = data[:, 1].mean()
    assert len(data) == n_iter
    assert result_0 - result_1 < 0.1
    assert result_0 - expected_value < 0.1
    """__________________________________________________________________________________________________________
Esempio n. 3
0
def test_mock_pigpio_base(patch_pigpio_base):
    """__________________________________________________________________________________________________________TEST #1
    Tests that the base fixture of pigpio mocks is indeed enough to instantiate pigpio.pi()
    """
    pig = PigpioConnection()
    assert isinstance(pig, pigpio.pi)
    assert pig.connected
    pig.stop()
    assert not pig.connected
    """__________________________________________________________________________________________________________
def test_analog_sensor_single_read_drop_kwargs(patch_pigpio_i2c, mock_i2c_hardware, ads1x15, seed):
    """__________________________________________________________________________________________________________TEST #4
    Same as the above test, except it will randomly drop kwargs to check that the default attributes are
        properly filled in and that the read functions normally.
        - Note: calibration values are stored seperately s.t. the later verification of the result can be calculated
         even without the store the default calibration for later conversion.
    """
    random.seed(seed)
    kwargs = {
        "MUX": random.choice(ads1x15._CONFIG_VALUES[1]),
        "PGA": random.choice(ads1x15._CONFIG_VALUES[2]),
        "MODE": random.choice(ads1x15._CONFIG_VALUES[3]),
        "DR": random.choice(ads1x15._CONFIG_VALUES[4]),
        'offset_voltage': 0,
        'output_span': 5,
        'conversion_factor': 10
    }
    kw_copy = kwargs.copy()
    for field in kw_copy:
        if random.getrandbits(1) and field is not "MUX":
            del kwargs[field]
            kw_copy[field] = dict(**ads1x15._DEFAULT_VALUES, **AnalogSensor._DEFAULT_CALIBRATION)[field]

    mock = mock_i2c_hardware(
        i2c_bus=1,
        i2c_address=ads1x15._DEFAULT_ADDRESS,
        n_registers=4,
        reg_values=[
            b'\x00\x00',
            b'\x85\x83'
        ]
    )
    pig = PigpioConnection()
    pig.add_mock_hardware(mock['device'], mock['i2c_address'], mock['i2c_bus'])
    ads = ads1x15(pig=pig)
    a_sensor = AnalogSensor(ads, **kwargs)
    n_iter = 250
    conversion_bytes = [token_bytes(2) for _ in range(n_iter)]
    raw_voltage = [int.from_bytes(cb, 'big', signed=True) * kw_copy['PGA'] / 32767 for cb in conversion_bytes]
    expected = [
        kw_copy['conversion_factor'] * (rv - kw_copy['offset_voltage']) / kw_copy['output_span'] for rv in raw_voltage
    ]
    for i in range(n_iter):
        pig.mock_i2c[1][mock['i2c_address']].write_mock_hardware_register(0, conversion_bytes[i])
        result = a_sensor.get()
        assert round(result, 9) == round(expected[i], 9)
    """__________________________________________________________________________________________________________
Esempio n. 5
0
def test_pigpio_connection_exception(patch_pigpio_base, patch_bad_socket):
    """__________________________________________________________________________________________________________TEST #2
    Tests to make sure an exception is thrown if, upon init, a PigpioConnection finds it is not connected.
    """
    with pytest.raises(RuntimeError):
        PigpioConnection()
    with pytest.raises(RuntimeError):
        IODeviceBase()
def test_analog_sensor_single_read(patch_pigpio_i2c, mock_i2c_hardware, ads1x15, seed, pga, mode):
    """__________________________________________________________________________________________________________TEST #3
    Tests the proper functioning of an AnalogSensor with random, but plausible, calibration.

    - Performs a sequence of observations and verifies that each matches expectations and that the age of each reading
        properly reflects called updates
    """
    random.seed(seed)
    kwargs = {
        "MUX": random.choice(ads1x15._CONFIG_VALUES[1]),
        "PGA": pga,
        "MODE": mode,
        "DR": random.choice(ads1x15._CONFIG_VALUES[4]),
        'offset_voltage': round(random.uniform(-0.35, 0.35) * pga, 2),
        'output_span': round(random.uniform(.75, 1.0) * pga, 2),
        'conversion_factor': round(random.choice([-1, 1]) * random.uniform(1, 10), 2)
    }
    mock = mock_i2c_hardware(
        i2c_bus=1,
        i2c_address=ads1x15._DEFAULT_ADDRESS,
        n_registers=4,
        reg_values=[
            b'\x00\x00',
            b'\x85\x83'
        ]
    )
    pig = PigpioConnection()
    pig.add_mock_hardware(mock['device'], mock['i2c_address'], mock['i2c_bus'])
    ads = ads1x15(pig=pig)
    a_sensor = AnalogSensor(ads, **kwargs)
    n_iter = 250
    conversion_bytes = [token_bytes(2) for _ in range(n_iter)]
    raw_voltage = [int.from_bytes(cb, 'big', signed=True) * kwargs['PGA'] / 32767 for cb in conversion_bytes]
    expected = [
        kwargs['conversion_factor'] * (rv - kwargs['offset_voltage']) / kwargs['output_span'] for rv in raw_voltage
    ]
    for i in range(n_iter):
        pig.mock_i2c[1][mock['i2c_address']].write_mock_hardware_register(0, conversion_bytes[i])
        result = a_sensor.get()
        assert round(result, 9) == round(expected[i], 9)
    """__________________________________________________________________________________________________________
def test_analog_sensor_kwarg_exceptions(patch_pigpio_i2c, mock_i2c_hardware, ads1x15, seed, pga, mode):
    """__________________________________________________________________________________________________________TEST #5
    Tests that an exception is properly raised when either:
        - a kwarg is passed that it unrecognized
        - MUX is not passed in kwargs
    """
    random.seed(seed)
    kwargs = {
        "MUX": random.choice(ads1x15._CONFIG_VALUES[1]),
        "PGA": pga,
        "MODE": mode,
        "DR": random.choice(ads1x15._CONFIG_VALUES[4]),
        'offset_voltage': round(random.uniform(-0.35, 0.35) * pga, 2),
        'output_span': round(random.uniform(.75, 1.0) * pga, 2),
        'conversion_factor': round(random.choice([-1, 1]) * random.uniform(1, 10), 2)
    }
    mock = mock_i2c_hardware(
        i2c_bus=1,
        i2c_address=ads1x15._DEFAULT_ADDRESS,
        n_registers=4,
        reg_values=[
            b'\x00\x00',
            b'\x85\x83'
        ]
    )
    pig = PigpioConnection()
    pig.add_mock_hardware(mock['device'], mock['i2c_address'], mock['i2c_bus'])
    ads = ads1x15(pig=pig)
    with pytest.raises(TypeError):
        bad_kwargs = kwargs.copy()
        bad_kwargs['bad_key'] = 'bad_value'
        AnalogSensor(ads, **bad_kwargs)
    with pytest.raises(TypeError):
        bad_kwargs = kwargs.copy()
        del bad_kwargs['MUX']
        AnalogSensor(ads, **bad_kwargs)
    """__________________________________________________________________________________________________________
Esempio n. 8
0
def test_i2c_device(patch_pigpio_i2c, mock_i2c_hardware, seed):
    """__________________________________________________________________________________________________________TEST #5
    Tests the various basic I2CDevice methods, open, close, read,  write, etc.
        - Note: i2c_device.read_device() returns raw bytes (assumed to have big-endian ordering.) read_register, on the
        other hand, returns the integer representation of those bytes. write_device and write_register take an integer
        argument which is the written to the device register as a big-endian two's complement.
        - The RPi is native little endian, so to simulate/test the byte-swapping that occurs over I2C we generate a
        random 16-bit integer (`data`), write it to the register, and read it back.
        - If the int->byte-> int conversions in i2c_device are working correctly, we should expect one of two possible
         values to be returned (depending on whether read_device() or read_register() is called)
            - read_device() should return the big-endian two's complement of `data`
            - read_register() should just return `data`
    """
    results = []
    random.seed(seed)
    mock = mock_i2c_hardware()
    n_registers = len(mock['values'])
    data = [random.getrandbits(15) for _ in range(n_registers)]
    signed = random.getrandbits(1)
    expected = [data[0].to_bytes(2, 'big', signed=signed)
                ] if n_registers == 1 else data
    pig = PigpioConnection()
    pig.add_mock_hardware(mock['device'], mock['i2c_address'], mock['i2c_bus'])
    i2c_device = I2CDevice(mock['i2c_address'], mock['i2c_bus'], pig=pig)
    assert i2c_device.pigpiod_ok
    if n_registers == 1:
        i2c_device.write_device(data[0], signed=signed)
        results.append(i2c_device.read_device()[1])
    else:
        for register in range(n_registers):
            i2c_device.write_register(register, data[register], signed=signed)
            results.append(i2c_device.read_register(register, signed=signed))
    i2c_device._close()
    assert not i2c_device._pig.mock_i2c[mock['i2c_bus']]
    assert results == expected
    """__________________________________________________________________________________________________________
def test_sfm_single_read(patch_pigpio_i2c, mock_i2c_hardware, seed):
    """__________________________________________________________________________________________________________TEST #7
    Tests the proper functioning of an SFM sensor. similar to single read of analog sensor, except starts with 4 bytes
        in the register and discards two (just like in real life)
    """
    random.seed(seed)
    mock = mock_i2c_hardware(
        i2c_bus=1,
        i2c_address=SFM3200._DEFAULT_ADDRESS,
        reg_values=[b'\x00\x00']
    )
    pig = PigpioConnection()
    pig.add_mock_hardware(mock['device'], mock['i2c_address'], mock['i2c_bus'])
    sfm = SFM3200(address=mock['i2c_address'], i2c_bus=mock['i2c_bus'], pig=pig)

    n_iter = random.randint(100, 1000)
    conversion_bytes = [token_bytes(4) for _ in range(n_iter)]
    raw_int = [int.from_bytes(cb[:2], 'big') for cb in conversion_bytes]
    expected = [(rv - sfm._FLOW_OFFSET) / sfm._FLOW_SCALE_FACTOR for rv in raw_int]
    for i in range(n_iter):
        pig.mock_i2c[1][mock['i2c_address']].write_mock_hardware_register(0, conversion_bytes[i])
        result = sfm.get()
        assert round(result, 10) == round(expected[i], 10)
    """__________________________________________________________________________________________________________
Esempio n. 10
0
def test_mock_pigpio_i2c(patch_pigpio_i2c, mock_i2c_hardware, seed):
    """__________________________________________________________________________________________________________TEST #4
    Tests the functionality of the mock pigpio i2c device interface. More specifically, tests that:
    - mock hardware devices are initialized correctly
    - mock handles, i2c_open(), and i2c_close() can be used to add, interact with, and remove mock hardware devices
        - correct functioning of i2c_open is implied by the read/write tests
        - the correct functioning of i2c_close() is ascertained from the assertion that pig.mock_i2c[i2c_bus] is empty
    - mock i2c read and write functions work as intended:
        - This is three tests in one. For each register of each mock hardware device:
            1) Read the register with i2c_read and store the result in results['init']. We expect it to be the value
            from the correct register of the matching mock_device (expected['init'])
            2) Write two random bytes to the register with i2c_write. Look at the actual contents of the target register
                and put them in results['write']. We expect them to be the same as the two random bytes we generated.
            3) Read the register with i2c_read again and put the results in expected['read']. These should also match
                the two random bytes from the 'write' test.
            -> Assert that the results match what we expect
    - if there is only one register on the device, test read_device() and write_device() instead of read_register()
        and write_register() -> this matches how such a device would be interacted with in practice.
    """
    random.seed(seed)
    n_devices = random.randint(1, 20)
    address_pool = random.sample(range(128), k=n_devices)
    pig = PigpioConnection()
    mocks = []
    for i in range(n_devices):
        mock = mock_i2c_hardware(i2c_address=address_pool.pop())
        pig.add_mock_hardware(mock['device'], mock['i2c_address'],
                              mock['i2c_bus'])
        mock['handle'] = pig.i2c_open(mock['i2c_bus'], mock['i2c_address'])
        mocks.append(mock)
    for mock_device in mocks:
        handle = mock_device['handle']
        bus = mock_device['i2c_bus']
        address = mock_device['i2c_address']
        results = {'init': [], 'write': [], 'read': []}
        expected = {'init': [], 'write': [], 'read': []}
        for reg in range(len(mock_device['values'])):
            expected['init'] = mock_device['values'][reg]
            expected['write'] = token_bytes(2)
            expected['read'] = expected['write']
            if len(mock_device['values']) == 1:
                results['init'] = pig.i2c_read_device(handle, 2)[1]
                pig.i2c_write_device(handle, expected['write'])
                results['write'] = pig.mock_i2c[bus][address].registers[0][-1]
                results['read'] = pig.i2c_read_device(handle, 2)[1]
            else:
                results['init'] = pig.i2c_read_i2c_block_data(handle,
                                                              reg,
                                                              count=2)[1]
                pig.i2c_write_i2c_block_data(handle, reg, expected['write'])
                results['write'] = pig.mock_i2c[bus][address].registers[reg][
                    -1]
                results['read'] = pig.i2c_read_i2c_block_data(handle,
                                                              reg,
                                                              count=2)[1]
            assert results == expected
        pig.i2c_close(handle)
    assert not pig.mock_i2c[0]
    assert not pig.mock_i2c[1]
    assert not pig.mock_i2c['spi']
    """__________________________________________________________________________________________________________