From 38599e6125bd1007f1a8467d7062e4e8bfb882ec Mon Sep 17 00:00:00 2001 From: metasophiea Date: Wed, 9 Oct 2024 16:29:27 +0100 Subject: [PATCH] added way to disconnect the board --- Cargo.toml | 2 +- examples/blink.rs | 4 ++-- examples/button.rs | 2 +- src/board/mod.rs | 7 +++++++ src/connection_wrapper/engine.rs | 14 ++++++++++++++ src/connection_wrapper/mod.rs | 16 ++++++++++++++++ src/connection_wrapper/to_engine_command.rs | 3 +++ src/types/error.rs | 21 ++++++++++++++++----- 8 files changed, 60 insertions(+), 9 deletions(-) create mode 100644 src/connection_wrapper/to_engine_command.rs diff --git a/Cargo.toml b/Cargo.toml index 9103442..a560029 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "firmata-client" -version = "0.5.3" +version = "0.6.0" license = "MIT OR Apache-2.0" authors = ["Brandon Walsh "] readme = "README.md" diff --git a/examples/blink.rs b/examples/blink.rs index adbfd86..66a320c 100644 --- a/examples/blink.rs +++ b/examples/blink.rs @@ -5,7 +5,7 @@ use serialport::*; fn main() { tracing_subscriber::fmt::init(); - let serial_port_builder = serialport::new("/dev/tty.usbmodem14301", 57_600) + let serial_port_builder = serialport::new("/dev/tty.usbmodem14201", 57_600) .data_bits(DataBits::Eight) .parity(Parity::None) .stop_bits(StopBits::One) @@ -19,7 +19,7 @@ fn main() { } println!("setup complete"); - let pin = 15; + let pin = 13; board.set_pin_mode(pin, firmata_client::PIN_MODE_OUTPUT).expect("pin mode set"); let mut state = false; diff --git a/examples/button.rs b/examples/button.rs index 365a09c..5b0106f 100644 --- a/examples/button.rs +++ b/examples/button.rs @@ -20,7 +20,7 @@ fn main() { } println!("setup complete"); - let led = 5; + let led = 13; let button = 2; board.report_digital(button, true).expect("digital reporting mode"); diff --git a/src/board/mod.rs b/src/board/mod.rs index 26d6ae2..5c52319 100644 --- a/src/board/mod.rs +++ b/src/board/mod.rs @@ -60,6 +60,13 @@ use crate::types::{ } } +// disconnect + impl Board { + pub fn disconnect(&mut self) -> Result<()> { + self.connection_wrapper.disconnect() + } + } + // tools impl Board { /// Write on the internal connection. diff --git a/src/connection_wrapper/engine.rs b/src/connection_wrapper/engine.rs index 8aaa8af..db9e2c8 100644 --- a/src/connection_wrapper/engine.rs +++ b/src/connection_wrapper/engine.rs @@ -7,12 +7,15 @@ use serialport::{ use crate::types::{Error, Result}; +use super::Command; + pub struct Engine { //loop control halt: bool, //communication receiver: std::sync::mpsc::Receiver>, + command_receiver: std::sync::mpsc::Receiver, sender: std::sync::mpsc::Sender>, error_sender: std::sync::mpsc::Sender, @@ -23,6 +26,7 @@ pub struct Engine { impl Engine { pub fn new( receiver: std::sync::mpsc::Receiver>, + command_receiver: std::sync::mpsc::Receiver, sender: std::sync::mpsc::Sender>, error_sender: std::sync::mpsc::Sender, serial_port_builder: SerialPortBuilder, @@ -36,6 +40,7 @@ impl Engine { halt: false, receiver, + command_receiver, sender, error_sender, @@ -53,6 +58,15 @@ impl Engine { impl Engine { #[tracing::instrument(skip(self), level = "DEBUG")] fn revolution(&mut self) { + for command in self.command_receiver.try_iter() { + match command { + Command::Halt => { + self.halt = true; + return; + } + } + } + let buf = self.receiver.try_iter().flatten().collect::>(); if let Err(write_all_error) = self.connection.write_all(&buf) { tracing::warn!("write_all error: {write_all_error}"); diff --git a/src/connection_wrapper/mod.rs b/src/connection_wrapper/mod.rs index e73fc03..6b70f4c 100644 --- a/src/connection_wrapper/mod.rs +++ b/src/connection_wrapper/mod.rs @@ -4,26 +4,33 @@ use serialport::SerialPortBuilder; use crate::types::{Error, Result}; +mod to_engine_command; +pub use to_engine_command::Command; + mod engine; use engine::Engine; + #[derive(Debug)] pub struct ConnectionWrapper { thread_handle: std::thread::JoinHandle<()>, receiver: std::sync::mpsc::Receiver>, sender: std::sync::mpsc::Sender>, + command_sender: std::sync::mpsc::Sender, error_receiver: std::sync::mpsc::Receiver, } impl ConnectionWrapper { pub fn new(serial_port_builder: SerialPortBuilder) -> ConnectionWrapper { let (to_engine_sender, to_engine_receiver) = std::sync::mpsc::channel::>(); + let (to_engine_command_sender, to_engine_command_receiver) = std::sync::mpsc::channel::(); let (from_engine_sender, from_engine_receiver) = std::sync::mpsc::channel::>(); let (from_engine_error_sender, from_engine_error_receiver) = std::sync::mpsc::channel::(); let thread_handle = std::thread::spawn(move || { match Engine::new( to_engine_receiver, + to_engine_command_receiver, from_engine_sender, from_engine_error_sender.clone(), serial_port_builder, @@ -42,6 +49,7 @@ impl ConnectionWrapper { thread_handle, receiver: from_engine_receiver, sender: to_engine_sender, + command_sender: to_engine_command_sender, error_receiver: from_engine_error_receiver } } @@ -51,6 +59,14 @@ impl ConnectionWrapper { pub fn is_active(&self) -> bool { !self.thread_handle.is_finished() } + pub fn disconnect(&mut self) -> Result<()> { + if self.thread_handle.is_finished() { + return Err(Error::Disconnected); + } + + self.command_sender.send(Command::Halt)?; + return Ok(()); + } } impl ConnectionWrapper { diff --git a/src/connection_wrapper/to_engine_command.rs b/src/connection_wrapper/to_engine_command.rs new file mode 100644 index 0000000..0d54174 --- /dev/null +++ b/src/connection_wrapper/to_engine_command.rs @@ -0,0 +1,3 @@ +pub enum Command { + Halt +} \ No newline at end of file diff --git a/src/types/error.rs b/src/types/error.rs index 9120538..95bf4f6 100644 --- a/src/types/error.rs +++ b/src/types/error.rs @@ -2,6 +2,8 @@ use std::sync::mpsc::SendError; use serialport::Error as SerialPortError; +use super::super::connection_wrapper::Command; + /// Firmata error type. #[derive(Debug)] pub enum Error { @@ -15,8 +17,10 @@ pub enum Error { StdIo(std::io::Error), /// UTF8 error Utf8(std::str::Utf8Error), - /// Mpsc `SendError` - MpscSend(SendError>), + /// Mpsc Buf `SendError` + MpscBufSend(SendError>), + /// Mpsc Command `SendError` + MpscCommandSend(SendError), /// Invalid Pin Mode InvalidPinMode { pin: u8, modes: Vec }, /// Pin out of bounds @@ -35,7 +39,7 @@ impl Error { } } -impl std::fmt::Display for Error { +impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Error::Disconnected => write!(f, "Disconnected"), @@ -43,7 +47,8 @@ impl std::fmt::Display for Error { Error::BadByte(byte) => write!(f, "Received a bad byte: {byte}"), Error::StdIo(error) => write!(f, "I/O error: {error}"), Error::Utf8(error) => write!(f, "UTF8 error: {error}"), - Error::MpscSend(error) => write!(f, "Mpsc SendError error: {error}"), + Error::MpscBufSend(error) => write!(f, "Mpsc Buf SendError error: {error}"), + Error::MpscCommandSend(error) => write!(f, "Mpsc Command SendError error: {error}"), Error::InvalidPinMode { pin, modes } => write!(f, "Invalid Pin Mode: {pin} modes: {modes:?}"), Error::PinOutOfBounds { pin, len, source } => write!(f, "Pin out of bounds: {pin} ({len}) source: {source}"), Error::Serialport(error) => write!(f, "Serialport Error: {error}"), @@ -65,7 +70,13 @@ impl From for Error { impl From>> for Error { fn from(error: SendError>) -> Self { - Error::MpscSend(error) + Error::MpscBufSend(error) + } +} + +impl From> for Error { + fn from(error: SendError) -> Self { + Error::MpscCommandSend(error) } }