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