fw: do most of command interface

This commit is contained in:
David Lenfesty 2023-06-03 11:43:39 -06:00
parent 0aef4f295d
commit 32eeab2c66
4 changed files with 108 additions and 2 deletions

7
firmware/Cargo.lock generated
View File

@ -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",

View File

@ -11,11 +11,12 @@ riscv = "0.10.1"
panic-halt = "0.2.0"
embedded-hal = "0.2.7"
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

View File

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

View File

@ -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];