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 padding: u8,
153}
154
155impl Default for PduHeader {
156 fn default() -> Self {
157 Self {
158 protocol_version: ProtocolVersion::IEEE1278_1_2012,
159 exercise_id: 1,
160 pdu_type: PduType::default(),
161 protocol_family: ProtocolFamily::default(),
162 timestamp: Self::calculate_dis_timestamp(),
163 length: 0,
164 status_record: PduStatusRecord::default(),
165 padding: 0,
166 }
167 }
168}
169
170impl GenericHeader for PduHeader {
171 fn pdu_type(&self) -> PduType {
172 self.pdu_type
173 }
174
175 fn set_pdu_type(&mut self, value: PduType) {
176 self.pdu_type = value;
177 }
178
179 fn protocol_family(&self) -> ProtocolFamily {
180 self.protocol_family
181 }
182
183 fn set_protocol_family(&mut self, value: ProtocolFamily) {
184 self.protocol_family = value;
185 }
186
187 fn length(&self) -> u16 {
188 self.length
189 }
190
191 fn set_length(&mut self, value: u16) {
192 self.length = value;
193 }
194
195 fn serialize(&self, buf: &mut BytesMut) {
196 buf.put_u8(self.protocol_version as u8);
197 buf.put_u8(self.exercise_id);
198 buf.put_u8(self.pdu_type as u8);
199 buf.put_u8(self.protocol_family as u8);
200 buf.put_u32(self.timestamp);
201 buf.put_u16(self.length);
202 buf.put_u8(self.status_record.to_u8());
203 buf.put_u8(self.padding);
204 }
205
206 fn deserialize<B: Buf>(buf: &mut B) -> Self {
207 Self {
208 protocol_version: ProtocolVersion::deserialize(buf),
209 exercise_id: buf.get_u8(),
210 pdu_type: PduType::deserialize(buf),
211 protocol_family: ProtocolFamily::deserialize(buf),
212 timestamp: buf.get_u32(),
213 length: buf.get_u16(),
214 status_record: PduStatusRecord::from_u8(buf.get_u8()),
215 padding: buf.get_u8(),
216 }
217 }
218}
219
220impl PduHeader {
221 #[must_use]
222 pub fn new(
223 pdu_type: PduType,
224 protocol_family: ProtocolFamily,
225 exercise_id: u8,
226 length: u16,
227 ) -> Self {
228 Self {
229 protocol_version: ProtocolVersion::IEEE1278_1_2012,
230 exercise_id,
231 pdu_type,
232 protocol_family,
233 timestamp: Self::calculate_dis_timestamp(),
234 length,
235 status_record: PduStatusRecord::default(),
236 padding: 0,
237 }
238 }
239
240 #[must_use]
242 #[allow(
243 clippy::cast_precision_loss,
244 clippy::cast_possible_truncation,
245 clippy::cast_sign_loss
246 )]
247 pub fn calculate_dis_timestamp() -> u32 {
248 let minute_curr = u64::from((Utc::now().minute() * 60) * 1_000_000);
249 let second_curr = u64::from(Utc::now().second() * 1_000_000);
250 let nanosecond_curr = u64::from(Utc::now().nanosecond() / 1000);
251 let dis_time = (second_curr + minute_curr + nanosecond_curr) as f32 / 1.68;
252 dis_time as u32
253 }
254}
255
256impl FieldSerialize for PduHeader {
257 fn serialize_field(&self, buf: &mut BytesMut) {
258 self.serialize(buf);
259 }
260}
261
262impl FieldDeserialize for PduHeader {
263 fn deserialize_field<B: Buf>(buf: &mut B) -> Self {
264 Self::deserialize(buf)
265 }
266}
267
268impl FieldLen for PduHeader {
269 fn field_len(&self) -> usize {
270 Self::LENGTH
271 }
272}
273
274impl SerializedLength for PduHeader {
275 const LENGTH: usize = 12;
276}