use crate::framing::RxDecoder;
use crate::packet;
pub const DEFAULT_UDP_PORT: u16 = 9002;
pub struct UdpClient<const CAP: usize> {
sock: std::net::UdpSocket,
decoder: RxDecoder<CAP>,
}
impl<const CAP: usize> UdpClient<CAP> {
pub fn connect(addr: &str) -> std::io::Result<Self> {
let sock = std::net::UdpSocket::bind("0.0.0.0:0")?;
sock.connect(addr)?;
Ok(Self {
sock,
decoder: RxDecoder::new(),
})
}
pub fn send_packet(&self, packet: &[u8]) -> std::io::Result<usize> {
self.sock.send(packet)
}
pub fn send_command(&self, cmd: &[u8], scratch: &mut [u8]) -> std::io::Result<usize> {
let n = packet::build(cmd, scratch).ok_or_else(|| {
std::io::Error::new(std::io::ErrorKind::InvalidInput, "scratch too small")
})?;
self.sock.send(&scratch[..n])
}
pub fn recv(&mut self) -> std::io::Result<RecvStatus> {
let mut buf = [0u8; 2048];
let n = self.sock.recv(&mut buf)?;
self.decoder.feed(&buf[..n]);
Ok(RecvStatus {
datagram_len: n,
has_frame: self.decoder.has_frame(),
})
}
pub fn take_ref(&mut self) -> Option<crate::framing::RxFrameRef<'_>> {
self.decoder.take_ref()
}
pub fn take_packet(&mut self, out: &mut [u8]) -> Option<usize> {
self.decoder.take_packet(out)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RecvStatus {
pub datagram_len: usize,
pub has_frame: bool,
}
pub fn send_command_to(addr: &str, cmd: &[u8], scratch: &mut [u8]) -> std::io::Result<usize> {
let sock = std::net::UdpSocket::bind("0.0.0.0:0")?;
sock.connect(addr)?;
let n = packet::build(cmd, scratch).ok_or_else(|| {
std::io::Error::new(std::io::ErrorKind::InvalidInput, "scratch too small")
})?;
sock.send(&scratch[..n])
}
#[cfg(test)]
mod tests {
use super::*;
use crate::framing::HEADER_STREAM;
#[test]
fn packet_scratch_roundtrip() {
let mut scratch = [0u8; 64];
let n = packet::build(b"#TPUD2wCAP01", &mut scratch).unwrap();
assert!(packet::verify(&scratch[..n]));
assert_eq!(HEADER_STREAM.len(), 4);
}
}