use std::any::Any;
use bytes::{BytesMut, BufMut, Buf};
use serde::{Serialize, Deserialize};
use crate::common::{entity_id_record::{EntityIDRecord}, entity_type_record::{Country, EntityTypeRecord, Kind}, euler_angles_record::EulerAnglesRecord, linear_velocity_record::LinearVelocityRecord, pdu::PDU, pdu_header_record::{PDUHeaderRecord, PDUType, ProtocolFamily}, world_coordinate_record::WorldCoordinateRecord, dis_error::DISError};
use super::{entity_appearance_record::EntityAppearanceRecord, dead_reckoning_parameters_record::DeadReckoningParametersRecord, entity_marking_record::EntityMarkingRecord, entity_capabilities_record::{EntityCapabilitiesRecord}};
#[derive(Clone, Debug,)]
pub struct EntityStatePDU {
pub pdu_header_record: PDUHeaderRecord,
pub entity_id_record: EntityIDRecord,
pub force_id_field: ForceID,
pub number_of_articulation_parameters_field: u8,
pub entity_type_record: EntityTypeRecord,
pub alternative_entity_type_record: EntityTypeRecord,
pub entity_linear_velocity_record: LinearVelocityRecord,
pub entity_location_record: WorldCoordinateRecord,
pub entity_orientation_record: EulerAnglesRecord,
pub entity_appearance_record: EntityAppearanceRecord,
pub dead_reckoning_parameters_record: DeadReckoningParametersRecord,
pub entity_marking_record: EntityMarkingRecord,
pub entity_capabilities_record: EntityCapabilitiesRecord,
pub articulation_parameter_record: f32 }
impl EntityStatePDU {
pub fn default() -> Self {
EntityStatePDU {
pdu_header_record: PDUHeaderRecord::default(PDUType::EntityState, ProtocolFamily::EntityInformation, 864/8), entity_id_record: EntityIDRecord::default(2),
force_id_field: ForceID::Other,
number_of_articulation_parameters_field: 0,
entity_type_record: EntityTypeRecord{
kind_field: Kind::Munition,
domain_field: 1,
country_field: Country::Other,
category_field: 3,
subcategory_field: 0,
specific_field: 0,
extra_field: 0},
alternative_entity_type_record: EntityTypeRecord{
kind_field: Kind::Munition,
domain_field: 1,
country_field: Country::Other,
category_field: 0,
subcategory_field: 0,
specific_field: 0,
extra_field: 0},
entity_linear_velocity_record: LinearVelocityRecord::new(0.0, 0.0, 0.0),
entity_location_record: WorldCoordinateRecord::new(0.0, 0.0, 0.0),
entity_orientation_record: EulerAnglesRecord::new(0.0, 0.0, 0.0),
entity_appearance_record: EntityAppearanceRecord::default(),
dead_reckoning_parameters_record: DeadReckoningParametersRecord::default(),
entity_marking_record: EntityMarkingRecord::default("".to_string()),
entity_capabilities_record: EntityCapabilitiesRecord::default(),
articulation_parameter_record: 0.0 }
}
}
impl PDU for EntityStatePDU {
fn deserialise(mut buffer: BytesMut) -> Result<EntityStatePDU, DISError> {
let pdu_header = PDUHeaderRecord::decode(&mut buffer);
if pdu_header.pdu_type == PDUType::EntityState {
let entity_id = EntityIDRecord::decode(&mut buffer);
let force_id = ForceID::decode(&mut buffer);
let articulation_params = &buffer.get_u8();
let entity_type = EntityTypeRecord::decode(&mut buffer);
let alt_entity_type = EntityTypeRecord::decode(&mut buffer);
let linear_velocity = LinearVelocityRecord::decode(&mut buffer);
let world_coordinate = WorldCoordinateRecord::decode(&mut buffer);
let orientation = EulerAnglesRecord::decode(&mut buffer);
let appearance = EntityAppearanceRecord::decode(&mut buffer);
let dead_reckoning = DeadReckoningParametersRecord::decode(&mut buffer);
let entity_marking = EntityMarkingRecord::decode(&mut buffer);
let entity_capabilities = EntityCapabilitiesRecord::decode(&mut buffer);
return Ok(EntityStatePDU {
pdu_header_record: pdu_header,
entity_id_record: entity_id,
force_id_field: force_id,
number_of_articulation_parameters_field: *articulation_params,
entity_type_record: entity_type,
alternative_entity_type_record: alt_entity_type,
entity_linear_velocity_record: linear_velocity,
entity_location_record: world_coordinate,
entity_orientation_record: orientation,
entity_appearance_record: appearance,
dead_reckoning_parameters_record: dead_reckoning,
entity_marking_record: entity_marking,
entity_capabilities_record: entity_capabilities,
articulation_parameter_record: 0.0,
})
} else {
Err(DISError::InvalidDISHeader)
}
}
fn serialise(&self, buf: &mut BytesMut) {
self.pdu_header_record.serialize(buf);
self.entity_id_record.serialize(buf);
buf.put_u8(self.force_id_field as u8);
buf.put_u8(self.number_of_articulation_parameters_field as u8);
self.entity_type_record.serialize(buf);
self.alternative_entity_type_record.serialize(buf);
self.entity_linear_velocity_record.serialize(buf);
self.entity_location_record.serialize(buf);
self.entity_orientation_record.serialize(buf);
self.entity_appearance_record.serialize(buf);
self.dead_reckoning_parameters_record.serialize(buf);
self.entity_marking_record.serialize(buf);
self.entity_capabilities_record.serialize(buf);
}
fn as_any(&self) -> &dyn Any {
self
}
fn deserialise_without_header(mut buffer: BytesMut, pdu_header: PDUHeaderRecord) -> Result<Self, DISError> where Self: Sized {
let entity_id = EntityIDRecord::decode(&mut buffer);
let force_id = ForceID::decode(&mut buffer);
let articulation_params = &buffer.get_u8();
let entity_type = EntityTypeRecord::decode(&mut buffer);
let alt_entity_type = EntityTypeRecord::decode(&mut buffer);
let linear_velocity = LinearVelocityRecord::decode(&mut buffer);
let world_coordinate = WorldCoordinateRecord::decode(&mut buffer);
let orientation = EulerAnglesRecord::decode(&mut buffer);
let appearance = EntityAppearanceRecord::decode(&mut buffer);
let dead_reckoning = DeadReckoningParametersRecord::decode(&mut buffer);
let entity_marking = EntityMarkingRecord::decode(&mut buffer);
let entity_capabilities = EntityCapabilitiesRecord::decode(&mut buffer);
return Ok(EntityStatePDU {
pdu_header_record: pdu_header,
entity_id_record: entity_id,
force_id_field: force_id,
number_of_articulation_parameters_field: *articulation_params,
entity_type_record: entity_type,
alternative_entity_type_record: alt_entity_type,
entity_linear_velocity_record: linear_velocity,
entity_location_record: world_coordinate,
entity_orientation_record: orientation,
entity_appearance_record: appearance,
dead_reckoning_parameters_record: dead_reckoning,
entity_marking_record: entity_marking,
entity_capabilities_record: entity_capabilities,
articulation_parameter_record: 0.0,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum ForceID {
Other = 0,
Friendly = 1,
Opposing = 2,
Neutral = 3
}
impl ForceID {
pub fn decode(buf: &mut BytesMut) -> ForceID {
match buf.get_u8() {
1 => ForceID::Friendly,
2 => ForceID::Opposing,
3 => ForceID::Neutral,
_ => ForceID::Other,
}
}
}
#[cfg(test)]
mod tests {
use bytes::BytesMut;
use crate::{common::{pdu_header_record::{PDUHeaderRecord, PDUType, ProtocolFamily}, pdu::PDU}, entity_information::entity_state_pdu::EntityStatePDU};
#[test]
fn header_creation() {
let entity_state_pdu = EntityStatePDU::default();
let header = PDUHeaderRecord::default(PDUType::EntityState, ProtocolFamily::EntityInformation, 864/8);
assert_eq!(header.protocol_version, entity_state_pdu.pdu_header_record.protocol_version);
assert_eq!(header.exercise_id, entity_state_pdu.pdu_header_record.exercise_id);
assert_eq!(header.pdu_type, entity_state_pdu.pdu_header_record.pdu_type);
assert_eq!(header.protocol_family, entity_state_pdu.pdu_header_record.protocol_family);
assert_eq!(header.timestamp, entity_state_pdu.pdu_header_record.timestamp);
assert_eq!(header.length, entity_state_pdu.pdu_header_record.length);
assert_eq!(header.padding, entity_state_pdu .pdu_header_record.padding);
}
#[test]
fn header_deserialise() {
let entity_state_pdu = EntityStatePDU::default();
let mut buffer = BytesMut::new();
entity_state_pdu.serialise(&mut buffer);
let new_entity_state_pdu = EntityStatePDU::deserialise(buffer).unwrap();
assert_eq!(new_entity_state_pdu.pdu_header_record, entity_state_pdu.pdu_header_record);
}
}