def test_program_bitstream(success): # prepare calls = [] fpga = TinyFPGAB(None, lambda *a: calls.append(('progress', a))) # patching methods fpga.wake = lambda *a: calls.append(('wake', a)) fpga.read_sts = lambda *a: calls.append(('read_sts', a)) fpga.read = lambda *a: calls.append(('read', a)) if success: fpga.program = lambda *a: calls.append(('program', a)) or True else: fpga.program = lambda *a: calls.append(('program', a)) or False fpga.boot = lambda *a: calls.append(('boot', a)) # run output = fpga.program_bitstream(0x123456, DATA) # check assert output == success expected_calls = [ ('progress', ('Waking up SPI flash', )), ('progress', ('35 bytes to program', )), ('program', (0x123456, DATA)), ] if success: expected_calls.append(('boot', ())) assert calls == expected_calls
def exitBootloader(self): with serial.Serial(self.port[0], 10000000, timeout=0.2, writeTimeout=0.2) as ser: try: TinyFPGAB(ser).boot() except serial.SerialTimeoutException: com_port_status_sv.set("Hmm...try pressing the reset button on TinyFPGA again.")
def checkPortStatus(self, update_button_state): try: with serial.Serial(self.port[0], 115200, timeout=0.2, writeTimeout=0.2) as ser: fpga = TinyFPGAB(ser) if fpga.is_bootloader_active(): com_port_status_sv.set( "Connected to TinyFPGA B2. Ready to program.") return True else: com_port_status_sv.set( "Unable to communicate with TinyFPGA. Reconnect and reset TinyFPGA before programming." ) return False except serial.SerialTimeoutException: com_port_status_sv.set( "Hmm...try pressing the reset button on TinyFPGA again.") return False except: com_port_status_sv.set( "Bootloader not active. Press reset button on TinyFPGA before programming." ) return False
def test_wait_while_busy(): # prepare serial = FakeSerial('0101010100'.decode('hex')) fpga = TinyFPGAB(serial) # run assert fpga.wait_while_busy() is None # check assert not serial.read_data serial.assert_written(['010100020005'.decode('hex')] * 5)
def test_wait_while_busy(): # prepare serial = FakeSerial(bytearray.fromhex('0101010100')) fpga = TinyFPGAB(serial) # run assert fpga.wait_while_busy() is None # check assert not serial.read_data serial.assert_written([bytearray.fromhex('010100020005')] * 5)
def test_read(length, serial_outs): # prepare serial = FakeSerial(DATA[:length]) fpga = TinyFPGAB(serial) # run output = fpga.read(0x123456, length) # check assert output == DATA[:length] assert not serial.read_data serial.assert_written([d.decode('hex') for d in serial_outs])
def test_program(success): # prepare calls = [] fpga = TinyFPGAB(None, lambda *a: calls.append(('progress', a))) # patching methods fpga.erase = lambda *a: calls.append(('erase', a)) fpga.write = lambda *a: calls.append(('write', a)) if success: fpga.read = lambda *a: calls.append(('read', a)) or DATA else: fpga.read = lambda *a: calls.append(('read', a)) or 'This is a fail' # run output = fpga.program(0x123456, DATA) # check assert output == success expected_calls = [ ('progress', ('Erasing designated flash pages', )), ('erase', (0x123456, 35)), ('progress', ('Writing bitstream', )), ('write', (0x123456, DATA)), ('progress', ('Verifying bitstream', )), ('read', (0x123456, 35)), ] if success: expected_calls.extend([ ('progress', ('Success!', )), ]) else: expected_calls.extend([ ('progress', ('Need to rewrite some pages...', )), ('progress', ('len: 000023 00000e', )), ('progress', ('rewriting page 123456', )), ('erase', (1193046, 35)), ('write', (1193046, 'Thequickbrownfoxjumpsoverthelazydog')), ('read', (1193046, 35)), ('erase', (1193046, 35)), ('write', (1193046, 'Thequickbrownfoxjumpsoverthelazydog')), ('read', (1193046, 35)), ('erase', (1193046, 35)), ('write', (1193046, 'Thequickbrownfoxjumpsoverthelazydog')), ('read', (1193046, 35)), ('erase', (1193046, 35)), ('write', (1193046, 'Thequickbrownfoxjumpsoverthelazydog')), ('read', (1193046, 35)), ('erase', (1193046, 35)), ('write', (1193046, 'Thequickbrownfoxjumpsoverthelazydog')), ('read', (1193046, 35)), ('erase', (1193046, 35)), ('write', (1193046, 'Thequickbrownfoxjumpsoverthelazydog')), ('read', (1193046, 35)), ('progress', ('Verification Failed!', )), ]) assert calls == expected_calls
def test_simple_cmds(method, serial_out, serial_in, expected): # prepare serial = FakeSerial(bytearray.fromhex(serial_in)) fpga = TinyFPGAB(serial) if expected is not None: expected = bytearray.fromhex(expected) # run output = getattr(fpga, method)() # check assert output == expected assert not serial.read_data serial.assert_written([bytearray.fromhex(serial_out)])
def test_write(offset, length, serial_outs): # prepare serial = FakeSerial() fpga = TinyFPGAB(serial) fpga.write_enable = lambda: None # patch write_enable fpga.wait_while_busy = lambda: None # patch wait_while_busy data = DATA[:length] # run assert fpga.write(offset, data) is None # check assert not serial.read_data serial.assert_written([d.decode('hex') for d in serial_outs])
def test_simple_cmds(method, serial_out, serial_in, expected): # prepare serial = FakeSerial(serial_in.decode('hex')) fpga = TinyFPGAB(serial) if expected is not None: expected = expected.decode('hex') # run output = getattr(fpga, method)() # check assert output == expected assert not serial.read_data serial.assert_written([serial_out.decode('hex')])
def test_slurp(bitstream_dir, ext): # prepare fpga = TinyFPGAB(None) filename = os.path.join(bitstream_dir, 'bitstream.{}'.format(ext)) expected = (0x30000, DATA) # run if ext == 'unknown': with pytest.raises(ValueError): fpga.slurp(filename) else: output = fpga.slurp(filename) # check assert output == expected
def test_write(offset, length, serial_outs): # prepare serial = FakeSerial() fpga = TinyFPGAB(serial) fpga.write_enable = lambda: None # patch write_enable fpga.wait_while_busy = lambda: None # patch wait_while_busy data = DATA[:length] # run assert fpga.write(offset, data) is None # check assert not serial.read_data prueba = [bytes.fromhex(d) for d in serial_outs] print("Creado: {}".format(prueba)) serial.assert_written(prueba)
def program(self, filename, progress): global max_progress with serial.Serial(self.port[0], 115200, timeout=2, writeTimeout=2) as ser: fpga = TinyFPGAB(ser, progress) (addr, bitstream) = fpga.slurp(filename) max_progress = len(bitstream) * 3 try: fpga.program_bitstream(addr, bitstream) except: program_failure = True traceback.print_exc()
def test_is_bootloader_active(success_after): # prepare calls = [] fpga = TinyFPGAB(None) read_id = ['ABC'] * success_after + ['\x1f\x84\x01'] # patching methods fpga.wake = lambda *a: calls.append(('wake', a)) fpga.read = lambda *a: calls.append(('read', a)) fpga.read_id = lambda *a: calls.append(('read_id', a)) or read_id.pop(0) # run output = fpga.is_bootloader_active() # check assert output == (success_after < 6) expected_calls = [ ('wake', ()), ('read', (0, 16)), ('wake', ()), ('read_id', ()), ] * min(success_after + 1, 6) assert calls == expected_calls
def test_erase(offset, length, block_len, serial_outs): # prepare calls = [] serial = FakeSerial() fpga = TinyFPGAB(serial) fpga.write_enable = lambda: None # patch write_enable fpga.wait_while_busy = lambda: None # patch wait_while_busy fpga.read = lambda *a: calls.append(('read', a)) \ or DATA_4096[a[0] % 4096:][:a[1]] fpga.write = lambda *a: calls.append(('write', a)) # run assert fpga.erase(offset, length) is None # check assert not serial.read_data serial.assert_written([d.decode('hex') for d in serial_outs]) expected_calls = [] restore_first_block = None if offset % block_len > 0: # restore start of first block restore_offset = offset & ~(block_len - 1) restore_len = offset % block_len expected_calls.append(('read', (restore_offset, restore_len))) expected_calls.append( ('write', (restore_offset, DATA_4096[:restore_len]))) restore_first_block = restore_offset if (offset + length) % block_len > 0: # restore end of last block restore_offset = offset + length restore_len = block_len - (restore_offset % block_len) read_call = ('read', (restore_offset, restore_len)) if restore_first_block == ((offset + length) & ~(block_len - 1)): # restore before and after erase in same block expected_calls.insert(1, read_call) # 2nd read before 1st write else: expected_calls.append(read_call) # 2nd read after 1st write expected_calls.append( ('write', (restore_offset, DATA_4096[restore_offset % block_len:]))) assert calls == expected_calls
def test_program(success): # prepare calls = [] fpga = TinyFPGAB(None, lambda *a: calls.append(('progress', a))) # patching methods fpga.erase = lambda *a: calls.append(('erase', a)) fpga.write = lambda *a: calls.append(('write', a)) if success: fpga.read = lambda *a: calls.append(('read', a)) or DATA else: fpga.read = lambda *a: calls.append(('read', a)) or 'This is a fail' # run output = fpga.program(0x123456, DATA) # check assert output == success assert calls == [ ('progress', ('Erasing designated flash pages', )), ('erase', (0x123456, 35)), ('progress', ('Writing bitstream', )), ('write', (0x123456, DATA)), ('progress', ('Verifying bitstream', )), ('read', (0x123456, 35)), ('progress', ('Success!' if success else 'Verification Failed!', )), ]
def _main(): import argparse from serial.tools.list_ports import comports from tinyfpgab import TinyFPGAB parser = argparse.ArgumentParser() parser.add_argument("-l", "--list", action="store_true", help="list connected and active TinyFPGA B-series " "boards") parser.add_argument("-p", "--program", type=str, help="program TinyFPGA board with the given bitstream") parser.add_argument("-b", "--boot", action="store_true", help="command the TinyFPGA B-series board to exit the " "bootloader and load the user configuration") parser.add_argument("-c", "--com", type=str, help="serial port name") parser.add_argument("-d", "--device", type=str, default="1209:2100", help="device id (vendor:product); default is " "TinyFPGA-B (1209:2100)") parser.add_argument("-a", "--addr", type=int, help="force the address to write the bitstream to") args = parser.parse_args() print "" print " TinyFPGA B-series Programmer CLI" print " --------------------------------" device = args.device.lower().replace(':', '') if len(device) != 8 or not all(c in '0123456789abcdef' for c in device): print " Invalid device id, use format vendor:product" sys.exit(1) device = '{}:{}'.format(device[:4], device[4:]) print " Using device id {}".format(device) active_boards = [p[0] for p in comports() if device in p[2].lower()] # find port to use active_port = None if args.com is not None: active_port = args.com elif not active_boards: print " No port was specified and no active bootloaders found." print " Activate bootloader by pressing the reset button." sys.exit(1) elif len(active_boards) == 1: print " Only one board with active bootloader, using it." active_port = active_boards[0] else: print " Please choose a board with the -c option." # list boards if args.list or active_port is None: print " Boards with active bootloaders:" for p in active_boards: print " " + p if len(active_boards) == 0: print " No active bootloaders found. Check USB connections" print " and press reset button to activate bootloader." # program the flash memory elif args.program is not None: print " Programming " + active_port + " with " + args.program def progress(info): if isinstance(info, str): print " " + info for attempt in range(3): with serial.Serial(active_port, 115200, timeout=0.2, writeTimeout=0.2) as ser: fpga = TinyFPGAB(ser, progress) (addr, bitstream) = fpga.slurp(args.program) if args.addr is not None: addr = args.addr if addr < 0: print " Negative write addr: {}".format(addr) sys.exit(1) if addr + len(bitstream) >= 0x400000: print " Write addr over 4Mio: {}".format(addr) sys.exit(1) if not fpga.is_bootloader_active(): print " Bootloader not active" continue print " Programming at addr {:06x}".format(addr) if fpga.program_bitstream(addr, bitstream): sys.exit(0) else: continue # boot the FPGA if args.boot: print " Booting " + active_port with serial.Serial(active_port, 115200, timeout=0.2, writeTimeout=0.2) as ser: fpga = TinyFPGAB(ser) fpga.boot() elif args.program is not None: # exit with error if programming is not successful sys.exit(1)