Use built-in Python DFU-util

This commit is contained in:
iabdalkader 2014-10-03 03:33:00 +02:00
parent 0573d0726d
commit 4bb1d3fc3f
3 changed files with 84 additions and 50 deletions

View File

@ -55,6 +55,7 @@
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="border_width">5</property> <property name="border_width">5</property>
<property name="title" translatable="yes">Update Firmware</property> <property name="title" translatable="yes">Update Firmware</property>
<property name="modal">True</property>
<property name="window_position">center-on-parent</property> <property name="window_position">center-on-parent</property>
<property name="destroy_with_parent">True</property> <property name="destroy_with_parent">True</property>
<property name="type_hint">dialog</property> <property name="type_hint">dialog</property>
@ -107,12 +108,15 @@
</packing> </packing>
</child> </child>
<child> <child>
<object class="GtkSpinner" id="fw_spinner"> <object class="GtkProgressBar" id="fw_progressbar">
<property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="show_text">True</property>
<property name="text" translatable="yes"> </property>
</object> </object>
<packing> <packing>
<property name="expand">True</property> <property name="expand">True</property>
<property name="fill">True</property> <property name="fill">False</property>
<property name="position">1</property> <property name="position">1</property>
</packing> </packing>
</child> </child>

View File

@ -1,28 +1,30 @@
#!/usr/bin/env python #!/usr/bin/env python
import pydfu
import openmv
import sys, os, os.path import sys, os, os.path
import gtk from time import sleep
import gtksourceview2 as gtksourceview import gtk, gtksourceview2 as gtksourceview
import gio import gio
import pango
import gobject import gobject
import vte import vte
import serial import serial
from time import sleep
import usb.core import usb.core
import usb.util import usb.util
import numpy as np import numpy as np
import openmv
from os.path import expanduser from os.path import expanduser
import subprocess
UI_PATH =os.path.dirname(os.path.realpath(__file__))+"/openmv-ide.glade" UI_PATH =os.path.dirname(os.path.realpath(__file__))+"/openmv-ide.glade"
CONFIG_PATH = expanduser("~")+"/.openmvide.config" CONFIG_PATH = expanduser("~")+"/.openmvide.config"
EXAMPLE_PATH = os.path.dirname(os.path.realpath(__file__))+"/examples" EXAMPLE_PATH = os.path.dirname(os.path.realpath(__file__))+"/examples"
SCRIPTS_PATH = os.path.dirname(os.path.realpath(__file__))+"/scripts" SCRIPTS_PATH = os.path.dirname(os.path.realpath(__file__))+"/scripts"
FWBIN_PATH = "" FWBIN_PATH = "/home/mux/src/c/stm32f4/openmv/src/build/openmv.bin"
DFU_CMD = "dfu-util -d 0483:df11 -c 1 -i 0 -a 0 -s 0x08000000 -D %s" DFU_CMD = "dfu-util -d 0483:df11 -c 1 -i 0 -a 0 -s 0x08000000 -D %s"
SCALE =1 SCALE =1
flash_offsets= [0x08000000, 0x08004000, 0x08008000, 0x0800C000,
0x08010000, 0x08020000, 0x08040000, 0x08060000,
0x08080000, 0x080A0000, 0x080C0000, 0x080E0000]
class OMVGtk: class OMVGtk:
def __init__(self): def __init__(self):
@ -146,6 +148,11 @@ class OMVGtk:
message.run() message.run()
message.destroy() message.destroy()
def refresh_gui(self, delay=0.0001, wait=0.0001):
sleep(delay)
gtk.main_iteration_do(block=False)
sleep(wait)
def connect(self): def connect(self):
self.terminal = self.builder.get_object('terminal') self.terminal = self.builder.get_object('terminal')
try: try:
@ -218,16 +225,54 @@ class OMVGtk:
dialog.destroy() dialog.destroy()
# Fake multitasking :P
def fwupdate_task(self, state):
if (state["init"]):
pydfu.init()
state["init"]=False
state["erase"]=True
state["bar"].set_text("Erasing...")
return True
elif (state["erase"]):
page = state["page"]
total = len(flash_offsets)
pydfu.page_erase(flash_offsets[page])
page +=1
state["bar"].set_fraction(page/float(total))
if (page == total):
state["erase"] = False
state["write"] = True
state["bar"].set_text("Uploading...")
state["page"] = page
return True
elif (state["write"]):
buf = state["buf"]
xfer_bytes = state["xfer_bytes"]
xfer_total = state["xfer_total"]
# Send chunk
chunk = min (64, xfer_total-xfer_bytes)
pydfu.write_page(buf[xfer_bytes:xfer_bytes+chunk], xfer_bytes)
xfer_bytes += chunk
state["xfer_bytes"] = xfer_bytes
state["bar"].set_fraction(xfer_bytes/float(xfer_total))
if (xfer_bytes == xfer_total):
pydfu.exit_dfu()
state["dialog"].hide()
return False
return True
def fwupdate_clicked(self, widget): def fwupdate_clicked(self, widget):
if (self.connected): if (self.connected):
dialog = self.builder.get_object("fw_dialog") dialog = self.builder.get_object("fw_dialog")
fw_entry = self.builder.get_object("fw_entry") fw_entry = self.builder.get_object("fw_entry")
spinner = self.builder.get_object("fw_spinner") fw_progress = self.builder.get_object("fw_progressbar")
ok_button = self.builder.get_object("fw_ok_button") ok_button = self.builder.get_object("fw_ok_button")
cancel_button = self.builder.get_object("fw_cancel_button") cancel_button = self.builder.get_object("fw_cancel_button")
spinner.stop()
spinner.set_visible(False)
ok_button.set_sensitive(True) ok_button.set_sensitive(True)
cancel_button.set_sensitive(True) cancel_button.set_sensitive(True)
dialog.set_transient_for(self.window); dialog.set_transient_for(self.window);
@ -238,24 +283,24 @@ class OMVGtk:
if dialog.run() == gtk.RESPONSE_OK: if dialog.run() == gtk.RESPONSE_OK:
ok_button.set_sensitive(False) ok_button.set_sensitive(False)
cancel_button.set_sensitive(False) cancel_button.set_sensitive(False)
spinner.set_visible(True) fw_progress.set_text("")
spinner.start() fw_progress.set_fraction(0.0)
with open(fw_entry.get_text(), 'r') as f:
buf= f.read()
state={"init":True, "erase":False, "write":False,
"page":0, "buf":buf, "bar":fw_progress, "dialog":dialog,
"xfer_bytes":0, "xfer_total":len(buf)}
# call dfu-util # call dfu-util
openmv.enter_dfu() openmv.enter_dfu()
sleep(1.0) sleep(1.0)
gobject.gobject.idle_add(self.fwupdate_task, state);
dfu_util = subprocess.Popen(DFU_CMD%fw_entry.get_text(), shell=True, stdout=subprocess.PIPE) # try:
# except Exception as e:
while dfu_util.poll() == None and gtk.events_pending(): # self.show_message_dialog(gtk.MESSAGE_ERROR, "Failed to update firmware%s"%(e))
gtk.main_iteration()
if (dfu_util.returncode):
self.show_message_dialog(gtk.MESSAGE_ERROR, "Failed to update firmware\n")
openmv.exit_dfu()
dialog.hide()
def reset_clicked(self, widget): def reset_clicked(self, widget):
if (self.connected): if (self.connected):

