diff options
author | Matthias P. Braendli <matthias.braendli@mpb.li> | 2018-08-26 22:03:10 +0200 |
---|---|---|
committer | Matthias P. Braendli <matthias.braendli@mpb.li> | 2018-08-26 22:04:27 +0200 |
commit | 37a60e2d14857c582ad5770a936c6a5647ea2b9e (patch) | |
tree | 3751ae13d7d8bba88b93fb50c5d8d28fca80f3b9 /src/kiss.rs | |
download | raspi-rfm95-kiss-37a60e2d14857c582ad5770a936c6a5647ea2b9e.tar.gz raspi-rfm95-kiss-37a60e2d14857c582ad5770a936c6a5647ea2b9e.tar.bz2 raspi-rfm95-kiss-37a60e2d14857c582ad5770a936c6a5647ea2b9e.zip |
Add initial code
Diffstat (limited to 'src/kiss.rs')
-rw-r--r-- | src/kiss.rs | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/src/kiss.rs b/src/kiss.rs new file mode 100644 index 0000000..397922d --- /dev/null +++ b/src/kiss.rs @@ -0,0 +1,183 @@ +// Taken from ax25-rs, which is +// SPDX-License-Identifier: Apache-2.0 +use std::io; +use std::io::prelude::*; +use std::io::{Read, Write}; + +const FEND: u8 = 0xC0; +const FESC: u8 = 0xDB; +const TFEND: u8 = 0xDC; +const TFESC: u8 = 0xDD; + +pub struct KissDecoder<'a> { + stream: &'a Read, + buffer: Vec<u8> +} + +impl<'a> KissDecoder<'a> { + pub fn new<T>(stream: &T) -> io::Result<KissDecoder> + where T: Read + { + Ok(KissDecoder { + stream: stream, + buffer: Vec::new() + }) + } + + pub fn receive_frame(&mut self) -> io::Result<Vec<u8>> { + loop { + if let Some(frame) = make_frame_from_buffer(&mut self.buffer) { + return Ok(frame); + } + let mut buf = vec![0u8; 1024]; + let n_bytes = self.stream.read(&mut buf)?; + self.buffer.extend(buf.iter().take(n_bytes)); + } + } +} + +/* +pub struct KissEncoder { + stream: Write, + buffer: Vec<u8> +} + +impl KissEncoder { + pub fn new(stream: Write) -> io::Result<KissEncoder> { + Ok(KissEncoder { + stream: stream, + buffer: Vec::new() + }) + } + + pub fn send_frame(&mut self, frame: &[u8]) -> io::Result<()> { + // 0x00 is the KISS command byte, which is two nybbles + // port = 0 + // command = 0 (all following bytes are a data frame to transmit) + self.stream.write(&[FEND, 0x00])?; + self.stream.write(frame)?; + self.stream.write(&[FEND])?; + self.stream.flush()?; + Ok(()) + } +} + +fn make_frame_from_buffer(buffer: &mut Vec<u8>) -> Option<Vec<u8>> { + let mut possible_frame = Vec::new(); + + enum Scan { + LookingForStartMarker, + Data, + Escaped + } + let mut state = Scan::LookingForStartMarker; + let mut final_idx = 0; + + // Check for possible frame read-only until we know we have a complete frame + // If we take one out, clear out buffer up to the final index + for (idx, &c) in buffer.iter().enumerate() { + match state { + Scan::LookingForStartMarker => { + if c == FEND { + state = Scan::Data; + } + }, + Scan::Data => { + if c == FEND { + if !possible_frame.is_empty() { + // Successfully read a non-zero-length frame + final_idx = idx; + break; + } + } else if c == FESC { + state = Scan::Escaped; + } else { + possible_frame.push(c); + } + }, + Scan::Escaped => { + if c == TFEND { + possible_frame.push(FEND); + } else if c == TFESC { + possible_frame.push(FESC); + } else if c == FEND { + if !possible_frame.is_empty() { + // Successfully read a non-zero-length frame + final_idx = idx; + break; + } + } + state = Scan::Data; + } + } + } + + match final_idx { + 0 => None, + n => { + // Draining up to "n" will leave the final FEND in place + // This way we can use it as the start marker for the next frame + buffer.drain(0..n); + Some(possible_frame) + } + } +} + +#[test] +fn test_normal_frame() { + let mut rx = vec![FEND, 0x01, 0x02, FEND]; + assert_eq!(make_frame_from_buffer(&mut rx), Some(vec![0x01, 0x02])); + assert_eq!(rx, vec![FEND]); +} + +#[test] +fn test_trailing_data() { + let mut rx = vec![FEND, 0x01, 0x02, FEND, 0x03, 0x04]; + assert_eq!(make_frame_from_buffer(&mut rx), Some(vec![0x01, 0x02])); + assert_eq!(rx, vec![FEND, 0x03, 0x04]); +} + +#[test] +fn test_leading_data() { + let mut rx = vec![0x03, 0x04, FEND, 0x01, 0x02, FEND]; + assert_eq!(make_frame_from_buffer(&mut rx), Some(vec![0x01, 0x02])); + assert_eq!(rx, vec![FEND]); +} + +#[test] +fn test_consecutive_marker() { + let mut rx = vec![FEND, FEND, FEND, 0x01, 0x02, FEND]; + assert_eq!(make_frame_from_buffer(&mut rx), Some(vec![0x01, 0x02])); + assert_eq!(rx, vec![FEND]); +} + +#[test] +fn test_escapes() { + let mut rx = vec![FEND, 0x01, FESC, TFESC, 0x02, FESC, TFEND, 0x03, FEND]; + assert_eq!(make_frame_from_buffer(&mut rx), Some(vec![0x01, FESC, 0x02, FEND, 0x03])); + assert_eq!(rx, vec![FEND]); +} + +#[test] +fn test_incorrect_escape_skipped() { + let mut rx = vec![FEND, 0x01, FESC, 0x04, TFESC /* passes normally without leading FESC */, 0x02, FEND]; + assert_eq!(make_frame_from_buffer(&mut rx), Some(vec![0x01, TFESC, 0x02])); + assert_eq!(rx, vec![FEND]); +} + +#[test] +fn test_two_frames_single_fend() { + let mut rx = vec![FEND, 0x01, 0x02, FEND, 0x03, 0x04, FEND]; + assert_eq!(make_frame_from_buffer(&mut rx), Some(vec![0x01, 0x02])); + assert_eq!(make_frame_from_buffer(&mut rx), Some(vec![0x03, 0x04])); + assert_eq!(rx, vec![FEND]); +} + +#[test] +fn test_two_frames_double_fend() { + let mut rx = vec![FEND, 0x01, 0x02, FEND, FEND, 0x03, 0x04, FEND]; + assert_eq!(make_frame_from_buffer(&mut rx), Some(vec![0x01, 0x02])); + assert_eq!(make_frame_from_buffer(&mut rx), Some(vec![0x03, 0x04])); + assert_eq!(rx, vec![FEND]); +} +*/ |