parse data from device in-place
This commit is contained in:
parent
e6e5685f7c
commit
76ebebd0c5
2 changed files with 154 additions and 62 deletions
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue