diff options
author | Josh Blum <josh@joshknows.com> | 2011-03-26 23:03:04 -0700 |
---|---|---|
committer | Josh Blum <josh@joshknows.com> | 2011-03-26 23:03:04 -0700 |
commit | 8d8c694baecccd3cff52c95cae8a7d2afae615d7 (patch) | |
tree | 0303ab75335d0ff4a011184e0af6ff5fa0a70876 /host/utils/usrp_n2xx_net_burner_gui.py | |
parent | 95b966a599c0030921dc6b530ca8c94633d905f6 (diff) | |
download | uhd-8d8c694baecccd3cff52c95cae8a7d2afae615d7.tar.gz uhd-8d8c694baecccd3cff52c95cae8a7d2afae615d7.tar.bz2 uhd-8d8c694baecccd3cff52c95cae8a7d2afae615d7.zip |
usrp2: created net burner gui wrapper for N series
The gui looks and works much like the card burner gui.
However, the possible devices are not enumerated.
Handles errors, resetting, and showing progress.
Added hooks to net burner for progress callbacks (progress meter).
Changed --ip option to --addr (any resolvable address will work).
Fixes issue with "timeout" on reset, by catching socket.timeout.
Updated the manual to reflect using the gui app and --addr option.
Diffstat (limited to 'host/utils/usrp_n2xx_net_burner_gui.py')
-rw-r--r-- | host/utils/usrp_n2xx_net_burner_gui.py | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/host/utils/usrp_n2xx_net_burner_gui.py b/host/utils/usrp_n2xx_net_burner_gui.py new file mode 100644 index 000000000..7fcb7d121 --- /dev/null +++ b/host/utils/usrp_n2xx_net_burner_gui.py @@ -0,0 +1,188 @@ +#!/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 threading +import usrp_n2xx_net_burner #import implementation +import Tkinter, tkFileDialog, tkFont, 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 = tkFileDialog.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 = tkFont.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() + threading.Thread(target=self._burn_bg).start() + + def _burn_bg(self): + #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: + tkMessageBox.showerror('Error:', 'No address specified!') + return + if not fw and not fpga: + tkMessageBox.showerror('Error:', 'No images specified!') + return + if fw and not os.path.exists(fw): + tkMessageBox.showerror('Error:', 'Firmware image not found!') + return + if fpga and not os.path.exists(fpga): + tkMessageBox.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)) + burner.set_callbacks(progress_cb=self._pbar.set, status_cb=status_cb) + burner.burn_fw(fw=fw_img, fpga=fpga_img, reset=False, safe=False) + + if tkMessageBox.askyesno("Burn was successful!", "Reset the device?"): + burner.reset_usrp() + + except Exception, e: + tkMessageBox.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() |