#!/usr/bin/env python """ # TOP2049 Open Source programming suite # # Universal Device Tester # # Copyright (c) 2010 Michael Buesch # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. """ from libtoprammer.toprammer_main import * from PyQt4.QtCore import * from PyQt4.QtGui import * def stringRemoveChars(string, chars): ret = "" for c in string: if c not in chars: ret += c return ret class ZifWidget(QGroupBox): def __init__(self, parent, top): QGroupBox.__init__(self, parent.tr("ZIF socket"), parent) self.top = top self.setLayout(QGridLayout()) self.nrPins = top.vccx.getNrOfPins() assert(self.nrPins == top.vpp.getNrOfPins()) assert(self.nrPins == top.gnd.getNrOfPins()) assert(self.nrPins % 2 == 0) self.blockedPins = [] self.ignoreOutChange = False label = QLabel(self) label.setFrameStyle(QFrame.Panel | QFrame.Sunken) label.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) self.layout().addWidget(label, 0, 2, self.nrPins // 2, 1) self.pins = [ None ] * self.nrPins self.pinOuten = [ None ] * self.nrPins for i in range(0, self.nrPins // 2): left = i + 1 right = self.nrPins - i self.pins[left - 1] = QCheckBox(str(left), self) self.connect(self.pins[left - 1], SIGNAL("stateChanged(int)"), self.__outChanged) self.pinOuten[left - 1] = QCheckBox("out", self) self.connect(self.pinOuten[left - 1], SIGNAL("stateChanged(int)"), self.__outEnChanged) self.layout().addWidget(self.pinOuten[left - 1], left - 1, 0) self.layout().addWidget(self.pins[left - 1], left - 1, 1) self.pins[right - 1] = QCheckBox(str(right), self) self.connect(self.pins[right - 1], SIGNAL("stateChanged(int)"), self.__outChanged) self.pinOuten[right - 1] = QCheckBox("out", self) self.connect(self.pinOuten[right - 1], SIGNAL("stateChanged(int)"), self.__outEnChanged) self.layout().addWidget(self.pins[right - 1], self.nrPins - right, 3) self.layout().addWidget(self.pinOuten[right - 1], self.nrPins - right, 4) self.__outEnChanged() self.__outChanged() def readInputs(self): try: inputMask = self.top.chip.getInputs() except (TOPException), e: QMessageBox.critical(self, self.tr("TOP communication failed"), self.tr("Failed to fetch input states:\n") +\ str(e)) return False for i in range(0, self.nrPins): if self.pinOuten[i].checkState() != Qt.Checked and\ i + 1 not in self.blockedPins: state = Qt.Unchecked if inputMask & (1 << i): state = Qt.Checked self.ignoreOutChange = True self.pins[i].setCheckState(state) self.ignoreOutChange = False return True def __updateInOutStates(self): for i in range(0, self.nrPins): if i + 1 in self.blockedPins: self.pins[i].setEnabled(False) self.pins[i].setCheckState(Qt.Unchecked) self.pinOuten[i].setEnabled(False) self.pinOuten[i].setCheckState(Qt.Unchecked) else: self.pinOuten[i].setEnabled(True) if self.pinOuten[i].checkState() == Qt.Checked: self.pins[i].setEnabled(True) else: self.pins[i].setEnabled(False) def __outEnChanged(self): self.__updateInOutStates() outEnMask = 0 for i in range(0, self.nrPins): if self.pinOuten[i].checkState() == Qt.Checked: outEnMask |= (1 << i) try: self.top.chip.setOutputEnableMask(outEnMask) except (TOPException), e: QMessageBox.critical(self, self.tr("TOP communication failed"), self.tr("Failed to set output-enable states:\n") +\ str(e)) return self.readInputs() def __outChanged(self): if self.ignoreOutChange: return outMask = 0 for i in range(0, self.nrPins): if self.pins[i].checkState() == Qt.Checked: outMask |= (1 << i) try: self.top.chip.setOutputs(outMask) except (TOPException), e: QMessageBox.critical(self, self.tr("TOP communication failed"), self.tr("Failed to set output states:\n") +\ str(e)) return self.readInputs() def setBlockedPins(self, blockedPins): self.blockedPins = blockedPins self.__updateInOutStates() self.readInputs() class MainWidget(QWidget): def __init__(self, mainwnd): QWidget.__init__(self, mainwnd) self.mainwnd = mainwnd self.setLayout(QGridLayout()) try: self.top = TOP(verbose=2) self.top.initializeChip("unitest") self.zifWidget = ZifWidget(self, self.top) self.layout().addWidget(self.zifWidget, 0, 0, 10, 1) except (TOPException), e: QMessageBox.critical(self, self.tr("TOP init failed"), self.tr("Initialization of TOP device failed:\n") +\ str(e)) raise group = QGroupBox(self.tr("GND layout"), self) group.setLayout(QGridLayout()) self.gndLayout = QComboBox(self) self.gndLayout.addItem(self.tr("Not connected"), QVariant(0)) for (layId, layMask) in self.top.gnd.supportedLayouts(): if not layMask: continue descr = self.tr("GND on pin ") for i in range(0, self.top.gnd.getNrOfPins()): if layMask & (1 << i): descr += str(i + 1) + " " self.gndLayout.addItem(descr, QVariant(layId)) group.layout().addWidget(self.gndLayout, 0, 0) self.layout().addWidget(group, 0, 1) group = QGroupBox(self.tr("VCCX layout"), self) group.setLayout(QGridLayout()) self.vccxVoltage = QDoubleSpinBox(self) self.vccxVoltage.setSuffix(self.tr(" V")) self.vccxVoltage.setMinimum(self.top.vccx.minVoltage()) self.vccxVoltage.setMaximum(self.top.vccx.maxVoltage()) self.vccxVoltage.setSingleStep(0.1) group.layout().addWidget(self.vccxVoltage, 0, 0) self.vccxLayout = QComboBox(self) self.vccxLayout.addItem(self.tr("Not connected"), QVariant(0)) for (layId, layMask) in self.top.vccx.supportedLayouts(): if not layMask: continue descr = self.tr("VCCX on pin ") for i in range(0, self.top.vccx.getNrOfPins()): if layMask & (1 << i): descr += str(i + 1) + " " self.vccxLayout.addItem(descr, QVariant(layId)) group.layout().addWidget(self.vccxLayout, 1, 0) self.layout().addWidget(group, 1, 1) group = QGroupBox(self.tr("Input polling"), self) group.setLayout(QGridLayout()) self.inputPollEn = QCheckBox(self.tr("Input polling enabled"), self) self.inputPollEn.setCheckState(Qt.Checked) group.layout().addWidget(self.inputPollEn, 0, 0) self.inputPollInterval = QDoubleSpinBox(self) self.inputPollInterval.setPrefix(self.tr("Interval ")) self.inputPollInterval.setSuffix(self.tr(" seconds")) self.inputPollInterval.setMinimum(0.25) self.inputPollInterval.setSingleStep(0.25) self.inputPollInterval.setValue(1.0) group.layout().addWidget(self.inputPollInterval, 1, 0) self.layout().addWidget(group, 2, 1) group = QGroupBox(self.tr("Oscillator"), self) group.setLayout(QGridLayout()) self.oscPin = QComboBox(self) self.oscPin.addItem("Disabled", QVariant(0)) for i in range(0, self.zifWidget.nrPins): self.oscPin.addItem("On pin %d" % (i + 1), QVariant(1 << i)) group.layout().addWidget(self.oscPin, 0, 0) self.oscDiv = QSpinBox(self) self.oscDiv.setPrefix("Divider ") self.oscDiv.setSingleStep(1) self.oscDiv.setMinimum(1) self.oscDiv.setMaximum(24000000) self.oscDiv.setValue(24) group.layout().addWidget(self.oscDiv, 1, 0) self.oscFreq = QLabel(self) group.layout().addWidget(self.oscFreq, 2, 0) self.layout().addWidget(group, 3, 1) group = QGroupBox(self.tr("VPP layout"), self) group.setLayout(QGridLayout()) self.vppVoltage = QDoubleSpinBox(self) self.vppVoltage.setSuffix(self.tr(" V")) self.vppVoltage.setMinimum(self.top.vpp.minVoltage()) self.vppVoltage.setMaximum(self.top.vpp.maxVoltage()) self.vppVoltage.setSingleStep(0.1) group.layout().addWidget(self.vppVoltage, 0, 0, 1, 2) self.vppLayouts = {} xOffset = 0 yOffset = 0 for (layId, layMask) in self.top.vpp.supportedLayouts(): if not layMask: continue for i in range(0, self.top.vpp.getNrOfPins()): if layMask & (1 << i): descr = str(i + 1) + " " self.vppLayouts[layId] = QCheckBox(descr, self) self.connect(self.vppLayouts[layId], SIGNAL("stateChanged(int)"), self.vppLayoutChanged) group.layout().addWidget(self.vppLayouts[layId], yOffset + 1, xOffset) yOffset += 1 if yOffset == len(self.top.vpp.supportedLayouts()) // 2: yOffset = 0 xOffset += 1 self.layout().addWidget(group, 0, 2, 8, 1) self.inputPollTimer = QTimer() self.connect(self.inputPollTimer, SIGNAL("timeout()"), self.doInputPollTimer) self.connect(self.inputPollEn, SIGNAL("stateChanged(int)"), self.inputPollChanged) self.connect(self.inputPollInterval, SIGNAL("valueChanged(double)"), self.inputPollChanged) self.connect(self.gndLayout, SIGNAL("currentIndexChanged(int)"), self.gndLayoutChanged) self.connect(self.vccxVoltage, SIGNAL("valueChanged(double)"), self.vccxLayoutChanged) self.connect(self.vccxLayout, SIGNAL("currentIndexChanged(int)"), self.vccxLayoutChanged) self.connect(self.vppVoltage, SIGNAL("valueChanged(double)"), self.vppLayoutChanged) self.connect(self.oscPin, SIGNAL("currentIndexChanged(int)"), self.oscChanged) self.connect(self.oscDiv, SIGNAL("valueChanged(int)"), self.oscChanged) self.gndLayoutChanged() self.vccxLayoutChanged() self.inputPollChanged() self.oscChanged() def shutdown(self): self.inputPollTimer.stop() try: self.top.shutdownChip() except (TOPException), e: QMessageBox.critical(self, self.tr("TOP shutdown failed"), self.tr("Failed to shutdown TOP device:\n") +\ str(e)) def updateZifCheckboxes(self): blockedPins = [] # GND idx = self.gndLayout.currentIndex() lay = self.gndLayout.itemData(idx).toInt()[0] blockedPins.extend(self.top.gnd.ID2pinlist(lay)) # VCCX idx = self.vccxLayout.currentIndex() lay = self.vccxLayout.itemData(idx).toInt()[0] blockedPins.extend(self.top.vccx.ID2pinlist(lay)) # VPP for key in self.vppLayouts.keys(): if self.vppLayouts[key].checkState() == Qt.Checked: blockedPins.extend(self.top.vpp.ID2pinlist(key)) # OSC idx = self.oscPin.currentIndex() mask = self.oscPin.itemData(idx).toInt()[0] for i in range(0, self.zifWidget.nrPins): if mask & (1 << i): blockedPins.append(i + 1) self.zifWidget.setBlockedPins(blockedPins) def gndLayoutChanged(self, unused=None): idx = self.gndLayout.currentIndex() selLayout = self.gndLayout.itemData(idx).toInt()[0] try: self.top.chip.setGND(selLayout) except (TOPException), e: QMessageBox.critical(self, self.tr("TOP communication failed"), self.tr("Failed to set GND layout:\n") +\ str(e)) return self.updateZifCheckboxes() def vccxLayoutChanged(self, unused=None): selVoltage = self.vccxVoltage.value() idx = self.vccxLayout.currentIndex() selLayout = self.vccxLayout.itemData(idx).toInt()[0] try: self.top.chip.setVCCX(selVoltage, selLayout) except (TOPException), e: QMessageBox.critical(self, self.tr("TOP communication failed"), self.tr("Failed to set VCCX layout:\n") +\ str(e)) return self.updateZifCheckboxes() def vppLayoutChanged(self, unused=None): selVoltage = self.vppVoltage.value() selLayouts = [] for key in self.vppLayouts.keys(): if self.vppLayouts[key].checkState() == Qt.Checked: selLayouts.append(key) try: self.top.chip.setVPP(selVoltage, selLayouts) except (TOPException), e: QMessageBox.critical(self, self.tr("TOP communication failed"), self.tr("Failed to set VPP layout:\n") +\ str(e)) return self.updateZifCheckboxes() def doInputPollTimer(self): if not self.zifWidget.readInputs(): # Whoops, error. Disable input polling self.inputPollEn.setCheckState(Qt.Unchecked) def inputPollChanged(self, unused=None): if self.inputPollEn.checkState() == Qt.Checked: self.inputPollInterval.setEnabled(True) self.doInputPollTimer() inter = int(self.inputPollInterval.value() * 1000) self.inputPollTimer.start(inter) else: self.inputPollInterval.setEnabled(False) self.inputPollTimer.stop() def oscChanged(self, unused=None): try: div = self.oscDiv.value() self.top.chip.setOscDivider(div) idx = self.oscPin.currentIndex() mask = self.oscPin.itemData(idx).toInt()[0] self.top.chip.setOscMask(mask) except (TOPException), e: QMessageBox.critical(self, self.tr("TOP communication failed"), self.tr("Failed configure oscillator:\n") +\ str(e)) return self.oscFreq.setText("%.03f Hz" % (24000000.0 / div)) self.updateZifCheckboxes() class MainWindow(QMainWindow): def __init__(self, parent=None): QMainWindow.__init__(self, parent) self.setWindowTitle(self.tr("Toprammer - Universal tester")) self.setCentralWidget(MainWidget(self)) self.setMenuBar(QMenuBar(self)) menu = QMenu(self.tr("Unitest"), self) menu.addAction(self.tr("Load settings..."), self.loadSettings) menu.addAction(self.tr("Save settings..."), self.saveSettings) menu.addSeparator() menu.addAction(self.tr("Raw command..."), self.sendRawCommand) menu.addSeparator() menu.addAction(self.tr("Exit"), self.close) self.menuBar().addMenu(menu) self.prevRawCommand = "" def closeEvent(self, ev): self.centralWidget().shutdown() def loadSettings(self): pass#TODO def saveSettings(self): pass#TODO def sendRawCommand(self): (string, ok) = QInputDialog.getText(self, self.tr("Send raw command"), self.tr("Enter raw command to send.\n" +\ "Hex format AABB1122..."), QLineEdit.Normal, self.prevRawCommand) if not ok: return string = str(string).strip().upper() string = stringRemoveChars(string, " \t\r\n") if stringRemoveChars(string, "0123456789ABCDEF"): QMessageBox.critical(self, self.tr("Invalid characters"), self.tr("Invalid characters in raw command string.\n" +\ "Only hex characters 0-9,a-f allowed.")) return if len(string) % 2 != 0 or len(string) // 2 > 64: QMessageBox.critical(self, self.tr("Invalid length"), self.tr("Invalid command length. Length must be even " +\ "and smaller or equal to 64 bytes.")) return self.prevRawCommand = string command = "" for i in range(0, len(string), 2): byteString = string[i:i+2] command += chr(int(byteString, 16)) assert(len(command) == len(string) // 2) try: top = self.centralWidget().top top.queueCommand(command) top.flushCommands() except (TOPException), e: QMessageBox.critical(self, self.tr("Raw command failed"), self.tr("Failed to send raw command:\n") + str(e)) return self.centralWidget().doInputPollTimer() def main(argv): try: app = QApplication(argv) mainwnd = MainWindow() mainwnd.show() return app.exec_() except (TOPException), e: print e return 1 if __name__ == "__main__": sys.exit(main(sys.argv))