open_dis_rust/
distributed_emissions.rs

1//     open-dis-rust - Rust implementation of the IEEE 1278.1-2012 Distributed Interactive
2//                     Simulation (DIS) application protocol
3//     Copyright (C) 2025 Cameron Howell
4//
5//     Licensed under the BSD 2-Clause License
6
7//! The Distributed Emission Regeneration protocol family
8
9#![allow(deprecated)]
10
11use crate::{
12    common::{
13        GenericHeader, SerializedLength,
14        data_types::{
15            EntityCoordinateVector, EntityId, EventId, LinearAcceleration, WorldCoordinate,
16            acoustic_emitter_system::AcousticEmitterSystem, apa_data::ApaData, beam_data::BeamData,
17            electromagnetic_emission_system_data::ElectromagneticEmissionSystemData,
18            fundamental_operational_data::FundamentalOperationalData,
19            iff_fundamental_parameter_data::IFFFundamentalParameterData, layer_header::LayerHeader,
20            propulsion_system_data::PropulsionSystemData,
21            secondary_operational_data::SecondaryOperationalData, shaft_rpms::ShaftRPMs,
22            system_id::SystemId, vectoring_nozzle_system_data::VectoringNozzleSystemData,
23        },
24        enums::{
25            DeadReckoningAlgorithm, DesignatorCode, DesignatorSystemName,
26            EEAttributeStateIndicator, PduType, ProtocolFamily, UAPassiveParameterIndex,
27            UAStateChangeUpdateIndicator,
28        },
29        pdu::Pdu,
30        pdu_header::PduHeader,
31    },
32    define_pdu,
33};
34
35define_pdu! {
36    #[derive(Debug)]
37    /// Implemented according to IEEE 1278.1-2012 §7.6.2
38    pub struct ElectromagneticEmissionsPdu {
39        header: PduHeader,
40        pdu_type: PduType::ElectromagneticEmission,
41        protocol_family: ProtocolFamily::DistributedEmissionRegeneration,
42        fields: {
43            pub emitting_entity_id: EntityId,
44            pub event_id: EventId,
45            pub state_update_indicator: EEAttributeStateIndicator,
46            pub number_of_systems: u8,
47            padding: u16,
48            pub systems: Vec<ElectromagneticEmissionSystemData>,
49        }
50    }
51}
52
53define_pdu! {
54    #[derive(Debug)]
55    /// Implemented according to IEEE 1278.1-2012 §7.6.3
56    pub struct DesignatorPdu {
57        header: PduHeader,
58        pdu_type: PduType::Designator,
59        protocol_family: ProtocolFamily::DistributedEmissionRegeneration,
60        fields: {
61            pub designating_entity_id: EntityId,
62            pub code_name: DesignatorSystemName,
63            pub designated_entity_id: EntityId,
64            pub designator_code: DesignatorCode,
65            pub designator_power: f32,
66            pub designator_wavelength: f32,
67            pub designator_spot_wrt_designated: EntityCoordinateVector,
68            pub designator_spot_location: WorldCoordinate,
69            pub dead_reckoning_algorithm: DeadReckoningAlgorithm,
70            padding: u8,
71            padding2: u16,
72            pub entity_linear_acceleration: LinearAcceleration,
73        }
74    }
75}
76
77define_pdu! {
78    #[derive(Debug)]
79    /// Implemented according to IEEE 1278.1-2012 §7.6.4
80    pub struct UnderwaterAcousticPdu {
81        header: PduHeader,
82        pdu_type: PduType::UnderwaterAcoustic,
83        protocol_family: ProtocolFamily::DistributedEmissionRegeneration,
84        fields: {
85            pub emitting_entity_id: EntityId,
86            pub event_id: EventId,
87            pub state_change_update_indicator: UAStateChangeUpdateIndicator,
88            padding: u8,
89            pub passive_parameter_index: UAPassiveParameterIndex,
90            pub propulsion_plant_configuration: u8,
91            pub number_of_shafts: u8,
92            pub number_of_apas: u8,
93            pub number_of_ua_emitter_systems: u8,
94            pub shaft_rpms: Vec<ShaftRPMs>,
95            pub apa_data: Vec<ApaData>,
96            pub emitter_systems: Vec<AcousticEmitterSystem>,
97        }
98    }
99}
100
101define_pdu! {
102    #[derive(Debug)]
103    /// Implemented according to IEEE 1278.1-2012 §7.6.5
104    pub struct IFFPdu {
105        header: PduHeader,
106        pdu_type: PduType::IFF,
107        protocol_family: ProtocolFamily::DistributedEmissionRegeneration,
108        fields: {
109            pub emitting_entity_id: EntityId,
110            pub event_id: EventId,
111            pub relative_antenna_location: EntityCoordinateVector,
112            pub system_id: SystemId,
113            pub system_designator: u8,
114            pub system_specific_data: u8,
115            pub fundamental_operational_data: FundamentalOperationalData,
116            pub layer_header: LayerHeader,
117            pub beam_data: BeamData,
118            pub secondary_operational_data: SecondaryOperationalData,
119            pub iff_parameters: Vec<IFFFundamentalParameterData>,
120        }
121    }
122}
123
124define_pdu! {
125    #[derive(Debug)]
126    /// Implemented according to IEEE 1278.1-2012 §7.6.6
127    pub struct SupplementalEmissionPdu {
128        header: PduHeader,
129        pdu_type: PduType::SupplementalEmission,
130        protocol_family: ProtocolFamily::DistributedEmissionRegeneration,
131        fields: {
132            pub originating_entity_id: EntityId,
133            pub infrared_signature_representation_index: u16,
134            pub acoustic_signature_representation_index: u16,
135            pub radar_cross_section_signature_representation_index: u16,
136            pub number_of_propulsion_systems: u16,
137            pub number_of_vectoring_nozzle_systems: u16,
138            pub propulsion_system_data: Vec<PropulsionSystemData>,
139            pub vectoring_nozzle_system_data: Vec<VectoringNozzleSystemData>,
140        }
141    }
142}
143
144#[cfg(test)]
145mod tests {
146    use super::*;
147    use crate::common::{constants::BITS_PER_BYTE, pdu::Pdu};
148    use bytes::BytesMut;
149
150    mod designator_pdu_tests {
151        use super::*;
152
153        #[test]
154        fn cast_to_any() {
155            let pdu = DesignatorPdu::new();
156            let any_pdu = pdu.as_any();
157            assert!(any_pdu.is::<DesignatorPdu>());
158        }
159
160        #[test]
161        fn serialize_then_deserialize() {
162            let mut pdu = DesignatorPdu::new();
163            let mut serialize_buf = BytesMut::new();
164            let _ = pdu.serialize(&mut serialize_buf);
165
166            let mut deserialize_buf = serialize_buf.freeze();
167            let new_pdu = DesignatorPdu::deserialize(&mut deserialize_buf).unwrap_or_default();
168            assert_eq!(new_pdu.header(), pdu.header());
169        }
170
171        #[test]
172        fn check_default_pdu_length() {
173            const DEFAULT_LENGTH: u16 = 704 / BITS_PER_BYTE;
174            let pdu = DesignatorPdu::new();
175            assert_eq!(pdu.header().length, DEFAULT_LENGTH);
176        }
177    }
178
179    mod electromagnetic_emissions_pdu_tests {
180        use super::*;
181
182        #[test]
183        fn cast_to_any() {
184            let pdu = ElectromagneticEmissionsPdu::new();
185            let any_pdu = pdu.as_any();
186            assert!(any_pdu.is::<ElectromagneticEmissionsPdu>());
187        }
188
189        #[test]
190        fn serialize_then_deserialize() {
191            let mut pdu = ElectromagneticEmissionsPdu::new();
192            let mut serialize_buf = BytesMut::new();
193            let _ = pdu.serialize(&mut serialize_buf);
194
195            let mut deserialize_buf = serialize_buf.freeze();
196            let new_pdu =
197                ElectromagneticEmissionsPdu::deserialize(&mut deserialize_buf).unwrap_or_default();
198            assert_eq!(new_pdu.header(), pdu.header());
199        }
200
201        #[test]
202        fn check_default_pdu_length() {
203            const DEFAULT_LENGTH: u16 = 224 / BITS_PER_BYTE;
204            let pdu = ElectromagneticEmissionsPdu::new();
205            assert_eq!(pdu.header().length, DEFAULT_LENGTH);
206        }
207    }
208
209    mod underwater_acoustic_pdu_tests {
210        use super::*;
211
212        #[test]
213        fn cast_to_any() {
214            let pdu = UnderwaterAcousticPdu::new();
215            let any_pdu = pdu.as_any();
216            assert!(any_pdu.is::<UnderwaterAcousticPdu>());
217        }
218
219        #[test]
220        fn serialize_then_deserialize() {
221            let mut pdu = UnderwaterAcousticPdu::new();
222            let mut serialize_buf = BytesMut::new();
223            let _ = pdu.serialize(&mut serialize_buf);
224
225            let mut deserialize_buf = serialize_buf.freeze();
226            let new_pdu =
227                UnderwaterAcousticPdu::deserialize(&mut deserialize_buf).unwrap_or_default();
228            assert_eq!(new_pdu.header(), pdu.header());
229        }
230
231        #[test]
232        fn check_default_pdu_length() {
233            const DEFAULT_LENGTH: u16 = 256 / BITS_PER_BYTE;
234            let pdu = UnderwaterAcousticPdu::new();
235            assert_eq!(pdu.header().length, DEFAULT_LENGTH);
236        }
237    }
238
239    mod iff_pdu_tests {
240        use super::*;
241
242        #[test]
243        fn cast_to_any() {
244            let pdu = IFFPdu::new();
245            let any_pdu = pdu.as_any();
246            assert!(any_pdu.is::<IFFPdu>());
247        }
248
249        #[test]
250        fn serialize_then_deserialize() {
251            let mut pdu = IFFPdu::new();
252            let mut serialize_buf = BytesMut::new();
253            let _ = pdu.serialize(&mut serialize_buf);
254
255            let mut deserialize_buf = serialize_buf.freeze();
256            let new_pdu = IFFPdu::deserialize(&mut deserialize_buf).unwrap_or_default();
257            assert_eq!(new_pdu.header(), pdu.header());
258        }
259
260        #[test]
261        fn check_default_pdu_length() {
262            const DEFAULT_LENGTH: u16 = 704 / BITS_PER_BYTE;
263            let pdu = IFFPdu::new();
264            assert_eq!(pdu.header().length, DEFAULT_LENGTH);
265        }
266    }
267
268    mod supplemental_emission_pdu_tests {
269        use super::*;
270
271        #[test]
272        fn cast_to_any() {
273            let pdu = SupplementalEmissionPdu::new();
274            let any_pdu = pdu.as_any();
275            assert!(any_pdu.is::<SupplementalEmissionPdu>());
276        }
277
278        #[test]
279        fn serialize_then_deserialize() {
280            let mut pdu = SupplementalEmissionPdu::new();
281            let mut serialize_buf = BytesMut::new();
282            let _ = pdu.serialize(&mut serialize_buf);
283
284            let mut deserialize_buf = serialize_buf.freeze();
285            let new_pdu =
286                SupplementalEmissionPdu::deserialize(&mut deserialize_buf).unwrap_or_default();
287            assert_eq!(new_pdu.header(), pdu.header());
288        }
289
290        #[test]
291        fn check_default_pdu_length() {
292            const DEFAULT_LENGTH: u16 = 224 / BITS_PER_BYTE;
293            let pdu = SupplementalEmissionPdu::new();
294            assert_eq!(pdu.header().length, DEFAULT_LENGTH);
295        }
296    }
297}