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#[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}