diff options
| -rw-r--r-- | host/docs/usrp2.rst | 2 | ||||
| -rw-r--r-- | host/utils/CMakeLists.txt | 12 | ||||
| -rw-r--r-- | host/utils/usrp2_addr_burner.cpp (renamed from host/utils/usrp2_burner.cpp) | 2 | ||||
| -rwxr-xr-x | host/utils/usrp2_card_burner.py | 285 | 
4 files changed, 295 insertions, 6 deletions
| diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst index dfde06b27..c453354ca 100644 --- a/host/docs/usrp2.rst +++ b/host/docs/usrp2.rst @@ -103,7 +103,7 @@ Run the following commands:  ::      cd <prefix>/share/uhd/utils -    ./usrp_burner --addr=192.168.10.2 --new-ip=192.168.10.3 +    ./usrp_addr_burner --addr=192.168.10.2 --new-ip=192.168.10.3  **Method 2 (Linux Only):**  This method assumes that you do not know the IP address of your USRP2. diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt index 3c2236379..d28576e8c 100644 --- a/host/utils/CMakeLists.txt +++ b/host/utils/CMakeLists.txt @@ -19,12 +19,16 @@ ADD_EXECUTABLE(uhd_find_devices uhd_find_devices.cpp)  TARGET_LINK_LIBRARIES(uhd_find_devices uhd)  INSTALL(TARGETS uhd_find_devices RUNTIME DESTINATION ${RUNTIME_DIR}) -ADD_EXECUTABLE(usrp2_burner usrp2_burner.cpp) -TARGET_LINK_LIBRARIES(usrp2_burner uhd) -INSTALL(TARGETS usrp2_burner RUNTIME DESTINATION ${PKG_DATA_DIR}/utils) +ADD_EXECUTABLE(usrp2_addr_burner usrp2_addr_burner.cpp) +TARGET_LINK_LIBRARIES(usrp2_addr_burner uhd) +INSTALL(TARGETS usrp2_addr_burner RUNTIME DESTINATION ${PKG_DATA_DIR}/utils)  ADD_EXECUTABLE(uhd_burn_db_eeprom uhd_burn_db_eeprom.cpp)  TARGET_LINK_LIBRARIES(uhd_burn_db_eeprom uhd)  INSTALL(TARGETS uhd_burn_db_eeprom RUNTIME DESTINATION ${PKG_DATA_DIR}/utils) -INSTALL(PROGRAMS usrp2_recovery.py DESTINATION ${PKG_DATA_DIR}/utils) +INSTALL(PROGRAMS +    usrp2_recovery.py +    usrp2_card_burner.py +    DESTINATION ${PKG_DATA_DIR}/utils +) diff --git a/host/utils/usrp2_burner.cpp b/host/utils/usrp2_addr_burner.cpp index 9c1bf72fe..08fc1e218 100644 --- a/host/utils/usrp2_burner.cpp +++ b/host/utils/usrp2_addr_burner.cpp @@ -39,7 +39,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      //print the help message      if (vm.count("help")){ -        std::cout << boost::format("USRP2 Burner %s") % desc << std::endl; +        std::cout << boost::format("USRP2 Address Burner %s") % desc << std::endl;          return ~0;      } diff --git a/host/utils/usrp2_card_burner.py b/host/utils/usrp2_card_burner.py new file mode 100755 index 000000000..99cdcb626 --- /dev/null +++ b/host/utils/usrp2_card_burner.py @@ -0,0 +1,285 @@ +#!/usr/bin/env python + +######################################################################## +# Deal with raw devices +######################################################################## +import glob +import platform +import tempfile +import subprocess +import urllib + +SECTOR_SIZE = 512                 # bytes +MAX_FILE_SIZE =  1 * (2**20)      # maximum number of bytes we'll burn to a slot + +FPGA_OFFSET = 0                   # offset in flash to fpga image +FIRMWARE_OFFSET = 1 * (2**20)     # offset in flash to firmware image + +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() +            open(dd_path, 'wb').write(dd_bin) +        return dd_path +    return 'dd' + +def get_raw_device_hints(): +    if platform.system() == 'Windows': +        output = subprocess.Popen( +            [get_dd_path(), '--list'],#, '--filter=removable'], +            stdout=subprocess.PIPE, +            stderr=subprocess.STDOUT, +        ).stdout.read() +        volumes = list() +        for info in output.replace('\r', '').split('\n\\\\'): +            if 'removeable' not in info.lower(): continue +            if 'link to' not in info: continue +            if 'size is' in info: +                size = info.split('size is')[-1].split()[0] +                if int(size) > 2048e6: continue +            if 'Mounted on' in info: +                volumes.append(info.split('Mounted on')[-1].split()[0]) +                continue +            volumes.append(info.split('link to')[-1].split()[0]) +        return volumes +    if platform.system() == 'Linux': +        return sorted(set(filter(lambda sd: not sd[-1].isdigit(), glob.glob("/dev/sd*")))) +    return () + +def verify_image(image_file, device_file, offset): +    #create a temporary file to store the readback +    tmp = tempfile.mkstemp() +    os.close(tmp[0]) +    tmp_file = tmp[1] + +    #execute a dd subprocess +    args = [ +        get_dd_path(), +        "of=%s"%tmp_file, +        "if=%s"%device_file, +        "skip=%d"%offset, +        "bs=%d"%SECTOR_SIZE, +        "count=%d"%(MAX_FILE_SIZE/SECTOR_SIZE), +    ] +    p = subprocess.Popen( +        args, +        stdout=subprocess.PIPE, +        stderr=subprocess.STDOUT, +    ) +    ret = p.wait() +    verbose = p.stdout.read() +    if ret != 0: raise Exception, verbose + +    #read in the image and readback +    img_data = open(image_file, 'rb').read() +    tmp_data = open(tmp_file, 'rb').read(len(img_data)) + +    #verfy the data +    if img_data != tmp_data: return 'Verification Failed:\n%s'%verbose +    return 'Verification Passed:\n%s'%verbose + +def write_image(image_file, device_file, offset): +    args = [ +        get_dd_path(), +        "if=%s"%image_file, +        "of=%s"%device_file, +        "seek=%d"%offset, +        "bs=%d"%SECTOR_SIZE, +    ] +    p = subprocess.Popen( +        args, +        stdout=subprocess.PIPE, +        stderr=subprocess.STDOUT, +    ) +    ret = p.wait() +    verbose = p.stdout.read() + +    #get the verbose back to the caller +    if ret != 0: raise Exception, verbose +    return verbose + +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 +    return '%s\n%s'%( +        write_image( +            image_file=image_file, +            device_file=device_file, +            offset=offset, +        ), verify_image( +            image_file=image_file, +            device_file=device_file, +            offset=offset, +        ), +    ) + +def burn_sd_card(dev, fw, fpga): +    verbose = '' +    if fw: verbose += 'Burn firmware image verbose:\n%s\n'%write_and_verify( +        image_file=fw, device_file=dev, offset=FIRMWARE_OFFSET +    ) +    if fpga: verbose += 'Burn fpga image verbose:\n%s\n'%write_and_verify( +        image_file=fpga, device_file=dev, offset=FPGA_OFFSET +    ) +    return verbose + +######################################################################## +# Graphical Tk stuff +######################################################################## +import Tkinter, Tkconstants, 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 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) + +        self._hints = Tkinter.Listbox(self) +        self._hints.bind("<<ListboxSelect>>", self._listbox_cb) +        for hint in get_raw_device_hints(): +            self._hints.insert(Tkinter.END, hint) +        self._hints.pack(expand=Tkinter.YES, fill=Tkinter.X) + +        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) + +    def _listbox_cb(self, event): +        try: +            sel = self._hints.get(self._hints.curselection()[0]) +            self._entry.delete(0, Tkinter.END) +            self._entry.insert(0, sel) +        except Exception, e: print e + +    def get_devname(self): +        return self._entry.get() + +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 USRP2CardBurnerApp(Tkinter.Frame): +    """ +    The top level gui application for the usrp2 sd card burner. +    Creates entry widgets and button with callback to write images. +    """ + +    def __init__(self, root, dev, 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 Device").pack(pady=5) +        self._raw_dev_entry = DeviceEntryWidget(self, text=dev) +        self._raw_dev_entry.pack() + +        #the do it button +        SectionLabel(self, text="").pack(pady=5) +        Tkinter.Button(self, text="Burn SD Card", command=self._burn).pack() + +    def _burn(self): +        #grab strings from the gui +        fw = self._fw_img_entry.get_filename() +        fpga = self._fpga_img_entry.get_filename() +        dev = self._raw_dev_entry.get_devname() + +        #check input +        if not dev: +            tkMessageBox.showerror('Error:', 'No device 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 + +        #burn the sd card +        try: +            verbose = burn_sd_card(dev=dev, fw=fw, fpga=fpga) +            tkMessageBox.showinfo('Verbose:', verbose) +        except Exception, e: +            tkMessageBox.showerror('Verbose:', 'Error: %s'%str(e)) + +######################################################################## +# Main +######################################################################## +import optparse + +if __name__=='__main__': +    parser = optparse.OptionParser() +    parser.add_option("--gui", action="store_true", default=False, help="run in gui mode") +    parser.add_option("--dev", type="string", help="raw device path", 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='') +    (options, args) = parser.parse_args() + +    if options.gui: +        root = Tkinter.Tk() +        root.title('USRP2 SD Card Burner') +        USRP2CardBurnerApp(root, dev=options.dev, fw=options.fw, fpga=options.fpga).pack() +        root.mainloop() +        exit() + +    if not options.dev: raise Exception, 'no raw device path specified' +    print burn_sd_card(dev=options.dev, fw=options.fw, fpga=options.fpga) | 
