use crate::{
builder::ConnectBuilder, error::*,
DtDataBuilder
};
use bytes::{Buf, BufMut, BytesMut};
use num_enum::{IntoPrimitive, TryFromPrimitive};
use std::fmt::Debug;
#[derive(Debug, Eq, PartialEq)]
pub struct CoptFrame<F: Debug + Eq + PartialEq> {
pub pdu_type: PduType<F>
}
impl<F: Debug + Eq + PartialEq> CoptFrame<F> {
pub fn builder_of_dt_data(
payload: F
) -> DtDataBuilder<F> {
DtDataBuilder::new(payload)
}
pub fn builder_of_connect()
-> ConnectBuilder<F> {
ConnectBuilder::<F>::default()
}
pub fn length(&self) -> u8 {
self.pdu_type.length()
}
}
#[derive(Debug, Eq, PartialEq)]
pub enum PduType<F: Debug + Eq + PartialEq> {
ConnectRequest(ConnectComm),
ConnectConfirm(ConnectComm),
DtData(DtData<F>)
}
impl<F: Debug + Eq + PartialEq> PduType<F> {
pub fn length(&self) -> u8 {
match self {
PduType::ConnectRequest(conn) => {
conn.length()
},
PduType::ConnectConfirm(conn) => {
conn.length()
},
PduType::DtData(_) => 2
}
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct DtData<F: Debug + Eq + PartialEq> {
pub(crate) tpdu_number: u8,
pub(crate) last_data_unit: bool,
pub(crate) payload: F
}
impl<F: Debug + Eq + PartialEq> DtData<F> {
pub fn tpdu_number(&self) -> u8 {
self.tpdu_number
}
pub fn last_data_unit(&self) -> bool {
self.last_data_unit
}
pub fn payload(self) -> F {
self.payload
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct ConnectComm {
pub destination_ref: [u8; 2],
pub source_ref: [u8; 2],
pub class: u8,
pub extended_formats: bool,
pub no_explicit_flow_control: bool,
pub parameters: Vec<Parameter>
}
impl ConnectComm {
pub fn length(&self) -> u8 {
6 + self
.parameters
.iter()
.fold(0, |x, item| x + item.length())
}
pub(crate) fn decode(
src: &mut BytesMut
) -> Result<Self> {
if src.len() < 5 {
return Err(Error::Error(
"data not enough".to_string()
));
}
let destination_ref =
[src.get_u8(), src.get_u8()];
let source_ref =
[src.get_u8(), src.get_u8()];
let merge = src.get_u8();
let class = merge >> 4;
let extended_formats =
merge << 6 >> 7 > 0;
let no_explicit_flow_control =
merge & 1 > 0;
let mut parameters = Vec::new();
while let Some(parameter) =
Parameter::decode(src)?
{
parameters.push(parameter);
}
Ok(Self {
destination_ref,
source_ref,
class,
extended_formats,
no_explicit_flow_control,
parameters
})
}
pub(crate) fn encode(
&self,
dst: &mut BytesMut
) {
dst.put_slice(
self.destination_ref.as_ref()
);
dst.put_slice(self.source_ref.as_ref());
let merge = self.class << 4
& if self.extended_formats {
2
} else {
0
}
& if self.no_explicit_flow_control {
1
} else {
0
};
dst.put_u8(merge);
self.parameters
.iter()
.for_each(|x| x.encode(dst));
}
}
#[derive(Debug, Eq, PartialEq)]
pub enum Parameter {
TpduSize(TpduSize),
SrcTsap(Vec<u8>),
DstTsap(Vec<u8>)
}
#[derive(
Debug,
Clone,
Copy,
Eq,
PartialEq,
TryFromPrimitive,
IntoPrimitive,
)]
#[repr(u8)]
pub enum TpduSize {
L8192 = 0b0000_1101,
L4096 = 0b0000_1100,
L2048 = 0b0000_1011,
L1024 = 0b0000_1010,
L512 = 0b0000_1001,
L256 = 0b0000_1000,
L128 = 0b0000_0111
}
impl TpduSize {
pub fn pdu_ref(&self) -> u16 {
match self {
TpduSize::L8192 => 8192,
TpduSize::L4096 => 4096,
TpduSize::L2048 => 2048,
TpduSize::L1024 => 1024,
TpduSize::L512 => 512,
TpduSize::L256 => 256,
TpduSize::L128 => 128
}
}
}
impl Parameter {
pub fn new_dst_tsap(data: Vec<u8>) -> Self {
Self::DstTsap(data)
}
pub fn new_src_tsap(data: Vec<u8>) -> Self {
Self::SrcTsap(data)
}
pub fn new_tpdu_size(size: TpduSize) -> Self {
Self::TpduSize(size)
}
pub fn length(&self) -> u8 {
match self {
Parameter::TpduSize(_) => 3u8,
Parameter::SrcTsap(data) => {
2 + data.len() as u8
},
Parameter::DstTsap(data) => {
2 + data.len() as u8
},
}
}
fn decode(
dst: &mut BytesMut
) -> Result<Option<Self>> {
if dst.len() == 0 {
return Ok(None);
}
let (Some(ty), Some(length)) = (dst.get(0), dst.get(1)) else {
return Err(Error::Error("data not enough".to_string()));
};
let length = (length + 2) as usize;
let ty = *ty;
if dst.len() < length {
return Err(Error::Error(
"data not enough".to_string()
));
}
let mut data =
dst.split_to(length).split_off(2);
match ty {
0xc0 => {
let size = data.get_u8();
Ok(Some(Self::TpduSize(
size.try_into()?
)))
},
0xc1 => Ok(Some(Self::SrcTsap(
data.to_vec()
))),
0xc2 => Ok(Some(Self::DstTsap(
data.to_vec()
))),
_ => {
return Err(Error::Error(
format!(
"not support parameter: \
{}",
ty
)
));
}
}
}
fn encode(&self, dst: &mut BytesMut) {
match self {
Parameter::TpduSize(data) => {
dst.put_u8(0xc0);
dst.put_u8(1u8);
dst.put_u8(data.clone().into())
},
Parameter::SrcTsap(data) => {
dst.put_u8(0xc1);
dst.put_u8(data.len() as u8);
dst.extend_from_slice(
data.as_ref()
)
},
Parameter::DstTsap(data) => {
dst.put_u8(0xc2);
dst.put_u8(data.len() as u8);
dst.extend_from_slice(
data.as_ref()
)
}
}
}
}