Ejemplo n.º 1
0
class CameraClient(QtWidgets.QWidget):
    andor_servername = 'andor'
    andor_serial_number = 0

    servername = 'camera'
    update_id = np.random.randint(0, 2**31 - 1)
    data_directory = os.path.join(os.getenv('LABRADDATA'), 'data')
    name = None
    cxn = None

    timeRange = (0, 1e9)
    timeDisplayUnits = [(0, 's'), (-3, 'ms'), (-6, 'us')]
    timeDigits = 2

    def __init__(self, reactor):
        super(CameraClient, self).__init__()
        self.reactor = reactor
        self.connect()

    @inlineCallbacks
    def connect(self):
        if self.cxn is None:
            self.cxn = connection()
            cname = '{} - {} - client'.format(self.servername, self.name)
            yield self.cxn.connect(name=cname)
        try:
            self.populate()
            yield self.connectSignals()
        except Exception as e:
            print(e)

    def populate(self):
        self.andorLabel = ClickableLabel('<b>' + 'IXon - 888' + '</b>')

        self.tempLabel = ClickableLabel('Temp: ')
        self.tempBox = QtWidgets.QDoubleSpinBox()
        self.tempBox.setRange(-150, 50)
        self.tempBox.setReadOnly(True)
        self.tempBox.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons)
        self.tempBox.setDecimals(0)
        self.tempBox.setSuffix(' \u00b0 C')
        self.tempBox.setFixedWidth(80)

        self.emgainLabel = ClickableLabel('EM Gain: ')
        self.emgainBox = QtWidgets.QDoubleSpinBox()
        self.emgainBox.setRange(0, 300)
        self.emgainBox.setReadOnly(True)
        self.emgainBox.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons)
        self.emgainBox.setDecimals(0)
        self.emgainBox.setFixedWidth(80)

        self.exposureLabel = ClickableLabel('Exposure Time: ')
        self.exposureBox = SuperSpinBox(self.timeRange, self.timeDisplayUnits,
                                        self.timeDigits)
        self.exposureBox.setReadOnly(True)
        self.exposureBox.setFixedWidth(80)

        self.accumulationLabel = ClickableLabel('Accumulation Time: ')
        self.accumulationBox = SuperSpinBox(self.timeRange,
                                            self.timeDisplayUnits,
                                            self.timeDigits)
        self.accumulationBox.setReadOnly(True)
        self.accumulationBox.setFixedWidth(80)

        self.kineticLabel = ClickableLabel('Kinetic Time: ')
        self.kineticBox = SuperSpinBox(self.timeRange, self.timeDisplayUnits,
                                       self.timeDigits)
        self.kineticBox.setReadOnly(True)
        self.kineticBox.setFixedWidth(80)

        self.readoutLabel = ClickableLabel('Readout Time: ')
        self.readoutBox = SuperSpinBox(self.timeRange, self.timeDisplayUnits,
                                       self.timeDigits)
        self.readoutBox.setReadOnly(True)
        self.readoutBox.setFixedWidth(80)

        self.imageView = pg.ImageView()
        self.imageView.setColorMap(MyColorMap)
        self.imageView.show()

        self.layout = QtWidgets.QGridLayout()
        self.layout.setSpacing(5)
        self.layout.setContentsMargins(5, 5, 5, 5)

        self.layout.addWidget(self.andorLabel, 1, 0, 1, 2,
                              QtCore.Qt.AlignCenter)
        self.layout.addWidget(self.tempLabel, 1, 2, 1, 1, QtCore.Qt.AlignRight)
        self.layout.addWidget(self.tempBox, 1, 3, 1, 1)
        self.layout.addWidget(self.emgainLabel, 1, 4, 1, 1,
                              QtCore.Qt.AlignRight)
        self.layout.addWidget(self.emgainBox, 1, 5, 1, 1)
        self.layout.addWidget(self.exposureLabel, 1, 6, 1, 1,
                              QtCore.Qt.AlignRight)
        self.layout.addWidget(self.exposureBox, 1, 7, 1, 1)
        self.layout.addWidget(self.accumulationLabel, 1, 8, 1, 1,
                              QtCore.Qt.AlignRight)
        self.layout.addWidget(self.accumulationBox, 1, 9, 1, 1)
        self.layout.addWidget(self.kineticLabel, 1, 10, 1, 1,
                              QtCore.Qt.AlignRight)
        self.layout.addWidget(self.kineticBox, 1, 11, 1, 1)
        self.layout.addWidget(self.readoutLabel, 1, 12, 1, 1,
                              QtCore.Qt.AlignRight)
        self.layout.addWidget(self.readoutBox, 1, 13, 1, 1)
        self.layout.addWidget(self.imageView, 2, 0, 15, 15)
        self.setLayout(self.layout)
        # self.setFixedSize(1200, 800)
        self.setWindowTitle('{} - {} - client'.format(self.servername,
                                                      self.name))

    @inlineCallbacks
    def connectSignals(self):
        self.context = yield self.cxn.context()
        server = yield self.cxn.get_server(self.servername)
        yield server.signal__update(self.update_id)
        yield server.addListener(listener=self.receive_update,
                                 source=None,
                                 ID=self.update_id)
        yield self.cxn.add_on_connect(self.servername, self.reinitialize)
        yield self.cxn.add_on_disconnect(self.servername, self.disable)

        self.imageView.scene.sigMouseClicked.connect(self.handle_click)

        self.andorLabel.clicked.connect(self.getAll)
        self.tempLabel.clicked.connect(self.getTemperature)
        self.emgainLabel.clicked.connect(self.getEMGain)
        self.getAll()

    @inlineCallbacks
    def reinitialize(self):
        server = yield self.cxn.get_server(self.servername)
        yield server.signal__update(self.update_id, context=self.context)
        try:
            yield server.removeListener(listener=self.receive_update,
                                        source=None,
                                        ID=self.update_id,
                                        context=self.context)
            yield server.addListener(listener=self.receive_update,
                                     source=None,
                                     ID=self.update_id,
                                     context=self.context)
        except:
            pass

    def disable(self):
        pass

    def getAll(self):
        self.getTemperature()
        self.getEMGain()
        self.getAcquisitionTiming()
        self.getReadOutTime()

    @inlineCallbacks
    def getTemperature(self):
        server = yield self.cxn.get_server(self.andor_servername)
        temp = yield server.get_temperature(self.andor_serial_number)
        self.DisplayTemperature(temp[1])

    def DisplayTemperature(self, temp):
        self.tempBox.setValue(temp)

    @inlineCallbacks
    def getEMGain(self):
        server = yield self.cxn.get_server(self.andor_servername)
        error, emgain = yield server.get_emccd_gain(self.andor_serial_number)
        self.DisplayEMGain(emgain)

    def DisplayEMGain(self, emgain):
        self.emgainBox.setValue(emgain)

    @inlineCallbacks
    def getAcquisitionTiming(self):
        server = yield self.cxn.get_server(self.andor_servername)
        error, exposure, accumulation, kinetic = yield server.get_acquisition_timings(
            self.andor_serial_number)
        self.DisplayExposure(exposure)
        self.DisplayAccumulation(accumulation)
        self.DisplayKinetic(kinetic)

    def DisplayExposure(self, exposure):
        self.exposureBox.display(exposure)

    def DisplayAccumulation(self, accumulation):
        self.accumulationBox.display(accumulation)

    def DisplayKinetic(self, kinetic):
        self.kineticBox.display(kinetic)

    @inlineCallbacks
    def getReadOutTime(self):
        server = yield self.cxn.get_server(self.andor_servername)
        error, readoutTime = yield server.get_read_out_time(
            self.andor_serial_number)
        self.DisplayReadOutTime(readoutTime)

    def DisplayReadOutTime(self, readoutTime):
        self.readoutBox.display(readoutTime)

    def handle_click(self, mouseClickEvent):
        print(mouseClickEvent.double())
        if mouseClickEvent.double():
            scenePos = mouseClickEvent.scenePos()
            print(scenePos)
            pos = self.imageView.getView().mapSceneToView(scenePos)
            if not hasattr(self, 'crosshairs'):
                self.crosshairs = {
                    'x': pg.InfiniteLine(angle=90, pen='g'),
                    'y': pg.InfiniteLine(angle=0, pen='g'),
                }
                self.imageView.addItem(self.crosshairs['x'])
                self.imageView.addItem(self.crosshairs['y'])

            self.crosshairs['x'].setPos(pos.x())
            self.crosshairs['y'].setPos(pos.y())

    def receive_update(self, c, signal):
        signal = json.loads(signal)
        for key, value in signal.items():
            if key == self.name:
                record_path = value['record_path']
                record_type = value['record_type']
                record_settings = value['record_settings']
                image_path = self.data_directory.format(*record_path)
                image_path = os.path.join(self.data_directory,
                                          *record_path.split('/')) + '.hdf5'
                self.plot(image_path, record_type, record_settings)

    def plot(self, image_path, record_type, record_settings):
        image = process_image(image_path, record_type, record_settings)
        image = np.rot90(image)
        self.imageView.setImage(image, autoRange=False, autoLevels=False)

    def closeEvent(self, x):
        self.reactor.stop()
