diff --git a/satrs-core/src/hal/std/tcp_server.rs b/satrs-core/src/hal/std/tcp_server.rs index 436cbfc..3e75784 100644 --- a/satrs-core/src/hal/std/tcp_server.rs +++ b/satrs-core/src/hal/std/tcp_server.rs @@ -13,7 +13,7 @@ use thiserror::Error; // Re-export the TMTC in COBS server. pub use crate::hal::std::tcp_with_cobs_server::{ - parse_buffer_for_cobs_encoded_packets, TcpTmtcInCobsServer, + parse_buffer_for_cobs_encoded_packets, CobsTcParser, CobsTmSender, TcpTmtcInCobsServer, }; /// TCP configuration struct. @@ -87,7 +87,10 @@ pub struct ConnectionResult { pub num_sent_tms: u32, } -pub trait TcpTcHandler { +/// Generic parser abstraction for an object which can parse for telecommands given a raw +/// bytestream received from a TCP socket and send them to a generic [ReceivesTc] telecommand +/// receiver. This allows different encoding schemes for telecommands. +pub trait TcpTcParser { fn handle_tc_parsing( &mut self, tc_buffer: &mut [u8], @@ -97,7 +100,12 @@ pub trait TcpTcHandler { next_write_idx: &mut usize, ) -> Result<(), TcpTmtcError>; } -pub trait TcpTmHandler { + +/// Generic sender abstraction for an object which can pull telemetry from a given TM source +/// using a [TmPacketSource] and then send them back to a client using a given [TcpStream]. +/// The concrete implementation can also perform any encoding steps which are necessary before +/// sending back the data to a client. +pub trait TcpTmSender { fn handle_tm_sending( &mut self, tm_buffer: &mut [u8], @@ -107,11 +115,28 @@ pub trait TcpTmHandler { ) -> Result>; } +/// TCP TMTC server implementation for exchange of generic TMTC packets in a generic way which +/// stays agnostic to the encoding scheme and format used for both telecommands and telemetry. +/// +/// This server implements a generic TMTC handling logic and allows modifying its behaviour +/// through the following 4 core abstractions: +/// +/// 1. [TcpTcParser] to parse for telecommands from the raw bytestream received from a client. +/// 2. Parsed telecommands will be sent to the [ReceivesTc] telecommand receiver. +/// 3. [TcpTmSender] to send telemetry pulled from a TM source back to the client. +/// 4. [TmPacketSource] as a generic TM source used by the [TcpTmSender]. +/// +/// It is possible to specify custom abstractions to build a dedicated TCP TMTC server without +/// having to re-implement common logic. +/// +/// Currently, this framework offers the following concrete implementations: +/// +/// 1. [TcpTmtcInCobsServer] to exchange TMTC wrapped inside the COBS framing protocol. pub struct TcpTmtcGenericServer< TmError, TcError, - TmHandler: TcpTmHandler, - TcHandler: TcpTcHandler, + TmHandler: TcpTmSender, + TcHandler: TcpTcParser, > { base: TcpTmtcServerBase, tc_handler: TcHandler, @@ -121,31 +146,33 @@ pub struct TcpTmtcGenericServer< impl< TmError: 'static, TcError: 'static, - TmHandler: TcpTmHandler, - TcHandler: TcpTcHandler, - > TcpTmtcGenericServer + TmSender: TcpTmSender, + TcParser: TcpTcParser, + > TcpTmtcGenericServer { - /// Create a new TMTC server which exchanges TMTC packets encoded with - /// [COBS protocol](https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing). + /// Create a new generic TMTC server instance. /// /// ## Parameter /// /// * `cfg` - Configuration of the server. + /// * `tc_parser` - Parser which extracts telecommands from the raw bytestream received from + /// the client. + /// * `tm_sender` - Sends back telemetry to the client using the specified TM source. /// * `tm_source` - Generic TM source used by the server to pull telemetry packets which are /// then sent back to the client. /// * `tc_receiver` - Any received telecommand which was decoded successfully will be forwarded /// to this TC receiver. pub fn new( cfg: ServerConfig, - tc_handler: TcHandler, - tm_handler: TmHandler, + tc_parser: TcParser, + tm_sender: TmSender, tm_source: Box + Send>, tc_receiver: Box + Send>, - ) -> Result, std::io::Error> { + ) -> Result, std::io::Error> { Ok(Self { base: TcpTmtcServerBase::new(cfg, tm_source, tc_receiver)?, - tc_handler, - tm_handler, + tc_handler: tc_parser, + tm_handler: tm_sender, }) } @@ -165,10 +192,14 @@ impl< /// /// 1. It calls the [std::net::TcpListener::accept] method internally using the blocking API /// until a client connects. - /// 2. It reads all the telecommands from the client, which are expected to be COBS - /// encoded packets. - /// 3. After reading and parsing all telecommands, it sends back all telemetry it can retrieve - /// from the user specified [TmPacketSource] back to the client. + /// 2. It reads all the telecommands from the client and parses all received data using the + /// user specified [TcpTcParser]. + /// 3. After reading and parsing all telecommands, it sends back all telemetry using the + /// user specified [TcpTmSender]. + /// + /// The server will delay for a user-specified period if the client connects to the server + /// for prolonged periods and there is no traffic for the server. This is the case if the + /// client does not send any telecommands and no telemetry needs to be sent back to the client. pub fn handle_next_connection( &mut self, ) -> Result> { diff --git a/satrs-core/src/hal/std/tcp_with_cobs_server.rs b/satrs-core/src/hal/std/tcp_with_cobs_server.rs index ad1913a..ec39615 100644 --- a/satrs-core/src/hal/std/tcp_with_cobs_server.rs +++ b/satrs-core/src/hal/std/tcp_with_cobs_server.rs @@ -13,13 +13,13 @@ use crate::tmtc::ReceivesTc; use crate::tmtc::TmPacketSource; use crate::hal::std::tcp_server::{ - ConnectionResult, ServerConfig, TcpTcHandler, TcpTmHandler, TcpTmtcError, TcpTmtcGenericServer, + ConnectionResult, ServerConfig, TcpTcParser, TcpTmSender, TcpTmtcError, TcpTmtcGenericServer, }; #[derive(Default)] -struct CobsTcParser {} +pub struct CobsTcParser {} -impl TcpTcHandler for CobsTcParser { +impl TcpTcParser for CobsTcParser { fn handle_tc_parsing( &mut self, tc_buffer: &mut [u8], @@ -39,11 +39,11 @@ impl TcpTcHandler for CobsTcParser { } } -struct CobsTmParser { +pub struct CobsTmSender { tm_encoding_buffer: Vec, } -impl CobsTmParser { +impl CobsTmSender { fn new(tm_buffer_size: usize) -> Self { Self { // The buffer should be large enough to hold the maximum expected TM size encoded with @@ -53,7 +53,7 @@ impl CobsTmParser { } } -impl TcpTmHandler for CobsTmParser { +impl TcpTmSender for CobsTmSender { fn handle_tm_sending( &mut self, tm_buffer: &mut [u8], @@ -93,13 +93,10 @@ impl TcpTmHandler for CobsTmParser { /// TCP TMTC server implementation for exchange of generic TMTC packets which are framed with the /// [COBS protocol](https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing). /// -/// TCP is stream oriented, so a client can read available telemetry using [std::io::Read] as well. -/// To allow flexibly specifying the telemetry sent back to clients, a generic TM abstraction -/// in form of the [TmPacketSource] trait is used. Telemetry will be encoded with the COBS -/// protocol using [cobs::encode] in addition to being wrapped with the sentinel value 0 as the -/// packet delimiter as well before being sent back to the client. Please note that the server -/// will send as much data as it can retrieve from the [TmPacketSource] in its current -/// implementation. +/// Telemetry will be encoded with the COBS protocol using [cobs::encode] in addition to being +/// wrapped with the sentinel value 0 as the packet delimiter as well before being sent back to +/// the client. Please note that the server will send as much data as it can retrieve from the +/// [TmPacketSource] in its current implementation. /// /// Using a framing protocol like COBS imposes minimal restrictions on the type of TMTC data /// exchanged while also allowing packets with flexible size and a reliable way to reconstruct full @@ -107,10 +104,20 @@ impl TcpTmHandler for CobsTmParser { /// [parse_buffer_for_cobs_encoded_packets] function to parse for packets and pass them to a /// generic TC receiver. pub struct TcpTmtcInCobsServer { - generic_server: TcpTmtcGenericServer, + generic_server: TcpTmtcGenericServer, } impl TcpTmtcInCobsServer { + /// Create a new TCP TMTC server which exchanges TMTC packets encoded with + /// [COBS protocol](https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing). + /// + /// ## Parameter + /// + /// * `cfg` - Configuration of the server. + /// * `tm_source` - Generic TM source used by the server to pull telemetry packets which are + /// then sent back to the client. + /// * `tc_receiver` - Any received telecommand which was decoded successfully will be forwarded + /// to this TC receiver. pub fn new( cfg: ServerConfig, tm_source: Box + Send>, @@ -120,7 +127,7 @@ impl TcpTmtcInCobsServer { generic_server: TcpTmtcGenericServer::new( cfg, CobsTcParser::default(), - CobsTmParser::new(cfg.tm_buffer_size), + CobsTmSender::new(cfg.tm_buffer_size), tm_source, tc_receiver, )?, @@ -135,15 +142,7 @@ impl TcpTmtcInCobsServer { /// useful if using the port number 0 for OS auto-assignment. pub fn local_addr(&self) -> std::io::Result; - /// This call is used to handle the next connection to a client. Right now, it performs - /// the following steps: - /// - /// 1. It calls the [std::net::TcpListener::accept] method internally using the blocking API - /// until a client connects. - /// 2. It reads all the telecommands from the client, which are expected to be COBS - /// encoded packets. - /// 3. After reading and parsing all telecommands, it sends back all telemetry it can retrieve - /// from the user specified [TmPacketSource] back to the client. + /// Delegation to the [TcpTmtcGenericServer::handle_next_connection] call. pub fn handle_next_connection( &mut self, ) -> Result>;