Skip to content

Commit

Permalink
Make indirect indications possible
Browse files Browse the repository at this point in the history
  • Loading branch information
diondokter committed Feb 21, 2025
1 parent 464e5b7 commit 496a362
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 24 deletions.
20 changes: 17 additions & 3 deletions lr-wpan-rs/src/mac/commander.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
use crate::{
allocation::{Allocated, Allocation},
reqresp::ReqResp,
reqresp::{ReqResp, RequestFuture},
sap::{
ConfirmValue, DynamicRequest, Indication, IndicationValue, Request, RequestValue,
ResponseValue,
},
};

pub const CHANNEL_SIZE: usize = 4;

/// The main interface to the MAC layer. It can be used to make requests and receive indications
pub struct MacCommander {
request_confirm_channel: ReqResp<RequestValue, ConfirmValue, 4>,
indication_response_channel: ReqResp<IndicationValue, ResponseValue, 4>,
request_confirm_channel: ReqResp<RequestValue, ConfirmValue, CHANNEL_SIZE>,
indication_response_channel: ReqResp<IndicationValue, ResponseValue, CHANNEL_SIZE>,
}

impl MacCommander {
Expand Down Expand Up @@ -85,8 +87,12 @@ impl Default for MacCommander {
}
}

pub type IndicateIndirectFuture<'a> =
RequestFuture<'a, IndicationValue, ResponseValue, CHANNEL_SIZE>;

pub(crate) struct MacHandler<'a> {
commander: &'a MacCommander,

}

impl MacHandler<'_> {
Expand All @@ -99,6 +105,14 @@ impl MacHandler<'_> {
.into()
}

/// Send an indication, but don't immediately wait on it.
/// Instead the response wait is put in a buffer so it can be dealt with later.
pub fn indicate_indirect<I: Indication>(&self, indication: I) -> IndicateIndirectFuture<'_> {
self.commander
.indication_response_channel
.request(indication.into())
}

pub async fn wait_for_request(&self) -> RequestResponder<'_, RequestValue> {
let (id, request) = self
.commander
Expand Down
22 changes: 16 additions & 6 deletions lr-wpan-rs/src/mac/mlme_associate.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
use super::{
callback::DataRequestCallback,
commander::RequestResponder,
commander::{MacHandler, RequestResponder},
state::{DataRequestMode, MacState, ScheduledDataRequest},
};
use crate::{
phy::{Phy, SendContinuation, SendResult},
pib::MacPib,
sap::{
associate::{AssociateConfirm, AssociateRequest},
associate::{AssociateConfirm, AssociateIndication, AssociateRequest},
SecurityInfo, Status,
},
wire::{
command::Command, Address, Frame, FrameContent, FrameType, FrameVersion, Header, PanId,
ShortAddress,
},
command::{CapabilityInformation, Command}, Address, ExtendedAddress, Frame, FrameContent, FrameType, FrameVersion, Header, PanId, ShortAddress
}, DeviceAddress,
};

pub async fn process_associate_request<'a>(
Expand Down Expand Up @@ -152,7 +151,7 @@ pub async fn process_associate_request<'a>(
return;
};

debug!("Association procedure now waiting until");
debug!("Association procedure now waiting until the response can be requested");

// We have received the ack to our association request.
// Now we must wait and request our data later.
Expand All @@ -172,3 +171,14 @@ pub async fn process_associate_request<'a>(
callback: DataRequestCallback::AssociationProcedure(responder),
});
}

// Received from the radio, not as an MLME request
pub async fn process_received_associate_request(mac_handler: &MacHandler<'_>, device_address: ExtendedAddress, capability_information: CapabilityInformation) {
let indirect_response = mac_handler.indicate_indirect(AssociateIndication {
device_address,
capability_information,
security_info: SecurityInfo::new_none_security(),
});

// TODO: Store the indirect_response and await it later
}
20 changes: 20 additions & 0 deletions lr-wpan-rs/src/mac/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -837,5 +837,25 @@ async fn process_message<P: Phy>(
});
}

