kiss-tnc 0.1.2

A library to connect to KISS TNCs, such as Direwolf
Documentation
use crate::constants::*;
use crate::errors::*;
use std::borrow::Cow;
use std::io::{Read, Write};

#[derive(Debug)]
pub(crate) enum Command<'a> {
	DataFrame(Cow<'a, [u8]>),
	TxDelay(u8),
	/*
	Persistence(u8),
	SlotTime(u8),
	TxTail(u8),
	FullDuplex(u8),
	*/
	Return,
}

impl<'a> Command<'a> {
	pub fn owned_frame(data: Vec<u8>) -> Self {
		Self::DataFrame(Cow::Owned(data))
	}

	pub fn borrowed_frame(data: &'a [u8]) -> Self {
		Self::DataFrame(Cow::Borrowed(data))
	}

	pub fn write<W: Write>(&self, port: u8, writer: &mut W) -> std::io::Result<usize> {
		assert!(port < 16);
		let port = port << 4;

		let mut count = 0;
		count += writer.write(&[FEND])?;
		match self {
			Self::DataFrame(data) => {
				count += writer.write(&[DATA_FRAME | port])?;
				for &b in data.as_ref() {
					count += match b {
						FEND => writer.write(&[FESC, TFEND])?,
						FESC => writer.write(&[FESC, TFESC])?,
						_ => writer.write(&[b])?,
					}
				}
			}

			Self::TxDelay(delay) => {
				count += writer.write(&[TX_DELAY | port])?;
				count += writer.write(&[*delay])?;
			}

			Self::Return => {
				count += writer.write(&[RETURN])?;
			}
		}
		count += writer.write(&[FEND])?;

		Ok(count)
	}

	pub fn read<R: Read>(reader: &mut R) -> Result<(u8, Self), ReadError> {
		// BUG - Anything received on port 12 will cause issues
		// Because data frames will be marked as 0xC0 - the same as FEND
		// I'm not sure how many people actually use 12 ports, so this is
		// probably a non-issue.

		let mut buf = [0];
		reader.read_exact(&mut buf)?;

		if buf != [0xC0] {
			// First byte must be FEND
			return Err(ReadError::MalformedData);
		}

		// Additional 0xC0 frames should be dropped
		while buf == [0xC0] {
			reader.read_exact(&mut buf)?;
		}

		let port = (buf[0] & 0xF0) >> 4;
		let code = buf[0] & 0x0F;

		if code != 0x00 {
			// The TNC can only send us data frames
			return Err(ReadError::MalformedData);
		}

		let mut data = vec![];
		reader.read_exact(&mut buf)?;
		while buf[0] != 0xC0 {
			let b = buf[0];
			if b == FESC {
				reader.read_exact(&mut buf)?;
				match buf[0] {
					TFEND => {
						data.push(FEND);
					}
					TFESC => {
						data.push(FESC);
					}
					_ => return Err(ReadError::MalformedData),
				}
			} else {
				data.push(b);
			}

			reader.read_exact(&mut buf)?;
		}

		Ok((port, Self::owned_frame(data)))
	}
}