dis_rs/common/iff/
parser.rs

1use crate::common::iff::model::{
2    ChangeOptionsRecord, DamageStatus, DapSource, DapValue, EnabledStatus, EnhancedMode1Code,
3    FundamentalOperationalData, Iff, IffDataRecord, IffDataSpecification,
4    IffFundamentalParameterData, IffLayer2, IffLayer3, IffLayer4, IffLayer5, IffPresence,
5    InformationLayers, LatLonAltSource, LayerHeader, LayersPresenceApplicability,
6    MalfunctionStatus, Mode5BasicData, Mode5InterrogatorBasicData, Mode5InterrogatorStatus,
7    Mode5MessageFormats, Mode5TransponderBasicData, Mode5TransponderStatus,
8    Mode5TransponderSupplementalData, ModeSAltitude, ModeSBasicData, ModeSInterrogatorBasicData,
9    ModeSInterrogatorStatus, ModeSLevelsPresent, ModeSTransponderBasicData, ModeSTransponderStatus,
10    OnOffStatus, OperationalStatus, ParameterCapable, SquitterStatus, SystemId, SystemSpecificData,
11    SystemStatus, BASE_IFF_DATA_RECORD_LENGTH_OCTETS,
12};
13use crate::common::model::PduBody;
14use crate::common::parser::{beam_data, entity_id, event_id, simulation_address, vec3_f32};
15use crate::common::DisError;
16use crate::constants::EIGHT_OCTETS;
17use crate::enumerations::{
18    AircraftIdentificationType, AircraftPresentDomain, CapabilityReport, DataCategory,
19    IffApplicableModes, IffSystemMode, IffSystemName, IffSystemType, NavigationSource,
20    VariableRecordType,
21};
22use nom::bytes::complete::take;
23use nom::multi::count;
24use nom::number::complete::{be_f32, be_u16, be_u32, be_u8};
25use nom::IResult;
26
27pub(crate) fn iff_body(input: &[u8]) -> IResult<&[u8], PduBody> {
28    let (input, entity_id) = entity_id(input)?;
29    let (input, event_id) = event_id(input)?;
30    let (input, antenna_location) = vec3_f32(input)?;
31    let (input, system_id) = system_id(input)?;
32    let (input, system_designator) = be_u8(input)?;
33    let (input, system_specific_data) = be_u8(input)?;
34    let (input, fundamental_data) = fundamental_operational_data(input)?;
35
36    let builder = Iff::builder();
37
38    let (input, builder) = if fundamental_data.information_layers.layer_2
39        == LayersPresenceApplicability::PresentApplicable
40    {
41        let (input, layer_2) = iff_layer_2(input)?;
42        (input, builder.with_layer_2(layer_2))
43    } else {
44        (input, builder)
45    };
46    let (input, builder) = if fundamental_data.information_layers.layer_3
47        == LayersPresenceApplicability::PresentApplicable
48    {
49        let (input, layer_3) = iff_layer_3(&system_id.system_type)(input)?;
50        (input, builder.with_layer_3(layer_3))
51    } else {
52        (input, builder)
53    };
54    let (input, builder) = if fundamental_data.information_layers.layer_4
55        == LayersPresenceApplicability::PresentApplicable
56    {
57        let (input, layer_4) = iff_layer_4(&system_id.system_type)(input)?;
58        (input, builder.with_layer_4(layer_4))
59    } else {
60        (input, builder)
61    };
62    let (input, builder) = if fundamental_data.information_layers.layer_5
63        == LayersPresenceApplicability::PresentApplicable
64    {
65        let (input, layer_5) = iff_layer_5(input)?;
66        (input, builder.with_layer_5(layer_5))
67    } else {
68        (input, builder)
69    };
70
71    let builder = builder
72        .with_emitting_entity_id(entity_id)
73        .with_event_id(event_id)
74        .with_relative_antenna_location(antenna_location)
75        .with_system_id(system_id)
76        .with_system_designator(system_designator)
77        .with_system_specific_data(system_specific_data)
78        .with_fundamental_operational_data(fundamental_data);
79
80    Ok((input, builder.build().into_pdu_body()))
81}
82
83fn iff_layer_2(input: &[u8]) -> IResult<&[u8], IffLayer2> {
84    let (input, layer_header) = layer_header(input)?;
85    let (input, beam_data) = beam_data(input)?;
86    let (input, operational_parameter_1) = be_u8(input)?;
87    let (input, operational_parameter_2) = be_u8(input)?;
88    let (input, num_params) = be_u16(input)?;
89    let (input, fundamental_parameters) =
90        count(iff_fundamental_parameter_data, num_params.into())(input)?;
91
92    Ok((
93        input,
94        IffLayer2::builder()
95            .with_header(layer_header)
96            .with_beam_data(beam_data)
97            .with_operational_parameter_1(operational_parameter_1)
98            .with_operational_parameter_2(operational_parameter_2)
99            .with_iff_fundamental_parameters(fundamental_parameters)
100            .build(),
101    ))
102}
103
104fn iff_layer_3(system_type: &IffSystemType) -> impl Fn(&[u8]) -> IResult<&[u8], IffLayer3> + '_ {
105    move |input: &[u8]| {
106        let (input, layer_header) = layer_header(input)?;
107        let (input, reporting_simulation) = simulation_address(input)?;
108        let (input, basic_data) = mode_5_basic_data(system_type)(input)?;
109        let (input, _padding) = be_u16(input)?;
110        let (input, data_specification) = iff_data_specification(input)?;
111
112        Ok((
113            input,
114            IffLayer3::builder()
115                .with_header(layer_header)
116                .with_reporting_simulation(reporting_simulation)
117                // TODO when we cannot match the system type, we insert the default Basic Data (transponder)
118                .with_mode_5_basic_data(basic_data.unwrap_or(Mode5BasicData::new_transponder(
119                    Mode5TransponderBasicData::default(),
120                )))
121                .with_iff_data_specification(data_specification)
122                .build(),
123        ))
124    }
125}
126
127fn iff_layer_4(system_type: &IffSystemType) -> impl Fn(&[u8]) -> IResult<&[u8], IffLayer4> + '_ {
128    move |input: &[u8]| {
129        let (input, layer_header) = layer_header(input)?;
130        let (input, reporting_simulation) = simulation_address(input)?;
131        let (input, basic_data) = mode_s_basic_data(system_type)(input)?;
132        let (input, _padding) = be_u16(input)?;
133        let (input, data_specification) = iff_data_specification(input)?;
134
135        Ok((
136            input,
137            IffLayer4::builder()
138                .with_header(layer_header)
139                .with_reporting_simulation(reporting_simulation)
140                // TODO when we cannot match the system type, we insert the default Basic Data (transponder)
141                .with_mode_s_basic_data(basic_data.unwrap_or(ModeSBasicData::Transponder(
142                    ModeSTransponderBasicData::default(),
143                )))
144                .with_iff_data_specification(data_specification)
145                .build(),
146        ))
147    }
148}
149
150fn iff_layer_5(input: &[u8]) -> IResult<&[u8], IffLayer5> {
151    let (input, layer_header) = layer_header(input)?;
152    let (input, reporting_simulation) = simulation_address(input)?;
153    let (input, _padding) = be_u16(input)?;
154    let (input, applicable_layers) = information_layers(input)?;
155    let (input, data_category) = be_u8(input)?;
156    let data_category = DataCategory::from(data_category);
157    let (input, _padding) = be_u16(input)?;
158    let (input, data_specification) = iff_data_specification(input)?;
159
160    Ok((
161        input,
162        IffLayer5::builder()
163            .with_header(layer_header)
164            .with_reporting_simulation(reporting_simulation)
165            .with_applicable_layers(applicable_layers)
166            .with_data_category(data_category)
167            .with_iff_data_specification(data_specification)
168            .build(),
169    ))
170}
171
172fn change_options_record(input: &[u8]) -> IResult<&[u8], ChangeOptionsRecord> {
173    let (input, record) = be_u8(input)?;
174
175    Ok((input, ChangeOptionsRecord::from(record)))
176}
177
178fn fundamental_operational_data(input: &[u8]) -> IResult<&[u8], FundamentalOperationalData> {
179    let (input, system_status) = system_status(input)?;
180    let (input, data_field_1) = be_u8(input)?;
181    let (input, information_layers) = information_layers(input)?;
182    let (input, data_field_2) = be_u8(input)?;
183    let (input, parameter_1) = be_u16(input)?;
184    let (input, parameter_2) = be_u16(input)?;
185    let (input, parameter_3) = be_u16(input)?;
186    let (input, parameter_4) = be_u16(input)?;
187    let (input, parameter_5) = be_u16(input)?;
188    let (input, parameter_6) = be_u16(input)?;
189
190    Ok((
191        input,
192        FundamentalOperationalData::builder()
193            .with_system_status(system_status)
194            .with_data_field_1(data_field_1)
195            .with_information_layers(information_layers)
196            .with_data_field_2(data_field_2)
197            .with_parameter_1(parameter_1)
198            .with_parameter_2(parameter_2)
199            .with_parameter_3(parameter_3)
200            .with_parameter_4(parameter_4)
201            .with_parameter_5(parameter_5)
202            .with_parameter_6(parameter_6)
203            .build(),
204    ))
205}
206
207fn iff_data_record(input: &[u8]) -> IResult<&[u8], IffDataRecord> {
208    let (input, record_type) = be_u32(input)?;
209    let record_type = VariableRecordType::from(record_type);
210    let (input, record_length) = be_u16(input)?;
211    let (input, field) =
212        take(record_length.saturating_sub(BASE_IFF_DATA_RECORD_LENGTH_OCTETS))(input)?;
213
214    Ok((
215        input,
216        IffDataRecord::builder()
217            .with_record_type(record_type)
218            .with_record_specific_field(field.to_vec())
219            .build(),
220    ))
221}
222
223fn iff_data_specification(input: &[u8]) -> IResult<&[u8], IffDataSpecification> {
224    let (input, num_records) = be_u16(input)?;
225    let (input, records) = count(iff_data_record, num_records.into())(input)?;
226
227    Ok((
228        input,
229        IffDataSpecification::builder()
230            .with_iff_data_records(records)
231            .build(),
232    ))
233}
234
235fn information_layers(input: &[u8]) -> IResult<&[u8], InformationLayers> {
236    let (input, record) = be_u8(input)?;
237
238    Ok((input, InformationLayers::from(record)))
239}
240
241fn iff_fundamental_parameter_data(input: &[u8]) -> IResult<&[u8], IffFundamentalParameterData> {
242    let (input, erp) = be_f32(input)?;
243    let (input, frequency) = be_f32(input)?;
244    let (input, pgrf) = be_f32(input)?;
245    let (input, pulse_width) = be_f32(input)?;
246    let (input, burst_length) = be_f32(input)?;
247    let (input, applicable_modes) = be_u8(input)?;
248    let applicable_modes = IffApplicableModes::from(applicable_modes);
249    let (input, system_specific_data) = system_specific_data(input)?;
250
251    Ok((
252        input,
253        IffFundamentalParameterData::builder()
254            .with_erp(erp)
255            .with_frequency(frequency)
256            .with_pgrf(pgrf)
257            .with_pulse_width(pulse_width)
258            .with_burst_length(burst_length)
259            .with_applicable_modes(applicable_modes)
260            .with_system_specific_data(system_specific_data)
261            .build(),
262    ))
263}
264
265fn layer_header(input: &[u8]) -> IResult<&[u8], LayerHeader> {
266    let (input, layer_number) = be_u8(input)?;
267    let (input, layer_specific_information) = be_u8(input)?;
268    let (input, length) = be_u16(input)?;
269
270    Ok((
271        input,
272        LayerHeader::builder()
273            .with_layer_number(layer_number)
274            .with_layer_specific_information(layer_specific_information)
275            .with_length(length)
276            .build(),
277    ))
278}
279
280fn system_specific_data(input: &[u8]) -> IResult<&[u8], SystemSpecificData> {
281    let (input, part_1) = be_u8(input)?;
282    let (input, part_2) = be_u8(input)?;
283    let (input, part_3) = be_u8(input)?;
284
285    Ok((
286        input,
287        SystemSpecificData::builder()
288            .with_part_1(part_1)
289            .with_part_2(part_2)
290            .with_part_3(part_3)
291            .build(),
292    ))
293}
294
295fn system_id(input: &[u8]) -> IResult<&[u8], SystemId> {
296    let (input, system_type) = be_u16(input)?;
297    let system_type = IffSystemType::from(system_type);
298    let (input, system_name) = be_u16(input)?;
299    let system_name = IffSystemName::from(system_name);
300    let (input, system_mode) = be_u8(input)?;
301    let system_mode = IffSystemMode::from(system_mode);
302    let (input, change_options_record) = change_options_record(input)?;
303
304    Ok((
305        input,
306        SystemId::builder()
307            .with_system_type(system_type)
308            .with_system_name(system_name)
309            .with_system_mode(system_mode)
310            .with_change_options(change_options_record)
311            .build(),
312    ))
313}
314
315fn dap_source(input: &[u8]) -> IResult<&[u8], DapSource> {
316    let (input, record) = be_u8(input)?;
317
318    Ok((input, DapSource::from(record)))
319}
320
321impl From<u8> for DapValue {
322    fn from(value: u8) -> Self {
323        match value {
324            0 => DapValue::ComputeLocally,
325            _ => DapValue::DataRecordAvailable,
326        }
327    }
328}
329
330fn enhanced_mode_1_code(input: &[u8]) -> IResult<&[u8], EnhancedMode1Code> {
331    let (input, record) = be_u16(input)?;
332
333    Ok((input, EnhancedMode1Code::from(record)))
334}
335
336fn system_status(input: &[u8]) -> IResult<&[u8], SystemStatus> {
337    let (input, record) = be_u8(input)?;
338
339    Ok((input, SystemStatus::from(record)))
340}
341
342// TODO This bit of error handling the correct system type to parse is not that nice.
343#[allow(clippy::match_same_arms)]
344fn mode_5_basic_data(
345    system_type: &IffSystemType,
346) -> impl Fn(&[u8]) -> IResult<&[u8], Result<Mode5BasicData, DisError>> + '_ {
347    move |input: &[u8]| match system_type {
348        IffSystemType::MarkXXIIATCRBSTransponder
349        | IffSystemType::SovietTransponder
350        | IffSystemType::RRBTransponder
351        | IffSystemType::MarkXIIATransponder
352        | IffSystemType::Mode5Transponder
353        | IffSystemType::ModeSTransponder => {
354            let (input, basic_data) = mode_5_transponder_basic_data(input)?;
355            Ok((input, Ok(Mode5BasicData::Transponder(basic_data))))
356        }
357        IffSystemType::MarkXXIIATCRBSInterrogator
358        | IffSystemType::SovietInterrogator
359        | IffSystemType::MarkXIIAInterrogator
360        | IffSystemType::Mode5Interrogator
361        | IffSystemType::ModeSInterrogator => {
362            let (input, basic_data) = mode_5_interrogator_basic_data(input)?;
363            Ok((input, Ok(Mode5BasicData::Interrogator(basic_data))))
364        }
365        IffSystemType::MarkXIIACombinedInterrogatorTransponder_CIT_
366        | IffSystemType::MarkXIICombinedInterrogatorTransponder_CIT_
367        | IffSystemType::TCASACASTransceiver => {
368            Ok((input, Err(DisError::IffUndeterminedSystemType)))
369        }
370        IffSystemType::NotUsed_InvalidValue_ => Ok((input, Err(DisError::IffIncorrectSystemType))),
371        IffSystemType::Unspecified(_) => Ok((input, Err(DisError::IffIncorrectSystemType))),
372    }
373}
374
375fn mode_5_interrogator_basic_data(input: &[u8]) -> IResult<&[u8], Mode5InterrogatorBasicData> {
376    let (input, status) = mode_5_interrogator_status(input)?;
377    let (input, _padding) = be_u8(input)?;
378    let (input, _padding) = be_u16(input)?;
379    let (input, message_formats) = mode_5_message_formats(input)?;
380    let (input, entity_id) = entity_id(input)?;
381    let (input, _padding) = be_u16(input)?;
382
383    Ok((
384        input,
385        Mode5InterrogatorBasicData::builder()
386            .with_status(status)
387            .with_mode_5_message_formats_present(message_formats)
388            .with_interrogated_entity_id(entity_id)
389            .build(),
390    ))
391}
392
393fn mode_5_interrogator_status(input: &[u8]) -> IResult<&[u8], Mode5InterrogatorStatus> {
394    let (input, record) = be_u8(input)?;
395
396    Ok((input, Mode5InterrogatorStatus::from(record)))
397}
398
399fn mode_5_message_formats(input: &[u8]) -> IResult<&[u8], Mode5MessageFormats> {
400    let (input, record) = be_u32(input)?;
401
402    Ok((input, Mode5MessageFormats::from(record)))
403}
404
405fn mode_5_transponder_basic_data(input: &[u8]) -> IResult<&[u8], Mode5TransponderBasicData> {
406    let (input, status) = mode_5_transponder_status(input)?;
407    let (input, pin) = be_u16(input)?;
408    let (input, message_formats_present) = mode_5_message_formats(input)?;
409    let (input, enhanced_mode_1) = enhanced_mode_1_code(input)?;
410    let (input, national_origin) = be_u16(input)?;
411    let (input, supplemental_data) = mode_5_transponder_supplemental_data(input)?;
412    let (input, navigation_source) = be_u8(input)?;
413    let navigation_source = NavigationSource::from(navigation_source);
414    let (input, figure_of_merit) = be_u8(input)?;
415    let (input, _padding) = be_u8(input)?;
416
417    Ok((
418        input,
419        Mode5TransponderBasicData::builder()
420            .with_status(status)
421            .with_pin(pin)
422            .with_mode_5_message_formats_present(message_formats_present)
423            .with_enhanced_mode_1(enhanced_mode_1)
424            .with_national_origin(national_origin)
425            .with_supplemental_data(supplemental_data)
426            .with_navigation_source(navigation_source)
427            .with_figure_of_merit(figure_of_merit)
428            .build(),
429    ))
430}
431
432fn mode_5_transponder_supplemental_data(
433    input: &[u8],
434) -> IResult<&[u8], Mode5TransponderSupplementalData> {
435    let (input, record) = be_u8(input)?;
436
437    Ok((input, Mode5TransponderSupplementalData::from(record)))
438}
439
440fn mode_5_transponder_status(input: &[u8]) -> IResult<&[u8], Mode5TransponderStatus> {
441    let (input, record) = be_u16(input)?;
442
443    Ok((input, Mode5TransponderStatus::from(record)))
444}
445
446fn mode_s_altitude(input: &[u8]) -> IResult<&[u8], ModeSAltitude> {
447    let (input, record) = be_u16(input)?;
448
449    Ok((input, ModeSAltitude::from(record)))
450}
451
452// TODO This bit of error handling the correct system type to parse is not that nice.
453#[allow(clippy::match_same_arms)]
454fn mode_s_basic_data(
455    system_type: &IffSystemType,
456) -> impl Fn(&[u8]) -> IResult<&[u8], Result<ModeSBasicData, DisError>> + '_ {
457    move |input: &[u8]| match system_type {
458        IffSystemType::MarkXXIIATCRBSTransponder
459        | IffSystemType::SovietTransponder
460        | IffSystemType::RRBTransponder
461        | IffSystemType::MarkXIIATransponder
462        | IffSystemType::Mode5Transponder
463        | IffSystemType::ModeSTransponder => {
464            let (input, basic_data) = mode_s_transponder_basic_data(input)?;
465            Ok((input, Ok(ModeSBasicData::Transponder(basic_data))))
466        }
467        IffSystemType::MarkXXIIATCRBSInterrogator
468        | IffSystemType::SovietInterrogator
469        | IffSystemType::MarkXIIAInterrogator
470        | IffSystemType::Mode5Interrogator
471        | IffSystemType::ModeSInterrogator => {
472            let (input, basic_data) = mode_s_interrogator_basic_data(input)?;
473            Ok((input, Ok(ModeSBasicData::Interrogator(basic_data))))
474        }
475        IffSystemType::MarkXIIACombinedInterrogatorTransponder_CIT_
476        | IffSystemType::MarkXIICombinedInterrogatorTransponder_CIT_
477        | IffSystemType::TCASACASTransceiver => {
478            Ok((input, Err(DisError::IffUndeterminedSystemType)))
479        }
480        IffSystemType::NotUsed_InvalidValue_ => Ok((input, Err(DisError::IffIncorrectSystemType))),
481        IffSystemType::Unspecified(_) => Ok((input, Err(DisError::IffIncorrectSystemType))),
482    }
483}
484
485fn mode_s_interrogator_basic_data(input: &[u8]) -> IResult<&[u8], ModeSInterrogatorBasicData> {
486    const PAD_168_BITS_IN_OCTETS: usize = 21;
487
488    let (input, status) = mode_s_interrogator_status(input)?;
489    let (input, _padding_1_octet) = be_u8(input)?;
490    let (input, levels_present) = mode_s_levels_present(input)?;
491    let (input, _padding_21_octets) = take(PAD_168_BITS_IN_OCTETS)(input)?;
492
493    Ok((
494        input,
495        ModeSInterrogatorBasicData::builder()
496            .with_mode_s_interrogator_status(status)
497            .with_mode_s_levels_present(levels_present)
498            .build(),
499    ))
500}
501
502fn mode_s_interrogator_status(input: &[u8]) -> IResult<&[u8], ModeSInterrogatorStatus> {
503    let (input, record) = be_u8(input)?;
504
505    Ok((input, ModeSInterrogatorStatus::from(record)))
506}
507
508fn mode_s_levels_present(input: &[u8]) -> IResult<&[u8], ModeSLevelsPresent> {
509    let (input, record) = be_u8(input)?;
510
511    Ok((input, ModeSLevelsPresent::from(record)))
512}
513
514fn mode_s_transponder_basic_data(input: &[u8]) -> IResult<&[u8], ModeSTransponderBasicData> {
515    let (input, status) = mode_s_transponder_status(input)?;
516    let (input, levels_present) = mode_s_levels_present(input)?;
517    let (input, aircraft_present_domain) = be_u8(input)?;
518    let aircraft_present_domain = AircraftPresentDomain::from(aircraft_present_domain);
519
520    let mut buf: [u8; EIGHT_OCTETS] = [0; EIGHT_OCTETS];
521    let (input, ()) = nom::multi::fill(be_u8, &mut buf)(input)?;
522
523    let mut aircraft_id = String::from_utf8_lossy(&buf[..]).into_owned();
524    aircraft_id.truncate(
525        aircraft_id
526            .trim_end()
527            .trim_end_matches(|c: char| !c.is_alphanumeric())
528            .len(),
529    );
530
531    let (input, aircraft_address) = be_u32(input)?;
532    let (input, aircraft_identification_type) = be_u8(input)?;
533    let aircraft_identification_type =
534        AircraftIdentificationType::from(aircraft_identification_type);
535    let (input, dap_source) = dap_source(input)?;
536    let (input, altitude) = mode_s_altitude(input)?;
537    let (input, capability_report) = be_u8(input)?;
538    let capability_report = CapabilityReport::from(capability_report);
539
540    Ok((
541        input,
542        ModeSTransponderBasicData::builder()
543            .with_status(status)
544            .with_levels_present(levels_present)
545            .with_aircraft_present_domain(aircraft_present_domain)
546            .with_aircraft_identification(aircraft_id)
547            .with_aircraft_address(aircraft_address)
548            .with_aircraft_identification_type(aircraft_identification_type)
549            .with_dap_source(dap_source)
550            .with_altitude(altitude)
551            .with_capability_report(capability_report)
552            .build(),
553    ))
554}
555
556fn mode_s_transponder_status(input: &[u8]) -> IResult<&[u8], ModeSTransponderStatus> {
557    let (input, record) = be_u16(input)?;
558
559    Ok((input, ModeSTransponderStatus::from(record)))
560}
561
562impl From<u8> for OnOffStatus {
563    fn from(value: u8) -> Self {
564        match value {
565            0 => OnOffStatus::Off,
566            _ => OnOffStatus::On,
567        }
568    }
569}
570
571impl From<u8> for DamageStatus {
572    fn from(value: u8) -> Self {
573        match value {
574            0 => DamageStatus::NoDamage,
575            _ => DamageStatus::Damaged,
576        }
577    }
578}
579
580impl From<u8> for MalfunctionStatus {
581    fn from(value: u8) -> Self {
582        match value {
583            0 => MalfunctionStatus::NoMalfunction,
584            _ => MalfunctionStatus::Malfunction,
585        }
586    }
587}
588
589impl From<u8> for EnabledStatus {
590    fn from(value: u8) -> Self {
591        match value {
592            0 => EnabledStatus::NotEnabled,
593            _ => EnabledStatus::Enabled,
594        }
595    }
596}
597
598impl From<u8> for LatLonAltSource {
599    fn from(value: u8) -> Self {
600        match value {
601            0 => LatLonAltSource::ComputeLocally,
602            _ => LatLonAltSource::TransponderLocationDataRecordPresent,
603        }
604    }
605}
606
607impl From<u8> for IffPresence {
608    fn from(value: u8) -> Self {
609        match value {
610            0 => IffPresence::NotPresent,
611            _ => IffPresence::Present,
612        }
613    }
614}
615
616impl From<u8> for SquitterStatus {
617    fn from(value: u8) -> Self {
618        match value {
619            0 => SquitterStatus::Off,
620            _ => SquitterStatus::On,
621        }
622    }
623}
624
625impl From<u8> for ParameterCapable {
626    fn from(value: u8) -> Self {
627        match value {
628            0 => ParameterCapable::Capable,
629            _ => ParameterCapable::NotCapable,
630        }
631    }
632}
633
634impl From<u8> for OperationalStatus {
635    fn from(value: u8) -> Self {
636        match value {
637            0 => OperationalStatus::Operational,
638            _ => OperationalStatus::SystemFailed,
639        }
640    }
641}
642
643impl From<u8> for LayersPresenceApplicability {
644    fn from(value: u8) -> Self {
645        match value {
646            0 => LayersPresenceApplicability::NotPresentApplicable,
647            _ => LayersPresenceApplicability::PresentApplicable,
648        }
649    }
650}