taptap/gateway/
link.rs

1//! The gateway link layer.
2
3mod address;
4
5pub use address::{Address, GatewayID, InvalidGatewayID};
6
7mod crc;
8
9mod escaping;
10mod receive;
11pub use receive::{Counters, Receiver, Sink};
12
13/// A gateway link layer frame.
14#[derive(Debug, Clone, Eq, PartialEq)]
15pub struct Frame {
16    pub address: Address,
17    pub frame_type: Type,
18    pub payload: Vec<u8>,
19}
20
21impl Frame {
22    /// Encode the frame into `Bytes` ready for transmission by the physical layer, including a
23    /// preamble.
24    pub fn encode(&self) -> Vec<u8> {
25        let start = match self.address {
26            Address::From(_) => [0xff, 0x7e, 0x07].as_slice(),
27            Address::To(_) => [0x00, 0xff, 0xff, 0x7e, 0x07].as_slice(),
28        };
29        let end = &[0x7e, 0x08];
30
31        let mut output_buffer = Vec::with_capacity(
32            start.len()
33                + 4 // worst case escaped address
34                + 4 // worst case escaped frame type
35                + escaping::escaped_length(&self.payload)
36                + 4 // worst case CRC
37                + end.len(), // frame end
38        );
39        let initial_output_buffer_capacity = output_buffer.capacity();
40
41        // Add the start sequence
42        output_buffer.extend_from_slice(start);
43
44        // Assemble the middle
45        let mut body = Vec::with_capacity(2 + 2 + self.payload.len() + 2);
46        let initial_body_capacity = body.capacity();
47        body.extend_from_slice(&<[u8; 2]>::from(self.address));
48        body.extend_from_slice(&self.frame_type.0.to_be_bytes());
49        body.extend_from_slice(&self.payload);
50
51        // Calculate and append the CRC
52        let crc = crc::crc(&body);
53        body.extend_from_slice(&crc.to_le_bytes());
54
55        // Append the escaped content to the output buffer
56        escaping::escape(&body, &mut output_buffer);
57
58        // Append the terminator
59        output_buffer.extend_from_slice(end);
60
61        // Ensure we didn't need to reallocate
62        debug_assert_eq!(body.capacity(), initial_body_capacity);
63        debug_assert_eq!(output_buffer.capacity(), initial_output_buffer_capacity);
64
65        // Ensure we didn't over-allocate
66        debug_assert_eq!(body.len(), initial_body_capacity);
67        debug_assert!(initial_output_buffer_capacity <= output_buffer.len() + 6);
68
69        output_buffer
70    }
71}
72
73/// A link layer frame type.
74#[derive(Copy, Clone, Eq, PartialEq)]
75pub struct Type(pub u16);
76impl Type {
77    pub const RECEIVE_REQUEST: Self = Type(0x0148);
78    pub const RECEIVE_RESPONSE: Self = Type(0x0149);
79    pub const COMMAND_REQUEST: Self = Type(0x0B0F);
80    pub const COMMAND_RESPONSE: Self = Type(0x0B10);
81    pub const PING_REQUEST: Self = Type(0x0B00);
82    pub const PING_RESPONSE: Self = Type(0x0B01);
83    pub const ENUMERATION_START_REQUEST: Self = Type(0x0014);
84    pub const ENUMERATION_START_RESPONSE: Self = Type(0x0015);
85    pub const ENUMERATION_REQUEST: Self = Type(0x0038);
86    pub const ENUMERATION_RESPONSE: Self = Type(0x0039);
87    pub const ASSIGN_GATEWAY_ID_REQUEST: Self = Type(0x003C);
88    pub const ASSIGN_GATEWAY_ID_RESPONSE: Self = Type(0x003D);
89    pub const IDENTIFY_REQUEST: Self = Type(0x003A);
90    pub const IDENTIFY_RESPONSE: Self = Type(0x003B);
91    pub const VERSION_REQUEST: Self = Type(0x000A);
92    pub const VERSION_RESPONSE: Self = Type(0x000B);
93    pub const ENUMERATION_END_REQUEST: Self = Type(0x0E02);
94    pub const ENUMERATION_END_RESPONSE: Self = Type(0x0006);
95}
96
97impl std::fmt::Debug for Type {
98    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99        match *self {
100            Self::RECEIVE_REQUEST => f.write_str("Type::RECEIVE_REQUEST"),
101            Self::RECEIVE_RESPONSE => f.write_str("Type::RECEIVE_RESPONSE"),
102            Self::COMMAND_REQUEST => f.write_str("Type::COMMAND_REQUEST"),
103            Self::COMMAND_RESPONSE => f.write_str("Type::COMMAND_RESPONSE"),
104            Self::PING_REQUEST => f.write_str("Type::PING_REQUEST"),
105            Self::PING_RESPONSE => f.write_str("Type::PING_RESPONSE"),
106            Self::ENUMERATION_START_REQUEST => f.write_str("Type::ENUMERATION_START_REQUEST"),
107            Self::ENUMERATION_START_RESPONSE => f.write_str("Type::ENUMERATION_START_RESPONSE"),
108            Self::ENUMERATION_REQUEST => f.write_str("Type::ENUMERATION_REQUEST"),
109            Self::ENUMERATION_RESPONSE => f.write_str("Type::ENUMERATION_RESPONSE"),
110            Self::ASSIGN_GATEWAY_ID_REQUEST => f.write_str("Type::ASSIGN_GATEWAY_ID_REQUEST"),
111            Self::ASSIGN_GATEWAY_ID_RESPONSE => f.write_str("Type::ASSIGN_GATEWAY_ID_RESPONSE"),
112            Self::IDENTIFY_REQUEST => f.write_str("Type::IDENTIFY_REQUEST"),
113            Self::IDENTIFY_RESPONSE => f.write_str("Type::IDENTIFY_RESPONSE"),
114            Self::VERSION_REQUEST => f.write_str("Type::VERSION_REQUEST"),
115            Self::VERSION_RESPONSE => f.write_str("Type::VERSION_RESPONSE"),
116            Self::ENUMERATION_END_REQUEST => f.write_str("Type::ENUMERATION_END_REQUEST"),
117            Self::ENUMERATION_END_RESPONSE => f.write_str("Type::ENUMERATION_END_RESPONSE"),
118            Self(value) => f
119                .debug_tuple("Type")
120                .field(&format_args!("{:#04x}", value))
121                .finish(),
122        }
123    }
124}
125
126#[cfg(test)]
127mod tests {
128    use super::*;
129
130    #[test]
131    fn frame_encoding() {
132        let encoded = Frame {
133            address: Address::From(GatewayID::try_from(0x1201).unwrap()),
134            frame_type: Type(0x0149),
135            payload: b"\x00\xFF\x7C\xDB\xC2".as_slice().into(),
136        }
137        .encode();
138
139        assert_eq!(
140            encoded.as_slice(),
141            [
142                0xFF, 0x7E, 0x07, 0x92, 0x01, 0x01, 0x49, 0x00, 0xFF, 0x7C, 0xDB, 0xC2, 0x7E, 0x05,
143                0x85, 0x7E, 0x08
144            ]
145            .as_slice()
146        );
147
148        assert!(encoded.capacity() <= encoded.len() + 6);
149    }
150
151    #[test]
152    fn type_debug() {
153        assert_eq!(
154            format!("{:?}", &Type::RECEIVE_RESPONSE),
155            "Type::RECEIVE_RESPONSE"
156        );
157        assert_eq!(format!("{:?}", &Type(0x1234)), "Type(0x1234)");
158    }
159}