rsiot/drivers_i2c/ds3231/data_models/
hour.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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use bitvec::{order::Lsb0, view::BitView};

pub struct Hour(u8);

impl Hour {
    pub fn new_from_bcd(raw: u8) -> Self {
        let raw_bits = raw.view_bits::<Lsb0>();

        let hour_base = 10 * (raw_bits[4] as u8)
            + 8 * (raw_bits[3] as u8)
            + 4 * (raw_bits[2] as u8)
            + 2 * (raw_bits[1] as u8)
            + (raw_bits[0] as u8);
        let hour_base = hour_base as i32;

        let hour_add = if raw_bits[6] {
            // 12-часовой формат
            if raw_bits[5] {
                // PM
                if hour_base != 12 {
                    12
                } else {
                    0
                }
            } else {
                // AM
                if hour_base == 12 {
                    -12
                } else {
                    0
                }
            }
        } else {
            // 24 часовой формат
            if raw_bits[5] {
                20
            } else {
                0
            }
        };

        let hour = (hour_base + hour_add) as u8;

        Self(hour)
    }

    pub fn new_from_dec(value: u8) -> Self {
        Self(value)
    }

    pub fn get_bcd(&self) -> u8 {
        let mut dec = self.0;

        let mut bcd = 0_u8;
        let bcd_bits = bcd.view_bits_mut::<Lsb0>();

        if dec >= 20 {
            bcd_bits.set(5, true);
            dec -= 20;
        }
        if dec >= 10 {
            bcd_bits.set(4, true);
            dec -= 10;
        }
        if dec >= 8 {
            bcd_bits.set(3, true);
            dec -= 8;
        }
        if dec >= 4 {
            bcd_bits.set(2, true);
            dec -= 4;
        }
        if dec >= 2 {
            bcd_bits.set(1, true);
            dec -= 2;
        }
        if dec >= 1 {
            bcd_bits.set(0, true);
        }
        bcd
    }

    pub fn get_dec(&self) -> u8 {
        self.0
    }
}

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

    /// Запуск:
    ///
    /// ```bash
    /// cargo test --target x86_64-unknown-linux-gnu --lib --features cmp_esp -- drivers_i2c::ds3231::data_models::hour::tests::test_bcd_to_dec --exact --show-output
    /// ```
    #[test]
    fn test_bcd_to_dec() {
        assert_eq!(0, Hour::new_from_bcd(0b0000_0000).get_dec());
        assert_eq!(1, Hour::new_from_bcd(0b0000_0001).get_dec());
        assert_eq!(8, Hour::new_from_bcd(0b0000_1000).get_dec());
        assert_eq!(10, Hour::new_from_bcd(0b0001_0000).get_dec());
        assert_eq!(12, Hour::new_from_bcd(0b0001_0010).get_dec());
        assert_eq!(13, Hour::new_from_bcd(0b0001_0011).get_dec());
        assert_eq!(20, Hour::new_from_bcd(0b0010_0000).get_dec());
        assert_eq!(23, Hour::new_from_bcd(0b0010_0011).get_dec());
    }

    /// Запуск:
    ///
    /// ```bash
    /// cargo test --target x86_64-unknown-linux-gnu --lib --features cmp_esp -- drivers_i2c::ds3231::data_models::hour::tests::test_dec_to_bcd --exact --show-output
    /// ```
    #[test]
    fn test_dec_to_bcd() {
        assert_eq!(0b0000_0000, Hour::new_from_dec(0).get_bcd());
        assert_eq!(0b0000_0001, Hour::new_from_dec(1).get_bcd());
        assert_eq!(0b0000_1000, Hour::new_from_dec(8).get_bcd());
        assert_eq!(0b0001_0000, Hour::new_from_dec(10).get_bcd());
        assert_eq!(0b0001_0010, Hour::new_from_dec(12).get_bcd());
        assert_eq!(0b0001_0011, Hour::new_from_dec(13).get_bcd());
        assert_eq!(0b0010_0000, Hour::new_from_dec(20).get_bcd());
        assert_eq!(0b0010_0011, Hour::new_from_dec(23).get_bcd());
    }
}