diff --git a/dot15d4/src/frame/addressing.rs b/dot15d4/src/frame/addressing.rs
index adbe90f..98d1783 100644
--- a/dot15d4/src/frame/addressing.rs
+++ b/dot15d4/src/frame/addressing.rs
@@ -73,6 +73,16 @@ impl Address {
}
}
+impl From
for AddressingMode {
+ fn from(value: Address) -> Self {
+ match value {
+ Address::Absent => AddressingMode::Absent,
+ Address::Short(_) => AddressingMode::Short,
+ Address::Extended(_) => AddressingMode::Extended,
+ }
+ }
+}
+
impl core::fmt::Display for Address {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
diff --git a/dot15d4/src/frame/repr/ie/mod.rs b/dot15d4/src/frame/repr/ie/mod.rs
index 96b8138..918c31f 100644
--- a/dot15d4/src/frame/repr/ie/mod.rs
+++ b/dot15d4/src/frame/repr/ie/mod.rs
@@ -12,7 +12,7 @@ use super::super::InformationElements;
use heapless::Vec;
/// A high-level representation of Information Elements.
-#[derive(Debug)]
+#[derive(Debug, Default)]
pub struct InformationElementsRepr {
/// The header information elements.
pub header_information_elements: Vec,
diff --git a/dot15d4/src/frame/repr/mod.rs b/dot15d4/src/frame/repr/mod.rs
index 9f5ee7a..4a3c476 100644
--- a/dot15d4/src/frame/repr/mod.rs
+++ b/dot15d4/src/frame/repr/mod.rs
@@ -82,3 +82,98 @@ impl<'f> FrameRepr<'f> {
}
}
}
+
+pub struct FrameBuilder<'p> {
+ frame: FrameRepr<'p>,
+}
+
+impl<'p> FrameBuilder<'p> {
+ pub fn new_ack() -> Self {
+ Self {
+ frame: FrameRepr {
+ frame_control: FrameControlRepr {
+ frame_type: super::FrameType::Ack,
+ security_enabled: false,
+ frame_pending: false,
+ ack_request: false,
+ pan_id_compression: false,
+ sequence_number_suppression: true,
+ information_elements_present: false,
+ dst_addressing_mode: super::AddressingMode::Absent,
+ src_addressing_mode: super::AddressingMode::Absent,
+ frame_version: super::FrameVersion::Ieee802154_2020,
+ },
+ sequence_number: None,
+ addressing_fields: AddressingFieldsRepr {
+ dst_pan_id: None,
+ src_pan_id: None,
+ dst_address: None,
+ src_address: None,
+ },
+ information_elements: None,
+ payload: None,
+ },
+ }
+ }
+
+ pub fn set_sequence_number(mut self, sequence_number: u8) -> Self {
+ self.frame.sequence_number = Some(sequence_number);
+ self.frame.frame_control.sequence_number_suppression = false;
+ self
+ }
+
+ pub fn set_dst_pan_id(mut self, pan_id: u16) -> Self {
+ self.frame.addressing_fields.dst_pan_id = Some(pan_id);
+ self
+ }
+
+ pub fn set_src_pan_id(mut self, pan_id: u16) -> Self {
+ self.frame.addressing_fields.src_pan_id = Some(pan_id);
+ self
+ }
+
+ pub fn set_dst_address(mut self, address: super::Address) -> Self {
+ self.frame.frame_control.dst_addressing_mode = address.into();
+ self.frame.addressing_fields.dst_address = Some(address);
+ self
+ }
+
+ pub fn set_src_address(mut self, address: super::Address) -> Self {
+ self.frame.frame_control.src_addressing_mode = address.into();
+ self.frame.addressing_fields.src_address = Some(address);
+ self
+ }
+
+ pub fn add_header_information_element(mut self, ie: HeaderInformationElementRepr) -> Self {
+ self.frame.frame_control.information_elements_present = true;
+ self.frame
+ .information_elements
+ .get_or_insert_with(InformationElementsRepr::default)
+ .header_information_elements
+ .push(ie)
+ .unwrap();
+
+ self
+ }
+
+ pub fn add_payload_information_element(mut self, ie: PayloadInformationElementRepr) -> Self {
+ self.frame.frame_control.information_elements_present = true;
+ self.frame
+ .information_elements
+ .get_or_insert_with(InformationElementsRepr::default)
+ .payload_information_elements
+ .push(ie)
+ .unwrap();
+
+ self
+ }
+
+ pub fn set_payload(mut self, payload: &'p [u8]) -> Self {
+ self.frame.payload = Some(payload);
+ self
+ }
+
+ pub fn finalize(self) -> FrameRepr<'p> {
+ self.frame
+ }
+}
diff --git a/dot15d4/src/frame/tests.rs b/dot15d4/src/frame/tests.rs
index 5c982f9..7fda8cc 100644
--- a/dot15d4/src/frame/tests.rs
+++ b/dot15d4/src/frame/tests.rs
@@ -54,39 +54,19 @@ fn parse_ack_frame() {
#[test]
fn emit_ack_frame() {
- let frame = FrameRepr {
- frame_control: FrameControlRepr {
- frame_type: FrameType::Ack,
- security_enabled: false,
- frame_pending: false,
- ack_request: false,
- pan_id_compression: false,
- sequence_number_suppression: false,
- information_elements_present: true,
- dst_addressing_mode: AddressingMode::Extended,
- src_addressing_mode: AddressingMode::Absent,
- frame_version: FrameVersion::Ieee802154_2020,
- },
- sequence_number: Some(55),
- addressing_fields: AddressingFieldsRepr {
- dst_pan_id: Some(0xabcd),
- src_pan_id: None,
- dst_address: Some(Address::Extended([
- 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02,
- ])),
- src_address: None,
- },
- information_elements: Some(InformationElementsRepr {
- header_information_elements: Vec::from_iter([
- HeaderInformationElementRepr::TimeCorrection(TimeCorrectionRepr {
- time_correction: crate::time::Duration::from_us(-31),
- nack: true,
- }),
- ]),
- payload_information_elements: Vec::new(),
- }),
- payload: None,
- };
+ let frame = FrameBuilder::new_ack()
+ .set_sequence_number(55)
+ .set_dst_pan_id(0xabcd)
+ .set_dst_address(Address::Extended([
+ 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02,
+ ]))
+ .add_header_information_element(HeaderInformationElementRepr::TimeCorrection(
+ TimeCorrectionRepr {
+ time_correction: Duration::from_us(-31),
+ nack: true,
+ },
+ ))
+ .finalize();
let mut buffer = vec![0; frame.buffer_len()];
frame.emit(&mut Frame::new_unchecked(&mut buffer[..]));
@@ -165,15 +145,6 @@ fn emit_data_frame() {
information_elements: None,
payload: Some(&[0x2b, 0x00, 0x00, 0x00]),
};
- println!(
- "buffer len: {}",
- [
- 0x41, 0xd8, 0x01, 0xcd, 0xab, 0xff, 0xff, 0xc7, 0xd9, 0xb5, 0x14, 0x00, 0x4b, 0x12,
- 0x00, 0x2b, 0x00, 0x00, 0x00,
- ]
- .len()
- );
- println!("frame buffer len: {}", frame.buffer_len());
let mut buffer = vec![0; frame.buffer_len()];