'''
expEYES Junior CRO+ program
Author  : Ajith Kumar B.P, bpajith@gmail.com
License : GNU GPL version 3
Date : Apr-2012
'''
from __future__ import print_function

import gettext
gettext.bindtextdomain("expeyes")
gettext.textdomain('expeyes')
_ = gettext.gettext

import sys
sys.path=[".."] + sys.path
if sys.version_info.major==3:
    from tkinter import *
else:
    from Tkinter import *

import expeyes.eyesj as eyes
import expeyes.eyeplot as eyeplot
import expeyes.eyemath as eyemath
import time, os

bgcol = 'ivory'

BUFSIZE = 1800		# uC buffer size in bytes
TIMER = 100
WIDTH  = 500   		# width of drawing canvas  (make 550)
HEIGHT = 400   		# height 
VPERDIV = 1.0		# Volts per division, vertical scale
NP = 400			# Number of samples
NC = 1				# Number of channels
MINDEL = 4		
delay = MINDEL		# Time interval between samples
CMERR = False

MAXCHAN = 4
chan4 = [ [1, [], [],0,[],0,0,0,None,None,0.0 ],\
          [0, [], [],0,[],0,0,0,None,None,0.0 ],\
          [0, [], [],0,[],0,0,0,None,None,0.0 ],\
          [0, [], [],0,[],0,0,0,None,None,0.0 ]\
]
# Source, t, v, fitflag, vfit, amp, freq, phase, widget1, widget2, display offset in volts
CHSRC   = 0		# index of each item in the list above.
TDATA   = 1
VDATA   = 2
FITFLAG = 3
VFDAT   = 4
AMP     = 5
FREQ    = 6
PHASE   = 7
WINFO   = 8
WFIT    = 9
DOFFSET = 10

# Data Sources and their names
sources = ['A1','A2','IN1', 'IN2', 'SEN', 'SQ1', 'SQ2', 'OD1', 'CCS']
channels = ['CH1', 'CH2', 'CH3', 'CH4']
chancols = ['black', 'red', 'blue','magenta']
# Actions before capturing waveforms
actions = ['ATR', 'WHI', 'WLO', 'WRE', 'WFE','SHI', 'SLO', 'HTP', 'LTP']
acthelp = [_('Analog Trigger'),_('Wait for HIGH'), _('Wait for LOW'),
	   _('Wait for Rising Edge'), _('Wait for Falling Edge'),
	   _('Set HIGH'), _('Set LOW'), _('High True Pulse'),
	   _('Low True Pulse')
]

srchelp = [
  _('Analog Input -5 to +5 volts. Drag this to CH1 .. CH4 to Display it'),
  _('Analog Input -5 to +5 volts. Drag this to CH1 .. CH4 to Display it'),
  _('Analog Input  0 to +5 volts. Drag this to CH1 .. CH4 to Display it'),
  _('Analog Input  0 to +5 volts. Drag this to CH1 .. CH4 to Display it'),
  _('Analog Input  0 to +5 volts. Drag this to CH1 .. CH4 to Display it'),
  _('Analog Input  0 to +5 volts. Drag this to CH1 .. CH4 to Display it'),
  _('Analog Input  0 to +5 volts. Drag this to CH1 .. CH4 to Display it'),
  _('Digital Output 0 to +5 volts. SHI, SLO,HTP or LTP can be assigned to this'),
  _('Constant Current Source Output. SHI, SLO,HTP or LTP can be assigned to this')
]

# Geometry of the left panel, selection of triggers  & channels
LPWIDTH  = 80
LPHEIGHT = 320
VSTEP    = 25
VBORD    = 10
OFFSET   = VSTEP * len(sources)
SELSRC   = 1
SETACT   = 2
WAITACT  = 3
SELCHAN  = 4
NORMAL   = 100	      # Status of Display channel
FIT      = 101	      # Fit to Sinusoid
DEL      = 102	      # Remove entry
FTR      = 103	      # Fourier transform
selection = 0
seltag    = ''	      # selected tag

def set_ch1_offset(val):
    chan4[0][DOFFSET] = int(val) * VPERDIV

def set_ch2_offset(val):
    chan4[1][DOFFSET] = int(val) * VPERDIV

def set_ch3_offset(val):
    chan4[2][DOFFSET] = int(val) * VPERDIV

def set_ch4_offset(val):
    chan4[3][DOFFSET] = int(val) * VPERDIV

