+
+struct PendingPacket {
+ lsf: Option<LsfFrame>,
+
+ app_data: [u8; 825],
+ app_data_len: usize,
+ app_data_transmitted: usize,
+}
+
+impl PendingPacket {
+ fn new() -> Self {
+ Self {
+ lsf: None,
+ app_data: [0u8; 825],
+ app_data_len: 0,
+ app_data_transmitted: 0,
+ }
+ }
+
+ /// Returns next frame, not including preamble or EOT.
+ ///
+ /// False means all data frames have been sent.
+ fn next_frame(&mut self) -> Option<ModulatorFrame> {
+ if let Some(lsf) = self.lsf.take() {
+ return Some(ModulatorFrame::Lsf(lsf));
+ }
+ if self.app_data_len == self.app_data_transmitted {
+ return None;
+ }
+ let remaining = self.app_data_len - self.app_data_transmitted;
+ let (counter, data_len) = if remaining <= 25 {
+ (
+ PacketFrameCounter::FinalFrame {
+ payload_len: remaining,
+ },
+ remaining,
+ )
+ } else {
+ (
+ PacketFrameCounter::Frame {
+ index: self.app_data_transmitted / 25,
+ },
+ 25,
+ )
+ };
+ let mut payload = [0u8; 25];
+ payload[0..data_len].copy_from_slice(
+ &self.app_data[self.app_data_transmitted..(self.app_data_transmitted + data_len)],
+ );
+ self.app_data_transmitted += data_len;
+ Some(ModulatorFrame::Packet(PacketFrame { payload, counter }))
+ }
+}
+
+impl Default for PendingPacket {
+ fn default() -> Self {
+ Self {
+ lsf: None,
+ app_data: [0u8; 825],
+ app_data_len: 0,
+ app_data_transmitted: 0,
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::kiss::{KissCommand, PORT_STREAM};
+ use crate::protocol::{PacketType, StreamFrame};
+
+ #[test]
+ fn tnc_receive_single_frame_packet() {
+ let lsf = LsfFrame::new_packet(
+ &Address::Callsign(Callsign(*b"VK7XT ")),
+ &Address::Broadcast,
+ );
+ let mut payload = [0u8; 25];
+ let (pt, pt_len) = PacketType::Sms.as_proto();
+ payload[0..pt_len].copy_from_slice(&pt[0..pt_len]);
+ payload[pt_len] = 0x41; // a message
+ let crc = crate::crc::m17_crc(&payload[0..=pt_len]).to_be_bytes();
+ payload[pt_len + 1] = crc[0];
+ payload[pt_len + 2] = crc[1];
+
+ let packet = PacketFrame {
+ payload,
+ counter: PacketFrameCounter::FinalFrame {
+ payload_len: pt_len + 3,
+ },
+ };
+ let mut tnc = SoftTnc::new();
+ let mut kiss = KissFrame::new_empty();
+
+ // TNC consumes LSF but has nothing to report yet
+ tnc.handle_frame(Frame::Lsf(lsf));
+ assert_eq!(tnc.read_kiss(&mut kiss.data), 0);
+
+ // TODO: when support is added for the basic packet port they could arrive in either order
+
+ tnc.handle_frame(Frame::Packet(packet));
+ kiss.len = tnc.read_kiss(&mut kiss.data);
+ assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
+ assert_eq!(kiss.port().unwrap(), PORT_PACKET_FULL);
+
+ let mut payload_buf = [0u8; 2048];
+ let n = kiss.decode_payload(&mut payload_buf).unwrap();
+ assert_eq!(n, 30 + 1 + pt_len + 2);
+
+ // did we receive our message? (after the LSF)
+ assert_eq!(payload_buf[pt_len + 30], 0x41);
+ }
+
+ #[test]
+ fn tnc_receive_multiple_frame_packet() {
+ let lsf = LsfFrame::new_packet(
+ &Address::Callsign(Callsign(*b"VK7XT ")),
+ &Address::Broadcast,
+ );
+ let mut payload = [0x41u8; 26]; // spans two frames
+ let (pt, pt_len) = PacketType::Sms.as_proto();
+ payload[0..pt_len].copy_from_slice(&pt[0..pt_len]);
+ let crc = crate::crc::m17_crc(&payload[0..24]).to_be_bytes();
+ payload[24] = crc[0];
+ payload[25] = crc[1];
+
+ let packet1 = PacketFrame {
+ payload: payload[0..25].try_into().unwrap(),
+ counter: PacketFrameCounter::Frame { index: 0 },
+ };
+ let mut payload2 = [0u8; 25];
+ payload2[0] = payload[25];
+ let packet2 = PacketFrame {
+ payload: payload2,
+ counter: PacketFrameCounter::FinalFrame { payload_len: 1 },
+ };
+
+ let mut tnc = SoftTnc::new();
+ let mut kiss = KissFrame::new_empty();
+
+ // Nothing to report until second final packet frame received
+ tnc.handle_frame(Frame::Lsf(lsf));
+ assert_eq!(tnc.read_kiss(&mut kiss.data), 0);
+ tnc.handle_frame(Frame::Packet(packet1));
+ assert_eq!(tnc.read_kiss(&mut kiss.data), 0);
+
+ tnc.handle_frame(Frame::Packet(packet2));
+ kiss.len = tnc.read_kiss(&mut kiss.data);
+ assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
+ assert_eq!(kiss.port().unwrap(), PORT_PACKET_FULL);
+
+ let mut payload_buf = [0u8; 2048];
+ let n = kiss.decode_payload(&mut payload_buf).unwrap();
+ assert_eq!(n, 30 + 26);
+
+ // did we receive our message? (after the LSF)
+ assert_eq!(payload_buf[pt_len + 30], 0x41);
+ }
+
+ #[test]
+ fn tnc_receive_partial_packet() {
+ let lsf = LsfFrame::new_packet(
+ &Address::Callsign(Callsign(*b"VK7XT ")),
+ &Address::Broadcast,
+ );
+ let mut payload = [0x41u8; 26]; // spans two frames
+ let (pt, pt_len) = PacketType::Sms.as_proto();
+ payload[0..pt_len].copy_from_slice(&pt[0..pt_len]);
+ let crc = crate::crc::m17_crc(&payload[0..24]).to_be_bytes();
+ payload[24] = crc[0];
+ payload[25] = crc[1];
+
+ let packet1 = PacketFrame {
+ payload: payload[0..25].try_into().unwrap(),
+ counter: PacketFrameCounter::Frame { index: 0 },
+ };
+ // final frame of this transmission is dropped
+
+ let lsf2 = LsfFrame::new_packet(
+ &Address::Callsign(Callsign(*b"VK7XT ")),
+ &Address::Broadcast,
+ );
+ let mut payload = [0u8; 25];
+ let (pt, pt_len) = PacketType::Sms.as_proto();
+ payload[0..pt_len].copy_from_slice(&pt[0..pt_len]);
+ payload[pt_len] = 0x42;
+ let crc = crate::crc::m17_crc(&payload[0..=pt_len]).to_be_bytes();
+ payload[pt_len + 1] = crc[0];
+ payload[pt_len + 2] = crc[1];
+
+ let packet2 = PacketFrame {
+ payload: payload[0..25].try_into().unwrap(),
+ counter: PacketFrameCounter::FinalFrame {
+ payload_len: pt_len + 3,
+ },
+ };
+
+ let mut tnc = SoftTnc::new();
+ let mut kiss = KissFrame::new_empty();
+
+ // Nothing to report until second packet received in its entirety
+ tnc.handle_frame(Frame::Lsf(lsf));
+ assert_eq!(tnc.read_kiss(&mut kiss.data), 0);
+ tnc.handle_frame(Frame::Packet(packet1));
+ assert_eq!(tnc.read_kiss(&mut kiss.data), 0);
+ tnc.handle_frame(Frame::Lsf(lsf2));
+ assert_eq!(tnc.read_kiss(&mut kiss.data), 0);
+ tnc.handle_frame(Frame::Packet(packet2));
+
+ kiss.len = tnc.read_kiss(&mut kiss.data);
+ assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
+ assert_eq!(kiss.port().unwrap(), PORT_PACKET_FULL);
+
+ let mut payload_buf = [0u8; 2048];
+ let n = kiss.decode_payload(&mut payload_buf).unwrap();
+ assert_eq!(n, 30 + 1 + pt_len + 2);
+ // we have received the second packet which has 0x42 in it
+ assert_eq!(payload_buf[pt_len + 30], 0x42);
+ }
+
+ #[test]
+ fn tnc_receive_stream() {
+ let lsf = LsfFrame([
+ 255, 255, 255, 255, 255, 255, 0, 0, 0, 159, 221, 81, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 131, 53,
+ ]);
+ let stream1 = StreamFrame {
+ lich_idx: 0,
+ lich_part: [255, 255, 255, 255, 255],
+ frame_number: 0,
+ end_of_stream: false,
+ stream_data: [
+ 128, 0, 119, 115, 220, 252, 41, 235, 8, 0, 116, 195, 94, 244, 45, 75,
+ ],
+ };
+ let stream2 = StreamFrame {
+ lich_idx: 1,
+ lich_part: [255, 0, 0, 0, 159],
+ frame_number: 1,
+ end_of_stream: true,
+ stream_data: [
+ 17, 0, 94, 82, 216, 135, 181, 15, 30, 0, 125, 195, 152, 183, 41, 57,
+ ],
+ };
+ let mut tnc = SoftTnc::new();
+ let mut kiss = KissFrame::new_empty();
+ assert_eq!(tnc.read_kiss(&mut kiss.data), 0);
+
+ tnc.handle_frame(Frame::Lsf(lsf));
+ kiss.len = tnc.read_kiss(&mut kiss.data);
+ assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
+ assert_eq!(kiss.port().unwrap(), PORT_STREAM);
+
+ let mut payload_buf = [0u8; 2048];
+ let n = kiss.decode_payload(&mut payload_buf).unwrap();
+ assert_eq!(n, 30);
+
+ tnc.handle_frame(Frame::Stream(stream1));
+ kiss.len = tnc.read_kiss(&mut kiss.data);
+ assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
+ assert_eq!(kiss.port().unwrap(), PORT_STREAM);
+
+ let n = kiss.decode_payload(&mut payload_buf).unwrap();
+ assert_eq!(n, 26);
+
+ tnc.handle_frame(Frame::Stream(stream2));
+ kiss.len = tnc.read_kiss(&mut kiss.data);
+ assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
+ assert_eq!(kiss.port().unwrap(), PORT_STREAM);
+
+ let n = kiss.decode_payload(&mut payload_buf).unwrap();
+ assert_eq!(n, 26);
+ }
+
+ #[test]
+ fn tnc_acquire_stream() {
+ let frames = [
+ StreamFrame {
+ lich_idx: 0,
+ lich_part: [255, 255, 255, 255, 255],
+ frame_number: 0,
+ end_of_stream: false,
+ stream_data: [
+ 128, 0, 119, 115, 220, 252, 41, 235, 8, 0, 116, 195, 94, 244, 45, 75,
+ ],
+ },
+ StreamFrame {
+ lich_idx: 1,
+ lich_part: [255, 0, 0, 0, 159],
+ frame_number: 1,
+ end_of_stream: false,
+ stream_data: [
+ 17, 0, 94, 82, 216, 135, 181, 15, 30, 0, 125, 195, 152, 183, 41, 57,
+ ],
+ },
+ StreamFrame {
+ lich_idx: 2,
+ lich_part: [221, 81, 5, 5, 0],
+ frame_number: 2,
+ end_of_stream: false,
+ stream_data: [
+ 17, 128, 93, 74, 154, 167, 169, 11, 20, 0, 116, 91, 158, 220, 45, 111,
+ ],
+ },
+ StreamFrame {
+ lich_idx: 3,
+ lich_part: [0, 0, 0, 0, 0],
+ frame_number: 3,
+ end_of_stream: false,
+ stream_data: [
+ 15, 128, 114, 83, 218, 252, 59, 111, 31, 128, 116, 91, 84, 231, 45, 105,
+ ],
+ },
+ StreamFrame {
+ lich_idx: 4,
+ lich_part: [0, 0, 0, 0, 0],
+ frame_number: 4,
+ end_of_stream: false,
+ stream_data: [
+ 9, 128, 119, 115, 220, 220, 57, 15, 48, 128, 124, 83, 158, 236, 181, 91,
+ ],
+ },
+ StreamFrame {
+ lich_idx: 5,
+ lich_part: [0, 0, 0, 131, 53],
+ frame_number: 5,
+ end_of_stream: false,
+ stream_data: [
+ 52, 0, 116, 90, 152, 167, 225, 216, 32, 0, 116, 83, 156, 212, 33, 216,
+ ],
+ },
+ ];
+
+ let mut tnc = SoftTnc::new();
+ let mut kiss = KissFrame::new_empty();
+ for f in frames {
+ tnc.handle_frame(Frame::Stream(f));
+ }
+ kiss.len = tnc.read_kiss(&mut kiss.data);
+ let mut payload_buf = [0u8; 2048];
+ let n = kiss.decode_payload(&mut payload_buf).unwrap();
+ assert_eq!(n, 30);
+ assert_eq!(
+ &payload_buf[0..30],
+ [
+ 255, 255, 255, 255, 255, 255, 0, 0, 0, 159, 221, 81, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 131, 53,
+ ]
+ );
+ }
+
+ #[test]
+ fn tnc_handle_skipped_stream_frame() {
+ let lsf = LsfFrame([
+ 255, 255, 255, 255, 255, 255, 0, 0, 0, 159, 221, 81, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 131, 53,
+ ]);
+ let stream1 = StreamFrame {
+ lich_idx: 0,
+ lich_part: [255, 255, 255, 255, 255],
+ frame_number: 0,
+ end_of_stream: false,
+ stream_data: [
+ 128, 0, 119, 115, 220, 252, 41, 235, 8, 0, 116, 195, 94, 244, 45, 75,
+ ],
+ };
+ let stream3 = StreamFrame {
+ lich_idx: 2,
+ lich_part: [221, 81, 5, 5, 0],
+ frame_number: 2,
+ end_of_stream: false,
+ stream_data: [
+ 17, 128, 93, 74, 154, 167, 169, 11, 20, 0, 116, 91, 158, 220, 45, 111,
+ ],
+ };
+ let mut tnc = SoftTnc::new();
+ let mut kiss = KissFrame::new_empty();
+ assert_eq!(tnc.read_kiss(&mut kiss.data), 0);
+
+ tnc.handle_frame(Frame::Lsf(lsf));
+ kiss.len = tnc.read_kiss(&mut kiss.data);
+ assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
+ assert_eq!(kiss.port().unwrap(), PORT_STREAM);
+
+ let mut payload_buf = [0u8; 2048];
+ let n = kiss.decode_payload(&mut payload_buf).unwrap();
+ assert_eq!(n, 30);
+
+ tnc.handle_frame(Frame::Stream(stream1));
+ kiss.len = tnc.read_kiss(&mut kiss.data);
+ assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
+ assert_eq!(kiss.port().unwrap(), PORT_STREAM);
+
+ let n = kiss.decode_payload(&mut payload_buf).unwrap();
+ assert_eq!(n, 26);
+
+ tnc.handle_frame(Frame::Stream(stream3));
+ kiss.len = tnc.read_kiss(&mut kiss.data);
+ assert_eq!(kiss.command().unwrap(), KissCommand::DataFrame);
+ assert_eq!(kiss.port().unwrap(), PORT_STREAM);
+
+ let n = kiss.decode_payload(&mut payload_buf).unwrap();
+ assert_eq!(n, 26);
+ }
+}