use bitfield_struct::bitfield;
use macro_bits::serializable_enum;
use scroll::{
ctx::{MeasureWith, TryFromCtx, TryIntoCtx},
Pread, Pwrite,
};
use crate::elements::{Element, ElementID};
use super::SupportedMCSSet;
serializable_enum! {
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub enum SecondaryChannelOffset: u8 {
#[default]
NotPresent => 0x00,
Above => 0x01,
Reserved => 0x02,
Below => 0x03
}
}
serializable_enum! {
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub enum HTProtectionMode: u8 {
#[default]
None => 0x00,
NonMember => 0x01,
TwentyMHz => 0x02,
NonHTMixed => 0x03
}
}
#[bitfield(u64, defmt = cfg(feature = "defmt"))]
#[derive(PartialEq, Eq, Hash)]
pub struct HTOperationInformation {
#[bits(2)]
pub secondary_channel_offset: SecondaryChannelOffset,
pub any_channel_width: bool,
pub rifs_permitted: bool,
#[bits(4)]
__: u8,
#[bits(2)]
pub ht_protection_mode: HTProtectionMode,
pub nongreenfield_ht_sta_present: bool,
__: bool,
pub obss_non_ht_sta_present: bool,
#[bits(8)]
pub channel_center_frequency_segment_2: u8,
#[bits(9)]
__: u16,
pub dual_beacon: bool,
pub dual_cts_protection: bool,
pub stbc_beacon: bool,
#[bits(31)]
__: u64,
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct HTOperationElement {
pub primary_channel: u8,
pub ht_operation_information: HTOperationInformation,
pub basic_ht_mcs_set: SupportedMCSSet,
}
impl MeasureWith<()> for HTOperationElement {
fn measure_with(&self, _ctx: &()) -> usize {
22
}
}
impl TryFromCtx<'_> for HTOperationElement {
type Error = scroll::Error;
fn try_from_ctx(from: &[u8], _ctx: ()) -> Result<(Self, usize), Self::Error> {
let mut offset = 0;
let primary_channel = from.gread(&mut offset)?;
let mut ht_operation_information = [0u8; 8];
ht_operation_information[..5].copy_from_slice(from.gread_with(&mut offset, 5)?);
let ht_operation_information =
HTOperationInformation::from_bits(u64::from_le_bytes(ht_operation_information));
let basic_ht_mcs_set = from.gread(&mut offset)?;
Ok((
Self {
primary_channel,
ht_operation_information,
basic_ht_mcs_set,
},
offset,
))
}
}
impl TryIntoCtx for HTOperationElement {
type Error = scroll::Error;
fn try_into_ctx(self, buf: &mut [u8], _ctx: ()) -> Result<usize, Self::Error> {
let mut offset = 0;
buf.gwrite(self.primary_channel, &mut offset)?;
buf.gwrite(
&self.ht_operation_information.into_bits().to_be_bytes()[..5],
&mut offset,
)?;
buf.gwrite(self.basic_ht_mcs_set, &mut offset)?;
Ok(offset)
}
}
impl Element for HTOperationElement {
const ELEMENT_ID: ElementID = ElementID::Id(0x3d);
type ReadType<'a> = Self;
}