ham_cats/
packet.rs

1use core::fmt::Debug;
2
3use crc::{Crc, CRC_16_IBM_SDLC};
4use labrador_ldpc::decoder::DecodeFrom;
5
6use crate::{
7    buffer::{Buffer, BufferOverflow},
8    error::{CommentError, DecodeError, DigipeatError, EncodeError, PacketRouteAppendError},
9    identity::Identity,
10    interleaver, ldpc, utf8,
11    whisker::{
12        Arbitrary, Comment, Destination, Gps, Identification, NodeInfo, PastHop, Route, RouteHop,
13        Timestamp, ValidatedWhiskerIter, Whisker, WhiskerIter, COMMENT_TYPE,
14    },
15    whitener,
16};
17
18const X25: Crc<u16> = Crc::<u16>::new(&CRC_16_IBM_SDLC);
19
20macro_rules! uniq_whisker {
21    ($t:meta) => {
22        ::paste::paste! {
23            pub fn [<$t:snake:lower>](&self) -> Option<$t> {
24                self.iter().find_map(|w| match w {
25                    Whisker::$t(x) => Some(x),
26                    _ => None,
27                })
28            }
29
30            pub fn [<add_ $t:snake:lower>](&mut self, w: $t) -> Result<(), EncodeError> {
31                if self.[<$t:snake:lower>]().is_some() {
32                    return Err(EncodeError::DuplicateData);
33                }
34
35                try_lock(&mut self.buf, |data| {
36					let mut buf = [0; 256];
37                    // safe to unwrap since we know we have enough space
38                    let out = w.encode(&mut buf).unwrap();
39
40                    data.try_push(crate::whisker::[<$t:snake:upper _TYPE>]).ok().ok_or(EncodeError::CatsOverflow)?;
41                    data.try_extend_from_slice(out).ok().ok_or(EncodeError::CatsOverflow)?;
42
43                    Ok(())
44                })?;
45
46                Ok(())
47            }
48
49			pub fn [<clear_ $t:snake:lower>](&mut self) {
50				self.clear_by_type(crate::whisker::[<$t:snake:upper _TYPE>], false);
51			}
52        }
53    };
54}
55
56macro_rules! poly_whisker {
57    ($t: meta) => {
58        ::paste::paste! {
59            pub fn [<$t:lower _iter>](&self) -> core::iter::FilterMap<ValidatedWhiskerIter<'_>, fn(Whisker) -> Option<$t>> {
60				fn filt(w: Whisker) -> Option<$t> {
61                    match w {
62                        Whisker::$t(x) => Some(x),
63                        _ => None
64                    }
65				}
66
67                self.iter().filter_map(filt)
68            }
69
70			pub fn [<add_ $t:lower>](&mut self, w: $t) -> Result<(), EncodeError> {
71				try_lock(&mut self.buf, |data| {
72					let mut buf = [0; 256];
73                    // safe to unwrap since we know we have enough space
74                    let out = w.encode(&mut buf).unwrap();
75
76                    data.try_push(crate::whisker::[<$t:upper _TYPE>]).ok().ok_or(EncodeError::CatsOverflow)?;
77                    data.try_extend_from_slice(out).ok().ok_or(EncodeError::CatsOverflow)?;
78
79                    Ok(())
80                })?;
81
82                Ok(())
83			}
84
85			pub fn [<clear_ $t:lower>](&mut self) {
86				self.clear_by_type(crate::whisker::[<$t:upper _TYPE>], true);
87			}
88        }
89    };
90}
91
92/// N is the maximum packet size we can handle
93/// Panics if N >= 8191
94pub struct Packet<'a, const N: usize> {
95    buf: Buffer<'a, N>,
96}
97
98impl<'a, const N: usize> Packet<'a, N> {
99    pub fn new(buf: &'a mut [u8; N]) -> Self {
100        Self { buf: buf.into() }
101    }
102
103    pub fn clone_backing<'b>(&self, buf: &'b mut [u8; N]) -> Packet<'b, N> {
104        Packet {
105            buf: self.buf.clone_backing(buf),
106        }
107    }
108
109    /// Expects bytes in the `buf`
110    /// `buf` is used as the backing buffer for the Packet
111    pub fn decode(buf: Buffer<'a, N>) -> Result<Self, DecodeError> {
112        assert!(N <= 8191);
113
114        // validate the data
115        for w in WhiskerIter::new(&buf) {
116            w?;
117        }
118
119        let comment_iter = WhiskerIter::new(&buf)
120            .filter_map(|w| match w.unwrap() {
121                Whisker::Comment(c) => Some(c.internal_data().clone()),
122                _ => None,
123            })
124            .flatten();
125
126        if !utf8::validate(comment_iter) {
127            return Err(DecodeError::InvalidComment);
128        }
129
130        Ok(Self { buf })
131    }
132
133    pub fn encode(&self) -> &[u8] {
134        &self.buf
135    }
136
137    /// Directly after the CRC block in The Pipeline
138    pub fn semi_encode(mut self) -> Result<Buffer<'a, N>, (EncodeError, Self)> {
139        let crc = X25.checksum(&self.buf).to_le_bytes();
140
141        let res: Result<(), BufferOverflow> = try_lock(&mut self.buf, |data| {
142            data.try_push(crc[0])?;
143            data.try_push(crc[1])?;
144
145            Ok(())
146        });
147
148        match res {
149            Ok(()) => Ok(self.buf),
150            Err(_) => Err((EncodeError::CatsOverflow, self)),
151        }
152    }
153
154    /// Directly after the CRC block in The Pipeline
155    /// Expects bytes in the `buf`
156    /// `buf` is used as the backing buffer for the Packet
157    pub fn semi_decode(mut buf: Buffer<'a, N>) -> Result<Self, DecodeError> {
158        let crc1 = buf.pop().ok_or(DecodeError::UnexpectedEndOfInput)?;
159        let crc0 = buf.pop().ok_or(DecodeError::UnexpectedEndOfInput)?;
160        let crc_expected = u16::from_le_bytes([crc0, crc1]);
161        let crc_actual = X25.checksum(&buf);
162
163        if crc_expected != crc_actual {
164            return Err(DecodeError::CrcMismatch);
165        }
166
167        Self::decode(buf)
168    }
169
170    /// Encodes packet for transmission on the air.
171    /// Includes the data length L, but does not include the preamble or sync word.
172    pub fn fully_encode<const M: usize>(self, out: &mut Buffer<M>) -> Result<(), EncodeError> {
173        let mut data = self.semi_encode().map_err(|(err, _)| err)?;
174        whitener::whiten(&mut data);
175        ldpc::encode(&mut data)?;
176
177        // safe to unwrap - length must be below 8191
178        out.try_extend_from_slice(&u16::try_from(data.len()).unwrap().to_le_bytes())
179            .map_err(|_| EncodeError::CatsOverflow)?;
180        interleaver::interleave(&data, out)?;
181
182        Ok(())
183    }
184
185    /// Decodes packet that was received over the air.
186    /// Packet shouldn't have preamble, sync word, or data langth L.
187    /// Expects bytes in `data`
188    /// `buf` is used as the backing buffer for the Packet
189    pub fn fully_decode(data: &[u8], buf: &'a mut [u8; N]) -> Result<Self, DecodeError> {
190        let mut buf = Buffer::new_empty(buf);
191        interleaver::uninterleave(data, &mut buf).map_err(|_| DecodeError::Overflow)?;
192        ldpc::decode(&mut buf).ok_or(DecodeError::LdpcError)?;
193        whitener::whiten(&mut buf);
194
195        Self::semi_decode(buf)
196    }
197
198    /// Expects soft bits in `data`. Bits should be LLR, with positive numbers more likely to be 0.
199    /// Returns `DecodeError::Overflow` if `M` is less than `data.len()`.
200    pub fn fully_decode_soft<const M: usize, T: DecodeFrom>(
201        data: &mut [T],
202        buf: &'a mut [u8; N],
203    ) -> Result<Self, DecodeError> {
204        let mut out = [T::zero(); M];
205        let mut out = Buffer::new_empty(&mut out);
206        interleaver::uninterleave_soft(data, &mut out).map_err(|_| DecodeError::Overflow)?;
207        let mut buf = Buffer::new_empty(buf);
208        ldpc::decode_soft(&mut out, &mut buf).ok_or(DecodeError::LdpcError)?;
209        whitener::whiten(&mut buf);
210
211        Self::semi_decode(buf)
212    }
213
214    pub fn iter(&self) -> ValidatedWhiskerIter<'_> {
215        ValidatedWhiskerIter::new(&self.buf)
216    }
217
218    uniq_whisker!(Identification);
219    uniq_whisker!(Timestamp);
220    uniq_whisker!(Gps);
221    uniq_whisker!(Route);
222    uniq_whisker!(NodeInfo);
223    poly_whisker!(Destination);
224    poly_whisker!(Arbitrary);
225
226    pub fn comment<'b>(&self, buf: &'b mut [u8]) -> Result<&'b str, CommentError> {
227        let iter = self.iter().filter_map(|w| match w {
228            Whisker::Comment(c) => Some(c),
229            _ => None,
230        });
231
232        let mut i = 0;
233        let mut has_comment = false;
234        for c in iter {
235            has_comment = true;
236            let data = c.internal_data();
237            buf.get_mut(i..(i + data.len()))
238                .ok_or(CommentError::BufferOverflow)?
239                .copy_from_slice(data);
240
241            i += data.len();
242        }
243
244        if !has_comment {
245            return Err(CommentError::NoComment);
246        }
247
248        // Safe to unwrap since the comment was pre-validated
249        Ok(core::str::from_utf8(&buf[0..i]).unwrap())
250    }
251
252    pub fn add_comment(&mut self, comment: &str) -> Result<(), EncodeError> {
253        if self.iter().any(|w| matches!(w, Whisker::Comment(_))) {
254            // we already have a comment
255            return Err(EncodeError::DuplicateData);
256        }
257
258        try_lock(&mut self.buf, |data| {
259            let mut comment = comment.as_bytes();
260
261            while comment.len() > 255 {
262                let c = Comment::new(&comment[0..255]).unwrap();
263                let mut buf = [0; 256];
264                let out = c.encode(&mut buf).unwrap();
265
266                data.try_push(COMMENT_TYPE)
267                    .map_err(|_| EncodeError::CatsOverflow)?;
268                data.try_extend_from_slice(out)
269                    .map_err(|_| EncodeError::CatsOverflow)?;
270
271                comment = &comment[255..];
272            }
273
274            let c = Comment::new(comment).unwrap();
275            let mut buf = [0; 256];
276            let out = c.encode(&mut buf).unwrap();
277
278            data.try_push(COMMENT_TYPE)
279                .map_err(|_| EncodeError::CatsOverflow)?;
280            data.try_extend_from_slice(out)
281                .map_err(|_| EncodeError::CatsOverflow)?;
282
283            Ok(())
284        })?;
285
286        Ok(())
287    }
288
289    pub fn clear_comment(&mut self) {
290        self.clear_by_type(COMMENT_TYPE, true);
291    }
292
293    /// Given the callsign and ssid of a node, should it digipeat this packet?
294    /// Takes into account things such as if we've digipeated it already, the max hops, etc.
295    pub fn should_digipeat(&self, identity: Identity) -> Result<(), DigipeatError> {
296        let route = match self.route() {
297            Some(x) => x,
298            None => {
299                return Err(DigipeatError::NoRoute);
300            }
301        };
302
303        if let Some(ident) = self.identification() {
304            if &ident.callsign == identity.callsign() && ident.ssid == identity.ssid() {
305                return Err(DigipeatError::Us);
306            }
307        }
308
309        let max_hops: usize = route.max_hops.into();
310        let cur_hops = route
311            .iter()
312            .filter(|r| match r {
313                RouteHop::Internet => false,
314                RouteHop::Past(_) => true,
315                RouteHop::Future(_) => false,
316            })
317            .count();
318
319        if max_hops <= cur_hops {
320            return Err(DigipeatError::MaxHops);
321        }
322
323        let already_digipeated = route.iter().any(|r| match r {
324            RouteHop::Internet => false,
325            RouteHop::Past(past_hop) => past_hop.identity() == identity,
326            RouteHop::Future(_) => false,
327        });
328
329        if already_digipeated {
330            return Err(DigipeatError::AlreadyDigipeated);
331        }
332
333        let next_node = route.iter().find_map(|r| match r {
334            RouteHop::Future(x) => Some(x),
335            _ => None,
336        });
337
338        match next_node {
339            Some(ident) if ident != identity => Err(DigipeatError::SetDestiny),
340            _ => Ok(()),
341        }
342    }
343
344    /// Note that if this fails due to a CATS overflow, it will wipe the route off of the packet
345    pub fn append_to_route(
346        &mut self,
347        callsign: &str,
348        ssid: u8,
349        rssi: Option<f64>,
350    ) -> Result<(), PacketRouteAppendError> {
351        let mut route = self.route().ok_or(PacketRouteAppendError::NoRouteWhisker)?;
352        route
353            .append_hop(PastHop::new(Identity::new(callsign, ssid), rssi))
354            .map_err(|error| PacketRouteAppendError::Route { error })?;
355        self.clear_route();
356
357        self.add_route(route)
358            .map_err(|_| PacketRouteAppendError::PacketOverflow)?;
359
360        Ok(())
361    }
362
363    fn clear_by_type(&mut self, whisker_type: u8, all: bool) {
364        let mut i = 0;
365        while i < self.buf.len() {
366            let t = self.buf[i];
367            let step = usize::from(self.buf[i + 1]) + 2;
368
369            if t == whisker_type {
370                self.buf.drain(i, i + step);
371
372                if !all {
373                    return;
374                }
375            } else {
376                i += step;
377            }
378        }
379    }
380}
381
382impl<const N: usize> Debug for Packet<'_, N> {
383    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
384        f.debug_list()
385            .entries(ValidatedWhiskerIter::new(&self.buf))
386            .finish()
387    }
388}
389
390// if the function returns an error, we roll back the array
391// by rolling it back, we really just pop bytes off the end until the length matches
392fn try_lock<'a, const N: usize, T, E, F: Fn(&mut Buffer<'a, N>) -> Result<T, E>>(
393    buf: &mut Buffer<'a, N>,
394    f: F,
395) -> Result<T, E> {
396    let len = buf.len();
397
398    match f(buf) {
399        Ok(x) => Ok(x),
400        Err(e) => {
401            buf.truncate(len);
402
403            Err(e)
404        }
405    }
406}
407
408#[cfg(test)]
409mod tests {
410    use super::*;
411    use crate::whisker::NodeInfoBuilder;
412    use crate::{soft_bit::FromHardBit, whisker::AckData};
413    use arrayvec::ArrayString;
414    use bitvec::{order::Msb0, view::BitView};
415
416    #[test]
417    fn dest() {
418        let d1 = Destination::new("CALL1", 23, Some(AckData::new(7, false))).unwrap();
419        let d2 = Destination::new("CALL2", 2, Some(AckData::new(23, true))).unwrap();
420
421        let mut buf = [0; 1024];
422        let mut packet: Packet<1024> = Packet::new(&mut buf);
423        packet.add_destination(d1.clone()).unwrap();
424        packet.add_destination(d2.clone()).unwrap();
425
426        let mut dests = packet.destination_iter();
427        assert_eq!(d1, dests.next().unwrap());
428        assert_eq!(d2, dests.next().unwrap());
429        assert_eq!(None, dests.next());
430    }
431
432    #[test]
433    fn route_clear() {
434        let mut buf = [0; 1024];
435        let mut p: Packet<1024> = Packet::new(&mut buf);
436        p.add_identification(Identification::new("call", 43, 123).unwrap())
437            .unwrap();
438        let mut r = Route::new(8);
439        r.push_internet().unwrap();
440        p.add_route(r).unwrap();
441        p.add_comment("This is a comment").unwrap();
442
443        p.clear_route();
444
445        assert_eq!(
446            Identification::new("call", 43, 123).unwrap(),
447            p.identification().unwrap()
448        );
449        assert_eq!(None, p.route());
450        let mut buf = [0; 32];
451        assert_eq!("This is a comment", p.comment(&mut buf).unwrap());
452    }
453
454    #[test]
455    fn semi_e2e() {
456        let comment = "Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.";
457
458        let mut buf = [0; 2048];
459        let mut packet = Packet::new(&mut buf);
460        packet
461            .add_identification(Identification {
462                icon: 123,
463                callsign: ArrayString::from("ABCXYZ_LONG_CALL").unwrap(),
464                ssid: 43,
465            })
466            .unwrap();
467
468        packet.add_comment(comment).unwrap();
469
470        let res = packet.add_identification(Identification {
471            icon: 456,
472            callsign: ArrayString::from("NOPE").unwrap(),
473            ssid: 0,
474        });
475        assert!(matches!(res, Err(EncodeError::DuplicateData)));
476
477        let semi = packet.semi_encode().unwrap();
478
479        let packet2 = Packet::semi_decode(semi).unwrap();
480        assert_eq!(
481            Identification {
482                icon: 123,
483                callsign: ArrayString::from("ABCXYZ_LONG_CALL").unwrap(),
484                ssid: 43,
485            },
486            packet2.identification().unwrap()
487        );
488
489        let mut buf = [0; 1024];
490        assert_eq!(comment, packet2.comment(&mut buf).unwrap());
491    }
492
493    #[test]
494    fn full_e2e() {
495        let comment = "Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.";
496
497        let mut buf = [0; 4096];
498        let mut packet = Packet::new(&mut buf);
499        packet
500            .add_identification(Identification {
501                icon: 123,
502                callsign: ArrayString::from("ABCXYZ_LONG_CALL").unwrap(),
503                ssid: 43,
504            })
505            .unwrap();
506
507        packet.add_comment(comment).unwrap();
508
509        let res = packet.add_identification(Identification {
510            icon: 456,
511            callsign: ArrayString::from("NOPE").unwrap(),
512            ssid: 0,
513        });
514        assert!(matches!(res, Err(EncodeError::DuplicateData)));
515
516        let mut buf2 = [0; 4096];
517        let mut fully = Buffer::new_empty(&mut buf2);
518        packet.fully_encode(&mut fully).unwrap();
519
520        fully[40] ^= 0x55;
521        fully[844] ^= 0x7B;
522
523        // exclude length
524        let mut buf3 = [0; 8191];
525        let packet2: Packet<8191> = Packet::fully_decode(&fully[2..], &mut buf3).unwrap();
526        assert_eq!(
527            Identification {
528                icon: 123,
529                callsign: ArrayString::from("ABCXYZ_LONG_CALL").unwrap(),
530                ssid: 43,
531            },
532            packet2.identification().unwrap()
533        );
534
535        let mut buf = [0; 1024];
536        assert_eq!(comment, packet2.comment(&mut buf).unwrap());
537    }
538
539    #[test]
540    fn full_e2e_soft_decode() {
541        let comment = "Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.Hello world! This is a comment. It's long so that it needs to be split across more than one whisker.";
542
543        let mut buf = [0; 4096];
544        let mut packet = Packet::new(&mut buf);
545        packet
546            .add_identification(Identification {
547                icon: 123,
548                callsign: ArrayString::from("ABCXYZ_LONG_CALL").unwrap(),
549                ssid: 43,
550            })
551            .unwrap();
552
553        packet.add_comment(comment).unwrap();
554
555        let res = packet.add_identification(Identification {
556            icon: 456,
557            callsign: ArrayString::from("NOPE").unwrap(),
558            ssid: 0,
559        });
560        assert!(matches!(res, Err(EncodeError::DuplicateData)));
561
562        let mut buf2 = [0; 4096];
563        let mut fully = Buffer::new_empty(&mut buf2);
564        packet.fully_encode(&mut fully).unwrap();
565
566        fully[40] ^= 0x55;
567        fully[844] ^= 0x7B;
568
569        let mut soft = [0.0; 8191 * 8];
570        let mut soft = Buffer::new_empty(&mut soft);
571        for b in fully.view_bits::<Msb0>().iter() {
572            soft.push(f32::from_hard_bit(*b));
573        }
574        let soft = &mut soft[16..];
575
576        let mut buf3 = [0; 8191];
577        // exclude length
578        let packet2: Packet<8191> =
579            Packet::fully_decode_soft::<{ 8191 * 8 }, _>(soft, &mut buf3).unwrap();
580        assert_eq!(
581            Identification {
582                icon: 123,
583                callsign: ArrayString::from("ABCXYZ_LONG_CALL").unwrap(),
584                ssid: 43,
585            },
586            packet2.identification().unwrap()
587        );
588
589        let mut buf = [0; 1024];
590        assert_eq!(comment, packet2.comment(&mut buf).unwrap());
591    }
592
593    #[test]
594    fn node_info_e2e() {
595        let mut buf = [0; 4096];
596        let mut packet = Packet::new(&mut buf);
597        packet
598            .add_node_info(
599                NodeInfoBuilder::default()
600                    .hardware_id(0xBEEF)
601                    .software_id(0xBC)
602                    .uptime(2304)
603                    .antenna_height(5)
604                    .antenna_gain(3.0)
605                    .tx_power(30.0)
606                    .voltage(12.6)
607                    .xcvr_temperature(-15)
608                    .battery_charge(65.0)
609                    .build(),
610            )
611            .unwrap();
612
613        let mut buf2 = [0; 4096];
614        let mut encoded = Buffer::new_empty(&mut buf2);
615        packet.fully_encode(&mut encoded).unwrap();
616
617        let mut buf3 = [0; 4096];
618        let packet2 = Packet::fully_decode(&encoded[2..], &mut buf3).unwrap();
619
620        let node_info = packet2.node_info().unwrap();
621        assert_eq!(0xBEEF, node_info.hardware_id().unwrap());
622        assert_eq!(0xBC, node_info.software_id().unwrap());
623        assert_eq!(2304, node_info.uptime().unwrap());
624        assert_eq!(5, node_info.antenna_height().unwrap());
625        assert_eq!(3.0, node_info.antenna_gain().unwrap());
626        assert_eq!(30.0, node_info.tx_power().unwrap());
627        assert_eq!(12.6, node_info.voltage().unwrap());
628        assert_eq!(-15, node_info.xcvr_temperature().unwrap());
629        assert_eq!(64.70588235294117, node_info.battery_charge().unwrap());
630    }
631
632    #[test]
633    fn node_info_e2e_some_unpopulated() {
634        let mut buf = [0; 4096];
635        let mut packet = Packet::new(&mut buf);
636        packet
637            .add_node_info(
638                NodeInfoBuilder::default()
639                    .software_id(0xBC)
640                    .uptime(2304)
641                    .antenna_gain(3.0)
642                    .voltage(12.6)
643                    .xcvr_temperature(-15)
644                    .build(),
645            )
646            .unwrap();
647
648        let mut buf2 = [0; 4096];
649        let mut encoded = Buffer::new_empty(&mut buf2);
650        packet.fully_encode(&mut encoded).unwrap();
651
652        let mut buf3 = [0; 4096];
653        let packet2 = Packet::fully_decode(&encoded[2..], &mut buf3).unwrap();
654
655        let node_info = packet2.node_info().unwrap();
656        assert_eq!(None, node_info.hardware_id());
657        assert_eq!(0xBC, node_info.software_id().unwrap());
658        assert_eq!(2304, node_info.uptime().unwrap());
659        assert_eq!(None, node_info.antenna_height());
660        assert_eq!(3.0, node_info.antenna_gain().unwrap());
661        assert_eq!(None, node_info.tx_power());
662        assert_eq!(12.6, node_info.voltage().unwrap());
663        assert_eq!(-15, node_info.xcvr_temperature().unwrap());
664        assert_eq!(None, node_info.battery_charge());
665    }
666
667    #[test]
668    fn fully_decode_fuzz_tests() {
669        let data = [
670            112, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 74, 0, 0, 0, 0, 41, 0,
671            0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 114, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
672            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
673            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
674            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
675            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255,
676            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
677            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 10, 112, 0, 0, 0, 0, 0, 0, 2, 1, 0,
678            0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 74, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39,
679            114, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
680            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
681            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
682            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
683            0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 247, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
684            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 118, 118, 118, 118, 118, 118, 118, 118, 118,
685            118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 7, 0, 118, 118, 118, 118, 118, 118, 118, 118,
686            118, 118, 118, 145, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
687            59, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
688            118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
689            118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
690            118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
691            118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
692            118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
693            118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 7,
694            0, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
695            118, 118, 118, 118, 118, 118, 118, 118, 59, 118, 118, 118, 118, 118, 118, 118, 118,
696            118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
697            118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
698            118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
699            118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
700            118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
701            118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
702            118, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0,
703            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
704            0, 0, 0, 0, 228, 0, 0, 0, 64, 0, 65, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 7, 0, 118, 118, 118,
705            118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
706            118, 118, 1, 0, 0, 10, 118, 118, 118, 118, 118, 118, 118, 118, 0, 0, 0, 0, 0, 0, 0, 0,
707            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
708            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 228, 0, 0, 0, 64,
709            0, 65, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 7, 0, 118, 118, 118, 118, 118, 118, 118, 118, 118,
710            118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 1, 0, 0, 10, 118, 118,
711            118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
712            118, 118, 118, 118, 118, 118, 118, 118, 118, 1, 2, 118, 118, 118, 118, 118, 118, 118,
713            118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
714            118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
715            118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118,
716            118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 0, 0, 118, 118, 118, 118,
717            118, 118, 118, 118, 118, 118, 118, 0, 0, 0, 0, 96, 96,
718        ];
719
720        let mut buf = [0; 1024];
721        let _ = Packet::<1024>::fully_decode(&data, &mut buf);
722    }
723
724    #[test]
725    fn semi_decode_fuzz_tests() {
726        let cases = [
727            &[
728                42, 64, 64, 64, 229, 40, 64, 64, 0, 0, 173, 173, 173, 173, 173, 173, 173, 173, 64,
729                64, 0, 0, 173, 187, 187, 187, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173,
730                173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 187, 187,
731                187, 101, 157, 138, 74, 101, 157, 138, 74, 0, 0, 0, 0, 1, 126, 255, 255, 255, 187,
732                187, 187, 187, 187, 187, 187, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173,
733                173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 187, 101, 157, 138, 74, 101,
734                157, 138, 106, 0, 0, 0, 0, 1, 126, 255, 255, 255, 0, 212, 0, 0, 0, 0, 1, 187, 187,
735                187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187,
736                187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 173, 187, 187, 187, 101,
737                157, 138, 74, 101, 157, 138, 74, 0, 0, 0, 0, 1, 126, 255, 255, 255, 0, 212, 0, 0,
738                0, 0, 1, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187,
739                187, 187, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 157, 138, 74, 0, 0, 0,
740                0, 1, 126, 255, 255, 255, 0, 212, 0, 0, 0, 0, 1, 187, 187, 187, 187, 187, 187, 187,
741                187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187,
742                187, 187, 187, 187, 187, 187, 173, 187, 187, 64, 187, 101, 157, 138, 74, 101, 157,
743                50, 138, 74, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
744                255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
745                255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
746                255, 255, 255, 255, 255, 1, 126, 255, 255, 255, 0, 212, 0, 0, 0, 0, 1, 187, 187,
747                187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187,
748                187, 187, 187, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173,
749                173, 173, 173, 173, 173, 173, 64, 64, 0, 0, 173, 173, 173, 173, 173, 173, 173, 173,
750                173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173,
751                173, 187, 187, 187, 101, 157, 138, 74, 101, 157, 138, 74, 0, 0, 0, 0, 1, 126, 255,
752                255, 255, 0, 212, 0, 0, 0, 0, 1, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187,
753                187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187,
754                187, 187, 187, 173, 187, 187, 187, 101, 157, 138, 74, 101, 157, 138, 74, 0, 0, 0,
755                0, 1, 126, 255, 255, 255, 0, 212, 0, 0, 0, 0, 1, 187, 187, 0, 0, 192, 192, 0, 187,
756                187, 187, 187, 187, 187, 187, 187, 187, 187, 173, 173, 173, 173, 173, 173, 173,
757                173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173,
758                173, 64, 64, 0, 0, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173,
759                173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 187, 187, 187, 101,
760                157, 138, 74, 101, 157, 138, 74, 0, 0, 0, 0, 1, 126, 255, 255, 255, 0, 212, 0, 0,
761                0, 0, 1, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187,
762                187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187,
763                187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187,
764                187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 126,
765            ][..],
766            &[
767                48, 5, 4, 255, 5, 5, 5, 5, 5, 5, 5, 37, 5, 7, 5, 5, 35, 5, 5, 5, 5, 4, 5, 7, 5, 5,
768                5, 5, 5, 5, 5, 5, 11, 126, 3, 101, 5, 3, 3, 96, 192, 128, 192, 192,
769            ][..],
770        ];
771
772        for data in cases {
773            let mut buf = [0; 1024];
774            let mut buf = Buffer::new_empty(&mut buf);
775            buf.extend(data);
776            let _ = Packet::<1024>::semi_decode(buf);
777        }
778    }
779
780    #[test]
781    fn decode_fuzz_tests() {
782        let cases = [&[4, 0, 0, 0][..], &[4, 5, 0, 0, 0, 10, 255, 255, 0, 0][..]];
783
784        for data in cases {
785            let mut buf = [0; 1024];
786            let mut buf = Buffer::new_empty(&mut buf);
787            buf.extend(data);
788            let _ = Packet::<1024>::decode(buf);
789        }
790    }
791
792    #[test]
793    fn fully_decode_soft_fuzz_tests() {
794        // When adding to this, don't forget to do the u8 -> i8 conversion
795        let cases = [
796            &mut [
797                -39, -39, -39, -118, -58, -58, -58, -58, -89, -39, -118, -58, -58, -58, 34, 34, 34,
798                34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, -58, -58,
799                127, 81, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
800                127, 127, 127, 127, 127, 127, 127, 127, 127, 127, -86, 127, 127, 127, 127, 127,
801                127, 127, 127, 127, 127, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, -58, -58, 127,
802                81, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 34, 34, 34, 34, 34, 34, 34,
803                34, 34, 34, 34, -58, -58, 127, 81, 127, 127, 127, 127, 127, 127, 127, 127, 127,
804                127, 127, 127, 127, 127, 127, -128, -128, -128, -128, -128, -128, -128, -128, -128,
805                -128, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, -128, -128,
806            ][..],
807            &mut [
808                -73, -73, -73, -73, -75, -76, -73, -73, -73, -73, -73, -73, -73, -73, 73, 72, 72,
809                72, 72, 72, 72, 62, -73, -118, 120, 127, 127, 121, 127, 112, 127, 127,
810            ],
811        ];
812
813        for data in cases {
814            let mut buf = [0; 1024];
815            let _ = Packet::<1024>::fully_decode_soft::<8192, i8>(data, &mut buf);
816        }
817    }
818}