use postcard::experimental::max_size::MaxSize;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum Ltf {
Lltf,
HtLtf,
HtLtf2,
HeLtf,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Segment {
pub ltf: Ltf,
pub ranges: &'static [(i16, i16)],
}
impl Segment {
pub const fn len(&self) -> usize {
let mut n = 0;
let mut i = 0;
while i < self.ranges.len() {
let (a, b) = self.ranges[i];
n += (b - a + 1) as usize;
i += 1;
}
n
}
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn indices(&self) -> impl Iterator<Item = i16> + '_ {
self.ranges.iter().flat_map(|&(a, b)| a..=b)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, MaxSize)]
#[non_exhaustive]
#[repr(u8)]
pub enum LayoutId {
Unknown = 0,
ClassicNoneNonHt,
ClassicNoneHt20,
ClassicNoneHt20Stbc,
ClassicBelowNonHt,
ClassicBelowHt20,
ClassicBelowHt20Stbc,
ClassicBelowHt40,
ClassicBelowHt40Stbc,
ClassicAboveNonHt,
ClassicAboveHt20,
ClassicAboveHt20Stbc,
ClassicAboveHt40,
ClassicAboveHt40Stbc,
C5LltfNone,
C5LltfBelow,
C5LltfAbove,
C5Ht20None,
C5Ht20NoneStbc,
C5Ht20Below,
C5Ht20BelowStbc,
C5Ht20Above,
C5Ht20AboveStbc,
C5Ht40,
C5Ht40Stbc,
C5He20Su,
}
const R_0_31_M32_M1: &[(i16, i16)] = &[(0, 31), (-32, -1)];
const R_0_63: &[(i16, i16)] = &[(0, 63)];
const R_0_62: &[(i16, i16)] = &[(0, 62)];
const R_M64_M1: &[(i16, i16)] = &[(-64, -1)];
const R_M62_M1: &[(i16, i16)] = &[(-62, -1)];
const R_0_63_M64_M1: &[(i16, i16)] = &[(0, 63), (-64, -1)];
const R_0_60_M60_M1: &[(i16, i16)] = &[(0, 60), (-60, -1)];
const R_0_26_M26_M1: &[(i16, i16)] = &[(0, 26), (-26, -1)];
const R_0_52: &[(i16, i16)] = &[(0, 52)];
const R_M53_M1: &[(i16, i16)] = &[(-53, -1)];
const R_0_28_M28_M1: &[(i16, i16)] = &[(0, 28), (-28, -1)];
const R_0_56: &[(i16, i16)] = &[(0, 56)];
const R_M57_M1: &[(i16, i16)] = &[(-57, -1)];
const R_0_58_M58_M1: &[(i16, i16)] = &[(0, 58), (-58, -1)];
const R_0_122_M122_M1: &[(i16, i16)] = &[(0, 122), (-122, -1)];
macro_rules! seg {
($ltf:ident, $ranges:expr) => {
Segment { ltf: Ltf::$ltf, ranges: $ranges }
};
}
impl LayoutId {
pub const fn segments(self) -> &'static [Segment] {
match self {
Self::Unknown => &[],
Self::ClassicNoneNonHt => &[seg!(Lltf, R_0_31_M32_M1)],
Self::ClassicNoneHt20 => &[seg!(Lltf, R_0_31_M32_M1), seg!(HtLtf, R_0_31_M32_M1)],
Self::ClassicNoneHt20Stbc => &[
seg!(Lltf, R_0_31_M32_M1),
seg!(HtLtf, R_0_31_M32_M1),
seg!(HtLtf2, R_0_31_M32_M1),
],
Self::ClassicBelowNonHt => &[seg!(Lltf, R_0_63)],
Self::ClassicBelowHt20 => &[seg!(Lltf, R_0_63), seg!(HtLtf, R_0_63)],
Self::ClassicBelowHt20Stbc => {
&[seg!(Lltf, R_0_63), seg!(HtLtf, R_0_62), seg!(HtLtf2, R_0_62)]
}
Self::ClassicBelowHt40 => &[seg!(Lltf, R_0_63), seg!(HtLtf, R_0_63_M64_M1)],
Self::ClassicBelowHt40Stbc => &[
seg!(Lltf, R_0_63),
seg!(HtLtf, R_0_60_M60_M1),
seg!(HtLtf2, R_0_60_M60_M1),
],
Self::ClassicAboveNonHt => &[seg!(Lltf, R_M64_M1)],
Self::ClassicAboveHt20 => &[seg!(Lltf, R_M64_M1), seg!(HtLtf, R_M64_M1)],
Self::ClassicAboveHt20Stbc => &[
seg!(Lltf, R_M64_M1),
seg!(HtLtf, R_M62_M1),
seg!(HtLtf2, R_M62_M1),
],
Self::ClassicAboveHt40 => &[seg!(Lltf, R_M64_M1), seg!(HtLtf, R_0_63_M64_M1)],
Self::ClassicAboveHt40Stbc => &[
seg!(Lltf, R_M64_M1),
seg!(HtLtf, R_0_60_M60_M1),
seg!(HtLtf2, R_0_60_M60_M1),
],
Self::C5LltfNone => &[seg!(Lltf, R_0_26_M26_M1)],
Self::C5LltfBelow => &[seg!(Lltf, R_0_52)],
Self::C5LltfAbove => &[seg!(Lltf, R_M53_M1)],
Self::C5Ht20None => &[seg!(HtLtf, R_0_28_M28_M1)],
Self::C5Ht20NoneStbc => &[seg!(HtLtf, R_0_28_M28_M1), seg!(HtLtf2, R_0_28_M28_M1)],
Self::C5Ht20Below => &[seg!(HtLtf, R_0_56)],
Self::C5Ht20BelowStbc => &[seg!(HtLtf, R_0_56), seg!(HtLtf2, R_0_56)],
Self::C5Ht20Above => &[seg!(HtLtf, R_M57_M1)],
Self::C5Ht20AboveStbc => &[seg!(HtLtf, R_M57_M1), seg!(HtLtf2, R_M57_M1)],
Self::C5Ht40 => &[seg!(HtLtf, R_0_58_M58_M1)],
Self::C5Ht40Stbc => &[seg!(HtLtf, R_0_58_M58_M1), seg!(HtLtf2, R_0_58_M58_M1)],
Self::C5He20Su => &[seg!(HeLtf, R_0_122_M122_M1)],
}
}
pub const fn byte_len(self) -> Option<usize> {
let segs = self.segments();
if segs.is_empty() {
return None;
}
let mut n = 0;
let mut i = 0;
while i < segs.len() {
n += segs[i].len();
i += 1;
}
Some(n * 2)
}
const fn checked(self, len: usize) -> Self {
match self.byte_len() {
Some(n) if n == len => self,
_ => Self::Unknown,
}
}
pub const fn classify_classic(secondary: u8, sig_mode: u8, forty: bool, stbc: bool, len: usize) -> Self {
let id = match (secondary, sig_mode, forty, stbc) {
(0, 0, _, _) => Self::ClassicNoneNonHt,
(0, 1, false, false) => Self::ClassicNoneHt20,
(0, 1, false, true) => Self::ClassicNoneHt20Stbc,
(2, 0, _, _) => Self::ClassicBelowNonHt,
(2, 1, false, false) => Self::ClassicBelowHt20,
(2, 1, false, true) => Self::ClassicBelowHt20Stbc,
(2, 1, true, false) => Self::ClassicBelowHt40,
(2, 1, true, true) => Self::ClassicBelowHt40Stbc,
(1, 0, _, _) => Self::ClassicAboveNonHt,
(1, 1, false, false) => Self::ClassicAboveHt20,
(1, 1, false, true) => Self::ClassicAboveHt20Stbc,
(1, 1, true, false) => Self::ClassicAboveHt40,
(1, 1, true, true) => Self::ClassicAboveHt40Stbc,
_ => Self::Unknown,
};
id.checked(len)
}
pub const fn classify_c5(bb_format: u8, secondary: u8, len: usize) -> Self {
if len == 106 {
return match secondary {
0 => Self::C5LltfNone,
2 => Self::C5LltfBelow,
1 => Self::C5LltfAbove,
_ => Self::Unknown,
};
}
match (bb_format, secondary, len) {
(2 | 3, 0, 114) => Self::C5Ht20None,
(2 | 3, 0, 228) => Self::C5Ht20NoneStbc,
(2, 2, 114) => Self::C5Ht20Below,
(2, 2, 228) => Self::C5Ht20BelowStbc,
(2, 1, 114) => Self::C5Ht20Above,
(2, 1, 228) => Self::C5Ht20AboveStbc,
(2, 1 | 2, 234) => Self::C5Ht40,
(2, 1 | 2, 468) => Self::C5Ht40Stbc,
(4, 0, 490) => Self::C5He20Su,
_ => Self::Unknown,
}
}
pub fn indices(self) -> impl Iterator<Item = (Ltf, i16)> {
self.segments()
.iter()
.flat_map(|s| s.indices().map(move |i| (s.ltf, i)))
}
}
pub const SPACING_HZ_LEGACY: u32 = 312_500;
pub const SPACING_HZ_HE: u32 = 78_125;
impl Ltf {
pub const fn spacing_hz(self) -> u32 {
match self {
Self::HeLtf => SPACING_HZ_HE,
_ => SPACING_HZ_LEGACY,
}
}
}