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(); } } }