@@ -12,6 +12,7 @@ use base64::Engine;
1212use log:: debug;
1313
1414use 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
9194pub 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