dis_rust/entity_information/
entity_state_pdu.rs

1//     dis-rust - A rust implementation of the DIS simulation protocol.
2//     Copyright (C) 2022 Thomas Mann
3// 
4//     This software is dual-licensed. It is available under the conditions of
5//     the GNU Affero General Public License (see the LICENSE file included) 
6//     or under a commercial license (email contact@coffeebreakdevs.com for
7//     details).
8
9use std::any::Any;
10
11use bytes::{BytesMut, BufMut, Buf};
12use serde::{Serialize, Deserialize};
13
14use crate::common::{entity_id_record::{EntityIDRecord}, entity_type_record::{Country, EntityTypeRecord, Kind}, euler_angles_record::EulerAnglesRecord, linear_velocity_record::LinearVelocityRecord, pdu::PDU, pdu_header_record::{PDUHeaderRecord, PDUType, ProtocolFamily}, world_coordinate_record::WorldCoordinateRecord, dis_error::DISError};
15
16use super::{entity_appearance_record::EntityAppearanceRecord, dead_reckoning_parameters_record::DeadReckoningParametersRecord, entity_marking_record::EntityMarkingRecord, entity_capabilities_record::{EntityCapabilitiesRecord}};
17
18#[derive(Clone, Debug,)]
19/// Entity State PDU as defined in IEEE 1278.1 standard. Used to communicate the state of an entity during the simulation.
20pub struct EntityStatePDU {
21    pub pdu_header_record: PDUHeaderRecord,
22    pub entity_id_record: EntityIDRecord,
23    pub force_id_field: ForceID,
24    pub number_of_articulation_parameters_field: u8,
25    pub entity_type_record: EntityTypeRecord,
26    pub alternative_entity_type_record: EntityTypeRecord,
27    pub entity_linear_velocity_record: LinearVelocityRecord,
28    pub entity_location_record: WorldCoordinateRecord,
29    pub entity_orientation_record: EulerAnglesRecord,
30    pub entity_appearance_record: EntityAppearanceRecord,
31    pub dead_reckoning_parameters_record: DeadReckoningParametersRecord,
32    pub entity_marking_record: EntityMarkingRecord,
33    pub entity_capabilities_record: EntityCapabilitiesRecord,
34    pub articulation_parameter_record: f32 // TODO: Correct this!
35}
36
37impl EntityStatePDU {
38    /// Provides a function to create a default EntityStatePDU.
39    /// The provided PDU represents a simple munition used for testing. 
40    pub fn default() -> Self {
41        EntityStatePDU {
42            pdu_header_record: PDUHeaderRecord::default(PDUType::EntityState, ProtocolFamily::EntityInformation, 864/8), // length assumes no articulating parameters (TODO: Calculate dynamically!)
43            entity_id_record: EntityIDRecord::default(2),
44            force_id_field: ForceID::Other,
45            number_of_articulation_parameters_field: 0,
46            entity_type_record: EntityTypeRecord{
47                kind_field: Kind::Munition,
48                domain_field: 1,
49                country_field: Country::Other,
50                category_field: 3,
51                subcategory_field: 0,
52                specific_field: 0,
53                extra_field: 0},
54            alternative_entity_type_record: EntityTypeRecord{
55                kind_field: Kind::Munition,
56                domain_field: 1,
57                country_field: Country::Other,
58                category_field: 0,
59                subcategory_field: 0,
60                specific_field: 0,
61                extra_field: 0},
62            entity_linear_velocity_record: LinearVelocityRecord::new(0.0, 0.0, 0.0),
63            entity_location_record: WorldCoordinateRecord::new(0.0, 0.0, 0.0),
64            entity_orientation_record: EulerAnglesRecord::new(0.0, 0.0, 0.0),
65            entity_appearance_record: EntityAppearanceRecord::default(),
66            dead_reckoning_parameters_record: DeadReckoningParametersRecord::default(),
67            entity_marking_record: EntityMarkingRecord::default("".to_string()),
68            entity_capabilities_record: EntityCapabilitiesRecord::default(),
69            articulation_parameter_record: 0.0 // TODO: Needs correcting to proper value!
70        }
71    }  
72}
73
74impl PDU for EntityStatePDU {
75    /// Creates an EntityStatePDU from a BytesMut struct.
76    fn deserialise(mut buffer: BytesMut) -> Result<EntityStatePDU, DISError> {
77        let pdu_header = PDUHeaderRecord::decode(&mut buffer);
78        if pdu_header.pdu_type == PDUType::EntityState {
79            let entity_id = EntityIDRecord::decode(&mut buffer);
80            let force_id = ForceID::decode(&mut buffer);
81            let articulation_params = &buffer.get_u8();
82            let entity_type = EntityTypeRecord::decode(&mut buffer);
83            let alt_entity_type = EntityTypeRecord::decode(&mut buffer);
84            let linear_velocity = LinearVelocityRecord::decode(&mut buffer);
85            let world_coordinate = WorldCoordinateRecord::decode(&mut buffer);
86            let orientation = EulerAnglesRecord::decode(&mut buffer);
87            let appearance = EntityAppearanceRecord::decode(&mut buffer);
88            let dead_reckoning = DeadReckoningParametersRecord::decode(&mut buffer);
89            let entity_marking = EntityMarkingRecord::decode(&mut buffer);
90            let entity_capabilities = EntityCapabilitiesRecord::decode(&mut buffer);
91            
92            return Ok(EntityStatePDU {
93                pdu_header_record: pdu_header,
94                entity_id_record: entity_id,
95                force_id_field: force_id,
96                number_of_articulation_parameters_field: *articulation_params,
97                entity_type_record: entity_type,
98                alternative_entity_type_record: alt_entity_type,
99                entity_linear_velocity_record: linear_velocity,
100                entity_location_record: world_coordinate,
101                entity_orientation_record: orientation,
102                entity_appearance_record: appearance,
103                dead_reckoning_parameters_record: dead_reckoning,
104                entity_marking_record: entity_marking,
105                entity_capabilities_record: entity_capabilities,
106                articulation_parameter_record: 0.0,
107            })
108        } else {
109            Err(DISError::InvalidDISHeader)
110        }
111    }
112
113    /// Fills a BytesMut struct with a EntityStatePDU serialised into binary. This buffer is then ready to be sent via
114    /// UDP to the simluation network.
115    fn serialise(&self, buf: &mut BytesMut) {
116        self.pdu_header_record.serialize(buf);
117        self.entity_id_record.serialize(buf);
118        buf.put_u8(self.force_id_field as u8);
119        buf.put_u8(self.number_of_articulation_parameters_field as u8);
120        self.entity_type_record.serialize(buf);
121        self.alternative_entity_type_record.serialize(buf);
122        self.entity_linear_velocity_record.serialize(buf);
123        self.entity_location_record.serialize(buf);
124        self.entity_orientation_record.serialize(buf);
125        self.entity_appearance_record.serialize(buf);
126        self.dead_reckoning_parameters_record.serialize(buf);
127        self.entity_marking_record.serialize(buf);
128        self.entity_capabilities_record.serialize(buf);
129    }
130
131    fn as_any(&self) -> &dyn Any {
132        self
133      }
134
135    fn deserialise_without_header(mut buffer: BytesMut, pdu_header: PDUHeaderRecord) -> Result<Self, DISError> where Self: Sized {
136        let entity_id = EntityIDRecord::decode(&mut buffer);
137            let force_id = ForceID::decode(&mut buffer);
138            let articulation_params = &buffer.get_u8();
139            let entity_type = EntityTypeRecord::decode(&mut buffer);
140            let alt_entity_type = EntityTypeRecord::decode(&mut buffer);
141            let linear_velocity = LinearVelocityRecord::decode(&mut buffer);
142            let world_coordinate = WorldCoordinateRecord::decode(&mut buffer);
143            let orientation = EulerAnglesRecord::decode(&mut buffer);
144            let appearance = EntityAppearanceRecord::decode(&mut buffer);
145            let dead_reckoning = DeadReckoningParametersRecord::decode(&mut buffer);
146            let entity_marking = EntityMarkingRecord::decode(&mut buffer);
147            let entity_capabilities = EntityCapabilitiesRecord::decode(&mut buffer);
148            
149            return Ok(EntityStatePDU {
150                pdu_header_record: pdu_header,
151                entity_id_record: entity_id,
152                force_id_field: force_id,
153                number_of_articulation_parameters_field: *articulation_params,
154                entity_type_record: entity_type,
155                alternative_entity_type_record: alt_entity_type,
156                entity_linear_velocity_record: linear_velocity,
157                entity_location_record: world_coordinate,
158                entity_orientation_record: orientation,
159                entity_appearance_record: appearance,
160                dead_reckoning_parameters_record: dead_reckoning,
161                entity_marking_record: entity_marking,
162                entity_capabilities_record: entity_capabilities,
163                articulation_parameter_record: 0.0,
164            })
165    }
166}
167
168#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
169/// Enum to represent the Force the entity is part of during the simulation.
170pub enum ForceID {
171    Other = 0,
172    Friendly = 1,
173    Opposing = 2,
174    Neutral = 3
175}
176
177impl ForceID {
178    pub fn decode(buf: &mut BytesMut) -> ForceID {
179        match buf.get_u8() {
180            1 => ForceID::Friendly,
181            2 => ForceID::Opposing,
182            3 => ForceID::Neutral,
183            _ => ForceID::Other,
184        }
185    }
186}
187
188#[cfg(test)]
189mod tests {
190    use bytes::BytesMut;
191
192    use crate::{common::{pdu_header_record::{PDUHeaderRecord, PDUType, ProtocolFamily}, pdu::PDU}, entity_information::entity_state_pdu::EntityStatePDU};
193
194    #[test]
195    fn header_creation() {
196        let entity_state_pdu = EntityStatePDU::default();
197        let header = PDUHeaderRecord::default(PDUType::EntityState, ProtocolFamily::EntityInformation, 864/8);
198        assert_eq!(header.protocol_version, entity_state_pdu.pdu_header_record.protocol_version);
199        assert_eq!(header.exercise_id, entity_state_pdu.pdu_header_record.exercise_id);
200        assert_eq!(header.pdu_type, entity_state_pdu.pdu_header_record.pdu_type);
201        assert_eq!(header.protocol_family, entity_state_pdu.pdu_header_record.protocol_family);
202        assert_eq!(header.timestamp, entity_state_pdu.pdu_header_record.timestamp);
203        assert_eq!(header.length, entity_state_pdu.pdu_header_record.length);
204        assert_eq!(header.padding, entity_state_pdu .pdu_header_record.padding);
205    }
206
207    #[test]
208    fn header_deserialise() {
209        let entity_state_pdu = EntityStatePDU::default();
210        let mut buffer = BytesMut::new();
211        entity_state_pdu.serialise(&mut buffer);
212
213        let new_entity_state_pdu = EntityStatePDU::deserialise(buffer).unwrap();
214        assert_eq!(new_entity_state_pdu.pdu_header_record, entity_state_pdu.pdu_header_record);
215    }
216}