diff options
| author | xoviat <[email protected]> | 2025-11-17 11:16:55 -0600 |
|---|---|---|
| committer | xoviat <[email protected]> | 2025-11-17 11:16:55 -0600 |
| commit | 26038cfbc60e9a7b64d70ade51e9e9f34c912e2e (patch) | |
| tree | c154fccb98da0b182f1abfc7390dbc21dc8a2295 | |
| parent | 80ceb42eb1c842fcb214a5fbfbb1c39265c6b29b (diff) | |
wpan: parse frames correctly
| -rw-r--r-- | embassy-stm32-wpan/Cargo.toml | 3 | ||||
| -rw-r--r-- | embassy-stm32-wpan/src/mac/commands.rs | 26 | ||||
| -rw-r--r-- | embassy-stm32-wpan/src/mac/driver.rs | 12 | ||||
| -rw-r--r-- | embassy-stm32-wpan/src/mac/indications.rs | 18 | ||||
| -rw-r--r-- | embassy-stm32-wpan/src/mac/runner.rs | 87 | ||||
| -rw-r--r-- | embassy-stm32-wpan/src/mac/typedefs.rs | 42 |
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" } | |||
| 33 | embassy-hal-internal = { version = "0.3.0", path = "../embassy-hal-internal" } | 33 | embassy-hal-internal = { version = "0.3.0", path = "../embassy-hal-internal" } |
| 34 | embassy-embedded-hal = { version = "0.5.0", path = "../embassy-embedded-hal" } | 34 | embassy-embedded-hal = { version = "0.5.0", path = "../embassy-embedded-hal" } |
| 35 | embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver", optional=true } | 35 | embassy-net-driver = { version = "0.2.0", path = "../embassy-net-driver", optional=true } |
| 36 | smoltcp = { version = "0.12.0", optional=true, default-features = false } | ||
| 36 | 37 | ||
| 37 | defmt = { version = "1.0.1", optional = true } | 38 | defmt = { version = "1.0.1", optional = true } |
| 38 | log = { version = "0.4.17", optional = true } | 39 | log = { version = "0.4.17", optional = true } |
| @@ -52,7 +53,7 @@ bitflags = { version = "2.3.3", optional = true } | |||
| 52 | defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-internal/defmt", "stm32wb-hci?/defmt"] | 53 | defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embassy-hal-internal/defmt", "stm32wb-hci?/defmt"] |
| 53 | 54 | ||
| 54 | ble = ["dep:stm32wb-hci"] | 55 | ble = ["dep:stm32wb-hci"] |
| 55 | mac = ["dep:bitflags", "dep:embassy-net-driver" ] | 56 | mac = ["dep:bitflags", "dep:embassy-net-driver", "dep:smoltcp", "smoltcp/medium-ieee802154"] |
| 56 | 57 | ||
| 57 | extended = [] | 58 | extended = [] |
| 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 | ||
| 11 | use smoltcp::wire::ieee802154::Frame; | ||
| 12 | |||
| 11 | pub trait MacCommand: Sized { | 13 | pub 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 | ||
| 384 | impl<'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 | |||
| 382 | impl Default for DataRequest { | 408 | impl 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; | |||
| 11 | use embassy_sync::waitqueue::AtomicWaker; | 11 | use embassy_sync::waitqueue::AtomicWaker; |
| 12 | 12 | ||
| 13 | use crate::mac::event::MacEvent; | 13 | use crate::mac::event::MacEvent; |
| 14 | use crate::mac::indications::write_frame_from_data_indication; | ||
| 14 | use crate::mac::runner::{BUF_SIZE, ZeroCopyPubSub}; | 15 | use crate::mac::runner::{BUF_SIZE, ZeroCopyPubSub}; |
| 15 | use crate::mac::{Control, MTU, Runner}; | 16 | use crate::mac::{Control, MTU, Runner}; |
| 16 | use crate::sub::mac::{Mac, MacRx, MacTx}; | 17 | use 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 | ||
| 10 | use smoltcp::wire::Ieee802154FrameType; | ||
| 11 | use 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 | ||
| 256 | pub 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}; | |||
| 6 | use embassy_sync::channel::Channel; | 6 | use embassy_sync::channel::Channel; |
| 7 | use embassy_sync::mutex::Mutex; | 7 | use embassy_sync::mutex::Mutex; |
| 8 | use embassy_sync::signal::Signal; | 8 | use embassy_sync::signal::Signal; |
| 9 | use smoltcp::wire::Ieee802154FrameType; | ||
| 10 | use smoltcp::wire::ieee802154::Frame; | ||
| 9 | 11 | ||
| 10 | use crate::mac::MTU; | 12 | use crate::mac::MTU; |
| 11 | use crate::mac::commands::*; | 13 | use crate::mac::commands::*; |
| 12 | use crate::mac::driver::NetworkState; | 14 | use crate::mac::driver::NetworkState; |
| 13 | use crate::mac::event::MacEvent; | 15 | use crate::mac::event::MacEvent; |
| 14 | use crate::mac::typedefs::*; | ||
| 15 | use crate::sub::mac::{MacRx, MacTx}; | 16 | use crate::sub::mac::{MacRx, MacTx}; |
| 16 | 17 | ||
| 17 | pub type ZeroCopyPubSub<M, T> = blocking_mutex::Mutex<M, RefCell<Option<Signal<NoopRawMutex, T>>>>; | 18 | pub 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 @@ | |||
| 1 | use core::fmt::Debug; | 1 | use core::fmt::Debug; |
| 2 | use smoltcp::wire::ieee802154::{Address, AddressingMode, Pan}; | ||
| 2 | 3 | ||
| 3 | use crate::numeric_enum; | 4 | use crate::numeric_enum; |
| 4 | 5 | ||
| @@ -109,12 +110,41 @@ numeric_enum! { | |||
| 109 | } | 110 | } |
| 110 | } | 111 | } |
| 111 | 112 | ||
| 113 | impl 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)] |
| 113 | pub union MacAddress { | 127 | pub 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 | ||
| 132 | impl 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 | |||
| 142 | impl From<MacAddress> for Address { | ||
| 143 | fn from(_value: MacAddress) -> Self { | ||
| 144 | todo!() | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 118 | impl Debug for MacAddress { | 148 | impl 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]); | |||
| 379 | impl PanId { | 409 | impl PanId { |
| 380 | pub const BROADCAST: Self = Self([0xFF, 0xFF]); | 410 | pub const BROADCAST: Self = Self([0xFF, 0xFF]); |
| 381 | } | 411 | } |
| 412 | |||
| 413 | impl From<Pan> for PanId { | ||
| 414 | fn from(value: Pan) -> Self { | ||
| 415 | Self(value.0.to_be_bytes()) | ||
| 416 | } | ||
| 417 | } | ||
| 418 | |||
| 419 | impl From<PanId> for Pan { | ||
| 420 | fn from(value: PanId) -> Self { | ||
| 421 | Self(u16::from_be_bytes(value.0)) | ||
| 422 | } | ||
| 423 | } | ||
