use strum_macros::FromRepr;
use crate::dpt::DPT;
use crate::knxnet::KnxNetIpError;
#[derive(PartialEq, FromRepr, Debug, Clone, Default)]
#[repr(u16)]
pub enum Apdu<D: DPT+Default>{
#[default]
GroupValueRead = 0b0000_000000,
GroupValueResponse(D) = 0b0001_000000,
GroupValueWrite(D) = 0b0010_000000,
IndividualAddressWrite = 0b0011_000000,
IndividualAddressRead = 0b0100_000000,
IndividualAddressResponse = 0b0101_000000,
AdcRead = 0b0110_000000,
AdcResponse = 0b0111_000000,
None
}
impl<D: DPT+Default> Apdu<D> {
pub(crate) fn length(&self)->u8 {
match self {
Apdu::GroupValueWrite(dpt) | Apdu::GroupValueResponse(dpt) => {
return if dpt.bit_len() > 6 { (1 + dpt.bit_len() / 8) as u8 } else { 1 }
}
Apdu::GroupValueRead => 1,
_ => 0
}
}
fn identifier(&self) -> u16 {
unsafe { *<*const _>::from(self).cast::<u16>() }
}
pub(crate) fn encode(&self, buf: &mut Vec<u8>, previous_byte: u8) {
let apci = self.identifier() & 0b1111_111111;
buf.push(previous_byte | ((apci >> 8) & 0x3) as u8);
match self {
Apdu::GroupValueRead => {buf.push((apci & 0xff) as u8);},
Apdu::GroupValueWrite(dpt) | Apdu::GroupValueResponse(dpt) => {
if dpt.bit_len() <= 6 {
dpt.encode(buf);
let len = buf.len();
buf[len-1] |= (apci & 0xff) as u8
} else {
buf.push((apci & 0xff) as u8);
dpt.encode(buf);
}
}
_ => {
buf.push((apci & 0xff) as u8);
}
}
}
pub(crate) fn decode(buf: &[u8]) -> Result<Apdu<D>, KnxNetIpError> {
Ok(
if buf[0] == 0 {
Apdu::None
} else {
let apci = ((buf[1] & 0x3) as u16) << 8 | (buf[2]) as u16;
let short_apci = apci & 0b1111_000000;
match Apdu::from_repr(short_apci) {
None => return Err(KnxNetIpError::Unknown),
Some(mut a ) => match a{
Apdu::GroupValueRead => a,
Apdu::GroupValueResponse(ref mut dpt) | Apdu::GroupValueWrite(ref mut dpt) => {
dpt.decode(&buf[2..])?; a},
_ => return Err(KnxNetIpError::NotImplemented)
}
}
}
)
}
}