diff --git a/src/common/enums.rs b/src/common/enums.rs index 58334a1..a9fdc21 100644 --- a/src/common/enums.rs +++ b/src/common/enums.rs @@ -8805,8 +8805,8 @@ impl GriddedDataFieldNumber { #[derive(Copy, Clone, Debug, Default, FromPrimitive, PartialEq)] pub enum GriddedDataCoordinateSystem { #[default] - RighthandedCartesian = 0, - LefthandedCartesian = 1, + RightHandedCartesian = 0, + LeftHandedCartesian = 1, LatitudeLongitudeHeight = 2, LatitudeLongitudeDepth = 3, } @@ -8814,7 +8814,7 @@ pub enum GriddedDataCoordinateSystem { impl GriddedDataCoordinateSystem { #[must_use] pub fn decode(buf: &mut BytesMut) -> Self { - Self::from_u8(buf.get_u8()).unwrap_or(Self::default()) + Self::from_u16(buf.get_u16()).unwrap_or(Self::default()) } } diff --git a/src/distributed_emissions/designator_pdu.rs b/src/distributed_emissions/designator_pdu.rs index 2ac1d41..00b2190 100644 --- a/src/distributed_emissions/designator_pdu.rs +++ b/src/distributed_emissions/designator_pdu.rs @@ -34,7 +34,7 @@ impl Default for DesignatorPdu { pdu_header: PduHeader::default( PduType::Designator, ProtocolFamily::DistributedEmissionRegeneration, - 56, + 88, ), designating_entity_id: EntityId::default(1), code_name: 0, @@ -165,7 +165,7 @@ mod tests { let pdu_header = PduHeader::default( PduType::Designator, ProtocolFamily::DistributedEmissionRegeneration, - 448 / 8, + 88, ); assert_eq!( diff --git a/src/distributed_emissions/electromagnetic_emissions_pdu.rs b/src/distributed_emissions/electromagnetic_emissions_pdu.rs index 58f69e9..10dde32 100644 --- a/src/distributed_emissions/electromagnetic_emissions_pdu.rs +++ b/src/distributed_emissions/electromagnetic_emissions_pdu.rs @@ -44,7 +44,7 @@ impl Default for ElectromagneticEmissionsPdu { pdu_header: PduHeader::default( PduType::ElectromagneticEmission, ProtocolFamily::DistributedEmissionRegeneration, - 56, + 28, ), emitting_entity_id: EntityId::default(1), event_id: EventId::default(1), diff --git a/src/synthetic_environment/data_types/grid_axis_descriptor.rs b/src/synthetic_environment/data_types/grid_axis_descriptor.rs index e69de29..d408660 100644 --- a/src/synthetic_environment/data_types/grid_axis_descriptor.rs +++ b/src/synthetic_environment/data_types/grid_axis_descriptor.rs @@ -0,0 +1,137 @@ +// open-dis-rust - Rust implementation of the IEEE-1278.1 Distributed Interactive Simulation +// Copyright (C) 2023 Cameron Howell +// +// Licensed under the BSD-2-Clause License + +use bytes::{Buf, BufMut, BytesMut}; + +use crate::common::enums::GridAxisDescriptorAxisType; + +#[derive(Clone, Debug, PartialEq)] +pub enum GridAxisType { + FixedSpacing { + number_of_points_on_x_axis: u16, + initial_index: u16, + }, + VariableSpacing { + number_of_points_on_x_axis: u16, + initial_index: u16, + coordinate_scale_x: f64, + coordinate_offset_x: f64, + x_values: Vec, + padding: Vec, + }, +} + +#[derive(Clone, Debug)] +pub struct GridAxisDescriptor { + pub domain_initial: f64, + pub domain_final: f64, + pub domain_points: u16, + pub interleaf_factor: u8, + pub axis_type: GridAxisDescriptorAxisType, + pub data: GridAxisType, +} + +impl GridAxisDescriptor { + #[must_use] + pub fn new( + domain_initial: f64, + domain_final: f64, + domain_points: u16, + interleaf_factor: u8, + axis_type: GridAxisDescriptorAxisType, + data: GridAxisType, + ) -> Self { + GridAxisDescriptor { + domain_initial, + domain_final, + domain_points, + interleaf_factor, + axis_type, + data, + } + } + + pub fn serialize(&self, buf: &mut BytesMut) { + buf.put_f64(self.domain_initial); + buf.put_f64(self.domain_final); + buf.put_u16(self.domain_points); + buf.put_u8(self.interleaf_factor); + buf.put_u8(self.axis_type as u8); + match &self.data { + GridAxisType::FixedSpacing { + number_of_points_on_x_axis, + initial_index, + } => { + buf.put_u16(*number_of_points_on_x_axis); + buf.put_u16(*initial_index); + } + GridAxisType::VariableSpacing { + number_of_points_on_x_axis, + initial_index, + coordinate_scale_x, + coordinate_offset_x, + x_values, + padding, + } => { + buf.put_u16(*number_of_points_on_x_axis); + buf.put_u16(*initial_index); + buf.put_f64(*coordinate_scale_x); + buf.put_f64(*coordinate_offset_x); + for x in x_values { + buf.put_u16(*x); + } + for p in padding { + buf.put_u8(*p); + } + } + } + } + + pub fn decode(buf: &mut BytesMut) -> Self { + let domain_initial = buf.get_f64(); + let domain_final = buf.get_f64(); + let domain_points = buf.get_u16(); + let interleaf_factor = buf.get_u8(); + let axis_type = GridAxisDescriptorAxisType::decode(buf); + let data = match axis_type { + GridAxisDescriptorAxisType::RegularAxis => GridAxisType::FixedSpacing { + number_of_points_on_x_axis: buf.get_u16(), + initial_index: buf.get_u16(), + }, + GridAxisDescriptorAxisType::IrregularAxis => { + let number_of_points_on_x_axis = buf.get_u16(); + let initial_index = buf.get_u16(); + let coordinate_scale_x = buf.get_f64(); + let coordinate_offset_x = buf.get_f64(); + let mut x_values: Vec = vec![]; + for _ in 0..number_of_points_on_x_axis { + x_values.push(buf.get_u16()); + } + let mut padding: Vec = vec![]; + while buf.has_remaining() { + padding.push(buf.get_u8()); + } + + GridAxisType::VariableSpacing { + number_of_points_on_x_axis, + initial_index, + coordinate_scale_x, + coordinate_offset_x, + x_values, + padding, + } + } + }; + + GridAxisDescriptor { + domain_initial, + domain_final, + domain_points, + interleaf_factor, + axis_type, + data, + } + } +} diff --git a/src/synthetic_environment/data_types/grid_data_record.rs b/src/synthetic_environment/data_types/grid_data_record.rs index ddb9087..92a2da5 100644 --- a/src/synthetic_environment/data_types/grid_data_record.rs +++ b/src/synthetic_environment/data_types/grid_data_record.rs @@ -5,58 +5,160 @@ use bytes::{Buf, BufMut, BytesMut}; -#[derive(Clone, Debug, Default)] +use crate::common::enums::{GriddedDataDataRepresentation, GriddedDataSampleType}; + +#[derive(Clone, Debug, PartialEq)] +pub enum DataRepresentationType { + Type0 { + number_of_octets: u16, + data_values: Vec, + padding: Vec, + }, + Type1 { + field_scale: f32, + field_offset: f32, + number_of_values: u16, + data_values: Vec, + padding: Vec, + }, + Type2 { + number_of_values: u16, + padding: u16, + data_values: Vec, + }, +} + +#[derive(Clone, Debug)] pub struct GridDataRecord { - pub sample_type: u16, - pub data_representation: u16, - pub number_of_octets: u16, - pub data_values: Vec, - pub padding: u8, + pub sample_type: GriddedDataSampleType, + pub data_representation: GriddedDataDataRepresentation, + pub data: DataRepresentationType, } impl GridDataRecord { #[must_use] pub fn new( - sample_type: u16, - data_representation: u16, - number_of_octets: u16, - data_values: Vec, - padding: u8, + sample_type: GriddedDataSampleType, + data_representation: GriddedDataDataRepresentation, + data: DataRepresentationType, ) -> Self { GridDataRecord { sample_type, data_representation, - number_of_octets, - data_values, - padding, + data, } } pub fn serialize(&self, buf: &mut BytesMut) { - buf.put_u16(self.sample_type); - buf.put_u16(self.data_representation); - buf.put_u16(self.number_of_octets); - for i in 0..self.data_values.len() { - buf.put_u8(self.data_values[i]); + buf.put_u16(self.sample_type as u16); + buf.put_u16(self.data_representation as u16); + match &self.data { + DataRepresentationType::Type0 { + number_of_octets, + data_values, + padding, + } => { + buf.put_u16(*number_of_octets); + for i in data_values { + buf.put_u8(*i); + } + for p in padding { + buf.put_u8(*p); + } + } + DataRepresentationType::Type1 { + field_scale, + field_offset, + number_of_values, + data_values, + padding, + } => { + buf.put_f32(*field_scale); + buf.put_f32(*field_offset); + buf.put_u16(*number_of_values); + for i in data_values { + buf.put_u16(*i); + } + for p in padding { + buf.put_u8(*p); + } + } + DataRepresentationType::Type2 { + number_of_values, + padding, + data_values, + } => { + buf.put_u16(*number_of_values); + buf.put_u16(*padding); + for i in data_values { + buf.put_f32(*i); + } + } } - buf.put_u8(self.padding); } pub fn decode(buf: &mut BytesMut) -> GridDataRecord { - let sample_type = buf.get_u16(); - let data_representation = buf.get_u16(); - let number_of_octets = buf.get_u16(); - let mut data_values: Vec = vec![]; - for _i in 0..number_of_octets { - data_values.push(buf.get_u8()); - } - let padding = buf.get_u8(); + let sample_type = GriddedDataSampleType::decode(buf); + let data_representation = GriddedDataDataRepresentation::decode(buf); + let data = match data_representation { + GriddedDataDataRepresentation::Type0 => { + let number_of_octets = buf.get_u16(); + let mut data_values: Vec = vec![]; + for _ in 0..number_of_octets { + data_values.push(buf.get_u8()); + } + let mut padding: Vec = vec![]; + while buf.has_remaining() { + padding.push(buf.get_u8()); + } + + DataRepresentationType::Type0 { + number_of_octets, + data_values, + padding, + } + } + GriddedDataDataRepresentation::Type1 => { + let field_scale = buf.get_f32(); + let field_offset = buf.get_f32(); + let number_of_values = buf.get_u16(); + let mut data_values: Vec = vec![]; + for _ in 0..number_of_values { + data_values.push(buf.get_u16()); + } + let mut padding: Vec = vec![]; + while buf.has_remaining() { + padding.push(buf.get_u8()); + } + + DataRepresentationType::Type1 { + field_scale, + field_offset, + number_of_values, + data_values, + padding, + } + } + GriddedDataDataRepresentation::Type2 => { + let number_of_values = buf.get_u16(); + let padding = buf.get_u16(); + let mut data_values: Vec = vec![]; + for _ in 0..number_of_values { + data_values.push(buf.get_f32()); + } + + DataRepresentationType::Type2 { + number_of_values, + padding, + data_values, + } + } + }; + GridDataRecord { sample_type, data_representation, - number_of_octets, - data_values, - padding, + data, } } } diff --git a/src/synthetic_environment/gridded_data_pdu.rs b/src/synthetic_environment/gridded_data_pdu.rs index 7bc8e07..0828645 100644 --- a/src/synthetic_environment/gridded_data_pdu.rs +++ b/src/synthetic_environment/gridded_data_pdu.rs @@ -10,31 +10,35 @@ use crate::common::{ dis_error::DISError, entity_id::EntityId, entity_type::EntityType, + enums::{GriddedDataConstantGrid, GriddedDataCoordinateSystem}, euler_angles::EulerAngles, pdu::Pdu, pdu_header::{PduHeader, PduType, ProtocolFamily}, }; -use super::data_types::grid_data_record::GridDataRecord; +use super::data_types::{ + grid_axis_descriptor::GridAxisDescriptor, grid_data_record::GridDataRecord, +}; #[derive(Clone, Debug)] /// Implemented according to IEEE 1278.1-2012 ยง5.11.2.3 pub struct GriddedDataPdu { pub pdu_header: PduHeader, - pub environmental_simulation_application_id: EntityId, + pub environmental_simulation_id: EntityId, pub field_number: u16, pub pdu_number: u16, pub pdu_total: u16, - pub coordinate_system: u16, + pub coordinate_system: GriddedDataCoordinateSystem, pub number_of_grid_axes: u8, - pub constant_grid: u8, + pub constant_grid: GriddedDataConstantGrid, pub environment_type: EntityType, pub orientation: EulerAngles, pub sample_time: u64, pub total_values: u32, pub vector_dimension: u8, - pub padding1: u16, - pub padding2: u8, + pub padding1: u8, + pub padding2: u16, + pub grid_axis_descriptors: Vec, pub grid_data_list: Vec, } @@ -54,15 +58,15 @@ impl Default for GriddedDataPdu { pdu_header: PduHeader::default( PduType::GriddedData, ProtocolFamily::SyntheticEnvironment, - 56, + 112, ), - environmental_simulation_application_id: EntityId::default(0), + environmental_simulation_id: EntityId::default(0), field_number: 0, pdu_number: 0, pdu_total: 0, - coordinate_system: 0, + coordinate_system: GriddedDataCoordinateSystem::default(), number_of_grid_axes: 0, - constant_grid: 0, + constant_grid: GriddedDataConstantGrid::default(), environment_type: EntityType::default(), orientation: EulerAngles::default(), sample_time: 0, @@ -70,6 +74,7 @@ impl Default for GriddedDataPdu { vector_dimension: 0, padding1: 0, padding2: 0, + grid_axis_descriptors: vec![], grid_data_list: vec![], } } @@ -78,20 +83,23 @@ impl Default for GriddedDataPdu { impl Pdu for GriddedDataPdu { fn serialize(&self, buf: &mut BytesMut) { self.pdu_header.serialize(buf); - self.environmental_simulation_application_id.serialize(buf); + self.environmental_simulation_id.serialize(buf); buf.put_u16(self.field_number); buf.put_u16(self.pdu_number); buf.put_u16(self.pdu_total); - buf.put_u16(self.coordinate_system); + buf.put_u16(self.coordinate_system as u16); buf.put_u8(self.number_of_grid_axes); - buf.put_u8(self.constant_grid); + buf.put_u8(self.constant_grid as u8); self.environment_type.serialize(buf); self.orientation.serialize(buf); buf.put_u64(self.sample_time); buf.put_u32(self.total_values); buf.put_u8(self.vector_dimension); - buf.put_u16(self.padding1); - buf.put_u8(self.padding2); + buf.put_u8(self.padding1); + buf.put_u16(self.padding2); + for i in 0..self.grid_axis_descriptors.len() { + self.grid_axis_descriptors[i].serialize(buf); + } for i in 0..self.grid_data_list.len() { self.grid_data_list[i].serialize(buf); } @@ -103,27 +111,32 @@ impl Pdu for GriddedDataPdu { { let pdu_header = PduHeader::decode(&mut buffer); if pdu_header.pdu_type == PduType::GriddedData { - let environmental_simulation_application_id = EntityId::decode(&mut buffer); + let environmental_simulation_id = EntityId::decode(&mut buffer); let field_number = buffer.get_u16(); let pdu_number = buffer.get_u16(); let pdu_total = buffer.get_u16(); - let coordinate_system = buffer.get_u16(); + let coordinate_system = GriddedDataCoordinateSystem::decode(&mut buffer); let number_of_grid_axes = buffer.get_u8(); - let constant_grid = buffer.get_u8(); + let constant_grid = GriddedDataConstantGrid::decode(&mut buffer); let environment_type = EntityType::decode(&mut buffer); let orientation = EulerAngles::decode(&mut buffer); let sample_time = buffer.get_u64(); let total_values = buffer.get_u32(); let vector_dimension = buffer.get_u8(); - let padding1 = buffer.get_u16(); - let padding2 = buffer.get_u8(); + let padding1 = buffer.get_u8(); + let padding2 = buffer.get_u16(); + let mut grid_axis_descriptors: Vec = vec![]; + for _ in 0..number_of_grid_axes { + grid_axis_descriptors.push(GridAxisDescriptor::decode(&mut buffer)); + } let mut grid_data_list: Vec = vec![]; - for _i in 0..number_of_grid_axes { + while buffer.has_remaining() { grid_data_list.push(GridDataRecord::decode(&mut buffer)); } + Ok(GriddedDataPdu { pdu_header, - environmental_simulation_application_id, + environmental_simulation_id, field_number, pdu_number, pdu_total, @@ -137,6 +150,7 @@ impl Pdu for GriddedDataPdu { vector_dimension, padding1, padding2, + grid_axis_descriptors, grid_data_list, }) } else { @@ -155,27 +169,31 @@ impl Pdu for GriddedDataPdu { where Self: Sized, { - let environmental_simulation_application_id = EntityId::decode(&mut buffer); + let environmental_simulation_id = EntityId::decode(&mut buffer); let field_number = buffer.get_u16(); let pdu_number = buffer.get_u16(); let pdu_total = buffer.get_u16(); - let coordinate_system = buffer.get_u16(); + let coordinate_system = GriddedDataCoordinateSystem::decode(&mut buffer); let number_of_grid_axes = buffer.get_u8(); - let constant_grid = buffer.get_u8(); + let constant_grid = GriddedDataConstantGrid::decode(&mut buffer); let environment_type = EntityType::decode(&mut buffer); let orientation = EulerAngles::decode(&mut buffer); let sample_time = buffer.get_u64(); let total_values = buffer.get_u32(); let vector_dimension = buffer.get_u8(); - let padding1 = buffer.get_u16(); - let padding2 = buffer.get_u8(); + let padding1 = buffer.get_u8(); + let padding2 = buffer.get_u16(); + let mut grid_axis_descriptors: Vec = vec![]; + for _ in 0..number_of_grid_axes { + grid_axis_descriptors.push(GridAxisDescriptor::decode(&mut buffer)); + } let mut grid_data_list: Vec = vec![]; - for _i in 0..number_of_grid_axes { + while buffer.has_remaining() { grid_data_list.push(GridDataRecord::decode(&mut buffer)); } Ok(GriddedDataPdu { pdu_header, - environmental_simulation_application_id, + environmental_simulation_id, field_number, pdu_number, pdu_total, @@ -189,6 +207,7 @@ impl Pdu for GriddedDataPdu { vector_dimension, padding1, padding2, + grid_axis_descriptors, grid_data_list, }) } @@ -209,7 +228,7 @@ mod tests { let pdu_header = PduHeader::default( PduType::GriddedData, ProtocolFamily::SyntheticEnvironment, - 448 / 8, + 112, ); assert_eq!( @@ -238,4 +257,14 @@ mod tests { let new_gridded_data_pdu = GriddedDataPdu::deserialize(buffer).unwrap(); assert_eq!(new_gridded_data_pdu.pdu_header, gridded_data_pdu.pdu_header); } + + #[test] + fn check_pdu_size() { + let gridded_data_pdu = GriddedDataPdu::default(); + + assert_eq!( + gridded_data_pdu.pdu_header.length, + gridded_data_pdu.pdu_header.length + ); + } }