From f72705c15bf07d49c17646ec7d68dce0ecb72abd Mon Sep 17 00:00:00 2001 From: David Meyer Date: Wed, 30 Oct 2024 23:50:21 -0700 Subject: [PATCH 1/3] add nlab cli to the python package --- Cargo.toml | 1 + pyproject.toml | 11 ++++++----- src/python.rs | 40 +++++++++++++++++++++++++++++++++++++++- src/python/cli.rs | 15 +++++++++++++++ 4 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 src/python/cli.rs diff --git a/Cargo.toml b/Cargo.toml index 7bb64e2..8aead9d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ log = "~0.4" regex = "~1" rusb = { version = "0.9.3", features = ["vendored"] } dfu-libusb = "0.5.1" +clap = { version = "4.5.16", features = ["derive"] } pyo3 = { version = "~0.22", features = ["multiple-pymethods"] } [dev-dependencies] diff --git a/pyproject.toml b/pyproject.toml index 28b1de9..1ebdacf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,12 +5,13 @@ build-backend = "maturin" [project] name = "nlabapi" requires-python = ">=3.8" -classifiers = [ - "Programming Language :: Rust", - "Programming Language :: Python :: Implementation :: CPython", - "Programming Language :: Python :: Implementation :: PyPy", -] +readme = "README.md" +license = { file = "LICENSE" } dynamic = ["version"] + +[project.scripts] +nlab = "nlabapi:run_cli" + [tool.maturin] module-name = "nlabapi" features = ["pyo3/extension-module"] diff --git a/src/python.rs b/src/python.rs index 5f73f10..a21847f 100644 --- a/src/python.rs +++ b/src/python.rs @@ -2,9 +2,46 @@ mod bench; mod scope; mod analog_output; mod pulse_output; +mod cli; +use std::thread; +use std::time::Duration; use pyo3::prelude::*; -use crate::{AnalogSignalPolarity, AnalogWaveType, PowerStatus, PowerState}; +use crate::{AnalogSignalPolarity, AnalogWaveType, PowerStatus, PowerState, LabBench as NativeLabBench}; +use cli::{Cli, Commands}; +use clap::Parser; + +#[pyfunction] +fn run_cli(_py: Python) -> PyResult<()> { + let args: Vec<_> = std::env::args_os().skip(1).collect(); + let cli = Cli::parse_from(args); + + match &cli.command { + Commands::Update => { + if let Ok(mut bench) = NativeLabBench::new() { + for nlab_link in bench.list() { + // Request DFU on any nLab that is available + if nlab_link.available { + if let Err(e) = nlab_link.request_dfu() { + println!("Failed to request DFU on an available nLab: {e}") + } + } + } + // Wait 500ms for the scope to detach and re-attach as DFU + thread::sleep(Duration::from_millis(500)); + bench.refresh(); + + for nlab_link in bench.list() { + if let Err(e) = nlab_link.update() { + println!("Encountered an error updating nLab: {e}") + } + } + } + } + } + + Ok(()) +} #[pyclass] struct LabBench; @@ -21,5 +58,6 @@ fn nlabapi(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_class::()?; m.add_class::()?; m.add_class::()?; + m.add_function(wrap_pyfunction!(run_cli, m)?)?; Ok(()) } \ No newline at end of file diff --git a/src/python/cli.rs b/src/python/cli.rs new file mode 100644 index 0000000..fcdbada --- /dev/null +++ b/src/python/cli.rs @@ -0,0 +1,15 @@ +use clap::{Parser, Subcommand}; + +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +#[command(propagate_version = true)] +pub(super) struct Cli { + #[command(subcommand)] + pub command: Commands, +} + +#[derive(Subcommand, Debug)] +pub(super) enum Commands { + /// Update all detected nLabs + Update, +} \ No newline at end of file From 56aa62f769ac1cfd0dc773db8ae319b26124ce3c Mon Sep 17 00:00:00 2001 From: David Meyer Date: Thu, 7 Nov 2024 20:19:21 -0800 Subject: [PATCH 2/3] add in some print statements --- src/python.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/python.rs b/src/python.rs index a21847f..2e1383e 100644 --- a/src/python.rs +++ b/src/python.rs @@ -10,6 +10,7 @@ use pyo3::prelude::*; use crate::{AnalogSignalPolarity, AnalogWaveType, PowerStatus, PowerState, LabBench as NativeLabBench}; use cli::{Cli, Commands}; use clap::Parser; +use pyo3::exceptions::PyRuntimeError; #[pyfunction] fn run_cli(_py: Python) -> PyResult<()> { @@ -23,19 +24,23 @@ fn run_cli(_py: Python) -> PyResult<()> { // Request DFU on any nLab that is available if nlab_link.available { if let Err(e) = nlab_link.request_dfu() { - println!("Failed to request DFU on an available nLab: {e}") + println!("Failed to request DFU on an available nLab: {e}"); + return Err(PyRuntimeError::new_err(format!("{e}"))); } } } + println!("Updating all connected nLabs..."); // Wait 500ms for the scope to detach and re-attach as DFU thread::sleep(Duration::from_millis(500)); bench.refresh(); for nlab_link in bench.list() { if let Err(e) = nlab_link.update() { - println!("Encountered an error updating nLab: {e}") + println!("Encountered an error updating nLab: {e}"); + return Err(PyRuntimeError::new_err(format!("{e}"))); } } + println!("Update complete!"); } } } From 9ab976092a6e9d78523d2e75bf86225a8b3443d0 Mon Sep 17 00:00:00 2001 From: David Meyer Date: Thu, 7 Nov 2024 20:35:37 -0800 Subject: [PATCH 3/3] allow calling update from python code --- src/python.rs | 45 ++++++++------------------------------------- src/python/bench.rs | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 37 deletions(-) diff --git a/src/python.rs b/src/python.rs index 2e1383e..2cc34ba 100644 --- a/src/python.rs +++ b/src/python.rs @@ -4,13 +4,16 @@ mod analog_output; mod pulse_output; mod cli; -use std::thread; -use std::time::Duration; use pyo3::prelude::*; -use crate::{AnalogSignalPolarity, AnalogWaveType, PowerStatus, PowerState, LabBench as NativeLabBench}; +use crate::{AnalogSignalPolarity, AnalogWaveType, PowerStatus, PowerState}; use cli::{Cli, Commands}; use clap::Parser; -use pyo3::exceptions::PyRuntimeError; + +#[pyclass] +struct LabBench; + +#[pyclass] +struct Nlab(crate::Nlab); #[pyfunction] fn run_cli(_py: Python) -> PyResult<()> { @@ -18,42 +21,10 @@ fn run_cli(_py: Python) -> PyResult<()> { let cli = Cli::parse_from(args); match &cli.command { - Commands::Update => { - if let Ok(mut bench) = NativeLabBench::new() { - for nlab_link in bench.list() { - // Request DFU on any nLab that is available - if nlab_link.available { - if let Err(e) = nlab_link.request_dfu() { - println!("Failed to request DFU on an available nLab: {e}"); - return Err(PyRuntimeError::new_err(format!("{e}"))); - } - } - } - println!("Updating all connected nLabs..."); - // Wait 500ms for the scope to detach and re-attach as DFU - thread::sleep(Duration::from_millis(500)); - bench.refresh(); - - for nlab_link in bench.list() { - if let Err(e) = nlab_link.update() { - println!("Encountered an error updating nLab: {e}"); - return Err(PyRuntimeError::new_err(format!("{e}"))); - } - } - println!("Update complete!"); - } - } + Commands::Update => { LabBench::update_all_nlabs() } } - - Ok(()) } -#[pyclass] -struct LabBench; - -#[pyclass] -struct Nlab(crate::Nlab); - /// A Python module implemented in Rust. #[pymodule] fn nlabapi(m: &Bound<'_, PyModule>) -> PyResult<()> { diff --git a/src/python/bench.rs b/src/python/bench.rs index 4fb571f..72bccac 100644 --- a/src/python/bench.rs +++ b/src/python/bench.rs @@ -1,3 +1,5 @@ +use std::thread; +use std::time::Duration; use pyo3::exceptions::*; use pyo3::prelude::*; use crate::{LabBench, python}; @@ -25,4 +27,40 @@ impl python::LabBench { println!("Cannot create LabBench"); } } + + #[staticmethod] + fn count_connected_nlabs() -> usize { + if let Ok(bench) = LabBench::new() { + return bench.list().count(); + } + 0 + } + + #[staticmethod] + pub(super) fn update_all_nlabs() -> PyResult<()> { + if let Ok(mut bench) = LabBench::new() { + for nlab_link in bench.list() { + // Request DFU on any nLab that is available + if nlab_link.available { + if let Err(e) = nlab_link.request_dfu() { + println!("Failed to request DFU on an available nLab: {e}"); + return Err(PyRuntimeError::new_err(format!("{e}"))); + } + } + } + println!("Updating all connected nLabs..."); + // Wait 500ms for the scope to detach and re-attach as DFU + thread::sleep(Duration::from_millis(500)); + bench.refresh(); + + for nlab_link in bench.list() { + if let Err(e) = nlab_link.update() { + println!("Encountered an error updating nLab: {e}"); + return Err(PyRuntimeError::new_err(format!("{e}"))); + } + } + println!("Update complete!"); + } + Ok(()) + } }