fw: do most of command interface
This commit is contained in:
parent
0aef4f295d
commit
32eeab2c66
7
firmware/Cargo.lock
generated
7
firmware/Cargo.lock
generated
@ -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",
|
||||
|
@ -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
|
||||
|
97
firmware/src/command_interface.rs
Normal file
97
firmware/src/command_interface.rs
Normal 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);
|
||||
}
|
||||
}
|
@ -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];
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user