View File

@ -1,14 +1,20 @@
#!/usr/bin/env python #!/usr/bin/env python
import sys # This file is part of the OpenMV project.
# Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com>
# This work is licensed under the MIT license, see the file LICENSE for details.
#
# Openmv module.
import struct
import sys,time
import usb.core import usb.core
import usb.util import usb.util
import struct import pydfu
import numpy as np import numpy as np
from PIL import Image from PIL import Image
import time
import StringIO
__dev = None __dev = None
# VID/PID # VID/PID
__VID=0xf055 __VID=0xf055
__PID=0x9800 __PID=0x9800
@ -59,7 +65,6 @@ def init():
__dev.set_interface_altsetting(__INTERFACE, __ALTSETTING) __dev.set_interface_altsetting(__INTERFACE, __ALTSETTING)
def release(): def release():
global __dev
try: try:
# Release device # Release device
usb.util.dispose_resources(dev) usb.util.dispose_resources(dev)
@ -83,20 +88,16 @@ def fb_to_arr(buff, bpp):
return np.column_stack((r,g,b)) return np.column_stack((r,g,b))
def fb_size(): def fb_size():
global __dev
# read fb header # read fb header
buf = __dev.ctrl_transfer(0xC1, __USBDBG_FRAME_SIZE, 0, __INTERFACE, __FB_HDR_SIZE, __TIMEOUT) buf = __dev.ctrl_transfer(0xC1, __USBDBG_FRAME_SIZE, 0, __INTERFACE, __FB_HDR_SIZE, __TIMEOUT)
size = struct.unpack("III", buf) size = struct.unpack("III", buf)
return size return size
def fb_lock(): def fb_lock():
global __dev
buf = __dev.ctrl_transfer(0xC1, __USBDBG_FRAME_LOCK, 0, __INTERFACE, 1, __TIMEOUT) buf = __dev.ctrl_transfer(0xC1, __USBDBG_FRAME_LOCK, 0, __INTERFACE, 1, __TIMEOUT)
return struct.unpack("B", buf)[0] return struct.unpack("B", buf)[0]
def fb_dump(): def fb_dump():
global __dev
if (fb_lock() == 0): if (fb_lock() == 0):
return None return None
@ -161,22 +162,6 @@ def enter_dfu():
except: except:
pass pass
#See app note AN3156
def exit_dfu():
timeout = 1000
dev = usb.core.find(idVendor=0x0483, idProduct=0xdf11)
# Claim DFU interface
usb.util.claim_interface(dev, 0)
# Send DNLOAD with 0 length to exit DFU
dev.ctrl_transfer(0x21, 0x01, 0, 0, None, timeout)
# Execute last command
dev.ctrl_transfer(0xA1, 0x03, 0, 0, 6, timeout)
# Release device
usb.util.dispose_resources(dev)
def reset(): def reset():
try: try:
# This will timeout. # This will timeout.