use core::slice;
use heterob::{bit_numbering::Lsb, endianness::Le, Seq, P16, P2, P3, P4, P5, P8};
use snafu::Snafu;
use super::ExtendedCapabilityHeader;
#[derive(Snafu, Debug, Clone, PartialEq, Eq)]
pub enum ProtocolMultiplexingError {
#[snafu(display("capability, control and status fields are unreadable"))]
Mandatory,
#[snafu(display(
"ureadable bytes for PMUX Protocol Array (expected: {expected}, found: {found})"
))]
PmuxProtocolArray { expected: usize, found: usize },
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ProtocolMultiplexing<'a> {
pub pmux_capability: PmuxCapability,
pub pmux_control: PmuxControl,
pub pmux_status: PmuxStatus,
pub pmux_protocol_array: PmuxProtocolArray<'a>,
}
impl<'a> TryFrom<&'a [u8]> for ProtocolMultiplexing<'a> {
type Error = ProtocolMultiplexingError;
fn try_from(slice: &'a [u8]) -> Result<Self, Self::Error> {
let slice = slice
.get(ExtendedCapabilityHeader::SIZE..)
.unwrap_or_default();
let Seq {
head: Le((pmux_capability, pmux_control, pmux_status)),
tail,
} = P3(slice)
.try_into()
.map_err(|_| ProtocolMultiplexingError::Mandatory)?;
let pmux_capability @ PmuxCapability {
pmux_protocol_array_size,
..
} = From::<u32>::from(pmux_capability);
let len = pmux_protocol_array_size as usize * PmuxProtocolArrayEntry::SIZE;
tail.get(..len)
.ok_or(ProtocolMultiplexingError::PmuxProtocolArray {
expected: len,
found: tail.len(),
})
.map(|slice| Self {
pmux_capability,
pmux_control: From::<u32>::from(pmux_control),
pmux_status: From::<u32>::from(pmux_status),
pmux_protocol_array: PmuxProtocolArray::new(slice),
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PmuxCapability {
pub pmux_protocol_array_size: u8,
pub pmux_supported_link_speeds: PmuxSupportedLinkSpeeds,
}
impl From<u32> for PmuxCapability {
fn from(dword: u32) -> Self {
let Lsb((pmux_protocol_array_size, (), pmux_supported_link_speeds, ())) =
P4::<_, 6, 2, 8, 16>(dword).into();
Self {
pmux_protocol_array_size,
pmux_supported_link_speeds: From::<u8>::from(pmux_supported_link_speeds),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PmuxSupportedLinkSpeeds {
pub speed_2_5_gtps: bool,
pub speed_5_0_gtps: bool,
pub speed_8_0_gtps: bool,
pub speed_16_0_gtps: bool,
}
impl From<u8> for PmuxSupportedLinkSpeeds {
fn from(byte: u8) -> Self {
let Lsb((speed_2_5_gtps, speed_5_0_gtps, speed_8_0_gtps, speed_16_0_gtps, ())) =
P5::<_, 1, 1, 1, 1, 4>(byte).into();
Self {
speed_2_5_gtps,
speed_5_0_gtps,
speed_8_0_gtps,
speed_16_0_gtps,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PmuxControl {
pub pmux_channel_0_assignment: u8,
pub pmux_channel_1_assignment: u8,
pub pmux_channel_2_assignment: u8,
pub pmux_channel_3_assignment: u8,
}
impl From<u32> for PmuxControl {
fn from(dword: u32) -> Self {
let Lsb((
pmux_channel_0_assignment,
(),
pmux_channel_1_assignment,
(),
pmux_channel_2_assignment,
(),
pmux_channel_3_assignment,
(),
)) = P8::<_, 6, 2, 6, 2, 6, 2, 6, 2>(dword).into();
Self {
pmux_channel_0_assignment,
pmux_channel_1_assignment,
pmux_channel_2_assignment,
pmux_channel_3_assignment,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PmuxStatus {
pub pmux_channel_0_disabled_link_speed: bool,
pub pmux_channel_0_disabled_link_width: bool,
pub pmux_channel_0_disabled_link_protocol_specific: bool,
pub pmux_channel_1_disabled_link_speed: bool,
pub pmux_channel_1_disabled_link_width: bool,
pub pmux_channel_1_disabled_link_protocol_specific: bool,
pub pmux_channel_2_disabled_link_speed: bool,
pub pmux_channel_2_disabled_link_width: bool,
pub pmux_channel_2_disabled_link_protocol_specific: bool,
pub pmux_channel_3_disabled_link_speed: bool,
pub pmux_channel_3_disabled_link_width: bool,
pub pmux_channel_3_disabled_link_protocol_specific: bool,
}
impl From<u32> for PmuxStatus {
fn from(dword: u32) -> Self {
let Lsb((
pmux_channel_0_disabled_link_speed,
pmux_channel_0_disabled_link_width,
pmux_channel_0_disabled_link_protocol_specific,
(),
pmux_channel_1_disabled_link_speed,
pmux_channel_1_disabled_link_width,
pmux_channel_1_disabled_link_protocol_specific,
(),
pmux_channel_2_disabled_link_speed,
pmux_channel_2_disabled_link_width,
pmux_channel_2_disabled_link_protocol_specific,
(),
pmux_channel_3_disabled_link_speed,
pmux_channel_3_disabled_link_width,
pmux_channel_3_disabled_link_protocol_specific,
(),
)) = P16::<_, 1, 1, 1, 5, 1, 1, 1, 5, 1, 1, 1, 5, 1, 1, 1, 5>(dword).into();
Self {
pmux_channel_0_disabled_link_speed,
pmux_channel_0_disabled_link_width,
pmux_channel_0_disabled_link_protocol_specific,
pmux_channel_1_disabled_link_speed,
pmux_channel_1_disabled_link_width,
pmux_channel_1_disabled_link_protocol_specific,
pmux_channel_2_disabled_link_speed,
pmux_channel_2_disabled_link_width,
pmux_channel_2_disabled_link_protocol_specific,
pmux_channel_3_disabled_link_speed,
pmux_channel_3_disabled_link_width,
pmux_channel_3_disabled_link_protocol_specific,
}
}
}
#[derive(Debug, Clone)]
pub struct PmuxProtocolArray<'a>(pub slice::Chunks<'a, u8>);
impl<'a> PmuxProtocolArray<'a> {
pub fn new(slice: &'a [u8]) -> Self {
Self(slice.chunks(PmuxProtocolArrayEntry::SIZE))
}
}
impl<'a> PartialEq for PmuxProtocolArray<'a> {
fn eq(&self, other: &Self) -> bool {
self.0.clone().eq(other.0.clone())
}
}
impl<'a> Eq for PmuxProtocolArray<'a> {}
impl<'a> Iterator for PmuxProtocolArray<'a> {
type Item = PmuxProtocolArrayEntry;
fn next(&mut self) -> Option<Self::Item> {
let slice = self.0.next()?;
let Seq {
head: Le((protocol_id, authority_id)),
..
} = P2(slice).try_into().ok()?;
Some(PmuxProtocolArrayEntry {
protocol_id,
authority_id,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PmuxProtocolArrayEntry {
pub protocol_id: u16,
pub authority_id: u16,
}
impl PmuxProtocolArrayEntry {
pub const SIZE: usize = 4;
}
impl From<PmuxProtocolArrayEntry> for [u8; PmuxProtocolArrayEntry::SIZE] {
fn from(entry: PmuxProtocolArrayEntry) -> Self {
let [a, b] = entry.protocol_id.to_le_bytes();
let [c, d] = entry.authority_id.to_le_bytes();
[a, b, c, d]
}
}