def show_ftr(ch):
    fa = eyemath.fit_sine(chan4[ch][TDATA],chan4[ch][VDATA])	# get frequency to decide suitable 'dt'
    if fa != None:
        fr = fa[1][1]*1000        # frequency in Hz
        dt = int(1.e6/ (20 * fr)) # dt in usecs, 20 samples per cycle
        t,v = p.capture(chan4[ch][CHSRC], 1800, dt)
        xa,ya = eyemath.fft(v,dt)
        eyeplot.plot(xa*1000,ya,
                     title = _('Fourier Transform,power spectrum'),
                     xl = _('Freq'), yl = _('Amp'))
        eyeplot.plot(t,v,
                     title = _('Original signal resampled'),
                     xl = _('ms'), yl = _('V'))
        msg(_('%s Fourier transform done, Data saved to "cro.dat" and "fft.dat"')
            % (channels[seltag]))
        p.save([[t,v]], 'cro.dat')
        p.save([[xa,ya]],'fft.dat')

def msg(s, col='blue'):
    msgwin.config(text=s, fg=col)

def set_timebase(w):
    global delay, NP, NC, VPERDIV, chan4
    divs = [0.100, 0.200, 0.500, 1.0, 2.0, 5.0, 10.0, 20.0, 50.0,100.0]
    msperdiv = divs[int(timebase.get())]
    totalusec = int(msperdiv * 1000 * 10)
    chans = []             # Update channel & color information
    for m in range(len(chan4)):
        if chan4[m][0] > 0:
            chans.append(chan4[m][0])  # channel number
    NC = len(chans)
    if NC < 1:
        return
    if totalusec == 1000:
        NP = 250
        delay = 4*NC
    else:
        NP = 400
        delay = (totalusec/NP)*NC

    if delay < MINDEL*NC:
        delay = MINDEL*NC
    elif delay > 1000:
        delay = 1000

    totalmsec = round(0.001 * NP * NC *delay)
    tms = int(totalmsec)
    NP = tms * 1000/NC/delay
    if NP%2 == 1 : NP += 1  # Must be an even number, for fitting
    if NP > 450: NP = 450
    g.setWorld(0,-5*VPERDIV, NP * delay * 0.001, 5*VPERDIV,_('mS'),'V')
    #print (_('NP delay = '),NP, delay, 0.0001 * NP*delay, msperdiv)

def measure_freq(e):
    w = e.widget
    tag =w.find_closest(e.x, e.y)
    item = w.itemcget(tag,'tag')
    target = int(item.split()[0])
    if e.x < LPWIDTH/2 and e.y < OFFSET and 2 < target < 8:
        # Selected IN1, IN2, SEN, SQR1 or SQR2
        freq = p.get_frequency(target)
        if freq > 0.5:
            r2f = p.r2ftime(target, target)*1.0e-6
            msg(_('%4s : Freq = %5.3f. Duty Cycle = %5.1f %%')
                % (sources[target-1], freq, r2f*freq*100))
            s=_('%4s\n%5.3f Hz\n%5.1f %%')%(sources[target-1], freq, r2f*freq*100)
            g.disp(s)
        else:
            msg(_('No squarewave detected on %4s')
                % (sources[target-1]))
    elif e.x > LPWIDTH/2 and e.y > OFFSET and target < 3:
        # Selected CH1, CH2 or CH3
        if chan4[target][CHSRC] != 0 and chan4[target+1][CHSRC] != 0:  # both channels active
            fa = eyemath.fit_sine(chan4[target][TDATA],
                                  chan4[target][VDATA])
            fb = eyemath.fit_sine(chan4[target+1][TDATA],
                                  chan4[target+1][VDATA])
            if fa != None and fb != None:
                v1 = fa[1][0]
                v2 = fb[1][0]
                f1 = fa[1][1]*1000
                # millisecond x-axis gives frequency in kHz, convert it
                f2 = fb[1][1]*1000
                p1 = fa[1][2]
                p2 = fb[1][2]
                s = _('%s: %5.3f V, %5.2f Hz | %s: %5.2f V, %5.3f Hz | Phase difference = %5.1f degree') \
                    % (channels[target], v1, f1, channels[target+1],v2, f2, (p2-p1)*180/3.1416)
                msg(s)
                s=_('%4s\n%5.3f Hz\n%5.1f %%') \
                   % (sources[target-1], freq, r2f*freq*100)
                g.disp(s)
            else:
                msg(_('Fitting of data failed. Try with Xmgrace'))
        else:
            msg(_('Selected channel and the next one should have data'), 'red')

