use core::cell::RefCell; use core::future::Future; use core::sync::atomic::{Ordering, compiler_fence}; use core::task; use core::task::Poll; use embassy_net_driver::LinkState; use embassy_sync::blocking_mutex; use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; use embassy_sync::mutex::Mutex; use embassy_sync::signal::Signal; use futures_util::FutureExt; use crate::mac::commands::*; use crate::mac::driver::NetworkState; use crate::mac::event::MacEvent; use crate::mac::runner::ZeroCopyPubSub; use crate::mac::typedefs::*; use crate::sub::mac::MacTx; pub struct Control<'a> { rx_event_channel: &'a ZeroCopyPubSub>, mac_tx: &'a Mutex>, #[allow(unused)] network_state: &'a blocking_mutex::Mutex>, } impl<'a> Control<'a> { pub(crate) fn new( rx_event_channel: &'a ZeroCopyPubSub>, mac_tx: &'a Mutex>, network_state: &'a blocking_mutex::Mutex>, ) -> Self { Self { rx_event_channel, mac_tx, network_state, } } pub async fn init_link(&mut self, pan_id: [u8; 2]) { debug!("resetting"); debug!( "{:#x}", self.send_command_and_get_response(&ResetRequest { set_default_pib: true, ..Default::default() }) .await .unwrap() .await ); let (short_address, mac_address) = critical_section::with(|cs| { let mut network_state = self.network_state.borrow(cs).borrow_mut(); network_state.pan_id = pan_id; (network_state.short_addr, network_state.mac_addr) }); debug!("setting extended address"); debug!( "{:#x}", self.send_command_and_get_response(&SetRequest { pib_attribute_ptr: &u64::from_be_bytes(mac_address) as *const _ as *const u8, pib_attribute: PibId::ExtendedAddress, }) .await .unwrap() .await ); debug!("setting short address"); debug!( "{:#x}", self.send_command_and_get_response(&SetRequest { pib_attribute_ptr: &u16::from_be_bytes(short_address) as *const _ as *const u8, pib_attribute: PibId::ShortAddress, }) .await .unwrap() .await ); debug!("setting association permit"); let association_permit: bool = true; debug!( "{:#x}", self.send_command_and_get_response(&SetRequest { pib_attribute_ptr: &association_permit as *const _ as *const u8, pib_attribute: PibId::AssociationPermit, }) .await .unwrap() .await ); debug!("setting TX power"); let transmit_power: i8 = 2; debug!( "{:#x}", self.send_command_and_get_response(&SetRequest { pib_attribute_ptr: &transmit_power as *const _ as *const u8, pib_attribute: PibId::TransmitPower, }) .await .unwrap() .await ); debug!("starting FFD device"); debug!( "{:#x}", self.send_command_and_get_response(&StartRequest { pan_id: PanId(pan_id), channel_number: MacChannel::Channel16, beacon_order: 0x0F, superframe_order: 0x0F, pan_coordinator: true, battery_life_extension: false, ..Default::default() }) .await .unwrap() .await ); debug!("setting RX on when idle"); let rx_on_while_idle: bool = true; debug!( "{:#x}", self.send_command_and_get_response(&SetRequest { pib_attribute_ptr: &rx_on_while_idle as *const _ as *const u8, pib_attribute: PibId::RxOnWhenIdle, }) .await .unwrap() .await ); critical_section::with(|cs| { let mut network_state = self.network_state.borrow(cs).borrow_mut(); network_state.link_state = LinkState::Up; network_state.link_waker.wake(); }); } pub async fn send_command(&self, cmd: &T) -> Result<(), MacError> where T: MacCommand, { self.mac_tx.lock().await.send_command(cmd).await } pub async fn send_command_and_get_response(&self, cmd: &T) -> Result, MacError> where T: MacCommand, { let token = EventToken::new(self.rx_event_channel); compiler_fence(Ordering::Release); self.mac_tx.lock().await.send_command(cmd).await?; Ok(token) } } pub struct EventToken<'a> { rx_event_channel: &'a ZeroCopyPubSub>, } impl<'a> EventToken<'a> { pub(crate) fn new(rx_event_channel: &'a ZeroCopyPubSub>) -> Self { // Enable event receiving rx_event_channel.lock(|s| { *s.borrow_mut() = Some(Signal::new()); }); Self { rx_event_channel } } } impl<'a> Future for EventToken<'a> { type Output = MacEvent<'a>; fn poll(self: core::pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll { self.rx_event_channel .lock(|s| s.borrow_mut().as_mut().unwrap().wait().poll_unpin(cx)) } } impl<'a> Drop for EventToken<'a> { fn drop(&mut self) { // Disable event receiving // This will also drop the contained event, if it exists, and will free up receiving the next event self.rx_event_channel.lock(|s| { *s.borrow_mut() = None; }); } }