diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile
new file mode 100644
index 0000000..e6e7c4d
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile
@@ -0,0 +1,6 @@
+all:
+	arm-none-eabi-gcc -o test.o -c test.S -mthumb -mcpu=cortex-m3 -g3
+	arm-none-eabi-gcc -o main.o -c main.c -mthumb -mcpu=cortex-m3 -Os -g3
+	arm-none-eabi-gcc -o memset.o -c memset.c -mthumb -mcpu=cortex-m3 -Os -g3
+	arm-none-eabi-gcc -o sram.elf test.o main.o memset.o -nostartfiles -nostdlib -Tram.ld -mcpu=cortex-m3 -mthumb -g3
+	arm-none-eabi-objcopy -O binary sram.elf shellcode-0xRoM.bin

diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile
new file mode 100644
index 0000000..e6e7c4d
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile
@@ -0,0 +1,6 @@
+all:
+	arm-none-eabi-gcc -o test.o -c test.S -mthumb -mcpu=cortex-m3 -g3
+	arm-none-eabi-gcc -o main.o -c main.c -mthumb -mcpu=cortex-m3 -Os -g3
+	arm-none-eabi-gcc -o memset.o -c memset.c -mthumb -mcpu=cortex-m3 -Os -g3
+	arm-none-eabi-gcc -o sram.elf test.o main.o memset.o -nostartfiles -nostdlib -Tram.ld -mcpu=cortex-m3 -mthumb -g3
+	arm-none-eabi-objcopy -O binary sram.elf shellcode-0xRoM.bin
diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c
new file mode 100644
index 0000000..4d52bb9
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c
@@ -0,0 +1,323 @@
+#include <stdint.h>
+uint32_t volatile * const rccApb2 = (uint32_t *) 0x40021018u;
+uint32_t volatile * const ioAModerH = (uint32_t *) 0x40010804u;
+uint32_t volatile * const uart1Ctrl = (uint32_t *) 0x40013800u;
+
+void readChar( uint8_t const chr );
+void writeByte( uint8_t b );
+void writeStr( uint8_t const * const str );
+void writeChar( uint8_t const chr );
+void writeWordLe( uint32_t const word );
+void writeWordBe( uint32_t const word );
+void readCmd( uint8_t const * const cmd);
+uint32_t hexToInt(uint8_t const * const hex);
+void readMem(uint32_t const addr, uint32_t const len);
+void writeMem(uint32_t const addr, uint32_t const data);
+
+uint8_t const strHelp[] = 	"Help\r\n-----------\r\n"
+				"ADDR, VAL, LEN: 32-bit Hex encoded:\r\n e.g., 0A1337FF\r\n"
+				"-----------\r\n"
+				"R ADDR LEN - Read 32-bit word\r\n"
+				"W ADDR VAL - Write 32-bit word\r\n"
+				"D          - Dump all flash memory\r\n"
+				"P          - Jump into chall4 function\r\n"
+				"S          - Reboot\r\n"
+				"E          - Exit\r\n"
+				"H          - Show help \r\n"
+				"---------------\r\n";
+
+int main(void)
+{
+	/* IOA + USART1 clock enable */
+	*rccApb2 = (uint32_t) 0x4004u;
+
+	/* USART1 TX+RX (PA9, PX10) on */
+	*ioAModerH = (uint32_t) 0x444444B4u;
+
+	/* config and enable uart */
+	uart1Ctrl[2] = 0x00000341u;
+	uart1Ctrl[3] = 0x0000200Cu;
+	
+	writeStr("\r\n##############################\r\n"
+		 "# Low-Level Shell v.0xRoM    #\r\n"
+		 "# CPU-ID: 0x");
+	uint32_t cpuid = *((uint32_t *) 0xe000ed00);
+	writeWordBe(cpuid);
+	writeStr(                    "         #\r\n");
+	writeStr("##############################\r\n\r\n");
+	writeStr("> ");
+
+	while (1)
+	{
+		if ((uart1Ctrl[0] & 0x80u) && (0))
+		{
+			uart1Ctrl[1] = 0x33u;
+		}
+
+		if (uart1Ctrl[0] & 0x20u)
+		{
+			uint32_t data = uart1Ctrl[1];
+			readChar((uint8_t) data);
+		}
+	}
+}
+
+/* hex must have length 8 */
+uint32_t hexToInt(uint8_t const * const hex)
+{
+	uint32_t ind = 0u;
+	uint32_t res = 0u;
+
+	for (ind = 0; ind < 8; ++ind)
+	{
+		uint8_t chr = hex[ind];
+		uint32_t val = 0u;
+
+		res <<= 4u;
+
+		if ((chr >= '0') && (chr <= '9'))
+		{
+			val = chr - '0';
+		}
+		else if ((chr >= 'a') && (chr <= 'f'))
+		{
+			val = chr - 'a' + 0x0a;
+		}
+		else if ((chr >= 'A') && (chr <= 'F'))
+		{
+			val = chr - 'A' + 0x0a;
+		}
+		else
+		{
+			val = 0u;
+		}
+		res |= val;
+	}
+
+	return res;
+}
+
+void readChar( uint8_t const chr )
+{
+	#define CMDBUF_LEN (64u)
+	static uint8_t cmdbuf[CMDBUF_LEN] = {0u};
+	static uint32_t cmdInd = 0u;
+
+	switch (chr)
+	{
+		case '\n':
+		case '\r':
+			cmdbuf[cmdInd] = 0u;
+			if (cmdInd != 0)
+			{
+				writeStr("\r\n");
+			}
+			readCmd(cmdbuf);
+			cmdInd = 0u;
+			writeStr("\r\n> ");
+			{
+				uint32_t ind = 0u;
+				for (ind = 0; ind<CMDBUF_LEN; ++ind)
+				{
+					cmdbuf[ind]=0x00u;
+				}
+			}
+		break;
+
+		case 8:
+		case 255:
+		case 127: /* TODO backspace */
+			if (cmdInd > 0u)
+				--cmdInd;
+			writeChar(chr);
+		break;
+
+		default:
+			if (cmdInd < (CMDBUF_LEN - 1))
+			{
+				cmdbuf[cmdInd] = chr;
+				++cmdInd;
+				writeChar(chr);
+			}
+		break;
+	}
+}
+
+void readCmd( uint8_t const * const cmd )
+{
+	void (*chall4)(void) = (void (*)(void))0x08000ba9;
+	switch (cmd[0])
+	{
+		case 0:
+			return;
+			break;
+
+		/* chall4 function */
+		case 'p':
+		case 'P':
+			writeStr("time to change baudrate to 115200\r\n");
+			for (volatile uint32_t i = 0; i < 5000000; i++);  // Crude delay
+			chall4();
+			break;
+
+		/* read 32-bit command */
+		case 'r':
+		case 'R':
+			/* r 08000000 00000100 */
+			readMem(hexToInt(&cmd[2]), hexToInt(&cmd[11]));
+			break;
+
+		/* write 32-bit command */
+		case 'w':
+		case 'W':
+			/* w 20000000 12345678 */
+			writeMem(hexToInt(&cmd[2]), hexToInt(&cmd[11]));
+			break;
+
+		/* Dump all flash */
+		case 'd':
+		case 'D':
+			writeStr("\r\n\r\n");
+			{
+				uint32_t const * addr = (uint32_t*) 0x08000000;
+				uint32_t br = 8u;
+				while (((uintptr_t) addr) < (0x08000000 + 64u * 1024u))
+				{
+					if (br == 8u)
+					{
+						writeStr("\r\n[");
+						writeWordBe((uint32_t) addr);
+						writeStr("]: ");
+						br = 0u;
+					}
+
+					writeWordBe(*addr);
+					writeChar(' ');
+					++addr;
+					++br;
+				}
+			}
+			writeStr("\r\n\r\n");
+			break;
+
+		/* Help command */
+		case 'h':
+		case 'H':
+			writeStr(strHelp);
+			break;
+
+		/* Reboot */
+		case 's':
+		case 'S':
+			writeStr("Rebooting...\r\n\r\n");
+			*((uint32_t *) 0xE000ED0C) = 0x05FA0004u;
+			break;
+
+		/* exit */
+		case 'e':
+		case 'E':
+			writeStr("Bye.\r\n");
+			while (1)
+			{
+				__asm__ volatile("wfi");
+			}
+			break;
+
+
+		default:
+			writeStr("Unknown command: ");
+			writeStr(cmd);
+			writeStr("\r\n");
+			break;
+	}
+}
+	
+const uint8_t txtMap[] = "0123456789ABCDEF";
+
+void writeByte( uint8_t b )
+{
+	writeChar(txtMap[b >> 4]);
+	writeChar(txtMap[b & 0x0F]);
+}
+
+
+void writeStr( uint8_t const * const str )
+{
+	uint32_t ind = 0u;
+
+	while (str[ind])
+	{
+		writeChar(str[ind]);
+		++ind;
+	}
+}
+
+void writeChar( uint8_t const chr )
+{
+	while (!(uart1Ctrl[0] & 0x80u))
+	{
+		/* wait */
+	}
+
+	uart1Ctrl[1] = chr;
+}
+
+void writeWordLe( uint32_t const word )
+{
+	writeByte((word & 0x000000FF));
+	writeByte((word & 0x0000FF00) >> 8);
+	writeByte((word & 0x00FF0000) >> 16);
+	writeByte((word & 0xFF000000) >> 24);
+}
+
+void writeWordBe( uint32_t const word )
+{
+	writeByte((word & 0xFF000000) >> 24);
+	writeByte((word & 0x00FF0000) >> 16);
+	writeByte((word & 0x0000FF00) >> 8);
+	writeByte((word & 0x000000FF));
+
+}
+
+void alertCrash( uint32_t crashId )
+{
+	writeStr("!!! EXCEPTION !!!\r\nID: ");
+	writeByte(crashId);
+	writeStr("\r\nRestart required!\r\n\r\n");
+	*((uint32_t *) 0xE000ED0C) = 0x05FA0004u;
+	while (1);
+}
+
+void readMem(uint32_t const addr, uint32_t const len)
+{
+	uint32_t it = 0u;
+	uint32_t addrx = 0u;
+	uint32_t lenx = 0u;
+
+	lenx = len;
+	if (lenx == 0u)
+	{
+		lenx = 4u;
+	}
+
+	for (it = 0u; it < (lenx / 4u); ++it)
+	{
+		addrx = addr + it*4u;
+		writeStr("Read [");
+		writeWordBe(addrx);
+		writeStr("]: ");
+		writeWordBe(*((uint32_t*)addrx));
+		writeStr("\r\n");
+	}
+}
+
+void writeMem(uint32_t const addr, uint32_t const data)
+{
+	writeStr("Write [");
+	writeWordBe(addr);
+	writeStr("]: ");
+	writeWordBe(data);
+	*((uint32_t*) addr) = data;
+	writeStr("\r\n");
+}
+

diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile
new file mode 100644
index 0000000..e6e7c4d
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile
@@ -0,0 +1,6 @@
+all:
+	arm-none-eabi-gcc -o test.o -c test.S -mthumb -mcpu=cortex-m3 -g3
+	arm-none-eabi-gcc -o main.o -c main.c -mthumb -mcpu=cortex-m3 -Os -g3
+	arm-none-eabi-gcc -o memset.o -c memset.c -mthumb -mcpu=cortex-m3 -Os -g3
+	arm-none-eabi-gcc -o sram.elf test.o main.o memset.o -nostartfiles -nostdlib -Tram.ld -mcpu=cortex-m3 -mthumb -g3
+	arm-none-eabi-objcopy -O binary sram.elf shellcode-0xRoM.bin
diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c
new file mode 100644
index 0000000..4d52bb9
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c
@@ -0,0 +1,323 @@
+#include <stdint.h>
+uint32_t volatile * const rccApb2 = (uint32_t *) 0x40021018u;
+uint32_t volatile * const ioAModerH = (uint32_t *) 0x40010804u;
+uint32_t volatile * const uart1Ctrl = (uint32_t *) 0x40013800u;
+
+void readChar( uint8_t const chr );
+void writeByte( uint8_t b );
+void writeStr( uint8_t const * const str );
+void writeChar( uint8_t const chr );
+void writeWordLe( uint32_t const word );
+void writeWordBe( uint32_t const word );
+void readCmd( uint8_t const * const cmd);
+uint32_t hexToInt(uint8_t const * const hex);
+void readMem(uint32_t const addr, uint32_t const len);
+void writeMem(uint32_t const addr, uint32_t const data);
+
+uint8_t const strHelp[] = 	"Help\r\n-----------\r\n"
+				"ADDR, VAL, LEN: 32-bit Hex encoded:\r\n e.g., 0A1337FF\r\n"
+				"-----------\r\n"
+				"R ADDR LEN - Read 32-bit word\r\n"
+				"W ADDR VAL - Write 32-bit word\r\n"
+				"D          - Dump all flash memory\r\n"
+				"P          - Jump into chall4 function\r\n"
+				"S          - Reboot\r\n"
+				"E          - Exit\r\n"
+				"H          - Show help \r\n"
+				"---------------\r\n";
+
+int main(void)
+{
+	/* IOA + USART1 clock enable */
+	*rccApb2 = (uint32_t) 0x4004u;
+
+	/* USART1 TX+RX (PA9, PX10) on */
+	*ioAModerH = (uint32_t) 0x444444B4u;
+
+	/* config and enable uart */
+	uart1Ctrl[2] = 0x00000341u;
+	uart1Ctrl[3] = 0x0000200Cu;
+	
+	writeStr("\r\n##############################\r\n"
+		 "# Low-Level Shell v.0xRoM    #\r\n"
+		 "# CPU-ID: 0x");
+	uint32_t cpuid = *((uint32_t *) 0xe000ed00);
+	writeWordBe(cpuid);
+	writeStr(                    "         #\r\n");
+	writeStr("##############################\r\n\r\n");
+	writeStr("> ");
+
+	while (1)
+	{
+		if ((uart1Ctrl[0] & 0x80u) && (0))
+		{
+			uart1Ctrl[1] = 0x33u;
+		}
+
+		if (uart1Ctrl[0] & 0x20u)
+		{
+			uint32_t data = uart1Ctrl[1];
+			readChar((uint8_t) data);
+		}
+	}
+}
+
+/* hex must have length 8 */
+uint32_t hexToInt(uint8_t const * const hex)
+{
+	uint32_t ind = 0u;
+	uint32_t res = 0u;
+
+	for (ind = 0; ind < 8; ++ind)
+	{
+		uint8_t chr = hex[ind];
+		uint32_t val = 0u;
+
+		res <<= 4u;
+
+		if ((chr >= '0') && (chr <= '9'))
+		{
+			val = chr - '0';
+		}
+		else if ((chr >= 'a') && (chr <= 'f'))
+		{
+			val = chr - 'a' + 0x0a;
+		}
+		else if ((chr >= 'A') && (chr <= 'F'))
+		{
+			val = chr - 'A' + 0x0a;
+		}
+		else
+		{
+			val = 0u;
+		}
+		res |= val;
+	}
+
+	return res;
+}
+
+void readChar( uint8_t const chr )
+{
+	#define CMDBUF_LEN (64u)
+	static uint8_t cmdbuf[CMDBUF_LEN] = {0u};
+	static uint32_t cmdInd = 0u;
+
+	switch (chr)
+	{
+		case '\n':
+		case '\r':
+			cmdbuf[cmdInd] = 0u;
+			if (cmdInd != 0)
+			{
+				writeStr("\r\n");
+			}
+			readCmd(cmdbuf);
+			cmdInd = 0u;
+			writeStr("\r\n> ");
+			{
+				uint32_t ind = 0u;
+				for (ind = 0; ind<CMDBUF_LEN; ++ind)
+				{
+					cmdbuf[ind]=0x00u;
+				}
+			}
+		break;
+
+		case 8:
+		case 255:
+		case 127: /* TODO backspace */
+			if (cmdInd > 0u)
+				--cmdInd;
+			writeChar(chr);
+		break;
+
+		default:
+			if (cmdInd < (CMDBUF_LEN - 1))
+			{
+				cmdbuf[cmdInd] = chr;
+				++cmdInd;
+				writeChar(chr);
+			}
+		break;
+	}
+}
+
+void readCmd( uint8_t const * const cmd )
+{
+	void (*chall4)(void) = (void (*)(void))0x08000ba9;
+	switch (cmd[0])
+	{
+		case 0:
+			return;
+			break;
+
+		/* chall4 function */
+		case 'p':
+		case 'P':
+			writeStr("time to change baudrate to 115200\r\n");
+			for (volatile uint32_t i = 0; i < 5000000; i++);  // Crude delay
+			chall4();
+			break;
+
+		/* read 32-bit command */
+		case 'r':
+		case 'R':
+			/* r 08000000 00000100 */
+			readMem(hexToInt(&cmd[2]), hexToInt(&cmd[11]));
+			break;
+
+		/* write 32-bit command */
+		case 'w':
+		case 'W':
+			/* w 20000000 12345678 */
+			writeMem(hexToInt(&cmd[2]), hexToInt(&cmd[11]));
+			break;
+
+		/* Dump all flash */
+		case 'd':
+		case 'D':
+			writeStr("\r\n\r\n");
+			{
+				uint32_t const * addr = (uint32_t*) 0x08000000;
+				uint32_t br = 8u;
+				while (((uintptr_t) addr) < (0x08000000 + 64u * 1024u))
+				{
+					if (br == 8u)
+					{
+						writeStr("\r\n[");
+						writeWordBe((uint32_t) addr);
+						writeStr("]: ");
+						br = 0u;
+					}
+
+					writeWordBe(*addr);
+					writeChar(' ');
+					++addr;
+					++br;
+				}
+			}
+			writeStr("\r\n\r\n");
+			break;
+
+		/* Help command */
+		case 'h':
+		case 'H':
+			writeStr(strHelp);
+			break;
+
+		/* Reboot */
+		case 's':
+		case 'S':
+			writeStr("Rebooting...\r\n\r\n");
+			*((uint32_t *) 0xE000ED0C) = 0x05FA0004u;
+			break;
+
+		/* exit */
+		case 'e':
+		case 'E':
+			writeStr("Bye.\r\n");
+			while (1)
+			{
+				__asm__ volatile("wfi");
+			}
+			break;
+
+
+		default:
+			writeStr("Unknown command: ");
+			writeStr(cmd);
+			writeStr("\r\n");
+			break;
+	}
+}
+	
+const uint8_t txtMap[] = "0123456789ABCDEF";
+
+void writeByte( uint8_t b )
+{
+	writeChar(txtMap[b >> 4]);
+	writeChar(txtMap[b & 0x0F]);
+}
+
+
+void writeStr( uint8_t const * const str )
+{
+	uint32_t ind = 0u;
+
+	while (str[ind])
+	{
+		writeChar(str[ind]);
+		++ind;
+	}
+}
+
+void writeChar( uint8_t const chr )
+{
+	while (!(uart1Ctrl[0] & 0x80u))
+	{
+		/* wait */
+	}
+
+	uart1Ctrl[1] = chr;
+}
+
+void writeWordLe( uint32_t const word )
+{
+	writeByte((word & 0x000000FF));
+	writeByte((word & 0x0000FF00) >> 8);
+	writeByte((word & 0x00FF0000) >> 16);
+	writeByte((word & 0xFF000000) >> 24);
+}
+
+void writeWordBe( uint32_t const word )
+{
+	writeByte((word & 0xFF000000) >> 24);
+	writeByte((word & 0x00FF0000) >> 16);
+	writeByte((word & 0x0000FF00) >> 8);
+	writeByte((word & 0x000000FF));
+
+}
+
+void alertCrash( uint32_t crashId )
+{
+	writeStr("!!! EXCEPTION !!!\r\nID: ");
+	writeByte(crashId);
+	writeStr("\r\nRestart required!\r\n\r\n");
+	*((uint32_t *) 0xE000ED0C) = 0x05FA0004u;
+	while (1);
+}
+
+void readMem(uint32_t const addr, uint32_t const len)
+{
+	uint32_t it = 0u;
+	uint32_t addrx = 0u;
+	uint32_t lenx = 0u;
+
+	lenx = len;
+	if (lenx == 0u)
+	{
+		lenx = 4u;
+	}
+
+	for (it = 0u; it < (lenx / 4u); ++it)
+	{
+		addrx = addr + it*4u;
+		writeStr("Read [");
+		writeWordBe(addrx);
+		writeStr("]: ");
+		writeWordBe(*((uint32_t*)addrx));
+		writeStr("\r\n");
+	}
+}
+
+void writeMem(uint32_t const addr, uint32_t const data)
+{
+	writeStr("Write [");
+	writeWordBe(addr);
+	writeStr("]: ");
+	writeWordBe(data);
+	*((uint32_t*) addr) = data;
+	writeStr("\r\n");
+}
+
diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c
new file mode 100644
index 0000000..83154c6
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c
@@ -0,0 +1,19 @@
+// memset.c
+void *memset(void *dest, int val, unsigned int len) {
+    unsigned char *ptr = dest;
+    unsigned int value = (unsigned char)val; // Promote to avoid unnecessary casting
+
+    // Use a word-by-word copy if possible
+    while (len >= 4) {
+        *(unsigned int*)ptr = value | (value << 8) | (value << 16) | (value << 24);
+        ptr += 4;
+        len -= 4;
+    }
+
+    // If any bytes are left, fill them
+    while (len--) {
+        *ptr++ = (unsigned char)value;
+    }
+
+    return dest;
+}

diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile
new file mode 100644
index 0000000..e6e7c4d
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile
@@ -0,0 +1,6 @@
+all:
+	arm-none-eabi-gcc -o test.o -c test.S -mthumb -mcpu=cortex-m3 -g3
+	arm-none-eabi-gcc -o main.o -c main.c -mthumb -mcpu=cortex-m3 -Os -g3
+	arm-none-eabi-gcc -o memset.o -c memset.c -mthumb -mcpu=cortex-m3 -Os -g3
+	arm-none-eabi-gcc -o sram.elf test.o main.o memset.o -nostartfiles -nostdlib -Tram.ld -mcpu=cortex-m3 -mthumb -g3
+	arm-none-eabi-objcopy -O binary sram.elf shellcode-0xRoM.bin
diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c
new file mode 100644
index 0000000..4d52bb9
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c
@@ -0,0 +1,323 @@
+#include <stdint.h>
+uint32_t volatile * const rccApb2 = (uint32_t *) 0x40021018u;
+uint32_t volatile * const ioAModerH = (uint32_t *) 0x40010804u;
+uint32_t volatile * const uart1Ctrl = (uint32_t *) 0x40013800u;
+
+void readChar( uint8_t const chr );
+void writeByte( uint8_t b );
+void writeStr( uint8_t const * const str );
+void writeChar( uint8_t const chr );
+void writeWordLe( uint32_t const word );
+void writeWordBe( uint32_t const word );
+void readCmd( uint8_t const * const cmd);
+uint32_t hexToInt(uint8_t const * const hex);
+void readMem(uint32_t const addr, uint32_t const len);
+void writeMem(uint32_t const addr, uint32_t const data);
+
+uint8_t const strHelp[] = 	"Help\r\n-----------\r\n"
+				"ADDR, VAL, LEN: 32-bit Hex encoded:\r\n e.g., 0A1337FF\r\n"
+				"-----------\r\n"
+				"R ADDR LEN - Read 32-bit word\r\n"
+				"W ADDR VAL - Write 32-bit word\r\n"
+				"D          - Dump all flash memory\r\n"
+				"P          - Jump into chall4 function\r\n"
+				"S          - Reboot\r\n"
+				"E          - Exit\r\n"
+				"H          - Show help \r\n"
+				"---------------\r\n";
+
+int main(void)
+{
+	/* IOA + USART1 clock enable */
+	*rccApb2 = (uint32_t) 0x4004u;
+
+	/* USART1 TX+RX (PA9, PX10) on */
+	*ioAModerH = (uint32_t) 0x444444B4u;
+
+	/* config and enable uart */
+	uart1Ctrl[2] = 0x00000341u;
+	uart1Ctrl[3] = 0x0000200Cu;
+	
+	writeStr("\r\n##############################\r\n"
+		 "# Low-Level Shell v.0xRoM    #\r\n"
+		 "# CPU-ID: 0x");
+	uint32_t cpuid = *((uint32_t *) 0xe000ed00);
+	writeWordBe(cpuid);
+	writeStr(                    "         #\r\n");
+	writeStr("##############################\r\n\r\n");
+	writeStr("> ");
+
+	while (1)
+	{
+		if ((uart1Ctrl[0] & 0x80u) && (0))
+		{
+			uart1Ctrl[1] = 0x33u;
+		}
+
+		if (uart1Ctrl[0] & 0x20u)
+		{
+			uint32_t data = uart1Ctrl[1];
+			readChar((uint8_t) data);
+		}
+	}
+}
+
+/* hex must have length 8 */
+uint32_t hexToInt(uint8_t const * const hex)
+{
+	uint32_t ind = 0u;
+	uint32_t res = 0u;
+
+	for (ind = 0; ind < 8; ++ind)
+	{
+		uint8_t chr = hex[ind];
+		uint32_t val = 0u;
+
+		res <<= 4u;
+
+		if ((chr >= '0') && (chr <= '9'))
+		{
+			val = chr - '0';
+		}
+		else if ((chr >= 'a') && (chr <= 'f'))
+		{
+			val = chr - 'a' + 0x0a;
+		}
+		else if ((chr >= 'A') && (chr <= 'F'))
+		{
+			val = chr - 'A' + 0x0a;
+		}
+		else
+		{
+			val = 0u;
+		}
+		res |= val;
+	}
+
+	return res;
+}
+
+void readChar( uint8_t const chr )
+{
+	#define CMDBUF_LEN (64u)
+	static uint8_t cmdbuf[CMDBUF_LEN] = {0u};
+	static uint32_t cmdInd = 0u;
+
+	switch (chr)
+	{
+		case '\n':
+		case '\r':
+			cmdbuf[cmdInd] = 0u;
+			if (cmdInd != 0)
+			{
+				writeStr("\r\n");
+			}
+			readCmd(cmdbuf);
+			cmdInd = 0u;
+			writeStr("\r\n> ");
+			{
+				uint32_t ind = 0u;
+				for (ind = 0; ind<CMDBUF_LEN; ++ind)
+				{
+					cmdbuf[ind]=0x00u;
+				}
+			}
+		break;
+
+		case 8:
+		case 255:
+		case 127: /* TODO backspace */
+			if (cmdInd > 0u)
+				--cmdInd;
+			writeChar(chr);
+		break;
+
+		default:
+			if (cmdInd < (CMDBUF_LEN - 1))
+			{
+				cmdbuf[cmdInd] = chr;
+				++cmdInd;
+				writeChar(chr);
+			}
+		break;
+	}
+}
+
+void readCmd( uint8_t const * const cmd )
+{
+	void (*chall4)(void) = (void (*)(void))0x08000ba9;
+	switch (cmd[0])
+	{
+		case 0:
+			return;
+			break;
+
+		/* chall4 function */
+		case 'p':
+		case 'P':
+			writeStr("time to change baudrate to 115200\r\n");
+			for (volatile uint32_t i = 0; i < 5000000; i++);  // Crude delay
+			chall4();
+			break;
+
+		/* read 32-bit command */
+		case 'r':
+		case 'R':
+			/* r 08000000 00000100 */
+			readMem(hexToInt(&cmd[2]), hexToInt(&cmd[11]));
+			break;
+
+		/* write 32-bit command */
+		case 'w':
+		case 'W':
+			/* w 20000000 12345678 */
+			writeMem(hexToInt(&cmd[2]), hexToInt(&cmd[11]));
+			break;
+
+		/* Dump all flash */
+		case 'd':
+		case 'D':
+			writeStr("\r\n\r\n");
+			{
+				uint32_t const * addr = (uint32_t*) 0x08000000;
+				uint32_t br = 8u;
+				while (((uintptr_t) addr) < (0x08000000 + 64u * 1024u))
+				{
+					if (br == 8u)
+					{
+						writeStr("\r\n[");
+						writeWordBe((uint32_t) addr);
+						writeStr("]: ");
+						br = 0u;
+					}
+
+					writeWordBe(*addr);
+					writeChar(' ');
+					++addr;
+					++br;
+				}
+			}
+			writeStr("\r\n\r\n");
+			break;
+
+		/* Help command */
+		case 'h':
+		case 'H':
+			writeStr(strHelp);
+			break;
+
+		/* Reboot */
+		case 's':
+		case 'S':
+			writeStr("Rebooting...\r\n\r\n");
+			*((uint32_t *) 0xE000ED0C) = 0x05FA0004u;
+			break;
+
+		/* exit */
+		case 'e':
+		case 'E':
+			writeStr("Bye.\r\n");
+			while (1)
+			{
+				__asm__ volatile("wfi");
+			}
+			break;
+
+
+		default:
+			writeStr("Unknown command: ");
+			writeStr(cmd);
+			writeStr("\r\n");
+			break;
+	}
+}
+	
+const uint8_t txtMap[] = "0123456789ABCDEF";
+
+void writeByte( uint8_t b )
+{
+	writeChar(txtMap[b >> 4]);
+	writeChar(txtMap[b & 0x0F]);
+}
+
+
+void writeStr( uint8_t const * const str )
+{
+	uint32_t ind = 0u;
+
+	while (str[ind])
+	{
+		writeChar(str[ind]);
+		++ind;
+	}
+}
+
+void writeChar( uint8_t const chr )
+{
+	while (!(uart1Ctrl[0] & 0x80u))
+	{
+		/* wait */
+	}
+
+	uart1Ctrl[1] = chr;
+}
+
+void writeWordLe( uint32_t const word )
+{
+	writeByte((word & 0x000000FF));
+	writeByte((word & 0x0000FF00) >> 8);
+	writeByte((word & 0x00FF0000) >> 16);
+	writeByte((word & 0xFF000000) >> 24);
+}
+
+void writeWordBe( uint32_t const word )
+{
+	writeByte((word & 0xFF000000) >> 24);
+	writeByte((word & 0x00FF0000) >> 16);
+	writeByte((word & 0x0000FF00) >> 8);
+	writeByte((word & 0x000000FF));
+
+}
+
+void alertCrash( uint32_t crashId )
+{
+	writeStr("!!! EXCEPTION !!!\r\nID: ");
+	writeByte(crashId);
+	writeStr("\r\nRestart required!\r\n\r\n");
+	*((uint32_t *) 0xE000ED0C) = 0x05FA0004u;
+	while (1);
+}
+
+void readMem(uint32_t const addr, uint32_t const len)
+{
+	uint32_t it = 0u;
+	uint32_t addrx = 0u;
+	uint32_t lenx = 0u;
+
+	lenx = len;
+	if (lenx == 0u)
+	{
+		lenx = 4u;
+	}
+
+	for (it = 0u; it < (lenx / 4u); ++it)
+	{
+		addrx = addr + it*4u;
+		writeStr("Read [");
+		writeWordBe(addrx);
+		writeStr("]: ");
+		writeWordBe(*((uint32_t*)addrx));
+		writeStr("\r\n");
+	}
+}
+
+void writeMem(uint32_t const addr, uint32_t const data)
+{
+	writeStr("Write [");
+	writeWordBe(addr);
+	writeStr("]: ");
+	writeWordBe(data);
+	*((uint32_t*) addr) = data;
+	writeStr("\r\n");
+}
+
diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c
new file mode 100644
index 0000000..83154c6
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c
@@ -0,0 +1,19 @@
+// memset.c
+void *memset(void *dest, int val, unsigned int len) {
+    unsigned char *ptr = dest;
+    unsigned int value = (unsigned char)val; // Promote to avoid unnecessary casting
+
+    // Use a word-by-word copy if possible
+    while (len >= 4) {
+        *(unsigned int*)ptr = value | (value << 8) | (value << 16) | (value << 24);
+        ptr += 4;
+        len -= 4;
+    }
+
+    // If any bytes are left, fill them
+    while (len--) {
+        *ptr++ = (unsigned char)value;
+    }
+
+    return dest;
+}
diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin
new file mode 100644
index 0000000..2c9c70f
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin
Binary files differ

diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile
new file mode 100644
index 0000000..e6e7c4d
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile
@@ -0,0 +1,6 @@
+all:
+	arm-none-eabi-gcc -o test.o -c test.S -mthumb -mcpu=cortex-m3 -g3
+	arm-none-eabi-gcc -o main.o -c main.c -mthumb -mcpu=cortex-m3 -Os -g3
+	arm-none-eabi-gcc -o memset.o -c memset.c -mthumb -mcpu=cortex-m3 -Os -g3
+	arm-none-eabi-gcc -o sram.elf test.o main.o memset.o -nostartfiles -nostdlib -Tram.ld -mcpu=cortex-m3 -mthumb -g3
+	arm-none-eabi-objcopy -O binary sram.elf shellcode-0xRoM.bin
diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c
new file mode 100644
index 0000000..4d52bb9
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c
@@ -0,0 +1,323 @@
+#include <stdint.h>
+uint32_t volatile * const rccApb2 = (uint32_t *) 0x40021018u;
+uint32_t volatile * const ioAModerH = (uint32_t *) 0x40010804u;
+uint32_t volatile * const uart1Ctrl = (uint32_t *) 0x40013800u;
+
+void readChar( uint8_t const chr );
+void writeByte( uint8_t b );
+void writeStr( uint8_t const * const str );
+void writeChar( uint8_t const chr );
+void writeWordLe( uint32_t const word );
+void writeWordBe( uint32_t const word );
+void readCmd( uint8_t const * const cmd);
+uint32_t hexToInt(uint8_t const * const hex);
+void readMem(uint32_t const addr, uint32_t const len);
+void writeMem(uint32_t const addr, uint32_t const data);
+
+uint8_t const strHelp[] = 	"Help\r\n-----------\r\n"
+				"ADDR, VAL, LEN: 32-bit Hex encoded:\r\n e.g., 0A1337FF\r\n"
+				"-----------\r\n"
+				"R ADDR LEN - Read 32-bit word\r\n"
+				"W ADDR VAL - Write 32-bit word\r\n"
+				"D          - Dump all flash memory\r\n"
+				"P          - Jump into chall4 function\r\n"
+				"S          - Reboot\r\n"
+				"E          - Exit\r\n"
+				"H          - Show help \r\n"
+				"---------------\r\n";
+
+int main(void)
+{
+	/* IOA + USART1 clock enable */
+	*rccApb2 = (uint32_t) 0x4004u;
+
+	/* USART1 TX+RX (PA9, PX10) on */
+	*ioAModerH = (uint32_t) 0x444444B4u;
+
+	/* config and enable uart */
+	uart1Ctrl[2] = 0x00000341u;
+	uart1Ctrl[3] = 0x0000200Cu;
+	
+	writeStr("\r\n##############################\r\n"
+		 "# Low-Level Shell v.0xRoM    #\r\n"
+		 "# CPU-ID: 0x");
+	uint32_t cpuid = *((uint32_t *) 0xe000ed00);
+	writeWordBe(cpuid);
+	writeStr(                    "         #\r\n");
+	writeStr("##############################\r\n\r\n");
+	writeStr("> ");
+
+	while (1)
+	{
+		if ((uart1Ctrl[0] & 0x80u) && (0))
+		{
+			uart1Ctrl[1] = 0x33u;
+		}
+
+		if (uart1Ctrl[0] & 0x20u)
+		{
+			uint32_t data = uart1Ctrl[1];
+			readChar((uint8_t) data);
+		}
+	}
+}
+
+/* hex must have length 8 */
+uint32_t hexToInt(uint8_t const * const hex)
+{
+	uint32_t ind = 0u;
+	uint32_t res = 0u;
+
+	for (ind = 0; ind < 8; ++ind)
+	{
+		uint8_t chr = hex[ind];
+		uint32_t val = 0u;
+
+		res <<= 4u;
+
+		if ((chr >= '0') && (chr <= '9'))
+		{
+			val = chr - '0';
+		}
+		else if ((chr >= 'a') && (chr <= 'f'))
+		{
+			val = chr - 'a' + 0x0a;
+		}
+		else if ((chr >= 'A') && (chr <= 'F'))
+		{
+			val = chr - 'A' + 0x0a;
+		}
+		else
+		{
+			val = 0u;
+		}
+		res |= val;
+	}
+
+	return res;
+}
+
+void readChar( uint8_t const chr )
+{
+	#define CMDBUF_LEN (64u)
+	static uint8_t cmdbuf[CMDBUF_LEN] = {0u};
+	static uint32_t cmdInd = 0u;
+
+	switch (chr)
+	{
+		case '\n':
+		case '\r':
+			cmdbuf[cmdInd] = 0u;
+			if (cmdInd != 0)
+			{
+				writeStr("\r\n");
+			}
+			readCmd(cmdbuf);
+			cmdInd = 0u;
+			writeStr("\r\n> ");
+			{
+				uint32_t ind = 0u;
+				for (ind = 0; ind<CMDBUF_LEN; ++ind)
+				{
+					cmdbuf[ind]=0x00u;
+				}
+			}
+		break;
+
+		case 8:
+		case 255:
+		case 127: /* TODO backspace */
+			if (cmdInd > 0u)
+				--cmdInd;
+			writeChar(chr);
+		break;
+
+		default:
+			if (cmdInd < (CMDBUF_LEN - 1))
+			{
+				cmdbuf[cmdInd] = chr;
+				++cmdInd;
+				writeChar(chr);
+			}
+		break;
+	}
+}
+
+void readCmd( uint8_t const * const cmd )
+{
+	void (*chall4)(void) = (void (*)(void))0x08000ba9;
+	switch (cmd[0])
+	{
+		case 0:
+			return;
+			break;
+
+		/* chall4 function */
+		case 'p':
+		case 'P':
+			writeStr("time to change baudrate to 115200\r\n");
+			for (volatile uint32_t i = 0; i < 5000000; i++);  // Crude delay
+			chall4();
+			break;
+
+		/* read 32-bit command */
+		case 'r':
+		case 'R':
+			/* r 08000000 00000100 */
+			readMem(hexToInt(&cmd[2]), hexToInt(&cmd[11]));
+			break;
+
+		/* write 32-bit command */
+		case 'w':
+		case 'W':
+			/* w 20000000 12345678 */
+			writeMem(hexToInt(&cmd[2]), hexToInt(&cmd[11]));
+			break;
+
+		/* Dump all flash */
+		case 'd':
+		case 'D':
+			writeStr("\r\n\r\n");
+			{
+				uint32_t const * addr = (uint32_t*) 0x08000000;
+				uint32_t br = 8u;
+				while (((uintptr_t) addr) < (0x08000000 + 64u * 1024u))
+				{
+					if (br == 8u)
+					{
+						writeStr("\r\n[");
+						writeWordBe((uint32_t) addr);
+						writeStr("]: ");
+						br = 0u;
+					}
+
+					writeWordBe(*addr);
+					writeChar(' ');
+					++addr;
+					++br;
+				}
+			}
+			writeStr("\r\n\r\n");
+			break;
+
+		/* Help command */
+		case 'h':
+		case 'H':
+			writeStr(strHelp);
+			break;
+
+		/* Reboot */
+		case 's':
+		case 'S':
+			writeStr("Rebooting...\r\n\r\n");
+			*((uint32_t *) 0xE000ED0C) = 0x05FA0004u;
+			break;
+
+		/* exit */
+		case 'e':
+		case 'E':
+			writeStr("Bye.\r\n");
+			while (1)
+			{
+				__asm__ volatile("wfi");
+			}
+			break;
+
+
+		default:
+			writeStr("Unknown command: ");
+			writeStr(cmd);
+			writeStr("\r\n");
+			break;
+	}
+}
+	
+const uint8_t txtMap[] = "0123456789ABCDEF";
+
+void writeByte( uint8_t b )
+{
+	writeChar(txtMap[b >> 4]);
+	writeChar(txtMap[b & 0x0F]);
+}
+
+
+void writeStr( uint8_t const * const str )
+{
+	uint32_t ind = 0u;
+
+	while (str[ind])
+	{
+		writeChar(str[ind]);
+		++ind;
+	}
+}
+
+void writeChar( uint8_t const chr )
+{
+	while (!(uart1Ctrl[0] & 0x80u))
+	{
+		/* wait */
+	}
+
+	uart1Ctrl[1] = chr;
+}
+
+void writeWordLe( uint32_t const word )
+{
+	writeByte((word & 0x000000FF));
+	writeByte((word & 0x0000FF00) >> 8);
+	writeByte((word & 0x00FF0000) >> 16);
+	writeByte((word & 0xFF000000) >> 24);
+}
+
+void writeWordBe( uint32_t const word )
+{
+	writeByte((word & 0xFF000000) >> 24);
+	writeByte((word & 0x00FF0000) >> 16);
+	writeByte((word & 0x0000FF00) >> 8);
+	writeByte((word & 0x000000FF));
+
+}
+
+void alertCrash( uint32_t crashId )
+{
+	writeStr("!!! EXCEPTION !!!\r\nID: ");
+	writeByte(crashId);
+	writeStr("\r\nRestart required!\r\n\r\n");
+	*((uint32_t *) 0xE000ED0C) = 0x05FA0004u;
+	while (1);
+}
+
+void readMem(uint32_t const addr, uint32_t const len)
+{
+	uint32_t it = 0u;
+	uint32_t addrx = 0u;
+	uint32_t lenx = 0u;
+
+	lenx = len;
+	if (lenx == 0u)
+	{
+		lenx = 4u;
+	}
+
+	for (it = 0u; it < (lenx / 4u); ++it)
+	{
+		addrx = addr + it*4u;
+		writeStr("Read [");
+		writeWordBe(addrx);
+		writeStr("]: ");
+		writeWordBe(*((uint32_t*)addrx));
+		writeStr("\r\n");
+	}
+}
+
+void writeMem(uint32_t const addr, uint32_t const data)
+{
+	writeStr("Write [");
+	writeWordBe(addr);
+	writeStr("]: ");
+	writeWordBe(data);
+	*((uint32_t*) addr) = data;
+	writeStr("\r\n");
+}
+
diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c
new file mode 100644
index 0000000..83154c6
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c
@@ -0,0 +1,19 @@
+// memset.c
+void *memset(void *dest, int val, unsigned int len) {
+    unsigned char *ptr = dest;
+    unsigned int value = (unsigned char)val; // Promote to avoid unnecessary casting
+
+    // Use a word-by-word copy if possible
+    while (len >= 4) {
+        *(unsigned int*)ptr = value | (value << 8) | (value << 16) | (value << 24);
+        ptr += 4;
+        len -= 4;
+    }
+
+    // If any bytes are left, fill them
+    while (len--) {
+        *ptr++ = (unsigned char)value;
+    }
+
+    return dest;
+}
diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin
new file mode 100644
index 0000000..2c9c70f
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin
Binary files differ
diff --git a/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall02.py b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall02.py
new file mode 100644
index 0000000..6a4b4a2
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall02.py
@@ -0,0 +1,54 @@
+######
+# config to complete Level 1, Challenge 2 using "glitch-o-bolt"
+######
+# LEAVE THESE IMPORTS!
+######
+import functions
+import random
+from textual.widgets import Log
+
+######
+# config values
+######
+
+SERIAL_PORT = '/dev/ttyUSB0'
+BAUD_RATE = 115200
+
+LENGTH = 42
+REPEAT = 1
+DELAY = 0
+
+###
+# ^ = pullup, v = pulldown
+###
+triggers = [
+    ['-', False],  #0
+    ['-', False],  #1
+    ['-', False],  #2
+    ['-', False],  #3
+    ['-', False],  #4
+    ['-', False],  #5
+    ['-', False],  #6
+    ['-', False],  #7
+]
+
+###
+# name, enabled, string to match in output, function to run
+# if string is blank ("") doesnt show toggle, just run button
+###
+conditions = [
+    ["Flag", True,  "ctf", "stop_glitching"],
+    ["Chal2", True, "Hold one of", "start_chal_02"] # requires bolt output gpio pin 0 -> challenge board chall 2 button
+]
+
+######
+# Custom functions for conditions to trigger
+######
+
+def stop_glitching():
+	elapsed = functions.get_glitch_elapsed()
+	functions.glitching_switch(False)
+	functions.add_text(f"[auto] glitching stopped (elapsed: {elapsed})")    
+
+def start_chal_02():
+    functions.run_output_high(0, 30000000) ## can also run_output_low() if need too
\ No newline at end of file

diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile
new file mode 100644
index 0000000..e6e7c4d
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile
@@ -0,0 +1,6 @@
+all:
+	arm-none-eabi-gcc -o test.o -c test.S -mthumb -mcpu=cortex-m3 -g3
+	arm-none-eabi-gcc -o main.o -c main.c -mthumb -mcpu=cortex-m3 -Os -g3
+	arm-none-eabi-gcc -o memset.o -c memset.c -mthumb -mcpu=cortex-m3 -Os -g3
+	arm-none-eabi-gcc -o sram.elf test.o main.o memset.o -nostartfiles -nostdlib -Tram.ld -mcpu=cortex-m3 -mthumb -g3
+	arm-none-eabi-objcopy -O binary sram.elf shellcode-0xRoM.bin
diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c
new file mode 100644
index 0000000..4d52bb9
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c
@@ -0,0 +1,323 @@
+#include <stdint.h>
+uint32_t volatile * const rccApb2 = (uint32_t *) 0x40021018u;
+uint32_t volatile * const ioAModerH = (uint32_t *) 0x40010804u;
+uint32_t volatile * const uart1Ctrl = (uint32_t *) 0x40013800u;
+
+void readChar( uint8_t const chr );
+void writeByte( uint8_t b );
+void writeStr( uint8_t const * const str );
+void writeChar( uint8_t const chr );
+void writeWordLe( uint32_t const word );
+void writeWordBe( uint32_t const word );
+void readCmd( uint8_t const * const cmd);
+uint32_t hexToInt(uint8_t const * const hex);
+void readMem(uint32_t const addr, uint32_t const len);
+void writeMem(uint32_t const addr, uint32_t const data);
+
+uint8_t const strHelp[] = 	"Help\r\n-----------\r\n"
+				"ADDR, VAL, LEN: 32-bit Hex encoded:\r\n e.g., 0A1337FF\r\n"
+				"-----------\r\n"
+				"R ADDR LEN - Read 32-bit word\r\n"
+				"W ADDR VAL - Write 32-bit word\r\n"
+				"D          - Dump all flash memory\r\n"
+				"P          - Jump into chall4 function\r\n"
+				"S          - Reboot\r\n"
+				"E          - Exit\r\n"
+				"H          - Show help \r\n"
+				"---------------\r\n";
+
+int main(void)
+{
+	/* IOA + USART1 clock enable */
+	*rccApb2 = (uint32_t) 0x4004u;
+
+	/* USART1 TX+RX (PA9, PX10) on */
+	*ioAModerH = (uint32_t) 0x444444B4u;
+
+	/* config and enable uart */
+	uart1Ctrl[2] = 0x00000341u;
+	uart1Ctrl[3] = 0x0000200Cu;
+	
+	writeStr("\r\n##############################\r\n"
+		 "# Low-Level Shell v.0xRoM    #\r\n"
+		 "# CPU-ID: 0x");
+	uint32_t cpuid = *((uint32_t *) 0xe000ed00);
+	writeWordBe(cpuid);
+	writeStr(                    "         #\r\n");
+	writeStr("##############################\r\n\r\n");
+	writeStr("> ");
+
+	while (1)
+	{
+		if ((uart1Ctrl[0] & 0x80u) && (0))
+		{
+			uart1Ctrl[1] = 0x33u;
+		}
+
+		if (uart1Ctrl[0] & 0x20u)
+		{
+			uint32_t data = uart1Ctrl[1];
+			readChar((uint8_t) data);
+		}
+	}
+}
+
+/* hex must have length 8 */
+uint32_t hexToInt(uint8_t const * const hex)
+{
+	uint32_t ind = 0u;
+	uint32_t res = 0u;
+
+	for (ind = 0; ind < 8; ++ind)
+	{
+		uint8_t chr = hex[ind];
+		uint32_t val = 0u;
+
+		res <<= 4u;
+
+		if ((chr >= '0') && (chr <= '9'))
+		{
+			val = chr - '0';
+		}
+		else if ((chr >= 'a') && (chr <= 'f'))
+		{
+			val = chr - 'a' + 0x0a;
+		}
+		else if ((chr >= 'A') && (chr <= 'F'))
+		{
+			val = chr - 'A' + 0x0a;
+		}
+		else
+		{
+			val = 0u;
+		}
+		res |= val;
+	}
+
+	return res;
+}
+
+void readChar( uint8_t const chr )
+{
+	#define CMDBUF_LEN (64u)
+	static uint8_t cmdbuf[CMDBUF_LEN] = {0u};
+	static uint32_t cmdInd = 0u;
+
+	switch (chr)
+	{
+		case '\n':
+		case '\r':
+			cmdbuf[cmdInd] = 0u;
+			if (cmdInd != 0)
+			{
+				writeStr("\r\n");
+			}
+			readCmd(cmdbuf);
+			cmdInd = 0u;
+			writeStr("\r\n> ");
+			{
+				uint32_t ind = 0u;
+				for (ind = 0; ind<CMDBUF_LEN; ++ind)
+				{
+					cmdbuf[ind]=0x00u;
+				}
+			}
+		break;
+
+		case 8:
+		case 255:
+		case 127: /* TODO backspace */
+			if (cmdInd > 0u)
+				--cmdInd;
+			writeChar(chr);
+		break;
+
+		default:
+			if (cmdInd < (CMDBUF_LEN - 1))
+			{
+				cmdbuf[cmdInd] = chr;
+				++cmdInd;
+				writeChar(chr);
+			}
+		break;
+	}
+}
+
+void readCmd( uint8_t const * const cmd )
+{
+	void (*chall4)(void) = (void (*)(void))0x08000ba9;
+	switch (cmd[0])
+	{
+		case 0:
+			return;
+			break;
+
+		/* chall4 function */
+		case 'p':
+		case 'P':
+			writeStr("time to change baudrate to 115200\r\n");
+			for (volatile uint32_t i = 0; i < 5000000; i++);  // Crude delay
+			chall4();
+			break;
+
+		/* read 32-bit command */
+		case 'r':
+		case 'R':
+			/* r 08000000 00000100 */
+			readMem(hexToInt(&cmd[2]), hexToInt(&cmd[11]));
+			break;
+
+		/* write 32-bit command */
+		case 'w':
+		case 'W':
+			/* w 20000000 12345678 */
+			writeMem(hexToInt(&cmd[2]), hexToInt(&cmd[11]));
+			break;
+
+		/* Dump all flash */
+		case 'd':
+		case 'D':
+			writeStr("\r\n\r\n");
+			{
+				uint32_t const * addr = (uint32_t*) 0x08000000;
+				uint32_t br = 8u;
+				while (((uintptr_t) addr) < (0x08000000 + 64u * 1024u))
+				{
+					if (br == 8u)
+					{
+						writeStr("\r\n[");
+						writeWordBe((uint32_t) addr);
+						writeStr("]: ");
+						br = 0u;
+					}
+
+					writeWordBe(*addr);
+					writeChar(' ');
+					++addr;
+					++br;
+				}
+			}
+			writeStr("\r\n\r\n");
+			break;
+
+		/* Help command */
+		case 'h':
+		case 'H':
+			writeStr(strHelp);
+			break;
+
+		/* Reboot */
+		case 's':
+		case 'S':
+			writeStr("Rebooting...\r\n\r\n");
+			*((uint32_t *) 0xE000ED0C) = 0x05FA0004u;
+			break;
+
+		/* exit */
+		case 'e':
+		case 'E':
+			writeStr("Bye.\r\n");
+			while (1)
+			{
+				__asm__ volatile("wfi");
+			}
+			break;
+
+
+		default:
+			writeStr("Unknown command: ");
+			writeStr(cmd);
+			writeStr("\r\n");
+			break;
+	}
+}
+	
+const uint8_t txtMap[] = "0123456789ABCDEF";
+
+void writeByte( uint8_t b )
+{
+	writeChar(txtMap[b >> 4]);
+	writeChar(txtMap[b & 0x0F]);
+}
+
+
+void writeStr( uint8_t const * const str )
+{
+	uint32_t ind = 0u;
+
+	while (str[ind])
+	{
+		writeChar(str[ind]);
+		++ind;
+	}
+}
+
+void writeChar( uint8_t const chr )
+{
+	while (!(uart1Ctrl[0] & 0x80u))
+	{
+		/* wait */
+	}
+
+	uart1Ctrl[1] = chr;
+}
+
+void writeWordLe( uint32_t const word )
+{
+	writeByte((word & 0x000000FF));
+	writeByte((word & 0x0000FF00) >> 8);
+	writeByte((word & 0x00FF0000) >> 16);
+	writeByte((word & 0xFF000000) >> 24);
+}
+
+void writeWordBe( uint32_t const word )
+{
+	writeByte((word & 0xFF000000) >> 24);
+	writeByte((word & 0x00FF0000) >> 16);
+	writeByte((word & 0x0000FF00) >> 8);
+	writeByte((word & 0x000000FF));
+
+}
+
+void alertCrash( uint32_t crashId )
+{
+	writeStr("!!! EXCEPTION !!!\r\nID: ");
+	writeByte(crashId);
+	writeStr("\r\nRestart required!\r\n\r\n");
+	*((uint32_t *) 0xE000ED0C) = 0x05FA0004u;
+	while (1);
+}
+
+void readMem(uint32_t const addr, uint32_t const len)
+{
+	uint32_t it = 0u;
+	uint32_t addrx = 0u;
+	uint32_t lenx = 0u;
+
+	lenx = len;
+	if (lenx == 0u)
+	{
+		lenx = 4u;
+	}
+
+	for (it = 0u; it < (lenx / 4u); ++it)
+	{
+		addrx = addr + it*4u;
+		writeStr("Read [");
+		writeWordBe(addrx);
+		writeStr("]: ");
+		writeWordBe(*((uint32_t*)addrx));
+		writeStr("\r\n");
+	}
+}
+
+void writeMem(uint32_t const addr, uint32_t const data)
+{
+	writeStr("Write [");
+	writeWordBe(addr);
+	writeStr("]: ");
+	writeWordBe(data);
+	*((uint32_t*) addr) = data;
+	writeStr("\r\n");
+}
+
diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c
new file mode 100644
index 0000000..83154c6
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c
@@ -0,0 +1,19 @@
+// memset.c
+void *memset(void *dest, int val, unsigned int len) {
+    unsigned char *ptr = dest;
+    unsigned int value = (unsigned char)val; // Promote to avoid unnecessary casting
+
+    // Use a word-by-word copy if possible
+    while (len >= 4) {
+        *(unsigned int*)ptr = value | (value << 8) | (value << 16) | (value << 24);
+        ptr += 4;
+        len -= 4;
+    }
+
+    // If any bytes are left, fill them
+    while (len--) {
+        *ptr++ = (unsigned char)value;
+    }
+
+    return dest;
+}
diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin
new file mode 100644
index 0000000..2c9c70f
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin
Binary files differ
diff --git a/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall02.py b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall02.py
new file mode 100644
index 0000000..6a4b4a2
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall02.py
@@ -0,0 +1,54 @@
+######
+# config to complete Level 1, Challenge 2 using "glitch-o-bolt"
+######
+# LEAVE THESE IMPORTS!
+######
+import functions
+import random
+from textual.widgets import Log
+
+######
+# config values
+######
+
+SERIAL_PORT = '/dev/ttyUSB0'
+BAUD_RATE = 115200
+
+LENGTH = 42
+REPEAT = 1
+DELAY = 0
+
+###
+# ^ = pullup, v = pulldown
+###
+triggers = [
+    ['-', False],  #0
+    ['-', False],  #1
+    ['-', False],  #2
+    ['-', False],  #3
+    ['-', False],  #4
+    ['-', False],  #5
+    ['-', False],  #6
+    ['-', False],  #7
+]
+
+###
+# name, enabled, string to match in output, function to run
+# if string is blank ("") doesnt show toggle, just run button
+###
+conditions = [
+    ["Flag", True,  "ctf", "stop_glitching"],
+    ["Chal2", True, "Hold one of", "start_chal_02"] # requires bolt output gpio pin 0 -> challenge board chall 2 button
+]
+
+######
+# Custom functions for conditions to trigger
+######
+
+def stop_glitching():
+	elapsed = functions.get_glitch_elapsed()
+	functions.glitching_switch(False)
+	functions.add_text(f"[auto] glitching stopped (elapsed: {elapsed})")    
+
+def start_chal_02():
+    functions.run_output_high(0, 30000000) ## can also run_output_low() if need too
\ No newline at end of file
diff --git a/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall03.py b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall03.py
new file mode 100644
index 0000000..1099895
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall03.py
@@ -0,0 +1,49 @@
+######
+# config to complete Level 1, Challenge 3 using "glitch-o-bolt"
+######
+# LEAVE THESE IMPORTS!
+######
+import functions
+import random
+from textual.widgets import Log
+
+######
+# config values
+######
+
+SERIAL_PORT = '/dev/ttyUSB0'
+BAUD_RATE = 115200
+
+LENGTH = 6000
+REPEAT = 0
+DELAY = 1098144
+
+###
+# ^ = pullup, v = pulldown
+###
+triggers = [
+    ['-', False],  #0
+    ['v', True],  #1
+    ['-', False],  #2
+    ['-', False],  #3
+    ['-', False],  #4
+    ['-', False],  #5
+    ['-', False],  #6
+    ['-', False],  #7
+]
+
+###
+# name, enabled, string to match
+###
+conditions = [
+    ['Flag', True, 'ctf', 'stop_glitching'],
+]
+
+######
+# Custom functions for conditions to trigger
+######
+
+def stop_glitching():
+        elapsed = functions.get_glitch_elapsed()
+        functions.glitching_switch(False)
+        functions.add_text(f"[auto] glitching stopped (elapsed: {elapsed})") 

diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile
new file mode 100644
index 0000000..e6e7c4d
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile
@@ -0,0 +1,6 @@
+all:
+	arm-none-eabi-gcc -o test.o -c test.S -mthumb -mcpu=cortex-m3 -g3
+	arm-none-eabi-gcc -o main.o -c main.c -mthumb -mcpu=cortex-m3 -Os -g3
+	arm-none-eabi-gcc -o memset.o -c memset.c -mthumb -mcpu=cortex-m3 -Os -g3
+	arm-none-eabi-gcc -o sram.elf test.o main.o memset.o -nostartfiles -nostdlib -Tram.ld -mcpu=cortex-m3 -mthumb -g3
+	arm-none-eabi-objcopy -O binary sram.elf shellcode-0xRoM.bin
diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c
new file mode 100644
index 0000000..4d52bb9
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c
@@ -0,0 +1,323 @@
+#include <stdint.h>
+uint32_t volatile * const rccApb2 = (uint32_t *) 0x40021018u;
+uint32_t volatile * const ioAModerH = (uint32_t *) 0x40010804u;
+uint32_t volatile * const uart1Ctrl = (uint32_t *) 0x40013800u;
+
+void readChar( uint8_t const chr );
+void writeByte( uint8_t b );
+void writeStr( uint8_t const * const str );
+void writeChar( uint8_t const chr );
+void writeWordLe( uint32_t const word );
+void writeWordBe( uint32_t const word );
+void readCmd( uint8_t const * const cmd);
+uint32_t hexToInt(uint8_t const * const hex);
+void readMem(uint32_t const addr, uint32_t const len);
+void writeMem(uint32_t const addr, uint32_t const data);
+
+uint8_t const strHelp[] = 	"Help\r\n-----------\r\n"
+				"ADDR, VAL, LEN: 32-bit Hex encoded:\r\n e.g., 0A1337FF\r\n"
+				"-----------\r\n"
+				"R ADDR LEN - Read 32-bit word\r\n"
+				"W ADDR VAL - Write 32-bit word\r\n"
+				"D          - Dump all flash memory\r\n"
+				"P          - Jump into chall4 function\r\n"
+				"S          - Reboot\r\n"
+				"E          - Exit\r\n"
+				"H          - Show help \r\n"
+				"---------------\r\n";
+
+int main(void)
+{
+	/* IOA + USART1 clock enable */
+	*rccApb2 = (uint32_t) 0x4004u;
+
+	/* USART1 TX+RX (PA9, PX10) on */
+	*ioAModerH = (uint32_t) 0x444444B4u;
+
+	/* config and enable uart */
+	uart1Ctrl[2] = 0x00000341u;
+	uart1Ctrl[3] = 0x0000200Cu;
+	
+	writeStr("\r\n##############################\r\n"
+		 "# Low-Level Shell v.0xRoM    #\r\n"
+		 "# CPU-ID: 0x");
+	uint32_t cpuid = *((uint32_t *) 0xe000ed00);
+	writeWordBe(cpuid);
+	writeStr(                    "         #\r\n");
+	writeStr("##############################\r\n\r\n");
+	writeStr("> ");
+
+	while (1)
+	{
+		if ((uart1Ctrl[0] & 0x80u) && (0))
+		{
+			uart1Ctrl[1] = 0x33u;
+		}
+
+		if (uart1Ctrl[0] & 0x20u)
+		{
+			uint32_t data = uart1Ctrl[1];
+			readChar((uint8_t) data);
+		}
+	}
+}
+
+/* hex must have length 8 */
+uint32_t hexToInt(uint8_t const * const hex)
+{
+	uint32_t ind = 0u;
+	uint32_t res = 0u;
+
+	for (ind = 0; ind < 8; ++ind)
+	{
+		uint8_t chr = hex[ind];
+		uint32_t val = 0u;
+
+		res <<= 4u;
+
+		if ((chr >= '0') && (chr <= '9'))
+		{
+			val = chr - '0';
+		}
+		else if ((chr >= 'a') && (chr <= 'f'))
+		{
+			val = chr - 'a' + 0x0a;
+		}
+		else if ((chr >= 'A') && (chr <= 'F'))
+		{
+			val = chr - 'A' + 0x0a;
+		}
+		else
+		{
+			val = 0u;
+		}
+		res |= val;
+	}
+
+	return res;
+}
+
+void readChar( uint8_t const chr )
+{
+	#define CMDBUF_LEN (64u)
+	static uint8_t cmdbuf[CMDBUF_LEN] = {0u};
+	static uint32_t cmdInd = 0u;
+
+	switch (chr)
+	{
+		case '\n':
+		case '\r':
+			cmdbuf[cmdInd] = 0u;
+			if (cmdInd != 0)
+			{
+				writeStr("\r\n");
+			}
+			readCmd(cmdbuf);
+			cmdInd = 0u;
+			writeStr("\r\n> ");
+			{
+				uint32_t ind = 0u;
+				for (ind = 0; ind<CMDBUF_LEN; ++ind)
+				{
+					cmdbuf[ind]=0x00u;
+				}
+			}
+		break;
+
+		case 8:
+		case 255:
+		case 127: /* TODO backspace */
+			if (cmdInd > 0u)
+				--cmdInd;
+			writeChar(chr);
+		break;
+
+		default:
+			if (cmdInd < (CMDBUF_LEN - 1))
+			{
+				cmdbuf[cmdInd] = chr;
+				++cmdInd;
+				writeChar(chr);
+			}
+		break;
+	}
+}
+
+void readCmd( uint8_t const * const cmd )
+{
+	void (*chall4)(void) = (void (*)(void))0x08000ba9;
+	switch (cmd[0])
+	{
+		case 0:
+			return;
+			break;
+
+		/* chall4 function */
+		case 'p':
+		case 'P':
+			writeStr("time to change baudrate to 115200\r\n");
+			for (volatile uint32_t i = 0; i < 5000000; i++);  // Crude delay
+			chall4();
+			break;
+
+		/* read 32-bit command */
+		case 'r':
+		case 'R':
+			/* r 08000000 00000100 */
+			readMem(hexToInt(&cmd[2]), hexToInt(&cmd[11]));
+			break;
+
+		/* write 32-bit command */
+		case 'w':
+		case 'W':
+			/* w 20000000 12345678 */
+			writeMem(hexToInt(&cmd[2]), hexToInt(&cmd[11]));
+			break;
+
+		/* Dump all flash */
+		case 'd':
+		case 'D':
+			writeStr("\r\n\r\n");
+			{
+				uint32_t const * addr = (uint32_t*) 0x08000000;
+				uint32_t br = 8u;
+				while (((uintptr_t) addr) < (0x08000000 + 64u * 1024u))
+				{
+					if (br == 8u)
+					{
+						writeStr("\r\n[");
+						writeWordBe((uint32_t) addr);
+						writeStr("]: ");
+						br = 0u;
+					}
+
+					writeWordBe(*addr);
+					writeChar(' ');
+					++addr;
+					++br;
+				}
+			}
+			writeStr("\r\n\r\n");
+			break;
+
+		/* Help command */
+		case 'h':
+		case 'H':
+			writeStr(strHelp);
+			break;
+
+		/* Reboot */
+		case 's':
+		case 'S':
+			writeStr("Rebooting...\r\n\r\n");
+			*((uint32_t *) 0xE000ED0C) = 0x05FA0004u;
+			break;
+
+		/* exit */
+		case 'e':
+		case 'E':
+			writeStr("Bye.\r\n");
+			while (1)
+			{
+				__asm__ volatile("wfi");
+			}
+			break;
+
+
+		default:
+			writeStr("Unknown command: ");
+			writeStr(cmd);
+			writeStr("\r\n");
+			break;
+	}
+}
+	
+const uint8_t txtMap[] = "0123456789ABCDEF";
+
+void writeByte( uint8_t b )
+{
+	writeChar(txtMap[b >> 4]);
+	writeChar(txtMap[b & 0x0F]);
+}
+
+
+void writeStr( uint8_t const * const str )
+{
+	uint32_t ind = 0u;
+
+	while (str[ind])
+	{
+		writeChar(str[ind]);
+		++ind;
+	}
+}
+
+void writeChar( uint8_t const chr )
+{
+	while (!(uart1Ctrl[0] & 0x80u))
+	{
+		/* wait */
+	}
+
+	uart1Ctrl[1] = chr;
+}
+
+void writeWordLe( uint32_t const word )
+{
+	writeByte((word & 0x000000FF));
+	writeByte((word & 0x0000FF00) >> 8);
+	writeByte((word & 0x00FF0000) >> 16);
+	writeByte((word & 0xFF000000) >> 24);
+}
+
+void writeWordBe( uint32_t const word )
+{
+	writeByte((word & 0xFF000000) >> 24);
+	writeByte((word & 0x00FF0000) >> 16);
+	writeByte((word & 0x0000FF00) >> 8);
+	writeByte((word & 0x000000FF));
+
+}
+
+void alertCrash( uint32_t crashId )
+{
+	writeStr("!!! EXCEPTION !!!\r\nID: ");
+	writeByte(crashId);
+	writeStr("\r\nRestart required!\r\n\r\n");
+	*((uint32_t *) 0xE000ED0C) = 0x05FA0004u;
+	while (1);
+}
+
+void readMem(uint32_t const addr, uint32_t const len)
+{
+	uint32_t it = 0u;
+	uint32_t addrx = 0u;
+	uint32_t lenx = 0u;
+
+	lenx = len;
+	if (lenx == 0u)
+	{
+		lenx = 4u;
+	}
+
+	for (it = 0u; it < (lenx / 4u); ++it)
+	{
+		addrx = addr + it*4u;
+		writeStr("Read [");
+		writeWordBe(addrx);
+		writeStr("]: ");
+		writeWordBe(*((uint32_t*)addrx));
+		writeStr("\r\n");
+	}
+}
+
+void writeMem(uint32_t const addr, uint32_t const data)
+{
+	writeStr("Write [");
+	writeWordBe(addr);
+	writeStr("]: ");
+	writeWordBe(data);
+	*((uint32_t*) addr) = data;
+	writeStr("\r\n");
+}
+
diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c
new file mode 100644
index 0000000..83154c6
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c
@@ -0,0 +1,19 @@
+// memset.c
+void *memset(void *dest, int val, unsigned int len) {
+    unsigned char *ptr = dest;
+    unsigned int value = (unsigned char)val; // Promote to avoid unnecessary casting
+
+    // Use a word-by-word copy if possible
+    while (len >= 4) {
+        *(unsigned int*)ptr = value | (value << 8) | (value << 16) | (value << 24);
+        ptr += 4;
+        len -= 4;
+    }
+
+    // If any bytes are left, fill them
+    while (len--) {
+        *ptr++ = (unsigned char)value;
+    }
+
+    return dest;
+}
diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin
new file mode 100644
index 0000000..2c9c70f
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin
Binary files differ
diff --git a/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall02.py b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall02.py
new file mode 100644
index 0000000..6a4b4a2
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall02.py
@@ -0,0 +1,54 @@
+######
+# config to complete Level 1, Challenge 2 using "glitch-o-bolt"
+######
+# LEAVE THESE IMPORTS!
+######
+import functions
+import random
+from textual.widgets import Log
+
+######
+# config values
+######
+
+SERIAL_PORT = '/dev/ttyUSB0'
+BAUD_RATE = 115200
+
+LENGTH = 42
+REPEAT = 1
+DELAY = 0
+
+###
+# ^ = pullup, v = pulldown
+###
+triggers = [
+    ['-', False],  #0
+    ['-', False],  #1
+    ['-', False],  #2
+    ['-', False],  #3
+    ['-', False],  #4
+    ['-', False],  #5
+    ['-', False],  #6
+    ['-', False],  #7
+]
+
+###
+# name, enabled, string to match in output, function to run
+# if string is blank ("") doesnt show toggle, just run button
+###
+conditions = [
+    ["Flag", True,  "ctf", "stop_glitching"],
+    ["Chal2", True, "Hold one of", "start_chal_02"] # requires bolt output gpio pin 0 -> challenge board chall 2 button
+]
+
+######
+# Custom functions for conditions to trigger
+######
+
+def stop_glitching():
+	elapsed = functions.get_glitch_elapsed()
+	functions.glitching_switch(False)
+	functions.add_text(f"[auto] glitching stopped (elapsed: {elapsed})")    
+
+def start_chal_02():
+    functions.run_output_high(0, 30000000) ## can also run_output_low() if need too
\ No newline at end of file
diff --git a/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall03.py b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall03.py
new file mode 100644
index 0000000..1099895
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall03.py
@@ -0,0 +1,49 @@
+######
+# config to complete Level 1, Challenge 3 using "glitch-o-bolt"
+######
+# LEAVE THESE IMPORTS!
+######
+import functions
+import random
+from textual.widgets import Log
+
+######
+# config values
+######
+
+SERIAL_PORT = '/dev/ttyUSB0'
+BAUD_RATE = 115200
+
+LENGTH = 6000
+REPEAT = 0
+DELAY = 1098144
+
+###
+# ^ = pullup, v = pulldown
+###
+triggers = [
+    ['-', False],  #0
+    ['v', True],  #1
+    ['-', False],  #2
+    ['-', False],  #3
+    ['-', False],  #4
+    ['-', False],  #5
+    ['-', False],  #6
+    ['-', False],  #7
+]
+
+###
+# name, enabled, string to match
+###
+conditions = [
+    ['Flag', True, 'ctf', 'stop_glitching'],
+]
+
+######
+# Custom functions for conditions to trigger
+######
+
+def stop_glitching():
+        elapsed = functions.get_glitch_elapsed()
+        functions.glitching_switch(False)
+        functions.add_text(f"[auto] glitching stopped (elapsed: {elapsed})") 
diff --git a/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall04.py b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall04.py
new file mode 100644
index 0000000..d1c2ea1
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall04.py
@@ -0,0 +1,94 @@
+######
+# config to complete Level 1, Challenge 4 using "glitch-o-bolt"
+######
+# LEAVE THESE IMPORTS!
+######
+import time
+import functions
+
+from pyocd.core.helpers import ConnectHelper
+from pyocd.flash.file_programmer import FileProgrammer
+
+######
+# config values
+######
+
+SERIAL_PORT = '/dev/ttyUSB0'
+BAUD_RATE = 115200
+
+LENGTH = 50
+REPEAT = 1
+DELAY = 1
+
+###
+# name, enabled, string to match
+###
+conditions = [
+    ['Start', False, '', 'start_chall_04'],
+    ['Step1', False, '', 'step_1'],
+    ['Step2', False, '', 'step_2'],
+]
+
+######
+# Custom functions for conditions to trigger
+######
+
+def start_chall_04():
+    functions.add_text(f"[Chall 4] enable uart switch then hold chall 4 button to load the challenge into memory.")
+    functions.add_text(f"[Chall 4] once loaded hold 'boot 1' button and press 'reset' button to put in bootloader mode") 
+    functions.add_text(f"[Chall 4] then press 'Step1'")
+
+def step_1():
+    functions.set_uart_switch(False)
+
+    functions.add_text(f"\n[Chall 4] uploading firmware to ram... please wait")
+
+    # Connect to the target board
+    session = ConnectHelper.session_with_chosen_probe()
+    session.open()
+
+    # Optionally halt the target
+    target = session.target
+    target.halt()
+
+    # Load binary file to specified address (e.g., 0x20000000)
+    newFirmware = "/tmp/f103-analysis/h3/rootshell/shellcode-0xRoM.bin"
+    programmer = FileProgrammer(session)
+    programmer.program(newFirmware, base_address=0x20000000, file_format='bin')
+
+    # Optionally resume execution
+    target.resume()
+    # Clean up
+    session.close()
+
+    with open(newFirmware, "rb") as f:
+        original_data = f.read()
+
+    # Connect to the target
+    session = ConnectHelper.session_with_chosen_probe()
+    session.open()
+
+    target = session.target
+    target.halt()
+
+    # Read back the memory from the target
+    read_data = target.read_memory_block8(0x20000000, len(original_data))
+
+    # Compare
+    if bytes(read_data) == original_data:
+         functions.add_text(f"[+] Shellcode loaded successfully.")
+    else:
+         functions.add_text(f"[!] Mismatch detected. Shellcode may not have loaded correctly.")
+
+    session.close()
+
+    functions.change_baudrate(9600)
+    functions.add_text(f"[Chall 4] hold buttons 'boot0' and 'boot1' and press the 'glitch' button")
+    functions.add_text(f"[Chall 4] this single glitch will boot from SRAM")
+    functions.add_text(f"[Chall 4] enable UART to access 'Low-level Shell' (might need to press reset)")
+    functions.add_text(f"[Chall 4] then press 'Step2'")
+    
+def step_2():
+    functions.send_uart_message("p") 
+    time.sleep(1)
+    functions.change_baudrate(115200)

diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile
new file mode 100644
index 0000000..e6e7c4d
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/Makefile
@@ -0,0 +1,6 @@
+all:
+	arm-none-eabi-gcc -o test.o -c test.S -mthumb -mcpu=cortex-m3 -g3
+	arm-none-eabi-gcc -o main.o -c main.c -mthumb -mcpu=cortex-m3 -Os -g3
+	arm-none-eabi-gcc -o memset.o -c memset.c -mthumb -mcpu=cortex-m3 -Os -g3
+	arm-none-eabi-gcc -o sram.elf test.o main.o memset.o -nostartfiles -nostdlib -Tram.ld -mcpu=cortex-m3 -mthumb -g3
+	arm-none-eabi-objcopy -O binary sram.elf shellcode-0xRoM.bin
diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c
new file mode 100644
index 0000000..4d52bb9
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/main.c
@@ -0,0 +1,323 @@
+#include <stdint.h>
+uint32_t volatile * const rccApb2 = (uint32_t *) 0x40021018u;
+uint32_t volatile * const ioAModerH = (uint32_t *) 0x40010804u;
+uint32_t volatile * const uart1Ctrl = (uint32_t *) 0x40013800u;
+
+void readChar( uint8_t const chr );
+void writeByte( uint8_t b );
+void writeStr( uint8_t const * const str );
+void writeChar( uint8_t const chr );
+void writeWordLe( uint32_t const word );
+void writeWordBe( uint32_t const word );
+void readCmd( uint8_t const * const cmd);
+uint32_t hexToInt(uint8_t const * const hex);
+void readMem(uint32_t const addr, uint32_t const len);
+void writeMem(uint32_t const addr, uint32_t const data);
+
+uint8_t const strHelp[] = 	"Help\r\n-----------\r\n"
+				"ADDR, VAL, LEN: 32-bit Hex encoded:\r\n e.g., 0A1337FF\r\n"
+				"-----------\r\n"
+				"R ADDR LEN - Read 32-bit word\r\n"
+				"W ADDR VAL - Write 32-bit word\r\n"
+				"D          - Dump all flash memory\r\n"
+				"P          - Jump into chall4 function\r\n"
+				"S          - Reboot\r\n"
+				"E          - Exit\r\n"
+				"H          - Show help \r\n"
+				"---------------\r\n";
+
+int main(void)
+{
+	/* IOA + USART1 clock enable */
+	*rccApb2 = (uint32_t) 0x4004u;
+
+	/* USART1 TX+RX (PA9, PX10) on */
+	*ioAModerH = (uint32_t) 0x444444B4u;
+
+	/* config and enable uart */
+	uart1Ctrl[2] = 0x00000341u;
+	uart1Ctrl[3] = 0x0000200Cu;
+	
+	writeStr("\r\n##############################\r\n"
+		 "# Low-Level Shell v.0xRoM    #\r\n"
+		 "# CPU-ID: 0x");
+	uint32_t cpuid = *((uint32_t *) 0xe000ed00);
+	writeWordBe(cpuid);
+	writeStr(                    "         #\r\n");
+	writeStr("##############################\r\n\r\n");
+	writeStr("> ");
+
+	while (1)
+	{
+		if ((uart1Ctrl[0] & 0x80u) && (0))
+		{
+			uart1Ctrl[1] = 0x33u;
+		}
+
+		if (uart1Ctrl[0] & 0x20u)
+		{
+			uint32_t data = uart1Ctrl[1];
+			readChar((uint8_t) data);
+		}
+	}
+}
+
+/* hex must have length 8 */
+uint32_t hexToInt(uint8_t const * const hex)
+{
+	uint32_t ind = 0u;
+	uint32_t res = 0u;
+
+	for (ind = 0; ind < 8; ++ind)
+	{
+		uint8_t chr = hex[ind];
+		uint32_t val = 0u;
+
+		res <<= 4u;
+
+		if ((chr >= '0') && (chr <= '9'))
+		{
+			val = chr - '0';
+		}
+		else if ((chr >= 'a') && (chr <= 'f'))
+		{
+			val = chr - 'a' + 0x0a;
+		}
+		else if ((chr >= 'A') && (chr <= 'F'))
+		{
+			val = chr - 'A' + 0x0a;
+		}
+		else
+		{
+			val = 0u;
+		}
+		res |= val;
+	}
+
+	return res;
+}
+
+void readChar( uint8_t const chr )
+{
+	#define CMDBUF_LEN (64u)
+	static uint8_t cmdbuf[CMDBUF_LEN] = {0u};
+	static uint32_t cmdInd = 0u;
+
+	switch (chr)
+	{
+		case '\n':
+		case '\r':
+			cmdbuf[cmdInd] = 0u;
+			if (cmdInd != 0)
+			{
+				writeStr("\r\n");
+			}
+			readCmd(cmdbuf);
+			cmdInd = 0u;
+			writeStr("\r\n> ");
+			{
+				uint32_t ind = 0u;
+				for (ind = 0; ind<CMDBUF_LEN; ++ind)
+				{
+					cmdbuf[ind]=0x00u;
+				}
+			}
+		break;
+
+		case 8:
+		case 255:
+		case 127: /* TODO backspace */
+			if (cmdInd > 0u)
+				--cmdInd;
+			writeChar(chr);
+		break;
+
+		default:
+			if (cmdInd < (CMDBUF_LEN - 1))
+			{
+				cmdbuf[cmdInd] = chr;
+				++cmdInd;
+				writeChar(chr);
+			}
+		break;
+	}
+}
+
+void readCmd( uint8_t const * const cmd )
+{
+	void (*chall4)(void) = (void (*)(void))0x08000ba9;
+	switch (cmd[0])
+	{
+		case 0:
+			return;
+			break;
+
+		/* chall4 function */
+		case 'p':
+		case 'P':
+			writeStr("time to change baudrate to 115200\r\n");
+			for (volatile uint32_t i = 0; i < 5000000; i++);  // Crude delay
+			chall4();
+			break;
+
+		/* read 32-bit command */
+		case 'r':
+		case 'R':
+			/* r 08000000 00000100 */
+			readMem(hexToInt(&cmd[2]), hexToInt(&cmd[11]));
+			break;
+
+		/* write 32-bit command */
+		case 'w':
+		case 'W':
+			/* w 20000000 12345678 */
+			writeMem(hexToInt(&cmd[2]), hexToInt(&cmd[11]));
+			break;
+
+		/* Dump all flash */
+		case 'd':
+		case 'D':
+			writeStr("\r\n\r\n");
+			{
+				uint32_t const * addr = (uint32_t*) 0x08000000;
+				uint32_t br = 8u;
+				while (((uintptr_t) addr) < (0x08000000 + 64u * 1024u))
+				{
+					if (br == 8u)
+					{
+						writeStr("\r\n[");
+						writeWordBe((uint32_t) addr);
+						writeStr("]: ");
+						br = 0u;
+					}
+
+					writeWordBe(*addr);
+					writeChar(' ');
+					++addr;
+					++br;
+				}
+			}
+			writeStr("\r\n\r\n");
+			break;
+
+		/* Help command */
+		case 'h':
+		case 'H':
+			writeStr(strHelp);
+			break;
+
+		/* Reboot */
+		case 's':
+		case 'S':
+			writeStr("Rebooting...\r\n\r\n");
+			*((uint32_t *) 0xE000ED0C) = 0x05FA0004u;
+			break;
+
+		/* exit */
+		case 'e':
+		case 'E':
+			writeStr("Bye.\r\n");
+			while (1)
+			{
+				__asm__ volatile("wfi");
+			}
+			break;
+
+
+		default:
+			writeStr("Unknown command: ");
+			writeStr(cmd);
+			writeStr("\r\n");
+			break;
+	}
+}
+	
+const uint8_t txtMap[] = "0123456789ABCDEF";
+
+void writeByte( uint8_t b )
+{
+	writeChar(txtMap[b >> 4]);
+	writeChar(txtMap[b & 0x0F]);
+}
+
+
+void writeStr( uint8_t const * const str )
+{
+	uint32_t ind = 0u;
+
+	while (str[ind])
+	{
+		writeChar(str[ind]);
+		++ind;
+	}
+}
+
+void writeChar( uint8_t const chr )
+{
+	while (!(uart1Ctrl[0] & 0x80u))
+	{
+		/* wait */
+	}
+
+	uart1Ctrl[1] = chr;
+}
+
+void writeWordLe( uint32_t const word )
+{
+	writeByte((word & 0x000000FF));
+	writeByte((word & 0x0000FF00) >> 8);
+	writeByte((word & 0x00FF0000) >> 16);
+	writeByte((word & 0xFF000000) >> 24);
+}
+
+void writeWordBe( uint32_t const word )
+{
+	writeByte((word & 0xFF000000) >> 24);
+	writeByte((word & 0x00FF0000) >> 16);
+	writeByte((word & 0x0000FF00) >> 8);
+	writeByte((word & 0x000000FF));
+
+}
+
+void alertCrash( uint32_t crashId )
+{
+	writeStr("!!! EXCEPTION !!!\r\nID: ");
+	writeByte(crashId);
+	writeStr("\r\nRestart required!\r\n\r\n");
+	*((uint32_t *) 0xE000ED0C) = 0x05FA0004u;
+	while (1);
+}
+
+void readMem(uint32_t const addr, uint32_t const len)
+{
+	uint32_t it = 0u;
+	uint32_t addrx = 0u;
+	uint32_t lenx = 0u;
+
+	lenx = len;
+	if (lenx == 0u)
+	{
+		lenx = 4u;
+	}
+
+	for (it = 0u; it < (lenx / 4u); ++it)
+	{
+		addrx = addr + it*4u;
+		writeStr("Read [");
+		writeWordBe(addrx);
+		writeStr("]: ");
+		writeWordBe(*((uint32_t*)addrx));
+		writeStr("\r\n");
+	}
+}
+
+void writeMem(uint32_t const addr, uint32_t const data)
+{
+	writeStr("Write [");
+	writeWordBe(addr);
+	writeStr("]: ");
+	writeWordBe(data);
+	*((uint32_t*) addr) = data;
+	writeStr("\r\n");
+}
+
diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c
new file mode 100644
index 0000000..83154c6
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4-Firmware/memset.c
@@ -0,0 +1,19 @@
+// memset.c
+void *memset(void *dest, int val, unsigned int len) {
+    unsigned char *ptr = dest;
+    unsigned int value = (unsigned char)val; // Promote to avoid unnecessary casting
+
+    // Use a word-by-word copy if possible
+    while (len >= 4) {
+        *(unsigned int*)ptr = value | (value << 8) | (value << 16) | (value << 24);
+        ptr += 4;
+        len -= 4;
+    }
+
+    // If any bytes are left, fill them
+    while (len--) {
+        *ptr++ = (unsigned char)value;
+    }
+
+    return dest;
+}
diff --git a/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin
new file mode 100644
index 0000000..2c9c70f
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/Chall-4_Shellcode-0xRoM.bin
Binary files differ
diff --git a/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall02.py b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall02.py
new file mode 100644
index 0000000..6a4b4a2
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall02.py
@@ -0,0 +1,54 @@
+######
+# config to complete Level 1, Challenge 2 using "glitch-o-bolt"
+######
+# LEAVE THESE IMPORTS!
+######
+import functions
+import random
+from textual.widgets import Log
+
+######
+# config values
+######
+
+SERIAL_PORT = '/dev/ttyUSB0'
+BAUD_RATE = 115200
+
+LENGTH = 42
+REPEAT = 1
+DELAY = 0
+
+###
+# ^ = pullup, v = pulldown
+###
+triggers = [
+    ['-', False],  #0
+    ['-', False],  #1
+    ['-', False],  #2
+    ['-', False],  #3
+    ['-', False],  #4
+    ['-', False],  #5
+    ['-', False],  #6
+    ['-', False],  #7
+]
+
+###
+# name, enabled, string to match in output, function to run
+# if string is blank ("") doesnt show toggle, just run button
+###
+conditions = [
+    ["Flag", True,  "ctf", "stop_glitching"],
+    ["Chal2", True, "Hold one of", "start_chal_02"] # requires bolt output gpio pin 0 -> challenge board chall 2 button
+]
+
+######
+# Custom functions for conditions to trigger
+######
+
+def stop_glitching():
+	elapsed = functions.get_glitch_elapsed()
+	functions.glitching_switch(False)
+	functions.add_text(f"[auto] glitching stopped (elapsed: {elapsed})")    
+
+def start_chal_02():
+    functions.run_output_high(0, 30000000) ## can also run_output_low() if need too
\ No newline at end of file
diff --git a/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall03.py b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall03.py
new file mode 100644
index 0000000..1099895
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall03.py
@@ -0,0 +1,49 @@
+######
+# config to complete Level 1, Challenge 3 using "glitch-o-bolt"
+######
+# LEAVE THESE IMPORTS!
+######
+import functions
+import random
+from textual.widgets import Log
+
+######
+# config values
+######
+
+SERIAL_PORT = '/dev/ttyUSB0'
+BAUD_RATE = 115200
+
+LENGTH = 6000
+REPEAT = 0
+DELAY = 1098144
+
+###
+# ^ = pullup, v = pulldown
+###
+triggers = [
+    ['-', False],  #0
+    ['v', True],  #1
+    ['-', False],  #2
+    ['-', False],  #3
+    ['-', False],  #4
+    ['-', False],  #5
+    ['-', False],  #6
+    ['-', False],  #7
+]
+
+###
+# name, enabled, string to match
+###
+conditions = [
+    ['Flag', True, 'ctf', 'stop_glitching'],
+]
+
+######
+# Custom functions for conditions to trigger
+######
+
+def stop_glitching():
+        elapsed = functions.get_glitch_elapsed()
+        functions.glitching_switch(False)
+        functions.add_text(f"[auto] glitching stopped (elapsed: {elapsed})") 
diff --git a/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall04.py b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall04.py
new file mode 100644
index 0000000..d1c2ea1
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/ConfigChall04.py
@@ -0,0 +1,94 @@
+######
+# config to complete Level 1, Challenge 4 using "glitch-o-bolt"
+######
+# LEAVE THESE IMPORTS!
+######
+import time
+import functions
+
+from pyocd.core.helpers import ConnectHelper
+from pyocd.flash.file_programmer import FileProgrammer
+
+######
+# config values
+######
+
+SERIAL_PORT = '/dev/ttyUSB0'
+BAUD_RATE = 115200
+
+LENGTH = 50
+REPEAT = 1
+DELAY = 1
+
+###
+# name, enabled, string to match
+###
+conditions = [
+    ['Start', False, '', 'start_chall_04'],
+    ['Step1', False, '', 'step_1'],
+    ['Step2', False, '', 'step_2'],
+]
+
+######
+# Custom functions for conditions to trigger
+######
+
+def start_chall_04():
+    functions.add_text(f"[Chall 4] enable uart switch then hold chall 4 button to load the challenge into memory.")
+    functions.add_text(f"[Chall 4] once loaded hold 'boot 1' button and press 'reset' button to put in bootloader mode") 
+    functions.add_text(f"[Chall 4] then press 'Step1'")
+
+def step_1():
+    functions.set_uart_switch(False)
+
+    functions.add_text(f"\n[Chall 4] uploading firmware to ram... please wait")
+
+    # Connect to the target board
+    session = ConnectHelper.session_with_chosen_probe()
+    session.open()
+
+    # Optionally halt the target
+    target = session.target
+    target.halt()
+
+    # Load binary file to specified address (e.g., 0x20000000)
+    newFirmware = "/tmp/f103-analysis/h3/rootshell/shellcode-0xRoM.bin"
+    programmer = FileProgrammer(session)
+    programmer.program(newFirmware, base_address=0x20000000, file_format='bin')
+
+    # Optionally resume execution
+    target.resume()
+    # Clean up
+    session.close()
+
+    with open(newFirmware, "rb") as f:
+        original_data = f.read()
+
+    # Connect to the target
+    session = ConnectHelper.session_with_chosen_probe()
+    session.open()
+
+    target = session.target
+    target.halt()
+
+    # Read back the memory from the target
+    read_data = target.read_memory_block8(0x20000000, len(original_data))
+
+    # Compare
+    if bytes(read_data) == original_data:
+         functions.add_text(f"[+] Shellcode loaded successfully.")
+    else:
+         functions.add_text(f"[!] Mismatch detected. Shellcode may not have loaded correctly.")
+
+    session.close()
+
+    functions.change_baudrate(9600)
+    functions.add_text(f"[Chall 4] hold buttons 'boot0' and 'boot1' and press the 'glitch' button")
+    functions.add_text(f"[Chall 4] this single glitch will boot from SRAM")
+    functions.add_text(f"[Chall 4] enable UART to access 'Low-level Shell' (might need to press reset)")
+    functions.add_text(f"[Chall 4] then press 'Step2'")
+    
+def step_2():
+    functions.send_uart_message("p") 
+    time.sleep(1)
+    functions.change_baudrate(115200)
diff --git a/FaultInjection/examples/CuriousBolt/Level-1/glitch-o-matic.py b/FaultInjection/examples/CuriousBolt/Level-1/glitch-o-matic.py
new file mode 100644
index 0000000..784b70e
--- /dev/null
+++ b/FaultInjection/examples/CuriousBolt/Level-1/glitch-o-matic.py
@@ -0,0 +1,223 @@
+import serial
+import time
+import sys
+import os
+from tabulate import tabulate
+from scope import Scope
+from collections import deque
+
+# Serial port settings
+SERIAL_PORT = "/dev/ttyUSB0"
+BAUD_RATE = 115200
+TIMEOUT = 2
+
+# Glitch configuration limits
+INCREMENT_LEN = 1
+LOWER_GLITCH_LEN = 41
+UPPER_GLITCH_LEN = 60
+
+INCREMENT_REPEAT = 1
+LOWER_GLITCH_REPEAT = 1
+UPPER_GLITCH_REPEAT = 30
+
+INCREMENT_DELAY = 5
+LOWER_DELAY_TIME = 0
+UPPER_DELAY_TIME = 30
+
+message_history = deque(maxlen=20)
+
+def restartDeviceAndChall():
+    s.io.add(0, 0, delay=20000000)
+    s.io.add(0, 1, delay=20000000)
+    s.io.upload()
+    s.trigger()
+    time.sleep(5)
+    
+    s.io.add(1, 1, delay=30000000)
+    s.io.add(1, 0, delay=30000000)
+    s.io.upload()
+    s.trigger()
+    time.sleep(5)
+
+def restartChall():
+    s.io.add(1, 1, delay=30000000)
+    s.io.add(1, 0, delay=30000000)
+    s.io.upload()
+    s.trigger()
+    time.sleep(5)
+
+def clear_console():
+    os.system('cls' if os.name == 'nt' else 'clear')
+
+def store_message(message):
+    message_history.append(message)
+
+def print_info(message):
+    store_message(f"[INFO] {message}")
+
+def print_warning(message):
+    store_message(f"[WARNING] {message}")
+
+def print_error(message):
+    store_message(f"[ERROR] {message}")
+
+def print_last_x_messages(x):
+    # Ensure we print only the last 'x' messages, or all if less than x
+    for msg in list(message_history)[-x:]:
+        print(msg)
+
+def format_elapsed_time(seconds):
+    days = seconds // (24 * 3600)
+    hours = (seconds % (24 * 3600)) // 3600
+    minutes = (seconds % 3600) // 60
+    seconds = seconds % 60
+    return f"{int(days)}d {int(hours)}h {int(minutes)}m {int(seconds)}s"
+
+def print_table(
+glitch_len, trigger_repeats, delay_time, elapsed_time):
+    headers = ["Glitch Len", "Repeats", "Delay", "Elapsed Time"]
+    data = [[f"{glitch_len} / {UPPER_GLITCH_LEN}", 
+             f"{trigger_repeats} / {UPPER_GLITCH_REPEAT}", 
+             f"{delay_time} / {UPPER_DELAY_TIME}", 
+             elapsed_time]]
+
+    clear_console()
+    print_banner()
+    print(tabulate(data, headers=headers, tablefmt="fancy_grid"))
+
+def connect_serial():
+    try:
+        ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=TIMEOUT)
+        print_info("Connected to serial port.")
+        
+        time.sleep(1)
+        ser.flushInput()
+        version_info = ser.readline().decode("utf-8", errors="ignore").strip()
+
+        if version_info:
+            print_info(f"Connected to version: {version_info}")
+        else:
+            print_warning("No version information received. Device might be unresponsive.")
+
+        return ser
+    except serial.SerialException as e:
+        print_error(f"Could not open serial port {SERIAL_PORT}: {e}")
+        sys.exit(1)
+
+def read_serial():
+    global glitch_len, trigger_repeats, delay_time
+    global UPPER_GLITCH_LEN, LOWER_GLITCH_LEN, INCREMENT_LEN
+    global UPPER_GLITCH_REPEAT, LOWER_GLITCH_REPEAT, INCREMENT_REPEAT
+    global UPPER_DELAY_TIME, LOWER_DELAY_TIME, INCREMENT_DELAY
+    
+    glitch_len = LOWER_GLITCH_LEN
+    trigger_repeats = LOWER_GLITCH_REPEAT
+    delay_time = LOWER_DELAY_TIME
+    start_time = time.time()
+
+    last_restart_time = time.time()
+    restart_interval = 600 # 600 secs = 10 min
+
+    ser = connect_serial()
+    print_info("Restarting device and challenge")
+    #restartDeviceAndChall()
+    
+    while True:
+        cycle_start_time = time.time()
+        line = ""
+
+        while time.time() - cycle_start_time < TIMEOUT:
+            if ser.in_waiting > 0:
+                char = ser.read().decode("utf-8", errors="ignore")
+                line += char
+                if char == '\n':
+                    break
+
+        if line:
+            line = line.strip()
+            print_info(f"Received data: {line}")
+
+            line_lower = line.lower()
+
+            if "ctf" in line_lower:
+                print_info(f"Flag: {line}")
+                print_warning("Received 'ctf', exiting...")
+                print_table(glitch_len, trigger_repeats, delay_time, elapsed_time)
+                print_last_x_messages(10)
+                sys.exit()
+            
+            elif "starting challenge" in line_lower:
+                print_info("Detected 'Starting Challenge'. Resetting glitch repeat count.")
+                if (glitch_len + trigger_repeats) % 2 == 0:
+                    #UPPER_GLITCH_REPEAT = trigger_repeats
+                    trigger_repeats -= INCREMENT_REPEAT
+                    glitch_len += INCREMENT_LEN
+                else:
+                    UPPER_GLITCH_LEN = glitch_len
+                    glitch_len -= INCREMENT_LEN
+                    trigger_repeats += INCREMENT_REPEAT
+
+            elif "hold" in line_lower:
+                print_info("Detected 'Hold'. Restarting Challenge.")
+                #restartChall()
+
+            else:
+                execute_scope_script(glitch_len, trigger_repeats, delay_time)
+
+                 # 1. Increment delay time first
+                if delay_time < UPPER_DELAY_TIME:
+                    delay_time += INCREMENT_DELAY
+                else:
+                    delay_time = LOWER_DELAY_TIME  # Reset delay time
+
+                    # 2. Alternate between glitch_len and trigger_repeats when delay resets
+                    if (glitch_len + trigger_repeats) % 2 == 0:
+                        if glitch_len < UPPER_GLITCH_LEN:
+                            glitch_len += INCREMENT_LEN
+                            print_info(f"Incrementing glitch length: {glitch_len}")
+                        elif (glitch_len > UPPER_GLITCH_LEN):
+                            UPPER_GLITCH_LEN += INCREMENT_LEN
+                        else:
+                            glitch_len = LOWER_GLITCH_LEN  # Reset glitch length
+                            trigger_repeats += INCREMENT_REPEAT  # Increment trigger repeats
+                            print_info(f"Glitch length reset. Incrementing trigger repeats: {trigger_repeats}")
+                    else:
+                        if trigger_repeats < UPPER_GLITCH_REPEAT:
+                            trigger_repeats += INCREMENT_REPEAT
+                            print_info(f"Incrementing trigger repeats: {trigger_repeats}")
+                        else:
+                            if(glitch_len == UPPER_GLITCH_LEN):
+                                trigger_repeats = LOWER_GLITCH_REPEAT  # Reset trigger repeats
+                            else:
+                                trigger_repeats = LOWER_GLITCH_REPEAT
+                                glitch_len += INCREMENT_LEN  # Increment glitch length
+                            print_info(f"Trigger repeats reset. Incrementing glitch length: {glitch_len}")
+
+
+                elapsed_time = format_elapsed_time(time.time() - start_time)
+                print_table(glitch_len, trigger_repeats, delay_time, elapsed_time)
+                # To print the last 3 messages
+                print_last_x_messages(10)
+
+                if time.time() - last_restart_time >= restart_interval:
+                    print_info(f"10 min mark. Setting glitch length: 80 and restarting device")
+                    UPPER_GLITCH_LEN = 80
+                    #restartDeviceAndChall()
+                    last_restart_time = time.time()
+
+def execute_scope_script(glitch_len, trigger_repeats, delay):
+    s.glitch.repeat = glitch_len
+    s.glitch.ext_offset = delay
+    for _ in range(trigger_repeats):
+        s.trigger()
+
+def print_banner():
+    print("   ___ _ _ _      _                          _   _    ")
+    print("  / __| (_) |_ __| |_ ___ ___ ___ _ __  __ _| |_(_)__ ")
+    print(" | (_ | | |  _/ _| ' \\___/ _ \\___| '  \\/ _` |  _| / _|")
+    print("  \\___|_|_|\\__\\__|_||_|  \\___/   |_|_|_\\__,_|\\__|_\\__|")
+
+if __name__ == "__main__":
+    print_info("Starting Program")
+    s = Scope()
+    read_serial()
\ No newline at end of file