def release(e):
    global selection, seltag, chan4, NC
    w = e.widget
    w.configure(cursor = 'arrow')
    if selection == 0:
        msg(_('Invalid Action'), 'red')
        return
    tag =w.find_closest(e.x, e.y)
    item = w.itemcget(tag,'tag')
    target = int(item.split()[0])
    if e.x > LPWIDTH/2 and e.y > OFFSET and selection == SELSRC:
        # Assign source to channel
        msg(_('Assigned Data Input %4s to Channel %s') %(sources[seltag-1],channels[target]))
        s = '%s:' %(sources[seltag-1])
        chan4[target][WINFO].config(text = s, fg=chancols[target])
        chan4[target][0] = seltag
        set_timebase(0)	# Adding  a channel require recalculation
    elif e.x < LPWIDTH/2 and e.y < OFFSET and selection == SETACT and target > 6:   
        msg(_('%4s effective on Output %s') 
            %(acthelp[seltag], sources[target-1]))
        p.enable_action(seltag, target+2) # There is an offset of 2 for OD1 & CCS
        #print ('SET ', seltag,target+2)
    elif e.x < LPWIDTH/2 and e.y < OFFSET and selection == WAITACT and target <= 7:   
        msg(_('%4s effective on Input %s') 
            %(acthelp[seltag], sources[target-1]))
        p.enable_action(seltag, target)
    elif e.x < LPWIDTH/2 and e.y > OFFSET and selection == SELCHAN:
        # Selected channel    
        if target == DEL:
            chan4[seltag][CHSRC] = 0 
            chan4[seltag][FITFLAG] = 0 
            chan4[seltag][WINFO].config(text = '')
            chan4[seltag][WFIT].config(text = '')
            msg('Disabled Display channel %s'%(channels[seltag]))
            set_timebase(0)				# Deleting a channel require recalculation
        elif target == FIT:
            if chan4[seltag][CHSRC] != 0:
                chan4[seltag][FITFLAG] = True
                msg('Selected %s for fitting'%(channels[seltag]))
            else:
                msg(_('Channel %s is Empty')
                    %(channels[seltag]), 'red')
        elif target == FTR:
            if chan4[seltag][CHSRC] != 0:
                show_ftr(seltag)	# Channel for FT
            else:
                msg(_('Channel %s is Empty') %(channels[seltag]), 'red')
        elif target == NORMAL:
            if chan4[seltag][CHSRC] != 0:
                chan4[seltag][FITFLAG] = False
                chan4[seltag][WFIT].config(text = '')
                msg(_('Disabled fitting %s') %(channels[seltag]))
            else:
                msg(_('Channel %s is Empty')
                    %(channels[seltag]), 'red')
    elif e.x < LPWIDTH/2 and e.y < OFFSET and selection == SELSRC:
        # Selected Source
        src = sources[target-1]
        val = p.get_voltage(target)
        ss = _('Voltage at %s = %5.3f V') %(src,val)
        sm = _('%3s: %5.3f V')%(src, val)
        if 2 < target < 8:
            level = p.get_state(target)
            ss += _(' (Logic Level = %d)') %level
            msg(ss)
            g.disp(sm)
        else:
            msg(_('Invalid selection'), 'red')		

def press(e):
    global selection, seltag
    selection = 0
    w = e.widget
    tag =w.find_closest(e.x, e.y)
    item = w.itemcget(tag,'tag')
    if item == '' or item[0] == 'c': return		# clicked on borders
    seltag = int(item.split()[0])
    if e.x < LPWIDTH/2 and e.y < OFFSET:		# Source selection
        if seltag > 7: 
            msg(_('%4s is an Output') %sources[seltag-1], 'red')
            return
        selection = SELSRC
        msg(_('Selected Data Input %4s. For Trace, Drag this to CH1 .. CH4. To print value release the button.')\
            %sources[seltag-1])
        w.configure(cursor = 'pencil')
    elif e.x > LPWIDTH/2 and e.y < OFFSET:		# Trigger selection
        if seltag >= 5:
            selection = SETACT
            msg(_('Selected %4s. Drag cursor to the OD1 or CSS Output') %acthelp[seltag])
            w.configure(cursor = 'hand1')
        else:
            selection = WAITACT
            msg(_('Selected %4s. Drag cursor to desired Data Input') %acthelp[seltag],)
            w.configure(cursor = 'hand2')
    elif e.x > LPWIDTH/2 and e.y > OFFSET:		# Channel selection
        selection = SELCHAN
        msg(_('Selected %4s. Drag cursor to NML FIT or DEL') %channels[seltag],)
        w.configure(cursor = 'pencil')

