use std::any::Any;
use std::ops::BitOr;
use byteorder::{BigEndian, ByteOrder};
use strum_macros::FromRepr;
use crate::cemi::l_data::SystemBroadcast::Broadcast;
use crate::cemi::Message;
use crate::cemi::apdu::Apdu;
use crate::dpt::DPT;
use crate::knxnet::{KnxNetIpError, Service};
#[derive(FromRepr, Debug, Copy, Clone, PartialEq, Default)]
#[repr(u8)]
pub enum FrameType{
Extended = 0x00,
#[default]
Standard = 0x80,
}
#[derive(FromRepr, Debug, Copy, Clone, PartialEq, Default)]
#[repr(u8)]
pub enum Repetition{
Repeat = 0x00,
#[default]
NoRepeat = 0x20,
}
#[derive(FromRepr, Debug, Copy, Clone, PartialEq, Default)]
#[repr(u8)]
pub enum SystemBroadcast{
SystemBroadcast = 0x00,
#[default]
Broadcast = 0x10,
}
#[derive(FromRepr, Debug, Copy, Clone, PartialEq, Default)]
#[repr(u8)]
pub enum Priority {
#[default]
Low = 0x0C,
Normal = 0x04,
Urgent = 0x08,
System = 0x00,
}
#[derive(FromRepr, Debug, Copy, Clone, PartialEq, Default)]
#[repr(u8)]
pub enum Acknowledge {
NoAcknowledge = 0x00,
#[default]
Acknowledge = 0x02,
}
#[derive(FromRepr, Debug, Copy, Clone, PartialEq, Default)]
#[repr(u8)]
pub enum Confirmation {
#[default]
NoError = 0x00,
Error = 0x01,
}
#[derive(FromRepr, Debug, Copy, Clone, PartialEq, Default)]
#[repr(u8)]
pub enum FrameFormat {
#[default]
Standard = 0x00,
LTE0 = 0x04,
LTE1 = 0x05,
LTE2 = 0x06,
LTE3 = 0x07,
}
#[derive(FromRepr, Debug, Copy, Clone, PartialEq, Default)]
#[repr(u8)]
pub enum AddressType {
Individual = 0x00,
#[default]
Group = 0x80,
}
#[derive(Debug, Clone, PartialEq)]
pub(crate) struct LData<D: DPT+Default>{
pub(crate) frame_type: FrameType,
pub(crate) repetition: Repetition,
pub(crate) system_broadcast: SystemBroadcast,
pub(crate) priority: Priority,
pub(crate) acknowledge: Acknowledge,
pub(crate) confirmation: Confirmation,
pub(crate) destination_address_type: AddressType,
pub(crate) hop_count: u8,
pub(crate) frame_format: FrameFormat,
pub(crate) source: u16,
pub(crate) destination: u16,
pub(crate) control: bool,
pub(crate) numbered: bool,
pub(crate) seq: u8,
pub(crate) data: Apdu<D>,
}
impl<D: DPT+Default> Default for LData<D>{
fn default() -> Self {
return LData{
frame_type: FrameType::default(),
repetition: Repetition::default(),
system_broadcast: SystemBroadcast::default(),
priority: Priority::default(),
acknowledge: Acknowledge::default(),
confirmation: Confirmation::default(),
destination_address_type: AddressType::default(),
hop_count: 6,
frame_format: FrameFormat::default(),
source: 0,
destination: 0,
control: false,
numbered: false,
seq: 0,
data: Apdu::default(),
}
}
}
impl<D:DPT+Default> LData<D> {
pub(crate) fn length(&self)->u8 {
return (8 + self.data.length()) as u8
}
pub(crate) fn encode(&self, buf: &mut Vec<u8>) {
buf.push(self.frame_type as u8|self.repetition as u8|self.system_broadcast as u8|self.priority as u8|self.acknowledge as u8|self.confirmation as u8);
buf.push(self.destination_address_type as u8 | ((self.hop_count&0x7) << 4) | self.frame_format as u8);
buf.extend(self.source.to_be_bytes());
buf.extend(self.destination.to_be_bytes());
buf.push(self.data.length() as u8);
let b7 = if self.control {0x80} else {0} | if self.numbered {0x40} else {0} | ((self.seq & 0xF)<<2);
self.data.encode(buf, b7);
}
pub(crate) fn decode(&mut self, buf: &[u8]) -> Result<(), KnxNetIpError> {
if buf.len() < 8 || buf.len() < (8 + buf[6]) as usize {
return Err(KnxNetIpError::MessageTooShort(buf.len()))
}
self.frame_type = FrameType::from_repr(buf[0]&0x80).unwrap();
self.repetition = Repetition::from_repr(buf[0] & 0x20).unwrap();
self.system_broadcast = SystemBroadcast::from_repr(buf[0] & 0x10).unwrap();
self.priority = Priority::from_repr(buf[0] & 0x0C).unwrap();
self.acknowledge = Acknowledge::from_repr(buf[0] & 0x02).unwrap();
self.confirmation = Confirmation::from_repr(buf[0] & 0x01).unwrap();
self.destination_address_type = AddressType::from_repr(buf[1] & 0x80).unwrap();
self.hop_count = (buf[1] & 0x70) >> 4;
self.frame_format = match FrameFormat::from_repr(buf[1] & 0x07) {Some(v) => v, None =>{ return Err(KnxNetIpError::Unknown)}};
self.source = BigEndian::read_u16(&buf[2..4]);
self.destination = BigEndian::read_u16(&buf[4..6]);
self.control = (buf[7] & 0x80) != 0;
self.numbered = (buf[7] & 0x40) != 0;
self.seq = (buf[7] >> 2) & 0xF;
self.data = Apdu::decode(&buf[6..(8+buf[6] as usize)])?;
return Ok(());
}
}