Ver código fonte

minimal working remote_control version

Patrick Schreiber 8 anos atrás
pai
commit
8acdc74921
4 arquivos alterados com 649 adições e 70 exclusões
  1. 1 1
      KCG/widgets/__init__.py
  2. 1 1
      KCG/widgets/acquiresettings.py
  3. 205 68
      KCG/widgets/remote.py
  4. 442 0
      kcg_remote_client_qt.py

+ 1 - 1
KCG/widgets/__init__.py

@@ -1 +1 @@
-__all__ = ['acquiresettings', 'singleread', 'timingWidget', 'externalTriggerWidget'] #, 'remote'] #, 'example_widget']
+__all__ = ['acquiresettings', 'singleread', 'timingWidget', 'externalTriggerWidget', 'remote'] #, 'example_widget']

+ 1 - 1
KCG/widgets/acquiresettings.py

@@ -44,7 +44,7 @@ class acquireSettings(kcgw.KCGWidgets):
         self.countLabel = self.createLabel(tr("Label", "Count"))
         self.countSpinbox = self.createSpinbox(1, 10000000, start_value=10, connect=self.on_count_changed) # TODO: does 10000000 as max make sense?
         self.waitLabel = self.createLabel(tr("Label", "Wait(s)"))
-        self.waitSpinbox = self.createSpinbox(1, 60, start_value=15, connect=self.on_wait_changed) # TODO: does 60 as max and default as 15 make sense?
+        self.waitSpinbox = self.createSpinbox(0, 60, start_value=15, connect=self.on_wait_changed) # TODO: does 60 as max and default as 15 make sense?
         self.simulatePilotBunch = self.createCheckbox(tr("Button", "Simulate Pilot Bunch"), connect=self.on_simulate_pilot_bunch_changed)
         self.buildSpectrogrammTickbox = self.createCheckbox(tr("Button", "Build Spectograms"), connect=self.on_build_spectrograms_changed)
         # -------[ register observers ]------

+ 205 - 68
KCG/widgets/remote.py

@@ -1,18 +1,29 @@
 from PyQt4 import QtGui, QtCore
+import pyqtgraph as pg
+import pyqtgraph.exporters as exp
+import os
 import socket
-import base.kcgwidget as kcgw
-import base.backendinterface as bif
-from base.backend import board
-from base.groupedelements import Elements
-import config
+from collections import OrderedDict
+from ..base import kcgwidget as kcgw
+from ..base import backendinterface as bif
+from ..base.plotWidget import SubPlotWidget, PlotType
+from ..base.backend import board
+from ..base.groupedelements import Elements
+from ..base.backend import io
+from .. import config
 
 __widget_id__ = None
+DOES_NOT_SET_CLOSE = 1
+DOES_SET_CLOSE = 2
 
 class Remote(kcgw.KCGWidgets):
     response = QtCore.pyqtSignal(str)
+    close_connection_requested = QtCore.pyqtSignal()
     def __init__(self, unique_id, parent):
         super(Remote, self).__init__()
 
+        board.status.last_file = '/home/blaxxun/Documents/Hiwi/KaptureSimulator/2015-05-07_test-patrick/1431006860.291.out'
+
         self.id = unique_id
         self.par = parent
 
@@ -40,15 +51,23 @@ class Remote(kcgw.KCGWidgets):
 
         self.rl = RemoteListener(self.host, self.port.value(), parent=self)
         self.rl.command_received.connect(self.evaluate)
-        self.response.connect(self.rl.response)
+        # self.response.connect(self.rl.response)
+        self.response.connect(self.rl.responde)
 
         self.commands = {
-            'calibrate': [["after_start"], bif.bk_calibrate],
-            'sync': [["after_start", "synchronize"], bif.bk_sync_board],
-            'set_defaults': [['after_start', 'set_defaults'], lambda: bif.bk_write_values(defaults=False)],
-            'soft_reset': [['after_start'], bif.bk_soft_reset]
+            'calibrate': [["after_start"], bif.bk_calibrate, DOES_NOT_SET_CLOSE],
+            'sync': [["after_start", "synchronize"], bif.bk_sync_board, DOES_NOT_SET_CLOSE],
+            'set_defaults': [['after_start', 'set_defaults'], lambda: bif.bk_write_values(defaults=True), DOES_NOT_SET_CLOSE],
+            'soft_reset': [['after_start'], bif.bk_soft_reset, DOES_NOT_SET_CLOSE],
+            'acquire': [[], self.acquire, DOES_SET_CLOSE],
+            'set': [[], self.set_value, DOES_SET_CLOSE],
+            'get': [[], self.get_value, DOES_SET_CLOSE],
+            'help': [[], self.help, DOES_SET_CLOSE],
+            'get_image': [[], self.get_image, DOES_SET_CLOSE],
+            'singleread': [['acquire'], self.single_read, DOES_SET_CLOSE]
         }
