open_dis_rust/common/
pdu_header.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 chrono::{Timelike, Utc};
9use num_derive::FromPrimitive;
10
11#[derive(Copy, Clone, Debug, Default, PartialEq)]
12pub struct PduHeader {
13    /// The version of the protocol
14    pub protocol_version: ProtocolVersion,
15    /// Exercise ID
16    pub exercise_id: u8,
17    /// Type of PDU, unique for each PDU class
18    pub pdu_type: PduType,
19    /// Value that refers to the protocol family
20    pub protocol_family: ProtocolFamily,
21    /// Timestamp value
22    pub timestamp: u32,
23    /// Length, in bytes, of the PDU
24    pub length: u16,
25    /// Zero-filled array of padding
26    pub padding: u16,
27}
28
29impl PduHeader {
30    #[must_use]
31    pub fn new(
32        pdu_type: PduType,
33        protocol_family: ProtocolFamily,
34        exercise_id: u8,
35        length: u16,
36    ) -> Self {
37        PduHeader {
38            protocol_version: ProtocolVersion::IEEE1278_1_2012,
39            exercise_id,
40            pdu_type,
41            protocol_family,
42            timestamp: PduHeader::calculate_dis_timestamp(),
43            length,
44            padding: 0_u16,
45        }
46    }
47
48    #[must_use]
49    pub fn default(pdu_type: PduType, protocol_family: ProtocolFamily, length: u16) -> Self {
50        PduHeader {
51            protocol_version: ProtocolVersion::IEEE1278_1_2012,
52            exercise_id: 1,
53            pdu_type,
54            protocol_family,
55            timestamp: PduHeader::calculate_dis_timestamp(),
56            length,
57            padding: 0_u16,
58        }
59    }
60
61    /// Gets the current time in terms of IEEE-1278.1 DIS time units
62    #[must_use]
63    #[allow(
64        clippy::cast_precision_loss,
65        clippy::cast_possible_truncation,
66        clippy::cast_sign_loss
67    )]
68    pub fn calculate_dis_timestamp() -> u32 {
69        let minute_curr = u64::from((Utc::now().minute() * 60) * 1_000_000);
70        let second_curr = u64::from(Utc::now().second() * 1_000_000);
71        let nanosecond_curr = u64::from(Utc::now().nanosecond() / 1000);
72        let dis_time = (second_curr + minute_curr + nanosecond_curr) as f32 / 1.68;
73        dis_time as u32
74    }
75
76    pub fn serialize(&self, buf: &mut BytesMut) {
77        buf.put_u8(self.protocol_version as u8);
78        buf.put_u8(self.exercise_id);
79        buf.put_u8(self.pdu_type as u8);
80        buf.put_u8(self.protocol_family as u8);
81        buf.put_u32(self.timestamp);
82        buf.put_u16(self.length);
83        buf.put_u16(self.padding);
84    }
85
86    fn decode_protocol_version(data: u8) -> ProtocolVersion {
87        match data {
88            1 => ProtocolVersion::DIS_PDUv1,
89            2 => ProtocolVersion::IEEE1278_1993,
90            3 => ProtocolVersion::DIS_PDUv2_Third_Draft,
91            4 => ProtocolVersion::DIS_PDUv2_Fourth_Draft_Revised,
92            5 => ProtocolVersion::IEEE1278_1_1995,
93            6 => ProtocolVersion::IEEE1278_1A_1998,
94            7 => ProtocolVersion::IEEE1278_1_2012,
95            _ => ProtocolVersion::Other,
96        }
97    }
98
99    pub fn decode(buf: &mut BytesMut) -> PduHeader {
100        PduHeader {
101            protocol_version: PduHeader::decode_protocol_version(buf.get_u8()),
102            exercise_id: buf.get_u8(),
103            pdu_type: PduHeader::decode_pdu_type(buf.get_u8()),
104            protocol_family: PduHeader::decode_protocol_family(buf.get_u8()),
105            timestamp: buf.get_u32(),
106            length: buf.get_u16(),
107            padding: buf.get_u16(),
108        }
109    }
110
111    #[must_use]
112    pub fn decode_pdu_type(data: u8) -> PduType {
113        match data {
114            1 => PduType::EntityState,
115            2 => PduType::Fire,
116            3 => PduType::Detonation,
117            4 => PduType::Collision,
118            5 => PduType::ServiceRequest,
119            6 => PduType::ResupplyOffer,
120            7 => PduType::ResupplyReceived,
121            8 => PduType::ResupplyCancel,
122            9 => PduType::RepairComplete,
123            10 => PduType::RepairResponse,
124            11 => PduType::CreateEntity,
125            12 => PduType::RemoveEntity,
126            13 => PduType::StartResume,
127            14 => PduType::StopFreeze,
128            15 => PduType::Acknowledge,
129            16 => PduType::ActionRequest,
130            17 => PduType::ActionResponse,
131            18 => PduType::DataQuery,
132            19 => PduType::SetData,
133            20 => PduType::Data,
134            21 => PduType::EventReport,
135            22 => PduType::Comment,
136            23 => PduType::ElectromagneticEmission,
137            24 => PduType::Designator,
138            25 => PduType::Transmitter,
139            26 => PduType::Signal,
140            27 => PduType::Receiver,
141            28 => PduType::IFF,
142            29 => PduType::UnderwaterAcoustic,
143            30 => PduType::SupplementalEmission,
144            31 => PduType::IntercomSignal,
145            32 => PduType::IntercomControl,
146            33 => PduType::AggregateState,
147            34 => PduType::IsGroupOf,
148            35 => PduType::TransferOwnership,
149            36 => PduType::IsPartOf,
150            37 => PduType::MinefieldState,
151            38 => PduType::MinefieldQuery,
152            39 => PduType::MinefieldData,
153            40 => PduType::MinefieldResponseNack,
154            41 => PduType::EnvironmentalProcess,
155            42 => PduType::GriddedData,
156            43 => PduType::PointObjectState,
157            44 => PduType::LinearObjectState,
158            45 => PduType::ArealObjectState,
159            46 => PduType::TSPI,
160            47 => PduType::Appearance,
161            48 => PduType::ArticulatedParts,
162            49 => PduType::LEFire,
163            50 => PduType::LEDetonation,
164            51 => PduType::CreateEntityReliable,
165            52 => PduType::RemoveEntityReliable,
166            53 => PduType::StartResumeReliable,
167            54 => PduType::StopFreezeReliable,
168            55 => PduType::AcknowledgeReliable,
169            56 => PduType::ActionRequestReliable,
170            57 => PduType::ActionResponseReliable,
171            58 => PduType::DataQueryReliable,
172            59 => PduType::SetDataReliable,
173            60 => PduType::DataReliable,
174            61 => PduType::EventReportReliable,
175            62 => PduType::CommentReliable,
176            63 => PduType::RecordReliable,
177            64 => PduType::SetRecordReliable,
178            65 => PduType::RecordQueryReliable,
179            66 => PduType::CollisionElastic,
180            67 => PduType::EntityStateUpdate,
181            68 => PduType::DirectedEnergyFire,
182            69 => PduType::EntityDamageStatus,
183            70 => PduType::InformationOperationsAction,
184            71 => PduType::InformationOperationsReport,
185            72 => PduType::Attribute,
186            _ => PduType::Other,
187        }
188    }
189
190    #[must_use]
191    fn decode_protocol_family(data: u8) -> ProtocolFamily {
192        match data {
193            1 => ProtocolFamily::EntityInformation,
194            2 => ProtocolFamily::Warfare,
195            3 => ProtocolFamily::Logistics,
196            4 => ProtocolFamily::RadioCommunications,
197            5 => ProtocolFamily::SimulationManagement,
198            6 => ProtocolFamily::DistributedEmissionRegeneration,
199            7 => ProtocolFamily::EntityManagement,
200            8 => ProtocolFamily::Minefield,
201            9 => ProtocolFamily::SyntheticEnvironment,
202            10 => ProtocolFamily::SimulationManagementWithReliability,
203            11 => ProtocolFamily::LiveEntityInformationInteraction,
204            12 => ProtocolFamily::NonRealTime,
205            13 => ProtocolFamily::InformationOperations,
206            _ => ProtocolFamily::Other,
207        }
208    }
209}
210
211#[derive(Copy, Clone, Debug, Default, FromPrimitive, PartialEq)]
212pub enum ProtocolFamily {
213    #[default]
214    Other = 0,
215    EntityInformation = 1,
216    Warfare = 2,
217    Logistics = 3,
218    RadioCommunications = 4,
219    SimulationManagement = 5,
220    DistributedEmissionRegeneration = 6,
221    EntityManagement = 7,
222    Minefield = 8,
223    SyntheticEnvironment = 9,
224    SimulationManagementWithReliability = 10,
225    LiveEntityInformationInteraction = 11,
226    NonRealTime = 12,
227    InformationOperations = 13,
228}
229
230#[derive(Copy, Clone, Debug, Default, FromPrimitive, PartialEq)]
231#[allow(non_camel_case_types)]
232pub enum ProtocolVersion {
233    #[default]
234    Other = 0,
235    DIS_PDUv1 = 1,
236    IEEE1278_1993 = 2,
237    DIS_PDUv2_Third_Draft = 3,
238    DIS_PDUv2_Fourth_Draft_Revised = 4,
239    IEEE1278_1_1995 = 5,
240    IEEE1278_1A_1998 = 6,
241    IEEE1278_1_2012 = 7,
242}
243
244#[derive(Copy, Clone, Debug, Default, FromPrimitive, PartialEq)]
245pub enum PduType {
246    #[default]
247    Other = 0,
248    EntityState = 1,
249    Fire = 2,
250    Detonation = 3,
251    Collision = 4,
252    ServiceRequest = 5,
253    ResupplyOffer = 6,
254    ResupplyReceived = 7,
255    ResupplyCancel = 8,
256    RepairComplete = 9,
257    RepairResponse = 10,
258    CreateEntity = 11,
259    RemoveEntity = 12,
260    StartResume = 13,
261    StopFreeze = 14,
262    Acknowledge = 15,
263    ActionRequest = 16,
264    ActionResponse = 17,
265    DataQuery = 18,
266    SetData = 19,
267    Data = 20,
268    EventReport = 21,
269    Comment = 22,
270    ElectromagneticEmission = 23,
271    Designator = 24,
272    Transmitter = 25,
273    Signal = 26,
274    Receiver = 27,
275    IFF = 28,
276    UnderwaterAcoustic = 29,
277    SupplementalEmission = 30,
278    IntercomSignal = 31,
279    IntercomControl = 32,
280    AggregateState = 33,
281    IsGroupOf = 34,
282    TransferOwnership = 35,
283    IsPartOf = 36,
284    MinefieldState = 37,
285    MinefieldQuery = 38,
286    MinefieldData = 39,
287    MinefieldResponseNack = 40,
288    EnvironmentalProcess = 41,
289    GriddedData = 42,
290    PointObjectState = 43,
291    LinearObjectState = 44,
292    ArealObjectState = 45,
293    TSPI = 46,
294    Appearance = 47,
295    ArticulatedParts = 48,
296    LEFire = 49,
297    LEDetonation = 50,
298    CreateEntityReliable = 51,
299    RemoveEntityReliable = 52,
300    StartResumeReliable = 53,
301    StopFreezeReliable = 54,
302    AcknowledgeReliable = 55,
303    ActionRequestReliable = 56,
304    ActionResponseReliable = 57,
305    DataQueryReliable = 58,
306    SetDataReliable = 59,
307    DataReliable = 60,
308    EventReportReliable = 61,
309    CommentReliable = 62,
310    RecordReliable = 63,
311    SetRecordReliable = 64,
312    RecordQueryReliable = 65,
313    CollisionElastic = 66,
314    EntityStateUpdate = 67,
315    DirectedEnergyFire = 68,
316    EntityDamageStatus = 69,
317    InformationOperationsAction = 70,
318    InformationOperationsReport = 71,
319    Attribute = 72,
320}