open_dis_rust/common/
pdu_header.rs1#![allow(clippy::must_use_candidate)]
8
9use bytes::{Buf, BufMut, BytesMut};
10use chrono::{Timelike, Utc};
11use modular_bitfield::prelude::*;
12
13use crate::{
14 common::{
15 GenericHeader, SerializedLength,
16 enums::{
17 ActiveInterrogationIndicator, CoupledExtensionIndicator, DetonationTypeIndicator,
18 FireTypeIndicator, IntercomAttachedIndicator, LVCIndicator, PduStatusIFFSimulationMode,
19 PduType, ProtocolFamily, ProtocolVersion, RadioAttachedIndicator,
20 TransferredEntityIndicator,
21 },
22 },
23 pdu_macro::{FieldDeserialize, FieldLen, FieldSerialize},
24};
25
26#[bitfield(bits = 8)]
27#[derive(Copy, Clone, Debug, PartialEq, Eq)]
28pub struct PduStatusRecord {
29 pub tei: TransferredEntityIndicator,
30 pub lvc: LVCIndicator,
31 pub cei: CoupledExtensionIndicator,
32 pub bit4_5: B2,
33 #[skip]
34 __reserved: B2,
35}
36
37impl PduStatusRecord {
38 #[must_use]
39 pub const fn new_zero() -> Self {
40 Self::new()
41 }
42
43 #[must_use]
44 pub fn get_dti(&self) -> DetonationTypeIndicator {
45 DetonationTypeIndicator::from(self.bit4_5())
46 }
47
48 pub fn set_dti(&mut self, dti: DetonationTypeIndicator) {
49 self.set_bit4_5(dti.into());
50 }
51
52 #[must_use]
53 pub fn get_rai(&self) -> RadioAttachedIndicator {
54 RadioAttachedIndicator::from(self.bit4_5())
55 }
56
57 pub fn set_rai(&mut self, rai: RadioAttachedIndicator) {
58 self.set_bit4_5(rai.into());
59 }
60
61 #[must_use]
62 pub fn get_iai(&self) -> IntercomAttachedIndicator {
63 IntercomAttachedIndicator::from(self.bit4_5())
64 }
65
66 pub fn set_iai(&mut self, iai: IntercomAttachedIndicator) {
67 self.set_bit4_5(iai.into());
68 }
69
70 #[must_use]
71 pub fn get_fti(&self) -> FireTypeIndicator {
72 let bit4 = self.bit4_5() & 0b01;
73 if bit4 == 0 {
74 FireTypeIndicator::Munition
75 } else {
76 FireTypeIndicator::Expendable
77 }
78 }
79
80 pub fn set_fti(&mut self, fti: FireTypeIndicator) {
81 let mut v = self.bit4_5();
82 v = (v & 0b10) | (fti as u8 & 0x01);
83 self.set_bit4_5(v);
84 }
85
86 #[must_use]
87 pub fn get_ism(&self) -> PduStatusIFFSimulationMode {
88 let bit4 = self.bit4_5() & 0b01;
89 if bit4 == 0 {
90 PduStatusIFFSimulationMode::Regeneration
91 } else {
92 PduStatusIFFSimulationMode::Interactive
93 }
94 }
95
96 pub fn set_ism(&mut self, ism: PduStatusIFFSimulationMode) {
97 let mut v = self.bit4_5();
98 v = (v & 0b10) | (ism as u8 & 0x01);
99 self.set_bit4_5(v);
100 }
101
102 #[must_use]
103 pub fn get_aii(&self) -> ActiveInterrogationIndicator {
104 let bit5 = (self.bit4_5() >> 1) & 0b01;
105 if bit5 == 0 {
106 ActiveInterrogationIndicator::NotActive
107 } else {
108 ActiveInterrogationIndicator::Active
109 }
110 }
111
112 pub fn set_aii(&mut self, aii: ActiveInterrogationIndicator) {
113 let mut v = self.bit4_5();
114 v = (v & 0b01) | ((aii as u8) << 1);
115 self.set_bit4_5(v);
116 }
117
118 #[must_use]
119 pub const fn to_u8(&self) -> u8 {
120 self.into_bytes()[0]
121 }
122
123 #[must_use]
124 pub const fn from_u8(b: u8) -> Self {
125 Self::from_bytes([b])
126 }
127}
128
129impl Default for PduStatusRecord {
130 fn default() -> Self {
131 Self::new_zero()
132 }
133}
134
135#[derive(Copy, Clone, Debug, PartialEq, Eq)]
136pub struct PduHeader {
137 pub protocol_version: ProtocolVersion,
139 pub exercise_id: u8,
141 pub pdu_type: PduType,
143 pub protocol_family: ProtocolFamily,
145 pub timestamp: u32,
147 pub length: u16,
149 pub status_record: PduStatusRecord,
151}
152
153impl Default for PduHeader {
154 fn default() -> Self {
155 Self {
156 protocol_version: ProtocolVersion::IEEE1278_1_2012,
157 exercise_id: 1,
158 pdu_type: PduType::default(),
159 protocol_family: ProtocolFamily::default(),
160 timestamp: Self::calculate_dis_timestamp(),
161 length: 0,
162 status_record: PduStatusRecord::default(),
163 }
164 }
165}
166
167impl GenericHeader for PduHeader {
168 fn pdu_type(&self) -> PduType {
169 self.pdu_type
170 }
171
172 fn set_pdu_type(&mut self, value: PduType) {
173 self.pdu_type = value;
174 }
175
176 fn protocol_family(&self) -> ProtocolFamily {
177 self.protocol_family
178 }
179
180 fn set_protocol_family(&mut self, value: ProtocolFamily) {
181 self.protocol_family = value;
182 }
183
184 fn length(&self) -> u16 {
185 self.length
186 }
187
188 fn set_length(&mut self, value: u16) {
189 self.length = value;
190 }
191
192 fn serialize(&self, buf: &mut BytesMut) {
193 buf.put_u8(self.protocol_version as u8);
194 buf.put_u8(self.exercise_id);
195 buf.put_u8(self.pdu_type as u8);
196 buf.put_u8(self.protocol_family as u8);
197 buf.put_u32(self.timestamp);
198 buf.put_u16(self.length);
199 buf.put_u8(self.status_record.to_u8());
200 }
201
202 fn deserialize<B: Buf>(buf: &mut B) -> Self {
203 Self {
204 protocol_version: ProtocolVersion::deserialize(buf),
205 exercise_id: buf.get_u8(),
206 pdu_type: PduType::deserialize(buf),
207 protocol_family: ProtocolFamily::deserialize(buf),
208 timestamp: buf.get_u32(),
209 length: buf.get_u16(),
210 status_record: PduStatusRecord::from_u8(buf.get_u8()),
211 }
212 }
213}
214
215impl PduHeader {
216 #[must_use]
217 pub fn new(
218 pdu_type: PduType,
219 protocol_family: ProtocolFamily,
220 exercise_id: u8,
221 length: u16,
222 ) -> Self {
223 Self {
224 protocol_version: ProtocolVersion::IEEE1278_1_2012,
225 exercise_id,
226 pdu_type,
227 protocol_family,
228 timestamp: Self::calculate_dis_timestamp(),
229 length,
230 status_record: PduStatusRecord::default(),
231 }
232 }
233
234 #[must_use]
236 #[allow(
237 clippy::cast_precision_loss,
238 clippy::cast_possible_truncation,
239 clippy::cast_sign_loss
240 )]
241 pub fn calculate_dis_timestamp() -> u32 {
242 let minute_curr = u64::from((Utc::now().minute() * 60) * 1_000_000);
243 let second_curr = u64::from(Utc::now().second() * 1_000_000);
244 let nanosecond_curr = u64::from(Utc::now().nanosecond() / 1000);
245 let dis_time = (second_curr + minute_curr + nanosecond_curr) as f32 / 1.68;
246 dis_time as u32
247 }
248}
249
250impl FieldSerialize for PduHeader {
251 fn serialize_field(&self, buf: &mut BytesMut) {
252 self.serialize(buf);
253 }
254}
255
256impl FieldDeserialize for PduHeader {
257 fn deserialize_field<B: Buf>(buf: &mut B) -> Self {
258 Self::deserialize(buf)
259 }
260}
261
262impl FieldLen for PduHeader {
263 fn field_len(&self) -> usize {
264 Self::LENGTH
265 }
266}
267
268impl SerializedLength for PduHeader {
269 const LENGTH: usize = 12;
270}