# -*- coding: utf-8; mode: python; indent-tabs-mode: t; tab-width:4 -*-
import sys, time, math, os.path

import utils
from QtVersion import *

import sys, time
from utils import pg
import numpy as np
import eyes17.eyemath17 as em
from functools import partial

from .layouts import ui_schoolscope_layout
from .layouts.advancedLoggerTools import LOGGER
from .layouts.sensor_utilities import DIOSENSOR, DIOROBOT, DIOCONTROL
from .layouts.gauge import Gauge


class Expt(QtWidgets.QWidget, ui_schoolscope_layout.Ui_Form):
    TIMER = 2
    loopCounter = 0
    AWGmin = 1
    AWGmax = 5000
    AWGval = 1000
    SQ1min = 0
    SQ1max = 50000
    SQ1val = 0
    PV1min = -5.0
    PV1max = 5.0
    PV1val = 0.0
    PV2min = -3.3
    PV2max = 3.3
    PV2val = 0.0

    RPVspacing = 3  # Right panel Widget spacing
    RPWIDTH = 300
    LABW = 60

    # Scope parameters
    MAXCHAN = 4
    Ranges12 = ['16 V', '8 V', '4 V', '2.5 V', '1 V', '.5V']  # Voltage ranges for A1 and A2
    RangeVals12 = [16., 8., 4., 2.5, 1., 0.5]
    Ranges34 = ['4 V', '2 V', '1 V', '.5V']  # Voltage ranges for A3 and MIC
    RangeVals34 = [4, 2, 1, 0.5]
    chanStatus = [1, 0, 0, 0]
    timeData = [None] * 4
    voltData = [None] * 4
    voltDataFit = [None] * 4
    traceWidget = [None] * 4
    offSliders = [None] * 4
    offValues = [0] * 4
    DiffTraceW = None
    fitResWidget = [None] * 4
    chanSelCB = [None] * 4
    rangeSelPB = [None] * 4
    fitSelCB = [None] * 4
    fitSelLabels = [None] * 4
    fitFlags = [0] * 4
    Amplitude = [0] * 4
    Frequency = [0] * 4
    Phase = [0] * 4
    rangeVals = [4] * 4  # selected value of range
    rangeTexts = ['4 V'] * 4  # selected value of range
    scaleLabs = [None] * 4  # display fullscale value inside pg
    voltMeters = [None] * 3
    voltMeterCB = {}
    valueLabel = None
    trigEnable = True

    sources = ['A1', 'A2', 'A3', 'MIC', 'SEN', 'IN1', 'AN8']

    tbvals = [0.100, 0.200, 0.500, 1.0, 2.0, 5.0, 10.0, 20.0, 50.0]  # allowed mS/div values
    NP = 500  # Number of samples
    TG = 1  # Number of channels
    MINDEL = 1  # minimum time between samples, in usecs
    MAXDEL = 1000
    delay = MINDEL  # Time interval between samples
    TBval = 1  # timebase list index
    Trigindex = 0
    Triglevel = 0
    dutyCycle = 50
    MAXRES = 5
    resLabs = [None] * MAXRES
    Results = [None] * MAXRES

    Wgains = ['80 mV', '1V', '3V']
    wgainindex = 2

    Waves = ['sine', 'tria', 'SQR2']
    waveindex = 0
    voltmeter = None

        

    def __init__(self, device=None):
        super(Expt, self).__init__()
        self.sensorList = []
        self.setupUi(self)
        penCols2  = ['#990', '#090', '#900','magenta','cyan']     #pqtgraph pen colors
        htmlcols2 = ['#990', '#090', '#900','magenta','cyan']
        self.resultCols = penCols2
        self.traceCols = [pg.mkPen(p, width=2) for p in penCols2]
        self.htmlColors = htmlcols2
        self.plot_widget = pg.PlotWidget(self.pwinview)
        self.plot_widget.setBackground('w')
        self.plotLayout.addWidget(self.plot_widget)
        self.p = device  # connection to the device hardware

        self.chanStatus = [1, 0, 0, 0]  # PyQt problem. chanStatus somehow getting preserved ???

        self.offSliders = [self.slider1, self.slider2, self.slider3, self.slider4]
        for ch in range(self.MAXCHAN):
            self.offSliders[ch].valueChanged.connect(partial(self.set_offset, ch))
            self.offSliders[ch].setStyleSheet('''QSlider::handle:vertical{background: %s;};''' % (self.htmlColors[ch]))
        self.plot_widget.proxy = pg.SignalProxy(self.plot_widget.scene().sigMouseMoved, rateLimit=60, slot=self.updateTV)
        self.plot_widget.showGrid(x=True, y=True)  # with grid

        for k in range(self.MAXCHAN):  # pg textItem to show the voltage scales
            self.scaleLabs[k] = pg.TextItem(text='')

        for k in range(self.MAXRES):  # pg textItem to show the Results
            self.resLabs[k] = pg.TextItem()
            self.plot_widget.addItem(self.resLabs[k])


        vLine = pg.InfiniteLine(angle=90, movable=False, pen='r')
        self.plot_widget.addItem(vLine, ignoreBounds=True)
        self.plot_widget.vLine = vLine
        self.plot_widget.vLine.setPos(-1)

        ax = self.plot_widget.getAxis('bottom')
        ax.setLabel(self.tr('Time (mS)'))
        ax = self.plot_widget.getAxis('left')
        ax.setStyle(showValues=False)
        ax.setLabel(self.tr('Voltage'))

        self.set_timebase(self.TBval)
        self.plot_widget.disableAutoRange()
        self.plot_widget.setXRange(0, self.tbvals[self.TBval] * 10)
        self.plot_widget.setYRange(-16, 16)
        self.plot_widget.hideButtons()  # Do not show the 'A' button of pg

        # Create arrow item for trigger level
        self.trigger_arrow = pg.ArrowItem(angle=180, tipAngle=30, baseAngle=30, pen='g', brush='#333')
        self.plot_widget.addItem(self.trigger_arrow)
        self.trigger_arrow.setPos( 0.,0. )  # Set initial position to 0 volts
        #self.trigger_arrow.hide()  # Hide initially


        for ch in range(self.MAXCHAN):  # initialize the pg trace widgets
            self.traceWidget[ch] = self.plot_widget.plot([0, 0], [0, 0], pen=self.traceCols[ch])
        self.diffTraceW = self.plot_widget.plot([0, 0], [0, 0], pen=self.traceCols[-1])

        self.CAP.clicked.connect(self.measure_cap)

        self.FREQ.clicked.connect(self.measure_freq)

        self.OD1.stateChanged.connect(self.control_od1)
        self.CCS.stateChanged.connect(self.control_ccs)

        self.chanSelCB = [self.A1Box, self.A2Box, self.A3Box, self.MICBox]
        self.rangeSelPB = [self.A1Range, self.A2Range, self.A3Range, self.MICRange]
        self.fitSelCB = [self.A1FitCombo, self.A2FitCombo, self.A3FitCombo, self.MICFitCombo]
        self.fitSelLabels = [self.A1Fit, self.A2Fit, self.A3Fit, self.MICFit]
        self.fitOptions = ['FIT', 'sine', 'p2p', 'rms', 'avg', 'min', 'max']
        for b in self.fitSelCB:
            b.addItems(self.fitOptions)

        for a,mn,mx in zip(['A1','A2','A3'],[-16,-16,-3.3,0],[16,16,3.3,3.3]):
            gauge = Gauge(self,a)
            gauge.setObjectName(a)
            gauge.set_MinValue(mn)
            gauge.set_MaxValue(mx)
            gauge.mouseDoubleClickEvent = gauge.toggleChecked
            self.gaugeLayout.addWidget(gauge)
            self.voltMeterCB[a] = gauge

        for ch in range(4):
            self.chanSelCB[ch].stateChanged.connect(partial(self.select_channel, ch))
            self.chanSelCB[ch].setStyleSheet('''border: 1px solid %s;''' % (self.htmlColors[ch]))  # <font color="%s">

            self.rangeSelPB[ch].currentIndexChanged['int'].connect(partial(self.select_range, ch))

        self.chanSelCB[0].setChecked(True)
        self.trigSources = ['CH1','CH2','CH3','CH4','OFF']
        self.trigBox.addItems(self.trigSources)
        self.A1Map.addItems(self.sources)
        self.recover()
        self.timer = QTimer()
        self.timer.timeout.connect(self.update)
        self.timer.start(self.TIMER)

    def toggled(self):
        for inp in self.fields:
            if self.cbs[inp].isChecked():
                self.curves[inp].setVisible(True)
                self.gauges[inp][0].set_NeedleColor()
                self.gauges[inp][0].set_enable_filled_Polygon()
            else:
                self.curves[inp].setVisible(False)
                self.gauges[inp][0].set_NeedleColor(255,0,0,30)
                self.gauges[inp][0].set_enable_filled_Polygon(False)


    def recover(self):  # Recover the settings before it got disconnected
        self.msgwin.setText('<font color="green">' + self.tr('Reconnecting...'))
        try:
            self.control_od1()
            self.pv1_text()
            self.pv2_text()
            if self.p:
                self.p.set_sqr1(self.SQ1val, self.dutyCycle)
            self.select_wave(self.waveindex)
            if self.p: self.p.set_wave(self.AWGval)
            self.select_wgain(self.wgainindex)
            self.set_trigger(self.Triglevel * 1000)
            if self.p: self.p.set_sine(self.AWGval)
            if self.p: self.p.configure_trigger(0, 'A1', 0)
            # self.select_range((0,2))
            # self.select_range((1,2))
            # self.select_range((2,0))
            # self.select_range((3,0))
            if self.p and self.p.calibrated:
                cal = self.tr('Calibrated ')
            else:
                cal = self.tr('Not Calibrated ')
            self.msgwin.setText('<font color="green">' + self.tr('Device Reconnected:') + cal)
            if self.p and self.p.version_number >= 5.0:
                self.pcsFrame.show()
                self.CS1.show()
                self.CS2.show()
                self.CS3.show()
                self.CS4.show()
                self.CCS.hide()
            else:
                self.pcsFrame.hide()
                self.CS1.hide()
                self.CS2.hide()
                self.CS3.hide()
                self.CS4.hide()
                self.CCS.show()

            if self.voltmeter is not None:
                self.voltmeter.reconnect(self.p)
            else:
                from .layouts.oscilloscope_widget import DIOINPUT
                try:
                    self.voltmeter = DIOINPUT(self, self.p, confirmValues=None)
                except Exception as e:
                    print('device not found', e)
            for a, b in zip([self.WGLabel, self.SQ1Label, self.PV1Label, self.PV2Label], ['WG', 'SQ1', 'PV1', 'PV2']):
                a.clicked.connect(partial(self.voltmeter.launch, b))

        except Exception as e:
            print(e)
            self.msgwin.setText('<font color="red">' + self.tr('Error. Could not connect. Check cable. '))


    def show_fft(self):
        for ch in range(4):
            if self.chanStatus[ch] == 1:
                try:
                    fa = em.fit_sine(self.timeData[ch], self.voltData[ch])
                except Exception as err:
                    print('fit_sine error:', err)
                    fa = None
                if fa != None:
                    fr = fa[1][1] * 1000  # frequency in Hz
                    dt = int(1.e6 / (20 * fr))  # dt in usecs, 20 samples per cycle
                    try:
                        t, v = self.p.capture1(self.sources[ch], 3000, dt)
                    except:
                        self.comerr()

                    xa, ya = em.fft(v, dt)
                    xa *= 1000
                    peak = self.peak_index(xa, ya)
                    ypos = np.max(ya)
                    pop = pg.plot(xa, ya, pen=self.traceCols[ch])
                    pop.showGrid(x=True, y=True)
                    txt = pg.TextItem(text=self.tr('Fundamental frequency = %5.1f Hz') % peak, color='w')
                    txt.setPos(peak, ypos)
                    pop.addItem(txt)
                    pop.setWindowTitle(self.tr('Frequency Spectrum'))
                else:
                    self.msg(self.tr('FFT Error'))

    def peak_index(self, xa, ya):
        peak = 0
        peak_index = 0
        for k in range(2, len(ya)):
            if ya[k] > peak:
                peak = ya[k]
                peak_index = xa[k]
        return peak_index

    def save_data(self):
        self.timer.stop()
        fn = QFileDialog.getSaveFileName()
        if fn != '':
            dat = []
            for ch in range(4):
                if self.chanStatus[ch] == 1:
                    dat.append([self.timeData[ch], self.voltData[ch]])
            self.p.save(dat, fn)
            ss = fn
            self.msg(self.tr('Traces saved to ') + ss)
        self.timer.start(self.TIMER)

    def set_offset(self, ch):
        self.offValues[ch] = self.offSliders[ch].value()
        self.updateTriggerArrow()

    def cross_hair(self):
        if self.Cross.isChecked() == False:
            self.plot_widget.vLine.setPos(-1)

    def showVoltagesAtCursor(self, xval):
        for k in range(self.MAXRES):
            self.plot_widget.removeItem(self.resLabs[k])
        t = self.timeData[0]
        index = 0
        for k in range(len(t) - 1):  # find out Time at the cursor position
            if t[k] < xval < t[k + 1]:
                index = k

        self.resLabs[0] = pg.TextItem(
            text=self.tr('Time: %6.2fmS ') % t[index],
            color=self.resultCols[0]
        )
        self.resLabs[0].setPos(0, -11)
        self.plot_widget.addItem(self.resLabs[0])

        for k in range(self.MAXCHAN):
            if self.chanStatus[k] == 1:
                self.Results[k + 1] = self.tr('%s:%6.2fV ') % (self.sources[k], self.voltData[k][index])
                self.resLabs[k + 1] = pg.TextItem(text=self.Results[k + 1], color=self.resultCols[k])
                self.resLabs[k + 1].setPos(0, -12 - 1.0 * k)
                self.plot_widget.addItem(self.resLabs[k + 1])

    def updateTV(self, evt):
        if self.p == None: return
        if self.Cross.isChecked() == False:
            self.plot_widget.vLine.setPos(-1)
            return
        pos = evt[0]  ## using signal proxy turns original arguments into a tuple
        if self.plot_widget.sceneBoundingRect().contains(pos):
            mousePoint = self.plot_widget.plotItem.vb.mapSceneToView(pos)
            xval = mousePoint.x()
            self.plot_widget.vLine.setPos(mousePoint.x())
            self.showVoltagesAtCursor(xval)

    def update(self):
        if self.p is None:
            return
        if not self.p.connected:
            self.comerr()
            return
        if self.voltmeter is not None:
            if self.voltmeter.isVisible() and self.voltmeter.type == 'input' and self.voltmeter.autoRefresh:
                try:
                    v = self.voltmeter.read()
                except Exception as e:
                    self.comerr()
                    return
                if v is not None:
                    self.voltmeter.setValue(v)

        for a in self.sensorList:
            if a[0].isVisible():
                if a[0].isPaused == 0 or (a[0].currentPage != None and a[
                    0].currentPage == 0):  # If on logger page(1) , pause button should be unchecked
                    v = a[0].readValues()
                    if v is not None:
                        a[0].setValue(v)

        # Check if oscilloscope is paused. If so, continue.
        if self.Freeze.isChecked(): return
        A1Map = str(self.A1Map.currentText())
        if (A1Map in self.sources):
            try:
                if self.chanStatus[2] == 1 or self.chanStatus[3] == 1:  # channel 3 or 4 selected
                    self.timeData[0], self.voltData[0], \
                        self.timeData[1], self.voltData[1], \
                        self.timeData[2], self.voltData[2], \
                        self.timeData[3], self.voltData[3] = self.p.capture4(self.NP, self.TG,
                                                                             A1Map,
                                                                             trigger=self.trigEnable)
                elif self.chanStatus[1] == 1:  # channel 2 is selected
                    self.timeData[0], self.voltData[0], \
                        self.timeData[1], self.voltData[1] = self.p.capture2(self.NP, self.TG,
                                                                             A1Map,
                                                                             trigger=self.trigEnable)
                elif self.chanStatus[0] == 1:  # only A1 selected
                    self.timeData[0], self.voltData[0] = self.p.capture1(A1Map, self.NP, self.TG,
                                                                         trigger=self.trigEnable)
            except:
                self.comerr()
                self.p.connected = False
                return

        # elif self.chanStatus[0] == 1:
        #    self.timeData[0], self.voltData[0] = self.p.capture_i2c(0x68, 0x3B+10, 2, 4000, 40) #  address, register, chunksize, totalchunks, tg MPU

        for ch in range(4):
            if self.chanStatus[ch] == 1:
                r = 16. / self.rangeVals[ch]
                self.traceWidget[ch].setData(self.timeData[ch], self.voltData[ch] * r + 4 * self.offValues[ch])
                if np.max(self.voltData[ch]) > self.rangeVals[ch]:
                    self.msg(self.tr('%s input is clipped. Increase range') % self.sources[ch])

                if self.fitSelCB[ch].currentText() == 'sine':
                    try:
                        fa = em.fit_sine(self.timeData[ch], self.voltData[ch])
                    except Exception as err:
                        print('fit_sine error:', err)
                        fa = None
                    if fa != None:
                        self.voltDataFit[ch] = fa[0]
                        self.Amplitude[ch] = abs(fa[1][0])
                        self.Frequency[ch] = fa[1][1] * 1000
                        self.Phase[ch] = fa[1][2] * 180 / em.pi
                        s = self.tr('%5.2f V, %5.1f Hz') % (self.Amplitude[ch], self.Frequency[ch])
                        self.fitSelLabels[ch].setText(s)
                elif self.fitSelCB[ch].currentText() == 'p2p':
                    s = self.tr('%5.2f V') % (max(self.voltData[ch]) - min(self.voltData[ch]))
                    self.fitSelLabels[ch].setText(s)
                elif self.fitSelCB[ch].currentText() == 'avg':
                    s = self.tr('%5.2f V') % (np.average(self.voltData[ch]))
                    self.fitSelLabels[ch].setText(s)
                elif self.fitSelCB[ch].currentText() == 'rms':
                    s = self.tr('%5.2f V') % (np.sqrt(np.average(self.voltData[ch]**2)))
                    self.fitSelLabels[ch].setText(s)
                elif self.fitSelCB[ch].currentText() == 'max':
                    s = self.tr('%5.2f V') % (max(self.voltData[ch]))
                    self.fitSelLabels[ch].setText(s)
                elif self.fitSelCB[ch].currentText() == 'min':
                    s = self.tr('%5.2f V') % (min(self.voltData[ch]))
                    self.fitSelLabels[ch].setText(s)
                else:
                    self.fitSelLabels[ch].setText('')

        if self.Diff.isChecked() == True and self.chanStatus[0] == 1 and self.chanStatus[1] == 1:
            r = 16. / self.rangeVals[0]
            self.diffTraceW.setData(self.timeData[0], r * (self.voltData[0] - self.voltData[1]))
        else:
            self.diffTraceW.setData([0, 0], [0, 0])

        if self.Cross.isChecked():
            self.showVoltagesAtCursor(self.plot_widget.vLine.x())
        else:
            for k in range(self.MAXRES):
                try:
                    self.plot_widget.removeItem(self.resLabs[k])
                except:
                    pass

        ###PCS Monitoring in version 5+
        if self.p.version_number >= 5.0:  # Current source monitoring
            self.pcsVal.display(int(self.p.get_voltage('AN8') * 1e3))

        self.loopCounter += 1
        if self.loopCounter % 5 == 0:
            for ch in ['A1','A2','A3']:
                if self.voltMeterCB[ch].isChecked() == True:
                    try:
                        v = self.p.get_voltage(ch)  # Voltmeter functions
                    except:
                        self.comerr()
                    self.voltMeterCB[ch].update_value(v)
                else:
                    self.voltMeterCB[ch].update_value(0)

            try:
                res = self.p.get_resistance()
                if res != np.inf and res > 100 and res < 100000:
                    self.RES.setText('Resistance: <font color="blue">' + self.tr('%5.0f Ohm') % (res))
                else:
                    self.RES.setText(self.tr('Resistance: <100Ohm  or  >100k'))
                self.p.select_range('A1', self.rangeVals[0])
                self.p.select_range('A2', self.rangeVals[1])
            except:
                self.comerr()

    # End of update

    def show_diff(self):
        if self.Diff.isChecked() == False:
            self.diffTraceW.setData([0, 0], [0, 0])

    def showRange(self, ch):
        spacing = self.tbvals[self.TBval]
        self.plot_widget.removeItem(self.scaleLabs[ch])
        if self.chanStatus[ch] == 0:
            return
        self.scaleLabs[ch] = pg.TextItem(text=self.rangeTexts[ch], color=self.resultCols[ch], angle=315)
        self.scaleLabs[ch].setPos(ch * spacing / 3, 15.5)
        # self.scaleLabs[ch].setText('hello')
        self.plot_widget.addItem(self.scaleLabs[ch])

    def select_channel(self, ch):
        if self.chanSelCB[ch].isChecked() == True:
            self.chanStatus[ch] = 1
            self.traceWidget[ch] = self.plot_widget.plot([0, 0], [0, 0], pen=self.traceCols[ch])
        else:
            self.chanStatus[ch] = 0
            self.plot_widget.removeItem(self.traceWidget[ch])
        self.showRange(ch)

    def select_range(self, ch, index):
        if ch <= 1:
            self.rangeTexts[ch] = self.Ranges12[index]
            self.rangeVals[ch] = self.RangeVals12[index]
            try:
                self.p.select_range(self.sources[ch], self.RangeVals12[index])
            except:
                self.comerr()
                return
        else:
            self.rangeTexts[ch] = self.Ranges34[index]
            self.rangeVals[ch] = self.RangeVals34[index]
        self.showRange(ch)
        ss1 = '%s' % self.sources[ch]
        ss2 = '%s' % self.rangeTexts[ch]
        self.msg(self.tr('Range of') + ss1 + self.tr(' set to ') + ss2)
        self.updateTriggerArrow()

    def show_fft(self):
        for ch in range(4):
            if self.chanStatus[ch] == 1:
                try:
                    fa = em.fit_sine(self.timeData[ch], self.voltData[ch])
                except Exception as err:
                    print('fit_sine error:', err)
                    fa = None
                if fa != None:
                    fr = fa[1][1] * 1000  # frequency in Hz
                    dt = int(1.e6 / (20 * fr))  # dt in usecs, 20 samples per cycle
                    try:
                        t, v = self.p.capture1(self.sources[ch], 3000, dt)
                    except:
                        self.comerr()

                    xa, ya = em.fft(v, dt)
                    xa *= 1000
                    peak = self.peak_index(xa, ya)
                    ypos = np.max(ya)
                    pop = pg.plot(xa, ya, pen=self.traceCols[ch])
                    pop.showGrid(x=True, y=True)
                    txt = pg.TextItem(text=self.tr('Fundamental frequency = %5.1f Hz') % peak, color='w')
                    txt.setPos(peak, ypos)
                    pop.addItem(txt)
                    pop.setWindowTitle(self.tr('Frequency Spectrum'))
                else:
                    self.msg(self.tr('FFT Error'))

    def peak_index(self, xa, ya):
        peak = 0
        peak_index = 0
        for k in range(2, len(ya)):
            if ya[k] > peak:
                peak = ya[k]
                peak_index = xa[k]
        return peak_index

    def save_data(self):
        self.timer.stop()
        fn = QFileDialog.getSaveFileName()
        if fn != '':
            dat = []
            for ch in range(4):
                if self.chanStatus[ch] == 1:
                    dat.append([self.timeData[ch], self.voltData[ch]])
            self.p.save(dat, fn)
            ss = fn
            self.msg(self.tr('Traces saved to ') + ss)
        self.timer.start(self.TIMER)

    def select_trig_source(self, index):
        src = self.trigSources[self.Trigindex]
        self.Trigindex = index
        self.trigEnable = True
        if index > 3:
            self.Trigindex = 0
            self.trigEnable = False
        try:
            self.p.configure_trigger(self.Trigindex, self.sources[self.Trigindex], self.Triglevel)
        except:
            self.comerr()
        self.updateTriggerArrow()

    def set_trigger(self, tr):
        # Update the position of the trigger arrow
        self.updateTriggerArrow()

        self.Triglevel = tr * 0.001  # convert to volts
        try:
            if self.TBval > 3:
                self.p.configure_trigger(self.Trigindex, self.sources[self.Trigindex], self.Triglevel, resolution=10,
                                         prescaler=5)
            else:
                self.p.configure_trigger(self.Trigindex, self.sources[self.Trigindex], self.Triglevel)
        except:
            self.comerr()

    def updateTriggerArrow(self):
        r = 16. / self.rangeVals[self.Trigindex]

        self.trigger_arrow.setPos(0., self.Triglevel*r + 4*self.offValues[self.Trigindex])  # Update arrow position to the current trigger level
        self.trigger_arrow.setVisible(self.trigEnable)  # Show or hide based on trigger enable state


    def set_timebase(self, tb):
        self.TBval = tb
        self.plot_widget.setXRange(0, self.tbvals[self.TBval] * 10)
        msperdiv = self.tbvals[int(tb)]  # millisecs / division
        totalusec = msperdiv * 1000 * 10.0  # total 10 divisions
        self.TG = int(totalusec / self.NP)
        if self.TG < self.MINDEL:
            self.TG = self.MINDEL
        elif self.TG > self.MAXDEL:
            self.TG = self.MAXDEL
        for k in range(self.MAXCHAN):
            self.showRange(k)

    def pv1_text(self):
        try:
            val = float(self.PV1text.value())
        except Exception as e:
            return
        if self.PV1min <= val <= self.PV1max:
            self.PV1val = val
            try:
                self.p.set_pv1(val)
                self.PV1slider.setValue(int(val * 1000))
            except:
                self.comerr()

    def pv1_slider(self, pos):
        val = float(pos) / 1000.0
        if self.PV1min <= val <= self.PV1max:
            self.PV1val = val
            self.PV1text.setValue(val)
            try:
                self.p.set_pv1(val)
            except:
                self.comerr()

    def pv2_text(self):
        try:
            val = self.PV2text.value()
        except:
            return
        if self.PV2min <= val <= self.PV2max:
            self.PV2val = val
            try:
                self.p.set_pv2(val)
                self.PV2slider.setValue(int(val * 1000))
                self.pcsVal_I.display((val + 3.3) / 6.6)
            except:
                self.comerr()

    def pv2_slider(self, pos):
        val = float(pos) / 1000.0
        if self.PV2min <= val <= self.PV2max:
            self.PV2val = val
            self.PV2text.setValue(val)
            self.pcsVal_I.setText('%.2f mA' % (3.3 - 3.3 * ((val + 3.3) / 6.6)))
            try:
                self.p.set_pv2(val)
            except:
                self.comerr()

    def pcs_slider(self, val):
        self.PV2slider.setValue(int(val))

    def sq1_dc(self):
        try:
            val = self.SQ1DCtext.value()
        except:
            return
        if 1 <= val <= 99:
            self.dutyCycle = val
            self.sq1_text()

    def sq1_text(self):
        try:
            val = float(self.SQ1text.value())
        except Exception as e:
            print(e)
            return
        if self.SQ1min <= val <= self.SQ1max:
            self.SQ1val = val
            self.SQ1slider.setValue(int(self.SQ1val))
            try:
                if 0 <= val < .1: val = 0
                self.SQ1text.setValue(val)
                res = self.p.set_sqr1(val, self.dutyCycle)
                # res = self.p.set_sqrs(val, self.dutyCycle)

                ss = '%5.1f' % res
                self.msg(self.tr('sqr1 set to ') + ss)
            except:
                self.comerr()
        else:
            self.SQ1text.setValue(self.SQ1min)

    def sq1_slider(self, val):
        if self.SQ1min <= val <= self.SQ1max:
            self.SQ1val = val
            self.SQ1text.setValue(val)
            self.sq1_text()

    def select_wgain(self, index):
        self.wgainindex = index
        try:
            self.p.set_sine_amp(index)
        except:
            self.comerr()

    def set_wave(self):
        if not self.p: return
        try:
            if self.waveindex <= 1:
                res = self.p.set_wave(self.AWGval, self.Waves[self.waveindex])
                ss = '%6.2f' % res
                self.msg(self.tr('AWG set to ') + ss + self.tr(' Hz'))
            else:
                self.p.set_sqr2(self.AWGval)
                self.msg(self.tr('Output Changed from WG to SQ2'))
        except Exception as e:
            print('what', e)
            self.comerr()

    def select_wave(self, index):
        self.waveindex = index
        self.set_wave()

    def awg_text(self):
        text = self.AWGtext.value()
        try:
            val = float(text)
            if self.AWGmin <= val <= self.AWGmax:
                self.AWGval = val
                self.AWGslider.setValue(int(self.AWGval))
                self.set_wave()
        except:
            return

    def awg_slider(self, val):
        if self.AWGmin <= val <= self.AWGmax:
            self.AWGval = val
            self.AWGtext.setValue(val)
            self.set_wave()

    def CS_changed(self):
        pos = 0
        if (self.CS1.isChecked()): pos |= 1
        if (self.CS2.isChecked()): pos |= 2
        if (self.CS3.isChecked()): pos |= 4
        if (self.CS4.isChecked()): pos |= 8
        self.p.set_multiplexer(pos)

    def control_od1(self):
        try:
            state = self.OD1.isChecked()
            if state == True:
                self.p.set_state(OD1=1)
            else:
                self.p.set_state(OD1=0)
        except:
            self.comerr()

    def control_ccs(self):
        try:
            state = self.CCS.isChecked()
            if state == True:
                self.p.set_state(CCS=1)
            else:
                self.p.set_state(CCS=0)
        except:
            self.comerr()

    def measure_cap(self):
        try:
            cap = self.p.get_capacitance()
            if cap == None:
                self.msg(self.tr('Capacitance too high or short to ground'))
            else:
                if cap < 1.0e-12:
                    self.CAP.setText('MEASURE CAP(IN1) ' + self.tr(' : < 1pF'))
                elif cap < 1.0e-9:
                    ss = '%6.1f' % (cap * 1e12)
                    self.CAP.setText('MEASURE CAP(IN1) ' + ss + self.tr(' pF'))
                elif cap < 1.0e-6:
                    ss = '%6.1f' % (cap * 1e9)
                    self.CAP.setText('MEASURE CAP(IN1) ' + ss + self.tr(' nF'))
                elif cap < 1.0e-3:
                    ss = '%6.1f' % (cap * 1e6)
                    self.CAP.setText('MEASURE CAP(IN1) ' + ss + self.tr(' uF'))
        except:
            self.comerr()

    def measure_freq(self):
        try:
            fr = self.p.get_freq()
            hi = self.p.r2ftime('IN2', 'IN2')
        except:
            self.comerr()
        if fr > 0:
            T = 1. / fr
            dc = hi * 100 / T
            self.FREQ.setText(u'MEASURE FREQUENCY(IN2) ' + self.tr('%5.1fHz %4.1f%%') % (fr, dc))
        else:
            self.FREQ.setText(u'MEASURE FREQUENCY(IN2) ' + self.tr('No signal'))

    def show_voltmeter(self):
        if self.voltmeter is not None:
            self.voltmeter.launch('Voltmeter')

    def msg(self, m):
        self.msgwin.setText(self.tr(m))

    def comerr(self):
        self.msgwin.setText('<font color="red">' + self.tr('Error. Try Device->Reconnect'))


if __name__ == '__main__':
    import eyes17.eyes

    dev = eyes17.eyes.open()
    app = QApplication(sys.argv)

    # translation stuff
    lang = QLocale.system().name()
    t = QTranslator()
    t.load("lang/" + lang, os.path.dirname(__file__))
    app.installTranslator(t)
    t1 = QTranslator()
    t1.load("qt_" + lang,
            QLibraryInfo.location(QLibraryInfo.TranslationsPath))
    app.installTranslator(t1)

    mw = Expt(dev)
    mw.show()
    sys.exit(app.exec_())
