diff --git a/src/python/about.ui b/src/python/about.ui new file mode 100644 index 00000000..b69e79ba --- /dev/null +++ b/src/python/about.ui @@ -0,0 +1,91 @@ + + + About + + + + 0 + 0 + 400 + 300 + + + + About + + + false + + + true + + + + + 30 + 240 + 341 + 32 + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + 10 + 20 + 381 + 211 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is a GUI demonstrator for the SWIG_Avrdude Python bindings.</p></body></html> + + + + + + + buttonBox + accepted() + About + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + About + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/python/adgui.py b/src/python/adgui.py new file mode 100755 index 00000000..a17731b2 --- /dev/null +++ b/src/python/adgui.py @@ -0,0 +1,175 @@ +#!/usr/bin/env python + +import sys +import os +import pathlib +import re + +builddir = None +if os.name == 'posix': + # Linux, *BSD, MacOS + sysname = os.uname()[0].lower() + builddir = f'build_{sysname}/src' +elif os.name == 'nt': + # Windows + for candidate in ['build_msvc/src', 'build_mingw64/src']: + if os.path.exists(candidate): + builddir = candidate + os.add_dll_directory(os.path.realpath(candidate)) + break + +if builddir == None: + print("Cannot determine build directory, module loading might fail.", file=sys.stderr) +else: + sys.path.append(builddir) + sys.path.append(builddir + '/python') + +import swig_avrdude as ad + + + +def avrdude_init(): + ad.init_config() + + found = False + for d in [builddir, "/etc", "/usr/local/etc"]: + p = pathlib.Path(d + "/avrdude.conf") + if p.is_file(): + ad.read_config(d + "/avrdude.conf") + return (True, f"Found avrdude.conf in {d}\n") + + return (False, "Sorry, no avrdude.conf could be found.\n") + +def classify_devices(): + result = { + 'at90': [], + 'attiny': [], + 'atmega': [], + 'atxmega': [], + 'avr_de': [], + 'other': [] + } + avr_de_re = re.compile('AVR\d+[DE][A-Z]\d+') + part = ad.lfirst(ad.cvar.part_list) + while part: + p = ad.ldata_avrpart(part) + part = ad.lnext(part) + if not p.id.startswith('.'): + if p.desc.startswith('AT90'): + result['at90'].append(p.desc) + elif p.desc.startswith('ATtiny'): + result['attiny'].append(p.desc) + elif p.desc.startswith('ATmega'): + result['atmega'].append(p.desc) + elif p.desc.startswith('ATxmega'): + result['atxmega'].append(p.desc) + elif avr_de_re.match(p.desc): + result['avr_de'].append(p.desc) + else: + result['other'].append(p.desc) + return result + +from PySide2.QtWidgets import * +from PySide2.QtCore import QFile, QIODevice + +from ui_adgui import Ui_MainWindow +from ui_about import Ui_About +from ui_device import Ui_Device + +class About(QDialog): + def __init__(self): + super().__init__() + self.ui = Ui_About() + self.ui.setupUi(self) + +class Device(QDialog): + def __init__(self): + super().__init__() + self.ui = Ui_Device() + self.ui.setupUi(self) + +class MainWindow(QMainWindow): + def __init__(self): + super(MainWindow, self).__init__() + self.ui = Ui_MainWindow() + self.ui.setupUi(self) + +class adgui(): + def __init__(self, argv): + self.logstring = "Welcome to AVRDUDE!\n" + self.app = QApplication(sys.argv) + + self.window = MainWindow() + self.window.show() + self.about = About() + self.device = Device() + + self.window.ui.actionAbout.triggered.connect(self.about.show) + self.window.ui.actionDevice.triggered.connect(self.device.show) + self.window.ui.loggingArea.setPlainText(self.logstring) + + (success, message) = avrdude_init() + self.initialized = success + self.logstring += message + self.window.ui.loggingArea.setPlainText(self.logstring) + if not success: + self.window.ui.actionDevice.setEnabled(False) + self.window.ui.actionProgrammer.setEnabled(False) + # essentially, only Exit and Help work anymore + else: + self.devices = classify_devices() + self.update_device_cb() + self.device.ui.at90.stateChanged.connect(self.update_device_cb) + self.device.ui.attiny.stateChanged.connect(self.update_device_cb) + self.device.ui.atmega.stateChanged.connect(self.update_device_cb) + self.device.ui.atxmega.stateChanged.connect(self.update_device_cb) + self.device.ui.avr_de.stateChanged.connect(self.update_device_cb) + self.device.ui.other.stateChanged.connect(self.update_device_cb) + + # rough equivalent of avrdude_message2() + # first argument is either "stdout" or "stderr" + # + # install callback with ad.set_msg_callback(msg_callback) + def msg_callback(self, target: str, lno: int, fname: str, func: str, + msgmode: int, msglvl: int, msg: str): + if ad.cvar.verbose >= msglvl: + s = "" + if msgmode & ad.MSG2_PROGNAME: + s += ad.cvar.progname + if ad.cvar.verbose >= ad.MSG_NOTICE and (msgmode & ad.MSG2_FUNCTION) != 0: + s += " " + func + "()" + if ad.cvar.verbose >= ad.MSG_DEBUG and (msgmode & ad.MSG2_FILELINE) != 0: + n = os.path.basename(fname) + s += f" [{n}:{lno}]" + if (msgmode & ad.MSG2_TYPE) != 0: + s += " " + message_type(msglvl) + s += ": " + elif (msgmode & ad.MSG2_INDENT1) != 0: + s = (len(ad.cvar.progname) + 1) * ' ' + elif (msgmode & ad.MSG2_INDENT2) != 0: + s = (len(ad.cvar.progname) + 2) * ' ' + s += msg + try: + self.logstring += s + except UnicodeDecodeError: + self.logstring += "message contained invalid characters\n" + self.window.ui.loggingArea.setPlainText(self.logstring) + + def update_device_cb(self): + fams = list(self.devices.keys()) + #fams.sort() + self.device.ui.devices.clear() + for f in fams: + obj = eval('self.device.ui.' + f + '.isChecked()') + if obj: + for d in self.devices[f]: + self.device.ui.devices.addItem(d) + + +def main(): + gui = adgui(sys.argv) + + sys.exit(gui.app.exec_()) + +if __name__ == "__main__": + main() diff --git a/src/python/adgui.ui b/src/python/adgui.ui new file mode 100644 index 00000000..3700a970 --- /dev/null +++ b/src/python/adgui.ui @@ -0,0 +1,180 @@ + + + MainWindow + + + + 0 + 0 + 780 + 746 + + + + AVRDUDE GUI + + + + + + 0 + 660 + 781 + 41 + + + + + 15 + + + 15 + + + + + + 100 + 0 + + + + -- % + + + + + + + false + + + 0 + + + + + + + + 100 + 0 + + + + --:-- + + + + + + + + + 0 + 0 + 821 + 651 + + + + false + + + false + + + true + + + + + + + 0 + 0 + 780 + 22 + + + + + File + + + + + + + + + View + + + + + + Settings + + + + + Help + + + + + + + + + + + + Device ... + + + + + Programmer ... + + + + + Exit + + + + + false + + + Device Memories + + + + + About ... + + + + + + + actionExit + triggered() + MainWindow + close() + + + -1 + -1 + + + 399 + 299 + + + + + diff --git a/src/python/device.ui b/src/python/device.ui new file mode 100644 index 00000000..bb24b3d2 --- /dev/null +++ b/src/python/device.ui @@ -0,0 +1,157 @@ + + + Device + + + + 0 + 0 + 398 + 217 + + + + Device selection + + + + + 280 + 140 + 81 + 61 + + + + Qt::Vertical + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + 180 + 50 + 191 + 25 + + + + + + + 20 + 10 + 131 + 191 + + + + + + + Families enabled: + + + + + + + AT90 + + + true + + + + + + + ATtiny + + + true + + + + + + + ATmega + + + true + + + + + + + ATxmega + + + true + + + + + + + AVR…D/E… + + + true + + + + + + + Other + + + true + + + + + + + + + + buttonBox + accepted() + Device + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + Device + reject() + + + 316 + 260 + + + 286 + 274 + + + + +