def __init__(self, settings, globalDict, parent=None, *args): QtCore.QAbstractTableModel.__init__(self, parent, *args) self.settings = settings self.globalDict = globalDict self.defaultBG = QtGui.QColor(QtCore.Qt.white) self.textBG = QtGui.QColor(QtCore.Qt.green).lighter(175) self.column = enum('variable', 'value') self.defaultFontName = "Segoe UI" self.defaultFontSize = 9 self.normalFont = QtGui.QFont(self.defaultFontName, self.defaultFontSize, QtGui.QFont.Normal) self.boldFont = QtGui.QFont(self.defaultFontName, self.defaultFontSize, QtGui.QFont.Bold) self.dataLookup = { (QtCore.Qt.DisplayRole, self.column.variable): lambda row: self.settings.varDict.keyAt(row), (QtCore.Qt.DisplayRole, self.column.value): lambda row: str(self.settings.varDict.at(row)['value']), (QtCore.Qt.FontRole, self.column.variable): lambda row: self.boldFont if self.settings.varDict.keyAt(row).startswith('Duration') else self.normalFont, (QtCore.Qt.FontRole, self.column.value): lambda row: self.boldFont if self.settings.varDict.keyAt(row).startswith('Duration') else self.normalFont, (QtCore.Qt.EditRole, self.column.value): lambda row: firstNotNone( self.settings.varDict.at(row)['text'], str(self.settings.varDict.at(row)['value'])), (QtCore.Qt.BackgroundColorRole, self.column.value): lambda row: self.defaultBG if self.settings.varDict.at(row)['text'] is None else self.textBG, (QtCore.Qt.ToolTipRole, self.column.value): lambda row: self.settings.varDict.at(row)['text'] if self.settings.varDict.at(row)['text'] else None } self.setDataLookup = { (QtCore.Qt.EditRole, self.column.value): self.setValue, (QtCore.Qt.UserRole, self.column.value): self.setText }
def __init__(self, parent=None, parameterDict=None): super(ParameterTableModel, self).__init__(parent) self.parameterDict = parameterDict if parameterDict else SequenceDict() self.column = enum('name', 'value') self.textBG = QtGui.QColor(QtCore.Qt.green).lighter(175) self.dataLookup = { (QtCore.Qt.DisplayRole, self.column.name): lambda param: param.name if param.dataType != 'action' else None, (QtCore.Qt.DisplayRole, self.column.value): lambda param: (str(param.value) if param.dataType != 'multiselect' else ' | '.join(param.value)) if param.dataType != 'bool' else None, (QtCore.Qt.EditRole, self.column.value): lambda param: firstNotNone(param.text, param.value), (QtCore.Qt.ToolTipRole, self.column.name): lambda param: param.tooltip, (QtCore.Qt.ToolTipRole, self.column.value): lambda param: firstNotNone(param.text, param.tooltip), (QtCore.Qt.CheckStateRole, self.column.value): lambda param: (QtCore.Qt.Checked if param.value else QtCore.Qt.Unchecked) if param.dataType == 'bool' else None, (QtCore.Qt.BackgroundColorRole, self.column.value): lambda param: self.textBG if param.text else None } self.setDataLookup = { (QtCore.Qt.EditRole, self.column.value): self.setValue, (QtCore.Qt.UserRole, self.column.value): self.setText, (QtCore.Qt.CheckStateRole, self.column.value): self.setValue }
def __init__(self, config, _globalDict_, parent=None): super(GlobalVariablesModel, self).__init__(list(_globalDict_.values()), parent) self.config = config self._globalDict_ = _globalDict_ self.columnNames = ['name', 'value'] self.numColumns = len(self.columnNames) self.column = enum(*self.columnNames) self.headerLookup.update({ (QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole, self.column.name): "Name", (QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole, self.column.value): "Value" }) self.dataLookup.update({ (QtCore.Qt.DisplayRole, self.column.name): lambda node: node.content.name, (QtCore.Qt.DisplayRole, self.column.value): lambda node: format(node.content.value), (QtCore.Qt.EditRole, self.column.name): lambda node: node.content.name, (QtCore.Qt.EditRole, self.column.value): lambda node: format(node.content.value) }) self.setDataLookup.update({ (QtCore.Qt.EditRole, self.column.name): self.setName, (QtCore.Qt.EditRole, self.column.value): self.setValue }) self.flagsLookup = { self.column.name: QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled, self.column.value: QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled } self.allowReordering = True self.allowDeletion = True self.showGrid = True self.connectAllVariableSignals()
class EvaluationDefinition(object): AbszisseType = enum('x', 'time', 'index') def __init__(self): self.counter = None self.evaluation = None self.settings = HashableDict() self.name = None self.plotname = None self.settingsCache = HashableDict() self.showHistogram = False self.analysis = None self.counterId = 0 self.type = 'Counter' self.abszisse = AbszisseType.x def __setstate__(self, state): self.__dict__ = state if 'errorBars' in self.settings: # remove errorBars property in old unpickled instances self.settings.pop('errorBars') self.__dict__.setdefault('analysis', None) self.__dict__.setdefault('counterId', 0) self.__dict__.setdefault('type', 'Counter') self.__dict__.setdefault('abszisse', AbszisseType.x) stateFields = [ 'counterId', 'type', 'counter', 'evaluation', 'settings', 'settingsCache', 'name', 'plotname', 'showHistogram', 'analysis', 'abszisse' ] def __eq__(self, other): return isinstance(other, self.__class__) and tuple( getattr(self, field) for field in self.stateFields) == tuple( getattr(other, field) for field in self.stateFields) def __ne__(self, other): return not self == other def __hash__(self): if not isinstance(self.settings, HashableDict): logging.getLogger(__name__).info( "Replacing dict with hashable dict") self.settings = HashableDict(self.settings) return hash(tuple(getattr(self, field) for field in self.stateFields)) @property def channelKey(self): if self.type == 'Counter': return ((self.counterId & 0xff) << 8) | (self.counter & 0xff) else: return (self.counter & 0xff) def getChannelData(self, data): if self.type == 'Counter': return data.count[self.channelKey] elif data.result is not None: return data.result[self.channelKey] return []
class FeedbackEvaluation(EvaluationBase): name = 'Feedback' tooltip = "Slow feedback on external parameter" sourceType = enum('Counter','Result') def __init__(self, globalDict=None, settings=None): EvaluationBase.__init__(self, globalDict, settings) self.integrator = None self.lastUpdate = None def setDefault(self): self.settings.setdefault('SetPoint', Q(0)) self.settings.setdefault('P', Q(0)) self.settings.setdefault('I', Q(0)) self.settings.setdefault('AveragingTime', Q(10, 's')) self.settings.setdefault('GlobalVariable', "") self.settings.setdefault('Reset', False) def __setstate__(self, state): self.__dict__ = state def evaluateMinMax(self, countarray): mean = numpy.mean( countarray ) return mean, (mean-numpy.min(countarray), numpy.max(countarray)-mean), numpy.sum(countarray) def evaluate(self, data, evaluation, expected=None, ppDict=None, globalDict=None): countarray = evaluation.getChannelData(data) globalName = self.settings['GlobalVariable'] if not countarray: return 2, (0,0), 0 if not globalDict or globalName not in globalDict: return 1, (0,0), 0 if self.integrator is None or self.settings['Reset']: self.integrator = globalDict[globalName] self.settings['Reset'] = False mean, (_, _), raw = self.evaluateMinMax(countarray) errorval = self.settings['SetPoint'].value - mean pOut = self.settings['P'] * errorval self.integrator = self.integrator + errorval * self.settings['I'] totalOut = pOut + self.integrator globalDict[globalName] = totalOut return float(totalOut), (0.0, 0.0), raw def parameters(self): parameterDict = super(FeedbackEvaluation, self).parameters() if isinstance(self.settings['SetPoint'], ExpressionValue): self.settings['SetPoint'] = self.settings['SetPoint'].value tooltipLookup = SequenceDict([ ('SetPoint', 'Set point of PI loop'), ('P', 'Proportional gain'), ('I', 'Integral gain'), ('AveragingTime', 'Time spent accumulating data before updating the servo output') ]) for name, tooltip in tooltipLookup.items(): parameterDict[name] = Parameter(name=name, dataType='magnitude', value=self.settings[name], text=self.settings.get( (name, 'text') ), tooltip=tooltip) parameterDict['GlobalVariable'] = Parameter(name='GlobalVariable', dataType='select', value=self.settings['GlobalVariable'], choices=sorted(self.globalDict.keys()), tooltip="Name of variable to which servo output value should be pushed") parameterDict['Reset'] = Parameter(name='Reset', dataType='bool', value=self.settings['Reset'], tooltip="Reset integrator") return parameterDict
class Settings(object): """Settings associated with AWGUi. Each entry in the settings menu has a corresponding Settings object. Attributes: deviceSettings(dict): dynamic settings of the device, controlled by the parameterTable. Elements are defined in the device's 'parameters' method channelSettingsList (list of dicts): each element corresponds to a channel of the AWG. Each element is a dict, with keys that determine the channel's setting (e.g. 'plotEnabled', etc.) filename (str): the filename from which to save/load AWG segment data varDict (SequenceDict): the list of variables which determine the AWG waveform saveIfNecessary (function): the AWGUi's function that save's the settings replot (function): the AWGUi's function that replots all waveforms Note that "deviceProperties" are fixed settings of an AWG device, while "deviceSettings" are settings that can be changed on the fly. """ plotStyles = enum('lines', 'points', 'linespoints') saveIfNecessary = None replot = None deviceProperties = dict() stateFields = { 'channelSettingsList': list(), 'deviceSettings': dict(), 'filename': '', 'varDict': SequenceDict(), 'cacheDepth': 0 } def __init__(self): [ setattr(self, field, copy.copy(fieldDefault)) for field, fieldDefault in list(self.stateFields.items()) ] def __setstate__(self, state): self.__dict__ = state def __eq__(self, other): return isinstance(other, self.__class__) and tuple( getattr(self, field, None) for field in list(self.stateFields.keys())) == tuple( getattr(other, field, None) for field in list(self.stateFields.keys())) def __ne__(self, other): return not self == other def update(self, other): [ setattr(self, field, getattr(other, field)) for field in list(self.stateFields.keys()) if hasattr(other, field) ]
class NumberEvaluation(EvaluationBase): name = 'Number' tooltip = "Number of results" sourceType = enum('Counter','Result') def __init__(self, globalDict=None, settings=None): EvaluationBase.__init__(self, globalDict, settings) def evaluate(self, data, evaluation, expected=None, ppDict=None, globalDict=None): countarray = evaluation.getChannelData(data) if not countarray: return 0, None, 0 return len(countarray), None, len(countarray)
def __init__(self, parent=None, parameterDict=None): super(ParameterTableModel, self).__init__(parent) self.parameterDict = parameterDict if parameterDict else SequenceDict() self.column = enum('name', 'value') self.textBG = QtGui.QColor(QtCore.Qt.green).lighter(175) self.dataLookup = { (QtCore.Qt.DisplayRole, self.column.name): lambda param: param.name if param.dataType!='action' else None, (QtCore.Qt.DisplayRole, self.column.value): lambda param: (str(param.value) if param.dataType!='multiselect' else ' | '.join(param.value)) if param.dataType!='bool' else None, (QtCore.Qt.EditRole, self.column.value): lambda param: firstNotNone(param.text, param.value), (QtCore.Qt.ToolTipRole, self.column.name): lambda param: param.tooltip, (QtCore.Qt.ToolTipRole, self.column.value): lambda param: firstNotNone(param.text, param.tooltip), (QtCore.Qt.CheckStateRole, self.column.value): lambda param: (QtCore.Qt.Checked if param.value else QtCore.Qt.Unchecked) if param.dataType=='bool' else None, (QtCore.Qt.BackgroundColorRole, self.column.value): lambda param: self.textBG if param.text else None } self.setDataLookup = { (QtCore.Qt.EditRole, self.column.value): self.setValue, (QtCore.Qt.UserRole, self.column.value): self.setText, (QtCore.Qt.CheckStateRole, self.column.value): self.setValue }
def __init__(self, config, _globalDict_, parent=None): super(GlobalVariablesModel, self).__init__(list(_globalDict_.values()), parent) self.config = config self._globalDict_ = _globalDict_ self.columnNames = ['name', 'value'] self.numColumns = len(self.columnNames) self.column = enum(*self.columnNames) self.headerLookup.update({ (QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole, self.column.name): "Name", (QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole, self.column.value): "Value" }) self.dataLookup.update({ (QtCore.Qt.DisplayRole, self.column.name): lambda node: node.content.name, (QtCore.Qt.DisplayRole, self.column.value): lambda node: node.content.value.__format__("~"), (QtCore.Qt.EditRole, self.column.name): lambda node: node.content.name, (QtCore.Qt.EditRole, self.column.value): lambda node: node.content.value.__format__("~") }) self.setDataLookup.update({ (QtCore.Qt.EditRole, self.column.name): self.setName, (QtCore.Qt.EditRole, self.column.value): self.setValue }) self.flagsLookup = { self.column.name: QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled, self.column.value: QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled } self.allowReordering = True self.allowDeletion = True self.showGrid = True self.connectAllVariableSignals()
def __init__(self, channel, settings, globalDict, parent=None, *args): QtCore.QAbstractTableModel.__init__(self, parent, *args) self.channel = channel self.settings = settings self.globalDict = globalDict self.column = enum('enabled', 'amplitude', 'duration') self.dataLookup = { (QtCore.Qt.CheckStateRole, self.column.enabled): lambda row: QtCore.Qt.Checked if self.segmentList[row]['enabled'] else QtCore.Qt.Unchecked, (QtCore.Qt.DisplayRole, self.column.amplitude): lambda row: self.segmentList[row]['amplitude'], (QtCore.Qt.DisplayRole, self.column.duration): lambda row: self.segmentList[row]['duration'], (QtCore.Qt.EditRole, self.column.amplitude): lambda row: self.segmentList[row]['amplitude'], (QtCore.Qt.EditRole, self.column.duration): lambda row: self.segmentList[row]['duration'] } self.setDataLookup = { (QtCore.Qt.CheckStateRole, self.column.enabled): lambda index, value: self.setEnabled(index, value), (QtCore.Qt.EditRole, self.column.amplitude): lambda index, value: self.setValue(index, value, 'amplitude'), (QtCore.Qt.EditRole, self.column.duration): lambda index, value: self.setValue(index, value, 'duration') } self.flagsLookup = { self.column.enabled: QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsSelectable, self.column.amplitude: QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsSelectable, self.column.duration: QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsSelectable }
def __init__(self, channel, settings, globalDict, parent=None, *args): QtCore.QAbstractTableModel.__init__(self, parent, *args) self.channel = channel self.settings = settings self.globalDict = globalDict self.column = enum('enabled', 'amplitude', 'duration') self.dataLookup = { (QtCore.Qt.CheckStateRole, self.column.enabled): lambda row: QtCore.Qt.Checked if self.segmentList[row]['enabled'] else QtCore.Qt.Unchecked, (QtCore.Qt.DisplayRole, self.column.amplitude): lambda row: self.segmentList[row]['amplitude'], (QtCore.Qt.DisplayRole, self.column.duration): lambda row: self.segmentList[row]['duration'], (QtCore.Qt.EditRole, self.column.amplitude): lambda row: self.segmentList[row]['amplitude'], (QtCore.Qt.EditRole, self.column.duration): lambda row: self.segmentList[row]['duration'] } self.setDataLookup = { (QtCore.Qt.CheckStateRole, self.column.enabled): lambda index, value: self.setEnabled(index, value), (QtCore.Qt.EditRole, self.column.amplitude): lambda index, value: self.setValue(index, value, 'amplitude'), (QtCore.Qt.EditRole, self.column.duration): lambda index, value: self.setValue(index, value, 'duration') } self.flagsLookup = { self.column.enabled: QtCore.Qt.ItemIsEnabled| QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsSelectable, self.column.amplitude: QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsSelectable, self.column.duration: QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsSelectable }
def __init__(self, channel, settings, globalDict, parent=None): super(AWGSegmentModel, self).__init__(parent) self.channel = channel self.settings = settings self.globalDict = globalDict self.root = self.settings.channelSettingsList[self.channel]['segmentDataRoot'] self.columnNames = ['enabled', 'equation', 'duration', 'repetitions'] self.numColumns = len(self.columnNames) self.column = enum(*self.columnNames) self.allowDeletion=True segmentSetBG = QtGui.QColor(255, 253, 222, 255) self.headerLookup = { (QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole, self.column.enabled): "", (QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole, self.column.equation): "Equation", (QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole, self.column.duration): "Duration", (QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole, self.column.repetitions): "Repetitions" } self.dataLookup = { (QtCore.Qt.CheckStateRole,self.column.enabled): lambda node: QtCore.Qt.Checked if node.enabled else QtCore.Qt.Unchecked, (QtCore.Qt.DisplayRole, self.column.equation): lambda node: node.equation if node.nodeType==nodeTypes.segment else None, (QtCore.Qt.DisplayRole, self.column.duration): lambda node: node.duration if node.nodeType==nodeTypes.segment else None, (QtCore.Qt.DisplayRole, self.column.repetitions): lambda node: node.repetitions if node.nodeType==nodeTypes.segmentSet else None, (QtCore.Qt.BackgroundColorRole, self.column.enabled): lambda node: segmentSetBG if node.nodeType==nodeTypes.segmentSet else None, (QtCore.Qt.BackgroundColorRole, self.column.equation): lambda node: segmentSetBG if node.nodeType==nodeTypes.segmentSet else None, (QtCore.Qt.BackgroundColorRole, self.column.duration): lambda node: segmentSetBG if node.nodeType==nodeTypes.segmentSet else None, (QtCore.Qt.BackgroundColorRole, self.column.repetitions): lambda node: segmentSetBG if node.nodeType==nodeTypes.segmentSet else None, (QtCore.Qt.EditRole, self.column.equation): lambda node: node.equation if node.nodeType==nodeTypes.segment else None, (QtCore.Qt.EditRole, self.column.duration): lambda node: node.duration if node.nodeType==nodeTypes.segment else None, (QtCore.Qt.EditRole, self.column.repetitions): lambda node: node.repetitions if node.nodeType==nodeTypes.segmentSet else None } self.setDataLookup = { (QtCore.Qt.CheckStateRole, self.column.enabled): lambda index, value: self.setEnabled(index, value), (QtCore.Qt.EditRole, self.column.equation): lambda index, value: self.setValue(index, value, 'equation'), (QtCore.Qt.EditRole, self.column.duration): lambda index, value: self.setValue(index, value, 'duration'), (QtCore.Qt.EditRole, self.column.repetitions): lambda index, value: self.setValue(index, value, 'repetitions'), }
class TracePlotting(object): Types = enum('default','steps') def __init__(self, xColumn='x',yColumn='y',topColumn=None,bottomColumn=None,heightColumn=None, rawColumn=None,name="",type_ =None, xAxisUnit=None, xAxisLabel=None, windowName=None ): self.xColumn = xColumn self.yColumn = yColumn self.topColumn = topColumn self.bottomColumn = bottomColumn self.heightColumn = heightColumn self.rawColumn = rawColumn self.fitFunction = None self.name = name self.xAxisUnit = xAxisUnit self.xAxisLabel = xAxisLabel self.type = TracePlotting.Types.default if type_ is None else type_ self.windowName = windowName def __setstate__(self, d): self.__dict__ = d self.__dict__.setdefault( 'xAxisUnit', None ) self.__dict__.setdefault( 'xAxisLabel', None ) self.__dict__.setdefault( 'windowName', None) attrFields = ['xColumn','yColumn','topColumn', 'bottomColumn','heightColumn', 'name', 'type', 'xAxisUnit', 'xAxisLabel', 'windowName']
class MeasurementTableModel(QtCore.QAbstractTableModel): valueChanged = QtCore.pyqtSignal(object) headerDataLookup = ['Plot', 'Study', 'Scan', 'Name', 'Evaluation', 'Target', 'Parameter', 'Pulse Program', 'Started', 'Comment', 'Filename' ] column = enum('plot', 'study', 'scan', 'name', 'evaluation', 'target', 'parameter', 'pulseprogram', 'started', 'comment', 'filename') coreColumnCount = 11 measurementModelDataChanged = QtCore.pyqtSignal(str, str, str) #string with trace creation date, change type, new value def __init__(self, measurements, extraColumns, traceuiLookup, container=None, parent=None, *args): QtCore.QAbstractTableModel.__init__(self, parent, *args) self.container = container self.extraColumns = extraColumns # list of tuples (source, space, name) # measurements are given as a list self.measurements = measurements self.flagsLookup = { self.column.plot: QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled, self.column.comment: QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled, } self.failedBG = QtGui.QColor(0xff, 0xa6, 0xa6, 0xff) self.defaultBG = QtGui.QColor(QtCore.Qt.white) self.dataLookup = { (QtCore.Qt.CheckStateRole, self.column.plot): lambda row: self.isPlotted(self.measurements[row]), (QtCore.Qt.DisplayRole, self.column.study): lambda row: self.measurements[row].study, (QtCore.Qt.DisplayRole, self.column.scan): lambda row: self.measurements[row].scanType, (QtCore.Qt.DisplayRole, self.column.name): lambda row: self.measurements[row].scanName, (QtCore.Qt.DisplayRole, self.column.evaluation): lambda row: self.measurements[row].evaluation, (QtCore.Qt.DisplayRole, self.column.target): lambda row: self.measurements[row].scanTarget, (QtCore.Qt.DisplayRole, self.column.parameter): lambda row: self.measurements[row].scanParameter, (QtCore.Qt.DisplayRole, self.column.pulseprogram): lambda row: self.measurements[row].scanPP, (QtCore.Qt.DisplayRole, self.column.started): lambda row: self.measurements[row].startDate.astimezone(tzlocal()).strftime('%Y-%m-%d %H:%M:%S'), (QtCore.Qt.DisplayRole, self.column.comment): lambda row: self.measurements[row].comment, (QtCore.Qt.DisplayRole, self.column.filename): self.getFilename, (QtCore.Qt.EditRole, self.column.comment): lambda row: self.measurements[row].comment, (QtCore.Qt.BackgroundColorRole, self.column.plot): lambda row: self.defaultBG if self.measurements[row].failedAnalysis is None else self.failedBG, (QtCore.Qt.BackgroundColorRole, self.column.study): lambda row: self.defaultBG if self.measurements[row].failedAnalysis is None else self.failedBG, (QtCore.Qt.BackgroundColorRole, self.column.scan): lambda row: self.defaultBG if self.measurements[row].failedAnalysis is None else self.failedBG, (QtCore.Qt.BackgroundColorRole, self.column.name): lambda row: self.defaultBG if self.measurements[row].failedAnalysis is None else self.failedBG, (QtCore.Qt.BackgroundColorRole, self.column.evaluation): lambda row: self.defaultBG if self.measurements[row].failedAnalysis is None else self.failedBG, (QtCore.Qt.BackgroundColorRole, self.column.target): lambda row: self.defaultBG if self.measurements[row].failedAnalysis is None else self.failedBG, (QtCore.Qt.BackgroundColorRole, self.column.parameter): lambda row: self.defaultBG if self.measurements[row].failedAnalysis is None else self.failedBG, (QtCore.Qt.BackgroundColorRole, self.column.pulseprogram): lambda row: self.defaultBG if self.measurements[row].failedAnalysis is None else self.failedBG, (QtCore.Qt.BackgroundColorRole, self.column.started): lambda row: self.defaultBG if self.measurements[row].failedAnalysis is None else self.failedBG, (QtCore.Qt.BackgroundColorRole, self.column.comment): lambda row: self.defaultBG if self.measurements[row].failedAnalysis is None else self.failedBG, (QtCore.Qt.BackgroundColorRole, self.column.filename): lambda row: self.defaultBG if self.measurements[row].failedAnalysis is None else self.failedBG } self.setDataLookup = { (QtCore.Qt.CheckStateRole, self.column.plot): self.setPlotted, (QtCore.Qt.EditRole, self.column.comment): self.setComment } self.traceuiLookup = traceuiLookup def getFilename(self, row): filename = self.measurements[row].filename if filename is None: return None return os.path.split(filename)[1] @QtCore.pyqtSlot(str, str, str) def onTraceModelDataChanged(self, traceCreation, changeType, data): """Trace data changed via traceui. Update model.""" traceCreation = str(traceCreation) changeType = str(changeType) data=str(data) measurement = self.container.measurementDict.get(traceCreation) row = self.measurements.index(measurement) if measurement in self.measurements else -1 if row >= 0: if changeType=='comment': self.setComment(row, data) self.dataChanged.emit(self.index(row, self.column.comment), self.index(row, self.column.comment)) elif changeType=='isPlotted': self.dataChanged.emit(self.index(row, self.column.plot), self.index(row, self.column.plot)) elif changeType=='filename': self.setFilename(row, data) self.dataChanged.emit(self.index(row, self.column.filename), self.index(row, self.column.filename)) @QtCore.pyqtSlot(str) def onTraceRemoved(self, traceCreation): """If the signal that a trace was removed is received, remove it from the measurement dict""" traceCreation = str(traceCreation) measurement = self.container.measurementDict.get(traceCreation) row = self.measurements.index(measurement) if measurement in self.measurements else -1 if measurement: self.container.measurementDict.pop(traceCreation) if row >= 0: self.measurements[row].plottedTraceList = [] self.dataChanged.emit(self.index(row, self.column.plot), self.index(row, self.column.plot)) def addColumn(self, extraColumn ): self.beginInsertColumns( QtCore.QModelIndex(), self.coreColumnCount+len(self.extraColumns), self.coreColumnCount+len(self.extraColumns)) self.extraColumns.append( extraColumn ) self.endInsertColumns() def removeColumn(self, columnIndex): self.beginRemoveColumns( QtCore.QModelIndex(), columnIndex, columnIndex ) self.extraColumns.pop( columnIndex-self.coreColumnCount ) self.endRemoveColumns() def isPlotted(self, measurement): count = 0 plottedTraceList = measurement.plottedTraceList total = len(plottedTraceList) for pt in plottedTraceList: if pt.isPlotted: count += 1 if total==0 or count==0: return QtCore.Qt.Unchecked if count < total: return QtCore.Qt.PartiallyChecked return QtCore.Qt.Checked def setPlotted(self, row, value): measurement = self.measurements[row] plotted = value == QtCore.Qt.Checked if not plotted: for pt in measurement.plottedTraceList: pt.plot(0) else: plottedTraceList = measurement.plottedTraceList if len(plottedTraceList)>0: for pt in plottedTraceList: pt.plot(-1) else: if measurement.filename is not None and exists(measurement.filename): self.loadTrace(measurement) self.container.measurementDict[str(measurement.startDate.astimezone(pytz.utc))] = measurement self.measurementModelDataChanged.emit(str(measurement.startDate.astimezone(pytz.utc)), 'isPlotted', '') return True def loadTrace(self, measurement): measurement.plottedTraceList = self.traceuiLookup[measurement.scanType].openFile(measurement.filename) def setComment(self, row, comment): """Set the comment at the specified row""" measurement = self.measurements[row] if measurement.comment != comment: measurement.comment = comment measurement._sa_instance_state.session.commit() self.measurementModelDataChanged.emit(str(measurement.startDate.astimezone(pytz.utc)), 'comment', comment) return True else: return False def setFilename(self, row, filename): """Set the filename at the specified row""" measurement = self.measurements[row] if measurement.filename != filename: measurement.filename = filename measurement._sa_instance_state.session.commit() return True else: return False def beginInsertRows(self, event): self.firstAdded = event.first self.lastAdded = event.last return QtCore.QAbstractTableModel.beginInsertRows(self, QtCore.QModelIndex(), event.first, event.last ) def endInsertRows(self): return QtCore.QAbstractTableModel.endInsertRows(self) def rowCount(self, parent=QtCore.QModelIndex()): return len(self.measurements) def columnCount(self, parent=QtCore.QModelIndex()): return self.coreColumnCount + len(self.extraColumns) def data(self, index, role): if index.isValid(): if index.column()<self.coreColumnCount: return self.dataLookup.get((role, index.column()), lambda row: None)(index.row()) else: source, space, name = self.extraColumns[index.column()-self.coreColumnCount] if source=='parameter': param = self.measurements[index.row()].parameterByName(space, name) value = param.value if param is not None else None elif source=='result': result = self.measurements[index.row()].resultByName(name) value = result.value if result is not None else None if role==QtCore.Qt.DisplayRole: return str(value) if value is not None else None elif role==QtCore.Qt.EditRole: return value return None def setData(self, index, value, role): return self.setDataLookup.get((role, index.column()), lambda row, value: False)(index.row(), value) def flags(self, index): return self.flagsLookup.get( index.column(), QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled ) def headerData(self, section, orientation, role): if (role == QtCore.Qt.DisplayRole): if (orientation == QtCore.Qt.Horizontal): return self.headerDataLookup[section] if section<self.coreColumnCount else self.extraColumns[section-self.coreColumnCount][2] elif (orientation == QtCore.Qt.Vertical): return self.measurements[section].id return None # QtCore.QVariant() def sort(self, column, order): if column == 0 and self.variables: self.measurements.sort(reverse=order == QtCore.Qt.DescendingOrder) self.dataChanged.emit(self.index(0, 0), self.index(len(self.variables) - 1, 1)) def setMeasurements(self, event): self.beginResetModel() self.measurements = event.measurements self.endResetModel()
# ***************************************************************** # IonControl: Copyright 2016 Sandia Corporation # This Software is released under the GPL license detailed # in the file "license.txt" in the top-level IonControl directory # ***************************************************************** import logging import random import numpy from modules import DataDirectory from modules import enum from modules.Expression import Expression from modules.quantity import is_Q, Q OpStates = enum.enum('idle', 'running', 'paused', 'starting', 'stopping', 'interrupted') NoneScanCode = [4095, 0] # TODO: should use the pulserconfiguration dataMemorySize MaxWordsInFifo = 2040 class ParameterScanGenerator: expression = Expression() def __init__(self, scan): self.scan = scan self.nextIndexToWrite = 0 self.numUpdatedVariables = 1 def prepare(self, pulseProgramUi, maxUpdatesToWrite=None): self.maxUpdatesToWrite = maxUpdatesToWrite if self.scan.gateSequenceUi.settings.enabled: _, data, self.gateSequenceSettings = self.scan.gateSequenceUi.gateSequenceScanData()
class PulserHardwareServer(Process, OKBase): timestep = Q(5, 'ns') integrationTimestep = Q(20, 'ns') dedicatedDataClass = DedicatedData def __init__(self, dataQueue=None, commandPipe=None, loggingQueue=None, sharedMemoryArray=None): Process.__init__(self) OKBase.__init__(self) self.dataQueue = dataQueue self.commandPipe = commandPipe self.running = True self.loggingQueue = loggingQueue self.sharedMemoryArray = sharedMemoryArray # PipeReader stuff self.state = self.analyzingState.normal self.data = Data() self.dedicatedData = self.dedicatedDataClass(time_time()) self.timestampOffset = 0 self._shutter = 0 self._trigger = 0 self._counterMask = 0 self._adcMask = 0 self._integrationTime = Q(100, 'ms') self.logicAnalyzerEnabled = False self.logicAnalyzerStopAtEnd = False self.logicAnalyzerData = LogicAnalyzerData() self.logicAnalyzerBuffer = bytearray() self.logicAnalyzerReadStatus = 0 # self._pulserConfiguration = None def run(self): try: configureServerLogging(self.loggingQueue) logger = logging.getLogger(__name__) while (self.running): if self.commandPipe.poll(0.01): try: commandstring, argument = self.commandPipe.recv() command = getattr(self, commandstring) logger.debug( "PulserHardwareServer {0}".format(commandstring)) self.commandPipe.send(command(*argument)) except Exception as e: self.commandPipe.send(e) self.readDataFifo() self.dataQueue.put(FinishException()) logger.info("Pulser Hardware Server Process finished.") except Exception as e: logger.error( "Pulser Hardware Server Process exception {0}".format(e)) self.dataQueue.close() self.loggingQueue.put(None) self.loggingQueue.close() # self.loggingQueue.join_thread() def syncTime(self): if self.xem: self.xem.ActivateTriggerIn(0x40, 15) logging.getLogger(__name__).info("Time synchronized at {0}".format( time_time())) else: logging.getLogger(__name__).error( "No time synchronization because FPGA is not available") self.timeTickOffset = time_time() def finish(self): self.running = False return True analyzingState = enum.enum('normal', 'scanparameter', 'dependentscanparameter') def readDataFifo(self): """ run is responsible for reading the data back from the FPGA 0xffffffffffffffff end of experiment marker 0xfffexxxxxxxxxxxx exitcode marker 0xfffd000000000000 timestamping overflow marker 0xfffcxxxxxxxxxxxx scan parameter, followed by scanparameter value 0xfffb00000000xxxx timing was not met, xxxx address of update command whose timing could not be met 0x01ddnnxxxxxxxxxx count result from channel n id dd 0x02ddnnxxxxxxxxxx timestamp result channel n id dd 0x03ddnnxxxxxxxxxx timestamp gate start channel n id dd 0x04nnxxxxxxxxxxxx other return 0x05nnxxxxxxxxxxxx ADC return MSB 16 bits count, LSB 32 bits sum 0x06ddxxxxxxxxxxxx 0xeennxxxxxxxxxxxx dedicated result 0x50nn00000000xxxx result n return Hi 16 bits, only being sent if xxxx is not identical to zero 0x51nnxxxxxxxxxxxx result n return Low 48 bits, guaranteed to come first """ logger = logging.getLogger(__name__) if (self.logicAnalyzerEnabled): logicAnalyzerData, _ = self.ppReadLogicAnalyzerData(8) if self.logicAnalyzerOverrun: logger.warning("Logic Analyzer Pipe overrun") self.logicAnalyzerClearOverrun() self.logicAnalyzerData.overrun = True if logicAnalyzerData: self.logicAnalyzerBuffer.extend(logicAnalyzerData) for s in sliceview(self.logicAnalyzerBuffer, 8): if self.logicAnalyzerReadStatus == 0: (code, ) = struct.unpack('Q', s) self.logicAnalyzerData.wordcount += 1 self.logicAnalyzerTime = ( code & 0xffffff) + self.logicAnalyzerData.countOffset pattern = (code >> 24) & 0xffffffff header = (code >> 56) if header == 2: # overrun marker self.logicAnalyzerData.countOffset += 0x1000000 # overrun of 24 bit counter elif header == 1: # end marker self.logicAnalyzerData.stopMarker = self.logicAnalyzerTime self.dataQueue.put(self.logicAnalyzerData) self.logicAnalyzerData = LogicAnalyzerData() elif header == 4: # trigger self.logicAnalyzerReadStatus = 4 elif header == 3: # standard self.logicAnalyzerReadStatus = 3 elif header == 5: # aux data self.logicAnalyzerReadStatus = 5 elif header == 6: self.logicAnalyzerReadStatus = 6 logger.debug( "Time {0:x} header {1} pattern {2:x} {3:x} {4:x}". format(self.logicAnalyzerTime, header, pattern, code, self.logicAnalyzerData.countOffset)) elif self.logicAnalyzerReadStatus == 3: (pattern, ) = struct.unpack('Q', s) self.logicAnalyzerData.data.append( (self.logicAnalyzerTime, pattern)) self.logicAnalyzerReadStatus = 0 elif self.logicAnalyzerReadStatus == 4: (pattern, ) = struct.unpack('Q', s) self.logicAnalyzerData.trigger.append( (self.logicAnalyzerTime, pattern)) self.logicAnalyzerReadStatus = 0 elif self.logicAnalyzerReadStatus == 5: (pattern, ) = struct.unpack('Q', s) self.logicAnalyzerData.auxData.append( (self.logicAnalyzerTime, pattern)) self.logicAnalyzerReadStatus = 0 elif self.logicAnalyzerReadStatus == 6: (pattern, ) = struct.unpack('Q', s) self.logicAnalyzerData.gateData.append( (self.logicAnalyzerTime, pattern)) self.logicAnalyzerReadStatus = 0 self.logicAnalyzerBuffer = bytearray( sliceview_remainder(self.logicAnalyzerBuffer, 8)) data, self.data.overrun, self.data.externalStatus = self.ppReadData(8) self.dedicatedData.externalStatus = self.data.externalStatus self.dedicatedData.maxBytesRead = max(self.dedicatedData.maxBytesRead, len(data) if data else 0) if data: for s in sliceview(data, 8): (token, ) = struct.unpack('Q', s) #print(hex(token)) if self.state == self.analyzingState.dependentscanparameter: self.data.dependentValues.append(token) logger.debug("Dependent value {0} received".format(token)) self.state = self.analyzingState.normal elif self.state == self.analyzingState.scanparameter: logger.debug("Scan value {0} received".format(token)) if self.data.scanvalue is None: self.data.scanvalue = token else: self.data.timeTickOffset = self.timeTickOffset self.dataQueue.put(self.data) self.data = Data() self.data.scanvalue = token self.state = self.analyzingState.normal elif token & 0xff00000000000000 == 0xee00000000000000: # dedicated results try: channel = (token >> 48) & 0xff if self.dedicatedData.data[channel] is not None: self.dataQueue.put(self.dedicatedData) self.dedicatedData = self.dedicatedDataClass( self.timeTickOffset) if channel == 33: self.dedicatedData.data[channel] = ( token & 0xffffffffff) + self.timestampOffset else: self.dedicatedData.data[ channel] = token & 0xffffffffffff except IndexError: pass #logger.debug("dedicated {0} {1}".format(channel, token & 0xffffffffffff)) elif token & 0xff00000000000000 == 0xff00000000000000: if token == 0xffffffffffffffff: # end of run self.data.final = True self.data.exitcode = 0x0000 self.data.timeTickOffset = self.timeTickOffset self.dataQueue.put(self.data) logger.info("End of Run marker received") self.data = Data() elif token & 0xffff000000000000 == 0xfffe000000000000: # exitparameter self.data.final = True self.data.exitcode = token & 0x0000ffffffffffff logger.info("Exitcode {0:x} received".format( self.data.exitcode)) self.data.timeTickOffset = self.timeTickOffset self.dataQueue.put(self.data) self.data = Data() elif token == 0xfffd000000000000: self.timestampOffset += (1 << 40) elif token & 0xffff000000000000 == 0xfffc000000000000: # new scan parameter self.state = self.analyzingState.dependentscanparameter if ( token & 0x8000 == 0x8000) else self.analyzingState.scanparameter elif token & 0xffff000000000000 == 0xfffb000000000000: if self.data.timingViolations is None: self.data.timingViolations = list() self.data.timingViolations.append(token & 0xffff) else: key = token >> 56 #print("token", hex(token)) if key == 1: # count channel = (token >> 40) & 0xffff value = token & 0x000000ffffffffff (self.data.count[channel]).append(value) elif key == 2: # timestamp channel = (token >> 40) & 0xffff value = token & 0x000000ffffffffff if self.data.timestamp is None: self.data.timestamp = defaultdict(list) self.data.timestamp[channel][-1].append( self.timestampOffset + value - self.data.timestampZero[channel][-1]) elif key == 3: # timestamp gate start channel = (token >> 40) & 0xffff value = token & 0x000000ffffffffff if self.data.timestampZero is None: self.data.timestampZero = defaultdict(list) self.data.timestampZero[channel].append( self.timestampOffset + value) if self.data.timestamp is None: self.data.timestamp = defaultdict(list) self.data.timestamp[channel].append(list()) elif key == 4: # other return value channel = (token >> 40) & 0xffff value = token & 0x000000ffffffffff self.data.other.append(value) elif key == 5: # ADC return channel = (token >> 40) & 0xffff sumvalue = token & 0xfffffff count = (token >> 28) & 0xfff if count > 0: self.data.count[channel + 32].append(sumvalue / float(count)) elif key == 6: # clock timestamp self.data.timeTick[(token >> 40) & 0xff].append( self.timestampOffset + (token & 0xffffffffff)) elif key == 0x51: channel = (token >> 48) & 0xff value = token & 0x0000ffffffffffff if self.data.result is None: self.data.result = defaultdict(list) self.data.result[channel].append(value) elif key == 0x50: channel = (token >> 48) & 0xff value = token & 0x000000000000ffff self.data.result[channel][-1] |= (value << 48) # logger.debug("result key: {0} hi-low: {1} value: {2} length: {3} value: {4}".format(resultkey,channel,value&0xffff,len(self.data.result[resultkey]),self.data.result[resultkey][-1])) else: self.data.other.append(token) if self.data.overrun: logger.info("Overrun detected, triggered data queue") self.data.timeTickOffset = self.timeTickOffset self.dataQueue.put(self.data) self.data = Data() self.clearOverrun() def __getattr__(self, name): """delegate not available procedures to xem""" if name.startswith('__') and name.endswith('__'): return super(PulserHardwareServer, self).__getattr__(name) def wrapper(*args): if self.xem: return getattr(self.xem, name)(*args) return None setattr(self, name, wrapper) return wrapper def openBySerial(self, serial): super(PulserHardwareServer, self).openBySerial(serial) self.syncTime() def getShutter(self): return self._shutter # def setShutter(self, value): if self.xem: data = bytearray(struct.pack('=HQ', 0x10, value)) self.xem.WriteToPipeIn(0x84, data) self._shutter = value else: logging.getLogger(__name__).warning( "Pulser Hardware not available") return self._shutter def setShutterBit(self, bit, value): mask = 1 << bit newval = (self._shutter & (~mask)) | (mask if value else 0) return self.setShutter(newval) def getTrigger(self): return self._trigger def setExtendedWireIn(self, address, value): if self.xem: self.xem.WriteToPipeIn( 0x84, bytearray( struct.pack('=HQ' if value > 0 else '=Hq', address, value))) logging.getLogger(__name__).debug( "Writing Extended wire {0} value {1} {2}".format( address, value, hex(value))) else: logging.getLogger(__name__).warning( "Pulser Hardware not available") def setMultipleExtendedWireIn(self, items): if self.xem: writebuffer = bytearray() for address, value in items: writebuffer.extend( bytearray( struct.pack('=HQ' if value > 0 else '=Hq', address, value))) self.xem.WriteToPipeIn(0x84, writebuffer) logging.getLogger(__name__).debug( "Writing All Extended wire values") else: logging.getLogger(__name__).warning( "Pulser Hardware not available") def setTrigger(self, value): if self.xem: self.xem.WriteToPipeIn(0x84, bytearray(struct.pack('=HQ', 0x11, value))) self._trigger = value else: logging.getLogger(__name__).warning( "Pulser Hardware not available") return self._trigger def getCounterMask(self): return self._counterMask def setCounterMask(self, value): if self.xem: self._counterMask = (value & 0xffff) self.setExtendedWireIn(0x1d, self._counterMask) logging.getLogger(__name__).info("set counterMask {0}".format( hex(self._counterMask))) else: logging.getLogger(__name__).warning( "Pulser Hardware not available") return self._counterMask def getAdcMask(self): return self._adcMask def setAdcMask(self, value): if self.xem: self._adcMask = value & 0xffff self.setExtendedWireIn(0x1c, self._adcMask) logging.getLogger(__name__).info("set adc mask {0}".format( hex(self._adcMask))) else: logging.getLogger(__name__).warning( "Pulser Hardware not available") return self._adcMask def getIntegrationTime(self): return self._integrationTime def setIntegrationTime(self, value): self.integrationTimeBinary = int(value / self.integrationTimestep) if self.xem: logging.getLogger(__name__).info( "set dedicated integration time {0} {1}".format( value, self.integrationTimeBinary)) self.setExtendedWireIn(0x1b, self.integrationTimeBinary) self._integrationTime = value else: logging.getLogger(__name__).warning( "Pulser Hardware not available") return self.integrationTimeBinary def getIntegrationTimeBinary(self, value): return int(round(float(value / self.integrationTimestep))) & 0xffffffff def ppUpload(self, xxx_todo_changeme, codestartaddress=0, datastartaddress=0): (code, data) = xxx_todo_changeme self.ppUploadCode(code, codestartaddress) self.ppUploadData(data, datastartaddress) def ppUploadCode(self, binarycode, startaddress=0): if self.xem: logger = logging.getLogger(__name__) logger.info( "PP Code segment uses {0} / {1} words {2:.0f} %".format( len(binarycode) / 4, 4095, len(binarycode) / 4 / 40.95)) if len(binarycode ) / 4 > self._pulserConfiguration.commandMemorySize - 1: raise PulserHardwareException( "Code segment exceeds 4095 words ({0})".format( len(binarycode) / 4)) logger.info("starting PP Code upload") check(self.xem.SetWireInValue(0x00, startaddress, 0x0FFF), "ppUpload write start address") # start addr at zero self.xem.UpdateWireIns() check(self.xem.ActivateTriggerIn(0x41, 1), "ppUpload trigger") logger.info("{0} bytes".format(len(binarycode))) num = self.xem.WriteToPipeIn(0x83, bytearray(binarycode)) check(num, 'Write to program pipe') logger.info("uploaded pp file {0} bytes".format(num)) num, data = self.ppDownloadCode(0, num) logger.info("Verified {0} bytes. {1}".format( num, data == binarycode)) return True else: logging.getLogger(__name__).warning( "Pulser Hardware not available") return False def ppDownloadCode(self, startaddress, length): if self.xem: self.xem.SetWireInValue(0x00, startaddress, 0x0FFF) # start addr at 3900 self.xem.UpdateWireIns() self.xem.ActivateTriggerIn(0x41, 0) self.xem.ActivateTriggerIn(0x41, 1) data = bytearray(b'\000' * length) num = self.xem.ReadFromPipeOut(0xA4, data) return num, data else: logging.getLogger(__name__).warning( "Pulser Hardware not available") return 0, None def ppUploadData(self, binarydata, startaddress=0): if self.xem: logger = logging.getLogger(__name__) logger.info( "PP Data segment uses {0} / {1} words ( {2:.0f} % )".format( len(binarydata) / 8, 4095, len(binarydata) / 8 / 40.95)) if len(binarydata) / 8 > self._pulserConfiguration.dataMemorySize: raise PulserHardwareException( "Code segment exceeds 4095 words ({0})".format( len(binarydata) / 8)) logger.info("starting PP Datasegment upload") check(self.xem.SetWireInValue(0x00, startaddress, 0x0FFF), "ppUpload write start address") # start addr at zero self.xem.UpdateWireIns() check(self.xem.ActivateTriggerIn(0x41, 10), "ppUpload trigger") logger.info("{0} bytes".format(len(binarydata))) num = self.xem.WriteToPipeIn(0x80, bytearray(binarydata)) check(num, 'Write to program pipe') logger.info("uploaded pp file {0} bytes".format(num)) num, data = self.ppDownloadData(0, num) logger.info("Verified {0} bytes. {1}".format( num, data == binarydata)) return True else: logging.getLogger(__name__).warning( "Pulser Hardware not available") return False def ppDownloadData(self, startaddress, length): if self.xem: self.xem.SetWireInValue(0x00, startaddress, 0x0FFF) # start addr at 3900 self.xem.UpdateWireIns() self.xem.ActivateTriggerIn(0x41, 0) self.xem.ActivateTriggerIn(0x41, 10) data = bytearray(b'\000' * length) num = self.xem.ReadFromPipeOut(0xA0, data) return num, data else: logging.getLogger(__name__).warning( "Pulser Hardware not available") return 0, None def ppIsRunning(self): if self.xem: data = b'\x00' * 32 self.xem.ReadFromPipeOut(0xA1, data) if ((data[:2] != b'\xED\xFE') or (data[-2:] != b'\xED\x0F')): logging.getLogger(__name__).warning( "Bad data string: {0}".format(list(map(ord, data)))) return True data = list(map(ord, data[2:-2])) #Decode active = bool(data[1] & 0x80) return active else: logging.getLogger(__name__).warning( "Pulser Hardware not available") return False def ppReset(self): #, widget = None, data = None): if self.xem: self.xem.ActivateTriggerIn(0x40, 0) self.xem.ActivateTriggerIn(0x41, 0) logging.getLogger(__name__).warning( "pp_reset is not working right now... CWC 08302012") else: logging.getLogger(__name__).warning( "Pulser Hardware not available") def ppStart(self): #, widget = None, data = None): if self.xem: self.xem.ActivateTriggerIn(0x40, 3) # pp_stop_trig self.xem.ActivateTriggerIn(0x41, 4) # clear fifo self.xem.ActivateTriggerIn(0x41, 9) # reset overrun self.readDataFifo() self.readDataFifo( ) # after the first time the could still be data in the FIFO not reported by the fifo count self.data = Data() # flush data that might have been accumulated logging.getLogger(__name__).debug("Sending start trigger") self.xem.ActivateTriggerIn(0x40, 2) # pp_start_trig return True else: logging.getLogger(__name__).warning( "Pulser Hardware not available") return False def ppStop(self): #, widget, data= None): if self.xem: self.xem.ActivateTriggerIn(0x40, 3) # pp_stop_trig return True else: logging.getLogger(__name__).warning( "Pulser Hardware not available") return False def ppInterrupt(self): """Set a stop flag for the pulse program. The prepare_next_scan_point() function will then exit with exitrcode 0xfffe100000000000 to signal an interrupt""" self.xem.ActivateTriggerIn(0x40, 14) def interruptRead(self): self.sleepQueue.put(False) def ppWriteData(self, data): if self.xem: if isinstance(data, bytearray): return self.xem.WriteToPipeIn(0x81, data) else: code = bytearray() for item in data: code.extend(struct.pack('Q' if item > 0 else 'q', item)) #print "ppWriteData length",len(code) return self.xem.WriteToPipeIn(0x81, code) else: logging.getLogger(__name__).warning( "Pulser Hardware not available") return None def ppReadData(self, minbytes=8): if self.xem: self.xem.UpdateWireOuts() wirevalue = self.xem.GetWireOutValue(0x25) # pipe_out_available byteswaiting = (wirevalue & 0x1ffe) * 2 externalStatus = self.xem.GetWireOutValue(0x30) | ( self.xem.GetWireOutValue(0x31) << 16) if byteswaiting: data = bytearray(byteswaiting) self.xem.ReadFromPipeOut(0xa2, data) overrun = (wirevalue & 0x4000) != 0 return data, overrun, externalStatus return None, False, externalStatus return None, False, None def ppReadLogicAnalyzerData(self, minbytes=8): if self.xem: self.xem.UpdateWireOuts() wirevalue = self.xem.GetWireOutValue(0x27) # pipe_out_available byteswaiting = (wirevalue & 0x1ffe) * 2 self.logicAnalyzerOverrun = (wirevalue & 0x4000) == 0x4000 if byteswaiting: data = bytearray(byteswaiting) self.xem.ReadFromPipeOut(0xa1, data) overrun = (wirevalue & 0x4000) != 0 return data, overrun return None, False def wordListToBytearray(self, wordlist): """ convert list of words to binary bytearray """ return bytearray( numpy.array(wordlist, dtype=numpy.int64).view(dtype=numpy.int8)) def bytearrayToWordList(self, barray): return list( numpy.array(barray, dtype=numpy.int8).view(dtype=numpy.int64)) def ppWriteRam(self, data, address): if self.xem: appendlength = int(math.ceil(len(data) / 128.)) * 128 - len(data) data += bytearray([0] * appendlength) logging.getLogger(__name__).info( "set write address {0}".format(address)) self.xem.SetWireInValue(0x01, address & 0xffff) self.xem.SetWireInValue(0x02, (address >> 16) & 0xffff) self.xem.UpdateWireIns() self.xem.ActivateTriggerIn(0x41, 6) # ram set wwrite address return self.xem.WriteToPipeIn(0x82, data) else: logging.getLogger(__name__).warning( "Pulser Hardware not available") return None def ppReadRam(self, data, address): if self.xem: # print "set read address" self.xem.SetWireInValue(0x01, address & 0xffff) self.xem.SetWireInValue(0x02, (address >> 16) & 0xffff) self.xem.UpdateWireIns() self.xem.ActivateTriggerIn(0x41, 7) # Ram set read address self.xem.ReadFromPipeOut(0xa3, data) # print "read", len(data) else: logging.getLogger(__name__).warning( "Pulser Hardware not available") quantum = 1024 * 1024 def ppWriteRamWordList(self, wordlist, address): logger = logging.getLogger(__name__) data = self.wordListToBytearray(wordlist) for start in range(0, len(data), self.quantum): self.ppWriteRam(data[start:start + self.quantum], address + start) matches = True myslice = bytearray(self.quantum) for start in range(0, len(data), self.quantum): self.ppReadRam(myslice, address + start) length = min(self.quantum, len(data) - start) matches = matches and data[start:start + self.quantum] == myslice[:length] logger.info("ppWriteRamWordList {0}".format(len(data))) if not matches: logger.warning( "Write unsuccessful data does not match write length {0} read length {1}" .format(len(data), len(data))) raise PulserHardwareException("RAM write unsuccessful") def ppReadRamWordList(self, wordlist, address): data = bytearray(len(wordlist) * 8) myslice = bytearray(self.quantum) for start in range(0, len(data), self.quantum): length = min(self.quantum, len(data) - start) self.ppReadRam(myslice, address + start) data[start:start + length] = myslice[:length] wordlist[:] = self.bytearrayToWordList(data) return wordlist def ppWriteRamWordListShared(self, length, address, check=True): #self.ppWriteRamWordList(self.sharedMemoryArray[:length], address) logger = logging.getLogger(__name__) data = self.wordListToBytearray(self.sharedMemoryArray[:length]) #logger.debug( "write {0}".format([hex(int(d)) for d in data[0:100]]) ) self.ppWriteRam(data, address) if check: myslice = bytearray(len(data)) self.ppReadRam(myslice, address) #logger.debug( "read {0}".format([hex(int(d)) for d in myslice[0:100]]) ) matches = data == myslice logger.info("ppWriteRamWordList {0}".format(len(data))) if not matches: logger.warning( "Write unsuccessful data does not match write length {0} read length {1}" .format(len(data), len(data))) raise PulserHardwareException("RAM write unsuccessful") def ppReadRamWordListShared(self, length, address): data = bytearray([0] * length * 8) self.ppReadRam(data, address) self.sharedMemoryArray[:length] = self.bytearrayToWordList(data) return True def ppClearWriteFifo(self): if self.xem: self.xem.ActivateTriggerIn(0x41, 3) else: logging.getLogger(__name__).warning( "Pulser Hardware not available") def ppFlushData(self): if self.xem: self.data = Data() else: logging.getLogger(__name__).warning( "Pulser Hardware not available") return None def ppClearReadFifo(self): if self.xem: self.xem.ActivateTriggerIn(0x41, 4) else: logging.getLogger(__name__).warning( "Pulser Hardware not available") def ppReadLog(self): if self.xem: #Commented CWC 04032012 data = bytearray(32) self.xem.ReadFromPipeOut(0xA1, data) with open(r'debug\log', 'wb') as f: f.write(data) return data else: logging.getLogger(__name__).warning( "Pulser Hardware not available") return None def enableLogicAnalyzer(self, enable): if enable != self.logicAnalyzerEnabled: self.logicAnalyzerEnabled = enable if enable: if self.xem: self.xem.SetWireInValue(0x0d, 1, 0x01) # set logic analyzer enabled self.xem.UpdateWireIns() else: if self.xem: self.xem.SetWireInValue( 0x0d, 0, 0x01) # set logic analyzer disabled self.xem.UpdateWireIns() def logicAnalyzerTrigger(self): self.logicAnalyzerEnabled = True self.logicAnalyzerStopAtEnd = True if self.xem: self.xem.ActivateTriggerIn(0x40, 12) # Ram set read address def logicAnalyzerClearOverrun(self): if self.xem: self.xem.ActivateTriggerIn(0x40, 10) # Ram set read address def clearOverrun(self): if self.xem: self.xem.ActivateTriggerIn(0x41, 9) # reset overrun def uploadBitfile(self, bitfile): OKBase.uploadBitfile(self, bitfile) self.syncTime() def getOpenModule(self): return self.openModule def pulserConfiguration(self, configfile=None, hardwareId=None): if configfile is not None: pulserConfigurationList = getPulserConfiguration(configfile) hardwareId = self.hardwareConfigurationId( ) if hardwareId is None else hardwareId if hardwareId in pulserConfigurationList: self._pulserConfiguration = pulserConfigurationList[hardwareId] return self._pulserConfiguration else: raise PulserHardwareException( "No information on configuration 0x{0:x} in configuration file '{1}'" .format(hardwareId, configfile)) return None return self._pulserConfiguration
# ***************************************************************** # IonControl: Copyright 2016 Sandia Corporation # This Software is released under the GPL license detailed # in the file "license.txt" in the top-level IonControl directory # ***************************************************************** from PyQt5 import QtCore, QtGui, QtWidgets from modules.enum import enum from modules.Utility import indexWithDefault from sys import getrefcount from uiModules.KeyboardFilter import KeyListFilter from copy import copy nodeTypes = enum('category', 'data') class Node(object): """Class for tree nodes""" def __init__(self, parent, id, nodeType, content): self.parent = parent #parent node self.id = id #All nodes need a unique id self.content = content #content is the actual data in the tree, it can be anything self.children = [] self.nodeType = nodeType #nodeTypes.category or nodeTypes.data self.isBold = False #Determines whether node is shown bold self.bgColor = None #background color def childCount(self): return len(self.children) def child(self, row):
class ScanControl(ScanControlForm, ScanControlBase): ScanModes = enum('SingleScan', 'StepInPlace', 'GateSequenceScan') currentScanChanged = QtCore.pyqtSignal(object) integrationMode = enum('IntegrateAll', 'IntegrateRun', 'NoIntegration') scanConfigurationListChanged = QtCore.pyqtSignal(object) logger = logging.getLogger(__name__) def __init__(self, config, globalVariablesUi, parentname, plotnames=None, parent=None, analysisNames=None): logger = logging.getLogger(__name__) ScanControlForm.__init__(self) ScanControlBase.__init__(self, parent) self.config = config self.configname = 'ScanControl.' + parentname self.globalDict = globalVariablesUi.globalDict # History and Dictionary try: self.settingsDict = self.config.get(self.configname + '.dict', dict()) except (TypeError, AttributeError): logger.info( "Unable to read scan control settings dictionary. Setting to empty dictionary." ) self.settingsDict = dict() self.scanConfigurationListChanged.emit(self.settingsDict) self.settingsHistory = list() self.settingsHistoryPointer = None self.historyFinalState = None try: self.settings = self.config.get(self.configname, Scan()) except (TypeError, AttributeError): logger.info( "Unable to read scan control settings. Setting to new scan.") self.settings = Scan() self.gateSequenceUi = None self.settingsName = self.config.get(self.configname + '.settingsName', '') self.pulseProgramUi = None self.parameters = self.config.get(self.configname + '.parameters', ScanControlParameters()) self.globalVariablesUi = globalVariablesUi self.scanTargetDict = dict() def setupUi(self, parent): ScanControlForm.setupUi(self, parent) # History and Dictionary self.saveButton.clicked.connect(self.onSave) self.removeButton.clicked.connect(self.onRemove) self.reloadButton.clicked.connect(self.onReload) self.tableModel = ScanSegmentTableModel(self.checkSettingsSavable, self.globalDict) self.tableView.setModel(self.tableModel) self.addSegmentButton.clicked.connect(self.onAddScanSegment) self.removeSegmentButton.clicked.connect(self.onRemoveScanSegment) self.magnitudeDelegate = MagnitudeSpinBoxDelegate(self.globalDict) self.tableView.setItemDelegate(self.magnitudeDelegate) self.tableView.resizeRowsToContents() # try: self.setSettings(self.settings) # except AttributeError: # logger.error( "Ignoring exception" ) self.comboBox.addItems(sorted(self.settingsDict.keys())) if self.settingsName and self.comboBox.findText(self.settingsName): self.comboBox.setCurrentIndex( self.comboBox.findText(self.settingsName)) self.comboBox.currentIndexChanged[str].connect(self.onLoad) self.comboBox.lineEdit().editingFinished.connect( self.checkSettingsSavable) # update connections self.comboBoxParameter.currentIndexChanged[str].connect( self.onCurrentTextChanged) self.parallelInternalScanComboBox.currentIndexChanged[str].connect( self.onCurrentParallelScanChanged) self.scanTypeCombo.currentIndexChanged[int].connect( functools.partial(self.onCurrentIndexChanged, 'scantype')) self.autoSaveCheckBox.stateChanged.connect( functools.partial(self.onStateChanged, 'autoSave')) self.saveRawCheckBox.stateChanged.connect( functools.partial(self.onStateChanged, 'saveRawData')) self.histogramSaveCheckBox.stateChanged.connect( functools.partial(self.onStateChanged, 'histogramSave')) self.scanModeComboBox.currentIndexChanged[int].connect( self.onModeChanged) self.filenameEdit.editingFinished.connect( functools.partial(self.onEditingFinished, self.filenameEdit, 'filename')) self.rawFilenameEdit.editingFinished.connect( functools.partial(self.onEditingFinished, self.rawFilenameEdit, 'rawFilename')) self.histogramFilenameEdit.editingFinished.connect( functools.partial(self.onEditingFinished, self.histogramFilenameEdit, 'histogramFilename')) self.xUnitEdit.editingFinished.connect( functools.partial(self.onEditingFinished, self.xUnitEdit, 'xUnit')) self.xExprEdit.editingFinished.connect( functools.partial(self.onEditingFinished, self.xExprEdit, 'xExpression')) self.maxPointsBox.valueChanged.connect(self.onMaxPointsChanged) self.loadPPcheckBox.stateChanged.connect( functools.partial(self.onStateChanged, 'loadPP')) self.loadPPComboBox.currentIndexChanged[str].connect(self.onLoadPP) self.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu) self.autoSaveAction = QtWidgets.QAction("auto save", self) self.autoSaveAction.setCheckable(True) self.autoSaveAction.setChecked(self.parameters.autoSave) self.autoSaveAction.triggered.connect(self.onAutoSave) self.addAction(self.autoSaveAction) self.settings.evaluate(self.globalDict) self.globalVariablesUi.valueChanged.connect(self.evaluate) self.comboBoxScanTarget.currentIndexChanged[str].connect( self.onChangeScanTarget) self.currentScanChanged.emit(self.settingsName) self.defaultFilenameAction = QtWidgets.QAction('Use default filename', self) self.defaultFilenameAction.setCheckable(True) self.defaultFilenameAction.setChecked( self.parameters.useDefaultFilename) self.defaultFilenameAction.triggered.connect(self.onDefaultFilename) self.addAction(self.defaultFilenameAction) self.defaultHdf5TypeAction = QtGui.QAction( 'Use hdf5 as default file type', self) self.defaultHdf5TypeAction.setCheckable(True) self.defaultHdf5TypeAction.setChecked(self.parameters.useHdf5Filetype) self.defaultHdf5TypeAction.triggered.connect(self.onDefaultHdf5Type) self.addAction(self.defaultHdf5TypeAction) self.onDefaultFilename() self.parallelInternalScanComboBox.setVisible( self.parameters.currentScanTarget != "Internal") def evaluate(self, name): if self.settings.evaluate(self.globalDict): self.tableModel.update() self.tableView.viewport().repaint() def onAutoSave(self, checked): self.parameters.autoSave = checked if self.parameters.autoSave: self.onSave() @QtCore.pyqtSlot(bool) def onDefaultFilename(self, checked=None): if checked is not None: self.parameters.useDefaultFilename = checked if self.parameters.useDefaultFilename: self.settings.filename = self.settingsName if self.settingsName else 'untitled' if self.parameters.useHdf5Filetype: self.settings.filename += '.hdf5' self.filenameEdit.setText(self.settings.filename) self.filenameEdit.setDisabled(True) else: self.filenameEdit.setDisabled(False) @QtCore.pyqtSlot(bool) def onDefaultHdf5Type(self, checked): self.parameters.useHdf5Filetype = checked self.onDefaultFilename() def onAddScanSegment(self): self.settings.scanSegmentList.append(ScanSegmentDefinition()) self.tableModel.setScanList(self.settings.scanSegmentList) def onRemoveScanSegment(self): for index in sorted(unique( [i.column() for i in self.tableView.selectedIndexes()]), reverse=True): del self.settings.scanSegmentList[index] self.tableModel.setScanList(self.settings.scanSegmentList) def setSettings(self, settings): self.settings = copy.deepcopy(settings) if self.globalDict: self.settings.evaluate(self.globalDict) self.scanModeComboBox.setCurrentIndex(self.settings.scanMode) self.scanTypeCombo.setCurrentIndex(self.settings.scantype) self.autoSaveCheckBox.setChecked(self.settings.autoSave) self.saveRawCheckBox.setChecked(self.settings.saveRawData) self.histogramSaveCheckBox.setChecked(self.settings.histogramSave) if self.settings.scanTarget: self.settings.scanParameter = self.doChangeScanTarget( self.settings.scanTarget, self.settings.scanParameter) elif self.comboBoxScanTarget.count() > 0: self.settings.scanTarget = str( self.comboBoxScanTarget.currentText()) self.settings.scanParameter = self.doChangeScanTarget( self.settings.scanTarget, None) if self.settings.parallelInternalScanParameter: updateComboBoxItems(self.parallelInternalScanComboBox, self.scanTargetDict.get('Internal'), self.settings.parallelInternalScanParameter) filename = getattr(self.settings, 'filename', '') self.filenameEdit.setText(filename if filename else '') self.rawFilenameEdit.setText(getattr(self.settings, 'rawFilename', '')) self.histogramFilenameEdit.setText( getattr(self.settings, 'histogramFilename', '')) self.scanTypeCombo.setEnabled(self.settings.scanMode in [0, 1]) self.xUnitEdit.setText(self.settings.xUnit) self.xExprEdit.setText(self.settings.xExpression) self.maxPointsBox.setValue(self.settings.maxPoints) self.loadPPcheckBox.setChecked(self.settings.loadPP) if self.settings.loadPPName: index = self.loadPPComboBox.findText(self.settings.loadPPName) if index >= 0: self.loadPPComboBox.setCurrentIndex(index) self.onLoadPP(self.settings.loadPPName) self.onModeChanged(self.settings.scanMode) if self.gateSequenceUi: self.gateSequenceUi.setSettings(self.settings.gateSequenceSettings) self.checkSettingsSavable() self.tableModel.setScanList(self.settings.scanSegmentList) def checkSettingsSavable(self, savable=None): if not isinstance(savable, bool): currentText = str(self.comboBox.currentText()) try: if currentText is None or currentText == "": savable = False elif self.settingsName and self.settingsName in self.settingsDict: savable = self.settingsDict[ self. settingsName] != self.settings or currentText != self.settingsName else: savable = True if self.parameters.autoSave and savable: self.onSave() savable = False except ValueError: pass self.saveButton.setEnabled(savable) def onLoadPP(self, ppname): logger = logging.getLogger(__name__) self.settings.loadPPName = str(ppname) logger.debug("ScanControl.onLoadPP {0} {1} {2}".format( self.settings.loadPP, bool(self.settings.loadPPName), self.settings.loadPPName)) if self.settings.loadPP and self.settings.loadPPName and hasattr( self, "pulseProgramUi"): self.pulseProgramUi.loadContextByName(self.settings.loadPPName) self.checkSettingsSavable() def onRecentPPFilesChanged(self, namelist): updateComboBoxItems(self.loadPPComboBox, sorted(namelist)) self.checkSettingsSavable() def setPulseProgramUi(self, pulseProgramUi): logger = logging.getLogger(__name__) logger.debug("ScanControl.setPulseProgramUi {0}".format( list(pulseProgramUi.configParams.recentFiles.keys()))) isStartup = self.pulseProgramUi is None self.pulseProgramUi = pulseProgramUi updateComboBoxItems(self.loadPPComboBox, sorted(pulseProgramUi.contextDict.keys()), self.settings.loadPPName) try: self.pulseProgramUi.contextDictChanged.connect( self.onRecentPPFilesChanged, QtCore.Qt.UniqueConnection) except TypeError: pass # is raised if the connection already existed if not self.gateSequenceUi: self.gateSequenceUi = GateSequenceUi.GateSequenceUi() self.gateSequenceUi.valueChanged.connect(self.checkSettingsSavable) self.gateSequenceUi.postInit('test', self.config, self.pulseProgramUi.pulseProgram) self.gateSequenceUi.setupUi(self.gateSequenceUi) self.toolBox.addItem(self.gateSequenceUi, "Gate Sequences") if pulseProgramUi.currentContext.parameters: self.gateSequenceUi.setVariables( pulseProgramUi.currentContext.parameters) try: self.gateSequenceUi.setSettings(self.settings.gateSequenceSettings) except GateSequenceException as e: logger.exception(e) if isStartup: self.onLoadPP(self.settings.loadPPName) def onEditingFinished(self, edit, attribute): setattr(self.settings, attribute, str(edit.text())) self.checkSettingsSavable() def onStateChanged(self, attribute, state): setattr(self.settings, attribute, (state == QtCore.Qt.Checked)) self.checkSettingsSavable() def onCurrentTextChanged(self, text): self.settings.scanParameter = str(text) self.checkSettingsSavable() def onCurrentParallelScanChanged(self, text): self.settings.parallelInternalScanParameter = str(text) self.checkSettingsSavable() def onCurrentIndexChanged(self, attribute, index): setattr(self.settings, attribute, index) self.checkSettingsSavable() def onMaxPointsChanged(self, value): self.settings.maxPoints = int(value) self.checkSettingsSavable() def onModeChanged(self, index): self.settings.scanMode = index self.scanTypeCombo.setEnabled(index in [0, 2]) self.xUnitEdit.setEnabled(index in [0, 3]) self.xExprEdit.setEnabled(index in [0, 3]) self.comboBoxParameter.setEnabled(index == 0) self.comboBoxScanTarget.setEnabled(index == 0) self.addSegmentButton.setEnabled(index == 0) self.removeSegmentButton.setEnabled(index == 0) self.tableView.setEnabled(index == 0) self.maxPointsLabel.setVisible(index == 1) self.maxPointsBox.setVisible(index == 1) self.checkSettingsSavable() self.parallelInternalScanComboBox.setEnabled(index == 0) def onValueChanged(self, attribute, value): setattr(self.settings, attribute, Q(value)) self.checkSettingsSavable() def onBareValueChanged(self, attribute, value): setattr(self.settings, attribute, value) self.checkSettingsSavable() def onIntValueChanged(self, attribute, value): setattr(self.settings, attribute, value) self.checkSettingsSavable() def setVariables(self, variabledict): self.updateScanTarget( 'Internal', sorted(var.name for var in variabledict.values() if var.type == 'parameter')) self.variabledict = variabledict if self.settings.scanParameter: self.comboBoxParameter.setCurrentIndex( self.comboBoxParameter.findText(self.settings.scanParameter)) elif self.comboBoxParameter.count( ) > 0: # if scanParameter is None set it to the current selection self.settings.scanParameter = str( self.comboBoxParameter.currentText()) if self.settings.parallelInternalScanParameter: # TODO: self.parallelInternalScanComboBox.setCurrentIndex( self.parallelInternalScanComboBox.findText( self.settings.parallelInternalScanParameter)) if self.gateSequenceUi: self.gateSequenceUi.setVariables(variabledict) self.checkSettingsSavable() def updateScanTarget(self, target, scannames): if target == "Internal": extended = ["None"] extended.extend(sorted(scannames)) else: extended = sorted(scannames) self.scanTargetDict[target] = extended updateComboBoxItems(self.comboBoxScanTarget, list(self.scanTargetDict.keys()), self.parameters.currentScanTarget) self.parameters.currentScanTarget = firstNotNone( self.parameters.currentScanTarget, target) if target == self.parameters.currentScanTarget: self.settings.scanParameter = str( updateComboBoxItems(self.comboBoxParameter, self.scanTargetDict[target], self.settings.scanParameter)) if not self.settings.scanTarget: self.settings.scanTarget = self.parameters.currentScanTarget if target == "Internal": updateComboBoxItems(self.parallelInternalScanComboBox, self.scanTargetDict[target], self.settings.parallelInternalScanParameter) def onChangeScanTarget(self, name): """ called on currentIndexChanged[QString] signal of ComboBox""" name = str(name) if name != self.parameters.currentScanTarget: self.parameters.scanTargetCache[ self.parameters. currentScanTarget] = self.settings.scanParameter cachedParam = self.parameters.scanTargetCache.get(name) cachedParam = updateComboBoxItems( self.comboBoxParameter, sorted(self.scanTargetDict[name]), cachedParam) self.settings.scanParameter = cachedParam self.settings.scanTarget = name self.parameters.currentScanTarget = name self.parallelInternalScanComboBox.setVisible(name != "Internal") self.checkSettingsSavable() def doChangeScanTarget(self, name, scanParameter): """ Change the scan target as part of loading a parameter set, we know the ScanParameter to select and want it either selected or added as red item """ name = str(name) if name != self.parameters.currentScanTarget: with BlockSignals(self.comboBoxScanTarget): self.comboBoxScanTarget.setCurrentIndex( self.comboBoxScanTarget.findText(name)) targets = self.scanTargetDict.get(name) if targets is not None: targets = sorted(targets) scanParameter = updateComboBoxItems(self.comboBoxParameter, targets, scanParameter) self.settings.scanTarget = name self.parameters.currentScanTarget = name else: self.comboBoxParameter.setCurrentIndex( self.comboBoxParameter.findText(scanParameter)) self.checkSettingsSavable() return scanParameter def getScan(self): scan = copy.deepcopy(self.settings) if scan.scanMode != 0: scan.scanTarget = 'Internal' scan.scanTarget = str(scan.scanTarget) scan.type = [ ScanList.ScanType.LinearUp, ScanList.ScanType.LinearDown, ScanList.ScanType.Randomized, ScanList.ScanType.CenterOut ][self.settings.scantype] if scan.scanMode == Scan.ScanMode.Freerunning: scan.list = None else: scan.list = list( concatenate_iter(*[ linspace(segment.start, segment.stop, segment.steps) for segment in scan.scanSegmentList ])) if scan.type == 0: scan.list = sorted(scan.list) scan.start = scan.list[0] scan.stop = scan.list[-1] elif scan.type == 1: scan.list = sorted(scan.list, reverse=True) scan.start = scan.list[-1] scan.stop = scan.list[0] elif scan.type == 2: scan.list = sorted(scan.list) scan.start = scan.list[0] scan.stop = scan.list[-1] random.shuffle(scan.list) elif scan.type == 3: scan.list = sorted(scan.list) center = len(scan.list) // 2 scan.list = list( interleave_iter(scan.list[center:], reversed(scan.list[:center]))) scan.gateSequenceUi = self.gateSequenceUi scan.settingsName = self.settingsName return scan def saveConfig(self): self.config[self.configname] = self.settings for e in self.settingsDict.values(): e.scanTarget = str(e.scanTarget) e.scanParameter = str(e.scanParameter) self.config[self.configname + '.dict'] = self.settingsDict self.config[self.configname + '.settingsName'] = self.settingsName self.config[self.configname + '.parameters'] = self.parameters def onSave(self): self.settingsName = str(self.comboBox.currentText()) if self.settingsName != '': if self.settingsName not in self.settingsDict: if self.comboBox.findText(self.settingsName) == -1: self.comboBox.addItem(self.settingsName) self.settingsDict[self.settingsName] = copy.deepcopy(self.settings) self.scanConfigurationListChanged.emit(self.settingsDict) self.checkSettingsSavable(savable=False) self.currentScanChanged.emit(self.settingsName) def onRemove(self): name = str(self.comboBox.currentText()) if name != '': if name in self.settingsDict: self.settingsDict.pop(name) idx = self.comboBox.findText(name) if idx >= 0: self.comboBox.removeItem(idx) self.scanConfigurationListChanged.emit(self.settingsDict) def onLoad(self, name): self.settingsName = str(name) if self.settingsName != '' and self.settingsName in self.settingsDict: self.setSettings(self.settingsDict[self.settingsName]) if self.parameters.useDefaultFilename: self.settings.filename = self.settingsName self.filenameEdit.setText(self.settingsName) self.checkSettingsSavable() self.currentScanChanged.emit(self.settingsName) def loadSetting(self, name): if name and self.comboBox.findText(name) >= 0: self.comboBox.setCurrentIndex(self.comboBox.findText(name)) self.onLoad(name) def onReload(self): self.onLoad(self.comboBox.currentText()) def documentationString(self): return self.settings.documentationString() def editEvaluationTable(self, index): if index.column() in [0, 1, 2, 4]: self.evalTableView.edit(index)
# ***************************************************************** # IonControl: Copyright 2016 Sandia Corporation # This Software is released under the GPL license detailed # in the file "license.txt" in the top-level IonControl directory # ***************************************************************** from PyQt5 import QtGui, QtCore, QtWidgets from .MagnitudeSpinBoxDelegate import MagnitudeSpinBoxDelegateMixin from .ComboBoxDelegate import ComboBoxDelegateMixin from modules.enum import enum ModeTypes = enum('ComboBox', 'Magnitude') class CamelionDelegate(QtWidgets.QStyledItemDelegate, ComboBoxDelegateMixin, MagnitudeSpinBoxDelegateMixin): """Class for combo box editors in models""" def __init__(self, emptyStringValue=0): QtWidgets.QStyledItemDelegate.__init__(self) self.mode = ModeTypes.Magnitude self.globalDict = dict() self.emptyStringValue = emptyStringValue def createEditor(self, parent, option, index): """Create the combo box editor""" choice = index.model().choice(index) if hasattr(index.model(), 'choice') else None if choice is not None: self.mode = ModeTypes.ComboBox return ComboBoxDelegateMixin.createEditor(self, parent, option, index) else: self.mode = ModeTypes.Magnitude return MagnitudeSpinBoxDelegateMixin.createEditor(self, parent, option, index) def setEditorData(self, editor, index):
# ***************************************************************** # IonControl: Copyright 2016 Sandia Corporation # This Software is released under the GPL license detailed # in the file "license.txt" in the top-level IonControl directory # ***************************************************************** import functools import random import numpy from modules import enum from modules.concatenate_iter import interleave_iter ScanType = enum.enum('LinearUp', 'LinearDown', 'Randomized', 'CenterOut', 'LinearUpDown', 'LinearDownUp') def shuffle( mylist ): random.shuffle(mylist) return mylist def scanspace( start, stop, steps, scanSelect=0 ): if scanSelect==0: return numpy.linspace(start, stop, steps) else: mysteps = abs(steps) if stop>start else -abs(steps) return numpy.arange(start, stop+mysteps//2, mysteps) def shuffled(start, stop, steps, scanSelect ): return shuffle(scanspace(start, stop, steps, scanSelect ))
class DedicatedCounters(DedicatedCountersForm, DedicatedCountersBase ): dataAvailable = QtCore.pyqtSignal( object ) OpStates = enum.enum('idle', 'running', 'paused') def __init__(self, config, dbConnection, pulserHardware, globalVariablesUi, shutterUi, externalInstrumentObservable, parent=None): DedicatedCountersForm.__init__(self) DedicatedCountersBase.__init__(self, parent) self.curvesDict = {} self.dataSlotConnected = False self.config = config self.configName = 'DedicatedCounter' self.pulserHardware = pulserHardware self.state = self.OpStates.idle self.xData = [numpy.array([])]*20 self.yData = [numpy.array([])]*20 self.refValue = [None] * 20 self.integrationTime = 0 self.integrationTimeLookup = dict() self.tick = 0 self.analogCalbrations = None self.globalVariablesUi = globalVariablesUi self.shutterUi = shutterUi self.externalInstrumentObservable = externalInstrumentObservable self.dbConnection = dbConnection self.plotDict = dict() self.area = None # [ # AnalogInputCalibration.PowerDetectorCalibration(), # AnalogInputCalibration.PowerDetectorCalibrationTwo(), # AnalogInputCalibration.AnalogInputCalibration(), # AnalogInputCalibration.AnalogInputCalibration() ] @property def settings(self): return self.settingsUi.settings def setupUi(self, parent): DedicatedCountersForm.setupUi(self, parent) self.setupPlots() self.actionSave.triggered.connect( self.onSave ) self.actionClear.triggered.connect( self.onClear ) self.actionStart.triggered.connect( self.onStart ) self.actionStop.triggered.connect( self.onStop ) self.settingsUi = DedicatedCountersSettings.DedicatedCountersSettings(self.config,self.plotDict) self.settingsUi.setupUi(self.settingsUi) self.settingsDock.setWidget( self.settingsUi ) self.settingsUi.valueChanged.connect( self.onSettingsChanged ) #Plot buttons self.addPlot = QtGui.QAction( QtGui.QIcon(":/openicon/icons/add-plot.png"), "Add new plot", self) self.addPlot.setToolTip("Add new plot") self.addPlot.triggered.connect(self.onAddPlot) self.toolBar.addAction(self.addPlot) self.removePlot = QtGui.QAction( QtGui.QIcon(":/openicon/icons/remove-plot.png"), "Remove a plot", self) self.removePlot.setToolTip("Remove a plot") self.removePlot.triggered.connect(self.onRemovePlot) self.toolBar.addAction(self.removePlot) self.renamePlot = QtGui.QAction( QtGui.QIcon(":/openicon/icons/rename-plot.png"), "Rename a plot", self) self.renamePlot.setToolTip("Rename a plot") self.renamePlot.triggered.connect(self.onRenamePlot) self.toolBar.addAction(self.renamePlot) # Input Calibrations self.calibrationUi = InputCalibrationUi.InputCalibrationUi(self.config, 4) self.calibrationUi.setupUi(self.calibrationUi) self.calibrationDock = QtWidgets.QDockWidget("Input Calibration") self.calibrationDock.setObjectName("Input Calibration") self.calibrationDock.setWidget( self.calibrationUi ) self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.calibrationDock) self.analogCalbrations = self.calibrationUi.calibrations # Display Channels 0-3 self.displayUi = DedicatedDisplay.DedicatedDisplay(self.config, "Channel 0-3") self.displayUi.setupUi(self.displayUi) self.displayDock = QtWidgets.QDockWidget("Channel 0-3") self.displayDock.setObjectName("Channel 0-3") self.displayDock.setWidget( self.displayUi ) self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.displayDock) # Display Channel 4-7 self.displayUi2 = DedicatedDisplay.DedicatedDisplay(self.config, "Channel 4-7") self.displayUi2.setupUi(self.displayUi2) self.displayDock2 = QtWidgets.QDockWidget("Channel 4-7") self.displayDock2.setObjectName("Channel 4-7") self.displayDock2.setWidget(self.displayUi2) self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.displayDock2) # Display ADC 0-3 self.displayUiADC = DedicatedDisplay.DedicatedDisplay(self.config, "Analog Channels") self.displayUiADC.setupUi(self.displayUiADC) self.displayDockADC = QtWidgets.QDockWidget("Analog Channels") self.displayDockADC.setObjectName("Analog Channels") self.displayDockADC.setWidget(self.displayUiADC) self.addDockWidget(QtCore.Qt.RightDockWidgetArea, self.displayDockADC) # Arrange the dock widgets self.tabifyDockWidget( self.displayDockADC, self.displayDock2) self.tabifyDockWidget( self.displayDock2, self.displayDock ) self.tabifyDockWidget( self.calibrationDock, self.settingsDock ) self.calibrationDock.hide() # AutoLoad self.autoLoad = AutoLoad.AutoLoad(self.config, self.dbConnection, self.pulserHardware, self.dataAvailable, self.globalVariablesUi,self.shutterUi, self.externalInstrumentObservable) self.autoLoad.setupUi(self.autoLoad) self.autoLoadDock = QtWidgets.QDockWidget("Auto Loader") self.autoLoadDock.setObjectName("Auto Loader") self.autoLoadDock.setWidget( self.autoLoad ) self.autoLoad.valueChanged.connect( self.onSettingsChanged ) self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self.autoLoadDock) # external Status display self.statusDisplay = StatusDisplay(self.config, self.pulserHardware.pulserConfiguration()) self.statusDisplay.setupUi(self.statusDisplay) self.statusDock = QtWidgets.QDockWidget("Status display") self.statusDock.setObjectName("Status display") self.statusDock.setWidget( self.statusDisplay ) self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, self.statusDock) if self.configName+'.MainWindow.State' in self.config: QtGui.QMainWindow.restoreState(self,self.config[self.configName+'.MainWindow.State']) self.onSettingsChanged() def onSettingsChanged(self): self.integrationTimeLookup[ self.pulserHardware.getIntegrationTimeBinary(self.settings.integrationTime) & 0xffffff] = self.settings.integrationTime self.pulserHardware.integrationTime = self.settings.integrationTime self.autoLoadCounterMask = self.autoLoad.settings.counterMask self.plotCounterMask = self.settingsUi.settings.counterMask self.counterDisplayData = self.autoLoad.settings.counterDisplayData self.plotDisplayData = self.settingsUi.settings.plotDisplayData self.countDict = self.settingsUi.settings.counterDict self.adcDict = self.settingsUi.settings.adcDict if self.state == self.OpStates.running: mask = 0 mask += self.autoLoadCounterMask | self.plotCounterMask self.pulserHardware.counterMask = mask self.pulserHardware.adcMask = self.settings.adcMask for windowName, dataSourceNames in self.plotDisplayData.items(): if windowName in self.plotDict: self.curvesDict.setdefault(windowName, dict()) counterIndexList = [self.countDict[n] for n in dataSourceNames if n in self.countDict] adcIndexList = [self.adcDict[n] for n in dataSourceNames if n in self.adcDict] mycurves = self.curvesDict[windowName] for cIdx in counterIndexList: mycurves.setdefault(cIdx, self.plotDict[windowName]['view'].plot(pen=penList[cIdx + 1][0])) for aIdx in adcIndexList: mycurves.setdefault(aIdx + 16, self.plotDict[windowName]['view'].plot(pen=penList[cIdx + 1][0])) for eIdx in set(mycurves) - set(counterIndexList) - set(i + 16 for i in adcIndexList): curve = mycurves.pop(eIdx) self.plotDict[windowName]['view'].removeItem(curve) self.xData[eIdx] = numpy.array([]) self.yData[eIdx] = numpy.array([]) def saveConfig(self): self.config[self.configName+'.pos'] = self.pos() self.config[self.configName+'.size'] = self.size() self.config[self.configName+'.Settings'] = self.settings self.config[self.configName+'.MainWindow.State'] = QtWidgets.QMainWindow.saveState(self) self.config[self.configName+'.PlotNames'] = list(self.plotDict.keys()) self.displayUi.saveConfig() self.displayUi2.saveConfig() self.displayUiADC.saveConfig() self.autoLoad.saveConfig() self.calibrationUi.saveConfig() self.settingsUi.saveConfig() self.statusDisplay.saveConfig() def onClose(self): self.autoLoad.onClose() def closeEvent(self, e): self.onClose() def reject(self): self.config[self.configName+'.pos'] = self.pos() self.config[self.configName+'.size'] = self.size() self.pulserHardware.dedicatedDataAvailable.disconnect( self.onData ) self.hide() def show(self): if self.configName+'.pos' in self.config: self.move(self.config[self.configName+'.pos']) if self.configName+'.size' in self.config: self.resize(self.config[self.configName+'.size']) super(DedicatedCounters,self).show() if not self.dataSlotConnected: self.pulserHardware.dedicatedDataAvailable.connect( self.onData ) self.dataSlotConnected = True def onStart(self): self.pulserHardware.counterMask = self.settings.counterMask self.pulserHardware.adcMask = self.settings.adcMask self.state = self.OpStates.running self.onSettingsChanged() def onStop(self): self.pulserHardware.counterMask = 0 self.pulserHardware.adcMask = 0 self.state = self.OpStates.idle self.onSettingsChanged() def onSave(self): logger = logging.getLogger(__name__) self.plotDisplayData = self.settingsUi.settings.plotDisplayData for plotName in self.plotDisplayData.keys(): for n in range(20): if len(self.xData[n])>0 and len(self.yData[n])>0: trace = TraceCollection() trace.x = self.xData[n] trace.y = self.yData[n] if n < 16: trace.description["counter"] = str(plotName) else: trace.description["ADC"] = str(plotName) filename, _ = DataDirectory().sequencefile("DedicatedCounter_{0}.txt".format(n)) trace.addTracePlotting( TracePlotting(name="Counter {0}".format(n)) ) trace.save() logger.info("saving dedicated counters") def onClear(self): self.xData = [numpy.array([])]*20 self.yData = [numpy.array([])]*20 self.tick = 0 for name, subdict in self.curvesDict.items(): for n in list(subdict.keys()): subdict[n].setData(self.xData[n], self.yData[n]) def onData(self, data): self.tick += 1 self.displayUi.values = data.data[0:4] self.displayUi2.values = data.data[4:8] self.displayUiADC.values = self.convertAnalog(data.analog()) data.analogValues = self.displayUiADC.values # if data.data[16] is not None and data.data[16] in self.integrationTimeLookup: # self.dataIntegrationTime = self.integrationTimeLookup[ data.data[16] ] # else: self.dataIntegrationTime = self.settings.integrationTime data.integrationTime = self.dataIntegrationTime self.plotDisplayData = self.settingsUi.settings.plotDisplayData msIntegrationTime = self.dataIntegrationTime.m_as('ms') for index, value in enumerate(data.data[:16]): if value is not None: y = self.settings.displayUnit.convert(value, msIntegrationTime) self.yData[index] = rollingUpdate(self.yData[index], y, self.settings.pointsToKeep) self.xData[index] = rollingUpdate(self.xData[index], data.timestamp, self.settings.pointsToKeep) for index, value in enumerate(data.analogValues): if value is not None: myindex = 16 + index refValue = self.refValue[myindex] if is_Q(value): if refValue is not None and refValue.dimensionality == value.dimensionality: y = value.m_as(refValue) else: self.refValue[myindex] = value y = value.m else: y = value self.yData[myindex] = rollingUpdate(self.yData[myindex], y, self.settings.pointsToKeep) self.xData[myindex] = rollingUpdate(self.xData[myindex], data.timestamp, self.settings.pointsToKeep) for name, plotwin in self.curvesDict.items(): if plotwin: with BlockAutoRange(next(iter(plotwin.values()))): for index, plotdata in plotwin.items(): plotdata.setData(self.xData[index], self.yData[index]) self.statusDisplay.setData(data) self.dataAvailable.emit(data) # logging.getLogger(__name__).info("Max bytes read {0}".format(data.maxBytesRead)) self.statusDisplay.setData(data) self.dataAvailable.emit(data) def convertAnalog(self, data): converted = list() for channel, cal in enumerate(self.analogCalbrations): converted.append( cal.convertMagnitude(data[channel]) ) return converted def setupPlots(self): self.area = DockArea() self.setCentralWidget(self.area) self.plotDict = SequenceDict() # initialize all the plot windows we want plotNames = self.config.get(self.configName+'.PlotNames', ['Plot']) if len(plotNames) < 1: plotNames.append('Plot') if 'Autoload' not in plotNames: plotNames.append('Autoload') for name in plotNames: dock = Dock(name) widget = DateTimePlotWidget(self, name=name) view = widget._graphicsView self.area.addDock(dock, "bottom") dock.addWidget(widget) self.plotDict[name] = {"dock":dock, "widget":widget, "view":view} def onAddPlot(self): name, ok = QtGui.QInputDialog.getText(self, 'Plot Name', 'Please enter a plot name: ') if ok and name!= 'Autoload': name = str(name) dock = Dock(name) widget = DateTimePlotWidget(self) view = widget._graphicsView self.area.addDock(dock, "bottom") dock.addWidget(widget) self.plotDict[name] = {"dock":dock, "widget":widget, "view":view} def onRemovePlot(self): self.editablePlots = {} self.editablePlots.update(self.plotDict) if 'Autoload' in self.editablePlots: self.editablePlots.pop('Autoload') logger = logging.getLogger(__name__) if len(self.plotDict) > 0: name, ok = QtGui.QInputDialog.getItem(self, "Select Plot", "Please select which plot to remove: ", self.editablePlots.keys(), editable=False) if ok and name != 'Autoload': if ok: name = str(name) self.plotDict[name]["dock"].close() del self.plotDict[name] else: logger.info("There are no plots which can be removed") def onRenamePlot(self): self.plotDisplayData = self.settingsUi.settings.plotDisplayData self.editablePlots = {} self.editablePlots.update(self.plotDict) if 'Autoload' in self.editablePlots: self.editablePlots.pop('Autoload') logger = logging.getLogger(__name__) if len(self.plotDict) > 0: name, ok = QtGui.QInputDialog.getItem(self, "Select Plot", "Please select which plot to rename: ", self.editablePlots.keys(), editable=False) if ok and name != 'Autoload': newName, newOk = QtGui.QInputDialog.getText(self, 'New Plot Name', 'Please enter a new plot name: ') if newOk and newName != 'Autoload': name = str(name) newName = str(newName) self.plotDict[name]["dock"].label.setText(QtCore.QString(newName)) self.plotDict[newName] = self.plotDict[name] for plotName in list(self.plotDisplayData.keys()): plotString = str(plotName) if name == plotString: plotIndex = self.plotDisplayData.index(plotName) self.plotDisplayData.renameAt(plotIndex, newName) del self.plotDict[name] self.onSettingsChanged() else: logger.info("There are no plots which can be renamed")
class EvaluationControl(ControlForm, ControlBase): evaluationConfigurationChanged = QtCore.pyqtSignal(object) currentEvaluationChanged = QtCore.pyqtSignal(object) integrationMode = enum('IntegrateAll', 'IntegrateRun', 'NoIntegration') logger = logging.getLogger(__name__) def __init__(self, config, globalDict, parentname, plotnames=None, parent=None, analysisNames=None, counterNames=None): logger = logging.getLogger(__name__) ControlForm.__init__(self) ControlBase.__init__(self, parent) self.config = config self.configname = 'EvaluationControl.' + parentname self.globalDict = globalDict self.ppDict = None self.counterNames = counterNames # History and Dictionary try: self.settingsDict = self.config.get(self.configname + '.dict', dict()) except (TypeError, UnpicklingError): logger.info( "Unable to read scan control settings dictionary. Setting to empty dictionary." ) self.settingsDict = dict() self.evaluationConfigurationChanged.emit(self.settingsDict) try: self.settings = self.config.get(self.configname, Evaluation()) except TypeError: logger.info( "Unable to read scan control settings. Setting to new scan.") self.settings = Evaluation() self.settingsName = self.config.get(self.configname + '.settingsName', None) self.evalAlgorithmList = list() self.plotnames = plotnames self.analysisNames = analysisNames self.pulseProgramUi = None self.parameters = self.config.get(self.configname + '.parameters', EvaluationControlParameters()) self.project = getProject() self.timestampsEnabled = self.project.isEnabled( 'software', 'Timestamps') def setupUi(self, parent): ControlForm.setupUi(self, parent) # History and Dictionary self.saveButton.clicked.connect(self.onSave) self.removeButton.clicked.connect(self.onRemove) self.reloadButton.clicked.connect(self.onReload) self.evalTableModel = EvaluationTableModel( self.checkSettingsSavable, plotnames=self.plotnames, analysisNames=self.analysisNames, counterNames=self.counterNames, globalDict=self.globalDict) self.evalTableModel.dataChanged.connect(self.checkSettingsSavable) self.evalTableModel.dataChanged.connect(self.onActiveEvalChanged) self.evalTableView.setModel(self.evalTableModel) self.delegate = ComboBoxDelegate() self.magnitudeDelegate = MagnitudeSpinBoxDelegate() self.camelionDelegate = CamelionDelegate() self.evalTableView.setItemDelegateForColumn(0, self.delegate) self.evalTableView.setItemDelegateForColumn(1, self.magnitudeDelegate) self.evalTableView.setItemDelegateForColumn(2, self.camelionDelegate) self.evalTableView.setItemDelegateForColumn(3, self.delegate) self.evalTableView.setItemDelegateForColumn(6, self.delegate) self.evalTableView.setItemDelegateForColumn(7, self.delegate) self.addEvaluationButton.clicked.connect(self.onAddEvaluation) self.removeEvaluationButton.clicked.connect(self.onRemoveEvaluation) self.evalTableView.selectionModel().currentChanged.connect( self.onActiveEvalChanged) self.evalTableView.resizeColumnsToContents() self.evalParamTable.setupUi(globalDict=self.globalDict) # try: self.setSettings(self.settings) # except AttributeError: # logger.error( "Ignoring exception" ) self.comboBox.addItems(sorted(self.settingsDict.keys())) if self.settingsName and self.comboBox.findText(self.settingsName): self.comboBox.setCurrentIndex( self.comboBox.findText(self.settingsName)) self.comboBox.currentIndexChanged['QString'].connect(self.onLoad) self.comboBox.lineEdit().editingFinished.connect( self.checkSettingsSavable) # Evaluation self.histogramBinsBox.valueChanged.connect(self.onHistogramBinsChanged) self.integrateHistogramCheckBox.stateChanged.connect( self.onIntegrateHistogramClicked) # Timestamps if self.timestampsEnabled: self.binwidthSpinBox.valueChanged.connect( functools.partial(self.onValueChanged, 'binwidth')) self.roiStartSpinBox.valueChanged.connect( functools.partial(self.onValueChanged, 'roiStart')) self.roiWidthSpinBox.valueChanged.connect( functools.partial(self.onValueChanged, 'roiWidth')) self.enableCheckBox.stateChanged.connect( functools.partial(self.onStateChanged, 'enableTimestamps')) self.saveRawDataCheckBox.stateChanged.connect( functools.partial(self.onStateChanged, 'saveRawData')) self.integrateCombo.currentIndexChanged[int].connect( self.onIntegrationChanged) self.channelSpinBox.valueChanged.connect( functools.partial(self.onBareValueChanged, 'timestampsChannel')) else: self.settings.enableTimestamps = False timestampsWidget = self.toolBox.widget(1) self.toolBox.removeItem(1) #Remove timestamps from toolBox timestampsWidget.deleteLater() #Delete timestamps widget self.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu) self.autoSaveAction = QtWidgets.QAction("auto save", self) self.autoSaveAction.setCheckable(True) self.autoSaveAction.setChecked(self.parameters.autoSave) self.autoSaveAction.triggered.connect(self.onAutoSave) self.addAction(self.autoSaveAction) self.currentEvaluationChanged.emit(self.settingsName) def evaluate(self, globalName): self.evalParamTable.evaluate(globalName) def onAutoSave(self, checked): self.parameters.autoSave = checked if self.parameters.autoSave: self.onSave() def setAnalysisNames(self, names): self.evalTableModel.setAnalysisNames(names) def setSettings(self, settings): self.settings = copy.deepcopy(settings) # Evaluation self.histogramBinsBox.setValue(self.settings.histogramBins) self.integrateHistogramCheckBox.setChecked( self.settings.integrateHistogram) # Timestamps if self.timestampsEnabled: self.enableCheckBox.setChecked(self.settings.enableTimestamps) self.saveRawDataCheckBox.setChecked(self.settings.saveRawData) self.binwidthSpinBox.setValue(self.settings.binwidth) self.roiStartSpinBox.setValue(self.settings.roiStart) self.roiWidthSpinBox.setValue(self.settings.roiWidth) self.integrateCombo.setCurrentIndex( self.settings.integrateTimestamps) self.channelSpinBox.setValue(self.settings.timestampsChannel) self.checkSettingsSavable() self.evalAlgorithmList = [] for evaluation in self.settings.evalList: self.addEvaluation(evaluation) assert len(self.settings.evalList) == len( self.evalAlgorithmList ), "EvalList and EvalAlgoithmList length mismatch" self.evalTableModel.setEvalList(self.settings.evalList, self.evalAlgorithmList) self.evalTableView.resizeColumnsToContents() def addEvaluation(self, evaluation): algo = EvaluationAlgorithms[evaluation.evaluation]( globalDict=self.globalDict) algo.subscribe( self.checkSettingsSavable ) # track changes of the algorithms settings so the save status is displayed correctly algo.setSettings(evaluation.settings, evaluation.name) self.evalAlgorithmList.append(algo) def onAddEvaluation(self): evaluation = EvaluationDefinition() evaluation.counter = 0 evaluation.plotname = "Scan Data" #Default to "Scan Data" plot evaluation.evaluation = 'Mean' if 'Mean' in list( EvaluationAlgorithms.keys()) else list( EvaluationAlgorithms.keys())[0] self.settings.evalList.append(evaluation) self.addEvaluation(evaluation) assert len(self.settings.evalList) == len( self.evalAlgorithmList ), "EvalList and EvalAlgoithmList length mismatch" self.evalTableModel.setEvalList(self.settings.evalList, self.evalAlgorithmList) self.evalTableView.resizeColumnsToContents() self.evalTableView.horizontalHeader().setStretchLastSection(True) self.checkSettingsSavable() def removeEvaluation(self, index): del self.evalAlgorithmList[index] def onRemoveEvaluation(self): for index in sorted(unique( [i.row() for i in self.evalTableView.selectedIndexes()]), reverse=True): del self.settings.evalList[index] self.removeEvaluation(index) assert len(self.settings.evalList) == len( self.evalAlgorithmList ), "EvalList and EvalAlgoithmList length mismatch" self.evalTableModel.setEvalList(self.settings.evalList, self.evalAlgorithmList) self.checkSettingsSavable() def onActiveEvalChanged(self, modelIndex, modelIndex2): eval = self.evalAlgorithmList[modelIndex.row()] self.evalParamTable.setParameters(eval.parameters()) try: self.evalParamTable.valueChanged.disconnect() except Exception: pass self.evalParamTable.valueChanged.connect(eval.update) self.evalParamTable.evaluate() def checkSettingsSavable(self, savable=None): if not isinstance(savable, bool): currentText = str(self.comboBox.currentText()) try: if currentText is None or currentText == "": savable = False elif self.settingsName and self.settingsName in self.settingsDict: try: savable = self.settingsDict[ self. settingsName] != self.settings or currentText != self.settingsName except AttributeError: savable = True else: savable = True if self.parameters.autoSave and savable: self.onSave() savable = False except ValueError: pass self.saveButton.setEnabled(savable) def onStateChanged(self, attribute, state): setattr(self.settings, attribute, (state == QtCore.Qt.Checked)) self.checkSettingsSavable() def onValueChanged(self, attribute, value): setattr(self.settings, attribute, Q(value)) self.checkSettingsSavable() def onBareValueChanged(self, attribute, value): setattr(self.settings, attribute, value) self.checkSettingsSavable() def getEvaluation(self): evaluation = copy.deepcopy(self.settings) evaluation.evalAlgorithmList = copy.deepcopy(self.evalAlgorithmList) evaluation.settingsName = self.settingsName return evaluation def saveConfig(self): self.config[self.configname] = self.settings self.config[self.configname + '.dict'] = self.settingsDict self.config[self.configname + '.settingsName'] = self.settingsName self.config[self.configname + '.parameters'] = self.parameters def onSave(self): self.settingsName = str(self.comboBox.currentText()) if self.settingsName != '': if self.settingsName not in self.settingsDict: if self.comboBox.findText(self.settingsName) == -1: self.comboBox.addItem(self.settingsName) self.settingsDict[self.settingsName] = copy.deepcopy(self.settings) self.evaluationConfigurationChanged.emit(self.settingsDict) self.checkSettingsSavable(False) self.currentEvaluationChanged.emit(self.settingsName) def onRemove(self): name = str(self.comboBox.currentText()) if name != '': if name in self.settingsDict: self.settingsDict.pop(name) idx = self.comboBox.findText(name) if idx >= 0: self.comboBox.removeItem(idx) self.evaluationConfigurationChanged.emit(self.settingsDict) def onLoad(self, name): self.settingsName = str(name) if self.settingsName != '' and self.settingsName in self.settingsDict: self.setSettings(self.settingsDict[self.settingsName]) self.checkSettingsSavable() self.currentEvaluationChanged.emit(self.settingsName) def loadSetting(self, name): if name and self.comboBox.findText(name) >= 0: self.comboBox.setCurrentIndex(self.comboBox.findText(name)) self.onLoad(name) def onReload(self): self.onLoad(self.comboBox.currentText()) def onIntegrationChanged(self, value): self.settings.integrateTimestamps = value self.checkSettingsSavable() def onAlgorithmValueChanged(self, algo, name, value): self.checkSettingsSavable() def onIntegrateHistogramClicked(self, state): self.settings.integrateHistogram = self.integrateHistogramCheckBox.isChecked( ) self.checkSettingsSavable() def onHistogramBinsChanged(self, bins): self.settings.histogramBins = bins self.checkSettingsSavable() def onAlgorithmNameChanged(self, name): self.checkSettingsSavable() def editEvaluationTable(self, index): if index.column() in [0, 1, 2, 4]: self.evalTableView.edit(index) def evaluationNames(self): return [e.name for e in self.settings.evalList]
class PlottedTrace(object): Styles = enum.enum('lines', 'points', 'linespoints', 'lines_with_errorbars', 'points_with_errorbars', 'linepoints_with_errorbars') PointsStyles = [ 1, 4 ] Types = enum.enum('default', 'steps') def __init__(self,Trace,graphicsView,penList=None,pen=0,style=None,plotType=None, xColumn='x',yColumn='y',topColumn='top',bottomColumn='bottom',heightColumn='height', rawColumn='raw', tracePlotting=None, name="", xAxisLabel = None, xAxisUnit = None, yAxisLabel = None, yAxisUnit = None, fill=True, windowName=None): self.category = None self.fill = fill if penList is None: penList = pens.penList self.penList = penList self._graphicsView = graphicsView if self._graphicsView is not None: if not hasattr(self._graphicsView, 'penUsageDict'): self._graphicsView.penUsageDict = [0]*len(pens.penList) self.penUsageDict = self._graphicsView.penUsageDict # TODO circular reference self.trace = Trace self.curve = None self.fitcurve = None self.errorBarItem = None self.style = self.Styles.lines if style is None else style self.type = self.Types.default if plotType is None else plotType self.curvePen = 0 self.name = name self.xAxisLabel = xAxisLabel self.xAxisUnit = xAxisUnit self.yAxisLabel = yAxisLabel self.yAxisUnit = yAxisUnit self.lastPlotTime = time.time() self.needsReplot = False # we use pointers to the relevant columns in trace if tracePlotting is not None: self.tracePlotting = tracePlotting self._xColumn = tracePlotting.xColumn self._yColumn = tracePlotting.yColumn self._topColumn = tracePlotting.topColumn self._bottomColumn = tracePlotting.bottomColumn self._heightColumn = tracePlotting.heightColumn self._rawColumn = tracePlotting.rawColumn self.type = tracePlotting.type self.xAxisLabel = tracePlotting.xAxisLabel self.xAxisUnit = tracePlotting.xAxisUnit self.windowName = tracePlotting.windowName elif self.trace is not None: self._xColumn = xColumn self._yColumn = yColumn self._topColumn = topColumn self._bottomColumn = bottomColumn self._heightColumn = heightColumn self._rawColumn = rawColumn self.tracePlotting = TracePlotting(xColumn=self._xColumn, yColumn=self._yColumn, topColumn=self._topColumn, bottomColumn=self._bottomColumn, # TODO double check for reference heightColumn=self._heightColumn, rawColumn=self._rawColumn, name=name, type_=self.type, xAxisUnit=self.xAxisUnit, xAxisLabel=self.xAxisLabel, windowName=windowName ) self.trace.addTracePlotting( self.tracePlotting ) # TODO check for reference self.windowName = windowName self.stylesLookup = { self.Styles.lines: partial( WeakMethod.ref(self.plotLines), errorbars=False), self.Styles.points: partial( WeakMethod.ref(self.plotPoints), errorbars=False), self.Styles.linespoints: partial( WeakMethod.ref(self.plotLinespoints), errorbars=False), self.Styles.lines_with_errorbars: partial( WeakMethod.ref(self.plotLines), errorbars=True), self.Styles.points_with_errorbars: partial( WeakMethod.ref(self.plotPoints), errorbars=True), self.Styles.linepoints_with_errorbars: partial( WeakMethod.ref(self.plotLinespoints), errorbars=True)} def setGraphicsView(self, graphicsView, name): if graphicsView!=self._graphicsView: self.removePlots() self._graphicsView = graphicsView self.windowName = name self.tracePlotting.windowName = name self.plot() @property def okToDelete(self): """A trace is OK to delete if it has been finalized""" return 'traceFinalized' in self.trace.description @property def traceCollection(self): """This is to make the code more readable while maintaining backwards compatibility. self.traceCollection is the same thing as self.trace.""" return self.trace @traceCollection.setter def traceCollection(self, t): self.trace = t @property def hasTopColumn(self): return self._topColumn and self._topColumn in self.trace @property def hasBottomColumn(self): return self._bottomColumn and self._bottomColumn in self.trace @property def hasHeightColumn(self): return self._heightColumn and self._heightColumn in self.trace @property def hasRawColumn(self): return self._rawColumn and self._rawColumn in self.trace def timeintervalAppend(self, timeinterval, maxPoints=0): self.trace.timeintervalAppend(timeinterval, maxPoints) @property def timeinterval(self): return self.trace.timeinterval @timeinterval.setter def timeinterval(self, val): self.trace.timeinterval = val @property def x(self): return self.trace[self._xColumn] @x.setter def x(self, column): self.trace[self._xColumn] = column @property def y(self): return self.trace[self._yColumn] @y.setter def y(self, column): self.trace[self._yColumn] = column @property def top(self): return self.trace[self._topColumn] @top.setter def top(self, column): self.trace[self._topColumn] = column @property def bottom(self): return self.trace[self._bottomColumn] @bottom.setter def bottom(self, column): self.trace[self._bottomColumn] = column @property def height(self): return self.trace[self._heightColumn] @height.setter def height(self, column): self.trace[self._heightColumn] = column @property def raw(self): return self.trace[self._rawColumn] @raw.setter def raw(self, column): self.trace[self._rawColumn] = column @property def isPlotted(self): return self.curvePen>0 @isPlotted.setter def isPlotted(self, plotted): if plotted != (self.curvePen>0): self.plot( -1 if plotted else 0 ) def removePlots(self): if self._graphicsView is not None: if self.curve is not None: self._graphicsView.removeItem(self.curve) self.curve = None self.penUsageDict[self.curvePen] -= 1 if self.errorBarItem is not None: self._graphicsView.removeItem(self.errorBarItem) self.errorBarItem = None if self.fitcurve is not None: self._graphicsView.removeItem(self.fitcurve) self.fitcurve = None def plotFitfunction(self, penindex): if self.fitFunction and self._graphicsView is not None: self.fitFunctionPenIndex = penindex self.fitx = numpy.linspace(numpy.min(self.x), numpy.max(self.x), 300) self.fity = self.fitFunction.value(self.fitx) if self.fitcurve is not None: self._graphicsView.removeItem(self.fitcurve) self.fitcurve = self._graphicsView.plot(self.fitx, self.fity, pen=self.penList[penindex][0]) def replotFitFunction(self): if self.fitFunction and self._graphicsView is not None: self.fitx = numpy.linspace(numpy.min(self.x), numpy.max(self.x), 300) self.fity = self.fitFunction.value(self.fitx) if self.fitcurve is not None: self.fitcurve.setData( self.fitx, self.fity ) else: self.__dict__.setdefault( 'fitFunctionPenIndex', self.curvePen ) self.fitcurve = self._graphicsView.plot(self.fitx, self.fity, pen=self.penList[self.fitFunctionPenIndex][0]) def plotStepsFitfunction(self, penindex): if self.fitFunction and self._graphicsView is not None: self.fitFunctionPenIndex = penindex self.fitx = numpy.linspace(numpy.min(self.x)+0.5, numpy.max(self.x)-1.5, len(self.x)-1 ) self.fity = self.fitFunction.value(self.fitx) if self.fitcurve is not None: self._graphicsView.removeItem(self.fitcurve) self.fitcurve = self._graphicsView.plot(self.fitx, self.fity, pen=self.penList[penindex][0]) def replotStepsFitFunction(self): if self.fitFunction and self._graphicsView is not None: self.fitx = numpy.linspace(numpy.min(self.x)+0.5, numpy.max(self.x)-1.5, len(self.x)-1 ) self.fity = self.fitFunction.value(self.fitx) if self.fitcurve is not None: self.fitcurve.setData( self.fitx, self.fity ) else: self.__dict__.setdefault( 'fitFunctionPenIndex', self.curvePen ) self.fitcurve = self._graphicsView.plot(self.fitx, self.fity, pen=self.penList[self.fitFunctionPenIndex][0]) def plotErrorBars(self, penindex): if self._graphicsView is not None: if self.hasHeightColumn: self.errorBarItem = ErrorBarItem(x=(self.x), y=(self.y), height=(self.height), pen=self.penList[penindex][0]) elif self.hasTopColumn and self.hasBottomColumn: self.errorBarItem = ErrorBarItem(x=(self.x), y=(self.y), top=(self.top), bottom=(self.bottom), pen=self.penList[penindex][0]) self._graphicsView.addItem(self.errorBarItem) def plotLines(self,penindex, errorbars=True ): if self._graphicsView is not None: if errorbars: self.plotErrorBars(penindex) x, y = sort_lists_by((self.x, self.y), key_list=0) if len(self.x) > 0 else (self.x, self.y) self.curve = self._graphicsView.plot( numpy.array(x), numpy.array(y), pen=self.penList[penindex][0]) if self.xAxisLabel: if self.xAxisUnit: self._graphicsView.setLabel('bottom', text = "{0} ({1})".format(self.xAxisLabel, self.xAxisUnit)) else: self._graphicsView.setLabel('bottom', text = "{0}".format(self.xAxisLabel)) def plotPoints(self,penindex, errorbars=True ): if self._graphicsView is not None: if errorbars: self.plotErrorBars(penindex) self.curve = self._graphicsView.plot((self.x), (self.y), pen=None, symbol=self.penList[penindex][1], symbolPen=self.penList[penindex][2], symbolBrush=self.penList[penindex][3]) if self.xAxisLabel: if self.xAxisUnit: self._graphicsView.setLabel('bottom', text = "{0} ({1})".format(self.xAxisLabel, self.xAxisUnit)) else: self._graphicsView.setLabel('bottom', text = "{0}".format(self.xAxisLabel)) def plotLinespoints(self,penindex, errorbars=True ): if self._graphicsView is not None: if errorbars: self.plotErrorBars(penindex) x, y = sort_lists_by( (self.x, self.y), key_list=0) self.curve = self._graphicsView.plot( numpy.array(x), numpy.array(y), pen=self.penList[penindex][0], symbol=self.penList[penindex][1], symbolPen=self.penList[penindex][2], symbolBrush=self.penList[penindex][3]) if self.xAxisLabel: if self.xAxisUnit: self._graphicsView.setLabel('bottom', text = "{0} ({1})".format(self.xAxisLabel, self.xAxisUnit)) else: self._graphicsView.setLabel('bottom', text = "{0}".format(self.xAxisLabel)) def plotSteps(self, penindex): if self._graphicsView is not None: mycolor = list(self.penList[penindex][4]) mycolor[3] = 80 self.curve = PlotCurveItem(self.x, self.y, stepMode=True, fillLevel=0 if self.fill else None, brush=mycolor if self.fill else None, pen=self.penList[penindex][0]) if self.xAxisLabel: if self.xAxisUnit: self._graphicsView.setLabel('bottom', text = "{0} ({1})".format(self.xAxisLabel, self.xAxisUnit)) else: self._graphicsView.setLabel('bottom', text = "{0}".format(self.xAxisLabel)) self._graphicsView.addItem( self.curve ) self.curvePen = penindex def plot(self,penindex=-1,style=None): if self._graphicsView is not None: self.style = self.style if style is None else style self.removePlots() penindex = { -2: self.__dict__.get('curvePen', 0), -1: sorted(zip(self.penUsageDict, list(range(len(self.penUsageDict)))))[1][1] }.get(penindex, penindex) if penindex>0: if self.type==self.Types.default: self.plotFitfunction(penindex) self.stylesLookup.get(self.style, self.plotLines)(penindex) elif self.type ==self.Types.steps: self.plotStepsFitfunction(penindex+1) self.plotSteps(penindex) self.penUsageDict[penindex] += 1 self.curvePen = penindex def replot(self): if self._graphicsView is not None: if len(self.x)>500 and time.time()-self.lastPlotTime<len(self.x)/500.: if not self.needsReplot: self.needsReplot = True QtCore.QTimer.singleShot(len(self.x)*2, self._replot) else: self._replot() def _replot(self): if hasattr(self, 'curve') and self.curve is not None: if self.style not in self.PointsStyles and self.type==self.Types.default: x, y = sort_lists_by((self.x, self.y), key_list=0) if len(self.x) > 0 else (self.x, self.y) self.curve.setData( numpy.array(x), numpy.array(y) ) else: self.curve.setData( (self.x), (self.y) ) if hasattr(self, 'errorBarItem') and self.errorBarItem is not None: if self.hasHeightColumn: self.errorBarItem.setData(x=(self.x), y=(self.y), height=(self.trace.height)) else: self.errorBarItem.setOpts(x=(self.x), y=(self.y), top=(self.top), bottom=(self.bottom)) if self.fitFunction is not None: if self.type==self.Types.default: self.replotFitFunction() elif self.type==self.Types.steps: self.replotStepsFitFunction() elif self.fitcurve is not None: self._graphicsView.removeItem(self.fitcurve) self.fitcurve = None self.lastPlotTime = time.time() self.needsReplot = False def setView(self, graphicsView ): self.removePlots() self._graphicsView = graphicsView self.plot(-1) @property def fitFunction(self): return self.tracePlotting.fitFunction if self.tracePlotting else None @fitFunction.setter def fitFunction(self, fitfunction): self.tracePlotting.fitFunction = fitfunction
def __init__(self, channel, settings, globalDict, parent=None): super(AWGSegmentModel, self).__init__(parent) self.channel = channel self.settings = settings self.globalDict = globalDict self.root = self.settings.channelSettingsList[ self.channel]['segmentDataRoot'] self.columnNames = ['enabled', 'equation', 'duration', 'repetitions'] self.numColumns = len(self.columnNames) self.column = enum(*self.columnNames) self.allowDeletion = True segmentSetBG = QtGui.QColor(255, 253, 222, 255) self.headerLookup = { (QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole, self.column.enabled): "", (QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole, self.column.equation): "Equation", (QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole, self.column.duration): "Duration", (QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole, self.column.repetitions): "Repetitions" } self.dataLookup = { (QtCore.Qt.CheckStateRole, self.column.enabled): lambda node: QtCore.Qt.Checked if node.enabled else QtCore.Qt.Unchecked, (QtCore.Qt.DisplayRole, self.column.equation): lambda node: node.equation if node.nodeType == nodeTypes.segment else None, (QtCore.Qt.DisplayRole, self.column.duration): lambda node: node.duration if node.nodeType == nodeTypes.segment else None, (QtCore.Qt.DisplayRole, self.column.repetitions): lambda node: node.repetitions if node.nodeType == nodeTypes.segmentSet else None, (QtCore.Qt.BackgroundColorRole, self.column.enabled): lambda node: segmentSetBG if node.nodeType == nodeTypes.segmentSet else None, (QtCore.Qt.BackgroundColorRole, self.column.equation): lambda node: segmentSetBG if node.nodeType == nodeTypes.segmentSet else None, (QtCore.Qt.BackgroundColorRole, self.column.duration): lambda node: segmentSetBG if node.nodeType == nodeTypes.segmentSet else None, (QtCore.Qt.BackgroundColorRole, self.column.repetitions): lambda node: segmentSetBG if node.nodeType == nodeTypes.segmentSet else None, (QtCore.Qt.EditRole, self.column.equation): lambda node: node.equation if node.nodeType == nodeTypes.segment else None, (QtCore.Qt.EditRole, self.column.duration): lambda node: node.duration if node.nodeType == nodeTypes.segment else None, (QtCore.Qt.EditRole, self.column.repetitions): lambda node: node.repetitions if node.nodeType == nodeTypes.segmentSet else None } self.setDataLookup = { (QtCore.Qt.CheckStateRole, self.column.enabled): lambda index, value: self.setEnabled(index, value), (QtCore.Qt.EditRole, self.column.equation): lambda index, value: self.setValue(index, value, 'equation'), (QtCore.Qt.EditRole, self.column.duration): lambda index, value: self.setValue(index, value, 'duration'), (QtCore.Qt.EditRole, self.column.repetitions): lambda index, value: self.setValue(index, value, 'repetitions'), }
class GateSequenceUi(Form, Base): Mode = enum('FullList', 'Gate') valueChanged = QtCore.pyqtSignal() def __init__(self,parent=None): Form.__init__(self) Base.__init__(self, parent) def postInit(self, name, config, pulseProgram): self.config = config self.configname = "GateSequenceUi."+name self.settings = self.config.get(self.configname, Settings()) self.gatedef = GateDefinition() self.gateSequenceContainer = GateSequenceContainer(self.gatedef) self.gateSequenceCompiler = GateSequenceCompiler(pulseProgram) def setupUi(self, parent): super(GateSequenceUi, self).setupUi(parent) self.setSettings( self.settings ) self.GateSequenceEnableCheckBox.stateChanged.connect( self.onEnableChanged ) self.GateDefinitionButton.clicked.connect( self.onLoadGateDefinition ) self.GateSequenceButton.clicked.connect( self.onLoadGateSequenceList ) self.FullListRadioButton.toggled.connect( self.onRadioButtonToggled ) self.GateEdit.editingFinished.connect( self.onGateEditChanged ) self.StartAddressBox.currentIndexChanged['QString'].connect( self.onStartAddressParam ) self.repetitionSpinBox.valueChanged.connect( self.onRepetitionChanged ) self.GateSequenceBox.currentIndexChanged[str].connect( self.onGateSequenceChanged ) self.GateDefinitionBox.currentIndexChanged[str].connect( self.onGateDefinitionChanged ) self.debugCheckBox.stateChanged.connect( self.onDebugChanged ) self.project = getProject() self.defaultGateSequencesDir = self.project.configDir+'/GateSequences' if not os.path.exists(self.defaultGateSequencesDir): exampleGateSequencesDir = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', 'config/GateSequences')) #/IonControl/config/GateSequences directory shutil.copytree(exampleGateSequencesDir, self.defaultGateSequencesDir) #Copy over all example gate sequence files def getSettings(self): logger = logging.getLogger(__name__) logger.debug( "GateSequenceUi GetSettings {0}".format(self.settings.__dict__) ) return self.settings def setSettings(self, settings): logger = logging.getLogger(__name__) logger.debug( str( settings) ) logger.debug( "GateSequenceUi SetSettings {0}".format( settings.__dict__ ) ) self.settings = settings self.GateSequenceEnableCheckBox.setChecked( self.settings.enabled ) self.GateSequenceFrame.setEnabled( self.settings.enabled ) self.GateEdit.setText( ", ".join(self.settings.gate )) self.repetitionSpinBox.setValue( self.settings.thisSequenceRepetition ) if self.settings.startAddressParam: self.StartAddressBox.setCurrentIndex(self.StartAddressBox.findText(self.settings.startAddressParam) ) else: self.settings.startAddressParam = str(self.StartAddressBox.currentText()) self.settings.startAddressParam = str(self.settings.startAddressParam) try: updateComboBoxItems(self.GateDefinitionBox, list(self.settings.gateDefinitionCache.keys())) updateComboBoxItems(self.GateSequenceBox, list(self.settings.gateSequenceCache.keys())) self.updateDatastructures() except IOError as err: logger.warning( "{0} during loading of GateSequence Files, ignored.".format(err) ) with BlockSignals(self.FullListRadioButton) as w: if self.settings.active == self.Mode.FullList: self.FullListRadioButton.setChecked(True) elif self.settings.active == self.Mode.Gate: self.GateRadioButton.setChecked(True) def updateDatastructures(self): if self.settings.enabled: if self.settings.gateDefinition and self.settings.gateDefinition in self.settings.gateDefinitionCache: self.loadGateDefinition( self.settings.gateDefinitionCache[self.settings.gateDefinition] ) self.GateDefinitionBox.setCurrentIndex(self.GateDefinitionBox.findText(self.settings.gateDefinition)) if self.settings.gateSequence and self.settings.gateSequence in self.settings.gateSequenceCache: self.loadGateSequenceList( self.settings.gateSequenceCache[self.settings.gateSequence] ) self.GateSequenceBox.setCurrentIndex(self.GateSequenceBox.findText(self.settings.gateSequence)) else: self.clearGateDefinition() self.clearGateSequenceList() def documentationString(self): return repr(self.settings) def descritpion(self): return self.settings.description() def onGateDefinitionChanged(self, name): name = str(name) if name in self.settings.gateDefinitionCache: self.loadGateDefinition( self.settings.gateDefinitionCache[name] ) self.valueChanged.emit() def onGateSequenceChanged(self, name): name = str(name) if name in self.settings.gateSequenceCache: self.loadGateSequenceList( self.settings.gateSequenceCache[name] ) self.valueChanged.emit() def onRepetitionChanged(self, value): self.settings.thisSequenceRepetition = value self.valueChanged.emit() def onStartAddressParam(self, name): self.settings.startAddressParam = str(name) self.valueChanged.emit() def onEnableChanged(self, state): self.settings.enabled = state == QtCore.Qt.Checked self.GateSequenceFrame.setEnabled( self.settings.enabled ) self.updateDatastructures() self.valueChanged.emit() def onDebugChanged(self, state): self.settings.debug = state == QtCore.Qt.Checked self.valueChanged.emit() def close(self): self.config[self.configname] = self.settings def onLoadGateDefinition(self): path, _ = QtWidgets.QFileDialog.getOpenFileName(self, "Open Gate definition file:", self.defaultGateSequencesDir) if path!="": filedir, filename = os.path.split(path) self.settings.lastDir = filedir self.loadGateDefinition(path) if filename not in self.settings.gateDefinitionCache: self.settings.gateDefinitionCache[filename] = path self.GateDefinitionBox.addItem(filename) self.GateDefinitionBox.setCurrentIndex( self.GateDefinitionBox.findText(filename)) self.valueChanged.emit() def loadGateDefinition(self, path): self.gatedef.loadGateDefinition(path) _, filename = os.path.split(path) self.settings.gateDefinition = filename self.GateDefinitionBox.setCurrentIndex(self.GateDefinitionBox.findText(filename)) self.gatedef.printGates() self.valueChanged.emit() def clearGateDefinition(self): self.gatedef.loadGateDefinition(None) self.GateDefinitionBox.setCurrentIndex(-1) self.valueChanged.emit() def onLoadGateSequenceList(self): path, _ = QtWidgets.QFileDialog.getOpenFileName(self, "Open Gate Set file:", self.defaultGateSequencesDir) if path!="": filedir, filename = os.path.split(path) self.settings.lastDir = filedir self.loadGateSequenceList(path) if filename not in self.settings.gateSequenceCache: self.settings.gateSequenceCache[filename] = path self.GateSequenceBox.addItem(filename) self.GateSequenceBox.setCurrentIndex( self.GateSequenceBox.findText(filename)) self.valueChanged.emit() def loadGateSequenceList(self, path): logger = logging.getLogger(__name__) self.gateSequenceContainer.loadXml(path) logger.debug( "loaded {0} gateSequences from {1}.".format(len(self.gateSequenceContainer.GateSequenceDict), path) ) _, filename = os.path.split(path) self.settings.gateSequence = filename self.GateSequenceBox.setCurrentIndex(self.GateSequenceBox.findText(filename)) def clearGateSequenceList(self): self.gateSequenceContainer.loadXml(None) self.GateSequenceBox.setCurrentIndex(-1) def onGateEditChanged(self): self.settings.gate = list(map(operator.methodcaller('strip'), str(self.GateEdit.text()).split(','))) self.GateEdit.setText( ", ".join(self.settings.gate )) self.valueChanged.emit() def onRadioButtonToggled(self): if self.FullListRadioButton.isChecked(): self.settings.active = self.Mode.FullList else: self.settings.active = self.Mode.Gate self.valueChanged.emit() def gateSequenceScanData(self): if self.settings.active == self.Mode.FullList: address, data = self.gateSequenceCompiler.gateSequencesCompile( self.gateSequenceContainer ) else: self.gateSequenceCompiler.gateCompile( self.gateSequenceContainer.gateDefinition ) data = self.gateSequenceCompiler.gateSequenceCompile( self.settings.gate ) address = [0]*self.settings.thisSequenceRepetition return address, data, self.settings def gateSequenceAttributes(self): if self.settings.active == self.Mode.FullList: return list(self.gateSequenceContainer.GateSequenceAttributes.values()) return None def setVariables(self, variabledict): self.variabledict = variabledict #oldParameterName = self.StartAddressBox.currentText() self.StartAddressBox.clear() for _, var in iter(sorted(variabledict.items())): if var.type == "address": self.StartAddressBox.addItem(var.name) if self.settings.startAddressParam: self.StartAddressBox.setCurrentIndex(self.StartAddressBox.findText(self.settings.startAddressParam) ) else: self.settings.startAddressParam = self.StartAddressBox.currentText()
class Scan: ScanMode = enum('ParameterScan', 'StepInPlace', 'GateSequenceScan', 'Freerunning') ScanType = enum('LinearStartToStop', 'LinearStopToStart', 'Randomized', 'CenterOut') def __init__(self): # Scan self.scanParameter = None self.parallelInternalScanParameter = "None" self.scanTarget = None self.start = 0 self.stop = 0 self.center = 0 self.span = 0 self.steps = 0 self.stepSize = 1 self.stepsSelect = 0 self.scantype = 0 self.scanMode = 0 self.filename = "" self.histogramFilename = "" self.autoSave = True self.histogramSave = False self.xUnit = "" self.xExpression = "" self.loadPP = False self.loadPPName = "" self.saveRawData = False self.rawFilename = "" # GateSequence Settings self.gateSequenceSettings = GateSequenceUi.Settings() self.scanSegmentList = [ScanSegmentDefinition()] self.maxPoints = 0 def __setstate__(self, state): """this function ensures that the given fields are present in the class object after unpickling. Only new class attributes need to be added here. """ self.__dict__ = state self.__dict__.setdefault('xUnit', '') self.__dict__.setdefault('xExpression', '') self.__dict__.setdefault('loadPP', False) self.__dict__.setdefault('loadPPName', "") self.__dict__.setdefault('stepSize', 1) self.__dict__.setdefault('center', 0) self.__dict__.setdefault('span', 0) self.__dict__.setdefault('gateSequenceSettings', GateSequenceUi.Settings()) self.__dict__.setdefault('scanSegmentList', [ScanSegmentDefinition()]) self.__dict__.setdefault('externalScanParameter', None) self.__dict__.setdefault('histogramFilename', "") self.__dict__.setdefault('histogramSave', False) self.__dict__.setdefault('scanTarget', None) self.__dict__.setdefault('saveRawData', False) self.__dict__.setdefault('rawFilename', "") self.__dict__.setdefault('maxPoints', 0) self.__dict__.setdefault('parallelInternalScanParameter', "None") def __eq__(self, other): try: equal = isinstance(other, self.__class__) and tuple( getattr(self, field) for field in self.stateFields) == tuple( getattr(other, field) for field in self.stateFields) except ValueError: equal = False return equal def __ne__(self, other): return not self == other def __hash__(self): return hash(tuple(getattr(self, field) for field in self.stateFields)) stateFields = [ 'scanParameter', 'scanTarget', 'scantype', 'scanMode', 'filename', 'histogramFilename', 'autoSave', 'histogramSave', 'xUnit', 'xExpression', 'loadPP', 'loadPPName', 'gateSequenceSettings', 'scanSegmentList', 'saveRawData', 'rawFilename', 'maxPoints', 'parallelInternalScanParameter' ] documentationList = [ 'scanParameter', 'scanTarget', 'scantype', 'scanMode', 'xUnit', 'xExpression', 'loadPP', 'loadPPName', 'parallelInternalScanParameter' ] def documentationString(self): r = "\r\n".join([ "{0}\t{1}".format(field, getattr(self, field)) for field in self.documentationList ]) r += self.gateSequenceSettings.documentationString() return r def description(self): desc = dict(((field, getattr(self, field)) for field in self.documentationList)) return desc def evaluate(self, globalDictionary): return any([ segment.evaluate(globalDictionary) for segment in self.scanSegmentList ])
class TraceControl(Form, Base): StateOptions = enum('stopped', 'running', 'single') newDataAvailable = QtCore.pyqtSignal( object ) def __init__(self,controller,config,traceui,plotDict,parent=None): Base.__init__(self, parent) Form.__init__(self) self.controller = controller self.config = config self.traceSettings = self.config.get("TraceControl.Settings", TraceSettings()) self.state = self.StateOptions.stopped self.traceui = traceui self.plotDict = plotDict self.controller.scopeDataAvailable.connect( self.onData ) self.trace = None self.trace = None self.errorSigCurve = None self.freqCurve = None self.lockSettings = None def setupSpinBox(self, localname, settingsname, updatefunc, unit ): box = getattr(self, localname) value = getattr(self.traceSettings, settingsname) box.setValue( value ) box.dimension = unit box.valueChanged.connect( updatefunc ) updatefunc( value ) def setupUi(self): Form.setupUi(self, self) self.setupSpinBox('magNumberSamples', 'samples', self.setSamples, '') self.setupSpinBox('magSubsample', 'subsample', self.setSubSample, '') self.setupSpinBox('magTriggerLevel', 'triggerLevel', self.setTriggerLevel, 'V') self.comboTriggerMode.currentIndexChanged[int].connect( self.setTriggerMode ) self.comboTriggerMode.setCurrentIndex( self.traceSettings.triggerMode ) self.runButton.clicked.connect( self.onRun ) self.singleButton.clicked.connect( self.onSingle ) self.stopButton.clicked.connect(self.onStop) self.addTraceButton.clicked.connect( self.onAddTrace ) self.initPlotCombo( self.frequencyPlotCombo, 'frequencyPlot', self.onChangeFrequencyPlot) self.initPlotCombo( self.errorSigPlotCombo, 'errorSigPlot', self.onChangeErrorSigPlot) def initPlotCombo(self, combo, plotAttrName, onChange ): combo.addItems( list(self.plotDict.keys()) ) plotName = getattr(self.traceSettings, plotAttrName) if plotName is not None and plotName in self.plotDict: combo.setCurrentIndex( combo.findText(plotName)) else: setattr( self.traceSettings, plotAttrName, str( combo.currentText()) ) combo.currentIndexChanged[str].connect( onChange ) def onChangeFrequencyPlot(self, name): name = str(name) if name!=self.traceSettings.frequencyPlot and name in self.plotDict: self.traceSettings.frequencyPlot = name if self.freqCurve is not None: self.freqCurve.setView( self.plotDict[name]['view']) def onChangeErrorSigPlot(self, name): name = str(name) if name!=self.traceSettings.errorSigPlot and name in self.plotDict: self.traceSettings.errorSigPlot = name if self.errorSigCurve is not None: self.errorSigCurve.setView( self.plotDict[name]['view']) def onControlChanged(self, value): self.lockSettings = value def setState(self, state): self.state = state self.statusLabel.setText( self.StateOptions.reverse_mapping[self.state] ) def onData(self, data): if data.errorSig and data.frequency: errorSig = list(map( binToVoltageV, data.errorSig )) if self.trace is None: self.trace = TraceCollection() self.trace.name = "Scope" self.trace.x = numpy.arange(len(errorSig)) * (sampleTime.m_as('us') * (1 + int(self.traceSettings.subsample))) self.trace.y = numpy.array( errorSig ) if self.errorSigCurve is None: self.errorSigCurve = PlottedTrace(self.trace, self.plotDict[self.traceSettings.errorSigPlot]['view'], pen=-1, style=PlottedTrace.Styles.lines, name="Error Signal", #@UndefinedVariable windowName=self.traceSettings.errorSigPlot) self.errorSigCurve.plot() self.traceui.addTrace( self.errorSigCurve, pen=-1 ) else: self.errorSigCurve.replot() self.newDataAvailable.emit( self.trace ) frequency = list(map( binToFreqHz, data.frequency )) self.trace['freq'] = numpy.array( frequency ) if self.freqCurve is None: self.freqCurve = PlottedTrace(self.trace, self.plotDict[self.traceSettings.frequencyPlot]['view'], pen=-1, style=PlottedTrace.Styles.lines, name="Frequency", #@UndefinedVariable xColumn='x', yColumn='freq', windowName=self.traceSettings.frequencyPlot ) self.freqCurve.plot() self.traceui.addTrace( self.freqCurve, pen=-1 ) else: self.freqCurve.replot() if self.state==self.StateOptions.running: QtCore.QTimer.singleShot(10, self.delayedArm ) # wait 10ms before re-arming else: self.setState(self.StateOptions.stopped) def delayedArm(self): self.controller.armScope() def onAddTrace(self): if self.errorSigCurve: self.errorSigCurve = None self.trace = None if self.freqCurve: self.freqCurve = None self.trace = None def onPlotConfigurationChanged(self, plotDict): self.plotDict = plotDict if self.traceSettings.frequencyPlot not in self.plotDict: self.traceSettings.frequencyPlot = list(self.plotDict.keys())[0] if self.traceSettings.errorSigPlot not in self.plotDict: self.traceSettings.errorSigPlot = list(self.plotDict.keys())[0] updateComboBoxItems( self.frequencyPlotCombo, list(self.plotDict.keys()) ) updateComboBoxItems( self.errorSigPlotCombo, list(self.plotDict.keys()) ) def onRun(self): self.controller.armScope() self.setState(self.StateOptions.running) def onStop(self): self.setState( self.StateOptions.stopped) def onSingle(self): self.controller.armScope() self.setState( self.StateOptions.single ) def setTriggerMode(self, mode): self.traceSettings.triggerMode = mode self.controller.setTriggerMode(mode) def setTriggerLevel(self, value): self.traceSettings.triggerLevel = value self.controller.setTriggerLevel( voltageToBin(value) ) def setSamples(self, samples): self.traceSettings.samples = samples self.controller.setSamples(int(samples)) def setSubSample(self, subsample): self.traceSettings.subsample = subsample self.controller.setSubSample(int(subsample)) def saveConfig(self): self.config["TraceControl.Settings"] = self.traceSettings
class LockControl(Form, Base): dataChanged = QtCore.pyqtSignal(object) AutoStates = enum('idle', 'autoOffset', 'autoLock') FilterOptions = enum('NoFilter', 'Lowp_50_29', 'Lowp_40_29', 'Low_30_20', 'Lowp_100_29', 'Lowp_200_29', 'Lowp_300_29', 'Lowp_300_13', 'Lowp_200_9', 'Lowp100_17') HarmonicOutputOptions = enum('Off', 'On', 'External') def __init__(self, controller, config, settings, parent=None): Base.__init__(self, parent) Form.__init__(self) self.controller = controller self.config = config self.settings = settings self.lockSettings = self.config.get("LockSettings", LockSettings()) self.autoState = self.AutoStates.idle self.mutex = QtCore.QMutex() def closeEvent(self, e): self.lockServer.quit() def setupSpinBox(self, localname, settingsname, updatefunc, unit): box = getattr(self, localname) value = getattr(self.lockSettings, settingsname) box.setValue(value) box.dimension = unit box.valueChanged.connect(updatefunc) updatefunc(value) def setupUi(self): Form.setupUi(self, self) self.setupSpinBox('magReferenceFreq', 'referenceFrequency', self.setReferenceFrequency, 'MHz') self.setupSpinBox('magReferenceAmpl', 'referenceAmplitude', self.setReferenceAmplitude, '') self.setupSpinBox('magOutputFreq', 'outputFrequency', self.setOutputFrequency, 'MHz') self.setupSpinBox('magOutputAmpl', 'outputAmplitude', self.setOutputAmplitude, '') self.setupSpinBox('magHarmonic', 'harmonic', self.setHarmonic, '') self.setupSpinBox('magErrorsigHarmonic', 'errorsigHarmonic', self.setErrorsigHarmonic, '') self.setupSpinBox('magHarmonicReference', 'harmonicReferenceFrequency', self.setharmonicReferenceFrequency, 'MHz') self.setupSpinBox('magOffset', 'offset', self.setOffset, 'V') self.setupSpinBox('magPCoeff', 'pCoefficient', self.setpCoefficient, '') self.setupSpinBox('magICoeff', 'iCoefficient', self.setiCoefficient, '') self.setupSpinBox('magResonanceFreq', 'resonanceFrequency', self.setResonanceFreq, 'MHz') self.setupSpinBox('magDCThreshold', 'dcThreshold', self.onDCThreshold, 'V') self.filterCombo.addItems(list(self.FilterOptions.mapping.keys())) self.filterCombo.setCurrentIndex(self.lockSettings.filter) self.filterCombo.currentIndexChanged[int].connect(self.onFilterChange) self.harmonicOutputCombo.addItems( list(self.HarmonicOutputOptions.mapping.keys())) self.harmonicOutputCombo.setCurrentIndex( self.lockSettings.harmonicOutput) self.harmonicOutputCombo.currentIndexChanged[int].connect( self.onHarmonicOutputChange) self.autoLockButton.clicked.connect(self.onAutoLock) self.lockButton.clicked.connect(self.onLock) self.unlockButton.clicked.connect(self.onUnlock) self.dataChanged.emit(self.lockSettings) self.dcThresholdBox.setChecked(self.lockSettings.enableDCThreshold) self.dcThresholdBox.stateChanged.connect(self.onDCThresholdEnable) self._setHarmonics() self.lockServer = LockServer(("", 16888), b"yb171", self) self.lockServer.start() def setharmonicReferenceFrequency(self, value): self.lockSettings.harmonicReferenceFrequency = value self.calculateOffset() def onDCThresholdEnable(self, state): self.lockSettings.enableDCThreshold = state == QtCore.Qt.Checked self.onDCThreshold(self.lockSettings.dcThreshold) def onDCThreshold(self, value): binvalue = encode(value, self.settings.onBoardADCEncoding ) if self.lockSettings.enableDCThreshold else 0 self.controller.setDCThreshold(binvalue) self.lockSettings.dcThreshold = value self.dataChanged.emit(self.lockSettings) def onFilterChange(self, filterMode): self.lockSettings.filter = filterMode self.lockSettings.mode = setBit(self.lockSettings.mode, 1, self.lockSettings.filter > 0) self.controller.setFilter(self.lockSettings.filter) self.controller.setMode(self.lockSettings.mode) self.dataChanged.emit(self.lockSettings) def onHarmonicOutputChange(self, outputMode): self.lockSettings.harmonicOutput = outputMode self.lockSettings.mode = setBit(self.lockSettings.mode, 14, outputMode == 1) self.lockSettings.mode = setBit(self.lockSettings.mode, 15, outputMode == 2) self.controller.setMode(self.lockSettings.mode) self.dataChanged.emit(self.lockSettings) def onLock(self): self.lockSettings.mode = setBit(self.lockSettings.mode, 0, True) self.controller.setMode(self.lockSettings.mode) def onUnlock(self): self.lockSettings.mode = setBit(self.lockSettings.mode, 0, False) self.controller.setMode(self.lockSettings.mode) def onAutoLock(self): self.autoOffset() def setReferenceFrequency(self, value): binvalue = freqToBin(value) self.controller.setReferenceFrequency(binvalue) self.lockSettings.referenceFrequency = value self.dataChanged.emit(self.lockSettings) self.calculateOffset() def setResonanceFreq(self, value): self.lockSettings.resonanceFrequency = value self.calculateOffset() def calculateOffset(self): refGTcombLine = True #True if the reference frequency is greater than the comb line it is mixed with fhf = self.lockSettings.resonanceFrequency n = self.lockSettings.harmonic #e.g. 105 error_n = self.lockSettings.errorsigHarmonic #e.g. 32 fref_uwave = self.lockSettings.harmonicReferenceFrequency fref_rf = self.lockSettings.referenceFrequency f_out = self.lockSettings.outputFrequency f_rep = (fref_uwave - fref_rf) / error_n if refGTcombLine else ( fref_uwave + fref_rf) / error_n offsetFrequency = abs(fhf - abs(n) * f_rep + (-1 if n < 0 else 1) * f_out) self.magOffsetFreq.setValue(offsetFrequency) def setReferenceAmplitude(self, value): binvalue = int(value) self.controller.setReferenceAmplitude(binvalue) self.lockSettings.referenceAmplitude = value self.dataChanged.emit(self.lockSettings) def setOutputFrequencyGui(self, value): self.magOutputFreq.setValue(value) self.setOutputFrequency(value) def setOutputFrequency(self, value): binvalue = freqToBin(value) self.controller.setOutputFrequency(binvalue) self.lockSettings.outputFrequency = value self.dataChanged.emit(self.lockSettings) self.calculateOffset() def setOutputAmplitude(self, value): binvalue = int(value) self.controller.setOutputAmplitude(binvalue) self.lockSettings.outputAmplitude = value self.dataChanged.emit(self.lockSettings) def setHarmonicGui(self, harmonic): with BlockSignals(self.magHarmonic): self.magHarmonic.setValue(harmonic) self.setHarmonic(harmonic) def setHarmonic(self, value): self.lockSettings.harmonic = value self._setHarmonics() def setErrorsigHarmonic(self, value): self.lockSettings.errorsigHarmonic = value self._setHarmonics() def _setHarmonics(self): errorsigHarmonic = int(self.lockSettings.errorsigHarmonic) self.controller.setHarmonic(int(self.lockSettings.harmonic)) self.controller.setFixedPointHarmonic( int(self.lockSettings.harmonic * ((1 << 56) / float(errorsigHarmonic)))) self.lockSettings.coreMode = 0 if errorsigHarmonic == 1 else 1 self.controller.setCoreMode(self.lockSettings.coreMode) self.dataChanged.emit(self.lockSettings) self.calculateOffset() def setOffset(self, value): binvalue = voltageToBin(value) self.controller.setInputOffset(binvalue) logging.getLogger(__name__).debug("offset {0} binary {1:x}".format( value, binvalue)) self.lockSettings.offset = value self.dataChanged.emit(self.lockSettings) def setpCoefficient(self, pCoeff): binvalue = int(pCoeff) self.controller.setpCoeff(binvalue) self.lockSettings.pCoefficient = pCoeff self.dataChanged.emit(self.lockSettings) def setiCoefficient(self, iCoeff): binvalue = int(iCoeff) self.controller.setiCoeff(binvalue) self.lockSettings.iCoefficient = iCoeff self.dataChanged.emit(self.lockSettings) def saveConfig(self): self.config["LockSettings"] = self.lockSettings def onTraceData(self, data): pass def onStreamData(self, data): if self.autoState == self.AutoStates.autoOffset: newOffset = (data.errorSigMax + data.errorSigMin) / 2 + self.lockSettings.offset self.magOffset.setValue(newOffset) self.setOffset(newOffset) self.autoState = self.AutoStates.idle def autoOffset(self): if self.autoState == self.AutoStates.idle: self.autoState = self.AutoStates.autoOffset
def __init__(self, traceList, penicons, graphicsViewDict, parent=None, highlightUnsaved=False): super(TraceModel, self).__init__(traceList, parent, categoriesAttr='category') #traceDict is a mapping between trace collection creation times and trace collection top level nodes self.traceDict = {node.children[0].content.traceCollection.traceCreation : node for node in self.root.children if node.children} self.penicons = penicons self.graphicsViewDict = graphicsViewDict self.allowDeletion = True self.allowReordering = True self.columnNames = ['name', 'pen', 'window', 'comment', 'filename'] self.numColumns = len(self.columnNames) self.column = enum(*self.columnNames) unsavedBG = QtGui.QColor(255, 220, 220) if highlightUnsaved else None self.headerLookup.update({ (QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole, self.column.name): "Name", (QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole, self.column.pen): "Pen ", (QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole, self.column.window): "Window", (QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole, self.column.comment): "Comment", (QtCore.Qt.Horizontal, QtCore.Qt.DisplayRole, self.column.filename): "Filename" }) self.categoryDataLookup.update({ (QtCore.Qt.CheckStateRole, self.column.name): self.isCategoryChecked, (QtCore.Qt.DisplayRole, self.column.comment): self.comment, (QtCore.Qt.EditRole, self.column.comment): self.comment }) self.categoryDataAllColLookup.update({ QtCore.Qt.BackgroundRole: lambda node: node.bgColor if self.isCategorySaved(node) else unsavedBG, }) self.dataLookup.update({ (QtCore.Qt.DisplayRole, self.column.name): lambda node: node.content.name, (QtCore.Qt.CheckStateRole, self.column.name): lambda node: QtCore.Qt.Checked if node.content.curvePen > 0 else QtCore.Qt.Unchecked, (QtCore.Qt.DecorationRole, self.column.pen): lambda node: QtGui.QIcon(self.penicons[node.content.curvePen]) if hasattr(node.content, 'curve') and node.content.curve is not None else None, (QtCore.Qt.EditRole, self.column.pen): lambda node: node.content.curvePen, (QtCore.Qt.DisplayRole, self.column.window): lambda node: node.content.windowName, (QtCore.Qt.EditRole, self.column.window): lambda node: node.content.windowName, (QtCore.Qt.DisplayRole, self.column.comment): self.comment, (QtCore.Qt.EditRole, self.column.comment): self.comment, (QtCore.Qt.DisplayRole, self.column.filename): lambda node: getattr(node.content.traceCollection, 'fileleaf', None) }) self.dataAllColLookup.update({ QtCore.Qt.BackgroundRole: lambda node: node.bgColor if node.content.traceCollection.saved else unsavedBG }) self.setDataLookup.update({ (QtCore.Qt.CheckStateRole, self.column.name): self.checkboxChange, (QtCore.Qt.EditRole, self.column.pen): self.penChange, (QtCore.Qt.EditRole, self.column.window): self.windowChange, (QtCore.Qt.EditRole, self.column.comment): self.commentChange }) self.categorySetDataLookup.update({ (QtCore.Qt.CheckStateRole, self.column.name): self.categoryCheckboxChange, (QtCore.Qt.EditRole, self.column.comment): self.commentChange }) self.flagsLookup = { self.column.name: QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled, self.column.pen: QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled, self.column.window: QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled, self.column.comment: QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled, self.column.filename: QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled } self.categoryFlagsLookup = { self.column.name: QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled, self.column.pen: QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled, self.column.window: QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled, self.column.comment: QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled, self.column.filename: QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled }
# ***************************************************************** # IonControl: Copyright 2016 Sandia Corporation # This Software is released under the GPL license detailed # in the file "license.txt" in the top-level IonControl directory # ***************************************************************** from PyQt5 import QtGui, QtCore, QtWidgets from .MagnitudeSpinBoxDelegate import MagnitudeSpinBoxDelegateMixin from .ComboBoxDelegate import ComboBoxDelegateMixin from modules.enum import enum ModeTypes = enum('ComboBox', 'Magnitude') class CamelionDelegate(QtWidgets.QStyledItemDelegate, ComboBoxDelegateMixin, MagnitudeSpinBoxDelegateMixin): """Class for combo box editors in models""" def __init__(self, emptyStringValue=0): QtWidgets.QStyledItemDelegate.__init__(self) self.mode = ModeTypes.Magnitude self.globalDict = dict() self.emptyStringValue = emptyStringValue def createEditor(self, parent, option, index): """Create the combo box editor""" choice = index.model().choice(index) if hasattr( index.model(), 'choice') else None if choice is not None: self.mode = ModeTypes.ComboBox return ComboBoxDelegateMixin.createEditor(self, parent, option, index) else:
""" Created on 09 Dec 2015 at 8:38 PM author: jmizrahi """ from PyQt5 import QtCore, QtWidgets, QtGui from modules.Expression import Expression from modules.firstNotNone import firstNotNone from modules.enum import enum from modules.MagnitudeParser import isIdentifier, isValueExpression from uiModules.KeyboardFilter import KeyListFilter import logging nodeTypes = enum('segmentSet', 'segment') class AWGSegmentNode(object): def __init__(self, parent, *args, **kwds): self.parent = parent self.children = [] self.enabled = kwds.get('enabled', True) def childCount(self): return len(self.children) def child(self, row): if 0 <= row < self.childCount(): return self.children[row] @property
""" Created on 09 Dec 2015 at 8:38 PM author: jmizrahi """ from PyQt5 import QtCore, QtWidgets, QtGui from modules.Expression import Expression from modules.firstNotNone import firstNotNone from modules.enum import enum from modules.MagnitudeParser import isIdentifier, isValueExpression from uiModules.KeyboardFilter import KeyListFilter import logging nodeTypes = enum('segmentSet', 'segment') class AWGSegmentNode(object): def __init__(self, parent, *args, **kwds): self.parent = parent self.children = [] self.enabled = kwds.get('enabled', True) def childCount(self): return len(self.children) def child(self, row): if 0 <= row < self.childCount(): return self.children[row] @property def row(self):
# ***************************************************************** # IonControl: Copyright 2016 Sandia Corporation # This Software is released under the GPL license detailed # in the file "license.txt" in the top-level IonControl directory # ***************************************************************** import logging import random import numpy from modules import DataDirectory from modules import enum from modules.Expression import Expression from modules.quantity import is_Q, Q OpStates = enum.enum('idle', 'running', 'paused', 'starting', 'stopping', 'interrupted') NoneScanCode = [4095, 0] # TODO: should use the pulserconfiguration dataMemorySize MaxWordsInFifo = 2040 class ParameterScanGenerator: expression = Expression() def __init__(self, scan): self.scan = scan self.nextIndexToWrite = 0 self.numUpdatedVariables = 1 def prepare(self, pulseProgramUi, maxUpdatesToWrite=None):
class DigitalLockControllerServer(Process): timestep = Q(5, 'ns') def __init__(self, dataQueue, commandPipe, loggingQueue): super(DigitalLockControllerServer, self).__init__() self.dataQueue = dataQueue self.commandPipe = commandPipe self.running = True self.openModule = None self.xem = None self.loggingQueue = loggingQueue # PipeReader stuff self.state = self.analyzingState.normal self.scopeData = ScopeData() self.streamData = StreamData() self.timestampOffset = 0 self.streamBuffer = bytearray() self._integrationTime = Q(100, 'ms') self.scopeEnabled = False self.scopeStopAtEnd = False self.scopeData = ScopeData() def run(self): configureServerLogging(self.loggingQueue) logger = logging.getLogger(__name__) while (self.running): if self.commandPipe.poll(0.02): try: commandstring, argument = self.commandPipe.recv() command = getattr(self, commandstring) logger.debug("DigitalLockControllerServer {0} {1}".format( commandstring, argument)) self.commandPipe.send(command(*argument)) except Exception as e: self.commandPipe.send(e) self.readDataFifo() self.dataQueue.put(FinishException()) logger.info("Pulser Hardware Server Process finished.") self.dataQueue.close() self.loggingQueue.put(None) self.loggingQueue.close() # self.loggingQueue.join_thread() def finish(self): self.running = False return True analyzingState = enum.enum('normal', 'scanparameter') def readDataFifo(self): logger = logging.getLogger(__name__) if (self.scopeEnabled): scopeData, _ = self.readScopeData(8) if scopeData is not None: for s in sliceview(scopeData, 8): (code, ) = struct.unpack('Q', s) if code == 0xffffffffffffffff: self.dataQueue.put(self.scopeData) logger.debug("sent data {0}".format( len(self.scopeData.errorSig))) self.scopeData = ScopeData() self.scopeEnabled = False else: self.scopeData.errorSig.append( twos_comp(code >> 48, 16)) self.scopeData.frequency.append( twos_comp(code & 0x7fffffffffff, 47)) data, self.streamData.overrun = self.readStreamData(48) if data: self.streamBuffer.extend(data) while len(self.streamBuffer) >= 64: try: for itembuffer in sliceview(self.streamBuffer, 64): self.unpackStreamRecord(itembuffer) if len(self.streamData) > 0: self.dataQueue.put(self.streamData) self.streamData = StreamData() self.streamBuffer = bytearray( sliceview_remainder(self.streamBuffer, 64)) except AlignmentException as e: logger.info("data not aligned skipping 2 bytes") self.streamBuffer = bytearray( self.streamBuffer[e.length * 48 + 2:] ) # e.length holds the number of successfully read records def unpackStreamRecord(self, itembuffer): item = StreamDataItem() (errorsig, item.errorSigMax, item.errorSigMin, item.samples, freq0, freq1, freq2, item.errorSigSumSq, item.externalMax, item.externalMin, item.externalCount, externalSum) = struct.unpack('QhhIQQQQHHIQ', itembuffer) item.lockStatus = (externalSum >> 46) & 0x3 item.externalMax &= 0xffff item.externalMin &= 0xffff if errorsig & 0xffff000000000000 != 0xfefe000000000000 or freq2 & 0xffff000000000000 != 0xefef000000000000: raise AlignmentException(len(self.streamData)) if item.samples > 0: item.errorSigSum = twos_comp((errorsig & 0xffffffffffff), 48) item.freqMin = twos_comp(freq1 & 0xffffffffffff, 48) item.freqMax = twos_comp(freq2 & 0xffffffffffff, 48) item.freqSum = twos_comp((freq0 << 8) | (freq1 >> 56), 72) item.externalSum = externalSum & 0xfffffffffff self.streamData.append(item) def __getattr__(self, name): """delegate not available procedures to xem""" if name.startswith('__') and name.endswith('__'): return super(DigitalLockControllerServer, self).__getattr__(name) def wrapper(*args): if self.xem: return getattr(self.xem, name)(*args) return None setattr(self, name, wrapper) return wrapper def SetWireInValue(self, address, data): if self.xem: self.xem.SetWireInValue(address, data) def armScope(self): self.scopeEnabled = True if self.xem: self.xem.ActivateTriggerIn(0x40, 13) def clearIntegrator(self): if self.xem: self.xem.ActivateTriggerIn(0x40, 5) def setDCThreshold(self, value): if self.xem: self.xem.SetWireInValue(0x1d, value & 0xffff) self.xem.UpdateWireIns() def setStreamEnabled(self, enabled): if self.xem: if enabled: check(self.xem.ActivateTriggerIn(0x41, 0), "setStreamEnabled") else: check(self.xem.ActivateTriggerIn(0x41, 1), "setStreamEnabled") logging.getLogger(__name__).warning( "setStreamEnabled {0}".format(enabled)) else: logging.getLogger(__name__).warning( "Controller Hardware not available") def setReferenceFrequency(self, binvalue): if self.xem: self.xem.SetWireInValue(0x00, binvalue & 0xffff) self.xem.SetWireInValue(0x01, (binvalue >> 16) & 0xffff) self.xem.SetWireInValue(0x02, (binvalue >> 32) & 0xffff) self.xem.UpdateWireIns() self.xem.ActivateTriggerIn(0x40, 7) def setOutputFrequency(self, binvalue): if self.xem: self.xem.SetWireInValue(0x03, binvalue & 0xffff) self.xem.SetWireInValue(0x04, (binvalue >> 16) & 0xffff) self.xem.SetWireInValue(0x05, (binvalue >> 32) & 0xffff) self.xem.UpdateWireIns() self.xem.ActivateTriggerIn(0x40, 8) def setReferenceAmplitude(self, binvalue): if self.xem: self.xem.SetWireInValue(0x0c, binvalue & 0xffff) self.xem.UpdateWireIns() self.xem.ActivateTriggerIn(0x40, 2) def setOutputAmplitude(self, binvalue): if self.xem: self.xem.SetWireInValue(0x0d, binvalue & 0xffff) self.xem.UpdateWireIns() self.xem.ActivateTriggerIn(0x40, 3) def setpCoeff(self, binvalue): if self.xem: self.xem.SetWireInValue(0x0e, binvalue & 0xffff) self.xem.SetWireInValue(0x0f, (binvalue >> 16) & 0xffff) self.xem.UpdateWireIns() def setiCoeff(self, binvalue): if self.xem: self.xem.SetWireInValue(0x10, binvalue & 0xffff) self.xem.SetWireInValue(0x11, (binvalue >> 16) & 0xffff) self.xem.UpdateWireIns() def setMode(self, binvalue): if self.xem: self.xem.SetWireInValue(0x12, binvalue & 0xffff) self.xem.UpdateWireIns() def setFilter(self, filterMode): if self.xem: self.xem.SetWireInValue(0x1C, filterMode & 0xffff) self.xem.UpdateWireIns() self.xem.ActivateTriggerIn(0x41, 2) def setInputOffset(self, binvalue): if self.xem: self.xem.SetWireInValue(0x13, binvalue & 0xffff) self.xem.UpdateWireIns() def setHarmonic(self, binvalue): if self.xem: self.xem.SetWireInValue(0x14, binvalue & 0xffff) self.xem.UpdateWireIns() def setFixedPointHarmonic(self, binvalue): if self.xem: self.xem.SetWireInValue(0x06, binvalue & 0xffff) binvalue >>= 16 self.xem.SetWireInValue(0x07, binvalue & 0xffff) binvalue >>= 16 self.xem.SetWireInValue(0x08, binvalue & 0xffff) binvalue >>= 16 self.xem.SetWireInValue(0x09, binvalue & 0xffff) self.xem.UpdateWireIns() def setCoreMode(self, mode): if self.xem: self.xem.SetWireInValue(0x0a, mode & 0xffff) self.xem.UpdateWireIns() def setStreamAccum(self, binvalue): if self.xem: self.xem.SetWireInValue(0x15, binvalue & 0xffff) self.xem.SetWireInValue(0x16, (binvalue >> 16) & 0xffff) self.xem.UpdateWireIns() def setSamples(self, binvalue): if self.xem: self.xem.SetWireInValue(0x17, binvalue & 0xffff) self.xem.SetWireInValue(0x18, (binvalue >> 16) & 0xffff) self.xem.UpdateWireIns() def setSubSample(self, binvalue): if self.xem: self.xem.SetWireInValue(0x19, binvalue & 0xffff) self.xem.UpdateWireIns() def setTriggerLevel(self, binvalue): if self.xem: self.xem.SetWireInValue(0x1a, binvalue & 0xffff) self.xem.UpdateWireIns() def setTriggerMode(self, binvalue): if self.xem: self.xem.SetWireInValue(0x1b, binvalue & 0xffff) self.xem.UpdateWireIns() def readStreamData(self, minbytes=4): if self.xem: self.xem.UpdateWireOuts() wirevalue = self.xem.GetWireOutValue(0x20) # pipe_out_available byteswaiting = (wirevalue & 0x0ffe) * 2 if byteswaiting and wirevalue & 0x7000 == 0x2000: data = bytearray(byteswaiting) self.xem.ReadFromPipeOut(0xa0, data) overrun = (wirevalue & 0x8000) != 0 return data, overrun return None, False def readScopeData(self, minbytes=4): if self.xem: self.xem.UpdateWireOuts() wirevalue = self.xem.GetWireOutValue(0x21) # pipe_out_available byteswaiting = (wirevalue & 0x7ffe) * 2 if byteswaiting: data = bytearray(byteswaiting) self.xem.ReadFromPipeOut(0xa1, data) overrun = (wirevalue & 0x8000) != 0 return data, overrun return None, False def listBoards(self): xem = ok.FrontPanel() self.moduleCount = xem.GetDeviceCount() self.modules = dict() for i in range(self.moduleCount): serial = xem.GetDeviceListSerial(i) tmp = ok.FrontPanel() check(tmp.OpenBySerial(serial), "OpenBySerial") desc = self.getDeviceDescription(tmp) tmp = None self.modules[desc.identifier] = desc del (xem) if self.openModule is not None: self.modules[self.openModule.identifier] = self.openModule return self.modules def getDeviceDescription(self, xem): """Get informaion from an open device """ desc = DeviceDescription() desc.serial = xem.GetSerialNumber() desc.identifier = xem.GetDeviceID() desc.major = xem.GetDeviceMajorVersion() desc.minor = xem.GetDeviceMinorVersion() desc.model = xem.GetBoardModel() desc.modelName = ModelStrings.get(desc.model, 'Unknown') return desc def renameBoard(self, serial, newname): tmp = ok.FrontPanel() tmp.OpenBySerial(serial) oldname = tmp.GetDeviceID() tmp.SetDeviceId(newname) tmp.OpenBySerial(serial) newname = tmp.GetDeviceID() if newname != oldname: self.modules[newname] = self.modules.pop(oldname) def uploadBitfile(self, bitfile): logger = logging.getLogger(__name__) if self.xem is not None and self.xem.IsOpen(): check(self.xem.ConfigureFPGA(bitfile), "Configure bitfile {0}".format(bitfile)) self.xem.ActivateTriggerIn(0x41, 9) # reset overrun logger.info("upload bitfile '{0}'".format(bitfile)) logger.info(str(BitfileInfo(bitfile))) def openByName(self, name): self.xem = ok.FrontPanel() check(self.xem.OpenBySerial(self.modules[name].serial), "OpenByName {0}".format(name)) return self.xem def openBySerial(self, serial): logger = logging.getLogger(__name__) if self.xem is None or not self.xem.IsOpen( ) or self.xem.GetSerialNumber() != serial: logger.debug("Open Serial {0}".format(serial)) self.xem = ok.FrontPanel() check(self.xem.OpenBySerial(serial), "OpenBySerial '{0}'".format(serial)) self.openModule = self.getDeviceDescription(self.xem) else: logger.debug("Serial {0} is already open".format(serial)) return None
# ***************************************************************** # IonControl: Copyright 2016 Sandia Corporation # This Software is released under the GPL license detailed # in the file "license.txt" in the top-level IonControl directory # ***************************************************************** import functools import random import numpy from modules import enum from modules.concatenate_iter import interleave_iter ScanType = enum.enum('LinearUp', 'LinearDown', 'Randomized', 'CenterOut', 'LinearUpDown', 'LinearDownUp') def shuffle(mylist): random.shuffle(mylist) return mylist def scanspace(start, stop, steps, scanSelect=0): if scanSelect == 0: return numpy.linspace(start, stop, steps) else: mysteps = abs(steps) if stop > start else -abs(steps) return numpy.arange(start, stop + mysteps // 2, mysteps)
class PulseProgramUi(PulseProgramWidget, PulseProgramBase): pulseProgramChanged = QtCore.pyqtSignal() contextDictChanged = QtCore.pyqtSignal(object) definitionWords = [ 'counter', 'var', 'shutter', 'parameter', 'masked_shutter', 'trigger', 'address', 'exitcode', 'const' ] builtinWords = [] for key, val in SymbolTable().items( ): #Extract the builtin words which should be highlighted if type(val).__name__ == 'Builtin': builtinWords.append(key) SourceMode = enum('pp', 'ppp') def __init__(self, config, parameterdict, channelNameData): PulseProgramWidget.__init__(self) PulseProgramBase.__init__(self) self.dependencyGraph = DiGraph() self.pulseProgram = PulseProgram.PulseProgram() self.sourceCodeEdits = dict() self.pppCodeEdits = dict() self.config = config self.variableTableModel = None self.globalVariablesChanged = None self.channelNameData = channelNameData self.pppCompileException = None self.globaldict = parameterdict self.project = getProject() self.defaultPPPDir = self.project.configDir + '/PulseProgramsPlus' if not os.path.exists(self.defaultPPPDir): os.makedirs(self.defaultPPPDir) examplePPPDir = os.path.realpath( os.path.join(os.path.dirname(__file__), '..', 'config/PulseProgramsPlus') ) #/IonControl/config/PulseProgramsPlus directory for basename in os.listdir(examplePPPDir): if basename.endswith('.ppp'): pathname = os.path.join(examplePPPDir, basename) if os.path.isfile(pathname): shutil.copy( pathname, self.defaultPPPDir ) #Copy over all example PPP pulse programs self.defaultRAMDir = self.project.configDir + '/RAMFiles' if not os.path.exists(self.defaultRAMDir): exampleRAMDir = os.path.realpath( os.path.join( os.path.dirname(__file__), '..', 'config/RAMFiles')) #/IonControl/config/RAMFiles directory shutil.copytree( exampleRAMDir, self.defaultRAMDir) #Copy over all example RAM files def setupUi(self, experimentname, parent): super(PulseProgramUi, self).setupUi(parent) self.setCentralWidget(None) #No central widget self.experimentname = experimentname self.configname = 'PulseProgramUi.' + self.experimentname self.contextDict = self.config.get(self.configname + '.contextdict', dict()) self.populateDependencyGraph() for context in self.contextDict.values( ): # set the global dict as this field does not survive pickling context.setGlobaldict(self.globaldict) self.currentContext = self.config.get( self.configname + '.currentContext', PulseProgramContext(self.globaldict)) self.currentContext.setGlobaldict(self.globaldict) self.configParams = self.config.get(self.configname, ConfiguredParams()) self.currentContextName = self.configParams.lastContextName self.filenameComboBox.addItems([ key for key, path in self.configParams.recentFiles.items() if os.path.exists(path) ]) self.contextComboBox.addItems(sorted(self.contextDict.keys())) self.parentComboBox.addItems([''] + sorted(self.contextDict.keys())) self.ramFilenameComboBox.addItems([''] + [ key for key, path in self.configParams.recentRamFiles.items() if os.path.exists(path) ]) self.writeRamCheckbox.setChecked(self.currentContext.writeRam) #setup documentation list definitionDict, builtinDict, encodingDict = self.getDocs() self.addDocs(definitionDict, "Variable Definitions") self.addDocs(builtinDict, "Pulse Program Commands") self.addDocs(encodingDict, "Encodings") #connect actions self.actionOpen.triggered.connect(self.onLoad) self.actionSave.triggered.connect(self.onSave) self.actionReset.triggered.connect(self.onReset) self.loadButton.setDefaultAction(self.actionOpen) self.saveButton.setDefaultAction(self.actionSave) self.resetButton.setDefaultAction(self.actionReset) self.loadButtonRam.clicked.connect(self.onLoadRamFile) self.writeRamCheckbox.clicked.connect(self.onWriteRamCheckbox) self.shutterTableView.setHorizontalHeader( RotatedHeaderView(QtCore.Qt.Horizontal, self.shutterTableView)) self.triggerTableView.setHorizontalHeader( RotatedHeaderView(QtCore.Qt.Horizontal, self.triggerTableView)) self.counterTableView.setHorizontalHeader( RotatedHeaderView(QtCore.Qt.Horizontal, self.counterTableView)) self.reloadContextButton.clicked.connect(self.onReloadContext) self.saveContextButton.clicked.connect(self.onSaveContext) self.deleteContextButton.clicked.connect(self.onDeleteContext) self.contextComboBox.currentIndexChanged[str].connect( self.onLoadContext) self.parentComboBox.currentIndexChanged[str].connect(self.onSetParent) self.linkAllButton.clicked.connect(self.onLinkAllToParent) self.unlinkAllButton.clicked.connect(self.onUnlinkAllFromParent) self.filenameComboBox.currentIndexChanged[str].connect( self.onFilenameChange) self.ramFilenameComboBox.currentIndexChanged[str].connect( self.onRamFilenameChange) self.removeCurrent.clicked.connect(self.onRemoveCurrent) self.removeCurrentRamFile.clicked.connect(self.onRemoveCurrentRamFile) self.variableTableModel = VariableTableModel( self.currentContext.parameters, self.config, self.currentContextName) if self.globalVariablesChanged: self.globalVariablesChanged.connect( self.variableTableModel.recalculateDependent) self.variableView.setModel(self.variableTableModel) self.variableView.resizeColumnToContents(0) self.variableView.clicked.connect(self.onVariableViewClicked) self.filter = KeyListFilter( [], [QtCore.Qt.Key_B, QtCore.Qt.Key_W, QtCore.Qt.Key_R]) self.filter.controlKeyPressed.connect(self.onControl) self.variableView.installEventFilter(self.filter) self.shutterTableModel = ShutterTableModel( self.currentContext.shutters, self.channelNameData[0], size=48, globalDict=self.globaldict, channelSignal=self.channelNameData[1]) self.triggerTableModel = TriggerTableModel( self.currentContext.triggers, self.channelNameData[2], size=32, globalDict=self.globaldict, channelSignal=self.channelNameData[3]) self.counterTableModel = CounterTableModel( self.currentContext.counters, self.channelNameData[4], globalDict=self.globaldict) self.delegates = list() for model, view in [(self.shutterTableModel, self.shutterTableView), (self.triggerTableModel, self.triggerTableView), (self.counterTableModel, self.counterTableView)]: view.setModel(model) delegate = MagnitudeSpinBoxDelegate(globalDict=self.globaldict) self.delegates.append( delegate ) # we need to keep those around, otherwise python will crash. view.setItemDelegateForColumn(model.numericDataColumn, delegate) if model.tristate: view.setItemDelegateForColumn(model.numericMaskColumn, delegate) view.clicked.connect(model.onClicked) view.resizeColumnsToContents() view.setupUi(self.globaldict) if self.globalVariablesChanged: self.globalVariablesChanged.connect( model.recalculateAllDependents) self.counterIdDelegate = MagnitudeSpinBoxDelegate() self.counterTableView.setItemDelegateForColumn( self.counterTableModel.idColumn, self.counterIdDelegate) try: self.loadContext(self.currentContext) if self.configParams.lastContextName: index = self.contextComboBox.findText( self.configParams.lastContextName) with BlockSignals(self.contextComboBox) as w: w.setCurrentIndex(index) except: logging.getLogger(__name__).exception( "Loading of previous context failed") #self.contextComboBox.editTextChanged.connect( self.updateSaveStatus ) self.contextComboBox.lineEdit().editingFinished.connect( self.updateSaveStatus) self.variableTableModel.contentsChanged.connect(self.updateSaveStatus) self.counterTableModel.contentsChanged.connect(self.updateSaveStatus) self.shutterTableModel.contentsChanged.connect(self.updateSaveStatus) self.triggerTableModel.contentsChanged.connect(self.updateSaveStatus) self.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu) self.autoSaveAction = QtWidgets.QAction( "Automatically save configuration", self) self.autoSaveAction.setCheckable(True) self.autoSaveAction.setChecked(self.configParams.autoSaveContext) self.autoSaveAction.triggered.connect(self.onAutoSave) self.addAction(self.autoSaveAction) #background color context menu setBackgroundColorAction = QtGui.QAction("Set Background Color", self) setBackgroundColorAction.triggered.connect(self.onSetBackgroundColor) self.addAction(setBackgroundColorAction) removeBackgroundColorAction = QtGui.QAction("Remove Background Color", self) removeBackgroundColorAction.triggered.connect( self.onRemoveBackgroundColor) self.addAction(removeBackgroundColorAction) self.initMenu() self.tabifyDockWidget(self.shutterDock, self.triggerDock) self.tabifyDockWidget(self.triggerDock, self.counterDock) self.restoreLayout() def populateDependencyGraph(self): self.dependencyGraph = DiGraph() self.dependencyGraph.add_nodes_from(self.contextDict.keys()) for name, context in self.contextDict.items(): if context.parentContext is not None: try: self.dependencySetParent(name, context.parentContext) except CyclicDependencyError as ce: context.parentContext = ce.parent def dependencySetParent(self, child, parent): parent = parent if parent else None oldParentEdges = self.dependencyGraph.out_edges([child]) _, oldParent = first(oldParentEdges, (None, None)) if parent != oldParent: self.dependencyGraph.remove_edges_from(oldParentEdges) if parent: self.dependencyGraph.add_edge(child, parent) cycles = simple_cycles(self.dependencyGraph) try: cycle = next(cycles) # StopIteration is raised if there are cycles self.dependencyGraph.remove_edge(child, parent) self.dependencyGraph.add_edges_from(oldParentEdges) raise CyclicDependencyError(oldParent) except StopIteration: pass def restoreLayout(self): """Restore layout from config settings""" windowState = self.config.get(self.configname + ".state") if windowState: self.restoreState(windowState) docSplitterState = self.config.get(self.configname + '.docSplitter') if docSplitterState: self.docSplitter.restoreState(docSplitterState) def initMenu(self): self.menuView.clear() dockList = self.findChildren(QtWidgets.QDockWidget) for dock in dockList: self.menuView.addAction(dock.toggleViewAction()) def onAutoSave(self, checked): self.configParams.autoSaveContext = checked if checked: self.onSaveContext() def loadContext(self, newContext): previousContext = self.currentContext self.currentContext = copy.deepcopy(newContext) #changeMode = self.currentContext.pulseProgramMode != previousContext.pulseProgramMode if self.currentContext.pulseProgramFile != previousContext.pulseProgramFile or len( self.sourceCodeEdits) == 0: self.currentContext.pulseProgramFile = self.project.findFile( self.currentContext.pulseProgramFile) self.adaptiveLoadFile(self.currentContext.pulseProgramFile) if self.currentContext.ramFile != previousContext.ramFile or ( self.currentContext.ramFile): self.currentContext.ramFile = self.project.findFile( self.currentContext.ramFile) self.loadRamFile(self.currentContext.ramFile) self.mergeVariablesIntoContext(self.pulseProgram.variabledict) self.updateDisplayContext() self.updateSaveStatus(isSaved=True) def onReloadContext(self): self.loadContext(self.contextDict[str( self.contextComboBox.currentText())]) self.updateSaveStatus() def onSaveContext(self): name = str(self.contextComboBox.currentText()) isNewContext = not name in self.contextDict self.contextDict[name] = copy.deepcopy(self.currentContext) if self.contextComboBox.findText(name) < 0: with BlockSignals(self.contextComboBox) as w: w.addItem(name) with BlockSignals(self.parentComboBox) as w: w.addItem(name) if isNewContext: self.contextDictChanged.emit(list(self.contextDict.keys())) self.updateSaveStatus(isSaved=True) self.currentContextName = name def onDeleteContext(self): name = str(self.contextComboBox.currentText()) index = self.contextComboBox.findText(name) if index >= 0: self.contextDict.pop(name) self.contextComboBox.removeItem(index) self.parentComboBox.removeItem(self.parentComboBox.findText(name)) self.contextDictChanged.emit(list(self.contextDict.keys())) self.updateSaveStatus() self.currentContextName = None def onLoadContext(self): name = str(self.contextComboBox.currentText()) self.currentContextName = name if name in self.contextDict: self.loadContext(self.contextDict[name]) else: self.onSaveContext() def onSetParent(self, parent): try: parent = parent if parent else None self.dependencySetParent(self.currentContextName, parent) self.currentContext.parentContext = parent self.variableTableModel.setContextHasParent(bool(parent)) except CyclicDependencyError as ce: parent = ce.parent self.currentContext.parentContext = parent self.parentComboBox.setCurrentIndex( self.parentComboBox.findText(parent if parent else '')) self.currentContext.parentContext = parent self.setParentData(self.currentContext.parentContext) def loadContextByName(self, name): if name in self.contextDict: self.loadContext(self.contextDict[name]) with BlockSignals(self.contextComboBox) as w: w.setCurrentIndex(w.findText(name)) def updatepppDisplay(self): for pppTab in list(self.pppCodeEdits.values()): self.sourceTabs.removeTab(self.sourceTabs.indexOf(pppTab)) self.pppCodeEdits = dict() if self.currentContext.pulseProgramMode == 'ppp': for name, text in [(self.pppSourceFile, self.pppSource)]: textEdit = PulseProgramSourceEdit(mode='ppp') encodingStrings = [ encoding for encoding in EncodingDict.keys() if type(encoding) == str ] textEdit.setupUi(textEdit, extraKeywords1=self.definitionWords + encodingStrings, extraKeywords2=self.builtinWords) textEdit.setPlainText(text) self.pppCodeEdits[name] = textEdit self.sourceTabs.addTab(textEdit, name) def updateppDisplay(self): for pppTab in list(self.sourceCodeEdits.values()): self.sourceTabs.removeTab(self.sourceTabs.indexOf(pppTab)) self.sourceCodeEdits = dict() for name, text in self.pulseProgram.source.items(): textEdit = PulseProgramSourceEdit() textEdit.setupUi(textEdit, extraKeywords1=self.definitionWords, extraKeywords2=[key for key in OPS]) textEdit.setPlainText(text) self.sourceCodeEdits[name] = textEdit self.sourceTabs.addTab(textEdit, name) textEdit.setReadOnly(self.currentContext.pulseProgramMode != 'pp') def updateDisplayContext(self): self.setParentData(self.currentContext.parentContext) self.variableTableModel.setVariables(self.currentContext.parameters, self.currentContextName) self.variableTableModel.setContextHasParent( bool(self.currentContext.parentContext)) with BlockSignals(self.parentComboBox) as w: w.setCurrentIndex( self.parentComboBox.findText( self.currentContext.parentContext if self.currentContext. parentContext else '')) self.variableView.resizeColumnsToContents() self.shutterTableModel.setDataDict(self.currentContext.shutters) self.triggerTableModel.setDataDict(self.currentContext.triggers) self.counterTableModel.setDataDict(self.currentContext.counters) self.writeRamCheckbox.setChecked(self.currentContext.writeRam) def documentationString(self): messages = [ "PulseProgram {0}".format(self.configParams.lastLoadFilename) ] r = "\n".join(messages) return "\n".join([r, self.pulseProgram.currentVariablesText()]) def description(self): desc = dict() desc["PulseProgram"] = self.configParams.lastLoadFilename desc.update(self.pulseProgram.variables()) return desc def onFilenameChange(self, name): name = str(name) if name in self.configParams.recentFiles and self.configParams.recentFiles[ name] != self.currentContext.pulseProgramFile: self.adaptiveLoadFile(self.configParams.recentFiles[name]) if str(self.filenameComboBox.currentText()) != name: with BlockSignals(self.filenameComboBox) as w: w.setCurrentIndex(self.filenameComboBox.findText(name)) self.updateSaveStatus() def onRamFilenameChange(self, name): name = str(name) if name in self.configParams.recentRamFiles and self.configParams.recentRamFiles[ name] != self.currentContext.ramFile: self.loadRamFile(self.configParams.recentRamFiles[name]) if str(self.ramFilenameComboBox.currentText()) != name: with BlockSignals(self.ramFilenameComboBox) as w: w.setCurrentIndex(self.ramFilenameComboBox.findText(name)) self.updateSaveStatus() def onOk(self): pass def onLoadRamFile(self): path, _ = QtWidgets.QFileDialog.getOpenFileName(self, 'Open RAM file', self.defaultRAMDir, filter='*.yml') if path: self.loadRamFile(path) self.updateSaveStatus() @QtCore.pyqtProperty(list) def ramData(self): return self.loadRamData(filename=self.currentContext.ramFile) @QtCore.pyqtProperty(bool) def writeRam(self): return self.currentContext.writeRam @file_data_cache(maxsize=3) def loadRamData(self, filename=''): """load in the data from a RAM file""" with open(filename, 'r') as f: yamldata = yaml.load(f) return [ self.pulseProgram.convertParameter( Q(float(ramValue['value']), ramValue['unit']), ramValue['encoding']) for ramValue in yamldata ] def loadRamFile(self, path): if path and os.path.exists(path): self.currentContext.ramFile = path filename = os.path.basename(path) if filename not in self.configParams.recentRamFiles: self.ramFilenameComboBox.addItem(filename) self.configParams.recentRamFiles[filename] = path with BlockSignals(self.ramFilenameComboBox) as w: w.setCurrentIndex(self.ramFilenameComboBox.findText(filename)) else: self.currentContext.ramFile = '' with BlockSignals(self.ramFilenameComboBox) as w: w.setCurrentIndex(self.ramFilenameComboBox.findText('')) def onWriteRamCheckbox(self): self.currentContext.writeRam = self.writeRamCheckbox.isChecked() self.updateSaveStatus() def onRemoveCurrentRamFile(self): text = str(self.ramFilenameComboBox.currentText()) if text in self.configParams.recentRamFiles: self.configParams.recentRamFiles.pop(text) self.ramFilenameComboBox.removeItem( self.ramFilenameComboBox.currentIndex()) self.currentContext.ramFile = '' self.updateSaveStatus() def onLoad(self): path, _ = QtWidgets.QFileDialog.getOpenFileName( self, 'Open Pulse Programmer file', self.defaultPPPDir, filter='*.ppp *.pp') if path != "": self.adaptiveLoadFile(path) self.updateSaveStatus() def adaptiveLoadFile(self, path): if path: _, ext = os.path.splitext(path) self.currentContext.pulseProgramFile = path if ext == ".ppp": self.currentContext.pulseProgramMode = 'ppp' self.loadpppFile(path) else: self.currentContext.pulseProgramMode = 'pp' self.updatepppDisplay() self.loadppFile(path) self.configParams.lastLoadFilename = path def onReset(self): if self.configParams.lastLoadFilename is not None: self.variabledict = VariableDictionary( self.pulseProgram.variabledict, self.parameterdict) self.adaptiveLoadFile(self.configParams.lastLoadFilename) def loadpppFile(self, path): self.pppSourcePath = path _, self.pppSourceFile = os.path.split(path) with open(path, "r") as f: self.pppSource = f.read() self.updatepppDisplay() ppFilename = getPpFileName(path) if self.compileppp(ppFilename): self.loadppFile(ppFilename, cache=False) filename = os.path.basename(path) if filename not in self.configParams.recentFiles: self.filenameComboBox.addItem(filename) self.configParams.recentFiles[filename] = path with BlockSignals(self.filenameComboBox) as w: w.setCurrentIndex(self.filenameComboBox.findText(filename)) def saveppp(self, path): if self.pppSource and path: with open(path, 'w') as f: f.write(self.pppSource) def compileppp(self, savefilename): self.pppSource = self.pppSource.expandtabs(4) success = False try: compiler = pppCompiler() ppCode = compiler.compileString(self.pppSource) self.pppReverseLineLookup = compiler.reverseLineLookup self.pppCompileException = None with open(savefilename, "w") as f: f.write(ppCode) success = True self.pppCodeEdits[self.pppSourceFile].clearHighlightError() except CompileException as e: self.pppCodeEdits[self.pppSourceFile].highlightError(e.message(), e.lineno(), col=e.col()) except ParseException as e: e.__class__ = CompileException # cast to CompileException. Is possible because CompileException does ONLY add behavior self.pppCodeEdits[self.pppSourceFile].highlightError(e.message(), e.lineno(), col=e.col()) return success def loadppFile(self, path, cache=True): self.pulseProgram.loadSource(path, docompile=False) self.updateppDisplay() try: self.pulseProgram.compileCode() except PulseProgram.ppexception as compileexception: self.sourceCodeEdits[compileexception.file].highlightError( str(compileexception), compileexception.line, compileexception.context) if cache: filename = os.path.basename(path) if filename not in self.configParams.recentFiles: self.filenameComboBox.addItem(filename) self.configParams.recentFiles[filename] = path self.filenameComboBox.setCurrentIndex( self.filenameComboBox.findText(filename)) # Merge any new values into the current context self.mergeVariablesIntoContext(self.pulseProgram.variabledict) self.updateDisplayContext() self.pulseProgramChanged.emit() def mergeVariablesIntoContext(self, variabledict): """Merge variables into context, propagating variable changes up the parentContext list""" # Follow the parenting links parent = self.currentContext.parentContext parents = [] while parent is not None and parent in self.contextDict and parent not in parents: parentContext = self.contextDict[parent] if parentContext.pulseProgramFile != self.currentContext.pulseProgramFile: break # Stop if the parent's pulse program does not match the current parents.append(parent) # Prevents infinite loops parent = parentContext.parentContext # Propagate variable changes up the parentContext tree in reverse order so the variable # linking up the tree doesn't break. linkNewToParent = False for parent in reversed(parents): self.contextDict[parent].merge(variabledict, linkNewToParent=linkNewToParent) linkNewToParent = True # Finally, merge into the current context self.currentContext.merge(variabledict, linkNewToParent=linkNewToParent) def onRemoveCurrent(self): text = str(self.filenameComboBox.currentText()) if text in self.configParams.recentFiles: self.configParams.recentFiles.pop(text) self.filenameComboBox.removeItem(self.filenameComboBox.currentIndex()) def onSave(self): self.onApply() if self.currentContext.pulseProgramMode == 'pp': self.pulseProgram.saveSource() else: self.saveppp(self.pppSourcePath) def onApply(self): if self.currentContext.pulseProgramMode == 'pp': try: positionCache = dict() for name, textEdit in self.sourceCodeEdits.items(): self.pulseProgram.source[name] = str( textEdit.toPlainText()) positionCache[name] = (textEdit.textEdit.cursorPosition(), textEdit.textEdit.scrollPosition()) self.pulseProgram.loadFromMemory() self.updateppDisplay() for name, textEdit in self.sourceCodeEdits.items(): textEdit.clearHighlightError() if name in positionCache: cursorpos, scrollpos = positionCache[name] textEdit.textEdit.setCursorPosition(*cursorpos) textEdit.textEdit.setScrollPosition(scrollpos) except PulseProgram.ppexception as ppex: textEdit = self.sourceCodeEdits[ppex.file].highlightError( str(ppex), ppex.line, ppex.context) else: positionCache = dict() for name, textEdit in self.pppCodeEdits.items(): self.pppSource = str(textEdit.toPlainText()) positionCache[name] = (textEdit.textEdit.cursorPosition(), textEdit.textEdit.scrollPosition()) ppFilename = getPpFileName(self.pppSourcePath) if self.compileppp(ppFilename): self.loadppFile(ppFilename, cache=False) for name, textEdit in self.pppCodeEdits.items(): textEdit.clearHighlightError() if name in positionCache: cursorpos, scrollpos = positionCache[name] textEdit.textEdit.setCursorPosition(*cursorpos) textEdit.textEdit.setScrollPosition(scrollpos) def onAccept(self): self.saveConfig() def onReject(self): pass def saveConfig(self): """Save the pulse program configuration state""" self.configParams.lastContextName = str( self.contextComboBox.currentText()) self.config[self.configname + ".state"] = self.saveState() #Arrangement of dock widgets self.config[self.configname] = self.configParams self.config[self.configname + '.contextdict'] = self.contextDict self.config[self.configname + '.currentContext'] = self.currentContext self.config[self.configname + '.docSplitter'] = self.docSplitter.saveState() self.variableTableModel.saveConfig() def getPulseProgramBinary(self, parameters=dict(), override=dict()): # need to update variables self.pulseProgram.updateVariables( self.) substitutes = dict(self.currentContext.parameters.valueView.items()) for model in [ self.shutterTableModel, self.triggerTableModel, self.counterTableModel ]: substitutes.update(model.getVariables()) substitutes.update(override) self.pulseProgram.updateVariables(substitutes) return self.pulseProgram.toBinary() def exitcode(self, number): return self.pulseProgram.exitcode(number) def getVariableValue(self, name): return self.variableTableModel.getVariableValue(name) def variableScanCode(self, variablename, values, extendedReturn=False): tempparameters = copy.deepcopy(self.currentContext.parameters) updatecode = list() numVariablesPerUpdate = 0 for currentval in values: upd_names, upd_values = tempparameters.setValue( variablename, currentval) numVariablesPerUpdate = len(upd_names) upd_names.append(variablename) upd_values.append(currentval) updatecode.extend( self.pulseProgram.multiVariableUpdateCode( upd_names, upd_values)) logging.getLogger(__name__).info("{0}: {1}".format( upd_names, upd_values)) if extendedReturn: return updatecode, numVariablesPerUpdate return updatecode def updateSaveStatus(self, isSaved=None): try: if isSaved is None: currentText = str(self.contextComboBox.currentText()) if not currentText: self.contextSaveStatus = True elif currentText in self.contextDict: self.contextSaveStatus = self.contextDict[ currentText] == self.currentContext else: self.contextSaveStatus = False if self.configParams.autoSaveContext and not self.contextSaveStatus: self.onSaveContext() self.contextSaveStatus = True else: self.contextSaveStatus = isSaved self.saveContextButton.setEnabled(not self.contextSaveStatus) except Exception: pass def onControl(self, key): if key == QtCore.Qt.Key_B: self.onBold() elif key == QtCore.Qt.Key_W: self.onSetBackgroundColor() elif key == QtCore.Qt.Key_R: self.onRemoveBackgroundColor() def onBold(self): indexes = self.variableView.selectedIndexes() for index in indexes: self.variableTableModel.toggleBold(index) def onSetBackgroundColor(self): indexes = self.variableView.selectedIndexes() if indexes: color = QtGui.QColorDialog.getColor() if not color.isValid(): color = None for index in indexes: self.variableTableModel.setBackgroundColor(index, color) def onRemoveBackgroundColor(self): indexes = self.variableView.selectedIndexes() for index in indexes: self.variableTableModel.removeBackgroundColor(index) def lineOfInstruction(self, binaryelement): ppline = self.pulseProgram.lineOfInstruction(binaryelement) pppline = self.pppReverseLineLookup.get(ppline, None) if hasattr( self, 'pppReverseLineLookup') else None return ppline, pppline def setTimingViolations(self, linelist): edit = self.pppCodeEdits.get(self.pppSourceFile) if edit: edit.highlightTimingViolation([l[1] - 1 for l in linelist]) def getDocs(self): """Assemble the pulse program function documentation into dictionaries""" definitionDocPath = os.path.join( os.path.dirname(__file__), '..', r'docs/manual/pppDefinitionDocs.include') definitionDict = self.readDocFile(definitionDocPath) encodingDocPath = os.path.join(os.path.dirname(__file__), '..', r'docs/manual/pppEncodingDocs.include') encodingDict = self.readDocFile(encodingDocPath) builtinDict = OrderedDict() symbolTable = SymbolTable() for name in self.builtinWords: builtinDict[name] = symbolTable[ name].doc or "This should be documentation for builtin word {0}".format( name) return definitionDict, builtinDict, encodingDict def readDocFile(self, filename): """Read in the rst file 'filename' """ docdict = OrderedDict() try: with open(filename, 'r') as f: docs = f.read() sepdocs = docs.split('.. py:data:: ') for doc in sepdocs: if doc: doclines = doc.splitlines() name = doclines.pop(0) for line in doclines: if line: documentation = line.strip( ) #Take the first line with content as the documentation to display in the program break docdict[name] = documentation except Exception as e: logging.getLogger(__name__).warning( "Unable to load documentation: {0}".format(e)) return docdict def addDocs(self, docDict, category): """Add the documentation dictionary docDict to the docTree under 'category' """ categoryItem = QtWidgets.QTreeWidgetItem(self.docTreeWidget, [category]) self.docTreeWidget.addTopLevelItem(categoryItem) for name, documentation in docDict.items(): nameItem = QtWidgets.QTreeWidgetItem(categoryItem, [name]) label = QtWidgets.QLabel(documentation) label.setWordWrap(True) docItem = QtWidgets.QTreeWidgetItem(nameItem) self.docTreeWidget.setItemWidget(docItem, 0, label) def onVariableViewClicked(self, index): if index.column() == 1 and self.currentContext.parentContext: var = self.currentContext.parameters.at(index.row()) if var.hasParent: var.useParentValue ^= True try: self.setParentData(self.currentContext.parentContext, var) except KeyError: var.hasParent = False self.variableTableModel.onClicked(index) self.updateSaveStatus() def onLinkAllToParent(self): """ Link all variables to their parents """ self.variableTableModel.beginResetModel() if self.currentContext.parentContext: for var in self.currentContext.parameters.values(): if var.hasParent: var.useParentValue = True self.setParentData(self.currentContext.parentContext) self.variableTableModel.endResetModel() self.updateSaveStatus() def onUnlinkAllFromParent(self): """ Unlink all variables from their parents """ self.variableTableModel.beginResetModel() for var in self.currentContext.parameters.values(): var.useParentValue = False self.setParentData(self.currentContext.parentContext) self.variableTableModel.endResetModel() self.updateSaveStatus() def setParentData(self, parentContext, var=None): for var in [ var ] if var is not None else self.currentContext.parameters.values(): try: var.hasParent = bool(parentContext) if var.useParentValue and var.hasParent: rootName = self.findControllingNode(var.name) self.setParentValue(var.name, rootName) var.parentObject = self.contextDict[rootName].parameters[ var.name] else: self.currentContext.parameters.setStrValue( var.name, var.strvalue) var.parentObject = None except KeyError: var.hasParent = False def findControllingNode(self, paramName): current, parent = self.currentContextName, self.currentContext.parentContext var = self.currentContext.parameters[paramName] child = None if not (parent and var.useParentValue): return None for child, parent in dfs_edges(self.dependencyGraph, parent): try: var = self.contextDict[parent].parameters[paramName] if not (var.useParentValue and var.hasParent): return child except KeyError: return child return parent def setParentValue(self, paramName, contextName): self.currentContext.parameters.setParentValue( paramName, self.contextDict[contextName].parameters[paramName].value) self.currentContext.parameters.setParentStrValue( paramName, self.contextDict[contextName].parameters[paramName].strvalue)
class LogicAnalyzer(Form, Base): OpStates = enum('stopped', 'running', 'single', 'idle') #added idle in response to exception def __init__(self, config, pulserHardware, channelNameData, parent=None): Form.__init__(self) Base.__init__(self, parent) self.state = self.OpStates.idle self.config = config self.pulserHardware = pulserHardware self.settings = Settings( ) #self.config.get( "LogicAnalyzerSettings", Settings() ) self.pulserHardware.logicAnalyzerDataAvailable.connect(self.onData) self.curveBundle = None self.curveTriggerBundle = None self.xTrigger = None self.yTrigger = None self.yTriggerBundle = None self.xData = None self.yData = None self.yDataBundle = None self.xAuxData = None self.yAuxData = None self.yAuxDataBundle = None self.curveAuxBundle = None self.xGateData = None self.yGateData = None self.yGateDataBundle = None self.curveGateBundle = None self.channelNameData = channelNameData self.lastEnabledChannels = None self.textItems = list() self.logicData = None def setupUi(self, parent): Form.setupUi(self, parent) self.actionRun.triggered.connect(self.onRun) self.actionStop.triggered.connect(self.onStop) self.actionSingle.triggered.connect(self.onSingle) self._graphicsView = self.graphicsLayout._graphicsView self.signalTableModel = LogicAnalyzerSignalTableModel( self.config, self.channelNameData) self.signalTableView.setModel(self.signalTableModel) self.signalTableView.resizeColumnsToContents() if 'LogicAnalyzer.State' in self.config: self.restoreState(self.config['LogicAnalyzer.State']) self.signalTableModel.enableChanged.connect(self.refresh) self.headerView = RotatedHeaderView(QtCore.Qt.Horizontal) self.traceTableView.setHorizontalHeader(self.headerView) self.traceTableModel = LogicAnalyzerTraceTableModel( self.config, self.signalTableModel) self.traceTableView.setModel(self.traceTableModel) self.traceTableView.resizeColumnsToContents() self.traceTableView.doubleClicked.connect( self.traceTableModel.setReferenceTimeCell) # Context Menu for Table self.signalTableView.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu) self.hideSelectedAction = QtWidgets.QAction("hide selected", self) self.showSelectedAction = QtWidgets.QAction("show selected", self) self.hideSelectedAction.triggered.connect(partial(self.onShow, False)) self.showSelectedAction.triggered.connect(partial(self.onShow, True)) self.signalTableView.addAction(self.hideSelectedAction) self.signalTableView.addAction(self.showSelectedAction) restoreGuiState(self, self.config.get('LogicAnalyzer.guiState')) def onShow(self, show, checked): rows = sorted( unique([i.row() for i in self.signalTableView.selectedIndexes()])) if rows: for row in rows: self.signalTableModel.setData( self.signalTableModel.createIndex(row, 0), QtCore.Qt.Checked if show else QtCore.Qt.Unchecked, QtCore.Qt.CheckStateRole) self.signalTableModel.dataChanged.emit( self.signalTableModel.createIndex(rows[0], 0), self.signalTableModel.createIndex(rows[-1], 0)) def onData(self, logicData): logger = logging.getLogger(__name__) logger.debug(str(logicData)) logger.debug("Wordcount: {0}".format(logicData.wordcount)) self.logicData = logicData offset = 0 if logicData.data: self.xData, self.yData = list(zip(*logicData.data)) self.xData = [x * self.settings.scaling for x in self.xData] # convert tuple to list self.xData.append(logicData.stopMarker * self.settings.scaling) self.yDataBundle = [ list() for _ in range(self.settings.numChannels) ] for i in range(self.settings.numChannels): if self.signalTableModel.enabledList[i]: for value in self.yData: self.yDataBundle[i].append( offset + self.settings.height if value & (1 << i) else offset) offset += 1 nextChannel = self.settings.numChannels if logicData.auxData: self.xAuxData, self.yAuxData = list(zip(*logicData.auxData)) self.xAuxData = [x * self.settings.scaling for x in self.xAuxData] # convert tuple to list self.xAuxData.append(logicData.stopMarker * self.settings.scaling) self.yAuxDataBundle = [ list() for _ in range(self.settings.numAuxChannels) ] for i in range(self.settings.numAuxChannels): if self.signalTableModel.enabledList[nextChannel + i]: for value in self.yAuxData: self.yAuxDataBundle[i].append( offset + self.settings.height if value & (1 << i) else offset) offset += 1 nextChannel += self.settings.numAuxChannels if logicData.trigger: self.xTrigger, self.yTrigger = list(zip(*logicData.trigger)) self.xTrigger = list( flatten([ (x * self.settings.scaling, x * self.settings.scaling + self.settings.triggerWidth) for x in self.xTrigger ])) # convert tuple to list self.yTrigger = list(flatten([(y, 0) for y in self.yTrigger])) self.xTrigger.append(logicData.stopMarker * self.settings.scaling) self.yTriggerBundle = [ list() for _ in range(self.settings.numTriggerChannels) ] for i in range(self.settings.numTriggerChannels): if self.signalTableModel.enabledList[nextChannel + i]: for value in self.yTrigger: self.yTriggerBundle[i].append( offset + self.settings.height if value & (1 << i) else offset) offset += 1 nextChannel += self.settings.numTriggerChannels if logicData.gateData: self.xGateData, self.yGateData = list(zip(*logicData.gateData)) self.xGateData = [ x * self.settings.scaling for x in self.xGateData ] # convert tuple to list self.xGateData.append(logicData.stopMarker * self.settings.scaling) self.yGateDataBundle = [ list() for _ in range(self.settings.numGateChannels) ] for i in range(self.settings.numGateChannels): if self.signalTableModel.enabledList[nextChannel + i]: for value in self.yGateData: self.yGateDataBundle[i].append( offset + self.settings.height if value & (1 << i) else offset) offset += 1 self.plotData() if self.state == self.OpStates.single: self.setStatusStopped() self.evaluateData(logicData) def evaluateData(self, logicData): self.pulseData = dict() if logicData.data: lastval = None for clockcycle, value in logicData.data: dictutil.getOrInsert(self.pulseData, clockcycle * self.settings.scaling, dict()).update( bitEvaluate(self.settings.numChannels, value, lastval)) lastval = value self.pulseData[logicData.stopMarker * self.settings.scaling] = dict() inext = self.settings.numChannels if logicData.auxData: lastval = None for clockcycle, value in logicData.auxData: dictutil.getOrInsert( self.pulseData, clockcycle * self.settings.scaling, dict()).update( bitEvaluate(self.settings.numAuxChannels, value, lastval, inext)) lastval = value inext += self.settings.numAuxChannels if logicData.trigger: lastval = None for clockcycle, value in logicData.trigger: dictutil.getOrInsert( self.pulseData, clockcycle * self.settings.scaling, dict()).update( bitEvaluate(self.settings.numTriggerChannels, value, lastval, inext, trigger=True)) lastval = value inext += self.settings.numTriggerChannels if logicData.gateData: lastval = None for clockcycle, value in logicData.gateData: dictutil.getOrInsert( self.pulseData, clockcycle * self.settings.scaling, dict()).update( bitEvaluate(self.settings.numGateChannels, value, lastval, inext)) lastval = value self.traceTableModel.setPulseData(self.pulseData) self.traceTableView.resizeColumnsToContents() def plotData(self): offset = 0 lastAutoRangeState = self._graphicsView.vb.getState()['autoRange'] self._graphicsView.disableAutoRange(ViewBox.XYAxes) if self.lastEnabledChannels and self.lastEnabledChannels != self.signalTableModel.enabledList: for curve in concatenate_iter(self.curveBundle, self.curveAuxBundle, self.curveTriggerBundle, self.curveGateBundle): if curve: self._graphicsView.removeItem(curve) self.curveBundle = None self.curveAuxBundle = None self.curveTriggerBundle = None self.curveGateBundle = None if self.textItems: for item in self.textItems: self._graphicsView.removeItem(item) if self.yDataBundle: if self.curveBundle is None: self.curveBundle = list() for i, yData in enumerate(self.yDataBundle): if yData: curve = PlotCurveItem(self.xData, yData, stepMode=True, fillLevel=offset, brush=penList[1][4], pen=penList[1][0]) self._graphicsView.addItem(curve) self.curveBundle.append(curve) textItem = TextItem( self.signalTableModel.primaryChannelName(i), anchor=(1, 1), color=(0, 0, 0)) textItem.setPos(0, offset) self._graphicsView.addItem(textItem) self.textItems.append(textItem) offset += 1 else: self.curveBundle.append(None) else: for curve, yData in zip(self.curveBundle, self.yDataBundle): if yData: if curve: curve.setData(x=self.xData, y=yData) nextChannel = self.settings.numChannels if self.yAuxDataBundle: if self.curveAuxBundle is None: self.curveAuxBundle = list() for i, yAuxData in enumerate(self.yAuxDataBundle): if yAuxData: curve = PlotCurveItem(self.xAuxData, yAuxData, stepMode=True, fillLevel=offset, brush=penList[2][4], pen=penList[2][0]) self._graphicsView.addItem(curve) self.curveAuxBundle.append(curve) textItem = TextItem( self.signalTableModel.auxChannelName(i), anchor=(1, 1), color=(0, 0, 0)) textItem.setPos(0, offset) self._graphicsView.addItem(textItem) self.textItems.append(textItem) offset += 1 else: self.curveAuxBundle.append(None) else: for curve, yAuxData in zip(self.curveAuxBundle, self.yAuxDataBundle): if yAuxData: if curve: curve.setData(x=self.xAuxData, y=yAuxData) nextChannel += self.settings.numAuxChannels if self.yTriggerBundle: if self.curveTriggerBundle is None: self.curveTriggerBundle = list() for i, yTrigger in enumerate(self.yTriggerBundle): if yTrigger: curve = PlotCurveItem(self.xTrigger, yTrigger, stepMode=True, fillLevel=offset, brush=penList[3][4], pen=penList[3][0]) self._graphicsView.addItem(curve) self.curveTriggerBundle.append(curve) textItem = TextItem( self.signalTableModel.triggerChannelName(i), anchor=(1, 1), color=(0, 0, 0)) textItem.setPos(0, offset) self._graphicsView.addItem(textItem) self.textItems.append(textItem) offset += 1 else: self.curveTriggerBundle.append(None) else: for curve, yTrigger in zip(self.curveTriggerBundle, self.yTriggerBundle): if yTrigger: if curve: curve.setData(x=self.xTrigger, y=yTrigger) nextChannel = self.settings.numTriggerChannels if self.yGateDataBundle: if self.curveGateBundle is None: self.curveGateBundle = list() for i, yGateData in enumerate(self.yGateDataBundle): if yGateData: curve = PlotCurveItem(self.xGateData, yGateData, stepMode=True, fillLevel=offset, brush=penList[2][4], pen=penList[2][0]) self._graphicsView.addItem(curve) self.curveGateBundle.append(curve) textItem = TextItem( self.signalTableModel.gateChannelName(i), anchor=(1, 1), color=(0, 0, 0)) textItem.setPos(0, offset) self._graphicsView.addItem(textItem) self.textItems.append(textItem) offset += 1 else: self.curveGateBundle.append(None) else: for curve, yGateData in zip(self.curveGateBundle, self.yGateDataBundle): if yGateData: if curve: curve.setData(x=self.xGateData, y=yGateData) self.lastEnabledChannels = list(self.signalTableModel.enabledList) xautorange, yautorange = lastAutoRangeState if xautorange: self._graphicsView.enableAutoRange(ViewBox.XAxis) if yautorange: self._graphicsView.enableAutoRange(ViewBox.YAxis) self._graphicsView.autoRange() def refresh(self): if self.logicData: self.onData(self.logicData) def onRun(self): logger = logging.getLogger(__name__) logger.debug("Starting Logic Analyzer") self.pulserHardware.enableLogicAnalyzer(True) self.setStatusRunning() def onStop(self): logger = logging.getLogger(__name__) logger.debug("Stopping Logic Analyzer") self.pulserHardware.enableLogicAnalyzer(False) self.setStatusStopped() def onSingle(self): logger = logging.getLogger(__name__) logger.debug("Logic Analyzer Single Shot") self.pulserHardware.enableLogicAnalyzer(False) self.pulserHardware.logicAnalyzerTrigger() self.setStatusSingle() def setStatusStopped(self): self.state = self.OpStates.idle self.statusBar.showMessage("Stopped") def setStatusRunning(self): self.state = self.OpStates.idle self.statusBar.showMessage("Running") def setStatusSingle(self): self.state = self.OpStates.idle self.statusBar.showMessage("Single shot") def saveConfig(self): self.config["LogicAnalyzerSettings"] = self.settings self.signalTableModel.saveConfig() self.config['LogicAnalyzer.State'] = self.saveState() self.config['LogicAnalyzer.guiState'] = saveGuiState(self) def onClose(self): pass def closeEvent(self, e): self.onClose()
class ScanProgress(Form, Base): OpStates = enum('idle', 'running', 'paused', 'starting', 'stopping', 'interrupted', 'stashing', 'resuming') stateChanged = QtCore.pyqtSignal(object) def __init__(self): Form.__init__(self) Base.__init__(self) self.state = self.OpStates.idle self.range = 1 self.startTime = time.time() # time of last start self.previouslyElapsedTime = 0 # time spent on run before last start self.expected = 0 self.timer = None def getData(self): return (self.startTime, self.previouslyElapsedTime) def setData(self, data): self.startTime, self.previouslyElapsedTime = data def setupUi(self): super(ScanProgress, self).setupUi(self) self.statusLabel.setText("Idle") self.progressBar.setFormat("%p%") self.scanLabel.setText("") self.evaluationLabel.setText("") self.analysisLabel.setText("") def __getattr__(self, name): """generates the is_idle, is_running, ... attributes""" if name[0:3] == 'is_': desiredState = self.OpStates.mapping.get(name[3:]) if desiredState is None: raise AttributeError( "{0} is not a valid state of ScanProgress") return self.state == desiredState raise AttributeError() def setScanLabel(self, scanName): self.scanLabel.setText(firstNotNone(scanName, "")) def setEvaluationLabel(self, scanName): self.evaluationLabel.setText(firstNotNone(scanName, "")) def setAnalysisLabel(self, scanName): self.analysisLabel.setText(firstNotNone(scanName, "")) def startTimer(self): self.timer = QtCore.QTimer() self.timer.timeout.connect(self.setTimeLabel) self.timer.start(1000) def stopTimer(self): if self.timer: self.timer = None def setIdle(self): self.statusLabel.setText("Idle") self.progressBar.setValue(0) self.state = self.OpStates.idle self.stateChanged.emit('idle') self.previouslyElapsedTime = time.time() - self.startTime self.widget.setStyleSheet("QWidget { background: #ffffff; }") def setRunning(self, total): self.statusLabel.setText("Running") self.range = total self.progressBar.setRange(0, total) self.progressBar.setValue(0) #self.progressBar.setStyleSheet("") self.setTimeLabel() self.state = self.OpStates.running self.stateChanged.emit('running') self.startTime = time.time() self.previouslyElapsedTime = 0 self.widget.setStyleSheet("QWidget { background: #a0ffa0; }") self.startTimer() self.previouslyElapsedTime = 0 def resumeRunning(self, index): self.statusLabel.setText("Running") self.progressBar.setValue(index) self.startTime = time.time() self.state = self.OpStates.running self.stateChanged.emit('running') self.widget.setStyleSheet("QWidget { background: #a0ffa0; }") self.startTimer() def setPaused(self): #self.progressBar.setStyleSheet(StyleSheets.RedProgressBar) self.statusLabel.setText("Paused") self.setTimeLabel() self.state = self.OpStates.paused self.stateChanged.emit('paused') self.previouslyElapsedTime += time.time() - self.startTime self.widget.setStyleSheet("QWidget { background: #c0c0ff; }") self.stopTimer() def setStarting(self): self.statusLabel.setText("Starting") self.state = self.OpStates.starting self.stateChanged.emit('starting') def setStopping(self): self.statusLabel.setText("Stopping") self.state = self.OpStates.stopping self.stateChanged.emit('stopping') def setStashing(self): self.statusLabel.setText("Stashing") self.state = self.OpStates.stashing self.stateChanged.emit('stashing') def setInterrupted(self, reason): #self.progressBar.setStyleSheet(StyleSheets.RedProgressBar) self.previouslyElapsedTime = time.time() - self.startTime self.statusLabel.setText("Interrupted ({0})".format(reason)) self.state = self.OpStates.interrupted self.stateChanged.emit('interrupted') self.setTimeLabel() self.previouslyElapsedTime += time.time() - self.startTime self.widget.setStyleSheet("QWidget { background: #ffa0a0; }") self.stopTimer() def onData(self, index): self.progressBar.setValue(index) self.expected = self.elapsedTime() / ( index / float(self.range)) if index > 0 else 0 self.setTimeLabel() def elapsedTime(self): return self.previouslyElapsedTime + ( (time.time() - self.startTime) if self.state == self.OpStates.running else 0) def setTimeLabel(self): self.timeLabel.setText("{0} / {1}".format( timedelta(seconds=round(self.elapsedTime())), timedelta(seconds=round(self.expected))))