aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32-wpan
diff options
context:
space:
mode:
authorxoviat <[email protected]>2025-11-17 11:16:55 -0600
committerxoviat <[email protected]>2025-11-17 11:16:55 -0600
commit26038cfbc60e9a7b64d70ade51e9e9f34c912e2e (patch)
treec154fccb98da0b182f1abfc7390dbc21dc8a2295 /embassy-stm32-wpan
parent80ceb42eb1c842fcb214a5fbfbb1c39265c6b29b (diff)
wpan: parse frames correctly
Diffstat (limited to 'embassy-stm32-wpan')
-rw-r--r--embassy-stm32-wpan/Cargo.toml3
-rw-r--r--embassy-stm32-wpan/src/mac/commands.rs26
-rw-r--r--embassy-stm32-wpan/src/mac/driver.rs12
-rw-r--r--embassy-stm32-wpan/src/mac/indications.rs18
-rw-r--r--embassy-stm32-wpan/src/mac/runner.rs87
-rw-r--r--embassy-stm32-wpan/src/mac/typedefs.rs42
6 files changed, 148 insertions, 40 deletions
diff --git a/embassy-stm32-wpan/Cargo.toml b/embassy-stm32-wpan/Cargo.toml
index 75d978d1a..05d76f4a6 100644
--- a/embassy-stm32-wpan/Cargo.toml
+++ b/embassy-stm32-wpan/Cargo.toml
@@ -33,6 +33,7 @@ embassy-futures = { version = "0.1.2", path = "../embassy-futures" }
33embassy-hal-internal = { version = "0.3.0", path = "../embassy-hal-internal" } 33embassy-hal-internal = { version = "0.3.0", path = "../embassy-hal-internal" }
34embassy-embedded-hal = { version = "0.5.0", path = "../embassy-embedded-hal" } 34embassy-embedded-hal = { version = "0.5.0", path = "../embassy-embedded-hal" }
35embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver", optional=true } 35embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver", optional=true }
36smoltcp = { version = "0.12.0", optional=true, default-features = false }
36 37
37defmt = { version = "1.0.1", optional = true } 38defmt = { version = "1.0.1", optional = true }
38log = { version = "0.4.17", optional = true } 39log = { version = "0.4.17", optional = true }
@@ -52,7 +53,7 @@ bitflags = { version = "2.3.3", optional = true }
52defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-internal/defmt", "stm32wb-hci?/defmt"] 53defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-internal/defmt", "stm32wb-hci?/defmt"]
53 54
54ble = ["dep:stm32wb-hci"] 55ble = ["dep:stm32wb-hci"]
55mac = ["dep:bitflags", "dep:embassy-net-driver" ] 56mac = ["dep:bitflags", "dep:embassy-net-driver", "dep:smoltcp", "smoltcp/medium-ieee802154"]
56 57
57extended = [] 58extended = []
58 59
diff --git a/embassy-stm32-wpan/src/mac/commands.rs b/embassy-stm32-wpan/src/mac/commands.rs
index 82b9d2772..e0bc50e2a 100644
--- a/embassy-stm32-wpan/src/mac/commands.rs
+++ b/embassy-stm32-wpan/src/mac/commands.rs
@@ -8,6 +8,8 @@ use super::typedefs::{
8 PanId, PibId, ScanType, SecurityLevel, 8 PanId, PibId, ScanType, SecurityLevel,
9}; 9};
10 10
11use smoltcp::wire::ieee802154::Frame;
12
11pub trait MacCommand: Sized { 13pub trait MacCommand: Sized {
12 const OPCODE: OpcodeM4ToM0; 14 const OPCODE: OpcodeM4ToM0;
13 15
@@ -379,6 +381,30 @@ impl DataRequest {
379 } 381 }
380} 382}
381 383
384impl<'a, T: AsRef<[u8]>> TryFrom<Frame<&'a T>> for DataRequest {
385 type Error = ();
386
387 fn try_from(frame: Frame<&'a T>) -> Result<Self, Self::Error> {
388 // TODO: map the rest of these
389
390 let mut request = DataRequest {
391 src_addr_mode: frame.src_addressing_mode().try_into()?,
392 dst_addr_mode: frame.dst_addressing_mode().try_into()?,
393 dst_pan_id: frame.dst_pan_id().ok_or(())?.into(),
394 dst_address: frame.dst_addr().ok_or(())?.into(),
395 msdu_handle: frame.sequence_number().ok_or(())?,
396 ack_tx: 0x00,
397 gts_tx: false,
398 security_level: SecurityLevel::Unsecure,
399 ..Default::default()
400 };
401
402 request.set_buffer(frame.payload().ok_or(())?);
403
404 Ok(request)
405 }
406}
407
382impl Default for DataRequest { 408impl Default for DataRequest {
383 fn default() -> Self { 409 fn default() -> Self {
384 Self { 410 Self {
diff --git a/embassy-stm32-wpan/src/mac/driver.rs b/embassy-stm32-wpan/src/mac/driver.rs
index 5592723a2..c71fabe09 100644
--- a/embassy-stm32-wpan/src/mac/driver.rs
+++ b/embassy-stm32-wpan/src/mac/driver.rs
@@ -11,6 +11,7 @@ use embassy_sync::mutex::Mutex;
11use embassy_sync::waitqueue::AtomicWaker; 11use embassy_sync::waitqueue::AtomicWaker;
12 12
13use crate::mac::event::MacEvent; 13use crate::mac::event::MacEvent;
14use crate::mac::indications::write_frame_from_data_indication;
14use crate::mac::runner::{BUF_SIZE, ZeroCopyPubSub}; 15use crate::mac::runner::{BUF_SIZE, ZeroCopyPubSub};
15use crate::mac::{Control, MTU, Runner}; 16use crate::mac::{Control, MTU, Runner};
16use crate::sub::mac::{Mac, MacRx, MacTx}; 17use crate::sub::mac::{Mac, MacRx, MacTx};
@@ -179,14 +180,13 @@ impl<'d> embassy_net_driver::RxToken for RxToken<'d> {
179 where 180 where
180 F: FnOnce(&mut [u8]) -> R, 181 F: FnOnce(&mut [u8]) -> R,
181 { 182 {
182 // Only valid data events should be put into the queue 183 let mut buffer = [0u8; MTU];
183 184 match self.rx.try_receive().unwrap() {
184 let data_event = match self.rx.try_receive().unwrap() { 185 MacEvent::McpsDataInd(data_event) => write_frame_from_data_indication(data_event, &mut buffer),
185 MacEvent::McpsDataInd(data_event) => data_event, 186 _ => {}
186 _ => unreachable!(),
187 }; 187 };
188 188
189 f(&mut data_event.payload()) 189 f(&mut buffer[..])
190 } 190 }
191} 191}
192 192
diff --git a/embassy-stm32-wpan/src/mac/indications.rs b/embassy-stm32-wpan/src/mac/indications.rs
index c0b86d745..45f79ac5b 100644
--- a/embassy-stm32-wpan/src/mac/indications.rs
+++ b/embassy-stm32-wpan/src/mac/indications.rs
@@ -7,6 +7,9 @@ use super::typedefs::{
7 PanId, SecurityLevel, 7 PanId, SecurityLevel,
8}; 8};
9 9
10use smoltcp::wire::Ieee802154FrameType;
11use smoltcp::wire::ieee802154::Frame;
12
10/// MLME ASSOCIATE Indication which will be used by the MAC 13/// MLME ASSOCIATE Indication which will be used by the MAC
11/// to indicate the reception of an association request command 14/// to indicate the reception of an association request command
12#[repr(C)] 15#[repr(C)]
@@ -250,6 +253,21 @@ impl DataIndication {
250 } 253 }
251} 254}
252 255
256pub fn write_frame_from_data_indication<'a, T: AsRef<[u8]> + AsMut<[u8]>>(data: &'a DataIndication, buffer: &'a mut T) {
257 let mut frame = Frame::new_unchecked(buffer);
258
259 // TODO: complete frame creation
260 frame.set_frame_type(Ieee802154FrameType::Data);
261 frame.set_dst_addr(data.dst_address.into());
262 frame.set_src_addr(data.src_address.into());
263 frame.set_dst_pan_id(data.dst_pan_id.into());
264 frame.set_src_pan_id(data.src_pan_id.into());
265 frame.set_sequence_number(data.dsn);
266
267 // No way around the copy with the current API
268 frame.payload_mut().unwrap().copy_from_slice(data.payload());
269}
270
253/// MLME POLL Indication which will be used for indicating the Data Request 271/// MLME POLL Indication which will be used for indicating the Data Request
254/// reception to upper layer as defined in Zigbee r22 - D.8.2 272/// reception to upper layer as defined in Zigbee r22 - D.8.2
255#[repr(C)] 273#[repr(C)]
diff --git a/embassy-stm32-wpan/src/mac/runner.rs b/embassy-stm32-wpan/src/mac/runner.rs
index 92c74c2ee..acca70019 100644
--- a/embassy-stm32-wpan/src/mac/runner.rs
+++ b/embassy-stm32-wpan/src/mac/runner.rs
@@ -6,12 +6,13 @@ use embassy_sync::blocking_mutex::raw::{CriticalSectionRawMutex, NoopRawMutex};
6use embassy_sync::channel::Channel; 6use embassy_sync::channel::Channel;
7use embassy_sync::mutex::Mutex; 7use embassy_sync::mutex::Mutex;
8use embassy_sync::signal::Signal; 8use embassy_sync::signal::Signal;
9use smoltcp::wire::Ieee802154FrameType;
10use smoltcp::wire::ieee802154::Frame;
9 11
10use crate::mac::MTU; 12use crate::mac::MTU;
11use crate::mac::commands::*; 13use crate::mac::commands::*;
12use crate::mac::driver::NetworkState; 14use crate::mac::driver::NetworkState;
13use crate::mac::event::MacEvent; 15use crate::mac::event::MacEvent;
14use crate::mac::typedefs::*;
15use crate::sub::mac::{MacRx, MacTx}; 16use crate::sub::mac::{MacRx, MacTx};
16 17
17pub type ZeroCopyPubSub<M, T> = blocking_mutex::Mutex<M, RefCell<Option<Signal<NoopRawMutex, T>>>>; 18pub type ZeroCopyPubSub<M, T> = blocking_mutex::Mutex<M, RefCell<Option<Signal<NoopRawMutex, T>>>>;
@@ -68,55 +69,75 @@ impl<'a> Runner<'a> {
68 } 69 }
69 } 70 }
70 71
72 async fn send_request<T: MacCommand, U: TryInto<T>>(&self, frame: U) -> Result<(), ()>
73 where
74 (): From<<U as TryInto<T>>::Error>,
75 {
76 let request: T = frame.try_into()?;
77 self.mac_tx.lock().await.send_command(&request).await.map_err(|_| ())?;
78
79 Ok(())
80 }
81
71 pub async fn run(&'a self) -> ! { 82 pub async fn run(&'a self) -> ! {
72 join::join( 83 join::join(
73 async { 84 async {
74 loop { 85 loop {
75 if let Ok(mac_event) = self.mac_rx.read().await { 86 if let Ok(mac_event) = self.mac_rx.read().await {
76 match mac_event { 87 match mac_event {
88 MacEvent::MlmeAssociateCnf(_)
89 | MacEvent::MlmeDisassociateCnf(_)
90 | MacEvent::MlmeGetCnf(_)
91 | MacEvent::MlmeGtsCnf(_)
92 | MacEvent::MlmeResetCnf(_)
93 | MacEvent::MlmeRxEnableCnf(_)
94 | MacEvent::MlmeScanCnf(_)
95 | MacEvent::MlmeSetCnf(_)
96 | MacEvent::MlmeStartCnf(_)
97 | MacEvent::MlmePollCnf(_)
98 | MacEvent::MlmeDpsCnf(_)
99 | MacEvent::MlmeSoundingCnf(_)
100 | MacEvent::MlmeCalibrateCnf(_)
101 | MacEvent::McpsDataCnf(_)
102 | MacEvent::McpsPurgeCnf(_) => {
103 self.rx_event_channel.lock(|s| {
104 s.borrow().as_ref().map(|signal| signal.signal(mac_event));
105 });
106 }
77 MacEvent::McpsDataInd(_) => { 107 MacEvent::McpsDataInd(_) => {
108 // Pattern should match driver
78 self.rx_data_channel.send(mac_event).await; 109 self.rx_data_channel.send(mac_event).await;
79 } 110 }
80 _ => { 111 _ => {
81 self.rx_event_channel.lock(|s| { 112 debug!("unhandled mac event: {:#x}", mac_event);
82 s.borrow().as_ref().map(|signal| signal.signal(mac_event));
83 });
84 } 113 }
85 } 114 }
86 } 115 }
87 } 116 }
88 }, 117 },
89 async { 118 async {
90 let mut msdu_handle = 0x02;
91
92 loop { 119 loop {
93 let (buf, len) = self.tx_data_channel.receive().await; 120 let (buf, _) = self.tx_data_channel.receive().await;
94 let mac_tx = self.mac_tx.lock().await; 121
95 122 // Smoltcp has created this frame, so there's no need to reparse it.
96 let pan_id = critical_section::with(|cs| self.network_state.borrow(cs).borrow().pan_id); 123 let frame = Frame::new_unchecked(&buf);
97 124
98 // TODO: get the destination address from the packet instead of using the broadcast address 125 let result: Result<(), ()> = match frame.frame_type() {
99 126 Ieee802154FrameType::Beacon => Err(()),
100 // The mutex should be dropped on the next loop iteration 127 Ieee802154FrameType::Data => self.send_request::<DataRequest, _>(frame).await,
101 mac_tx 128 Ieee802154FrameType::Acknowledgement => Err(()),
102 .send_command( 129 Ieee802154FrameType::MacCommand => Err(()),
103 DataRequest { 130 Ieee802154FrameType::Multipurpose => Err(()),
104 src_addr_mode: AddressMode::Short, 131 Ieee802154FrameType::FragmentOrFrak => Err(()),
105 dst_addr_mode: AddressMode::Short, 132 Ieee802154FrameType::Extended => Err(()),
106 dst_pan_id: PanId(pan_id), 133 _ => Err(()),
107 dst_address: MacAddress::BROADCAST, 134 };
108 msdu_handle: msdu_handle, 135
109 ack_tx: 0x00, 136 if result.is_err() {
110 gts_tx: false, 137 debug!("failed to parse mac frame");
111 security_level: SecurityLevel::Unsecure, 138 } else {
112 ..Default::default() 139 trace!("data frame sent!");
113 } 140 }
114 .set_buffer(&buf[..len]),
115 )
116 .await
117 .unwrap();
118
119 msdu_handle = msdu_handle.wrapping_add(1);
120 141
121 // The tx channel should always be of equal capacity to the tx_buf channel 142 // The tx channel should always be of equal capacity to the tx_buf channel
122 self.tx_buf_channel.try_send(buf).unwrap(); 143 self.tx_buf_channel.try_send(buf).unwrap();
diff --git a/embassy-stm32-wpan/src/mac/typedefs.rs b/embassy-stm32-wpan/src/mac/typedefs.rs
index 0552b8ea1..44028bf47 100644
--- a/embassy-stm32-wpan/src/mac/typedefs.rs
+++ b/embassy-stm32-wpan/src/mac/typedefs.rs
@@ -1,4 +1,5 @@
1use core::fmt::Debug; 1use core::fmt::Debug;
2use smoltcp::wire::ieee802154::{Address, AddressingMode, Pan};
2 3
3use crate::numeric_enum; 4use crate::numeric_enum;
4 5
@@ -109,12 +110,41 @@ numeric_enum! {
109} 110}
110} 111}
111 112
113impl TryFrom<AddressingMode> for AddressMode {
114 type Error = ();
115
116 fn try_from(value: AddressingMode) -> Result<Self, Self::Error> {
117 match value {
118 AddressingMode::Absent => Ok(Self::NoAddress),
119 AddressingMode::Extended => Ok(Self::Extended),
120 AddressingMode::Short => Ok(Self::Short),
121 AddressingMode::Unknown(_) => Err(()),
122 }
123 }
124}
125
112#[derive(Clone, Copy)] 126#[derive(Clone, Copy)]
113pub union MacAddress { 127pub union MacAddress {
114 pub short: [u8; 2], 128 pub short: [u8; 2],
115 pub extended: [u8; 8], 129 pub extended: [u8; 8],
116} 130}
117 131
132impl From<Address> for MacAddress {
133 fn from(value: Address) -> Self {
134 match value {
135 Address::Short(addr) => Self { short: addr },
136 Address::Extended(addr) => Self { extended: addr },
137 Address::Absent => Self { short: [0u8; 2] },
138 }
139 }
140}
141
142impl From<MacAddress> for Address {
143 fn from(_value: MacAddress) -> Self {
144 todo!()
145 }
146}
147
118impl Debug for MacAddress { 148impl Debug for MacAddress {
119 fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 149 fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
120 unsafe { 150 unsafe {
@@ -379,3 +409,15 @@ pub struct PanId(pub [u8; 2]);
379impl PanId { 409impl PanId {
380 pub const BROADCAST: Self = Self([0xFF, 0xFF]); 410 pub const BROADCAST: Self = Self([0xFF, 0xFF]);
381} 411}
412
413impl From<Pan> for PanId {
414 fn from(value: Pan) -> Self {
415 Self(value.0.to_be_bytes())
416 }
417}
418
419impl From<PanId> for Pan {
420 fn from(value: PanId) -> Self {
421 Self(u16::from_be_bytes(value.0))
422 }
423}