match frame.content {
FrameContent::Command(Command::AssociationRequest(capability_info)) => {
match frame.header.source {
Some(Address::Extended(_, device_address)) => {
mlme_associate::process_received_associate_request(
mac_handler,
device_address,
capability_info,
)
.await
}
_ => warn!("Association request came from frame without correct source field"),
}
}
content => warn!(
"Received frame has content we don't yet process: {}",
content
),
}

next_event
}
2 changes: 1 addition & 1 deletion lr-wpan-rs/src/pib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,7 @@ impl MacPib {
min_be: 0,
pan_id: PanId::broadcast(),
promiscuous_mode: false,
response_wait_time: 2,
response_wait_time: 64,
rx_on_when_idle: false,
security_enabled: false,
short_address: ShortAddress::BROADCAST,
Expand Down
56 changes: 43 additions & 13 deletions lr-wpan-rs/src/reqresp.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
use core::sync::atomic::{AtomicU32, Ordering};

use embassy_futures::join::join;
use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, channel::Channel};
use maitake_sync::WaitMap;
use core::{
future::Future,
sync::atomic::{AtomicU32, Ordering},
task::Poll,
};

use embassy_futures::join::{join, Join};
use embassy_sync::{
blocking_mutex::raw::CriticalSectionRawMutex,
channel::{Channel, SendFuture},
};
use maitake_sync::{wait_map::Wait, WaitMap};

pub struct ReqResp<Request, Response, const N: usize> {
requests: Channel<CriticalSectionRawMutex, (u32, Request), N>,
Expand All @@ -19,16 +26,15 @@ impl<Request, Response, const N: usize> ReqResp<Request, Response, N> {
}
}

pub async fn request(&self, request: Request) -> Response {
pub fn request(&self, request: Request) -> RequestFuture<Request, Response, N> {
let current_id = self.next_id.fetch_add(1, Ordering::Relaxed);

let (response, _) = join(
self.responses.wait(current_id),
self.requests.send((current_id, request)),
)
.await;

response.expect("Always succeeds because we use a unique ID")
RequestFuture {
inner: join(
self.responses.wait(current_id),
self.requests.send((current_id, request)),
),
}
}

pub async fn wait_for_request(&self) -> (u32, Request) {
Expand All @@ -40,6 +46,30 @@ impl<Request, Response, const N: usize> ReqResp<Request, Response, N> {
}
}

pub struct RequestFuture<'a, Request, Response, const N: usize> {
inner:
Join<Wait<'a, u32, Response>, SendFuture<'a, CriticalSectionRawMutex, (u32, Request), N>>,
}

impl<'a, Request, Response, const N: usize> Future for RequestFuture<'a, Request, Response, N> {
type Output = Response;

fn poll(
self: core::pin::Pin<&mut Self>,
cx: &mut core::task::Context<'_>,
) -> Poll<Self::Output> {
// Safety: Inner is just as pinned as the outer, so it should be safe to project
let inner = unsafe { core::pin::Pin::new_unchecked(&mut self.get_unchecked_mut().inner) };

match inner.poll(cx) {
Poll::Ready((response, _)) => {
Poll::Ready(response.expect("Always succeeds because we use a unique ID"))
}
Poll::Pending => Poll::Pending,
}
}
}

#[cfg(test)]
mod tests {
use embassy_futures::join::join_array;
Expand Down
4 changes: 3 additions & 1 deletion lr-wpan-rs/src/wire/frame/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub mod security;
use byte::{ctx::Bytes, BytesExt, TryRead, TryWrite, LE};
use ccm::aead::generic_array::typenum::consts::U16;
use cipher::{BlockCipher, BlockEncrypt, NewBlockCipher};
use derive_more::Display;
use header::FrameType;
pub use header::Header;

Expand Down Expand Up @@ -387,8 +388,9 @@ impl Default for FooterMode {
}

/// Content of a frame
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[derive(Clone, Debug, Eq, Hash, PartialEq, Display)]
#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
#[display("{self:?}")]
pub enum FrameContent {
/// Beacon frame content
Beacon(Beacon),
Expand Down

0 comments on commit 496a362

Please sign in to comment.