def update():
    global delay, NP, NC, VPERDIV, chan4, CMERR
    global NP, NC, delay,chan4
    chans = []                    # Update channel & color information
    index = []
    for m in range(len(chan4)):
        if chan4[m][0] > 0:
            chans.append(chan4[m][0])  # channel number
            index.append(m) # Store the used indices, for storing & fitting
    NC = len( chans)
    
    # force int types as NP and delay can come from float divisions
    # with Python3
    NP=int(NP)
    delay=int(delay)
    
    try:
        if NC == 1:
            chan4[index[0]][TDATA], \
                chan4[index[0]][VDATA] \
                =  p.capture_hr(chans[0], NP, delay)
            v1 = []
            for k in range(NP): v1.append(
                    chan4[index[0]][VDATA][k] +
                    chan4[index[0]][DOFFSET])
            g.delete_lines()
            g.line(chan4[index[0]][TDATA],v1, index[0])
        elif NC == 2:
            chan4[index[0]][TDATA],chan4[index[0]][VDATA], \
                chan4[index[1]][TDATA],chan4[index[1]][VDATA] = p.capture2_hr( chans[0],  chans[1], NP, delay)
            v1 = []
            v2 = []
            for k in range(NP): 
                v1.append(
                    chan4[index[0]][VDATA][k] +
                    chan4[index[0]][DOFFSET])
                v2.append(
                    chan4[index[1]][VDATA][k] +
                    chan4[index[1]][DOFFSET])
            g.delete_lines()
            g.line(chan4[index[0]][TDATA], v1, index[0])
            g.line(chan4[index[1]][TDATA], v2, index[1])
        elif NC == 3:
            chan4[index[0]][TDATA],chan4[index[0]][VDATA], chan4[index[1]][TDATA],chan4[index[1]][VDATA], \
                chan4[index[2]][TDATA],chan4[index[2]][VDATA] = p.capture3( chans[0], chans[1], chans[2], NP, delay)
            v1 = []
            v2 = []
            v3 = []
            for k in range(NP): 
                v1.append(
                    chan4[index[0]][VDATA][k] +
                    chan4[index[0]][DOFFSET])
                v2.append(
                    chan4[index[1]][VDATA][k] +
                    chan4[index[1]][DOFFSET])
                v3.append(
                    chan4[index[2]][VDATA][k] +
                    chan4[index[2]][DOFFSET])
            g.delete_lines()
            g.line(chan4[index[0]][TDATA], v1, index[0])
            g.line(chan4[index[1]][TDATA], v2, index[1])
            g.line(chan4[index[2]][TDATA], v3, index[2])
        elif NC == 4:
            chan4[index[0]][TDATA],chan4[index[0]][VDATA], chan4[index[1]][TDATA],chan4[index[1]][VDATA], \
                chan4[index[2]][TDATA],chan4[index[2]][VDATA], chan4[index[3]][TDATA],chan4[index[3]][VDATA] \
                = p.capture4( chans[0],  chans[1], chans[2], chans[3], NP, delay)
            v1 = []
            v2 = []
            v3 = []
            v4 = []
            for k in range(NP): 
                v1.append(
                    chan4[index[0]][VDATA][k] +
                    chan4[index[0]][DOFFSET])
                v2.append(
                    chan4[index[1]][VDATA][k] +
                    chan4[index[1]][DOFFSET])
                v3.append(
                    chan4[index[2]][VDATA][k] +
                    chan4[index[2]][DOFFSET])
                v4.append(
                    chan4[index[3]][VDATA][k] +
                    chan4[index[3]][DOFFSET])
            g.delete_lines()
            g.line(chan4[index[0]][TDATA], v1, index[0])
            g.line(chan4[index[1]][TDATA], v2, index[1])
            g.line(chan4[index[2]][TDATA], v3, index[2])
            g.line(chan4[index[3]][TDATA], v4, index[3])
        if CMERR == True: 
            CMERR = False
            msg('')
    except:
        msg(_('Communication Error. Check input voltage levels.'),
            'red')
        CMERR = True
	
    for k in range(4):
        if chan4[k][CHSRC] != 0 and chan4[k][FITFLAG] == 1:
            fa = eyemath.fit_sine(chan4[k][TDATA],chan4[k][VDATA])
            if fa != None:
                chan4[k][VFDAT] = fa[0]
                chan4[k][AMP] = abs(fa[1][0])
                chan4[k][FREQ] = fa[1][1]*1000
                chan4[k][PHASE] = fa[1][2] * 180/eyemath.pi
                s = _('%5.2f V, %5.1f Hz')\
                    %(chan4[k][AMP],chan4[k][FREQ])
                chan4[k][WFIT].config(text = s, fg= chancols[k])
    if looping.get() == '0':
        root.after(10,update)

