regain_core/
camera_options.rs1use crate::RecoveryOptions;
3use anyhow::Result;
4use serde::{Deserialize, Serialize};
5use std::sync::{Arc, Mutex};
6
7#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
8#[serde(rename_all = "camelCase", deny_unknown_fields)]
9pub struct CameraRuntimeOptions {
10 pub transfer_log_mode: String,
11 pub cooler_max_power_change_per_5_seconds: f64,
12}
13impl CameraRuntimeOptions {
14 pub fn from_recovery(options: &RecoveryOptions) -> Self {
15 Self {
16 transfer_log_mode: options.transfer_log_mode.clone(),
17 cooler_max_power_change_per_5_seconds: options.cooler_max_power_change_per_5_seconds,
18 }
19 }
20 pub fn validate(&self) -> Result<()> {
21 let mut recovery = RecoveryOptions::default();
22 self.apply(&mut recovery);
23 recovery.validate()
24 }
25 pub fn apply(&self, recovery: &mut RecoveryOptions) {
26 recovery
27 .transfer_log_mode
28 .clone_from(&self.transfer_log_mode);
29 recovery.cooler_max_power_change_per_5_seconds = self.cooler_max_power_change_per_5_seconds;
30 }
31}
32#[derive(Clone)]
33pub struct CameraRuntimeHandle(Arc<Mutex<CameraRuntimeOptions>>);
34impl CameraRuntimeHandle {
35 pub(crate) fn new(options: &RecoveryOptions) -> Self {
36 Self(Arc::new(Mutex::new(CameraRuntimeOptions::from_recovery(
37 options,
38 ))))
39 }
40 pub fn get(&self) -> CameraRuntimeOptions {
41 self.0.lock().unwrap().clone()
42 }
43 pub fn update(&self, options: CameraRuntimeOptions) -> Result<()> {
44 options.validate()?;
45 *self.0.lock().unwrap() = options;
46 Ok(())
47 }
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53 #[test]
54 fn live_controls_are_shared_with_one_owner_and_invalid_changes_are_inert() {
55 let recovery = RecoveryOptions::default();
56 let first = CameraRuntimeHandle::new(&recovery);
57 let owner = first.clone();
58 let second = CameraRuntimeHandle::new(&recovery);
59 let mut options = first.get();
60 options.transfer_log_mode = "off".into();
61 options.cooler_max_power_change_per_5_seconds = 5.0;
62 first.update(options.clone()).unwrap();
63 assert_eq!(owner.get(), options);
64 assert_eq!(second.get(), CameraRuntimeOptions::from_recovery(&recovery));
65 for invalid in [0.0, f64::NAN, 101.0] {
66 let mut bad = options.clone();
67 bad.cooler_max_power_change_per_5_seconds = invalid;
68 assert!(first.update(bad).is_err());
69 assert_eq!(owner.get(), options);
70 }
71 let mut bad = options.clone();
72 bad.transfer_log_mode = "anything".into();
73 assert!(first.update(bad).is_err());
74 assert_eq!(owner.get(), options);
75 }
76}