diff --git a/Cargo.toml b/Cargo.toml index 9df412b..d6c066e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,12 +9,12 @@ license = "MPL-2.0" edition = "2018" [features] -util = [ "structopt", "simplelog", "rand", "hex" ] +util = [ "clap", "simplelog", "rand", "hex" ] examples = [] default = [ "util" ] [dependencies] -embedded-hal = { version = "1.0.0-alpha.7" } +embedded-hal = { version = "1.0.0-rc.1" } libc = "0.2.66" log = "0.4.8" @@ -24,22 +24,10 @@ lazy_static = "1.4.0" failure = "0.1.7" rusb = "0.9.0" - -[dependencies.structopt] -version = "0.3.5" -optional = true - -[dependencies.simplelog] -version = "0.9.0" -optional = true - -[dependencies.hex] -version = "0.4.2" -optional = true - -[dependencies.rand] -version = "0.8.0" -optional = true +clap = { version = "4.4.7", optional = true, features = [ "derive", "env" ] } +simplelog = { version = "0.9.0", optional = true } +hex = { version = "0.4.2", optional = true } +rand = { version = "0.8.0", optional = true } [dev-dependencies] ssd1306 = "0.7.0" diff --git a/src/cli.rs b/src/cli.rs index 2d19402..7b93b10 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -3,8 +3,8 @@ //! //! Copyright 2019 Ryan Kurte -extern crate structopt; -use structopt::StructOpt; +extern crate clap; +use clap::Parser; #[macro_use] extern crate log; extern crate simplelog; @@ -13,37 +13,37 @@ use simplelog::{TermLogger, LevelFilter, TerminalMode}; use driver_cp2130::prelude::*; extern crate embedded_hal; -use embedded_hal::spi::blocking::*; +use embedded_hal::spi::*; extern crate hex; extern crate rand; use crate::rand::Rng; -#[derive(Debug, StructOpt)] -#[structopt(name = "cp2130-util")] +#[derive(Debug, Parser)] +#[clap(name = "cp2130-util")] /// CP2130 Utility pub struct Options { - #[structopt(subcommand)] + #[clap(subcommand)] pub command: Command, - #[structopt(flatten)] + #[clap(flatten)] pub filter: Filter, - #[structopt(flatten)] + #[clap(flatten)] pub options: UsbOptions, - #[structopt(long, default_value="0")] + #[clap(long, default_value="0")] /// Device index (to select from multiple devices) pub index: usize, - #[structopt(long = "log-level", default_value="info")] + #[clap(long = "log-level", default_value="info")] /// Enable verbose logging pub level: LevelFilter, } -#[derive(Debug, StructOpt)] +#[derive(Debug, Parser)] pub enum Command { /// Fetch the chip version Version, @@ -51,68 +51,68 @@ pub enum Command { Info, /// Set a GPIO output SetOutput { - #[structopt(long, default_value="6")] + #[clap(long, default_value="6")] /// GPIO pin index pin: u8, - #[structopt(long, default_value="push-pull")] + #[clap(long, default_value="push-pull")] /// GPIO pin mode to set (input, open drain, push-pull) mode: GpioMode, - #[structopt(default_value="high")] + #[clap(default_value="high")] /// GPIO pin state (high, low) state: GpioLevel, }, /// Read a GPIO input ReadInput { - #[structopt(long, default_value="6")] + #[clap(long, default_value="6")] /// GPIO pin index pin: u8, - #[structopt(long)] + #[clap(long)] /// GPIO pin mode to set mode: Option, }, /// Transfer (write-read) to an attached SPI device SpiTransfer { - #[structopt(parse(try_from_str=parse_hex_str))] + #[clap(value_parser=parse_hex_str)] /// Data to write (in hex) data: Data, - #[structopt(flatten)] + #[clap(flatten)] spi_opts: SpiOpts, }, /// Write to an attached SPI device SpiWrite { - #[structopt(parse(try_from_str=parse_hex_str))] + #[clap(value_parser=parse_hex_str)] /// Data to write (in hex) data: Data, - #[structopt(flatten)] + #[clap(flatten)] spi_opts: SpiOpts, }, /// Test interaction with the CP2130 device Test(TestOpts) } -#[derive(Clone, Debug, PartialEq, StructOpt)] +#[derive(Clone, Debug, PartialEq, Parser)] pub struct SpiOpts { - #[structopt(long, default_value="0")] + #[clap(long, default_value="0")] /// SPI Channel channel: u8, - #[structopt(long, default_value="0")] + #[clap(long, default_value="0")] /// SPI CS gpio index cs_pin: u8, } -#[derive(Debug, StructOpt)] +#[derive(Debug, Parser)] pub struct TestOpts { - #[structopt(long, default_value="0")] + #[clap(long, default_value="0")] /// Pin for GPIO write write_pin: u8, - #[structopt(long, default_value="1")] + #[clap(long, default_value="1")] /// Pin for GPIO read read_pin: u8, } @@ -125,7 +125,7 @@ fn parse_hex_str(src: &str) -> Result, hex::FromHexError> { fn main() { - let opts = Options::from_args(); + let opts = Options::parse(); // Setup logging TermLogger::init(opts.level, simplelog::Config::default(), TerminalMode::Mixed).unwrap(); @@ -166,7 +166,7 @@ fn main() { let mut buff = data.clone(); - spi.transfer_inplace(&mut buff).unwrap(); + spi.transfer_in_place(&mut buff).unwrap(); cp2130.set_gpio_mode_level(spi_opts.cs_pin, GpioMode::PushPull, GpioLevel::High).unwrap(); diff --git a/src/device.rs b/src/device.rs index e1f7f39..b0a16a9 100644 --- a/src/device.rs +++ b/src/device.rs @@ -171,13 +171,13 @@ struct Endpoint { /// Options for creating a device instance #[derive(Debug, PartialEq, Clone)] -#[cfg_attr(feature = "structopt", derive(structopt::StructOpt))] +#[cfg_attr(feature = "clap", derive(clap::Parser))] pub struct UsbOptions { - #[cfg_attr(feature = "structopt", structopt(long))] + #[cfg_attr(feature = "clap", clap(long))] /// Detach kernel driver if required pub detach_kernel_driver: bool, - #[cfg_attr(feature = "structopt", structopt(long))] + #[cfg_attr(feature = "clap", clap(long))] /// Attempt to claim interface pub claim_interface: bool, } diff --git a/src/lib.rs b/src/lib.rs index 458735e..f983fd3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,7 @@ //! //! Copyright 2019 Ryan Kurte -use std::sync::{Arc, Mutex}; +use std::{sync::{Arc, Mutex}, time::{Instant, Duration}}; #[macro_use] extern crate log; @@ -145,7 +145,7 @@ impl Cp2130 { } /// Underlying device functions -impl Device for Cp2130 { +impl Device for Cp2130 { fn spi_read(&self, buff: &mut [u8]) -> Result { let mut inner = self.inner.lock().unwrap(); inner.spi_read(buff) @@ -189,61 +189,51 @@ pub struct Spi { inner: Arc>, } +use embedded_hal::spi::Operation as SpiOp; -impl embedded_hal::spi::blocking::Transfer for Spi { +impl embedded_hal::spi::SpiDevice for Spi { + + fn transaction(&mut self, operations: &mut [SpiOp<'_, u8>]) -> Result<(), Self::Error> { + for o in operations { + match o { + SpiOp::Write(w) => self.write(w)?, + SpiOp::Transfer(r, w) => self.transfer(r, w)?, + SpiOp::TransferInPlace(b) => self.transfer_in_place(b)?, + SpiOp::Read(r) => self.read(r)?, + SpiOp::DelayUs(us) => { + let now = Instant::now(); + while now.elapsed() < Duration::from_micros(*us as u64) {} + } + } + } - fn transfer<'w>(&mut self, buff: &'w mut [u8], out: &'w [u8]) -> Result<(), Self::Error> { - let _n = self.inner.lock().unwrap().spi_write_read(&out, buff)?; Ok(()) } -} - -impl embedded_hal::spi::blocking::TransferInplace for Spi { - - fn transfer_inplace<'w>(&mut self, buff: &'w mut [u8]) -> Result<(), Self::Error> { - let out = buff.to_vec(); + + fn read(&mut self, buff: &mut [u8] ) -> Result<(), Self::Error> { + let out = vec![0u8; buff.len()]; let _n = self.inner.lock().unwrap().spi_write_read(&out, buff)?; Ok(()) } -} - - -impl embedded_hal::spi::blocking::Write for Spi { fn write(&mut self, words: &[u8] ) -> Result<(), Self::Error> { let _n = self.inner.lock().unwrap().spi_write(words)?; Ok(()) } -} -impl embedded_hal::spi::blocking::Read for Spi { - - fn read(&mut self, buff: &mut [u8] ) -> Result<(), Self::Error> { - let out = vec![0u8; buff.len()]; + fn transfer<'w>(&mut self, buff: &'w mut [u8], out: &'w [u8]) -> Result<(), Self::Error> { let _n = self.inner.lock().unwrap().spi_write_read(&out, buff)?; Ok(()) } -} - -use embedded_hal::spi::blocking::{Operation, Read as _, Write as _, Transfer as _, TransferInplace}; - -/// Default impl for transactional SPI -impl embedded_hal::spi::blocking::Transactional for Spi { - - fn exec<'a>(&mut self, operations: &mut [Operation<'a, u8>]) -> Result<(), Self::Error> { - for o in operations { - match o { - Operation::Write(w) => self.write(w)?, - Operation::Transfer(r, w) => self.transfer(r, w)?, - Operation::TransferInplace(b) => self.transfer_inplace(b)?, - Operation::Read(r) => self.read(r)?, - } - } + fn transfer_in_place<'w>(&mut self, buff: &'w mut [u8]) -> Result<(), Self::Error> { + let out = buff.to_vec(); + let _n = self.inner.lock().unwrap().spi_write_read(&out, buff)?; Ok(()) } } + impl embedded_hal::spi::ErrorType for Spi { type Error = Error; } @@ -259,7 +249,7 @@ pub struct InputPin { inner: Arc>, } -impl embedded_hal::digital::blocking::InputPin for InputPin { +impl embedded_hal::digital::InputPin for InputPin { fn is_high(&self) -> Result { self.inner.lock().unwrap().get_gpio_level(self.index) } @@ -274,6 +264,12 @@ impl embedded_hal::digital::ErrorType for InputPin { type Error = Error; } +impl embedded_hal::digital::Error for Error { + fn kind(&self) -> embedded_hal::digital::ErrorKind { + embedded_hal::digital::ErrorKind::Other + } +} + /// OutputPin object implements embedded-hal OutputPin traits for the CP2130 pub struct OutputPin { index: u8, @@ -281,7 +277,7 @@ pub struct OutputPin { inner: Arc>, } -impl embedded_hal::digital::blocking::OutputPin for OutputPin { +impl embedded_hal::digital::OutputPin for OutputPin { fn set_high(&mut self) -> Result<(), Self::Error> { self.inner.lock().unwrap().set_gpio_mode_level(self.index, self.mode, GpioLevel::High) } diff --git a/src/manager.rs b/src/manager.rs index ec75c5c..bd27d8f 100644 --- a/src/manager.rs +++ b/src/manager.rs @@ -5,13 +5,13 @@ pub use rusb::{Device as UsbDevice, UsbContext as _, Context as UsbContext, DeviceList, DeviceDescriptor}; -#[cfg(feature = "structopt")] +#[cfg(feature = "clap")] use std::num::ParseIntError; -#[cfg(feature = "structopt")] -use structopt::StructOpt; +#[cfg(feature = "clap")] +use clap::Parser; -use crate::{Error}; +use crate::Error; use crate::device::{VID, PID}; lazy_static!{ @@ -28,18 +28,18 @@ pub struct Manager { } #[derive(Debug, Clone, PartialEq)] -#[cfg_attr(feature = "structopt", derive(StructOpt))] +#[cfg_attr(feature = "clap", derive(Parser))] pub struct Filter { - #[cfg_attr(feature = "structopt", structopt(long, default_value="10c4", parse(try_from_str=parse_hex)))] + #[cfg_attr(feature = "clap", clap(long, default_value="10c4", value_parser=parse_hex))] /// Device Vendor ID (VID) in hex pub vid: u16, - #[cfg_attr(feature = "structopt", structopt(long, default_value="87a0", parse(try_from_str=parse_hex)))] + #[cfg_attr(feature = "clap", clap(long, default_value="87a0", value_parser=parse_hex))] /// Device Product ID (PID) in hex pub pid: u16, } -#[cfg(feature = "structopt")] +#[cfg(feature = "clap")] fn parse_hex(src: &str) -> Result { u16::from_str_radix(src, 16) }