dis_rust/common/
pdu_header_record.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::u8;
10
11use bytes::{BytesMut, BufMut, Buf};
12use chrono::{Utc, Timelike};
13use num_derive::FromPrimitive;    
14
15#[derive(Copy, Clone, Debug, PartialEq)]
16/// PDU Header Record as defined in IEEE 1278.1 standard. Used to communicate PDU information during the simulation.
17pub struct PDUHeaderRecord {
18    pub protocol_version: ProtocolVersion,
19    pub exercise_id: u8,
20    pub pdu_type: PDUType,
21    pub protocol_family: ProtocolFamily,
22    pub timestamp: u32,
23    pub length: u16,
24    pub padding: u16
25}
26
27impl PDUHeaderRecord {
28    /// Provides a function to create a new PDUHeaderRecord. 
29    /// Timestamps are automatically generated using the current system time.
30    pub fn new(pdu_type: PDUType, protocol_family: ProtocolFamily, exercise_id: u8, length: u16,) -> Self {
31        PDUHeaderRecord {
32            protocol_version: ProtocolVersion::DIS_PDUv2_Fourth_Draft_Revised,
33            exercise_id,
34            pdu_type,
35            protocol_family,
36            timestamp: PDUHeaderRecord::calculate_dis_timestamp() as u32,
37            length: length as u16,
38            padding: 0 as u16
39        }
40    }
41
42    /// Provides a function to create a default PDUHeaderRecord. The header uses exercise ID 1.
43    /// Timestamps are automatically generated using the current system time.
44    pub fn default(pdu_type: PDUType, protocol_family: ProtocolFamily, length: u16,) -> Self {
45        PDUHeaderRecord {
46            protocol_version: ProtocolVersion::DIS_PDUv2_Fourth_Draft_Revised,
47            exercise_id: 1,
48            pdu_type,
49            protocol_family,
50            timestamp: PDUHeaderRecord::calculate_dis_timestamp() as u32,
51            length: length as u16,
52            padding: 0 as u16
53        }
54    }
55
56    /// Calculates the timestamp in DIS time units (1.68 micro-seconds) within a micro-second
57    pub fn calculate_dis_timestamp() -> u32 {
58        let current_minute = ((Utc::now().minute() * 60) * 1e6 as u32) as u64 ;
59        let current_second = (Utc::now().second() * 1e6 as u32) as u64;
60        let current_nanos = (Utc::now().nanosecond() / 1000) as u64;
61        let dis_units = (current_second + current_minute + current_nanos) as f32 / 1.68;
62        dis_units as u32
63    }
64
65    /// Fills a BytesMut struct with a PDUHeaderRecord serialised into binary. This buffer is then ready to be sent via
66    /// UDP to the simluation network.
67    pub fn serialize(&self, buf: &mut BytesMut) {
68        buf.put_u8(self.protocol_version as u8);
69        buf.put_u8(self.exercise_id as u8);
70        buf.put_u8(self.pdu_type as u8);
71        buf.put_u8(self.protocol_family as u8);
72        buf.put_u32(self.timestamp as u32);
73        buf.put_u16(self.length as u16);
74        buf.put_u16(self.padding as u16);
75    }
76
77    fn decode_protocol_version(data: u8) -> ProtocolVersion {
78        match data {
79            1 => ProtocolVersion::DIS_PDUv1,
80            2 => ProtocolVersion::IEEE1278,
81            3 => ProtocolVersion::DIS_PDUv2_Third_Draft,
82            4 => ProtocolVersion::DIS_PDUv2_Fourth_Draft_Revised,
83            5 => ProtocolVersion::IEEE1278_1,
84            _ => ProtocolVersion::Other
85        }
86    }
87
88    pub fn decode(buf: &mut BytesMut) -> PDUHeaderRecord {
89        PDUHeaderRecord { 
90            protocol_version: PDUHeaderRecord::decode_protocol_version(buf.get_u8()), 
91            exercise_id: buf.get_u8(), 
92            pdu_type: PDUHeaderRecord::decode_pdu_type(buf.get_u8()), 
93            protocol_family: PDUHeaderRecord::decode_protocol_family(buf.get_u8()), 
94            timestamp: buf.get_u32(), 
95            length: buf.get_u16(), 
96            padding: buf.get_u16()
97        }
98    }
99
100    fn decode_pdu_type(data: u8) -> PDUType {
101        match data {
102            1 => PDUType::EntityState,
103            2 => PDUType::Fire,
104            3 => PDUType::Detonation,
105            4 => PDUType::Collision,
106            5 => PDUType::ServiceRequest,
107            6 => PDUType::ResupplyOffer,
108            7 => PDUType::ResupplyReceived,
109            8 => PDUType::ResupplyCancel,
110            9 => PDUType::RepairComplete,
111            10 => PDUType::RepairRepsonse,
112            11 => PDUType::CreateEntity,
113            12 => PDUType::RemoveEntity,
114            13 => PDUType::StartResume,
115            14 => PDUType::StopFreeze,
116            15 => PDUType::Acknowledge,
117            16 => PDUType::ActionRequest,
118            17 => PDUType::ActionReponse,
119            18 => PDUType::DataQuery,
120            19 => PDUType::SetData,
121            20 => PDUType::Data,
122            21 => PDUType::EventReport,
123            22 => PDUType::Comment,
124            23 => PDUType::ElectromagneticEmission,
125            24 => PDUType::Designator,
126            25 => PDUType::Transmitter,
127            26 => PDUType::Signal,
128            27 => PDUType::Recevier,
129            // ...
130            _ => PDUType::Other
131        }
132    }
133
134    fn decode_protocol_family(data: u8) -> ProtocolFamily {
135        match data {
136            1 => ProtocolFamily::EntityInformation,
137            2 => ProtocolFamily::Warfare,
138            3 => ProtocolFamily::Logistics,
139            4 => ProtocolFamily::RadioCommunications,
140            5 => ProtocolFamily::SimulationManagement,
141            6 => ProtocolFamily::DistributedEmissionRegeneration,
142            _ => ProtocolFamily::Other
143        }
144    }
145    
146}
147
148
149#[derive(Copy, Clone, Debug, FromPrimitive, PartialEq)]
150/// Enum to represent the Protocol Family the PDU header is recording.
151pub enum ProtocolFamily {
152    Other = 0,
153    EntityInformation = 1,
154    Warfare = 2,
155    Logistics = 3,
156    RadioCommunications = 4,
157    SimulationManagement = 5,
158    DistributedEmissionRegeneration = 6
159}
160
161#[derive(Copy, Clone, Debug, FromPrimitive, PartialEq)]
162#[allow(non_camel_case_types)]
163/// Enum to represent the Protocol Version the PDU header is recording.
164pub enum ProtocolVersion {
165    Other = 0,
166    DIS_PDUv1 = 1,
167    IEEE1278 = 2,
168    DIS_PDUv2_Third_Draft = 3,
169    DIS_PDUv2_Fourth_Draft_Revised = 4,
170    IEEE1278_1 = 5
171}
172
173#[derive(Copy, Clone, Debug, FromPrimitive, PartialEq)]
174/// Enum to represent the PDU Type the PDU header is recording.
175pub enum PDUType {
176    Other = 0,
177    EntityState = 1,
178    Fire = 2,
179    Detonation = 3,
180    Collision = 4,
181    ServiceRequest = 5,
182    ResupplyOffer = 6,
183    ResupplyReceived = 7,
184    ResupplyCancel = 8,
185    RepairComplete = 9,
186    RepairRepsonse = 10,
187    CreateEntity = 11,
188    RemoveEntity = 12,
189    StartResume = 13,
190    StopFreeze = 14,
191    Acknowledge = 15,
192    ActionRequest = 16,
193    ActionReponse = 17,
194    DataQuery = 18,
195    SetData = 19,
196    Data = 20,
197    EventReport = 21,
198    Comment = 22,
199    ElectromagneticEmission = 23,
200    Designator = 24,
201    Transmitter = 25,
202    Signal = 26,
203    Recevier = 27,
204    // ..
205}