# -*- coding: utf-8 -*-
"""
GUI Code
"""

import LinkGPIB
import pyqtgraph as pg
from pyqtgraph.Qt import QtGui, QtCore
from pyqtgraph.widgets.RemoteGraphicsView import RemoteGraphicsView
import numpy as np
from time import sleep, strftime

## Constants
versionTxt = 'CellShot V2.6.3'
observerModel = 2602 #2461
sourceModel = 2401
timerPeriod = .4
bufferDepth = 1
plotWindow = 2048*4
plotSubsampling = 22
remotePlot = False
setAntialias = False

class MeterGUI(QtGui.QMainWindow):
    # User-Defined constants
    triggered = False
    defaultTopThreshold = '3.6E+6'
    defaultBotThreshold = '3.4E+6'
    defaultPercentage = '8'
    obSettingUpdated = False  # True
    ijSettingUpdated = False  # True
    revertPolarityClicked = False
    defaultYMax = '2.5E+6'
    defaultYMin = '0.5E+0'

    def __init__(self, readport='COM8', baudrate=230400, bufferSize=bufferDepth,
                 winSize=(800,400)): ## COM port and baudrate are for serial comm.

        super(MeterGUI, self).__init__()

        self.lastUpdate = 0.0
        self.startTime = 0.1

        self.data = np.empty((16 * plotWindow, 2))
        self.ptr = 0
        self.avgFPS = 0.0

        # self.kb = KeyBoard()

        self.baseLineValue =    float(self.defaultBotThreshold)
        self.topLineValue =     float(self.defaultTopThreshold)
        self.botLineValue =     float(self.defaultBotThreshold)
        self.percentThreshold = float(self.defaultPercentage)
        self.placeholder = 'Messages\nto be shown\nhere.'

        self.injectionCount = 0

        # QTimer
        self.timer = QtCore.QTimer()

        # GUI Layout
        pg.setConfigOptions(antialias=setAntialias)
        self.layout = pg.LayoutWidget()

        # self.kb = QtGui.QGraphicsView(self)
        self.layout.installEventFilter(self)
        # self.setCentralWidget(self.layout)
        self.createLayout(winSize)

    def initLink(self, externalInjector = True):
        # Initialize Link

        if self.dcheck.isChecked():
            self.lastUpdate = pg.ptime.time()
            self.startTime = pg.ptime.time()
        else:
            try:
                handler.connGPIB(bufferDepth)
                handler.initMeter()
                sleep(3.5)
                # handler.setMeterBuffer(bufferDepth)
                if observerModel == 2401:
                    handler.resetTimer()
                    self.startTime = float(handler.dev[0].query('SYST:TIME?'))
            except:
                print('Failed.')

        # Fill in GUI Boxes
        self.vsenseBox.setText(str(handler.sourceVolt))
        self.ilimitBox.setText(str(handler.sourceILim))
        self.ishotBox.setText(str(handler.injectCurr))
        self.vclampBox.setText(str(handler.injectVLim))
        self.tPulseBox.setText(str(handler.injectWidth))


    def runTimer(self):
        self.timer.timeout.connect(self.update)
        self.timer.start(timerPeriod)

        ## All GPIB assumed.


    def createLayout(self, winSize):
        # GUI Items Declaration
        self.revertPolarityBtn = QtGui.QPushButton('Revert\nPolarity')
        self.revertPolarityBtn.clicked.connect(self.revertPolarity)
        self.expbtn = QtGui.QPushButton('Export')
        self.expbtn.clicked.connect(self.csvExport)
        self.rstbtn = QtGui.QPushButton('Reset')
        self.rstbtn.clicked.connect(self.resetData)
        self.filterEnChk = QtGui.QCheckBox('Analog Filter')
        self.filterEnChk.clicked.connect(self.filterSetting)
        self.filterEnChk.setChecked(False)
        self.ymaxBox = QtGui.QLineEdit(self.defaultYMax)
        self.ymaxBox.editingFinished.connect(self.yrangeSetting)
        self.ymaxBox.setFixedWidth(60)
        self.ymaxBox.setAlignment(QtCore.Qt.AlignRight)
        self.yminBox = QtGui.QLineEdit(self.defaultYMin)
        self.yminBox.editingFinished.connect(self.yrangeSetting)
        self.yminBox.setFixedWidth(60)
        self.yminBox.setAlignment(QtCore.Qt.AlignRight)
        self.autoYChk = QtGui.QCheckBox('Auto Y-Range')
        self.autoYChk.clicked.connect(self.yrangeSetting)
        self.autoYChk.setChecked(True)
        self.dcheck = QtGui.QCheckBox('Debug')
        self.dcheck.setChecked(False)
        self.measureEnChk = QtGui.QCheckBox('Measure Enable')
        self.measureEnChk.setChecked(False)
        self.startBtn = QtGui.QPushButton('Start')
        self.startBtn.clicked.connect(self.startObserve)
        self.plotEnChk = QtGui.QCheckBox('Plot Enable')
        self.plotEnChk.setChecked(True)
        self.msgLab = QtGui.QLabel(self.placeholder)
        self.autoInjectChk = QtGui.QCheckBox('Auto Injection')
        self.autoInjectChk.setChecked(True)
        self.autoInjectChk.clicked.connect(self.aijUpdate)
        self.topThresholdBox = QtGui.QLineEdit(self.defaultTopThreshold)
        self.topThresholdBox.editingFinished.connect(self.thresholdSetting)
        self.topThresholdBox.setFixedWidth(60)
        self.topThresholdBox.setAlignment(QtCore.Qt.AlignRight)
        self.botThresholdBox = QtGui.QLineEdit(self.defaultBotThreshold)
        self.botThresholdBox.editingFinished.connect(self.thresholdSetting)
        self.botThresholdBox.setFixedWidth(60)
        self.botThresholdBox.setAlignment(QtCore.Qt.AlignRight)
        self.adaptThresholdChk = QtGui.QCheckBox('Adaptive Th')
        self.adaptThresholdChk.setChecked(True)
        self.adaptThresholdChk.clicked.connect(self.adaptUpdate)
        self.percentThresholdBox = QtGui.QLineEdit(self.defaultPercentage)
        self.percentThresholdBox.editingFinished.connect(self.tpSetting)
        self.percentThresholdBox.setFixedWidth(60)
        self.percentThresholdBox.setAlignment(QtCore.Qt.AlignRight)

        self.baseLineLab = QtGui.QLabel()

        self.bsline = pg.InfiniteLine(self.baseLineValue, 0)
        self.ttline = pg.InfiniteLine(self.topLineValue, 0, pen='c')
        self.tbline = pg.InfiniteLine(self.botLineValue, 0, pen='m')

        self.manualTrigBtn = QtGui.QPushButton('Manual\nTrigger')  # trigger
        self.manualTrigBtn.clicked.connect(self.setManualTrigger) #handler.dev[1].write(':INIT'))#
        self.injectionCountTitleLab = QtGui.QLabel('Injection#:')
        self.injectionCountLab = QtGui.QLabel(str(self.injectionCount))
        self.rebaseBtn = QtGui.QPushButton('RB')
        self.rebaseBtn.clicked.connect(self.resetBaseLine)
        self.rezeroCountBtn = QtGui.QPushButton('RZ')
        self.rezeroCountBtn.clicked.connect(self.resetInjectionCount)

        self.vsenseBox = QtGui.QLineEdit()  # vsense
        self.ilimitBox = QtGui.QLineEdit()  # ilimit
        self.ishotBox  = QtGui.QLineEdit()  # ishot
        self.vclampBox = QtGui.QLineEdit()  # vclamp
        self.tPulseBox = QtGui.QLineEdit()  # tpulse
        self.filterCntBox = QtGui.QLineEdit('22')  # filterCnt
        self.revertThresholdBox = QtGui.QLineEdit('2E+6') # Revert at this value

        self.autoRevertChk = QtGui.QCheckBox('Auto Revert')
        self.autoRevertChk.setChecked(True)
        self.autoRevertChk.clicked.connect(self.autoRevert)
        self.manualRevertChk = QtGui.QCheckBox('Manual Revert')
        self.manualRevertChk.setChecked(True)
        self.manualRevertChk.clicked.connect(self.manualRevert)

        self.vsenseBox.textEdited.connect(self.setObSettingsUpdated)
        self.ilimitBox.textEdited.connect(self.setObSettingsUpdated)
        self.ishotBox.textEdited.connect(self.setIjSettingsUpdated)
        self.vclampBox.textEdited.connect(self.setIjSettingsUpdated)
        self.tPulseBox.textEdited.connect(self.setIjSettingsUpdated)

        self.updateSettingsBtn = QtGui.QPushButton('Update\nSettings')  # updateSettings
        self.updateSettingsBtn.clicked.connect(self.updateInstSettings)

        self.logBox = QtGui.QTextEdit()

        # Plot Area
        if remotePlot:
            self.rview = RemoteGraphicsView()
            self.rview.pg.setConfigOptions(antialias=setAntialias)
            self.plt = self.rview.pg.PlotItem(title='Real-time Impedance Plot')
            self.plt._setProxyOptions(deferGetattr=True)
            self.rview.setCentralItem(self.plt)
            self.tline = self.plt.plot()
        else:

            self.plt = pg.PlotWidget(title='Real-time Impedance Plot')
            self.plt.addItem(self.bsline)
            self.plt.addItem(self.ttline)
            self.plt.addItem(self.tbline)

        self.plt.showGrid(x=True, y=True)
        self.plt.setClipToView(True)
        self.plt.setLabel('bottom', 'Time', 's')
        self.plt.setLabel('left', 'Impedance', 'Ω')

        ####################
        ## Set GUI Layout ##
        #self.layout.addWidget(self.dcheck, row=0, col=0)
        self.layout.addWidget(self.expbtn, row=0, col=0)
        self.layout.addWidget(self.startBtn, row=1, col=0)
        self.layout.addWidget(self.rstbtn, row=2, col=0)

        self.logo = QtGui.QLabel()
        self.logo.setPixmap(QtGui.QPixmap('resources\\img\\FBM_logo02.png'))
        #self.logo.setFixedHeight(40)
        #self.logo.setFixedWidth(300)
        self.layout.addWidget(self.logo, row=0, col=1, colspan=3)
        self.layout.addWidget(self.measureEnChk, row=1, col=1)
        self.filterCntLab = QtGui.QLabel('Moving Avg.(2~100):')
        self.layout.addWidget(self.filterCntLab, row=2, col=1)
        self.filterCntLab.setFixedWidth(160)
        self.filterCntLab.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)

        self.layout.addWidget(self.filterEnChk, row=1, col=2)
        self.filterCntBox.setFixedWidth(40)
        self.layout.addWidget(self.filterCntBox, row=2, col=2)

        self.vsenseLab = QtGui.QLabel('V_sense:')
        self.vsenseLab.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        self.layout.addWidget(self.vsenseLab, row=1, col=3)
        self.ilimitLab = QtGui.QLabel('I_limit:')
        self.ilimitLab.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        self.layout.addWidget(self.ilimitLab, row=2, col=3)

        # Polarity Reversion
        self.revertPolarityBtn.setFixedWidth(60)
        self.layout.addWidget(self.revertPolarityBtn, row=0, col=4)
        # V-sense
        self.vsenseBox.setFixedWidth(60)
        self.layout.addWidget(self.vsenseBox, row=1, col=4)
        # I-limit
        self.ilimitBox.setFixedWidth(60)
        self.layout.addWidget(self.ilimitBox, row=2, col=4)

        # Update Settings
        self.updateSettingsBtn.setFixedWidth(60)
        self.layout.addWidget(self.updateSettingsBtn, row=0, col=5)
        # Ishot Box
        self.ishotLab = QtGui.QLabel('I_shot:')
        self.ishotLab.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        self.layout.addWidget(self.ishotLab, row=1, col=5)
        self.ishotBox.setFixedWidth(60)
        self.layout.addWidget(self.ishotBox, row=1, col=6)
        # Vclamp box
        self.vclampLab = QtGui.QLabel('V_clamp:')
        self.vclampLab.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        self.layout.addWidget(self.vclampLab, row=2, col=5)
        self.vclampBox.setFixedWidth(60)
        self.layout.addWidget(self.vclampBox, row=2, col=6)
        # tPulse Box
        self.tPulseLab = QtGui.QLabel('t_Pulse:')
        self.tPulseLab.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        self.layout.addWidget(self.tPulseLab, row=3, col=5)
        self.tPulseBox.setFixedWidth(60)
        self.layout.addWidget(self.tPulseBox, row=3, col=6)
        # Manual Trig
        self.manualTrigBtn.setFixedWidth(60)
        self.layout.addWidget(self.manualTrigBtn, row=0, col=6)

        self.layout.addWidget(self.autoRevertChk, row=4, col=5, colspan=2)
        self.revertThresholdLab = QtGui.QLabel('Flip @')
        self.revertThresholdLab.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        self.layout.addWidget(self.revertThresholdLab, row=5, col=5)
        self.revertThresholdBox.setFixedWidth(60)
        self.layout.addWidget(self.revertThresholdBox, row=5, col=6)
        self.layout.addWidget(self.autoInjectChk, row=6, col=5, colspan=2)
        self.layout.addWidget(self.botThresholdBox, row=7, col=5)
        self.layout.addWidget(self.topThresholdBox, row=7, col=6)
        self.layout.addWidget(self.baseLineLab, row=8, col=5)
        self.rebaseBtn.setFixedWidth(30)
        self.layout.addWidget(self.rebaseBtn, row=8, col=6)
        # Peak counter
        self.injectionCountTitleLab.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignBottom)
        self.layout.addWidget(self.injectionCountTitleLab, row=9, col=5, colspan=1)
        self.injectionCountLab.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
        self.layout.addWidget(self.injectionCountLab, row=10, col=5)
        self.rezeroCountBtn.setFixedWidth(30)
        self.layout.addWidget(self.rezeroCountBtn, row=10, col=6)

        # Version
        self.versionLab = QtGui.QLabel(versionTxt)
        self.versionLab.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTop)
        self.layout.addWidget(self.versionLab, row=0, col=7, colspan=2)
        # Plot Speed
        self.layout.addWidget(self.msgLab,          row=1, col=7, rowspan=2, colspan=2)
        self.msgLab.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTop)
        self.layout.addWidget(self.manualRevertChk, row=4, col=7, colspan=2)
        self.layout.addWidget(self.plotEnChk,       row=5, col=7, colspan=2)
        self.layout.addWidget(self.autoYChk,        row=6, col=7, colspan=2)
        self.layout.addWidget(self.yminBox,         row=7, col=7)
        self.layout.addWidget(self.ymaxBox,         row=7, col=8)
        self.layout.addWidget(self.adaptThresholdChk, row=9, col=7, colspan=2)
        self.layout.addWidget(self.percentThresholdBox, row=10, col=7)
        self.layout.addWidget(QtGui.QLabel('%'),    row=10, col=8)

        self.layout.addWidget(self.logBox,          row=11, col=5, colspan=4)

        if remotePlot:
            self.layout.addWidget(self.rview, row=3, col=0, rowspan=10, colspan=5)
        else:
            self.layout.addWidget(self.plt, row=3, col=0, rowspan=10, colspan=5)

        self.layout.resize(*winSize)
        self.layout.show()
        self.curve = self.plt.plot()
    #        if remotePlot:

    def startObserve(self):
        if (observerModel == 2602) :
            handler.dev[0].write('startObserve()')
            print('Starting...')
        self.measureEnChk.setChecked(True)

    def aijUpdate(self):
        if observerModel == 2602:
            if self.autoInjectChk.isChecked():
                handler.dev[0].write('Aij(true)')
            else:
                handler.dev[0].write('Aij(false)')

    def resetBaseLine(self):
        self.baseLineValue = float(self.defaultBotThreshold)
        self.topLineValue = float(self.defaultTopThreshold)
        self.botLineValue = float(self.defaultBotThreshold)
        handler.dev[0].write('reb()')

    def resetInjectionCount(self):
        self.injectionCount = 0
        handler.dev[0].write('rez()')

    def setManualTrigger(self):
        if observerModel == 2602:
            handler.dev[0].write('genPulse(ijWidth)')
        else:
            handler.dev[1].write(':INIT')

    def setObSettingsUpdated(self):
        self.obSettingUpdated = True

    def setIjSettingsUpdated(self):
        self.ijSettingUpdated = True
        print('Injector setting has been changed.')
        #print(self.ijSettingUpdated)
        #print((self.ijSettingUpdated == True) )
        #print((self.obSettingUpdated != True) & (self.ijSettingUpdated != True))


    def updateInstSettings(self):
        if ((self.obSettingUpdated != True) & (self.ijSettingUpdated != True)):
            print('No setting has been changed.')

        else:
            if self.obSettingUpdated:
                self.obSettingUpdated = False
                self.ijSettingUpdated = False
                handler.sourceVolt = float(self.vsenseBox.text())
                handler.sourceILim = float(self.ilimitBox.text())
                if observerModel == 2602:
                    handler.dev[0].write('updateSMUA('+ str(handler.sourceVolt)
                                         + ',' + str(handler.sourceILim) + ')')
                    print('updateSMUA('+ str(handler.sourceVolt)
                          + ',' + str(handler.sourceILim) + ')')
                    # updating function

            if self.ijSettingUpdated:
                self.ijSettingUpdated = False
                handler.injectCurr = float(self.ishotBox.text())
                handler.injectVLim = float(self.vclampBox.text())
                handler.injectWidth = float(self.tPulseBox.text())
                if observerModel == 2602:
                    handler.dev[0].write('updateSMUB(' + str(handler.injectCurr)
                                         + ',' + str(handler.injectVLim) + ')')
                    handler.dev[0].write('ijWidth = '+str(handler.injectWidth))
                else:
                    handler.dev[1].write(':SOUR:CURR:LEV ' + str(handler.injectCurr))
                    handler.dev[1].write(':SENS:VOLT:PROT ' + str(handler.injectVLim))

    def adaptUpdate(self):
        if observerModel == 2602:
            if self.adaptThresholdChk.isChecked():
                percent = self.percentThresholdBox.text()
            else:
                percent = '0'
            print('adaptiveT(' + percent + ')')
            handler.dev[0].write('adaptiveT(' + percent + ')')


    def revertPolarity(self):
        if observerModel == 2602:
            #handler.dev[0].write('rvt()')
            print('Obsolete function since V2.5.6')
        else:
            self.obSettingUpdated = ~self.obSettingUpdated # Why?
            self.revertPolarityClicked = True
        handler.sourceVolt = -handler.sourceVolt
        self.vsenseBox.setText(str(handler.sourceVolt))
        print('Source is changed to %02.1f' % handler.sourceVolt)

    def csvExport(self):
        filename = strftime('%Y%m%d_%H%M')+'.csv'
        np.savetxt(filename, self.data, fmt='%.06f',delimiter=',',header='|Z|(ohms),time(s)')
        choice = QtGui.QMessageBox.information(self, 'Message',
                                               "Impedance data is saved in "+filename+'!',
                                               QtGui.QMessageBox.Ok)
        if choice == QtGui.QMessageBox.Ok:
            print("Exporting confirmed.")

    def resetData(self):
        self.ptr = 0
        self.data = np.empty((16 * plotWindow, 2))
        self.avgFPS = 0.0
        self.baseLineValue = float(self.defaultBotThreshold)
        self.topLineValue = float(self.defaultTopThreshold)
        self.botLineValue = float(self.defaultBotThreshold)

        if self.dcheck.isChecked():
            self.startTime = pg.ptime.time()
        elif observerModel == 2401:
            self.startTime = 0
            handler.dev[0].write(':SYST:TIME:RES')
        return

    def autoRevert(self):
        global handler
        if self.autoRevertChk.isChecked():
            if observerModel == 2602:
                handler.dev[0].write('revertThreshold = ' + self.revertThresholdBox.text())
                handler.dev[0].write('autoRevert = true')
                print('Auto polarity reversion is applied.')
        else:
            if observerModel == 2602:
                handler.dev[0].write('autoRevert = false')
                print('Auto polarity reversion is cancelled.')
        return

    def manualRevert(self):
        global handler
        if self.manualRevertChk.isChecked():
            if observerModel == 2602:
                handler.dev[0].write('manualRevert = true')
                print('Manual polarity reversion is enabled.')
        else:
            if observerModel == 2602:
                handler.dev[0].write('manualRevert = false')
                print('Manual polarity reversion is disabled.')
        return

    def filterSetting(self):
        global handler
        if self.filterEnChk.isChecked():
            #self.ser.write(b'RES:FILT ON\n')
            if observerModel == 2602:
                handler.dev[0].write('smua.measure.filter.count = '+ self.filterCntBox.text())
                handler.dev[0].write('smua.measure.filter.enable = smua.FILTER_ON')
            elif observerModel == 2401:
                handler.dev[0].write(':SENS:AVER ON')
            elif observerModel == 2461:
                #if observerModel == 2461:
                handler.dev[0].write(':SENS:CURR:AVER ON')
            print('Analog LPF is applied.')
        else:
            #self.ser.write(b'RES:FILT OFF\n')
            if observerModel == 2602:
                handler.dev[0].write('smua.measure.filter.enable = smua.FILTER_OFF')
            elif observerModel == 2401:
                handler.dev[0].write(':SENS:AVER OFF')
            elif observerModel == 2461:
                handler.dev[0].write(':SENS:CURR:AVER OFF')
            print('Analog LPF is disabled.')
        return

    def yrangeUpdate(self):
        self.defaultYMax = self.ymaxBox.text()
        self.defaultYMin = self.yminBox.text()
        print(self.defaultYMax, self.defaultYMin)
        return

    def yrangeSetting(self):
        self.yrangeUpdate()
        if self.autoYChk.isChecked():
            self.plt.enableAutoRange(axis='y')
            print('Auto Y-range is set.')
        else:
            # self.plt.setRange(yRange=[float(self.ymin),float(self.ymax)],update=True,disableAutoRange=True)
            self.plt.disableAutoRange(axis='y')
            self.plt.setYRange(float(self.defaultYMin), float(self.defaultYMax))
            print('Manual Y-range is set.')
        return

    def thresholdSetting(self):
        self.defaultTopThreshold = self.topThresholdBox.text()
        self.defaultBotThreshold = self.botThresholdBox.text()
        self.topLineValue = float(self.defaultTopThreshold)
        self.botLineValue = float(self.defaultBotThreshold)
        self.ttline.setValue(self.topLineValue)
        self.tbline.setValue(self.botLineValue)

    def tpSetting(self):
        self.percentThreshold = float(self.percentThresholdBox.text())

    def update(self):
        if self.measureEnChk.isChecked():
            ## Expanding data buffer

            self.ptr += bufferDepth
            if self.ptr >= self.data.shape[0]:
                tmp = self.data
                self.data = np.empty((self.data.shape[0]*2,2))
                self.data[:tmp.shape[0],:] = tmp
                print('Expanding data buffer...')

            # Updating Z-data
            if self.dcheck.isChecked():
                now = pg.ptime.time()
                self.data[self.ptr - bufferDepth:self.ptr, 0] = np.random.normal(size=bufferDepth)
                self.data[self.ptr, 1] = now - self.startTime
                for i in range(1, bufferDepth):
                    self.data[self.ptr - i, 1] = self.data[self.ptr, 1] - (now - self.lastUpdate) * i / float(bufferDepth)

            else:
                # Pre-processing may be necessary
                self.data[self.ptr-bufferDepth : self.ptr] = self.getData()

            if self.revertPolarityClicked:
                self.revertPolarityClicked = False
                if observerModel == 2461:
                    handler.dev[0].write(':SOUR:VOLT '+str(handler.sourceVolt)+'\n')

            if self.plotEnChk.isChecked() & ((self.ptr / bufferDepth) % plotSubsampling == 0):
                now = self.data[self.ptr-1, 1]
                try:
                    fps = 1 / (now - self.lastUpdate)
                except:
                    fps = 1

                if self.ptr < plotWindow: ## Plot is not moving at this point
                    self.curve.setData(x=self.data[:self.ptr, 1], y=self.data[:self.ptr, 0], _callSync='off')
                    self.sigma = np.std(self.data[:self.ptr, 0])
                else: # Moving plot
                    self.curve.setData(x=self.data[self.ptr - plotWindow:self.ptr, 1],
                                       y=self.data[self.ptr - plotWindow:self.ptr, 0], _callSync='off')
                    self.sigma = np.std(self.data[self.ptr - plotWindow:self.ptr, 0])

                self.bsline.setValue(self.baseLineValue)
                self.ttline.setValue(self.topLineValue)
                self.tbline.setValue(self.botLineValue)

                self.avgFPS = self.avgFPS * 0.95 + fps * 0.05
                self.msgLab.setText('Plotting\n@%02.2ffps\n(%0.1fpoints/s)\nσ=%.2e' % \
                                    (self.avgFPS, self.avgFPS * bufferDepth * plotSubsampling, self.sigma))
                self.baseLineLab.setText('%02.2e' % self.baseLineValue)
                self.injectionCountLab.setText(str(self.injectionCount))
                self.lastUpdate = now

        return

    def getData(self):
        global handler
        ## GPIB
        try:
            #received = handler.dev[0].read().split(',')
            if observerModel == 2602:
                try:
                    received = handler.dev[0].read().rstrip('\n').split(',')
                except:
                    print(received)
                    #handler.dev[0].read()
                    #if (handler.dev[0].read()!="TSP>\n"): print('Non-prompt output detected.')

            elif observerModel == 2461:
                handler.dev[0].write(':READ:DIG? "defbuffer1",READ,REL')
                #handler.dev[0].write(':READ? "defbuffer1",READ,REL')
                received = LinkGPIB.formatSRE(handler.dev[0].read_raw())

            elif observerModel == 2401:
                received = LinkGPIB.formatSRE(handler.dev[0].read_raw())

            #received = handler.dev[0].query(':READ?').split(',')
            #received = handler.readMeterBuffer().split(',')
            #print(received)

            readValues = np.empty((bufferDepth,2)) # Z, t

            if observerModel == 2602: # re-coded for V2.5
                # Cell detection: Source Voltage and Read Current
                readValues[:,0] = received[0::6] # Z, t, base, bot, top, ijCnt
                readValues[:,1] = received[1::6]

                self.baseLineValue = float(received[2])
                self.botLineValue = received[3]
                self.topLineValue = received[4]
                self.injectionCount = int(received[5])
            #
            #     if self.autoInjectChk.isChecked():
            #         if ~self.triggered & (np.max(readValues[:, 0]) > self.topLineValue):
            #                 handler.dev[1].write(':INIT')
            #                 self.triggered = True
            #                 self.injectionCount += 1 # Counts number of injections
            #         elif (np.min(readValues[:,0]) < self.botLineValue):
            #             if (np.min(readValues[:,0]) < self.baseLineValue):
            #                 self.baseLineValue = self.baseLineValue * 0.996 + np.average(readValues[:, 0]) * 0.004
            #             else:
            #                 self.baseLineValue = self.baseLineValue * 0.98 + np.average(readValues[:, 0]) * 0.02
            #             if self.adaptThresholdChk.isChecked():
            #                 self.botLineValue = self.baseLineValue * (1 + 0.006 * self.percentThreshold)
            #                 self.topLineValue = self.baseLineValue * (1 + 0.01 * self.percentThreshold)
            #             #print(self.baseLineValue)
            #             if self.triggered:
            #                 self.triggered = False

            elif observerModel == 2461:
                # Cell detection: Source Voltage and Read Current
                readValues[:,0] = [ handler.sourceVolt / x for x in received[0::2]]

                ## debugging - source current and read voltage
                #readValues[:,0] = [x / handler.sourceCurr for x in received[0::2]]
                #print(readValues[:,0])
                if self.autoInjectChk.isChecked():
                    if ~self.triggered & (np.max(readValues[:, 0]) > self.topLineValue):
                        handler.dev[1].write(':INIT')
                        self.triggered = True
                    elif (np.min(readValues[:,0]) < self.botLineValue):
                        self.baseLineValue = self.baseLineValue * 0.95 + np.average(readValues[:, 0]) * 0.05
                        if self.adaptThresholdChk.isChecked():
                            self.botLineValue = self.baseLineValue * (1 + 0.006 * self.percentThreshold)
                            self.topLineValue = self.baseLineValue * (1 + 0.01 * self.percentThreshold)
                        #print(self.baseLineValue)
                        if self.triggered:
                            self.triggered = False
                readValues[:,1] = received[1::2]

            else:
                readValues[:,0] = received[0::2]
                readValues[:,1] = received[1::2]
                #print(readValues[:,1])

                #print(readValues)
        except:
            readValues = np.random.normal(size=(bufferDepth,2))
        return readValues

    def eventFilter(self, source, event):
        if (source is self.layout and
                    event.type() == QtCore.QEvent.KeyPress):
            key = event.key()
            if key == QtCore.Qt.Key_Escape:
                print('Esc button is pressed.')
                # sys.exit(1)
            elif key == QtCore.Qt.Key_Space:
                self.setManualTrigger()
        return QtGui.QMainWindow.eventFilter(self, source, event)

    # def closeEvent(self, event):
    #     print('Calling')
    #     print('event: {0}'.format(event))
    #     event.accept()


if __name__ == '__main__':
    import sys
    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        app = QtGui.QApplication(sys.argv)
        handler = LinkGPIB.LinkHandler()
        m = MeterGUI()
        m.initLink()
        #handler.dev[0].write('startObserve()')
        m.runTimer()
        sys.exit(app.exec_())
