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,
+        }
+    }
+}