TipController

Struct TipController 

Source
pub struct TipController { /* private fields */ }
Expand description

Enhanced tip controller with pulse voltage stepping

Implementations§

Source§

impl TipController

Source

pub fn new( driver: ActionDriver, signal_index: SignalIndex, pulse_voltage: f32, bound: (f32, f32), ) -> Self

Create new tip controller with basic signal bounds

Examples found in repository?
examples/tip_prep_demo.rs (line 23)
16fn main() -> Result<(), Box<dyn std::error::Error>> {
17    env_logger::init();
18
19    // Create ActionDriver
20    let driver = ActionDriver::new("127.0.0.1", 6501)?;
21
22    // Create controller with custom pulse stepping parameters
23    let mut custom_controller = TipController::new(driver, SignalIndex(76), 2.0, (-2.0, 0.0));
24
25    let file_path = create_log_file_path()?;
26    println!("{file_path:?}");
27
28    // Configure custom pulse stepping parameters with dynamic threshold
29    custom_controller
30        //.set_pulse_stepping(1.5, Box::new(|signal| signal.abs() / 10.0), 4, 8.0)
31        .set_pulse_stepping_fixed(1.5, 2.0, 4, 10.0)
32        .set_stability_threshold(5)
33        .with_logger(Logger::new(file_path, 5));
34
35    // Create atomic flag for graceful shutdown
36    let running = Arc::new(AtomicBool::new(true));
37    let running_clone = Arc::clone(&running);
38
39    // Wrap controller in Arc<Mutex<>> for signal handler
40    let controller = Arc::new(Mutex::new(custom_controller));
41    let controller_clone = Arc::clone(&controller);
42
43    // Set up Ctrl-C handler to flush logger and signal stop
44    ctrlc::set_handler(move || {
45        info!("Received Ctrl-C, signaling stop and flushing logger...");
46        running_clone.store(false, Ordering::SeqCst);
47
48        if let Ok(mut ctrl) = controller_clone.lock() {
49            // Force flush the logger
50            match ctrl.flush_logger() {
51                Ok(()) => info!("Logger flushed successfully on exit"),
52                Err(e) => info!("Failed to flush logger on exit: {}", e),
53            }
54        }
55    })?;
56
57    // Run control loop with periodic checks for the stop signal
58    let result: Result<(), Box<dyn std::error::Error>> = {
59        let mut ctrl = controller.lock().unwrap();
60
61        // Run in shorter intervals so we can check the stop signal
62        let mut total_elapsed = Duration::from_secs(0);
63        let max_duration = Duration::from_secs(1000);
64        let check_interval = Duration::from_secs(5);
65
66        while total_elapsed < max_duration && running.load(Ordering::SeqCst) {
67            let remaining = max_duration - total_elapsed;
68            let run_duration = check_interval.min(remaining);
69
70            match ctrl.run(run_duration) {
71                Ok(final_state) => {
72                    info!("Controller finished with state: {:?}", final_state);
73                    break;
74                }
75                Err(e) if e.to_string().contains("Loop timeout") => {
76                    // Expected timeout, continue if still running
77                    total_elapsed += run_duration;
78                    if !running.load(Ordering::SeqCst) {
79                        info!("Stop signal received, exiting gracefully");
80                        break;
81                    }
82                }
83                Err(e) => {
84                    info!("Controller failed: {}", e);
85                    break;
86                }
87            }
88        }
89
90        Ok(())
91    };
92
93    match result {
94        Ok(()) => {
95            info!("Controller loop completed");
96        }
97        Err(e) => {
98            info!("Controller loop failed: {}", e);
99        }
100    }
101
102    Ok(())
103}
Source

pub fn set_pulse_stepping( &mut self, pulse_step: f32, change_threshold: Box<dyn Fn(f32) -> f32 + Send + Sync>, cycles_before_step: u32, max_pulse: f32, ) -> &mut Self

Set pulse stepping parameters with closure-based threshold

Source

pub fn set_pulse_stepping_fixed( &mut self, pulse_step: f32, change_threshold: f32, cycles_before_step: u32, max_pulse: f32, ) -> &mut Self

Set pulse stepping parameters with fixed threshold (convenience method)

