def run_tests(elf, comment): mark = 0 comment("Starting to run prac 3 tests") ii = InterrogatorInterface() comment(ii.comms_test()) ii.reset(0) # pull line low. This does a reset with OpenOCD(comment) as openocd: time.sleep(0.2) ii.reset(1) # release line. Allows code to run. with GDBInterface(elf, comment) as gdb: gdb.open_file() gdb.connect() gdb.erase() gdb.load() gdb.send_continue() # assert no button, ensure that AA->55->AA timing is 0.47-0.53 2/2 comment("=== Part 1 ===") mark += part1_tests(ii, comment) comment("===Part 2 ===") mark += part2_tests(ii, comment) comment("=== Part 3 ===") mark += part3_tests(ii, comment) ii.highz_pin(0) ii.highz_pin(1) comment("All tests complete. Mark: {m}".format(m=mark)) return mark
def run_tests(self): mark = 0 self.comment("Starting to run prac 5 tests") self.ii = InterrogatorInterface() self.comment(self.ii.comms_test()) self.ii.reset(0) # pull line low. This does a reset with OpenOCD(self.comment) as self.openocd: time.sleep(0.2) self.ii.reset(1) # release line. Allows OpenOCD to establish connection to core. with GDBInterface(self.full_path_to_elf, self.comment) as self.gdb: self.gdb.open_file() self.gdb.connect() self.gdb.erase() self.gdb.load() for test in [self.part1_tests, self.part2_tests, self.part3_tests, self.part4_tests]: mark += test() self.ii.highz_pin(0) self.ii.highz_pin(1) size_of_text = elf_parser.get_text_size(self.full_path_to_elf) if size_of_text > 272: print("======Size of TEXT suspiciously large==========") self.comment("All tests complete. Mark: {m}".format(m=mark)) return mark
def run_tests(self): mark = 0 self.comment("Starting to run prac 6 tests") self.ii = InterrogatorInterface() self.comment(self.ii.comms_test()) self.ii.reset(0) # pull line low. This does a reset with OpenOCD(self.comment) as self.openocd: time.sleep(0.2) self.ii.reset(1) # release line. Allows OpenOCD to establish connection to core. with GDBInterface(self.full_path_to_elf, self.comment) as self.gdb: self.gdb.open_file() self.gdb.connect() self.gdb.erase() self.gdb.load() self.gdb.send_continue() time.sleep(3) for test in [self.part1_tests, self.part2_tests, self.part3_tests]: mark += test() self.ii.highz_pin(0) self.ii.highz_pin(1) self.ii.highz_pin(2) self.ii.highz_pin(3) self.comment("All tests complete. Mark: {m}".format(m=mark)) return mark
def run_tests(self): mark = 0 self.comment("Starting to run prac 7 tests") self.ii = InterrogatorInterface() self.comment(self.ii.comms_test()) self.ii.reset(0) # pull line low. This does a reset with OpenOCD(self.comment) as self.openocd: time.sleep(0.2) self.ii.reset(1) # release line. Allows OpenOCD to establish connection to core. with GDBInterface(self.full_path_to_elf, self.comment) as self.gdb: self.gdb.open_file() self.gdb.connect() self.gdb.erase() self.gdb.load() for test in [self.part1_tests]: try: mark += test() except Exception as e: self.comment("Unrecoverable exception while running test. Aborting") self.comment(str(e)) break self.ii.highz_pin(0) self.ii.highz_pin(1) self.ii.highz_pin(2) self.ii.highz_pin(3) self.comment("All tests complete. Mark: {m}".format(m=mark)) return mark
def run_tests(elf, comment): mark = 0 comment("Starting to run prac 1 tests") ii = InterrogatorInterface() comment(ii.comms_test()) ii.reset(0) # pull line low. This does a reset with OpenOCD(comment) as openocd: time.sleep(0.2) ii.reset(1) # release line. Allows code to run. with GDBInterface(elf, comment) as gdb: gdb.open_file() gdb.connect() gdb.erase() gdb.load() # run to copy_to_RAM_complete if gdb.run_to_label("copy_to_RAM_complete") == False: # could not find label comment("Mark = 0") return mark comment("Now verifying the first four words in RAM") # verify the 4 words, awarding a mark for each mark += verify_word(gdb, comment, 0x20000000, 0xAABBCCDD) mark += verify_word(gdb, comment, 0x20000004, 0x00001122) mark += verify_word(gdb, comment, 0x20000008, 0x00002233) mark += verify_word(gdb, comment, 0x2000000c, 0x55555555) # modify the 4 words comment("Modifying 0x20000000 to be 0xCC0000BB") gdb.write_word(0x20000000, 0xCC0000BB) comment("Modifying 0x20000004 to be 0xAA") gdb.write_word(0x20000004, 0xAA) comment("Modifying 0x20000008 to be 0x42") gdb.write_word(0x20000008, 0x42) comment("Modifying 0x2000000c to be 0x69") gdb.write_word(0x2000000c, 0x69) # move data into 0x20000020, same data as 0x20000010 gdb.write_word(0x20000020, 0xCC000011) # run to infinite_loop if gdb.run_to_label("infinite_loop") == False: comment("Aborting.") return mark # verify the 4 words mark += verify_word(gdb, comment, 0x20000010, 0xCC000011) mark += verify_word(gdb, comment, 0x20000014, 0xCC0001A7) mark += verify_word(gdb, comment, 0x20000018, 0xE8) mark += verify_word(gdb, comment, 0x2000001c, 0x2bd4) # query pattern on LEDs led_data = ii.read_port(0) comment("Bonus: data read from LEDs as: {a:#x}, and should be 0x11".format(a = led_data)) if led_data == 0x11: comment("Bonus correct! :-). 2/0") mark += 2 else: comment("Bonus not done. 0/0") comment("All tests complete. Mark: {m}".format(m=mark)) return mark
def run_tests(self): mark = 0 self.comment("Starting to run prac 4 tests") self.ii = InterrogatorInterface() self.comment(self.ii.comms_test()) self.ii.reset(0) # pull line low. This does a reset with OpenOCD(self.comment) as self.openocd: time.sleep(0.2) self.ii.reset(1) # release line. Allows OpenOCD to establish connection to core. with GDBInterface(self.full_path_to_elf, self.comment) as self.gdb: self.gdb.open_file() self.gdb.connect() self.gdb.erase() self.gdb.load() self.comment("=== Part 1 ===") mark += self.part1_tests() self.comment("===Part 2 ===") mark += self.part2_tests() self.comment("Sending 'continue' to allow code to free-run") self.gdb.send_continue() self.comment("=== Part 3 ===") mark += self.part3_tests() self.comment("=== Part 4 ===") mark += self.part4_tests() self.comment("=== Part 5 ===") mark += self.part5_tests() self.ii.highz_pin(0) self.ii.highz_pin(1) self.comment("All tests complete. Mark: {m}".format(m=mark)) return mark
def run_tests(elf, comment): mark = 0 comment("Starting to run prac 2 tests") ii = InterrogatorInterface() comment(ii.comms_test()) ii.reset(0) # pull line low. This does a reset with OpenOCD(comment) as openocd: time.sleep(0.2) ii.reset(1) # release line. Allows code to run. with GDBInterface(elf, comment) as gdb: gdb.open_file() gdb.connect() gdb.erase() gdb.load() if gdb.run_to_label("all_off") == False: comment("Could not hit label 'all off'. Aborting") return mark # ensure that only the correct pins are set as outputs: if gdb.read_word(0x48000400) <= 0x5555: comment("Only the lower byte of port B set to outputs. 1/1") mark += 1 else: comment("More than the lower byte of port B set to outputs. 0/1") for label, expected in [["display_AA", 0x00], ["all_on", 0xAA], ["bonus", 0xFF]]: if gdb.run_to_label(label) == False: comment("Could not hit label '{l}'. Aborting".format(l=label)) return mark led_data = ii.read_port(0) if led_data == expected: mark_to_add = 2 else: mark_to_add = 0 comment("LED data should be {exp:#X} and is {led:#X}: {toadd}/2".format(exp = expected, led=led_data, toadd=mark_to_add)) mark += mark_to_add comment("Attempting bonus") gdb.delete_all_breakpoints() bonus_correct = True for i in range(0, 7): # checking the bonus 7 times. if [0, 1, 1, 1, 0, 0, 1][i] == 1: # sequence of button pushes and not pushes ii.highz_pin(0) # simulate a button release comment("Simulating not pushing SW0") if gdb.run_to_label("all_off") == False: comment("Could not hit label 'all_off' implying that you don't have a loop. Aborting") return mark if ii.read_port(0) != 0xFF: # should be all on when not pushing button comment("Excpected 0xFF on the LEDs but got {led:#X}".format(led = ii.read_port(0))) bonus_correct = False break comment("Expected 0xFF on LEDs and got it") else: ii.clear_pin(0) # simulate a button push comment("Simulating pushing SW0") if gdb.run_to_label("all_off") == False: comment("Could not hit label 'all_off' implying that you don't have a loop. Aborting") return mark if ii.read_port(0) != 0x55: comment("Excpected 0x55 on the LEDs but got {led:#X}".format(led = ii.read_port(0))) bonus_correct = False break comment("Expected 0x55 on LEDs and got it") if bonus_correct == True: comment("Bonus correct! :-). 2/0") mark += 2 else: comment("Bonus not done. 0/0") comment("All tests complete. Mark: {m}".format(m=mark)) return mark
class Prac5Tests: def __init__(self, comment, submission_dir, src_name): self.comment = comment self.src_name = src_name self.full_path_to_elf = None self.submission_dir = submission_dir def build(self): as_proc = subprocess.Popen(["arm-none-eabi-as", \ "-mcpu=cortex-m0", "-mthumb", "-g", \ "-o", self.submission_dir + "/main.o", \ self.submission_dir + "/" + self.src_name], \ stdout=subprocess.PIPE, stderr=subprocess.PIPE) if (as_proc.wait() != 0): error_message = as_proc.communicate() self.comment("Compile failed. Awarding 0. Error message:") self.comment(error_message[0].decode()) self.comment(error_message[1].decode()) return False self.comment("Compile succeeded. Attempting to link.") ld_proc = subprocess.Popen(["arm-none-eabi-ld", \ "-Ttext=0x08000000", \ "-o", self.submission_dir + "/main.elf", \ self.submission_dir + "/main.o"], \ stdout=subprocess.PIPE, stderr=subprocess.PIPE) if (ld_proc.wait() != 0): error_message = ld_proc.communicate() self.comment("Link failed. Awarding 0. Error message:") self.comment(error_message[0].decode()) self.comment(error_message[1].decode()) return False self.full_path_to_elf = self.submission_dir + "/main.elf" self.comment("Link succeeded") return True def run_tests(self): mark = 0 self.comment("Starting to run prac 5 tests") self.ii = InterrogatorInterface() self.comment(self.ii.comms_test()) self.ii.reset(0) # pull line low. This does a reset with OpenOCD(self.comment) as self.openocd: time.sleep(0.2) self.ii.reset(1) # release line. Allows OpenOCD to establish connection to core. with GDBInterface(self.full_path_to_elf, self.comment) as self.gdb: self.gdb.open_file() self.gdb.connect() self.gdb.erase() self.gdb.load() for test in [self.part1_tests, self.part2_tests, self.part3_tests, self.part4_tests]: mark += test() self.ii.highz_pin(0) self.ii.highz_pin(1) size_of_text = elf_parser.get_text_size(self.full_path_to_elf) if size_of_text > 272: print("======Size of TEXT suspiciously large==========") self.comment("All tests complete. Mark: {m}".format(m=mark)) return mark def scale_mark(self): self.comment("Scaling PRAC5 mark by factor dependant on submission time") self.comment("No scale factor implemented for this prac.") return mark def part1_tests(self): self.comment("=== Part 1 ===") # run to initialisations_complete if self.gdb.run_to_label("initialisations_complete") == False: return 0 # set start of ram to some sensible value self.comment("Setting 0x20000000 to {sa:#x}".format(sa = SPECIAL_ADDRESS)) self.gdb.write_word(0x20000000, SPECIAL_ADDRESS) # run to fib_calc_complete and verify fibs if self.gdb.run_to_label("fib_calc_complete") == False: self.comment("Could not hit label 'fib_calc_complete'. Aborting") return 0 self.comment("Verifying array of fib numbers") for idx, val in enumerate(FIB_NUMBERS): address = 0x20002000 - 0x4 - (4 * idx) if self.gdb.read_word(address) != val: self.comment("Words at address {addr:#x} should be {exp} but is {act}".format(\ addr = address, exp = val, act = self.gdb.read_word(address))) self.comment("Aborting") return 0 self.comment("Verification completed successfully. 2/2") return 2 def part2_tests(self): self.comment("=== Part 2 ===") # run to cycle_patterns if self.gdb.run_to_label("cycle_patterns") == False: return 0 # validate sensible values data_at_special_address = self.gdb.read_word(SPECIAL_ADDRESS) self.comment("Data at {sa:#x} should be {max_fib:#x}. Found to be {found:#x}".format( \ sa = SPECIAL_ADDRESS, max_fib = FIB_NUMBERS[-1], found = data_at_special_address)) if data_at_special_address != FIB_NUMBERS[-1]: self.comment("Incorrect. 0/2") return 0 else: self.comment("Correct. 2/2") return 2 def part3_tests(self): self.comment("=== Part 3 ===") self.gdb.soft_reset() # run to initialisations_complete if self.gdb.run_to_label("initialisations_complete") == False: return 0 # set illegal value in start of RAM self.comment("Setting 0x20000000 to {sa:#x}".format(sa = ILLEGAL_ADDRESS)) self.gdb.write_word(0x20000000, ILLEGAL_ADDRESS) # continue and verify that pattern is 0xAA if self.gdb.run_to_label("HardFault_Handler") == False: return 0 self.gdb.send_continue() time.sleep(0.5) pattern_on_leds = self.ii.read_port(0) if pattern_on_leds != 0xAA: self.comment("HardFault handler expected to produce pattern 0xAA but instead got {p:#x}".format(\ p = pattern_on_leds)) return 0 self.comment("HardFault handler hit on illegal value and displaying 0xAA. 1/1") return 1 def part4_tests(self): self.comment("=== Part 4 ===") # reset self.gdb.send_control_c() self.gdb.soft_reset() if self.gdb.run_to_label("initialisations_complete") == False: return 0 # run to initialisations_complete # set start of ram to some sensible value self.comment("Setting 0x20000000 to {sa:#x}".format(sa = SPECIAL_ADDRESS)) self.gdb.write_word(0x20000000, SPECIAL_ADDRESS) # set breakpoint on delay_routine # run to breakpoint in a loop until pattern 0x81 is found. #self.comment("Running to 'delay_routine' in a loop until pattern 0x81 found") #pattern_found = False #for i in range(0, 10): # self.gdb.run_to_label("delay_routine") # if self.ii.read_port(0) == 0x81: # pattern_found = True # break #if pattern_found == False: # self.comment("Could not find 0x81 on LEDs after 10 loop itterations. Aborting") # return 0 #self.comment("Found 0x81. Now checking the rest of the patterns by running to 'delay_routine'.") # run to delay_routine again. Verify that next pattern until all patterns pattern_array = [0xC3, 0xE7, 0xFF, 0x7E, 0x3C, 0x18] #for idx, val in enumerate(pattern_array): # self.gdb.run_to_label("delay_routine") # pattern_on_leds = self.ii.read_port(0) # if pattern_on_leds != pattern_array[idx]: # self.comment("On loop iteration number {lp} the pattern {found:#x} was found but should be {exp:#x}".format( # lp = idx, found = pattern_on_leds, exp = val)) # return 0 # continue #self.comment("All patterns found to use 'delay_routine'") self.comment("Testing time between patterns") self.gdb.send_continue() # verify all patterns with 0.5 delay between. for i in range(0, len(pattern_array) - 1): delay = self.ii.transition_timing(pattern_array[i], pattern_array[i+1]) self.comment("Delay between {p1:#x} and {p2:#x} found to be {d}".format( p1 = pattern_array[i], p2 = pattern_array[i+1], d = round(delay,2))) if delay > 0.53 or delay < 0.47: self.comment("Incorrect. 0/2") return 0 self.comment("Delays found to be correct. 2/2") return 2
class Prac6Tests: def __init__(self, comment, submission_dir, src_name): self.comment = comment self.src_name = src_name self.full_path_to_elf = None self.submission_dir = submission_dir def build(self): self.comment("Changing dir to submission dir") os.chdir(self.submission_dir) all_files = os.listdir() elf_files = [fi for fi in all_files if fi.endswith(".elf")] if len(elf_files) > 0: self.comment("Elf files exist before make run: {e}".format(e = all_files)) self.comment("Aborting") return False self.comment("Running 'make'") make_proc = subprocess.Popen(["make"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) try: return_code = make_proc.wait(timeout = 5) except subprocess.TimeoutExpired: make_proc.kill() self.comment("Make did not complete after 5 seconds. Aborting") return False if (return_code != 0): error_message = make_proc.communicate() self.comment("Make failed. Awarding 0. Error message:") self.comment(error_message[0].decode()) self.comment(error_message[1].decode()) return False self.comment("Make succeeded. Attempting to link.") self.comment("Searching submission directory for .elf files") all_files = os.listdir() elf_files = [fi for fi in all_files if fi.endswith(".elf")] if len(elf_files) > 1: self.comment("Too many elf files out of {e}".format(e = all_files)) return False if len(elf_files) == 0: self.comment("No elf files out of: {e}".format(e = all_files)) return False self.comment("One elf file produced: {e}".format(e = elf_files[0])) self.full_path_to_elf = self.submission_dir + "/" + elf_files[0] return True def run_tests(self): mark = 0 self.comment("Starting to run prac 6 tests") self.ii = InterrogatorInterface() self.comment(self.ii.comms_test()) self.ii.reset(0) # pull line low. This does a reset with OpenOCD(self.comment) as self.openocd: time.sleep(0.2) self.ii.reset(1) # release line. Allows OpenOCD to establish connection to core. with GDBInterface(self.full_path_to_elf, self.comment) as self.gdb: self.gdb.open_file() self.gdb.connect() self.gdb.erase() self.gdb.load() self.gdb.send_continue() time.sleep(3) for test in [self.part1_tests, self.part2_tests, self.part3_tests]: mark += test() self.ii.highz_pin(0) self.ii.highz_pin(1) self.ii.highz_pin(2) self.ii.highz_pin(3) self.comment("All tests complete. Mark: {m}".format(m=mark)) return mark def part1_tests(self): self.comment("=== Part 1 ===") self.comment("Releasing both SW2 and SW3") self.ii.highz_pin(2) self.ii.highz_pin(3) time.sleep(1) current_pattern = self.ii.read_port(0) timing = self.ii.transition_timing(current_pattern + 3, current_pattern + 4) self.comment("Timing between an increment expected to be 0.5 and found to be: {t}".format(t = round(timing, 2))) if timing < 0.47 or timing > 0.53: self.comment("Timing out. Awarding 0") return 0 self.comment("Correct. 4/4") return 4 def part2_tests(self): self.comment("=== Part 2 ===") self.comment("Releasing SW2 and pressing SW3") self.ii.highz_pin(2) self.ii.clear_pin(3) time.sleep(1) current_pattern = self.ii.read_port(0) timing = self.ii.transition_timing(current_pattern - 3, current_pattern - 4) self.comment("Timing between a decrement expected to be 0.5 and found to be: {t}".format(t = round(timing, 2))) if timing < 0.47 or timing > 0.53: self.comment("Timing out. Awarding 0") return 0 self.comment("Correct. 1/1") self.ii.highz_pin(2) self.ii.highz_pin(3) return 1 def part3_tests(self): self.comment("=== Part 3 ===") self.comment("Pressing SW2 and releasing SW3") self.ii.clear_pin(2) self.ii.highz_pin(3) self.comment("Asserting 0.54 V on port A5. Period should become 0.17 seconds.") self.ii.write_dac(42) time.sleep(1) current_pattern = self.ii.read_port(0) timing = self.ii.transition_timing(current_pattern + 4, current_pattern + 5) self.comment("Timing between an increment expected to be 0.17 and found to be: {t}".format(t = round(timing, 2))) if timing < 0.14 or timing > 0.20: self.comment("Timing out. Awarding 0") return 0 self.comment("Pressing SW2 and pressing SW3") self.ii.clear_pin(2) self.ii.clear_pin(3) self.comment("Asserting 2.59 V on port A5. Period should become 0.41 seconds.") self.ii.write_dac(200) time.sleep(1) current_pattern = self.ii.read_port(0) timing = self.ii.transition_timing(current_pattern - 3, current_pattern - 4) self.comment("Timing between an increment expected to be 0.41 and found to be: {t}".format(t = round(timing, 2))) if timing < 0.37 or timing > 0.45: self.comment("Timing out. Awarding 0") return 0 return 3
class Prac7Tests: def __init__(self, comment, submission_dir, src_name): self.comment = comment self.src_name = src_name self.full_path_to_elf = None self.submission_dir = submission_dir def build(self): self.comment("Changing dir to submission dir") os.chdir(self.submission_dir) all_files = os.listdir() elf_files = [fi for fi in all_files if fi.endswith(".elf")] if len(elf_files) > 0: self.comment("Elf files exist before make run: {e}".format(e = all_files)) self.comment("Aborting") return False self.comment("Running 'make'") make_proc = subprocess.Popen(["make"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) try: return_code = make_proc.wait(timeout = 5) except subprocess.TimeoutExpired: make_proc.kill() self.comment("Make did not complete after 5 seconds. Aborting") return False if (return_code != 0): error_message = make_proc.communicate() self.comment("Make failed. Awarding 0. Error message:") self.comment(error_message[0].decode()) self.comment(error_message[1].decode()) return False self.comment("Searching submission directory for .elf files") all_files = os.listdir() elf_files = [fi for fi in all_files if fi.endswith(".elf")] if len(elf_files) > 1: self.comment("Too many elf files out of {e}".format(e = all_files)) return False if len(elf_files) == 0: self.comment("No elf files out of: {e}".format(e = all_files)) return False self.comment("One elf file produced: {e}".format(e = elf_files[0])) self.full_path_to_elf = self.submission_dir + "/" + elf_files[0] return True def run_tests(self): mark = 0 self.comment("Starting to run prac 7 tests") self.ii = InterrogatorInterface() self.comment(self.ii.comms_test()) self.ii.reset(0) # pull line low. This does a reset with OpenOCD(self.comment) as self.openocd: time.sleep(0.2) self.ii.reset(1) # release line. Allows OpenOCD to establish connection to core. with GDBInterface(self.full_path_to_elf, self.comment) as self.gdb: self.gdb.open_file() self.gdb.connect() self.gdb.erase() self.gdb.load() for test in [self.part1_tests]: try: mark += test() except Exception as e: self.comment("Unrecoverable exception while running test. Aborting") self.comment(str(e)) break self.ii.highz_pin(0) self.ii.highz_pin(1) self.ii.highz_pin(2) self.ii.highz_pin(3) self.comment("All tests complete. Mark: {m}".format(m=mark)) return mark def part1_tests(self): self.comment("=== Part 1 ===") self.comment("Running to main") self.gdb.run_to_function("main") self.comment("Allowing code to free run") self.gdb.send_continue() self.comment("Reading value displayed on LED") time.sleep(1) leds = self.ii.read_port(0) self.comment("Pattern expected to be 0xAA, and found to be {l:#x}.".format(l=leds)) if leds == 0xAA: self.comment("Correct. 3/3") return 3 else: self.comment("Incorrect. 0/3") return 0
class Prac10Tests: def __init__(self, comment, submission_dir, src_name): self.comment = comment self.src_name = src_name self.full_path_to_elf = None self.submission_dir = submission_dir def build(self): self.comment("Changing dir to submission dir") os.chdir(self.submission_dir) all_files = os.listdir() elf_files = [fi for fi in all_files if fi.endswith(".elf")] if len(elf_files) > 0: self.comment("Elf files exist before make run: {e}".format(e = all_files)) self.comment("Aborting") return False self.comment("Running 'make'") make_proc = subprocess.Popen(["make"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) try: return_code = make_proc.wait(timeout = 5) except subprocess.TimeoutExpired: make_proc.kill() self.comment("Make did not complete after 5 seconds. Aborting") return False if (return_code != 0): error_message = make_proc.communicate() self.comment("Make failed. Awarding 0. Error message:") self.comment(error_message[0].decode()) self.comment(error_message[1].decode()) return False self.comment("Make succeeded. Attempting to link.") self.comment("Searching submission directory for .elf files") all_files = os.listdir() elf_files = [fi for fi in all_files if fi.endswith(".elf")] if len(elf_files) > 1: self.comment("Too many elf files out of {e}".format(e = all_files)) return False if len(elf_files) == 0: self.comment("No elf files out of: {e}".format(e = all_files)) return False self.comment("One elf file produced: {e}".format(e = elf_files[0])) self.full_path_to_elf = self.submission_dir + "/" + elf_files[0] return True def run_tests(self): mark = 0 self.comment("Starting to run prac 10 tests") self.ii = InterrogatorInterface() self.comment(self.ii.comms_test()) self.ii.reset(0) # pull line low. This does a reset with OpenOCD(self.comment) as self.openocd: time.sleep(0.2) self.ii.reset(1) # release line. Allows OpenOCD to establish connection to core. with GDBInterface(self.full_path_to_elf, self.comment) as self.gdb: self.gdb.open_file() self.gdb.connect() self.gdb.erase() self.gdb.load() self.gdb.send_continue() for test in [self.part1_tests, self.part2_tests, self.part3_tests, self.part4_tests, self.part5_tests]: try: mark += test() except Exception as e: self.comment("Unrecoverable exception while running test. Aborting") self.comment(str(e)) self.comment(type(e)) break self.ii.highz_pin(0) self.ii.highz_pin(1) self.ii.highz_pin(2) self.ii.highz_pin(3) self.comment("All tests complete. Mark: {m}".format(m=mark)) return mark def part1_tests(self): self.comment("=== Part 1 ===") self.comment("Verifying timing between all patterns. Should be 1 second +-6%.") pattern_array = [0x01, 0x02, 0x04, 0x08, 0x88, 0x48, 0x28, 0x18] for i in range(1, len(pattern_array)+3, 2): pat0 = pattern_array[i % len(pattern_array)] pat1 = pattern_array[(i+1) % len(pattern_array)] timing = round(self.ii.transition_timing(pat0, pat1), 3) self.comment("Timing between {p0:#x} and {p1:#x} found to be: {t}".format(p0 = pat0, p1 = pat1, t = timing)) if timing < 1.0*0.88 or timing > 1*1.12: self.comment("Timing out. Awarding 0.") return 0 elif timing < 1.0*0.94 or timing > 1*1.06: self.comment("Timing somewhat out. Awarding 1.") return 1 self.comment("Correct. 2/2") return 2 def part2_tests(self): mark = 1 self.comment("=== Part 2 ===") self.comment("Waiting until pattern 0x48 is displayed.") t0 = time.time() leds = self.ii.read_port(0) while( (time.time() - t0 < 10.0) and leds != 0x48): leds = self.ii.read_port(0) if leds != 0x48: self.comment("Could not find 0x48 after 10 seconds. Timeout. 0/2") return 0 self.comment("Pattern 0x48 is now on LEDs. Asserting a 100 ms pulse on SW0") self.ii.clear_pin(0) time.sleep(0.1) self.ii.highz_pin(0) time.sleep(0.1) pattern = self.ii.read_port(0) self.comment("Pattern should now be 0x01 and is {p:#x}.".format(p = pattern)) if pattern != 0x01: self.comment("Incorrect. 0/2") return 0 self.comment("Correct. 1/2") self.comment("Now holding SW0 down and ensuring that transitions occur.") self.ii.clear_pin(0) timing = round(self.ii.transition_timing(0x02, 0x04), 3) self.ii.highz_pin(0) if timing != -1: self.comment("Transition successfully found with SW0 held. 2/2") return 2 self.comment("No transition found with SW0 held. 1/2") return 1 def part3_tests(self): self.comment("=== Part 3 ===") self.comment("Pulsing SW0 again to reset pattern to start.") self.ii.clear_pin(0) time.sleep(0.1) self.ii.highz_pin(0) time.sleep(0.1) self.comment("Pulsing SW1 to change frequency to 2 Hz.") self.ii.clear_pin(1) time.sleep(0.1) self.ii.highz_pin(1) time.sleep(0.1) self.comment("Now looking for transition from 0x04 to 0x08. Should be 0.5 seconds +- 6%") timing = round(self.ii.transition_timing(0x04, 0x08), 3) self.comment("Timing found to be: {t}".format(t = timing)) if timing < 0.5 * 0.9 or timing > 0.5 * 1.1: self.comment("Timing out. Awarding 0") return 0 self.comment("Timing good. 2/2") return 2 def part4_tests(self): self.comment("=== Part 4 ===") self.comment("Pulsing SW0 again to reset pattern to start.") self.ii.clear_pin(0) time.sleep(0.1) self.ii.highz_pin(0) time.sleep(0.1) self.comment("Pulsing SW2 to change frequency to 5 Hz.") self.ii.clear_pin(2) time.sleep(0.1) self.ii.highz_pin(2) time.sleep(0.1) self.comment("Now looking for transition from 0x04 to 0x08. Should be 0.2 seconds +- 6%") timing = round(self.ii.transition_timing(0x04, 0x08), 3) self.comment("Timing found to be: {t}".format(t = timing)) if timing < 0.2 * 0.9 or timing > 0.2 * 1.1: self.comment("Timing out. Awarding 0") return 0 self.comment("Timing good. Now checking that Part 3 tests still work.") if self.part3_tests() != 0: self.comment("Part 3 tests still good, awarding part 4. 1/1") return 1 self.comment("Part 3 tests seem broken. Awarding 0") return 0 def part5_tests(self): self.comment("=== Part 5 ===") self.comment("Asserting SW3.") self.ii.clear_pin(3) self.comment("Applying 0V to both pot0 and pot1. Frequency should be 1 Hz.") self.ii.write_dac(0) self.ii.configure_dac_channel(0, 0) self.ii.configure_dac_channel(1, 0) self.comment("Pulsing SW0 and looking for timing from 0x02 to 0x04.") self.ii.clear_pin(0) time.sleep(0.1) self.ii.highz_pin(0) time.sleep(0.1) timing = round(self.ii.transition_timing(0x02, 0x04), 3) self.comment("Timing found to be: {t}".format(t = timing)) if timing < 1 * 0.9 or timing > 1 * 1.1: self.comment("Timing out. Awarding 0") return 0 self.comment("Timing good.") self.ii.write_dac(50) # v = 50/256 * 3.3 = 0.645 V self.ii.configure_dac_channel(0, 1) self.ii.configure_dac_channel(1, 0) time.sleep(2) self.comment("Asserting 0.65 V on pot0 and 0 V on pot 1. Timing should be 0.814 seconds") self.comment("Pulsing SW0 and looking for timing from 0x02 to 0x04.") self.ii.clear_pin(0) time.sleep(0.1) self.ii.highz_pin(0) time.sleep(0.1) timing = round(self.ii.transition_timing(0x02, 0x04), 3) self.comment("Timing found to be: {t}".format(t = timing)) if timing < 0.814 * 0.9 or timing > 0.814 * 1.1: self.comment("Timing out. Awarding 0") return 0 self.comment("Timing good.") self.ii.write_dac(200) # v = 200/255 * 3.3 = 2.589 V self.ii.configure_dac_channel(0, 0) self.ii.configure_dac_channel(1, 1) time.sleep(2) self.comment("Asserting 2.589 V on pot1 and 0 V on pot 0. Timing should be 0.255 seconds") self.comment("Pulsing SW0 and looking for timing from 0x02 to 0x04.") self.ii.clear_pin(0) time.sleep(0.1) self.ii.highz_pin(0) time.sleep(0.1) timing = round(self.ii.transition_timing(0x02, 0x04), 3) self.comment("Timing found to be: {t}".format(t = timing)) if timing < 0.255 * 0.9 or timing > 0.255 * 1.1: self.comment("Timing out. Awarding 0") return 0 self.comment("All timing good. 3/3") return 3
class Prac4Tests: def __init__(self, comment, submission_dir, src_name): self.comment = comment self.src_name = src_name self.full_path_to_elf = None self.submission_dir = submission_dir def build(self): print("building {f} in dir: {d}".format(f= self.src_name, d=self.submission_dir)) as_proc = subprocess.Popen(["arm-none-eabi-as", \ "-mcpu=cortex-m0", "-mthumb", "-g", \ "-o", self.submission_dir + "/main.o", \ self.submission_dir + "/" + self.src_name], \ stdout=subprocess.PIPE, stderr=subprocess.PIPE) if (as_proc.wait() != 0): error_message = as_proc.communicate() self.comment("Compile failed. Awarding 0. Error message:") self.comment(error_message[0].decode()) self.comment(error_message[1].decode()) return False self.comment("Compile succeeded. Attempting to link.") ld_proc = subprocess.Popen(["arm-none-eabi-ld", \ "-Ttext=0x08000000", \ "-o", self.submission_dir + "/main.elf", \ self.submission_dir + "/main.o"], \ stdout=subprocess.PIPE, stderr=subprocess.PIPE) if (ld_proc.wait() != 0): error_message = ld_proc.communicate() self.comment("Link failed. Awarding 0. Error message:") self.comment(error_message[0].decode()) self.comment(error_message[1].decode()) return False self.full_path_to_elf = self.submission_dir + "/main.elf" self.comment("Link succeeded") return True def run_tests(self): mark = 0 self.comment("Starting to run prac 4 tests") self.ii = InterrogatorInterface() self.comment(self.ii.comms_test()) self.ii.reset(0) # pull line low. This does a reset with OpenOCD(self.comment) as self.openocd: time.sleep(0.2) self.ii.reset(1) # release line. Allows OpenOCD to establish connection to core. with GDBInterface(self.full_path_to_elf, self.comment) as self.gdb: self.gdb.open_file() self.gdb.connect() self.gdb.erase() self.gdb.load() self.comment("=== Part 1 ===") mark += self.part1_tests() self.comment("===Part 2 ===") mark += self.part2_tests() self.comment("Sending 'continue' to allow code to free-run") self.gdb.send_continue() self.comment("=== Part 3 ===") mark += self.part3_tests() self.comment("=== Part 4 ===") mark += self.part4_tests() self.comment("=== Part 5 ===") mark += self.part5_tests() self.ii.highz_pin(0) self.ii.highz_pin(1) self.comment("All tests complete. Mark: {m}".format(m=mark)) return mark def part1_tests(self): if self.gdb.run_to_label("copy_to_RAM_complete") == False: self.comment("Could not hit label 'copy_to_RAM_complete'. Aborting") return 0 self.comment("Verifying array in RAM") for idx, val in enumerate(data_array): address = 0x20000000 + (4*idx) data_in_RAM = self.gdb.read_word(address) if data_in_RAM != val: self.comment("Data at address {addr:#x} should be {v:#x} but is {d:#x}".format(addr = address, v = val, d = data_in_RAM)) return 0 self.comment("Data correct in RAM. 3/3") return 3 def part2_tests(self): if self.gdb.run_to_label("increment_of_bytes_complete") == False: self.comment("Could not hit label 'increment_of_bytes_complete'. Aborting") return 0 self.comment("Verifying incremented array in RAM") mark_to_return = 2 for idx, val in enumerate(data_array): address = 0x20000000 + (4*idx) data_in_RAM = self.gdb.read_word(address) for byte_offset in range(0, 3): # add one at the correct place, then shift the byte of interest down to LSB and select with mask val_byte = ((val + (1 << (byte_offset * 8))) >> (byte_offset * 8)) & 0xFF data_byte = ((data_in_RAM ) >> (byte_offset * 8)) & 0xFF if val_byte != data_byte: self.comment("Data at address {addr:#x} should be {v:#x} but is {d:#x}".format( \ addr = address + byte_offset, v = val_byte, d = data_byte)) self.comment("Aborting verification phase. 0/2") mark_to_return = 0 break if mark_to_return == 2: self.comment("Data correct in RAM. 2/2") self.comment("Now modifying data in RAM. Setting all words to 0x88888888") for word_offset in range(0, len(data_array)): word_addr = 0x20000000 + (word_offset*4) self.gdb.write_word(word_addr, 0x88888888) self.comment("Setting address 0x2000000C0 to 0x8870FA05") self.comment("This implies a max unsigned of 0xFA, min unsigned of 0x05 and max signed of 0x70") self.gdb.write_word(0x20000008, 0x8870FA05) return mark_to_return def part3_tests(self): # simulate SW1 and not SW0. Should be flashing AA,55 at 0.25 seconds self.ii.highz_pin(0) self.ii.highz_pin(1) time.sleep(0.5) self.comment("Releasing both SW0 and SW1") led_data = self.ii.read_port(0) self.comment("Data on LEDs should be max unsigned (0xFA), and found to be {d:#X}".format(d=led_data)) if led_data != 0xFA: self.comment("Incorrect. 0/3") return 0 self.comment("Part 3 correct. 3/3") return 3 def part4_tests(self): # simulate SW1 and not SW0. Should be flashing AA,55 at 0.25 seconds self.ii.clear_pin(0) self.ii.highz_pin(1) time.sleep(0.5) self.comment("Pressing SW0 and releasing SW1") led_data = self.ii.read_port(0) self.comment("Data on LEDs should be min unsigned (0x05), and found to be {d:#X}".format(d=led_data)) if led_data != 0x05: self.comment("Incorrect. 0/2") return 0 self.comment("Part 4 correct. 2/2") return 2 def part5_tests(self): # simulate SW1 and not SW0. Should be flashing AA,55 at 0.25 seconds self.ii.highz_pin(0) self.ii.clear_pin(1) time.sleep(0.5) self.comment("Releasing SW0 and pressing SW1") led_data = self.ii.read_port(0) self.comment("Data on LEDs should be max signed (0x70), and found to be {d:#X}".format(d=led_data)) if led_data != 0x70: self.comment("Incorrect. 0/1") return 0 self.comment("Part 5 correct. 1/1") return 1
class Prac9Tests: def __init__(self, comment, submission_dir, src_name): self.comment = comment self.src_name = src_name self.full_path_to_elf = None self.submission_dir = submission_dir def build(self): self.comment("Changing dir to submission dir") os.chdir(self.submission_dir) all_files = os.listdir() elf_files = [fi for fi in all_files if fi.endswith(".elf")] if len(elf_files) > 0: self.comment("Elf files exist before make run: {e}".format(e = all_files)) self.comment("Aborting") return False self.comment("Running 'make'") make_proc = subprocess.Popen(["make"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) try: return_code = make_proc.wait(timeout = 5) except subprocess.TimeoutExpired: make_proc.kill() self.comment("Make did not complete after 5 seconds. Aborting") return False if (return_code != 0): error_message = make_proc.communicate() self.comment("Make failed. Awarding 0. Error message:") self.comment(error_message[0].decode()) self.comment(error_message[1].decode()) return False self.comment("Make succeeded. Attempting to link.") self.comment("Searching submission directory for .elf files") all_files = os.listdir() elf_files = [fi for fi in all_files if fi.endswith(".elf")] if len(elf_files) > 1: self.comment("Too many elf files out of {e}".format(e = all_files)) return False if len(elf_files) == 0: self.comment("No elf files out of: {e}".format(e = all_files)) return False self.comment("One elf file produced: {e}".format(e = elf_files[0])) self.full_path_to_elf = self.submission_dir + "/" + elf_files[0] return True def run_tests(self): mark = 0 self.comment("Starting to run prac 9 tests") self.ii = InterrogatorInterface() self.comment(self.ii.comms_test()) self.ii.reset(0) # pull line low. This does a reset with OpenOCD(self.comment) as self.openocd: time.sleep(0.2) self.ii.reset(1) # release line. Allows OpenOCD to establish connection to core. with GDBInterface(self.full_path_to_elf, self.comment) as self.gdb: self.gdb.open_file() self.gdb.connect() self.gdb.erase() self.gdb.load() self.gdb.send_continue() for test in [self.part1_tests, self.part2_tests, self.part3_tests]: try: mark += test() except Exception as e: self.comment("Unrecoverable exception while running test. Aborting") self.comment(str(e)) break if mark == 7: mark += self.bonus_tests() else: self.comment("Not attempting bonus due to previous errors") self.ii.highz_pin(0) self.ii.highz_pin(1) self.ii.highz_pin(2) self.ii.highz_pin(3) self.comment("All tests complete. Mark: {m}".format(m=mark)) return mark def part1_tests(self): self.comment("=== Part 1 ===") self.comment("Releasing both SW2 and SW3") self.ii.highz_pin(2) self.ii.highz_pin(3) time.sleep(2) current_pattern = self.ii.read_port(0) timing = self.ii.transition_timing(current_pattern + 2, current_pattern + 3) self.comment("Timing between an increment expected to be 0.5 and found to be: {t}".format(t = round(timing, 2))) if timing < 0.46 or timing > 0.54: self.comment("Timing out. Awarding 0") return 0 self.comment("Correct. 2/2") return 2 def part2_tests(self): self.comment("=== Part 2 ===") self.comment("Releasing SW2 and pressing SW3") self.ii.highz_pin(2) self.ii.clear_pin(3) time.sleep(0.6) current_pattern = self.ii.read_port(0) timing = self.ii.transition_timing(current_pattern - 2, current_pattern - 3) self.comment("Timing between a decrement expected to be 0.5 and found to be: {t}".format(t = round(timing, 2))) if timing < 0.47 or timing > 0.53: self.comment("Timing out. Awarding 0") return 0 self.comment("Correct. 1/1") self.ii.highz_pin(2) self.ii.highz_pin(3) return 2 def part3_tests(self): self.comment("=== Part 3 ===") self.comment("Pressing SW2 and releasing SW3") self.ii.clear_pin(2) self.ii.highz_pin(3) self.comment("Asserting 0.52 V on port A6. Period should become 0.16 seconds.") self.ii.write_dac(40) time.sleep(1) current_pattern = self.ii.read_port(0) timing = self.ii.transition_timing(current_pattern + 4, current_pattern + 5) self.comment("Timing between an increment found to be: {t}".format(t = round(timing, 2))) if timing < 0.14 or timing > 0.18: self.comment("Timing out. Awarding 0") return 0 self.comment("Pressing SW2 and pressing SW3") self.ii.clear_pin(2) self.ii.clear_pin(3) self.comment("Asserting 1.93 V on port A6. Period should become 0.33 seconds.") self.ii.write_dac(150) time.sleep(1) current_pattern = self.ii.read_port(0) timing = self.ii.transition_timing(current_pattern - 4, current_pattern - 5) self.comment("Timing between an decrement found to be: {t}".format(t = round(timing, 2))) if timing < 0.30 or timing > 0.36: self.comment("Timing out. Awarding 0") return 0 return 3 def bonus_tests(self): self.comment("=== Bonus ===") self.comment("Releasing SW2 and SW3.") self.ii.highz_pin(2) self.ii.highz_pin(3) time.sleep(1) value_before_rst = self.ii.read_port(0) self.ii.reset(0) self.comment("Value on LEDs before reset: {leds:#x}".format(leds = value_before_rst)) self.comment("Pulling NRST line low and sleeping for 2 seconds.") time.sleep(2) self.comment("Releasing NSRT line and sleeping for 100 ms") self.ii.reset(1) time.sleep(0.1) value_after_rst = self.ii.read_port(0) self.comment("Value on LEDs after reset: {leds:#x}".format(leds = value_after_rst)) if value_before_rst != value_after_rst: self.comment("Values different. 0/0") return 0 self.comment("Bonus correct! 1/0") return 1