<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>