firmware_flasher: automatically restart keyboard in bootloader mode and flash
parent
d6b0a6cb54
commit
7795ad5d07
|
|
@ -6,13 +6,16 @@ import struct
|
||||||
import time
|
import time
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
from PyQt5.QtCore import pyqtSignal
|
from PyQt5.QtCore import pyqtSignal, QCoreApplication
|
||||||
from PyQt5.QtGui import QFontDatabase
|
from PyQt5.QtGui import QFontDatabase
|
||||||
from PyQt5.QtWidgets import QHBoxLayout, QLineEdit, QToolButton, QPlainTextEdit, QProgressBar,QFileDialog, QDialog
|
from PyQt5.QtWidgets import QHBoxLayout, QLineEdit, QToolButton, QPlainTextEdit, QProgressBar,QFileDialog, QDialog
|
||||||
|
|
||||||
from basic_editor import BasicEditor
|
from basic_editor import BasicEditor
|
||||||
from util import tr, chunks
|
from util import tr, chunks, find_vial_devices
|
||||||
from vial_device import VialBootloader
|
from vial_device import VialBootloader, VialKeyboard
|
||||||
|
|
||||||
|
|
||||||
|
BL_SUPPORTED_VERSION = 0
|
||||||
|
|
||||||
|
|
||||||
def send_retries(dev, data, retries=20):
|
def send_retries(dev, data, retries=20):
|
||||||
|
|
@ -32,6 +35,18 @@ def send_retries(dev, data, retries=20):
|
||||||
CHUNK = 64
|
CHUNK = 64
|
||||||
|
|
||||||
|
|
||||||
|
def bl_get_version(dev):
|
||||||
|
dev.send(b"VC\x00")
|
||||||
|
data = dev.recv(8)
|
||||||
|
return data[0]
|
||||||
|
|
||||||
|
|
||||||
|
def bl_get_uid(dev):
|
||||||
|
dev.send(b"VC\x01")
|
||||||
|
data = dev.recv(8)
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
def cmd_flash(device, firmware, log_cb, progress_cb, complete_cb, error_cb):
|
def cmd_flash(device, firmware, log_cb, progress_cb, complete_cb, error_cb):
|
||||||
if firmware[0:8] != b"VIALFW00":
|
if firmware[0:8] != b"VIALFW00":
|
||||||
return error_cb("Error: Invalid signature")
|
return error_cb("Error: Invalid signature")
|
||||||
|
|
@ -50,24 +65,22 @@ def cmd_flash(device, firmware, log_cb, progress_cb, complete_cb, error_cb):
|
||||||
))
|
))
|
||||||
|
|
||||||
# Check bootloader is correct version
|
# Check bootloader is correct version
|
||||||
device.send(b"VC\x00")
|
ver = bl_get_version(device)
|
||||||
data = device.recv(8)
|
log_cb("* Bootloader version: {}".format(ver))
|
||||||
log_cb("* Bootloader version: {}".format(data[0]))
|
if ver != BL_SUPPORTED_VERSION:
|
||||||
if data[0] != 0:
|
|
||||||
return error_cb("Error: Unsupported bootloader version")
|
return error_cb("Error: Unsupported bootloader version")
|
||||||
|
|
||||||
device.send(b"VC\x01")
|
uid = bl_get_uid(device)
|
||||||
data = device.recv(8)
|
log_cb("* Vial ID: {}".format(uid.hex()))
|
||||||
log_cb("* Vial ID: {}".format(data.hex()))
|
|
||||||
|
|
||||||
if data == b"\xFF" * 8:
|
if uid == b"\xFF" * 8:
|
||||||
log_cb("\n\n\n!!! WARNING !!!\nBootloader UID is not set, make sure to configure it"
|
log_cb("\n\n\n!!! WARNING !!!\nBootloader UID is not set, make sure to configure it"
|
||||||
" before releasing production firmware\n!!! WARNING !!!\n\n")
|
" before releasing production firmware\n!!! WARNING !!!\n\n")
|
||||||
|
|
||||||
if data != fw_uid:
|
if uid != fw_uid:
|
||||||
return error_cb("Error: Firmware package was built for different device\n\texpected={}\n\tgot={}".format(
|
return error_cb("Error: Firmware package was built for different device\n\texpected={}\n\tgot={}".format(
|
||||||
fw_uid.hex(),
|
fw_uid.hex(),
|
||||||
data.hex()
|
uid.hex()
|
||||||
))
|
))
|
||||||
|
|
||||||
# OK all checks complete, we can flash now
|
# OK all checks complete, we can flash now
|
||||||
|
|
@ -139,12 +152,18 @@ class FirmwareFlasher(BasicEditor):
|
||||||
def rebuild(self, device):
|
def rebuild(self, device):
|
||||||
super().rebuild(device)
|
super().rebuild(device)
|
||||||
self.txt_logger.clear()
|
self.txt_logger.clear()
|
||||||
|
|
||||||
|
if not self.valid():
|
||||||
|
return
|
||||||
|
|
||||||
if isinstance(self.device, VialBootloader):
|
if isinstance(self.device, VialBootloader):
|
||||||
self.log("Valid Vial Bootloader device at {}".format(self.device.desc["path"].decode("utf-8")))
|
self.log("Valid Vial Bootloader device at {}".format(self.device.desc["path"].decode("utf-8")))
|
||||||
|
elif isinstance(self.device, VialKeyboard):
|
||||||
|
self.log("Vial keyboard detected")
|
||||||
|
|
||||||
def valid(self):
|
def valid(self):
|
||||||
# TODO: it is also valid to flash a VialKeyboard which supports optional "vibl-integration" feature
|
return isinstance(self.device, VialBootloader) or\
|
||||||
return isinstance(self.device, VialBootloader)
|
isinstance(self.device, VialKeyboard) and self.device.keyboard.vibl
|
||||||
|
|
||||||
def on_click_select_file(self):
|
def on_click_select_file(self):
|
||||||
dialog = QFileDialog()
|
dialog = QFileDialog()
|
||||||
|
|
@ -170,6 +189,34 @@ class FirmwareFlasher(BasicEditor):
|
||||||
|
|
||||||
self.log("Preparing to flash...")
|
self.log("Preparing to flash...")
|
||||||
self.lock_ui()
|
self.lock_ui()
|
||||||
|
|
||||||
|
# TODO: this needs to switch to the secure assisted-reset feature before public release
|
||||||
|
if isinstance(self.device, VialKeyboard):
|
||||||
|
uid = self.device.keyboard.get_uid()
|
||||||
|
|
||||||
|
self.log("Restarting in bootloader mode...")
|
||||||
|
self.device.keyboard.reset()
|
||||||
|
|
||||||
|
# watch for bootloaders to appear and ask them for their UID, return one that matches the keyboard
|
||||||
|
while True:
|
||||||
|
self.log("Looking for devices...")
|
||||||
|
QCoreApplication.processEvents()
|
||||||
|
time.sleep(1)
|
||||||
|
devices = find_vial_devices()
|
||||||
|
found = None
|
||||||
|
for dev in devices:
|
||||||
|
if isinstance(dev, VialBootloader):
|
||||||
|
dev.open()
|
||||||
|
# TODO: update version check before release
|
||||||
|
if bl_get_version(dev) != BL_SUPPORTED_VERSION or bl_get_uid(dev) != uid:
|
||||||
|
dev.close()
|
||||||
|
found = dev
|
||||||
|
break
|
||||||
|
if found:
|
||||||
|
self.log("Found Vial Bootloader device at {}".format(found.desc["path"].decode("utf-8")))
|
||||||
|
self.device = found
|
||||||
|
break
|
||||||
|
|
||||||
threading.Thread(target=lambda: cmd_flash(
|
threading.Thread(target=lambda: cmd_flash(
|
||||||
self.device, firmware, self.on_log, self.on_progress, self.on_complete, self.on_error)).start()
|
self.device, firmware, self.on_log, self.on_progress, self.on_complete, self.on_error)).start()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ class Keyboard:
|
||||||
self.macro_count = 0
|
self.macro_count = 0
|
||||||
self.macro_memory = 0
|
self.macro_memory = 0
|
||||||
self.macro = b""
|
self.macro = b""
|
||||||
|
self.vibl = False
|
||||||
|
|
||||||
self.vial_protocol = self.keyboard_id = -1
|
self.vial_protocol = self.keyboard_id = -1
|
||||||
|
|
||||||
|
|
@ -103,6 +104,10 @@ class Keyboard:
|
||||||
|
|
||||||
payload = json.loads(lzma.decompress(payload))
|
payload = json.loads(lzma.decompress(payload))
|
||||||
|
|
||||||
|
if "vial" in payload:
|
||||||
|
vial = payload["vial"]
|
||||||
|
self.vibl = vial.get("vibl", False)
|
||||||
|
|
||||||
self.layouts = payload.get("layouts")
|
self.layouts = payload.get("layouts")
|
||||||
|
|
||||||
self.rows = payload["matrix"]["rows"]
|
self.rows = payload["matrix"]["rows"]
|
||||||
|
|
@ -275,3 +280,13 @@ class Keyboard:
|
||||||
|
|
||||||
self.set_layout_options(data["layout_options"])
|
self.set_layout_options(data["layout_options"])
|
||||||
self.set_macro(base64.b64decode(data["macro"]))
|
self.set_macro(base64.b64decode(data["macro"]))
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self.usb_send(self.dev, struct.pack("B", 0xB))
|
||||||
|
self.dev.close()
|
||||||
|
|
||||||
|
def get_uid(self):
|
||||||
|
""" Retrieve UID from the keyboard, explicitly sending a query packet """
|
||||||
|
data = self.usb_send(self.dev, struct.pack("BB", CMD_VIA_VIAL_PREFIX, CMD_VIAL_GET_KEYBOARD_ID))
|
||||||
|
keyboard_id = data[4:12]
|
||||||
|
return keyboard_id
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ def is_rawhid(dev):
|
||||||
return dev["interface_number"] == 1
|
return dev["interface_number"] == 1
|
||||||
|
|
||||||
|
|
||||||
def find_vial_devices(sideload_vid, sideload_pid):
|
def find_vial_devices(sideload_vid=None, sideload_pid=None):
|
||||||
from vial_device import VialBootloader, VialKeyboard
|
from vial_device import VialBootloader, VialKeyboard
|
||||||
|
|
||||||
filtered = []
|
filtered = []
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue