#!/usr/bin/python3 import sys import subprocess from os import path import PySide from PySide.QtGui import QMainWindow, QFileDialog, QApplication, QDialog, QMessageBox from PySide.QtUiTools import QUiLoader from PySide.QtCore import QFile, QCoreApplication from Ui_MainWindow import Ui_MainWindow import config def path_exists(p): if path.exists(p): return True else: print(p, 'does not exist!') return False def validateDataDir(): return path_exists(config.dataDir) and \ path_exists(config.database) and \ path_exists(config.rom) def validateBuildRom(): return path_exists(config.buildRom) class MainWindow(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setupUi(self) self.configure() # init logic self.programming_enabled = False self._programmersOk = False self._serialNumberOk = False # init UI self.detectProgrammersButton.clicked.connect(self.detectProgrammers) self.programButton.clicked.connect(self.program) self.programUconCheckBox.toggled.connect(self.programUconToggled) self.programFlashCheckBox.toggled.connect(self.programFlashToggled) self.flashNewRadioButton.toggled.connect(self.flashNewToggled) self.serialNumberSpinBox.valueChanged[int].connect(self.spinBoxValueChanged) self.findPushButton.clicked.connect(self.selectFile) self.bootRomLineEdit.textChanged.connect(self.bootRomSet) self.bootRomLineEdit.setText(config.rom) # Triggers self.bootRomSet self.initSpinBox() def selectFile(self): filename = QFileDialog.getOpenFileName()[0] if path.exists(filename): self.bootRomLineEdit.setText(filename) def bootRomSet(self): rom = self.bootRomLineEdit.text() self._bootRomOk = path.exists(rom) if self._bootRomOk: config.rom = rom self.statusbar.clearMessage() self.enable() else: self.disable() self.statusbar.showMessage("File \"" + rom + "\" does not exist!") def initSpinBox(self): try: f = open(config.nextSerial) self.serialNumberSpinBox.setValue(int(f.read())) f.close() except IOError: pass except ValueError: pass def spinBoxValueChanged(self, v=None): used = self.serialNumberUsed(v or self.serialNumberSpinBox.value) self._serialNumberOk = False if self.reflashRadioButton.isChecked() and not used: self.statusbar.showMessage("Impossible to reflash: unknown serial number!") elif (not self.reflashRadioButton.isChecked()) and used: self.statusbar.showMessage("Serial number already used!") else: self._serialNumberOk = True self.statusbar.clearMessage() self.enable() if not self._serialNumberOk: self.disable() def programUconToggled(self, enabled): if enabled: self.detectProgrammers() elif not self.programFlashCheckBox.isChecked(): self.programFlashCheckBox.toggle() def programFlashToggled(self, enabled): if enabled: self.detectProgrammers() elif not self.programUconCheckBox.isChecked(): self.programUconCheckBox.toggle() for i in [self.flashNewRadioButton, #self.reflashRadioButton, #self.bootRomLineEdit, self.bootRomLabel, self.findPushButton]: i.setEnabled(enabled) def flashNewToggled(self, enabled): self.spinBoxValueChanged(self.serialNumberSpinBox.value()) def configure(self): if validateDataDir() and validateBuildRom(): return self.configError() def configError(self): QMessageBox.critical(self, "Configuration problem", "Edit config.py") self.close() def runHelper(self, *args, **kwargs): try: process = subprocess.Popen(*args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kwargs) out = process.communicate()[0] return (process.returncode, out) except OSError: return (-255, b'') def disable(self): self._enable(False) def enable(self): if self._serialNumberOk and (not self.programFlashCheckBox.isChecked() or (self._programmersOk and self._bootRomOk)): self._enable() def _enable(self, enabled=True): self.programming_enabled = enabled self.programButton.setEnabled(enabled) self.progressBar.setEnabled(enabled) def finish(self, status=None, output=None, success=False): self.progressBar.setEnabled(False) self.progressBar.setValue(0) if not success: self.disable() if status: self.statusbar.showMessage(status) if output: self.textBrowser.setPlainText(output.decode(errors='replace')) def detectProgrammers(self): if self.programUconCheckBox.isChecked(): self.statusbar.showMessage("Detecting MSP430 programmer...") (n, o) = self.runHelper(config.mspdebug + ['exit']) if n != 0: self._programmersOk = False return self.finish(output=o, status="MSP430 programmer not working!") if self.programFlashCheckBox.isChecked(): self.statusbar.showMessage("Detecting SPI Flash programmer...") (n, o) = self.runHelper(config.flashrom) if n != 0: self._programmersOk = False return self.finish(output=o, status="SPI Flash programmer not working!") self._programmersOk = True self.statusbar.clearMessage() self.textBrowser.clear() self.enable() def program(self): self.step = 0 def nextStep(): self.step = self.step + 1 self.progressBar.setValue(self.step) steps = 0 if self.programUconCheckBox.isChecked(): steps = steps + 1 if self.programFlashCheckBox.isChecked(): steps = steps + 2 if self.flashNewRadioButton.isChecked(): steps = steps + 1 self.progressBar.setMaximum(steps) if not self.programming_enabled: self.statusbar.showMessage("Programming disabled!") return if self.programUconCheckBox.isChecked(): self.statusbar.showMessage("Programming MSP430...") QCoreApplication.processEvents() (n, o) = self.runHelper(config.mspdebug + ["prog " + path.abspath(config.firmware)], cwd=config.libmsp430_dir) nextStep() # Save version in database self.statusbar.showMessage("Saving to database...") QCoreApplication.processEvents() savePwrSeqName(self.serialNumberSpinBox.value(), config.firmware) self.statusbar.showMessage("MSP430 programmed successfuly") self.textBrowser.clear() if n != 0: return self.finish(output=o, status="MSP430 programming failed!") if self.programFlashCheckBox.isChecked(): QMessageBox(text="Before continuing, press SW1 to turn on the board.").exec_() if self.programFlashCheckBox.isChecked(): # Build ROM self.statusbar.showMessage("Building ROM...") QCoreApplication.processEvents() if self.reflashRadioButton.isChecked(): (n, o) = self.runHelper([config.buildRom, '-c', config.rom, '-S', config.nextSerial, '-d', config.database, '-r', str(self.serialNumberSpinBox.value())]) else: (n, o) = self.runHelper([config.buildRom, '-f', config.macStart, '-t', config.macEnd, '-c', config.rom, '-S', config.nextSerial, '-d', config.database, '-n', str(self.serialNumberSpinBox.value())]) nextStep() self.textBrowser.setPlainText(o.decode(errors='replace')) if n != 0: return self.finish(status= "ROM construction failed! Configuration may be wrong.") # Program Flash self.statusbar.showMessage("Programming SPI Flash...") QCoreApplication.processEvents() (n,o) = self.runHelper(config.flashrom +['-w', config.rom]) nextStep() if n != 0: return self.finish(output=o, status="SPI Flash programming failed!") # Save version in database self.statusbar.showMessage("Saving to database...") QCoreApplication.processEvents() saveCorebootName(self.serialNumberSpinBox.value(), config.rom) # Commit in Git if self.flashNewRadioButton.isChecked(): self.initSpinBox() self.statusbar.showMessage("Commiting in git...") QCoreApplication.processEvents() n = subprocess.call(['git', 'commit', '-m', o, path.abspath(config.database), path.abspath(config.nextSerial)], cwd=config.dataDir) nextStep() if n != 0: self.statusbar.showMessage("WARNING: Could not commit in git!") return self.statusbar.clearMessage() def serialNumberUsed(self, n): import sqlite3 conn = sqlite3.connect(config.database) c = conn.cursor() return c.execute('SELECT 1 FROM xioh_data WHERE serial_number=? LIMIT 1', (n,)) \ .fetchone() def _saveName(field, serial, name): import sqlite3 conn = sqlite3.connect(config.database) c = conn.cursor() c.execute('UPDATE xioh_data SET '+field+' = ? WHERE serial_number=?', (name,serial)) conn.commit() if conn.total_changes < 1: print("WARNING: No row was changed trying to update ", field, "for board", serial, "to value", name) c.close() def saveCorebootName(serial, name): _saveName("coreboot_version", serial, name) def savePwrSeqName(serial, name): _saveName("pwrseq_version", serial, name) if __name__ == '__main__': app = QApplication(sys.argv) frame = MainWindow() frame.show() app.exec_()