dot15d4_frame/repr/
builder.rs

1use super::*;
2use crate::{Address, AddressingMode, FrameType, FrameVersion};
3use crate::{Error, Result};
4
5pub struct Beacon;
6pub struct EnhancedBeacon;
7pub struct Ack;
8pub struct Data;
9
10/// A helper for building IEEE 802.15.4 frames.
11pub struct FrameBuilder<'p, T> {
12    frame: FrameRepr<'p>,
13    r#type: core::marker::PhantomData<T>,
14}
15
16impl<'p> FrameBuilder<'p, Ack> {
17    /// Create a new builder for an immediate acknowledgment frame.
18    pub fn new_imm_ack(sequence_number: u8) -> Self {
19        Self {
20            frame: FrameRepr {
21                frame_control: FrameControlRepr {
22                    frame_type: FrameType::Ack,
23                    security_enabled: false,
24                    frame_pending: false,
25                    ack_request: false,
26                    pan_id_compression: false,
27                    sequence_number_suppression: false,
28                    information_elements_present: false,
29                    dst_addressing_mode: AddressingMode::Absent,
30                    src_addressing_mode: AddressingMode::Absent,
31                    frame_version: FrameVersion::Ieee802154_2006,
32                },
33                sequence_number: Some(sequence_number),
34                addressing_fields: None,
35                information_elements: None,
36                payload: None,
37            },
38            r#type: Default::default(),
39        }
40    }
41
42    /// Create a new builder for an acknowledgment frame.
43    pub fn new_ack() -> Self {
44        Self {
45            frame: FrameRepr {
46                frame_control: FrameControlRepr {
47                    frame_type: FrameType::Ack,
48                    security_enabled: false,
49                    frame_pending: false,
50                    ack_request: false,
51                    pan_id_compression: false,
52                    sequence_number_suppression: true,
53                    information_elements_present: false,
54                    dst_addressing_mode: AddressingMode::Absent,
55                    src_addressing_mode: AddressingMode::Absent,
56                    frame_version: FrameVersion::Ieee802154_2020,
57                },
58                sequence_number: None,
59                addressing_fields: None,
60                information_elements: None,
61                payload: None,
62            },
63            r#type: Default::default(),
64        }
65    }
66}
67
68impl<'p> FrameBuilder<'p, Beacon> {
69    /// Create a new builder for a beacon frame.
70    pub fn new_beacon() -> Self {
71        Self {
72            frame: FrameRepr {
73                frame_control: FrameControlRepr {
74                    frame_type: FrameType::Beacon,
75                    security_enabled: false,
76                    frame_pending: false,
77                    ack_request: false,
78                    pan_id_compression: false,
79                    sequence_number_suppression: true,
80                    information_elements_present: false,
81                    dst_addressing_mode: AddressingMode::Absent,
82                    src_addressing_mode: AddressingMode::Absent,
83                    frame_version: FrameVersion::Ieee802154_2006,
84                },
85                sequence_number: None,
86                addressing_fields: None,
87                information_elements: None,
88                payload: None,
89            },
90            r#type: core::marker::PhantomData,
91        }
92    }
93}
94
95impl<'p> FrameBuilder<'p, EnhancedBeacon> {
96    /// Create a new builder for an enhanced beacon frame.
97    pub fn new_enhanced_beacon() -> Self {
98        Self {
99            frame: FrameRepr {
100                frame_control: FrameControlRepr {
101                    frame_type: FrameType::Beacon,
102                    security_enabled: false,
103                    frame_pending: false,
104                    ack_request: false,
105                    pan_id_compression: false,
106                    sequence_number_suppression: true,
107                    information_elements_present: false,
108                    dst_addressing_mode: AddressingMode::Absent,
109                    src_addressing_mode: AddressingMode::Absent,
110                    frame_version: FrameVersion::Ieee802154_2020,
111                },
112                sequence_number: None,
113                addressing_fields: None,
114                information_elements: None,
115                payload: None,
116            },
117            r#type: core::marker::PhantomData,
118        }
119    }
120}
121
122impl<'p> FrameBuilder<'p, Data> {
123    /// Create a new builder for a data frame.
124    pub fn new_data(payload: &'p [u8]) -> Self {
125        Self {
126            frame: FrameRepr {
127                frame_control: FrameControlRepr {
128                    frame_type: FrameType::Data,
129                    security_enabled: false,
130                    frame_pending: false,
131                    ack_request: false,
132                    pan_id_compression: false,
133                    sequence_number_suppression: true,
134                    information_elements_present: false,
135                    dst_addressing_mode: AddressingMode::Absent,
136                    src_addressing_mode: AddressingMode::Absent,
137                    frame_version: FrameVersion::Ieee802154_2006,
138                },
139                sequence_number: None,
140                addressing_fields: None,
141                information_elements: None,
142                payload: Some(payload),
143            },
144            r#type: core::marker::PhantomData,
145        }
146    }
147}
148
149impl<'p, T> FrameBuilder<'p, T> {
150    /// Set the frame sequence number.
151    ///
152    /// # Note
153    /// This method disables sequence number suppression.
154    pub fn set_sequence_number(mut self, sequence_number: u8) -> Self {
155        self.frame.sequence_number = Some(sequence_number);
156        self.frame.frame_control.sequence_number_suppression = false;
157        self
158    }
159
160    /// Set the destination PAN ID.
161    pub fn set_dst_pan_id(mut self, pan_id: u16) -> Self {
162        self.frame
163            .addressing_fields
164            .get_or_insert_with(AddressingFieldsRepr::default)
165            .dst_pan_id = Some(pan_id);
166
167        self
168    }
169
170    /// Set the source PAN ID.
171    pub fn set_src_pan_id(mut self, pan_id: u16) -> Self {
172        self.frame
173            .addressing_fields
174            .get_or_insert_with(AddressingFieldsRepr::default)
175            .src_pan_id = Some(pan_id);
176        self
177    }
178
179    /// Set the destination address.
180    ///
181    /// # Note
182    /// Based on the address, the addressing mode will be set.
183    pub fn set_dst_address(mut self, address: Address) -> Self {
184        self.frame.frame_control.dst_addressing_mode = address.into();
185        self.frame
186            .addressing_fields
187            .get_or_insert_with(AddressingFieldsRepr::default)
188            .dst_address = Some(address);
189        self
190    }
191
192    /// Set the source address.
193    ///
194    /// # Note
195    /// Based on the address, the addressing mode will be set.
196    pub fn set_src_address(mut self, address: Address) -> Self {
197        self.frame.frame_control.src_addressing_mode = address.into();
198        self.frame
199            .addressing_fields
200            .get_or_insert_with(AddressingFieldsRepr::default)
201            .src_address = Some(address);
202        self
203    }
204
205    /// Add a header Information Element.
206    ///
207    /// # Note
208    /// This method will enable the Information Elements Present bit in the
209    /// frame control. The frame version will be set to IEEE 802.15.4-2020.
210    pub fn add_header_information_element(mut self, ie: HeaderInformationElementRepr) -> Self {
211        self.frame.frame_control.information_elements_present = true;
212        self.frame
213            .information_elements
214            .get_or_insert_with(InformationElementsRepr::default)
215            .header_information_elements
216            .push(ie)
217            .unwrap();
218
219        self.frame.frame_control.frame_version = FrameVersion::Ieee802154_2020;
220
221        self
222    }
223
224    /// Add a payload Information Element.
225    ///
226    /// # Note
227    /// This method will enable the Information Elements Present bit in the
228    /// frame control. The frame version will be set to IEEE 802.15.4-2020.
229    pub fn add_payload_information_element(mut self, ie: PayloadInformationElementRepr) -> Self {
230        self.frame.frame_control.information_elements_present = true;
231        self.frame
232            .information_elements
233            .get_or_insert_with(InformationElementsRepr::default)
234            .payload_information_elements
235            .push(ie)
236            .unwrap();
237
238        self.frame.frame_control.frame_version = FrameVersion::Ieee802154_2020;
239
240        self
241    }
242
243    /// Set the frame payload.
244    pub fn set_payload(mut self, payload: &'p [u8]) -> Self {
245        self.frame.payload = Some(payload);
246        self
247    }
248
249    /// Finalize the frame builder, returning the frame representation.
250    ///
251    /// # Note
252    /// This method will check and set if PAN ID compression is possible,
253    /// depending on the frame version.
254    pub fn finalize(mut self) -> Result<FrameRepr<'p>> {
255        // Check if PAN ID compression is possible, depending on the frame version.
256        if self.frame.frame_control.frame_version == FrameVersion::Ieee802154_2020 {
257            let Some(addr) = self.frame.addressing_fields.as_mut() else {
258                return Err(Error);
259            };
260
261            self.frame.frame_control.pan_id_compression = match (
262                addr.dst_address,
263                addr.src_address,
264                addr.dst_pan_id,
265                addr.src_pan_id,
266            ) {
267                (None, None, None, None) => false,
268                (None, None, Some(_), None) => true,
269                (Some(_), None, Some(_), None) => false,
270                (None, Some(_), None, Some(_)) => false,
271                (None, Some(_), None, None) => true,
272                (Some(Address::Extended(_)), Some(Address::Extended(_)), Some(_), None) => false,
273                (Some(Address::Extended(_)), Some(Address::Extended(_)), None, None) => true,
274                (Some(Address::Short(_)), Some(Address::Short(_)), Some(dst), Some(src)) => {
275                    if dst == src {
276                        addr.src_pan_id = None;
277                    }
278
279                    dst == src
280                }
281                (Some(Address::Short(_)), Some(Address::Extended(_)), Some(dst), Some(src)) => {
282                    if dst == src {
283                        addr.src_pan_id = None;
284                    }
285
286                    dst == src
287                }
288                (Some(Address::Extended(_)), Some(Address::Short(_)), Some(dst), Some(src)) => {
289                    if dst == src {
290                        addr.src_pan_id = None;
291                    }
292
293                    dst == src
294                }
295                (Some(Address::Short(_)), Some(Address::Extended(_)), Some(_), None) => true,
296                (Some(Address::Extended(_)), Some(Address::Short(_)), Some(_), None) => true,
297                (Some(Address::Short(_)), Some(Address::Short(_)), Some(_), None) => true,
298                _ => return Err(Error),
299            };
300        } else {
301            if matches!(self.frame.frame_control.frame_type, FrameType::Ack) {
302                // The sequence number is required for immediate acknowledgment frames.
303                if self.frame.sequence_number.is_none() {
304                    return Err(Error);
305                }
306
307                // The addressing fields are not present in acknowledgment frames.
308                self.frame.addressing_fields = None;
309
310                return Ok(self.frame);
311            }
312
313            // - If both destination and source addresses are present, and the PAN IDs are
314            //   equal, then PAN ID compression is possible. In this case, the source PAN ID
315            //   field is omitted and the PAN ID compression bit is set to 1. If PAN IDs are
316            //   different, the PAN ID compression bit is set to 0.
317            // - If only either the destination or source address is present, the PAN ID
318            //   compression bit is set to 0. The PAN ID field of the single address shall
319            //   be included in the frame.
320            let Some(addr) = self.frame.addressing_fields.as_mut() else {
321                return Err(Error);
322            };
323
324            match (
325                addr.dst_address,
326                addr.src_address,
327                addr.dst_pan_id,
328                addr.src_pan_id,
329            ) {
330                (Some(_), Some(_), Some(dst_pan_id), Some(src_pan_id)) => {
331                    if dst_pan_id == src_pan_id {
332                        self.frame.frame_control.pan_id_compression = true;
333                        addr.src_pan_id = None;
334                    }
335                }
336                (Some(_), None, Some(_), _) => {
337                    self.frame.frame_control.pan_id_compression = false;
338                    addr.src_pan_id = None;
339                }
340                (None, Some(_), _, Some(_)) => {
341                    self.frame.frame_control.pan_id_compression = false;
342                    addr.dst_pan_id = None;
343                }
344                _ => return Err(Error),
345            }
346        }
347
348        Ok(self.frame)
349    }
350}