def set_vertical(w):
    global delay, NP, NC, VPERDIV
    divs = [5.0, 1.0, 0.5, 0.2]
    VPERDIV = divs[int(Vpd.get())]
    g.setWorld(0,-5*VPERDIV, NP * delay * 0.001, 5*VPERDIV,_('mS'),'V')

def set_trigger(w):
    tv = Trig.get()
    if p != None: p.set_trigger(tv)

def cro_mode():
    state = looping.get()
    if state == '1':
        Loop.config(text=_('ONE '))
        msg(_('Press SCAN Button to do a single Capture'))
    else:
        Loop.config(text=_('LOOP'))
        root.after(10,update)

def scan():
    if looping.get() == '1':
        update()
        msg(_('Captured %d points in %d usecs') %(NP,NP*delay))
    else:
        msg(_('Use this only in Single scan mode'), 'red')

def set_pvs(e):
    try:
        v = float(Pvs.get())
        res = p.set_voltage(v)
        if res == None:
            msg(_('Enter a value between 0 to +5 volts'),'red')
        else:
            msg(_('PVS set to %5.3f volts') %res)
            g.disp(_('PVS: %5.3f V')%res)
    except:
        msg(_('Enter voltage between -5 and +5 volts'),'red')

def set_sqr1():
    state = int(Sqr1.get())
    if state == 0:
        p.set_sqr1(-1)
        msg(_('SQR1 set to LOW'))
    else:
        try:
            fr = float(Freq.get())
            res = p.set_sqr1(fr)
            if res == None:
                msg(_('Enter a value between .7 to 200000 Hz'))
            else:
                msg(_('SQR1 set to %5.1f Hertz') %res)
        except:
            msg(_('Enter valid frequency, in Hertz'),'red')

def set_sqr2():
    state = int(Sqr2.get())
    if state == 0:
        p.set_sqr2(-1)
        msg(_('SQR2 set to LOW'))
    else:
        try:
            fr = float(Freq.get())
            res = p.set_sqr2(fr)
            if res == None:
                msg(_('Enter a value between .7 to 200000 Hz'))
            else:
                msg(_('SQR2 set to %5.1f Hertz') %res)
        except:
            msg(_('Enter valid frequency, in Hertz'),'red')

def set_sqrs():
    state = int(Both.get())
    if state == 0:
        p.set_sqr1(-1)
        p.set_sqr2(-1)
        msg(_('SQR1 and SQR2 set to LOW'))
    else:
        try:
            fr = float(Freq.get())
            shift = float(Phase.get())
            res = p.set_sqrs(fr,shift)
            if res == None:
                msg(_('Enter a value between .7 to 200000 Hz'))
            else:
                msg(_('SQR1 and SQR2 set to %5.1f Hertz, Shift is %5.2f %% of Period') %(res,shift))
        except:
            msg(_('Enter valid frequency in Hertz and phase shift in percentage'),'red')
            
def sqr1_slider(w):
    if p == None: return
    freq = SQR1slider.get()
    if freq == 0: 
        p.set_sqr1(-1)
        msg(_('SQR1 set to LOW'))
    else:
        fs = p.set_sqr1(freq)
        msg(_('SQR1 set to %5.1f') %fs)

def control_od1():
    state = int(Od1.get())
    p.set_state(10, state)

def control_ccs():
    state = int(Ccs.get())
    p.set_state(11, state)

def measurecap():
    msg(_('Starting Capacitance Measurement..'))
    cap = p.measure_cap()
    if cap == None:
        msg(_('Error: Capacitance too high or short to ground'),'red')
        return
    g.disp(_('IN1: %6.1f pF')%cap)
    if p.socket_cap == 30.0 and p.cap_calib == 1.0:
        msg(_('IN1 Not Calibrated.'))
    else:
        msg(_('IN1: %6.1f pF')%cap)


def measureres():
    res = p.measure_res()
    if res == None:
        msg(p.msg,'red')
        return
    msg(_('Resistance from SEN to GND = %6.0f Ohm')%res)
    g.disp(_('%5.0f Ohm'%res))

def save_data():
    fn = Fname.get()
    dat = []
    for k in range(4):
        if chan4[k][CHSRC] != 0:
            dat.append( [chan4[k][TDATA],chan4[k][VDATA]])
    p.save(dat,fn)
    msg(_('Traces saved to %s') %fn)

def xmgrace():
    dat = []
    for k in range(4):
        if chan4[k][CHSRC] != 0:
            dat.append( [chan4[k][TDATA],chan4[k][VDATA]])
    if p.grace(dat) == False:
        msg(_('Could not find Xmgrace or Pygrace. Install them'),'red')
    else:
        msg(_('Traces send to Xmgrace'))

