n2k_base/n2k/header/
mod.rs

1/// An N2kHeader is just a u32, created using the right fields.
2#[derive(Debug, PartialEq, Clone, Copy)]
3pub struct N2kHeader(u32);
4
5impl N2kHeader {
6    /// create an N2kHeader
7    pub fn new(priority: u8, source: u8, destination: u8, pgn: u32) -> N2kHeader {
8        // TODO: asserts on incoming values (maybe even Result<N2kHeader>)
9        let mut id = (priority as u32) << 26 | (pgn << 8) | source as u32;
10
11        let pdu_format = (pgn >> 8) as u8;
12
13        if pdu_format < 240 {
14            //addressable, thus set the destination
15            id = id | ((destination as u32) << 8);
16        }
17        N2kHeader(id)
18    }
19
20    pub fn from_raw(raw_id: u32) -> N2kHeader {
21        N2kHeader(raw_id)
22    }
23}
24
25/// automatic conversion into a u32
26impl Into<u32> for N2kHeader {
27    fn into(self) -> u32 {
28        self.0
29    }
30}
31
32/// Basic trait to derive N2k header data. Usually the header is just a simple u32.
33/// Implementation provided below.
34pub trait N2kHeaderDecoder {
35    fn get_pgn(&self) -> u32;
36    fn get_source(&self) -> u8;
37    fn get_destination(&self) -> u8;
38    fn get_priority(&self) -> u8;
39}
40
41impl N2kHeaderDecoder for N2kHeader {
42    fn get_pgn(&self) -> u32 {
43        let pf = get_pdu_format(&self.0);
44        let pdu_specific = get_pdu_specific(&self.0);
45        let dp = get_data_page(&self.0);
46
47        if pf < 240 {
48            (dp as u32) << 16 | (pf as u32) << 8
49        } else {
50            (dp as u32) << 16 | (pf as u32) << 8 | pdu_specific as u32
51        }
52    }
53
54    fn get_source(&self) -> u8 {
55        self.0 as u8
56    }
57
58    fn get_destination(&self) -> u8 {
59        let pf = get_pdu_format(&self.0);
60        let ps = get_pdu_specific(&self.0);
61        if pf < 240 {
62            ps
63        } else {
64            0xFF
65        }
66    }
67
68    fn get_priority(&self) -> u8 {
69        ((self.0 >> 26) & 0x7) as u8
70    }
71}
72
73
74fn get_pdu_specific(id: &u32) -> u8 {
75    (id >> 8) as u8
76}
77
78fn get_pdu_format(id: &u32) -> u8 {
79    (id >> 16) as u8
80}
81
82fn get_data_page(id: &u32) -> u8 {
83    ((id >> 24) & 1 as u32) as u8
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89
90    #[test]
91    fn read_iso_address_claim_header() {
92        let id = N2kHeader(0x18EEFF0A);
93        assert_eq!(id.get_source(), 10);
94        assert_eq!(id.get_pgn(), 60928);
95        assert_eq!(id.get_destination(), 255);
96        assert_eq!(id.get_priority(), 6);
97    }
98
99    #[test]
100    fn read_wind_data_header() {
101        let id = N2kHeader(0x09FD020A);
102
103        assert_eq!(id.get_source(), 10);
104        assert_eq!(id.get_pgn(), 130306);
105        assert_eq!(id.get_destination(), 255);
106        assert_eq!(id.get_priority(), 2);
107    }
108
109    #[test]
110    fn create_iso_address_claim_header() {
111        let id = N2kHeader::new(
112            6,
113            10,
114            255,
115            60928,
116        );
117
118        assert_eq!(id, N2kHeader(0x18EEFF0A));
119        assert_eq!(id.get_source(), 10);
120        assert_eq!(id.get_pgn(), 60928);
121        assert_eq!(id.get_destination(), 255);
122        assert_eq!(id.get_priority(), 6);
123    }
124
125    #[test]
126    fn create_wind_data_header() {
127        let id = N2kHeader::new(
128            2,
129            10,
130            255,
131            130306,
132        );
133        assert_eq!(id, N2kHeader(0x09FD020A));
134        assert_eq!(id.get_source(), 10);
135        assert_eq!(id.get_pgn(), 130306);
136        assert_eq!(id.get_destination(), 255);
137        assert_eq!(id.get_priority(), 2);
138    }
139}