dis-rs 0.13.0

An implementation of the Distributed Interactive Simulation protocol (IEEE-1278.1) in Rust. This main crate contains PDU implementations and facilities to read/write PDUs from Rust data structures to the wire format and vice versa. It supports versions 6 and 7 of the protocol.
Documentation
use crate::common::model::{PduBody, PduHeader};
use crate::common::parser::{entity_id, entity_type, location, orientation, vec3_f32};
use crate::common::transmitter::model::{
    BeamAntennaPattern, CryptoKeyId, ModulationType, SpreadSpectrum, Transmitter,
    VariableTransmitterParameter, BASE_VTP_RECORD_LENGTH,
};
use crate::enumerations::{
    ProtocolVersion, TransmitterAntennaPatternReferenceSystem, TransmitterAntennaPatternType,
    TransmitterCryptoSystem, TransmitterInputSource, TransmitterMajorModulation,
    TransmitterModulationTypeSystem, TransmitterTransmitState, VariableRecordType,
};
use crate::BodyRaw;
use nom::bytes::complete::take;
use nom::multi::count;
use nom::number::complete::{be_f32, be_u16, be_u32, be_u64, be_u8};
use nom::IResult;
use nom::Parser;

pub(crate) fn transmitter_body(
    header: &PduHeader,
) -> impl Fn(&[u8]) -> IResult<&[u8], PduBody> + '_ {
    move |input: &[u8]| {
        let (input, radio_reference_id) = entity_id(input)?;
        let (input, radio_number) = be_u16(input)?;
        let (input, radio_type) = entity_type(input)?;
        let (input, transmit_state) = be_u8(input)?;
        let transmit_state = TransmitterTransmitState::from(transmit_state);
        let (input, input_source) = be_u8(input)?;
        let input_source = TransmitterInputSource::from(input_source);
        #[allow(clippy::wildcard_in_or_patterns)]
        let (input, number_of_vtp) = {
            let (input, number_of_vtp) = be_u16(input)?;
            match header.protocol_version {
                ProtocolVersion::IEEE1278_12012 => (input, number_of_vtp),
                ProtocolVersion::IEEE1278_1A1998 | _ => {
                    (input, 0u16) // set to zeroed padding to prevent parsing of not present Variable Transmitter Parameters
                }
            }
        };
        let (input, antenna_location) = location(input)?;
        let (input, relative_antenna_location) = vec3_f32(input)?;
        let (input, antenna_pattern_type) = be_u16(input)?;
        let antenna_pattern_type = TransmitterAntennaPatternType::from(antenna_pattern_type);
        let (input, antenna_pattern_length) = be_u16(input)?;
        let (input, frequency) = be_u64(input)?;
        let (input, transmit_frequency_bandwidth) = be_f32(input)?;
        let (input, power) = be_f32(input)?;
        let (input, modulation_type) = modulation_type(input)?;
        let (input, crypto_system) = be_u16(input)?;
        let crypto_system = TransmitterCryptoSystem::from(crypto_system);
        let (input, crypto_key_id) = crypto_key_id(input)?;
        let (input, length_of_modulation_parameters) = be_u8(input)?;
        let (input, _padding) = be_u8(input)?;
        let (input, _padding) = be_u16(input)?;

        let (input, modulation_parameters) = if length_of_modulation_parameters > 0 {
            let (input, params) = take(length_of_modulation_parameters)(input)?;
            (input, Some(params))
        } else {
            (input, None)
        };
        let (input, antenna_pattern) = if antenna_pattern_length > 0 {
            let (input, pattern) = beam_antenna_pattern(input)?;
            (input, Some(pattern))
        } else {
            (input, None)
        };

        let (input, vt_params) =
            count(variable_transmitter_parameter, number_of_vtp.into()).parse(input)?;

        let body = Transmitter::builder()
            .with_radio_reference_id(radio_reference_id)
            .with_radio_number(radio_number)
            .with_radio_type(radio_type)
            .with_transmit_state(transmit_state)
            .with_input_source(input_source)
            .with_antenna_location(antenna_location)
            .with_relative_antenna_location(relative_antenna_location)
            .with_antenna_pattern_type(antenna_pattern_type)
            .with_frequency(frequency)
            .with_transmit_frequency_bandwidth(transmit_frequency_bandwidth)
            .with_power(power)
            .with_modulation_type(modulation_type)
            .with_crypto_system(crypto_system)
            .with_crypto_key_id(crypto_key_id)
            .with_variable_transmitter_parameters(vt_params);
        let body = if let Some(antenna_pattern) = antenna_pattern {
            body.with_antenna_pattern(antenna_pattern)
        } else {
            body
        };
        let body = if let Some(modulation_parameters) = modulation_parameters {
            body.with_modulation_parameters(modulation_parameters.to_vec())
        } else {
            body
        };
        let body = body.build();

        Ok((input, body.into_pdu_body()))
    }
}

