open_dis_rust/distributed_emissions/
underwater_acoustic_pdu.rs

1//     open-dis-rust - Rust implementation of the IEEE 1278.1-2012 Distributed Interactive
2//                     Simulation (DIS) application protocol
3//     Copyright (C) 2023 Cameron Howell
4//
5//     Licensed under the BSD 2-Clause License
6
7use bytes::{Buf, BufMut, BytesMut};
8use std::any::Any;
9
10use crate::common::{
11    dis_error::DISError,
12    entity_id::EntityId,
13    enums::{UAPassiveParameterIndex, UAStateChangeUpdateIndicator},
14    event_id::EventId,
15    pdu::Pdu,
16    pdu_header::{PduHeader, PduType, ProtocolFamily},
17};
18
19use super::data_types::{
20    acoustic_emitter_system::AcousticEmitterSystem, apa_data::ApaData, shaft_rpms::ShaftRPMs,
21};
22
23#[derive(Clone, Debug)]
24/// Implemented according to IEEE 1278.1-2012 ยง7.6.4
25pub struct UnderwaterAcousticPdu {
26    pub pdu_header: PduHeader,
27    pub emitting_entity_id: EntityId,
28    pub event_id: EventId,
29    pub state_change_indicator: UAStateChangeUpdateIndicator,
30    pub pad: u8,
31    pub passive_parameter_index: UAPassiveParameterIndex,
32    pub propulsion_plant_configuration: u8,
33    pub number_of_shafts: u8,
34    pub number_of_apas: u8,
35    pub number_of_ua_emitter_systems: u8,
36    pub shaft_rpms: Vec<ShaftRPMs>,
37    pub apa_data: Vec<ApaData>,
38    pub emitter_systems: Vec<AcousticEmitterSystem>,
39}
40
41impl Default for UnderwaterAcousticPdu {
42    /// Creates a default-initialized Underwater Acoustic PDU
43    ///
44    /// # Examples
45    ///
46    /// Initializing an Underwater Acoustic PDU:
47    /// ```
48    /// use open_dis_rust::distributed_emissions::underwater_acoustic_pdu::UnderwaterAcousticPdu;
49    /// let mut underwater_acoustic_pdu = UnderwaterAcousticPdu::default();
50    /// ```
51    ///
52    fn default() -> Self {
53        UnderwaterAcousticPdu {
54            pdu_header: PduHeader::default(
55                PduType::UnderwaterAcoustic,
56                ProtocolFamily::DistributedEmissionRegeneration,
57                56,
58            ),
59            emitting_entity_id: EntityId::default(1),
60            event_id: EventId::default(1),
61            state_change_indicator: UAStateChangeUpdateIndicator::default(),
62            pad: 0,
63            passive_parameter_index: UAPassiveParameterIndex::default(),
64            propulsion_plant_configuration: 0,
65            number_of_shafts: 0,
66            number_of_apas: 0,
67            number_of_ua_emitter_systems: 0,
68            shaft_rpms: vec![],
69            apa_data: vec![],
70            emitter_systems: vec![],
71        }
72    }
73}
74
75impl Pdu for UnderwaterAcousticPdu {
76    /// Serialize contents of `UnderwaterAcousticPdu` into `BytesMut` buffer
77    fn serialize(&mut self, buf: &mut BytesMut) {
78        self.pdu_header.length = u16::try_from(std::mem::size_of_val(self))
79            .expect("The length of the PDU should fit in a u16.");
80        self.pdu_header.serialize(buf);
81        self.emitting_entity_id.serialize(buf);
82        self.event_id.serialize(buf);
83        buf.put_u8(self.state_change_indicator as u8);
84        buf.put_u8(self.pad);
85        buf.put_u16(self.passive_parameter_index as u16);
86        buf.put_u8(self.propulsion_plant_configuration);
87        buf.put_u8(self.number_of_shafts);
88        buf.put_u8(self.number_of_apas);
89        buf.put_u8(self.number_of_ua_emitter_systems);
90        for i in 0..self.shaft_rpms.len() {
91            self.shaft_rpms[i].serialize(buf);
92        }
93        for i in 0..self.apa_data.len() {
94            self.apa_data[i].serialize(buf);
95        }
96        for i in 0..self.emitter_systems.len() {
97            self.emitter_systems[i].serialize(buf);
98        }
99    }
100
101    /// Deserialize bytes from `BytesMut` buffer and interpret as `UnderwaterAcousticPdu`
102    fn deserialize(mut buffer: BytesMut) -> Result<Self, DISError>
103    where
104        Self: Sized,
105    {
106        let pdu_header = PduHeader::deserialize(&mut buffer);
107        if pdu_header.pdu_type == PduType::UnderwaterAcoustic {
108            let emitting_entity_id = EntityId::deserialize(&mut buffer);
109            let event_id = EventId::deserialize(&mut buffer);
110            let state_change_indicator = UAStateChangeUpdateIndicator::deserialize(&mut buffer);
111            let pad = buffer.get_u8();
112            let passive_parameter_index = UAPassiveParameterIndex::deserialize(&mut buffer);
113            let propulsion_plant_configuration = buffer.get_u8();
114            let number_of_shafts = buffer.get_u8();
115            let number_of_apas = buffer.get_u8();
116            let number_of_ua_emitter_systems = buffer.get_u8();
117            let mut shaft_rpms: Vec<ShaftRPMs> = vec![];
118            for _i in 0..number_of_shafts {
119                shaft_rpms.push(ShaftRPMs::deserialize(&mut buffer));
120            }
121            let mut apa_data: Vec<ApaData> = vec![];
122            for _i in 0..number_of_apas {
123                apa_data.push(ApaData::deserialize(&mut buffer));
124            }
125            let mut emitter_systems: Vec<AcousticEmitterSystem> = vec![];
126            for _i in 0..number_of_ua_emitter_systems {
127                emitter_systems.push(AcousticEmitterSystem::deserialize(&mut buffer));
128            }
129            Ok(UnderwaterAcousticPdu {
130                pdu_header,
131                emitting_entity_id,
132                event_id,
133                state_change_indicator,
134                pad,
135                passive_parameter_index,
136                propulsion_plant_configuration,
137                number_of_shafts,
138                number_of_apas,
139                number_of_ua_emitter_systems,
140                shaft_rpms,
141                apa_data,
142                emitter_systems,
143            })
144        } else {
145            Err(DISError::invalid_header(
146                format!(
147                    "Expected PDU type UnderwaterAcoustic, got {:?}",
148                    pdu_header.pdu_type
149                ),
150                None,
151            ))
152        }
153    }
154
155    /// Treat `UnderwaterAcousticPdu` as Any type
156    fn as_any(&self) -> &dyn Any {
157        self
158    }
159
160    /// Deserialize bytes from `BytesMut` buffer, but assume PDU header exists already
161    fn deserialize_without_header(
162        mut buffer: BytesMut,
163        pdu_header: PduHeader,
164    ) -> Result<Self, DISError>
165    where
166        Self: Sized,
167    {
168        let emitting_entity_id = EntityId::deserialize(&mut buffer);
169        let event_id = EventId::deserialize(&mut buffer);
170        let state_change_indicator = UAStateChangeUpdateIndicator::deserialize(&mut buffer);
171        let pad = buffer.get_u8();
172        let passive_parameter_index = UAPassiveParameterIndex::deserialize(&mut buffer);
173        let propulsion_plant_configuration = buffer.get_u8();
174        let number_of_shafts = buffer.get_u8();
175        let number_of_apas = buffer.get_u8();
176        let number_of_ua_emitter_systems = buffer.get_u8();
177        let mut shaft_rpms: Vec<ShaftRPMs> = vec![];
178        for _i in 0..number_of_shafts {
179            shaft_rpms.push(ShaftRPMs::deserialize(&mut buffer));
180        }
181        let mut apa_data: Vec<ApaData> = vec![];
182        for _i in 0..number_of_apas {
183            apa_data.push(ApaData::deserialize(&mut buffer));
184        }
185        let mut emitter_systems: Vec<AcousticEmitterSystem> = vec![];
186        for _i in 0..number_of_ua_emitter_systems {
187            emitter_systems.push(AcousticEmitterSystem::deserialize(&mut buffer));
188        }
189        Ok(UnderwaterAcousticPdu {
190            pdu_header,
191            emitting_entity_id,
192            event_id,
193            state_change_indicator,
194            pad,
195            passive_parameter_index,
196            propulsion_plant_configuration,
197            number_of_shafts,
198            number_of_apas,
199            number_of_ua_emitter_systems,
200            shaft_rpms,
201            apa_data,
202            emitter_systems,
203        })
204    }
205}
206
207#[cfg(test)]
208mod tests {
209    use super::UnderwaterAcousticPdu;
210    use crate::common::{
211        pdu::Pdu,
212        pdu_header::{PduHeader, PduType, ProtocolFamily},
213    };
214    use bytes::BytesMut;
215
216    #[test]
217    fn create_header() {
218        let supplemental_emission_pdu = UnderwaterAcousticPdu::default();
219        let pdu_header = PduHeader::default(
220            PduType::UnderwaterAcoustic,
221            ProtocolFamily::DistributedEmissionRegeneration,
222            448 / 8,
223        );
224
225        assert_eq!(
226            pdu_header.protocol_version,
227            supplemental_emission_pdu.pdu_header.protocol_version
228        );
229        assert_eq!(
230            pdu_header.exercise_id,
231            supplemental_emission_pdu.pdu_header.exercise_id
232        );
233        assert_eq!(
234            pdu_header.pdu_type,
235            supplemental_emission_pdu.pdu_header.pdu_type
236        );
237        assert_eq!(
238            pdu_header.protocol_family,
239            supplemental_emission_pdu.pdu_header.protocol_family
240        );
241        assert_eq!(
242            pdu_header.length,
243            supplemental_emission_pdu.pdu_header.length
244        );
245        assert_eq!(
246            pdu_header.status_record,
247            supplemental_emission_pdu.pdu_header.status_record
248        );
249    }
250
251    #[test]
252    fn cast_to_any() {
253        let udnerwater_acoustic_pdu = UnderwaterAcousticPdu::default();
254        let any_pdu = udnerwater_acoustic_pdu.as_any();
255
256        assert!(any_pdu.is::<UnderwaterAcousticPdu>());
257    }
258
259    #[test]
260    fn deserialize_header() {
261        let mut supplemental_emission_pdu = UnderwaterAcousticPdu::default();
262        let mut buffer = BytesMut::new();
263        supplemental_emission_pdu.serialize(&mut buffer);
264
265        let new_supplemental_emission_pdu = UnderwaterAcousticPdu::deserialize(buffer).unwrap();
266        assert_eq!(
267            new_supplemental_emission_pdu.pdu_header,
268            supplemental_emission_pdu.pdu_header
269        );
270    }
271}