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 *-
|
# -* encoding: utf-8 *-
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os.path
|
import os.path
|
||||||
import re
|
import re
|
||||||
@ -51,12 +52,12 @@ def indexof(path):
|
|||||||
return [a for a, b in file_index_re.findall(resp.text) if a == b]
|
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
|
"""Provides similar API to threading.Thread but with additional error
|
||||||
reporting based on Qt Signals"""
|
reporting based on Qt Signals"""
|
||||||
def __init__(self, parent=None, target=None, args=None, kwargs=None,
|
def __init__(self, parent=None, target=None, args=None, kwargs=None,
|
||||||
error=None):
|
error=None):
|
||||||
super(QThread, self).__init__(parent)
|
super(QuickThread, self).__init__(parent)
|
||||||
self.target = target
|
self.target = target
|
||||||
self.args = args or []
|
self.args = args or []
|
||||||
self.kwargs = kwargs or {}
|
self.kwargs = kwargs or {}
|
||||||
@ -71,6 +72,48 @@ class QThread(QtCore.QThread):
|
|||||||
# raise here causes windows builds to just die. ¯\_(ツ)_/¯
|
# raise here causes windows builds to just die. ¯\_(ツ)_/¯
|
||||||
logging.exception('Unhandled exception')
|
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):
|
class MainWindow(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
||||||
signal = QtCore.Signal([str, int])
|
signal = QtCore.Signal([str, int])
|
||||||
@ -92,9 +135,13 @@ class MainWindow(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
|||||||
|
|
||||||
self.i18n_init(QtCore.QLocale.system())
|
self.i18n_init(QtCore.QLocale.system())
|
||||||
|
|
||||||
# TODO: extract this to separate thread
|
self.firmware_list = FirmwareListThread()
|
||||||
self.populate_versions()
|
self.firmware_list.onFirmware.connect(self.populate_versions)
|
||||||
self.populate_boards(serial.tools.list_ports.comports())
|
self.firmware_list.start()
|
||||||
|
|
||||||
|
self.port_detect = PortDetectThread()
|
||||||
|
self.port_detect.portsUpdate.connect(self.populate_boards)
|
||||||
|
self.port_detect.start()
|
||||||
|
|
||||||
self.on_expertModeBox_clicked()
|
self.on_expertModeBox_clicked()
|
||||||
|
|
||||||
@ -120,10 +167,10 @@ class MainWindow(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
|||||||
self.app.installTranslator(self.translator)
|
self.app.installTranslator(self.translator)
|
||||||
self.retranslateUi(self)
|
self.retranslateUi(self)
|
||||||
|
|
||||||
def populate_versions(self):
|
def populate_versions(self, files):
|
||||||
"""Loads available firmware versions into versionbox widget"""
|
"""Loads available firmware versions into versionbox widget"""
|
||||||
|
|
||||||
for fname in indexof(UPDATE_REPOSITORY):
|
for fname in files:
|
||||||
if not fname.endswith('.bin'):
|
if not fname.endswith('.bin'):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@ -131,10 +178,14 @@ class MainWindow(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
|||||||
item.setData(UPDATE_REPOSITORY + fname, ROLE_DEVICE)
|
item.setData(UPDATE_REPOSITORY + fname, ROLE_DEVICE)
|
||||||
self.versionBox.model().appendRow(item)
|
self.versionBox.model().appendRow(item)
|
||||||
|
|
||||||
|
self.statusbar.clearMessage()
|
||||||
|
|
||||||
def populate_boards(self, ports):
|
def populate_boards(self, ports):
|
||||||
"""Populates board selection combobox from list of pyserial
|
"""Populates board selection combobox from list of pyserial
|
||||||
ListPortInfo objects"""
|
ListPortInfo objects"""
|
||||||
|
|
||||||
|
self.boardBox.clear()
|
||||||
|
|
||||||
prefered, others = self.group_ports(ports)
|
prefered, others = self.group_ports(ports)
|
||||||
|
|
||||||
for b in prefered:
|
for b in prefered:
|
||||||
@ -201,13 +252,12 @@ class MainWindow(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
|||||||
"Invalid version / file does not exist"))
|
"Invalid version / file does not exist"))
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.uploadThread and self.uploadThread.isRunning():
|
if self.flash_board.running():
|
||||||
self.statusbar.showMessage(self.tr("Work in progess..."))
|
self.statusbar.showMessage(self.tr("Work in progess..."))
|
||||||
return
|
return
|
||||||
|
|
||||||
self.uploadThread = QThread(self, self.flash_board, [
|
self.flash_board(self.signal, device, binary_uri,
|
||||||
self.signal, device, binary_uri], error=self.errorSignal)
|
error=self.errorSignal)
|
||||||
self.uploadThread.start()
|
|
||||||
|
|
||||||
def cache_download(self, progress, binary_uri):
|
def cache_download(self, progress, binary_uri):
|
||||||
"""Downloads and caches file with status reports via Qt Signals"""
|
"""Downloads and caches file with status reports via Qt Signals"""
|
||||||
@ -235,6 +285,7 @@ class MainWindow(QtWidgets.QMainWindow, mainwindow.Ui_MainWindow):
|
|||||||
|
|
||||||
return cache_fname
|
return cache_fname
|
||||||
|
|
||||||
|
@QuickThread.wrap
|
||||||
def flash_board(self, progress, device, binary_uri, baudrate=460800):
|
def flash_board(self, progress, device, binary_uri, baudrate=460800):
|
||||||
if binary_uri.startswith(ALLOWED_PROTO):
|
if binary_uri.startswith(ALLOWED_PROTO):
|
||||||
binary_uri = self.cache_download(progress, binary_uri)
|
binary_uri = self.cache_download(progress, binary_uri)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user