dash7_alp/wizzilab/v5_3/dash7/
interface_tx_status.rs

1#[cfg(test)]
2use crate::test_tools::test_item;
3use crate::{
4    codec::{Codec, StdError, WithOffset, WithSize},
5    wizzilab::v5_3::dash7::{
6        stack_error::InterfaceFinalStatusCode, Address, AddressType, NlsMethod,
7    },
8};
9#[cfg(test)]
10use hex_literal::hex;
11use std::convert::TryFrom;
12
13/// Dash7 metadata upon packet transmission.
14#[derive(Clone, Debug, PartialEq)]
15pub struct InterfaceTxStatus {
16    /// PHY layer channel header
17    pub ch_header: u8,
18    /// PHY layer channel index
19    pub ch_idx: u16,
20    /// Target power in dBm
21    pub eirp: i8,
22    /// D7A Error
23    pub err: InterfaceFinalStatusCode,
24    /// RFU
25    /// XXX align to u32
26    pub rfu_0: u8,
27    pub rfu_1: u8,
28    pub rfu_2: u8,
29    /// End transmission date using the local RTC time stamp
30    pub lts: u32,
31    /// Access class
32    pub access_class: u8,
33    /// NLS method
34    pub nls_method: NlsMethod,
35    /// Addressee
36    pub address: Address,
37}
38impl std::fmt::Display for InterfaceTxStatus {
39    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
40        write!(
41            f,
42            "ch({};{}),eirp={},err={},lts={},address={}",
43            self.ch_header, self.ch_idx, self.eirp, self.err, self.lts, self.address
44        )
45    }
46}
47#[derive(Debug, Copy, Clone, PartialEq)]
48pub enum InterfaceTxStatusDecodingError {
49    MissingBytes(usize),
50    UnknownStatusCode(u8),
51}
52impl From<StdError> for InterfaceTxStatusDecodingError {
53    fn from(e: StdError) -> Self {
54        match e {
55            StdError::MissingBytes(n) => Self::MissingBytes(n),
56        }
57    }
58}
59impl Codec for InterfaceTxStatus {
60    type Error = InterfaceTxStatusDecodingError;
61    fn encoded_size(&self) -> usize {
62        1 + 2 + 1 + 1 + 1 + 1 + 1 + 4 + 1 + 1 + self.address.encoded_size()
63    }
64
65    unsafe fn encode_in(&self, out: &mut [u8]) -> usize {
66        let mut i = 0;
67        out[i] = self.ch_header;
68        i += 1;
69        out[i..(i + 2)].clone_from_slice(&self.ch_idx.to_be_bytes());
70        i += 2;
71        out[i] = self.eirp as u8;
72        i += 1;
73        out[i] = self.err as u8;
74        i += 1;
75        out[i] = self.rfu_0;
76        i += 1;
77        out[i] = self.rfu_1;
78        i += 1;
79        out[i] = self.rfu_2;
80        i += 1;
81        out[i..(i + 4)].clone_from_slice(&self.lts.to_le_bytes());
82        i += 4;
83        out[i] = ((self.address.id_type() as u8) << 4) | (self.nls_method as u8);
84        i += 1;
85        out[i] = self.access_class;
86        i += 1;
87        i += self.address.encode_in(&mut out[i..]);
88        i
89    }
90    fn decode(out: &[u8]) -> Result<WithSize<Self>, WithOffset<Self::Error>> {
91        if out.len() < 15 {
92            return Err(WithOffset::new_head(Self::Error::MissingBytes(
93                15 - out.len(),
94            )));
95        }
96
97        let ch_header = out[0];
98        let ch_idx = ((out[1] as u16) << 8) + out[2] as u16;
99        let eirp = out[3] as i8;
100        let err = InterfaceFinalStatusCode::try_from(out[4])
101            .map_err(|e| WithOffset::new(4, Self::Error::UnknownStatusCode(e)))?;
102        let rfu_0 = out[5];
103        let rfu_1 = out[6];
104        let rfu_2 = out[7];
105        let lts = u32::from_le_bytes([out[8], out[9], out[10], out[11]]);
106        let address_type = AddressType::from((out[12] & 0x30) >> 4);
107        let nls_method = unsafe { NlsMethod::from(out[12] & 0x07) };
108        let access_class = out[13];
109        let WithSize {
110            size: address_size,
111            value: address,
112        } = Address::parse(address_type, &out[14..]).map_err(|e| {
113            let WithOffset { offset, value } = e;
114            WithOffset {
115                offset: offset + 5,
116                value: value.into(),
117            }
118        })?;
119        let size = 14 + address_size;
120        Ok(WithSize {
121            value: Self {
122                ch_header,
123                ch_idx,
124                eirp,
125                err,
126                rfu_0,
127                rfu_1,
128                rfu_2,
129                lts,
130                access_class,
131                nls_method,
132                address,
133            },
134            size,
135        })
136    }
137}
138#[test]
139fn test_interface_tx_status() {
140    test_item(
141        InterfaceTxStatus {
142            ch_header: 1,
143            ch_idx: 0x0123,
144            eirp: 2,
145            err: InterfaceFinalStatusCode::Busy,
146            rfu_0: 4,
147            rfu_1: 5,
148            rfu_2: 6,
149            lts: 0x0708_0000,
150            access_class: 0xFF,
151            nls_method: NlsMethod::AesCcm64,
152            address: Address::Vid([0x00, 0x11]),
153        },
154        &hex!("01 0123 02 FF 04 05 06 0000 0807 36 FF 0011 000000000000"),
155    )
156}