-        self.value_types = {
+
+        self.value_types = OrderedDict({
             'fpga_delay_max': int,
             'fpga_delay': int,
             'fpga_delay_factor': int,
@@ -76,62 +95,171 @@ class Remote(kcgw.KCGWidgets):
             'build_spectrograms': bool,
             'pilot_bunch': bool,
             'header': bool
+        })
+        self.help_text = {
+            'calibrate': ['-', 'Calibrates the board'],
+            'sync': ['-', 'Synchronizes the board'],
+            'set_defaults': ['-', 'Sets defaults and writes them to the board'],
+            'soft_reset': ['-', 'Performs a soft reset'],
+            'aquire': ['-', 'Starts an acquisition'],
+            'set': [["One of", self.value_types.keys(), '<value>'], 'Write values'],
+            'get': [['Sublist of', self.value_types.keys()], 'Read values'],
+            'help': [['[command]'], 'Get Help'],
+            'get_image': [['<type>', '<adc>'], 'Gets the last acquired data as image (type is one of "trains", "fft", "heatmap", "combined"'],
+            'singleread': [[], 'Performs a single read']
         }
 
+
     def is_possible(self, groups):
         for group in groups:
+            print group
             if not Elements.isEnabled(group):
                 return False
         return True
 
+    # -----[ remote commands ]----------
+    def acquire(self):
+        if self.is_possible(["acquireTrigger"]):
+            bif.bk_acquire()
+            if board.status.acquisition:
+                self.response.emit("Acquisition started - Check status using 'get status'")
+            else:
+                self.response.emit("Acquisition stopped")
+        else:
+            self.response.emit("Not Possible")
+
+    def single_read(self):
+        try:
+            bif.bk_single_read()
+            self.response.emit("Singleread done")
+        except Exception as e:
+            self.response.emit(str(e))
+
+    def set_value(self, c):
+        if len(c) != 2:
+            self.response.emit("You need to specify the option (only one) and a value.\nset <option> <value>")
+            return
+        try:
+            board.config.update(c[0], self.value_types[c[0]](c[1]))
+            self.response.emit("Success: Set Value "+c[0]+" to "+c[1])
+        except (ValueError, KeyError) as e:
+            self.response.emit("Failed - Invalid Value: " + str(e))
+
+    def get_value(self, c):
+        if c[0] == 'status':
+            if board.status.acquisition:
+                perc = int(board.acquisition_progressbar.value() / float(
+                                                             board.acquisition_progressbar.maximum() -
+                                                             board.acquisition_progressbar.minimum()) * 100)
+                perc = str(perc) + "%"
+            else:
+                perc = "No Acquisition"
+            self.response.emit(str(perc))
+        elif c[0] == 'all_acquisition': # get all values important for acquisition
+            resp = "Orbits Observed: " + str(board.config.get("orbits_observe")) + "\n" + \
+                   "Orbits Skipped: " + str(board.config.get("orbits_skip")) + "\n" + \
+                   "Count: " + str(board.config.get("orbits_count")) + "\n" + \
+                   "Wait Time: " + str(board.config.get("orbits_wait_time")) + "\n" + \
+                   "Pilot Bunch Simulator: " + str(board.config.get("pilot_bunch")) + "\n" + \
+                   "Header: " + str(board.config.get("header"))
+            self.response.emit(resp)
+        elif c[0] == 'possible_keys':
+            resp = ''
+            for key in self.value_types.keys():
+                resp += key + '\n'
+            self.response.emit(resp)
+        else:
+            if len(c) == 2 and c[1] == 'clean':
+                try:
+                    self.response.emit(str(board.config.get(c[0])))
+                except ValueError as e:
+                    self.response.emit("Failed - Invalid Value: " + str(e))
+            else:
+                ret = ""
+                try:
+                    for key in c:
+                        ret += key + " = " + str(board.config.get(key)) + "\n"
+                    self.response.emit(ret[:-1])
+                except ValueError as e:
+                    self.response.emit("Failed - Invalid Value: " + str(e))
+
+    def help(self, c=None):
+        if isinstance(c, list):
+            command = c[0]
+        if c is None:
+            ret = "Possible commands:"
+            for key in self.commands:
+                ret += '\n'+ key
+        elif command in self.help_text:
+            ret = command + ":\n"
+            ret += "Options: "
+            if isinstance(self.help_text[command][0], list):
+                for i in self.help_text[command][0]:
+                    ret += str(i) + ", "
+            else:
+                ret += str(self.help_text[command][0])
+            ret += '\n'
+            ret += str(self.help_text[command][1])
+        else:
+            ret = "Either the command or the help for this command doesn't exist"
+        self.response.emit(ret)
+
+    def get_image(self, c=None):
+        if c is None:
+            c = ['trains', 1]
+        imgpath = board.status.last_file
+        sw = SubPlotWidget()
+        if c[0] == 'trains':
+            data = io.read_from_file(imgpath, force=False, header=board.config.get('header'), cache=False).train(adc=int(c[1]), frm=0, to=10000)
+            # test = pg.plot(data)
+            # export = exp.ImageExporter(test.plotItem)
+            # export.parameters()['width'] = 500
+            sw.changeType(PlotType.Trains)
+            # sw.plot(data)
+            # export.export('tempimage.png')
+            # test.parent().close()
+            # del test
+            # del export
+        elif c[0] == 'fft':
+            data = io.read_from_file(imgpath, force=False, header=board.config.get('header'), cache=False).fft(adc=int(c[1]), frm=0, to=10000, drop_first_bin=True)
+            sw.changeType(PlotType.FFT)
+        elif c[0] == 'heatmap':
+            data = io.read_from_file(imgpath, force=False, header=board.config.get('header'), cache=False).heatmap(adc=int(c[1]), frm=0, to=10000)
+            sw.changeType(PlotType.Heatmap)
+        elif c[0] == 'combined':
+            data = io.read_from_file(imgpath, force=False, header=board.config.get('header'), cache=False).combined(frm=0, to=10000)
+            sw.changeType(PlotType.Combined)
+        sw.plot(data, autorange=True)
+        QtGui.QApplication.processEvents()
+        export = exp.ImageExporter(sw.plotItem)
+        export.parameters()['width'] = 1000
+        export.export('tempimage.png')
+        f = open('tempimage.png', 'r')
+        self.rl.c.sendall(f.read())
+        f.close()
+        os.remove('tempimage.png')
+        sw.close()
+        del sw
+        del export
+
+
     @QtCore.pyqtSlot(str)
     def evaluate(self, command):
         c = str(command).split(" ")
         try:
-            if c[0] == 'acquire':
-                if self.is_possible(["acquireTrigger"]):
-                    bif.bk_acquire()
-                    if board.status.acquisition:
-                        self.response.emit("Acquisition started - Check status using 'get status'")
-                    else:
-                        self.response.emit("Acquisition stopped")
-                else:
-                    self.response.emit("Not Possible")
-
-
             if c[0] in self.commands:
                 if self.is_possible(self.commands[c[0]][0]):
-                    self.response.emit(".Processing")
-                    self.commands[c[0]][1]()
-                    self.response.emit("Success")
-                else:
-                    self.response.emit("Not Possible")
-            if c[0] == 'set': #  set values in board.config
-                board.config.update(c[1], self.value_types[c[1]](c[2]))
-                print 'setting', c[1], 'to', c[2]
-                self.response.emit("Success")
-            if c[0] == 'get':  # get values from board.config
-                if c[1] == 'status':
-                    if board.status.acquisition:
-                        perc = int(board.acquisition_progressbar.value() / float(
-                                                                     board.acquisition_progressbar.maximum() -
-                                                                     board.acquisition_progressbar.minimum()) * 100)
-                        perc = str(perc) + "%"
+                    # self.response.emit("Command Received")
+                    if len(c) > 1:
+                        self.commands[c[0]][1](c[1:])
                     else:
-                        perc = "No Acquisition"
-                    self.response.emit(str(perc))
-                elif c[1] == 'all_acquisition': # get all values important for acquisition
-                    resp = "Orbits Observed: " + str(board.config.get("orbits_observe")) + "\n" + \
-                           "Orbits Skipped: " + str(board.config.get("orbits_skip")) + "\n" + \
-                           "Count: " + str(board.config.get("orbits_count")) + "\n" + \
-                           "Wait Time: " + str(board.config.get("orbits_wait_time")) + "\n" + \
-                           "Pilot Bunch Simulator: " + str(board.config.get("pilot_bunch")) + "\n" + \
-                           "Header: " + str(board.config.get("header"))
-                    self.response.emit(resp)
+                        self.commands[c[0]][1]()
+                    if self.commands[c[0]][2] == DOES_NOT_SET_CLOSE:
+                        self.response.emit("Success: " + c[0])
+                    self.close_connection_requested.emit()
                 else:
-                    self.response.emit(str(board.config.get(c[1])))
-
-        except Exception, e:
+                    self.response.emit("Not Possible")
+        except Exception as e:
             self.response.emit("Failed \n"+str(e))
 
 
@@ -195,6 +323,7 @@ class RemoteListener(QtCore.QObject):
         self.soc.bind((self.host, self.port))
         self.soc.listen(0)
         self.response_text = None
+        self.response_updated = False
 
     def evaluate(self, command):
         self.command_received.emit(command)
@@ -204,35 +333,43 @@ class RemoteListener(QtCore.QObject):
         # conn, addr = soc.accept()
         while self.status:
             try:
+                self.close = False
                 conn, addr = self.soc.accept()
+                self.c = conn
                 command = conn.recv(1024)
                 if not command: continue
-                if command == "stop":
-                    break
+                # if command == "stop":
+                #     break
                 self.evaluate(command)
-                # while True:
-                #     if self.response:
-                #         self.soc.send(self.response)
-                #     else:
-                #         time.sleep(0.01)
-                self.wait_signal(self.parent.response, 2000)
-                if self.response_text:
-                    while self.response_text[0] == '.':
-                        conn.send(self.response_text)
-                        self.wait_signal(self.parent.response, 2000)
-                    conn.send(self.response_text)
-                else:
-                    conn.send("Failed")
 
-                self.response_text = None
+                # -------[ OLD wait ]---------
+                # self.wait_signal(self.parent.response, 20000)
+                # if self.response_text:
+                    # while self.response_text[0] == '.':
+                    #     conn.send(self.response_text)
+                    #     self.wait_signal(self.parent.response, 20000)
+                    # conn.send(self.response_text)
+                # else:
+                #     conn.send("Failed")
 
+                # self.response_text = None
+                self.wait_signal(self.parent.close_connection_requested, 10000)
+                conn.send("close") # tell the client to close the connection
                 conn.close()
             except socket.error:  # Go on even in case of exception
                 pass
-        conn.close()
+        self.c.send("close") # tell the client to close the connection
+        self.c.close()
 
     def response(self, res):
         self.response_text = res
+        self.response_updated = True
+
+    def responde(self, res):
+        try:
+            self.c.sendall(str(res))
+        except Exception as e:
+            print str(e)
 
     def wait_signal(self, signal, timeout=10000):
         """Block loop until signal emitted, or timeout (ms) elapses."""

+ 442 - 0
kcg_remote_client_qt.py

@@ -0,0 +1,442 @@
+from PyQt4 import QtGui, QtCore
+import subprocess
+# import numpy as np
+# import pyqtgraph as pg
+# import cPickle
+import time
+import sys
+
+import kcg_remote_client as client
+
+def safe_call(cmd):
+    try:
+        return subprocess.check_output(cmd)
+    except subprocess.CalledProcessError as e:
+        pass
+    except OSError as e:
+        pass
+
+class settingHighlighter(QtGui.QSyntaxHighlighter):
+    def __init__( self, parent, theme):
+        super(settingHighlighter, self).__init__(parent)
+        self.parent = parent
+        self.highlightingRules = []
+
+
+        # equal = QtGui.QTextCharFormat()
+        # equal.setForeground(QtCore.Qt.green)
+        # equal.setFontWeight( QtGui.QFont.Bold )
+        # pattern = QtCore.QRegExp("=")
+        # self.highlightingRules.append((pattern, equal))
+
+        number = QtGui.QTextCharFormat()
+        number.setForeground(QtCore.Qt.blue)
+        number.setFontWeight( QtGui.QFont.Bold )
+        pattern = QtCore.QRegExp( "[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?" )
+        pattern.setMinimal(True)
+        self.highlightingRules.append((pattern, number))
+
+        bool_true = QtGui.QTextCharFormat()
+        bool_true.setForeground(QtCore.Qt.darkGreen)
+        bool_true.setFontWeight( QtGui.QFont.Bold )
+        pattern = QtCore.QRegExp( "True" )
+        self.highlightingRules.append((pattern, bool_true))
+
+        bool_false = QtGui.QTextCharFormat()
+        bool_false.setForeground(QtCore.Qt.darkRed)
+        bool_false.setFontWeight( QtGui.QFont.Bold )
+        pattern = QtCore.QRegExp( "False" )
+        self.highlightingRules.append((pattern, bool_false))
+
+        failed = QtGui.QTextCharFormat()
+        failed.setForeground(QtCore.Qt.red)
+        failed.setFontWeight( QtGui.QFont.Bold )
+        pattern = QtCore.QRegExp( "Failed|Connection Error" )
+        self.highlightingRules.append((pattern, failed))
+
+        success = QtGui.QTextCharFormat()
+        success.setForeground(QtGui.QColor(30, 210, 0))
+        success.setFontWeight( QtGui.QFont.Bold )
+        pattern = QtCore.QRegExp( "Success" )
+        self.highlightingRules.append((pattern, success))
+
+        header = QtGui.QTextCharFormat()
+        header.setForeground(QtCore.Qt.black)
+        header.setFontWeight( QtGui.QFont.Bold )
+        pattern = QtCore.QRegExp( "-----\[.*\]-----" )
+        pattern.setMinimal(True)
+        self.highlightingRules.append((pattern, header))
+
+        working = QtGui.QTextCharFormat()
+        working.setForeground(QtCore.Qt.black)
+        working.setFontWeight( QtGui.QFont.Bold )
+        pattern = QtCore.QRegExp("Working...")
+        self.highlightingRules.append((pattern, working))
+
+    def setKeywords(self, kw):
+        keyword = QtGui.QTextCharFormat()
+        keyword.setForeground( QtCore.Qt.darkBlue)
+        # keyword.setFontWeight( QtGui.QFont.Bold )
+        keywords = QtCore.QStringList(kw)
+        for word in keywords:
+            pattern = QtCore.QRegExp("\\b" + word + "\\b")
+            self.highlightingRules.append((pattern, keyword))
+
+
+
+    def highlightBlock( self, text ):
+        for pattern, format in self.highlightingRules:
+            # expression = QtCore.QRegExp( pattern )
+            # index = expression.indexIn( text )
+            index = pattern.indexIn(text)
+            while index >= 0:
+              length = pattern.matchedLength()
+              self.setFormat( index, length, format )
+              index = text.indexOf( pattern, index + length )
+        self.setCurrentBlockState( 0 )
+
+class customTextEdit(QtGui.QTextEdit):
+    def __init__(self):
+        super(customTextEdit, self).__init__()
+        self.highlighter = settingHighlighter(self, 'Classic')
+    def append(self, string):
+        # super(customTextEdit, self).append("---------------"*3)
+        super(customTextEdit, self).append("-----[ " + time.asctime() + " ]-----\n"+string+"\n")
+        self.ensureCursorVisible()
+    def setKeywords(self, kw):
+        self.highlighter.setKeywords(kw)
+
+class convenientGridLayout(QtGui.QGridLayout):
+    line = 0
+    column = 0
+    def addWidget(self, QWidget, newLine=False, line=None, col=None, rowSpan=1, colSpan=1):
+        if (line is not None) and (col is not None):
+            super(convenientGridLayout, self).addWidget(QWidget, line, col, rowSpan, colSpan)
+            return
+        elif line is not None:
+            super(convenientGridLayout, self).addWidget(QWidget, line, self.column, rowSpan, colSpan)
+            return
+        elif col is not None:
+            super(convenientGridLayout, self).addWidget(QWidget, self.line, col, rowSpan, colSpan)
+            return
+        if newLine:
+            self.line += 1
+            self.column = 0
+            super(convenientGridLayout, self).addWidget(QWidget, self.line, self.column, rowSpan, colSpan)
+            return
+        else:
+            super(convenientGridLayout, self).addWidget(QWidget, self.line, self.column, rowSpan, colSpan)
+            self.column += 1
+            return
+
+    def newLine(self):
+        self.line += 1
+        self.column = 0
+    def skipCol(self, cols=1):
+        self.column += cols
+    def hLine(self, cols):
+        line = QtGui.QFrame()
+        line.setFrameShape(QtGui.QFrame.HLine)
+        if cols == 'full':
+            self.addWidget(line, newLine=True, colSpan=self.columnCount())
+        else:
+            self.addWidget(line, newLine=True, colSpan=cols)
+    def vLine(self, rows, perm=False):
+        line = QtGui.QFrame()
+        line.setFrameShape(QtGui.QFrame.VLine)
+        if rows == 'full':
+            self.addWidget(line, rowSpan=self.rowCount())
+        else:
+            self.addWidget(line, rowSpan=rows)
+
+
+class KCGRemote(QtGui.QMainWindow):
+    def __init__(self):
+        super(KCGRemote, self).__init__()
+        self.c = KCGCentral()
+        self.setCentralWidget(self.c)
+        self.statusText = QtGui.QLabel("Not Connected")
+        self.statusbar = self.statusBar()
+        self.statusbar.addPermanentWidget(self.statusText)
+        self.setWindowTitle("KCG Remote Control")
+        if len(sys.argv) > 1 and sys.argv[1] == 'blue':
+            styleSheet = ''
+            with open('KCG/style/blue.css') as f:
+                    styleSheet += f.read()
+            self.setStyleSheet(styleSheet)
+
+
+class KCGCentral(QtGui.QWidget):
+    def __init__(self):
+        super(KCGCentral, self).__init__()
+
+        self.progressbar = QtGui.QProgressBar()
+        self.progressbar.hide()
+        # self.user_layout = QtGui.QGridLayout()
+        self.user_layout = convenientGridLayout()
+        self.layout = QtGui.QVBoxLayout()
+        self.layout.addLayout(self.user_layout)
+        self.setLayout(self.layout)
+
+        self.host_edit = QtGui.QLineEdit()
+        self.port_edit = QtGui.QLineEdit()
+        self.connect = QtGui.QPushButton("Connect")
+        self.connect.clicked.connect(self.conn)
+
+        self.host = None
+        self.port = None
+
+        self.cal_button = QtGui.QPushButton("Calibrate")
+        self.cal_button.clicked.connect(self.cal)
+        self.sync_button = QtGui.QPushButton("Synchronize")
+        self.sync_button.clicked.connect(self.sync)
+        self.set_def_button = QtGui.QPushButton("Set Defaults")
+        self.set_def_button.clicked.connect(self.set_def)
+        self.reset_button = QtGui.QPushButton("Reset")
+        self.reset_button.clicked.connect(self.reset)
+        self.acquire_button = QtGui.QPushButton("Toggle Acquisition")
+        self.acquire_button.clicked.connect(self.acq)
+        self.get_button = QtGui.QPushButton("Get Value")
+        self.get_button.clicked.connect(self.get)
+        self.set_button = QtGui.QPushButton("Set Value")
+        self.set_button.clicked.connect(self.set)
+        self.reinit_status_button = QtGui.QPushButton("Reinit Status")
+        self.reinit_status_button.clicked.connect(self.status)
+
+        self.get_image_button = QtGui.QPushButton("Get Image")
+        self.get_image_button.clicked.connect(self.get_image)
+
+        # self.get_field = QtGui.QLineEdit()
+        self.get_placeholder = QtGui.QLabel("Load possible keys first")
+        self.set_key_placeholder_button = QtGui.QPushButton("Load possible keys")
+        self.set_key_placeholder_button.clicked.connect(self.load_keys)
+        self.set_value_field = QtGui.QLineEdit()
+
+        self.get_image_type = QtGui.QComboBox()
+        self.get_image_type.addItems(['trains', 'fft', 'heatmap', 'combined'])
+        self.get_image_adc_field = QtGui.QSpinBox()
+        self.get_image_adc_field.setRange(1, 4)
+
+        self.single_read_button = QtGui.QPushButton("Single Read")
+        self.single_read_button.clicked.connect(self.single_read)
+
+        self.buttons = [self.cal_button,
+                        self.sync_button,
+                        self.set_def_button,
+                        self.reset_button,
+                        self.acquire_button,
+                        self.get_button,
+                        self.set_button,
+                        self.get_image_button,
+                        self.set_key_placeholder_button,
+                        self.reinit_status_button,
+                        self.get_image_type,
+                        self.get_image_adc_field,
+                        self.set_value_field,
+                        self.single_read_button]
+        for b in self.buttons:
+            b.setEnabled(False)
+
+        # self.user_layout.addWidget(QtGui.QLabel("Host"), 0, 0)
+        # self.user_layout.addWidget(self.host_edit, 1, 0)
+        # self.user_layout.addWidget(QtGui.QLabel("Port"), 0, 1)
+        # self.user_layout.addWidget(self.port_edit, 1, 1)
+        # self.user_layout.addWidget(self.connect, 1, 3)
+        # line = QtGui.QFrame()
+        # line.setFrameShape(QtGui.QFrame.HLine)
+        # self.user_layout.addWidget(line, 2, 0, 1, 4)
+
+
+        # self.user_layout.addWidget(self.cal_button, 3, 0)
+        # self.user_layout.addWidget(self.sync_button, 3, 1)
+        # self.user_layout.addWidget(self.set_def_button, 4, 1)
+        # self.user_layout.addWidget(self.reset_button, 4, 0)
+        # line2 = QtGui.QFrame()
+        # line2.setFrameShape(QtGui.QFrame.VLine)
+        # self.user_layout.addWidget(line2, 3, 2, 2, 1)
+        # line3 = QtGui.QFrame()
+        # line3.setFrameShape(QtGui.QFrame.HLine)
+        # self.user_layout.addWidget(line3, 5, 0, 1, 4)
+
+
+        # self.user_layout.addWidget(self.acquire_button, 3, 3)
+        # self.user_layout.addWidget(self.reinit_status_button, 4, 3)
+        # self.user_layout.addWidget(self.get_image_type, 6, 0)
+        # self.user_layout.addWidget(self.get_image_adc_field, 6, 1)
+        # self.user_layout.addWidget(self.get_image_button, 6, 3)
+        # self.user_layout.addWidget(self.get_placeholder, 7, 1)
+        # self.user_layout.addWidget(self.get_button, 7, 3)
+        # self.user_layout.addWidget(self.set_key_placeholder_button, 8, 0)
+        # self.user_layout.addWidget(self.set_value_field, 8, 1)
+        # self.user_layout.addWidget(self.set_button, 8, 3)
+
+
+        self.user_layout.addWidget(QtGui.QLabel("Host"))
+        self.user_layout.addWidget(QtGui.QLabel("Port"))
+        self.user_layout.newLine()
+        self.user_layout.addWidget(self.host_edit)
+        self.user_layout.addWidget(self.port_edit)
+        self.user_layout.addWidget(self.connect)
+        # line = QtGui.QFrame()
+        # line.setFrameShape(QtGui.QFrame.HLine)
+        # self.user_layout.addWidget(line, newLine=True, colSpan=4)
+        self.user_layout.hLine('full')
+
+
+        self.user_layout.newLine()
+        self.user_layout.addWidget(self.cal_button)
+        self.user_layout.addWidget(self.sync_button)
+        # line2 = QtGui.QFrame()
+        # line2.setFrameShape(QtGui.QFrame.VLine)
+        # self.user_layout.addWidget(line2, rowSpan=2)
+        self.user_layout.vLine(2)
+        self.user_layout.newLine()
+        self.user_layout.addWidget(self.set_def_button)
+        self.user_layout.addWidget(self.reset_button)
+
+        # line3 = QtGui.QFrame()
+        # line3.setFrameShape(QtGui.QFrame.HLine)
+        # self.user_layout.addWidget(line3, newLine=True, colSpan=4)
+        self.user_layout.hLine('full')
+
+        self.user_layout.newLine()
+        self.user_layout.addWidget(self.acquire_button)
+        self.user_layout.addWidget(self.single_read_button)
+        self.user_layout.addWidget(self.reinit_status_button)
+
+        # line4 = QtGui.QFrame()
+        # line4.setFrameShape(QtGui.QFrame.HLine)
+        # self.user_layout.addWidget(line4, newLine=True, colSpan=4)
+        self.user_layout.hLine('full')
+
+        self.user_layout.newLine()
+        self.user_layout.addWidget(self.get_image_type)
+        self.user_layout.addWidget(self.get_image_adc_field)
+        self.user_layout.addWidget(self.get_image_button)
+        self.user_layout.newLine()
+        self.user_layout.skipCol()
+        self.user_layout.addWidget(self.get_placeholder)
+        self.user_layout.addWidget(self.get_button)
+        self.user_layout.newLine()
+        self.user_layout.addWidget(self.set_key_placeholder_button)
+        self.user_layout.addWidget(self.set_value_field)
+        self.user_layout.addWidget(self.set_button)
+
+
+        self.output = customTextEdit()
+        self.output.setReadOnly(True)
+
+        self.layout.addWidget(self.output)
+
+        self.image = QtGui.QLabel()
+        self.image.hide()
+        # self.layout.addWidget(self.image)
+
+    def send(self, command):
+        bk = self.parent().statusText.text()
+        self.parent().statusText.setText("Working...")
+        QtGui.QApplication.processEvents()
+        r = client.send(command, self.host, self.port, p=False).strip()
+        self.parent().statusText.setText(bk)
+        return r
+
+    def conn(self):
+        try:
+            host = self.host_edit.text()
+            port = int(self.port_edit.text())
+            client.send('get status', host, port, p=False)
+            self.host = host
+            self.port = port
+            for button in self.buttons:
+                button.setEnabled(True)
+            self.parent().statusText.setText("Connected")
+            self.load_keys()
+        except:
+            self.output.append("Connection Error")
+
+    def load_keys(self):
+        r = self.send('get possible_keys')
+        idx1 = self.user_layout.getItemPosition(self.user_layout.indexOf(self.set_key_placeholder_button))
+        idx2 = self.user_layout.getItemPosition(self.user_layout.indexOf(self.get_placeholder))
+        self.user_layout.removeWidget(self.set_key_placeholder_button)
+        self.user_layout.removeWidget(self.get_placeholder)
+        self.set_key_placeholder_button.hide()
+        self.get_placeholder.hide()
+        self.set_key_field = QtGui.QComboBox()
+        self.get_field = QtGui.QComboBox()
+        self.get_field.addItem('all_acquisition')
+        self.set_key_field.addItems(r.split('\n'))
+        self.get_field.addItems(r.split('\n'))
+        self.user_layout.addWidget(self.set_key_field, line=idx1[0], col=idx1[1])
+        self.user_layout.addWidget(self.get_field, line=idx2[0], col=idx2[1])
+
+        syntax = r.split('\n')
+        syntax.extend(["Orbits Observed", "Orbits Skipped", "Count", "Wait Time", "Pilot Bunch Simulator", "Header"])
+        self.output.setKeywords(syntax)
+
+    def cal(self):
+        r = self.send('calibrate')
+        self.output.append(r)
+    def sync(self):
+        r = self.send('sync')
+        self.output.append(r)
+    def set_def(self):
+        r = self.send('set_defaults')
+        self.output.append(r)
+    def reset(self):
+        r = self.send('reset')
+        self.output.append(r)
+    def acq(self):
+        r = self.send('acquire')
+        self.output.append(r)
+        if 'started' in r:
+            self.parent().statusbar.addWidget(self.progressbar)
+            self.progressbar.show()
+            self.status()
+        else:
+            self.parent().statusbar.removeWidget(self.progressbar)
+            self.progressbar.hide()
+    def status(self):
+        r = self.send('get status')
+        if 'No' in r:
+            self.parent().statusbar.removeWidget(self.progressbar)
+            self.progressbar.hide()
+            self.output.append(r)
+        else:
+            if not self.progressbar in self.parent().statusbar.children():
+                self.parent().statusbar.addWidget(self.progressbar)
+                self.progressbar.show()
+            r = int(r.strip("%"))
+            self.progressbar.setValue(r)
+            timer = QtCore.QTimer()
+            timer.singleShot(1000, self.status)
+
+
+    def set(self):
+        r = self.send('set ' + str(self.set_key_field.currentText()) + " " + str(self.set_value_field.text()))
+        self.output.append(r)
+    def get(self):
+        r = self.send('get ' + str(self.get_field.currentText()))
+        self.output.append(r)
+
+    def get_image(self):
+        self.send('get_image '+str(self.get_image_type.currentText()) + ' ' + str(self.get_image_adc_field.value()))
+        pixmap = QtGui.QPixmap('/tmp/kcgimage.png')
+        self.image.setPixmap(pixmap.scaledToHeight(700, mode=QtCore.Qt.SmoothTransformation))
+        # self.image.setPixmap(pixmap)
+        self.image.setMinimumSize(self.image.pixmap().size())
+        self.image.show()
+
+    def single_read(self):
+        r = self.send("singleread")
+        self.output.append(r)
+
+
+
+
+
+
+app = QtGui.QApplication([])
+rem = KCGRemote()
+rem.show()
+app.exec_()