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"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crc-any"
|
||||||
|
version = "2.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "774646b687f63643eb0f4bf13dc263cb581c8c9e57973b6ddf78bda3994d88df"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "critical-section"
|
name = "critical-section"
|
||||||
version = "1.1.1"
|
version = "1.1.1"
|
||||||
@ -102,6 +108,7 @@ dependencies = [
|
|||||||
name = "fw"
|
name = "fw"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"crc-any",
|
||||||
"defmt",
|
"defmt",
|
||||||
"embedded-hal",
|
"embedded-hal",
|
||||||
"panic-halt",
|
"panic-halt",
|
||||||
|
@ -10,12 +10,13 @@ riscv-rt = "0.11.0"
|
|||||||
riscv = "0.10.1"
|
riscv = "0.10.1"
|
||||||
panic-halt = "0.2.0"
|
panic-halt = "0.2.0"
|
||||||
embedded-hal = "0.2.7"
|
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]
|
[dependencies.smoltcp]
|
||||||
version = "0.9.1"
|
version = "0.9.1"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["medium-ethernet", "proto-ipv4", "socket-icmp", "defmt"]
|
features = ["medium-ethernet", "proto-ipv4", "socket-tcp", "socket-icmp", "defmt"]
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
debug = true
|
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 litex_uart;
|
||||||
mod logging;
|
mod logging;
|
||||||
mod proto;
|
mod proto;
|
||||||
|
mod command_interface;
|
||||||
|
|
||||||
const MAC: [u8; 6] = [0xA0, 0xBB, 0xCC, 0xDD, 0xEE, 0xF0];
|
const MAC: [u8; 6] = [0xA0, 0xBB, 0xCC, 0xDD, 0xEE, 0xF0];
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user