Skip to main content

stackforge_core/layer/dot15d4/
builder.rs

1//! IEEE 802.15.4 packet builders with fluent API.
2//!
3//! Provides `Dot15d4Builder` for constructing 802.15.4 MAC frames
4//! and `Dot15d4FcsBuilder` which wraps and appends FCS.
5
6use super::crc;
7use super::types;
8use super::{FCS_LEN, build_fcf, compute_header_len};
9
10/// Address specification for the builder.
11#[derive(Debug, Clone)]
12pub enum Dot15d4Addr {
13    /// No address.
14    None,
15    /// Short (16-bit) address.
16    Short(u16),
17    /// Long (64-bit) address.
18    Long(u64),
19}
20
21impl Dot15d4Addr {
22    /// Get the address mode for this address.
23    fn mode(&self) -> u8 {
24        match self {
25            Self::None => types::addr_mode::NONE,
26            Self::Short(_) => types::addr_mode::SHORT,
27            Self::Long(_) => types::addr_mode::LONG,
28        }
29    }
30}
31
32/// Builder for constructing IEEE 802.15.4 MAC frames.
33#[derive(Debug, Clone)]
34pub struct Dot15d4Builder {
35    /// Frame type (3 bits).
36    pub frame_type: u8,
37    /// Security enabled flag.
38    pub security: bool,
39    /// Frame pending flag.
40    pub pending: bool,
41    /// ACK request flag.
42    pub ackreq: bool,
43    /// PAN ID compression flag.
44    pub panid_compress: bool,
45    /// Frame version (2 bits).
46    pub frame_ver: u8,
47    /// Sequence number.
48    pub seqnum: u8,
49    /// Destination PAN ID.
50    pub dest_panid: Option<u16>,
51    /// Destination address.
52    pub dest_addr: Dot15d4Addr,
53    /// Source PAN ID.
54    pub src_panid: Option<u16>,
55    /// Source address.
56    pub src_addr: Dot15d4Addr,
57}
58
59impl Dot15d4Builder {
60    /// Create a new builder with default values (Data frame, short addressing).
61    #[must_use]
62    pub fn new() -> Self {
63        Self {
64            frame_type: types::frame_type::DATA,
65            security: false,
66            pending: false,
67            ackreq: false,
68            panid_compress: false,
69            frame_ver: 0,
70            seqnum: 1,
71            dest_panid: Some(0xFFFF),
72            dest_addr: Dot15d4Addr::Short(0xFFFF),
73            src_panid: None,
74            src_addr: Dot15d4Addr::None,
75        }
76    }
77
78    /// Create a builder for a beacon frame.
79    #[must_use]
80    pub fn beacon() -> Self {
81        Self {
82            frame_type: types::frame_type::BEACON,
83            security: false,
84            pending: false,
85            ackreq: false,
86            panid_compress: false,
87            frame_ver: 0,
88            seqnum: 0,
89            dest_panid: None,
90            dest_addr: Dot15d4Addr::None,
91            src_panid: None,
92            src_addr: Dot15d4Addr::None,
93        }
94    }
95
96    /// Create a builder for a data frame.
97    #[must_use]
98    pub fn data() -> Self {
99        Self::new()
100    }
101
102    /// Create a builder for an ACK frame.
103    #[must_use]
104    pub fn ack() -> Self {
105        Self {
106            frame_type: types::frame_type::ACK,
107            security: false,
108            pending: false,
109            ackreq: false,
110            panid_compress: false,
111            frame_ver: 0,
112            seqnum: 0,
113            dest_panid: None,
114            dest_addr: Dot15d4Addr::None,
115            src_panid: None,
116            src_addr: Dot15d4Addr::None,
117        }
118    }
119
120    /// Create a builder for a command frame.
121    #[must_use]
122    pub fn command() -> Self {
123        Self {
124            frame_type: types::frame_type::MAC_CMD,
125            security: false,
126            pending: false,
127            ackreq: false,
128            panid_compress: false,
129            frame_ver: 0,
130            seqnum: 0,
131            dest_panid: Some(0xFFFF),
132            dest_addr: Dot15d4Addr::Short(0x0000),
133            src_panid: None,
134            src_addr: Dot15d4Addr::None,
135        }
136    }
137
138    // Fluent setters
139
140    /// Set the frame type.
141    #[must_use]
142    pub fn frame_type(mut self, ft: u8) -> Self {
143        self.frame_type = ft;
144        self
145    }
146
147    /// Set the security enabled flag.
148    #[must_use]
149    pub fn security(mut self, val: bool) -> Self {
150        self.security = val;
151        self
152    }
153
154    /// Set the frame pending flag.
155    #[must_use]
156    pub fn pending(mut self, val: bool) -> Self {
157        self.pending = val;
158        self
159    }
160
161    /// Set the ACK request flag.
162    #[must_use]
163    pub fn ackreq(mut self, val: bool) -> Self {
164        self.ackreq = val;
165        self
166    }
167
168    /// Set the PAN ID compression flag.
169    #[must_use]
170    pub fn panid_compress(mut self, val: bool) -> Self {
171        self.panid_compress = val;
172        self
173    }
174
175    /// Set the frame version.
176    #[must_use]
177    pub fn frame_ver(mut self, ver: u8) -> Self {
178        self.frame_ver = ver;
179        self
180    }
181
182    /// Set the sequence number.
183    #[must_use]
184    pub fn seqnum(mut self, seq: u8) -> Self {
185        self.seqnum = seq;
186        self
187    }
188
189    /// Set the destination PAN ID.
190    #[must_use]
191    pub fn dest_panid(mut self, panid: u16) -> Self {
192        self.dest_panid = Some(panid);
193        self
194    }
195
196    /// Set the destination short address.
197    #[must_use]
198    pub fn dest_addr_short(mut self, addr: u16) -> Self {
199        self.dest_addr = Dot15d4Addr::Short(addr);
200        if self.dest_panid.is_none() {
201            self.dest_panid = Some(0xFFFF);
202        }
203        self
204    }
205
206    /// Set the destination long address.
207    #[must_use]
208    pub fn dest_addr_long(mut self, addr: u64) -> Self {
209        self.dest_addr = Dot15d4Addr::Long(addr);
210        if self.dest_panid.is_none() {
211            self.dest_panid = Some(0xFFFF);
212        }
213        self
214    }
215
216    /// Clear the destination address (set to None).
217    #[must_use]
218    pub fn no_dest_addr(mut self) -> Self {
219        self.dest_addr = Dot15d4Addr::None;
220        self.dest_panid = None;
221        self
222    }
223
224    /// Set the source PAN ID.
225    #[must_use]
226    pub fn src_panid(mut self, panid: u16) -> Self {
227        self.src_panid = Some(panid);
228        self
229    }
230
231    /// Set the source short address.
232    #[must_use]
233    pub fn src_addr_short(mut self, addr: u16) -> Self {
234        self.src_addr = Dot15d4Addr::Short(addr);
235        self
236    }
237
238    /// Set the source long address.
239    #[must_use]
240    pub fn src_addr_long(mut self, addr: u64) -> Self {
241        self.src_addr = Dot15d4Addr::Long(addr);
242        self
243    }
244
245    /// Clear the source address (set to None).
246    #[must_use]
247    pub fn no_src_addr(mut self) -> Self {
248        self.src_addr = Dot15d4Addr::None;
249        self.src_panid = None;
250        self
251    }
252
253    /// Compute the destination address mode.
254    fn dest_addr_mode(&self) -> u8 {
255        self.dest_addr.mode()
256    }
257
258    /// Compute the source address mode.
259    fn src_addr_mode(&self) -> u8 {
260        self.src_addr.mode()
261    }
262
263    /// Build the 802.15.4 MAC frame bytes (without FCS).
264    #[must_use]
265    pub fn build(&self) -> Vec<u8> {
266        let dest_mode = self.dest_addr_mode();
267        let src_mode = self.src_addr_mode();
268
269        let fcf = build_fcf(
270            self.frame_type,
271            self.security,
272            self.pending,
273            self.ackreq,
274            self.panid_compress,
275            dest_mode,
276            self.frame_ver,
277            src_mode,
278        );
279
280        let header_len = compute_header_len(fcf);
281        let mut out = Vec::with_capacity(header_len);
282
283        // Frame Control Field (2 bytes, LE)
284        out.extend_from_slice(&fcf.to_le_bytes());
285
286        // Sequence Number (1 byte)
287        out.push(self.seqnum);
288
289        // Destination PAN ID + Address
290        if dest_mode != types::addr_mode::NONE {
291            let panid = self.dest_panid.unwrap_or(0xFFFF);
292            out.extend_from_slice(&panid.to_le_bytes());
293
294            match &self.dest_addr {
295                Dot15d4Addr::Short(addr) => {
296                    out.extend_from_slice(&addr.to_le_bytes());
297                },
298                Dot15d4Addr::Long(addr) => {
299                    out.extend_from_slice(&addr.to_le_bytes());
300                },
301                Dot15d4Addr::None => {}, // Should not happen if dest_mode != NONE
302            }
303        }
304
305        // Source PAN ID + Address
306        if src_mode != types::addr_mode::NONE {
307            if !self.panid_compress {
308                let panid = self.src_panid.unwrap_or(0x0000);
309                out.extend_from_slice(&panid.to_le_bytes());
310            }
311
312            match &self.src_addr {
313                Dot15d4Addr::Short(addr) => {
314                    out.extend_from_slice(&addr.to_le_bytes());
315                },
316                Dot15d4Addr::Long(addr) => {
317                    out.extend_from_slice(&addr.to_le_bytes());
318                },
319                Dot15d4Addr::None => {}, // Should not happen if src_mode != NONE
320            }
321        }
322
323        out
324    }
325
326    /// Get the expected header size for the current configuration.
327    #[must_use]
328    pub fn header_size(&self) -> usize {
329        let fcf = build_fcf(
330            self.frame_type,
331            self.security,
332            self.pending,
333            self.ackreq,
334            self.panid_compress,
335            self.dest_addr_mode(),
336            self.frame_ver,
337            self.src_addr_mode(),
338        );
339        compute_header_len(fcf)
340    }
341}
342
343impl Default for Dot15d4Builder {
344    fn default() -> Self {
345        Self::new()
346    }
347}
348
349/// Builder for IEEE 802.15.4 frames with FCS.
350///
351/// Wraps `Dot15d4Builder` and appends a CRC-16 CCITT Kermit FCS.
352#[derive(Debug, Clone)]
353pub struct Dot15d4FcsBuilder {
354    /// Inner builder for the frame content.
355    pub inner: Dot15d4Builder,
356}
357
358impl Dot15d4FcsBuilder {
359    /// Create a new FCS builder with default values.
360    #[must_use]
361    pub fn new() -> Self {
362        Self {
363            inner: Dot15d4Builder::new(),
364        }
365    }
366
367    /// Create from an existing `Dot15d4Builder`.
368    #[must_use]
369    pub fn from_builder(builder: Dot15d4Builder) -> Self {
370        Self { inner: builder }
371    }
372
373    /// Create a builder for a beacon frame with FCS.
374    #[must_use]
375    pub fn beacon() -> Self {
376        Self {
377            inner: Dot15d4Builder::beacon(),
378        }
379    }
380
381    /// Create a builder for a data frame with FCS.
382    #[must_use]
383    pub fn data() -> Self {
384        Self {
385            inner: Dot15d4Builder::data(),
386        }
387    }
388
389    /// Create a builder for an ACK frame with FCS.
390    #[must_use]
391    pub fn ack() -> Self {
392        Self {
393            inner: Dot15d4Builder::ack(),
394        }
395    }
396
397    /// Create a builder for a command frame with FCS.
398    #[must_use]
399    pub fn command() -> Self {
400        Self {
401            inner: Dot15d4Builder::command(),
402        }
403    }
404
405    // Fluent setters that delegate to inner builder
406
407    #[must_use]
408    pub fn frame_type(mut self, ft: u8) -> Self {
409        self.inner = self.inner.frame_type(ft);
410        self
411    }
412
413    #[must_use]
414    pub fn security(mut self, val: bool) -> Self {
415        self.inner = self.inner.security(val);
416        self
417    }
418
419    #[must_use]
420    pub fn pending(mut self, val: bool) -> Self {
421        self.inner = self.inner.pending(val);
422        self
423    }
424
425    #[must_use]
426    pub fn ackreq(mut self, val: bool) -> Self {
427        self.inner = self.inner.ackreq(val);
428        self
429    }
430
431    #[must_use]
432    pub fn panid_compress(mut self, val: bool) -> Self {
433        self.inner = self.inner.panid_compress(val);
434        self
435    }
436
437    #[must_use]
438    pub fn frame_ver(mut self, ver: u8) -> Self {
439        self.inner = self.inner.frame_ver(ver);
440        self
441    }
442
443    #[must_use]
444    pub fn seqnum(mut self, seq: u8) -> Self {
445        self.inner = self.inner.seqnum(seq);
446        self
447    }
448
449    #[must_use]
450    pub fn dest_panid(mut self, panid: u16) -> Self {
451        self.inner = self.inner.dest_panid(panid);
452        self
453    }
454
455    #[must_use]
456    pub fn dest_addr_short(mut self, addr: u16) -> Self {
457        self.inner = self.inner.dest_addr_short(addr);
458        self
459    }
460
461    #[must_use]
462    pub fn dest_addr_long(mut self, addr: u64) -> Self {
463        self.inner = self.inner.dest_addr_long(addr);
464        self
465    }
466
467    #[must_use]
468    pub fn no_dest_addr(mut self) -> Self {
469        self.inner = self.inner.no_dest_addr();
470        self
471    }
472
473    #[must_use]
474    pub fn src_panid(mut self, panid: u16) -> Self {
475        self.inner = self.inner.src_panid(panid);
476        self
477    }
478
479    #[must_use]
480    pub fn src_addr_short(mut self, addr: u16) -> Self {
481        self.inner = self.inner.src_addr_short(addr);
482        self
483    }
484
485    #[must_use]
486    pub fn src_addr_long(mut self, addr: u64) -> Self {
487        self.inner = self.inner.src_addr_long(addr);
488        self
489    }
490
491    #[must_use]
492    pub fn no_src_addr(mut self) -> Self {
493        self.inner = self.inner.no_src_addr();
494        self
495    }
496
497    /// Build the 802.15.4 MAC frame bytes with FCS appended.
498    #[must_use]
499    pub fn build(&self) -> Vec<u8> {
500        let mut frame = self.inner.build();
501        let fcs = crc::compute_fcs(&frame);
502        frame.extend_from_slice(&fcs);
503        frame
504    }
505
506    /// Get the expected total size (header + FCS).
507    #[must_use]
508    pub fn total_size(&self) -> usize {
509        self.inner.header_size() + FCS_LEN
510    }
511}
512
513impl Default for Dot15d4FcsBuilder {
514    fn default() -> Self {
515        Self::new()
516    }
517}
518
519#[cfg(test)]
520mod tests {
521    use super::*;
522    use crate::layer::dot15d4::{Dot15d4FcsLayer, Dot15d4Layer};
523
524    #[test]
525    fn test_builder_default() {
526        let b = Dot15d4Builder::new();
527        assert_eq!(b.frame_type, types::frame_type::DATA);
528        assert!(!b.security);
529        assert!(!b.ackreq);
530        assert_eq!(b.seqnum, 1);
531    }
532
533    #[test]
534    fn test_builder_beacon() {
535        let b = Dot15d4Builder::beacon();
536        assert_eq!(b.frame_type, types::frame_type::BEACON);
537    }
538
539    #[test]
540    fn test_builder_ack() {
541        let b = Dot15d4Builder::ack();
542        assert_eq!(b.frame_type, types::frame_type::ACK);
543        let frame = b.build();
544        assert_eq!(frame.len(), 3); // FCF + seqnum
545    }
546
547    #[test]
548    fn test_builder_fluent_api() {
549        let b = Dot15d4Builder::new()
550            .frame_type(types::frame_type::DATA)
551            .ackreq(true)
552            .panid_compress(true)
553            .seqnum(42)
554            .dest_panid(0x1234)
555            .dest_addr_short(0xFFFF)
556            .src_addr_short(0x0001);
557
558        assert_eq!(b.frame_type, types::frame_type::DATA);
559        assert!(b.ackreq);
560        assert!(b.panid_compress);
561        assert_eq!(b.seqnum, 42);
562    }
563
564    #[test]
565    fn test_build_data_frame_short() {
566        let frame = Dot15d4Builder::new()
567            .frame_type(types::frame_type::DATA)
568            .ackreq(true)
569            .panid_compress(true)
570            .seqnum(5)
571            .dest_panid(0x1234)
572            .dest_addr_short(0xFFFF)
573            .src_addr_short(0x0001)
574            .build();
575
576        // Parse it back
577        let layer = Dot15d4Layer::new(0, frame.len());
578        assert_eq!(layer.fcf_frametype(&frame).unwrap(), 1);
579        assert!(layer.fcf_ackreq(&frame).unwrap());
580        assert!(layer.fcf_panidcompress(&frame).unwrap());
581        assert_eq!(layer.fcf_destaddrmode(&frame).unwrap(), 2);
582        assert_eq!(layer.fcf_srcaddrmode(&frame).unwrap(), 2);
583        assert_eq!(layer.seqnum(&frame).unwrap(), 5);
584        assert_eq!(layer.dest_panid(&frame).unwrap(), Some(0x1234));
585        assert_eq!(layer.dest_addr_short(&frame).unwrap(), Some(0xFFFF));
586        assert_eq!(layer.src_panid(&frame).unwrap(), None); // compressed
587        assert_eq!(layer.src_addr_short(&frame).unwrap(), Some(0x0001));
588
589        // Header length should be 9
590        assert_eq!(frame.len(), 9);
591    }
592
593    #[test]
594    fn test_build_data_frame_long() {
595        let frame = Dot15d4Builder::new()
596            .frame_type(types::frame_type::DATA)
597            .seqnum(10)
598            .dest_panid(0x1234)
599            .dest_addr_long(0x0102030405060708)
600            .src_panid(0xABCD)
601            .src_addr_long(0x1112131415161718)
602            .build();
603
604        let layer = Dot15d4Layer::new(0, frame.len());
605        assert_eq!(layer.fcf_destaddrmode(&frame).unwrap(), 3);
606        assert_eq!(layer.fcf_srcaddrmode(&frame).unwrap(), 3);
607        assert_eq!(layer.dest_panid(&frame).unwrap(), Some(0x1234));
608        assert_eq!(
609            layer.dest_addr_long(&frame).unwrap(),
610            Some(0x0102030405060708)
611        );
612        assert_eq!(layer.src_panid(&frame).unwrap(), Some(0xABCD));
613        assert_eq!(
614            layer.src_addr_long(&frame).unwrap(),
615            Some(0x1112131415161718)
616        );
617
618        // Header: 3 + 2 + 8 + 2 + 8 = 23
619        assert_eq!(frame.len(), 23);
620    }
621
622    #[test]
623    fn test_build_ack_frame() {
624        let frame = Dot15d4Builder::ack().seqnum(42).build();
625
626        let layer = Dot15d4Layer::new(0, frame.len());
627        assert_eq!(layer.fcf_frametype(&frame).unwrap(), 2);
628        assert_eq!(layer.fcf_destaddrmode(&frame).unwrap(), 0);
629        assert_eq!(layer.fcf_srcaddrmode(&frame).unwrap(), 0);
630        assert_eq!(layer.seqnum(&frame).unwrap(), 42);
631        assert_eq!(frame.len(), 3);
632    }
633
634    #[test]
635    fn test_fcs_builder() {
636        let frame = Dot15d4FcsBuilder::new()
637            .frame_type(types::frame_type::DATA)
638            .ackreq(true)
639            .panid_compress(true)
640            .seqnum(5)
641            .dest_panid(0x1234)
642            .dest_addr_short(0xFFFF)
643            .src_addr_short(0x0001)
644            .build();
645
646        // Should be header + 2 bytes FCS
647        assert_eq!(frame.len(), 11); // 9 header + 2 FCS
648
649        // Verify FCS
650        let layer = Dot15d4FcsLayer::new(0, frame.len());
651        assert!(layer.verify_fcs(&frame).unwrap());
652
653        // Verify inner fields
654        assert_eq!(layer.fcf_frametype(&frame).unwrap(), 1);
655        assert_eq!(layer.seqnum(&frame).unwrap(), 5);
656    }
657
658    #[test]
659    fn test_fcs_builder_from_inner() {
660        let inner = Dot15d4Builder::ack().seqnum(99);
661        let fcs_builder = Dot15d4FcsBuilder::from_builder(inner);
662        let frame = fcs_builder.build();
663
664        assert_eq!(frame.len(), 5); // 3 header + 2 FCS
665
666        let layer = Dot15d4FcsLayer::new(0, frame.len());
667        assert!(layer.verify_fcs(&frame).unwrap());
668        assert_eq!(layer.seqnum(&frame).unwrap(), 99);
669    }
670
671    #[test]
672    fn test_header_size() {
673        let b = Dot15d4Builder::ack();
674        assert_eq!(b.header_size(), 3);
675
676        let b = Dot15d4Builder::new()
677            .dest_addr_short(0xFFFF)
678            .panid_compress(true)
679            .src_addr_short(0x0001);
680        assert_eq!(b.header_size(), 9);
681
682        let b = Dot15d4Builder::new()
683            .dest_addr_long(0x0102030405060708)
684            .src_addr_long(0x1112131415161718);
685        assert_eq!(b.header_size(), 23);
686    }
687
688    #[test]
689    fn test_fcs_total_size() {
690        let b = Dot15d4FcsBuilder::ack();
691        assert_eq!(b.total_size(), 5);
692    }
693
694    #[test]
695    fn test_builder_no_dest_addr() {
696        let b = Dot15d4Builder::new().no_dest_addr().no_src_addr();
697        let frame = b.build();
698        assert_eq!(frame.len(), 3);
699    }
700
701    #[test]
702    fn test_build_parse_roundtrip_short() {
703        let original = Dot15d4Builder::new()
704            .frame_type(types::frame_type::DATA)
705            .ackreq(true)
706            .panid_compress(true)
707            .seqnum(77)
708            .dest_panid(0xBEEF)
709            .dest_addr_short(0x1234)
710            .src_addr_short(0x5678);
711
712        let frame = original.build();
713        let layer = Dot15d4Layer::new(0, frame.len());
714
715        assert_eq!(
716            layer.fcf_frametype(&frame).unwrap(),
717            types::frame_type::DATA
718        );
719        assert!(layer.fcf_ackreq(&frame).unwrap());
720        assert!(layer.fcf_panidcompress(&frame).unwrap());
721        assert_eq!(layer.seqnum(&frame).unwrap(), 77);
722        assert_eq!(layer.dest_panid(&frame).unwrap(), Some(0xBEEF));
723        assert_eq!(layer.dest_addr_short(&frame).unwrap(), Some(0x1234));
724        assert_eq!(layer.src_addr_short(&frame).unwrap(), Some(0x5678));
725    }
726
727    #[test]
728    fn test_fcs_builder_beacon() {
729        let frame = Dot15d4FcsBuilder::beacon().seqnum(0).build();
730        let layer = Dot15d4FcsLayer::new(0, frame.len());
731        assert_eq!(
732            layer.fcf_frametype(&frame).unwrap(),
733            types::frame_type::BEACON
734        );
735        assert!(layer.verify_fcs(&frame).unwrap());
736    }
737
738    #[test]
739    fn test_fcs_builder_command() {
740        let frame = Dot15d4FcsBuilder::command()
741            .seqnum(10)
742            .dest_panid(0x1234)
743            .dest_addr_short(0x0001)
744            .build();
745        let layer = Dot15d4FcsLayer::new(0, frame.len());
746        assert_eq!(
747            layer.fcf_frametype(&frame).unwrap(),
748            types::frame_type::MAC_CMD
749        );
750        assert!(layer.verify_fcs(&frame).unwrap());
751    }
752}