open_dis_rust/radio_communications/
signal_pdu.rs

1//     open-dis-rust - Rust implementation of the IEEE-1278.1 Distributed Interactive Simulation
2//     Copyright (C) 2023 Cameron Howell
3//
4//     Licensed under the BSD-2-Clause License
5
6use crate::common::{
7    dis_error::DISError,
8    entity_id::EntityId,
9    pdu::Pdu,
10    pdu_header::{PduHeader, PduType, ProtocolFamily},
11};
12use bytes::{Buf, BufMut, BytesMut};
13use std::any::Any;
14
15#[derive(Clone, Debug)]
16/// Implemented according to IEEE 1278.1-2012 ยง7.7.3
17pub struct SignalPdu {
18    pub pdu_header: PduHeader,
19    pub entity_id: EntityId,
20    pub radio_id: u16,
21    pub encoding_scheme: u16,
22    pub tdl_type: u16,
23    pub sample_rate: u32,
24    pub data_length: u16,
25    pub samples: u16,
26    pub data: Vec<u8>,
27}
28
29impl Default for SignalPdu {
30    /// Creates a default Signal PDU with arbitrary originating and receiving
31    /// entity IDs
32    ///
33    /// # Examples
34    ///
35    /// Initializing a Signal PDU:
36    /// ```
37    /// use open_dis_rust::radio_communications::signal_pdu::SignalPdu;
38    /// let signal_pdu = SignalPdu::default();
39    /// ```
40    ///
41    fn default() -> Self {
42        SignalPdu {
43            pdu_header: PduHeader::default(
44                PduType::Signal,
45                ProtocolFamily::RadioCommunications,
46                256,
47            ),
48            entity_id: EntityId::default(1),
49            radio_id: 0,
50            encoding_scheme: 0,
51            tdl_type: 0,
52            sample_rate: 0,
53            data_length: 0,
54            samples: 0,
55            data: vec![],
56        }
57    }
58}
59
60impl Pdu for SignalPdu {
61    fn serialize(&mut self, buf: &mut BytesMut) {
62        self.pdu_header.length = u16::try_from(std::mem::size_of_val(self))
63            .expect("The length of the PDU should fit in a u16.");
64        self.pdu_header.serialize(buf);
65        self.entity_id.serialize(buf);
66        buf.put_u16(self.radio_id);
67        buf.put_u16(self.encoding_scheme);
68        buf.put_u16(self.tdl_type);
69        buf.put_u32(self.sample_rate);
70        buf.put_u16(self.data_length);
71        buf.put_u16(self.samples);
72        for i in 0..self.data.len() {
73            buf.put_u8(self.data[i]);
74        }
75    }
76
77    fn deserialize(mut buffer: BytesMut) -> Result<Self, DISError>
78    where
79        Self: Sized,
80    {
81        let pdu_header = PduHeader::deserialize(&mut buffer);
82        if pdu_header.pdu_type == PduType::Signal {
83            let entity_id = EntityId::deserialize(&mut buffer);
84            let radio_id = buffer.get_u16();
85            let encoding_scheme = buffer.get_u16();
86            let tdl_type = buffer.get_u16();
87            let sample_rate = buffer.get_u32();
88            let data_length = buffer.get_u16();
89            let samples = buffer.get_u16();
90            let mut data: Vec<u8> = vec![];
91            for _i in 0..data_length {
92                if !buffer.has_remaining() {
93                    break;
94                }
95                data.push(buffer.get_u8());
96            }
97            Ok(SignalPdu {
98                pdu_header,
99                entity_id,
100                radio_id,
101                encoding_scheme,
102                tdl_type,
103                sample_rate,
104                data_length,
105                samples,
106                data,
107            })
108        } else {
109            Err(DISError::invalid_header(
110                format!("Expected PDU type Signal, got {:?}", pdu_header.pdu_type),
111                None,
112            ))
113        }
114    }
115
116    fn as_any(&self) -> &dyn Any {
117        self
118    }
119
120    fn deserialize_without_header(
121        mut buffer: BytesMut,
122        pdu_header: PduHeader,
123    ) -> Result<Self, DISError>
124    where
125        Self: Sized,
126    {
127        let entity_id = EntityId::deserialize(&mut buffer);
128        let radio_id = buffer.get_u16();
129        let encoding_scheme = buffer.get_u16();
130        let tdl_type = buffer.get_u16();
131        let sample_rate = buffer.get_u32();
132        let data_length = buffer.get_u16();
133        let samples = buffer.get_u16();
134        let mut data: Vec<u8> = vec![];
135        for _i in 0..data_length {
136            if !buffer.has_remaining() {
137                break;
138            }
139            data.push(buffer.get_u8());
140        }
141        Ok(SignalPdu {
142            pdu_header,
143            entity_id,
144            radio_id,
145            encoding_scheme,
146            tdl_type,
147            sample_rate,
148            data_length,
149            samples,
150            data,
151        })
152    }
153}
154
155#[cfg(test)]
156mod tests {
157    use super::SignalPdu;
158    use crate::common::{
159        pdu::Pdu,
160        pdu_header::{PduHeader, PduType, ProtocolFamily},
161    };
162    use bytes::BytesMut;
163
164    #[test]
165    fn create_header() {
166        let signal_pdu = SignalPdu::default();
167        let pdu_header =
168            PduHeader::default(PduType::Signal, ProtocolFamily::RadioCommunications, 256);
169
170        assert_eq!(
171            pdu_header.protocol_version,
172            signal_pdu.pdu_header.protocol_version
173        );
174        assert_eq!(pdu_header.exercise_id, signal_pdu.pdu_header.exercise_id);
175        assert_eq!(pdu_header.pdu_type, signal_pdu.pdu_header.pdu_type);
176        assert_eq!(
177            pdu_header.protocol_family,
178            signal_pdu.pdu_header.protocol_family
179        );
180        assert_eq!(pdu_header.length, signal_pdu.pdu_header.length);
181        assert_eq!(
182            pdu_header.status_record,
183            signal_pdu.pdu_header.status_record
184        );
185    }
186
187    #[test]
188    fn deserialize_header() {
189        let mut signal_pdu = SignalPdu::default();
190        let mut buffer = BytesMut::new();
191        signal_pdu.serialize(&mut buffer);
192
193        let new_signal_pdu = SignalPdu::deserialize(buffer).unwrap();
194        assert_eq!(new_signal_pdu.pdu_header, signal_pdu.pdu_header);
195    }
196}