diff options
Diffstat (limited to 'host/utils')
-rw-r--r-- | host/utils/CMakeLists.txt | 6 | ||||
-rwxr-xr-x | host/utils/usrp2_card_burner.py | 44 | ||||
-rwxr-xr-x | host/utils/usrp2_card_burner_gui.py | 87 | ||||
-rwxr-xr-x | host/utils/usrp2_recovery.py | 12 | ||||
-rwxr-xr-x | host/utils/usrp_n2xx_net_burner.py | 151 | ||||
-rwxr-xr-x | host/utils/usrp_n2xx_net_burner_gui.py | 196 |
6 files changed, 351 insertions, 145 deletions
diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt index 53527c03d..98b5d41fb 100644 --- a/host/utils/CMakeLists.txt +++ b/host/utils/CMakeLists.txt @@ -28,7 +28,7 @@ FOREACH(util_source ${util_runtime_sources}) GET_FILENAME_COMPONENT(util_name ${util_source} NAME_WE) ADD_EXECUTABLE(${util_name} ${util_source}) TARGET_LINK_LIBRARIES(${util_name} uhd) - INSTALL(TARGETS ${util_name} RUNTIME DESTINATION ${RUNTIME_DIR}) + INSTALL(TARGETS ${util_name} RUNTIME DESTINATION ${RUNTIME_DIR} COMPONENT utilities) ENDFOREACH(util_source) ######################################################################## @@ -50,7 +50,7 @@ FOREACH(util_source ${util_share_sources}) GET_FILENAME_COMPONENT(util_name ${util_source} NAME_WE) ADD_EXECUTABLE(${util_name} ${util_source}) TARGET_LINK_LIBRARIES(${util_name} uhd) - INSTALL(TARGETS ${util_name} RUNTIME DESTINATION ${PKG_DATA_DIR}/utils) + INSTALL(TARGETS ${util_name} RUNTIME DESTINATION ${PKG_DATA_DIR}/utils COMPONENT utilities) ENDFOREACH(util_source) IF(ENABLE_USRP2) @@ -59,6 +59,8 @@ IF(ENABLE_USRP2) usrp2_card_burner.py usrp2_card_burner_gui.py usrp_n2xx_net_burner.py + usrp_n2xx_net_burner_gui.py DESTINATION ${PKG_DATA_DIR}/utils + COMPONENT utilities ) ENDIF(ENABLE_USRP2) diff --git a/host/utils/usrp2_card_burner.py b/host/utils/usrp2_card_burner.py index 1db5e59ce..741c7e3e1 100755 --- a/host/utils/usrp2_card_burner.py +++ b/host/utils/usrp2_card_burner.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2010 Ettus Research LLC +# Copyright 2010-2011 Ettus Research LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -19,7 +19,11 @@ import platform import tempfile import subprocess -import urllib +try: + import urllib.request +except ImportError: + import urllib + urllib.request = urllib import optparse import math import os @@ -46,16 +50,16 @@ def command(*args): stderr=subprocess.STDOUT, ) ret = p.wait() - verbose = p.stdout.read() - if ret != 0: raise Exception, verbose + verbose = p.stdout.read().decode('ascii') + if ret != 0: raise Exception(verbose) return verbose def get_dd_path(): if platform.system() == 'Windows': dd_path = os.path.join(tempfile.gettempdir(), 'dd.exe') if not os.path.exists(dd_path): - print 'Downloading dd.exe to %s'%dd_path - dd_bin = urllib.urlopen('http://www.ettus.com/downloads/dd.exe').read() + print('Downloading dd.exe to %s'%dd_path) + dd_bin = urllib.request.urlopen('http://www.ettus.com/downloads/dd.exe').read() open(dd_path, 'wb').write(dd_bin) return dd_path return 'dd' @@ -97,14 +101,14 @@ def get_raw_device_hints(): if key in info: return extract_info_value(info, key) return info.splitlines()[0].strip() - return sorted(set(map(extract_info_name, filter(is_info_valid, get_info_list(command(get_dd_path(), '--list')))))) + return sorted(set(map(extract_info_name, list(filter(is_info_valid, get_info_list(command(get_dd_path(), '--list'))))))) #################################################################### # Platform Linux: parse procfs /proc/partitions #################################################################### if platform.system() == 'Linux': devs = list() - try: output = open('/proc/partitions', 'r').read() + try: output = open('/proc/partitions', 'r').read().decode('ascii') except: return devs for line in output.splitlines(): try: @@ -120,15 +124,15 @@ def get_raw_device_hints(): # Platform Mac OS X: parse diskutil list and info commands #################################################################### if platform.system() == 'Darwin': - devs = map(lambda d: d.split()[0], filter(lambda l: l.startswith('/dev'), command('diskutil', 'list').splitlines())) + devs = [d.split()[0] for d in [l for l in command('diskutil', 'list').splitlines() if l.startswith('/dev')]] def output_to_info(output): - return dict([map(str.strip, pair.lower().split(':')) for pair in filter(lambda l: ':' in l, output.splitlines())]) + return dict([list(map(str.strip, pair.lower().split(':'))) for pair in [l for l in output.splitlines() if ':' in l]]) def is_dev_valid(dev): info = output_to_info(command('diskutil', 'info', dev)) try: - if info.has_key('internal'): assert info['internal'] == 'no' - if info.has_key('ejectable'): assert info['ejectable'] == 'yes' - if info.has_key('total size'): + if 'internal' in info: assert info['internal'] == 'no' + if 'ejectable' in info: assert info['ejectable'] == 'yes' + if 'total size' in info: size_match = re.match('^.*\((\d+)\s*bytes\).*$', info['total size']) if size_match: assert int(size_match.groups()[0]) <= MAX_SD_CARD_SIZE return True @@ -175,8 +179,8 @@ def write_image(image_file, device_file, offset): img_data = open(image_file, 'rb').read() count = int_ceil_div(len(img_data), SECTOR_SIZE) pad_len = SECTOR_SIZE*count - len(img_data) - pad_str = ''.join([chr(0)]*pad_len) #zero-padding - open(tmp_file, 'wb').write(img_data + pad_str) + padding = bytes(b'\x00')*pad_len #zero-padding + open(tmp_file, 'wb').write(img_data + padding) #execute a dd subprocess verbose = command( @@ -196,7 +200,7 @@ def write_image(image_file, device_file, offset): def write_and_verify(image_file, device_file, offset): if os.path.getsize(image_file) > MAX_FILE_SIZE: - raise Exception, 'Image file larger than %d bytes!'%MAX_FILE_SIZE + raise Exception('Image file larger than %d bytes!'%MAX_FILE_SIZE) return '%s\n%s'%( write_image( image_file=image_file, @@ -231,8 +235,8 @@ def get_options(): (options, args) = parser.parse_args() if options.list: - print 'Possible raw devices:' - print ' ' + '\n '.join(get_raw_device_hints()) + print('Possible raw devices:') + print(' ' + '\n '.join(get_raw_device_hints())) exit() return options @@ -242,5 +246,5 @@ def get_options(): ######################################################################## if __name__=='__main__': options = get_options() - if not options.dev: raise Exception, 'no raw device path specified' - print burn_sd_card(dev=options.dev, fw=options.fw, fpga=options.fpga) + if not options.dev: raise Exception('no raw device path specified') + print(burn_sd_card(dev=options.dev, fw=options.fw, fpga=options.fpga)) diff --git a/host/utils/usrp2_card_burner_gui.py b/host/utils/usrp2_card_burner_gui.py index 58b7a514a..2941629b9 100755 --- a/host/utils/usrp2_card_burner_gui.py +++ b/host/utils/usrp2_card_burner_gui.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2010 Ettus Research LLC +# Copyright 2010-2011 Ettus Research LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -17,10 +17,17 @@ # import usrp2_card_burner #import implementation -import Tkinter, tkFileDialog, tkFont, tkMessageBox +try: + import tkinter, tkinter.filedialog, tkinter.font, tkinter.messagebox +except ImportError: + import tkFileDialog, tkFont, tkMessageBox + import Tkinter as tkinter + tkinter.filedialog = tkFileDialog + tkinter.font = tkFont + tkinter.messagebox = tkMessageBox import os -class BinFileEntry(Tkinter.Frame): +class BinFileEntry(tkinter.Frame): """ Simple file entry widget for getting the file path of bin files. Combines a label, entry, and button with file dialog callback. @@ -28,15 +35,15 @@ class BinFileEntry(Tkinter.Frame): def __init__(self, root, what, def_path=''): self._what = what - Tkinter.Frame.__init__(self, root) - Tkinter.Label(self, text=what+":").pack(side=Tkinter.LEFT) - self._entry = Tkinter.Entry(self, width=50) - self._entry.insert(Tkinter.END, def_path) - self._entry.pack(side=Tkinter.LEFT) - Tkinter.Button(self, text="...", command=self._button_cb).pack(side=Tkinter.LEFT) + tkinter.Frame.__init__(self, root) + tkinter.Label(self, text=what+":").pack(side=tkinter.LEFT) + self._entry = tkinter.Entry(self, width=50) + self._entry.insert(tkinter.END, def_path) + self._entry.pack(side=tkinter.LEFT) + tkinter.Button(self, text="...", command=self._button_cb).pack(side=tkinter.LEFT) def _button_cb(self): - filename = tkFileDialog.askopenfilename( + filename = tkinter.filedialog.askopenfilename( parent=self, filetypes=[('bin files', '*.bin'), ('all files', '*.*')], title="Select bin file for %s"%self._what, @@ -45,65 +52,65 @@ class BinFileEntry(Tkinter.Frame): # open file on your own if filename: - self._entry.delete(0, Tkinter.END) + self._entry.delete(0, tkinter.END) self._entry.insert(0, filename) def get_filename(self): return self._entry.get() -class DeviceEntryWidget(Tkinter.Frame): +class DeviceEntryWidget(tkinter.Frame): """ Simple entry widget for getting the raw device name. Combines a label, entry, and helpful text box with hints. """ def __init__(self, root, text=''): - Tkinter.Frame.__init__(self, root) + tkinter.Frame.__init__(self, root) - Tkinter.Button(self, text="Rescan for Devices", command=self._reload_cb).pack() + tkinter.Button(self, text="Rescan for Devices", command=self._reload_cb).pack() - self._hints = Tkinter.Listbox(self) + self._hints = tkinter.Listbox(self) self._hints.bind("<<ListboxSelect>>", self._listbox_cb) self._reload_cb() - self._hints.pack(expand=Tkinter.YES, fill=Tkinter.X) + self._hints.pack(expand=tkinter.YES, fill=tkinter.X) - frame = Tkinter.Frame(self) + frame = tkinter.Frame(self) frame.pack() - Tkinter.Label(frame, text="Raw Device:").pack(side=Tkinter.LEFT) - self._entry = Tkinter.Entry(frame, width=50) - self._entry.insert(Tkinter.END, text) - self._entry.pack(side=Tkinter.LEFT) + tkinter.Label(frame, text="Raw Device:").pack(side=tkinter.LEFT) + self._entry = tkinter.Entry(frame, width=50) + self._entry.insert(tkinter.END, text) + self._entry.pack(side=tkinter.LEFT) def _reload_cb(self): - self._hints.delete(0, Tkinter.END) + self._hints.delete(0, tkinter.END) for hint in usrp2_card_burner.get_raw_device_hints(): - self._hints.insert(Tkinter.END, hint) + self._hints.insert(tkinter.END, hint) def _listbox_cb(self, event): try: sel = self._hints.get(self._hints.curselection()[0]) - self._entry.delete(0, Tkinter.END) + self._entry.delete(0, tkinter.END) self._entry.insert(0, sel) - except Exception, e: print e + except Exception as e: print(e) def get_devname(self): return self._entry.get() -class SectionLabel(Tkinter.Label): +class SectionLabel(tkinter.Label): """ Make a text label with bold font. """ def __init__(self, root, text): - Tkinter.Label.__init__(self, root, text=text) + tkinter.Label.__init__(self, root, text=text) #set the font bold - f = tkFont.Font(font=self['font']) + f = tkinter.font.Font(font=self['font']) f['weight'] = 'bold' self['font'] = f.name -class USRP2CardBurnerApp(Tkinter.Frame): +class USRP2CardBurnerApp(tkinter.Frame): """ The top level gui application for the usrp2 sd card burner. Creates entry widgets and button with callback to write images. @@ -111,7 +118,7 @@ class USRP2CardBurnerApp(Tkinter.Frame): def __init__(self, root, dev, fw, fpga): - Tkinter.Frame.__init__(self, root) + tkinter.Frame.__init__(self, root) #pack the file entry widgets SectionLabel(self, text="Select Images").pack(pady=5) @@ -127,8 +134,8 @@ class USRP2CardBurnerApp(Tkinter.Frame): #the do it button SectionLabel(self, text="").pack(pady=5) - Tkinter.Label(self, text="Warning! This tool can overwrite your hard drive. Use with caution.").pack() - Tkinter.Button(self, text="Burn SD Card", command=self._burn).pack() + tkinter.Label(self, text="Warning! This tool can overwrite your hard drive. Use with caution.").pack() + tkinter.Button(self, text="Burn SD Card", command=self._burn).pack() def _burn(self): #grab strings from the gui @@ -138,31 +145,31 @@ class USRP2CardBurnerApp(Tkinter.Frame): #check input if not dev: - tkMessageBox.showerror('Error:', 'No device specified!') + tkinter.messagebox.showerror('Error:', 'No device specified!') return if not fw and not fpga: - tkMessageBox.showerror('Error:', 'No images specified!') + tkinter.messagebox.showerror('Error:', 'No images specified!') return if fw and not os.path.exists(fw): - tkMessageBox.showerror('Error:', 'Firmware image not found!') + tkinter.messagebox.showerror('Error:', 'Firmware image not found!') return if fpga and not os.path.exists(fpga): - tkMessageBox.showerror('Error:', 'FPGA image not found!') + tkinter.messagebox.showerror('Error:', 'FPGA image not found!') return #burn the sd card try: verbose = usrp2_card_burner.burn_sd_card(dev=dev, fw=fw, fpga=fpga) - tkMessageBox.showinfo('Verbose:', verbose) - except Exception, e: - tkMessageBox.showerror('Verbose:', 'Error: %s'%str(e)) + tkinter.messagebox.showinfo('Verbose:', verbose) + except Exception as e: + tkinter.messagebox.showerror('Verbose:', 'Error: %s'%str(e)) ######################################################################## # main ######################################################################## if __name__=='__main__': options = usrp2_card_burner.get_options() - root = Tkinter.Tk() + root = tkinter.Tk() root.title('USRP2 SD Card Burner') USRP2CardBurnerApp(root, dev=options.dev, fw=options.fw, fpga=options.fpga).pack() root.mainloop() diff --git a/host/utils/usrp2_recovery.py b/host/utils/usrp2_recovery.py index 5654e93d3..c7578d3a0 100755 --- a/host/utils/usrp2_recovery.py +++ b/host/utils/usrp2_recovery.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright 2010 Ettus Research LLC +# Copyright 2010-2011 Ettus Research LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -39,7 +39,7 @@ RECOVERY_ETHERTYPE = 0xbeee IP_RECOVERY_CODE = 'addr' def mac_addr_repr_to_binary_string(mac_addr): - return ''.join(map(lambda x: chr(int(x, 16)), mac_addr.split(':'))) + return ''.join([chr(int(x, 16)) for x in mac_addr.split(':')]) if __name__ == '__main__': parser = optparse.OptionParser(usage='usage: %prog [options]\n'+__doc__) @@ -48,12 +48,12 @@ if __name__ == '__main__': (options, args) = parser.parse_args() #create the raw socket - print "Opening raw socket on interface:", options.ifc + print("Opening raw socket on interface:", options.ifc) soc = socket.socket(socket.PF_PACKET, socket.SOCK_RAW) soc.bind((options.ifc, RECOVERY_ETHERTYPE)) #create the recovery packet - print "Loading packet with ip address:", options.new_ip + print("Loading packet with ip address:", options.new_ip) packet = struct.pack( '!6s6sH4s4s', mac_addr_repr_to_binary_string(BCAST_MAC_ADDR), @@ -63,6 +63,6 @@ if __name__ == '__main__': socket.inet_aton(options.new_ip), ) - print "Sending packet (%d bytes)"%len(packet) + print("Sending packet (%d bytes)"%len(packet)) soc.send(packet) - print "Done" + print("Done") diff --git a/host/utils/usrp_n2xx_net_burner.py b/host/utils/usrp_n2xx_net_burner.py index 6fdc9df20..0b64f2008 100755 --- a/host/utils/usrp_n2xx_net_burner.py +++ b/host/utils/usrp_n2xx_net_burner.py @@ -92,7 +92,7 @@ def unpack_flash_info_fmt(s): def unpack_flash_ip_fmt(s): return struct.unpack(FLASH_IP_FMT, s) #(proto_ver, pktid, seq, ip_addr) -def pack_flash_args_fmt(proto_ver, pktid, seq, flash_addr, length, data): +def pack_flash_args_fmt(proto_ver, pktid, seq, flash_addr, length, data=bytes()): return struct.pack(FLASH_ARGS_FMT, proto_ver, pktid, seq, flash_addr, length, data) def pack_flash_info_fmt(proto_ver, pktid, seq, sector_size_bytes, memory_size_bytes): @@ -100,69 +100,60 @@ def pack_flash_info_fmt(proto_ver, pktid, seq, sector_size_bytes, memory_size_by def is_valid_fpga_image(fpga_image): for i in range(0,63): - if ord(fpga_image[i]) == 0xFF: - continue - if ord(fpga_image[i]) == 0xAA and ord(fpga_image[i+1]) == 0x99: - return 1 - - return 0 + if fpga_image[i:i+1] == bytes(b'\xFF'): continue + if fpga_image[i:i+2] == bytes(b'\xAA\x99'): return True + return False def is_valid_fw_image(fw_image): - for i in range(0,4): - if ord(fw_image[i]) != 0x0B: - return 0; - - return 1 + return fw_image[:4] == bytes(b'\x0B\x0B\x0B\x0B') ######################################################################## # Burner class, holds a socket and send/recv routines ######################################################################## class burner_socket(object): - def __init__(self, ip): + def __init__(self, addr): self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self._sock.settimeout(UDP_TIMEOUT) - self._sock.connect((ip, UDP_FW_UPDATE_PORT)) - - def send_and_recv(self, pkt): - try: self._sock.send(pkt) - except Exception, e: - print e - sys.exit(1) + self._sock.connect((addr, UDP_FW_UPDATE_PORT)) + self.set_callbacks(lambda *a: None, lambda *a: None) + self.init_update() #check that the device is there - try: recv_pkt = self._sock.recv(UDP_MAX_XFER_BYTES) - except Exception, e: - print e - sys.exit(1) + def set_callbacks(self, progress_cb, status_cb): + self._progress_cb = progress_cb + self._status_cb = status_cb - return recv_pkt + def send_and_recv(self, pkt): + self._sock.send(pkt) + return self._sock.recv(UDP_MAX_XFER_BYTES) #just here to validate comms def init_update(self): - out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_OHAI_LOL, seq(), 0, 0, "") - in_pkt = self.send_and_recv(out_pkt) + out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_OHAI_LOL, seq(), 0, 0) + try: in_pkt = self.send_and_recv(out_pkt) + except socket.timeout: raise Exception("No response from device") (proto_ver, pktid, rxseq, ip_addr) = unpack_flash_ip_fmt(in_pkt) if pktid == update_id_t.USRP2_FW_UPDATE_ID_OHAI_OMG: - print "USRP2P found." + print("USRP-N2XX found.") else: - raise Exception, "Invalid reply received from device." + raise Exception("Invalid reply received from device.") # print "Incoming:\n\tVer: %i\n\tID: %c\n\tSeq: %i\n\tIP: %i\n" % (proto_ver, chr(pktid), rxseq, ip_addr) def get_flash_info(self): - out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_WATS_TEH_FLASH_INFO_LOL, seq(), 0, 0, "") + out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_WATS_TEH_FLASH_INFO_LOL, seq(), 0, 0) in_pkt = self.send_and_recv(out_pkt) (proto_ver, pktid, rxseq, sector_size_bytes, memory_size_bytes) = unpack_flash_info_fmt(in_pkt) if pktid != update_id_t.USRP2_FW_UPDATE_ID_HERES_TEH_FLASH_INFO_OMG: - raise Exception, "Invalid reply %c from device." % (chr(pktid)) + raise Exception("Invalid reply %c from device." % (chr(pktid))) return (memory_size_bytes, sector_size_bytes) def burn_fw(self, fw, fpga, reset, safe): (flash_size, sector_size) = self.get_flash_info() - print "Flash size: %i\nSector size: %i\n\n" % (flash_size, sector_size) + print("Flash size: %i\nSector size: %i\n\n" % (flash_size, sector_size)) if fpga: if safe: image_location = SAFE_FPGA_IMAGE_LOCATION_ADDR @@ -172,20 +163,18 @@ class burner_socket(object): fpga_image = fpga_file.read() if len(fpga_image) > FPGA_IMAGE_SIZE_BYTES: - print "Error: FPGA image file too large." - return 0 + raise Exception("Error: FPGA image file too large.") if not is_valid_fpga_image(fpga_image): - print "Error: Invalid FPGA image file." - return 0 + raise Exception("Error: Invalid FPGA image file.") - print "Begin FPGA write: this should take about 1 minute..." + print("Begin FPGA write: this should take about 1 minute...") start_time = time.time() self.erase_image(image_location, FPGA_IMAGE_SIZE_BYTES) self.write_image(fpga_image, image_location) self.verify_image(fpga_image, image_location) - print "Time elapsed: %f seconds"%(time.time() - start_time) - print "\n\n" + print("Time elapsed: %f seconds"%(time.time() - start_time)) + print("\n\n") if fw: if safe: image_location = SAFE_FW_IMAGE_LOCATION_ADDR @@ -195,88 +184,91 @@ class burner_socket(object): fw_image = fw_file.read() if len(fw_image) > FW_IMAGE_SIZE_BYTES: - print "Error: Firmware image file too large." - return 0 + raise Exception("Error: Firmware image file too large.") if not is_valid_fw_image(fw_image): - print "Error: Invalid firmware image file." - return 0 + raise Exception("Error: Invalid firmware image file.") - print "Begin firmware write: this should take about 1 second..." + print("Begin firmware write: this should take about 1 second...") start_time = time.time() self.erase_image(image_location, FW_IMAGE_SIZE_BYTES) self.write_image(fw_image, image_location) self.verify_image(fw_image, image_location) - print "Time elapsed: %f seconds"%(time.time() - start_time) - print "\n\n" + print("Time elapsed: %f seconds"%(time.time() - start_time)) + print("\n\n") if reset: self.reset_usrp() def write_image(self, image, addr): - print "Writing image" + print("Writing image") + self._status_cb("Writing") + writedata = image #we split the image into smaller (256B) bits and send them down the wire - while image: - out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_WRITE_TEH_FLASHES_LOL, seq(), addr, FLASH_DATA_PACKET_SIZE, image[:FLASH_DATA_PACKET_SIZE]) + while writedata: + out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_WRITE_TEH_FLASHES_LOL, seq(), addr, FLASH_DATA_PACKET_SIZE, writedata[:FLASH_DATA_PACKET_SIZE]) in_pkt = self.send_and_recv(out_pkt) (proto_ver, pktid, rxseq, flash_addr, rxlength, data) = unpack_flash_args_fmt(in_pkt) if pktid != update_id_t.USRP2_FW_UPDATE_ID_WROTE_TEH_FLASHES_OMG: - raise Exception, "Invalid reply %c from device." % (chr(pktid)) + raise Exception("Invalid reply %c from device." % (chr(pktid))) - image = image[FLASH_DATA_PACKET_SIZE:] + writedata = writedata[FLASH_DATA_PACKET_SIZE:] addr += FLASH_DATA_PACKET_SIZE + self._progress_cb(float(len(image)-len(writedata))/len(image)) def verify_image(self, image, addr): - print "Verifying data" + print("Verifying data") + self._status_cb("Verifying") readsize = len(image) - readdata = str() + readdata = bytes() while readsize > 0: if readsize < FLASH_DATA_PACKET_SIZE: thisreadsize = readsize else: thisreadsize = FLASH_DATA_PACKET_SIZE - out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_READ_TEH_FLASHES_LOL, seq(), addr, thisreadsize, "") + out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_READ_TEH_FLASHES_LOL, seq(), addr, thisreadsize) in_pkt = self.send_and_recv(out_pkt) (proto_ver, pktid, rxseq, flash_addr, rxlength, data) = unpack_flash_args_fmt(in_pkt) if pktid != update_id_t.USRP2_FW_UPDATE_ID_KK_READ_TEH_FLASHES_OMG: - raise Exception, "Invalid reply %c from device." % (chr(pktid)) + raise Exception("Invalid reply %c from device." % (chr(pktid))) readdata += data[:thisreadsize] readsize -= FLASH_DATA_PACKET_SIZE addr += FLASH_DATA_PACKET_SIZE + self._progress_cb(float(len(readdata))/len(image)) - print "Read back %i bytes" % len(readdata) + print("Read back %i bytes" % len(readdata)) # print readdata # for i in range(256, 512): # print "out: %i in: %i" % (ord(image[i]), ord(readdata[i])) if readdata != image: - print "Verify failed. Image did not write correctly." + raise Exception("Verify failed. Image did not write correctly.") else: - print "Success." + print("Success.") def read_image(self, image, size, addr): - print "Reading image" + print("Reading image") readsize = size readdata = str() while readsize > 0: if readsize < FLASH_DATA_PACKET_SIZE: thisreadsize = readsize else: thisreadsize = FLASH_DATA_PACKET_SIZE - out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_READ_TEH_FLASHES_LOL, seq(), addr, thisreadsize, "") + out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_READ_TEH_FLASHES_LOL, seq(), addr, thisreadsize) in_pkt = self.send_and_recv(out_pkt) (proto_ver, pktid, rxseq, flash_addr, rxlength, data) = unpack_flash_args_fmt(in_pkt) if pktid != update_id_t.USRP2_FW_UPDATE_ID_KK_READ_TEH_FLASHES_OMG: - raise Exception, "Invalid reply %c from device." % (chr(pktid)) + raise Exception("Invalid reply %c from device." % (chr(pktid))) readdata += data[:thisreadsize] readsize -= FLASH_DATA_PACKET_SIZE addr += FLASH_DATA_PACKET_SIZE - print "Read back %i bytes" % len(readdata) + print("Read back %i bytes" % len(readdata)) #write to disk f = open(image, 'w') @@ -284,35 +276,40 @@ class burner_socket(object): f.close() def reset_usrp(self): - out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_RESET_MAH_COMPUTORZ_LOL, seq(), 0, 0, "") - in_pkt = self.send_and_recv(out_pkt) + out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_RESET_MAH_COMPUTORZ_LOL, seq(), 0, 0) + try: in_pkt = self.send_and_recv(out_pkt) + except socket.timeout: return (proto_ver, pktid, rxseq, flash_addr, rxlength, data) = unpack_flash_args_fmt(in_pkt) if pktid == update_id_t.USRP2_FW_UPDATE_ID_RESETTIN_TEH_COMPUTORZ_OMG: - raise Exception, "Device failed to reset." + raise Exception("Device failed to reset.") def erase_image(self, addr, length): + self._status_cb("Erasing") #get flash info first - out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_ERASE_TEH_FLASHES_LOL, seq(), addr, length, "") + out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_ERASE_TEH_FLASHES_LOL, seq(), addr, length) in_pkt = self.send_and_recv(out_pkt) (proto_ver, pktid, rxseq, flash_addr, rxlength, data) = unpack_flash_args_fmt(in_pkt) if pktid != update_id_t.USRP2_FW_UPDATE_ID_ERASING_TEH_FLASHES_OMG: - raise Exception, "Invalid reply %c from device." % (chr(pktid)) + raise Exception("Invalid reply %c from device." % (chr(pktid))) - print "Erasing %i bytes at %i" % (length, addr) + print("Erasing %i bytes at %i" % (length, addr)) + start_time = time.time() #now wait for it to finish while(True): - out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_R_U_DONE_ERASING_LOL, seq(), 0, 0, "") + out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_R_U_DONE_ERASING_LOL, seq(), 0, 0) in_pkt = self.send_and_recv(out_pkt) (proto_ver, pktid, rxseq, flash_addr, rxlength, data) = unpack_flash_args_fmt(in_pkt) if pktid == update_id_t.USRP2_FW_UPDATE_ID_IM_DONE_ERASING_OMG: break elif pktid != update_id_t.USRP2_FW_UPDATE_ID_NOPE_NOT_DONE_ERASING_OMG: - raise Exception, "Invalid reply %c from device." % (chr(pktid)) + raise Exception("Invalid reply %c from device." % (chr(pktid))) + time.sleep(0.01) #decrease network overhead by waiting a bit before polling + self._progress_cb(min(1.0, (time.time() - start_time)/(length/80e3))) ######################################################################## @@ -320,7 +317,7 @@ class burner_socket(object): ######################################################################## def get_options(): parser = optparse.OptionParser() - parser.add_option("--ip", type="string", help="USRP2P firmware address", default='') + parser.add_option("--addr", type="string", help="USRP-N2XX device address", default='') parser.add_option("--fw", type="string", help="firmware image path (optional)", default='') parser.add_option("--fpga", type="string", help="fpga image path (optional)", default='') parser.add_option("--reset", action="store_true", help="reset the device after writing", default=False) @@ -335,23 +332,23 @@ def get_options(): ######################################################################## if __name__=='__main__': options = get_options() - if not options.ip: raise Exception, 'no ip address specified' + if not options.addr: raise Exception('no address specified') - if not options.fpga and not options.fw and not options.reset: raise Exception, 'Must specify either a firmware image or FPGA image, and/or reset.' + if not options.fpga and not options.fw and not options.reset: raise Exception('Must specify either a firmware image or FPGA image, and/or reset.') if options.overwrite_safe and not options.read: print("Are you REALLY, REALLY sure you want to overwrite the safe image? This is ALMOST ALWAYS a terrible idea.") print("If your image is faulty, your USRP2+ will become a brick until reprogrammed via JTAG.") - response = raw_input("""Type "yes" to continue, or anything else to quit: """) + response = input("""Type "yes" to continue, or anything else to quit: """) if response != "yes": sys.exit(0) - burner = burner_socket(ip=options.ip) + burner = burner_socket(addr=options.addr) if options.read: if options.fw: file = options.fw if os.path.isfile(file): - response = raw_input("File already exists -- overwrite? (y/n) ") + response = input("File already exists -- overwrite? (y/n) ") if response != "y": sys.exit(0) size = FW_IMAGE_SIZE_BYTES addr = SAFE_FW_IMAGE_LOCATION_ADDR if options.overwrite_safe else PROD_FW_IMAGE_LOCATION_ADDR @@ -360,7 +357,7 @@ if __name__=='__main__': if options.fpga: file = options.fpga if os.path.isfile(file): - response = raw_input("File already exists -- overwrite? (y/n) ") + response = input("File already exists -- overwrite? (y/n) ") if response != "y": sys.exit(0) size = FPGA_IMAGE_SIZE_BYTES addr = SAFE_FPGA_IMAGE_LOCATION_ADDR if options.overwrite_safe else PROD_FPGA_IMAGE_LOCATION_ADDR diff --git a/host/utils/usrp_n2xx_net_burner_gui.py b/host/utils/usrp_n2xx_net_burner_gui.py new file mode 100755 index 000000000..3b414a918 --- /dev/null +++ b/host/utils/usrp_n2xx_net_burner_gui.py @@ -0,0 +1,196 @@ +#!/usr/bin/env python +# +# Copyright 2011 Ettus Research LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +import usrp_n2xx_net_burner #import implementation +try: + import tkinter, tkinter.filedialog, tkinter.font, tkinter.messagebox +except ImportError: + import tkFileDialog, tkFont, tkMessageBox + import Tkinter as tkinter + tkinter.filedialog = tkFileDialog + tkinter.font = tkFont + tkinter.messagebox = tkMessageBox +import os + +class BinFileEntry(tkinter.Frame): + """ + Simple file entry widget for getting the file path of bin files. + Combines a label, entry, and button with file dialog callback. + """ + + def __init__(self, root, what, def_path=''): + self._what = what + tkinter.Frame.__init__(self, root) + tkinter.Label(self, text=what+":").pack(side=tkinter.LEFT) + self._entry = tkinter.Entry(self, width=50) + self._entry.insert(tkinter.END, def_path) + self._entry.pack(side=tkinter.LEFT) + tkinter.Button(self, text="...", command=self._button_cb).pack(side=tkinter.LEFT) + + def _button_cb(self): + filename = tkinter.filedialog.askopenfilename( + parent=self, + filetypes=[('bin files', '*.bin'), ('all files', '*.*')], + title="Select bin file for %s"%self._what, + initialdir=os.path.dirname(self.get_filename()), + ) + + # open file on your own + if filename: + self._entry.delete(0, tkinter.END) + self._entry.insert(0, filename) + + def get_filename(self): + return self._entry.get() + +class ProgressBar(tkinter.Canvas): + """ + A simple implementation of a progress bar. + Draws rectangle that fills from left to right. + """ + + def __init__(self, root, width=500, height=20): + self._width = width + self._height = height + tkinter.Canvas.__init__(self, root, relief="sunken", borderwidth=2, width=self._width-2, height=self._height-2) + self._last_fill_pixels = None + self.set(0.0) + + def set(self, frac): + """ + Update the progress where fraction is between 0.0 and 1.0 + """ + #determine the number of pixels to draw + fill_pixels = int(round(self._width*frac)) + if fill_pixels == self._last_fill_pixels: return + self._last_fill_pixels = fill_pixels + + #draw a rectangle representing the progress + if frac: self.create_rectangle(0, 0, fill_pixels, self._height, fill="#357EC7") + else: self.create_rectangle(0, 0, self._width, self._height, fill="#E8E8E8") + +class SectionLabel(tkinter.Label): + """ + Make a text label with bold font. + """ + + def __init__(self, root, text): + tkinter.Label.__init__(self, root, text=text) + + #set the font bold + f = tkinter.font.Font(font=self['font']) + f['weight'] = 'bold' + self['font'] = f.name + +class USRPN2XXNetBurnerApp(tkinter.Frame): + """ + The top level gui application for the usrp-n2xx network burner. + Creates entry widgets and button with callback to write images. + """ + + def __init__(self, root, addr, fw, fpga): + + tkinter.Frame.__init__(self, root) + + #pack the file entry widgets + SectionLabel(self, text="Select Images").pack(pady=5) + self._fw_img_entry = BinFileEntry(self, "Firmware Image", def_path=fw) + self._fw_img_entry.pack() + self._fpga_img_entry = BinFileEntry(self, "FPGA Image", def_path=fpga) + self._fpga_img_entry.pack() + + #pack the destination entry widget + SectionLabel(self, text="Select Address").pack(pady=5) + self._addr_entry = tkinter.Entry(self, width=30) + self._addr_entry.insert(tkinter.END, addr) + self._addr_entry.pack() + + #the do it button + SectionLabel(self, text="").pack(pady=5) + button = tkinter.Button(self, text="Burn Images", command=self._burn) + self._enable_input = lambda: button.configure(state=tkinter.NORMAL) + self._disable_input = lambda: button.configure(state=tkinter.DISABLED) + button.pack() + + #a progress bar to monitor the status + progress_frame = tkinter.Frame(self) + progress_frame.pack() + self._status = tkinter.StringVar() + tkinter.Label(progress_frame, textvariable=self._status).pack(side=tkinter.LEFT) + self._pbar = ProgressBar(progress_frame) + self._pbar.pack(side=tkinter.RIGHT, expand=True) + + def _burn(self): + self._disable_input() + + #grab strings from the gui + fw = self._fw_img_entry.get_filename() + fpga = self._fpga_img_entry.get_filename() + addr = self._addr_entry.get() + + #check input + if not addr: + tkinter.messagebox.showerror('Error:', 'No address specified!') + return + if not fw and not fpga: + tkinter.messagebox.showerror('Error:', 'No images specified!') + return + if fw and not os.path.exists(fw): + tkinter.messagebox.showerror('Error:', 'Firmware image not found!') + return + if fpga and not os.path.exists(fpga): + tkinter.messagebox.showerror('Error:', 'FPGA image not found!') + return + + try: + #make a new burner object and attempt the burner operation + burner = usrp_n2xx_net_burner.burner_socket(addr=addr) + + for (image_type, fw_img, fpga_img) in (('FPGA', '', fpga), ('Firmware', fw, '')): + #setup callbacks that update the gui + def status_cb(status): + self._pbar.set(0.0) #status change, reset the progress + self._status.set("%s %s "%(status.title(), image_type)) + self.update() + def progress_cb(progress): + self._pbar.set(progress) + self.update() + burner.set_callbacks(progress_cb=progress_cb, status_cb=status_cb) + burner.burn_fw(fw=fw_img, fpga=fpga_img, reset=False, safe=False) + + if tkinter.messagebox.askyesno("Burn was successful!", "Reset the device?"): + burner.reset_usrp() + + except Exception as e: + tkinter.messagebox.showerror('Verbose:', 'Error: %s'%str(e)) + + #reset the progress bar + self._pbar.set(0.0) + self._status.set("") + self._enable_input() + +######################################################################## +# main +######################################################################## +if __name__=='__main__': + options = usrp_n2xx_net_burner.get_options() + root = tkinter.Tk() + root.title('USRP-N2XX Net Burner') + USRPN2XXNetBurnerApp(root, addr=options.addr, fw=options.fw, fpga=options.fpga).pack() + root.mainloop() + exit() |