Examples found in repository?
examples/tip_prep_demo.rs (line 31)
16fn main() -> Result<(), Box<dyn std::error::Error>> {
17    env_logger::init();
18
19    // Create ActionDriver
20    let driver = ActionDriver::new("127.0.0.1", 6501)?;
21
22    // Create controller with custom pulse stepping parameters
23    let mut custom_controller = TipController::new(driver, SignalIndex(76), 2.0, (-2.0, 0.0));
24
25    let file_path = create_log_file_path()?;
26    println!("{file_path:?}");
27
28    // Configure custom pulse stepping parameters with dynamic threshold
29    custom_controller
30        //.set_pulse_stepping(1.5, Box::new(|signal| signal.abs() / 10.0), 4, 8.0)
31        .set_pulse_stepping_fixed(1.5, 2.0, 4, 10.0)
32        .set_stability_threshold(5)
33        .with_logger(Logger::new(file_path, 5));
34
35    // Create atomic flag for graceful shutdown
36    let running = Arc::new(AtomicBool::new(true));
37    let running_clone = Arc::clone(&running);
38
39    // Wrap controller in Arc<Mutex<>> for signal handler
40    let controller = Arc::new(Mutex::new(custom_controller));
41    let controller_clone = Arc::clone(&controller);
42
43    // Set up Ctrl-C handler to flush logger and signal stop
44    ctrlc::set_handler(move || {
45        info!("Received Ctrl-C, signaling stop and flushing logger...");
46        running_clone.store(false, Ordering::SeqCst);
47
48        if let Ok(mut ctrl) = controller_clone.lock() {
49            // Force flush the logger
50            match ctrl.flush_logger() {
51                Ok(()) => info!("Logger flushed successfully on exit"),
52                Err(e) => info!("Failed to flush logger on exit: {}", e),
53            }
54        }
55    })?;
56
57    // Run control loop with periodic checks for the stop signal
58    let result: Result<(), Box<dyn std::error::Error>> = {
59        let mut ctrl = controller.lock().unwrap();
60
61        // Run in shorter intervals so we can check the stop signal
62        let mut total_elapsed = Duration::from_secs(0);
63        let max_duration = Duration::from_secs(1000);
64        let check_interval = Duration::from_secs(5);
65
66        while total_elapsed < max_duration && running.load(Ordering::SeqCst) {
67            let remaining = max_duration - total_elapsed;
68            let run_duration = check_interval.min(remaining);
69
70            match ctrl.run(run_duration) {
71                Ok(final_state) => {
72                    info!("Controller finished with state: {:?}", final_state);
73                    break;
74                }
75                Err(e) if e.to_string().contains("Loop timeout") => {
76                    // Expected timeout, continue if still running
77                    total_elapsed += run_duration;
78                    if !running.load(Ordering::SeqCst) {
79                        info!("Stop signal received, exiting gracefully");
80                        break;
81                    }
82                }
83                Err(e) => {
84                    info!("Controller failed: {}", e);
85                    break;
86                }
87            }
88        }
89
90        Ok(())
91    };
92
93    match result {
94        Ok(()) => {
95            info!("Controller loop completed");
96        }
97        Err(e) => {
98            info!("Controller loop failed: {}", e);
99        }
100    }
101
102    Ok(())
103}
Source

pub fn with_logger(&mut self, logger: Logger<LogLine>) -> &mut Self

Provide Json File logger for inspecting behavior

Examples found in repository?
examples/tip_prep_demo.rs (line 33)
16fn main() -> Result<(), Box<dyn std::error::Error>> {
17    env_logger::init();
18
19    // Create ActionDriver
20    let driver = ActionDriver::new("127.0.0.1", 6501)?;
21
22    // Create controller with custom pulse stepping parameters
23    let mut custom_controller = TipController::new(driver, SignalIndex(76), 2.0, (-2.0, 0.0));
24
25    let file_path = create_log_file_path()?;
26    println!("{file_path:?}");
27
28    // Configure custom pulse stepping parameters with dynamic threshold
29    custom_controller
30        //.set_pulse_stepping(1.5, Box::new(|signal| signal.abs() / 10.0), 4, 8.0)
31        .set_pulse_stepping_fixed(1.5, 2.0, 4, 10.0)
32        .set_stability_threshold(5)
33        .with_logger(Logger::new(file_path, 5));
34
35    // Create atomic flag for graceful shutdown
36    let running = Arc::new(AtomicBool::new(true));
37    let running_clone = Arc::clone(&running);
38
39    // Wrap controller in Arc<Mutex<>> for signal handler
40    let controller = Arc::new(Mutex::new(custom_controller));
41    let controller_clone = Arc::clone(&controller);
42
43    // Set up Ctrl-C handler to flush logger and signal stop
44    ctrlc::set_handler(move || {
45        info!("Received Ctrl-C, signaling stop and flushing logger...");
46        running_clone.store(false, Ordering::SeqCst);
47
48        if let Ok(mut ctrl) = controller_clone.lock() {
49            // Force flush the logger
50            match ctrl.flush_logger() {
51                Ok(()) => info!("Logger flushed successfully on exit"),
52                Err(e) => info!("Failed to flush logger on exit: {}", e),
53            }
54        }
55    })?;
56
57    // Run control loop with periodic checks for the stop signal
58    let result: Result<(), Box<dyn std::error::Error>> = {
59        let mut ctrl = controller.lock().unwrap();
60
61        // Run in shorter intervals so we can check the stop signal
62        let mut total_elapsed = Duration::from_secs(0);
63        let max_duration = Duration::from_secs(1000);
64        let check_interval = Duration::from_secs(5);
65
66        while total_elapsed < max_duration && running.load(Ordering::SeqCst) {
67            let remaining = max_duration - total_elapsed;
68            let run_duration = check_interval.min(remaining);
69
70            match ctrl.run(run_duration) {
71                Ok(final_state) => {
72                    info!("Controller finished with state: {:?}", final_state);
73                    break;
74                }
75                Err(e) if e.to_string().contains("Loop timeout") => {
76                    // Expected timeout, continue if still running
77                    total_elapsed += run_duration;
78                    if !running.load(Ordering::SeqCst) {
79                        info!("Stop signal received, exiting gracefully");
80                        break;
81                    }
82                }
83                Err(e) => {
84                    info!("Controller failed: {}", e);
85                    break;
86                }
87            }
88        }
89
90        Ok(())
91    };
92
93    match result {
94        Ok(()) => {
95            info!("Controller loop completed");
96        }
97        Err(e) => {
98            info!("Controller loop failed: {}", e);
99        }
100    }
101
102    Ok(())
103}
Source

