open_dis_rust/synthetic_environment/
gridded_data_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    entity_type::EntityType,
14    enums::{GriddedDataConstantGrid, GriddedDataCoordinateSystem},
15    euler_angles::EulerAngles,
16    pdu::Pdu,
17    pdu_header::{PduHeader, PduType, ProtocolFamily},
18};
19
20use super::data_types::{
21    grid_axis_descriptor::GridAxisDescriptor, grid_data_record::GridDataRecord,
22};
23
24#[derive(Clone, Debug)]
25/// Implemented according to IEEE 1278.1-2012 ยง7.10.3
26pub struct GriddedDataPdu {
27    pub pdu_header: PduHeader,
28    pub environmental_simulation_id: EntityId,
29    pub field_number: u16,
30    pub pdu_number: u16,
31    pub pdu_total: u16,
32    pub coordinate_system: GriddedDataCoordinateSystem,
33    pub number_of_grid_axes: u8,
34    pub constant_grid: GriddedDataConstantGrid,
35    pub environment_type: EntityType,
36    pub orientation: EulerAngles,
37    pub sample_time: u64,
38    pub total_values: u32,
39    pub vector_dimension: u8,
40    pub padding1: u8,
41    pub padding2: u16,
42    pub grid_axis_descriptors: Vec<GridAxisDescriptor>,
43    pub grid_data_list: Vec<GridDataRecord>,
44}
45
46impl Default for GriddedDataPdu {
47    /// Creates a default Gridded Data PDU with arbitrary environmental process ID
48    ///
49    /// # Examples
50    ///
51    /// Initializing a Gridded Data PDU:
52    /// ```
53    /// use open_dis_rust::synthetic_environment::gridded_data_pdu::GriddedDataPdu;
54    /// let gridded_data_pdu = GriddedDataPdu::default();
55    /// ```
56    ///
57    fn default() -> Self {
58        GriddedDataPdu {
59            pdu_header: PduHeader::default(
60                PduType::GriddedData,
61                ProtocolFamily::SyntheticEnvironment,
62                112,
63            ),
64            environmental_simulation_id: EntityId::default(0),
65            field_number: 0,
66            pdu_number: 0,
67            pdu_total: 0,
68            coordinate_system: GriddedDataCoordinateSystem::default(),
69            number_of_grid_axes: 0,
70            constant_grid: GriddedDataConstantGrid::default(),
71            environment_type: EntityType::default(),
72            orientation: EulerAngles::default(),
73            sample_time: 0,
74            total_values: 0,
75            vector_dimension: 0,
76            padding1: 0,
77            padding2: 0,
78            grid_axis_descriptors: vec![],
79            grid_data_list: vec![],
80        }
81    }
82}
83
84impl Pdu for GriddedDataPdu {
85    fn serialize(&mut self, buf: &mut BytesMut) {
86        self.pdu_header.length = u16::try_from(std::mem::size_of_val(self))
87            .expect("The length of the PDU should fit in a u16.");
88        self.pdu_header.serialize(buf);
89        self.environmental_simulation_id.serialize(buf);
90        buf.put_u16(self.field_number);
91        buf.put_u16(self.pdu_number);
92        buf.put_u16(self.pdu_total);
93        buf.put_u16(self.coordinate_system as u16);
94        buf.put_u8(self.number_of_grid_axes);
95        buf.put_u8(self.constant_grid as u8);
96        self.environment_type.serialize(buf);
97        self.orientation.serialize(buf);
98        buf.put_u64(self.sample_time);
99        buf.put_u32(self.total_values);
100        buf.put_u8(self.vector_dimension);
101        buf.put_u8(self.padding1);
102        buf.put_u16(self.padding2);
103        for i in 0..self.grid_axis_descriptors.len() {
104            self.grid_axis_descriptors[i].serialize(buf);
105        }
106        for i in 0..self.grid_data_list.len() {
107            self.grid_data_list[i].serialize(buf);
108        }
109    }
110
111    fn deserialize(mut buffer: BytesMut) -> Result<Self, DISError>
112    where
113        Self: Sized,
114    {
115        let pdu_header = PduHeader::deserialize(&mut buffer);
116        if pdu_header.pdu_type == PduType::GriddedData {
117            let environmental_simulation_id = EntityId::deserialize(&mut buffer);
118            let field_number = buffer.get_u16();
119            let pdu_number = buffer.get_u16();
120            let pdu_total = buffer.get_u16();
121            let coordinate_system = GriddedDataCoordinateSystem::deserialize(&mut buffer);
122            let number_of_grid_axes = buffer.get_u8();
123            let constant_grid = GriddedDataConstantGrid::deserialize(&mut buffer);
124            let environment_type = EntityType::deserialize(&mut buffer);
125            let orientation = EulerAngles::deserialize(&mut buffer);
126            let sample_time = buffer.get_u64();
127            let total_values = buffer.get_u32();
128            let vector_dimension = buffer.get_u8();
129            let padding1 = buffer.get_u8();
130            let padding2 = buffer.get_u16();
131            let mut grid_axis_descriptors: Vec<GridAxisDescriptor> = vec![];
132            for _ in 0..number_of_grid_axes {
133                grid_axis_descriptors.push(GridAxisDescriptor::deserialize(&mut buffer));
134            }
135            let mut grid_data_list: Vec<GridDataRecord> = vec![];
136            while buffer.has_remaining() {
137                grid_data_list.push(GridDataRecord::deserialize(&mut buffer));
138            }
139
140            Ok(GriddedDataPdu {
141                pdu_header,
142                environmental_simulation_id,
143                field_number,
144                pdu_number,
145                pdu_total,
146                coordinate_system,
147                number_of_grid_axes,
148                constant_grid,
149                environment_type,
150                orientation,
151                sample_time,
152                total_values,
153                vector_dimension,
154                padding1,
155                padding2,
156                grid_axis_descriptors,
157                grid_data_list,
158            })
159        } else {
160            Err(DISError::invalid_header(
161                format!(
162                    "Expected PDU type GriddedData, got {:?}",
163                    pdu_header.pdu_type
164                ),
165                None,
166            ))
167        }
168    }
169
170    fn as_any(&self) -> &dyn Any {
171        self
172    }
173
174    fn deserialize_without_header(
175        mut buffer: BytesMut,
176        pdu_header: PduHeader,
177    ) -> Result<Self, DISError>
178    where
179        Self: Sized,
180    {
181        let environmental_simulation_id = EntityId::deserialize(&mut buffer);
182        let field_number = buffer.get_u16();
183        let pdu_number = buffer.get_u16();
184        let pdu_total = buffer.get_u16();
185        let coordinate_system = GriddedDataCoordinateSystem::deserialize(&mut buffer);
186        let number_of_grid_axes = buffer.get_u8();
187        let constant_grid = GriddedDataConstantGrid::deserialize(&mut buffer);
188        let environment_type = EntityType::deserialize(&mut buffer);
189        let orientation = EulerAngles::deserialize(&mut buffer);
190        let sample_time = buffer.get_u64();
191        let total_values = buffer.get_u32();
192        let vector_dimension = buffer.get_u8();
193        let padding1 = buffer.get_u8();
194        let padding2 = buffer.get_u16();
195        let mut grid_axis_descriptors: Vec<GridAxisDescriptor> = vec![];
196        for _ in 0..number_of_grid_axes {
197            grid_axis_descriptors.push(GridAxisDescriptor::deserialize(&mut buffer));
198        }
199        let mut grid_data_list: Vec<GridDataRecord> = vec![];
200        while buffer.has_remaining() {
201            grid_data_list.push(GridDataRecord::deserialize(&mut buffer));
202        }
203        Ok(GriddedDataPdu {
204            pdu_header,
205            environmental_simulation_id,
206            field_number,
207            pdu_number,
208            pdu_total,
209            coordinate_system,
210            number_of_grid_axes,
211            constant_grid,
212            environment_type,
213            orientation,
214            sample_time,
215            total_values,
216            vector_dimension,
217            padding1,
218            padding2,
219            grid_axis_descriptors,
220            grid_data_list,
221        })
222    }
223}
224
225#[cfg(test)]
226mod tests {
227    use super::GriddedDataPdu;
228    use crate::common::{
229        pdu::Pdu,
230        pdu_header::{PduHeader, PduType, ProtocolFamily},
231    };
232    use bytes::BytesMut;
233
234    #[test]
235    fn create_header() {
236        let gridded_data_pdu = GriddedDataPdu::default();
237        let pdu_header = PduHeader::default(
238            PduType::GriddedData,
239            ProtocolFamily::SyntheticEnvironment,
240            112,
241        );
242
243        assert_eq!(
244            pdu_header.protocol_version,
245            gridded_data_pdu.pdu_header.protocol_version
246        );
247        assert_eq!(
248            pdu_header.exercise_id,
249            gridded_data_pdu.pdu_header.exercise_id
250        );
251        assert_eq!(pdu_header.pdu_type, gridded_data_pdu.pdu_header.pdu_type);
252        assert_eq!(
253            pdu_header.protocol_family,
254            gridded_data_pdu.pdu_header.protocol_family
255        );
256        assert_eq!(pdu_header.length, gridded_data_pdu.pdu_header.length);
257        assert_eq!(
258            pdu_header.status_record,
259            gridded_data_pdu.pdu_header.status_record
260        );
261    }
262
263    #[test]
264    fn deserialize_header() {
265        let mut gridded_data_pdu = GriddedDataPdu::default();
266        let mut buffer = BytesMut::new();
267        gridded_data_pdu.serialize(&mut buffer);
268
269        let new_gridded_data_pdu = GriddedDataPdu::deserialize(buffer).unwrap();
270        assert_eq!(new_gridded_data_pdu.pdu_header, gridded_data_pdu.pdu_header);
271    }
272
273    #[test]
274    fn check_pdu_size() {
275        let gridded_data_pdu = GriddedDataPdu::default();
276
277        assert_eq!(
278            gridded_data_pdu.pdu_header.length,
279            gridded_data_pdu.pdu_header.length
280        );
281    }
282}