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
126
127
128
use crate::std::{self, fmt};

use crate::{bool_enum, impl_default};

pub mod bitmask {
    pub const SEQUENCE_ID: u8 = 0x7f;
}

bool_enum!(
    SequenceFlag,
    r"
 Each time the master sends a new packet to a device it alternates the sequence flag. If a
 device receives a packet with the same sequence flag as the last one, it does not execute
 the command but simply repeats its last reply. In a reply packet the address and sequence
 flag match the command packet.
"
);

impl SequenceFlag {
    /// Creates a new [SequenceFlag].
    ///
    /// Defaults to unset.
    pub const fn new() -> Self {
        Self::Unset
    }
}

impl_default!(SequenceFlag);

/// A combination of two items of data: the sequence flag (MSB, bit7) and the address of the
/// device (bit 6 to bit 0, LSB).
///
/// For example a SMART Hopper by default has an address of 0x10 (16 decimal). When the
/// sync bit is equal to 1 the byte sent to the Hopper is 0x90. On the next command, the sync
/// bit is toggled, in this case 0, the byte sent would be 0x10.
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct SequenceId {
    flag: SequenceFlag,
    id: u8,
}

impl SequenceId {
    /// Creates a new [SequenceId].
    pub const fn new() -> Self {
        Self {
            flag: SequenceFlag::new(),
            id: 0,
        }
    }

    /// Converts a u8 into a [SequenceId].
    pub const fn from_u8(b: u8) -> Self {
        let flag = SequenceFlag::from_u8(b >> 7);
        let id = b & bitmask::SEQUENCE_ID;

        Self { flag, id }
    }

    /// Creates a [SequenceId] from a [SequenceFlag] and ID.
    pub const fn from_parts(flag: SequenceFlag, id: u8) -> Self {
        Self { flag, id }
    }

    /// Gets the [SequenceFlag].
    pub fn flag(&self) -> SequenceFlag {
        self.flag
    }

    /// Sets the [SequenceFlag].
    pub fn set_flag(&mut self, flag: SequenceFlag) {
        self.flag = flag;
    }

    /// Toggles the value of the [SequenceFlag].
    pub fn toggle_flag(&mut self) {
        self.flag = !self.flag;
    }

    /// Gets the sequence ID.
    pub fn id(&self) -> u8 {
        self.id
    }

    /// Sets the sequence ID.
    pub fn set_id(&mut self, id: u8) {
        self.id = id & bitmask::SEQUENCE_ID;
    }

    /// Increments the sequence ID.
    ///
    /// If the ID reaches the maximum (`0x7F`), incrementing resets the value to zero.
    ///
    /// This is the behavior described in the documentation.
    pub fn increment(&mut self) -> u8 {
        self.id = (self.id + 1) & bitmask::SEQUENCE_ID;

        self.id
    }
}

impl_default!(SequenceId);

impl std::ops::Not for SequenceId {
    type Output = SequenceId;

    fn not(self) -> Self::Output {
        SequenceId::from_parts(!self.flag(), self.id())
    }
}

impl From<u8> for SequenceId {
    fn from(b: u8) -> Self {
        Self::from_u8(b)
    }
}

impl From<SequenceId> for u8 {
    fn from(s: SequenceId) -> Self {
        (u8::from(s.flag) << 7) | (s.id & bitmask::SEQUENCE_ID)
    }
}

impl fmt::Display for SequenceId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "flag({}): 0x{:02x}", self.flag, self.id)
    }
}