1
0

3 Коміти 7b34880229 ... cf75b3bcf4

Автор SHA1 Опис Дата
  Kevin Lee cf75b3bcf4 Add upper bound on randomization attempts 10 місяців тому
  Kevin Lee 19aa6c19f8 Validate randomized pen settings 10 місяців тому
  Kevin Lee 914d7bc01a Add pen setting validation 10 місяців тому
4 змінених файлів з 187 додано та 38 видалено
  1. 1 1
      README.md
  2. 92 36
      src/config/pen.rs
  3. 50 1
      src/ezcad/pen.rs
  4. 44 0
      src/ezcad/types.rs

+ 1 - 1
README.md

@@ -95,7 +95,7 @@ Op:
     Speed: [100, 1000, 100] # [min, max, step]
     Power: [10, 100, 5] # [min, max, step]
     Frequency: [20000, 100000, 1000] # [min, max, step]
-    PulseWidth: [2, 250, 2] # [min, max, step]
+    PulseWidth: [2, 350, 2] # [min, max, step]
 ```
 
 Exporting a pen to a file:

+ 92 - 36
src/config/pen.rs

@@ -106,6 +106,7 @@ impl PatchPen {
         debug!("Patching pen #{}", self.pen);
         let pen: &mut Pen = pens.get_mut(self.pen).expect("Invalid pen index");
         self.patch.patch(pen);
+        pen.valid_settings();
     }
 }
 
@@ -290,6 +291,8 @@ impl PatternField {
 
             // Always enable custom settings for pen
             *dst.use_default = 0;
+
+            dst.valid_settings();
         }
     }
 }
@@ -319,6 +322,30 @@ impl PatternPen {
     }
 }
 
+#[derive(Copy, Clone, Default, PartialEq)]
+struct RandomizedSetting {
+    speed: Option<f64>,
+    power: Option<f64>,
+    frequency: Option<u32>,
+    pulse_width: Option<PulseWidth>,
+}
+
+impl RandomizedSetting {
+    fn apply(&self, pen: &mut Pen) {
+        self.speed.map(|speed| *pen.speed = speed);
+        self.power.map(|power| *pen.power = power);
+        self.frequency.map(|freq| {
+            *pen.frequency = freq;
+            *pen.frequency_2 = freq.try_into().unwrap();
+        });
+        self.pulse_width.map(|pw| {
+            let pw: u32 = pw.into();
+            *pen.pulse_width = pw;
+            *pen.pulse_width_2 = pw.try_into().unwrap();
+        });
+    }
+}
+
 #[derive(Debug, Serialize, Deserialize)]
 #[serde(rename_all = "PascalCase")]
 pub struct RandomizePen {
@@ -338,53 +365,82 @@ impl RandomizePen {
             self.index + self.count - 1
         );
 
+        let mut generated: Vec<RandomizedSetting> = vec![];
+        const MAX_ATTEMPTS: usize = 1000;
+
         for (index, pen) in pens
             .iter_mut()
             .skip(self.index)
             .take(self.count)
             .enumerate()
         {
-            if let Some((min, max, step)) = self.speed {
-                let offset: usize = rand::thread_rng().gen_range(0..=((max - min) / step) as usize);
-                let value: f64 = min + step * offset as f64;
-                debug!("Randomizing speed for pen #{} to {}", index, value);
-                *pen.speed = value;
-            }
+            for attempt in 0..=MAX_ATTEMPTS {
+                let mut setting: RandomizedSetting = RandomizedSetting::default();
+
+                if let Some((min, max, step)) = self.speed {
+                    let offset: usize =
+                        rand::thread_rng().gen_range(0..=((max - min) / step) as usize);
+                    let value: f64 = min + step * offset as f64;
+                    debug!("Randomizing speed for pen #{} to {}", index, value);
+                    setting.speed = Some(value);
+                }
 
-            if let Some((min, max, step)) = self.power {
-                let offset: usize = rand::thread_rng().gen_range(0..=((max - min) / step) as usize);
-                let value: f64 = min + step * offset as f64;
-                debug!("Randomizing power for pen #{} to {}", index, value);
-                *pen.power = value;
-            }
+                if let Some((min, max, step)) = self.power {
+                    let offset: usize =
+                        rand::thread_rng().gen_range(0..=((max - min) / step) as usize);
+                    let value: f64 = min + step * offset as f64;
+                    debug!("Randomizing power for pen #{} to {}", index, value);
+                    setting.power = Some(value);
+                }
 
-            if let Some((min, max, step)) = self.frequency {
-                let offset: usize = rand::thread_rng().gen_range(0..=((max - min) / step) as usize);
-                let value: u32 = min + step * offset as u32;
-                debug!("Randomizing frequency for pen #{} to {}", index, value);
-                *pen.frequency = value;
-                *pen.frequency_2 = value.try_into().unwrap();
-            }
+                if let Some((min, max, step)) = self.frequency {
+                    let offset: usize =
+                        rand::thread_rng().gen_range(0..=((max - min) / step) as usize);
+                    let value: u32 = min + step * offset as u32;
+                    debug!("Randomizing frequency for pen #{} to {}", index, value);
+                    setting.frequency = Some(value);
+                }
 
-            if let Some((min, max, step)) = self.pulse_width {
-                let mut pw = PulseWidth::iter();
-                let mut values: Vec<PulseWidth> = vec![pw.find(|x| *x == min).unwrap()];
-                values.extend(
-                    pw.skip(step - 1)
-                        .step_by(step)
-                        .take_while_inclusive(|x| *x != max)
-                        .collect_vec(),
-                );
+                if let Some((min, max, step)) = self.pulse_width {
+                    let mut pw = PulseWidth::iter();
+                    let mut values: Vec<PulseWidth> = vec![pw.find(|x| *x == min).unwrap()];
+                    values.extend(
+                        pw.skip(step - 1)
+                            .step_by(step)
+                            .take_while_inclusive(|x| *x != max)
+                            .collect_vec(),
+                    );
 
-                let width: &PulseWidth = values
-                    .choose_multiple(&mut rand::thread_rng(), 1)
-                    .next()
-                    .unwrap();
-                let value: u32 = (*width).into();
-                debug!("Randomizing pulse width for pen #{} to {}", index, value);
-                *pen.pulse_width = value;
-                *pen.pulse_width_2 = value.try_into().unwrap();
+                    let width: &PulseWidth = values
+                        .choose_multiple(&mut rand::thread_rng(), 1)
+                        .next()
+                        .unwrap();
+                    let value: u32 = (*width).into();
+                    debug!("Randomizing pulse width for pen #{} to {}", index, value);
+                    setting.pulse_width = Some(*width);
+                }
+
+                if !generated.contains(&setting) {
+                    generated.push(setting);
+                    setting.apply(pen);
+                    if !pen.valid_settings() {
+                        debug!("Retrying..");
+                    } else {
+                        break;
+                    }
+                } else {
+                    debug!("Duplicate random setting");
+                }
+
+                if attempt == MAX_ATTEMPTS {
+                    panic!(
+                        "Exceeded maximum number of {} randommization attempts",
+                        MAX_ATTEMPTS
+                    );
+                }
             }
+
+            pen.valid_settings();
         }
     }
 }

+ 50 - 1
src/ezcad/pen.rs

@@ -7,10 +7,11 @@ use std::{
 
 use binrw::{BinRead, BinWrite, BinWriterExt, FilePtr64};
 use diff::Diff;
+use log::{error, warn};
 
 use crate::{
     field_of::FieldOf,
-    types::{Bool, Field, Rgba, WString, WobbleType, F64, U32},
+    types::{Bool, Field, PulseWidth, Rgba, WString, WobbleType, F64, U32},
 };
 
 #[derive(BinRead, Debug)]
@@ -120,6 +121,54 @@ impl Pen {
             .write_all(buffer.into_inner().as_slice())
             .expect("Failed to write to output file");
     }
+
+    pub fn valid_settings(&self) -> bool {
+        let mut ret: bool = true;
+
+        if *self.frequency != *self.frequency_2 as u32 {
+            error!(
+                "Mismatch pen internal frequency setting: ({}, {:.3})",
+                *self.frequency, *self.frequency_2
+            );
+            ret = false;
+        }
+
+        if *self.pulse_width != *self.pulse_width_2 as u32 {
+            error!(
+                "Mismatch pen internal pulse width setting: ({}, {:.3})",
+                *self.pulse_width, *self.pulse_width_2
+            );
+            ret = false;
+        }
+
+        match PulseWidth::try_from(*self.pulse_width) {
+            Ok(pw) => match *self.frequency {
+                freq if freq < pw.min_freq() => {
+                    warn!(
+                        "Pen frequency of {} lower than pulse width minimum frequency of {}",
+                        *self.frequency,
+                        pw.min_freq()
+                    );
+                    ret = false;
+                }
+                freq if freq > pw.max_freq() => {
+                    warn!(
+                        "Pen frequency of {} higher than pulse width maximum frequency of {}",
+                        *self.frequency,
+                        pw.max_freq()
+                    );
+                    ret = false;
+                }
+                _ => (),
+            },
+            Err(_) => {
+                warn!("Invalid pen pulse width value: {}", *self.pulse_width);
+                ret = false;
+            }
+        }
+
+        ret
+    }
 }
 
 // Custom Debug implementation to only print known fields

+ 44 - 0
src/ezcad/types.rs

@@ -291,3 +291,47 @@ pub enum PulseWidth {
     Ns350 = 350,
     Ns500 = 500,
 }
+
+impl PulseWidth {
+    pub fn min_freq(&self) -> u32 {
+        match self {
+            PulseWidth::Ns2 => 850_000,
+            PulseWidth::Ns4 => 500_000,
+            PulseWidth::Ns6 => 320_000,
+            PulseWidth::Ns8 => 250_000,
+            PulseWidth::Ns12 => 170_000,
+            PulseWidth::Ns20 => 115_000,
+            PulseWidth::Ns30 => 90_000,
+            PulseWidth::Ns45 => 75_000,
+            PulseWidth::Ns60 => 65_000,
+            PulseWidth::Ns80 => 60_000,
+            PulseWidth::Ns100 => 45_000,
+            PulseWidth::Ns150 => 30_000,
+            PulseWidth::Ns200 => 25_000,
+            PulseWidth::Ns250 => 25_000,
+            PulseWidth::Ns350 => 25_000,
+            PulseWidth::Ns500 => 25_000,
+        }
+    }
+
+    pub fn max_freq(&self) -> u32 {
+        match self {
+            PulseWidth::Ns2 => 4_000_000,
+            PulseWidth::Ns4 => 4_000_000,
+            PulseWidth::Ns6 => 4_000_000,
+            PulseWidth::Ns8 => 4_000_000,
+            PulseWidth::Ns12 => 3_000_000,
+            PulseWidth::Ns20 => 3_000_000,
+            PulseWidth::Ns30 => 3_000_000,
+            PulseWidth::Ns45 => 2_000_000,
+            PulseWidth::Ns60 => 2_000_000,
+            PulseWidth::Ns80 => 2_000_000,
+            PulseWidth::Ns100 => 1_000_000,
+            PulseWidth::Ns150 => 1_000_000,
+            PulseWidth::Ns200 => 1_000_000,
+            PulseWidth::Ns250 => 900_000,
+            PulseWidth::Ns350 => 600_000,
+            PulseWidth::Ns500 => 500_000,
+        }
+    }
+}