use core::{mem, ptr}; use super::indications::{ AssociateIndication, BeaconNotifyIndication, CommStatusIndication, DataIndication, DisassociateIndication, DpsIndication, GtsIndication, OrphanIndication, PollIndication, SyncLossIndication, }; use super::responses::{ AssociateConfirm, CalibrateConfirm, DataConfirm, DisassociateConfirm, DpsConfirm, GetConfirm, GtsConfirm, PollConfirm, PurgeConfirm, ResetConfirm, RxEnableConfirm, ScanConfirm, SetConfirm, SoundingConfirm, StartConfirm, }; use crate::evt::{EvtBox, MemoryManager}; use crate::mac::opcodes::OpcodeM0ToM4; use crate::sub::mac::{self, Mac}; pub(crate) trait ParseableMacEvent: Sized { fn from_buffer<'a>(buf: &'a [u8]) -> Result<&'a Self, ()> { if buf.len() < mem::size_of::() { Err(()) } else { Ok(unsafe { &*(buf as *const _ as *const Self) }) } } } #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive(Debug)] pub enum MacEvent<'a> { MlmeAssociateCnf(&'a AssociateConfirm), MlmeDisassociateCnf(&'a DisassociateConfirm), MlmeGetCnf(&'a GetConfirm), MlmeGtsCnf(&'a GtsConfirm), MlmeResetCnf(&'a ResetConfirm), MlmeRxEnableCnf(&'a RxEnableConfirm), MlmeScanCnf(&'a ScanConfirm), MlmeSetCnf(&'a SetConfirm), MlmeStartCnf(&'a StartConfirm), MlmePollCnf(&'a PollConfirm), MlmeDpsCnf(&'a DpsConfirm), MlmeSoundingCnf(&'a SoundingConfirm), MlmeCalibrateCnf(&'a CalibrateConfirm), McpsDataCnf(&'a DataConfirm), McpsPurgeCnf(&'a PurgeConfirm), MlmeAssociateInd(&'a AssociateIndication), MlmeDisassociateInd(&'a DisassociateIndication), MlmeBeaconNotifyInd(&'a BeaconNotifyIndication), MlmeCommStatusInd(&'a CommStatusIndication), MlmeGtsInd(&'a GtsIndication), MlmeOrphanInd(&'a OrphanIndication), MlmeSyncLossInd(&'a SyncLossIndication), MlmeDpsInd(&'a DpsIndication), McpsDataInd(&'a DataIndication), MlmePollInd(&'a PollIndication), } impl<'a> MacEvent<'a> { pub(crate) fn new(event_box: EvtBox) -> Result { let payload = event_box.payload(); let opcode = u16::from_le_bytes(payload[0..2].try_into().unwrap()); let opcode = OpcodeM0ToM4::try_from(opcode)?; let buf = &payload[2..]; // To avoid re-parsing the opcode, we store the result of the parse // this requires use of unsafe because rust cannot assume that a reference will become // invalid when the underlying result is moved. However, because we refer to a "heap" // allocation, the underlying reference will not move until the struct is dropped. let mac_event = match opcode { OpcodeM0ToM4::MlmeAssociateCnf => { MacEvent::MlmeAssociateCnf(unsafe { &*(AssociateConfirm::from_buffer(buf)? as *const _) }) } OpcodeM0ToM4::MlmeDisassociateCnf => { MacEvent::MlmeDisassociateCnf(unsafe { &*(DisassociateConfirm::from_buffer(buf)? as *const _) }) } OpcodeM0ToM4::MlmeGetCnf => MacEvent::MlmeGetCnf(unsafe { &*(GetConfirm::from_buffer(buf)? as *const _) }), OpcodeM0ToM4::MlmeGtsCnf => MacEvent::MlmeGtsCnf(unsafe { &*(GtsConfirm::from_buffer(buf)? as *const _) }), OpcodeM0ToM4::MlmeResetCnf => { MacEvent::MlmeResetCnf(unsafe { &*(ResetConfirm::from_buffer(buf)? as *const _) }) } OpcodeM0ToM4::MlmeRxEnableCnf => { MacEvent::MlmeRxEnableCnf(unsafe { &*(RxEnableConfirm::from_buffer(buf)? as *const _) }) } OpcodeM0ToM4::MlmeScanCnf => { MacEvent::MlmeScanCnf(unsafe { &*(ScanConfirm::from_buffer(buf)? as *const _) }) } OpcodeM0ToM4::MlmeSetCnf => MacEvent::MlmeSetCnf(unsafe { &*(SetConfirm::from_buffer(buf)? as *const _) }), OpcodeM0ToM4::MlmeStartCnf => { MacEvent::MlmeStartCnf(unsafe { &*(StartConfirm::from_buffer(buf)? as *const _) }) } OpcodeM0ToM4::MlmePollCnf => { MacEvent::MlmePollCnf(unsafe { &*(PollConfirm::from_buffer(buf)? as *const _) }) } OpcodeM0ToM4::MlmeDpsCnf => MacEvent::MlmeDpsCnf(unsafe { &*(DpsConfirm::from_buffer(buf)? as *const _) }), OpcodeM0ToM4::MlmeSoundingCnf => { MacEvent::MlmeSoundingCnf(unsafe { &*(SoundingConfirm::from_buffer(buf)? as *const _) }) } OpcodeM0ToM4::MlmeCalibrateCnf => { MacEvent::MlmeCalibrateCnf(unsafe { &*(CalibrateConfirm::from_buffer(buf)? as *const _) }) } OpcodeM0ToM4::McpsDataCnf => { MacEvent::McpsDataCnf(unsafe { &*(DataConfirm::from_buffer(buf)? as *const _) }) } OpcodeM0ToM4::McpsPurgeCnf => { MacEvent::McpsPurgeCnf(unsafe { &*(PurgeConfirm::from_buffer(buf)? as *const _) }) } OpcodeM0ToM4::MlmeAssociateInd => { MacEvent::MlmeAssociateInd(unsafe { &*(AssociateIndication::from_buffer(buf)? as *const _) }) } OpcodeM0ToM4::MlmeDisassociateInd => { MacEvent::MlmeDisassociateInd(unsafe { &*(DisassociateIndication::from_buffer(buf)? as *const _) }) } OpcodeM0ToM4::MlmeBeaconNotifyInd => { MacEvent::MlmeBeaconNotifyInd(unsafe { &*(BeaconNotifyIndication::from_buffer(buf)? as *const _) }) } OpcodeM0ToM4::MlmeCommStatusInd => { MacEvent::MlmeCommStatusInd(unsafe { &*(CommStatusIndication::from_buffer(buf)? as *const _) }) } OpcodeM0ToM4::MlmeGtsInd => { MacEvent::MlmeGtsInd(unsafe { &*(GtsIndication::from_buffer(buf)? as *const _) }) } OpcodeM0ToM4::MlmeOrphanInd => { MacEvent::MlmeOrphanInd(unsafe { &*(OrphanIndication::from_buffer(buf)? as *const _) }) } OpcodeM0ToM4::MlmeSyncLossInd => { MacEvent::MlmeSyncLossInd(unsafe { &*(SyncLossIndication::from_buffer(buf)? as *const _) }) } OpcodeM0ToM4::MlmeDpsInd => { MacEvent::MlmeDpsInd(unsafe { &*(DpsIndication::from_buffer(buf)? as *const _) }) } OpcodeM0ToM4::McpsDataInd => { MacEvent::McpsDataInd(unsafe { &*(DataIndication::from_buffer(buf)? as *const _) }) } OpcodeM0ToM4::MlmePollInd => { MacEvent::MlmePollInd(unsafe { &*(PollIndication::from_buffer(buf)? as *const _) }) } }; // Forget the event box so that drop isn't called // We want to handle the lifetime ourselves mem::forget(event_box); Ok(mac_event) } } unsafe impl<'a> Send for MacEvent<'a> {} impl<'a> Drop for MacEvent<'a> { fn drop(&mut self) { unsafe { mac::Mac::drop_event_packet(ptr::null_mut()) }; } }