1use crate::acknowledge_r::parser::acknowledge_r_body;
2use crate::action_request_r::parser::action_request_r_body;
3use crate::action_response_r::parser::action_response_r_body;
4use crate::aggregate_state::parser::aggregate_state_body;
5use crate::comment_r::parser::comment_r_body;
6use crate::common::acknowledge::parser::acknowledge_body;
7use crate::common::action_request::parser::action_request_body;
8use crate::common::action_response::parser::action_response_body;
9use crate::common::attribute::parser::attribute_body;
10use crate::common::collision::parser::collision_body;
11use crate::common::collision_elastic::parser::collision_elastic_body;
12use crate::common::comment::parser::comment_body;
13use crate::common::create_entity::parser::create_entity_body;
14use crate::common::data::parser::data_body;
15use crate::common::data_query::parser::data_query_body;
16use crate::common::designator::parser::designator_body;
17use crate::common::detonation::parser::detonation_body;
18use crate::common::electromagnetic_emission::parser::emission_body;
19use crate::common::entity_state::parser::entity_state_body;
20use crate::common::entity_state_update::parser::entity_state_update_body;
21use crate::common::errors::DisError;
22use crate::common::event_report::parser::event_report_body;
23use crate::common::fire::parser::fire_body;
24use crate::common::iff::parser::iff_body;
25use crate::common::model::{
26 length_padded_to_num, ArticulatedPart, AttachedPart, BeamData, ClockTime, DatumSpecification,
27 DescriptorRecord, EntityAssociationParameter, EntityId, EntityType, EntityTypeParameter,
28 EventId, FixedDatum, Location, MunitionDescriptor, Orientation, Pdu, PduBody, PduHeader,
29 SeparationParameter, SimulationAddress, VariableDatum, VariableParameter, VectorF32,
30};
31use crate::common::other::parser::other_body;
32use crate::common::receiver::parser::receiver_body;
33use crate::common::remove_entity::parser::remove_entity_body;
34use crate::common::set_data::parser::set_data_body;
35use crate::common::signal::parser::signal_body;
36use crate::common::start_resume::parser::start_resume_body;
37use crate::common::stop_freeze::parser::stop_freeze_body;
38use crate::common::transmitter::parser::transmitter_body;
39use crate::constants::{
40 EIGHT_OCTETS, FIVE_LEAST_SIGNIFICANT_BITS, ONE_BYTE_IN_BITS, PDU_HEADER_LEN_BYTES,
41};
42use crate::create_entity_r::parser::create_entity_r_body;
43use crate::data_query_r::parser::data_query_r_body;
44use crate::data_r::parser::data_r_body;
45use crate::enumerations::{
46 ArticulatedPartsTypeClass, ArticulatedPartsTypeMetric, AttachedPartDetachedIndicator,
47 AttachedParts, ChangeIndicator, EntityAssociationAssociationStatus,
48 EntityAssociationGroupMemberType, EntityAssociationPhysicalAssociationType,
49 EntityAssociationPhysicalConnectionType, SeparationPreEntityIndicator,
50 SeparationReasonForSeparation, VariableParameterRecordType,
51};
52use crate::enumerations::{
53 Country, DetonationTypeIndicator, EntityKind, ExplosiveMaterialCategories, FireTypeIndicator,
54 MunitionDescriptorFuse, MunitionDescriptorWarhead, PduType, PlatformDomain, ProtocolFamily,
55 ProtocolVersion, StationName, VariableRecordType,
56};
57use crate::event_report_r::parser::event_report_r_body;
58use crate::is_group_of::parser::is_group_of_body;
59use crate::is_part_of::parser::is_part_of_body;
60use crate::model::{RecordSet, RecordSpecification, SupplyQuantity};
61use crate::record_query_r::parser::record_query_r_body;
62use crate::record_r::parser::record_r_body;
63use crate::remove_entity_r::parser::remove_entity_r_body;
64use crate::repair_complete::parser::repair_complete_body;
65use crate::repair_response::parser::repair_response_body;
66use crate::resupply_cancel::parser::resupply_cancel_body;
67use crate::resupply_offer::parser::resupply_offer_body;
68use crate::resupply_received::parser::resupply_received_body;
69use crate::sees::parser::sees_body;
70use crate::service_request::parser::service_request_body;
71use crate::set_data_r::parser::set_data_r_body;
72use crate::set_record_r::parser::set_record_r_body;
73use crate::start_resume_r::parser::start_resume_r_body;
74use crate::stop_freeze_r::parser::stop_freeze_r_body;
75use crate::transfer_ownership::parser::transfer_ownership_body;
76use crate::underwater_acoustic::parser::underwater_acoustic_body;
77use crate::v7::parser::parse_pdu_status;
78use nom::bytes::complete::take;
79use nom::combinator::peek;
80use nom::error::ErrorKind::Eof;
81use nom::multi::{count, many1};
82use nom::number::complete::{be_f32, be_f64, be_i32, be_u16, be_u32, be_u64, be_u8};
83use nom::sequence::tuple;
84use nom::Err;
85use nom::IResult;
86
87pub(crate) fn parse_multiple_pdu(input: &[u8]) -> Result<Vec<Pdu>, DisError> {
88 match many1(pdu)(input) {
89 Ok((_, pdus)) => Ok(pdus),
90 Err(err) => Err(DisError::ParseError(err.to_string())), }
92}
93
94#[allow(dead_code)]
95pub(crate) fn parse_pdu(input: &[u8]) -> Result<Pdu, DisError> {
96 match pdu(input) {
97 Ok((_, pdu)) => Ok(pdu),
98 Err(err) => Err(DisError::ParseError(err.to_string())), }
100}
101
102#[allow(dead_code)]
103pub(crate) fn parse_multiple_header(input: &[u8]) -> Result<Vec<PduHeader>, DisError> {
104 match many1(pdu_header_skip_body)(input) {
105 Ok((_, headers)) => Ok(headers),
106 Err(parse_error) => {
107 if let Err::Error(ref error) = parse_error {
108 if error.code == Eof {
109 return Err(DisError::InsufficientHeaderLength(input.len() as u16));
110 }
111 }
112 Err(DisError::ParseError(parse_error.to_string()))
113 }
114 }
115}
116
117#[allow(dead_code)]
119pub(crate) fn parse_header(input: &[u8]) -> Result<PduHeader, DisError> {
120 match pdu_header(input) {
121 Ok((input, header)) => {
122 let skipped = skip_body(header.pdu_length)(input); if let Err(Err::Error(error)) = skipped {
124 return if error.code == Eof {
125 Err(DisError::InsufficientPduLength(
126 header.pdu_length - PDU_HEADER_LEN_BYTES,
127 input.len() as u16,
128 ))
129 } else {
130 Err(DisError::ParseError(
131 "ParseError while parsing a pdu header and skipping body.".to_string(),
132 ))
133 };
134 }
135 Ok(header)
136 }
137 Err(parse_error) => {
138 if let Err::Error(ref error) = parse_error {
139 if error.code == Eof {
140 return Err(DisError::InsufficientHeaderLength(input.len() as u16));
141 }
142 }
143 Err(DisError::ParseError(parse_error.to_string()))
144 }
145 }
146}
147
148fn pdu(input: &[u8]) -> IResult<&[u8], Pdu> {
149 let (input, header) = pdu_header(input)?;
151
152 let (input, body) = pdu_body(&header)(input)?;
160
161 Ok((input, Pdu { header, body }))
162}
163
164fn pdu_header(input: &[u8]) -> IResult<&[u8], PduHeader> {
165 let protocol_version = protocol_version;
166 let exercise_id = be_u8;
167 let pdu_type = pdu_type;
168 let protocol_family = protocol_family;
169 let time_stamp = be_u32;
170 let pdu_length = be_u16;
171
172 let (input, (protocol_version, exercise_id, pdu_type, protocol_family, time_stamp, pdu_length)) =
173 tuple((
174 protocol_version,
175 exercise_id,
176 pdu_type,
177 protocol_family,
178 time_stamp,
179 pdu_length,
180 ))(input)?;
181 let (input, pdu_status, padding) = match u8::from(protocol_version) {
182 legacy_version if (1..=5).contains(&legacy_version) => {
183 let (input, padding) = be_u16(input)?;
184 (input, None, padding)
185 }
186 6 => {
187 let (input, padding) = be_u16(input)?;
188 (input, None, padding)
189 }
190 7 => {
191 let (input, (status, padding)) = parse_pdu_status(pdu_type)(input)?;
192 (input, Some(status), padding)
193 }
194 _future_version => {
195 let (input, (status, padding)) = parse_pdu_status(pdu_type)(input)?;
196 (input, Some(status), padding)
197 }
198 };
199
200 Ok((
201 input,
202 PduHeader {
203 protocol_version,
204 exercise_id,
205 pdu_type,
206 protocol_family,
207 time_stamp,
208 pdu_length,
209 pdu_status,
210 padding,
211 },
212 ))
213}
214
215#[allow(dead_code)]
216fn pdu_header_skip_body(input: &[u8]) -> IResult<&[u8], PduHeader> {
217 let (input, header) = pdu_header(input)?;
218 let (input, _) = skip_body(header.pdu_length)(input)?;
219 Ok((input, header))
220}
221
222fn pdu_body(header: &PduHeader) -> impl Fn(&[u8]) -> IResult<&[u8], PduBody> + '_ {
223 move |input: &[u8]| {
224 let (input, body) = match header.pdu_type {
227 PduType::Other => other_body(header)(input)?,
228 PduType::EntityState => entity_state_body(header)(input)?,
229 PduType::Fire => fire_body(header)(input)?,
230 PduType::Detonation => detonation_body(header)(input)?,
231 PduType::Collision => collision_body(input)?,
232 PduType::ServiceRequest => service_request_body(input)?,
233 PduType::ResupplyOffer => resupply_offer_body(input)?,
234 PduType::ResupplyReceived => resupply_received_body(input)?,
235 PduType::ResupplyCancel => resupply_cancel_body(input)?,
236 PduType::RepairComplete => repair_complete_body(input)?,
237 PduType::RepairResponse => repair_response_body(input)?,
238 PduType::CreateEntity => create_entity_body(input)?,
239 PduType::RemoveEntity => remove_entity_body(input)?,
240 PduType::StartResume => start_resume_body(input)?,
241 PduType::StopFreeze => stop_freeze_body(input)?,
242 PduType::Acknowledge => acknowledge_body(input)?,
243 PduType::ActionRequest => action_request_body(input)?,
244 PduType::ActionResponse => action_response_body(input)?,
245 PduType::DataQuery => data_query_body(input)?,
246 PduType::SetData => set_data_body(input)?,
247 PduType::Data => data_body(input)?,
248 PduType::EventReport => event_report_body(input)?,
249 PduType::Comment => comment_body(input)?,
250 PduType::ElectromagneticEmission => emission_body(header)(input)?,
251 PduType::Designator => designator_body(input)?,
252 PduType::Transmitter => transmitter_body(header)(input)?,
253 PduType::Signal => signal_body(input)?,
254 PduType::Receiver => receiver_body(input)?,
255 PduType::IFF => iff_body(input)?,
256 PduType::UnderwaterAcoustic => underwater_acoustic_body(input)?,
257 PduType::SupplementalEmissionEntityState => sees_body(input)?,
258 PduType::AggregateState => aggregate_state_body(input)?,
261 PduType::IsGroupOf => is_group_of_body(input)?,
262 PduType::TransferOwnership => transfer_ownership_body(input)?,
263 PduType::IsPartOf => is_part_of_body(input)?,
264 PduType::CreateEntityR => create_entity_r_body(input)?,
279 PduType::RemoveEntityR => remove_entity_r_body(input)?,
280 PduType::StartResumeR => start_resume_r_body(input)?,
281 PduType::StopFreezeR => stop_freeze_r_body(input)?,
282 PduType::AcknowledgeR => acknowledge_r_body(input)?,
283 PduType::ActionRequestR => action_request_r_body(input)?,
284 PduType::ActionResponseR => action_response_r_body(input)?,
285 PduType::DataQueryR => data_query_r_body(input)?,
286 PduType::SetDataR => set_data_r_body(input)?,
287 PduType::DataR => data_r_body(input)?,
288 PduType::EventReportR => event_report_r_body(input)?,
289 PduType::CommentR => comment_r_body(input)?,
290 PduType::RecordR => record_r_body(input)?,
291 PduType::SetRecordR => set_record_r_body(input)?,
292 PduType::RecordQueryR => record_query_r_body(input)?,
293 PduType::CollisionElastic => collision_elastic_body(input)?,
294 PduType::EntityStateUpdate => entity_state_update_body(input)?,
295 PduType::Attribute => attribute_body(input)?,
300 PduType::Unspecified(_type_number) => other_body(header)(input)?, _ => other_body(header)(input)?,
302 };
303 Ok((input, body))
304 }
305}
306
307#[allow(dead_code)]
308pub(crate) fn parse_peek_protocol_version(input: &[u8]) -> Result<ProtocolVersion, DisError> {
309 let parse_result = peek_protocol_version(input);
310 match parse_result {
311 Ok((_, protocol_version)) => Ok(ProtocolVersion::from(protocol_version)),
312 Err(err) => Err(DisError::ParseError(err.to_string())),
313 }
314}
315
316#[allow(dead_code)]
319fn peek_protocol_version(input: &[u8]) -> IResult<&[u8], u8> {
320 let (input, protocol_version) = peek(be_u8)(input)?;
321 Ok((input, protocol_version))
322}
323
324pub(crate) fn protocol_version(input: &[u8]) -> IResult<&[u8], ProtocolVersion> {
325 let (input, protocol_version) = be_u8(input)?;
326 let protocol_version = ProtocolVersion::from(protocol_version);
327 Ok((input, protocol_version))
328}
329
330pub(crate) fn pdu_type(input: &[u8]) -> IResult<&[u8], PduType> {
331 let (input, pdu_type) = be_u8(input)?;
332 let pdu_type = PduType::from(pdu_type);
333 Ok((input, pdu_type))
334}
335
336pub(crate) fn protocol_family(input: &[u8]) -> IResult<&[u8], ProtocolFamily> {
337 let (input, protocol_family) = be_u8(input)?;
338 let protocol_family = ProtocolFamily::from(protocol_family);
339 Ok((input, protocol_family))
340}
341
342#[allow(dead_code)]
345pub(crate) fn skip_body(total_bytes: u16) -> impl Fn(&[u8]) -> IResult<&[u8], &[u8]> {
346 let bytes_to_skip = total_bytes.saturating_sub(PDU_HEADER_LEN_BYTES);
353 move |input| take(bytes_to_skip)(input)
354}
355
356pub(crate) fn simulation_address(input: &[u8]) -> IResult<&[u8], SimulationAddress> {
357 let (input, site_id) = be_u16(input)?;
358 let (input, application_id) = be_u16(input)?;
359 Ok((input, SimulationAddress::new(site_id, application_id)))
360}
361
362pub(crate) fn entity_id(input: &[u8]) -> IResult<&[u8], EntityId> {
363 let (input, simulation_address) = simulation_address(input)?;
364 let (input, entity_id) = be_u16(input)?;
365 Ok((
366 input,
367 EntityId {
368 simulation_address,
369 entity_id,
370 },
371 ))
372}
373
374pub(crate) fn entity_type(input: &[u8]) -> IResult<&[u8], EntityType> {
375 let (input, kind) = kind(input)?;
376 let (input, domain) = domain(input)?;
377 let (input, country) = country(input)?;
378 let (input, category) = be_u8(input)?;
379 let (input, subcategory) = be_u8(input)?;
380 let (input, specific) = be_u8(input)?;
381 let (input, extra) = be_u8(input)?;
382 Ok((
383 input,
384 EntityType {
385 kind,
386 domain,
387 country,
388 category,
389 subcategory,
390 specific,
391 extra,
392 },
393 ))
394}
395
396fn kind(input: &[u8]) -> IResult<&[u8], EntityKind> {
397 let (input, kind) = be_u8(input)?;
398 let kind = EntityKind::from(kind);
399 Ok((input, kind))
400}
401
402fn domain(input: &[u8]) -> IResult<&[u8], PlatformDomain> {
403 let (input, domain) = be_u8(input)?;
404 let domain = PlatformDomain::from(domain);
405 Ok((input, domain))
406}
407
408fn country(input: &[u8]) -> IResult<&[u8], Country> {
409 let (input, country) = be_u16(input)?;
410 let country = Country::from(country);
411 Ok((input, country))
412}
413
414pub(crate) fn vec3_f32(input: &[u8]) -> IResult<&[u8], VectorF32> {
415 let (input, elements) = count(be_f32, 3)(input)?;
416 #[allow(clippy::get_first)]
417 Ok((
418 input,
419 VectorF32 {
420 first_vector_component: *elements
421 .get(0)
422 .expect("Value supposed to be parsed successfully"),
423 second_vector_component: *elements
424 .get(1)
425 .expect("Value supposed to be parsed successfully"),
426 third_vector_component: *elements
427 .get(2)
428 .expect("Value supposed to be parsed successfully"),
429 },
430 ))
431}
432
433pub(crate) fn location(input: &[u8]) -> IResult<&[u8], Location> {
434 let (input, locations) = count(be_f64, 3)(input)?;
435 #[allow(clippy::get_first)]
436 Ok((
437 input,
438 Location {
439 x_coordinate: *locations
440 .get(0)
441 .expect("Value supposed to be parsed successfully"),
442 y_coordinate: *locations
443 .get(1)
444 .expect("Value supposed to be parsed successfully"),
445 z_coordinate: *locations
446 .get(2)
447 .expect("Value supposed to be parsed successfully"),
448 },
449 ))
450}
451
452pub(crate) fn orientation(input: &[u8]) -> IResult<&[u8], Orientation> {
453 let (input, orientations) = count(be_f32, 3)(input)?;
454 #[allow(clippy::get_first)]
455 Ok((
456 input,
457 Orientation {
458 psi: *orientations
459 .get(0)
460 .expect("Value supposed to be parsed successfully"),
461 theta: *orientations
462 .get(1)
463 .expect("Value supposed to be parsed successfully"),
464 phi: *orientations
465 .get(2)
466 .expect("Value supposed to be parsed successfully"),
467 },
468 ))
469}
470
471pub(crate) fn event_id(input: &[u8]) -> IResult<&[u8], EventId> {
472 let (input, site_id) = be_u16(input)?;
473 let (input, application_id) = be_u16(input)?;
474 let (input, event_id) = be_u16(input)?;
475 Ok((
476 input,
477 EventId {
478 simulation_address: SimulationAddress {
479 site_id,
480 application_id,
481 },
482 event_id,
483 },
484 ))
485}
486
487pub(crate) fn descriptor_record_fti(
488 fire_type_indicator: FireTypeIndicator,
489) -> impl Fn(&[u8]) -> IResult<&[u8], DescriptorRecord> {
490 move |input: &[u8]| {
491 let (input, entity_type) = entity_type(input)?;
492
493 match fire_type_indicator {
494 FireTypeIndicator::Munition => {
495 let (input, munition) = munition_descriptor(input)?;
496
497 Ok((
498 input,
499 DescriptorRecord::Munition {
500 entity_type,
501 munition,
502 },
503 ))
504 }
505 FireTypeIndicator::Expendable => {
506 let (input, _pad_out) = be_u64(input)?;
507
508 Ok((input, DescriptorRecord::Expendable { entity_type }))
509 }
510 FireTypeIndicator::Unspecified(_) => {
511 let (input, _pad_out) = be_u64(input)?;
513
514 Ok((input, DescriptorRecord::Expendable { entity_type }))
515 }
516 }
517 }
518}
519
520pub(crate) fn descriptor_record_dti(
521 detonation_type_indicator: DetonationTypeIndicator,
522) -> impl Fn(&[u8]) -> IResult<&[u8], DescriptorRecord> {
523 move |input: &[u8]| {
524 let (input, entity_type) = entity_type(input)?;
525 match detonation_type_indicator {
526 DetonationTypeIndicator::Munition => {
527 let (input, munition) = munition_descriptor(input)?;
528
529 Ok((
530 input,
531 DescriptorRecord::Munition {
532 entity_type,
533 munition,
534 },
535 ))
536 }
537 DetonationTypeIndicator::Expendable => {
538 let (input, _pad_out) = be_u64(input)?;
539 Ok((input, DescriptorRecord::Expendable { entity_type }))
540 }
541 DetonationTypeIndicator::NonmunitionExplosion => {
542 let (input, explosive_material) = be_u16(input)?;
543 let explosive_material = ExplosiveMaterialCategories::from(explosive_material);
544 let (input, explosive_force) = be_f32(input)?;
545
546 Ok((
547 input,
548 DescriptorRecord::Explosion {
549 entity_type,
550 explosive_material,
551 explosive_force,
552 },
553 ))
554 }
555 DetonationTypeIndicator::Unspecified(_) => {
556 let (input, _pad_out) = be_u64(input)?;
558 Ok((input, DescriptorRecord::Expendable { entity_type }))
559 }
560 }
561 }
562}
563
564pub(crate) fn munition_descriptor(input: &[u8]) -> IResult<&[u8], MunitionDescriptor> {
565 let (input, warhead) = warhead(input)?;
566 let (input, fuse) = fuse(input)?;
567 let (input, quantity) = be_u16(input)?;
568 let (input, rate) = be_u16(input)?;
569
570 Ok((
571 input,
572 MunitionDescriptor {
573 warhead,
574 fuse,
575 quantity,
576 rate,
577 },
578 ))
579}
580
581fn warhead(input: &[u8]) -> IResult<&[u8], MunitionDescriptorWarhead> {
582 let (input, warhead) = be_u16(input)?;
583 let warhead = MunitionDescriptorWarhead::from(warhead);
584 Ok((input, warhead))
585}
586
587fn fuse(input: &[u8]) -> IResult<&[u8], MunitionDescriptorFuse> {
588 let (input, fuse) = be_u16(input)?;
589 let fuse = MunitionDescriptorFuse::from(fuse);
590 Ok((input, fuse))
591}
592
593pub(crate) fn clock_time(input: &[u8]) -> IResult<&[u8], ClockTime> {
594 let (input, hour) = be_i32(input)?;
595 let (input, time_past_hour) = be_u32(input)?;
596 let time = ClockTime::new(hour, time_past_hour);
597 Ok((input, time))
598}
599
600pub(crate) fn datum_specification(input: &[u8]) -> IResult<&[u8], DatumSpecification> {
601 let (input, num_fixed_datums) = be_u32(input)?;
602 let (input, num_variable_datums) = be_u32(input)?;
603
604 let (input, fixed_datums) = count(fixed_datum, num_fixed_datums as usize)(input)?;
605 let (input, variable_datums) = count(variable_datum, num_variable_datums as usize)(input)?;
606
607 let datums = DatumSpecification::new(fixed_datums, variable_datums);
608
609 Ok((input, datums))
610}
611
612pub(crate) fn fixed_datum(input: &[u8]) -> IResult<&[u8], FixedDatum> {
613 let (input, datum_id) = be_u32(input)?;
614 let (input, datum_value) = be_u32(input)?;
615
616 let datum_id = VariableRecordType::from(datum_id);
617 let datum = FixedDatum::new(datum_id, datum_value);
618
619 Ok((input, datum))
620}
621
622pub(crate) fn variable_datum(input: &[u8]) -> IResult<&[u8], VariableDatum> {
623 let (input, datum_id) = be_u32(input)?;
624 let datum_id = VariableRecordType::from(datum_id);
625 let (input, datum_length_bits) = be_u32(input)?;
626
627 let datum_length_bytes = datum_length_bits as usize / ONE_BYTE_IN_BITS;
631 let padded_record = length_padded_to_num(datum_length_bytes, EIGHT_OCTETS);
632
633 let (input, datum_value) = take(padded_record.data_length)(input)?;
634 let (input, _datum_padding) = take(padded_record.padding_length)(input)?;
635
636 let variable_datum = VariableDatum::new(datum_id, datum_value.to_vec());
637
638 Ok((input, variable_datum))
639}
640
641pub(crate) fn variable_parameter(input: &[u8]) -> IResult<&[u8], VariableParameter> {
642 let (input, parameter_type_designator) = be_u8(input)?;
643 let parameter_type = VariableParameterRecordType::from(parameter_type_designator);
644 let (input, variable_parameter) = match parameter_type {
645 VariableParameterRecordType::ArticulatedPart => articulated_part(input)?,
646 VariableParameterRecordType::AttachedPart => attached_part(input)?,
647 VariableParameterRecordType::Separation => separation(input)?,
648 VariableParameterRecordType::EntityType => entity_type_variable_parameter(input)?,
649 VariableParameterRecordType::EntityAssociation => entity_association(input)?,
650 VariableParameterRecordType::Unspecified(_) => {
651 let (input, bytes) = take(15usize)(input)?;
652 (
653 input,
654 VariableParameter::Unspecified(
655 parameter_type_designator,
656 <[u8; 15]>::try_from(bytes).unwrap(),
657 ),
658 )
659 } };
661
662 Ok((input, variable_parameter))
663}
664
665fn articulated_part(input: &[u8]) -> IResult<&[u8], VariableParameter> {
667 let (input, change_indicator) = be_u8(input)?;
668 let change_indicator = ChangeIndicator::from(change_indicator);
669 let (input, attachment_id) = be_u16(input)?;
670 let (input, parameter_type) = be_u32(input)?; let type_metric: u32 = parameter_type & FIVE_LEAST_SIGNIFICANT_BITS; let type_class: u32 = parameter_type - type_metric; let (input, value) = be_f32(input)?;
674 let (input, _pad_out) = be_u32(input)?;
675
676 Ok((
677 input,
678 VariableParameter::Articulated(ArticulatedPart {
679 change_indicator,
680 attachment_id,
681 type_metric: ArticulatedPartsTypeMetric::from(type_metric),
682 type_class: ArticulatedPartsTypeClass::from(type_class),
683 parameter_value: value,
684 }),
685 ))
686}
687
688fn attached_part(input: &[u8]) -> IResult<&[u8], VariableParameter> {
689 let (input, detached_indicator) = be_u8(input)?;
690 let detached_indicator = AttachedPartDetachedIndicator::from(detached_indicator);
691 let (input, attachment_id) = be_u16(input)?;
692 let (input, attached_part) = be_u32(input)?;
693 let (input, entity_type) = entity_type(input)?;
694
695 Ok((
696 input,
697 VariableParameter::Attached(AttachedPart {
698 detached_indicator,
699 attachment_id,
700 parameter_type: AttachedParts::from(attached_part),
701 attached_part_type: entity_type,
702 }),
703 ))
704}
705
706fn entity_association(input: &[u8]) -> IResult<&[u8], VariableParameter> {
707 let (input, change_indicator) = be_u8(input)?;
708 let (input, association_status) = be_u8(input)?;
709 let (input, association_type) = be_u8(input)?;
710 let (input, entity_id) = entity_id(input)?;
711 let (input, own_station_location) = be_u16(input)?;
712 let (input, physical_connection_type) = be_u8(input)?;
713 let (input, group_member_type) = be_u8(input)?;
714 let (input, group_number) = be_u16(input)?;
715
716 Ok((
717 input,
718 VariableParameter::EntityAssociation(EntityAssociationParameter {
719 change_indicator: ChangeIndicator::from(change_indicator),
720 association_status: EntityAssociationAssociationStatus::from(association_status),
721 association_type: EntityAssociationPhysicalAssociationType::from(association_type),
722 entity_id,
723 own_station_location: StationName::from(own_station_location),
724 physical_connection_type: EntityAssociationPhysicalConnectionType::from(
725 physical_connection_type,
726 ),
727 group_member_type: EntityAssociationGroupMemberType::from(group_member_type),
728 group_number,
729 }),
730 ))
731}
732
733fn entity_type_variable_parameter(input: &[u8]) -> IResult<&[u8], VariableParameter> {
734 let (input, change_indicator) = be_u8(input)?;
735 let (input, entity_type) = entity_type(input)?;
736 let (input, _pad_out_16) = be_u16(input)?;
737 let (input, _pad_out_32) = be_u32(input)?;
738
739 Ok((
740 input,
741 VariableParameter::EntityType(EntityTypeParameter {
742 change_indicator: ChangeIndicator::from(change_indicator),
743 entity_type,
744 }),
745 ))
746}
747
748fn separation(input: &[u8]) -> IResult<&[u8], VariableParameter> {
749 let (input, reason) = be_u8(input)?;
750 let (input, pre_entity_indicator) = be_u8(input)?;
751 let (input, parent_entity_id) = entity_id(input)?;
752 let (input, _pad_16) = be_u16(input)?;
753 let (input, station_name) = be_u16(input)?;
754 let (input, station_number) = be_u16(input)?;
755
756 Ok((
757 input,
758 VariableParameter::Separation(SeparationParameter {
759 reason: SeparationReasonForSeparation::from(reason),
760 pre_entity_indicator: SeparationPreEntityIndicator::from(pre_entity_indicator),
761 parent_entity_id,
762 station_name: StationName::from(station_name),
763 station_number,
764 }),
765 ))
766}
767
768pub(crate) fn beam_data(input: &[u8]) -> IResult<&[u8], BeamData> {
769 let (input, azimuth_center) = be_f32(input)?;
770 let (input, azimuth_sweep) = be_f32(input)?;
771 let (input, elevation_center) = be_f32(input)?;
772 let (input, elevation_sweep) = be_f32(input)?;
773 let (input, sweep_sync) = be_f32(input)?;
774
775 let data = BeamData::new()
776 .with_azimuth_center(azimuth_center)
777 .with_azimuth_sweep(azimuth_sweep)
778 .with_elevation_center(elevation_center)
779 .with_elevation_sweep(elevation_sweep)
780 .with_sweep_sync(sweep_sync);
781
782 Ok((input, data))
783}
784
785pub(crate) fn supply_quantity(input: &[u8]) -> IResult<&[u8], SupplyQuantity> {
786 let (input, supply_type) = entity_type(input)?;
787 let (input, quantity) = be_f32(input)?;
788
789 Ok((
790 input,
791 SupplyQuantity::default()
792 .with_supply_type(supply_type)
793 .with_quantity(quantity),
794 ))
795}
796
797pub(crate) fn record_specification(input: &[u8]) -> IResult<&[u8], RecordSpecification> {
799 let (input, number_of_records) = be_u32(input)?;
800 let (input, record_sets) = count(record_set, number_of_records as usize)(input)?;
801
802 Ok((
803 input,
804 RecordSpecification::default().with_record_sets(record_sets),
805 ))
806}
807
808pub(crate) fn record_set(input: &[u8]) -> IResult<&[u8], RecordSet> {
814 let (input, record_id) = be_u32(input)?;
815 let record_id = VariableRecordType::from(record_id);
816 let (input, serial_number) = be_u32(input)?;
817 let (input, _padding) = be_u32(input)?;
818 let (input, record_length_bits) = be_u16(input)?;
819 let record_length_bytes = ceil_bits_to_bytes(record_length_bits);
820 let (input, record_count) = be_u16(input)?;
821 let (input, record_values): (&[u8], Vec<&[u8]>) =
822 count(take(record_length_bytes), record_count as usize)(input)?;
823 let record_values = record_values.iter().map(|values| values.to_vec()).collect();
824 let padded_record_length =
825 length_padded_to_num((record_length_bytes * record_count) as usize, EIGHT_OCTETS);
826 let (input, _padding) = take(padded_record_length.padding_length)(input)?;
827
828 Ok((
829 input,
830 RecordSet::default()
831 .with_record_id(record_id)
832 .with_record_serial_number(serial_number)
833 .with_records(record_values),
834 ))
835}
836
837pub(crate) fn sanitize_marking(buf: &[u8]) -> String {
841 let mut marking_string = String::from_utf8_lossy(buf).into_owned();
842 marking_string.truncate(
843 marking_string
844 .trim_end()
845 .trim_end_matches(|c: char| !c.is_alphanumeric())
846 .len(),
847 );
848
849 marking_string
850}
851
852fn ceil_bits_to_bytes(bits: u16) -> u16 {
856 bits.div_ceil(ONE_BYTE_IN_BITS as u16)
857}
858
859#[cfg(test)]
860mod tests {
861 use crate::common::errors::DisError;
862 use crate::common::parser::{parse_multiple_header, skip_body};
863 use crate::constants::PDU_HEADER_LEN_BYTES;
864 use crate::enumerations::{PduType, ProtocolFamily, ProtocolVersion};
865
866 #[test]
867 fn parse_header() {
868 let bytes: [u8; 12] = [
869 0x06, 0x01, 0x01, 0x01, 0x4e, 0xea, 0x3b, 0x60, 0x00, 0x0c, 0x00, 0x00,
870 ];
871
872 let header = crate::common::parser::parse_header(&bytes);
873 assert!(header.is_ok());
874 let header = header.unwrap();
875 assert_eq!(header.protocol_version, ProtocolVersion::IEEE1278_1A1998);
876 assert_eq!(header.exercise_id, 1);
877 assert_eq!(header.pdu_type, PduType::EntityState);
878 assert_eq!(
879 header.protocol_family,
880 ProtocolFamily::EntityInformationInteraction
881 );
882 assert_eq!(header.time_stamp, 1_323_973_472);
883 assert_eq!(header.pdu_length, { PDU_HEADER_LEN_BYTES }); }
885
886 #[test]
887 fn parse_header_too_short() {
888 let bytes: [u8; 10] = [0x06, 0x01, 0x01, 0x01, 0x4e, 0xea, 0x3b, 0x60, 0x00, 0x60];
889
890 let header = crate::common::parser::parse_header(&bytes);
891 assert!(header.is_err());
892 let error = header.expect_err("Should be Err");
893 assert_eq!(error, DisError::InsufficientHeaderLength(10));
894 }
895
896 #[test]
897 fn parse_header_unspecified_version() {
898 let bytes: [u8; 12] = [
899 0x1F, 0x01, 0x01, 0x01, 0x4e, 0xea, 0x3b, 0x60, 0x00, 0x0c, 0x00, 0x00,
900 ];
901
902 let header = crate::common::parser::parse_header(&bytes);
903 assert!(header.is_ok());
904 let header = header.unwrap();
905 assert_eq!(header.protocol_version, ProtocolVersion::Unspecified(31));
906 assert_eq!(header.exercise_id, 1);
907 assert_eq!(header.pdu_type, PduType::EntityState);
908 assert_eq!(
909 header.protocol_family,
910 ProtocolFamily::EntityInformationInteraction
911 );
912 assert_eq!(header.time_stamp, 1_323_973_472);
913 assert_eq!(header.pdu_length, { PDU_HEADER_LEN_BYTES }); }
915
916 #[test]
917 fn parse_header_body_too_short() {
918 let bytes: [u8; 14] = [
920 0x06, 0x01, 0x01, 0x01, 0x4e, 0xea, 0x3b, 0x60, 0x00, 0xd0, 0x00, 0x00, 0x01, 0xf4,
921 ];
922
923 let header = crate::common::parser::parse_header(&bytes);
924 assert!(header.is_err());
925 let error = header.expect_err("Should be Err");
926 assert_eq!(
927 error,
928 DisError::InsufficientPduLength(208 - PDU_HEADER_LEN_BYTES, 2)
929 );
930 }
931
932 #[test]
933 fn parse_multiple_headers() {
934 let bytes: [u8; 24] = [
935 0x06, 0x01, 0x01, 0x01, 0x4e, 0xea, 0x3b, 0x60, 0x00, 0x0c, 0x00, 0x00, 0x06, 0x01,
936 0x01, 0x01, 0x4e, 0xea, 0x3b, 0x60, 0x00, 0x0c, 0x00, 0x00,
937 ];
938
939 let headers = parse_multiple_header(&bytes);
940 assert!(headers.is_ok());
941 let headers = headers.unwrap();
942 assert_eq!(headers.len(), 2);
943 }
944
945 #[test]
946 fn parse_multiple_headers_1st_too_short() {
947 let bytes: [u8; 23] = [
948 0x06, 0x01, 0x01, 0x01, 0x4e, 0xea, 0x3b, 0x60, 0x00, 0x0c, 0x00, 0x06, 0x01, 0x01,
949 0x01, 0x4e, 0xea, 0x3b, 0x60, 0x00, 0x0c, 0x00, 0x00,
950 ];
951 let headers = parse_multiple_header(&bytes);
954 assert!(headers.is_ok());
955 let headers = headers.unwrap();
956 assert_eq!(headers.len(), 1);
957 let header = headers.first().unwrap();
958 assert_ne!(header.padding, 0); }
960
961 #[test]
962 fn parse_multiple_headers_too_short() {
963 let bytes: [u8; 11] = [
964 0x06, 0x01, 0x01, 0x01, 0x4e, 0xea, 0x3b, 0x60, 0x00, 0x60, 0x00,
965 ];
966 let headers = parse_multiple_header(&bytes);
969 assert!(headers.is_err());
970 let error = headers.expect_err("Should be Err");
971 assert_eq!(error, DisError::InsufficientHeaderLength(11));
972 }
973
974 #[test]
975 fn skip_body_total_length_cannot_contain_a_header() {
976 let bytes: [u8; 2] = [0x00, 0x00];
977
978 let (input, skipped) = skip_body(2)(&bytes).unwrap();
979 assert_eq!(input, [0x00, 0x00]);
980 assert_eq!(skipped, []);
981 }
982}