dis_rs/common/electromagnetic_emission/
model.rs1use crate::common::model::{BeamData, EntityId, EventId, PduBody, VectorF32};
2use crate::common::{BodyInfo, Interaction};
3use crate::electromagnetic_emission::builder::ElectromagneticEmissionBuilder;
4use crate::enumerations::{
5 BeamStatusBeamState, ElectromagneticEmissionBeamFunction,
6 ElectromagneticEmissionStateUpdateIndicator, EmitterName, EmitterSystemFunction,
7 HighDensityTrackJam, PduType,
8};
9#[cfg(feature = "serde")]
10use serde::{Deserialize, Serialize};
11
12const EMISSION_BASE_BODY_LENGTH: u16 = 16;
13const EMITTER_SYSTEM_BASE_LENGTH: u16 = 20;
14const BEAM_BASE_LENGTH: u16 = 52;
15const TRACK_JAM_BASE_LENGTH: u16 = 8;
16
17#[derive(Clone, Debug, Default, PartialEq)]
21#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
22pub struct ElectromagneticEmission {
23 pub emitting_entity_id: EntityId,
24 pub event_id: EventId,
25 pub state_update_indicator: ElectromagneticEmissionStateUpdateIndicator,
26 pub emitter_systems: Vec<EmitterSystem>,
27}
28
29impl ElectromagneticEmission {
30 #[must_use]
31 pub fn builder() -> ElectromagneticEmissionBuilder {
32 ElectromagneticEmissionBuilder::new()
33 }
34
35 #[must_use]
36 pub fn into_builder(self) -> ElectromagneticEmissionBuilder {
37 ElectromagneticEmissionBuilder::new_from_body(self)
38 }
39
40 #[must_use]
41 pub fn into_pdu_body(self) -> PduBody {
42 PduBody::ElectromagneticEmission(self)
43 }
44}
45
46impl BodyInfo for ElectromagneticEmission {
47 fn body_length(&self) -> u16 {
48 EMISSION_BASE_BODY_LENGTH
49 + self
50 .emitter_systems
51 .iter()
52 .map(EmitterSystem::system_data_length_bytes)
53 .sum::<u16>()
54 }
55
56 fn body_type(&self) -> PduType {
57 PduType::ElectromagneticEmission
58 }
59}
60
61impl Interaction for ElectromagneticEmission {
62 fn originator(&self) -> Option<&EntityId> {
63 Some(&self.emitting_entity_id)
64 }
65
66 fn receiver(&self) -> Option<&EntityId> {
67 if let Some(emitter) = self.emitter_systems.first() {
69 if let Some(beam) = emitter.beams.first() {
70 if let Some(tracks) = beam.track_jam_data.first() {
71 Some(&tracks.entity_id)
72 } else {
73 None
74 }
75 } else {
76 None
77 }
78 } else {
79 None
80 }
81 }
82}
83
84#[derive(Clone, Debug, PartialEq)]
86#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
87pub struct EmitterSystem {
88 pub name: EmitterName,
89 pub function: EmitterSystemFunction,
90 pub number: u8,
91 pub location: VectorF32,
92 pub beams: Vec<Beam>,
93}
94
95impl Default for EmitterSystem {
96 fn default() -> Self {
97 Self::new()
98 }
99}
100
101impl EmitterSystem {
102 #[must_use]
103 pub fn new() -> Self {
104 Self {
105 name: EmitterName::default(),
106 function: EmitterSystemFunction::default(),
107 number: 0,
108 location: VectorF32::default(),
109 beams: vec![],
110 }
111 }
112
113 #[must_use]
114 pub fn with_name(mut self, name: EmitterName) -> Self {
115 self.name = name;
116 self
117 }
118
119 #[must_use]
120 pub fn with_function(mut self, function: EmitterSystemFunction) -> Self {
121 self.function = function;
122 self
123 }
124
125 #[must_use]
126 pub fn with_number(mut self, number: u8) -> Self {
127 self.number = number;
128 self
129 }
130
131 #[must_use]
132 pub fn with_location(mut self, location: VectorF32) -> Self {
133 self.location = location;
134 self
135 }
136
137 #[allow(clippy::return_self_not_must_use)]
138 pub fn with_beams(mut self, beams: &mut Vec<Beam>) -> Self {
139 self.beams.append(beams);
140 self
141 }
142
143 #[must_use]
144 pub fn with_beam(mut self, beam: Beam) -> Self {
145 self.beams.push(beam);
146 self
147 }
148
149 #[must_use]
150 pub fn system_data_length_bytes(&self) -> u16 {
151 EMITTER_SYSTEM_BASE_LENGTH
152 + self
153 .beams
154 .iter()
155 .map(Beam::beam_data_length_bytes)
156 .sum::<u16>()
157 }
158}
159
160#[derive(Clone, Default, Debug, PartialEq)]
161#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
162pub struct Beam {
163 pub number: u8,
164 pub parameter_index: u16,
165 pub parameter_data: FundamentalParameterData,
166 pub beam_data: BeamData,
167 pub beam_function: ElectromagneticEmissionBeamFunction,
168 pub high_density_track_jam: HighDensityTrackJam,
169 pub beam_status: BeamStatusBeamState,
170 pub jamming_technique: JammingTechnique,
171 pub track_jam_data: Vec<TrackJam>,
172}
173
174impl Beam {
175 #[must_use]
176 pub fn new() -> Self {
177 Self {
178 number: 0,
179 parameter_index: 0,
180 parameter_data: FundamentalParameterData::default(),
181 beam_data: BeamData::default(),
182 beam_function: ElectromagneticEmissionBeamFunction::default(),
183 high_density_track_jam: HighDensityTrackJam::default(),
184 beam_status: BeamStatusBeamState::default(),
185 jamming_technique: JammingTechnique::default(),
186 track_jam_data: vec![],
187 }
188 }
189
190 #[must_use]
191 pub fn with_number(mut self, number: u8) -> Self {
192 self.number = number;
193 self
194 }
195
196 #[must_use]
197 pub fn with_parameter_index(mut self, parameter_index: u16) -> Self {
198 self.parameter_index = parameter_index;
199 self
200 }
201
202 #[must_use]
203 pub fn with_parameter_data(mut self, parameter_data: FundamentalParameterData) -> Self {
204 self.parameter_data = parameter_data;
205 self
206 }
207
208 #[must_use]
209 pub fn with_beam_data(mut self, beam_data: BeamData) -> Self {
210 self.beam_data = beam_data;
211 self
212 }
213
214 #[must_use]
215 pub fn with_beam_function(
216 mut self,
217 beam_function: ElectromagneticEmissionBeamFunction,
218 ) -> Self {
219 self.beam_function = beam_function;
220 self
221 }
222
223 #[must_use]
224 pub fn with_high_density_track_jam(
225 mut self,
226 high_density_track_jam: HighDensityTrackJam,
227 ) -> Self {
228 self.high_density_track_jam = high_density_track_jam;
229 self
230 }
231
232 #[must_use]
233 pub fn with_beam_status(mut self, beam_status: BeamStatusBeamState) -> Self {
234 self.beam_status = beam_status;
235 self
236 }
237
238 #[must_use]
239 pub fn with_jamming_technique(mut self, jamming_technique: JammingTechnique) -> Self {
240 self.jamming_technique = jamming_technique;
241 self
242 }
243
244 #[allow(clippy::return_self_not_must_use)]
245 pub fn with_track_jams(mut self, track_jam_data: &mut Vec<TrackJam>) -> Self {
246 self.track_jam_data.append(track_jam_data);
247 self
248 }
249
250 #[must_use]
251 pub fn with_track_jam(mut self, track_jam_data: TrackJam) -> Self {
252 self.track_jam_data.push(track_jam_data);
253 self
254 }
255
256 #[must_use]
257 pub fn beam_data_length_bytes(&self) -> u16 {
258 BEAM_BASE_LENGTH + (TRACK_JAM_BASE_LENGTH * self.track_jam_data.len() as u16)
259 }
260}
261
262#[derive(Copy, Clone, Default, Debug, PartialEq)]
264#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
265pub struct FundamentalParameterData {
266 pub frequency: f32,
267 pub frequency_range: f32,
268 pub effective_power: f32,
269 pub pulse_repetition_frequency: f32,
270 pub pulse_width: f32,
271}
272
273impl FundamentalParameterData {
274 #[must_use]
275 pub fn new() -> Self {
276 Self {
277 frequency: 0.0,
278 frequency_range: 0.0,
279 effective_power: 0.0,
280 pulse_repetition_frequency: 0.0,
281 pulse_width: 0.0,
282 }
283 }
284
285 #[must_use]
286 pub fn with_frequency(mut self, frequency: f32) -> Self {
287 self.frequency = frequency;
288 self
289 }
290
291 #[must_use]
292 pub fn with_frequency_range(mut self, frequency_range: f32) -> Self {
293 self.frequency_range = frequency_range;
294 self
295 }
296
297 #[must_use]
298 pub fn with_effective_power(mut self, effective_power: f32) -> Self {
299 self.effective_power = effective_power;
300 self
301 }
302
303 #[must_use]
304 pub fn with_pulse_repetition_frequency(mut self, pulse_repetition_frequency: f32) -> Self {
305 self.pulse_repetition_frequency = pulse_repetition_frequency;
306 self
307 }
308
309 #[must_use]
310 pub fn with_pulse_width(mut self, pulse_width: f32) -> Self {
311 self.pulse_width = pulse_width;
312 self
313 }
314}
315
316#[derive(Clone, Default, Debug, PartialEq)]
318#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
319pub struct JammingTechnique {
320 pub kind: u8,
321 pub category: u8,
322 pub subcategory: u8,
323 pub specific: u8,
324}
325
326impl JammingTechnique {
327 #[must_use]
328 pub fn new() -> Self {
329 Self {
330 kind: 0,
331 category: 0,
332 subcategory: 0,
333 specific: 0,
334 }
335 }
336
337 #[must_use]
338 pub fn with_kind(mut self, kind: u8) -> Self {
339 self.kind = kind;
340 self
341 }
342
343 #[must_use]
344 pub fn with_category(mut self, category: u8) -> Self {
345 self.category = category;
346 self
347 }
348
349 #[must_use]
350 pub fn with_subcategory(mut self, subcategory: u8) -> Self {
351 self.subcategory = subcategory;
352 self
353 }
354
355 #[must_use]
356 pub fn with_specific(mut self, specific: u8) -> Self {
357 self.specific = specific;
358 self
359 }
360}
361
362#[derive(Clone, Default, Debug, PartialEq)]
364#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
365pub struct TrackJam {
366 pub entity_id: EntityId,
367 pub emitter: u8,
368 pub beam: u8,
369}
370
371impl TrackJam {
372 #[must_use]
373 pub fn new() -> Self {
374 Self {
375 entity_id: EntityId::default(),
376 emitter: 0,
377 beam: 0,
378 }
379 }
380
381 #[must_use]
382 pub fn with_entity_id(mut self, entity_id: EntityId) -> Self {
383 self.entity_id = entity_id;
384 self
385 }
386
387 #[must_use]
388 pub fn with_emitter(mut self, emitter: u8) -> Self {
389 self.emitter = emitter;
390 self
391 }
392
393 #[must_use]
394 pub fn with_beam(mut self, beam: u8) -> Self {
395 self.beam = beam;
396 self
397 }
398}