1use crate::common::electromagnetic_emission::model::{
2 Beam, ElectromagneticEmission, EmitterSystem, FundamentalParameterData, JammingTechnique,
3 TrackJam,
4};
5use crate::common::{Serialize, SerializePdu, SupportedVersion};
6use bytes::{BufMut, BytesMut};
7
8impl SerializePdu for ElectromagneticEmission {
9 fn serialize_pdu(&self, _version: SupportedVersion, buf: &mut BytesMut) -> u16 {
10 let entity_bytes = self.emitting_entity_id.serialize(buf);
11 let event_bytes = self.event_id.serialize(buf);
12 buf.put_u8(self.state_update_indicator.into());
13 buf.put_u8(self.emitter_systems.len() as u8);
14 buf.put_u16(0u16);
15 let systems_bytes = self
16 .emitter_systems
17 .iter()
18 .map(|system| system.serialize(buf))
19 .sum::<u16>();
20
21 entity_bytes + event_bytes + 4 + systems_bytes
22 }
23}
24
25impl Serialize for EmitterSystem {
26 fn serialize(&self, buf: &mut BytesMut) -> u16 {
27 let system_length_in_words = self.system_data_length_bytes() / 4;
28 buf.put_u8(system_length_in_words as u8);
29 buf.put_u8(self.beams.len() as u8);
30 buf.put_u16(0u16);
31 buf.put_u16(self.name.into());
32 buf.put_u8(self.function.into());
33 buf.put_u8(self.number);
34 let location_bytes = self.location.serialize(buf);
35
36 let beams_bytes = self
37 .beams
38 .iter()
39 .map(|beam| beam.serialize(buf))
40 .sum::<u16>();
41
42 8 + location_bytes + beams_bytes
43 }
44}
45
46impl Serialize for Beam {
47 fn serialize(&self, buf: &mut BytesMut) -> u16 {
48 let beam_length_in_words = self.beam_data_length_bytes() / 4;
49 buf.put_u8(beam_length_in_words as u8);
50 buf.put_u8(self.number);
51 buf.put_u16(self.parameter_index);
52 let parameter_data_bytes = self.parameter_data.serialize(buf);
53 let beam_data_bytes = self.beam_data.serialize(buf);
54 buf.put_u8(self.beam_function.into());
55 buf.put_u8(self.track_jam_data.len() as u8);
56 buf.put_u8(self.high_density_track_jam.into());
57 buf.put_u8(self.beam_status.into());
58 let technique_bytes = self.jamming_technique.serialize(buf);
59
60 let tracks_bytes = self
61 .track_jam_data
62 .iter()
63 .map(|tracks| tracks.serialize(buf))
64 .sum::<u16>();
65
66 8 + parameter_data_bytes + beam_data_bytes + technique_bytes + tracks_bytes
67 }
68}
69
70impl Serialize for FundamentalParameterData {
71 fn serialize(&self, buf: &mut BytesMut) -> u16 {
72 buf.put_f32(self.frequency);
73 buf.put_f32(self.frequency_range);
74 buf.put_f32(self.effective_power);
75 buf.put_f32(self.pulse_repetition_frequency);
76 buf.put_f32(self.pulse_width);
77
78 20
79 }
80}
81
82impl Serialize for JammingTechnique {
83 fn serialize(&self, buf: &mut BytesMut) -> u16 {
84 buf.put_u8(self.kind);
85 buf.put_u8(self.category);
86 buf.put_u8(self.subcategory);
87 buf.put_u8(self.specific);
88
89 4
90 }
91}
92
93impl Serialize for TrackJam {
94 fn serialize(&self, buf: &mut BytesMut) -> u16 {
95 let entity_bytes = self.entity_id.serialize(buf);
96 buf.put_u8(self.emitter);
97 buf.put_u8(self.beam);
98
99 entity_bytes + 2
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use crate::common::electromagnetic_emission::model::{
106 Beam, ElectromagneticEmission, EmitterSystem, FundamentalParameterData, TrackJam,
107 };
108 use crate::common::model::{
109 BeamData, EntityId, EventId, Pdu, PduHeader, SimulationAddress, VectorF32,
110 };
111 use crate::common::BodyInfo;
112 use crate::enumerations::{
113 ElectromagneticEmissionBeamFunction, EmitterName, EmitterSystemFunction,
114 HighDensityTrackJam,
115 };
116 use bytes::BytesMut;
117
118 #[test]
119 #[allow(clippy::too_many_lines)]
120 fn write_pdu_emission_with_tracks() {
121 let body = ElectromagneticEmission::builder()
122 .with_emitting_entity_id(EntityId::new(500, 11111, 62))
123 .with_event_id(EventId::new(SimulationAddress::new(500, 11111), 577))
124 .with_emitter_system(
125 EmitterSystem::new()
126 .with_name(EmitterName::Unnamed_32175)
127 .with_function(EmitterSystemFunction::Multifunction_1)
128 .with_number(1)
129 .with_location(VectorF32::new(0f32, 0f32, 5f32))
130 .with_beam(
131 Beam::new()
132 .with_number(2)
133 .with_parameter_index(122)
134 .with_parameter_data(
135 FundamentalParameterData::new()
136 .with_frequency(6_000_000_000f32)
137 .with_frequency_range(0f32)
138 .with_effective_power(f32::from_be_bytes([
139 0x42, 0xf0, 0x00, 0x00,
140 ]))
141 .with_pulse_repetition_frequency(0f32)
142 .with_pulse_width(0f32),
143 )
144 .with_beam_data(
145 BeamData::new()
146 .with_azimuth_center(f32::from_be_bytes([
147 0x3e, 0x05, 0xd5, 0xff,
148 ]))
149 .with_azimuth_sweep(f32::from_be_bytes([
150 0x3c, 0x0e, 0xfa, 0x35,
151 ]))
152 .with_elevation_center(f32::from_be_bytes([
153 0x3f, 0x30, 0x95, 0x12,
154 ]))
155 .with_elevation_sweep(f32::from_be_bytes([
156 0x3c, 0x0e, 0xfa, 0x35,
157 ]))
158 .with_sweep_sync(0f32),
159 )
160 .with_beam_function(ElectromagneticEmissionBeamFunction::Illumination)
161 .with_high_density_track_jam(HighDensityTrackJam::NotSelected)
162 .with_track_jam(
163 TrackJam::new()
164 .with_beam(0)
165 .with_emitter(0)
166 .with_entity_id(EntityId::new(500, 11111, 71)),
167 ),
168 )
169 .with_beam(
170 Beam::new()
171 .with_number(1)
172 .with_parameter_index(100)
173 .with_parameter_data(
174 FundamentalParameterData::new()
175 .with_frequency(6_000_000_000f32)
176 .with_frequency_range(0f32)
177 .with_effective_power(f32::from_be_bytes([
178 0x42, 0xf0, 0x00, 0x00,
179 ]))
180 .with_pulse_repetition_frequency(f32::from_be_bytes([
181 0x45, 0x9c, 0x40, 0x00,
182 ]))
183 .with_pulse_width(f32::from_be_bytes([0x42, 0x48, 0x00, 0x00])),
184 )
185 .with_beam_data(
186 BeamData::new()
187 .with_azimuth_center(f32::from_be_bytes([
188 0x3e, 0x05, 0xd6, 0x14,
189 ]))
190 .with_azimuth_sweep(f32::from_be_bytes([
191 0x3c, 0x0e, 0xfa, 0x35,
192 ]))
193 .with_elevation_center(f32::from_be_bytes([
194 0x3f, 0x30, 0x95, 0x54,
195 ]))
196 .with_elevation_sweep(f32::from_be_bytes([
197 0x3c, 0x0e, 0xfa, 0x35,
198 ]))
199 .with_sweep_sync(0f32),
200 )
201 .with_beam_function(ElectromagneticEmissionBeamFunction::Tracking)
202 .with_high_density_track_jam(HighDensityTrackJam::NotSelected)
203 .with_track_jam(
204 TrackJam::new()
205 .with_beam(0)
206 .with_emitter(0)
207 .with_entity_id(EntityId::new(500, 11111, 71)),
208 ),
209 )
210 .with_beam(
211 Beam::new()
212 .with_number(3)
213 .with_parameter_index(212)
214 .with_parameter_data(
215 FundamentalParameterData::new()
216 .with_frequency(6_000_000_000f32)
217 .with_frequency_range(0f32)
218 .with_effective_power(f32::from_be_bytes([
219 0x42, 0xf0, 0x00, 0x00,
220 ]))
221 .with_pulse_repetition_frequency(f32::from_be_bytes([
222 0x43, 0xbb, 0x8c, 0x01,
223 ]))
224 .with_pulse_width(f32::from_be_bytes([0x40, 0xa0, 0x00, 0x00])),
225 )
226 .with_beam_data(
227 BeamData::new()
228 .with_azimuth_center(f32::from_be_bytes([
229 0x3e, 0x05, 0xd6, 0x14,
230 ]))
231 .with_azimuth_sweep(f32::from_be_bytes([
232 0x3c, 0x0e, 0xfa, 0x35,
233 ]))
234 .with_elevation_center(f32::from_be_bytes([
235 0x3f, 0x30, 0x95, 0x54,
236 ]))
237 .with_elevation_sweep(f32::from_be_bytes([
238 0x3c, 0x0e, 0xfa, 0x35,
239 ]))
240 .with_sweep_sync(0f32),
241 )
242 .with_beam_function(
243 ElectromagneticEmissionBeamFunction::CommandGuidance,
244 )
245 .with_high_density_track_jam(HighDensityTrackJam::NotSelected)
246 .with_track_jam(
247 TrackJam::new()
248 .with_beam(0)
249 .with_emitter(0)
250 .with_entity_id(EntityId::new(500, 11111, 71)),
251 ),
252 ),
253 )
254 .build()
255 .into_pdu_body();
256
257 let header = PduHeader::new_v6(1, body.body_type());
258 let pdu = Pdu::finalize_from_parts(header, body, 0);
259
260 let mut buf = BytesMut::with_capacity(228);
261
262 let len = pdu.serialize(&mut buf).unwrap();
263 assert_eq!(len, 228);
264
265 let expected: [u8; 228] = [
266 0x06, 0x01, 0x17, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x01, 0xf4,
267 0x2b, 0x67, 0x00, 0x3e, 0x01, 0xf4, 0x2b, 0x67, 0x02, 0x41, 0x00, 0x01, 0x00, 0x00,
268 0x32, 0x03, 0x00, 0x00, 0x7d, 0xaf, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
269 0x00, 0x00, 0x40, 0xa0, 0x00, 0x00, 0x0f, 0x02, 0x00, 0x7a, 0x4f, 0xb2, 0xd0, 0x5e,
270 0x00, 0x00, 0x00, 0x00, 0x42, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
271 0x00, 0x00, 0x3e, 0x05, 0xd5, 0xff, 0x3c, 0x0e, 0xfa, 0x35, 0x3f, 0x30, 0x95, 0x12,
272 0x3c, 0x0e, 0xfa, 0x35, 0x00, 0x00, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00,
273 0x00, 0x00, 0x01, 0xf4, 0x2b, 0x67, 0x00, 0x47, 0x00, 0x00, 0x0f, 0x01, 0x00, 0x64,
274 0x4f, 0xb2, 0xd0, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x42, 0xf0, 0x00, 0x00, 0x45, 0x9c,
275 0x40, 0x00, 0x42, 0x48, 0x00, 0x00, 0x3e, 0x05, 0xd6, 0x14, 0x3c, 0x0e, 0xfa, 0x35,
276 0x3f, 0x30, 0x95, 0x54, 0x3c, 0x0e, 0xfa, 0x35, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01,
277 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf4, 0x2b, 0x67, 0x00, 0x47, 0x00, 0x00,
278 0x0f, 0x03, 0x00, 0xd4, 0x4f, 0xb2, 0xd0, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x42, 0xf0,
279 0x00, 0x00, 0x43, 0xbb, 0x8c, 0x01, 0x40, 0xa0, 0x00, 0x00, 0x3e, 0x05, 0xd6, 0x14,
280 0x3c, 0x0e, 0xfa, 0x35, 0x3f, 0x30, 0x95, 0x54, 0x3c, 0x0e, 0xfa, 0x35, 0x00, 0x00,
281 0x00, 0x00, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf4, 0x2b, 0x67,
282 0x00, 0x47, 0x00, 0x00,
283 ];
284
285 assert_eq!(buf.as_ref(), expected.as_ref());
286 }
287}