use bytes::{BufMut, BytesMut};
use crate::common::model::{Pdu, PduBody, PduHeader};
use crate::common::{Serialize, SerializePdu, SupportedVersion};
use crate::constants::{EIGHT_OCTETS, PDU_HEADER_LEN_BYTES};
use crate::common::model::{ClockTime, DescriptorRecord, EntityId, EventId, FixedDatum, Location, MunitionDescriptor, Orientation, SimulationAddress, VariableDatum, VectorF32};
use crate::enumerations::{ProtocolVersion};
use crate::length_padded_to_num_bytes;
impl Serialize for PduHeader {
fn serialize(&self, buf: &mut BytesMut) -> u16 {
buf.put_u8(self.protocol_version.into());
buf.put_u8(self.exercise_id);
buf.put_u8(self.pdu_type.into());
buf.put_u8(self.protocol_family.into());
buf.put_u32(self.time_stamp);
buf.put_u16(self.pdu_length);
match self.protocol_version {
ProtocolVersion::IEEE1278_12012 => {
if let Some(status) = self.pdu_status {
status.serialize(buf);
buf.put_u8(0u8);
} else { buf.put_u16(0u16) }
}
_ => { buf.put_u16(0u16) }
}
PDU_HEADER_LEN_BYTES
}
}
impl Serialize for Pdu {
fn serialize(&self, buf: &mut BytesMut) -> u16 {
let header_size = self.header.serialize(buf);
let version: SupportedVersion = self.header.protocol_version.into();
let body_size = match &self.body {
PduBody::Other(body) => { body.serialize_pdu(version, buf) } PduBody::EntityState(body) => { body.serialize_pdu(version, buf) }
PduBody::Fire(body) => { body.serialize_pdu(version, buf) }
PduBody::Detonation(body) => { body.serialize_pdu(version, buf) }
PduBody::Collision(body) => { body.serialize_pdu(version, buf) }
PduBody::CreateEntity(body) => { body.serialize_pdu(version, buf) }
PduBody::RemoveEntity(body) => { body.serialize_pdu(version, buf) }
PduBody::StartResume(body) => { body.serialize_pdu(version, buf) }
PduBody::StopFreeze(body) => { body.serialize_pdu(version, buf) }
PduBody::Acknowledge(body) => { body.serialize_pdu(version, buf) }
PduBody::ActionRequest(body) => { body.serialize_pdu(version, buf) }
PduBody::ActionResponse(body) => { body.serialize_pdu(version, buf) }
PduBody::DataQuery(body) => { body.serialize_pdu(version, buf) }
PduBody::SetData(body) => { body.serialize_pdu(version, buf) }
PduBody::Data(body) => { body.serialize_pdu(version, buf) }
PduBody::EventReport(body) => { body.serialize_pdu(version, buf) }
PduBody::Comment(body) => { body.serialize_pdu(version, buf) }
PduBody::ElectromagneticEmission(body) => { body.serialize_pdu(version, buf) }
PduBody::Designator(body) => { body.serialize_pdu(version, buf) }
PduBody::Transmitter(body) => { body.serialize_pdu(version, buf) }
PduBody::Signal(body) => { body.serialize_pdu(version, buf) }
PduBody::Receiver(body) => { body.serialize_pdu(version, buf) }
PduBody::CollisionElastic(body) => { body.serialize_pdu(version, buf) }
PduBody::EntityStateUpdate(body) => { body.serialize_pdu(version, buf) }
PduBody::Attribute(body) => { body.serialize_pdu(version, buf) }
_ => { 0 }
};
header_size + body_size
}
}
impl Serialize for EntityId {
fn serialize(&self, buf: &mut BytesMut) -> u16 {
let num_bytes = self.simulation_address.serialize(buf);
buf.put_u16(self.entity_id);
num_bytes + 2
}
}
impl Serialize for SimulationAddress {
fn serialize(&self, buf: &mut BytesMut) -> u16 {
buf.put_u16(self.site_id);
buf.put_u16(self.application_id);
4
}
}
impl Serialize for EventId {
fn serialize(&self, buf: &mut BytesMut) -> u16 {
let num_bytes = self.simulation_address.serialize(buf);
buf.put_u16(self.event_id);
num_bytes + 2
}
}
impl Serialize for VectorF32 {
fn serialize(&self, buf: &mut BytesMut) -> u16 {
buf.put_f32(self.first_vector_component);
buf.put_f32(self.second_vector_component);
buf.put_f32(self.third_vector_component);
12
}
}
impl Serialize for Location {
fn serialize(&self, buf: &mut BytesMut) -> u16 {
buf.put_f64(self.x_coordinate);
buf.put_f64(self.y_coordinate);
buf.put_f64(self.z_coordinate);
24
}
}
impl Serialize for Orientation {
fn serialize(&self, buf: &mut BytesMut) -> u16 {
buf.put_f32(self.psi);
buf.put_f32(self.theta);
buf.put_f32(self.phi);
12
}
}
impl Serialize for DescriptorRecord {
fn serialize(&self, buf: &mut BytesMut) -> u16 {
match self {
DescriptorRecord::Munition { entity_type, munition } => {
let entity_bytes = entity_type.serialize(buf);
let munition_bytes = munition.serialize(buf);
entity_bytes + munition_bytes
}
DescriptorRecord::Expendable { entity_type } => {
let entity_bytes = entity_type.serialize(buf);
buf.put_u64(0u64);
entity_bytes + 8
}
DescriptorRecord::Explosion { entity_type, explosive_material, explosive_force } => {
let entity_bytes = entity_type.serialize(buf);
buf.put_u16((*explosive_material).into());
buf.put_u16(0u16);
buf.put_f32(*explosive_force);
entity_bytes + 8
}
}
}
}
impl Serialize for MunitionDescriptor {
fn serialize(&self, buf: &mut BytesMut) -> u16 {
buf.put_u16(self.warhead.into());
buf.put_u16(self.fuse.into());
buf.put_u16(self.quantity);
buf.put_u16(self.rate);
8
}
}
impl Serialize for ClockTime {
fn serialize(&self, buf: &mut BytesMut) -> u16 {
buf.put_i32(self.hour);
buf.put_u32(self.time_past_hour);
8
}
}
impl Serialize for FixedDatum {
fn serialize(&self, buf: &mut BytesMut) -> u16 {
buf.put_u32(self.datum_id.into());
buf.put_u32(self.datum_value);
8
}
}
impl Serialize for VariableDatum {
fn serialize(&self, buf: &mut BytesMut) -> u16 {
buf.put_u32(self.datum_id.into());
let padded_record = length_padded_to_num_bytes(
EIGHT_OCTETS + self.datum_value.len(),
EIGHT_OCTETS);
let data_length_with_padding = padded_record.record_length_bytes as u16;
buf.put_u32(data_length_with_padding.into());
buf.put_slice(self.datum_value.as_slice());
buf.put_bytes(0, padded_record.padding_length_bytes);
8 + data_length_with_padding
}
}
#[cfg(test)]
mod tests {
use bytes::BytesMut;
use crate::common::Serialize;
use crate::constants::PDU_HEADER_LEN_BYTES;
use crate::enumerations::{PduType};
use crate::{LvcIndicator, PduHeader};
use crate::v7::model::PduStatus;
#[test]
fn serialize_header() {
let header = PduHeader::new_v6(1, PduType::EntityState)
.with_time_stamp(10)
.with_length(0);
let mut buf = BytesMut::with_capacity(PDU_HEADER_LEN_BYTES as usize);
header.serialize(&mut buf);
let expected : [u8;12] = [0x06, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x00];
assert_eq!(buf.as_ref(), expected.as_ref());
}
#[test]
fn serialize_header_v7_no_status() {
let header = PduHeader::new_v7(1, PduType::EntityState)
.with_time_stamp(10)
.with_length(0);
let mut buf = BytesMut::with_capacity(PDU_HEADER_LEN_BYTES as usize);
header.serialize(&mut buf);
let expected : [u8;12] = [0x07, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x00];
assert_eq!(buf.as_ref(), expected.as_ref());
}
#[test]
fn serialize_header_v7_with_status() {
let header = PduHeader::new_v7(1, PduType::EntityState)
.with_time_stamp(10)
.with_length(0)
.with_pdu_status(PduStatus::default().with_lvc_indicator(LvcIndicator::Live));
let mut buf = BytesMut::with_capacity(PDU_HEADER_LEN_BYTES as usize);
header.serialize(&mut buf);
let expected : [u8;12] = [0x07, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0c, 0x02, 0x00];
assert_eq!(buf.as_ref(), expected.as_ref());
}
}