diff --git a/.development/firmware_update.py b/.development/firmware_update.py new file mode 100644 index 0000000..fd3b4e6 --- /dev/null +++ b/.development/firmware_update.py @@ -0,0 +1,57 @@ +import urllib.request, tempfile, os, shutil, subprocess + +def firmware_update(verbose): + global __verbose + __verbose = verbose + + temp_path = tempfile.mktemp("firmware.dfu") + url = "https://s3.amazonaws.com/tilda-badge/mk4/firmware.dfu" + device = "1cbe:00ff" + + print("Hello - Welcome to the automated TiLDA Mk4 firmware updater") + try: + response = subprocess.run(["dfu-util", "--list"], capture_output=True) + if response.returncode != 0: + print(response) + return + + if ("Found DFU: [%s]" % device) not in response.stdout.decode('utf-8'): + print(response.stdout.decode('utf-8')) + print("We couldn't find a DFU enabled badge. Please check the following:") + print("") + print("1) Your badge is plugged into this computer via USB") + print("2) Your badge is in DFU mode. You can tell by a small, red flashing light at the back") + print("") + print("To put your badge into DFU mode (or if you're unsure whether it really is) you need to") + print("press the joystick to the right while pressing the reset button at the back.") + print("") + print("After that, please try this script again.") + return + + print("Downloading newest firmware: ", end="") + with urllib.request.urlopen(url) as response: + with open(temp_path, 'wb') as tmp_file: + shutil.copyfileobj(response, tmp_file) + print("DONE") + + response = subprocess.run(["dfu-util", "--download", temp_path]) + if response.returncode != 0: + print("Something went wrong during DFU updload :(") + print("") + print(response) + return + + print("") + print("You can now restart your badge by pressing the reset button on the back. Please follow the instructions on the screen to finish the setup") + print("Have a nice day!") + + except FileNotFoundError as e: + if "No such file or directory: 'dfu-utils'" in str(e): + print("We couldn't find dfu-util. You might have to install it.") + print("You can find instructions here: http://dfu-util.sourceforge.net/") + print("Please try again after you've installed dfu-util.") + else: + raise e + + finally: + if os.path.isfile(temp_path): os.remove(temp_path) diff --git a/.development/pydfu.py b/.development/pydfu.py deleted file mode 100644 index e08f41a..0000000 --- a/.development/pydfu.py +++ /dev/null @@ -1,543 +0,0 @@ -#!/usr/bin/env python -# This file is part of the OpenMV project. -# Copyright (c) 2013/2014 Ibrahim Abdelkader -# This work is licensed under the MIT license, see the file LICENSE for -# details. - -"""This module implements enough functionality to program the STM32F4xx over -DFU, without requiring dfu-util. -See app note AN3156 for a description of the DFU protocol. -See document UM0391 for a dscription of the DFuse file. -""" - -from __future__ import print_function - -import argparse -import re -import struct -import sys -import usb.core -import usb.util -import zlib - -# VID/PID -__VID = 0x0483 -__PID = 0xdf11 - -# USB request __TIMEOUT -__TIMEOUT = 4000 - -# DFU commands -__DFU_DETACH = 0 -__DFU_DNLOAD = 1 -__DFU_UPLOAD = 2 -__DFU_GETSTATUS = 3 -__DFU_CLRSTATUS = 4 -__DFU_GETSTATE = 5 -__DFU_ABORT = 6 - -# DFU status -__DFU_STATE_APP_IDLE = 0x00 -__DFU_STATE_APP_DETACH = 0x01 -__DFU_STATE_DFU_IDLE = 0x02 -__DFU_STATE_DFU_DOWNLOAD_SYNC = 0x03 -__DFU_STATE_DFU_DOWNLOAD_BUSY = 0x04 -__DFU_STATE_DFU_DOWNLOAD_IDLE = 0x05 -__DFU_STATE_DFU_MANIFEST_SYNC = 0x06 -__DFU_STATE_DFU_MANIFEST = 0x07 -__DFU_STATE_DFU_MANIFEST_WAIT_RESET = 0x08 -__DFU_STATE_DFU_UPLOAD_IDLE = 0x09 -__DFU_STATE_DFU_ERROR = 0x0a - -_DFU_DESCRIPTOR_TYPE = 0x21 - - -# USB device handle -__dev = None - -__verbose = None - -# USB DFU interface -__DFU_INTERFACE = 0 - -import inspect -if 'length' in inspect.getfullargspec(usb.util.get_string).args: - # PyUSB 1.0.0.b1 has the length argument - def get_string(dev, index): - return usb.util.get_string(dev, 255, index) -else: - # PyUSB 1.0.0.b2 dropped the length argument - def get_string(dev, index): - return usb.util.get_string(dev, index) - - -def init(): - """Initializes the found DFU device so that we can program it.""" - global __dev - devices = get_dfu_devices(idVendor=__VID, idProduct=__PID) - if not devices: - raise ValueError('No DFU device found') - if len(devices) > 1: - raise ValueError("Multiple DFU devices found") - __dev = devices[0] - __dev.set_configuration() - - # Claim DFU interface - usb.util.claim_interface(__dev, __DFU_INTERFACE) - - # Clear status - clr_status() - - -def clr_status(): - """Clears any error status (perhaps left over from a previous session).""" - __dev.ctrl_transfer(0x21, __DFU_CLRSTATUS, 0, __DFU_INTERFACE, - None, __TIMEOUT) - - -def get_status(): - """Get the status of the last operation.""" - stat = __dev.ctrl_transfer(0xA1, __DFU_GETSTATUS, 0, __DFU_INTERFACE, - 6, 20000) - # print (__DFU_STAT[stat[4]], stat) - return stat[4] - - -def mass_erase(): - """Performs a MASS erase (i.e. erases the entire device.""" - # Send DNLOAD with first byte=0x41 - __dev.ctrl_transfer(0x21, __DFU_DNLOAD, 0, __DFU_INTERFACE, - "\x41", __TIMEOUT) - - # Execute last command - if get_status() != __DFU_STATE_DFU_DOWNLOAD_BUSY: - raise Exception("DFU: erase failed") - - # Check command state - if get_status() != __DFU_STATE_DFU_DOWNLOAD_IDLE: - raise Exception("DFU: erase failed") - - -def page_erase(addr): - """Erases a single page.""" - if __verbose: - print("Erasing page: 0x%x..." % (addr)) - - # Send DNLOAD with first byte=0x41 and page address - buf = struct.pack(" 0: - write_size = size - if not mass_erase_used: - for segment in mem_layout: - if addr >= segment['addr'] and \ - addr <= segment['last_addr']: - # We found the page containing the address we want to - # write, erase it - page_size = segment['page_size'] - page_addr = addr & ~(page_size - 1) - if addr + write_size > page_addr + page_size: - write_size = page_addr + page_size - addr - page_erase(page_addr) - break - write_memory(addr, data[:write_size], progress, - elem_addr, elem_size) - data = data[write_size:] - addr += write_size - size -= write_size - if progress: - progress(elem_addr, addr - elem_addr, elem_size) - - -def cli_progress(addr, offset, size): - """Prints a progress report suitable for use on the command line.""" - width = 25 - done = offset * width // size - print("\r0x{:08x} {:7d} [{}{}] {:3d}% " - .format(addr, size, '=' * done, ' ' * (width - done), - offset * 100 // size), end="") - sys.stdout.flush() - if offset == size: - print("") - - -def main(): - """Test program for verifying this files functionality.""" - global __verbose - # Parse CMD args - parser = argparse.ArgumentParser(description='DFU Python Util') - #parser.add_argument("path", help="file path") - parser.add_argument( - "-l", "--list", - help="list available DFU devices", - action="store_true", - default=False - ) - parser.add_argument( - "-m", "--mass-erase", - help="mass erase device", - action="store_true", - default=False - ) - parser.add_argument( - "-u", "--upload", - help="read file from DFU device", - dest="path", - default=False - ) - parser.add_argument( - "-v", "--verbose", - help="increase output verbosity", - action="store_true", - default=False - ) - args = parser.parse_args() - - __verbose = args.verbose - - if args.list: - list_dfu_devices(idVendor=__VID, idProduct=__PID) - return - - init() - - if args.mass_erase: - print ("Mass erase...") - mass_erase() - - if args.path: - elements = read_dfu_file(args.path) - if not elements: - return - print("Writing memory...") - write_elements(elements, args.mass_erase, progress=cli_progress) - - print("Exiting DFU...") - exit_dfu() - return - - print("No command specified") - -if __name__ == '__main__': - main() diff --git a/.development/pydfu_util.py b/.development/pydfu_util.py deleted file mode 100644 index ba775a2..0000000 --- a/.development/pydfu_util.py +++ /dev/null @@ -1,49 +0,0 @@ -from pydfu import * -import urllib.request, tempfile, os, shutil, ssl - -def firmware_update(verbose): - global __verbose - __verbose = verbose - - temp_path = tempfile.mktemp("firmware.dfu") - url = "https://update.badge.emfcamp.org/firmware.dfu" - - print("Hello - Welcome to the automated TiLDA Mk4 firmware updater") - print("Finding badge: ", end="") - try: - init() - print("DONE") - - print("Downloading newest firmware: ", end="") - context = ssl._create_unverified_context() - with urllib.request.urlopen(url, context=context) as response: - with open(temp_path, 'wb') as tmp_file: - shutil.copyfileobj(response, tmp_file) - print("DONE") - - elements = read_dfu_file(temp_path) - if not elements: - return - - print("Resetting Badge: ", end="") - mass_erase() - print("DONE") - - print("Updating...") - write_elements(elements, True, progress=cli_progress) - exit_dfu() - - print("") - print("You can now restart your badge by pressing the reset button on the back. Please follow the instructions on the screen to finish the setup") - print("Have a nice day!") - - except ValueError as e: - print("FAIL") - print("") - print("We couldn't find your badge. You need to make sure it's plugged in and in DFU mode.") - print("To put your badge into DFU mode you need to press the joystick in the middle while pressing the reset button at the back.") - print("After that, please try this script again.") - print() - print("Error: %s" %(e)) - finally: - if os.path.isfile(temp_path): os.remove(temp_path) diff --git a/.development/tilda_tools.py b/.development/tilda_tools.py index 0119b74..8ed9431 100755 --- a/.development/tilda_tools.py +++ b/.development/tilda_tools.py @@ -51,7 +51,7 @@ Common parameters """ import sys, glob -import sync, pyboard_util, wifi +import sync, firmware_update, wifi, pyboard_util from resources import * def main(): @@ -73,8 +73,7 @@ def main(): run_tests = command == "test" if command == "firmware-update": - import pydfu_util # to avoid having a "usb" dependency for other calls - pydfu_util.firmware_update(args.verbose) + firmware_update.firmware_update(args.verbose) if command == "wifi": wifi.select_wifi()