Skip to content

Commit d9bf85c

Browse files
authored
Merge pull request #219 from sparkfun/RC__More_GUI_Updates
Uploader GUI v1.3
2 parents 3f65e58 + ab9d6a7 commit d9bf85c

File tree

7 files changed

+134
-34
lines changed

7 files changed

+134
-34
lines changed

Uploader_GUI/RTK_Firmware_Uploader_GUI.py

Lines changed: 134 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,17 @@
1313
1414
Pyinstaller:
1515
Windows:
16-
pyinstaller --onefile --clean --noconsole --distpath=./Windows_exe --icon=RTK.ico --add-binary="RTK_Surveyor.ino.partitions.bin;." --add-binary="RTK_Surveyor.ino.bootloader.bin;." --add-binary="boot_app0.bin;." --add-binary="RTK.png;." RTK_Firmware_Uploader_GUI.py
16+
pyinstaller --onefile --clean --noconsole --distpath=./Windows_exe --icon=RTK.ico --add-binary="RTK_Surveyor_Partitions_4MB.bin;." --add-binary="RTK_Surveyor_Partitions_16MB.bin;." --add-binary="RTK_Surveyor.ino.bootloader.bin;." --add-binary="boot_app0.bin;." --add-binary="RTK.png;." RTK_Firmware_Uploader_GUI.py
1717
Linux:
18-
pyinstaller --onefile --clean --noconsole --distpath=./Linux_exe --icon=RTK.ico --add-binary="RTK_Surveyor.ino.partitions.bin:." --add-binary="RTK_Surveyor.ino.bootloader.bin:." --add-binary="boot_app0.bin:." --add-binary="RTK.png:." RTK_Firmware_Uploader_GUI.py
18+
pyinstaller --onefile --clean --noconsole --distpath=./Linux_exe --icon=RTK.ico --add-binary="RTK_Surveyor_Partitions_4MB.bin:." --add-binary="RTK_Surveyor_Partitions_16MB.bin:." --add-binary="RTK_Surveyor.ino.bootloader.bin:." --add-binary="boot_app0.bin:." --add-binary="RTK.png:." RTK_Firmware_Uploader_GUI.py
1919
2020
Pyinstaller needs:
2121
RTK_Firmware_Uploader_GUI.py (this file!)
2222
RTK.ico (icon file for the .exe)
2323
RTK.png (icon for the GUI widget)
2424
esptool.py (v3.3, copied from https://github.com/espressif/esptool/releases/tag/v3.3)
25-
RTK_Surveyor.ino.partitions.bin
25+
RTK_Surveyor_Partitions_4MB.bin
26+
RTK_Surveyor_Partitions_16MB.bin
2627
RTK_Surveyor.ino.bootloader.bin
2728
boot_app0.bin
2829
@@ -35,12 +36,12 @@
3536

3637
from typing import Iterator, Tuple
3738

38-
from PyQt5.QtCore import QSettings, QProcess, QTimer, Qt, QIODevice, pyqtSlot
39+
from PyQt5.QtCore import QSettings, QProcess, QTimer, Qt, QIODevice, pyqtSlot, QObject
3940
from PyQt5.QtWidgets import QWidget, QLabel, QComboBox, QGridLayout, \
4041
QPushButton, QApplication, QLineEdit, QFileDialog, QPlainTextEdit, \
4142
QAction, QActionGroup, QMenu, QMenuBar, QMainWindow, QMessageBox
4243
from PyQt5.QtGui import QCloseEvent, QTextCursor, QIcon, QFont
43-
from PyQt5.QtSerialPort import QSerialPortInfo, QSerialPortInfo
44+
from PyQt5.QtSerialPort import QSerialPortInfo
4445

4546
import sys
4647
import os
@@ -55,9 +56,10 @@
5556
# Setting constants
5657
SETTING_PORT_NAME = 'port_name'
5758
SETTING_FILE_LOCATION = 'file_location'
59+
#SETTING_PARTITION_LOCATION = 'partition_location'
5860
SETTING_BAUD_RATE = 'baud'
5961

60-
guiVersion = 'v1.2'
62+
guiVersion = 'v1.3'
6163

6264
def gen_serial_ports() -> Iterator[Tuple[str, str, str]]:
6365
"""Return all available serial ports."""
@@ -70,12 +72,13 @@ def resource_path(relative_path):
7072
base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
7173
return os.path.join(base_path, relative_path)
7274

73-
class messageRedirect:
75+
class messageRedirect(QObject):
7476
"""Wrap a class around a QPlainTextEdit so we can redirect stdout and stderr to it"""
7577

76-
def __init__(self, edit, out=None) -> None:
78+
def __init__(self, edit, out=None, flashSize=None) -> None:
7779
self.edit = edit
7880
self.out = out
81+
self.flashSize = flashSize
7982

8083
def write(self, msg) -> None:
8184
if msg.startswith("\r"):
@@ -86,9 +89,21 @@ def write(self, msg) -> None:
8689
self.edit.insertPlainText(msg)
8790
self.edit.ensureCursorVisible()
8891
self.edit.repaint()
92+
QApplication.processEvents() # This prevents the circle of doom...
93+
8994
if self.out: # Echo to out (stdout) too if desired
9095
self.out.write(msg)
9196

97+
if self.flashSize:
98+
if msg.find("Detected flash size: 4MB") >= 0:
99+
self.flashSize[0] = 4
100+
elif msg.find("Detected flash size: 8MB") >= 0:
101+
self.flashSize[0] = 8
102+
elif msg.find("Detected flash size: 16MB") >= 0:
103+
self.flashSize[0] = 16
104+
elif msg.find("Detected flash size: ") >= 0:
105+
self.flashSize[0] = 0
106+
92107
def flush(self) -> None:
93108
None
94109

@@ -103,13 +118,12 @@ class MainWidget(QWidget):
103118
def __init__(self, parent: QWidget = None) -> None:
104119
super().__init__(parent)
105120

106-
self.timer=QTimer()
107-
self.timer.timeout.connect(self.repaintMessageBox)
121+
self.flashSize = [0] # flashSize needs to be mutable. Use a single element list
108122

109123
# File location line edit
110-
self.msg_label = QLabel(self.tr('Firmware File:'))
124+
self.file_label = QLabel(self.tr('Firmware File:'))
111125
self.fileLocation_lineedit = QLineEdit()
112-
self.msg_label.setBuddy(self.fileLocation_lineedit)
126+
self.file_label.setBuddy(self.fileLocation_lineedit)
113127
self.fileLocation_lineedit.setEnabled(False)
114128
self.fileLocation_lineedit.returnPressed.connect(self.on_browse_btn_pressed)
115129

@@ -118,6 +132,18 @@ def __init__(self, parent: QWidget = None) -> None:
118132
self.browse_btn.setEnabled(True)
119133
self.browse_btn.pressed.connect(self.on_browse_btn_pressed)
120134

135+
# # Partition file location line edit
136+
# self.partition_label = QLabel(self.tr('Partition File:'))
137+
# self.partitionFileLocation_lineedit = QLineEdit()
138+
# self.partition_label.setBuddy(self.partitionFileLocation_lineedit)
139+
# self.partitionFileLocation_lineedit.setEnabled(False)
140+
# self.partitionFileLocation_lineedit.returnPressed.connect(self.on_partition_browse_btn_pressed)
141+
142+
# # Browse for new file button
143+
# self.partition_browse_btn = QPushButton(self.tr('Browse'))
144+
# self.partition_browse_btn.setEnabled(True)
145+
# self.partition_browse_btn.pressed.connect(self.on_partition_browse_btn_pressed)
146+
121147
# Port Combobox
122148
self.port_label = QLabel(self.tr('COM Port:'))
123149
self.port_combobox = QComboBox()
@@ -152,10 +178,14 @@ def __init__(self, parent: QWidget = None) -> None:
152178
# Arrange Layout
153179
layout = QGridLayout()
154180

155-
layout.addWidget(self.msg_label, 1, 0)
181+
layout.addWidget(self.file_label, 1, 0)
156182
layout.addWidget(self.fileLocation_lineedit, 1, 1)
157183
layout.addWidget(self.browse_btn, 1, 2)
158184

185+
# layout.addWidget(self.partition_label, 2, 0)
186+
# layout.addWidget(self.partitionFileLocation_lineedit, 2, 1)
187+
# layout.addWidget(self.partition_browse_btn, 2, 2)
188+
159189
layout.addWidget(self.port_label, 2, 0)
160190
layout.addWidget(self.port_combobox, 2, 1)
161191
layout.addWidget(self.refresh_btn, 2, 2)
@@ -175,20 +205,11 @@ def __init__(self, parent: QWidget = None) -> None:
175205

176206
def writeMessage(self, msg) -> None:
177207
self.messageBox.moveCursor(QTextCursor.End)
178-
self.messageBox.ensureCursorVisible()
208+
#self.messageBox.ensureCursorVisible()
179209
self.messageBox.appendPlainText(msg)
180210
self.messageBox.ensureCursorVisible()
181211
self.messageBox.repaint()
182-
183-
def startTimer(self) -> None:
184-
self.timer.start(1000)
185-
186-
def endTimer(self) -> None:
187-
self.timer.stop()
188-
189-
def repaintMessageBox(self) -> None:
190-
self.messageBox.ensureCursorVisible()
191-
self.messageBox.repaint()
212+
QApplication.processEvents()
192213

193214
def _load_settings(self) -> None:
194215
"""Load settings on startup."""
@@ -202,6 +223,12 @@ def _load_settings(self) -> None:
202223
if lastFile is not None:
203224
self.fileLocation_lineedit.setText(lastFile)
204225

226+
# lastFile = self.settings.value(SETTING_PARTITION_LOCATION)
227+
# if lastFile is not None:
228+
# self.partitionFileLocation_lineedit.setText(lastFile)
229+
# else:
230+
# self.partitionFileLocation_lineedit.setText(resource_path("RTK_Surveyor.ino.partitions.bin"))
231+
205232
baud = self.settings.value(SETTING_BAUD_RATE)
206233
if baud is not None:
207234
index = self.baud_combobox.findData(baud)
@@ -212,6 +239,7 @@ def _save_settings(self) -> None:
212239
"""Save settings on shutdown."""
213240
self.settings.setValue(SETTING_PORT_NAME, self.port)
214241
self.settings.setValue(SETTING_FILE_LOCATION, self.theFileName)
242+
# self.settings.setValue(SETTING_PARTITION_LOCATION, self.thePartitionFileName)
215243
self.settings.setValue(SETTING_BAUD_RATE, self.baudRate)
216244

217245
def _clean_settings(self) -> None:
@@ -264,15 +292,18 @@ def theFileName(self) -> str:
264292
"""Return the file name."""
265293
return self.fileLocation_lineedit.text()
266294

295+
# @property
296+
# def thePartitionFileName(self) -> str:
297+
# """Return the partition file name."""
298+
# return self.partitionFileLocation_lineedit.text()
299+
267300
def closeEvent(self, event: QCloseEvent) -> None:
268301
"""Handle Close event of the Widget."""
269302
try:
270303
self._save_settings()
271304
except:
272305
pass
273306

274-
self.endTimer()
275-
276307
event.accept()
277308

278309
def on_refresh_btn_pressed(self) -> None:
@@ -291,6 +322,18 @@ def on_browse_btn_pressed(self) -> None:
291322
if fileName:
292323
self.fileLocation_lineedit.setText(fileName)
293324

325+
# def on_partition_browse_btn_pressed(self) -> None:
326+
# """Open dialog to select partition bin file."""
327+
# options = QFileDialog.Options()
328+
# fileName, _ = QFileDialog.getOpenFileName(
329+
# None,
330+
# "Select Partition File",
331+
# "",
332+
# "Parition Files (*.bin);;All Files (*)",
333+
# options=options)
334+
# if fileName:
335+
# self.partitionFileLocation_lineedit.setText(fileName)
336+
294337
def on_upload_btn_pressed(self) -> None:
295338
"""Upload the firmware"""
296339
portAvailable = False
@@ -303,7 +346,7 @@ def on_upload_btn_pressed(self) -> None:
303346

304347
fileExists = False
305348
try:
306-
f = open(self.fileLocation_lineedit.text())
349+
f = open(self.theFileName)
307350
fileExists = True
308351
except IOError:
309352
fileExists = False
@@ -313,11 +356,67 @@ def on_upload_btn_pressed(self) -> None:
313356
return
314357
f.close()
315358

359+
# fileExists = False
360+
# try:
361+
# f = open(self.thePartitionFileName)
362+
# fileExists = True
363+
# except IOError:
364+
# fileExists = False
365+
# finally:
366+
# if (fileExists == False):
367+
# self.writeMessage("File Not Found")
368+
# return
369+
# f.close()
370+
316371
try:
317372
self._save_settings() # Save the settings in case the upload crashes
318373
except:
319374
pass
320375

376+
self.flashSize[0] = 0
377+
378+
self.writeMessage("Detecting flash size\n\n")
379+
380+
command = []
381+
command.extend(["--chip","esp32"])
382+
command.extend(["--port",self.port])
383+
command.extend(["--baud",self.baudRate])
384+
command.extend(["flash_id"])
385+
386+
try:
387+
esptool.main(command)
388+
except (ValueError, IOError, FatalError, ImportError, NotImplementedInROMError, UnsupportedCommandError, NotSupportedError, RuntimeError) as err:
389+
self.writeMessage(str(err))
390+
self.messageBox.ensureCursorVisible()
391+
self.messageBox.repaint()
392+
return
393+
except:
394+
self.messageBox.ensureCursorVisible()
395+
self.messageBox.repaint()
396+
return
397+
398+
if self.flashSize[0] == 0:
399+
self.writeMessage("Flash size not detected! Defaulting to 16MB\n")
400+
self.flashSize[0] = 16
401+
else:
402+
self.writeMessage("Flash size is " + str(self.flashSize[0]) + "MB\n")
403+
404+
thePartitionFileName = ''
405+
firmwareSizeCorrect = True
406+
if self.flashSize[0] == 16:
407+
thePartitionFileName = resource_path("RTK_Surveyor_Partitions_16MB.bin")
408+
# if self.theFileName.find("16MB") < 0:
409+
# firmwareSizeCorrect = False
410+
else:
411+
thePartitionFileName = resource_path("RTK_Surveyor_Partitions_4MB.bin")
412+
# if self.theFileName.find("4MB") < 0:
413+
# firmwareSizeCorrect = False
414+
415+
if firmwareSizeCorrect == False:
416+
reply = QMessageBox.warning(self, "Firmware size mismatch", "Do you want to continue?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
417+
if reply == QMessageBox.No:
418+
return
419+
321420
self.writeMessage("Uploading firmware\n")
322421

323422
command = []
@@ -327,22 +426,23 @@ def on_upload_btn_pressed(self) -> None:
327426
command.extend(["--baud",self.baudRate])
328427
command.extend(["--before","default_reset","--after","hard_reset","write_flash","-z","--flash_mode","dio","--flash_freq","80m","--flash_size","detect"])
329428
command.extend(["0x1000",resource_path("RTK_Surveyor.ino.bootloader.bin")])
330-
command.extend(["0x8000",resource_path("RTK_Surveyor.ino.partitions.bin")])
429+
command.extend(["0x8000",thePartitionFileName])
331430
command.extend(["0xe000",resource_path("boot_app0.bin")])
332431
command.extend(["0x10000",self.theFileName])
333432

334433
self.writeMessage("Command: esptool.main(%s)\n\n" % " ".join(command))
335434

336435
#print("python esptool.py %s\n\n" % " ".join(command)) # Useful for debugging - cut and paste into a command prompt
337436

338-
self.startTimer()
339-
340437
try:
341438
esptool.main(command)
342439
except (ValueError, IOError, FatalError, ImportError, NotImplementedInROMError, UnsupportedCommandError, NotSupportedError, RuntimeError) as err:
343440
self.writeMessage(str(err))
441+
except:
442+
pass
344443

345-
self.endTimer()
444+
self.messageBox.ensureCursorVisible()
445+
self.messageBox.repaint()
346446

347447
if __name__ == '__main__':
348448
from sys import exit as sysExit
@@ -352,10 +452,10 @@ def on_upload_btn_pressed(self) -> None:
352452
app.setWindowIcon(QIcon(resource_path("RTK.png")))
353453
w = MainWidget()
354454
if 1: # Change to 0 to have the messages echoed on stdout
355-
sys.stdout = messageRedirect(w.messageBox) # Divert stdout to messageBox
455+
sys.stdout = messageRedirect(w.messageBox, flashSize=w.flashSize) # Divert stdout to messageBox. Report flash size via flashSize
356456
sys.stderr = messageRedirect(w.messageBox) # Divert stderr to messageBox
357457
else:
358-
sys.stdout = messageRedirect(w.messageBox, sys.stdout) # Echo to stdout too
359-
sys.stderr = messageRedirect(w.messageBox, sys.stderr) # Echo to stderr too
458+
sys.stdout = messageRedirect(w.messageBox, flashSize=w.flashSize, out=sys.stdout) # Echo to stdout too
459+
sys.stderr = messageRedirect(w.messageBox, out=sys.stderr) # Echo to stderr too
360460
w.show()
361461
sys.exit(app.exec_())
3 KB
Binary file not shown.
Binary file not shown.
54.3 KB
Binary file not shown.
-31.8 MB
Binary file not shown.
-31.8 MB
Binary file not shown.

0 commit comments

Comments
 (0)