Skip to main content

simple_someip/protocol/sd/
flags.rs

1const REBOOT_FLAG: u8 = 0b1000_0000;
2const UNICAST_FLAG: u8 = 0b0100_0000;
3
4/// Whether the sender has recently rebooted, as encoded in the SOME/IP-SD flags byte.
5///
6/// Per AUTOSAR SOME/IP-SD, this flag is set to [`RebootFlag::RecentlyRebooted`] from
7/// startup until the session counter wraps from `0xFFFF` to `1`, then permanently
8/// cleared to [`RebootFlag::Continuous`].
9#[derive(Clone, Copy, Debug, Eq, PartialEq)]
10pub enum RebootFlag {
11    /// Sender has recently rebooted; session counter has not yet wrapped.
12    RecentlyRebooted,
13    /// Sender is running continuously; session counter has wrapped at least once.
14    Continuous,
15}
16
17impl From<bool> for RebootFlag {
18    fn from(b: bool) -> Self {
19        if b {
20            Self::RecentlyRebooted
21        } else {
22            Self::Continuous
23        }
24    }
25}
26
27impl From<RebootFlag> for bool {
28    fn from(r: RebootFlag) -> Self {
29        matches!(r, RebootFlag::RecentlyRebooted)
30    }
31}
32
33/// Flags byte in the SD protocol.
34#[derive(Clone, Copy, Debug, Eq, PartialEq)]
35pub struct Flags {
36    reboot: bool,
37    unicast: bool,
38}
39
40impl From<u8> for Flags {
41    /// Only the two most significant bits are used.
42    fn from(value: u8) -> Self {
43        Self {
44            reboot: value & REBOOT_FLAG != 0,
45            unicast: value & UNICAST_FLAG != 0,
46        }
47    }
48}
49
50impl From<Flags> for u8 {
51    fn from(flags: Flags) -> u8 {
52        let mut value = 0;
53        if flags.reboot {
54            value |= REBOOT_FLAG;
55        }
56        if flags.unicast {
57            value |= UNICAST_FLAG;
58        }
59        value
60    }
61}
62
63impl Flags {
64    /// Creates flags with the given reboot and unicast values.
65    #[must_use]
66    pub const fn new(reboot: bool, unicast: bool) -> Self {
67        Self { reboot, unicast }
68    }
69    /// Creates SD flags with unicast always set to `true`.
70    #[must_use]
71    pub fn new_sd(reboot: RebootFlag) -> Self {
72        Self {
73            reboot: bool::from(reboot),
74            unicast: true,
75        }
76    }
77    /// Returns the reboot flag.
78    #[must_use]
79    pub fn reboot(self) -> RebootFlag {
80        RebootFlag::from(self.reboot)
81    }
82    /// Returns `true` if the unicast flag is set.
83    #[must_use]
84    pub const fn unicast(self) -> bool {
85        self.unicast
86    }
87}
88
89#[cfg(test)]
90mod tests {
91    use super::*;
92
93    #[test]
94    fn new_sd_sets_unicast_true() {
95        let flags = Flags::new_sd(RebootFlag::Continuous);
96        assert_eq!(flags.reboot(), RebootFlag::Continuous);
97        assert!(flags.unicast());
98    }
99
100    #[test]
101    fn new_sd_with_reboot_true() {
102        let flags = Flags::new_sd(RebootFlag::RecentlyRebooted);
103        assert_eq!(flags.reboot(), RebootFlag::RecentlyRebooted);
104        assert!(flags.unicast());
105    }
106
107    #[test]
108    fn unicast_accessor() {
109        assert!(Flags::new(false, true).unicast());
110        assert!(!Flags::new(false, false).unicast());
111    }
112
113    #[test]
114    fn roundtrip_both_flags_set() {
115        let flags = Flags::new(true, true);
116        let byte: u8 = flags.into();
117        let back = Flags::from(byte);
118        assert_eq!(flags, back);
119        assert_eq!(byte, 0b1100_0000);
120    }
121
122    #[test]
123    fn roundtrip_no_flags_set() {
124        let flags = Flags::new(false, false);
125        let byte: u8 = flags.into();
126        assert_eq!(byte, 0);
127        let back = Flags::from(byte);
128        assert_eq!(flags, back);
129    }
130}