fn modulation_type(input: &[u8]) -> IResult<&[u8], ModulationType> {
    let (input, spread_spectrum) = spread_spectrum(input)?;
    let (input, major_modulation) = be_u16(input)?;
    let (input, detail) = be_u16(input)?;
    let major_modulation =
        TransmitterMajorModulation::new_from_bytes_with_detail(major_modulation, detail);
    let (input, radio_system) = be_u16(input)?;
    let radio_system = TransmitterModulationTypeSystem::from(radio_system);

    Ok((
        input,
        ModulationType::new()
            .with_spread_spectrum(spread_spectrum)
            .with_major_modulation(major_modulation)
            .with_radio_system(radio_system),
    ))
}

fn spread_spectrum(input: &[u8]) -> IResult<&[u8], SpreadSpectrum> {
    let (input, spread_spectrum_values) = be_u16(input)?;

    Ok((input, SpreadSpectrum::from(spread_spectrum_values)))
}

fn crypto_key_id(input: &[u8]) -> IResult<&[u8], CryptoKeyId> {
    let (input, value) = be_u16(input)?;

    Ok((input, CryptoKeyId::from(value)))
}

fn beam_antenna_pattern(input: &[u8]) -> IResult<&[u8], BeamAntennaPattern> {
    let (input, beam_direction) = orientation(input)?;
    let (input, azimuth_beamwidth) = be_f32(input)?;
    let (input, elevation_beamwidth) = be_f32(input)?;
    let (input, reference_system) = be_u8(input)?;
    let reference_system = TransmitterAntennaPatternReferenceSystem::from(reference_system);
    let (input, _padding) = be_u8(input)?;
    let (input, _padding) = be_u16(input)?;
    let (input, e_z) = be_f32(input)?;
    let (input, e_x) = be_f32(input)?;
    let (input, phase) = be_f32(input)?;
    let (input, _padding) = be_u32(input)?;

    Ok((
        input,
        BeamAntennaPattern::new()
            .with_beam_direction(beam_direction)
            .with_azimuth_beamwidth(azimuth_beamwidth)
            .with_elevation_beamwidth(elevation_beamwidth)
            .with_reference_system(reference_system)
            .with_e_z(e_z)
            .with_e_x(e_x)
            .with_phase(phase),
    ))
}

fn variable_transmitter_parameter(input: &[u8]) -> IResult<&[u8], VariableTransmitterParameter> {
    let (input, record_type) = be_u32(input)?;
    let record_type = VariableRecordType::from(record_type);
    let (input, record_length) = be_u16(input)?;
    let fields_length_bytes = record_length - BASE_VTP_RECORD_LENGTH;
    let (input, specific_fields) = take(fields_length_bytes)(input)?;

    Ok((
        input,
        VariableTransmitterParameter::new()
            .with_record_type(record_type)
            .with_fields(specific_fields.to_vec()),
    ))
}