def process_command(e):
    cp = Result.index(INSERT)
    row = int(cp.split('.')[0])
    ss = Result.get("%d.0"%row, "%d.end"%row)	# User's entry
    cmd = 'p.'+ ss  # command
    p.msg = ''
    try:
        res = eval(cmd)
        if res == None: 
            res = p.msg
    except:
        res = 'Invalid command or argument'
        Result.insert("%d.0"%(row+1), '\n'+str(res)) # Result below

def pop_expt_menu(event):
    poped = True
    menu.post(event.x_root, event.y_root)

def reconnect():
    global p
    import expeyes.eyesj
    p=expeyes.eyesj.open()
    if p == None:
        msg(_('expEYES Junior NOT found. Bad connection or another program using it'),'red')
    else:
        Recon.forget()
        s = _('Four Channel CRO+ found expEYES-Junior on %s') %p.device
        root.title(s)
        msg(s)
        root.after(TIMER,update)

#=================== main program starts here ==================
root = Tk()    
top = Frame(root)
top.pack(side=TOP, anchor =W)
f1 = Frame(top, width = LPWIDTH, height = HEIGHT)
f1.pack(side=LEFT,  fill = BOTH, expand = 1)	# Left side frame

w = Canvas(f1, width=LPWIDTH, height=LPHEIGHT,bg = bgcol)   # Canvas for drag n drop controls
w.pack(side=TOP, anchor = W)
for k in range(len(sources)):
    if k >6: 
        col = 'blue'
    else:
        col = 'black'
    w.create_text (LPWIDTH/2-10, VBORD+k*VSTEP, anchor = E, text = sources[k], tag = k+1, fill=col)
for k in range(len(actions)):
    if  k >= 5:
        col = 'blue'
    else:
        col = 'black'
    w.create_text (LPWIDTH/2+10, VBORD+k*VSTEP, anchor = W, text = actions[k], tag = k, fill=col)
for k in range(4):
    w.create_text (LPWIDTH/2+10, VBORD + OFFSET + k*VSTEP, anchor = W, text = channels[k], tag = k,\
                   fill= chancols[k])
w.create_text (LPWIDTH/2-10, VBORD + OFFSET + 0*VSTEP, anchor = E, text = 'NML', tag = NORMAL)
w.create_text (LPWIDTH/2-10, VBORD + OFFSET + 1*VSTEP, anchor = E, text = 'FTR', tag = FTR)
w.create_text (LPWIDTH/2-10, VBORD + OFFSET + 2*VSTEP, anchor = E, text = 'FIT', tag = FIT)
w.create_text (LPWIDTH/2-10, VBORD + OFFSET + 3*VSTEP, anchor = E, text = 'DEL', tag = DEL)
w.create_line(LPWIDTH/2, 0, LPWIDTH/2, LPHEIGHT)
w.create_line(0, OFFSET, LPWIDTH, OFFSET)
w.bind ("<ButtonPress-1>", press)
w.bind ("<ButtonPress-3>", measure_freq)
w.bind ("<ButtonRelease-1>", release)
offsets = [_('Move UP'), _('CENTER'), _('Move DOWN')]	
offsetmenu = Menu(w, tearoff=0)
for k in range(len(offsets)):
    offsetmenu.add_command(label=offsets[k], background= 'ivory', command = lambda cmd=k :change_offset(cmd))

Label(f1,text = _('mSec/div')).pack(side=TOP, anchor = SW)		# Sliders for Adjusting Axes & Trigger Level
timebase = Scale(f1,command = set_timebase, orient=HORIZONTAL, length=LPWIDTH, showvalue=False,\
                 from_ = 0, to=9, resolution=1)
timebase.pack(side=TOP, anchor = SW)

Label(f1,text = _('Volt/div')).pack(side=TOP, anchor = SW)
Vpd = Scale(f1,command = set_vertical, orient=HORIZONTAL, length=LPWIDTH, showvalue=False,\
            from_ = 0, to=3, resolution=1)
Vpd.pack(side=TOP, anchor = SW)
Vpd.set(1)

Label(f1,text = _('Trig level')).pack(side=TOP, anchor = SW)
Trig = Scale(f1,command = set_trigger, orient=HORIZONTAL, length=LPWIDTH, showvalue=False,\
             from_ = 100, to=4000, resolution=10)
Trig.pack(side=TOP, anchor = SW)
Trig.set(2050)


#----------------------- Middle Frame ------------------------
a = Frame(top, width = LPWIDTH, height = HEIGHT)
a.pack(side=LEFT,  fill = BOTH, expand = 1)
f = Frame(a, width = 75, height = HEIGHT)
f.pack(side=TOP,  fill = BOTH, expand = 1)
g = eyeplot.graph(f, width=WIDTH, height=HEIGHT)	# make plot objects using draw.disp
g.setWorld(0, -5, 20, 5,_('mS'),'V')