class MSQClient(QtWidgets.QWidget):
    """ Widget for Msquared server control """
    msquared_servername = None
    msquared_devicename = None
    wlm_servername = None

    update_time1 = 2500  # [ms]
    update_time2 = 5000  # [ms]
    lock_update_time = 2500  # [ms]
    is_on_OneShot = False

    frequency_units = ['THz', 'GHz']
    wavelength_units = ['nm', 'um']

    etalon_range = (0, 100)  # Etalon tuner
    etalon_units = [(0, '%')]
    etalon_digits = 2
    etalon_max = 196

    resonator_range = (0, 100)  # Resonator tuner
    resonator_units = [(0, '%')]
    resonator_digits = 4
    resonator_max = 196

    fineresonator_range = (0, 100)  # Resonator Fine tuner
    fineresonator_units = [(0, '%')]
    fineresonator_digits = 2

    PD_range = (0, 100)
    PD_units = [(0, 'V')]
    PD_digits = 4

    xy_range = (0, 100)  # X, Y tuner
    xy_units = [(0, '%')]
    xy_digits = 2

    wl_range = (696, 877)  # Rough wavelength
    wl_units = [(0, 'nm')]
    wl_digits = 1

    spinbox_height = 30
    spinbox_width = 80
    update_id = np.random.randint(0, 2**31 - 1)

    def __init__(self, reactor, cxn, msquared_servername, msquared_devicename,
                 wlm_servername, parent):
        super(MSQClient, self).__init__()
        try:
            self.reactor = reactor
            self.cxn = cxn
            self.msquared_servername = msquared_servername
            self.msquared_devicename = msquared_devicename
            self.wlm_servername = wlm_servername
            self.parent = parent
            self.connect()
        except Exception as e:
            print(e)
            traceback.print_exc()

    @inlineCallbacks
    def connect(self):
        if self.cxn == None:
            self.cxn = connection()
            yield self.cxn.connect()
        self.populate()
        yield self.connectWidgets()

    def populate(self):
        self.nameLabel = ClickableLabel('<b> MSquared Laser Control </b>')

        self.statusLabel = ClickableLabel('<b> MSquared Status: </b>')
        self.statusText = QtWidgets.QLineEdit()
        self.statusText.setReadOnly(True)
        self.statusText.setAlignment(QtCore.Qt.AlignCenter)
        self.statusText.setFixedHeight(40)
        self.statusText.setFont(QtGui.QFont('Arial', 10))

        self.wlmLabel = ClickableLabel('<b> HF Wavemeter: </b>')
        self.wlmText = QtWidgets.QLineEdit()
        self.wlmText.setReadOnly(True)
        self.wlmText.setAlignment(QtCore.Qt.AlignCenter)
        self.wlmText.setFixedHeight(40)
        self.wlmText.setFont(QtGui.QFont('Arial', 10))

        self.lockButton = QtWidgets.QPushButton()
        self.lockButton.setCheckable(True)
        self.lockButton.setFixedHeight(40)
        self.lockButton.setFixedWidth(120)

        self.oneshotButton = QtWidgets.QPushButton()
        self.oneshotButton.setFixedHeight(40)
        self.oneshotButton.setFixedWidth(120)
        self.oneshotButton.setText('One Shot Alignment')

        self.manualButton = QtWidgets.QPushButton()
        self.manualButton.setFixedHeight(40)
        self.manualButton.setFixedWidth(120)
        self.manualButton.setText('Manual Alignment')

        self.EtalonTunerLabel = ClickableLabel('Etalon Tuner: ')
        self.EtalonTunerBox = SuperSpinBox(self.etalon_range,
                                           self.etalon_units,
                                           self.etalon_digits)
        self.EtalonTunerBox.setFixedHeight(self.spinbox_height)
        self.EtalonTunerBox.setFixedWidth(self.spinbox_width)

        self.ResonatorTunerLabel = ClickableLabel('Resonator Tuner: ')
        self.ResonatorTunerBox = SuperSpinBox(self.resonator_range,
                                              self.resonator_units,
                                              self.resonator_digits)
        self.ResonatorTunerBox.setFixedHeight(self.spinbox_height)
        self.ResonatorTunerBox.setFixedWidth(self.spinbox_width)

        self.ResonatorFineTunerLabel = ClickableLabel(
            'Resonator Fine \n Tuner:')
        self.ResonatorFineTunerLabel.setAlignment(QtCore.Qt.AlignRight
                                                  | QtCore.Qt.AlignVCenter)
        self.ResonatorFineTunerBox = SuperSpinBox(self.fineresonator_range,
                                                  self.fineresonator_units,
                                                  self.fineresonator_digits)
        self.ResonatorFineTunerBox.setFixedHeight(self.spinbox_height)
        self.ResonatorFineTunerBox.setFixedWidth(self.spinbox_width)

        self.XLabel = ClickableLabel('X Tuner: ')
        self.XBox = SuperSpinBox(self.xy_range, self.xy_units, self.xy_digits)
        self.XBox.setFixedHeight(self.spinbox_height)
        self.XBox.setFixedWidth(self.spinbox_width)

        self.YLabel = ClickableLabel('Y Tuner: ')
        self.YBox = SuperSpinBox(self.xy_range, self.xy_units, self.xy_digits)
        self.YBox.setFixedHeight(self.spinbox_height)
        self.YBox.setFixedWidth(self.spinbox_width)

        self.wavelengthLabel = ClickableLabel(
            'Preset wavelength: \n (rough tune)')
        self.wavelengthLabel.setAlignment(QtCore.Qt.AlignRight
                                          | QtCore.Qt.AlignVCenter)
        self.wavelengthBox = SuperSpinBox(self.wl_range, self.wl_units,
                                          self.wl_digits)
        self.wavelengthBox.setFixedHeight(self.spinbox_height)
        self.wavelengthBox.setFixedWidth(self.spinbox_width)

        self.EtalonPDLabel = ClickableLabel('Etalon PD DC:')
        self.EtalonPDLabel.setAlignment(QtCore.Qt.AlignRight
                                        | QtCore.Qt.AlignVCenter)
        self.EtalonPDBox = SuperSpinBox(self.PD_range, self.PD_units,
                                        self.PD_digits)
        self.EtalonPDBox.setFixedHeight(self.spinbox_height)
        self.EtalonPDBox.setFixedWidth(self.spinbox_width)
        self.EtalonPDBox.setReadOnly(True)

        self.OutputPDLabel = ClickableLabel('Output PD:')
        self.OutputPDLabel.setAlignment(QtCore.Qt.AlignRight
                                        | QtCore.Qt.AlignVCenter)
        self.OutputPDBox = SuperSpinBox(self.PD_range, self.PD_units,
                                        self.PD_digits)
        self.OutputPDBox.setFixedHeight(self.spinbox_height)
        self.OutputPDBox.setFixedWidth(self.spinbox_width)
        self.OutputPDBox.setReadOnly(True)

        self.layout = QtWidgets.QGridLayout()
        self.layout.addWidget(self.nameLabel, 1, 0, 1, 6,
                              QtCore.Qt.AlignHCenter)
        self.layout.addWidget(self.statusLabel, 2, 0, 2, 1,
                              QtCore.Qt.AlignRight)
        self.layout.addWidget(self.statusText, 2, 1, 2, 5)
        self.layout.addWidget(self.wlmLabel, 4, 0, 2, 1, QtCore.Qt.AlignRight)
        self.layout.addWidget(self.wlmText, 4, 1, 2, 5)
        self.layout.addWidget(self.lockButton, 6, 0, 2, 2,
                              QtCore.Qt.AlignHCenter)
        self.layout.addWidget(self.oneshotButton, 6, 2, 2, 2,
                              QtCore.Qt.AlignHCenter)
        self.layout.addWidget(self.manualButton, 6, 4, 2, 2,
                              QtCore.Qt.AlignHCenter)
        self.layout.addWidget(self.EtalonTunerLabel, 8, 0, 2, 1,
                              QtCore.Qt.AlignRight)
        self.layout.addWidget(self.EtalonTunerBox, 8, 1, 2, 2,
                              QtCore.Qt.AlignLeft)
        self.layout.addWidget(self.XLabel, 8, 3, 2, 1, QtCore.Qt.AlignRight)
        self.layout.addWidget(self.XBox, 8, 4, 2, 2, QtCore.Qt.AlignLeft)
        self.layout.addWidget(self.ResonatorTunerLabel, 10, 0, 2, 1,
                              QtCore.Qt.AlignRight)
        self.layout.addWidget(self.ResonatorTunerBox, 10, 1, 2, 2,
                              QtCore.Qt.AlignLeft)
        self.layout.addWidget(self.YLabel, 10, 3, 2, 1, QtCore.Qt.AlignRight)
        self.layout.addWidget(self.YBox, 10, 4, 2, 2, QtCore.Qt.AlignLeft)
        self.layout.addWidget(self.ResonatorFineTunerLabel, 12, 0, 2, 1,
                              QtCore.Qt.AlignRight)
        self.layout.addWidget(self.ResonatorFineTunerBox, 12, 1, 2, 2,
                              QtCore.Qt.AlignLeft)
        self.layout.addWidget(self.wavelengthLabel, 12, 3, 2, 1,
                              QtCore.Qt.AlignRight)
        self.layout.addWidget(self.wavelengthBox, 12, 4, 2, 2,
                              QtCore.Qt.AlignLeft)
        self.layout.addWidget(self.EtalonPDLabel, 14, 0, 2, 1,
                              QtCore.Qt.AlignRight)
        self.layout.addWidget(self.EtalonPDBox, 14, 1, 2, 2,
                              QtCore.Qt.AlignLeft)
        self.layout.addWidget(self.OutputPDLabel, 14, 3, 2, 1,
                              QtCore.Qt.AlignRight)
        self.layout.addWidget(self.OutputPDBox, 14, 4, 2, 2,
                              QtCore.Qt.AlignLeft)

        self.layout.setContentsMargins(5, 5, 5, 5)
        self.layout.setSpacing(5)
        self.setLayout(self.layout)
        self.setFixedSize(450, 450)

    @inlineCallbacks
    def connectWidgets(self):
        self.msquared_server = yield self.cxn.get_server(
            self.msquared_servername)
        yield self.msquared_server.signal__update(self.update_id)
        yield self.msquared_server.addListener(listener=self.receive_update,
                                               source=None,
                                               ID=self.update_id)
        self.wlm_server = yield self.cxn.get_server(self.wlm_servername)
        self.nameLabel.clicked.connect(self.onNameLabelClick)
        self.wlmLabel.clicked.connect(self.getWLM)
        self.lockButton.released.connect(self.onLockButton)
        self.oneshotButton.released.connect(self.onOneShotButton)
        self.manualButton.released.connect(self.onManualButton)
        self.XBox.returnPressed.connect(self.onX)
        self.YBox.returnPressed.connect(self.onY)
        self.wavelengthBox.returnPressed.connect(self.onWavelength)
        self.EtalonPDLabel.clicked.connect(self.getEtalonPD)
        self.OutputPDLabel.clicked.connect(self.getOutputPD)

        self.timer1 = QtCore.QTimer(self)
        self.timer1.timeout.connect(self.timer_task1)
        self.timer1.start(self.update_time1)

        self.timer2 = QtCore.QTimer(self)
        self.timer2.timeout.connect(self.timer_task2)
        self.timer2.start(self.update_time2)

        self.lock_timer = QtCore.QTimer(self)
        self.lock_timer.timeout.connect(self.lock_timer_task)

        self.getAll()

    def receive_update(self, c, signal_json):
        signal = json.loads(signal_json)
        message = signal.get('alignment_x_auto')
        if message is not None:
            value = message[self.msquared_devicename]
            self.displayX(value)
        message = signal.get('alignment_y_auto')
        if message is not None:
            value = message[self.msquared_devicename]
            self.displayY(value)

    def disable_when_wlm_lock(self, state):
        self.lockButton.setDisabled(state)
        self.EtalonTunerBox.setDisabled(state)
        self.wavelengthBox.setDisabled(state)

        resonator_state = not bool(state ^ self.lockButton.isChecked())
        self.ResonatorTunerBox.setDisabled(resonator_state)
        self.ResonatorFineTunerBox.setDisabled(resonator_state)

    def onNameLabelClick(self):
        self.getAll()

    def timer_task1(self):
        if self.lockButton.isChecked():
            self.getLockState()
        if self.parent.LockClient.lockButton.isChecked():
            self.lock_timer.start(self.lock_update_time)
        else:
            self.lock_timer.stop()

    def timer_task2(self):
        if self.is_on_OneShot:
            self.getOneShotState()
            self.getOutputPD()
            self.getEtalonPD()

    def lock_timer_task(self):
        self.getWLM()
        self.getResonatorTuner()
        self.getEtalonPD()
        self.getOutputPD()

    def getAll(self):
        self.getLockState()
        self.getEtalonTuner()
        self.getResonatorTuner()
        self.getX()
        self.getY()
        self.getWavelength()
        self.getWLM()
        self.getEtalonPD()
        self.getOutputPD()

    def onLockButton(self):
        lock_state = self.lockButton.isChecked()
        self.setLockState(lock_state)

    @inlineCallbacks
    def setLockState(self, lock_state):
        if lock_state:
            request_json = json.dumps({self.msquared_devicename: True})
        else:
            request_json = json.dumps({self.msquared_devicename: False})
        yield self.msquared_server.etalon_lock(request_json)
        self.displayLockState(lock_state)

    @inlineCallbacks
    def getLockState(self):
        request_json = json.dumps({self.msquared_devicename: None})
        response_json = yield self.msquared_server.etalon_lock(request_json)
        response = json.loads(response_json)
        message = response[self.msquared_devicename]
        if message == True:
            lock_state = True
        elif message == False:
            lock_state = False
        else:
            lock_state = False
            self.statusText.setText(message)
            request_json = json.dumps({self.msquared_devicename: False})
            yield self.msquared_server.etalon_lock(request_json)
        self.displayLockState(lock_state)

    def displayLockState(self, lock_state):
        if lock_state == True:
            self.lockButton.setChecked(1)
            self.lockButton.setText('Remove Etalon Lock')
            self.statusText.setText('Etalon lock ON')
            self.ResonatorTunerBox.setDisabled(False)
            self.ResonatorFineTunerBox.setDisabled(False)
        else:
            self.lockButton.setChecked(0)
            self.lockButton.setText('Apply Etalon Lock')
            self.statusText.setText('Etalon lock OFF')
            self.ResonatorTunerBox.setDisabled(True)
            self.ResonatorFineTunerBox.setDisabled(True)
        self.parent.toggle_lock()

    @inlineCallbacks
    def onOneShotButton(self):
        if not self.is_on_OneShot:
            self.is_on_OneShot = True
            mode = 4  # 4 for One Shot
            request_json = json.dumps({self.msquared_devicename: mode})
            yield self.msquared_server.beam_alignment(request_json)
            self.statusText.setText('One Shot Alignment Started...')
            self.oneshotButton.setDisabled(True)
            self.manualButton.setEnabled(True)
            self.XBox.setDisabled(True)
            self.YBox.setDisabled(True)
        else:
            pass

    @inlineCallbacks
    def getOneShotState(self):
        if self.is_on_OneShot:
            request_json = json.dumps({self.msquared_devicename: None})
            response_json = yield self.msquared_server.beam_alignment(
                request_json)
            status = json.loads(response_json).get(self.msquared_devicename)
            if status == True:
                self.is_on_OneShot = False
                self.statusText.setText('One Shot Alignment Completed')
                self.oneshotButton.setDisabled(False)
                self.XBox.setDisabled(False)
                self.YBox.setDisabled(False)
            else:
                pass
        else:
            pass

    @inlineCallbacks
    def onNewEtalonTuner(self):
        value = self.EtalonTunerBox.value()
        request_json = json.dumps({self.msquared_devicename: value})
        yield self.msquared_server.etalon_tune(request_json)
        self.displayEtalonTuner(value)

    @inlineCallbacks
    def getEtalonTuner(self):
        request_json = json.dumps({self.msquared_devicename: None})
        response_json = yield self.msquared_server.etalon_tune(request_json)
        response = json.loads(response_json)
        value = response.get(self.msquared_devicename)
        value_percentage = value / self.etalon_max * 100
        self.displayEtalonTuner(value_percentage)

    def displayEtalonTuner(self, value):
        self.EtalonTunerBox.display(value)

    @inlineCallbacks
    def onNewResonatorTuner(self):
        value = self.ResonatorTunerBox.value()
        request_json = json.dumps({self.msquared_devicename: value})
        yield self.msquared_server.resonator_tune(request_json)
        self.displayResonatorTuner(value)

    @inlineCallbacks
    def getResonatorTuner(self):
        request_json = json.dumps({self.msquared_devicename: None})
        response_json = yield self.msquared_server.resonator_tune(request_json)
        response = json.loads(response_json)
        value = response.get(self.msquared_devicename)
        value_percentage = value / self.resonator_max * 100
        self.displayResonatorTuner(value_percentage)

    def displayResonatorTuner(self, value):
        self.ResonatorTunerBox.display(value)

    @inlineCallbacks
    def onManualButton(self):
        self.is_on_OneShot = False
        self.oneshotButton.setDisabled(False)
        self.XBox.setDisabled(False)
        self.YBox.setDisabled(False)
        mode = 1  # 1 for Manual
        request_json = json.dumps({self.msquared_devicename: mode})
        yield self.msquared_server.beam_alignment(request_json)

    @inlineCallbacks
    def onX(self):
        value = self.XBox.value()
        request_json = json.dumps({self.msquared_devicename: value})
        yield self.msquared_server.alignment_x(request_json)
        self.displayX(value)

    @inlineCallbacks
    def getX(self):
        request_json = json.dumps({self.msquared_devicename: None})
        response_json = yield self.msquared_server.alignment_x(request_json)
        response = json.loads(response_json)
        value = response.get(self.msquared_devicename)
        self.displayX(value)

    def displayX(self, value):
        self.XBox.display(value)

    @inlineCallbacks
    def onY(self):
        value = self.YBox.value()
        request_json = json.dumps({self.msquared_devicename: value})
        yield self.msquared_server.alignment_y(request_json)
        self.displayY(value)

    @inlineCallbacks
    def getY(self):
        request_json = json.dumps({self.msquared_devicename: None})
        response_json = yield self.msquared_server.alignment_y(request_json)
        response = json.loads(response_json)
        value = response.get(self.msquared_devicename)
        self.displayY(value)

    def displayY(self, value):
        self.YBox.display(value)

    @inlineCallbacks
    def onWavelength(self):
        value = self.wavelengthBox.value()
        request_json = json.dumps({self.msquared_devicename: value})
        yield self.msquared_server.wavelength(request_json)
        self.displayWavelength(value)

    @inlineCallbacks
    def getWavelength(self):
        request_json = json.dumps({self.msquared_devicename: None})
        response_json = yield self.msquared_server.wavelength(request_json)
        response = json.loads(response_json)
        value = response.get(self.msquared_devicename)
        self.displayWavelength(value)

    def displayWavelength(self, value):
        self.wavelengthBox.display(value)

    @inlineCallbacks
    def getWLM(self):
        units = self.parent.PIDClient.unitsBox.currentText()
        channel = self.parent.PIDClient.channelBox.currentText()
        if units in self.frequency_units:
            value = yield self.wlm_server.get_frequency(int(channel))
        elif units in self.wavelength_units:
            value = yield self.wlm_server.get_wavelength(int(channel))
        self.displayWLM(value, units)

    def displayWLM(self, value, units):
        self.wlmText.setText('{} {}'.format(value, units))

    @inlineCallbacks
    def getEtalonPD(self):
        request_json = json.dumps({self.msquared_devicename: None})
        response_json = yield self.msquared_server.etalon_pd(request_json)
        response = json.loads(response_json)
        value = response.get(self.msquared_devicename)
        self.displayEtalonPD(value)

    def displayEtalonPD(self, value):
        self.EtalonPDBox.display(value)

    @inlineCallbacks
    def getOutputPD(self):
        request_json = json.dumps({self.msquared_devicename: None})
        response_json = yield self.msquared_server.output_pd(request_json)
        response = json.loads(response_json)
        value = response.get(self.msquared_devicename)
        self.displayOutputPD(value)

    def displayOutputPD(self, value):
        self.OutputPDBox.display(value)

    def closeEvent(self, x):
        pass
