Add port hotplug and firmware list download from separate thread
This commit is contained in:
parent
68a264f9ba
commit
6031cf8213
@ -1,4 +1,5 @@
|
||||
# -* encoding: utf-8 *-
|
||||
|
||||
import sys
|
||||
import os.path
|
||||
import re
|
||||
@ -51,12 +52,12 @@ def indexof(path):
|
||||
return [a for a, b in file_index_re.findall(resp.text) if a == b]
|
||||
|
||||
|
||||
class QThread(QtCore.QThread):
|
||||
class QuickThread(QtCore.QThread):
|
||||
"""Provides similar API to threading.Thread but with additional error
|
||||
reporting based on Qt Signals"""
|
||||
def __init__(self, parent=None, target=None, args=None, kwargs=None,
|
||||
error=None):
|
||||
super(QThread, self).__init__(parent)
|
||||
super(QuickThread, self).__init__(parent)
|
||||
self.target = target
|
||||
self.args = args or []
|
||||
self.kwargs = kwargs or {}
|
||||
@ -71,6 +72,48 @@ class QThread(QtCore.QThread):
|
||||
# raise here causes windows builds to just die. ¯\_(ツ)_/¯
|
||||
logging.exception('Unhandled exception')
|
||||
|
||||
@classmethod
|
||||
def wrap(cls, func):
|
||||
"""Decorator that wraps function in a QThread. Calling resulting
|
||||
function starts and creates QThread, with parent set to [self]"""
|
||||
def wrapped(*args, **kwargs):
|
||||
th = cls(parent=args[0], target=func, args=args, kwargs=kwargs,
|
||||
error=kwargs.pop('error', None))
|
||||
func._th = th
|
||||
th.start()
|
||||
|
||||
return th
|
||||
|
||||
wrapped.running = lambda: (hasattr(func, '_th') and
|
||||
func._th.isRunning())
|
||||
return wrapped
|
||||
|
||||
|
||||
class PortDetectThread(QtCore.QThread):
|
||||
interval = 1.0
|
||||
portsUpdate = QtCore.Signal([list])
|
||||
|
||||
def run(self):
|
||||
"""Checks list of available ports and emits signal when necessary"""
|
||||
|
||||
ports = []
|
||||
while True:
|
||||
new_ports = serial.tools.list_ports.comports()
|
||||
|
||||
if [p.name for p in ports] != [p.name for p in new_ports]:
|
||||
self.portsUpdate.emit(new_ports)
|
||||
|
||||
time.sleep(self.interval)
|
||||
|
||||
ports = new_ports
|
||||
|
||||
|
||||
class FirmwareListThread(QtCore.QThread):
|
||||
onFirmware = QtCore.Signal([list])
|
||||
|
||||
def run(self):
|
||||
"""Downloads list of available firmware updates in separate thread."""
|
||||
self.onFirmware.emit(list(indexof(UPDATE_REPOSITORY)))
|
||||
|
||||
class MainWindow(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
||||
signal = QtCore.Signal([str, int])
|
||||
@ -92,9 +135,13 @@ class MainWindow(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
||||
|
||||
self.i18n_init(QtCore.QLocale.system())
|
||||
|
||||
# TODO: extract this to separate thread
|
||||
self.populate_versions()
|
||||
self.populate_boards(serial.tools.list_ports.comports())
|
||||
self.firmware_list = FirmwareListThread()
|
||||
self.firmware_list.onFirmware.connect(self.populate_versions)
|
||||
self.firmware_list.start()
|
||||
|
||||
self.port_detect = PortDetectThread()
|
||||
self.port_detect.portsUpdate.connect(self.populate_boards)
|
||||
self.port_detect.start()
|
||||
|
||||
self.on_expertModeBox_clicked()
|
||||
|
||||
@ -120,10 +167,10 @@ class MainWindow(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
||||
self.app.installTranslator(self.translator)
|
||||
self.retranslateUi(self)
|
||||
|
||||
def populate_versions(self):
|
||||
def populate_versions(self, files):
|
||||
"""Loads available firmware versions into versionbox widget"""
|
||||
|
||||
for fname in indexof(UPDATE_REPOSITORY):
|
||||
for fname in files:
|
||||
if not fname.endswith('.bin'):
|
||||
continue
|
||||
|
||||
@ -131,10 +178,14 @@ class MainWindow(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
||||
item.setData(UPDATE_REPOSITORY + fname, ROLE_DEVICE)
|
||||
self.versionBox.model().appendRow(item)
|
||||
|
||||
self.statusbar.clearMessage()
|
||||
|
||||
def populate_boards(self, ports):
|
||||
"""Populates board selection combobox from list of pyserial
|
||||
ListPortInfo objects"""
|
||||
|
||||
self.boardBox.clear()
|
||||
|
||||
prefered, others = self.group_ports(ports)
|
||||
|
||||
for b in prefered:
|
||||
@ -201,13 +252,12 @@ class MainWindow(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
||||
"Invalid version / file does not exist"))
|
||||
return
|
||||
|
||||
if self.uploadThread and self.uploadThread.isRunning():
|
||||
if self.flash_board.running():
|
||||
self.statusbar.showMessage(self.tr("Work in progess..."))
|
||||
return
|
||||
|
||||
self.uploadThread = QThread(self, self.flash_board, [
|
||||
self.signal, device, binary_uri], error=self.errorSignal)
|
||||
self.uploadThread.start()
|
||||
self.flash_board(self.signal, device, binary_uri,
|
||||
error=self.errorSignal)
|
||||
|
||||
def cache_download(self, progress, binary_uri):
|
||||
"""Downloads and caches file with status reports via Qt Signals"""
|
||||
@ -235,6 +285,7 @@ class MainWindow(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
||||
|
||||
return cache_fname
|
||||
|
||||
@QuickThread.wrap
|
||||
def flash_board(self, progress, device, binary_uri, baudrate=460800):
|
||||
if binary_uri.startswith(ALLOWED_PROTO):
|
||||
binary_uri = self.cache_download(progress, binary_uri)
|
||||
|
Loading…
x
Reference in New Issue
Block a user