use std::sync::{Arc, Mutex};
use crate::config::ControllerConfig;
use crate::controller::{ControllerStatistics, PidController};
use crate::error::PidError;
#[cfg(feature = "debugging")]
use crate::controller::StatisticsTracker;
#[cfg(feature = "debugging")]
use crate::debug::{ControllerDebugger, DebugConfig};
pub struct ThreadSafePidController {
controller: Arc<Mutex<PidController>>,
}
impl Clone for ThreadSafePidController {
fn clone(&self) -> Self {
ThreadSafePidController {
controller: Arc::clone(&self.controller),
}
}
}
impl ThreadSafePidController {
pub fn new(config: ControllerConfig) -> Self {
ThreadSafePidController {
controller: Arc::new(Mutex::new(PidController::new(config))),
}
}
pub fn compute(&self, process_value: f64, dt: f64) -> Result<f64, PidError> {
let mut controller = self
.controller
.lock()
.map_err(|_| PidError::MutexPoisoned)?;
controller.compute(process_value, dt)
}
pub fn reset(&self) -> Result<(), PidError> {
let mut controller = self
.controller
.lock()
.map_err(|_| PidError::MutexPoisoned)?;
controller.reset();
Ok(())
}
pub fn get_control_signal(&self) -> Result<f64, PidError> {
let controller = self
.controller
.lock()
.map_err(|_| PidError::MutexPoisoned)?;
Ok(controller.state.last_output)
}
pub fn set_setpoint(&self, setpoint: f64) -> Result<(), PidError> {
let mut controller = self
.controller
.lock()
.map_err(|_| PidError::MutexPoisoned)?;
controller.set_setpoint(setpoint)
}
pub fn update_config(&self, config: ControllerConfig) -> Result<(), PidError> {
let mut controller = self
.controller
.lock()
.map_err(|_| PidError::MutexPoisoned)?;
controller.config = config;
Ok(())
}
pub fn get_statistics(&self) -> Result<ControllerStatistics, PidError> {
let controller = self
.controller
.lock()
.map_err(|_| PidError::MutexPoisoned)?;
Ok(controller.get_statistics())
}
pub fn set_kp(&self, kp: f64) -> Result<(), PidError> {
let mut controller = self
.controller
.lock()
.map_err(|_| PidError::MutexPoisoned)?;
controller.set_kp(kp)
}
pub fn set_ki(&self, ki: f64) -> Result<(), PidError> {
let mut controller = self
.controller
.lock()
.map_err(|_| PidError::MutexPoisoned)?;
controller.set_ki(ki)
}
pub fn set_kd(&self, kd: f64) -> Result<(), PidError> {
let mut controller = self
.controller
.lock()
.map_err(|_| PidError::MutexPoisoned)?;
controller.set_kd(kd)
}
pub fn set_output_limits(&self, min: f64, max: f64) -> Result<(), PidError> {
let mut controller = self
.controller
.lock()
.map_err(|_| PidError::MutexPoisoned)?;
controller.set_output_limits(min, max);
Ok(())
}
pub fn set_deadband(&self, deadband: f64) -> Result<(), PidError> {
let mut controller = self
.controller
.lock()
.map_err(|_| PidError::MutexPoisoned)?;
controller.set_deadband(deadband)
}
#[cfg(feature = "debugging")]
pub fn with_debugging(self, debug_config: DebugConfig) -> Result<Self, PidError> {
let lock = self
.controller
.lock()
.map_err(|_| PidError::MutexPoisoned)?;
let pid_controller = PidController {
config: lock.config.clone(),
state: lock.state.clone(),
stats: StatisticsTracker {
start_time: lock.stats.start_time,
error_sum: lock.stats.error_sum,
error_count: lock.stats.error_count,
max_error: lock.stats.max_error,
reached_setpoint: lock.stats.reached_setpoint,
rise_time: lock.stats.rise_time,
settle_time: lock.stats.settle_time,
settled_threshold: lock.stats.settled_threshold,
},
debugger: Some(ControllerDebugger::new(debug_config)),
};
Ok(ThreadSafePidController {
controller: Arc::new(Mutex::new(pid_controller)),
})
}
}