113 lines
3.4 KiB
Rust
113 lines
3.4 KiB
Rust
use smoltcp::socket::tcp::{Socket, State};
|
|
|
|
use crate::proto::{
|
|
serialize_response_error, serialize_response_value, ErrorCodes, PacketParser, ResponsePacket,
|
|
Settings,
|
|
};
|
|
|
|
pub struct CommandInterface {
|
|
parser: PacketParser,
|
|
}
|
|
|
|
const COMMAND_PORT: u16 = 2000;
|
|
|
|
impl CommandInterface {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
parser: PacketParser::new(),
|
|
}
|
|
}
|
|
|
|
/// Run the command interface
|
|
pub fn run(&mut self, sock: &mut Socket) {
|
|
// Note that we don't attempt to check status of the connection. All of
|
|
// the smoltcp functions handle the error cases gracefully. Recv
|
|
// provides a buffer of length 0 when there is nothing to receive, so we
|
|
// are good there. We just reset on any smoltcp errors.
|
|
|
|
if !sock.is_open() {
|
|
defmt::debug!("Socket has been closed");
|
|
// Socket has been closed, some error has occured
|
|
sock.listen(COMMAND_PORT);
|
|
return;
|
|
}
|
|
|
|
if !sock.can_recv() {
|
|
return;
|
|
}
|
|
|
|
// Try and parse a packet
|
|
let res = sock.recv(|rx_buf| {
|
|
let (res, processed_bytes) = self.parser.try_parse(rx_buf);
|
|
|
|
(processed_bytes, res.ok())
|
|
});
|
|
|
|
defmt::debug!("Received data");
|
|
|
|
// Check for socket errors
|
|
let packet = match res {
|
|
// We got a packet! unwrap it
|
|
Ok(Some(packet)) => packet,
|
|
// No packet to process, move on
|
|
Ok(None) => return,
|
|
Err(_) => {
|
|
defmt::debug!("rx err");
|
|
sock.abort();
|
|
return;
|
|
}
|
|
};
|
|
|
|
defmt::debug!("Packet rx");
|
|
|
|
// Check that setting is valid
|
|
let setting = match Settings::try_from(packet.setting) {
|
|
Ok(v) => v,
|
|
Err(()) => {
|
|
// Write out an error packet, we'll just ignore errors
|
|
let _ = sock.send(|tx_buf| {
|
|
if tx_buf.len() < 8 {
|
|
// Just drop the packet if we don't have buffer available
|
|
return (0, ());
|
|
}
|
|
|
|
let response =
|
|
serialize_response_error(packet.setting, ErrorCodes::InvalidSetting);
|
|
&tx_buf[0..8].copy_from_slice(&response);
|
|
return (8, ());
|
|
});
|
|
|
|
return;
|
|
}
|
|
};
|
|
|
|
defmt::debug!(
|
|
"Valid packet: {:?}, is_write: {}, value: {}",
|
|
packet.setting,
|
|
packet.is_write,
|
|
packet.value
|
|
);
|
|
|
|
// TODO validate setting values
|
|
|
|
// TODO handle actually changing/getting settings in all the ways
|
|
// For temp testing, return values sent
|
|
let res = sock.send(|tx_buf| {
|
|
if tx_buf.len() < 8 {
|
|
// Since this is a low-BW configuration socket, we assume we have space, and drop
|
|
// the response otherwise. If this is an issue, may re-think this and queue commands but
|
|
// for now this is fine.
|
|
return (0, ());
|
|
}
|
|
let response = serialize_response_value(setting, packet.value);
|
|
&tx_buf[0..8].copy_from_slice(&response);
|
|
return (8, ());
|
|
});
|
|
|
|
if res.is_err() {
|
|
defmt::debug!("tx err");
|
|
sock.abort();
|
|
}
|
|
}
|
|
}
|