Exemple #1
0
    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
        }
Exemple #2
0
 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()
Exemple #4
0
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
Exemple #6
0
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
     }
Exemple #9
0
 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()
Exemple #10
0
 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']
Exemple #14
0
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):
Exemple #20
0
# *****************************************************************
# 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 ))
       
Exemple #21
0
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")
Exemple #22
0
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'),
     }
Exemple #25
0
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
        ])
Exemple #27
0
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
Exemple #28
0
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
Exemple #29
0
 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):
Exemple #33
0
# *****************************************************************
# 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):
Exemple #34
0
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
Exemple #35
0
# *****************************************************************
# 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)

Exemple #36
0
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)
Exemple #37
0
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()
Exemple #38
0
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))))