diff options
author | Kévin Redon <kredon@sysmocom.de> | 2020-01-14 18:19:48 +0100 |
---|---|---|
committer | laforge <laforge@osmocom.org> | 2020-01-16 20:36:23 +0000 |
commit | e88be9e78285c7092b4cea5fa925dead5c62779b (patch) | |
tree | 1775c0df06d2824a0899d45bdfc3dfba46992deb /contrib | |
parent | b6e2f0f8e72acba7501dffe32bd49fed19020533 (diff) |
add script to flash latest firmware
this python script lists the SIMtrace 2 devices connected to USB
and will flash the latest version of the application (if necessary).
it requires pyusb and dfu-util.
it is intended for end users so they don't need to read the length
and error-prone instructions provided in the wiki.
TODO:
- support updating bootloader (once dfu-ram image exists)
- use python implementation of dfu-util to be python only
Change-Id: I3ebe0f54b6e3b7b45478603cc0a5b56e87b1f461
Diffstat (limited to 'contrib')
-rwxr-xr-x | contrib/flash.py | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/contrib/flash.py b/contrib/flash.py new file mode 100755 index 0000000..435d311 --- /dev/null +++ b/contrib/flash.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python +# encoding: utf-8 +# python: 3.8.1 + +# library to enumerate USB devices +import usb.core +from usb.util import * +# more elegant structure +from typing import NamedTuple +# regular expressions utilities +import re +# open utilities to handle files +import os, sys +# to download the firmwares +import urllib.request +# to flash using DFU-util +import subprocess + +# SIMtrace 2 device information +class Device(NamedTuple): + usb_vendor_id: int + usb_product_id: int + name: str + url: dict # 1: sniff/trace firmware, 2: card emulation firmware + +# SIMtrace 2 devices definitions +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"}) +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"}) +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"}) +DEVICES = [DEVICE_SIMTRACE, DEVICE_QMOD] + +# which firmware does the SIMtrace USN interface subclass correspond +FIRMWARE_SUBCLASS = {1: "trace", 2: "cardem"} + +def print_help(): + print("this script will flash SIMtrace 2 - based devices") + 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") + print("to flash a specific firmware, provide the name as argument") + print("the possible firmwares are: trace, cardem") + print("to list all devices connected to USB, provide the argument \"list\"") + +# the firmware to flash +to_flash = None + +# parse command line argument +if len(sys.argv) == 2: + to_flash = sys.argv[1] +if to_flash not in ["list", "trace", "cardem"] and len(sys.argv) > 1: + print_help() + exit(0) + +# get all USB devices +devices = [] +devices_nb = 0 +updated_nb = 0 +usb_devices = usb.core.find(find_all=True) +for usb_device in usb_devices: + # find SIMtrace devices + definitions = list(filter(lambda x: x.usb_vendor_id == usb_device.idVendor and x.usb_product_id == usb_device.idProduct, DEVICES)) + if 1 != len(definitions): + continue + devices_nb += 1 + definition = definitions[0] + serial = usb_device.serial_number or "unknown" + usb_path = str(usb_device.bus) + "-" + ".".join(map(str, usb_device.port_numbers)) + print("found " + definition.name + " device (chip ID " + serial + ") at USB path " + usb_path) + # determine if we are running DFU (in most cases the bootloader, but could also be the application) + dfu_interface = None + for configuration in usb_device: + # get DFU interface descriptor + dfu_interface = dfu_interface or find_descriptor(configuration, bInterfaceClass=254, bInterfaceSubClass=1) + if (None == dfu_interface): + print("no DFU USB interface found") + continue + dfu_mode = (2 == dfu_interface.bInterfaceProtocol) # InterfaceProtocol 1 is runtime mode, 2 is DFU mode + # determine firmware type (when not in DFU mode) + firmware = None + simtrace_interface = None + for configuration in usb_device: + simtrace_interface = simtrace_interface or find_descriptor(configuration, bInterfaceClass=255) + if simtrace_interface and simtrace_interface.bInterfaceSubClass in FIRMWARE_SUBCLASS: + firmware = firmware or FIRMWARE_SUBCLASS[simtrace_interface.bInterfaceSubClass] + if dfu_mode: + firmware = 'dfu' + if firmware: + print("installed firmware: " + firmware) + else: + print("unknown installed firmware") + continue + # determine version of the application/bootloader firmware + version = None + version_interface = None + for configuration in usb_device: + # get custom interface with string + version_interface = version_interface or find_descriptor(configuration, bInterfaceClass=255, bInterfaceSubClass=255) + if version_interface and version_interface.iInterface and version_interface.iInterface > 0 and get_string(usb_device, version_interface.iInterface): + version = get_string(usb_device, version_interface.iInterface) + if not version: + # the USB serial is set (in the application) since version 0.5.1.34-e026 from 2019-08-06 + # https://git.osmocom.org/simtrace2/commit/?id=e0265462d8c05ebfa133db2039c2fbe3ebbd286e + # the USB serial is set (in the bootloader) since version 0.5.1.45-ac7e from 2019-11-18 + # https://git.osmocom.org/simtrace2/commit/?id=5db9402a5f346e30288db228157f71c29aefce5a + # the firmware version is set (in the application) since version 0.5.1.37-ede8 from 2019-08-13 + # https://git.osmocom.org/simtrace2/commit/?id=ede87e067dadd07119f24e96261b66ac92b3af6f + # the firmware version is set (in the bootloader) since version 0.5.1.45-ac7e from 2019-11-18 + # https://git.osmocom.org/simtrace2/commit/?id=5db9402a5f346e30288db228157f71c29aefce5a + if dfu_mode: + if serial: + version = "< 0.5.1.45-ac7e" + else: + versoin = "< 0.5.1.45-ac7e" + else: + if serial: + version = "< 0.5.1.37-ede8" + else: + versoin = "< 0.5.1.34-e026" + print("device firmware version: " + version) + # flash latest firmware + if to_flash == "list": # we just want to list the devices, not flash them + continue + # check the firmware exists + if firmware == "dfu" and to_flash is None: + print("device is currently in DFU mode. you need to specify which firmware to flash") + continue + to_flash = to_flash or firmware + if to_flash not in definition.url.keys(): + print("no firmware image available for " + firmware + " firmware") + continue + # download firmware + try: + dl_path, header = urllib.request.urlretrieve(definition.url[to_flash]) + except: + print("could not download firmware " + definition.url[to_flash]) + continue + dl_file = open(dl_path, "rb") + dl_data = dl_file.read() + dl_file.close() + # compare versions + dl_version = re.search(b'firmware \d+\.\d+\.\d+\.\d+-[0-9a-fA-F]{4}', dl_data) + if dl_version is None: + print("could not get version from downloaded firmware image") + os.remove(dl_path) + continue + dl_version = dl_version.group(0).decode("utf-8").split(" ")[1] + print("latest firmware version: " + dl_version) + versions = list(map(lambda x: int(x), version.split(" ")[-1].split("-")[0].split("."))) + dl_versions = list(map(lambda x: int(x), dl_version.split("-")[0].split("."))) + 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])) + if not dl_newer: + print("no need to flash latest version") + os.remove(dl_path) + continue + print("flashing latest version") + 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]) + os.remove(dl_path) + if 0 != dfu_result.returncode: + printf("flashing firmware using dfu-util failed. ensure dfu-util is installed and you have the permissions to access this USB device") + continue + updated_nb += 1 + +print(str(devices_nb)+ " SIMtrace 2 device(s) found") +print(str(updated_nb)+ " SIMtrace 2 device(s) updated") |