tmp1x2 1.1.0

Platform-agnostic Rust driver for the TMP102 and TMP112 digital temperature sensors.
Documentation
use embedded_hal_mock::eh1::i2c::Transaction as I2cTransaction;

mod common;
use common::{
    setup, BitFlagsHigh as BFH, BitFlagsLow as BFL, Register, DEFAULT_CONFIG_LSB,
    DEFAULT_CONFIG_MSB, DEVICE_ADDRESS,
};

fn get_expectation(register: u8, lsb: u8, msb: u8) -> [I2cTransaction; 1] {
    [I2cTransaction::write_read(
        DEVICE_ADDRESS,
        vec![register],
        vec![msb, lsb],
    )]
}

macro_rules! read_test {
    ($name:ident, $method:ident, $register:ident, $lsb:expr, $msb:expr, $expected:expr) => {
        #[maybe_async_cfg::maybe(
            sync(cfg(not(feature = "async")), test),
            async(feature = "async", tokio::test)
        )]
        async fn $name() {
            let expectations = get_expectation(Register::$register, $lsb, $msb);
            let mut dev = setup(&expectations);
            let value = dev.$method().await.unwrap();
            assert_eq!($expected, value);
            dev.destroy().done();
        }
    };
}

read_test!(
    comp_alert_not_active,
    is_comparator_mode_alert_active,
    CONFIG,
    DEFAULT_CONFIG_LSB | BFL::ALERT,
    DEFAULT_CONFIG_MSB,
    false
);
read_test!(
    comp_alert_active,
    is_comparator_mode_alert_active,
    CONFIG,
    DEFAULT_CONFIG_LSB & !BFL::ALERT,
    DEFAULT_CONFIG_MSB,
    true
);

read_test!(
    comp_alert_not_active_high_pol,
    is_comparator_mode_alert_active,
    CONFIG,
    DEFAULT_CONFIG_LSB & !BFL::ALERT,
    DEFAULT_CONFIG_MSB | BFH::ALERT_POLARITY,
    false
);
read_test!(
    comp_alert_active_high_pol,
    is_comparator_mode_alert_active,
    CONFIG,
    DEFAULT_CONFIG_LSB | BFL::ALERT,
    DEFAULT_CONFIG_MSB | BFH::ALERT_POLARITY,
    true
);

macro_rules! assert_near {
    ($left:expr, $right:expr) => {
        assert!(($left - $right) < core::f32::EPSILON && ($right - $left) < core::f32::EPSILON);
    };
}

#[maybe_async_cfg::maybe(
    sync(cfg(not(feature = "async")), test),
    async(feature = "async", tokio::test)
)]
async fn in_one_shot_read_temperature_triggers_measurement() {
    let expectations = [
        I2cTransaction::write(
            DEVICE_ADDRESS,
            vec![
                Register::CONFIG,
                DEFAULT_CONFIG_MSB | BFH::SHUTDOWN,
                DEFAULT_CONFIG_LSB,
            ],
        ),
        I2cTransaction::write(
            DEVICE_ADDRESS,
            vec![
                Register::CONFIG,
                DEFAULT_CONFIG_MSB | BFH::ONE_SHOT | BFH::SHUTDOWN,
                DEFAULT_CONFIG_LSB,
            ],
        ),
    ];
    let dev = setup(&expectations);
    let mut dev = dev.into_one_shot().await.unwrap();
    match dev.read_temperature().await {
        Err(nb::Error::WouldBlock) => (),
        _ => panic!(),
    }
    dev.destroy().done();
}

#[maybe_async_cfg::maybe(
    sync(cfg(not(feature = "async")), test),
    async(feature = "async", tokio::test)
)]
async fn in_one_shot_read_temperature_returns_would_block_if_not_ready() {
    let expectations = [
        I2cTransaction::write(
            DEVICE_ADDRESS,
            vec![
                Register::CONFIG,
                DEFAULT_CONFIG_MSB | BFH::SHUTDOWN,
                DEFAULT_CONFIG_LSB,
            ],
        ),
        I2cTransaction::write(
            DEVICE_ADDRESS,
            vec![
                Register::CONFIG,
                DEFAULT_CONFIG_MSB | BFH::ONE_SHOT | BFH::SHUTDOWN,
                DEFAULT_CONFIG_LSB,
            ],
        ),
        I2cTransaction::write_read(
            DEVICE_ADDRESS,
            vec![Register::CONFIG],
            vec![DEFAULT_CONFIG_MSB, DEFAULT_CONFIG_LSB],
        ),
    ];
    let dev = setup(&expectations);
    let mut dev = dev.into_one_shot().await.unwrap();
    dev.read_temperature()
        .await
        .expect_err("Should return an error");
    match dev.read_temperature().await {
        Err(nb::Error::WouldBlock) => (),
        _ => panic!(),
    }
    dev.destroy().done();
}

#[maybe_async_cfg::maybe(
    sync(cfg(not(feature = "async")), test),
    async(feature = "async", tokio::test)
)]
async fn in_one_shot_can_read_temperature() {
    let expectations = [
        I2cTransaction::write(
            DEVICE_ADDRESS,
            vec![
                Register::CONFIG,
                DEFAULT_CONFIG_MSB | BFH::SHUTDOWN,
                DEFAULT_CONFIG_LSB,
            ],
        ),
        I2cTransaction::write(
            DEVICE_ADDRESS,
            vec![
                Register::CONFIG,
                DEFAULT_CONFIG_MSB | BFH::ONE_SHOT | BFH::SHUTDOWN,
                DEFAULT_CONFIG_LSB,
            ],
        ),
        I2cTransaction::write_read(
            DEVICE_ADDRESS,
            vec![Register::CONFIG],
            vec![DEFAULT_CONFIG_MSB | BFH::ONE_SHOT, DEFAULT_CONFIG_LSB],
        ),
        I2cTransaction::write_read(
            DEVICE_ADDRESS,
            vec![Register::TEMPERATURE],
            vec![0b0110_0100, 0],
        ),
    ];
    let dev = setup(&expectations);
    let mut dev = dev.into_one_shot().await.unwrap();
    dev.read_temperature()
        .await
        .expect_err("Should return an error");
    let temp = dev.read_temperature().await.unwrap();
    assert_near!(100.0, temp);
    dev.destroy().done();
}

#[maybe_async_cfg::maybe(
    sync(cfg(not(feature = "async")), test),
    async(feature = "async", tokio::test)
)]
async fn in_continuous_can_read_temperature() {
    let expectations = [I2cTransaction::write_read(
        DEVICE_ADDRESS,
        vec![Register::TEMPERATURE],
        vec![0b0110_0100, 0],
    )];
    let mut dev = setup(&expectations);
    let value = dev.read_temperature().await.unwrap();
    assert_near!(100.0, value);
    dev.destroy().done();
}