parse data from device in-place
This commit is contained in:
		@@ -328,45 +328,23 @@ where
 | 
			
		||||
                let len = (status & STATUS_F2_PKT_LEN_MASK) >> STATUS_F2_PKT_LEN_SHIFT;
 | 
			
		||||
                self.bus.wlan_read(buf, len).await;
 | 
			
		||||
                trace!("rx {:02x}", Bytes(&slice8_mut(buf)[..(len as usize).min(48)]));
 | 
			
		||||
                self.rx(&slice8_mut(buf)[..len as usize]);
 | 
			
		||||
                self.rx(&mut slice8_mut(buf)[..len as usize]);
 | 
			
		||||
            } else {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn rx(&mut self, packet: &[u8]) {
 | 
			
		||||
        if packet.len() < SdpcmHeader::SIZE {
 | 
			
		||||
            warn!("packet too short, len={}", packet.len());
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let sdpcm_header = SdpcmHeader::from_bytes(packet[..SdpcmHeader::SIZE].try_into().unwrap());
 | 
			
		||||
        trace!("rx {:?}", sdpcm_header);
 | 
			
		||||
        if sdpcm_header.len != !sdpcm_header.len_inv {
 | 
			
		||||
            warn!("len inv mismatch");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        if sdpcm_header.len as usize != packet.len() {
 | 
			
		||||
            // TODO: is this guaranteed??
 | 
			
		||||
            warn!("len from header doesn't match len from spi");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    fn rx(&mut self, packet: &mut [u8]) {
 | 
			
		||||
        let Some((sdpcm_header, payload)) = SdpcmHeader::parse(packet) else { return };
 | 
			
		||||
 | 
			
		||||
        self.update_credit(&sdpcm_header);
 | 
			
		||||
 | 
			
		||||
        let channel = sdpcm_header.channel_and_flags & 0x0f;
 | 
			
		||||
 | 
			
		||||
        let payload = &packet[sdpcm_header.header_length as _..];
 | 
			
		||||
 | 
			
		||||
        match channel {
 | 
			
		||||
            CHANNEL_TYPE_CONTROL => {
 | 
			
		||||
                if payload.len() < CdcHeader::SIZE {
 | 
			
		||||
                    warn!("payload too short, len={}", payload.len());
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                let cdc_header = CdcHeader::from_bytes(payload[..CdcHeader::SIZE].try_into().unwrap());
 | 
			
		||||
                let Some((cdc_header, response)) = CdcHeader::parse(payload) else { return; };
 | 
			
		||||
                trace!("    {:?}", cdc_header);
 | 
			
		||||
 | 
			
		||||
                if cdc_header.id == self.ioctl_id {
 | 
			
		||||
@@ -375,28 +353,21 @@ where
 | 
			
		||||
                        panic!("IOCTL error {}", cdc_header.status as i32);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    let resp_len = cdc_header.len as usize;
 | 
			
		||||
                    let response = &payload[CdcHeader::SIZE..][..resp_len];
 | 
			
		||||
                    info!("IOCTL Response: {:02x}", Bytes(response));
 | 
			
		||||
 | 
			
		||||
                    self.ioctl_state.ioctl_done(response);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            CHANNEL_TYPE_EVENT => {
 | 
			
		||||
                let bcd_header = BcdHeader::from_bytes(&payload[..BcdHeader::SIZE].try_into().unwrap());
 | 
			
		||||
                trace!("    {:?}", bcd_header);
 | 
			
		||||
 | 
			
		||||
                let packet_start = BcdHeader::SIZE + 4 * bcd_header.data_offset as usize;
 | 
			
		||||
 | 
			
		||||
                if packet_start + EventPacket::SIZE > payload.len() {
 | 
			
		||||
                let Some((_, bcd_packet)) = BcdHeader::parse(payload) else {
 | 
			
		||||
                    warn!("BCD event, incomplete header");
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                let bcd_packet = &payload[packet_start..];
 | 
			
		||||
                trace!("    {:02x}", Bytes(&bcd_packet[..(bcd_packet.len() as usize).min(36)]));
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                let mut event_packet = EventPacket::from_bytes(&bcd_packet[..EventPacket::SIZE].try_into().unwrap());
 | 
			
		||||
                event_packet.byteswap();
 | 
			
		||||
                let Some((event_packet, evt_data)) = EventPacket::parse(bcd_packet) else {
 | 
			
		||||
                    warn!("BCD event, incomplete data");
 | 
			
		||||
                    return;
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                const ETH_P_LINK_CTL: u16 = 0x886c; // HPNA, wlan link local tunnel, according to linux if_ether.h
 | 
			
		||||
                if event_packet.eth.ether_type != ETH_P_LINK_CTL {
 | 
			
		||||
@@ -427,13 +398,7 @@ where
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if event_packet.msg.datalen as usize >= (bcd_packet.len() - EventMessage::SIZE) {
 | 
			
		||||
                    warn!("BCD event, incomplete data");
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                let evt_type = events::Event::from(event_packet.msg.event_type as u8);
 | 
			
		||||
                let evt_data = &bcd_packet[EventMessage::SIZE..][..event_packet.msg.datalen as usize];
 | 
			
		||||
                debug!(
 | 
			
		||||
                    "=== EVENT {:?}: {:?} {:02x}",
 | 
			
		||||
                    evt_type,
 | 
			
		||||
@@ -449,16 +414,8 @@ where
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            CHANNEL_TYPE_DATA => {
 | 
			
		||||
                let bcd_header = BcdHeader::from_bytes(&payload[..BcdHeader::SIZE].try_into().unwrap());
 | 
			
		||||
                trace!("    {:?}", bcd_header);
 | 
			
		||||
 | 
			
		||||
                let packet_start = BcdHeader::SIZE + 4 * bcd_header.data_offset as usize;
 | 
			
		||||
                if packet_start > payload.len() {
 | 
			
		||||
                    warn!("packet start out of range.");
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                let packet = &payload[packet_start..];
 | 
			
		||||
                trace!("rx pkt {:02x}", Bytes(&packet[..(packet.len() as usize).min(48)]));
 | 
			
		||||
                let Some((_, packet)) = BcdHeader::parse(payload) else { return };
 | 
			
		||||
                trace!("rx pkt {:02x}", Bytes(&packet[..packet.len().min(48)]));
 | 
			
		||||
 | 
			
		||||
                match self.ch.try_rx_buf() {
 | 
			
		||||
                    Some(buf) => {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										149
									
								
								src/structs.rs
									
									
									
									
									
								
							
							
						
						
									
										149
									
								
								src/structs.rs
									
									
									
									
									
								
							@@ -1,4 +1,5 @@
 | 
			
		||||
use crate::events::Event;
 | 
			
		||||
use crate::fmt::Bytes;
 | 
			
		||||
 | 
			
		||||
macro_rules! impl_bytes {
 | 
			
		||||
    ($t:ident) => {
 | 
			
		||||
@@ -11,8 +12,28 @@ macro_rules! impl_bytes {
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            #[allow(unused)]
 | 
			
		||||
            pub fn from_bytes(bytes: &[u8; Self::SIZE]) -> Self {
 | 
			
		||||
                unsafe { core::mem::transmute(*bytes) }
 | 
			
		||||
            pub fn from_bytes(bytes: &[u8; Self::SIZE]) -> &Self {
 | 
			
		||||
                let alignment = core::mem::align_of::<Self>();
 | 
			
		||||
                assert_eq!(
 | 
			
		||||
                    bytes.as_ptr().align_offset(alignment),
 | 
			
		||||
                    0,
 | 
			
		||||
                    "{} is not aligned",
 | 
			
		||||
                    core::any::type_name::<Self>()
 | 
			
		||||
                );
 | 
			
		||||
                unsafe { core::mem::transmute(bytes) }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            #[allow(unused)]
 | 
			
		||||
            pub fn from_bytes_mut(bytes: &mut [u8; Self::SIZE]) -> &mut Self {
 | 
			
		||||
                let alignment = core::mem::align_of::<Self>();
 | 
			
		||||
                assert_eq!(
 | 
			
		||||
                    bytes.as_ptr().align_offset(alignment),
 | 
			
		||||
                    0,
 | 
			
		||||
                    "{} is not aligned",
 | 
			
		||||
                    core::any::type_name::<Self>()
 | 
			
		||||
                );
 | 
			
		||||
 | 
			
		||||
                unsafe { core::mem::transmute(bytes) }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
@@ -67,9 +88,35 @@ pub struct SdpcmHeader {
 | 
			
		||||
}
 | 
			
		||||
impl_bytes!(SdpcmHeader);
 | 
			
		||||
 | 
			
		||||
impl SdpcmHeader {
 | 
			
		||||
    pub fn parse(packet: &mut [u8]) -> Option<(&mut Self, &mut [u8])> {
 | 
			
		||||
        let packet_len = packet.len();
 | 
			
		||||
        if packet_len < Self::SIZE {
 | 
			
		||||
            warn!("packet too short, len={}", packet.len());
 | 
			
		||||
            return None;
 | 
			
		||||
        }
 | 
			
		||||
        let (sdpcm_header, sdpcm_packet) = packet.split_at_mut(Self::SIZE);
 | 
			
		||||
        let sdpcm_header = Self::from_bytes_mut(sdpcm_header.try_into().unwrap());
 | 
			
		||||
        trace!("rx {:?}", sdpcm_header);
 | 
			
		||||
 | 
			
		||||
        if sdpcm_header.len != !sdpcm_header.len_inv {
 | 
			
		||||
            warn!("len inv mismatch");
 | 
			
		||||
            return None;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if sdpcm_header.len as usize != packet_len {
 | 
			
		||||
            warn!("len from header doesn't match len from spi");
 | 
			
		||||
            return None;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let sdpcm_packet = &mut sdpcm_packet[(sdpcm_header.header_length as usize - Self::SIZE)..];
 | 
			
		||||
        Some((sdpcm_header, sdpcm_packet))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Copy)]
 | 
			
		||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 | 
			
		||||
#[repr(C)]
 | 
			
		||||
// #[cfg_attr(feature = "defmt", derive(defmt::Format))]
 | 
			
		||||
#[repr(C, packed(2))]
 | 
			
		||||
pub struct CdcHeader {
 | 
			
		||||
    pub cmd: u32,
 | 
			
		||||
    pub len: u32,
 | 
			
		||||
@@ -79,6 +126,21 @@ pub struct CdcHeader {
 | 
			
		||||
}
 | 
			
		||||
impl_bytes!(CdcHeader);
 | 
			
		||||
 | 
			
		||||
impl CdcHeader {
 | 
			
		||||
    pub fn parse(packet: &mut [u8]) -> Option<(&mut Self, &mut [u8])> {
 | 
			
		||||
        if packet.len() < Self::SIZE {
 | 
			
		||||
            warn!("payload too short, len={}", packet.len());
 | 
			
		||||
            return None;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let (cdc_header, payload) = packet.split_at_mut(Self::SIZE);
 | 
			
		||||
        let cdc_header = Self::from_bytes_mut(cdc_header.try_into().unwrap());
 | 
			
		||||
 | 
			
		||||
        let payload = &mut payload[..cdc_header.len as usize];
 | 
			
		||||
        Some((cdc_header, payload))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub const BDC_VERSION: u8 = 2;
 | 
			
		||||
pub const BDC_VERSION_SHIFT: u8 = 4;
 | 
			
		||||
 | 
			
		||||
@@ -95,6 +157,25 @@ pub struct BcdHeader {
 | 
			
		||||
}
 | 
			
		||||
impl_bytes!(BcdHeader);
 | 
			
		||||
 | 
			
		||||
impl BcdHeader {
 | 
			
		||||
    pub fn parse(packet: &mut [u8]) -> Option<(&mut Self, &mut [u8])> {
 | 
			
		||||
        if packet.len() < Self::SIZE {
 | 
			
		||||
            return None;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let (bcd_header, bcd_packet) = packet.split_at_mut(Self::SIZE);
 | 
			
		||||
        let bcd_header = Self::from_bytes_mut(bcd_header.try_into().unwrap());
 | 
			
		||||
        trace!("    {:?}", bcd_header);
 | 
			
		||||
 | 
			
		||||
        let packet_start = 4 * bcd_header.data_offset as usize;
 | 
			
		||||
 | 
			
		||||
        let bcd_packet = bcd_packet.get_mut(packet_start..)?;
 | 
			
		||||
        trace!("    {:02x}", Bytes(&bcd_packet[..bcd_packet.len().min(36)]));
 | 
			
		||||
 | 
			
		||||
        Some((bcd_header, bcd_packet))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Copy)]
 | 
			
		||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 | 
			
		||||
#[repr(C)]
 | 
			
		||||
@@ -130,8 +211,8 @@ impl EventHeader {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Copy)]
 | 
			
		||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 | 
			
		||||
#[repr(C)]
 | 
			
		||||
// #[cfg_attr(feature = "defmt", derive(defmt::Format))]
 | 
			
		||||
#[repr(C, packed(2))]
 | 
			
		||||
pub struct EventMessage {
 | 
			
		||||
    /// version   
 | 
			
		||||
    pub version: u16,
 | 
			
		||||
@@ -158,6 +239,45 @@ pub struct EventMessage {
 | 
			
		||||
}
 | 
			
		||||
impl_bytes!(EventMessage);
 | 
			
		||||
 | 
			
		||||
#[cfg(feature = "defmt")]
 | 
			
		||||
impl defmt::Format for EventMessage {
 | 
			
		||||
    fn format(&self, fmt: defmt::Formatter) {
 | 
			
		||||
        let event_type = self.event_type;
 | 
			
		||||
        let status = self.status;
 | 
			
		||||
        let reason = self.reason;
 | 
			
		||||
        let auth_type = self.auth_type;
 | 
			
		||||
        let datalen = self.datalen;
 | 
			
		||||
 | 
			
		||||
        defmt::write!(
 | 
			
		||||
            fmt,
 | 
			
		||||
            "EventMessage {{ \
 | 
			
		||||
            version: {=u16}, \
 | 
			
		||||
            flags: {=u16}, \
 | 
			
		||||
            event_type: {=u32}, \
 | 
			
		||||
            status: {=u32}, \
 | 
			
		||||
            reason: {=u32}, \
 | 
			
		||||
            auth_type: {=u32}, \
 | 
			
		||||
            datalen: {=u32}, \
 | 
			
		||||
            addr: {=[u8; 6]:x}, \
 | 
			
		||||
            ifname: {=[u8; 16]:x}, \
 | 
			
		||||
            ifidx: {=u8}, \
 | 
			
		||||
            bsscfgidx: {=u8}, \
 | 
			
		||||
        }} ",
 | 
			
		||||
            self.version,
 | 
			
		||||
            self.flags,
 | 
			
		||||
            event_type,
 | 
			
		||||
            status,
 | 
			
		||||
            reason,
 | 
			
		||||
            auth_type,
 | 
			
		||||
            datalen,
 | 
			
		||||
            self.addr,
 | 
			
		||||
            self.ifname,
 | 
			
		||||
            self.ifidx,
 | 
			
		||||
            self.bsscfgidx
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl EventMessage {
 | 
			
		||||
    pub fn byteswap(&mut self) {
 | 
			
		||||
        self.version = self.version.to_be();
 | 
			
		||||
@@ -172,7 +292,7 @@ impl EventMessage {
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Copy)]
 | 
			
		||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
 | 
			
		||||
#[repr(C)]
 | 
			
		||||
#[repr(C, packed(2))]
 | 
			
		||||
pub struct EventPacket {
 | 
			
		||||
    pub eth: EthernetHeader,
 | 
			
		||||
    pub hdr: EventHeader,
 | 
			
		||||
@@ -181,6 +301,21 @@ pub struct EventPacket {
 | 
			
		||||
impl_bytes!(EventPacket);
 | 
			
		||||
 | 
			
		||||
impl EventPacket {
 | 
			
		||||
    pub fn parse(packet: &mut [u8]) -> Option<(&mut Self, &mut [u8])> {
 | 
			
		||||
        if packet.len() < Self::SIZE {
 | 
			
		||||
            return None;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let (event_header, event_packet) = packet.split_at_mut(Self::SIZE);
 | 
			
		||||
        let event_header = Self::from_bytes_mut(event_header.try_into().unwrap());
 | 
			
		||||
        // warn!("event_header {:x}", event_header as *const _);
 | 
			
		||||
        event_header.byteswap();
 | 
			
		||||
 | 
			
		||||
        let event_packet = event_packet.get_mut(..event_header.msg.datalen as usize)?;
 | 
			
		||||
 | 
			
		||||
        Some((event_header, event_packet))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn byteswap(&mut self) {
 | 
			
		||||
        self.eth.byteswap();
 | 
			
		||||
        self.hdr.byteswap();
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user