diff --git a/examples/get_channel_info.rs b/examples/get_channel_info.rs index db3668b..b42335b 100644 --- a/examples/get_channel_info.rs +++ b/examples/get_channel_info.rs @@ -1,5 +1,7 @@ #![allow(clippy::unwrap_used)] +use std::fmt::Debug; + use arctictis::{ Command, Scanner, bc125at::{ @@ -9,29 +11,23 @@ use arctictis::{ }; #[tokio::main] -async fn main() -> Result<(), Box> { +async fn main() { let idx = std::env::args().nth(1).unwrap().parse().unwrap(); let idx = ChannelIndex::new(idx).unwrap(); - let mut scanner = Scanner::open()?; + let mut scanner = Scanner::open().unwrap(); println!("{scanner:#?}"); - scanner.command(EnterProgramMode).await?; - print_response(&mut scanner, GetChannelInfo(idx)).await?; - scanner.command(ExitProgramMode).await?; - - Ok(()) + print_response(&mut scanner, EnterProgramMode).await; + print_response(&mut scanner, GetChannelInfo(idx)).await; + print_response(&mut scanner, ExitProgramMode).await; } -async fn print_response( - scanner: &mut Scanner, - cmd: Cmd, -) -> Result<(), Box> +async fn print_response(scanner: &mut Scanner, cmd: Cmd) where - Cmd: Command + 'static, + Cmd: Command + Debug + 'static, Cmd::Response: std::fmt::Debug, { let name = String::from_utf8_lossy(Cmd::TEXT); - let r = scanner.command(cmd).await?; + let r = scanner.command(cmd).await.unwrap(); println!("{name} => {r:?}"); - Ok(()) } diff --git a/examples/set_channel_info.rs b/examples/set_channel_info.rs index 5fa2032..07e44aa 100644 --- a/examples/set_channel_info.rs +++ b/examples/set_channel_info.rs @@ -1,5 +1,7 @@ #![allow(clippy::unwrap_used)] +use std::fmt::Debug; + use arctictis::{ Command, Scanner, bc125at::{ @@ -9,37 +11,32 @@ use arctictis::{ }; #[tokio::main] -async fn main() -> Result<(), Box> { +async fn main() { let idx = std::env::args().nth(1).unwrap().parse().unwrap(); let idx = ChannelIndex::new(idx).unwrap(); let freq = std::env::args().nth(2).unwrap(); let freq = Frequency::new(freq.as_bytes()).unwrap(); - let mut scanner = Scanner::open()?; + let mut scanner = Scanner::open().unwrap(); println!("{scanner:#?}"); - scanner.command(EnterProgramMode).await?; - let current_info = scanner.command(GetChannelInfo(idx)).await?; + scanner.command(EnterProgramMode).await.unwrap(); + print_response(&mut scanner, EnterProgramMode).await; + let current_info = scanner.command(GetChannelInfo(idx)).await.unwrap(); let new_info = ChannelInfo { frequency: freq, ..current_info }; - print_response(&mut scanner, SetChannelInfo(new_info)).await?; - scanner.command(ExitProgramMode).await?; - - Ok(()) + print_response(&mut scanner, SetChannelInfo(new_info)).await; + print_response(&mut scanner, ExitProgramMode).await; } -async fn print_response( - scanner: &mut Scanner, - cmd: Cmd, -) -> Result<(), Box> +async fn print_response(scanner: &mut Scanner, cmd: Cmd) where - Cmd: Command + 'static, + Cmd: Command + Debug + 'static, Cmd::Response: std::fmt::Debug, { let name = String::from_utf8_lossy(Cmd::TEXT); - let r = scanner.command(cmd).await?; + let r = scanner.command(cmd).await.unwrap(); println!("{name} => {r:?}"); - Ok(()) } diff --git a/examples/version.rs b/examples/version.rs index 38f19f5..8a96c75 100644 --- a/examples/version.rs +++ b/examples/version.rs @@ -1,24 +1,22 @@ +#![allow(clippy::unwrap_used)] + +use std::fmt::Debug; + use arctictis::{Command, Scanner, bc125at::firmware_version::GetFirmwareVersion}; #[tokio::main] -async fn main() -> Result<(), Box> { - let mut scanner = Scanner::open()?; +async fn main() { + let mut scanner = Scanner::open().unwrap(); println!("{scanner:#?}"); - print_response(&mut scanner, GetFirmwareVersion).await?; - - Ok(()) + print_response(&mut scanner, GetFirmwareVersion).await; } -async fn print_response( - scanner: &mut Scanner, - cmd: Cmd, -) -> Result<(), Box> +async fn print_response(scanner: &mut Scanner, cmd: Cmd) where - Cmd: Command + 'static, + Cmd: Command + Debug + 'static, Cmd::Response: std::fmt::Debug, { let name = String::from_utf8_lossy(Cmd::TEXT); - let r = scanner.command(cmd).await?; + let r = scanner.command(cmd).await.unwrap(); println!("{name} => {r:?}"); - Ok(()) } diff --git a/examples/volume.rs b/examples/volume.rs index 0f9c11f..33809fc 100644 --- a/examples/volume.rs +++ b/examples/volume.rs @@ -1,5 +1,7 @@ #![allow(clippy::unwrap_used)] +use std::fmt::Debug; + use arctictis::{ Command, Scanner, bc125at::volume::{GetVolume, SetVolume, Volume}, @@ -7,25 +9,21 @@ use arctictis::{ #[tokio::main] async fn main() -> Result<(), Box> { - let mut scanner = Scanner::open()?; + let mut scanner = Scanner::open().unwrap(); println!("{scanner:#?}"); - print_response(&mut scanner, GetVolume).await?; - print_response(&mut scanner, SetVolume(Volume::new(5).unwrap())).await?; - print_response(&mut scanner, GetVolume).await?; + print_response(&mut scanner, GetVolume).await; + print_response(&mut scanner, SetVolume(Volume::new(5).unwrap())).await; + print_response(&mut scanner, GetVolume).await; Ok(()) } -async fn print_response( - scanner: &mut Scanner, - cmd: Cmd, -) -> Result<(), Box> +async fn print_response(scanner: &mut Scanner, cmd: Cmd) where - Cmd: Command + 'static, + Cmd: Command + Debug + 'static, Cmd::Response: std::fmt::Debug, { let name = String::from_utf8_lossy(Cmd::TEXT); - let r = scanner.command(cmd).await?; + let r = scanner.command(cmd).await.unwrap(); println!("{name} => {r:?}"); - Ok(()) } diff --git a/src/codec.rs b/src/codec.rs index 91e6103..5d5738d 100644 --- a/src/codec.rs +++ b/src/codec.rs @@ -84,13 +84,11 @@ impl RawResponse { #[derive(Debug, thiserror::Error)] pub enum DecoderError { - #[error("malformed response")] - Malformed, - - #[error("command must be executed in program mode")] - NotAcceptable, - - #[error("command format error or invalid value")] + #[error("response is empty")] + ResponseEmpty, + #[error("command not acceptable at this time")] + CommandNotAcceptable, + #[error("scanner returned error")] ErrorResponse, #[error(transparent)] @@ -114,14 +112,14 @@ impl Decoder for Codec { let mut all_fields = BytesSplit::new(output, PARAM_DELIMITER); let Some(cmd) = all_fields.next() else { - return Err(DecoderError::Malformed); + return Err(DecoderError::ResponseEmpty); }; let raw_values = all_fields.collect::>(); if raw_values.len() == 1 { match raw_values[0].as_ref() { - b"NG" => return Err(DecoderError::NotAcceptable), + b"NG" => return Err(DecoderError::CommandNotAcceptable), b"ERR" => return Err(DecoderError::ErrorResponse), _ => {} } diff --git a/src/command/bc125at/firmware_version.rs b/src/command/bc125at/firmware_version.rs index 408565c..be4bf8c 100644 --- a/src/command/bc125at/firmware_version.rs +++ b/src/command/bc125at/firmware_version.rs @@ -37,6 +37,7 @@ impl Response for FirmwareVersion { } } +#[derive(Debug, Clone, Copy)] pub struct GetFirmwareVersion; impl Command for GetFirmwareVersion { diff --git a/src/command/bc125at/program_mode.rs b/src/command/bc125at/program_mode.rs index e54a718..0909971 100644 --- a/src/command/bc125at/program_mode.rs +++ b/src/command/bc125at/program_mode.rs @@ -1,5 +1,6 @@ use crate::{Command, OkResponse, command::NoParams}; +#[derive(Clone, Copy, Debug)] pub struct EnterProgramMode; impl Command for EnterProgramMode { @@ -14,6 +15,7 @@ impl Command for EnterProgramMode { } } +#[derive(Clone, Copy, Debug)] pub struct ExitProgramMode; impl Command for ExitProgramMode { diff --git a/src/lib.rs b/src/lib.rs index 14abb4d..8fb501d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,6 @@ mod command; mod scanner; pub use crate::{ - codec::{DecoderError, ResponseError}, command::{Command, OkResponse, OkResponseError, bc125at}, - scanner::{EncodingError, Scanner, ScannerError}, + scanner::{CommandError, Scanner, ScannerError}, }; diff --git a/src/scanner.rs b/src/scanner.rs index 1382298..c6909be 100644 --- a/src/scanner.rs +++ b/src/scanner.rs @@ -16,9 +16,6 @@ const BAUD_RATE: u32 = 115_200; #[derive(Debug, thiserror::Error)] pub enum ScannerError { - #[error("port closed")] - PortClosed, - #[error("scanner not found")] ScannerNotFound, @@ -30,15 +27,55 @@ pub enum ScannerError { } #[derive(Debug, thiserror::Error)] -pub enum EncodingError { - #[error(transparent)] - Scanner(#[from] ScannerError), +pub enum CommandError { + #[error("port closed")] + PortClosed, + #[error("response is empty")] + ResponseEmpty, + #[error("command not acceptable at this time")] + CommandNotAcceptable, + #[error("scanner returned error")] + ErrorResponse, + // TODO: add expected/received fields + #[error("response is for wrong command")] + WrongCommand, + // TODO: add expected/received fields + #[error("incorrect number of fields in response")] + WrongNumberOfFields, #[error(transparent)] - Decoder(#[from] DecoderError), + FieldDecodeError(::Error), #[error(transparent)] - ResponseParserError(#[from] ResponseError), + Io(#[from] std::io::Error), +} + +impl From for CommandError { + fn from(error: DecoderError) -> Self { + use tokio_util::codec::AnyDelimiterCodecError; + match error { + DecoderError::ResponseEmpty => Self::ResponseEmpty, + DecoderError::CommandNotAcceptable => Self::CommandNotAcceptable, + DecoderError::ErrorResponse => Self::ErrorResponse, + DecoderError::DelimiterError(e) => match e { + AnyDelimiterCodecError::MaxChunkLengthExceeded => { + unreachable!("we do not limit the chunk length") + } + AnyDelimiterCodecError::Io(io_error) => Self::Io(io_error), + }, + DecoderError::Io(io_error) => Self::Io(io_error), + } + } +} + +impl From::Error>> for CommandError { + fn from(error: ResponseError<::Error>) -> Self { + match error { + ResponseError::WrongCommand => Self::WrongCommand, + ResponseError::WrongNumberOfFields => Self::WrongNumberOfFields, + ResponseError::InvalidFields(e) => Self::FieldDecodeError(e), + } + } } #[derive(Debug)] @@ -69,10 +106,12 @@ impl Scanner { pub async fn command( &mut self, cmd: Cmd, - ) -> Result::Error>> { - self.0.send(cmd).await.map_err(ScannerError::from)?; - let raw_response = self.0.next().await.ok_or(ScannerError::PortClosed)??; + ) -> Result> { + self.0.send(cmd).await?; + + let raw_response = self.0.next().await.ok_or(CommandError::PortClosed)??; let response = raw_response.deserialize::()?; + Ok(response) } }