open_dis_rust/entity_information/
entity_state_pdu.rs

1//     open-dis-rust - Rust implementation of the IEEE-1278.1 Distributed Interactive Simulation
2//                     (DIS) application protocol v6 and v7
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::{Country, EntityCapabilities, EntityKind, ForceId},
15    euler_angles::EulerAngles,
16    linear_velocity::LinearVelocity,
17    pdu::Pdu,
18    pdu_header::{PduHeader, PduType, ProtocolFamily},
19    world_coordinate::WorldCoordinate,
20};
21
22use super::data_types::{
23    dead_reckoning_parameters::DeadReckoningParameters, entity_marking::EntityMarking,
24};
25
26#[derive(Clone, Debug)]
27/// Implemented according to IEEE 1278.1-2012 ยง7.2.2
28pub struct EntityStatePdu {
29    pub pdu_header: PduHeader,
30    pub entity_id: EntityId,
31    pub force_id: ForceId,
32    pub number_of_articulation_parameters: u8,
33    pub entity_type: EntityType,
34    pub alternative_entity_type: EntityType,
35    pub entity_linear_velocity: LinearVelocity,
36    pub entity_location: WorldCoordinate,
37    pub entity_orientation: EulerAngles,
38    pub entity_appearance: u32,
39    pub dead_reckoning_parameters: DeadReckoningParameters,
40    pub entity_marking: EntityMarking,
41    pub entity_capabilities: EntityCapabilities,
42    pub articulation_parameter: f32,
43}
44
45impl Default for EntityStatePdu {
46    fn default() -> Self {
47        EntityStatePdu {
48            pdu_header: PduHeader::default(
49                PduType::EntityState,
50                ProtocolFamily::EntityInformation,
51                864 / 8,
52            ),
53            entity_id: EntityId::default(2),
54            force_id: ForceId::default(),
55            number_of_articulation_parameters: 0,
56            entity_type: EntityType {
57                kind: EntityKind::default(),
58                domain: 1,
59                country: Country::default(),
60                category: 3,
61                subcategory: 0,
62                specific: 0,
63                extra: 0,
64            },
65            alternative_entity_type: EntityType {
66                kind: EntityKind::default(),
67                domain: 1,
68                country: Country::default(),
69                category: 0,
70                subcategory: 0,
71                specific: 0,
72                extra: 0,
73            },
74            entity_linear_velocity: LinearVelocity::new(0.0, 0.0, 0.0),
75            entity_location: WorldCoordinate::new(0.0, 0.0, 0.0),
76            entity_orientation: EulerAngles::new(0.0, 0.0, 0.0),
77            entity_appearance: 0,
78            dead_reckoning_parameters: DeadReckoningParameters::default(),
79            entity_marking: EntityMarking::default(String::new()),
80            entity_capabilities: EntityCapabilities::default(),
81            articulation_parameter: 0.0,
82        }
83    }
84}
85
86impl Pdu for EntityStatePdu {
87    fn serialize(&mut self, buf: &mut BytesMut) {
88        self.pdu_header.length = u16::try_from(std::mem::size_of_val(self))
89            .expect("The length of the PDU should fit in a u16.");
90        self.pdu_header.serialize(buf);
91        self.entity_id.serialize(buf);
92        buf.put_u8(self.force_id as u8);
93        buf.put_u8(self.number_of_articulation_parameters);
94        self.entity_type.serialize(buf);
95        self.alternative_entity_type.serialize(buf);
96        self.entity_linear_velocity.serialize(buf);
97        self.entity_location.serialize(buf);
98        self.entity_orientation.serialize(buf);
99        buf.put_u32(self.entity_appearance);
100        self.dead_reckoning_parameters.serialize(buf);
101        self.entity_marking.serialize(buf);
102        buf.put_u8(self.entity_capabilities as u8);
103    }
104
105    fn deserialize(mut buffer: BytesMut) -> Result<EntityStatePdu, DISError> {
106        let pdu_header = PduHeader::deserialize(&mut buffer);
107        if pdu_header.pdu_type == PduType::EntityState {
108            let entity_id = EntityId::deserialize(&mut buffer);
109            let force_id = ForceId::deserialize(&mut buffer);
110            let articulation_params = &buffer.get_u8();
111            let entity_type = EntityType::deserialize(&mut buffer);
112            let alt_entity_type = EntityType::deserialize(&mut buffer);
113            let linear_velocity = LinearVelocity::deserialize(&mut buffer);
114            let world_coordinate = WorldCoordinate::deserialize(&mut buffer);
115            let orientation = EulerAngles::deserialize(&mut buffer);
116            let appearance = buffer.get_u32();
117            let dead_reckoning = DeadReckoningParameters::deserialize(&mut buffer);
118            let entity_marking = EntityMarking::deserialize(&mut buffer);
119            let entity_capabilities = EntityCapabilities::deserialize(&mut buffer);
120
121            Ok(EntityStatePdu {
122                pdu_header,
123                entity_id,
124                force_id,
125                number_of_articulation_parameters: *articulation_params,
126                entity_type,
127                alternative_entity_type: alt_entity_type,
128                entity_linear_velocity: linear_velocity,
129                entity_location: world_coordinate,
130                entity_orientation: orientation,
131                entity_appearance: appearance,
132                dead_reckoning_parameters: dead_reckoning,
133                entity_marking,
134                entity_capabilities,
135                articulation_parameter: 0.0,
136            })
137        } else {
138            Err(DISError::invalid_header(
139                format!(
140                    "Expected PDU type EntityState, got {:?}",
141                    pdu_header.pdu_type
142                ),
143                None,
144            ))
145        }
146    }
147
148    fn as_any(&self) -> &dyn Any {
149        self
150    }
151
152    fn deserialize_without_header(
153        mut buffer: BytesMut,
154        pdu_header: PduHeader,
155    ) -> Result<Self, DISError>
156    where
157        Self: Sized,
158    {
159        let entity_id = EntityId::deserialize(&mut buffer);
160        let force_id = ForceId::deserialize(&mut buffer);
161        let articulation_params = &buffer.get_u8();
162        let entity_type = EntityType::deserialize(&mut buffer);
163        let alt_entity_type = EntityType::deserialize(&mut buffer);
164        let linear_velocity = LinearVelocity::deserialize(&mut buffer);
165        let world_coordinate = WorldCoordinate::deserialize(&mut buffer);
166        let orientation = EulerAngles::deserialize(&mut buffer);
167        let appearance = buffer.get_u32();
168        let dead_reckoning_parameters = DeadReckoningParameters::deserialize(&mut buffer);
169        let entity_marking = EntityMarking::deserialize(&mut buffer);
170        let entity_capabilities = EntityCapabilities::deserialize(&mut buffer);
171
172        Ok(EntityStatePdu {
173            pdu_header,
174            entity_id,
175            force_id,
176            number_of_articulation_parameters: *articulation_params,
177            entity_type,
178            alternative_entity_type: alt_entity_type,
179            entity_linear_velocity: linear_velocity,
180            entity_location: world_coordinate,
181            entity_orientation: orientation,
182            entity_appearance: appearance,
183            dead_reckoning_parameters,
184            entity_marking,
185            entity_capabilities,
186            articulation_parameter: 0.0,
187        })
188    }
189}
190
191#[cfg(test)]
192mod tests {
193    use super::EntityStatePdu;
194    use crate::common::{
195        pdu::Pdu,
196        pdu_header::{PduHeader, PduType, ProtocolFamily},
197    };
198    use bytes::BytesMut;
199
200    #[test]
201    fn create_header() {
202        let entity_state_pdu = EntityStatePdu::default();
203        let header = PduHeader::default(
204            PduType::EntityState,
205            ProtocolFamily::EntityInformation,
206            864 / 8,
207        );
208        assert_eq!(
209            header.protocol_version,
210            entity_state_pdu.pdu_header.protocol_version
211        );
212        assert_eq!(header.exercise_id, entity_state_pdu.pdu_header.exercise_id);
213        assert_eq!(header.pdu_type, entity_state_pdu.pdu_header.pdu_type);
214        assert_eq!(
215            header.protocol_family,
216            entity_state_pdu.pdu_header.protocol_family
217        );
218        assert_eq!(header.length, entity_state_pdu.pdu_header.length);
219        assert_eq!(
220            header.status_record,
221            entity_state_pdu.pdu_header.status_record
222        );
223    }
224
225    #[test]
226    fn deserialize_header() {
227        let mut entity_state_pdu = EntityStatePdu::default();
228        let mut buffer = BytesMut::new();
229        entity_state_pdu.serialize(&mut buffer);
230
231        let new_entity_state_pdu = EntityStatePdu::deserialize(buffer).unwrap();
232        assert_eq!(new_entity_state_pdu.pdu_header, entity_state_pdu.pdu_header);
233    }
234}