#============== Vertical scales for OFFSET adjustment. Lambda not working with Scale callbacks !!! =====
of = Frame(top, width = 1, height = HEIGHT)
of.pack(side=LEFT,  fill = BOTH, expand = 1)

Scale(of, orient=VERTICAL, length=HEIGHT/4, showvalue = False, bg = chancols[0],\
      from_ = 4, to=-4, resolution=1, command = set_ch1_offset).pack(side=TOP)
Scale(of, orient=VERTICAL, length=HEIGHT/4, showvalue = False, bg = chancols[1],\
      from_ = 4, to=-4, resolution=1, command = set_ch2_offset).pack(side=TOP)
Scale(of, orient=VERTICAL, length=HEIGHT/4, showvalue = False, bg = chancols[2],\
      from_ = 4, to=-4, resolution=1, command = set_ch3_offset).pack(side=TOP)
Scale(of, orient=VERTICAL, length=HEIGHT/4, showvalue = False, bg = chancols[3],\
      from_ = 4, to=-4, resolution=1, command = set_ch4_offset).pack(side=TOP)

#================ Right Side panel ====================
rf = Frame(top, width = 75, height = HEIGHT)
rf.pack(side=LEFT,  fill = BOTH, expand = 1)

#---------------------- Extra Features -----------------------------
cf = Frame(rf, border = 1, relief = SUNKEN)
cf.pack(side=TOP,  fill = BOTH, expand = 1)

Label(cf, text = _('Setting Squarewaves'), fg='blue').pack(side=TOP)
f = Frame(cf)
f.pack(side=TOP, anchor = W)
Freq = Entry(f, width = 6)
Freq.pack(side=LEFT, anchor = N)
Freq.insert(0,'1000')
Label(f,text = _('Hz. dphi=')).pack(side=LEFT, anchor = N)
Phase = Entry(f, width=4)
Phase.pack(side=LEFT, anchor=N)
Phase.insert(0,'0')
Label(f,text = '%').pack(side=LEFT, anchor = N)

f = Frame(cf)			# Setting square waves
f.pack(side=TOP)
Sqr1 = IntVar()
Checkbutton(f,text = 'SQR1', command = set_sqr1, variable = Sqr1).pack(side=LEFT, anchor=N)
Sqr2 = IntVar()
Checkbutton(f,text = 'SQR2', command = set_sqr2, variable = Sqr2).pack(side=LEFT, anchor=N)
Both = IntVar()
Checkbutton(f,text = _('BOTH'), command = set_sqrs, variable = Both).pack(side=LEFT, anchor=N)

SQR1slider = Scale(cf,command = sqr1_slider, orient=HORIZONTAL, length=180, showvalue=False, from_ = 0, to=5000, resolution=5)
SQR1slider.pack(side=TOP, anchor=W)
Canvas(cf, height = 5,  width = 100).pack(side=TOP)	# Spacer

f = Frame(cf)			# Setting OD1 and CCS
f.pack(side=TOP)
Label(f, text = _('Set PVS =')).pack(side=LEFT)
Pvs = Entry(f, width = 6)
Pvs.pack(side=LEFT)
Pvs.bind("<Return>",set_pvs)
Pvs.bind("<KP_Enter>",set_pvs)
Pvs.insert(0,'0')
Label(f, text = 'V').pack(side=LEFT)

#Label(cf, text = 'Control OD1 & CCS', fg='blue').pack(side=TOP)
f = Frame(cf)			# Setting OD1 and CCS
f.pack(side=TOP)
Label(f, text = _('Set State')).pack(side=LEFT)
Od1 = IntVar()
Checkbutton(f,text = 'OD1', variable = Od1, command = control_od1).pack(side=LEFT, anchor=N)
Ccs = IntVar()
Checkbutton(f,text = 'CCS', variable = Ccs, command = control_ccs).pack(side=LEFT, anchor=N)
Canvas(cf, height = 5, width= 100).pack(side=TOP)	# Spacer

#ff = Frame(cf)			# Setting OD1 and CCS
#ff.pack(side=TOP)
#Button(ff,text =_('ZeroSet'), command=cap_setzero).pack(side=LEFT, anchor=N)

Button(cf,text =_('Measure C on IN1'), command=measurecap).pack(side=TOP, anchor=N)
Button(cf,text =_('Measure R on SEN'), command=measureres).pack(side=TOP, anchor=N)

Canvas(cf, height = 5, width= 100).pack(side=TOP)	# Spacer

