As of August 2020 the site you are on (wiki.newae.com) is deprecated, and content is now at rtfm.newae.com.

Changes

Jump to: navigation, search

Making Scripts

13,598 bytes added, 19:13, 10 April 2018
Updated scripts and added stm32 scripts
See {{Warningbox|For the older V3.x tools, see [[V3:Making_Scripts]]}}
<H1>THIS PAGE IS OLD - ONLY FOR 3== Scripting with ChipWhisperer as a python module == When used without the GUI, the 4.X SCRIPTS0 API removes much of the high level abstractions so you can have more control over the capture process. WILL BE UPDATED SHORTLYIt also answers questions like--when I capture a trace in what order are things happening? The following example scripts will give you a starting point when scripting with the ChipWhisperer tool. All these examples on this page can be found in their home <code>chipwhisperer/H1software/scripting-examples</code>.
=The Basic== Perform Some Traces during AES encryption and get the results as Numpy array ===User scripts allows partial (iThis script is an example of using the <code>chipwhisperer</code> module for capturing traces during AES encryption.e.: setting up <b>Make sure to have the environment) or total automation of correct firmware loaded on the execution flowtarget.</b> These traces are then saved and loaded later for analysis.
A basic script would look like this:==== XMEGA Target ====<syntaxhighlight lang=python>from __future__ import division, print_function
<pre>import timefrom chipwhisperer.common.scripts.base import UserScriptBaseos
import numpy as np
import matplotlib.pyplot as plt
from datetime import datetime
from tqdm import tqdm
class UserScript(UserScriptBase):import chipwhisperer as cw _name = "ChipWhisperer-Lite: AES SimpleSerial on XMEGA"from chipwhisperer.capture.acq_patterns.basic import AcqKeyTextPattern_Basic _description = "SimpleSerial with Standard Target for AES (XMEGA)"from chipwhisperer.tests.tools_for_tests import FIRMWARE_DIRfrom chipwhisperer.capture.api.programmers import XMEGAProgrammer
def __init__scope = cw.scope(self, api): super(UserScript, self)target = cw.__init__target(apiscope)
def run(self): #User commands heresetup scope parameters selfscope.apigain.setParameter(['Generic Settings', 'Scope Module', 'ChipWhisperer/OpenADC'])gain = 45 selfscope.apiadc.setParameter(['Generic Settings', 'Target Module', 'Simple Serial'])samples = 3000 selfscope.apiadc.setParameter(['Generic Settings', 'Trace Format', 'ChipWhisperer/Native'])offset = 1250 selfscope.apiadc.setParameter(['Simple Serial', 'Connection', 'ChipWhisperer-Lite'])basic_mode = "rising_edge" selfscope.apiclock.setParameter(['ChipWhisperer/OpenADC', 'Connection', 'ChipWhisperer-Lite']) clkgen_freq = 7370000 selfscope.apiclock.connect()adc_src = "clkgen_x4" #Example of using a list to set parametersscope. Slightly easier to copy/paste in this format lstexample trigger.triggers = [['CW Extra Settings', 'Trigger Pins', 'Target IO4 (Trigger Line)', True],"tio4" ['CW Extra Settings', 'Target IOn Pins', 'Target IO1', 'Serial RXD'], ['CW Extra Settings', 'Target IOn Pins', 'Target IO2', 'Serial TXD'], ['OpenADC', 'Clock Setup', 'CLKGEN Settings', 'Desired Frequency', 7370000scope.0], ['CW Extra Settings', 'Target HS IO-Out', 'CLKGEN'], ['OpenADC', 'Clock Setup', 'ADC Clock', 'Source', 'CLKGEN x4 via DCM'], ['OpenADC', 'Trigger Setup', 'Total Samples', 3000], ['OpenADC', 'Trigger Setup', 'Offset', 1250], ['OpenADC', 'Gain Setting', 'Setting', 45], ['OpenADC', 'Trigger Setup', 'Mode', 'rising edge'], #Final step: make DCMs relock in case they are lost ['OpenADC', 'Clock Setup', 'ADC Clock', 'Reset ADC DCM', None], ] for cmd in lstexample: selfio.api.setParameter(cmd) #Let's only do a few tracestio1 = "serial_rx" selfscope.apiio.setParameter(['Generic Settings', 'Acquisition Settings', 'Number of Traces', 50])tio2 = "serial_tx" #The environment is already set, lets do our first capture selfscope.apiio.capture1()</pre>hs2 = "clkgen"
User scripts should inherit from UserScriptBase that specifies # program the runtargetprogrammer = XMEGAProgrammer() method that is called when clicking it in the menu or pressing the attack button programmer.scope = scopeprogrammer._logging = Noneprogrammer.find(in the analyzer tool)programmer.erase()aes_firmware_dir = os.path.join(FIRMWARE_DIR, 'simpleserial-aes')aes_hex = os.path.join(aes_firmware_dir, r"simpleserial-aes-CW303.hex")programmer.program(aes_hex, memtype="flash", verify=True)programmer.close()
The API is passed as an argument by the GUI through the constructor in order to allow the script to "remote control" the existing section. A name and a description should also be specified.ktp = AcqKeyTextPattern_Basic(target=target)
traces =[]textin =Running from the Terminal[]keys =[]N =50 # Number of tracesThis step is only needed if you want to run the script from the terminaltarget. In this caseinit()for i in tqdm(range(N), you dondesc='t need to use the GUI, the capture can be performed using only the API. In order to do it, you should add the following lines to the end of your script fileCapturing traces'): # run aux stuff that should come before trace here
<pre>if __name__ key, text == '__main__':ktp.newPair() # manual creation of a key, text pair can be substituted here from chipwhisperertextin.common.api.CWCoreAPI import CWCoreAPI api = CWCoreAPIappend(text) # Instantiate the API apikeys.runScriptClassappend(UserScriptkey) # Run UserScript through the API</pre>or if you want the GUI:
<pre>if __name__ == '__main__': from chipwhisperertarget.common.api.CWCoreAPI import CWCoreAPI import chipwhisperer.capture.ui.CWCaptureGUI as cwc # Import the ChipWhispererCapture GUI from chipwhisperer.common.utils.parameter import Parameter app = cwc.makeApplication() Parameter.usePyQtGraph = True api = CWCoreAPI() # Instantiate the API gui = cwc.CWAnalyzerGUI(api) # Instantiate the GUI gui.show() api.runScriptClassreinit(UserScript) # Run UserScript through the API
apptarget.exec_setModeEncrypt() # only does something for targets that support it</pre> target.loadEncryptionKey(key) target.loadInput(text)
==Adding user scripts to # run aux stuff that should run before the GUI menu==New scripts can be added to the tool menu automatically by saving it in its respective script folder inside the chipwhisperer installation folder or user projects folder:scope arms here
* chipwhisperer/software/chipwhisperer/capture/scripts* chipwhisperer/software/chipwhisperer/analyzer/scripts* ~/chipwhisperer_projects/chipwhisperer/capture/scripts* ~/chipwhisperer_projects/chipwhisperer/analyzer/scripts scope.arm()
Files put in these directories are scanned during # run aux stuff that should run after the GUI initialization and all UserScriptBase classes are added to the menu. You can copy and past the content of the ''Analysis Script'' window to a text editor or use the ''Attack Script Generator''->''Attack Script''->''Copy'' option.scope arms here
target.go() timeout == Other examples==50The directories listed above already have some examples which can be used as a reference # wait for target to create new scriptsfinish while target.isDone() is False and timeout: timeout -= 1 time. More advanced scripts can be located in the chipwhisperer/software/chipwhisperer/tests foldersleep(0. 01)
Scripts auto-generated by the analyzer tool can also be executed standalone or saved into the scripts directory so that it will show up in the next GUI execution try: ret = scope.capture() if ret: print('Timeout happened during acquisition') except IOError as e: print('IOError: %s' % str(e))
# run aux stuff that should happen after trace here _ =Advancedtarget.readOutput() # clears the response from the serial port traces.append(scope.getLastTrace())trace_array =np.asarray(traces) # if you prefer to work with numpy array for number crunchingtextin_array = np.asarray(textin)known_keys = np.asarray(keys) # for fixed key, these keys are all the same
If you decide to run both tools in sequence, do as followsnow = datetime.now()fmt_string = '{:02}{:02}_{}.npy'trace_file_path = fmt_string.format(now.hour, now.minute, "traces")textin_file_path = fmt_string.format(now.hour, now.minute, "textins")keys_file_path = fmt_string.format(now.hour, now.minute, "keys")
<pre>if __name__ == print('__main__': from chipwhispererSaving results to {},{} and {}.common.api.CWCoreAPI import CWCoreAPI import chipwhisperer.capture.ui.CWCaptureGUI as cwc import chipwhisperer.analyzer.ui.CWAnalyzerGUI as cwa from chipwhisperer.common.utils.parameter import Parameter app = cwc'.makeApplicationformat(trace_file_path, textin_file_path, keys_file_path) Parameter.usePyQtGraph , end= True api = CWCoreAPI('') # Instantiate the API gui = cwc.CWCaptureGUI(api) # Instantiate the Capture GUIsave to a files for later processing guinp.showsave(trace_file_path, trace_array) apinp.runScriptClasssave(Capturetextin_file_path, textin_array) guinp.closesave(keys_file_path, known_keys) gui.resetprint('Done') # Delete saved geometry settings in the Capture tool so it will not be used by the Analyzer
gui = cwa.CWAnalyzerGUI(api) # Instantiate the Analyzer GUI guiuncomment plt.show()to show an example trace apiplt.runScriptClassplot(Attacktraces[0]) # Run the script plt.show(default is the "run" method)
# cleanup the connection to the target and scopescope.dis()target.dis()</syntaxhighlight> ==== STM32F3 Target ====<syntaxhighlight lang=python>from __future__ import division, print_function import timeimport os import numpy as npimport matplotlib.pyplot as pltfrom datetime import datetimefrom tqdm import tqdm import chipwhisperer as cwfrom chipwhisperer.capture.acq_patterns.basic import AcqKeyTextPattern_Basicfrom chipwhisperer.tests.tools_for_tests import FIRMWARE_DIRfrom chipwhisperer.capture.api.programmers import STM32FProgrammer scope = cw.scope()target = cw.target(scope) # setup scope parametersscope.gain.gain = 45scope.adc.samples = 5000scope.adc.offset = 0scope.adc.basic_mode = "rising_edge"scope.clock.clkgen_freq = 7370000scope.clock.adc_src = "clkgen_x4"scope.trigger.triggers = "tio4"scope.io.tio1 = "serial_rx"scope.io.tio2 = "serial_tx"scope.io.hs2 = "clkgen" # program the targetprogrammer = STM32FProgrammer()programmer.scope = scopeprogrammer._logging = Noneprogrammer.open()programmer.find()programmer.erase()aes_firmware_dir = os.path.join(FIRMWARE_DIR, 'simpleserial-aes')aes_hex = os.path.join(aes_firmware_dir, r"simpleserial-aes-CW308_STM32F3.hex")programmer.program(aes_hex, memtype="flash", verify=True)programmer.close() ktp = AcqKeyTextPattern_Basic(target=target) traces = []textin = []keys = []N = 50 # Number of tracestarget.init()for i in tqdm(range(N), desc='Capturing traces'): app# run aux stuff that should come before trace here  key, text = ktp.exec_newPair() # manual creation of a key, text pair can be substituted here textin.append(text) keys.append(key)  target.reinit()  target.setModeEncrypt() # only does something for targets that support it target.loadEncryptionKey(key) target.loadInput(text)  # run aux stuff that should run before the scope arms here  scope.arm()  # run aux stuff that should run after the scope arms here  target.go() timeout = 50 # wait for target to finish while target.isDone() is False and timeout: timeout -= 1 time.sleep(0.01)  try: ret = scope.capture() if ret: print('Timeout happened during acquisition') except IOError as e: print('IOError: %s' % str(e))  # run aux stuff that should happen after trace here  _ = target.readOutput() # throw out the target response traces.append(scope.getLastTrace())trace_array = np.asarray(traces) # if you prefer to work with numpy array for number crunchingtextin_array = np.asarray(textin)known_keys = np.asarray(keys) # for fixed key, these keys are all the same now = datetime.now()fmt_string = '{:02}{:02}_{}.npy'trace_file_path = fmt_string.format(now.hour, now.minute, "traces")textin_file_path = fmt_string.format(now.hour, now.minute, "textins")keys_file_path = fmt_string.format(now.hour, now.minute, "keys") print('Saving results to {},{} and {}...'.format(trace_file_path, textin_file_path, keys_file_path), end='')# save to a files for later processingnp.save(trace_file_path, trace_array)np.save(textin_file_path, textin_array)np.save(keys_file_path, known_keys)print('Done') # show an example traceplt.plot(traces[0])plt.show() # cleanup the connection to the target and scopescope.dis()target.dis()</syntaxhighlight> === Manually breaking AES encryption with your recorded traces (As much as scripting is manual) ===Using the saved traces of the AES encryption you can now break the sub-keys of the encryption key. This script is covered in more detail in [[Tutorial_B6_Breaking_AES_(Manual_CPA_Attack) | Tutorial B6]].  <syntaxhighlight lang=python>from __future__ import division, print_function import numpy as npfrom tqdm import tqdm HW = [bin(n).count("1") for n in range(0, 256)] sbox = ( 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16)  def intermediate(pt, keyguess): return sbox[pt ^ keyguess] # put the actual file names in herekeys = np.load('1147_keys.npy')textins = np.load('1147_textins.npy')traces = np.load('1147_traces.npy') knownkey = keys[0] # for fixed key they are all the samept = textinsnumtraces = np.shape(traces)[0]numpoint = np.shape(traces)[1] bestguess = [0] * 16pge = [256] * 16for bnum in tqdm(range(0, 16), desc='Attacking subkeys'): cpaoutput = [0] * 256 maxcpa = [0] * 256 for kguess in range(0, 256):  # Initialize arrays &amp; variables to zero sumnum = np.zeros(numpoint) sumden1 = np.zeros(numpoint) sumden2 = np.zeros(numpoint)  hyp = np.zeros(numtraces) for tnum in range(0, numtraces): hyp[tnum] = HW[intermediate(pt[tnum][bnum], kguess)]  # Mean of hypothesis meanh = np.mean(hyp, dtype=np.float64)  # Mean of all points in trace meant = np.mean(traces, axis=0, dtype=np.float64)  # For each trace, do the following for tnum in range(0, numtraces): hdiff = (hyp[tnum] - meanh) tdiff = traces[tnum, :] - meant  sumnum = sumnum + (hdiff * tdiff) sumden1 = sumden1 + hdiff * hdiff sumden2 = sumden2 + tdiff * tdiff  cpaoutput[kguess] = sumnum / np.sqrt(sumden1 * sumden2) maxcpa[kguess] = max(abs(cpaoutput[kguess]))  bestguess[bnum] = np.argmax(maxcpa)  cparefs = np.argsort(maxcpa)[::-1]  # Find PGE pge[bnum] = list(cparefs).index(knownkey[bnum]) print("Best Key Guess: ", end="")for b in bestguess: print("%02x " % b, end="") print("")print("PGE: ", end="")for b in pge: print("%02d " % b, end="")</syntaxhighlight> === Exploring glitches ===This script shows an example of using the ChipWhisperer tool for performing clock glitch attacks on a target executing code. This script has similar functionality of the glitch explorer in the GUI but exposes more the insides of the ChipWhisperer tool. This script varies the offset and the width percentage of the clock glitch applied to the target during code execution. More details about clock glitching can be found in [[Tutorial_A2_Introduction_to_Glitch_Attacks_(including_Glitch_Explorer) | Tutorial A2]] ==== XMEGA Target ====<syntaxhighlight lang=python>from __future__ import print_function, division import timeimport loggingimport osfrom collections import namedtupleimport csv import numpy as np import chipwhisperer as cwfrom chipwhisperer.tests.tools_for_tests import FIRMWARE_DIRfrom chipwhisperer.capture.api.programmers import XMEGAProgrammer#from scripting_utils import GlitchResultsDisplay logging.basicConfig(level=logging.WARN)scope = cw.scope()target = cw.target(scope) # setup parameters needed for glitch the XMEGAscope.glitch.clk_src = 'clkgen' scope.gain.gain = 45scope.adc.samples = 3000scope.adc.offset = 0scope.adc.basic_mode = "rising_edge"scope.clock.clkgen_freq = 7370000scope.clock.adc_src = "clkgen_x4"scope.trigger.triggers = "tio4"scope.io.tio1 = "serial_rx"scope.io.tio2 = "serial_tx"scope.io.hs2 = "glitch" target.go_cmd = ""target.key_cmd = "" # program the XMEGA with the built hex fileprogrammer = XMEGAProgrammer()programmer.scope = scopeprogrammer._logging = Noneprogrammer.find()programmer.erase()glitch_simple_firmware_dir = os.path.join(FIRMWARE_DIR, 'glitch-simple')glitch_simple_hex = os.path.join(glitch_simple_firmware_dir, r"glitchsimple-CW303.hex")programmer.program(glitch_simple_hex, memtype="flash", verify=True)programmer.close() # format output tableheaders = ['target output', 'width', 'offset', 'success']#glitch_display = GlitchResultsDisplay(headers) # set glitch parameters# trigger glitches with external triggerscope.glitch.trigger_src = 'ext_single'scope.glitch.repeat = 105 traces = []outputs = []widths = []offsets = [] # named tuples to make it easier to change the scope of the testRange = namedtuple('Range', ['min', 'max', 'step'])width_range = Range(-10, 10, 4)offset_range = Range(-10, 10, 4) # glitch cyclescope.glitch.width = width_range.minopen('glitch_out.csv', 'w').close()f = open('glitch_out.csv', 'ab')writer = csv.writer(f)target.init()while scope.glitch.width < width_range.max: scope.glitch.offset = offset_range.min while scope.glitch.offset < offset_range.max: # call before trace things here  # flush the garbage from the computer's target read buffer target.ser.flush()  # target enters reset mode scope.io.pdic = 'low'  # run aux stuff that should run before the scope arms here  scope.arm()  # run aux stuff that should run after the scope arms here  # target exits reset mode scope.io.pdic = 'high'  timeout = 50 # wait for target to finish while target.isDone() is False and timeout: timeout -= 1 time.sleep(0.01)  try: ret = scope.capture() if ret: logging.warning('Timeout happened during acquisition') except IOError as e: logging.error('IOError: %s' % str(e))  # get the results from the scope trace = scope.getLastTrace() # read from the targets buffer output = target.ser.read(32, timeout=10) traces.append(trace) outputs.append(output) widths.append(scope.glitch.width) offsets.append(scope.glitch.width)  # for table display purposes success = '1234' in repr(output) # check for glitch success (depends on targets active firmware) data = [repr(output), scope.glitch.width, scope.glitch.offset, success] #glitch_display.add_data(data) writer.writerow(data)  # run aux stuff that should happen after trace here scope.glitch.offset += offset_range.step scope.glitch.width += width_range.stepf.close()traces = np.asarray(traces)# the rest of the data is available with the outputs, widths, and offsets lists#glitch_display.display_table()print('Done') # clean up the connection to the scope and targetscope.dis()target.dis()</syntaxhighlight> ==== STM32F3 Target ====<syntaxhighlight lang=python>from __future__ import print_function, division import timeimport loggingimport osfrom collections import namedtupleimport csv import numpy as np import chipwhisperer as cwfrom chipwhisperer.tests.tools_for_tests import FIRMWARE_DIRfrom chipwhisperer.capture.api.programmers import STM32FProgrammerfrom scripting_utils import GlitchResultsDisplay logging.basicConfig(level=logging.WARN)scope = cw.scope()target = cw.target(scope) # setup parameters needed for glitch the stm32fscope.glitch.clk_src = 'clkgen' scope.gain.gain = 45scope.adc.samples = 5000scope.adc.offset = 0scope.adc.basic_mode = "rising_edge"scope.clock.clkgen_freq = 7370000scope.clock.adc_src = "clkgen_x4"scope.trigger.triggers = "tio4"scope.io.tio1 = "serial_rx"scope.io.tio2 = "serial_tx"scope.io.hs2 = "glitch" target.go_cmd = ""target.key_cmd = "" # program the stm32f with the built hex fileprogrammer = STM32FProgrammer()programmer.scope = scopeprogrammer._logging = Noneprogrammer.open()programmer.find()programmer.erase()glitch_simple_firmware_dir = os.path.join(FIRMWARE_DIR, 'glitch-simple')glitch_simple_hex = os.path.join(glitch_simple_firmware_dir, r"glitchsimple-CW308_STM32F3.hex")programmer.program(glitch_simple_hex, memtype="flash", verify=True)programmer.close() # format output tableheaders = ['target output', 'width', 'offset', 'success']glitch_display = GlitchResultsDisplay(headers) # set glitch parameters# trigger glitches with external triggerscope.glitch.trigger_src = 'ext_single'scope.glitch.repeat = 105 traces = []outputs = []widths = []offsets = [] # named tuples to make it easier to change the scope of the testRange = namedtuple('Range', ['min', 'max', 'step'])width_range = Range(-40, 40, 0.39*5)offset_range = Range(-40, 40, 0.39*5) # glitch cyclescope.glitch.width = width_range.minopen('glitch_out.csv', 'w').close()f = open('glitch_out.csv', 'ab')writer = csv.writer(f)target.init()while scope.glitch.width < width_range.max: scope.glitch.offset = offset_range.min while scope.glitch.offset < offset_range.max: # call before trace things here  # flush the garbage from the computer's target read buffer target.ser.flush()  # run aux stuff that should run before the scope arms here  # target enters reset state scope.io.nrst = 'low'  scope.arm()  # run aux stuff that should run after the scope arms here  # target exits reset state and starts execution scope.io.nrst = 'high'  timeout = 50 # wait for target to finish while target.isDone() is False and timeout: timeout -= 1 time.sleep(0.01)  try: ret = scope.capture() if ret: logging.warning('Timeout happened during acquisition') except IOError as e: logging.error('IOError: %s' % str(e))  # get the results from the scope trace = scope.getLastTrace() # read from the targets buffer output = target.ser.read(32, timeout=100) traces.append(trace) outputs.append(output) widths.append(scope.glitch.width) offsets.append(scope.glitch.width)  # for table display purposes success = '1234' in repr(output) # check for glitch success (depends on targets active firmware) data = [repr(output), scope.glitch.width, scope.glitch.offset, success] glitch_display.add_data(data) writer.writerow(data)  # run aux stuff that should happen after trace here scope.glitch.offset += offset_range.step scope.glitch.width += width_range.stepf.close()traces = np.asarray(traces)# the rest of the data is available with the outputs, widths, and offsets listsglitch_display.display_table()print('Done')</presyntaxhighlight>

Navigation menu