From cbace2759a624eac834318ba7a20fcd2dff4a8a2 Mon Sep 17 00:00:00 2001 From: "shimniok@gmail.com" Date: Fri, 26 Sep 2014 11:15:27 -0600 Subject: [PATCH 1/7] added functionality for starting bootloader via USBDBG_BOOT --- src/omv/usbdbg.c | 25 +++++++++++++++++++++++++ src/omv/usbdbg.h | 1 + 2 files changed, 26 insertions(+) diff --git a/src/omv/usbdbg.c b/src/omv/usbdbg.c index f333e13b8..8b40bafd9 100644 --- a/src/omv/usbdbg.c +++ b/src/omv/usbdbg.c @@ -14,6 +14,7 @@ #include "py/py_file.h" #include "core_cm4.h" #include "usbdbg.h" +#include "rcc_ctrl.h" #define USB_TX_BUF_SIZE (64) static int xfer_bytes; @@ -190,6 +191,30 @@ void usbdbg_control(void *buffer, uint8_t request, uint16_t length) NVIC_SystemReset(); break; + case USBDBG_BOOT: + /* + rcc_ctrl_hsi(); // run off the HSI clock, no PLL + SysTick->CTRL = 0; // reset the SysTick timer + SysTick->LOAD = 0; + SysTick->VAL = 0; + __set_PRIMASK(1); // disable interrupts + __set_MSP(0x20001000); // set main SP to its default + */ + asm volatile( + "ldr r0, =0x40023844\n\t" // RCC_APB2ENR + "ldr r1, =0x00004000\n\t" // enable SYSCFG clock + "str r1, [r0, #0]\n\t" + "ldr r0, =0x40013800\n\t" // SYSCFG_MEMRMP + "ldr r1, =0x00000001\n\t" // remap ROM at zero + "str r1, [r0, #0]\n\t" + "ldr r0, =0x1fff000\n\t" // load ROM base + "ldr sp,[r0, #0]\n\t" // assign main stack pointer + "ldr r0,[r0, #4]\n\t" // load bootloader address + "bx r0\n\t" + ); + while (1); + break; + default: /* error */ cmd = USBDBG_NONE; break; diff --git a/src/omv/usbdbg.h b/src/omv/usbdbg.h index 8fda766e2..4e0610b09 100644 --- a/src/omv/usbdbg.h +++ b/src/omv/usbdbg.h @@ -22,6 +22,7 @@ enum usbdbg_cmd { USBDBG_ATTR_READ, USBDBG_ATTR_WRITE, USBDBG_SYS_RESET, + USBDBG_BOOT }; void usbdbg_init(); int usbdbg_script_ready(); From ea6abcff77ce8a579d21321ea3cde395d532180e Mon Sep 17 00:00:00 2001 From: "shimniok@gmail.com" Date: Fri, 26 Sep 2014 11:16:09 -0600 Subject: [PATCH 2/7] added functionality to send USBDBG_BOOT to force camera into bootloader --- usr/openmv.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/usr/openmv.py b/usr/openmv.py index ded28922c..1649d112b 100755 --- a/usr/openmv.py +++ b/usr/openmv.py @@ -34,6 +34,7 @@ __USBDBG_DESCRIPTOR_SAVE=9 __USBDBG_ATTR_READ=10 __USBDBG_ATTR_WRITE=11 __USBDBG_SYS_RESET=12 +__USBDBG_SYS_BOOT=13 ATTR_CONTRAST=0 ATTR_BRIGHTNESS=1 @@ -153,6 +154,13 @@ def set_attr(attr, value): def get_attr(attr): return 0 +def bootloader(): + try: + # This will timeout. + __dev.ctrl_transfer(0x41, __USBDBG_SYS_BOOT, 0, __INTERFACE, None, __TIMEOUT) + except: + pass + def reset(): try: # This will timeout. From 9618f383eafbcbd9dd8fb0c6ece4e57568a1a9f7 Mon Sep 17 00:00:00 2001 From: "shimniok@gmail.com" Date: Fri, 26 Sep 2014 11:39:13 -0600 Subject: [PATCH 3/7] Implemented DFU bootloader widget in UI, enabled handler, wrote handler to call bootloader in openmv. --- usr/openmv-ide.glade | 94 +++++++++++++++++++++++++++----------------- usr/openmv-ide.py | 6 +++ 2 files changed, 64 insertions(+), 36 deletions(-) diff --git a/usr/openmv-ide.glade b/usr/openmv-ide.glade index 226688f4d..fb889cb30 100644 --- a/usr/openmv-ide.glade +++ b/usr/openmv-ide.glade @@ -1,9 +1,8 @@ - + - -2 2 @@ -23,18 +22,18 @@ False + False True False - False Copy Color True + False True False - False Save Template True @@ -42,9 +41,9 @@ + False True False - False Save Descriptor True @@ -71,18 +70,19 @@ True dialog - + True False 1 - + True False end gtk-ok + False True True True @@ -98,6 +98,7 @@ gtk-cancel + False True True True @@ -139,8 +140,6 @@ True False False - True - True True @@ -163,18 +162,19 @@ True dialog - + True False 1 - + True False end gtk-ok + False True True True @@ -190,6 +190,7 @@ gtk-cancel + False True True True @@ -230,8 +231,6 @@ template.pgm False False - True - True True @@ -263,9 +262,9 @@ False + False True False - False _File True @@ -275,9 +274,9 @@ gtk-new + False True False - False True True @@ -286,9 +285,9 @@ gtk-open + False True False - False True True @@ -297,9 +296,9 @@ gtk-save + False True False - False True True @@ -308,9 +307,9 @@ gtk-save-as + False True False - False True True @@ -318,33 +317,33 @@ + False True False - False + False True False - False Examples True + False True False - False gtk-quit + False True False - False True True @@ -356,9 +355,9 @@ + False True False - False _Edit True @@ -368,9 +367,9 @@ gtk-cut + False True False - False True True @@ -378,9 +377,9 @@ gtk-copy + False True False - False True True @@ -388,9 +387,9 @@ gtk-paste + False True False - False True True @@ -398,9 +397,9 @@ gtk-delete + False True False - False True True @@ -411,18 +410,18 @@ + False True False - False _View True + False True False - False _Help True @@ -432,9 +431,9 @@ gtk-about + False True False - False True True @@ -456,6 +455,7 @@ False + False True False False @@ -471,6 +471,7 @@ + False True False False @@ -484,8 +485,26 @@ True + + + False + True + False + Enter bootloader + False + toolbutton7 + True + gtk-edit + + + + False + True + + + False True False False @@ -497,6 +516,7 @@ + False True False Execute Script @@ -513,6 +533,7 @@ + False True False Stop Script @@ -529,6 +550,7 @@ + False True False False @@ -540,6 +562,7 @@ + False True False False @@ -557,6 +580,7 @@ + False True False False @@ -568,6 +592,7 @@ + False True False False @@ -583,6 +608,7 @@ + False True False False @@ -598,6 +624,7 @@ + False True False False @@ -613,6 +640,7 @@ + False True False False @@ -646,8 +674,6 @@ True True - automatic - automatic True @@ -777,7 +803,6 @@ True True - delayed contrast_adjust True 0 @@ -793,7 +818,6 @@ True True - delayed brightness_adjust 0 0 @@ -810,7 +834,6 @@ True True - delayed saturation_adjust off off @@ -847,7 +870,6 @@ True True - delayed gainceiling_adjust off off diff --git a/usr/openmv-ide.py b/usr/openmv-ide.py index c7e6a8cad..8ca7bfe15 100755 --- a/usr/openmv-ide.py +++ b/usr/openmv-ide.py @@ -42,6 +42,7 @@ class OMVGtk: # set control buttons self.controls = [ + self.builder.get_object('bootloader_button'), self.builder.get_object('reset_button'), self.builder.get_object('exec_button'), self.builder.get_object('stop_button'), @@ -92,6 +93,7 @@ class OMVGtk: "on_top_window_destroy" : self.quit, "on_connect_clicked" : self.connect_clicked, "on_reset_clicked" : self.reset_clicked, + "on_bootloader_clicked" : self.bootloader_clicked, "on_execute_clicked" : self.execute_clicked, "on_stop_clicked" : self.stop_clicked, "on_motion_notify" : self.motion_notify, @@ -193,6 +195,10 @@ class OMVGtk: def connect_clicked(self, widget): self.connect() + + def bootloader_clicked(self, widget): + if (self.connected): + openmv.bootloader() def reset_clicked(self, widget): if (self.connected): From dbb2019b9a3a3150c1add43d82bda41b0d189726 Mon Sep 17 00:00:00 2001 From: "shimniok@gmail.com" Date: Fri, 26 Sep 2014 22:55:01 -0600 Subject: [PATCH 4/7] Added feature to reset into DFU from omv onboard software when receiving USBDB_BOOT --- src/cmsis/src/st/startup_stm32f407xx.s | 14 ++++++++++ src/omv/usbdbg.c | 36 +++++++++++++++++--------- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/cmsis/src/st/startup_stm32f407xx.s b/src/cmsis/src/st/startup_stm32f407xx.s index b0a04d16c..c3c6f39e7 100644 --- a/src/cmsis/src/st/startup_stm32f407xx.s +++ b/src/cmsis/src/st/startup_stm32f407xx.s @@ -76,7 +76,20 @@ defined in linker script */ .section .text.Reset_Handler .weak Reset_Handler .type Reset_Handler, %function + Reset_Handler: + ldr r0,=0x20002000 /* load magic number location */ + ldr r2,[r0, #0] + str r0,[r0, #0] /* invalidate */ + ldr r1,=0xDEADBEEF /* if magic number found */ + cmp r2,r1 + bne EnableCCM /* run the bootloader, else... */ + +Reboot_Loader: + ldr r0,=0x1FFF0000 + ldr sp,[r0, #0] + ldr r0,[r0, #4] + bx r0 EnableCCM: /* enable ccm clock */ @@ -122,6 +135,7 @@ LoopFillZerobss: /* Call the application's entry point.*/ bl main bx lr + .size Reset_Handler, .-Reset_Handler /** diff --git a/src/omv/usbdbg.c b/src/omv/usbdbg.c index 8b40bafd9..301f62f94 100644 --- a/src/omv/usbdbg.c +++ b/src/omv/usbdbg.c @@ -14,7 +14,7 @@ #include "py/py_file.h" #include "core_cm4.h" #include "usbdbg.h" -#include "rcc_ctrl.h" +#include "stm32f4xx_hal_rcc.h" #define USB_TX_BUF_SIZE (64) static int xfer_bytes; @@ -192,26 +192,36 @@ void usbdbg_control(void *buffer, uint8_t request, uint16_t length) break; case USBDBG_BOOT: + /* http://goo.gl/VcKqst + * disable IRQ, reset USART1 and RCC before setting MSP/PC. + * Disable all peripheral clocks + * Disable used PLL + * Disable interrupts + * Clear pending interrupts + */ /* - rcc_ctrl_hsi(); // run off the HSI clock, no PLL - SysTick->CTRL = 0; // reset the SysTick timer + __set_PRIMASK(1); // disable interrupts + HAL_RCC_DeInit(); // reset RCC + HAL_USART_DeInit( ); // reset USART1 + SysTick->CTRL = 0; // reset the SysTick timer SysTick->LOAD = 0; SysTick->VAL = 0; - __set_PRIMASK(1); // disable interrupts - __set_MSP(0x20001000); // set main SP to its default - */ + //__set_MSP(0x20001000); // set main SP to its default asm volatile( - "ldr r0, =0x40023844\n\t" // RCC_APB2ENR - "ldr r1, =0x00004000\n\t" // enable SYSCFG clock - "str r1, [r0, #0]\n\t" "ldr r0, =0x40013800\n\t" // SYSCFG_MEMRMP "ldr r1, =0x00000001\n\t" // remap ROM at zero "str r1, [r0, #0]\n\t" - "ldr r0, =0x1fff000\n\t" // load ROM base - "ldr sp,[r0, #0]\n\t" // assign main stack pointer - "ldr r0,[r0, #4]\n\t" // load bootloader address + "ldr r0, =0x1fff000\n\t" // load ROM base + "ldr sp,[r0, #0]\n\t" // assign main stack pointer + "ldr r0,[r0, #4]\n\t" // load bootloader address "bx r0\n\t" ); + // STM32F40xxx e.g., 405, 407 : 0x1FFF77DE + // STM32F429xx : 0x1FFF76DE + */ + // set magic flag => reset handler will jump into boot loader + *((uint32_t *)0x20002000) = 0xDEADBEEF; + NVIC_SystemReset(); while (1); break; @@ -220,3 +230,5 @@ void usbdbg_control(void *buffer, uint8_t request, uint16_t length) break; } } + + From 3fca55514abf22e2483962eec6446c79d22b6937 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Sat, 27 Sep 2014 18:57:12 +0200 Subject: [PATCH 5/7] Remove commented code --- src/omv/usbdbg.c | 38 ++++---------------------------------- 1 file changed, 4 insertions(+), 34 deletions(-) diff --git a/src/omv/usbdbg.c b/src/omv/usbdbg.c index 301f62f94..9ee41ee23 100644 --- a/src/omv/usbdbg.c +++ b/src/omv/usbdbg.c @@ -14,7 +14,6 @@ #include "py/py_file.h" #include "core_cm4.h" #include "usbdbg.h" -#include "stm32f4xx_hal_rcc.h" #define USB_TX_BUF_SIZE (64) static int xfer_bytes; @@ -191,39 +190,10 @@ void usbdbg_control(void *buffer, uint8_t request, uint16_t length) NVIC_SystemReset(); break; - case USBDBG_BOOT: - /* http://goo.gl/VcKqst - * disable IRQ, reset USART1 and RCC before setting MSP/PC. - * Disable all peripheral clocks - * Disable used PLL - * Disable interrupts - * Clear pending interrupts - */ - /* - __set_PRIMASK(1); // disable interrupts - HAL_RCC_DeInit(); // reset RCC - HAL_USART_DeInit( ); // reset USART1 - SysTick->CTRL = 0; // reset the SysTick timer - SysTick->LOAD = 0; - SysTick->VAL = 0; - //__set_MSP(0x20001000); // set main SP to its default - asm volatile( - "ldr r0, =0x40013800\n\t" // SYSCFG_MEMRMP - "ldr r1, =0x00000001\n\t" // remap ROM at zero - "str r1, [r0, #0]\n\t" - "ldr r0, =0x1fff000\n\t" // load ROM base - "ldr sp,[r0, #0]\n\t" // assign main stack pointer - "ldr r0,[r0, #4]\n\t" // load bootloader address - "bx r0\n\t" - ); - // STM32F40xxx e.g., 405, 407 : 0x1FFF77DE - // STM32F429xx : 0x1FFF76DE - */ - // set magic flag => reset handler will jump into boot loader - *((uint32_t *)0x20002000) = 0xDEADBEEF; - NVIC_SystemReset(); - while (1); - break; + case USBDBG_BOOT: + *((uint32_t *)0x20002000) = 0xDEADBEEF; + NVIC_SystemReset(); + break; default: /* error */ cmd = USBDBG_NONE; From 6fd18847ed27345a211eeb2a077374db0d7f1624 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Sat, 27 Sep 2014 18:58:23 +0200 Subject: [PATCH 6/7] Add exit DFU --- usr/openmv.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/usr/openmv.py b/usr/openmv.py index 1649d112b..f2f3704ca 100755 --- a/usr/openmv.py +++ b/usr/openmv.py @@ -154,12 +154,27 @@ def set_attr(attr, value): def get_attr(attr): return 0 -def bootloader(): - try: +def enter_dfu(): + try: # This will timeout. - __dev.ctrl_transfer(0x41, __USBDBG_SYS_BOOT, 0, __INTERFACE, None, __TIMEOUT) - except: - pass + __dev.ctrl_transfer(0x41, __USBDBG_SYS_BOOT, 0, __INTERFACE, None, __TIMEOUT) + except: + pass + +#See app note AN3156 +def exit_dfu(): + timeout = 1000 + dev = usb.core.find(idVendor=0x0483, idProduct=0xdf11) + usb.util.claim_interface(dev, 0) + + # Clear status + dev.ctrl_transfer(0x21, 0x04, 0, 0, None, timeout) + + # 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) def reset(): try: From a819be7b804f51d44cc150b0285c1700ec4be377 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Sat, 27 Sep 2014 21:16:47 +0200 Subject: [PATCH 7/7] Add Firmware Update from IDE --- bin/openmv.bin | Bin 521648 -> 521832 bytes usr/openmv-ide.glade | 191 +++++++++++++++++++++++++++++++++---------- usr/openmv-ide.py | 66 +++++++++++++-- usr/openmv.py | 13 +-- 4 files changed, 215 insertions(+), 55 deletions(-) diff --git a/bin/openmv.bin b/bin/openmv.bin index fb086ecafa1c2227b29b3de682dc352e30a4f9e5..36d4fe89daddb4cf58c9b3a13f745bdd9e79f1f1 100755 GIT binary patch delta 43461 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
h^DXI;wyec2<@qAZ{N0sEeN5#LcBPt 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 delta 43277 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 Yz09T!0BNlGJ4Cw4`F;8~SJmbJ2QWUA@c;k- diff --git a/usr/openmv-ide.glade b/usr/openmv-ide.glade index fb889cb30..7b8f0262d 100644 --- a/usr/openmv-ide.glade +++ b/usr/openmv-ide.glade @@ -1,8 +1,9 @@ - + + -2 2 @@ -22,18 +23,18 @@ False - False True False + False Copy Color True - False True False + False Save Template True @@ -41,15 +42,130 @@ - False True False + False Save Descriptor True + + False + 5 + Update Firmware + center-on-parent + True + dialog + + + True + False + 1 + + + True + False + end + + + gtk-ok + True + True + True + False + True + + + False + False + 0 + + + + + gtk-cancel + True + True + True + False + True + + + False + False + 1 + + + + + False + True + end + 0 + + + + + False + + + True + True + 1 + + + + + True + False + + + True + True + + True + False + False + True + True + + + True + True + 0 + + + + + ... + True + True + True + False + + + + False + False + 1 + + + + + False + True + 2 + + + + + + fw_ok_button + fw_cancel_button + + 6 1 @@ -70,19 +186,18 @@ True dialog - + True False 1 - + True False end gtk-ok - False True True True @@ -98,7 +213,6 @@ gtk-cancel - False True True True @@ -140,6 +254,8 @@ True False False + True + True True @@ -162,19 +278,18 @@ True dialog - + True False 1 - + True False end gtk-ok - False True True True @@ -190,7 +305,6 @@ gtk-cancel - False True True True @@ -231,6 +345,8 @@ template.pgm False False + True + True True @@ -262,9 +378,9 @@ False - False True False + False _File True @@ -274,9 +390,9 @@ gtk-new - False True False + False True True @@ -285,9 +401,9 @@ gtk-open - False True False + False True True @@ -296,9 +412,9 @@ gtk-save - False True False + False True True @@ -307,9 +423,9 @@ gtk-save-as - False True False + False True True @@ -317,33 +433,33 @@ - False True False + False - False True False + False Examples True - False True False + False gtk-quit - False True False + False True True @@ -355,9 +471,9 @@ - False True False + False _Edit True @@ -367,9 +483,9 @@ gtk-cut - False True False + False True True @@ -377,9 +493,9 @@ gtk-copy - False True False + False True True @@ -387,9 +503,9 @@ gtk-paste - False True False + False True True @@ -397,9 +513,9 @@ gtk-delete - False True False + False True True @@ -410,18 +526,18 @@ - False True False + False _View True - False True False + False _Help True @@ -431,9 +547,9 @@ gtk-about - False True False + False True True @@ -455,7 +571,6 @@ False - False True False False @@ -471,7 +586,6 @@ - False True False False @@ -487,15 +601,14 @@ - False True False Enter bootloader False toolbutton7 True - gtk-edit - + gtk-go-up + False @@ -504,7 +617,6 @@ - False True False False @@ -516,7 +628,6 @@ - False True False Execute Script @@ -533,7 +644,6 @@ - False True False Stop Script @@ -550,7 +660,6 @@ - False True False False @@ -562,7 +671,6 @@ - False True False False @@ -580,7 +688,6 @@ - False True False False @@ -592,7 +699,6 @@ - False True False False @@ -608,7 +714,6 @@ - False True False False @@ -624,7 +729,6 @@ - False True False False @@ -640,7 +744,6 @@ - False True False False diff --git a/usr/openmv-ide.py b/usr/openmv-ide.py index 8ca7bfe15..96be79659 100755 --- a/usr/openmv-ide.py +++ b/usr/openmv-ide.py @@ -13,10 +13,14 @@ import usb.util import numpy as np import openmv from os.path import expanduser +import subprocess + UI_PATH =os.path.dirname(os.path.realpath(__file__))+"/openmv-ide.glade" CONFIG_PATH = expanduser("~")+"/.openmvide.config" EXAMPLE_PATH = os.path.dirname(os.path.realpath(__file__))+"/examples" SCRIPTS_PATH = os.path.dirname(os.path.realpath(__file__))+"/scripts" +FWBIN_PATH = "" +DFU_CMD = "dfu-util -d 0483:df11 -c 1 -i 0 -a 0 -s 0x08000000 -D %s" SCALE =1 @@ -42,8 +46,8 @@ class OMVGtk: # set control buttons self.controls = [ - self.builder.get_object('bootloader_button'), self.builder.get_object('reset_button'), + self.builder.get_object('bootloader_button'), self.builder.get_object('exec_button'), self.builder.get_object('stop_button'), self.builder.get_object('zoomin_button'), @@ -93,7 +97,8 @@ class OMVGtk: "on_top_window_destroy" : self.quit, "on_connect_clicked" : self.connect_clicked, "on_reset_clicked" : self.reset_clicked, - "on_bootloader_clicked" : self.bootloader_clicked, + "on_fwupdate_clicked" : self.fwupdate_clicked, + "on_fwpath_clicked" : self.fwpath_clicked, "on_execute_clicked" : self.execute_clicked, "on_stop_clicked" : self.stop_clicked, "on_motion_notify" : self.motion_notify, @@ -195,10 +200,61 @@ class OMVGtk: def connect_clicked(self, widget): self.connect() - - def bootloader_clicked(self, widget): + + def fwpath_clicked(self, widget): + fw_entry = self.builder.get_object("fw_entry") + dialog = gtk.FileChooserDialog(title=None,action=gtk.FILE_CHOOSER_ACTION_OPEN, + buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK)) + dialog.set_default_response(gtk.RESPONSE_OK) + dialog.set_current_folder(SCRIPTS_PATH) + ff = gtk.FileFilter() + ff.set_name("dfu") + ff.add_pattern("*.bin") #TODO change to DFU + dialog.add_filter(ff) + + if dialog.run() == gtk.RESPONSE_OK: + fw_entry.set_text(dialog.get_filename()) + + dialog.destroy() + + def fwupdate_clicked(self, widget): if (self.connected): - openmv.bootloader() + dialog = self.builder.get_object("fw_dialog") + fw_entry = self.builder.get_object("fw_entry") + spinner = self.builder.get_object("fw_spinner") + ok_button = self.builder.get_object("fw_ok_button") + cancel_button = self.builder.get_object("fw_cancel_button") + + spinner.stop() + spinner.set_visible(False) + ok_button.set_sensitive(True) + cancel_button.set_sensitive(True) + dialog.set_transient_for(self.window); + + # default FW bin path + fw_entry.set_text(FWBIN_PATH) + + if dialog.run() == gtk.RESPONSE_OK: + ok_button.set_sensitive(False) + cancel_button.set_sensitive(False) + spinner.set_visible(True) + spinner.start() + + # call dfu-util + openmv.enter_dfu() + sleep(1.0) + + dfu_util = subprocess.Popen(DFU_CMD%fw_entry.get_text(), shell=True, stdout=subprocess.PIPE) + + while dfu_util.poll() == None and gtk.events_pending(): + 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): if (self.connected): diff --git a/usr/openmv.py b/usr/openmv.py index f2f3704ca..a514c9a6a 100755 --- a/usr/openmv.py +++ b/usr/openmv.py @@ -61,8 +61,8 @@ def init(): def release(): global __dev try: - # release __INTERFACE - usb.util.release_interface(__dev, __INTERFACE) + # Release device + usb.util.dispose_resources(dev) # reattach kernel driver #__dev.attach_kernel_driver(__INTERFACE) @@ -165,17 +165,18 @@ def enter_dfu(): def exit_dfu(): timeout = 1000 dev = usb.core.find(idVendor=0x0483, idProduct=0xdf11) - usb.util.claim_interface(dev, 0) - # Clear status - dev.ctrl_transfer(0x21, 0x04, 0, 0, None, timeout) + # 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(): try: # This will timeout.