<p>laforge <strong>submitted</strong> this change.</p><p><a href="https://gerrit.osmocom.org/c/simtrace2/+/16874">View Change</a></p><div style="white-space:pre-wrap">Approvals:
laforge: Looks good to me, approved
Jenkins Builder: Verified
</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">add script to flash latest firmware<br><br>this python script lists the SIMtrace 2 devices connected to USB<br>and will flash the latest version of the application (if necessary).<br>it requires pyusb and dfu-util.<br>it is intended for end users so they don't need to read the length<br>and error-prone instructions provided in the wiki.<br><br>TODO:<br>- support updating bootloader (once dfu-ram image exists)<br>- use python implementation of dfu-util to be python only<br><br>Change-Id: I3ebe0f54b6e3b7b45478603cc0a5b56e87b1f461<br>---<br>A contrib/flash.py<br>1 file changed, 162 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/contrib/flash.py b/contrib/flash.py</span><br><span>new file mode 100755</span><br><span>index 0000000..435d311</span><br><span>--- /dev/null</span><br><span>+++ b/contrib/flash.py</span><br><span>@@ -0,0 +1,162 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#!/usr/bin/env python</span><br><span style="color: hsl(120, 100%, 40%);">+# encoding: utf-8</span><br><span style="color: hsl(120, 100%, 40%);">+# python: 3.8.1</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# library to enumerate USB devices</span><br><span style="color: hsl(120, 100%, 40%);">+import usb.core</span><br><span style="color: hsl(120, 100%, 40%);">+from usb.util import *</span><br><span style="color: hsl(120, 100%, 40%);">+# more elegant structure</span><br><span style="color: hsl(120, 100%, 40%);">+from typing import NamedTuple</span><br><span style="color: hsl(120, 100%, 40%);">+# regular expressions utilities</span><br><span style="color: hsl(120, 100%, 40%);">+import re</span><br><span style="color: hsl(120, 100%, 40%);">+# open utilities to handle files</span><br><span style="color: hsl(120, 100%, 40%);">+import os, sys</span><br><span style="color: hsl(120, 100%, 40%);">+# to download the firmwares</span><br><span style="color: hsl(120, 100%, 40%);">+import urllib.request</span><br><span style="color: hsl(120, 100%, 40%);">+# to flash using DFU-util</span><br><span style="color: hsl(120, 100%, 40%);">+import subprocess</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# SIMtrace 2 device information</span><br><span style="color: hsl(120, 100%, 40%);">+class Device(NamedTuple):</span><br><span style="color: hsl(120, 100%, 40%);">+ usb_vendor_id: int</span><br><span style="color: hsl(120, 100%, 40%);">+ usb_product_id: int</span><br><span style="color: hsl(120, 100%, 40%);">+ name: str</span><br><span style="color: hsl(120, 100%, 40%);">+ url: dict # 1: sniff/trace firmware, 2: card emulation firmware</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# SIMtrace 2 devices definitions</span><br><span style="color: hsl(120, 100%, 40%);">+DEVICE_SIMTRACE = Device(usb_vendor_id=0x1d50, usb_product_id=0x60e3, name="SIMtrace 2", url={"trace": "https://ftp.osmocom.org/binaries/simtrace2/firmware/latest/simtrace-trace-dfu-latest.bin", "cardem": "https://osmocom.org/attachments/download/3868/simtrace-cardem-dfu.bin"})</span><br><span style="color: hsl(120, 100%, 40%);">+DEVICE_QMOD = Device(usb_vendor_id=0x1d50, usb_product_id=0x4004, name="sysmoQMOD (Quad Modem)", url={"cardem": "https://ftp.osmocom.org/binaries/simtrace2/firmware/latest/qmod-cardem-dfu-latest.bin"})</span><br><span style="color: hsl(120, 100%, 40%);">+DEVICE_OWHW = Device(usb_vendor_id=0x1d50, usb_product_id=0x4001, name="OWHW", url={"cardem": "https://ftp.osmocom.org/binaries/simtrace2/firmware/latest/owhw-cardem-dfu-latest.bin"})</span><br><span style="color: hsl(120, 100%, 40%);">+DEVICES = [DEVICE_SIMTRACE, DEVICE_QMOD]</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# which firmware does the SIMtrace USN interface subclass correspond</span><br><span style="color: hsl(120, 100%, 40%);">+FIRMWARE_SUBCLASS = {1: "trace", 2: "cardem"}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def print_help():</span><br><span style="color: hsl(120, 100%, 40%);">+ print("this script will flash SIMtrace 2 - based devices")</span><br><span style="color: hsl(120, 100%, 40%);">+ print("when no argument is provided, it will try to flash the application firmware of all SIMtrace 2 devices connected to USB with the latest version")</span><br><span style="color: hsl(120, 100%, 40%);">+ print("to flash a specific firmware, provide the name as argument")</span><br><span style="color: hsl(120, 100%, 40%);">+ print("the possible firmwares are: trace, cardem")</span><br><span style="color: hsl(120, 100%, 40%);">+ print("to list all devices connected to USB, provide the argument \"list\"")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# the firmware to flash</span><br><span style="color: hsl(120, 100%, 40%);">+to_flash = None</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# parse command line argument</span><br><span style="color: hsl(120, 100%, 40%);">+if len(sys.argv) == 2:</span><br><span style="color: hsl(120, 100%, 40%);">+ to_flash = sys.argv[1]</span><br><span style="color: hsl(120, 100%, 40%);">+if to_flash not in ["list", "trace", "cardem"] and len(sys.argv) > 1:</span><br><span style="color: hsl(120, 100%, 40%);">+ print_help()</span><br><span style="color: hsl(120, 100%, 40%);">+ exit(0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+# get all USB devices</span><br><span style="color: hsl(120, 100%, 40%);">+devices = []</span><br><span style="color: hsl(120, 100%, 40%);">+devices_nb = 0</span><br><span style="color: hsl(120, 100%, 40%);">+updated_nb = 0</span><br><span style="color: hsl(120, 100%, 40%);">+usb_devices = usb.core.find(find_all=True)</span><br><span style="color: hsl(120, 100%, 40%);">+for usb_device in usb_devices:</span><br><span style="color: hsl(120, 100%, 40%);">+ # find SIMtrace devices</span><br><span style="color: hsl(120, 100%, 40%);">+ definitions = list(filter(lambda x: x.usb_vendor_id == usb_device.idVendor and x.usb_product_id == usb_device.idProduct, DEVICES))</span><br><span style="color: hsl(120, 100%, 40%);">+ if 1 != len(definitions):</span><br><span style="color: hsl(120, 100%, 40%);">+ continue</span><br><span style="color: hsl(120, 100%, 40%);">+ devices_nb += 1</span><br><span style="color: hsl(120, 100%, 40%);">+ definition = definitions[0]</span><br><span style="color: hsl(120, 100%, 40%);">+ serial = usb_device.serial_number or "unknown"</span><br><span style="color: hsl(120, 100%, 40%);">+ usb_path = str(usb_device.bus) + "-" + ".".join(map(str, usb_device.port_numbers))</span><br><span style="color: hsl(120, 100%, 40%);">+ print("found " + definition.name + " device (chip ID " + serial + ") at USB path " + usb_path)</span><br><span style="color: hsl(120, 100%, 40%);">+ # determine if we are running DFU (in most cases the bootloader, but could also be the application)</span><br><span style="color: hsl(120, 100%, 40%);">+ dfu_interface = None</span><br><span style="color: hsl(120, 100%, 40%);">+ for configuration in usb_device:</span><br><span style="color: hsl(120, 100%, 40%);">+ # get DFU interface descriptor</span><br><span style="color: hsl(120, 100%, 40%);">+ dfu_interface = dfu_interface or find_descriptor(configuration, bInterfaceClass=254, bInterfaceSubClass=1)</span><br><span style="color: hsl(120, 100%, 40%);">+ if (None == dfu_interface):</span><br><span style="color: hsl(120, 100%, 40%);">+ print("no DFU USB interface found")</span><br><span style="color: hsl(120, 100%, 40%);">+ continue</span><br><span style="color: hsl(120, 100%, 40%);">+ dfu_mode = (2 == dfu_interface.bInterfaceProtocol) # InterfaceProtocol 1 is runtime mode, 2 is DFU mode</span><br><span style="color: hsl(120, 100%, 40%);">+ # determine firmware type (when not in DFU mode)</span><br><span style="color: hsl(120, 100%, 40%);">+ firmware = None</span><br><span style="color: hsl(120, 100%, 40%);">+ simtrace_interface = None</span><br><span style="color: hsl(120, 100%, 40%);">+ for configuration in usb_device:</span><br><span style="color: hsl(120, 100%, 40%);">+ simtrace_interface = simtrace_interface or find_descriptor(configuration, bInterfaceClass=255)</span><br><span style="color: hsl(120, 100%, 40%);">+ if simtrace_interface and simtrace_interface.bInterfaceSubClass in FIRMWARE_SUBCLASS:</span><br><span style="color: hsl(120, 100%, 40%);">+ firmware = firmware or FIRMWARE_SUBCLASS[simtrace_interface.bInterfaceSubClass]</span><br><span style="color: hsl(120, 100%, 40%);">+ if dfu_mode:</span><br><span style="color: hsl(120, 100%, 40%);">+ firmware = 'dfu'</span><br><span style="color: hsl(120, 100%, 40%);">+ if firmware:</span><br><span style="color: hsl(120, 100%, 40%);">+ print("installed firmware: " + firmware)</span><br><span style="color: hsl(120, 100%, 40%);">+ else:</span><br><span style="color: hsl(120, 100%, 40%);">+ print("unknown installed firmware")</span><br><span style="color: hsl(120, 100%, 40%);">+ continue</span><br><span style="color: hsl(120, 100%, 40%);">+ # determine version of the application/bootloader firmware</span><br><span style="color: hsl(120, 100%, 40%);">+ version = None</span><br><span style="color: hsl(120, 100%, 40%);">+ version_interface = None</span><br><span style="color: hsl(120, 100%, 40%);">+ for configuration in usb_device:</span><br><span style="color: hsl(120, 100%, 40%);">+ # get custom interface with string</span><br><span style="color: hsl(120, 100%, 40%);">+ version_interface = version_interface or find_descriptor(configuration, bInterfaceClass=255, bInterfaceSubClass=255)</span><br><span style="color: hsl(120, 100%, 40%);">+ if version_interface and version_interface.iInterface and version_interface.iInterface > 0 and get_string(usb_device, version_interface.iInterface):</span><br><span style="color: hsl(120, 100%, 40%);">+ version = get_string(usb_device, version_interface.iInterface)</span><br><span style="color: hsl(120, 100%, 40%);">+ if not version:</span><br><span style="color: hsl(120, 100%, 40%);">+ # the USB serial is set (in the application) since version 0.5.1.34-e026 from 2019-08-06</span><br><span style="color: hsl(120, 100%, 40%);">+ # https://git.osmocom.org/simtrace2/commit/?id=e0265462d8c05ebfa133db2039c2fbe3ebbd286e</span><br><span style="color: hsl(120, 100%, 40%);">+ # the USB serial is set (in the bootloader) since version 0.5.1.45-ac7e from 2019-11-18</span><br><span style="color: hsl(120, 100%, 40%);">+ # https://git.osmocom.org/simtrace2/commit/?id=5db9402a5f346e30288db228157f71c29aefce5a</span><br><span style="color: hsl(120, 100%, 40%);">+ # the firmware version is set (in the application) since version 0.5.1.37-ede8 from 2019-08-13</span><br><span style="color: hsl(120, 100%, 40%);">+ # https://git.osmocom.org/simtrace2/commit/?id=ede87e067dadd07119f24e96261b66ac92b3af6f</span><br><span style="color: hsl(120, 100%, 40%);">+ # the firmware version is set (in the bootloader) since version 0.5.1.45-ac7e from 2019-11-18</span><br><span style="color: hsl(120, 100%, 40%);">+ # https://git.osmocom.org/simtrace2/commit/?id=5db9402a5f346e30288db228157f71c29aefce5a</span><br><span style="color: hsl(120, 100%, 40%);">+ if dfu_mode:</span><br><span style="color: hsl(120, 100%, 40%);">+ if serial:</span><br><span style="color: hsl(120, 100%, 40%);">+ version = "< 0.5.1.45-ac7e"</span><br><span style="color: hsl(120, 100%, 40%);">+ else:</span><br><span style="color: hsl(120, 100%, 40%);">+ versoin = "< 0.5.1.45-ac7e"</span><br><span style="color: hsl(120, 100%, 40%);">+ else:</span><br><span style="color: hsl(120, 100%, 40%);">+ if serial:</span><br><span style="color: hsl(120, 100%, 40%);">+ version = "< 0.5.1.37-ede8"</span><br><span style="color: hsl(120, 100%, 40%);">+ else:</span><br><span style="color: hsl(120, 100%, 40%);">+ versoin = "< 0.5.1.34-e026"</span><br><span style="color: hsl(120, 100%, 40%);">+ print("device firmware version: " + version)</span><br><span style="color: hsl(120, 100%, 40%);">+ # flash latest firmware</span><br><span style="color: hsl(120, 100%, 40%);">+ if to_flash == "list": # we just want to list the devices, not flash them</span><br><span style="color: hsl(120, 100%, 40%);">+ continue</span><br><span style="color: hsl(120, 100%, 40%);">+ # check the firmware exists</span><br><span style="color: hsl(120, 100%, 40%);">+ if firmware == "dfu" and to_flash is None:</span><br><span style="color: hsl(120, 100%, 40%);">+ print("device is currently in DFU mode. you need to specify which firmware to flash")</span><br><span style="color: hsl(120, 100%, 40%);">+ continue</span><br><span style="color: hsl(120, 100%, 40%);">+ to_flash = to_flash or firmware</span><br><span style="color: hsl(120, 100%, 40%);">+ if to_flash not in definition.url.keys():</span><br><span style="color: hsl(120, 100%, 40%);">+ print("no firmware image available for " + firmware + " firmware")</span><br><span style="color: hsl(120, 100%, 40%);">+ continue</span><br><span style="color: hsl(120, 100%, 40%);">+ # download firmware</span><br><span style="color: hsl(120, 100%, 40%);">+ try:</span><br><span style="color: hsl(120, 100%, 40%);">+ dl_path, header = urllib.request.urlretrieve(definition.url[to_flash])</span><br><span style="color: hsl(120, 100%, 40%);">+ except:</span><br><span style="color: hsl(120, 100%, 40%);">+ print("could not download firmware " + definition.url[to_flash])</span><br><span style="color: hsl(120, 100%, 40%);">+ continue</span><br><span style="color: hsl(120, 100%, 40%);">+ dl_file = open(dl_path, "rb")</span><br><span style="color: hsl(120, 100%, 40%);">+ dl_data = dl_file.read()</span><br><span style="color: hsl(120, 100%, 40%);">+ dl_file.close()</span><br><span style="color: hsl(120, 100%, 40%);">+ # compare versions</span><br><span style="color: hsl(120, 100%, 40%);">+ dl_version = re.search(b'firmware \d+\.\d+\.\d+\.\d+-[0-9a-fA-F]{4}', dl_data)</span><br><span style="color: hsl(120, 100%, 40%);">+ if dl_version is None:</span><br><span style="color: hsl(120, 100%, 40%);">+ print("could not get version from downloaded firmware image")</span><br><span style="color: hsl(120, 100%, 40%);">+ os.remove(dl_path)</span><br><span style="color: hsl(120, 100%, 40%);">+ continue</span><br><span style="color: hsl(120, 100%, 40%);">+ dl_version = dl_version.group(0).decode("utf-8").split(" ")[1]</span><br><span style="color: hsl(120, 100%, 40%);">+ print("latest firmware version: " + dl_version)</span><br><span style="color: hsl(120, 100%, 40%);">+ versions = list(map(lambda x: int(x), version.split(" ")[-1].split("-")[0].split(".")))</span><br><span style="color: hsl(120, 100%, 40%);">+ dl_versions = list(map(lambda x: int(x), dl_version.split("-")[0].split(".")))</span><br><span style="color: hsl(120, 100%, 40%);">+ dl_newer = (versions[0] < dl_versions[0] or (versions[0] == dl_versions[0] and versions[1] < dl_versions[1]) or (versions[0] == dl_versions[0] and versions[1] == dl_versions[1] and versions[2] < dl_versions[2]) or (versions[0] == dl_versions[0] and versions[1] == dl_versions[1] and versions[2] == dl_versions[2] and versions[3] < dl_versions[3]))</span><br><span style="color: hsl(120, 100%, 40%);">+ if not dl_newer:</span><br><span style="color: hsl(120, 100%, 40%);">+ print("no need to flash latest version")</span><br><span style="color: hsl(120, 100%, 40%);">+ os.remove(dl_path)</span><br><span style="color: hsl(120, 100%, 40%);">+ continue</span><br><span style="color: hsl(120, 100%, 40%);">+ print("flashing latest version")</span><br><span style="color: hsl(120, 100%, 40%);">+ dfu_result = subprocess.run(["dfu-util", "--device", hex(definition.usb_vendor_id) + ":" + hex(definition.usb_product_id), "--path", usb_path, "--cfg", "1", "--alt", "1", "--reset", "--download", dl_path])</span><br><span style="color: hsl(120, 100%, 40%);">+ os.remove(dl_path)</span><br><span style="color: hsl(120, 100%, 40%);">+ if 0 != dfu_result.returncode:</span><br><span style="color: hsl(120, 100%, 40%);">+ printf("flashing firmware using dfu-util failed. ensure dfu-util is installed and you have the permissions to access this USB device")</span><br><span style="color: hsl(120, 100%, 40%);">+ continue</span><br><span style="color: hsl(120, 100%, 40%);">+ updated_nb += 1</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+print(str(devices_nb)+ " SIMtrace 2 device(s) found")</span><br><span style="color: hsl(120, 100%, 40%);">+print(str(updated_nb)+ " SIMtrace 2 device(s) updated")</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/simtrace2/+/16874">change 16874</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/simtrace2/+/16874"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: simtrace2 </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I3ebe0f54b6e3b7b45478603cc0a5b56e87b1f461 </div>
<div style="display:none"> Gerrit-Change-Number: 16874 </div>
<div style="display:none"> Gerrit-PatchSet: 2 </div>
<div style="display:none"> Gerrit-Owner: tsaitgaist <kredon@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>
<div style="display:none"> Gerrit-Reviewer: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-MessageType: merged </div>