dis_rs/common/transmitter/
model.rs

1use crate::common::model::{
2    length_padded_to_num, EntityId, EntityType, Location, Orientation, PduBody, VectorF32,
3};
4use crate::common::{BodyInfo, Interaction};
5use crate::constants::{EIGHT_OCTETS, ZERO_OCTETS};
6use crate::enumerations::{
7    PduType, TransmitterAntennaPatternReferenceSystem, TransmitterAntennaPatternType,
8    TransmitterCryptoSystem, TransmitterDetailAmplitudeAngleModulation,
9    TransmitterDetailAmplitudeModulation, TransmitterDetailAngleModulation,
10    TransmitterDetailCarrierPhaseShiftModulation, TransmitterDetailCombinationModulation,
11    TransmitterDetailPulseModulation, TransmitterDetailSATCOMModulation,
12    TransmitterDetailUnmodulatedModulation, TransmitterInputSource, TransmitterMajorModulation,
13    TransmitterModulationTypeSystem, TransmitterTransmitState, VariableRecordType,
14};
15use crate::transmitter::builder::TransmitterBuilder;
16#[cfg(feature = "serde")]
17use serde::{Deserialize, Serialize};
18
19const BASE_TRANSMITTER_BODY_LENGTH: u16 = 92;
20pub const BEAM_ANTENNA_PATTERN_OCTETS: u16 = 40;
21pub const BASE_VTP_RECORD_LENGTH: u16 = 6;
22
23/// 5.8.3 Transmitter PDU
24///
25/// 7.7.2 Transmitter PDU
26#[derive(Clone, Debug, Default, PartialEq)]
27#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
28pub struct Transmitter {
29    pub radio_reference_id: EntityId,
30    pub radio_number: u16,
31    pub radio_type: EntityType,
32    pub transmit_state: TransmitterTransmitState,
33    pub input_source: TransmitterInputSource,
34    pub antenna_location: Location,
35    pub relative_antenna_location: VectorF32,
36    pub antenna_pattern_type: TransmitterAntennaPatternType,
37    pub frequency: u64,
38    pub transmit_frequency_bandwidth: f32,
39    pub power: f32,
40    pub modulation_type: ModulationType,
41    pub crypto_system: TransmitterCryptoSystem,
42    pub crypto_key_id: CryptoKeyId,
43    pub modulation_parameters: Option<Vec<u8>>,
44    pub antenna_pattern: Option<BeamAntennaPattern>,
45    pub variable_transmitter_parameters: Vec<VariableTransmitterParameter>,
46}
47
48impl Transmitter {
49    #[must_use]
50    pub fn builder() -> TransmitterBuilder {
51        TransmitterBuilder::new()
52    }
53
54    #[must_use]
55    pub fn into_builder(self) -> TransmitterBuilder {
56        TransmitterBuilder::new_from_body(self)
57    }
58
59    #[must_use]
60    pub fn into_pdu_body(self) -> PduBody {
61        PduBody::Transmitter(self)
62    }
63}
64
65impl BodyInfo for Transmitter {
66    fn body_length(&self) -> u16 {
67        BASE_TRANSMITTER_BODY_LENGTH
68            + self
69                .modulation_parameters
70                .as_ref()
71                .map_or(ZERO_OCTETS as u16, |params| params.len() as u16)
72            + self
73                .antenna_pattern
74                .as_ref()
75                .map_or(ZERO_OCTETS as u16, |_| BEAM_ANTENNA_PATTERN_OCTETS)
76            + self
77                .variable_transmitter_parameters
78                .iter()
79                .map(|vtp| {
80                    length_padded_to_num(
81                        BASE_VTP_RECORD_LENGTH as usize + vtp.fields.len(),
82                        EIGHT_OCTETS,
83                    )
84                    .record_length as u16
85                })
86                .sum::<u16>()
87    }
88
89    fn body_type(&self) -> PduType {
90        PduType::Transmitter
91    }
92}
93
94impl Interaction for Transmitter {
95    fn originator(&self) -> Option<&EntityId> {
96        Some(&self.radio_reference_id)
97    }
98
99    fn receiver(&self) -> Option<&EntityId> {
100        None
101    }
102}
103
104#[derive(Copy, Clone, Debug, PartialEq)]
105#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
106pub struct ModulationType {
107    pub spread_spectrum: SpreadSpectrum,
108    pub major_modulation: TransmitterMajorModulation,
109    pub radio_system: TransmitterModulationTypeSystem,
110}
111
112impl Default for ModulationType {
113    fn default() -> Self {
114        Self::new()
115    }
116}
117
118impl ModulationType {
119    #[must_use]
120    pub fn new() -> Self {
121        Self {
122            spread_spectrum: SpreadSpectrum::default(),
123            major_modulation: TransmitterMajorModulation::default(),
124            radio_system: TransmitterModulationTypeSystem::default(),
125        }
126    }
127
128    #[must_use]
129    pub fn with_spread_spectrum(mut self, spread_spectrum: SpreadSpectrum) -> Self {
130        self.spread_spectrum = spread_spectrum;
131        self
132    }
133
134    #[must_use]
135    pub fn with_major_modulation(mut self, major_modulation: TransmitterMajorModulation) -> Self {
136        self.major_modulation = major_modulation;
137        self
138    }
139
140    #[must_use]
141    pub fn with_radio_system(mut self, radio_system: TransmitterModulationTypeSystem) -> Self {
142        self.radio_system = radio_system;
143        self
144    }
145}
146
147#[derive(Copy, Clone, Debug, PartialEq)]
148#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
149pub struct SpreadSpectrum {
150    pub frequency_hopping: bool,
151    pub pseudo_noise: bool,
152    pub time_hopping: bool,
153}
154
155impl Default for SpreadSpectrum {
156    fn default() -> Self {
157        Self::new()
158    }
159}
160
161impl SpreadSpectrum {
162    #[must_use]
163    pub fn new() -> Self {
164        Self {
165            frequency_hopping: Default::default(),
166            pseudo_noise: Default::default(),
167            time_hopping: Default::default(),
168        }
169    }
170
171    #[must_use]
172    pub fn new_with_values(
173        frequency_hopping: bool,
174        pseudo_noise: bool,
175        time_hopping: bool,
176    ) -> Self {
177        Self {
178            frequency_hopping,
179            pseudo_noise,
180            time_hopping,
181        }
182    }
183
184    #[must_use]
185    pub fn with_frequency_hopping(mut self) -> Self {
186        self.frequency_hopping = true;
187        self
188    }
189
190    #[must_use]
191    pub fn with_pseudo_noise(mut self) -> Self {
192        self.pseudo_noise = true;
193        self
194    }
195
196    #[must_use]
197    pub fn with_time_hopping(mut self) -> Self {
198        self.time_hopping = true;
199        self
200    }
201}
202
203impl From<u16> for SpreadSpectrum {
204    fn from(spread_spectrum_values: u16) -> Self {
205        let frequency_hopping = ((spread_spectrum_values >> 15) & 0x0001) != 0;
206        let pseudo_noise = ((spread_spectrum_values >> 14) & 0x0001) != 0;
207        let time_hopping = ((spread_spectrum_values >> 13) & 0x0001) != 0;
208
209        SpreadSpectrum::new_with_values(frequency_hopping, pseudo_noise, time_hopping)
210    }
211}
212
213impl From<&SpreadSpectrum> for u16 {
214    fn from(value: &SpreadSpectrum) -> Self {
215        const BIT_0: u16 = 0x8000;
216        const BIT_1: u16 = 0x4000;
217        const BIT_2: u16 = 0x2000;
218
219        let spectrum = 0u16;
220        let spectrum = if value.frequency_hopping {
221            spectrum | BIT_0
222        } else {
223            spectrum
224        };
225        let spectrum = if value.pseudo_noise {
226            spectrum | BIT_1
227        } else {
228            spectrum
229        };
230        let spectrum = if value.time_hopping {
231            spectrum | BIT_2
232        } else {
233            spectrum
234        };
235        #[allow(clippy::let_and_return)]
236        spectrum
237    }
238}
239
240#[derive(Copy, Clone, Debug, PartialEq)]
241#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
242pub struct CryptoKeyId {
243    pub pseudo_crypto_key: u16,
244    pub crypto_mode: CryptoMode,
245}
246
247impl Default for CryptoKeyId {
248    fn default() -> Self {
249        Self {
250            pseudo_crypto_key: Default::default(),
251            crypto_mode: CryptoMode::Baseband,
252        }
253    }
254}
255
256impl From<u16> for CryptoKeyId {
257    fn from(value: u16) -> Self {
258        let pseudo_crypto_key = value >> 1;
259        let crypto_mode = (value & 0x0001) != 0;
260        let crypto_mode = CryptoMode::from(crypto_mode);
261
262        Self {
263            pseudo_crypto_key,
264            crypto_mode,
265        }
266    }
267}
268
269impl From<CryptoKeyId> for u16 {
270    fn from(value: CryptoKeyId) -> Self {
271        let crypto_mode = match value.crypto_mode {
272            CryptoMode::Baseband => 0u16,
273            CryptoMode::Diphase => 1u16,
274        };
275        (value.pseudo_crypto_key << 1) + crypto_mode
276    }
277}
278
279#[derive(Copy, Clone, Debug, PartialEq)]
280#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
281pub enum CryptoMode {
282    Baseband,
283    Diphase,
284}
285
286impl Default for CryptoMode {
287    fn default() -> Self {
288        Self::Baseband
289    }
290}
291
292impl From<bool> for CryptoMode {
293    fn from(value: bool) -> Self {
294        if value {
295            CryptoMode::Diphase
296        } else {
297            CryptoMode::Baseband
298        }
299    }
300}
301
302#[derive(Clone, Debug, PartialEq)]
303#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
304pub struct BeamAntennaPattern {
305    pub beam_direction: Orientation,
306    pub azimuth_beamwidth: f32,
307    pub elevation_beamwidth: f32,
308    pub reference_system: TransmitterAntennaPatternReferenceSystem,
309    pub e_z: f32,
310    pub e_x: f32,
311    pub phase: f32,
312}
313
314impl Default for BeamAntennaPattern {
315    fn default() -> Self {
316        Self::new()
317    }
318}
319
320impl BeamAntennaPattern {
321    #[must_use]
322    pub fn new() -> Self {
323        Self {
324            beam_direction: Orientation::default(),
325            azimuth_beamwidth: 0.0,
326            elevation_beamwidth: 0.0,
327            reference_system: TransmitterAntennaPatternReferenceSystem::default(),
328            e_z: 0.0,
329            e_x: 0.0,
330            phase: 0.0,
331        }
332    }
333
334    #[must_use]
335    pub fn with_beam_direction(mut self, beam_direction: Orientation) -> Self {
336        self.beam_direction = beam_direction;
337        self
338    }
339
340    #[must_use]
341    pub fn with_azimuth_beamwidth(mut self, azimuth_beamwidth: f32) -> Self {
342        self.azimuth_beamwidth = azimuth_beamwidth;
343        self
344    }
345
346    #[must_use]
347    pub fn with_elevation_beamwidth(mut self, elevation_beamwidth: f32) -> Self {
348        self.elevation_beamwidth = elevation_beamwidth;
349        self
350    }
351
352    #[must_use]
353    pub fn with_reference_system(
354        mut self,
355        reference_system: TransmitterAntennaPatternReferenceSystem,
356    ) -> Self {
357        self.reference_system = reference_system;
358        self
359    }
360
361    #[must_use]
362    pub fn with_e_z(mut self, e_z: f32) -> Self {
363        self.e_z = e_z;
364        self
365    }
366
367    #[must_use]
368    pub fn with_e_x(mut self, e_x: f32) -> Self {
369        self.e_x = e_x;
370        self
371    }
372
373    #[must_use]
374    pub fn with_phase(mut self, phase: f32) -> Self {
375        self.phase = phase;
376        self
377    }
378}
379
380#[derive(Clone, Debug, PartialEq)]
381#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
382pub struct VariableTransmitterParameter {
383    pub record_type: VariableRecordType,
384    pub fields: Vec<u8>,
385}
386
387impl Default for VariableTransmitterParameter {
388    fn default() -> Self {
389        Self::new()
390    }
391}
392
393impl VariableTransmitterParameter {
394    #[must_use]
395    pub fn new() -> Self {
396        Self {
397            record_type: VariableRecordType::default(),
398            fields: Vec::new(),
399        }
400    }
401
402    #[must_use]
403    pub fn with_record_type(mut self, record_type: VariableRecordType) -> Self {
404        self.record_type = record_type;
405        self
406    }
407
408    #[must_use]
409    pub fn with_fields(mut self, fields: Vec<u8>) -> Self {
410        self.fields = fields;
411        self
412    }
413}
414
415impl TransmitterMajorModulation {
416    #[must_use]
417    pub fn new_from_bytes_with_detail(major_modulation: u16, detail: u16) -> Self {
418        let major_modulation = TransmitterMajorModulation::from(major_modulation);
419        match major_modulation {
420            TransmitterMajorModulation::NoStatement => TransmitterMajorModulation::NoStatement,
421            TransmitterMajorModulation::Amplitude(_) => TransmitterMajorModulation::Amplitude(
422                TransmitterDetailAmplitudeModulation::from(detail),
423            ),
424            TransmitterMajorModulation::AmplitudeAndAngle(_) => {
425                TransmitterMajorModulation::AmplitudeAndAngle(
426                    TransmitterDetailAmplitudeAngleModulation::from(detail),
427                )
428            }
429            TransmitterMajorModulation::Angle(_) => {
430                TransmitterMajorModulation::Angle(TransmitterDetailAngleModulation::from(detail))
431            }
432            TransmitterMajorModulation::Combination(_) => TransmitterMajorModulation::Combination(
433                TransmitterDetailCombinationModulation::from(detail),
434            ),
435            TransmitterMajorModulation::Pulse(_) => {
436                TransmitterMajorModulation::Pulse(TransmitterDetailPulseModulation::from(detail))
437            }
438            TransmitterMajorModulation::Unmodulated(_) => TransmitterMajorModulation::Unmodulated(
439                TransmitterDetailUnmodulatedModulation::from(detail),
440            ),
441            TransmitterMajorModulation::CarrierPhaseShiftModulation_CPSM_(_) => {
442                TransmitterMajorModulation::CarrierPhaseShiftModulation_CPSM_(
443                    TransmitterDetailCarrierPhaseShiftModulation::from(detail),
444                )
445            }
446            TransmitterMajorModulation::SATCOM(_) => {
447                TransmitterMajorModulation::SATCOM(TransmitterDetailSATCOMModulation::from(detail))
448            }
449            TransmitterMajorModulation::Unspecified(_) => {
450                TransmitterMajorModulation::Unspecified(detail)
451            }
452        }
453    }
454
455    #[must_use]
456    pub fn to_bytes_with_detail(&self) -> (u16, u16) {
457        match self {
458            TransmitterMajorModulation::NoStatement => (0, 0),
459            TransmitterMajorModulation::Amplitude(detail) => (1, (*detail).into()),
460            TransmitterMajorModulation::AmplitudeAndAngle(detail) => (2, (*detail).into()),
461            TransmitterMajorModulation::Angle(detail) => (3, (*detail).into()),
462            TransmitterMajorModulation::Combination(detail) => (4, (*detail).into()),
463            TransmitterMajorModulation::Pulse(detail) => (5, (*detail).into()),
464            TransmitterMajorModulation::Unmodulated(detail) => (6, (*detail).into()),
465            TransmitterMajorModulation::CarrierPhaseShiftModulation_CPSM_(detail) => {
466                (7, (*detail).into())
467            }
468            TransmitterMajorModulation::SATCOM(detail) => (8, (*detail).into()),
469            TransmitterMajorModulation::Unspecified(detail) => (9, *detail),
470        }
471    }
472}