class DIM3000_RFClient(QtWidgets.QGroupBox):
    name = None
    DeviceProxy = None
    updateID = np.random.randint(0, 2**31 - 1)
    amplitudeDisplayUnits = [(0, 'dBm')]
    amplitudeDigits = None
    frequencyDisplayUnits = [(-6, 'uHz'), (-3, 'mHz'), (0, 'Hz'), (3, 'kHz'),
                             (6, 'MHz'), (9, 'GHz')]
    frequencyDigits = None
    fmfreqDisplayUnits = [(-6, 'uHz/V'), (-3, 'mHz/V'), (0, 'Hz/V'),
                          (3, 'kHz/V'), (6, 'MHz/V'), (9, 'GHz/V')]
    fmfreqDigits = None
    spinboxWidth = 80

    def __init__(self, reactor, cxn=None):
        QtWidgets.QDialog.__init__(self)
        self.reactor = reactor
        reactor.callInThread(self.initialize)
        self.connectLabrad()

    def initialize(self):
        import labrad
        cxn = labrad.connect(name=self.name,
                             host=os.getenv('LABRADHOST'),
                             password='')
        self.device = self.DeviceProxy(cxn)
        self.reactor.callFromThread(self.populateGUI)
        self.fm_dev = self.device.fm_dev

    def populateGUI(self):
        self.nameLabel = ClickableLabel('<b>' + self.name + '</b>')
        self.stateButton = QtWidgets.QPushButton()
        self.stateButton.setCheckable(True)

        self.frequencyLabel = ClickableLabel('Frequency: ')
        self.frequencyBox = SuperSpinBox(self.device._frequency_range,
                                         self.frequencyDisplayUnits,
                                         self.frequencyDigits)
        self.frequencyBox.setFixedWidth(self.spinboxWidth)

        self.amplitudeLabel = ClickableLabel('Amplitude: ')
        self.amplitudeBox = SuperSpinBox(self.device._amplitude_range,
                                         self.amplitudeDisplayUnits,
                                         self.amplitudeDigits)
        self.amplitudeBox.setFixedWidth(self.spinboxWidth)

        self.fmstateButton = QtWidgets.QPushButton()
        self.fmfreqBox = SuperSpinBox(self.device._fmfreq_range,
                                      self.fmfreqDisplayUnits,
                                      self.fmfreqDigits)
        self.fmfreqBox.setFixedWidth(self.spinboxWidth)
        self.fmfreqBox.setReadOnly(True)

        self.fmstateButton.setCheckable(True)
        self.fmdevLabel = ClickableLabel('FM Dev: ')
        self.fmdevBox = QtWidgets.QDoubleSpinBox()
        self.fmdevBox.setKeyboardTracking(False)
        self.fmdevBox.setRange(*self.device._fmdev_range)
        #        self.fmdevBox.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons)
        self.fmdevBox.setDecimals(0)

        self.layout = QtWidgets.QGridLayout()
        self.layout.addWidget(self.nameLabel, 0, 0, 1, 1, QtCore.Qt.AlignRight)
        self.layout.addWidget(self.stateButton, 0, 1)
        self.layout.addWidget(self.frequencyLabel, 1, 0, 1, 1,
                              QtCore.Qt.AlignRight)
        self.layout.addWidget(self.frequencyBox, 1, 1)
        self.layout.addWidget(self.amplitudeLabel, 2, 0, 1, 1,
                              QtCore.Qt.AlignRight)
        self.layout.addWidget(self.amplitudeBox, 2, 1)

        self.layout.addWidget(self.fmstateButton, 3, 0, 1, 1,
                              QtCore.Qt.AlignRight)
        self.layout.addWidget(self.fmfreqBox, 3, 1)
        self.layout.addWidget(self.fmdevLabel, 4, 0, 1, 1,
                              QtCore.Qt.AlignRight)
        self.layout.addWidget(self.fmdevBox, 4, 1)

        self.setLayout(self.layout)

        self.setWindowTitle(self.name)
        self.setFixedSize(120 + self.spinboxWidth, 180)

        self.connectSignals()
        self.reactor.callInThread(self.getAll)

    def getAll(self):
        self.getRFState()
        self.getFMState()
        self.getFrequency()
        self.getAmplitude()
        self.getFMdev()
        self.getFMfreq()

    def getFMdev(self):
        fm_dev = self.fm_dev
        self.reactor.callFromThread(self.displayFMdev, fm_dev)

    def displayFMdev(self, fm_dev):
        self.fmdevBox.setValue(fm_dev)

    def getFMfreq(self):
        fm_freq = 3200 * 2**int(self.fm_dev)
        self.reactor.callFromThread(self.displayFMfreq, fm_freq)

    def displayFMfreq(self, fm_freq):
        self.fmfreqBox.display(fm_freq)

    def getRFState(self):
        rf_state = self.device.state
        self.reactor.callFromThread(self.displayRFState, rf_state)

    def displayRFState(self, rf_state):
        if rf_state:
            self.stateButton.setChecked(1)
            self.stateButton.setText('RF ON')
        else:
            self.stateButton.setChecked(0)
            self.stateButton.setText('RF OFF')

    def getFMState(self):
        fm_state = self.device.fm
        self.reactor.callFromThread(self.displayFMState, fm_state)

    def displayFMState(self, fm_state):
        if fm_state:
            self.fmstateButton.setChecked(1)
            self.fmstateButton.setText('FM ON')
        else:
            self.fmstateButton.setChecked(0)
            self.fmstateButton.setText('FM OFF')

    def getFrequency(self):
        frequency = self.device.frequency
        self.reactor.callFromThread(self.displayFrequency, frequency)

    def displayFrequency(self, frequency):
        self.frequencyBox.display(frequency)

    def getAmplitude(self):
        amplitude = self.device.amplitude
        self.reactor.callFromThread(self.displayAmplitude, amplitude)

    def displayAmplitude(self, amplitude):
        self.amplitudeBox.display(amplitude)

    def connectSignals(self):
        self.nameLabel.clicked.connect(self.onNameLabelClick)
        self.frequencyLabel.clicked.connect(self.onFrequencyLabelClick)
        self.amplitudeLabel.clicked.connect(self.onAmplitudeLabelClick)

        self.stateButton.released.connect(self.onNewRFState)
        self.fmstateButton.released.connect(self.onNewFMState)

        self.frequencyBox.returnPressed.connect(self.onNewFrequency)
        self.amplitudeBox.returnPressed.connect(self.onNewAmplitude)

        self.fmdevBox.valueChanged.connect(self.onNewFMDev)

    def onNameLabelClick(self):
        self.reactor.callInThread(self.getAll)

    def onFrequencyLabelClick(self):
        self.reactor.callInThread(self.getFrequency)

    def onAmplitudeLabelClick(self):
        self.reactor.callInThread(self.getAmplitude)

    def onNewRFState(self):
        rf_state = self.stateButton.isChecked()
        self.reactor.callInThread(self.setRFState, rf_state)

    def setRFState(self, rf_state):
        self.device.state = rf_state
        self.reactor.callFromThread(self.displayRFState, rf_state)

    def onNewFMState(self):
        fm_state = self.fmstateButton.isChecked()
        self.reactor.callInThread(self.setFMState, fm_state)

    def setFMState(self, fm_state):
        self.device.fm = fm_state
        self.reactor.callFromThread(self.displayFMState, fm_state)

    def onNewFMDev(self):
        self.fm_dev = self.fmdevBox.value()
        fm_dev = self.fm_dev
        self.reactor.callInThread(self.setFMDev, fm_dev)

    def setFMDev(self, fm_dev):
        self.device.set_fm_dev(fm_dev)
        self.getFMdev()
        self.getFMfreq()

    def onNewFrequency(self):
        frequency = self.frequencyBox.value()
        self.reactor.callInThread(self.setFrequency, frequency)

    def setFrequency(self, frequency):
        self.device.frequency = frequency
        self.reactor.callFromThread(self.displayFrequency, frequency)

    def onNewAmplitude(self):
        amplitude = self.amplitudeBox.value()
        self.reactor.callInThread(self.setAmplitude, amplitude)

    def setAmplitude(self, amplitude):
        self.device.amplitude = amplitude
        self.reactor.callFromThread(self.displayAmplitude, amplitude)

    @inlineCallbacks
    def connectLabrad(self):
        from labrad.wrappers import connectAsync
        self.cxn = yield connectAsync(name=self.name,
                                      host=os.getenv('LABRADHOST'),
                                      password='')
        yield self.cxn.update.signal__signal(self.updateID)
        yield self.cxn.update.addListener(listener=self.receiveUpdate,
                                          source=None,
                                          ID=self.updateID)
        yield self.cxn.update.register(self.name)

    def receiveUpdate(self, c, updateJson):
        update = json.loads(updateJson)
        state = update.get('state')
        if state is not None:
            self.displayState(state)
        frequency = update.get('frequency')
        if frequency is not None:
            self.displayFrequency(frequency)
        amplitude = update.get('amplitude')
        if amplitude is not None:
            self.displayAmplitude(amplitude)

    def closeEvent(self, x):
        self.reactor.stop()