use crate::link::{llcp::ControlPdu, SeqNum};
use crate::{bytes::*, Error};
use core::{convert::TryInto, fmt};
#[derive(Copy, Clone)]
pub struct Header(u16);
impl Header {
pub fn new(llid: Llid) -> Self {
Header(llid as u16)
}
pub fn parse(raw: &[u8]) -> Self {
let bytes: [u8; 2] = raw[..2].try_into().expect("raw has fewer than 2 bytes");
Header(u16::from_le_bytes(bytes))
}
pub fn to_u16(&self) -> u16 {
self.0
}
pub fn payload_length(&self) -> u8 {
((self.0 & 0b11111111_00000000) >> 8) as u8
}
pub fn set_payload_length(&mut self, len: u8) {
self.0 = (u16::from(len) << 8) | (self.0 & 0x00ff);
}
pub fn llid(&self) -> Llid {
let bits = self.0 & 0b11;
match bits {
0b00 => Llid::Reserved,
0b01 => Llid::DataCont,
0b10 => Llid::DataStart,
0b11 => Llid::Control,
_ => unreachable!(),
}
}
pub fn nesn(&self) -> SeqNum {
let bit = self.0 & 0b0100;
if bit == 0 {
SeqNum::ZERO
} else {
SeqNum::ONE
}
}
pub fn set_nesn(&mut self, nesn: SeqNum) {
if nesn == SeqNum::ONE {
self.0 |= 0b0100;
} else {
self.0 &= !0b0100;
}
}
pub fn sn(&self) -> SeqNum {
let bit = self.0 & 0b1000;
if bit == 0 {
SeqNum::ZERO
} else {
SeqNum::ONE
}
}
pub fn set_sn(&mut self, sn: SeqNum) {
if sn == SeqNum::ONE {
self.0 |= 0b1000;
} else {
self.0 &= !0b1000;
}
}
pub fn md(&self) -> bool {
let bit = self.0 & 0b10000;
bit != 0
}
pub fn set_md(&mut self, md: bool) {
if md {
self.0 |= 0b10000;
} else {
self.0 &= !0b10000;
}
}
}
impl fmt::Debug for Header {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Header")
.field("LLID", &self.llid())
.field("NESN", &self.nesn())
.field("SN", &self.sn())
.field("MD", &self.md())
.field("Length", &self.payload_length())
.finish()
}
}
impl<'a> FromBytes<'a> for Header {
fn from_bytes(bytes: &mut ByteReader<'a>) -> Result<Self, Error> {
let raw = bytes.read_u16_le()?;
Ok(Header(raw))
}
}
impl ToBytes for Header {
fn to_bytes(&self, writer: &mut ByteWriter<'_>) -> Result<(), Error> {
writer.write_u16_le(self.to_u16())
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Llid {
Reserved = 0b00,
DataCont = 0b01,
DataStart = 0b10,
Control = 0b11,
}
#[derive(Debug)]
pub enum Pdu<'a, L> {
DataCont { message: L },
DataStart { message: L },
Control { data: BytesOr<'a, ControlPdu<'a>> },
}
impl<'a> Pdu<'a, &'a [u8]> {
pub fn empty() -> Self {
Pdu::DataCont { message: &[] }
}
}
impl<'a, L> Pdu<'a, L> {
pub fn llid(&self) -> Llid {
match self {
Pdu::DataCont { .. } => Llid::DataCont,
Pdu::DataStart { .. } => Llid::DataStart,
Pdu::Control { .. } => Llid::Control,
}
}
}
impl<'a, L: FromBytes<'a> + ?Sized> Pdu<'a, L> {
pub fn parse(header: Header, payload: &'a [u8]) -> Result<Self, Error> {
match header.llid() {
Llid::DataCont => Ok(Pdu::DataCont {
message: L::from_bytes(&mut ByteReader::new(payload))?,
}),
Llid::DataStart => Ok(Pdu::DataStart {
message: L::from_bytes(&mut ByteReader::new(payload))?,
}),
Llid::Control => Ok(Pdu::Control {
data: BytesOr::from_bytes(&mut ByteReader::new(payload))?,
}),
Llid::Reserved => Err(Error::InvalidValue),
}
}
}
impl<'a> From<&'a ControlPdu<'a>> for Pdu<'a, &'a [u8]> {
fn from(c: &'a ControlPdu<'a>) -> Self {
Pdu::Control { data: c.into() }
}
}
impl<'a, L: ToBytes> ToBytes for Pdu<'a, L> {
fn to_bytes(&self, buffer: &mut ByteWriter<'_>) -> Result<(), Error> {
match self {
Pdu::DataCont { message } | Pdu::DataStart { message } => message.to_bytes(buffer),
Pdu::Control { data } => data.to_bytes(buffer),
}
}
}