#Label(cf, text = _('Type command<Enter>'), fg='blue').pack(side=TOP)
Result = Text(cf, width = 25, height = 5)
Result.pack(side=TOP)
Result.bind("<Return>", process_command)
Result.bind("<KP_Enter>", process_command)

#-----------------------------------------------------------------
looping = 1				# Make Status display Region
for ch in range(4):
	f = Frame(rf)
	f.pack(side=TOP, anchor = W)
	chan4[ch][8] = Label(f, width=4, text = '', fg=chancols[ch])	# 8 is Label, 9 is value
	chan4[ch][8].pack(side=LEFT, anchor = N)
	chan4[ch][9] = Label(f, width=16, text = '')
	chan4[ch][9].pack(side=LEFT, anchor = N)
chan4[0][WINFO].config(text = 'A1')

#---------------
f = Frame(rf)
f.pack(side=TOP, anchor = W)
Save = Button(f,text=_('Save Traces to'), command = save_data)
Save.pack(side=LEFT, anchor=N)
Fname = Entry(f, width=8)
Fname.pack(side=LEFT)
Fname.insert(0,'cro.txt')

f = Frame(rf)
f.pack(side = TOP, anchor=W)
looping = StringVar()
Loop = Checkbutton(f, text=_('LOOP'), variable = looping, command = cro_mode)
Loop.pack(side=LEFT)
looping.set('0')
Scan = Button(f, text=_('SCAN'), command = scan)
Scan.pack(side=LEFT)
Grace = Button(f, text=_('XMG'), command = xmgrace)
Grace.pack(side=LEFT)

f = Frame(rf)
f.pack(side=TOP, anchor = W)
Expt = Button(f,text = _('EXPERIMENTS'))
Expt.bind("<ButtonRelease-1>", pop_expt_menu)
Expt.pack(side=LEFT)
q = Button(f,text=_('QUIT'), command = sys.exit)
q.pack(side=LEFT, anchor=N)

mf = Frame(root, bg='white')
mf.pack(side=TOP,  fill = BOTH, expand = 1)
msgwin = Label(mf,text = '', justify=CENTER, bg = 'white', fg = 'blue', font=('Helvetica', 12))
msgwin.pack(side=LEFT, anchor = CENTER)
Recon = Button(mf,text = _('Search Hardware'), command =reconnect)

p = eyes.open()
if p == None:
    msg(_('Could not open expEYES Junior. Bad connection or another program using it'),'red')
    Recon.pack(side=LEFT)
else:
	p.disable_actions()
	root.title(_('CRO Plus found expEYES-Junior on %s (firmware: %s)') %(p.device,p.get_version()))
	root.after(TIMER,update)
#------------------------------ experiments menu ------------------------------
expts = [ 
[_('Select Experiment'),''],
[_('Control PVS'),'change-pvs'],
[_('Study of AC Circuits'),'ac-circuit'],
[_('RC Circuit'),'RCcircuit'],
[_('RL Circuit'),'RLcircuit'],
[_('RLC Discharge'),'RLCdischarge'],
[_('EM Induction'),'induction'],
[_('Diode IV'),'diode_iv'],
[_('Transistor CE'),'transistor'],
[_('AM and FM'), 'amfm'],
[_('Frequency Response'),'freq-response'],
[_('Velocity of Sound') , 'velocity-sound'],
[_('Interference of Sound') , 'interference-sound'],
[_('Capture Burst of Sound') , 'sound-burst'],
[_('Driven Pendulum'),'driven-pendulum'],
[_('Rod Pendulum') , 'rodpend'],
[_('Pendulum Wavefrorm'),'pendulum'],
[_('PT100 Sensor'), 'pt100'],
[_('Stroboscope'), 'stroboscope'],
[_('Data Logger'), 'logger'],
[_('HY-SRF05 Echo module'), 'gecho'],
[_('Calibrate'),'calibrate']
 ]

def run_expt(expt):
    global p
    if expt == '': return
    p.fd.close()	# Free the device from this program, the child will open it
    cmd = sys.executable + ' ' + eyeplot.abs_path() + expt+'.py'
    os.system(cmd)
    msg(_('Finished "')+expt+'.py"')
    p = eyes.open()	# Establish hardware communication again, for the parent
    p.disable_actions()

menu = Menu(Expt, tearoff=0)
for k in range(len(expts)):
    text = expts[k][0]
    cmd = expts[k][1]
    #print (text, cmd)
    menu.add_command(label=text, background= 'ivory', command = lambda expt=cmd :run_expt(expt))

root.mainloop()

# Local Variables:
# python-indent: 4
# End:
