1use crate::{GF64K, SSDVPacket};
2use generic_array::GenericArray;
3#[cfg(feature = "std")]
4use thiserror::Error;
5
6#[derive(Debug)]
18pub struct Encoder<'a, S> {
19 buffer: &'a mut [S],
20}
21
22#[allow(clippy::enum_variant_names)] #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
27#[cfg_attr(feature = "std", derive(Error))]
28pub enum EncoderError {
29 #[cfg_attr(feature = "std", error("encoder input is empty"))]
31 EmptyInput,
32 #[cfg_attr(feature = "std", error("encoder input is too long"))]
34 TooLongInput,
35 #[cfg_attr(feature = "std", error("non-systematic packet in encoder input"))]
37 NonSystematicInput,
38}
39
40fn wj_inv(j: u16, k: u16) -> GF64K {
43 let xj = GF64K::from(j);
44 let mut ret = GF64K::from(1);
45 for m in 0..k {
46 if m != j {
47 let xm = GF64K::from(m);
48 ret *= xj - xm;
49 }
50 }
51 ret
52}
53
54impl<S: SSDVPacket> Encoder<'_, S> {
55 pub fn new(systematic_packets: &mut [S]) -> Result<Encoder<S>, EncoderError> {
65 if systematic_packets.is_empty() {
66 return Err(EncoderError::EmptyInput);
67 }
68 if systematic_packets.len() > usize::from(u16::MAX) {
69 return Err(EncoderError::TooLongInput);
70 }
71 if systematic_packets[0].is_fec_packet() {
73 return Err(EncoderError::NonSystematicInput);
74 }
75 let mut encoder = Encoder {
76 buffer: systematic_packets,
77 };
78 encoder.values_to_lagrange();
79 Ok(encoder)
80 }
81
82 fn values_to_lagrange(&mut self) {
83 let k = self.num_systematic();
96 for j in 0..k {
97 let wj = GF64K::from(1) / wj_inv(j, k);
99 let data = self.buffer[usize::from(j)].data_as_mut();
101 for word in data.chunks_exact_mut(2) {
102 let word: &mut [u8; 2] = word.try_into().unwrap();
103 let yj = GF64K::from(u16::from_be_bytes(*word));
104 let yj_wj = yj * wj;
105 *word = u16::from(yj_wj).to_be_bytes();
106 }
107 }
108 }
109
110 pub fn encode(&self, packet_id: u16, output: &mut S) {
117 self.encode_header(packet_id, output);
118 if output.is_fec_packet() {
119 self.encode_fec_data(packet_id, output.data_as_mut());
120 } else {
121 self.encode_systematic_data(packet_id, output.data_as_mut());
122 }
123 output.update_crc32();
124 }
125
126 fn encode_header(&self, packet_id: u16, output: &mut S) {
127 output.set_fixed_fields();
128 output.callsign_as_mut().copy_from_slice(self.callsign());
129 output.set_image_id(self.image_id());
130 output.set_packet_id(packet_id);
131 let is_fec = packet_id >= self.num_systematic();
132 if is_fec {
133 output.set_number_systematic_packets(self.num_systematic());
134 } else {
135 output.set_width(self.image_width());
136 output.set_height(self.image_height());
137 }
138 output.set_flags(self.flags());
139 output.set_eoi(packet_id == self.num_systematic() - 1);
140 output.set_fec_packet(is_fec);
141 }
142
143 fn encode_fec_data(&self, packet_id: u16, data: &mut GenericArray<u8, S::DataLen>) {
144 let x = GF64K::from(packet_id);
146 let k = self.num_systematic();
147 let mut lx = GF64K::from(1);
149 for j in 0..k {
150 let xj = GF64K::from(j);
151 lx *= x - xj;
152 }
153
154 for (r, word) in data.chunks_exact_mut(2).enumerate() {
157 let mut sum = GF64K::from(0);
158 for (j, wj_yj_s) in self.buffer.iter().map(|packet| packet.data()).enumerate() {
159 let wj_yj = GF64K::from(u16::from_be_bytes(
160 wj_yj_s[2 * r..2 * r + 2].try_into().unwrap(),
161 ));
162 let xj = GF64K::from(j as u16);
163 sum += wj_yj / (x - xj);
164 }
165 let word: &mut [u8; 2] = word.try_into().unwrap();
166 let result = lx * sum;
167 *word = u16::from(result).to_be_bytes();
168 }
169 }
170
171 fn encode_systematic_data(&self, packet_id: u16, data: &mut GenericArray<u8, S::DataLen>) {
172 let wjinv = wj_inv(packet_id, self.num_systematic());
177 for (word_in, word_out) in self.buffer[usize::from(packet_id)]
178 .data()
179 .chunks_exact(2)
180 .zip(data.chunks_exact_mut(2))
181 {
182 let wj_yj = GF64K::from(u16::from_be_bytes(word_in.try_into().unwrap()));
183 let yj = wj_yj * wjinv;
184 let word_out: &mut [u8; 2] = word_out.try_into().unwrap();
185 *word_out = u16::from(yj).to_be_bytes();
186 }
187 }
188
189 fn callsign(&self) -> &GenericArray<u8, S::CallsignLen> {
190 self.buffer[0].callsign()
191 }
192
193 fn num_systematic(&self) -> u16 {
194 self.buffer.len() as u16
195 }
196
197 fn image_id(&self) -> u8 {
198 self.buffer[0].image_id()
199 }
200
201 fn image_width(&self) -> u8 {
202 self.buffer[0].width().unwrap()
203 }
204
205 fn image_height(&self) -> u8 {
206 self.buffer[0].height().unwrap()
207 }
208
209 fn flags(&self) -> u8 {
210 self.buffer[0].flags()
211 }
212}
213
214#[derive(Debug)]
220pub struct Decoder {}
221
222#[derive(Debug)]
223struct DecoderHelper<'a, 'b, S: SSDVPacket> {
224 input: &'a mut [S],
225 output: &'b mut [S],
226 callsign: GenericArray<u8, S::CallsignLen>,
227 num_systematic: u16,
228 image_id: u8,
229 image_width: u8,
230 image_height: u8,
231 flags: u8,
232}
233
234#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
238#[cfg_attr(feature = "std", derive(Error))]
239pub enum DecoderError {
240 #[cfg_attr(feature = "std", error("EOI set on FEC packet"))]
242 EoiOnFecPacket,
243 #[cfg_attr(feature = "std", error("EOI set on several different packets"))]
245 DuplicatedEoi,
246 #[cfg_attr(
249 feature = "std",
250 error("mismatched number of systematic packets on different FEC packets")
251 )]
252 NumSystematicMismatch,
253 #[cfg_attr(
258 feature = "std",
259 error("could not determine number of systematic packets")
260 )]
261 UnknownNumSystematic,
262 #[cfg_attr(
265 feature = "std",
266 error("mismatch between EOI and number of systematic packets")
267 )]
268 EoiFecMismatch,
269 #[cfg_attr(feature = "std", error("not enough input packets"))]
274 NotEnoughInput,
275 #[cfg_attr(feature = "std", error("output buffer is too short"))]
280 OutputTooShort,
281 #[cfg_attr(feature = "std", error("wrong packet ID on systematic packet"))]
283 WrongSystematicId,
284 #[cfg_attr(feature = "std", error("multiple image IDs"))]
286 MultipleImageIds,
287 #[cfg_attr(feature = "std", error("inconsistent flags on different packets"))]
289 InconsistentFlags,
290 #[cfg_attr(
293 feature = "std",
294 error("mismatched width or height on different systematic packets")
295 )]
296 DimensionsMismatch,
297 #[cfg_attr(feature = "std", error("no systematic packets"))]
302 NoSystematic,
303}
304
305impl Decoder {
306 pub fn decode<'a, S: SSDVPacket>(
317 input: &mut [S],
318 output: &'a mut [S],
319 ) -> Result<&'a mut [S], DecoderError> {
320 let mut decoder = DecoderHelper::new(input, output)?;
321 decoder.init_output();
322 decoder.copy_systematic();
323 if !decoder.all_systematic_obtained() {
324 decoder.values_to_lagrange();
325 decoder.interpolate_missing();
326 }
327 Ok(&mut decoder.output[..usize::from(decoder.num_systematic)])
328 }
329}
330
331impl<'a, 'b, S: SSDVPacket> DecoderHelper<'a, 'b, S> {
332 fn new(input: &'a mut [S], output: &'b mut [S]) -> Result<Self, DecoderError> {
333 let input = Self::remove_duplicates_and_wrong_crcs(input);
334 let num_systematic = Self::find_num_systematic(input)?;
335 if input.is_empty() || input.len() < usize::from(num_systematic) {
340 return Err(DecoderError::NotEnoughInput);
341 }
342 if output.len() < usize::from(num_systematic) {
343 return Err(DecoderError::OutputTooShort);
344 }
345 let callsign = input[0].callsign().clone();
346 Self::check_systematic_ids(input, num_systematic)?;
347 let (image_id, flags) = Self::find_image_id_flags(input)?;
348 let (image_width, image_height) = Self::find_image_dimensions(input)?;
349 Ok(DecoderHelper {
350 input,
351 output,
352 callsign,
353 num_systematic,
354 image_id,
355 image_width,
356 image_height,
357 flags,
358 })
359 }
360
361 fn remove_duplicates_and_wrong_crcs(input: &mut [S]) -> &mut [S] {
362 let mut len = input.len();
363 let mut j = 0;
364 while j < len {
365 if !input[j].crc32_is_valid() {
366 input.copy_within(j + 1..len, j);
368 len -= 1;
369 continue;
370 }
371 let id = input[j].packet_id();
372 let mut k = j + 1;
373 while k < len {
374 if input[k].packet_id() == id {
375 input.copy_within(k + 1..len, k);
377 len -= 1;
378 } else {
379 k += 1;
380 }
381 }
382 j += 1;
383 }
384 &mut input[..len]
385 }
386
387 fn find_num_systematic(input: &[S]) -> Result<u16, DecoderError> {
388 let mut id_eoi = None;
389 let mut from_fec_packets = None;
390 for packet in input {
391 if packet.is_eoi() {
392 if packet.is_fec_packet() {
393 return Err(DecoderError::EoiOnFecPacket);
394 }
395 if id_eoi.is_some() {
396 return Err(DecoderError::DuplicatedEoi);
397 }
398 id_eoi = Some(packet.packet_id());
399 }
400 if let Some(k) = packet.number_systematic_packets() {
401 if let Some(k2) = from_fec_packets {
402 if k != k2 {
403 return Err(DecoderError::NumSystematicMismatch);
404 }
405 } else {
406 from_fec_packets = Some(k);
407 }
408 }
409 }
410 match (id_eoi, from_fec_packets) {
411 (None, None) => Err(DecoderError::UnknownNumSystematic),
412 (Some(k), None) => Ok(k + 1),
413 (None, Some(k)) => Ok(k),
414 (Some(k), Some(k2)) => {
415 if k + 1 == k2 {
416 Ok(k2)
417 } else {
418 Err(DecoderError::EoiFecMismatch)
419 }
420 }
421 }
422 }
423
424 fn check_systematic_ids(input: &[S], num_systematic: u16) -> Result<(), DecoderError> {
425 for packet in input {
426 if !packet.is_fec_packet() && packet.packet_id() >= num_systematic {
427 return Err(DecoderError::WrongSystematicId);
428 }
429 }
430 Ok(())
431 }
432
433 fn find_image_id_flags(input: &[S]) -> Result<(u8, u8), DecoderError> {
434 let image_id = input[0].image_id();
435
436 fn clean_flags(flags: u8) -> u8 {
437 flags & !0x44
439 }
440
441 let flags = clean_flags(input[0].flags());
442
443 for packet in input {
444 if packet.image_id() != image_id {
445 return Err(DecoderError::MultipleImageIds);
446 }
447 if clean_flags(packet.flags()) != flags {
448 return Err(DecoderError::InconsistentFlags);
449 }
450 }
451 Ok((image_id, flags))
452 }
453
454 fn find_image_dimensions(input: &[S]) -> Result<(u8, u8), DecoderError> {
455 let mut dimensions = None;
456 for packet in input {
457 if let Some(width) = packet.width() {
458 let height = packet.height().unwrap();
460 if let Some((w, h)) = dimensions {
461 if w != width || h != height {
462 return Err(DecoderError::DimensionsMismatch);
463 }
464 } else {
465 dimensions = Some((width, height))
466 }
467 }
468 }
469 dimensions.ok_or(DecoderError::NoSystematic)
470 }
471
472 fn init_output(&mut self) {
473 for packet in self.output.iter_mut() {
474 packet.set_packet_id(Self::INVALID_PACKET_ID);
476 }
477 }
478
479 const INVALID_PACKET_ID: u16 = 0xffff;
480
481 fn copy_systematic(&mut self) {
482 for packet in self.input.iter() {
483 if !packet.is_fec_packet() {
484 let id = packet.packet_id();
485 self.output[usize::from(id)].clone_from(packet);
486 }
487 }
488 }
489
490 fn all_systematic_obtained(&self) -> bool {
491 !self.output[..usize::from(self.num_systematic)]
492 .iter()
493 .any(|&packet| packet.packet_id() == Self::INVALID_PACKET_ID)
494 }
495
496 fn wj_inv(&self, j: usize) -> GF64K {
503 let xj = GF64K::from(self.input[j].packet_id());
504 let mut ret = GF64K::from(1);
505 for (m, p) in self.input[0..usize::from(self.num_systematic)]
506 .iter()
507 .enumerate()
508 {
509 if m != j {
510 let xm = GF64K::from(p.packet_id());
511 ret *= xj - xm;
512 }
513 }
514 ret
515 }
516
517 fn values_to_lagrange(&mut self) {
518 for j in 0..usize::from(self.num_systematic) {
520 let wj = GF64K::from(1) / self.wj_inv(j);
521 let data = self.input[j].data_as_mut();
522 for word in data.chunks_exact_mut(2) {
523 let word: &mut [u8; 2] = word.try_into().unwrap();
524 let yj = GF64K::from(u16::from_be_bytes(*word));
525 let yj_wj = yj * wj;
526 *word = u16::from(yj_wj).to_be_bytes();
527 }
528 }
529 }
530
531 fn interpolate_missing(&mut self) {
532 let k = usize::from(self.num_systematic);
534 for (j, packet) in self.output[..k]
535 .iter_mut()
536 .enumerate()
537 .filter(|(_, packet)| packet.packet_id() == Self::INVALID_PACKET_ID)
538 {
539 let x = GF64K::from(j as u16);
541 let mut lx = GF64K::from(1);
542 for p in &self.input[..k] {
543 let xj = GF64K::from(p.packet_id());
544 lx *= x - xj;
545 }
546
547 let data = packet.data_as_mut();
550 for (r, word) in data.chunks_exact_mut(2).enumerate() {
551 let mut sum = GF64K::from(0);
552 for p in &self.input[..k] {
553 let wj_yj_s = p.data();
554 let wj_yj = GF64K::from(u16::from_be_bytes(
555 wj_yj_s[2 * r..2 * r + 2].try_into().unwrap(),
556 ));
557 let xj = GF64K::from(p.packet_id());
558 sum += wj_yj / (x - xj);
559 }
560 let word: &mut [u8; 2] = word.try_into().unwrap();
561 let result = lx * sum;
562 *word = u16::from(result).to_be_bytes();
563 }
564
565 packet.set_fixed_fields();
567 packet.callsign_as_mut().copy_from_slice(&self.callsign);
568 packet.set_image_id(self.image_id);
569 packet.set_packet_id(j as u16);
570 packet.set_width(self.image_width);
571 packet.set_height(self.image_height);
572 packet.set_flags(self.flags);
573 packet.set_eoi(j == k - 1);
574 packet.set_fec_packet(false);
575
576 packet.update_crc32();
578 }
579 }
580}
581
582#[cfg(test)]
583mod test {
584 use super::*;
585 use crate::{
586 SSDVParameters,
587 packet_formats::longjiang2::{Parameters, SSDVPacket},
588 test_data::IMG_230_SSDV,
589 };
590 use generic_array::typenum::Unsigned;
591
592 const PACKET_LEN: usize = <Parameters as SSDVParameters>::PacketLen::USIZE;
593
594 #[test]
595 fn encode_img_230_systematic() {
596 let mut ssdv = IMG_230_SSDV
597 .chunks_exact(PACKET_LEN)
598 .map(|chunk| SSDVPacket::new_from_slice(chunk).unwrap())
599 .collect::<Vec<SSDVPacket>>();
600 let encoder = Encoder::new(&mut ssdv).unwrap();
601
602 let mut encoded_packet = SSDVPacket::default();
603 for (j, packet) in IMG_230_SSDV.chunks_exact(PACKET_LEN).enumerate() {
604 let original_packet = SSDVPacket::new_from_slice(packet).unwrap();
605 encoder.encode(u16::try_from(j).unwrap(), &mut encoded_packet);
606 assert_eq!(&encoded_packet, &original_packet);
607 }
608 }
609
610 #[test]
611 fn encode_decode_img_230_one_every_n() {
612 let ssdv = IMG_230_SSDV
613 .chunks_exact(PACKET_LEN)
614 .map(|chunk| SSDVPacket::new_from_slice(chunk).unwrap())
615 .collect::<Vec<SSDVPacket>>();
616 let k = ssdv.len();
617 let mut ssdv_copy = ssdv.clone();
619 let encoder = Encoder::new(&mut ssdv_copy).unwrap();
620
621 for one_in_every in 1..=10 {
622 let mut encoded_packets = (0..one_in_every * k)
623 .step_by(one_in_every)
624 .map(|j| {
625 let mut encoded_packet = SSDVPacket::default();
626 encoder.encode(u16::try_from(j).unwrap(), &mut encoded_packet);
627 encoded_packet
628 })
629 .collect::<Vec<SSDVPacket>>();
630
631 let mut output = vec![SSDVPacket::default(); k];
632 Decoder::decode(&mut encoded_packets[..], &mut output[..]).unwrap();
633 for (j, (s, o)) in ssdv.iter().zip(output.iter()).enumerate() {
634 assert_eq!(
635 &s, &o,
636 "SSDV packet {j} is different \
637 (decoding with one in every {one_in_every} packet received)"
638 );
639 }
640 }
641 }
642}