From 32eeab2c6663d169c10d52c8819994acff1e2943 Mon Sep 17 00:00:00 2001 From: David Lenfesty Date: Sat, 3 Jun 2023 11:43:39 -0600 Subject: [PATCH] fw: do most of command interface --- firmware/Cargo.lock | 7 +++ firmware/Cargo.toml | 5 +- firmware/src/command_interface.rs | 97 +++++++++++++++++++++++++++++++ firmware/src/main.rs | 1 + 4 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 firmware/src/command_interface.rs diff --git a/firmware/Cargo.lock b/firmware/Cargo.lock index f7b08e2..96acff7 100644 --- a/firmware/Cargo.lock +++ b/firmware/Cargo.lock @@ -50,6 +50,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "crc-any" +version = "2.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "774646b687f63643eb0f4bf13dc263cb581c8c9e57973b6ddf78bda3994d88df" + [[package]] name = "critical-section" version = "1.1.1" @@ -102,6 +108,7 @@ dependencies = [ name = "fw" version = "0.1.0" dependencies = [ + "crc-any", "defmt", "embedded-hal", "panic-halt", diff --git a/firmware/Cargo.toml b/firmware/Cargo.toml index 7d8f45d..31fe677 100644 --- a/firmware/Cargo.toml +++ b/firmware/Cargo.toml @@ -10,12 +10,13 @@ riscv-rt = "0.11.0" riscv = "0.10.1" panic-halt = "0.2.0" embedded-hal = "0.2.7" -defmt = {version = "0.3.4", features = ["encoding-raw"] } +defmt = { version = "0.3.4", features = ["encoding-raw"] } +crc-any = { version = "2.4", default-features = false } [dependencies.smoltcp] version = "0.9.1" default-features = false -features = ["medium-ethernet", "proto-ipv4", "socket-icmp", "defmt"] +features = ["medium-ethernet", "proto-ipv4", "socket-tcp", "socket-icmp", "defmt"] [profile.release] debug = true diff --git a/firmware/src/command_interface.rs b/firmware/src/command_interface.rs new file mode 100644 index 0000000..1532f61 --- /dev/null +++ b/firmware/src/command_interface.rs @@ -0,0 +1,97 @@ +use smoltcp::socket::tcp::{Socket, State}; + +use crate::proto::{ + serialize_response_error, serialize_response_value, PacketParser, ResponsePacket, Settings, ErrorCodes +}; + +struct CommandInterface { + parser: PacketParser, +} + +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. + + // TODO should put packet parsing behind a fn with the smoltcp result, then on smoltcp error + // we reconfigure here instead of calling it 4 times + + // 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()) + }); + + // Check for socket errors + let packet = match res { + Ok(Some(packet)) => packet, + // No packet to process + Ok(None) => return, + // Any socket error means we just want to drop the connection and re-connect + Err(_) => { + Self::reestablish_socket(sock); + return; + } + }; + + // Check that setting is valid + let setting = match Settings::try_from(packet.setting) { + Ok(v) => v, + Err(()) => { + // Write out an error packet + let result = sock.send(|tx_buf| { + if tx_buf.len() < 8 { + return (0, ()); + } + + let response = serialize_response_error(packet.setting, ErrorCodes::InvalidSetting); + &tx_buf[0..8].copy_from_slice(&response); + return (8, ()); + }); + + if let Err(_) = result { + // TX error, close socket and reconnect + Self::reestablish_socket(sock); + } + + return; + } + }; + + // TODO validate setting values + + // TODO handle actually changing/getting settings in all the ways + // For temp testing, return values sent + match 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, ()); + }) { + Ok(()) => (), + Err(_) => { + Self::reestablish_socket(sock); + } + }; + } + + fn reestablish_socket(sock: &mut Socket) { + sock.abort(); + sock.listen(2000); + } +} diff --git a/firmware/src/main.rs b/firmware/src/main.rs index 05d9a8a..3810544 100644 --- a/firmware/src/main.rs +++ b/firmware/src/main.rs @@ -29,6 +29,7 @@ mod uart; mod litex_uart; mod logging; mod proto; +mod command_interface; const MAC: [u8; 6] = [0xA0, 0xBB, 0xCC, 0xDD, 0xEE, 0xF0];