diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_attiny85.ino b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_attiny85.ino
new file mode 100644
index 0000000..c29dcdc
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_attiny85.ino
@@ -0,0 +1,55 @@
+#include <SoftwareSerial.h>
+
+#define RX    3   // *** D3, Pin 2
+#define TX    4   // *** D4, Pin 3
+SoftwareSerial Serial(RX, TX);
+
+void setup() {
+  Serial.begin(9600);
+  Serial.println(" ");
+  Serial.println("Initializing...");
+  randomSeed(analogRead(0));  // Seed the random number generator for more randomness
+  delay(2000);  // Delay for initialization
+}
+
+void loop() {
+  // Generate one random number and assign it to both variables
+  volatile int originalNumber = random(10, 100);  
+  volatile int num1 = originalNumber;
+  volatile int num2 = originalNumber;
+
+  // Perform reversible operations to increase glitch susceptibility but keep values comparable
+  num1 = num1 ^ 0x55;  // XOR num1 with 0x55
+  num2 = num2 ^ 0x55;  // XOR num2 with 0x55
+  
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  // Extract the first and second digits
+  volatile int num1FirstDigit = num1 / 10;   // Get the first digit of num1
+  volatile int num1SecondDigit = num1 % 10;  // Get the second digit of num1
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  // Check if the numbers still match after the potential glitch
+  int match = 0;
+  if (num1FirstDigit == num2FirstDigit) {
+    if (num1SecondDigit == num2SecondDigit) {
+       match = 1;
+    }
+  }
+  
+  if (match == 1) {
+    Serial.print("Numbers match: "); Serial.print(num1); Serial.print(" "); Serial.print(num2); Serial.print("\r");
+  } else {
+    Serial.print("Glitch detected! Numbers do not match: ");
+    Serial.print(num1); Serial.print(" "); Serial.print(num2);
+    Serial.print(" ("); Serial.print(num1FirstDigit); Serial.print(":"); Serial.print(num1SecondDigit); Serial.print(") ");
+    Serial.print("("); Serial.print(num2FirstDigit); Serial.print(":"); Serial.print(num2SecondDigit); Serial.println(")");
+    Serial.println(" ");
+  }
+  
+  delay(100);  // Shorter delay to increase glitch detection chances
+}
+

diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_attiny85.ino b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_attiny85.ino
new file mode 100644
index 0000000..c29dcdc
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_attiny85.ino
@@ -0,0 +1,55 @@
+#include <SoftwareSerial.h>
+
+#define RX    3   // *** D3, Pin 2
+#define TX    4   // *** D4, Pin 3
+SoftwareSerial Serial(RX, TX);
+
+void setup() {
+  Serial.begin(9600);
+  Serial.println(" ");
+  Serial.println("Initializing...");
+  randomSeed(analogRead(0));  // Seed the random number generator for more randomness
+  delay(2000);  // Delay for initialization
+}
+
+void loop() {
+  // Generate one random number and assign it to both variables
+  volatile int originalNumber = random(10, 100);  
+  volatile int num1 = originalNumber;
+  volatile int num2 = originalNumber;
+
+  // Perform reversible operations to increase glitch susceptibility but keep values comparable
+  num1 = num1 ^ 0x55;  // XOR num1 with 0x55
+  num2 = num2 ^ 0x55;  // XOR num2 with 0x55
+  
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  // Extract the first and second digits
+  volatile int num1FirstDigit = num1 / 10;   // Get the first digit of num1
+  volatile int num1SecondDigit = num1 % 10;  // Get the second digit of num1
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  // Check if the numbers still match after the potential glitch
+  int match = 0;
+  if (num1FirstDigit == num2FirstDigit) {
+    if (num1SecondDigit == num2SecondDigit) {
+       match = 1;
+    }
+  }
+  
+  if (match == 1) {
+    Serial.print("Numbers match: "); Serial.print(num1); Serial.print(" "); Serial.print(num2); Serial.print("\r");
+  } else {
+    Serial.print("Glitch detected! Numbers do not match: ");
+    Serial.print(num1); Serial.print(" "); Serial.print(num2);
+    Serial.print(" ("); Serial.print(num1FirstDigit); Serial.print(":"); Serial.print(num1SecondDigit); Serial.print(") ");
+    Serial.print("("); Serial.print(num2FirstDigit); Serial.print(":"); Serial.print(num2SecondDigit); Serial.println(")");
+    Serial.println(" ");
+  }
+  
+  delay(100);  // Shorter delay to increase glitch detection chances
+}
+
diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch.py b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch.py
new file mode 100644
index 0000000..cb08065
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch.py
@@ -0,0 +1,9 @@
+from scope import Scope
+import time
+
+s = Scope()
+s.glitch.repeat = 4
+s.glitch.ext_offset = 10
+
+for _ in range(50000):
+    s.trigger()

diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_attiny85.ino b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_attiny85.ino
new file mode 100644
index 0000000..c29dcdc
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_attiny85.ino
@@ -0,0 +1,55 @@
+#include <SoftwareSerial.h>
+
+#define RX    3   // *** D3, Pin 2
+#define TX    4   // *** D4, Pin 3
+SoftwareSerial Serial(RX, TX);
+
+void setup() {
+  Serial.begin(9600);
+  Serial.println(" ");
+  Serial.println("Initializing...");
+  randomSeed(analogRead(0));  // Seed the random number generator for more randomness
+  delay(2000);  // Delay for initialization
+}
+
+void loop() {
+  // Generate one random number and assign it to both variables
+  volatile int originalNumber = random(10, 100);  
+  volatile int num1 = originalNumber;
+  volatile int num2 = originalNumber;
+
+  // Perform reversible operations to increase glitch susceptibility but keep values comparable
+  num1 = num1 ^ 0x55;  // XOR num1 with 0x55
+  num2 = num2 ^ 0x55;  // XOR num2 with 0x55
+  
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  // Extract the first and second digits
+  volatile int num1FirstDigit = num1 / 10;   // Get the first digit of num1
+  volatile int num1SecondDigit = num1 % 10;  // Get the second digit of num1
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  // Check if the numbers still match after the potential glitch
+  int match = 0;
+  if (num1FirstDigit == num2FirstDigit) {
+    if (num1SecondDigit == num2SecondDigit) {
+       match = 1;
+    }
+  }
+  
+  if (match == 1) {
+    Serial.print("Numbers match: "); Serial.print(num1); Serial.print(" "); Serial.print(num2); Serial.print("\r");
+  } else {
+    Serial.print("Glitch detected! Numbers do not match: ");
+    Serial.print(num1); Serial.print(" "); Serial.print(num2);
+    Serial.print(" ("); Serial.print(num1FirstDigit); Serial.print(":"); Serial.print(num1SecondDigit); Serial.print(") ");
+    Serial.print("("); Serial.print(num2FirstDigit); Serial.print(":"); Serial.print(num2SecondDigit); Serial.println(")");
+    Serial.println(" ");
+  }
+  
+  delay(100);  // Shorter delay to increase glitch detection chances
+}
+
diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch.py b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch.py
new file mode 100644
index 0000000..cb08065
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch.py
@@ -0,0 +1,9 @@
+from scope import Scope
+import time
+
+s = Scope()
+s.glitch.repeat = 4
+s.glitch.ext_offset = 10
+
+for _ in range(50000):
+    s.trigger()
diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch_work.png b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch_work.png
new file mode 100644
index 0000000..4f7fe86
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch_work.png
Binary files differ

diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_attiny85.ino b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_attiny85.ino
new file mode 100644
index 0000000..c29dcdc
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_attiny85.ino
@@ -0,0 +1,55 @@
+#include <SoftwareSerial.h>
+
+#define RX    3   // *** D3, Pin 2
+#define TX    4   // *** D4, Pin 3
+SoftwareSerial Serial(RX, TX);
+
+void setup() {
+  Serial.begin(9600);
+  Serial.println(" ");
+  Serial.println("Initializing...");
+  randomSeed(analogRead(0));  // Seed the random number generator for more randomness
+  delay(2000);  // Delay for initialization
+}
+
+void loop() {
+  // Generate one random number and assign it to both variables
+  volatile int originalNumber = random(10, 100);  
+  volatile int num1 = originalNumber;
+  volatile int num2 = originalNumber;
+
+  // Perform reversible operations to increase glitch susceptibility but keep values comparable
+  num1 = num1 ^ 0x55;  // XOR num1 with 0x55
+  num2 = num2 ^ 0x55;  // XOR num2 with 0x55
+  
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  // Extract the first and second digits
+  volatile int num1FirstDigit = num1 / 10;   // Get the first digit of num1
+  volatile int num1SecondDigit = num1 % 10;  // Get the second digit of num1
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  // Check if the numbers still match after the potential glitch
+  int match = 0;
+  if (num1FirstDigit == num2FirstDigit) {
+    if (num1SecondDigit == num2SecondDigit) {
+       match = 1;
+    }
+  }
+  
+  if (match == 1) {
+    Serial.print("Numbers match: "); Serial.print(num1); Serial.print(" "); Serial.print(num2); Serial.print("\r");
+  } else {
+    Serial.print("Glitch detected! Numbers do not match: ");
+    Serial.print(num1); Serial.print(" "); Serial.print(num2);
+    Serial.print(" ("); Serial.print(num1FirstDigit); Serial.print(":"); Serial.print(num1SecondDigit); Serial.print(") ");
+    Serial.print("("); Serial.print(num2FirstDigit); Serial.print(":"); Serial.print(num2SecondDigit); Serial.println(")");
+    Serial.println(" ");
+  }
+  
+  delay(100);  // Shorter delay to increase glitch detection chances
+}
+
diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch.py b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch.py
new file mode 100644
index 0000000..cb08065
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch.py
@@ -0,0 +1,9 @@
+from scope import Scope
+import time
+
+s = Scope()
+s.glitch.repeat = 4
+s.glitch.ext_offset = 10
+
+for _ in range(50000):
+    s.trigger()
diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch_work.png b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch_work.png
new file mode 100644
index 0000000..4f7fe86
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch_work.png
Binary files differ
diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_attiny85.ino b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_attiny85.ino
new file mode 100644
index 0000000..68beb08
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_attiny85.ino
@@ -0,0 +1,72 @@
+#include <SoftwareSerial.h>
+
+#define RX    3   // *** D3, Pin 2
+#define TX    4   // *** D4, Pin 3
+SoftwareSerial Serial(RX, TX);
+
+const String correctPassword = "secure123";  // Hardcoded password
+String inputString = "";                     // Variable to hold user input
+bool stringComplete = false;                 // Flag to indicate when a string is complete
+bool loggedIn = false;
+
+void setup() {
+  Serial.begin(9600);
+  Serial.println(" ");
+  Serial.println("Initializing...");
+  delay(200);  // Delay for initialization
+  Serial.print("[-]> ");
+}
+
+void prompt(){
+  // Reset for the next input without checking password
+  inputString = "";
+  stringComplete = false;
+  if(loggedIn == false){
+    Serial.print("[-]"); // not logged in 
+  }else{
+    Serial.print("[+]"); // logged in
+  }
+  Serial.print("> ");
+}
+
+void loop() {
+  // If the string is complete, process the input
+  if (stringComplete) {
+    // Glitch-prone section: making the comparison more complex and glitch-susceptible
+    volatile bool match = false;  // Using 'volatile' to increase glitch vulnerability
+        
+    // Check if input is "ping"
+    if (inputString == "ping") {
+      Serial.println("pong");  // Respond with "pong" if input is "ping"
+      prompt();
+      return;  // Exit the loop to avoid further processing (no "Password incorrect!" after "pong")
+    }
+    // Now compare the user input with the hardcoded password, but with timing window
+    else if (inputString == correctPassword) {
+      match = true;  // Passwords match
+    }
+
+    // Add a chance for glitches to affect this critical condition
+    if (match) {
+      Serial.println("Password correct!");
+      loggedIn = true;
+    } else {
+      Serial.println("Password incorrect!");
+    }
+    prompt();
+  }
+
+  // Listen for input from the user
+  while (Serial.available()) {
+    char inChar = (char)Serial.read();  // Read the incoming character
+    
+    // Check if it is the return character (indicating the end of input)
+    if (inChar == '\r' || inChar == '\n') {
+      stringComplete = true;
+    } else {
+      // Append the character to the input string
+      inputString += inChar;
+    }
+  }
+}
+

diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_attiny85.ino b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_attiny85.ino
new file mode 100644
index 0000000..c29dcdc
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_attiny85.ino
@@ -0,0 +1,55 @@
+#include <SoftwareSerial.h>
+
+#define RX    3   // *** D3, Pin 2
+#define TX    4   // *** D4, Pin 3
+SoftwareSerial Serial(RX, TX);
+
+void setup() {
+  Serial.begin(9600);
+  Serial.println(" ");
+  Serial.println("Initializing...");
+  randomSeed(analogRead(0));  // Seed the random number generator for more randomness
+  delay(2000);  // Delay for initialization
+}
+
+void loop() {
+  // Generate one random number and assign it to both variables
+  volatile int originalNumber = random(10, 100);  
+  volatile int num1 = originalNumber;
+  volatile int num2 = originalNumber;
+
+  // Perform reversible operations to increase glitch susceptibility but keep values comparable
+  num1 = num1 ^ 0x55;  // XOR num1 with 0x55
+  num2 = num2 ^ 0x55;  // XOR num2 with 0x55
+  
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  // Extract the first and second digits
+  volatile int num1FirstDigit = num1 / 10;   // Get the first digit of num1
+  volatile int num1SecondDigit = num1 % 10;  // Get the second digit of num1
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  // Check if the numbers still match after the potential glitch
+  int match = 0;
+  if (num1FirstDigit == num2FirstDigit) {
+    if (num1SecondDigit == num2SecondDigit) {
+       match = 1;
+    }
+  }
+  
+  if (match == 1) {
+    Serial.print("Numbers match: "); Serial.print(num1); Serial.print(" "); Serial.print(num2); Serial.print("\r");
+  } else {
+    Serial.print("Glitch detected! Numbers do not match: ");
+    Serial.print(num1); Serial.print(" "); Serial.print(num2);
+    Serial.print(" ("); Serial.print(num1FirstDigit); Serial.print(":"); Serial.print(num1SecondDigit); Serial.print(") ");
+    Serial.print("("); Serial.print(num2FirstDigit); Serial.print(":"); Serial.print(num2SecondDigit); Serial.println(")");
+    Serial.println(" ");
+  }
+  
+  delay(100);  // Shorter delay to increase glitch detection chances
+}
+
diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch.py b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch.py
new file mode 100644
index 0000000..cb08065
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch.py
@@ -0,0 +1,9 @@
+from scope import Scope
+import time
+
+s = Scope()
+s.glitch.repeat = 4
+s.glitch.ext_offset = 10
+
+for _ in range(50000):
+    s.trigger()
diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch_work.png b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch_work.png
new file mode 100644
index 0000000..4f7fe86
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch_work.png
Binary files differ
diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_attiny85.ino b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_attiny85.ino
new file mode 100644
index 0000000..68beb08
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_attiny85.ino
@@ -0,0 +1,72 @@
+#include <SoftwareSerial.h>
+
+#define RX    3   // *** D3, Pin 2
+#define TX    4   // *** D4, Pin 3
+SoftwareSerial Serial(RX, TX);
+
+const String correctPassword = "secure123";  // Hardcoded password
+String inputString = "";                     // Variable to hold user input
+bool stringComplete = false;                 // Flag to indicate when a string is complete
+bool loggedIn = false;
+
+void setup() {
+  Serial.begin(9600);
+  Serial.println(" ");
+  Serial.println("Initializing...");
+  delay(200);  // Delay for initialization
+  Serial.print("[-]> ");
+}
+
+void prompt(){
+  // Reset for the next input without checking password
+  inputString = "";
+  stringComplete = false;
+  if(loggedIn == false){
+    Serial.print("[-]"); // not logged in 
+  }else{
+    Serial.print("[+]"); // logged in
+  }
+  Serial.print("> ");
+}
+
+void loop() {
+  // If the string is complete, process the input
+  if (stringComplete) {
+    // Glitch-prone section: making the comparison more complex and glitch-susceptible
+    volatile bool match = false;  // Using 'volatile' to increase glitch vulnerability
+        
+    // Check if input is "ping"
+    if (inputString == "ping") {
+      Serial.println("pong");  // Respond with "pong" if input is "ping"
+      prompt();
+      return;  // Exit the loop to avoid further processing (no "Password incorrect!" after "pong")
+    }
+    // Now compare the user input with the hardcoded password, but with timing window
+    else if (inputString == correctPassword) {
+      match = true;  // Passwords match
+    }
+
+    // Add a chance for glitches to affect this critical condition
+    if (match) {
+      Serial.println("Password correct!");
+      loggedIn = true;
+    } else {
+      Serial.println("Password incorrect!");
+    }
+    prompt();
+  }
+
+  // Listen for input from the user
+  while (Serial.available()) {
+    char inChar = (char)Serial.read();  // Read the incoming character
+    
+    // Check if it is the return character (indicating the end of input)
+    if (inChar == '\r' || inChar == '\n') {
+      stringComplete = true;
+    } else {
+      // Append the character to the input string
+      inputString += inChar;
+    }
+  }
+}
+
diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_glitch.py b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_glitch.py
new file mode 100644
index 0000000..69f7b0b
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_glitch.py
@@ -0,0 +1,159 @@
+import sys
+import time
+import pexpect  # Required to handle screen sessions
+import threading
+import argparse  # Import argparse for command-line arguments
+from scope import Scope
+ 
+DEFAULT_COMPORT = "/dev/ttyACM0"
+SCREEN_NAME = "ttyUSB0_screen"  # Replace this with the actual screen session name (screen -S tty_USB0_screen /dev/ttyUSB0 9800)
+ 
+# Argument parser for command-line arguments
+parser = argparse.ArgumentParser(description="Fault injection script with configurable parameters.")
+parser.add_argument("-g", "--glitch_repeat", type=int, default=4, dest="glitch_repeat", help="Number of times to repeat the glitch.")
+parser.add_argument("-p", "--pulse_sleep", type=float, default=0.05, dest="pulse_sleep", help="Sleep time between sending commands and triggering pulse.")
+parser.add_argument("-m", "--max_iterations", type=int, default=5, dest="max_iterations", help="Maximum number of attack iterations.")
+
+args = parser.parse_args()
+
+# Configure scope based on command-line argument
+s = Scope()
+s.glitch.repeat = args.glitch_repeat
+# Shared variable to store the response from the device
+device_response = None
+child = None  # Global child variable
+ 
+def initialize_child():
+    """Initialise the global child process for the screen session."""
+    global child
+    child = pexpect.spawn(f'screen -x {SCREEN_NAME}', encoding='utf-8')
+    child.expect(pexpect.TIMEOUT, timeout=1)  # Clear out any pre-existing buffer
+ 
+def send_test_message_and_read_response():
+    """Send 'ping' via screen to a serial device and check for 'correct!\n' or 'incorrect\n'."""
+    global child
+ 
+    # Send 'ping' to the screen session
+    child.sendline("ping")
+    sys.stdout.write("\rSent 'ping' to screen session.")
+    sys.stdout.flush()
+ 
+    # Wait a bit to ensure the command is processed
+    time.sleep(0.5)  
+ 
+    # Try reading any new output from the screen session
+    try:
+        response = child.read_nonblocking(size=1024, timeout=2)  # Read up to 1024 bytes of new data
+        if "pong" in response:
+            sys.stdout.write("\rReceived 'pong' response.")
+            return True
+        else:
+            sys.stdout.write(f"\rReceived unexpected response: {response}")
+        sys.stdout.flush()
+    except pexpect.exceptions.TIMEOUT:
+        sys.stdout.write("\rNo response received from the screen session (timeout).")
+        sys.stdout.flush()
+ 
+    return False
+ 
+def read_screen_output():
+    """Read output from the screen session in a separate thread."""
+    global device_response
+    buffer = ""  # Initialize a buffer to store incoming characters
+ 
+    try:
+        while True:
+            response = child.read_nonblocking(size=1024, timeout=2)  # Read up to 1024 bytes of new data
+            buffer += response  # Append the new response to the buffer
+            
+            # Check if there's a complete line in the buffer
+            while "\n" in buffer:
+                line, buffer = buffer.split("\n", 1)  # Split the buffer at the first newline
+                line = line.strip()  # Remove any leading/trailing whitespace
+ 
+                # Check for specific responses
+                if "incorrect!" in line:
+                    device_response = 'incorrect'
+                    return  # Exit the loop on incorrect response
+                elif "correct" in line:
+                    # Die here: Echo message, disarm device, and kill the program
+                    sys.stdout.write("\nReceived 'correct' response.\n PWNT, U R ADMIN\n Disarming the device and exiting...\n")
+                    sys.stdout.flush()
+                    exit()  # Exit the program
+                else:
+                    sys.stdout.write(f"\rReceived unexpected response: {line}")
+                    sys.stdout.flush()
+ 
+    except pexpect.exceptions.TIMEOUT:
+        sys.stdout.write("\rNo response received from the screen session (timeout).")
+        sys.stdout.flush()
+    except Exception as e:
+        sys.stdout.write(f"\rError reading from screen session: {e}")
+        sys.stdout.flush()
+ 
+def send_pulse_and_check_response():
+    """Send a pulse and check for 'correct!\n' or 'incorrect\n' response in parallel."""
+    global device_response
+    try:
+        # Send 'incorrectPassword' command to the screen session
+        sys.stdout.write("\rSending 'incorrectPassword' to screen session.")
+        sys.stdout.flush()
+        child.sendline("incorrectPassword")
+        
+        # Sleep time from command-line argument
+        time.sleep(args.pulse_sleep)
+ 
+        # Send 'pulse' command (simulating the pulse trigger)
+        s.trigger()
+        sys.stdout.write("\rdropped glitch")
+        sys.stdout.flush()
+ 
+        # Start a thread to read the screen output
+        reader_thread = threading.Thread(target=read_screen_output)
+        reader_thread.start()
+ 
+        # Wait for the reading thread to complete
+        reader_thread.join()
+        
+    except Exception as e:
+        sys.stdout.write(f"\rError interacting with screen session during pulse: {e}")
+        sys.stdout.flush()
+        return False
+ 
+def start_attack():
+    """Send a pulse through the FaultyCat and listen for the response concurrently."""
+    global child
+    try:
+        # Initialize the child process for screen session
+        initialize_child()
+ 
+        # Sending pulses and checking responses in a loop based on max_iterations argument
+        max_iterations = args.max_iterations
+        for i in range(max_iterations):
+            sys.stdout.write(f"\rLoop {i+1}/{max_iterations}: Sending pulse and checking response.\n")
+            sys.stdout.flush()
+ 
+            # Send the test message and check for pong
+            if send_test_message_and_read_response():
+ 
+                max_iterations_2 = 3
+                for j in range(max_iterations_2):
+                    # Send pulse and check for correct/incorrect response
+                    if send_pulse_and_check_response():
+                        break  # Break the loop if 'correct!' is received
+ 
+            # Small delay before next iteration
+            time.sleep(1)
+ 
+    except Exception as e:
+        sys.stdout.write(f"\rError: {e}\n")
+        sys.stdout.flush()
+    finally:
+        # Make sure to clean up the child process
+        if child:
+            child.close()
+ 
+if __name__ == "__main__":
+    start_attack()
+
+

diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_attiny85.ino b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_attiny85.ino
new file mode 100644
index 0000000..c29dcdc
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_attiny85.ino
@@ -0,0 +1,55 @@
+#include <SoftwareSerial.h>
+
+#define RX    3   // *** D3, Pin 2
+#define TX    4   // *** D4, Pin 3
+SoftwareSerial Serial(RX, TX);
+
+void setup() {
+  Serial.begin(9600);
+  Serial.println(" ");
+  Serial.println("Initializing...");
+  randomSeed(analogRead(0));  // Seed the random number generator for more randomness
+  delay(2000);  // Delay for initialization
+}
+
+void loop() {
+  // Generate one random number and assign it to both variables
+  volatile int originalNumber = random(10, 100);  
+  volatile int num1 = originalNumber;
+  volatile int num2 = originalNumber;
+
+  // Perform reversible operations to increase glitch susceptibility but keep values comparable
+  num1 = num1 ^ 0x55;  // XOR num1 with 0x55
+  num2 = num2 ^ 0x55;  // XOR num2 with 0x55
+  
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  // Extract the first and second digits
+  volatile int num1FirstDigit = num1 / 10;   // Get the first digit of num1
+  volatile int num1SecondDigit = num1 % 10;  // Get the second digit of num1
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  // Check if the numbers still match after the potential glitch
+  int match = 0;
+  if (num1FirstDigit == num2FirstDigit) {
+    if (num1SecondDigit == num2SecondDigit) {
+       match = 1;
+    }
+  }
+  
+  if (match == 1) {
+    Serial.print("Numbers match: "); Serial.print(num1); Serial.print(" "); Serial.print(num2); Serial.print("\r");
+  } else {
+    Serial.print("Glitch detected! Numbers do not match: ");
+    Serial.print(num1); Serial.print(" "); Serial.print(num2);
+    Serial.print(" ("); Serial.print(num1FirstDigit); Serial.print(":"); Serial.print(num1SecondDigit); Serial.print(") ");
+    Serial.print("("); Serial.print(num2FirstDigit); Serial.print(":"); Serial.print(num2SecondDigit); Serial.println(")");
+    Serial.println(" ");
+  }
+  
+  delay(100);  // Shorter delay to increase glitch detection chances
+}
+
diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch.py b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch.py
new file mode 100644
index 0000000..cb08065
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch.py
@@ -0,0 +1,9 @@
+from scope import Scope
+import time
+
+s = Scope()
+s.glitch.repeat = 4
+s.glitch.ext_offset = 10
+
+for _ in range(50000):
+    s.trigger()
diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch_work.png b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch_work.png
new file mode 100644
index 0000000..4f7fe86
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch_work.png
Binary files differ
diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_attiny85.ino b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_attiny85.ino
new file mode 100644
index 0000000..68beb08
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_attiny85.ino
@@ -0,0 +1,72 @@
+#include <SoftwareSerial.h>
+
+#define RX    3   // *** D3, Pin 2
+#define TX    4   // *** D4, Pin 3
+SoftwareSerial Serial(RX, TX);
+
+const String correctPassword = "secure123";  // Hardcoded password
+String inputString = "";                     // Variable to hold user input
+bool stringComplete = false;                 // Flag to indicate when a string is complete
+bool loggedIn = false;
+
+void setup() {
+  Serial.begin(9600);
+  Serial.println(" ");
+  Serial.println("Initializing...");
+  delay(200);  // Delay for initialization
+  Serial.print("[-]> ");
+}
+
+void prompt(){
+  // Reset for the next input without checking password
+  inputString = "";
+  stringComplete = false;
+  if(loggedIn == false){
+    Serial.print("[-]"); // not logged in 
+  }else{
+    Serial.print("[+]"); // logged in
+  }
+  Serial.print("> ");
+}
+
+void loop() {
+  // If the string is complete, process the input
+  if (stringComplete) {
+    // Glitch-prone section: making the comparison more complex and glitch-susceptible
+    volatile bool match = false;  // Using 'volatile' to increase glitch vulnerability
+        
+    // Check if input is "ping"
+    if (inputString == "ping") {
+      Serial.println("pong");  // Respond with "pong" if input is "ping"
+      prompt();
+      return;  // Exit the loop to avoid further processing (no "Password incorrect!" after "pong")
+    }
+    // Now compare the user input with the hardcoded password, but with timing window
+    else if (inputString == correctPassword) {
+      match = true;  // Passwords match
+    }
+
+    // Add a chance for glitches to affect this critical condition
+    if (match) {
+      Serial.println("Password correct!");
+      loggedIn = true;
+    } else {
+      Serial.println("Password incorrect!");
+    }
+    prompt();
+  }
+
+  // Listen for input from the user
+  while (Serial.available()) {
+    char inChar = (char)Serial.read();  // Read the incoming character
+    
+    // Check if it is the return character (indicating the end of input)
+    if (inChar == '\r' || inChar == '\n') {
+      stringComplete = true;
+    } else {
+      // Append the character to the input string
+      inputString += inChar;
+    }
+  }
+}
+
diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_glitch.py b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_glitch.py
new file mode 100644
index 0000000..69f7b0b
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_glitch.py
@@ -0,0 +1,159 @@
+import sys
+import time
+import pexpect  # Required to handle screen sessions
+import threading
+import argparse  # Import argparse for command-line arguments
+from scope import Scope
+ 
+DEFAULT_COMPORT = "/dev/ttyACM0"
+SCREEN_NAME = "ttyUSB0_screen"  # Replace this with the actual screen session name (screen -S tty_USB0_screen /dev/ttyUSB0 9800)
+ 
+# Argument parser for command-line arguments
+parser = argparse.ArgumentParser(description="Fault injection script with configurable parameters.")
+parser.add_argument("-g", "--glitch_repeat", type=int, default=4, dest="glitch_repeat", help="Number of times to repeat the glitch.")
+parser.add_argument("-p", "--pulse_sleep", type=float, default=0.05, dest="pulse_sleep", help="Sleep time between sending commands and triggering pulse.")
+parser.add_argument("-m", "--max_iterations", type=int, default=5, dest="max_iterations", help="Maximum number of attack iterations.")
+
+args = parser.parse_args()
+
+# Configure scope based on command-line argument
+s = Scope()
+s.glitch.repeat = args.glitch_repeat
+# Shared variable to store the response from the device
+device_response = None
+child = None  # Global child variable
+ 
+def initialize_child():
+    """Initialise the global child process for the screen session."""
+    global child
+    child = pexpect.spawn(f'screen -x {SCREEN_NAME}', encoding='utf-8')
+    child.expect(pexpect.TIMEOUT, timeout=1)  # Clear out any pre-existing buffer
+ 
+def send_test_message_and_read_response():
+    """Send 'ping' via screen to a serial device and check for 'correct!\n' or 'incorrect\n'."""
+    global child
+ 
+    # Send 'ping' to the screen session
+    child.sendline("ping")
+    sys.stdout.write("\rSent 'ping' to screen session.")
+    sys.stdout.flush()
+ 
+    # Wait a bit to ensure the command is processed
+    time.sleep(0.5)  
+ 
+    # Try reading any new output from the screen session
+    try:
+        response = child.read_nonblocking(size=1024, timeout=2)  # Read up to 1024 bytes of new data
+        if "pong" in response:
+            sys.stdout.write("\rReceived 'pong' response.")
+            return True
+        else:
+            sys.stdout.write(f"\rReceived unexpected response: {response}")
+        sys.stdout.flush()
+    except pexpect.exceptions.TIMEOUT:
+        sys.stdout.write("\rNo response received from the screen session (timeout).")
+        sys.stdout.flush()
+ 
+    return False
+ 
+def read_screen_output():
+    """Read output from the screen session in a separate thread."""
+    global device_response
+    buffer = ""  # Initialize a buffer to store incoming characters
+ 
+    try:
+        while True:
+            response = child.read_nonblocking(size=1024, timeout=2)  # Read up to 1024 bytes of new data
+            buffer += response  # Append the new response to the buffer
+            
+            # Check if there's a complete line in the buffer
+            while "\n" in buffer:
+                line, buffer = buffer.split("\n", 1)  # Split the buffer at the first newline
+                line = line.strip()  # Remove any leading/trailing whitespace
+ 
+                # Check for specific responses
+                if "incorrect!" in line:
+                    device_response = 'incorrect'
+                    return  # Exit the loop on incorrect response
+                elif "correct" in line:
+                    # Die here: Echo message, disarm device, and kill the program
+                    sys.stdout.write("\nReceived 'correct' response.\n PWNT, U R ADMIN\n Disarming the device and exiting...\n")
+                    sys.stdout.flush()
+                    exit()  # Exit the program
+                else:
+                    sys.stdout.write(f"\rReceived unexpected response: {line}")
+                    sys.stdout.flush()
+ 
+    except pexpect.exceptions.TIMEOUT:
+        sys.stdout.write("\rNo response received from the screen session (timeout).")
+        sys.stdout.flush()
+    except Exception as e:
+        sys.stdout.write(f"\rError reading from screen session: {e}")
+        sys.stdout.flush()
+ 
+def send_pulse_and_check_response():
+    """Send a pulse and check for 'correct!\n' or 'incorrect\n' response in parallel."""
+    global device_response
+    try:
+        # Send 'incorrectPassword' command to the screen session
+        sys.stdout.write("\rSending 'incorrectPassword' to screen session.")
+        sys.stdout.flush()
+        child.sendline("incorrectPassword")
+        
+        # Sleep time from command-line argument
+        time.sleep(args.pulse_sleep)
+ 
+        # Send 'pulse' command (simulating the pulse trigger)
+        s.trigger()
+        sys.stdout.write("\rdropped glitch")
+        sys.stdout.flush()
+ 
+        # Start a thread to read the screen output
+        reader_thread = threading.Thread(target=read_screen_output)
+        reader_thread.start()
+ 
+        # Wait for the reading thread to complete
+        reader_thread.join()
+        
+    except Exception as e:
+        sys.stdout.write(f"\rError interacting with screen session during pulse: {e}")
+        sys.stdout.flush()
+        return False
+ 
+def start_attack():
+    """Send a pulse through the FaultyCat and listen for the response concurrently."""
+    global child
+    try:
+        # Initialize the child process for screen session
+        initialize_child()
+ 
+        # Sending pulses and checking responses in a loop based on max_iterations argument
+        max_iterations = args.max_iterations
+        for i in range(max_iterations):
+            sys.stdout.write(f"\rLoop {i+1}/{max_iterations}: Sending pulse and checking response.\n")
+            sys.stdout.flush()
+ 
+            # Send the test message and check for pong
+            if send_test_message_and_read_response():
+ 
+                max_iterations_2 = 3
+                for j in range(max_iterations_2):
+                    # Send pulse and check for correct/incorrect response
+                    if send_pulse_and_check_response():
+                        break  # Break the loop if 'correct!' is received
+ 
+            # Small delay before next iteration
+            time.sleep(1)
+ 
+    except Exception as e:
+        sys.stdout.write(f"\rError: {e}\n")
+        sys.stdout.flush()
+    finally:
+        # Make sure to clean up the child process
+        if child:
+            child.close()
+ 
+if __name__ == "__main__":
+    start_attack()
+
+
diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_glitch_dump.png b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_glitch_dump.png
new file mode 100644
index 0000000..2637486
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_glitch_dump.png
Binary files differ

diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_attiny85.ino b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_attiny85.ino
new file mode 100644
index 0000000..c29dcdc
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_attiny85.ino
@@ -0,0 +1,55 @@
+#include <SoftwareSerial.h>
+
+#define RX    3   // *** D3, Pin 2
+#define TX    4   // *** D4, Pin 3
+SoftwareSerial Serial(RX, TX);
+
+void setup() {
+  Serial.begin(9600);
+  Serial.println(" ");
+  Serial.println("Initializing...");
+  randomSeed(analogRead(0));  // Seed the random number generator for more randomness
+  delay(2000);  // Delay for initialization
+}
+
+void loop() {
+  // Generate one random number and assign it to both variables
+  volatile int originalNumber = random(10, 100);  
+  volatile int num1 = originalNumber;
+  volatile int num2 = originalNumber;
+
+  // Perform reversible operations to increase glitch susceptibility but keep values comparable
+  num1 = num1 ^ 0x55;  // XOR num1 with 0x55
+  num2 = num2 ^ 0x55;  // XOR num2 with 0x55
+  
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  // Extract the first and second digits
+  volatile int num1FirstDigit = num1 / 10;   // Get the first digit of num1
+  volatile int num1SecondDigit = num1 % 10;  // Get the second digit of num1
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  // Check if the numbers still match after the potential glitch
+  int match = 0;
+  if (num1FirstDigit == num2FirstDigit) {
+    if (num1SecondDigit == num2SecondDigit) {
+       match = 1;
+    }
+  }
+  
+  if (match == 1) {
+    Serial.print("Numbers match: "); Serial.print(num1); Serial.print(" "); Serial.print(num2); Serial.print("\r");
+  } else {
+    Serial.print("Glitch detected! Numbers do not match: ");
+    Serial.print(num1); Serial.print(" "); Serial.print(num2);
+    Serial.print(" ("); Serial.print(num1FirstDigit); Serial.print(":"); Serial.print(num1SecondDigit); Serial.print(") ");
+    Serial.print("("); Serial.print(num2FirstDigit); Serial.print(":"); Serial.print(num2SecondDigit); Serial.println(")");
+    Serial.println(" ");
+  }
+  
+  delay(100);  // Shorter delay to increase glitch detection chances
+}
+
diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch.py b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch.py
new file mode 100644
index 0000000..cb08065
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch.py
@@ -0,0 +1,9 @@
+from scope import Scope
+import time
+
+s = Scope()
+s.glitch.repeat = 4
+s.glitch.ext_offset = 10
+
+for _ in range(50000):
+    s.trigger()
diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch_work.png b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch_work.png
new file mode 100644
index 0000000..4f7fe86
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch_work.png
Binary files differ
diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_attiny85.ino b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_attiny85.ino
new file mode 100644
index 0000000..68beb08
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_attiny85.ino
@@ -0,0 +1,72 @@
+#include <SoftwareSerial.h>
+
+#define RX    3   // *** D3, Pin 2
+#define TX    4   // *** D4, Pin 3
+SoftwareSerial Serial(RX, TX);
+
+const String correctPassword = "secure123";  // Hardcoded password
+String inputString = "";                     // Variable to hold user input
+bool stringComplete = false;                 // Flag to indicate when a string is complete
+bool loggedIn = false;
+
+void setup() {
+  Serial.begin(9600);
+  Serial.println(" ");
+  Serial.println("Initializing...");
+  delay(200);  // Delay for initialization
+  Serial.print("[-]> ");
+}
+
+void prompt(){
+  // Reset for the next input without checking password
+  inputString = "";
+  stringComplete = false;
+  if(loggedIn == false){
+    Serial.print("[-]"); // not logged in 
+  }else{
+    Serial.print("[+]"); // logged in
+  }
+  Serial.print("> ");
+}
+
+void loop() {
+  // If the string is complete, process the input
+  if (stringComplete) {
+    // Glitch-prone section: making the comparison more complex and glitch-susceptible
+    volatile bool match = false;  // Using 'volatile' to increase glitch vulnerability
+        
+    // Check if input is "ping"
+    if (inputString == "ping") {
+      Serial.println("pong");  // Respond with "pong" if input is "ping"
+      prompt();
+      return;  // Exit the loop to avoid further processing (no "Password incorrect!" after "pong")
+    }
+    // Now compare the user input with the hardcoded password, but with timing window
+    else if (inputString == correctPassword) {
+      match = true;  // Passwords match
+    }
+
+    // Add a chance for glitches to affect this critical condition
+    if (match) {
+      Serial.println("Password correct!");
+      loggedIn = true;
+    } else {
+      Serial.println("Password incorrect!");
+    }
+    prompt();
+  }
+
+  // Listen for input from the user
+  while (Serial.available()) {
+    char inChar = (char)Serial.read();  // Read the incoming character
+    
+    // Check if it is the return character (indicating the end of input)
+    if (inChar == '\r' || inChar == '\n') {
+      stringComplete = true;
+    } else {
+      // Append the character to the input string
+      inputString += inChar;
+    }
+  }
+}
+
diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_glitch.py b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_glitch.py
new file mode 100644
index 0000000..69f7b0b
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_glitch.py
@@ -0,0 +1,159 @@
+import sys
+import time
+import pexpect  # Required to handle screen sessions
+import threading
+import argparse  # Import argparse for command-line arguments
+from scope import Scope
+ 
+DEFAULT_COMPORT = "/dev/ttyACM0"
+SCREEN_NAME = "ttyUSB0_screen"  # Replace this with the actual screen session name (screen -S tty_USB0_screen /dev/ttyUSB0 9800)
+ 
+# Argument parser for command-line arguments
+parser = argparse.ArgumentParser(description="Fault injection script with configurable parameters.")
+parser.add_argument("-g", "--glitch_repeat", type=int, default=4, dest="glitch_repeat", help="Number of times to repeat the glitch.")
+parser.add_argument("-p", "--pulse_sleep", type=float, default=0.05, dest="pulse_sleep", help="Sleep time between sending commands and triggering pulse.")
+parser.add_argument("-m", "--max_iterations", type=int, default=5, dest="max_iterations", help="Maximum number of attack iterations.")
+
+args = parser.parse_args()
+
+# Configure scope based on command-line argument
+s = Scope()
+s.glitch.repeat = args.glitch_repeat
+# Shared variable to store the response from the device
+device_response = None
+child = None  # Global child variable
+ 
+def initialize_child():
+    """Initialise the global child process for the screen session."""
+    global child
+    child = pexpect.spawn(f'screen -x {SCREEN_NAME}', encoding='utf-8')
+    child.expect(pexpect.TIMEOUT, timeout=1)  # Clear out any pre-existing buffer
+ 
+def send_test_message_and_read_response():
+    """Send 'ping' via screen to a serial device and check for 'correct!\n' or 'incorrect\n'."""
+    global child
+ 
+    # Send 'ping' to the screen session
+    child.sendline("ping")
+    sys.stdout.write("\rSent 'ping' to screen session.")
+    sys.stdout.flush()
+ 
+    # Wait a bit to ensure the command is processed
+    time.sleep(0.5)  
+ 
+    # Try reading any new output from the screen session
+    try:
+        response = child.read_nonblocking(size=1024, timeout=2)  # Read up to 1024 bytes of new data
+        if "pong" in response:
+            sys.stdout.write("\rReceived 'pong' response.")
+            return True
+        else:
+            sys.stdout.write(f"\rReceived unexpected response: {response}")
+        sys.stdout.flush()
+    except pexpect.exceptions.TIMEOUT:
+        sys.stdout.write("\rNo response received from the screen session (timeout).")
+        sys.stdout.flush()
+ 
+    return False
+ 
+def read_screen_output():
+    """Read output from the screen session in a separate thread."""
+    global device_response
+    buffer = ""  # Initialize a buffer to store incoming characters
+ 
+    try:
+        while True:
+            response = child.read_nonblocking(size=1024, timeout=2)  # Read up to 1024 bytes of new data
+            buffer += response  # Append the new response to the buffer
+            
+            # Check if there's a complete line in the buffer
+            while "\n" in buffer:
+                line, buffer = buffer.split("\n", 1)  # Split the buffer at the first newline
+                line = line.strip()  # Remove any leading/trailing whitespace
+ 
+                # Check for specific responses
+                if "incorrect!" in line:
+                    device_response = 'incorrect'
+                    return  # Exit the loop on incorrect response
+                elif "correct" in line:
+                    # Die here: Echo message, disarm device, and kill the program
+                    sys.stdout.write("\nReceived 'correct' response.\n PWNT, U R ADMIN\n Disarming the device and exiting...\n")
+                    sys.stdout.flush()
+                    exit()  # Exit the program
+                else:
+                    sys.stdout.write(f"\rReceived unexpected response: {line}")
+                    sys.stdout.flush()
+ 
+    except pexpect.exceptions.TIMEOUT:
+        sys.stdout.write("\rNo response received from the screen session (timeout).")
+        sys.stdout.flush()
+    except Exception as e:
+        sys.stdout.write(f"\rError reading from screen session: {e}")
+        sys.stdout.flush()
+ 
+def send_pulse_and_check_response():
+    """Send a pulse and check for 'correct!\n' or 'incorrect\n' response in parallel."""
+    global device_response
+    try:
+        # Send 'incorrectPassword' command to the screen session
+        sys.stdout.write("\rSending 'incorrectPassword' to screen session.")
+        sys.stdout.flush()
+        child.sendline("incorrectPassword")
+        
+        # Sleep time from command-line argument
+        time.sleep(args.pulse_sleep)
+ 
+        # Send 'pulse' command (simulating the pulse trigger)
+        s.trigger()
+        sys.stdout.write("\rdropped glitch")
+        sys.stdout.flush()
+ 
+        # Start a thread to read the screen output
+        reader_thread = threading.Thread(target=read_screen_output)
+        reader_thread.start()
+ 
+        # Wait for the reading thread to complete
+        reader_thread.join()
+        
+    except Exception as e:
+        sys.stdout.write(f"\rError interacting with screen session during pulse: {e}")
+        sys.stdout.flush()
+        return False
+ 
+def start_attack():
+    """Send a pulse through the FaultyCat and listen for the response concurrently."""
+    global child
+    try:
+        # Initialize the child process for screen session
+        initialize_child()
+ 
+        # Sending pulses and checking responses in a loop based on max_iterations argument
+        max_iterations = args.max_iterations
+        for i in range(max_iterations):
+            sys.stdout.write(f"\rLoop {i+1}/{max_iterations}: Sending pulse and checking response.\n")
+            sys.stdout.flush()
+ 
+            # Send the test message and check for pong
+            if send_test_message_and_read_response():
+ 
+                max_iterations_2 = 3
+                for j in range(max_iterations_2):
+                    # Send pulse and check for correct/incorrect response
+                    if send_pulse_and_check_response():
+                        break  # Break the loop if 'correct!' is received
+ 
+            # Small delay before next iteration
+            time.sleep(1)
+ 
+    except Exception as e:
+        sys.stdout.write(f"\rError: {e}\n")
+        sys.stdout.flush()
+    finally:
+        # Make sure to clean up the child process
+        if child:
+            child.close()
+ 
+if __name__ == "__main__":
+    start_attack()
+
+
diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_glitch_dump.png b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_glitch_dump.png
new file mode 100644
index 0000000..2637486
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_glitch_dump.png
Binary files differ
diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_glitch_work.png b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_glitch_work.png
new file mode 100644
index 0000000..9e9fab9
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_glitch_work.png
Binary files differ

diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_attiny85.ino b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_attiny85.ino
new file mode 100644
index 0000000..c29dcdc
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_attiny85.ino
@@ -0,0 +1,55 @@
+#include <SoftwareSerial.h>
+
+#define RX    3   // *** D3, Pin 2
+#define TX    4   // *** D4, Pin 3
+SoftwareSerial Serial(RX, TX);
+
+void setup() {
+  Serial.begin(9600);
+  Serial.println(" ");
+  Serial.println("Initializing...");
+  randomSeed(analogRead(0));  // Seed the random number generator for more randomness
+  delay(2000);  // Delay for initialization
+}
+
+void loop() {
+  // Generate one random number and assign it to both variables
+  volatile int originalNumber = random(10, 100);  
+  volatile int num1 = originalNumber;
+  volatile int num2 = originalNumber;
+
+  // Perform reversible operations to increase glitch susceptibility but keep values comparable
+  num1 = num1 ^ 0x55;  // XOR num1 with 0x55
+  num2 = num2 ^ 0x55;  // XOR num2 with 0x55
+  
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  // Extract the first and second digits
+  volatile int num1FirstDigit = num1 / 10;   // Get the first digit of num1
+  volatile int num1SecondDigit = num1 % 10;  // Get the second digit of num1
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  // Check if the numbers still match after the potential glitch
+  int match = 0;
+  if (num1FirstDigit == num2FirstDigit) {
+    if (num1SecondDigit == num2SecondDigit) {
+       match = 1;
+    }
+  }
+  
+  if (match == 1) {
+    Serial.print("Numbers match: "); Serial.print(num1); Serial.print(" "); Serial.print(num2); Serial.print("\r");
+  } else {
+    Serial.print("Glitch detected! Numbers do not match: ");
+    Serial.print(num1); Serial.print(" "); Serial.print(num2);
+    Serial.print(" ("); Serial.print(num1FirstDigit); Serial.print(":"); Serial.print(num1SecondDigit); Serial.print(") ");
+    Serial.print("("); Serial.print(num2FirstDigit); Serial.print(":"); Serial.print(num2SecondDigit); Serial.println(")");
+    Serial.println(" ");
+  }
+  
+  delay(100);  // Shorter delay to increase glitch detection chances
+}
+
diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch.py b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch.py
new file mode 100644
index 0000000..cb08065
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch.py
@@ -0,0 +1,9 @@
+from scope import Scope
+import time
+
+s = Scope()
+s.glitch.repeat = 4
+s.glitch.ext_offset = 10
+
+for _ in range(50000):
+    s.trigger()
diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch_work.png b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch_work.png
new file mode 100644
index 0000000..4f7fe86
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/01-number_match_glitch_work.png
Binary files differ
diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_attiny85.ino b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_attiny85.ino
new file mode 100644
index 0000000..68beb08
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_attiny85.ino
@@ -0,0 +1,72 @@
+#include <SoftwareSerial.h>
+
+#define RX    3   // *** D3, Pin 2
+#define TX    4   // *** D4, Pin 3
+SoftwareSerial Serial(RX, TX);
+
+const String correctPassword = "secure123";  // Hardcoded password
+String inputString = "";                     // Variable to hold user input
+bool stringComplete = false;                 // Flag to indicate when a string is complete
+bool loggedIn = false;
+
+void setup() {
+  Serial.begin(9600);
+  Serial.println(" ");
+  Serial.println("Initializing...");
+  delay(200);  // Delay for initialization
+  Serial.print("[-]> ");
+}
+
+void prompt(){
+  // Reset for the next input without checking password
+  inputString = "";
+  stringComplete = false;
+  if(loggedIn == false){
+    Serial.print("[-]"); // not logged in 
+  }else{
+    Serial.print("[+]"); // logged in
+  }
+  Serial.print("> ");
+}
+
+void loop() {
+  // If the string is complete, process the input
+  if (stringComplete) {
+    // Glitch-prone section: making the comparison more complex and glitch-susceptible
+    volatile bool match = false;  // Using 'volatile' to increase glitch vulnerability
+        
+    // Check if input is "ping"
+    if (inputString == "ping") {
+      Serial.println("pong");  // Respond with "pong" if input is "ping"
+      prompt();
+      return;  // Exit the loop to avoid further processing (no "Password incorrect!" after "pong")
+    }
+    // Now compare the user input with the hardcoded password, but with timing window
+    else if (inputString == correctPassword) {
+      match = true;  // Passwords match
+    }
+
+    // Add a chance for glitches to affect this critical condition
+    if (match) {
+      Serial.println("Password correct!");
+      loggedIn = true;
+    } else {
+      Serial.println("Password incorrect!");
+    }
+    prompt();
+  }
+
+  // Listen for input from the user
+  while (Serial.available()) {
+    char inChar = (char)Serial.read();  // Read the incoming character
+    
+    // Check if it is the return character (indicating the end of input)
+    if (inChar == '\r' || inChar == '\n') {
+      stringComplete = true;
+    } else {
+      // Append the character to the input string
+      inputString += inChar;
+    }
+  }
+}
+
diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_glitch.py b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_glitch.py
new file mode 100644
index 0000000..69f7b0b
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_glitch.py
@@ -0,0 +1,159 @@
+import sys
+import time
+import pexpect  # Required to handle screen sessions
+import threading
+import argparse  # Import argparse for command-line arguments
+from scope import Scope
+ 
+DEFAULT_COMPORT = "/dev/ttyACM0"
+SCREEN_NAME = "ttyUSB0_screen"  # Replace this with the actual screen session name (screen -S tty_USB0_screen /dev/ttyUSB0 9800)
+ 
+# Argument parser for command-line arguments
+parser = argparse.ArgumentParser(description="Fault injection script with configurable parameters.")
+parser.add_argument("-g", "--glitch_repeat", type=int, default=4, dest="glitch_repeat", help="Number of times to repeat the glitch.")
+parser.add_argument("-p", "--pulse_sleep", type=float, default=0.05, dest="pulse_sleep", help="Sleep time between sending commands and triggering pulse.")
+parser.add_argument("-m", "--max_iterations", type=int, default=5, dest="max_iterations", help="Maximum number of attack iterations.")
+
+args = parser.parse_args()
+
+# Configure scope based on command-line argument
+s = Scope()
+s.glitch.repeat = args.glitch_repeat
+# Shared variable to store the response from the device
+device_response = None
+child = None  # Global child variable
+ 
+def initialize_child():
+    """Initialise the global child process for the screen session."""
+    global child
+    child = pexpect.spawn(f'screen -x {SCREEN_NAME}', encoding='utf-8')
+    child.expect(pexpect.TIMEOUT, timeout=1)  # Clear out any pre-existing buffer
+ 
+def send_test_message_and_read_response():
+    """Send 'ping' via screen to a serial device and check for 'correct!\n' or 'incorrect\n'."""
+    global child
+ 
+    # Send 'ping' to the screen session
+    child.sendline("ping")
+    sys.stdout.write("\rSent 'ping' to screen session.")
+    sys.stdout.flush()
+ 
+    # Wait a bit to ensure the command is processed
+    time.sleep(0.5)  
+ 
+    # Try reading any new output from the screen session
+    try:
+        response = child.read_nonblocking(size=1024, timeout=2)  # Read up to 1024 bytes of new data
+        if "pong" in response:
+            sys.stdout.write("\rReceived 'pong' response.")
+            return True
+        else:
+            sys.stdout.write(f"\rReceived unexpected response: {response}")
+        sys.stdout.flush()
+    except pexpect.exceptions.TIMEOUT:
+        sys.stdout.write("\rNo response received from the screen session (timeout).")
+        sys.stdout.flush()
+ 
+    return False
+ 
+def read_screen_output():
+    """Read output from the screen session in a separate thread."""
+    global device_response
+    buffer = ""  # Initialize a buffer to store incoming characters
+ 
+    try:
+        while True:
+            response = child.read_nonblocking(size=1024, timeout=2)  # Read up to 1024 bytes of new data
+            buffer += response  # Append the new response to the buffer
+            
+            # Check if there's a complete line in the buffer
+            while "\n" in buffer:
+                line, buffer = buffer.split("\n", 1)  # Split the buffer at the first newline
+                line = line.strip()  # Remove any leading/trailing whitespace
+ 
+                # Check for specific responses
+                if "incorrect!" in line:
+                    device_response = 'incorrect'
+                    return  # Exit the loop on incorrect response
+                elif "correct" in line:
+                    # Die here: Echo message, disarm device, and kill the program
+                    sys.stdout.write("\nReceived 'correct' response.\n PWNT, U R ADMIN\n Disarming the device and exiting...\n")
+                    sys.stdout.flush()
+                    exit()  # Exit the program
+                else:
+                    sys.stdout.write(f"\rReceived unexpected response: {line}")
+                    sys.stdout.flush()
+ 
+    except pexpect.exceptions.TIMEOUT:
+        sys.stdout.write("\rNo response received from the screen session (timeout).")
+        sys.stdout.flush()
+    except Exception as e:
+        sys.stdout.write(f"\rError reading from screen session: {e}")
+        sys.stdout.flush()
+ 
+def send_pulse_and_check_response():
+    """Send a pulse and check for 'correct!\n' or 'incorrect\n' response in parallel."""
+    global device_response
+    try:
+        # Send 'incorrectPassword' command to the screen session
+        sys.stdout.write("\rSending 'incorrectPassword' to screen session.")
+        sys.stdout.flush()
+        child.sendline("incorrectPassword")
+        
+        # Sleep time from command-line argument
+        time.sleep(args.pulse_sleep)
+ 
+        # Send 'pulse' command (simulating the pulse trigger)
+        s.trigger()
+        sys.stdout.write("\rdropped glitch")
+        sys.stdout.flush()
+ 
+        # Start a thread to read the screen output
+        reader_thread = threading.Thread(target=read_screen_output)
+        reader_thread.start()
+ 
+        # Wait for the reading thread to complete
+        reader_thread.join()
+        
+    except Exception as e:
+        sys.stdout.write(f"\rError interacting with screen session during pulse: {e}")
+        sys.stdout.flush()
+        return False
+ 
+def start_attack():
+    """Send a pulse through the FaultyCat and listen for the response concurrently."""
+    global child
+    try:
+        # Initialize the child process for screen session
+        initialize_child()
+ 
+        # Sending pulses and checking responses in a loop based on max_iterations argument
+        max_iterations = args.max_iterations
+        for i in range(max_iterations):
+            sys.stdout.write(f"\rLoop {i+1}/{max_iterations}: Sending pulse and checking response.\n")
+            sys.stdout.flush()
+ 
+            # Send the test message and check for pong
+            if send_test_message_and_read_response():
+ 
+                max_iterations_2 = 3
+                for j in range(max_iterations_2):
+                    # Send pulse and check for correct/incorrect response
+                    if send_pulse_and_check_response():
+                        break  # Break the loop if 'correct!' is received
+ 
+            # Small delay before next iteration
+            time.sleep(1)
+ 
+    except Exception as e:
+        sys.stdout.write(f"\rError: {e}\n")
+        sys.stdout.flush()
+    finally:
+        # Make sure to clean up the child process
+        if child:
+            child.close()
+ 
+if __name__ == "__main__":
+    start_attack()
+
+
diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_glitch_dump.png b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_glitch_dump.png
new file mode 100644
index 0000000..2637486
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_glitch_dump.png
Binary files differ
diff --git a/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_glitch_work.png b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_glitch_work.png
new file mode 100644
index 0000000..9e9fab9
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Crowbar_Glitching_Blog_01/02-pass_match_glitch_work.png
Binary files differ
diff --git a/FaultInjection/prereqs/CuriousBolt/scope.py b/FaultInjection/prereqs/CuriousBolt/scope.py
new file mode 100644
index 0000000..01cc88e
--- /dev/null
+++ b/FaultInjection/prereqs/CuriousBolt/scope.py
@@ -0,0 +1,328 @@
+import logging
+import serial
+from serial.tools.list_ports import comports
+from typing import Union, List
+
+class ADCSettings():
+    def __init__(self, dev:serial) -> None:
+        self._dev = dev
+        self._clk_freq = 25000000
+        self._delay = 0
+
+    @property
+    def clk_freq(self) -> int:
+        """
+        Get ADC CLK Frequency
+        """
+        return self._clk_freq
+    
+    @clk_freq.setter
+    def clk_freq(self, freq:int) -> None:
+        """
+        Set ADC CLK Frequency, valid between 0.5kHz and 31.25MHz
+        """
+        BASE_CLK = 250000000
+        pio_freq = freq*4
+        divider = BASE_CLK/pio_freq
+        integer = int(divider)
+        frac = int((divider-integer)*256)
+        if frac == 256:
+            frac = 0
+            integer += 1
+        self._dev.write(f":ADC:PLL {integer},{frac}\n".encode("ascii"))
+        self._clk_freq = BASE_CLK/(integer+frac/256)/4
+    
+    @property
+    def delay(self) -> int:
+        """
+        Get delay between trigger and start of sampling in cycles (8.3ns)
+        """
+        return self._delay
+    
+    @delay.setter
+    def delay(self, delay) -> None:
+        """
+        Set delay between trigger and start of sampling in cycles (8.3ns)
+        """
+        self._delay = delay
+        self._dev.write(f":ADC:DELAY {int(delay)}\n".encode("ascii"))
+
+class GlitchSettings():
+    def __init__(self, dev:serial) -> None:
+        self._dev = dev
+        self._offset = 10
+        self._repeat = 10
+
+    @property
+    def ext_offset(self) -> int:
+        """
+        Delay between trigger and start of glitch in cycles (8.3ns)
+        """
+        return self._offset
+    
+    @ext_offset.setter
+    def ext_offset(self, offset:int) -> None:
+        """
+        Set delay between trigger and start of glitch in cycles (8.3ns)
+        """
+        self._dev.write(f":GLITCH:DELAY {int(offset)}\n".encode("ascii"))
+        self._offset = offset
+    
+    @property
+    def repeat(self) -> int:
+        """Width of glitch in cycles (approx = 8.3 ns * width)"""
+        return self._repeat
+
+    @repeat.setter
+    def repeat(self, width:int) -> None:
+        """
+        Set width of glitch in cycles (8.3ns)
+        """
+        self._dev.write(f":GLITCH:LEN {int(width)}\n".encode("ascii"))
+        self._repeat = width
+
+class GPIOSettings():
+    def __init__(self, dev:serial) -> None:
+        self.gpio = []
+        for i in range(0, 4):
+            self.gpio.append(list())
+        self.dev = dev
+        self.MAX_CHANGES = 255
+        self.MAX_DELAY = 2147483647
+        
+    def add(self, pin:int, state:bool, delay:int=None, seconds:float=None) -> None:
+        """
+        Add state change to gpio
+
+        Arguments
+        ---------
+        pin : int
+            Which pin to add state change to, [0,3]
+        state : bool
+            What the state of the pin should be
+        delay : int
+            Number of cycles delay after state change, each cycle is 8.3ns
+        seconds : float
+            Seconds of delay after state change if delay is not provided
+
+        Returns
+        -------
+        None        
+        """
+        if pin < 0 or pin > 3:
+            raise ValueError("Pin must be between 0 and 3")
+        
+        if len(self.gpio[pin]) >= self.MAX_CHANGES:
+            raise ValueError("Pin reached max state changes")
+
+        if delay is None:
+            if seconds is None:
+                raise ValueError("delay or seconds must be provided")
+            delay = int(seconds*100000000)
+
+        if delay > self.MAX_DELAY:
+            raise ValueError("delay exceeds maximum")
+        
+        self.gpio[pin].append((delay << 1) | state)
+    
+    def reset(self) -> None:
+        """
+        Reset all GPIO state changes
+
+        Arguments
+        ---------
+        None
+
+        Returns
+        -------
+        None
+        """
+        self.dev.write(b":GPIO:RESET\n")
+        for i in range(0, 4):
+            self.gpio[i].clear()
+
+    def upload(self) -> None:
+        """
+        Upload GPIO changes to device
+
+        Arguments
+        ---------
+        None
+
+        Returns
+        -------
+        None
+        """
+        self.dev.write(b":GPIO:RESET\n")
+        for i in range(0, 4):
+            for item in self.gpio[i]:
+                self.dev.write(f":GPIO:ADD {i},{item}\n".encode("ascii"))
+    
+
+class Scope():
+    RISING_EDGE = 0
+    FALLING_EDGE = 1
+
+    def __init__(self, port=None) -> None:
+        if port is None:
+            ports = comports()
+            matches = [p.device for p in ports if p.interface == "Curious Bolt API"]
+            if len(matches) != 1:
+                matches = [p.device for p in ports if p.product == "Curious Bolt"]
+                matches.sort()
+                matches.reverse()
+                if len(matches) != 2:
+                    raise IOError('Curious Bolt device not found. Please check if it\'s connected, and pass its port explicitly if it is.')
+            port = matches[0]
+
+        self._port = port
+        self._dev = serial.Serial(port, 115200*10, timeout=1.0)
+        self._dev.reset_input_buffer()
+        self._dev.write(b":VERSION?\n")
+        data = self._dev.readline().strip()
+        if data is None or data == b"":
+            raise ValueError("Unable to connect")
+        print(f"Connected to version: {data.decode('ascii')}")
+        self.adc = ADCSettings(self._dev)
+        self.glitch = GlitchSettings(self._dev)
+        self.io = GPIOSettings(self._dev)
+
+    def arm(self, pin:int=0, edge:int=RISING_EDGE) -> None:
+        """
+        Arms the glitch/gpio/adc based on trigger pin
+
+        Arguments
+        ---------
+        pin : int
+            Which pin to use for trigger [0:7]
+        edge : int
+            On what edge to trigger can be RISING_EDGE or FALLING_EDGE
+
+        Returns
+        -------
+        None
+        """
+        if pin < 0 or pin > 7:
+            raise ValueError("Pin invalid")
+        
+        if edge != self.RISING_EDGE and edge != self.FALLING_EDGE:
+            raise ValueError("Edge invalid")
+
+        self._dev.write(f":TRIGGER:PIN {pin},{edge}\n".encode("ascii"))
+
+    def trigger(self) -> None:
+        """
+        Immediately trigger the glitch/gpio/adc
+
+        Arguments
+        ---------
+        None
+
+        Returns
+        -------
+        None
+        """
+        self._dev.write(b":TRIGGER:NOW\n")
+    
+    def default_setup(self) -> None:
+        """
+        Load some safe defaults into settings
+        """
+        self.glitch.repeat = 10
+        self.glitch.ext_offset = 0
+        self.adc.delay = 0
+        self.adc.clk_freq = 10000000
+        self.io.reset()
+
+    def con(self) -> None:
+        """
+        Connect to device if serial port is not open
+        """
+        if not self._dev.is_open:
+            self._dev.open()
+
+    def dis(self) -> None:
+        """
+        Disconnect from serial port
+        """
+        self._dev.close()
+
+    def get_last_trace(self, as_int:bool=False) -> Union[List[int], List[float]]:
+        """
+        Returns the latest captured data from ADC
+
+        Arguments
+        ---------
+        as_int : bool
+            Returns the data as raw 10bit value from the adc
+        
+        Returns
+        -------
+        data : list<int>
+        
+        """
+        self._dev.reset_input_buffer() #Clear any data
+        self._dev.write(b":ADC:DATA?\n")
+
+        data = self._dev.readline()
+        if data is None:
+            return []
+        data = data.decode("ascii").strip()
+        if "ERR" in data:
+            logging.warning(f"Received: {data}")
+            return []
+        data = data.split(",")
+        data = [x for x in data if x != '']
+        if as_int:
+            return [int(x) for x in data]
+        volt_per_step = 2 / 10 / 1024  # 2V pk-pk, 10x amplified from source, in 10-bit ADC
+        return [(float(x)-512)*volt_per_step for x in data]
+
+    def plot_last_trace(self, continuous=False):
+        try:
+            import matplotlib.pyplot as plt 
+        except ImportError:
+            print("Dependencies missing, please install python package matplotlib")
+            return
+        plt.ion()
+        fig = plt.figure()
+        ax = fig.add_subplot(111)
+        ax.set_xlabel("Time since trigger (us)")
+        ax.set_ylabel("Voltage difference (mV)")
+        us_per_measurement = 1e6 / self.adc.clk_freq
+        line, = ax.plot([float(x) * us_per_measurement for x in range(50000)], [0] * 50000, 'b-')
+
+        while True:
+            try:
+                res = self.get_last_trace()
+                if len(res) != 50000:
+                    print(f"Got {len(res)} entries, skipping")
+                    if continuous:
+                        continue
+                    else:
+                        break
+                trace = [x*1000 for x in res]
+                line.set_ydata(trace)
+                ax.relim()
+                ax.autoscale_view()
+                fig.canvas.draw()
+                fig.canvas.flush_events()
+                if continuous:
+                    self.trigger()
+                    continue
+                else:
+                    plt.show()
+                    break
+            except KeyboardInterrupt:
+                break
+
+    def update(self):
+        self._dev.write(b":BOOTLOADER\n")
+    
+
+
+if __name__ == "__main__":
+    s = Scope()
+    s.default_setup()
+    s.trigger()
+    s.plot_last_trace(continuous=True)