From cbde04c9bc45ea54cc509a65247c62a82f64bca9 Mon Sep 17 00:00:00 2001 From: LennertW <4999638+LennertW@users.noreply.github.com> Date: Sat, 6 Aug 2022 18:39:43 +0200 Subject: Initial commit --- src/python/example.py | 72 +++++++++++++++++++++++++++ src/python/pulsegen.py | 130 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 202 insertions(+) create mode 100644 src/python/example.py create mode 100644 src/python/pulsegen.py (limited to 'src/python') diff --git a/src/python/example.py b/src/python/example.py new file mode 100644 index 0000000..6995940 --- /dev/null +++ b/src/python/example.py @@ -0,0 +1,72 @@ +import numpy as np +import time +import serial +from tqdm import tnrange, tqdm +import random +from pulsegen import PicoPulseGen + +# Open serial interface +# I'm using this to detect when the glitch was successful +try: + ser = serial.Serial('/dev/ttyUSB0', 115200) + +except Exception as e: + print('Could not open /dev/ttyUSB0') + exit() + +# Connect to modchip +try: + glitcher = PicoPulseGen('/dev/ttyACM0') + logger.info('Connected to modchip') + + # You have to figure out the trig_edges parameter + # You have to figure out ranges for the pulse_offset and pulse_width parameters + glitcher.trig_edges = 0 + glitcher.pulse_offset = 0 + glitcher.pulse_width = 0 + glitcher.set_gpio(0) + +except Exception as e: + print('Could not connect to modchip') + exit() + +input("Press enter to start.") + +def generator(): + while True: + yield + +idx = 0 +success = False +for _ in tqdm(generator()): + if idx % 10 == 0: + # Pulse width and offset are expressed in number of cycles of the PIO state machine operating frequency (default in the provided fw is 250MHz). + glitch_width = random.randint(A, B) # You have to figure out good ranges here + glitch_offset = random.randint(C, D) + + glitcher.pulse_offset = glitch_offset + glitcher.pulse_width = glitch_width + + ser.reset_input_buffer() + glitcher.arm() # Arm the modchip, it will try to power up the UT and will wait for the number of set trigger pulses to occur before inserting a glitch + glitcher.wait_trig(timeout=5) # Waits for the modchip to signal it has triggered. The modchip will be disarmed if no glitch has occurred within 5 seconds. + + time.sleep(0.55) # Have to wait for the second stage to start to see serial output + data = ser.read(ser.in_waiting) + + if b'LENNERT' in data: # a check to determine if the glitch was successful. My BL2 has been modified to print LENNERT. + success = True + break + + glitcher.set_gpio(0) # Disables the core voltage regulator. The modchip firmware will re-enable the regulator automatically on the next glitch attempt. + time.sleep(0.1) + + idx += 1 + +if success: + print('Glitch successul!') + logger.debug('%d, %d, %d' %(idx, glitch_width, glitch_offset)) + logger.debug(data.decode('utf-8', 'ignore')) + +ser.close() +glitcher.close() \ No newline at end of file diff --git a/src/python/pulsegen.py b/src/python/pulsegen.py new file mode 100644 index 0000000..161625a --- /dev/null +++ b/src/python/pulsegen.py @@ -0,0 +1,130 @@ +import serial +import time +import signal + +class PicoPulseGen: + def __init__(self, port='/dev/ttyACM0'): + self._pulse_offset = 0 + self._pulse_width = 0 + self._trig_edges = 0 + + self.pico = serial.Serial(port, 115200) + time.sleep(0.1) + self.pico.write(b'S') + + test = self.pico.readline() + if b'PulseGenerator' not in test: + raise ConnectionError('Could not connect to the PulseGenerator :(') + + signal.signal(signal.SIGALRM, self.arm_abort) + + + @property + def pulse_offset(self): + return self._pulse_offset + + + @pulse_offset.setter + def pulse_offset(self, offset): + if type(offset) != int or offset < 0 or offset > 0xFFFFFFFF: + raise ValueError('Offset has to be an int between 0 and 0xFFFFFFFF') + + self._pulse_offset = offset + + self.pico.flushInput() + self.pico.write(b'O') + self.pico.write((self._pulse_offset).to_bytes(4, 'little')) + ret = self.pico.readline() + assert int(ret.strip()) == self._pulse_offset, ret + + + @property + def pulse_width(self): + return self._pulse_offset + + + @pulse_width.setter + def pulse_width(self, width): + if type(width) != int or width < 0 or width > 0xFFFFFFFF: + raise ValueError('Width has to be an int between 0 and 0xFFFFFFFF') + + self._pulse_width = width + + self.pico.flushInput() + self.pico.write(b'W') + self.pico.write((self._pulse_width).to_bytes(4, 'little')) + ret = self.pico.readline() + assert int(ret.strip()) == self._pulse_width, ret + + + @property + def trig_edges(self): + return self._trig_edges + + + @trig_edges.setter + def trig_edges(self, edges): + if type(edges) != int or edges < 0 or edges > 0xFFFFFFFF: + raise ValueError('Width has to be an int between 0 and 0xFFFFFFFF') + + self._trig_edges = edges + + self.pico.write(b'E') + self.pico.write((self._trig_edges).to_bytes(4, 'little')) + ret = self.pico.readline() + assert int(ret.strip()) == self._trig_edges, ret + + + def arm(self): + self.pico.write(b'A') + ret = self.pico.readline() + assert b'A' in ret + + + def wait_trig(self, timeout=5): + self.pico.write(b'B') + signal.alarm(timeout) + ret = self.pico.readline() + signal.alarm(0) + assert b'T' in ret + + + def arm_abort(self, signum, frame): + print('No trigger observed, disarming!') + self.pico.write(b'D') + + + def status(self): + self.pico.write(b'S') + ret = self.pico.readline() + print(ret.decode('utf-8')) + + + def set_gpio(self, state): + if type(state) != int or state < 0: + raise ValueError('State has to be zero (GPIO 0) or a positive value larger than zero (GPIO 1)') + + self.pico.write(b'G') + self.pico.write(bytes([7])) # For now there is only one GPIO pin used for this functionality + if state: + self.pico.write(bytes([1])) + else: + self.pico.write(bytes([0])) + + ret = self.pico.readline() + assert b'G' in ret + + + def read_gpios(self): + self.pico.write(b'R') + ret = self.pico.readline() + ret = int(ret.strip()) + return ret + + + def close(self): + self.pico.close() + + + def __del__(self): + self.pico.close() \ No newline at end of file -- cgit v1.2.3