1use num_complex::Complex;
8
9use crate::unpack_iq_24bit;
10
11#[derive(Debug, Clone, Default)]
17pub struct P1Status {
18 pub ptt: bool,
20 pub adc_overflow: u8,
22 pub forward_power: u16,
24 pub reverse_power: u16,
26 pub exciter_power: u16,
28 pub supply_voltage: u16,
30 pub response_addr: u8,
32}
33
34pub struct P1RxFrame {
40 pub samples: Vec<Vec<Complex<f64>>>,
42 pub status: P1Status,
44}
45
46pub fn parse_rx_packet(data: &[u8], nddc: usize) -> Option<P1RxFrame> {
59 if data.len() < 1032 || nddc == 0 {
60 return None;
61 }
62
63 let mut samples: Vec<Vec<Complex<f64>>> = (0..nddc).map(|_| Vec::new()).collect();
64 let mut status = P1Status::default();
65
66 for frame_idx in 0..2 {
67 let base = 8 + frame_idx * 512; let sync_ok = data[base] == 0x7F && data[base + 1] == 0x7F && data[base + 2] == 0x7F;
69 if !sync_ok {
70 return None;
71 }
72
73 let c0 = data[base + 3];
75 let c1 = data[base + 4];
76 let c2 = data[base + 5];
77 let c3 = data[base + 6];
78 let c4 = data[base + 7];
79
80 parse_response_control_bytes(&mut status, c0, c1, c2, c3, c4);
81
82 let iq_start = base + 8;
85 let iq_end = base + 512;
86 let bytes_per_sample = 6; let bytes_per_row = bytes_per_sample * nddc + 2; let mut offset = iq_start;
90 while offset + bytes_per_row <= iq_end {
91 for (ddc, ddc_samples) in samples.iter_mut().enumerate().take(nddc) {
92 let sample_offset = offset + ddc * bytes_per_sample;
93 if sample_offset + bytes_per_sample <= data.len() {
94 let iq = unpack_iq_24bit(data, sample_offset);
95 ddc_samples.push(iq);
96 }
97 }
98 offset += bytes_per_row;
99 }
100 }
101
102 Some(P1RxFrame { samples, status })
103}
104
105pub fn parse_response_control_bytes(status: &mut P1Status, c0: u8, c1: u8, c2: u8, c3: u8, c4: u8) {
111 let addr = c0 & 0x7E;
112 status.ptt = (c0 & 0x01) != 0;
113 status.response_addr = addr;
114
115 match addr {
116 0x00 => {
117 status.adc_overflow = c1;
118 }
119 0x08 => {
120 status.exciter_power = ((c1 as u16) << 8) | (c2 as u16);
121 status.forward_power = ((c3 as u16) << 8) | (c4 as u16);
122 }
123 0x10 => {
124 status.reverse_power = ((c1 as u16) << 8) | (c2 as u16);
125 }
126 0x18 => {
127 status.supply_voltage = ((c3 as u16) << 8) | (c4 as u16);
128 }
129 _ => {}
130 }
131}
132
133pub fn build_tx_packet(
150 seq: u32,
151 tx_iq: &[Complex<f64>],
152 control_bytes: [u8; 5],
153 control_bytes2: [u8; 5],
154) -> Vec<u8> {
155 let mut packet = vec![0u8; 1032];
156
157 packet[0] = 0xEF;
159 packet[1] = 0xFE;
160 packet[2] = 0x01; packet[3] = 0x02; packet[4] = ((seq >> 24) & 0xFF) as u8;
165 packet[5] = ((seq >> 16) & 0xFF) as u8;
166 packet[6] = ((seq >> 8) & 0xFF) as u8;
167 packet[7] = (seq & 0xFF) as u8;
168
169 for frame_idx in 0..2u32 {
171 let base = 8 + (frame_idx as usize) * 512;
172
173 packet[base] = 0x7F;
175 packet[base + 1] = 0x7F;
176 packet[base + 2] = 0x7F;
177
178 let cb = if frame_idx == 0 {
180 &control_bytes
181 } else {
182 &control_bytes2
183 };
184 packet[base + 3] = cb[0];
185 packet[base + 4] = cb[1];
186 packet[base + 5] = cb[2];
187 packet[base + 6] = cb[3];
188 packet[base + 7] = cb[4];
189
190 let iq_start = base + 8;
192 let iq_end = base + 512;
193 let bytes_per_block = 8; let max_samples = (iq_end - iq_start) / bytes_per_block; let sample_offset = (frame_idx as usize) * max_samples;
197 for i in 0..max_samples {
198 let sample_idx = sample_offset + i;
199 let (iv, qv) = if sample_idx < tx_iq.len() {
200 let s = &tx_iq[sample_idx];
201 let i_val = (s.re.clamp(-1.0, 1.0) * 32767.0) as i16;
202 let q_val = ((-s.im).clamp(-1.0, 1.0) * 32767.0) as i16;
204 (i_val, q_val)
205 } else {
206 (0i16, 0i16)
207 };
208
209 let offset = iq_start + i * bytes_per_block;
210 packet[offset] = 0;
212 packet[offset + 1] = 0;
213 packet[offset + 2] = 0;
214 packet[offset + 3] = 0;
215 packet[offset + 4] = ((iv as u16) >> 8) as u8;
217 packet[offset + 5] = (iv as u16 & 0xFF) as u8;
218 packet[offset + 6] = ((qv as u16) >> 8) as u8;
219 packet[offset + 7] = (qv as u16 & 0xFF) as u8;
220 }
221 }
222
223 packet
224}
225
226pub fn build_control_bytes(
248 address: u8,
249 frequency: u64,
250 sample_rate_index: u8,
251 ptt: bool,
252 nddc: u8,
253 rx_attenuation: u8,
254 tx_drive: u8,
255) -> [u8; 5] {
256 let mut cb = [0u8; 5];
257 let ptt_bit = if ptt { 0x01 } else { 0x00 };
258 cb[0] = address | ptt_bit;
259
260 match address {
261 0x00 => {
262 cb[1] = sample_rate_index & 0x03;
264 cb[4] = (nddc.saturating_sub(1) & 0x07) << 3 | 0x04;
267 }
268 0x02 | 0x04 | 0x06 | 0x08 | 0x0A | 0x0C | 0x0E => {
269 let freq = frequency.min(u32::MAX as u64) as u32;
271 cb[1] = ((freq >> 24) & 0xFF) as u8;
272 cb[2] = ((freq >> 16) & 0xFF) as u8;
273 cb[3] = ((freq >> 8) & 0xFF) as u8;
274 cb[4] = (freq & 0xFF) as u8;
275 }
276 0x12 => {
277 cb[1] = tx_drive;
279 }
280 0x14 => {
281 cb[4] = rx_attenuation & 0x1F;
283 }
284 _ => {}
285 }
286
287 cb
288}
289
290#[cfg(test)]
295mod tests {
296 use super::*;
297
298 #[test]
299 fn parse_rx_packet_too_short() {
300 let data = vec![0u8; 100];
301 assert!(parse_rx_packet(&data, 1).is_none());
302 }
303
304 #[test]
305 fn parse_rx_packet_zero_nddc() {
306 let data = vec![0u8; 1032];
307 assert!(parse_rx_packet(&data, 0).is_none());
308 }
309
310 #[test]
311 fn parse_rx_packet_bad_sync() {
312 let mut data = vec![0u8; 1032];
313 assert!(parse_rx_packet(&data, 1).is_none());
315
316 data[8] = 0x7F;
318 data[9] = 0x7F;
319 data[10] = 0x7F;
320 assert!(parse_rx_packet(&data, 1).is_none());
321 }
322
323 #[test]
324 fn parse_rx_packet_valid_frame() {
325 let mut data = vec![0u8; 1032];
326 data[8] = 0x7F;
328 data[9] = 0x7F;
329 data[10] = 0x7F;
330 data[520] = 0x7F;
331 data[521] = 0x7F;
332 data[522] = 0x7F;
333
334 let frame = parse_rx_packet(&data, 1).unwrap();
335 assert_eq!(frame.samples.len(), 1);
336 assert_eq!(frame.samples[0].len(), 126);
338 }
339
340 #[test]
341 fn build_tx_packet_structure() {
342 let tx_iq = vec![Complex::new(0.5, -0.5); 126];
343 let cb1 = [0x00, 0x01, 0x00, 0x00, 0x00];
344 let cb2 = [0x02, 0x00, 0x07, 0x07, 0x40];
345
346 let pkt = build_tx_packet(42, &tx_iq, cb1, cb2);
347 assert_eq!(pkt.len(), 1032);
348
349 assert_eq!(pkt[0], 0xEF);
351 assert_eq!(pkt[1], 0xFE);
352 assert_eq!(pkt[2], 0x01);
353 assert_eq!(pkt[3], 0x02);
354
355 assert_eq!(u32::from_be_bytes([pkt[4], pkt[5], pkt[6], pkt[7]]), 42);
357
358 assert_eq!(&pkt[8..11], &[0x7F, 0x7F, 0x7F]);
360 assert_eq!(&pkt[11..16], &cb1);
362
363 assert_eq!(&pkt[520..523], &[0x7F, 0x7F, 0x7F]);
365 assert_eq!(&pkt[523..528], &cb2);
367 }
368
369 #[test]
370 fn build_control_bytes_address_0x00() {
371 let cb = build_control_bytes(0x00, 7_074_000, 1, false, 2, 0, 0);
372 assert_eq!(cb[0], 0x00); assert_eq!(cb[1], 0x01); assert_eq!(cb[4], (1 << 3) | 0x04); }
376
377 #[test]
378 fn build_control_bytes_address_0x00_ptt() {
379 let cb = build_control_bytes(0x00, 7_074_000, 0, true, 1, 0, 0);
380 assert_eq!(cb[0], 0x01); }
382
383 #[test]
384 fn build_control_bytes_frequency() {
385 let freq: u64 = 14_200_000;
386 let cb = build_control_bytes(0x04, freq, 0, false, 1, 0, 0);
387 assert_eq!(cb[0], 0x04);
388 let parsed_freq = u32::from_be_bytes([cb[1], cb[2], cb[3], cb[4]]);
389 assert_eq!(parsed_freq, freq as u32);
390 }
391
392 #[test]
393 fn build_control_bytes_attenuation() {
394 let cb = build_control_bytes(0x14, 0, 0, false, 1, 20, 0);
395 assert_eq!(cb[0], 0x14);
396 assert_eq!(cb[4], 20);
397 }
398
399 #[test]
400 fn build_control_bytes_tx_drive() {
401 let cb = build_control_bytes(0x12, 0, 0, false, 1, 0, 200);
402 assert_eq!(cb[0], 0x12);
403 assert_eq!(cb[1], 200);
404 }
405
406 #[test]
407 fn parse_response_control_bytes_addr_0x08() {
408 let mut status = P1Status::default();
409 parse_response_control_bytes(&mut status, 0x08, 0x12, 0x34, 0x56, 0x78);
411 assert_eq!(status.response_addr, 0x08);
412 assert_eq!(status.exciter_power, 0x1234);
413 assert_eq!(status.forward_power, 0x5678);
414 assert!(!status.ptt);
415 }
416
417 #[test]
418 fn parse_response_control_bytes_ptt() {
419 let mut status = P1Status::default();
420 parse_response_control_bytes(&mut status, 0x01, 0, 0, 0, 0); assert!(status.ptt);
422 assert_eq!(status.response_addr, 0x00);
423 }
424
425 #[test]
426 fn roundtrip_tx_rx() {
427 let tx_iq = vec![Complex::new(0.0, 0.0); 126];
429 let cb1 = [0x00, 0x00, 0x00, 0x00, 0x00];
430 let cb2 = [0x00, 0x00, 0x00, 0x00, 0x00];
431
432 let pkt = build_tx_packet(0, &tx_iq, cb1, cb2);
433 assert_eq!(pkt.len(), 1032);
434 assert_eq!(&pkt[8..11], &[0x7F, 0x7F, 0x7F]);
436 assert_eq!(&pkt[520..523], &[0x7F, 0x7F, 0x7F]);
437 }
438}