pub fn flush_logger(&mut self) -> Result<(), NanonisError>

Flush the logger (useful for signal handlers)

Examples found in repository?
examples/tip_prep_demo.rs (line 50)
16fn main() -> Result<(), Box<dyn std::error::Error>> {
17    env_logger::init();
18
19    // Create ActionDriver
20    let driver = ActionDriver::new("127.0.0.1", 6501)?;
21
22    // Create controller with custom pulse stepping parameters
23    let mut custom_controller = TipController::new(driver, SignalIndex(76), 2.0, (-2.0, 0.0));
24
25    let file_path = create_log_file_path()?;
26    println!("{file_path:?}");
27
28    // Configure custom pulse stepping parameters with dynamic threshold
29    custom_controller
30        //.set_pulse_stepping(1.5, Box::new(|signal| signal.abs() / 10.0), 4, 8.0)
31        .set_pulse_stepping_fixed(1.5, 2.0, 4, 10.0)
32        .set_stability_threshold(5)
33        .with_logger(Logger::new(file_path, 5));
34
35    // Create atomic flag for graceful shutdown
36    let running = Arc::new(AtomicBool::new(true));
37    let running_clone = Arc::clone(&running);
38
39    // Wrap controller in Arc<Mutex<>> for signal handler
40    let controller = Arc::new(Mutex::new(custom_controller));
41    let controller_clone = Arc::clone(&controller);
42
43    // Set up Ctrl-C handler to flush logger and signal stop
44    ctrlc::set_handler(move || {
45        info!("Received Ctrl-C, signaling stop and flushing logger...");
46        running_clone.store(false, Ordering::SeqCst);
47
48        if let Ok(mut ctrl) = controller_clone.lock() {
49            // Force flush the logger
50            match ctrl.flush_logger() {
51                Ok(()) => info!("Logger flushed successfully on exit"),
52                Err(e) => info!("Failed to flush logger on exit: {}", e),
53            }
54        }
55    })?;
56
57    // Run control loop with periodic checks for the stop signal
58    let result: Result<(), Box<dyn std::error::Error>> = {
59        let mut ctrl = controller.lock().unwrap();
60
61        // Run in shorter intervals so we can check the stop signal
62        let mut total_elapsed = Duration::from_secs(0);
63        let max_duration = Duration::from_secs(1000);
64        let check_interval = Duration::from_secs(5);
65
66        while total_elapsed < max_duration && running.load(Ordering::SeqCst) {
67            let remaining = max_duration - total_elapsed;
68            let run_duration = check_interval.min(remaining);
69
70            match ctrl.run(run_duration) {
71                Ok(final_state) => {
72                    info!("Controller finished with state: {:?}", final_state);
73                    break;
74                }
75                Err(e) if e.to_string().contains("Loop timeout") => {
76                    // Expected timeout, continue if still running
77                    total_elapsed += run_duration;
78                    if !running.load(Ordering::SeqCst) {
79                        info!("Stop signal received, exiting gracefully");
80                        break;
81                    }
82                }
83                Err(e) => {
84                    info!("Controller failed: {}", e);
85                    break;
86                }
87            }
88        }
89
90        Ok(())
91    };
92
93    match result {
94        Ok(()) => {
95            info!("Controller loop completed");
96        }
97        Err(e) => {
98            info!("Controller loop failed: {}", e);
99        }
100    }
101
102    Ok(())
103}
Source

pub fn set_stability_threshold(&mut self, threshold: u32) -> &mut Self

Set stability threshold (how many good readings needed for stable)

