open_dis_rust/
synthetic_environment.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 Synthetic Environment protocol family
8
9use crate::{
10    common::{
11        GenericHeader, SerializedLength,
12        data_types::{
13            ClockTime, EntityId, EntityType, EulerAngles, WorldCoordinate,
14            environment::Environment, grid_axis_descriptor::GridAxisDescriptor,
15            grid_data_record::GridDataRecord, linear_segment_parameter::LinearSegmentParameter,
16            object_identifier::ObjectIdentifier, object_type::ObjectType,
17            simulation_address::SimulationAddress,
18        },
19        enums::{
20            ForceId, GriddedDataConstantGrid, GriddedDataCoordinateSystem,
21            ObjectStateAppearanceGeneral, PduType, ProtocolFamily,
22        },
23        pdu::Pdu,
24        pdu_header::PduHeader,
25    },
26    define_pdu,
27};
28
29define_pdu! {
30    #[derive(Debug)]
31    /// Implemented according to IEEE 1278.1-2012 §7.10.2
32    pub struct EnvironmentalProcessPdu {
33        header: PduHeader,
34        pdu_type: PduType::EnvironmentalProcess,
35        protocol_family: ProtocolFamily::SyntheticEnvironment,
36        fields: {
37            pub environmental_process_id: EntityId,
38            pub environment_type: EntityType,
39            pub model_type: u8,
40            pub environment_status: u8,
41            pub number_of_environment_records: u16,
42            pub sequence_number: u16,
43            pub environment_records: Vec<Environment>,
44        }
45    }
46}
47
48define_pdu! {
49    #[derive(Debug)]
50    /// Implemented according to IEEE 1278.1-2012 §7.10.3
51    pub struct GriddedDataPdu {
52        header: PduHeader,
53        pdu_type: PduType::GriddedData,
54        protocol_family: ProtocolFamily::SyntheticEnvironment,
55        fields: {
56            pub environmental_simulation_id: EntityId,
57            pub field_number: u16,
58            pub pdu_number: u16,
59            pub pdu_total: u16,
60            pub coordinate_system: GriddedDataCoordinateSystem,
61            pub number_of_grid_axes: u8,
62            pub constant_grid: GriddedDataConstantGrid,
63            pub environment_type: EntityType,
64            pub orientation: EulerAngles,
65            pub sample_time: ClockTime,
66            pub total_values: u32,
67            pub vector_dimension: u8,
68            padding: u8,
69            padding2: u16,
70            pub grid_axis_descriptors: Vec<GridAxisDescriptor>,
71            pub grid_data_list: Vec<GridDataRecord>,
72        }
73    }
74}
75
76define_pdu! {
77    #[derive(Debug)]
78    /// Implemented according to IEEE 1278.1-2012 §7.10.4
79    pub struct PointObjectStatePdu {
80        header: PduHeader,
81        pdu_type: PduType::PointObjectState,
82        protocol_family: ProtocolFamily::SyntheticEnvironment,
83        fields: {
84            pub object_id: EntityId,
85            pub referenced_object_id: EntityId,
86            pub update_number: u16,
87            pub force_id: ForceId,
88            pub modifications: u8,
89            pub object_type: ObjectType,
90            pub object_location: WorldCoordinate,
91            pub object_orientation: EulerAngles,
92            pub specific_object_appearance: u32,
93            pub general_object_appearance: u16,
94            padding: u16,
95            pub requester_id: SimulationAddress,
96            pub receiving_id: SimulationAddress,
97            padding2: u32,
98        }
99    }
100}
101
102define_pdu! {
103    #[derive(Debug)]
104    /// Implemented according to IEEE 1278.1-2012 §7.10.5
105    pub struct LinearObjectStatePdu {
106        header: PduHeader,
107        pdu_type: PduType::LinearObjectState,
108        protocol_family: ProtocolFamily::SyntheticEnvironment,
109        fields: {
110            pub object_id: ObjectIdentifier,
111            pub referenced_object_id: ObjectIdentifier,
112            pub update_number: u16,
113            pub force_id: ForceId,
114            pub number_of_segments: u8,
115            pub requester_id: SimulationAddress,
116            pub receiving_id: SimulationAddress,
117            pub object_type: ObjectType,
118            pub linear_segment_parameters: Vec<LinearSegmentParameter>,
119        }
120    }
121}
122
123define_pdu! {
124    #[derive(Debug)]
125    /// Implemented according to IEEE 1278.1-2012 §7.10.6
126    pub struct ArealObjectStatePdu {
127        header: PduHeader,
128        pdu_type: PduType::ArealObjectState,
129        protocol_family: ProtocolFamily::SyntheticEnvironment,
130        fields: {
131            pub object_id: ObjectIdentifier,
132            pub referenced_object_id: ObjectIdentifier,
133            pub update_number: u16,
134            pub force_id: ForceId,
135            pub modifications: u8, // TODO(@anyone) Replace with Modifications UID 242
136            pub object_type: ObjectType,
137            pub specific_object_appearance: u32, // TODO(@anyone) Implement Specific Object Appearance
138            pub general_object_appearance: ObjectStateAppearanceGeneral,
139            pub number_of_points: u16,
140            pub requester_id: SimulationAddress,
141            pub receiving_id: SimulationAddress,
142            pub object_location: Vec<WorldCoordinate>,
143        }
144    }
145}
146
147#[cfg(test)]
148mod tests {
149    use super::*;
150    use crate::common::{constants::BITS_PER_BYTE, pdu::Pdu};
151    use bytes::BytesMut;
152
153    mod environmental_process_pdu_tests {
154        use super::*;
155
156        #[test]
157        fn cast_to_any() {
158            let pdu = EnvironmentalProcessPdu::new();
159            let any_pdu = pdu.as_any();
160
161            assert!(any_pdu.is::<EnvironmentalProcessPdu>());
162        }
163
164        #[test]
165        fn serialize_then_deserialize() {
166            let mut pdu = EnvironmentalProcessPdu::new();
167            let mut serialize_buf = BytesMut::new();
168            let _ = pdu.serialize(&mut serialize_buf);
169
170            let mut deserialize_buf = serialize_buf.freeze();
171            let new_pdu =
172                EnvironmentalProcessPdu::deserialize(&mut deserialize_buf).unwrap_or_default();
173            assert_eq!(new_pdu.header, pdu.header);
174        }
175
176        #[test]
177        fn check_default_pdu_length() {
178            const DEFAULT_LENGTH: u16 = 256 / BITS_PER_BYTE;
179            let pdu = EnvironmentalProcessPdu::new();
180            assert_eq!(pdu.header().length, DEFAULT_LENGTH);
181        }
182    }
183
184    mod gridded_data_pdu_tests {
185        use super::*;
186
187        #[test]
188        fn cast_to_any() {
189            let pdu = GriddedDataPdu::new();
190            let any_pdu = pdu.as_any();
191
192            assert!(any_pdu.is::<GriddedDataPdu>());
193        }
194
195        #[test]
196        fn serialize_then_deserialize() {
197            let mut pdu = GriddedDataPdu::new();
198            let mut serialize_buf = BytesMut::new();
199            let _ = pdu.serialize(&mut serialize_buf);
200
201            let mut deserialize_buf = serialize_buf.freeze();
202            let new_pdu = GriddedDataPdu::deserialize(&mut deserialize_buf).unwrap_or_default();
203            assert_eq!(new_pdu.header, pdu.header);
204        }
205
206        #[test]
207        fn check_default_pdu_length() {
208            const DEFAULT_LENGTH: u16 = 512 / BITS_PER_BYTE;
209            let pdu = GriddedDataPdu::new();
210            assert_eq!(pdu.header().length, DEFAULT_LENGTH);
211        }
212    }
213
214    mod point_object_state_pdu_tests {
215        use super::*;
216
217        #[test]
218        fn cast_to_any() {
219            let pdu = PointObjectStatePdu::new();
220            let any_pdu = pdu.as_any();
221
222            assert!(any_pdu.is::<PointObjectStatePdu>());
223        }
224
225        #[test]
226        fn serialize_then_deserialize() {
227            let mut pdu = PointObjectStatePdu::new();
228            let mut serialize_buf = BytesMut::new();
229            let _ = pdu.serialize(&mut serialize_buf);
230
231            let mut deserialize_buf = serialize_buf.freeze();
232            let new_pdu =
233                PointObjectStatePdu::deserialize(&mut deserialize_buf).unwrap_or_default();
234            assert_eq!(new_pdu.header, pdu.header);
235        }
236
237        #[test]
238        fn check_default_pdu_length() {
239            const DEFAULT_LENGTH: u16 = 704 / BITS_PER_BYTE;
240            let pdu = PointObjectStatePdu::new();
241            assert_eq!(pdu.header().length, DEFAULT_LENGTH);
242        }
243    }
244
245    mod linear_object_state_pdu_tests {
246        use super::*;
247
248        #[test]
249        fn cast_to_any() {
250            let pdu = LinearObjectStatePdu::new();
251            let any_pdu = pdu.as_any();
252
253            assert!(any_pdu.is::<LinearObjectStatePdu>());
254        }
255        #[test]
256        fn serialize_then_deserialize() {
257            let mut pdu = LinearObjectStatePdu::new();
258            let mut serialize_buf = BytesMut::new();
259            let _ = pdu.serialize(&mut serialize_buf);
260
261            let mut deserialize_buf = serialize_buf.freeze();
262            let new_pdu =
263                LinearObjectStatePdu::deserialize(&mut deserialize_buf).unwrap_or_default();
264            assert_eq!(new_pdu.header, pdu.header);
265        }
266
267        #[test]
268        fn check_default_pdu_length() {
269            const DEFAULT_LENGTH: u16 = 320 / 8;
270            let pdu = LinearObjectStatePdu::new();
271            assert_eq!(pdu.header().length, DEFAULT_LENGTH);
272        }
273    }
274
275    mod areal_object_state_pdu_tests {
276        use super::*;
277
278        #[test]
279        fn cast_to_any() {
280            let pdu = ArealObjectStatePdu::new();
281            let any_pdu = pdu.as_any();
282
283            assert!(any_pdu.is::<ArealObjectStatePdu>());
284        }
285
286        #[test]
287        fn serialize_then_deserialize() {
288            let mut pdu = ArealObjectStatePdu::new();
289            let mut serialize_buf = BytesMut::new();
290            let _ = pdu.serialize(&mut serialize_buf);
291
292            let mut deserialize_buf = serialize_buf.freeze();
293            let new_pdu =
294                ArealObjectStatePdu::deserialize(&mut deserialize_buf).unwrap_or_default();
295            assert_eq!(new_pdu.header, pdu.header);
296        }
297
298        #[test]
299        fn check_default_pdu_length() {
300            const DEFAULT_LENGTH: u16 = 384 / BITS_PER_BYTE;
301            let pdu = ArealObjectStatePdu::new();
302            assert_eq!(pdu.header().length, DEFAULT_LENGTH);
303        }
304    }
305}