open_dis_rust/common/
live_entity_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) 2025 Cameron Howell
4//
5//     Licensed under the BSD 2-Clause License
6
7use bytes::{Buf, BufMut, BytesMut};
8use chrono::{Timelike, Utc};
9
10use crate::common::{
11    GenericHeader, SerializedLength,
12    enums::{DISLiveEntitySubprotocolNumber, PduType, ProtocolFamily, ProtocolVersion},
13};
14
15#[derive(Copy, Clone, Debug, PartialEq, Eq)]
16pub struct LiveEntityPduHeader {
17    /// The version of the protocol
18    pub protocol_version: ProtocolVersion,
19    /// Exercise ID
20    pub exercise_id: u8,
21    /// Type of PDU, unique for each PDU class
22    pub pdu_type: PduType,
23    /// Value that refers to the protocol family
24    pub protocol_family: ProtocolFamily,
25    /// Timestamp value
26    pub timestamp: u32,
27    /// Length, in bytes, of the PDU
28    pub length: u16,
29    /// The subprotocol to be used to decode the PDU
30    pub subprotocol_number: DISLiveEntitySubprotocolNumber,
31    /// Padded so that this header maintains the same length as the PDU Header
32    padding: u8,
33}
34
35impl Default for LiveEntityPduHeader {
36    fn default() -> Self {
37        Self {
38            protocol_version: ProtocolVersion::IEEE1278_1_2012,
39            exercise_id: 1,
40            pdu_type: PduType::default(),
41            protocol_family: ProtocolFamily::default(),
42            timestamp: Self::calculate_dis_timestamp(),
43            length: 0,
44            subprotocol_number: DISLiveEntitySubprotocolNumber::default(),
45            padding: 0,
46        }
47    }
48}
49
50impl GenericHeader for LiveEntityPduHeader {
51    fn pdu_type(&self) -> PduType {
52        self.pdu_type
53    }
54
55    fn set_pdu_type(&mut self, value: PduType) {
56        self.pdu_type = value;
57    }
58
59    fn protocol_family(&self) -> ProtocolFamily {
60        self.protocol_family
61    }
62
63    fn set_protocol_family(&mut self, value: ProtocolFamily) {
64        self.protocol_family = value;
65    }
66
67    fn length(&self) -> u16 {
68        self.length
69    }
70
71    fn set_length(&mut self, value: u16) {
72        self.length = value;
73    }
74
75    fn serialize(&self, buf: &mut BytesMut) {
76        buf.put_u8(self.protocol_version as u8);
77        buf.put_u8(self.exercise_id);
78        buf.put_u8(self.pdu_type as u8);
79        buf.put_u8(self.protocol_family as u8);
80        buf.put_u32(self.timestamp);
81        buf.put_u16(self.length);
82        buf.put_u8(self.subprotocol_number as u8);
83        buf.put_u8(self.padding);
84    }
85
86    fn deserialize<B: Buf>(buf: &mut B) -> Self {
87        Self {
88            protocol_version: ProtocolVersion::deserialize(buf),
89            exercise_id: buf.get_u8(),
90            pdu_type: PduType::deserialize(buf),
91            protocol_family: ProtocolFamily::deserialize(buf),
92            timestamp: buf.get_u32(),
93            length: buf.get_u16(),
94            subprotocol_number: DISLiveEntitySubprotocolNumber::deserialize(buf),
95            padding: buf.get_u8(),
96        }
97    }
98}
99
100impl LiveEntityPduHeader {
101    #[must_use]
102    pub fn new(
103        pdu_type: PduType,
104        protocol_family: ProtocolFamily,
105        exercise_id: u8,
106        length: u16,
107    ) -> Self {
108        Self {
109            protocol_version: ProtocolVersion::IEEE1278_1_2012,
110            exercise_id,
111            pdu_type,
112            protocol_family,
113            timestamp: Self::calculate_dis_timestamp(),
114            length,
115            ..Default::default()
116        }
117    }
118
119    /// Gets the current time in terms of IEEE-1278.1 DIS time units
120    #[must_use]
121    #[allow(
122        clippy::cast_precision_loss,
123        clippy::cast_possible_truncation,
124        clippy::cast_sign_loss
125    )]
126    pub fn calculate_dis_timestamp() -> u32 {
127        let minute_curr = u64::from((Utc::now().minute() * 60) * 1_000_000);
128        let second_curr = u64::from(Utc::now().second() * 1_000_000);
129        let nanosecond_curr = u64::from(Utc::now().nanosecond() / 1000);
130        let dis_time = (second_curr + minute_curr + nanosecond_curr) as f32 / 1.68;
131        dis_time as u32
132    }
133}
134
135impl SerializedLength for LiveEntityPduHeader {
136    const LENGTH: usize = 12;
137}