Examples found in repository?
examples/tip_prep_demo.rs (line 32)
16fn main() -> Result<(), Box<dyn std::error::Error>> {
17    env_logger::init();
18
19    // Create ActionDriver
20    let driver = ActionDriver::new("127.0.0.1", 6501)?;
21
22    // Create controller with custom pulse stepping parameters
23    let mut custom_controller = TipController::new(driver, SignalIndex(76), 2.0, (-2.0, 0.0));
24
25    let file_path = create_log_file_path()?;
26    println!("{file_path:?}");
27
28    // Configure custom pulse stepping parameters with dynamic threshold
29    custom_controller
30        //.set_pulse_stepping(1.5, Box::new(|signal| signal.abs() / 10.0), 4, 8.0)
31        .set_pulse_stepping_fixed(1.5, 2.0, 4, 10.0)
32        .set_stability_threshold(5)
33        .with_logger(Logger::new(file_path, 5));
34
35    // Create atomic flag for graceful shutdown
36    let running = Arc::new(AtomicBool::new(true));
37    let running_clone = Arc::clone(&running);
38
39    // Wrap controller in Arc<Mutex<>> for signal handler
40    let controller = Arc::new(Mutex::new(custom_controller));
41    let controller_clone = Arc::clone(&controller);
42
43    // Set up Ctrl-C handler to flush logger and signal stop
44    ctrlc::set_handler(move || {
45        info!("Received Ctrl-C, signaling stop and flushing logger...");
46        running_clone.store(false, Ordering::SeqCst);
47
48        if let Ok(mut ctrl) = controller_clone.lock() {
49            // Force flush the logger
50            match ctrl.flush_logger() {
51                Ok(()) => info!("Logger flushed successfully on exit"),
52                Err(e) => info!("Failed to flush logger on exit: {}", e),
53            }
54        }
55    })?;
56
57    // Run control loop with periodic checks for the stop signal
58    let result: Result<(), Box<dyn std::error::Error>> = {
59        let mut ctrl = controller.lock().unwrap();
60
61        // Run in shorter intervals so we can check the stop signal
62        let mut total_elapsed = Duration::from_secs(0);
63        let max_duration = Duration::from_secs(1000);
64        let check_interval = Duration::from_secs(5);
65
66        while total_elapsed < max_duration && running.load(Ordering::SeqCst) {
67            let remaining = max_duration - total_elapsed;
68            let run_duration = check_interval.min(remaining);
69
70            match ctrl.run(run_duration) {
71                Ok(final_state) => {
72                    info!("Controller finished with state: {:?}", final_state);
73                    break;
74                }
75                Err(e) if e.to_string().contains("Loop timeout") => {
76                    // Expected timeout, continue if still running
77                    total_elapsed += run_duration;
78                    if !running.load(Ordering::SeqCst) {
79                        info!("Stop signal received, exiting gracefully");
80                        break;
81                    }
82                }
83                Err(e) => {
84                    info!("Controller failed: {}", e);
85                    break;
86                }
87            }
88        }
89
90        Ok(())
91    };
92
93    match result {
94        Ok(()) => {
95            info!("Controller loop completed");
96        }
97        Err(e) => {
98            info!("Controller loop failed: {}", e);
99        }
100    }
101
102    Ok(())
103}
Source

pub fn current_pulse_voltage(&self) -> f32

Get current pulse voltage

Source

pub fn signal_history(&self) -> Option<&VecDeque<f32>>

Get signal history (most recent first) for the frequency shift signal

Source

pub fn average_signal(&self) -> Option<f32>

Calculate average of recent signals for the frequency shift signal

Source

pub fn average_signal_for(&self, signal_index: SignalIndex) -> Option<f32>

Calculate average of recent signals for a specific signal

Source

pub fn track_signal(&mut self, signal_index: SignalIndex, value: f32)

Track a signal value in history

Source

pub fn get_signal_change(&self, signal_index: SignalIndex) -> Option<f32>

Get signal change (latest - previous) for a specific signal

Source

pub fn get_signal_history( &self, signal_index: SignalIndex, ) -> Option<&VecDeque<f32>>

Get signal history for a specific signal (most recent first)

Source

pub fn get_last_signal(&self, signal_index: SignalIndex) -> Option<f32>

Source

pub fn clear_all_histories(&mut self)

Clear all signal histories (useful for logger integration)

Source

pub fn clear_signal_history(&mut self, signal_index: SignalIndex)

Clear history for a specific signal

Source§

impl TipController

Source

pub fn run_loop(&mut self, timeout: Duration) -> Result<TipState, NanonisError>

Main control loop - with pulse voltage stepping

Trait Implementations§

Source§

impl Job for TipController

Source§

type Output = TipState

The type returned on successful completion
Source§

fn run(&mut self, timeout: Duration) -> Result<Self::Output, NanonisError>

Run the job with a timeout Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.