summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/control/src/lib.rs10
-rw-r--r--crates/web/src/main.rs3
-rw-r--r--crates/windlass/examples/usb_test.rs4
-rw-r--r--crates/windlass/src/dictionary.rs28
-rw-r--r--crates/windlass/src/encoding.rs45
-rw-r--r--crates/windlass/src/lib.rs8
-rw-r--r--crates/windlass/src/macros.rs4
-rw-r--r--crates/windlass/src/mcu.rs142
-rw-r--r--crates/windlass/src/messages.rs4
-rw-r--r--crates/windlass/src/transport/frame.rs28
-rw-r--r--crates/windlass/src/transport/mod.rs59
-rw-r--r--crates/windlass/src/transport/rtt.rs5
12 files changed, 185 insertions, 155 deletions
diff --git a/crates/control/src/lib.rs b/crates/control/src/lib.rs
index 5691cf2..f0226f9 100644
--- a/crates/control/src/lib.rs
+++ b/crates/control/src/lib.rs
@@ -4,6 +4,8 @@
//! in a separate thread, on its own async executor.
//!
//! The main server spawns this thread by creating a [`Handle`] and communicates by sending [messages](crate::Message) over an MPSC channel.
+#![deny(clippy::all, clippy::pedantic, clippy::nursery)]
+#![allow(clippy::must_use_candidate, clippy::missing_errors_doc)]
use std::{
mem::ManuallyDrop,
@@ -21,6 +23,7 @@ const CHANNEL_CAPACITY: usize = 100;
/// A control message sent from the API to the printer control thread
pub enum Message {
+ Todo,
Quit,
}
@@ -32,6 +35,8 @@ pub struct Handle {
impl Handle {
/// Spawn a printer control thread, returning a handle
+ /// # Panics
+ /// If there is an error spawning the control thread
pub fn spawn() -> Self {
let (send, recv) = mpsc::channel(CHANNEL_CAPACITY);
@@ -58,8 +63,8 @@ impl Drop for Handle {
info!("waiting for printer thread to exit...");
ManuallyDrop::take(&mut self.thread_handle)
.join()
- .expect("error joining printer thread")
- };
+ .expect("error joining printer thread");
+ }
}
}
@@ -75,6 +80,7 @@ impl State {
while let Some(msg) = self.cmd_recv.recv().await {
match msg {
Message::Quit => break,
+ Message::Todo => todo!(),
}
}
}
diff --git a/crates/web/src/main.rs b/crates/web/src/main.rs
index d80b232..ad339d8 100644
--- a/crates/web/src/main.rs
+++ b/crates/web/src/main.rs
@@ -1,3 +1,6 @@
+#![deny(clippy::all, clippy::pedantic, clippy::nursery)]
+#![allow(clippy::must_use_candidate, clippy::missing_errors_doc)]
+
use std::sync::Arc;
use axum::{routing::get, Router};
diff --git a/crates/windlass/examples/usb_test.rs b/crates/windlass/examples/usb_test.rs
index 6aee77b..1977258 100644
--- a/crates/windlass/examples/usb_test.rs
+++ b/crates/windlass/examples/usb_test.rs
@@ -1,5 +1,5 @@
use tokio::time::Duration;
-use windlass::{mcu_command, mcu_reply, McuConnection};
+use windlass::{mcu_command, mcu_reply, Connection};
mcu_command!(DebugNop, "debug_nop");
mcu_command!(GetClock, "get_clock");
@@ -31,7 +31,7 @@ async fn main() {
let builder = tokio_serial::new(target, 96_000);
let port = tokio_serial::SerialStream::open(&builder).expect("USB open");
- let mut mcu = McuConnection::connect(port).await.expect("MCU connect");
+ let mut mcu = Connection::connect(port).await.expect("MCU connect");
let mut resp = mcu.register_response(Stats).expect("Register");
diff --git a/crates/windlass/src/dictionary.rs b/crates/windlass/src/dictionary.rs
index 270b0e5..2ff9481 100644
--- a/crates/windlass/src/dictionary.rs
+++ b/crates/windlass/src/dictionary.rs
@@ -71,21 +71,23 @@ impl Dictionary {
}
/// Extra data returned in the dictionary response
- pub fn extra(&self) -> &BTreeMap<String, serde_json::Value> {
+ pub const fn extra(&self) -> &BTreeMap<String, serde_json::Value> {
&self.extra
}
/// Figure out the actual value of a command tag
- fn map_tag(tag: i16) -> Result<u16, DictionaryError> {
+ #[allow(clippy::cast_sign_loss, clippy::cast_possible_wrap)]
+ fn map_tag(tag: i16) -> Result<u16, Error> {
+ // TODO: Hacky, and heap allocation is inefficient
let mut buf = vec![];
encode_vlq_int(&mut buf, tag as u32);
let v = if buf.len() > 1 {
- ((buf[0] as u16) & 0x7F) << 7 | (buf[1] as u16) & 0x7F
+ ((u16::from(buf[0])) & 0x7F) << 7 | (u16::from(buf[1])) & 0x7F
} else {
- (buf[0] as u16) & 0x7F
+ (u16::from(buf[0])) & 0x7F
};
if v >= 1 << 14 {
- Err(DictionaryError::InvalidCommandTag(v))
+ Err(Error::InvalidCommandTag(v))
} else {
Ok(v)
}
@@ -93,7 +95,7 @@ impl Dictionary {
}
impl TryFrom<RawDictionary> for Dictionary {
- type Error = DictionaryError;
+ type Error = Error;
fn try_from(raw: RawDictionary) -> Result<Self, Self::Error> {
let mut message_ids = BTreeMap::new();
@@ -101,9 +103,9 @@ impl TryFrom<RawDictionary> for Dictionary {
for (cmd, tag) in raw.commands {
let mut split = cmd.split(' ');
- let name = split.next().ok_or(DictionaryError::EmptyCommand)?;
+ let name = split.next().ok_or(Error::EmptyCommand)?;
let parser = MessageParser::new(name, split)
- .map_err(|e| DictionaryError::InvalidCommandFormat(name.to_string(), e))?;
+ .map_err(|e| Error::InvalidCommandFormat(name.to_string(), e))?;
let tag = Self::map_tag(tag)?;
message_parsers.insert(tag, parser);
message_ids.insert(name.to_string(), tag);
@@ -111,9 +113,9 @@ impl TryFrom<RawDictionary> for Dictionary {
for (resp, tag) in raw.responses {
let mut split = resp.split(' ');
- let name = split.next().ok_or(DictionaryError::EmptyCommand)?;
+ let name = split.next().ok_or(Error::EmptyCommand)?;
let parser = MessageParser::new(name, split)
- .map_err(|e| DictionaryError::InvalidCommandFormat(name.to_string(), e))?;
+ .map_err(|e| Error::InvalidCommandFormat(name.to_string(), e))?;
let tag = Self::map_tag(tag)?;
message_parsers.insert(tag, parser);
message_ids.insert(name.to_string(), tag);
@@ -121,12 +123,12 @@ impl TryFrom<RawDictionary> for Dictionary {
for (msg, tag) in raw.output {
let parser = MessageParser::new_output(&msg)
- .map_err(|e| DictionaryError::InvalidCommandFormat(msg.to_string(), e))?;
+ .map_err(|e| Error::InvalidCommandFormat(msg.to_string(), e))?;
let tag = Self::map_tag(tag)?;
message_parsers.insert(tag, parser);
}
- Ok(Dictionary {
+ Ok(Self {
message_ids,
message_parsers,
config: raw.config,
@@ -189,7 +191,7 @@ impl EnumDef {
/// Error encountered when getting dictionary from microcontroller
#[derive(thiserror::Error, Debug)]
-pub enum DictionaryError {
+pub enum Error {
/// Found an empty command
#[error("empty command found")]
EmptyCommand,
diff --git a/crates/windlass/src/encoding.rs b/crates/windlass/src/encoding.rs
index 27238c0..6b50c3c 100644
--- a/crates/windlass/src/encoding.rs
+++ b/crates/windlass/src/encoding.rs
@@ -8,15 +8,20 @@ pub(crate) fn crc16(buf: &[u8]) -> u16 {
for b in buf {
let b = *b ^ ((crc & 0xFF) as u8);
let b = b ^ (b << 4);
- let b16 = b as u16;
+ let b16 = u16::from(b);
crc = (b16 << 8 | crc >> 8) ^ (b16 >> 4) ^ (b16 << 3);
}
crc
}
/// Encode the given integer as a [VLQ](https://www.klipper3d.org/Protocol.html#variable-length-quantities), pushing it to the back of `output`.
+#[allow(clippy::cast_possible_wrap, clippy::cast_sign_loss)]
pub(crate) fn encode_vlq_int(output: &mut Vec<u8>, v: u32) {
+ // This is ok, as we're just doing bit fiddling and the signedness
+ // will be figured out at the other side again.
let sv = v as i32;
+
+ // Likewise for these casts
if !(-(1 << 26)..(3 << 26)).contains(&sv) {
output.push(((sv >> 28) & 0x7F) as u8 | 0x80);
}
@@ -33,14 +38,16 @@ pub(crate) fn encode_vlq_int(output: &mut Vec<u8>, v: u32) {
}
/// Parse a [VLQ](https://www.klipper3d.org/Protocol.html#variable-length-quantities) from the top of `data`.
+#[allow(clippy::cast_possible_wrap, clippy::cast_sign_loss)]
pub(crate) fn parse_vlq_int(data: &mut &[u8]) -> Result<u32, MessageDecodeError> {
- let mut c = next_byte(data)? as u32;
+ // Casting is fine here, as we're just doing bit fiddling
+ let mut c = u32::from(next_byte(data)?);
let mut v = c & 0x7F;
if (c & 0x60) == 0x60 {
v |= (-0x20i32) as u32;
}
while c & 0x80 != 0 {
- c = next_byte(data)? as u32;
+ c = u32::from(next_byte(data)?);
v = (v << 7) | (c & 0x7F);
}
@@ -97,7 +104,7 @@ pub enum FieldType {
impl FieldType {
/// Skip over a field of this type at the top of `input`.
- pub(crate) fn skip(&self, input: &mut &[u8]) -> Result<(), MessageDecodeError> {
+ pub(crate) fn skip(self, input: &mut &[u8]) -> Result<(), MessageDecodeError> {
match self {
Self::U32 => <u32 as Readable>::skip(input),
Self::I32 => <i32 as Readable>::skip(input),
@@ -110,7 +117,7 @@ impl FieldType {
}
/// Read a field of this type from the top of `input`.
- pub(crate) fn read(&self, input: &mut &[u8]) -> Result<FieldValue, MessageDecodeError> {
+ pub(crate) fn read(self, input: &mut &[u8]) -> Result<FieldValue, MessageDecodeError> {
Ok(match self {
Self::U32 => FieldValue::U32(<u32 as Readable>::read(input)?),
Self::I32 => FieldValue::I32(<i32 as Readable>::read(input)?),
@@ -131,13 +138,13 @@ impl FieldType {
"%hi" => Ok(Self::I16),
"%c" => Ok(Self::U8),
"%s" => Ok(Self::String),
- "%*s" => Ok(Self::ByteArray),
- "%.*s" => Ok(Self::ByteArray),
+ "%*s" | "%.*s" => Ok(Self::ByteArray),
s => Err(MessageSkipperError::InvalidFormatFieldType(s.to_string())),
}
}
/// Deserialise the next field type from a printf style declaration, also returning the rest of the string.
+ #[allow(clippy::option_if_let_else)]
pub(crate) fn from_format(s: &str) -> Result<(Self, &str), MessageSkipperError> {
if let Some(rest) = s.strip_prefix("%u") {
Ok((Self::U32, rest))
@@ -174,13 +181,13 @@ pub enum FieldValue {
impl Display for FieldValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
- Self::U32(v) => write!(f, "{}", v),
- Self::I32(v) => write!(f, "{}", v),
- Self::U16(v) => write!(f, "{}", v),
- Self::I16(v) => write!(f, "{}", v),
- Self::U8(v) => write!(f, "{}", v),
- Self::String(v) => write!(f, "{}", v),
- Self::ByteArray(v) => write!(f, "{:?}", v),
+ Self::U32(v) => write!(f, "{v}"),
+ Self::I32(v) => write!(f, "{v}"),
+ Self::U16(v) => write!(f, "{v}"),
+ Self::I16(v) => write!(f, "{v}"),
+ Self::U8(v) => write!(f, "{v}"),
+ Self::String(v) => write!(f, "{v}"),
+ Self::ByteArray(v) => write!(f, "{v:?}"),
}
}
}
@@ -196,12 +203,18 @@ macro_rules! int_readwrite {
( $type:tt, $field_type:expr ) => {
impl Readable<'_> for $type {
fn read(data: &mut &[u8]) -> Result<Self, MessageDecodeError> {
+ #[allow(clippy::cast_possible_wrap, clippy::cast_possible_truncation)]
parse_vlq_int(data).map(|v| v as $type)
}
}
impl Writable for $type {
fn write(&self, output: &mut Vec<u8>) {
+ #[allow(
+ clippy::cast_possible_wrap,
+ clippy::cast_lossless,
+ clippy::cast_sign_loss
+ )]
encode_vlq_int(output, *self as u32)
}
}
@@ -235,7 +248,7 @@ impl Readable<'_> for bool {
impl Writable for bool {
fn write(&self, output: &mut Vec<u8>) {
- encode_vlq_int(output, u32::from(*self))
+ encode_vlq_int(output, u32::from(*self));
}
}
@@ -277,6 +290,7 @@ impl<'de> Readable<'de> for &'de [u8] {
impl Writable for &[u8] {
fn write(&self, output: &mut Vec<u8>) {
+ #[allow(clippy::cast_possible_truncation)]
encode_vlq_int(output, self.len() as u32);
output.extend_from_slice(self);
}
@@ -321,6 +335,7 @@ impl<'de> Readable<'de> for &'de str {
impl Writable for &str {
fn write(&self, output: &mut Vec<u8>) {
let bytes = self.as_bytes();
+ #[allow(clippy::cast_possible_truncation)]
encode_vlq_int(output, bytes.len() as u32);
output.extend_from_slice(bytes);
}
diff --git a/crates/windlass/src/lib.rs b/crates/windlass/src/lib.rs
index 66a7674..2b27f79 100644
--- a/crates/windlass/src/lib.rs
+++ b/crates/windlass/src/lib.rs
@@ -1,4 +1,10 @@
//! Windlass is an implementation of the host side of the Klipper protocol.
+#![deny(clippy::all, clippy::pedantic, clippy::nursery)]
+#![allow(
+ clippy::must_use_candidate,
+ clippy::missing_errors_doc,
+ clippy::future_not_send
+)]
#[macro_use]
#[doc(hidden)]
@@ -10,4 +16,4 @@ pub mod messages;
mod mcu;
mod transport;
-pub use mcu::{McuConnection, McuConnectionError};
+pub use mcu::{Connection, ConnectionError};
diff --git a/crates/windlass/src/macros.rs b/crates/windlass/src/macros.rs
index f17c66d..c118ada 100644
--- a/crates/windlass/src/macros.rs
+++ b/crates/windlass/src/macros.rs
@@ -8,7 +8,7 @@
///
/// A struct with the given name will be defined, with relevant interfaces. The message name and
/// arguments will be matched to the MCU at runtime. The struct name has no restrictions, but it is
-/// recommended to pick a SnakeCased version of the command name.
+/// recommended to pick a `SnakeCased` version of the command name.
///
/// Optionally an `id` can be directly specified. Generally this is not needed. When not specified,
/// it will be automatically inferred at runtime and matched to the dictionary retrieved from the
@@ -53,7 +53,7 @@ macro_rules! mcu_command {
/// mcu_reply!(<struct name>, "<reply name>"( = <id>) [, arg: type, ..]);
/// ```
///
-/// For more information on the various fields, see the documentation for [mcu_command].
+/// For more information on the various fields, see the documentation for [`mcu_command`].
///
/// # Examples
///
diff --git a/crates/windlass/src/mcu.rs b/crates/windlass/src/mcu.rs
index c2ca54a..8bc725f 100644
--- a/crates/windlass/src/mcu.rs
+++ b/crates/windlass/src/mcu.rs
@@ -20,8 +20,8 @@ use tracing::{debug, error, trace};
use crate::messages::{format_command_args, EncodedMessage, Message, WithOid, WithoutOid};
use crate::transport::{Transport, TransportReceiver};
use crate::{
- dictionary::{Dictionary, DictionaryError, RawDictionary},
- transport::TransportError,
+ dictionary::{self, Dictionary, RawDictionary},
+ transport::Error,
};
use crate::{
encoding::{parse_vlq_int, MessageDecodeError},
@@ -38,7 +38,7 @@ mcu_reply!(
/// MCU Connection Errors
#[derive(thiserror::Error, Debug)]
-pub enum McuConnectionError {
+pub enum ConnectionError {
/// Encoding a message was attempted but a command with a matching name doesn't exist in the
/// dictionary.
#[error("unknown message ID for command '{0}'")]
@@ -51,7 +51,7 @@ pub enum McuConnectionError {
DictionaryFetch(Box<dyn std::error::Error + Send + Sync>),
/// An error was encountered while parsing the dictionary
#[error("dictionary issue: {0}")]
- Dictionary(#[from] DictionaryError),
+ Dictionary(#[from] dictionary::Error),
/// Received an unknown command from the MCU
#[error("unknown command {0}")]
UnknownCommand(u16),
@@ -60,7 +60,7 @@ pub enum McuConnectionError {
CommandMismatch(&'static str, String, String),
/// There was a transport-level issue
#[error("transport error: {0}")]
- Transport(#[from] TransportError),
+ Transport(#[from] Error),
}
#[derive(thiserror::Error, Debug)]
@@ -68,7 +68,7 @@ pub enum SendReceiveError {
#[error("timeout")]
Timeout,
#[error("mcu connection error: {0}")]
- McuConnection(#[from] McuConnectionError),
+ McuConnection(#[from] ConnectionError),
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd)]
@@ -94,7 +94,7 @@ impl std::fmt::Debug for Handlers {
let h = self
.handlers
.try_lock()
- .map(|h| h.keys().cloned().collect::<BTreeSet<_>>())
+ .map(|h| h.keys().copied().collect::<BTreeSet<_>>())
.unwrap_or_default();
f.debug_struct("Handlers")
.field("handlers", &h)
@@ -158,11 +158,11 @@ struct McuConnectionInner {
}
impl McuConnectionInner {
- async fn receive_loop(&self, mut inbox: TransportReceiver) -> Result<(), McuConnectionError> {
+ async fn receive_loop(&self, mut inbox: TransportReceiver) -> Result<(), ConnectionError> {
while let Some(frame) = inbox.recv().await {
let frame = match frame {
Ok(frame) => frame,
- Err(e) => return Err(McuConnectionError::Transport(e)),
+ Err(e) => return Err(ConnectionError::Transport(e)),
};
let frame = &mut frame.as_slice();
self.parse_frame(frame)?;
@@ -170,9 +170,9 @@ impl McuConnectionInner {
Ok(())
}
- fn parse_frame(&self, frame: &mut &[u8]) -> Result<(), McuConnectionError> {
+ fn parse_frame(&self, frame: &mut &[u8]) -> Result<(), ConnectionError> {
while !frame.is_empty() {
- let cmd = parse_vlq_int(frame)? as u16;
+ let cmd = u16::try_from(parse_vlq_int(frame)?).expect("command handler overflow");
// If a raw handler is registered for this, call it
if self.handlers.call(cmd, None, frame) {
@@ -206,7 +206,7 @@ impl McuConnectionInner {
);
}
} else {
- return Err(McuConnectionError::UnknownCommand(cmd));
+ return Err(ConnectionError::UnknownCommand(cmd));
}
} else {
break;
@@ -220,7 +220,7 @@ impl McuConnectionInner {
///
///
#[derive(Debug)]
-pub struct McuConnection {
+pub struct Connection {
inner: Arc<McuConnectionInner>,
transport: Transport,
_receiver: JoinHandle<()>,
@@ -229,22 +229,24 @@ pub struct McuConnection {
#[derive(Debug)]
enum ExitCode {
- Waiting(oneshot::Receiver<Result<(), McuConnectionError>>),
- Exited(Result<(), McuConnectionError>),
+ Waiting(oneshot::Receiver<Result<(), ConnectionError>>),
+ Exited(Result<(), ConnectionError>),
}
-impl McuConnection {
+impl Connection {
/// Connect to an MCU
///
/// Attempts to connect to a MCU on the given data stream interface. The MCU is contacted and
- /// the dictionary is loaded and applied. The returned [McuConnection] is fully ready to
+ /// the dictionary is loaded and applied. The returned [`McuConnection`] is fully ready to
/// communicate with the MCU.
- pub async fn connect<R, W>(rdr: R, wr: W) -> Result<Self, McuConnectionError>
+ /// # Panics
+ /// Panics if the MCU attempts to send an identify payload with size > [`u32::MAX`]
+ pub async fn connect<R, W>(rdr: R, wr: W) -> Result<Self, ConnectionError>
where
R: AsyncBufRead + Send + Unpin + 'static,
W: AsyncWrite + Send + Unpin + 'static,
{
- let (transport, inbox) = Transport::connect(rdr, wr).await;
+ let (transport, inbox) = Transport::connect(rdr, wr);
let (exit_tx, exit_rx) = oneshot::channel();
let inner = Arc::new(McuConnectionInner {
@@ -258,7 +260,7 @@ impl McuConnection {
let _ = exit_tx.send(receiver_inner.receive_loop(inbox).await);
});
- let conn = McuConnection {
+ let conn = Self {
inner,
transport,
_receiver: receiver,
@@ -269,16 +271,16 @@ impl McuConnection {
let identify_start = Instant::now();
loop {
let data = conn
- .send_receive(
- Identify::encode(identify_data.len() as u32, 40),
- IdentifyResponse,
- )
+ .send_receive::<_, IdentifyResponse>(Identify::encode(
+ u32::try_from(identify_data.len()).expect("identify data too long"),
+ 40,
+ ))
.await;
let mut data = match data {
Ok(data) => data,
Err(e) => {
if identify_start.elapsed() > Duration::from_secs(10) {
- return Err(McuConnectionError::DictionaryFetch(Box::new(e)));
+ return Err(ConnectionError::DictionaryFetch(Box::new(e)));
}
continue;
}
@@ -294,20 +296,19 @@ impl McuConnection {
let mut buf = Vec::new();
decoder
.read_to_end(&mut buf)
- .map_err(|err| McuConnectionError::DictionaryFetch(Box::new(err)))?;
+ .map_err(|err| ConnectionError::DictionaryFetch(Box::new(err)))?;
let raw_dict: RawDictionary = serde_json::from_slice(&buf)
- .map_err(|err| McuConnectionError::DictionaryFetch(Box::new(err)))?;
- let dict = Dictionary::try_from(raw_dict).map_err(McuConnectionError::Dictionary)?;
+ .map_err(|err| ConnectionError::DictionaryFetch(Box::new(err)))?;
+ let dict = Dictionary::try_from(raw_dict).map_err(ConnectionError::Dictionary)?;
debug!(dictionary = ?dict, "MCU dictionary");
- conn.inner
- .dictionary
- .set(dict)
- .expect("Dictionary already set");
+ let Ok(()) = conn.inner.dictionary.set(dict) else {
+ unreachable!()
+ };
Ok(conn)
}
- fn verify_command_matches<C: Message>(&self) -> Result<(), McuConnectionError> {
+ fn verify_command_matches<C: Message>(&self) -> Result<(), ConnectionError> {
// Special handling for identify/identify_response
if C::get_id(None) == Some(0) || C::get_id(None) == Some(1) {
return Ok(());
@@ -327,7 +328,7 @@ impl McuConnection {
// tested before then.
let dictionary = self.inner.dictionary.get().unwrap();
let id = C::get_id(Some(dictionary))
- .ok_or_else(|| McuConnectionError::UnknownMessageId(C::get_name()))?;
+ .ok_or_else(|| ConnectionError::UnknownMessageId(C::get_name()))?;
// Must exist because we know the tag
let parser = dictionary.message_parser(id).unwrap();
@@ -335,7 +336,7 @@ impl McuConnection {
let local_fields = C::fields().into_iter();
if !remote_fields.eq(local_fields) {
- return Err(McuConnectionError::CommandMismatch(
+ return Err(ConnectionError::CommandMismatch(
C::get_name(),
format_command_args(parser.fields.iter().map(|(s, t)| (s.as_str(), *t))),
format_command_args(C::fields().into_iter()),
@@ -354,9 +355,9 @@ impl McuConnection {
fn encode_command<C: Message>(
&self,
command: EncodedMessage<C>,
- ) -> Result<FrontTrimmableBuffer, McuConnectionError> {
+ ) -> Result<FrontTrimmableBuffer, ConnectionError> {
let id = C::get_id(self.inner.dictionary.get())
- .ok_or_else(|| McuConnectionError::UnknownMessageId(C::get_name()))?;
+ .ok_or_else(|| ConnectionError::UnknownMessageId(C::get_name()))?;
let mut payload = command.payload;
if id >= 0x80 {
payload.content[0] = ((id >> 7) & 0x7F) as u8 | 0x80;
@@ -368,24 +369,20 @@ impl McuConnection {
}
/// Sends a command to the MCU
- pub async fn send<C: Message>(
- &self,
- command: EncodedMessage<C>,
- ) -> Result<(), McuConnectionError> {
+ pub fn send<C: Message>(&self, command: EncodedMessage<C>) -> Result<(), ConnectionError> {
let cmd = self.encode_command(command)?;
self.transport
.send(cmd.as_slice())
- .map_err(|e| McuConnectionError::Transport(TransportError::Transmitter(e)))
+ .map_err(|e| ConnectionError::Transport(Error::Transmitter(e)))
}
async fn send_receive_impl<C: Message, R: Message>(
&self,
command: EncodedMessage<C>,
- reply: R,
oid: Option<u8>,
) -> Result<R::PodOwned, SendReceiveError> {
struct RespHandler<R: Message>(
- Option<oneshot::Sender<Result<R::PodOwned, McuConnectionError>>>,
+ Option<oneshot::Sender<Result<R::PodOwned, ConnectionError>>>,
);
impl<R: Message> Handler for RespHandler<R> {
@@ -393,7 +390,7 @@ impl McuConnection {
if let Some(tx) = self.0.take() {
let _ = match R::decode(data) {
Ok(msg) => tx.send(Ok(msg.into())),
- Err(e) => tx.send(Err(McuConnectionError::DecodingError(e))),
+ Err(e) => tx.send(Err(ConnectionError::DecodingError(e))),
};
}
HandlerResult::Deregister
@@ -406,13 +403,13 @@ impl McuConnection {
self.verify_command_matches::<R>()?;
let (tx, mut rx) = tokio::sync::oneshot::channel::<Result<R::PodOwned, _>>();
- self.register_raw_response(reply, oid, Box::new(RespHandler::<R>(Some(tx))))?;
+ self.register_raw_response::<R>(oid, Box::new(RespHandler::<R>(Some(tx))))?;
let mut retry_delay = 0.01;
for _retry in 0..=5 {
self.transport
.send(cmd.as_slice())
- .map_err(|e| McuConnectionError::Transport(TransportError::Transmitter(e)))?;
+ .map_err(|e| ConnectionError::Transport(Error::Transmitter(e)))?;
let sleep = tokio::time::sleep(Duration::from_secs_f32(retry_delay));
tokio::pin!(sleep);
@@ -425,7 +422,7 @@ impl McuConnection {
Err(_) => Err(SendReceiveError::Timeout)
};
},
- _ = &mut sleep => {},
+ () = &mut sleep => {},
}
retry_delay *= 2.0;
@@ -441,10 +438,9 @@ impl McuConnection {
pub async fn send_receive_oid<C: Message, R: Message + WithOid>(
&self,
command: EncodedMessage<C>,
- reply: R,
oid: u8,
) -> Result<R::PodOwned, SendReceiveError> {
- self.send_receive_impl(command, reply, Some(oid)).await
+ self.send_receive_impl::<C, R>(command, Some(oid)).await
}
/// Sends a message to the MCU, and await a reply
@@ -454,27 +450,24 @@ impl McuConnection {
pub async fn send_receive<C: Message, R: Message + WithoutOid>(
&self,
command: EncodedMessage<C>,
- reply: R,
) -> Result<R::PodOwned, SendReceiveError> {
- self.send_receive_impl(command, reply, None).await
+ self.send_receive_impl::<C, R>(command, None).await
}
fn register_raw_response<R: Message>(
&self,
- _reply: R,
oid: Option<u8>,
handler: Box<dyn Handler>,
- ) -> Result<RegisteredResponseHandle, McuConnectionError> {
+ ) -> Result<RegisteredResponseHandle, ConnectionError> {
let id = R::get_id(self.inner.dictionary.get())
- .ok_or_else(|| McuConnectionError::UnknownMessageId(R::get_name()))?;
+ .ok_or_else(|| ConnectionError::UnknownMessageId(R::get_name()))?;
Ok(self.inner.handlers.register(id, oid, handler))
}
fn register_response_impl<R: Message>(
&self,
- reply: R,
oid: Option<u8>,
- ) -> Result<UnboundedReceiver<R::PodOwned>, McuConnectionError> {
+ ) -> Result<UnboundedReceiver<R::PodOwned>, ConnectionError> {
struct RespHandler<R: Message>(UnboundedSender<R::PodOwned>, Option<oneshot::Sender<()>>);
impl<R: Message> Drop for RespHandler<R> {
@@ -489,7 +482,7 @@ impl McuConnection {
.expect("Parser should already have assured this could parse")
.into();
match self.0.send(msg) {
- Ok(_) => HandlerResult::Continue,
+ Ok(()) => HandlerResult::Continue,
Err(_) => HandlerResult::Deregister,
}
}
@@ -500,11 +493,8 @@ impl McuConnection {
let (tx, rx) = unbounded_channel();
let tx_closed = tx.clone();
let (closer_tx, closer_rx) = oneshot::channel();
- let uniq = self.register_raw_response(
- reply,
- oid,
- Box::new(RespHandler::<R>(tx, Some(closer_tx))),
- )?;
+ let uniq =
+ self.register_raw_response::<R>(oid, Box::new(RespHandler::<R>(tx, Some(closer_tx))))?;
// Safe because register_raw_response already verified this
let id = R::get_id(self.inner.dictionary.get()).unwrap();
@@ -512,7 +502,7 @@ impl McuConnection {
let inner = self.inner.clone();
spawn(async move {
select! {
- _ = tx_closed.closed() => {},
+ () = tx_closed.closed() => {},
_ = closer_rx => {},
}
inner.handlers.remove_handler(id, oid, Some(uniq));
@@ -528,10 +518,9 @@ impl McuConnection {
/// This version works with replies that have an `oid` field.
pub fn register_response_oid<R: Message + WithOid>(
&self,
- reply: R,
oid: u8,
- ) -> Result<UnboundedReceiver<R::PodOwned>, McuConnectionError> {
- self.register_response_impl(reply, Some(oid))
+ ) -> Result<UnboundedReceiver<R::PodOwned>, ConnectionError> {
+ self.register_response_impl::<R>(Some(oid))
}
/// Registers a subscriber for a reply message
@@ -541,14 +530,16 @@ impl McuConnection {
/// This version works with replies that do not have an `oid` field.
pub fn register_response<R: Message + WithoutOid>(
&self,
- reply: R,
- ) -> Result<UnboundedReceiver<R::PodOwned>, McuConnectionError> {
- self.register_response_impl(reply, None)
+ ) -> Result<UnboundedReceiver<R::PodOwned>, ConnectionError> {
+ self.register_response_impl::<R>(None)
}
/// Returns a reference the dictionary the MCU returned during initial handshake
pub fn dictionary(&self) -> &Dictionary {
- self.inner.dictionary.get().unwrap()
+ self.inner
+ .dictionary
+ .get()
+ .unwrap_or_else(|| unreachable!())
}
/// Closes the transport and ends all subscriptions. Returns when the transport is closed.
@@ -557,16 +548,13 @@ impl McuConnection {
}
/// Waits for the connection to close, returning the error that closed it if any.
- pub async fn closed(&mut self) -> &Result<(), McuConnectionError> {
+ pub async fn closed(&mut self) -> &Result<(), ConnectionError> {
if let ExitCode::Waiting(chan) = &mut self.exit_code {
- self.exit_code = ExitCode::Exited(match chan.await {
- Ok(r) => r,
- Err(_) => Ok(()),
- });
+ self.exit_code = ExitCode::Exited(chan.await.unwrap_or_else(|_| Ok(())));
}
match self.exit_code {
ExitCode::Exited(ref val) => val,
- _ => unreachable!(),
+ ExitCode::Waiting(_) => unreachable!(),
}
}
}
diff --git a/crates/windlass/src/messages.rs b/crates/windlass/src/messages.rs
index f08a3ca..bf2ca67 100644
--- a/crates/windlass/src/messages.rs
+++ b/crates/windlass/src/messages.rs
@@ -20,7 +20,7 @@ impl MessageParser {
pub(crate) fn new<'a>(
name: &str,
parts: impl Iterator<Item = &'a str>,
- ) -> Result<MessageParser, MessageSkipperError> {
+ ) -> Result<Self, MessageSkipperError> {
let mut fields = vec![];
for part in parts {
let (arg, ty) = part
@@ -38,7 +38,7 @@ impl MessageParser {
}
/// Create a parser for a message type with the given printf-style specifier
- pub(crate) fn new_output(msg: &str) -> Result<MessageParser, MessageSkipperError> {
+ pub(crate) fn new_output(msg: &str) -> Result<Self, MessageSkipperError> {
let mut fields = vec![];
let mut parts = vec![];
diff --git a/crates/windlass/src/transport/frame.rs b/crates/windlass/src/transport/frame.rs
index d33a2d8..4b0c321 100644
--- a/crates/windlass/src/transport/frame.rs
+++ b/crates/windlass/src/transport/frame.rs
@@ -14,7 +14,8 @@ use crate::{
/// A link-level frame. See [klipper docs](https://www.klipper3d.org/Protocol.html#message-blocks)
#[derive(Debug)]
-pub(crate) struct ReceivedFrame {
+#[allow(clippy::module_name_repetitions)]
+pub struct ReceivedFrame {
pub receive_time: Instant,
pub sequence: u8,
pub payload: Vec<u8>,
@@ -22,12 +23,12 @@ pub(crate) struct ReceivedFrame {
/// Buffers and reads link-level frames. See [`ReceivedFrame`].
#[derive(Debug, Default)]
-pub struct FrameReader {
+pub struct Reader {
buf: VecDeque<ReceivedFrame>,
partial: PartialFrameState,
}
-impl FrameReader {
+impl Reader {
/// Process new data from `b`
pub fn receive_data(&mut self, mut b: &[u8]) {
while !b.is_empty() {
@@ -78,7 +79,7 @@ impl PartialFrameState {
b = &b[idx + 1..];
}
}
- PartialFrameState::Synced => {
+ Self::Synced => {
// Attempt to start a new frame
let len = b[0] as usize;
if !(MESSAGE_LENGTH_MIN..=MESSAGE_LENGTH_MAX).contains(&len) {
@@ -97,7 +98,7 @@ impl PartialFrameState {
b = &b[1..];
}
- PartialFrameState::Receiving { len, so_far, .. } => {
+ Self::Receiving { len, so_far, .. } => {
// Continue to receive data for frame
let len = *len;
let take = len - so_far.len();
@@ -118,8 +119,8 @@ impl PartialFrameState {
}
let actual_crc = crc16(so_far);
- let frame_crc = (so_far[len - MESSAGE_TRAILER_CRC] as u16) << 8
- | (so_far[len - MESSAGE_TRAILER_CRC + 1] as u16);
+ let frame_crc = (u16::from(so_far[len - MESSAGE_TRAILER_CRC])) << 8
+ | (u16::from(so_far[len - MESSAGE_TRAILER_CRC + 1]));
if frame_crc != actual_crc {
*self = Self::Unsynced;
continue;
@@ -153,6 +154,7 @@ impl PartialFrameState {
/// A frame to be sent to the MCU
#[derive(Debug, Clone)]
+#[allow(clippy::module_name_repetitions)]
pub struct SentFrame {
/// When the frame was first sent
pub sent_at: Instant,
@@ -172,10 +174,16 @@ impl SentFrame {
}
let mut payload = Vec::with_capacity(len);
- payload.push(len as u8);
- payload.push(MESSAGE_DEST | ((sequence as u8) & MESSAGE_SEQ_MASK));
+ let Ok(len) = u8::try_from(len) else {
+ unreachable!()
+ };
+ payload.push(len);
+ payload.push(
+ MESSAGE_DEST
+ | ((u8::try_from(sequence).expect("sequence number overflow")) & MESSAGE_SEQ_MASK),
+ );
payload.extend_from_slice(data);
- let crc = crc16(&payload[0..len - MESSAGE_TRAILER_SIZE]);
+ let crc = crc16(&payload[0..len as usize - MESSAGE_TRAILER_SIZE]);
payload.push(((crc >> 8) & 0xFF) as u8);
payload.push((crc & 0xFF) as u8);
payload.push(MESSAGE_VALUE_SYNC);
diff --git a/crates/windlass/src/transport/mod.rs b/crates/windlass/src/transport/mod.rs
index eecb98d..8a24b8a 100644
--- a/crates/windlass/src/transport/mod.rs
+++ b/crates/windlass/src/transport/mod.rs
@@ -1,4 +1,4 @@
-use frame::{FrameReader, MessageEncodeError, ReceivedFrame, SentFrame};
+use frame::{MessageEncodeError, Reader, ReceivedFrame, SentFrame};
use rtt::RttState;
use std::collections::VecDeque;
use tokio::io::AsyncReadExt;
@@ -14,16 +14,16 @@ use tokio_util::{bytes::BytesMut, sync::CancellationToken};
mod frame;
mod rtt;
-pub(crate) const MESSAGE_HEADER_SIZE: usize = 2;
-pub(crate) const MESSAGE_TRAILER_SIZE: usize = 3;
-pub(crate) const MESSAGE_LENGTH_MIN: usize = MESSAGE_HEADER_SIZE + MESSAGE_TRAILER_SIZE;
-pub(crate) const MESSAGE_LENGTH_MAX: usize = 64;
-pub(crate) const MESSAGE_LENGTH_PAYLOAD_MAX: usize = MESSAGE_LENGTH_MAX - MESSAGE_LENGTH_MIN;
-pub(crate) const MESSAGE_POSITION_SEQ: usize = 1;
-pub(crate) const MESSAGE_TRAILER_CRC: usize = 3;
-pub(crate) const MESSAGE_VALUE_SYNC: u8 = 0x7E;
-pub(crate) const MESSAGE_DEST: u8 = 0x10;
-pub(crate) const MESSAGE_SEQ_MASK: u8 = 0x0F;
+pub const MESSAGE_HEADER_SIZE: usize = 2;
+pub const MESSAGE_TRAILER_SIZE: usize = 3;
+pub const MESSAGE_LENGTH_MIN: usize = MESSAGE_HEADER_SIZE + MESSAGE_TRAILER_SIZE;
+pub const MESSAGE_LENGTH_MAX: usize = 64;
+pub const MESSAGE_LENGTH_PAYLOAD_MAX: usize = MESSAGE_LENGTH_MAX - MESSAGE_LENGTH_MIN;
+pub const MESSAGE_POSITION_SEQ: usize = 1;
+pub const MESSAGE_TRAILER_CRC: usize = 3;
+pub const MESSAGE_VALUE_SYNC: u8 = 0x7E;
+pub const MESSAGE_DEST: u8 = 0x10;
+pub const MESSAGE_SEQ_MASK: u8 = 0x0F;
/// Wrapper around a connection to a klipper firmware MCU, which deals with
/// retransmission, flow control, etc.
@@ -46,13 +46,14 @@ enum TransportCommand {
Exit,
}
-pub(crate) type TransportReceiver = UnboundedReceiver<Result<Vec<u8>, TransportError>>;
+#[allow(clippy::module_name_repetitions)]
+pub type TransportReceiver = UnboundedReceiver<Result<Vec<u8>, Error>>;
impl Transport {
- pub(crate) async fn connect(
+ pub(crate) fn connect(
rdr: impl AsyncBufRead + Unpin + Send + 'static,
wr: impl AsyncWrite + Unpin + Send + 'static,
- ) -> (Transport, TransportReceiver) {
+ ) -> (Self, TransportReceiver) {
let (data_send, data_recv) = unbounded_channel();
let (cmd_send, cmd_recv) = unbounded_channel();
@@ -65,7 +66,7 @@ impl Transport {
});
(
- Transport {
+ Self {
task_inner,
cmd_send,
},
@@ -86,7 +87,7 @@ impl Transport {
}
#[derive(thiserror::Error, Debug)]
-pub enum TransportError {
+pub enum Error {
#[error("message encoding failed: {0}")]
MessageEncode(#[from] MessageEncodeError),
@@ -94,17 +95,17 @@ pub enum TransportError {
Transmitter(#[from] TransmitterError),
#[error("io error: {0}")]
- IOError(#[from] std::io::Error),
+ IO(#[from] std::io::Error),
}
/// State for the task which deals with transport state
#[derive(Debug)]
struct TransportState<R, W> {
- frdr: FrameReader,
+ frdr: Reader,
rdr: R,
wr: W,
- data_send: UnboundedSender<Result<Vec<u8>, TransportError>>,
+ data_send: UnboundedSender<Result<Vec<u8>, Error>>,
cmd_recv: UnboundedReceiver<TransportCommand>,
cancel: CancellationToken,
@@ -128,12 +129,12 @@ impl<R: AsyncBufRead + Unpin, W: AsyncWrite + Unpin> TransportState<R, W> {
fn new(
rdr: R,
wr: W,
- data_send: UnboundedSender<Result<Vec<u8>, TransportError>>,
+ data_send: UnboundedSender<Result<Vec<u8>, Error>>,
cmd_recv: UnboundedReceiver<TransportCommand>,
cancel: CancellationToken,
) -> Self {
Self {
- frdr: FrameReader::default(),
+ frdr: Reader::default(),
rdr,
wr,
data_send,
@@ -156,7 +157,7 @@ impl<R: AsyncBufRead + Unpin, W: AsyncWrite + Unpin> TransportState<R, W> {
}
}
- async fn run(&mut self) -> Result<(), TransportError> {
+ async fn run(&mut self) -> Result<(), Error> {
let mut buf = BytesMut::with_capacity(MESSAGE_LENGTH_MAX);
loop {
if self.retransmit_now {
@@ -210,7 +211,7 @@ impl<R: AsyncBufRead + Unpin, W: AsyncWrite + Unpin> TransportState<R, W> {
// Timeout for when we are able to send again
}
- _ = self.cancel.cancelled() => {
+ () = self.cancel.cancelled() => {
break;
},
}
@@ -223,9 +224,9 @@ impl<R: AsyncBufRead + Unpin, W: AsyncWrite + Unpin> TransportState<R, W> {
let rseq = self.receive_sequence;
// wrap-around logic(?)
- let mut sequence = (rseq & !(MESSAGE_SEQ_MASK as u64)) | (frame.sequence as u64);
+ let mut sequence = (rseq & !u64::from(MESSAGE_SEQ_MASK)) | u64::from(frame.sequence);
if sequence < rseq {
- sequence += (MESSAGE_SEQ_MASK as u64) + 1;
+ sequence += u64::from(MESSAGE_SEQ_MASK) + 1;
}
// Frame acknowledges some messages
@@ -284,7 +285,7 @@ impl<R: AsyncBufRead + Unpin, W: AsyncWrite + Unpin> TransportState<R, W> {
}
/// Send as many more frames as possible from [`self.pending_messages`]
- async fn send_more_frames(&mut self) -> Result<(), TransportError> {
+ async fn send_more_frames(&mut self) -> Result<(), Error> {
while self.can_send() && !self.pending_messages.is_empty() {
self.send_new_frame().await?;
}
@@ -293,7 +294,7 @@ impl<R: AsyncBufRead + Unpin, W: AsyncWrite + Unpin> TransportState<R, W> {
}
/// Send a single new frame from [`self.pending_messages`]
- async fn send_new_frame(&mut self) -> Result<(), TransportError> {
+ async fn send_new_frame(&mut self) -> Result<(), Error> {
let mut buf = Vec::new();
while let Some(next) = self.pending_messages.front() {
if !buf.is_empty() && buf.len() + next.len() <= MESSAGE_LENGTH_PAYLOAD_MAX {
@@ -316,7 +317,7 @@ impl<R: AsyncBufRead + Unpin, W: AsyncWrite + Unpin> TransportState<R, W> {
}
/// Retransmit all inflight messages
- async fn retransmit_pending(&mut self) -> Result<(), TransportError> {
+ async fn retransmit_pending(&mut self) -> Result<(), Error> {
let len: usize = self
.inflight_messages
.iter()
@@ -325,7 +326,7 @@ impl<R: AsyncBufRead + Unpin, W: AsyncWrite + Unpin> TransportState<R, W> {
let mut buf = Vec::with_capacity(1 + len);
buf.push(MESSAGE_VALUE_SYNC);
let now = Instant::now();
- for msg in self.inflight_messages.iter_mut() {
+ for msg in &mut self.inflight_messages {
buf.extend_from_slice(&msg.payload);
msg.is_retransmit = true;
msg.sent_at = now;
diff --git a/crates/windlass/src/transport/rtt.rs b/crates/windlass/src/transport/rtt.rs
index 69841f6..bb45b9e 100644
--- a/crates/windlass/src/transport/rtt.rs
+++ b/crates/windlass/src/transport/rtt.rs
@@ -5,6 +5,7 @@ const MAX_RTO: f32 = 5.000;
/// State for estimating the round trip time of the connection
#[derive(Debug)]
+#[allow(clippy::module_name_repetitions)]
pub struct RttState {
srtt: f32,
rttvar: f32,
@@ -34,8 +35,8 @@ impl RttState {
self.rttvar = r / 2.0;
self.srtt = r * 10.0; // Klipper uses this, we'll copy it
} else {
- self.rttvar = (3.0 * self.rttvar + (self.srtt - r).abs()) / 4.0;
- self.srtt = (7.0 * self.srtt + r) / 8.0;
+ self.rttvar = 3.0f32.mul_add(self.rttvar, (self.srtt - r).abs());
+ self.srtt = 7.0f32.mul_add(self.srtt, r);
}
let rttvar4 = (self.rttvar * 4.0).max(0.001);
self.rto = (self.srtt + rttvar4).clamp(MIN_RTO, MAX_RTO);