rsiot/drivers_i2c/pcf8575/
state.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
use std::{fmt::Binary, sync::Arc};

use tokio::sync::Mutex;

#[derive(Clone)]
pub struct State {
    state: Arc<Mutex<u16>>,
}

impl State {
    pub fn new() -> Self {
        Self {
            state: Arc::new(Mutex::new(0)),
        }
    }

    /// Переключить работу пина в режим входа
    pub async fn set_input(&mut self, pin_index: usize) {
        self.set_output_low(pin_index).await;
    }

    /// Переключить работу пина в режим выхода в отключенном состоянии
    pub async fn set_output_high(&mut self, pin: usize) {
        let mut state = self.state.lock().await;
        let mask = 1 << pin;
        *state &= !mask;
    }

    /// Переключить работу пина в режим выхода во включенном состоянии
    pub async fn set_output_low(&mut self, pin: usize) {
        let mut state = self.state.lock().await;
        let mask = 1 << pin;
        *state |= mask;
    }

    /// Вернуть конфигурацию в виде двух байт
    pub async fn to_bytes(&self) -> [u8; 2] {
        self.state.lock().await.to_le_bytes()
    }
}

impl Binary for State {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let state = *self.state.blocking_lock();
        write!(f, "{:b}", state)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    /// Запуск:
    ///
    /// ```bash
    /// cargo test --target x86_64-unknown-linux-gnu --lib --features executor -- drivers_i2c::pcf8575::state::tests::test1 --exact --show-output
    /// ```
    #[tokio::test]
    async fn test1() {
        let mut state = State::new();

        state.set_input(3).await;
        assert_eq!(*state.state.lock().await, 8);

        assert_eq!(state.to_bytes().await, [8, 0]);

        state.set_output_high(3).await;
        assert_eq!(*state.state.lock().await, 0);
    }
}