Skip to main content

dis_rs/common/
writer.rs

1use crate::DisError;
2use crate::common::model::{
3    ArticulatedPart, AttachedPart, BeamData, ClockTime, EntityAssociationParameter, EntityId,
4    EntityTypeParameter, EventId, ExpendableDescriptor, ExplosionDescriptor, FixedDatum, Location,
5    MunitionDescriptor, Orientation, SeparationParameter, SimulationAddress, VariableDatum,
6    VariableParameter, VectorF32, length_padded_to_num,
7};
8use crate::common::model::{Pdu, PduBody, PduHeader};
9use crate::common::{Serialize, SerializePdu, SupportedVersion};
10use crate::constants::{EIGHT_OCTETS, FOUR_OCTETS, ONE_BYTE_IN_BITS, PDU_HEADER_LEN_BYTES};
11use crate::enumerations::{ProtocolVersion, VariableParameterRecordType};
12use crate::model::{RecordSet, RecordSpecification, SupplyQuantity};
13use bytes::{BufMut, BytesMut};
14
15impl Serialize for PduHeader {
16    fn serialize(&self, buf: &mut BytesMut) -> u16 {
17        buf.put_u8(self.protocol_version.into());
18        buf.put_u8(self.exercise_id);
19        buf.put_u8(self.pdu_type.into());
20        buf.put_u8(self.protocol_family.into());
21        buf.put_u32(self.timestamp.into());
22        buf.put_u16(self.pdu_length);
23        match self.protocol_version {
24            ProtocolVersion::IEEE1278_12012 => {
25                if let Some(status) = self.pdu_status {
26                    buf.put_u8(crate::v7::writer::serialize_pdu_status(
27                        &status,
28                        &self.pdu_type,
29                    ));
30                    buf.put_u8(0u8);
31                } else {
32                    buf.put_u16(0u16);
33                }
34            }
35            _ => buf.put_u16(0u16),
36        }
37
38        PDU_HEADER_LEN_BYTES
39    }
40}
41
42impl Pdu {
43    /// Serializes `self` into the buffer.
44    ///
45    /// Fails when the capacity of the buffer is smaller than the serialized length of the PDU (header + body).
46    ///
47    /// # Errors
48    /// Returns a `DisError` when parsing fails
49    pub fn serialize(&self, buf: &mut BytesMut) -> Result<u16, DisError> {
50        if self.pdu_length() as usize > buf.capacity() {
51            return Err(DisError::InsufficientBufferSize(
52                self.pdu_length(),
53                buf.capacity(),
54            ));
55        }
56        let header_size = self.header.serialize(buf);
57        let version: SupportedVersion = self.header.protocol_version.into();
58        let body_size = match &self.body {
59            PduBody::Other(body) => body.serialize_pdu(version, buf),
60            PduBody::EntityState(body) => body.serialize_pdu(version, buf),
61            PduBody::Fire(body) => body.serialize_pdu(version, buf),
62            PduBody::Detonation(body) => body.serialize_pdu(version, buf),
63            PduBody::Collision(body) => body.serialize_pdu(version, buf),
64            PduBody::ServiceRequest(body) => body.serialize_pdu(version, buf),
65            PduBody::ResupplyOffer(body) => body.serialize_pdu(version, buf),
66            PduBody::ResupplyReceived(body) => body.serialize_pdu(version, buf),
67            PduBody::ResupplyCancel(body) => body.serialize_pdu(version, buf),
68            PduBody::RepairComplete(body) => body.serialize_pdu(version, buf),
69            PduBody::RepairResponse(body) => body.serialize_pdu(version, buf),
70            PduBody::CreateEntity(body) => body.serialize_pdu(version, buf),
71            PduBody::RemoveEntity(body) => body.serialize_pdu(version, buf),
72            PduBody::StartResume(body) => body.serialize_pdu(version, buf),
73            PduBody::StopFreeze(body) => body.serialize_pdu(version, buf),
74            PduBody::Acknowledge(body) => body.serialize_pdu(version, buf),
75            PduBody::ActionRequest(body) => body.serialize_pdu(version, buf),
76            PduBody::ActionResponse(body) => body.serialize_pdu(version, buf),
77            PduBody::DataQuery(body) => body.serialize_pdu(version, buf),
78            PduBody::SetData(body) => body.serialize_pdu(version, buf),
79            PduBody::Data(body) => body.serialize_pdu(version, buf),
80            PduBody::EventReport(body) => body.serialize_pdu(version, buf),
81            PduBody::Comment(body) => body.serialize_pdu(version, buf),
82            PduBody::ElectromagneticEmission(body) => body.serialize_pdu(version, buf),
83            PduBody::Designator(body) => body.serialize_pdu(version, buf),
84            PduBody::Transmitter(body) => body.serialize_pdu(version, buf),
85            PduBody::Signal(body) => body.serialize_pdu(version, buf),
86            PduBody::Receiver(body) => body.serialize_pdu(version, buf),
87            PduBody::IFF(body) => body.serialize_pdu(version, buf),
88            PduBody::UnderwaterAcoustic(body) => body.serialize_pdu(version, buf),
89            PduBody::SupplementalEmissionEntityState(body) => body.serialize_pdu(version, buf),
90            // PduBody::IntercomSignal(body) => { body.serialize_pdu(version, buf) }
91            // PduBody::IntercomControl(body) => { body.serialize_pdu(version, buf) }
92            PduBody::AggregateState(body) => body.serialize_pdu(version, buf),
93            PduBody::IsGroupOf(body) => body.serialize_pdu(version, buf),
94            PduBody::TransferOwnership(body) => body.serialize_pdu(version, buf),
95            PduBody::IsPartOf(body) => body.serialize_pdu(version, buf),
96            // PduBody::MinefieldState(body) => { body.serialize_pdu(version, buf) }
97            // PduBody::MinefieldQuery(body) => { body.serialize_pdu(version, buf) }
98            // PduBody::MinefieldData(body) => { body.serialize_pdu(version, buf) }
99            // PduBody::MinefieldResponseNACK(body) => { body.serialize_pdu(version, buf) }
100            // PduBody::EnvironmentalProcess(body) => { body.serialize_pdu(version, buf) }
101            // PduBody::GriddedData(body) => { body.serialize_pdu(version, buf) }
102            // PduBody::PointObjectState(body) => { body.serialize_pdu(version, buf) }
103            // PduBody::LinearObjectState(body) => { body.serialize_pdu(version, buf) }
104            // PduBody::ArealObjectState(body) => { body.serialize_pdu(version, buf) }
105            // PduBody::TSPI(body) => { body.serialize_pdu(version, buf) }
106            // PduBody::Appearance(body) => { body.serialize_pdu(version, buf) }
107            // PduBody::ArticulatedParts(body) => { body.serialize_pdu(version, buf) }
108            // PduBody::LEFire(body) => { body.serialize_pdu(version, buf) }
109            // PduBody::LEDetonation(body) => { body.serialize_pdu(version, buf) }
110            PduBody::CreateEntityR(body) => body.serialize_pdu(version, buf),
111            PduBody::RemoveEntityR(body) => body.serialize_pdu(version, buf),
112            PduBody::StartResumeR(body) => body.serialize_pdu(version, buf),
113            PduBody::StopFreezeR(body) => body.serialize_pdu(version, buf),
114            PduBody::AcknowledgeR(body) => body.serialize_pdu(version, buf),
115            PduBody::ActionRequestR(body) => body.serialize_pdu(version, buf),
116            PduBody::ActionResponseR(body) => body.serialize_pdu(version, buf),
117            PduBody::DataQueryR(body) => body.serialize_pdu(version, buf),
118            PduBody::SetDataR(body) => body.serialize_pdu(version, buf),
119            PduBody::DataR(body) => body.serialize_pdu(version, buf),
120            PduBody::EventReportR(body) => body.serialize_pdu(version, buf),
121            PduBody::CommentR(body) => body.serialize_pdu(version, buf),
122            PduBody::RecordR(body) => body.serialize_pdu(version, buf),
123            PduBody::SetRecordR(body) => body.serialize_pdu(version, buf),
124            PduBody::RecordQueryR(body) => body.serialize_pdu(version, buf),
125            PduBody::CollisionElastic(body) => body.serialize_pdu(version, buf),
126            PduBody::EntityStateUpdate(body) => body.serialize_pdu(version, buf),
127            // PduBody::DirectedEnergyFire(body) => { body.serialize_pdu(version, buf) }
128            // PduBody::EntityDamageStatus(body) => { body.serialize_pdu(version, buf) }
129            // PduBody::InformationOperationsAction(body) => { body.serialize_pdu(version, buf) }
130            // PduBody::InformationOperationsReport(body) => { body.serialize_pdu(version, buf) }
131            PduBody::Attribute(body) => body.serialize_pdu(version, buf),
132            _ => 0,
133        };
134
135        Ok(header_size + body_size)
136    }
137}
138
139impl Serialize for EntityId {
140    fn serialize(&self, buf: &mut BytesMut) -> u16 {
141        let num_bytes = self.simulation_address.serialize(buf);
142        buf.put_u16(self.entity_id);
143        num_bytes + 2
144    }
145}
146
147impl Serialize for SimulationAddress {
148    fn serialize(&self, buf: &mut BytesMut) -> u16 {
149        buf.put_u16(self.site_id);
150        buf.put_u16(self.application_id);
151        4
152    }
153}
154
155impl Serialize for EventId {
156    fn serialize(&self, buf: &mut BytesMut) -> u16 {
157        let num_bytes = self.simulation_address.serialize(buf);
158        buf.put_u16(self.event_id);
159        num_bytes + 2
160    }
161}
162
163impl Serialize for VectorF32 {
164    fn serialize(&self, buf: &mut BytesMut) -> u16 {
165        buf.put_f32(self.first_vector_component);
166        buf.put_f32(self.second_vector_component);
167        buf.put_f32(self.third_vector_component);
168        12
169    }
170}
171
172impl Serialize for Location {
173    fn serialize(&self, buf: &mut BytesMut) -> u16 {
174        buf.put_f64(self.x_coordinate);
175        buf.put_f64(self.y_coordinate);
176        buf.put_f64(self.z_coordinate);
177        24
178    }
179}
180
181impl Serialize for Orientation {
182    fn serialize(&self, buf: &mut BytesMut) -> u16 {
183        buf.put_f32(self.psi);
184        buf.put_f32(self.theta);
185        buf.put_f32(self.phi);
186        12
187    }
188}
189
190impl Serialize for MunitionDescriptor {
191    fn serialize(&self, buf: &mut BytesMut) -> u16 {
192        let entity_bytes = self.entity_type.serialize(buf);
193        buf.put_u16(self.warhead.into());
194        buf.put_u16(self.fuse.into());
195        buf.put_u16(self.quantity);
196        buf.put_u16(self.rate);
197        entity_bytes + 8
198    }
199}
200
201impl Serialize for ExplosionDescriptor {
202    fn serialize(&self, buf: &mut BytesMut) -> u16 {
203        let entity_bytes = self.entity_type.serialize(buf);
204        buf.put_u16(self.explosive_material.into());
205        buf.put_u16(0u16);
206        buf.put_f32(self.explosive_force);
207        entity_bytes + 8
208    }
209}
210
211impl Serialize for ExpendableDescriptor {
212    fn serialize(&self, buf: &mut BytesMut) -> u16 {
213        let entity_bytes = self.entity_type.serialize(buf);
214        buf.put_u64(0u64);
215        entity_bytes + 8
216    }
217}
218
219impl Serialize for ClockTime {
220    fn serialize(&self, buf: &mut BytesMut) -> u16 {
221        buf.put_i32(self.hour);
222        buf.put_u32(self.time_past_hour);
223        8
224    }
225}
226
227impl Serialize for FixedDatum {
228    fn serialize(&self, buf: &mut BytesMut) -> u16 {
229        buf.put_u32(self.datum_id.into());
230        buf.put_u32(self.datum_value);
231
232        8
233    }
234}
235
236impl Serialize for VariableDatum {
237    #[allow(clippy::cast_possible_truncation)]
238    fn serialize(&self, buf: &mut BytesMut) -> u16 {
239        const ALIGNMENT_BYTES: usize = 8; // 64-bits alignment
240
241        let data_length_bytes: usize = self.datum_value.len();
242        let padded = length_padded_to_num(data_length_bytes, ALIGNMENT_BYTES);
243        let padding_length_bytes = padded.padding_length;
244
245        buf.put_u32(self.datum_id.into());
246        buf.put_u32((data_length_bytes * 8) as u32);
247        buf.put_slice(&self.datum_value);
248        buf.put_bytes(0, padding_length_bytes);
249
250        8 + padded.record_length as u16
251    }
252}
253
254impl Serialize for VariableParameter {
255    fn serialize(&self, buf: &mut BytesMut) -> u16 {
256        match self {
257            VariableParameter::Articulated(inner) => {
258                buf.put_u8(VariableParameterRecordType::ArticulatedPart.into());
259                1 + inner.serialize(buf)
260            }
261            VariableParameter::Attached(inner) => {
262                buf.put_u8(VariableParameterRecordType::AttachedPart.into());
263                1 + inner.serialize(buf)
264            }
265            VariableParameter::Separation(inner) => {
266                buf.put_u8(VariableParameterRecordType::Separation.into());
267                1 + inner.serialize(buf)
268            }
269            VariableParameter::EntityType(inner) => {
270                buf.put_u8(VariableParameterRecordType::EntityType.into());
271                1 + inner.serialize(buf)
272            }
273            VariableParameter::EntityAssociation(inner) => {
274                buf.put_u8(VariableParameterRecordType::EntityAssociation.into());
275                1 + inner.serialize(buf)
276            }
277            VariableParameter::Unspecified(parameter_type, value) => {
278                buf.put_u8(*parameter_type);
279                buf.put(&value[..]);
280                16
281            }
282        }
283    }
284}
285
286impl Serialize for ArticulatedPart {
287    fn serialize(&self, buf: &mut BytesMut) -> u16 {
288        buf.put_u8(self.change_indicator);
289        buf.put_u16(self.attachment_id);
290        let type_class: u32 = self.type_class.into();
291        let type_metric: u32 = self.type_metric.into();
292        buf.put_u32(type_class + type_metric);
293        buf.put_f32(self.parameter_value);
294        buf.put_u32(0u32);
295
296        15
297    }
298}
299
300impl Serialize for AttachedPart {
301    fn serialize(&self, buf: &mut BytesMut) -> u16 {
302        buf.put_u8(self.detached_indicator.into());
303        buf.put_u16(self.attachment_id);
304        buf.put_u32(self.parameter_type.into());
305        self.attached_part_type.serialize(buf);
306
307        15
308    }
309}
310
311impl Serialize for SeparationParameter {
312    fn serialize(&self, buf: &mut BytesMut) -> u16 {
313        buf.put_u8(self.reason.into());
314        buf.put_u8(self.pre_entity_indicator.into());
315        buf.put_u8(0u8);
316        self.parent_entity_id.serialize(buf);
317        buf.put_u16(0u16);
318        buf.put_u16(self.station_name.into());
319        buf.put_u16(self.station_number);
320
321        15
322    }
323}
324
325impl Serialize for EntityTypeParameter {
326    fn serialize(&self, buf: &mut BytesMut) -> u16 {
327        buf.put_u8(self.change_indicator.into());
328        self.entity_type.serialize(buf);
329        buf.put_u16(0u16);
330        buf.put_u32(0u32);
331
332        15
333    }
334}
335
336impl Serialize for EntityAssociationParameter {
337    fn serialize(&self, buf: &mut BytesMut) -> u16 {
338        buf.put_u8(self.change_indicator.into());
339        buf.put_u8(self.association_status.into());
340        buf.put_u8(self.association_type.into());
341        self.entity_id.serialize(buf);
342        buf.put_u16(self.own_station_location.into());
343        buf.put_u8(self.physical_connection_type.into());
344        buf.put_u8(self.group_member_type.into());
345        buf.put_u16(self.group_number);
346
347        15
348    }
349}
350
351impl Serialize for BeamData {
352    fn serialize(&self, buf: &mut BytesMut) -> u16 {
353        buf.put_f32(self.azimuth_center);
354        buf.put_f32(self.azimuth_sweep);
355        buf.put_f32(self.elevation_center);
356        buf.put_f32(self.elevation_sweep);
357        buf.put_f32(self.sweep_sync);
358
359        20
360    }
361}
362
363impl Serialize for SupplyQuantity {
364    fn serialize(&self, buf: &mut BytesMut) -> u16 {
365        let type_bytes = self.supply_type.serialize(buf);
366        buf.put_f32(self.quantity);
367
368        type_bytes + 4
369    }
370}
371
372impl Serialize for RecordSpecification {
373    fn serialize(&self, buf: &mut BytesMut) -> u16 {
374        buf.put_u32(self.record_sets.len() as u32);
375        let record_sets_bytes: u16 = self
376            .record_sets
377            .iter()
378            .map(|record_set| record_set.serialize(buf))
379            .sum();
380
381        FOUR_OCTETS as u16 + record_sets_bytes
382    }
383}
384
385impl Serialize for RecordSet {
386    fn serialize(&self, buf: &mut BytesMut) -> u16 {
387        buf.put_u32(self.record_id.into());
388        buf.put_u32(self.record_serial_number);
389        buf.put_u32(0u32);
390
391        buf.put_u16(self.record_length_bytes * ONE_BYTE_IN_BITS as u16); // record length in bits
392        buf.put_u16(self.records.len() as u16); // record count
393        let records_bytes = self
394            .records
395            .iter()
396            .map(|record| {
397                buf.put(record.as_slice());
398                record.len()
399            })
400            .sum::<usize>() as u16;
401        let padded_record = length_padded_to_num(records_bytes as usize, EIGHT_OCTETS);
402        buf.put_bytes(0u8, padded_record.padding_length);
403
404        16 + records_bytes + padded_record.padding_length as u16
405    }
406}
407
408#[cfg(test)]
409mod tests {
410    use crate::common::Serialize;
411    use crate::common::model::{PduHeader, Timestamp};
412    use crate::constants::PDU_HEADER_LEN_BYTES;
413    use crate::enumerations::{LvcIndicator, PduType};
414    use crate::v7::model::PduStatus;
415    use alloc::vec;
416    use bytes::BytesMut;
417
418    #[test]
419    fn serialize_header() {
420        let header = PduHeader::new_v6(1, PduType::EntityState)
421            .with_timestamp(Timestamp::new(10u32))
422            .with_length(0);
423        let mut buf = BytesMut::with_capacity(PDU_HEADER_LEN_BYTES as usize);
424
425        header.serialize(&mut buf);
426
427        let expected: [u8; 12] = [
428            0x06, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x00,
429        ];
430        assert_eq!(buf.as_ref(), expected.as_ref());
431    }
432
433    #[test]
434    fn serialize_header_v7_no_status() {
435        let header = PduHeader::new_v7(1, PduType::EntityState)
436            .with_timestamp(Timestamp::new(10u32))
437            .with_length(0);
438        let mut buf = BytesMut::with_capacity(PDU_HEADER_LEN_BYTES as usize);
439
440        header.serialize(&mut buf);
441
442        let expected: [u8; 12] = [
443            0x07, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x00,
444        ];
445        assert_eq!(buf.as_ref(), expected.as_ref());
446    }
447
448    #[test]
449    fn serialize_header_v7_with_status() {
450        let header = PduHeader::new_v7(1, PduType::EntityState)
451            .with_timestamp(Timestamp::new(10u32))
452            .with_length(0)
453            .with_pdu_status(PduStatus::default().with_lvc_indicator(LvcIndicator::Live));
454        let mut buf = BytesMut::with_capacity(PDU_HEADER_LEN_BYTES as usize);
455
456        header.serialize(&mut buf);
457
458        let expected: [u8; 12] = [
459            0x07, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0c, 0x02, 0x00,
460        ];
461        assert_eq!(buf.as_ref(), expected.as_ref());
462    }
463
464    #[test]
465    fn serialize_variable_datum() {
466        use crate::enumerations::VariableRecordType;
467        use crate::model::VariableDatum;
468
469        let variable_datum = VariableDatum::new(VariableRecordType::Unspecified(1), vec![1, 2]);
470
471        let mut buf = BytesMut::new();
472        variable_datum.serialize(&mut buf);
473
474        let expected = [
475            0, 0, 0, 1, // Datum ID
476            0, 0, 0, 16, // Length of the data field in bits
477            // Data field + Padding
478            1, 2, // Actual data
479            0, 0, 0, 0, 0, 0, // Padding (for 64-bit aligment)
480        ];
481
482        assert_eq!(buf.as_ref(), expected.as_ref());
483    }
484}