use super::{Error, Result};
use crate::time::Duration;
use bitflags::bitflags;
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct NestedInformationElement<T: AsRef<[u8]>> {
data: T,
}
impl<T: AsRef<[u8]>> NestedInformationElement<T> {
pub fn new(data: T) -> Result<Self> {
let nested = Self::new_unchecked(data);
if !nested.check_len() {
return Err(Error);
}
Ok(nested)
}
fn check_len(&self) -> bool {
if self.data.as_ref().len() < 2 {
return false;
}
let len = self.length();
self.data.as_ref().len() >= len + 2
}
pub fn new_unchecked(data: T) -> Self {
Self { data }
}
pub fn length(&self) -> usize {
let b = &self.data.as_ref()[0..];
if self.is_long() {
(u16::from_le_bytes([b[0], b[1]]) & 0b1111111111) as usize
} else {
(u16::from_le_bytes([b[0], b[1]]) & 0b1111111) as usize
}
}
pub fn sub_id(&self) -> NestedSubId {
let b = &self.data.as_ref()[0..];
let id = u16::from_le_bytes([b[0], b[1]]);
if self.is_long() {
NestedSubId::Long(NestedSubIdLong::from(((id >> 11) & 0b1111) as u8))
} else {
NestedSubId::Short(NestedSubIdShort::from(((id >> 8) & 0b111111) as u8))
}
}
pub fn is_short(&self) -> bool {
!self.is_long()
}
pub fn is_long(&self) -> bool {
let b = &self.data.as_ref()[0..];
(u16::from_le_bytes([b[0], b[1]]) >> 15) & 0b1 == 0b1
}
pub fn content(&self) -> &[u8] {
&self.data.as_ref()[2..][..self.length()]
}
}
impl<T: AsRef<[u8]> + AsMut<[u8]>> NestedInformationElement<T> {
pub fn clear(&mut self) {
self.data.as_mut().fill(0);
}
pub fn set_length(&mut self, len: u16, id: NestedSubId) {
let mask: u16 = if id.is_short() {
0b0000_1111_1111
} else {
0b0111_1111_1111
};
let b = &mut self.data.as_mut()[0..2];
let value = u16::from_le_bytes([b[0], b[1]]) & !mask;
let value = value | (len & mask);
b[0..2].copy_from_slice(&value.to_le_bytes());
}
pub fn set_sub_id(&mut self, id: NestedSubId) {
let mask: u16 = if id.is_short() {
0b0111_1111_0000_0000
} else {
0b0111_1000_0000_0000
};
let b = &mut self.data.as_mut()[0..2];
let value = u16::from_le_bytes([b[0], b[1]]) & !mask;
let value = value
| match id {
NestedSubId::Short(id) => (id as u16) << 8,
NestedSubId::Long(id) => ((id as u16) << 11) | 0b1000_0000_0000_0000,
};
b[0..2].copy_from_slice(&value.to_le_bytes());
}
pub fn content_mut(&mut self) -> &mut [u8] {
&mut self.data.as_mut()[2..]
}
}
impl<T: AsRef<[u8]>> core::fmt::Display for NestedInformationElement<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self.sub_id() {
NestedSubId::Short(id) => match id {
NestedSubIdShort::TschSynchronization => {
let Ok(ts) = TschSynchronization::new(self.content()) else {
return write!(f, " {id}");
};
write!(f, " {id} {ts}")
}
NestedSubIdShort::TschTimeslot => {
let Ok(tt) = TschTimeslot::new(self.content()) else {
return write!(f, " {id}");
};
write!(f, " {id} {tt}")
}
NestedSubIdShort::TschSlotframeAndLink => {
let Ok(ts) = TschSlotframeAndLink::new(self.content()) else {
return write!(f, " {id}");
};
write!(f, " {id} {ts}")
}
_ => write!(f, " {:?}({:0x?})", id, self.content()),
},
NestedSubId::Long(id) => match id {
NestedSubIdLong::ChannelHopping => {
let Ok(ch) = ChannelHopping::new(self.content()) else {
return write!(f, " {id}");
};
write!(f, " {id} {ch}")
}
id => write!(f, " {:?}({:0x?})", id, self.content()),
},
}
}
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum NestedSubId {
Short(NestedSubIdShort),
Long(NestedSubIdLong),
}
impl NestedSubId {
pub fn from_short(value: u8) -> Self {
Self::Short(NestedSubIdShort::from(value))
}
pub fn from_long(value: u8) -> Self {
Self::Long(NestedSubIdLong::from(value))
}
pub fn is_short(&self) -> bool {
matches!(self, Self::Short(_))
}
pub fn is_long(&self) -> bool {
matches!(self, Self::Long(_))
}
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum NestedSubIdShort {
TschSynchronization = 0x1a,
TschSlotframeAndLink = 0x1b,
TschTimeslot = 0x1c,
HoppingTiming = 0x1d,
EnhancedBeaconFilter = 0x1e,
MacMetrics = 0x1f,
AllMacMetrics = 0x20,
CoexistenceSpecification = 0x21,
SunDeviceCapabilities = 0x22,
SunFskGenericPhy = 0x23,
ModeSwitchParameter = 0x24,
PhyParameterChange = 0x25,
OQpskPhyMode = 0x26,
PcaAllocation = 0x27,
LecimDsssOperatingMode = 0x28,
LecimFskOperatingMode = 0x29,
TvwsPhyOperatingMode = 0x2b,
TvwsDeviceCapabilities = 0x2c,
TvwsDeviceCategory = 0x2d,
TvwsDeviceIdentification = 0x2e,
TvwsDeviceLocation = 0x2f,
TvwsChannelInformationQuery = 0x30,
TvwsChannelInformationSource = 0x31,
Ctm = 0x32,
Timestamp = 0x33,
TimestampDifference = 0x34,
TmctpSpecification = 0x35,
RccPhyOperatingMode = 0x36,
LinkMargin = 0x37,
RsGfskDeviceCapabilities = 0x38,
MultiPhy = 0x39,
VendorSpecific = 0x40,
Srm = 0x46,
Unkown,
}
impl From<u8> for NestedSubIdShort {
fn from(value: u8) -> Self {
match value {
0x1a => Self::TschSynchronization,
0x1b => Self::TschSlotframeAndLink,
0x1c => Self::TschTimeslot,
0x1d => Self::HoppingTiming,
0x1e => Self::EnhancedBeaconFilter,
0x1f => Self::MacMetrics,
0x20 => Self::AllMacMetrics,
0x21 => Self::CoexistenceSpecification,
0x22 => Self::SunDeviceCapabilities,
0x23 => Self::SunFskGenericPhy,
0x24 => Self::ModeSwitchParameter,
0x25 => Self::PhyParameterChange,
0x26 => Self::OQpskPhyMode,
0x27 => Self::PcaAllocation,
0x28 => Self::LecimDsssOperatingMode,
0x29 => Self::LecimFskOperatingMode,
0x2b => Self::TvwsPhyOperatingMode,
0x2c => Self::TvwsDeviceCapabilities,
0x2d => Self::TvwsDeviceCategory,
0x2e => Self::TvwsDeviceIdentification,
0x2f => Self::TvwsDeviceLocation,
0x30 => Self::TvwsChannelInformationQuery,
0x31 => Self::TvwsChannelInformationSource,
0x32 => Self::Ctm,
0x33 => Self::Timestamp,
0x34 => Self::TimestampDifference,
0x35 => Self::TmctpSpecification,
0x36 => Self::RccPhyOperatingMode,
0x37 => Self::LinkMargin,
0x38 => Self::RsGfskDeviceCapabilities,
0x39 => Self::MultiPhy,
0x40 => Self::VendorSpecific,
0x46 => Self::Srm,
_ => Self::Unkown,
}
}
}
impl core::fmt::Display for NestedSubIdShort {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::TschTimeslot => write!(f, "TSCH Timeslot"),
Self::TschSlotframeAndLink => write!(f, "TSCH Slotframe and Link"),
Self::TschSynchronization => write!(f, "TSCH Synchronization"),
_ => write!(f, "{:?}", self),
}
}
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum NestedSubIdLong {
VendorSpecificNested = 0x08,
ChannelHopping = 0x09,
Unkown,
}
impl From<u8> for NestedSubIdLong {
fn from(value: u8) -> Self {
match value {
0x08 => Self::VendorSpecificNested,
0x09 => Self::ChannelHopping,
_ => Self::Unkown,
}
}
}
impl core::fmt::Display for NestedSubIdLong {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::ChannelHopping => write!(f, "Channel Hopping"),
_ => write!(f, "{:?}", self),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TschSynchronization<T: AsRef<[u8]>> {
data: T,
}
impl<T: AsRef<[u8]>> TschSynchronization<T> {
pub fn new(data: T) -> Result<Self> {
let ts = Self::new_unchecked(data);
if !ts.check_len() {
return Err(Error);
}
Ok(ts)
}
fn check_len(&self) -> bool {
self.data.as_ref().len() >= 6
}
pub fn new_unchecked(data: T) -> Self {
Self { data }
}
pub fn absolute_slot_number(&self) -> u64 {
let data = self.data.as_ref();
let mut asn = data[0] as u64;
asn += (data[1] as u64) << 8;
asn += (data[2] as u64) << 16;
asn += (data[3] as u64) << 24;
asn += (data[4] as u64) << 32;
asn
}
pub fn join_metric(&self) -> u8 {
self.data.as_ref()[5]
}
}
impl<T: AsRef<[u8]> + AsMut<[u8]>> TschSynchronization<T> {
pub fn set_absolute_slot_number(&mut self, asn: u64) {
let data = self.data.as_mut();
data[0] = (asn & 0xff) as u8;
data[1] = ((asn >> 8) & 0xff) as u8;
data[2] = ((asn >> 16) & 0xff) as u8;
data[3] = ((asn >> 24) & 0xff) as u8;
data[4] = ((asn >> 32) & 0xff) as u8;
}
pub fn set_join_metric(&mut self, join_metric: u8) {
self.data.as_mut()[5] = join_metric;
}
}
impl<T: AsRef<[u8]>> core::fmt::Display for TschSynchronization<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"ASN: {}, join metric: {}",
self.absolute_slot_number(),
self.join_metric()
)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TschTimeslot<T: AsRef<[u8]>> {
data: T,
}
impl<T: AsRef<[u8]>> TschTimeslot<T> {
pub const DEFAULT_ID: u8 = 0;
pub fn new(data: T) -> Result<Self> {
let ts = Self::new_unchecked(data);
if !ts.check_len() {
return Err(Error);
}
Ok(ts)
}
fn check_len(&self) -> bool {
let len = self.data.as_ref().len();
if len < 1 {
return false;
}
if self.id() == Self::DEFAULT_ID {
return len >= 1;
}
len >= 25
}
pub fn new_unchecked(data: T) -> Self {
Self { data }
}
pub fn id(&self) -> u8 {
self.data.as_ref()[0]
}
pub fn timeslot_timings(&self) -> TschTimeslotTimings {
if self.id() == Self::DEFAULT_ID {
TschTimeslotTimings::default()
} else {
TschTimeslotTimings {
id: self.id(),
cca_offset: Duration::from_us({
let b = &self.data.as_ref()[1..][..2];
u16::from_le_bytes([b[0], b[1]]) as i64
}),
cca: Duration::from_us({
let b = &self.data.as_ref()[3..][..2];
u16::from_le_bytes([b[0], b[1]]) as i64
}),
tx_offset: Duration::from_us({
let b = &self.data.as_ref()[5..][..2];
u16::from_le_bytes([b[0], b[1]]) as i64
}),
rx_offset: Duration::from_us({
let b = &self.data.as_ref()[7..][..2];
u16::from_le_bytes([b[0], b[1]]) as i64
}),
rx_ack_delay: Duration::from_us({
let b = &self.data.as_ref()[9..][..2];
u16::from_le_bytes([b[0], b[1]]) as i64
}),
tx_ack_delay: Duration::from_us({
let b = &self.data.as_ref()[11..][..2];
u16::from_le_bytes([b[0], b[1]]) as i64
}),
rx_wait: Duration::from_us({
let b = &self.data.as_ref()[13..][..2];
u16::from_le_bytes([b[0], b[1]]) as i64
}),
ack_wait: Duration::from_us({
let b = &self.data.as_ref()[15..][..2];
u16::from_le_bytes([b[0], b[1]]) as i64
}),
rx_tx: Duration::from_us({
let b = &self.data.as_ref()[17..][..2];
u16::from_le_bytes([b[0], b[1]]) as i64
}),
max_ack: Duration::from_us({
let b = &self.data.as_ref()[19..][..2];
u16::from_le_bytes([b[0], b[1]]) as i64
}),
max_tx: Duration::from_us({
let len = if self.data.as_ref().len() == 25 { 2 } else { 3 };
let b = &self.data.as_ref()[21..][..len];
u16::from_le_bytes([b[0], b[1]]) as i64
}),
time_slot_length: Duration::from_us({
let offset = if self.data.as_ref().len() == 25 {
23
} else {
24
};
let len = if self.data.as_ref().len() == 25 { 2 } else { 3 };
let b = &self.data.as_ref()[offset..][..len];
u16::from_le_bytes([b[0], b[1]]) as i64
}),
}
}
}
}
impl<T: AsRef<[u8]> + AsMut<[u8]>> TschTimeslot<T> {
pub fn set_time_slot_id(&mut self, id: u8) {
self.data.as_mut()[0] = id;
}
}
impl<T: AsRef<[u8]>> core::fmt::Display for TschTimeslot<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "slot ID: {}", self.id())
}
}
#[derive(Debug)]
pub struct TschTimeslotTimings {
id: u8,
cca_offset: Duration,
cca: Duration,
rx_tx: Duration,
tx_offset: Duration,
max_tx: Duration,
rx_ack_delay: Duration,
ack_wait: Duration,
rx_offset: Duration,
rx_wait: Duration,
tx_ack_delay: Duration,
max_ack: Duration,
time_slot_length: Duration,
}
impl Default for TschTimeslotTimings {
fn default() -> Self {
Self::new(0, Self::DEFAULT_GUARD_TIME)
}
}
impl TschTimeslotTimings {
pub const DEFAULT_GUARD_TIME: Duration = Duration::from_us(2200);
pub fn new(id: u8, guard_time: Duration) -> Self {
Self {
id,
cca_offset: Duration::from_us(1800),
cca: Duration::from_us(128),
tx_offset: Duration::from_us(2120),
rx_offset: Duration::from_us(2120) - (guard_time / 2),
rx_ack_delay: Duration::from_us(800),
tx_ack_delay: Duration::from_us(1000),
rx_wait: guard_time,
ack_wait: Duration::from_us(400),
rx_tx: Duration::from_us(192),
max_ack: Duration::from_us(2400),
max_tx: Duration::from_us(4256),
time_slot_length: Duration::from_us(10000),
}
}
pub const fn cca_offset(&self) -> Duration {
self.cca_offset
}
pub fn set_cca_offset(&mut self, cca_offset: Duration) {
self.cca_offset = cca_offset;
}
pub const fn cca(&self) -> Duration {
self.cca
}
pub fn set_cca(&mut self, cca: Duration) {
self.cca = cca;
}
pub const fn tx_offset(&self) -> Duration {
self.tx_offset
}
pub fn set_tx_offset(&mut self, tx_offset: Duration) {
self.tx_offset = tx_offset;
}
pub const fn rx_offset(&self) -> Duration {
self.rx_offset
}
pub fn set_rx_offset(&mut self, rx_offset: Duration) {
self.rx_offset = rx_offset;
}
pub const fn rx_ack_delay(&self) -> Duration {
self.rx_ack_delay
}
pub fn set_rx_ack_delay(&mut self, rx_ack_delay: Duration) {
self.rx_ack_delay = rx_ack_delay;
}
pub const fn tx_ack_delay(&self) -> Duration {
self.tx_ack_delay
}
pub fn set_tx_ack_delay(&mut self, tx_ack_delay: Duration) {
self.tx_ack_delay = tx_ack_delay;
}
pub const fn rx_wait(&self) -> Duration {
self.rx_wait
}
pub fn set_rx_wait(&mut self, rx_wait: Duration) {
self.rx_wait = rx_wait;
}
pub const fn ack_wait(&self) -> Duration {
self.ack_wait
}
pub fn set_ack_wait(&mut self, ack_wait: Duration) {
self.ack_wait = ack_wait;
}
pub const fn rx_tx(&self) -> Duration {
self.rx_tx
}
pub fn set_rx_tx(&mut self, rx_tx: Duration) {
self.rx_tx = rx_tx;
}
pub const fn max_ack(&self) -> Duration {
self.max_ack
}
pub fn set_max_ack(&mut self, max_ack: Duration) {
self.max_ack = max_ack;
}
pub const fn max_tx(&self) -> Duration {
self.max_tx
}
pub fn set_max_tx(&mut self, max_tx: Duration) {
self.max_tx = max_tx;
}
pub const fn time_slot_length(&self) -> Duration {
self.time_slot_length
}
pub fn set_time_slot_length(&mut self, time_slot_length: Duration) {
self.time_slot_length = time_slot_length;
}
pub fn emit(&self, buffer: &mut [u8]) {
buffer[0] = self.id;
buffer[1..][..2].copy_from_slice(&(self.cca_offset.as_us() as u16).to_le_bytes());
buffer[3..][..2].copy_from_slice(&(self.cca.as_us() as u16).to_le_bytes());
buffer[5..][..2].copy_from_slice(&(self.tx_offset.as_us() as u16).to_le_bytes());
buffer[7..][..2].copy_from_slice(&(self.rx_offset.as_us() as u16).to_le_bytes());
buffer[9..][..2].copy_from_slice(&(self.rx_ack_delay.as_us() as u16).to_le_bytes());
buffer[11..][..2].copy_from_slice(&(self.tx_ack_delay.as_us() as u16).to_le_bytes());
buffer[13..][..2].copy_from_slice(&(self.rx_wait.as_us() as u16).to_le_bytes());
buffer[15..][..2].copy_from_slice(&(self.ack_wait.as_us() as u16).to_le_bytes());
buffer[17..][..2].copy_from_slice(&(self.rx_tx.as_us() as u16).to_le_bytes());
buffer[19..][..2].copy_from_slice(&(self.max_ack.as_us() as u16).to_le_bytes());
buffer[21..][..2].copy_from_slice(&(self.max_tx.as_us() as u16).to_le_bytes());
buffer[23..][..2].copy_from_slice(&(self.time_slot_length.as_us() as u16).to_le_bytes());
}
fn fmt(&self, indent: usize, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
writeln!(f, "{:indent$}cca_offset: {}", "", self.cca_offset(),)?;
writeln!(f, "{:indent$}cca: {}", "", self.cca(), indent = indent)?;
writeln!(f, "{:indent$}tx offset: {}", "", self.tx_offset(),)?;
writeln!(f, "{:indent$}rx offset: {}", "", self.rx_offset(),)?;
writeln!(
f,
"{:indent$}tx ack delay: {}",
"",
self.tx_ack_delay(),
indent = indent
)?;
writeln!(f, "{:indent$}rx ack delay: {}", "", self.rx_ack_delay(),)?;
writeln!(f, "{:indent$}rx wait: {}", "", self.rx_wait(),)?;
writeln!(f, "{:indent$}ack wait: {}", "", self.ack_wait(),)?;
writeln!(f, "{:indent$}rx/tx: {}", "", self.rx_tx(), indent = indent)?;
writeln!(f, "{:indent$}max ack: {}", "", self.max_ack(),)?;
writeln!(f, "{:indent$}max tx: {}", "", self.max_tx(),)?;
writeln!(
f,
"{:indent$}time slot length: {}",
"",
self.time_slot_length(),
)
}
}
impl core::fmt::Display for TschTimeslotTimings {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.fmt(0, f)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TschSlotframeAndLink<T: AsRef<[u8]>> {
data: T,
}
impl<T: AsRef<[u8]>> TschSlotframeAndLink<T> {
pub fn new(data: T) -> Result<Self> {
let ts = Self::new_unchecked(data);
if !ts.check_len() {
return Err(Error);
}
Ok(ts)
}
fn check_len(&self) -> bool {
let len = self.data.as_ref().len();
if len < 1 {
return false;
}
let _number_of_slot_frames = self.number_of_slot_frames() as usize;
let slotframe_descriptors_len =
self.slotframe_descriptors().map(|d| d.len()).sum::<usize>();
len > slotframe_descriptors_len
}
pub fn new_unchecked(data: T) -> Self {
Self { data }
}
pub fn number_of_slot_frames(&self) -> u8 {
self.data.as_ref()[0]
}
pub fn slotframe_descriptors(&self) -> SlotframeDescriptorIterator {
SlotframeDescriptorIterator::new(
self.number_of_slot_frames() as usize,
&self.data.as_ref()[1..],
)
}
}
impl<T: AsRef<[u8]> + AsMut<[u8]>> TschSlotframeAndLink<T> {
pub fn set_number_of_slot_frames(&mut self, number_of_slot_frames: u8) {
self.data.as_mut()[0] = number_of_slot_frames;
}
}
impl<T: AsRef<[u8]>> core::fmt::Display for TschSlotframeAndLink<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "#slot frames: {}", self.number_of_slot_frames())
}
}
pub struct SlotframeDescriptor<T: AsRef<[u8]>> {
data: T,
}
impl<T: AsRef<[u8]>> SlotframeDescriptor<T> {
pub fn new(data: T) -> Result<Self> {
let descriptor = Self::new_unchecked(data);
if !descriptor.check_len() {
return Err(Error);
}
Ok(descriptor)
}
fn check_len(&self) -> bool {
let len = self.data.as_ref().len();
if len < 4 {
return false;
}
len > 4 + (self.links() as usize * LinkDescriptor::<&[u8]>::len())
}
pub fn new_unchecked(data: T) -> Self {
Self { data }
}
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
4 + (self.links() as usize) * 5
}
pub fn handle(&self) -> u8 {
self.data.as_ref()[0]
}
pub fn size(&self) -> u16 {
let b = &self.data.as_ref()[1..][..2];
u16::from_le_bytes([b[0], b[1]])
}
pub fn links(&self) -> u8 {
self.data.as_ref()[3]
}
pub fn link_descriptors(&self) -> LinkDescriptorIterator {
LinkDescriptorIterator::new(
&self.data.as_ref()[4..][..(self.links() as usize * LinkDescriptor::<&[u8]>::len())],
)
}
}
pub struct SlotframeDescriptorIterator<'f> {
data: &'f [u8],
offset: usize,
terminated: bool,
slotframes: usize,
slotframe_count: usize,
}
impl<'f> SlotframeDescriptorIterator<'f> {
pub fn new(slotframes: usize, data: &'f [u8]) -> Self {
let terminated = slotframes == 0;
Self {
data,
offset: 0,
terminated,
slotframes,
slotframe_count: 0,
}
}
}
impl<'f> Iterator for SlotframeDescriptorIterator<'f> {
type Item = SlotframeDescriptor<&'f [u8]>;
fn next(&mut self) -> Option<Self::Item> {
if self.terminated {
return None;
}
let Ok(descriptor) = SlotframeDescriptor::new(&self.data[self.offset..]) else {
self.terminated = true;
return None;
};
self.slotframe_count += 1;
self.offset += descriptor.len();
if self.offset >= self.data.as_ref().len() || self.slotframe_count >= self.slotframes {
self.terminated = true;
}
Some(descriptor)
}
}
pub struct LinkDescriptor<T: AsRef<[u8]>> {
data: T,
}
impl<T: AsRef<[u8]>> LinkDescriptor<T> {
pub fn new(data: T) -> Self {
Self { data }
}
pub const fn len() -> usize {
5
}
pub fn timeslot(&self) -> u16 {
let b = &self.data.as_ref()[0..][..2];
u16::from_le_bytes([b[0], b[1]])
}
pub fn channel_offset(&self) -> u16 {
let b = &self.data.as_ref()[2..][..2];
u16::from_le_bytes([b[0], b[1]])
}
pub fn link_options(&self) -> TschLinkOption {
TschLinkOption::from_bits_truncate(self.data.as_ref()[4])
}
}
pub struct LinkDescriptorIterator<'f> {
data: &'f [u8],
offset: usize,
terminated: bool,
}
impl<'f> LinkDescriptorIterator<'f> {
pub fn new(data: &'f [u8]) -> Self {
Self {
data,
offset: 0,
terminated: false,
}
}
}
impl<'f> Iterator for LinkDescriptorIterator<'f> {
type Item = LinkDescriptor<&'f [u8]>;
fn next(&mut self) -> Option<Self::Item> {
if self.terminated {
return None;
}
let descriptor = LinkDescriptor::new(&self.data[self.offset..]);
self.offset += LinkDescriptor::<&[u8]>::len();
self.terminated = self.offset >= self.data.as_ref().len();
Some(descriptor)
}
}
bitflags! {
#[derive(Copy, Clone)]
pub struct TschLinkOption: u8 {
const Tx = 0b0000_0001;
const Rx = 0b0000_0010;
const Shared = 0b0000_0100;
const TimeKeeping = 0b0000_1000;
const Priority = 0b0001_0000;
}
}
impl core::fmt::Debug for TschLinkOption {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
bitflags::parser::to_writer(self, f)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ChannelHopping<T: AsRef<[u8]>> {
data: T,
}
impl<T: AsRef<[u8]>> ChannelHopping<T> {
pub fn new(data: T) -> Result<Self> {
let ts = Self::new_unchecked(data);
if !ts.check_len() {
return Err(Error);
}
Ok(ts)
}
fn check_len(&self) -> bool {
!self.data.as_ref().is_empty()
}
pub fn new_unchecked(data: T) -> Self {
Self { data }
}
pub fn hopping_sequence_id(&self) -> u8 {
self.data.as_ref()[0]
}
}
impl<T: AsRef<[u8]> + AsMut<[u8]>> ChannelHopping<T> {
pub fn set_hopping_sequence_id(&mut self, id: u8) {
self.data.as_mut()[0] = id;
}
}
impl<T: AsRef<[u8]>> core::fmt::Display for ChannelHopping<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "sequence ID: {}", self.hopping_sequence_id())
}
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct NestedInformationElementsIterator<'f> {
data: &'f [u8],
offset: usize,
terminated: bool,
}
impl<'f> NestedInformationElementsIterator<'f> {
pub fn new(data: &'f [u8]) -> Self {
Self {
data,
offset: 0,
terminated: false,
}
}
}
impl<'f> Iterator for NestedInformationElementsIterator<'f> {
type Item = NestedInformationElement<&'f [u8]>;
fn next(&mut self) -> Option<Self::Item> {
if self.terminated {
None
} else {
let Ok(nested) = NestedInformationElement::new(&self.data[self.offset..]) else {
self.terminated = true;
return None;
};
let len = nested.length() + 2;
let nested = NestedInformationElement {
data: &self.data[self.offset..][..len],
};
self.offset += len;
if self.offset >= self.data.len() {
self.terminated = true;
}
Some(nested)
}
}
}