From: Thomas Karpiniec Date: Tue, 31 Dec 2024 03:22:59 +0000 (+1100) Subject: State definitions and read/write kiss machinery for SoftTnc X-Git-Url: https://code.octet-stream.net/m17rt/commitdiff_plain/21873f99445730506caeab640432413ed23df674?ds=inline State definitions and read/write kiss machinery for SoftTnc --- diff --git a/m17app/src/tnc.rs b/m17app/src/tnc.rs index 99bacc7..921585b 100644 --- a/m17app/src/tnc.rs +++ b/m17app/src/tnc.rs @@ -19,7 +19,7 @@ pub enum TncError { impl Tnc for std::net::TcpStream { fn try_clone(&mut self) -> Result { - self.try_clone().map_err(|_| TncError::Unknown) + std::net::TcpStream::try_clone(self).map_err(|_| TncError::Unknown) } fn start(&mut self) -> Result<(), TncError> { diff --git a/m17core/src/tnc.rs b/m17core/src/tnc.rs index 79adaa4..3f9eb02 100644 --- a/m17core/src/tnc.rs +++ b/m17core/src/tnc.rs @@ -1,12 +1,30 @@ -use crate::protocol::Frame; +use crate::kiss::{KissBuffer, KissFrame}; +use crate::protocol::{Frame, LichCollection, LsfFrame}; /// Handles the KISS protocol and frame management for `SoftModulator` and `SoftDemodulator`. /// /// These components work alongside each other. User is responsible for chaining them together /// or doing something else with the data. -pub struct SoftTnc {} +pub struct SoftTnc { + /// Handle framing of KISS commands from the host, which may arrive in arbitrary binary blobs. + kiss_buffer: KissBuffer, + + /// Kiss message that needs to be sent to the host. + outgoing_kiss: Option, + + /// Current RX or TX function of the TNC. + state: State, +} impl SoftTnc { + pub fn new() -> Self { + Self { + kiss_buffer: KissBuffer::new(), + outgoing_kiss: None, + state: State::Idle, + } + } + /// Process an individual `Frame` that has been decoded by the modem. pub fn handle_frame(&mut self, _frame: Frame) -> Result<(), SoftTncError> { Ok(()) @@ -23,12 +41,32 @@ impl SoftTnc { Ok(None) } - pub fn read_kiss(&mut self, _buf: &mut [u8]) -> Result { - Ok(0) + /// Read KISS message to be sent to host. + /// + /// After each frame input, this should be consumed in a loop until length 0 is returned. + /// This component will never block. Upstream interface can provide blocking `read()` if desired. + pub fn read_kiss(&mut self, target_buf: &mut [u8]) -> Result { + match self.outgoing_kiss.as_mut() { + Some(outgoing) => { + let n = (outgoing.kiss_frame.len - outgoing.sent).min(target_buf.len()); + target_buf[0..n] + .copy_from_slice(&outgoing.kiss_frame.data[outgoing.sent..(outgoing.sent + n)]); + outgoing.sent += n; + Ok(n) + } + None => Ok(0), + } } - pub fn write_kiss(&mut self, _buf: &[u8]) -> Result { - Ok(0) + pub fn write_kiss(&mut self, buf: &[u8]) -> Result { + let target_buf = self.kiss_buffer.buf_remaining(); + let n = buf.len().min(target_buf.len()); + target_buf[0..n].copy_from_slice(&buf[0..n]); + self.kiss_buffer.did_write(n); + while let Some(_kiss_frame) = self.kiss_buffer.next_frame() { + // TODO: handle host-to-TNC message + } + Ok(n) } } @@ -36,3 +74,43 @@ impl SoftTnc { pub enum SoftTncError { General(&'static str), } + +struct OutgoingKiss { + kiss_frame: KissFrame, + sent: usize, +} + +enum State { + /// Nothing happening. + Idle, + + /// We received some stream data but missed the leading LSF so we are trying to assemble from LICH. + RxAcquiringStream(RxAcquiringStreamState), + + /// We have acquired an identified stream transmission and are sending data payloads to the host. + RxStream(RxStreamState), + + /// We are receiving a packet. All is well so far, and there is more data to come before we tell the host. + RxPacket(RxPacketState), + // TODO: TX +} + +struct RxAcquiringStreamState { + /// Partial assembly of LSF by accumulating LICH fields. + lich: LichCollection, +} + +struct RxStreamState { + /// Track identifying information for this transmission so we can tell if it changes. + lsf: LsfFrame, +} + +struct RxPacketState { + /// Accumulation of packet data that we have received so far. + packet: [u8; 825], + + /// Number of frames we have received. If we are stably in the RxPacket state, + /// this will be between 1 and 32 inclusive. The first frame gets us into the + /// rx state, and the maximum 33rd frame must end the transmission and state. + count: usize, +}