diff --git a/src/main/python/firmware_flasher.py b/src/main/python/firmware_flasher.py index 081d39c..738a5b4 100644 --- a/src/main/python/firmware_flasher.py +++ b/src/main/python/firmware_flasher.py @@ -1,17 +1,22 @@ # SPDX-License-Identifier: GPL-2.0-or-later import datetime +import hashlib import struct import time import threading -from PyQt5.QtCore import pyqtSignal +from PyQt5.QtCore import pyqtSignal, QCoreApplication from PyQt5.QtGui import QFontDatabase from PyQt5.QtWidgets import QHBoxLayout, QLineEdit, QToolButton, QPlainTextEdit, QProgressBar,QFileDialog, QDialog from basic_editor import BasicEditor -from util import tr, chunks -from vial_device import VialBootloader +from unlocker import Unlocker +from util import tr, chunks, find_vial_devices +from vial_device import VialBootloader, VialKeyboard + + +BL_SUPPORTED_VERSION = 0 def send_retries(dev, data, retries=20): @@ -31,36 +36,65 @@ def send_retries(dev, data, retries=20): CHUNK = 64 -def cmd_flash(device, firmware, log_cb, progress_cb, complete_cb, error_cb): - while len(firmware) % CHUNK != 0: - firmware += b"\x00" +def cmd_flash(device, firmware, enable_insecure, log_cb, progress_cb, complete_cb, error_cb): + if firmware[0:8] != b"VIALFW00": + return error_cb("Error: Invalid signature") + + fw_uid = firmware[8:16] + fw_ts = struct.unpack("Lock from the menu."))) + layout.addWidget(QLabel(tr("Unlocker", "Press and hold the following keys until the progress bar " + "below fills up:"))) + + self.keyboard_reference = KeyboardWidget(layout_editor) + self.keyboard_reference.set_enabled(False) + self.keyboard_reference.set_scale(0.5) + layout.addWidget(self.keyboard_reference) + layout.setAlignment(self.keyboard_reference, Qt.AlignHCenter) + + layout.addWidget(self.progress) + + self.setLayout(layout) + self.setWindowFlag(Qt.Dialog) + + Unlocker.obj = self + + @classmethod + def get(cls): + return cls.obj + + def update_reference(self, keyboard): + """ Updates keycap reference image """ + + self.keyboard_reference.set_keys(keyboard.keys, keyboard.encoders) + + # use "active" background to indicate keys to hold + lock_keys = keyboard.get_unlock_keys() + for w in self.keyboard_reference.widgets: + if (w.desc.row, w.desc.col) in lock_keys: + w.setActive(True) + + self.keyboard_reference.update_layout() + self.keyboard_reference.update() + self.keyboard_reference.updateGeometry() + + def perform_unlock(self, keyboard): + # if it's already unlocked, don't need to do anything + unlock = keyboard.get_unlock_status() + if unlock == 1: + return + + self.update_reference(keyboard) + + self.progress.setMaximum(1) + self.progress.setValue(0) + + self.show() + self.keyboard = keyboard + self.keyboard.unlock_start() + + while True: + data = self.keyboard.unlock_poll() + unlocked = data[0] + unlock_counter = data[2] + + self.progress.setMaximum(max(self.progress.maximum(), unlock_counter)) + self.progress.setValue(self.progress.maximum() - unlock_counter) + + if unlocked == 1: + break + + QCoreApplication.processEvents() + time.sleep(0.2) + + # ok all done, the keyboard is now set to insecure state + self.hide() + + def closeEvent(self, ev): + ev.ignore() diff --git a/src/main/python/util.py b/src/main/python/util.py index 0b37b88..c687e56 100644 --- a/src/main/python/util.py +++ b/src/main/python/util.py @@ -32,7 +32,7 @@ def is_rawhid(dev): 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 filtered = [] diff --git a/src/main/python/vial_device.py b/src/main/python/vial_device.py index 2412b36..65eecbf 100644 --- a/src/main/python/vial_device.py +++ b/src/main/python/vial_device.py @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-or-later from hidproxy import hid from keyboard_comm import Keyboard +from util import MSG_LEN class VialDevice: @@ -19,8 +20,8 @@ class VialDevice: # add 00 at start for hidapi report id return self.dev.write(b"\x00" + data) - def recv(self, length): - return bytes(self.dev.read(length)) + def recv(self, length, timeout_ms=0): + return bytes(self.dev.read(length, timeout_ms=timeout_ms)) def close(self): self.dev.close() @@ -44,8 +45,28 @@ class VialKeyboard(VialDevice): s += " [sideload]" return s + def get_uid(self): + try: + super().open() + except OSError: + return b"" + self.send(b"\xFE\x00" + b"\x00" * 30) + data = self.recv(MSG_LEN, timeout_ms=500) + super().close() + return data[4:12] + class VialBootloader(VialDevice): def title(self): return "Vial Bootloader [{:04X}:{:04X}]".format(self.desc["vendor_id"], self.desc["product_id"]) + + def get_uid(self): + try: + super().open() + except OSError: + return b"" + self.send(b"VC\x01") + data = self.recv(8, timeout_ms=500) + super().close() + return data