Skip to content

Commit af7ba45

Browse files
committed
feat: thermal regulations daemon
1 parent 9eacdea commit af7ba45

File tree

5 files changed

+1525
-3
lines changed

5 files changed

+1525
-3
lines changed

rust/src/acquisition/daemon.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ mod tests {
149149
use super::*;
150150
use crate::acquisition::{get_default_audio_source, AudioStreamConsumer};
151151
use std::time::Duration;
152-
use tokio::time::timeout;
152+
use tokio::time::{sleep, timeout};
153153

154154
#[tokio::test]
155155
async fn test_acquisition_daemon() {

rust/src/daemon/launch_daemon.rs

Lines changed: 196 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ use crate::acquisition::{
2323
};
2424
use crate::processing::nodes::StreamingNodeRegistry;
2525
use crate::processing::{ProcessingConsumer, ProcessingGraph};
26+
use crate::thermal_regulation::{
27+
create_shared_thermal_state, SharedThermalState, ThermalRegulationSystemDaemon,
28+
};
2629
use crate::utility::PhotoacousticDataSource;
2730
use crate::visualization::server::build_rocket;
2831
use crate::visualization::shared_state::SharedVisualizationState;
@@ -80,6 +83,10 @@ pub struct Daemon {
8083
/// Shared configuration for dynamic configuration support
8184
/// This is the single source of truth for all configuration across the application
8285
config: Arc<RwLock<crate::config::Config>>,
86+
/// Thermal regulation system daemon for PID temperature control
87+
thermal_regulation_daemon: Option<ThermalRegulationSystemDaemon>,
88+
/// Shared thermal regulation state for historical data and monitoring
89+
thermal_regulation_state: SharedThermalState,
8390
}
8491

8592
impl Default for Daemon {
@@ -120,6 +127,8 @@ impl Daemon {
120127
visualization_state: Arc::new(SharedVisualizationState::new()),
121128
streaming_registry: Arc::new(StreamingNodeRegistry::new()),
122129
config: Arc::new(RwLock::new(crate::config::Config::default())),
130+
thermal_regulation_daemon: None,
131+
thermal_regulation_state: create_shared_thermal_state(),
123132
}
124133
}
125134

@@ -202,6 +211,11 @@ impl Daemon {
202211
self.start_modbus_server().await?;
203212
}
204213

214+
// Start thermal regulation system if enabled
215+
if self.config.read().unwrap().thermal_regulation.enabled {
216+
self.start_thermal_regulation_system().await?;
217+
}
218+
205219
// Start computation task if enabled
206220
if true {
207221
self.start_photoacoustic_computation()?;
@@ -863,6 +877,167 @@ impl Daemon {
863877
Ok(())
864878
}
865879

880+
/// Start the thermal regulation system daemon
881+
///
882+
/// Initializes and starts the thermal regulation system with multiple independent
883+
/// PID controllers, each running in its own thread with individual sampling frequencies.
884+
/// The system provides precise temperature control for photoacoustic applications.
885+
///
886+
/// This method creates a thermal regulation daemon that manages all configured
887+
/// thermal regulators according to the shared configuration. Each regulator
888+
/// operates independently with its own:
889+
/// - PID controller parameters (Kp, Ki, Kd)
890+
/// - Sampling frequency (sampling_frequency_hz)
891+
/// - Target temperature setpoint
892+
/// - Hardware driver (mock, native, or CP2112)
893+
///
894+
/// The thermal regulation system maintains a shared state with historical data
895+
/// (up to 3600 data points per regulator) that can be accessed by the web interface
896+
/// and other system components.
897+
///
898+
/// ### Returns
899+
///
900+
/// * `Result<()>` - Success if the thermal regulation system started successfully
901+
///
902+
/// ### Errors
903+
///
904+
/// This function can fail if:
905+
/// * Hardware initialization fails
906+
/// * Configuration is invalid
907+
/// * Thread spawning fails
908+
/// * Driver creation fails
909+
async fn start_thermal_regulation_system(&mut self) -> Result<()> {
910+
info!("Starting thermal regulation system");
911+
912+
// Extract thermal regulation configuration
913+
let thermal_config = {
914+
let config = self.config.read().unwrap();
915+
config.thermal_regulation.clone()
916+
};
917+
918+
if !thermal_config.enabled {
919+
info!("Thermal regulation system is disabled in configuration");
920+
return Ok(());
921+
}
922+
923+
if thermal_config.regulators.is_empty() {
924+
warn!("No thermal regulators configured");
925+
return Ok(());
926+
}
927+
928+
// Create thermal regulation system daemon
929+
let mut thermal_daemon = ThermalRegulationSystemDaemon::new(
930+
thermal_config,
931+
self.thermal_regulation_state.clone(),
932+
self.running.clone(),
933+
);
934+
935+
// Start the thermal regulation system
936+
thermal_daemon.start().await?;
937+
938+
info!(
939+
"Thermal regulation system started successfully with {} regulators",
940+
thermal_daemon
941+
.get_shared_state()
942+
.read()
943+
.await
944+
.get_regulator_ids()
945+
.len()
946+
);
947+
948+
// Store the daemon for later management
949+
self.thermal_regulation_daemon = Some(thermal_daemon);
950+
951+
Ok(())
952+
}
953+
954+
/// Get thermal regulation shared state for external access
955+
///
956+
/// Returns a reference to the shared thermal regulation state that contains
957+
/// historical data, current status, and PID parameters for all thermal regulators.
958+
/// This can be used by the web interface and API endpoints to provide
959+
/// real-time monitoring and control capabilities.
960+
///
961+
/// ### Returns
962+
///
963+
/// Reference to the shared thermal regulation state
964+
pub fn get_thermal_regulation_state(&self) -> &SharedThermalState {
965+
&self.thermal_regulation_state
966+
}
967+
968+
/// Update PID parameters for a specific thermal regulator
969+
///
970+
/// Allows dynamic updating of PID controller parameters for a specific regulator
971+
/// without requiring a system restart. This enables real-time tuning and
972+
/// optimization of thermal control performance.
973+
///
974+
/// ### Arguments
975+
///
976+
/// * `regulator_id` - Unique identifier of the thermal regulator
977+
/// * `kp` - Proportional gain
978+
/// * `ki` - Integral gain
979+
/// * `kd` - Derivative gain
980+
///
981+
/// ### Returns
982+
///
983+
/// * `Result<()>` - Success if parameters were updated successfully
984+
///
985+
/// ### Errors
986+
///
987+
/// This function can fail if:
988+
/// * The specified regulator is not found
989+
/// * The thermal regulation system is not running
990+
pub async fn update_thermal_regulator_pid_parameters(
991+
&mut self,
992+
regulator_id: &str,
993+
kp: f64,
994+
ki: f64,
995+
kd: f64,
996+
) -> Result<()> {
997+
if let Some(ref mut thermal_daemon) = self.thermal_regulation_daemon {
998+
thermal_daemon
999+
.update_regulator_pid_parameters(regulator_id, kp, ki, kd)
1000+
.await
1001+
} else {
1002+
Err(anyhow::anyhow!("Thermal regulation system is not running"))
1003+
}
1004+
}
1005+
1006+
/// Update setpoint temperature for a specific thermal regulator
1007+
///
1008+
/// Allows dynamic updating of the target temperature setpoint for a specific
1009+
/// regulator without requiring a system restart. This enables real-time control
1010+
/// of thermal regulation targets.
1011+
///
1012+
/// ### Arguments
1013+
///
1014+
/// * `regulator_id` - Unique identifier of the thermal regulator
1015+
/// * `setpoint_celsius` - New target temperature in degrees Celsius
1016+
///
1017+
/// ### Returns
1018+
///
1019+
/// * `Result<()>` - Success if setpoint was updated successfully
1020+
///
1021+
/// ### Errors
1022+
///
1023+
/// This function can fail if:
1024+
/// * The specified regulator is not found
1025+
/// * The thermal regulation system is not running
1026+
/// * The setpoint is outside safety limits
1027+
pub async fn update_thermal_regulator_setpoint(
1028+
&mut self,
1029+
regulator_id: &str,
1030+
setpoint_celsius: f64,
1031+
) -> Result<()> {
1032+
if let Some(ref mut thermal_daemon) = self.thermal_regulation_daemon {
1033+
thermal_daemon
1034+
.update_regulator_setpoint(regulator_id, setpoint_celsius)
1035+
.await
1036+
} else {
1037+
Err(anyhow::anyhow!("Thermal regulation system is not running"))
1038+
}
1039+
}
1040+
8661041
/// Get the shared data source
8671042
///
8681043
/// ### Returns
@@ -959,7 +1134,27 @@ impl Daemon {
9591134
/// Ok(())
9601135
/// }
9611136
/// ```
962-
pub async fn join(self) -> Result<()> {
1137+
pub async fn join(mut self) -> Result<()> {
1138+
// Stop thermal regulation system if running
1139+
if let Some(ref mut thermal_daemon) = self.thermal_regulation_daemon {
1140+
info!("Stopping thermal regulation system");
1141+
if let Err(e) = thermal_daemon.stop().await {
1142+
error!("Failed to stop thermal regulation system: {}", e);
1143+
}
1144+
}
1145+
1146+
// Stop other daemons
1147+
if let Some(ref record_consumer) = self.record_consumer_daemon {
1148+
info!("Stopping record consumer");
1149+
record_consumer.stop();
1150+
}
1151+
1152+
if let Some(ref processing_consumer) = self.processing_consumer_daemon {
1153+
info!("Stopping processing consumer");
1154+
processing_consumer.stop().await;
1155+
}
1156+
1157+
// Wait for all tasks to complete
9631158
for task in self.tasks {
9641159
match tokio::time::timeout(Duration::from_secs(5), task).await {
9651160
Ok(result) => {

0 commit comments

Comments
 (0)