use core::{fmt::Display, marker::PhantomData};
use mac_parser::MACAddress;
use scroll::{
ctx::{MeasureWith, StrCtx, TryFromCtx, TryIntoCtx},
Pread, Pwrite,
};
use crate::common::WIFI_ALLIANCE_OUI;
use super::{Element, ElementID};
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Pread, Pwrite)]
pub struct BandAndChannelInfo {
pub band: u8,
pub channel: u8,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct OWETransitionModeElement<'a, SSID = &'a str> {
pub bssid: MACAddress,
pub ssid: SSID,
pub band_and_channel_info: Option<BandAndChannelInfo>,
pub _phantom: PhantomData<&'a ()>,
}
impl<SSID: AsRef<str>> Display for OWETransitionModeElement<'_, SSID> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let mut binding = f.debug_struct("OWETransitionModeElement");
let debug_struct = binding
.field("bssid", &self.bssid)
.field("ssid", &self.ssid.as_ref());
if let Some(ref band_and_channel_info) = self.band_and_channel_info {
debug_struct.field("band_and_channel_info", band_and_channel_info)
} else {
debug_struct
}
.finish()
}
}
impl<'a> TryFromCtx<'a> for OWETransitionModeElement<'a> {
type Error = scroll::Error;
fn try_from_ctx(from: &'a [u8], _ctx: ()) -> Result<(Self, usize), Self::Error> {
let mut offset = 0;
let bssid = from.gread(&mut offset)?;
let ssid_len = from.gread::<u8>(&mut offset)? as usize;
let ssid = from.gread_with(&mut offset, StrCtx::Length(ssid_len))?;
let band_and_channel_info = from.gread(&mut offset).ok();
Ok((
Self {
bssid,
ssid,
band_and_channel_info,
_phantom: PhantomData,
},
offset,
))
}
}
impl<SSID: AsRef<str>> MeasureWith<()> for OWETransitionModeElement<'_, SSID> {
fn measure_with(&self, _ctx: &()) -> usize {
6 + 1
+ self.ssid.as_ref().len()
+ if self.band_and_channel_info.is_some() {
2
} else {
0
}
}
}
impl<SSID: AsRef<str>> TryIntoCtx for OWETransitionModeElement<'_, SSID> {
type Error = scroll::Error;
fn try_into_ctx(self, buf: &mut [u8], _ctx: ()) -> Result<usize, Self::Error> {
let mut offset = 0;
buf.gwrite(self.bssid, &mut offset)?;
buf.gwrite(self.ssid.as_ref().len() as u8, &mut offset)?;
buf.gwrite(self.ssid.as_ref(), &mut offset)?;
if let Some(band_and_channel_info) = self.band_and_channel_info {
buf.gwrite(band_and_channel_info, &mut offset)?;
}
Ok(offset)
}
}
impl<SSID: AsRef<str>> Element for OWETransitionModeElement<'_, SSID> {
const ELEMENT_ID: ElementID = ElementID::VendorSpecific {
prefix: &[
WIFI_ALLIANCE_OUI[0],
WIFI_ALLIANCE_OUI[1],
WIFI_ALLIANCE_OUI[2],
0x1c,
],
};
type ReadType<'a> = OWETransitionModeElement<'a>;
}