summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xhost/utils/usrp_n2xx_net_burner.py451
1 files changed, 224 insertions, 227 deletions
diff --git a/host/utils/usrp_n2xx_net_burner.py b/host/utils/usrp_n2xx_net_burner.py
index db94d50a4..6fdc9df20 100755
--- a/host/utils/usrp_n2xx_net_burner.py
+++ b/host/utils/usrp_n2xx_net_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
@@ -27,7 +27,7 @@ import re
import struct
import socket
import sys
-import os.path
+import time
########################################################################
# constants
@@ -76,77 +76,28 @@ class update_id_t:
_seq = -1
def seq():
- global _seq
- _seq = _seq+1
- return _seq
+ global _seq
+ _seq = _seq+1
+ return _seq
########################################################################
# helper functions
########################################################################
def unpack_flash_args_fmt(s):
- return struct.unpack(FLASH_ARGS_FMT, s) #(proto_ver, pktid, seq, flash_addr, length, data)
+ return struct.unpack(FLASH_ARGS_FMT, s) #(proto_ver, pktid, seq, flash_addr, length, data)
def unpack_flash_info_fmt(s):
- return struct.unpack(FLASH_INFO_FMT, s) #(proto_ver, pktid, seq, sector_size_bytes, memory_size_bytes)
+ return struct.unpack(FLASH_INFO_FMT, s) #(proto_ver, pktid, seq, sector_size_bytes, memory_size_bytes)
def unpack_flash_ip_fmt(s):
- return struct.unpack(FLASH_IP_FMT, s) #(proto_ver, pktid, seq, ip_addr)
+ 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):
- return struct.pack(FLASH_ARGS_FMT, proto_ver, pktid, seq, flash_addr, length, data)
+ 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):
- return struct.pack(FLASH_INFO_FMT, proto_ver, pktid, seq, sector_size_bytes, memory_size_bytes)
+ return struct.pack(FLASH_INFO_FMT, proto_ver, pktid, seq, sector_size_bytes, memory_size_bytes)
-def send_and_recv(pkt, ip):
- update_socket = create_socket()
-
- try:
- update_socket.sendto(pkt, (ip, UDP_FW_UPDATE_PORT))
- except Exception, e:
- print e
- sys.exit(1)
-
- try:
- (recv_pkt, recv_addr) = update_socket.recvfrom(UDP_MAX_XFER_BYTES)
- except Exception, e:
- print e
- sys.exit(1)
-
- if recv_addr != (options.ip, UDP_FW_UPDATE_PORT):
- raise Exception, "Packet received from invalid IP %s, expected %s" % (recv_addr, options.ip)
-
- return recv_pkt
-
-def create_socket():
- socket.setdefaulttimeout(UDP_TIMEOUT)
- update_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- return update_socket
-
-#just here to validate comms
-def init_update(ip):
- out_pkt = pack_flash_args_fmt(USRP2_FW_PROTO_VERSION, update_id_t.USRP2_FW_UPDATE_ID_OHAI_LOL, seq(), 0, 0, "")
- in_pkt = send_and_recv(out_pkt, ip)
- (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."
- else:
- 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(ip):
- 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 = send_and_recv(out_pkt, ip)
-
- (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))
-
-
- return (memory_size_bytes, sector_size_bytes)
-
def is_valid_fpga_image(fpga_image):
for i in range(0,63):
if ord(fpga_image[i]) == 0xFF:
@@ -155,7 +106,7 @@ def is_valid_fpga_image(fpga_image):
return 1
return 0
-
+
def is_valid_fw_image(fw_image):
for i in range(0,4):
if ord(fw_image[i]) != 0x0B:
@@ -163,158 +114,205 @@ def is_valid_fw_image(fw_image):
return 1
-def burn_fw(ip, fw, fpga, reset, safe):
- init_update(ip)
- (flash_size, sector_size) = get_flash_info(ip)
-
- print "Flash size: %i\nSector size: %i" % (flash_size, sector_size)
-
- if fpga:
- if safe:
- image_location = SAFE_FPGA_IMAGE_LOCATION_ADDR
- else:
- image_location = PROD_FPGA_IMAGE_LOCATION_ADDR
-
- fpga_file = open(fpga, 'rb')
- fpga_image = fpga_file.read()
-
- if len(fpga_image) > FPGA_IMAGE_SIZE_BYTES:
- print "Error: FPGA image file too large."
- return 0
-
- if not is_valid_fpga_image(fpga_image):
- print "Error: Invalid FPGA image file."
- return 0
-
- erase_image(ip, image_location, FPGA_IMAGE_SIZE_BYTES)
- write_image(ip, fpga_image, image_location)
- verify_image(ip, fpga_image, image_location)
-
- if fw:
- if safe:
- image_location = SAFE_FW_IMAGE_LOCATION_ADDR
- else:
- image_location = PROD_FW_IMAGE_LOCATION_ADDR
-
- fw_file = open(fw, 'rb')
- fw_image = fw_file.read()
-
- if len(fw_image) > FW_IMAGE_SIZE_BYTES:
- print "Error: Firmware image file too large."
- return 0
-
- if not is_valid_fw_image(fw_image):
- print "Error: Invalid firmware image file."
- return 0
-
- erase_image(ip, image_location, FW_IMAGE_SIZE_BYTES)
- write_image(ip, fw_image, image_location)
- verify_image(ip, fw_image, image_location)
-
- if reset:
- reset_usrp(ip)
-
-def write_image(ip, image, addr):
- print "Writing 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])
- in_pkt = send_and_recv(out_pkt, ip)
-
- (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))
-
- image = image[FLASH_DATA_PACKET_SIZE:]
- addr += FLASH_DATA_PACKET_SIZE
-
-def verify_image(ip, image, addr):
- print "Verifying data"
- readsize = len(image)
- 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, "")
- in_pkt = send_and_recv(out_pkt, ip)
-
- (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))
-
- readdata += data[:thisreadsize]
- readsize -= FLASH_DATA_PACKET_SIZE
- addr += FLASH_DATA_PACKET_SIZE
-
- 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."
- else:
- print "Success."
-
-def read_flash(ip, image, size, addr):
- 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, "")
- in_pkt = send_and_recv(out_pkt, ip)
-
- (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))
-
- readdata += data[:thisreadsize]
- readsize -= FLASH_DATA_PACKET_SIZE
- addr += FLASH_DATA_PACKET_SIZE
-
- print "Read back %i bytes" % len(readdata)
-
- #write to disk
- f = open(image, 'w')
- f.write(readdata)
- f.close()
-
-def reset_usrp(ip):
- 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 = send_and_recv(out_pkt, ip)
-
- (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."
-
-def erase_image(ip, addr, length):
- #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, "")
- in_pkt = send_and_recv(out_pkt, ip)
-
- (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))
-
- print "Erasing %i bytes at %i" % (length, addr)
-
- #now wait for it to finish
- while(1):
- 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 = send_and_recv(out_pkt, ip)
-
- (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))
+########################################################################
+# Burner class, holds a socket and send/recv routines
+########################################################################
+class burner_socket(object):
+ def __init__(self, ip):
+ 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)
+
+ try: recv_pkt = self._sock.recv(UDP_MAX_XFER_BYTES)
+ except Exception, e:
+ print e
+ sys.exit(1)
+
+ return recv_pkt
+
+ #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)
+ (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."
+ else:
+ 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, "")
+ 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))
+
+ 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)
+
+ if fpga:
+ if safe: image_location = SAFE_FPGA_IMAGE_LOCATION_ADDR
+ else: image_location = PROD_FPGA_IMAGE_LOCATION_ADDR
+
+ fpga_file = open(fpga, 'rb')
+ fpga_image = fpga_file.read()
+
+ if len(fpga_image) > FPGA_IMAGE_SIZE_BYTES:
+ print "Error: FPGA image file too large."
+ return 0
+
+ if not is_valid_fpga_image(fpga_image):
+ print "Error: Invalid FPGA image file."
+ return 0
+
+ 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"
+
+ if fw:
+ if safe: image_location = SAFE_FW_IMAGE_LOCATION_ADDR
+ else: image_location = PROD_FW_IMAGE_LOCATION_ADDR
+
+ fw_file = open(fw, 'rb')
+ fw_image = fw_file.read()
+
+ if len(fw_image) > FW_IMAGE_SIZE_BYTES:
+ print "Error: Firmware image file too large."
+ return 0
+
+ if not is_valid_fw_image(fw_image):
+ print "Error: Invalid firmware image file."
+ return 0
+
+ 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"
+
+ if reset: self.reset_usrp()
+
+ def write_image(self, image, addr):
+ print "Writing 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])
+ 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))
+
+ image = image[FLASH_DATA_PACKET_SIZE:]
+ addr += FLASH_DATA_PACKET_SIZE
+
+ def verify_image(self, image, addr):
+ print "Verifying data"
+ readsize = len(image)
+ 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, "")
+ 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))
+
+ readdata += data[:thisreadsize]
+ readsize -= FLASH_DATA_PACKET_SIZE
+ addr += FLASH_DATA_PACKET_SIZE
+
+ 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."
+ else:
+ print "Success."
+
+ def read_image(self, image, size, addr):
+ 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, "")
+ 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))
+
+ readdata += data[:thisreadsize]
+ readsize -= FLASH_DATA_PACKET_SIZE
+ addr += FLASH_DATA_PACKET_SIZE
+
+ print "Read back %i bytes" % len(readdata)
+
+ #write to disk
+ f = open(image, 'w')
+ f.write(readdata)
+ 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)
+
+ (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."
+
+ def erase_image(self, addr, length):
+ #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, "")
+ 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))
+
+ print "Erasing %i bytes at %i" % (length, addr)
+
+ #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, "")
+ 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))
########################################################################
@@ -340,33 +338,32 @@ if __name__=='__main__':
if not options.ip: raise Exception, 'no ip 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 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: """)
- if response != "yes":
- sys.exit(0)
-
- if options.read is True:
+ if response != "yes": sys.exit(0)
+
+ burner = burner_socket(ip=options.ip)
+
+ if options.read:
if options.fw:
file = options.fw
if os.path.isfile(file):
response = raw_input("File already exists -- overwrite? (y/n) ")
- if response != "y":
- sys.exit(0)
+ 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
- read_flash(options.ip, file, size, addr)
- if options.fpga:
+ burner.read_image(file, size, addr)
+
+ if options.fpga:
file = options.fpga
if os.path.isfile(file):
response = raw_input("File already exists -- overwrite? (y/n) ")
- if response != "y":
- sys.exit(0)
+ 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
- read_flash(options.ip, file, size, addr)
-
- else:
- burn_fw(ip=options.ip, fw=options.fw, fpga=options.fpga, reset=options.reset, safe=options.overwrite_safe)
+ burner.read_image(file, size, addr)
+
+ else: burner.burn_fw(fw=options.fw, fpga=options.fpga, reset=options.reset, safe=options.overwrite_safe)