This commit is contained in:
Robin Müller 2022-09-11 15:23:11 +02:00
parent 35942aadb6
commit 13f4852c89
No known key found for this signature in database
GPG Key ID: 9C287E88FED11DF3
3 changed files with 29 additions and 10 deletions

View File

@ -1 +1,2 @@
//! Helper modules intended to be used on hosts with a full [std] runtime
pub mod udp_server; pub mod udp_server;

View File

@ -1,10 +1,25 @@
//! UDP server helper components
use crate::tmtc::ReceivesTc; use crate::tmtc::ReceivesTc;
use std::boxed::Box; use std::boxed::Box;
use std::io::ErrorKind; use std::io::{Error, ErrorKind};
use std::net::{SocketAddr, ToSocketAddrs, UdpSocket}; use std::net::{SocketAddr, ToSocketAddrs, UdpSocket};
use std::vec; use std::vec;
use std::vec::Vec; use std::vec::Vec;
/// This TC server helper can be used to receive raw PUS telecommands thorough a UDP interface.
///
/// It caches all received telecomands into a vector. The maximum expected telecommand size should
/// be declared upfront. This avoids dynamic allocation during run-time. The user can specify a TC
/// receiver in form of a special trait object which implements [ReceivesTc]. Please note that the
/// receiver should copy out the received data if it the data is required past the
/// [ReceivesTc::pass_tc] call.
///
/// # Examples
///
/// The [fsrc-example crate](https://egit.irs.uni-stuttgart.de/rust/fsrc-launchpad/src/branch/obsw-client-example/fsrc-example) server code includes
/// [example code](https://egit.irs.uni-stuttgart.de/rust/fsrc-launchpad/src/branch/obsw-client-example/fsrc-example/src/bin/obsw/tmtc.rs)
/// on how to use this TC server. It uses the server to receive PUS telecommands on a specific port
/// and then forwards them to a generic CCSDS packet receiver.
pub struct UdpTcServer<E> { pub struct UdpTcServer<E> {
pub socket: UdpSocket, pub socket: UdpSocket,
recv_buf: Vec<u8>, recv_buf: Vec<u8>,
@ -15,26 +30,29 @@ pub struct UdpTcServer<E> {
#[derive(Debug)] #[derive(Debug)]
pub enum ReceiveResult<E> { pub enum ReceiveResult<E> {
WouldBlock, WouldBlock,
OtherIoError(std::io::Error), IoError(Error),
ReceiverError(E), ReceiverError(E),
} }
impl<E> From<Error> for ReceiveResult<E> {
fn from(e: Error) -> Self {
ReceiveResult::IoError(e)
}
}
impl<E> UdpTcServer<E> { impl<E> UdpTcServer<E> {
pub fn new<A: ToSocketAddrs>( pub fn new<A: ToSocketAddrs>(
addr: A, addr: A,
max_recv_size: usize, max_recv_size: usize,
tc_receiver: Box<dyn ReceivesTc<Error = E>>, tc_receiver: Box<dyn ReceivesTc<Error = E>>,
) -> Result<Self, std::io::Error> { ) -> Result<Self, Error> {
let server = Self { let server = Self {
socket: UdpSocket::bind(addr)?, socket: UdpSocket::bind(addr)?,
recv_buf: vec![0; max_recv_size], recv_buf: vec![0; max_recv_size],
sender_addr: None, sender_addr: None,
tc_receiver, tc_receiver,
}; };
server server.socket.set_nonblocking(true)?;
.socket
.set_nonblocking(true)
.expect("Setting server non blocking failed");
Ok(server) Ok(server)
} }
@ -42,10 +60,10 @@ impl<E> UdpTcServer<E> {
let res = match self.socket.recv_from(&mut self.recv_buf) { let res = match self.socket.recv_from(&mut self.recv_buf) {
Ok(res) => res, Ok(res) => res,
Err(e) => { Err(e) => {
return if e.kind() == ErrorKind::WouldBlock { return if e.kind() == ErrorKind::WouldBlock || e.kind() == ErrorKind::TimedOut {
Err(ReceiveResult::WouldBlock) Err(ReceiveResult::WouldBlock)
} else { } else {
Err(ReceiveResult::OtherIoError(e)) Err(e.into())
} }
} }
}; };

View File

@ -83,7 +83,7 @@ fn core_tc_handling(udp_tmtc_server: &mut UdpTmtcServer) -> bool {
true true
} }
}, },
ReceiveResult::OtherIoError(e) => { ReceiveResult::IoError(e) => {
println!("IO error {e}"); println!("IO error {e}");
false false
} }