dis_rust/simulation_management/
event_report_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};
12
13use crate::common::{pdu_header_record::{PDUHeaderRecord, PDUType, ProtocolFamily}, entity_id_record::EntityIDRecord, pdu::PDU, dis_error::DISError};
14
15#[derive(Copy, Clone, Debug,)]
16/// Event Report PDU as defined in IEEE 1278.1 standard. Used to communicate an important event during the simulation.
17pub struct EventReportPDU {
18    pub pdu_header_record: PDUHeaderRecord,
19    pub originating_entity_id_record: EntityIDRecord,
20    pub receviving_entity_id_record: EntityIDRecord,
21    pub event_type_field: EventType,
22    pub padding: u32,
23    pub number_of_fixed_datum_records_field: u32,
24    pub number_of_variable_datum_records_field: u32,
25    pub fixed_datum_records_field: u64,
26    pub variable_datum_records_field: u64,
27}
28
29impl EventReportPDU {
30    /// Provides a EventReportPDU signalling the creation of a new entity.
31    /// 
32    /// # Examples
33    /// 
34    /// Creating a blank EventReportPDU:
35    /// 
36    /// ```
37    /// let event_report_pdu = EventReportPDU::default();
38    /// ```
39    /// 
40    pub fn default() -> Self {
41        EventReportPDU {
42            pdu_header_record: PDUHeaderRecord::default(PDUType::EventReport, ProtocolFamily::SimulationManagement, 56),
43            originating_entity_id_record: EntityIDRecord::default(1),
44            receviving_entity_id_record: EntityIDRecord::default(2),
45            event_type_field: EventType::EntityInitialization,
46            padding: 0,
47            number_of_fixed_datum_records_field: 0,
48            number_of_variable_datum_records_field: 0,
49            fixed_datum_records_field: 0,
50            variable_datum_records_field: 0,
51        }
52    }
53}
54
55impl PDU for EventReportPDU {
56    /// Fills a BytesMut struct with a EventReportPDU serialised into binary. This buffer is then ready to be sent via
57    /// UDP to the simluation network.
58    fn serialise(&self, buf: &mut BytesMut) {
59        self.pdu_header_record.serialize(buf);
60        self.originating_entity_id_record.serialize(buf);
61        self.receviving_entity_id_record.serialize(buf);
62        buf.put_u32(self.event_type_field as u32);
63        buf.put_u32(self.padding);
64        buf.put_u32(self.number_of_fixed_datum_records_field);
65        buf.put_u32(self.number_of_variable_datum_records_field);
66        buf.put_u64(self.fixed_datum_records_field);
67        buf.put_u64(self.variable_datum_records_field);
68    }
69
70    fn deserialise(mut buffer: BytesMut) -> Result<Self, crate::common::dis_error::DISError> where Self: Sized {
71        let pdu_header = PDUHeaderRecord::decode(&mut buffer);
72        if pdu_header.pdu_type == PDUType::EventReport {
73            let originating_entity_id = EntityIDRecord::decode(&mut buffer);
74            let receviving_entity_id = EntityIDRecord::decode(&mut buffer);
75            let event_type = EventType::from_u32(buffer.get_u32());
76            let padding = buffer.get_u32();
77            let num_of_fixed_records = buffer.get_u32();
78            let num_of_variable_records = buffer.get_u32();
79            let mut fixed_records: u64 = 0;
80            for _record in 0..num_of_fixed_records as usize {
81                fixed_records += buffer.get_u64();
82            }
83            let mut variable_records: u64 = 0;
84            for _record in 0..num_of_variable_records as usize {
85                variable_records += buffer.get_u64();
86            }            
87            
88            return Ok(EventReportPDU {
89                pdu_header_record: pdu_header,
90                originating_entity_id_record: originating_entity_id,
91                receviving_entity_id_record: receviving_entity_id,
92                event_type_field: event_type,
93                padding,
94                number_of_fixed_datum_records_field: num_of_fixed_records,
95                number_of_variable_datum_records_field: num_of_variable_records,
96                fixed_datum_records_field: fixed_records,
97                variable_datum_records_field: variable_records,
98            })
99        } else {
100            Err(DISError::InvalidDISHeader)
101        }
102    }
103
104    fn as_any(&self) -> &dyn Any {
105        self
106      }
107
108    fn deserialise_without_header(mut buffer: BytesMut, pdu_header: PDUHeaderRecord) -> Result<Self, DISError> where Self: Sized {
109        let originating_entity_id = EntityIDRecord::decode(&mut buffer);
110            let receviving_entity_id = EntityIDRecord::decode(&mut buffer);
111            let event_type = EventType::from_u32(buffer.get_u32());
112            let padding = buffer.get_u32();
113            let num_of_fixed_records = buffer.get_u32();
114            let num_of_variable_records = buffer.get_u32();
115            let mut fixed_records: u64 = 0;
116            for _record in 0..num_of_fixed_records as usize {
117                fixed_records += buffer.get_u64();
118            }
119            let mut variable_records: u64 = 0;
120            for _record in 0..num_of_variable_records as usize {
121                variable_records += buffer.get_u64();
122            }            
123            
124            return Ok(EventReportPDU {
125                pdu_header_record: pdu_header,
126                originating_entity_id_record: originating_entity_id,
127                receviving_entity_id_record: receviving_entity_id,
128                event_type_field: event_type,
129                padding,
130                number_of_fixed_datum_records_field: num_of_fixed_records,
131                number_of_variable_datum_records_field: num_of_variable_records,
132                fixed_datum_records_field: fixed_records,
133                variable_datum_records_field: variable_records,
134            })
135    }
136}
137
138#[derive(Debug, Clone, Copy)]
139/// Enum to represent the type of event being reported.
140pub enum EventType {
141    Other = 0,
142    Unused = 1,
143    IndirectOrCASFire = 10,
144    MinefieldEntry = 11,
145    MinefieldDetonantion = 12,
146    VehicleMasterPowerOn = 13,
147    VehicleMasterPowerOff = 14,
148    AggregateStateChangeRequest = 15,
149    RanOutOfAmmunition = 2,
150    KilledInAction = 3,
151    Damage = 4,
152    MobilityDisabled = 5,
153    FireDisabled = 6,
154    RanOutOfFuel = 7,
155    EntityInitialization = 8,
156    RequestForIndirectOrCASFire = 9,
157}
158
159impl EventType {
160    pub fn from_u32(data: u32) -> EventType {
161        match data {
162            0 => EventType::Other,
163            1 => EventType::Unused,
164            10 => EventType::IndirectOrCASFire,
165            11 => EventType::MinefieldEntry,
166            12 => EventType::MinefieldDetonantion,
167            13 => EventType::VehicleMasterPowerOn,
168            14 => EventType::VehicleMasterPowerOff,
169            15 => EventType::AggregateStateChangeRequest,
170            2 => EventType::RanOutOfAmmunition,
171            3 => EventType::KilledInAction,
172            4 => EventType::Damage,
173            5 => EventType::MobilityDisabled,
174            6 => EventType::FireDisabled,
175            7 => EventType::RanOutOfFuel,
176            8 => EventType::EntityInitialization,
177            9  => EventType::RequestForIndirectOrCASFire,
178            _ => EventType::Other
179            
180        }
181    }
182}
183
184#[cfg(test)]
185mod tests {
186    use crate::{common::pdu_header_record::{PDUHeaderRecord, PDUType, ProtocolFamily}, simulation_management::event_report_pdu::EventReportPDU, };
187
188    #[test]
189    fn header_creation() {
190        let event_report_pdu = EventReportPDU::default();
191        let header = PDUHeaderRecord::default(PDUType::EventReport, ProtocolFamily::SimulationManagement, 448/8);
192        assert_eq!(header.protocol_version, event_report_pdu.pdu_header_record.protocol_version);
193        assert_eq!(header.exercise_id, event_report_pdu.pdu_header_record.exercise_id);
194        assert_eq!(header.pdu_type, event_report_pdu.pdu_header_record.pdu_type);
195        assert_eq!(header.protocol_family, event_report_pdu.pdu_header_record.protocol_family);
196        assert_eq!(header.timestamp, event_report_pdu.pdu_header_record.timestamp);
197        assert_eq!(header.length, event_report_pdu.pdu_header_record.length);
198        assert_eq!(header.padding, event_report_pdu .pdu_header_record.padding);
199    }
200}