Skip to content

Commit a8a6ea7

Browse files
committed
feat: formula validation before launch
1 parent 957a483 commit a8a6ea7

File tree

1 file changed

+214
-1
lines changed

1 file changed

+214
-1
lines changed

rust/src/config/utils.rs

Lines changed: 214 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use base64::Engine;
1212
use log::debug;
1313

1414
use super::{Config, USER_SESSION_SEPARATOR};
15+
use crate::utility::temperature_conversion::convert_voltage_to_temperature;
1516

1617
/// Output the embedded JSON schema to the console.
1718
///
@@ -67,7 +68,7 @@ pub fn is_valid_ip_address(addr: &str) -> bool {
6768
///
6869
/// This function performs deeper validation checks that can't be easily expressed in a JSON schema,
6970
/// such as verifying that certificate and key pairs are both present, validating base64 encoding
70-
/// of cryptographic material, and checking user password hashes.
71+
/// of cryptographic material, checking user password hashes, and testing temperature conversion formulas.
7172
///
7273
/// ### Arguments
7374
///
@@ -88,6 +89,8 @@ pub fn is_valid_ip_address(addr: &str) -> bool {
8889
/// - **IP Address Format**: Checks if the provided address is a valid IP address or special value
8990
/// - **User Credentials**: Validates that user password hashes are properly base64-encoded and follow
9091
/// the expected format from `openssl passwd`
92+
/// - **Temperature Formulas**: Tests temperature conversion formulas with sample voltages to ensure they
93+
/// work correctly with the `convert_voltage_to_temperature` function
9194
pub fn validate_specific_rules(config: &Config) -> Result<()> {
9295
debug!("Performing additional validation checks");
9396

@@ -167,5 +170,215 @@ pub fn validate_specific_rules(config: &Config) -> Result<()> {
167170
}
168171
}
169172

173+
// Validate temperature conversion formulas
174+
debug!("Validating temperature conversion formulas");
175+
176+
for regulator in &config.thermal_regulation.regulators {
177+
let formula = &regulator.temperature_conversion.formula;
178+
debug!(
179+
"Validating formula for regulator '{}': {}",
180+
regulator.name, formula
181+
);
182+
183+
// Test the formula with a few test voltages to ensure it works correctly
184+
let test_voltages = [1.0, 2.5, 4.0]; // Test voltages in volts
185+
186+
for &test_voltage in &test_voltages {
187+
match convert_voltage_to_temperature(formula.clone(), test_voltage) {
188+
Ok(temperature_k) => {
189+
debug!(
190+
"Formula validation for '{}': {}V -> {:.2}K ({:.2}°C)",
191+
regulator.name,
192+
test_voltage,
193+
temperature_k,
194+
temperature_k - 273.15
195+
);
196+
}
197+
Err(e) => {
198+
anyhow::bail!(
199+
"Temperature conversion formula validation failed for regulator '{}' at {}V: {}. Formula: '{}'",
200+
regulator.name,
201+
test_voltage,
202+
e,
203+
formula
204+
);
205+
}
206+
}
207+
}
208+
}
209+
170210
Ok(())
171211
}
212+
213+
#[cfg(test)]
214+
mod tests {
215+
use super::*;
216+
use crate::config::thermal_regulation::*;
217+
218+
/// Créer une configuration minimale pour tester la validation des formules
219+
fn create_test_config_with_formula(formula: &str) -> Config {
220+
use crate::config::*;
221+
use std::collections::HashMap;
222+
223+
let mut config = Config::default();
224+
225+
// Créer juste le minimum nécessaire pour le test
226+
let temp_conversion = TemperatureConversionConfig {
227+
formula: formula.to_string(),
228+
adc_resolution: 16,
229+
voltage_reference: 5.0,
230+
conversion_type: ConversionType::NtcThermistor,
231+
};
232+
233+
let temp_sensor = TemperatureSensorConfig {
234+
adc_address: 0x48,
235+
adc_channel: 0,
236+
sensor_type: TemperatureSensorType::ThermistorNtc,
237+
};
238+
239+
// Configuration minimale pour les actuateurs
240+
let thermal_control = ThermalControlConfig {
241+
pwm_controller: PwmChannelConfig {
242+
address: 0x40,
243+
channel: 0,
244+
},
245+
direction_controller: DirectionControllerConfig {
246+
address: 0x20,
247+
gpio_pins: HBridgeGpioPins {
248+
h_bridge_in1: 0,
249+
h_bridge_in2: 1,
250+
h_bridge_enable: 2,
251+
},
252+
},
253+
thermal_modes: ThermalModesConfig {
254+
heating_tec: ThermalModeConfig {
255+
description: "Heating via TEC".to_string(),
256+
h_bridge_direction: HBridgeDirection::Forward,
257+
power_range: "0-80%".to_string(),
258+
max_power_percent: 80.0,
259+
},
260+
cooling_tec: ThermalModeConfig {
261+
description: "Cooling via TEC".to_string(),
262+
h_bridge_direction: HBridgeDirection::Reverse,
263+
power_range: "0-80%".to_string(),
264+
max_power_percent: 80.0,
265+
},
266+
heating_resistive: ThermalModeConfig {
267+
description: "Heating via resistive element".to_string(),
268+
h_bridge_direction: HBridgeDirection::Forward,
269+
power_range: "0-100%".to_string(),
270+
max_power_percent: 100.0,
271+
},
272+
},
273+
};
274+
275+
let regulator = ThermalRegulatorConfig {
276+
id: "test_regulator".to_string(),
277+
name: "Test Regulator".to_string(),
278+
enabled: true,
279+
i2c_bus: "primary".to_string(),
280+
temperature_sensor: temp_sensor,
281+
actuators: ThermalActuatorsConfig { thermal_control },
282+
temperature_conversion: temp_conversion,
283+
pid_parameters: PidParameters {
284+
kp: 1.0,
285+
ki: 0.1,
286+
kd: 0.01,
287+
setpoint: 298.15,
288+
output_min: -100.0,
289+
output_max: 100.0,
290+
integral_max: 1000.0,
291+
settings: PidSettings::default(),
292+
},
293+
control_parameters: ControlParameters {
294+
sampling_frequency_hz: 1.0,
295+
pwm_frequency_hz: 1000.0,
296+
settings: ControlSettings::default(),
297+
},
298+
safety_limits: SafetyLimits {
299+
min_temperature_k: 273.15,
300+
max_temperature_k: 373.15,
301+
max_heating_duty: 80.0,
302+
max_cooling_duty: 80.0,
303+
emergency_settings: EmergencySettings::default(),
304+
},
305+
};
306+
307+
let mut i2c_buses = HashMap::new();
308+
i2c_buses.insert(
309+
"primary".to_string(),
310+
I2CBusConfig {
311+
bus_type: I2CBusType::Mock,
312+
device: "/dev/i2c-1".to_string(),
313+
usb_vendor_id: None,
314+
usb_product_id: None,
315+
pwm_controllers: vec![],
316+
adc_controllers: vec![],
317+
gpio_controllers: vec![],
318+
bus_settings: I2CBusSettings::default(),
319+
},
320+
);
321+
322+
config.thermal_regulation = ThermalRegulationConfig {
323+
enabled: true,
324+
i2c_buses,
325+
regulators: vec![regulator],
326+
global_settings: GlobalThermalSettings::default(),
327+
};
328+
329+
config
330+
}
331+
332+
#[test]
333+
fn test_validate_temperature_formula_valid() {
334+
// Test avec une formule valide NTC
335+
let formula = "1.0 / (1.0 / 298.15 + math::ln(10000.0 * voltage / (5.0 - voltage) / 10000.0) / 3977.0)";
336+
let config = create_test_config_with_formula(formula);
337+
338+
// La validation devrait réussir
339+
assert!(validate_specific_rules(&config).is_ok());
340+
}
341+
342+
#[test]
343+
fn test_validate_temperature_formula_invalid() {
344+
// Test avec une formule invalide
345+
let formula = "invalid_formula_without_voltage";
346+
let config = create_test_config_with_formula(formula);
347+
348+
// La validation devrait échouer
349+
assert!(validate_specific_rules(&config).is_err());
350+
}
351+
352+
#[test]
353+
fn test_validate_temperature_formula_no_voltage() {
354+
// Test avec une formule qui ne contient pas 'voltage'
355+
let formula = "273.15 + 10.0"; // Formule sans variable voltage
356+
let config = create_test_config_with_formula(formula);
357+
358+
// La validation devrait échouer
359+
let result = validate_specific_rules(&config);
360+
assert!(result.is_err());
361+
assert!(result.unwrap_err().to_string().contains("voltage"));
362+
}
363+
364+
#[test]
365+
fn test_validate_temperature_formula_malformed() {
366+
// Test avec une formule malformée
367+
let formula = "1.0 / (1.0 / 298.15 + math::ln(10000.0 * voltage / (5.0 - voltage) / 10000.0) / 3977.0"; // Parenthèse manquante
368+
let config = create_test_config_with_formula(formula);
369+
370+
// La validation devrait échouer
371+
let result = validate_specific_rules(&config);
372+
assert!(result.is_err());
373+
}
374+
375+
#[test]
376+
fn test_validate_temperature_formula_simple_linear() {
377+
// Test avec une formule linéaire simple
378+
let formula = "273.15 + voltage * 10.0";
379+
let config = create_test_config_with_formula(formula);
380+
381+
// La validation devrait réussir
382+
assert!(validate_specific_rules(&config).is_ok());
383+
}
384+
}

0 commit comments

Comments
 (0)