예제 #1
0
    def set_analog_outs(self):

        a1 = PV('analog_out_1')
        a2 = PV('analog_out_2')
        d = []
        j = []
        #print a1.get(), a2.get()
        a2.connect()
        #poll(evt=1.0, iot=0.01)
        a1.connect()
        poll(evt=1.0, iot=0.01)
        print a2.info
        for i in range(10):
            if i % 2 == 1:
                util.put_check(a2, 0.45)
                #util.put_check(a1, float(i))
            else:
                util.put_check(a2, 0.5)
                #util.put_check(a1, float(i))
            #j.append(a1.get())
            d.append(a2.get())
        print a1.status
        #util.put_check(a2, value2)
        print d
        print j
        return d
예제 #2
0
    def test_subarrays(self):
        write("Subarray test:  dynamic length arrays\n")
        driver = PV(pvnames.subarr_driver)
        subarr1 = PV(pvnames.subarr1)
        subarr1.connect()

        len_full = 64
        len_sub1 = 16
        full_data = numpy.arange(len_full) / 1.0

        caput("%s.NELM" % pvnames.subarr1, len_sub1)
        caput("%s.INDX" % pvnames.subarr1, 0)

        driver.put(full_data)
        time.sleep(0.1)
        subval = subarr1.get()

        self.assertEqual(len(subval), len_sub1)
        self.failUnless(numpy.all(subval == full_data[:len_sub1]))
        write("Subarray test:  C\n")
        caput("%s.NELM" % pvnames.subarr2, 19)
        caput("%s.INDX" % pvnames.subarr2, 3)

        subarr2 = PV(pvnames.subarr2)
        subarr2.get()

        driver.put(full_data)
        time.sleep(0.1)
        subval = subarr2.get()

        self.assertEqual(len(subval), 19)
        self.failUnless(numpy.all(subval == full_data[3:3 + 19]))

        caput("%s.NELM" % pvnames.subarr2, 5)
        caput("%s.INDX" % pvnames.subarr2, 13)

        driver.put(full_data)
        time.sleep(0.1)
        subval = subarr2.get()

        self.assertEqual(len(subval), 5)
        self.failUnless(numpy.all(subval == full_data[13:5 + 13]))
예제 #3
0
    def test_subarrays(self):
        write("Subarray test:  dynamic length arrays\n")
        driver = PV(pvnames.subarr_driver)
        subarr1 = PV(pvnames.subarr1)
        subarr1.connect()

        len_full = 64
        len_sub1 = 16
        full_data = numpy.arange(len_full)/1.0

        caput("%s.NELM" % pvnames.subarr1, len_sub1)
        caput("%s.INDX" % pvnames.subarr1, 0)


        driver.put(full_data) ;
        time.sleep(0.1)
        subval = subarr1.get()

        self.assertEqual(len(subval), len_sub1)
        self.failUnless(numpy.all(subval == full_data[:len_sub1]))
        write("Subarray test:  C\n")
        caput("%s.NELM" % pvnames.subarr2, 19)
        caput("%s.INDX" % pvnames.subarr2, 3)

        subarr2 = PV(pvnames.subarr2)
        subarr2.get()

        driver.put(full_data) ;   time.sleep(0.1)
        subval = subarr2.get()

        self.assertEqual(len(subval), 19)
        self.failUnless(numpy.all(subval == full_data[3:3+19]))

        caput("%s.NELM" % pvnames.subarr2, 5)
        caput("%s.INDX" % pvnames.subarr2, 13)

        driver.put(full_data) ;   time.sleep(0.1)
        subval = subarr2.get()

        self.assertEqual(len(subval), 5)
        self.failUnless(numpy.all(subval == full_data[13:5+13]))
    def remove_grp(self, grp):
        if grp < 1 or grp > self.num_lens_group:
            print("invalid lens group: # %d" % grp)
            return
        self.lens_group[grp - 1].put(state_removed)
        self.wait()

    def restore_state(self, name="last"):
        for i in range(len(self.saved_states[name])):
            self.lens_group[i].put(self.saved_states[name][i])

    def save_state(self, name="last"):
        self.get_state(silent=True)
        self.saved_states[name] = self.current_state

    def remove_all(self):
        for i in range(self.num_lens_group):
            self.lens_group[i].put(state_removed)
        self.get_state(silent=True)


## Transfocator CRLs
p = PV('XF:16IDC-OP{CRL:1}config')
sleep(1)
if p.connect():
    crl = Transfocator('XF:16IDC-OP{CRL', 9, 'crl')
else:
    print("transfocator is not available.")

del p
예제 #5
0
def main(argv=None):
    global simulate
    global fp
    global shut_open
    global current
    global x3h5capture
    global xmot_cur
    global ymot_cur
    global shut_status
    global beam_current

    #parse command line options
    usage = "usage: %prog [options]\nData files are written to /data/<year>/<month>/<day>/"
    parser = OptionParser(usage)
    parser.add_option("--detname", action="store", type="string", dest="detname", help="detector PV base")
    parser.add_option("--xstart", action="store", type="float", dest="xo", help="starting X position")
    parser.add_option("--xnumstep", action="store", type="int", dest="Nx", help="number of steps in X")
    parser.add_option("--xstepsize", action="store", type="float", dest="dx", help="step size in X")
    parser.add_option("--ystart", action="store", type="float", dest="yo", help="starting Y position")
    parser.add_option("--ynumstep", action="store", type="int", dest="Ny", help="number of steps in Y")
    parser.add_option("--ystepsize", action="store", type="float", dest="dy", help="step size in Y")
    parser.add_option("--wait", action="store", type="float", dest="stall", help="wait at each step [seconds]")
    parser.add_option("--simulate", action="store_true", dest="sim", default=False, help="simulate motor moves")
    parser.add_option("--checkbeam", action="store_true", dest="checkbeam", default=False, help="only acquire when beam is on")
    parser.add_option("--checkcryo", action="store_true", dest="checkcryo", default=False, help="only acquire when cryo status is ok")
    parser.add_option("--acqtime", action="store", type="float", dest="acqt", default=1, help="image integration time [sec]")
    parser.add_option("--acqnum", action="store", type="int", dest="acqn", default=1, help="frames per scan point")

    (options,args) = parser.parse_args()

    #open log file
    D0=time.localtime()[0]
    D1=time.localtime()[1]
    D2=time.localtime()[2]
    D3=time.localtime()[3]
    D4=time.localtime()[4]
    cd=os.getcwd()
    
    filedir = '/nfs/xf05id1/data/' 
    
    if sys.argv[0][0]=='.':
        out_filename=filedir+repr(D0)+'/'+repr(D1)+'/'+repr(D2)+'/'+'log_'+repr(D1)+'_'+repr(D2)+'_'+repr(D3)+'_'+repr(D4)+'_'+\
         string.split(string.strip(sys.argv[0],'./'),'/')[0]+'.txt'
    else:
        out_filename=filedir+repr(D0)+'/'+repr(D1)+'/'+repr(D2)+'/'+'log_'+repr(D1)+'_'+repr(D2)+'_'+repr(D3)+'_'+repr(D4)+'_'+\
         string.split(string.strip(sys.argv[0],'./'),'/')[5]+'.txt'
    try:
        os.chdir(filedir+repr(D0))
    except OSError:
        try:    
            os.mkdir(filedir+repr(D0))
        except Exception:
            print 'cannot create directory: '+'/data/'+repr(D0)
            sys.exit()

    try:
        os.chdir(filedir+repr(D0)+'/'+repr(D1))
    except OSError:
        try:
            os.mkdir(filedir+repr(D0)+'/'+repr(D1))
        except Exception:
            print 'cannot create directory: '+'/data/'+repr(D0)+'/'+repr(D1)
            sys.exit()
    try:
        os.chdir(filedir+repr(D0)+'/'+repr(D1)+'/'+repr(D2))
    except OSError:
        try:
            os.mkdir(filedir+repr(D0)+'/'+repr(D1)+'/'+repr(D2))
        except Exception:
            print 'cannot create directory: '+filedir+repr(D0)+'/'+repr(D1)+'/'+repr(D2)
            sys.exit()
    try:
        fp=open(out_filename,'a')
    except Exception:
        print 'cannot open file: '+out_filename
        sys.exit()
    os.chdir(cd)
    fp.write('#'+', '.join(sys.argv))
    fp.write('\n')
    H5path='/epics/data/2015-3/in-house'
    #H5path='/epics/data/2015-2/testing'
    #initialize PVs and callbacks
    if options.detname == None:
        detstr=''
        print "must provide detector pv base, e.g., 'XF:28IDA-BI{URL:01}'"
        sys.exit()
    else:
        detstr=options.detname

##### original script for Aerotech stages
#    xmotname='XF:05IDD-ES:1{Stg:Smpl1-Ax:X}'
#    ymotname='XF:05IDD-ES:1{Stg:Smpl1-Ax:Y}'
#    xmot=PV(xmotname+'Mtr.VAL')
#    xmot_cur=PV(xmotname+'Mtr.RBV')
#    ymot=PV(ymotname+'Mtr.VAL')
#    ymot_cur=PV(ymotname+'Mtr.RBV')
######
#####modified for nPoint Stages
#    xmot=PV('NPOINT:CH1:SET_POSITION.A',connection_timeout=2)
#    xmot_cur=PV('NPOINT:CH1:GET_POSITION',connection_timeout=2)
#    ymot=PV('NPOINT:CH2:SET_POSITION.A',connection_timeout=2)
#    ymot_cur=PV('NPOINT:CH2:GET_POSITION',connection_timeout=2)    
#####modified for HR coarse Stages; X=Attocube ECS505 X, Y=Attocube ECS505 Z
    xmot=PV('XF:05IDD-ES:1{Stg:Ecs50}:ACT0:CMD:TARGET',connection_timeout=2)
    xmot_cur=PV('XF:05IDD-ES:1{Stg:Ecs50}:ACT0:POSITION',connection_timeout=2)
    ymot=PV('XF:05IDD-ES:1{Stg:Ecs50}:ACT1:CMD:TARGET',connection_timeout=2)
    ymot_cur=PV('XF:05IDD-ES:1{Stg:Ecs50}:ACT1:POSITION',connection_timeout=2)  

#####
    shut_status=PV('SR:C05-EPS{PLC:1}Shutter:Sum-Sts',connection_timeout=2)
    beam_current=PV('SR:C03-BI{DCCT:1}I:Total-I',connection_timeout=2)
    bmot_cur=PV('XF:05IDA-OP:1{Mono:HDCM-Ax:P}Mtr.RBV',connection_timeout=2)
    #transmission
    #check command line options
    if options.yo == None:
        print "must provide a starting point in the vertical"
        sys.exit()
    else:   
        yo = options.yo
    if options.xo == None:
        print "must provide a starting point in the horizontal"
        sys.exit()
    else:   
        xo = options.xo
    if options.dx == None:
        dx = 0.00000001
    else:
        dx = options.dx
    if options.dy == None:
        dy = 0.00000001
    else:
        dy = options.dy
    if options.Nx == None:
        Nx = 0
    else:
        Nx = options.Nx
    if options.Ny == None:
        Ny = 0
    else:
        Ny = options.Ny
    if options.stall == None:
        twait = 0.
    else:
        twait = options.stall
    diode0=PV(detstr+'Cur:I0-I',connection_timeout=4)
    diode1=PV(detstr+'Cur:I1-I',connection_timeout=4)
    diode2=PV(detstr+'Cur:I2-I',connection_timeout=4)
    diode3=PV(detstr+'Cur:I3-I',connection_timeout=4)
    diode0.connect()
    diode1.connect()
    diode2.connect()
    diode3.connect()
    dett=PV('XF:05IDD-ES:1{EVR:1-Out:FP3}Src:Scale-SP',connection_timeout=2)
    deti=PV('XF:05IDA{IM:1}Per-SP',connection_timeout=4)
    detinit=PV('XF:05IDA{IM:1}Cmd:Init',connection_timeout=4)
                
    wb=srxslit.nsls2slit(tb='XF:05IDA-OP:1{Slt:1-Ax:T}',bb='XF:05IDA-OP:1{Slt:1-Ax:B}',ib='XF:05IDA-OP:1{Slt:1-Ax:I}',ob='XF:05IDA-OP:1{Slt:1-Ax:O}')
    pb=srxslit.nsls2slit(ib='XF:05IDA-OP:1{Slt:2-Ax:I}',ob='XF:05IDA-OP:1{Slt:2-Ax:O}')
    ssa=srxslit.nsls2slit(tb='XF:05IDB-OP:1{Slt:SSA-Ax:T}', bb='XF:05IDB-OP:1{Slt:SSA-Ax:B}', ob='XF:05IDB-OP:1{Slt:SSA-Ax:O}',ib='XF:05IDB-OP:1{Slt:SSA-Ax:I}')

    x3acq=PV('XSPRESS3-EXAMPLE:Acquire',connection_timeout=2)
    x3erase=PV('XSPRESS3-EXAMPLE:ERASE',connection_timeout=2)
    x3acqtime=PV('XSPRESS3-EXAMPLE:AcquireTime',connection_timeout=2)
    x3acqnum=PV('XSPRESS3-EXAMPLE:NumImages',connection_timeout=2)
    x3tmode=PV('XSPRESS3-EXAMPLE:TriggerMode',connection_timeout=2)
    x3h5path=PV('XSPRESS3-EXAMPLE:HDF5:FilePath',connection_timeout=2)
    x3h5fname=PV('XSPRESS3-EXAMPLE:HDF5:FileName',connection_timeout=2)
    x3h5fnum=PV('XSPRESS3-EXAMPLE:HDF5:FileNumber',connection_timeout=2)
    x3h5vdim=PV('XSPRESS3-EXAMPLE:HDF5:NumExtraDims',connection_timeout=2)
    x3h5size=PV('XSPRESS3-EXAMPLE:HDF5:ExtraDimSizeN',connection_timeout=2)
    x3h5d1=PV('XSPRESS3-EXAMPLE:HDF5:ExtraDimSizeX',connection_timeout=2)
    x3h5d2=PV('XSPRESS3-EXAMPLE:HDF5:ExtraDimSizeY',connection_timeout=2)
    #report ROIs for channels and counts at each point
    x3ch1roi0min=PV('XSPRESS3-EXAMPLE:C1_MCA_ROI1_LLM',connection_timeout=2)
    x3ch1roi0max=PV('XSPRESS3-EXAMPLE:C1_MCA_ROI1_HLM',connection_timeout=2)
    x3ch1roi0ct=PV('XSPRESS3-EXAMPLE:C1_ROI1:Value_RBV',connection_timeout=2)
    x3ch1roi1min=PV('XSPRESS3-EXAMPLE:C1_MCA_ROI2_LLM',connection_timeout=2)
    x3ch1roi1max=PV('XSPRESS3-EXAMPLE:C1_MCA_ROI2_HLM',connection_timeout=2)
    x3ch1roi1ct=PV('XSPRESS3-EXAMPLE:C1_ROI2:Value_RBV',connection_timeout=2)
    x3ch1roi2min=PV('XSPRESS3-EXAMPLE:C1_MCA_ROI3_LLM',connection_timeout=2)
    x3ch1roi2max=PV('XSPRESS3-EXAMPLE:C1_MCA_ROI3_HLM',connection_timeout=2)
    x3ch1roi2ct=PV('XSPRESS3-EXAMPLE:C1_ROI3:Value_RBV',connection_timeout=2)
    x3ch2roi0min=PV('XSPRESS3-EXAMPLE:C2_MCA_ROI1_LLM',connection_timeout=2)
    x3ch2roi0max=PV('XSPRESS3-EXAMPLE:C2_MCA_ROI1_HLM',connection_timeout=2)
    x3ch2roi0ct=PV('XSPRESS3-EXAMPLE:C2_ROI1:Value_RBV',connection_timeout=2)
    x3ch2roi1min=PV('XSPRESS3-EXAMPLE:C2_MCA_ROI2_LLM',connection_timeout=2)
    x3ch2roi1max=PV('XSPRESS3-EXAMPLE:C2_MCA_ROI2_HLM',connection_timeout=2)
    x3ch2roi1ct=PV('XSPRESS3-EXAMPLE:C2_ROI2:Value_RBV',connection_timeout=2)
    x3ch2roi2min=PV('XSPRESS3-EXAMPLE:C2_MCA_ROI3_LLM',connection_timeout=2)
    x3ch2roi2max=PV('XSPRESS3-EXAMPLE:C2_MCA_ROI3_HLM',connection_timeout=2)
    x3ch2roi2ct=PV('XSPRESS3-EXAMPLE:C2_ROI3:Value_RBV',connection_timeout=2)
    x3ch3roi0min=PV('XSPRESS3-EXAMPLE:C3_MCA_ROI1_LLM',connection_timeout=2)
    x3ch3roi0max=PV('XSPRESS3-EXAMPLE:C3_MCA_ROI1_HLM',connection_timeout=2)
    x3ch3roi0ct=PV('XSPRESS3-EXAMPLE:C3_ROI1:Value_RBV',connection_timeout=2)
    x3ch3roi1min=PV('XSPRESS3-EXAMPLE:C3_MCA_ROI2_LLM',connection_timeout=2)
    x3ch3roi1max=PV('XSPRESS3-EXAMPLE:C3_MCA_ROI2_HLM',connection_timeout=2)
    x3ch3roi1ct=PV('XSPRESS3-EXAMPLE:C3_ROI2:Value_RBV',connection_timeout=2)
    x3ch3roi2min=PV('XSPRESS3-EXAMPLE:C3_MCA_ROI3_LLM',connection_timeout=2)
    x3ch3roi2max=PV('XSPRESS3-EXAMPLE:C3_MCA_ROI3_HLM',connection_timeout=2)
    x3ch3roi2ct=PV('XSPRESS3-EXAMPLE:C3_ROI3:Value_RBV',connection_timeout=2)


    #claim ROI 4 for our own use.  we will integrate over all 4096 channels.
    x3ch1roi3min=PV('XSPRESS3-EXAMPLE:C1_MCA_ROI4_LLM',connection_timeout=2)
    x3ch1roi3max=PV('XSPRESS3-EXAMPLE:C1_MCA_ROI4_HLM',connection_timeout=2)
    x3ch1roi3ct=PV('XSPRESS3-EXAMPLE:C1_ROI4:Value_RBV',connection_timeout=2)
    x3ch2roi3min=PV('XSPRESS3-EXAMPLE:C2_MCA_ROI4_LLM',connection_timeout=2)
    x3ch2roi3max=PV('XSPRESS3-EXAMPLE:C2_MCA_ROI4_HLM',connection_timeout=2)
    x3ch2roi3ct=PV('XSPRESS3-EXAMPLE:C2_ROI4:Value_RBV',connection_timeout=2)
    x3ch3roi3min=PV('XSPRESS3-EXAMPLE:C3_MCA_ROI4_LLM',connection_timeout=2)
    x3ch3roi3max=PV('XSPRESS3-EXAMPLE:C3_MCA_ROI4_HLM',connection_timeout=2)
    x3ch3roi3ct=PV('XSPRESS3-EXAMPLE:C3_ROI4:Value_RBV',connection_timeout=2)

#    xmot_cur.get()
    xmot_cur.connect()
#    ymot_cur.get()
    ymot_cur.connect()

    norm0=PV('XF:05IDD-BI:1{BPM:01}.S20',connection_timeout=2)
    norm1=PV('XF:05IDD-BI:1{BPM:01}.S21',connection_timeout=2)
    norm2=PV('XF:05IDD-BI:1{BPM:01}.S22',connection_timeout=2)
    norm3=PV('XF:05IDD-BI:1{BPM:01}.S23',connection_timeout=2)

    xmot_cur.add_callback(cbfx)
    ymot_cur.add_callback(cbfy)
    shut_status.add_callback(cbf_shut)
    beam_current.add_callback(cbf_curr)
    xmot_cur.run_callbacks()
    ymot_cur.run_callbacks()
    shut_status.run_callbacks()
    beam_current.run_callbacks()

    x3h5path.put(H5path)
    x3h5fname.put(repr(D0)+'_'+repr(D1)+'_'+repr(D2)+'_'+repr(D3)+'_'+repr(D4)+'_')
    x3h5fnum.put(0)
    x3acqtime.put(options.acqt)
    x3acqnum.put(options.acqn)
    x3tmode.put(1)

    x3ch1roi3min.put(0)
    x3ch2roi3min.put(0)
    x3ch3roi3min.put(0)
    x3ch1roi3max.put(4096)
    x3ch2roi3max.put(4096)
    x3ch3roi3max.put(4096)
    #h5 set up
    x3h5vdim.put(2)
    x3h5size.put(options.acqn)
    x3h5d1.put(options.Nx+1)
    x3h5d2.put(options.Ny+1)
    dett.put(3)
    #overhead on triggering F460
    deti.put(float(options.acqn)*options.acqt*1.)
    detinit.put(1)
    #ring buffer and PV for tracking ion chamber value
    ic_hist=collections.deque(maxlen=50)
    ic_hist.append(0.)
    v19st=PV('XF:05IDA-UT{Cryo:1-IV:19}Pos-I',connection_timeout=4)
    v19st.connect()

    str='#NSLS-II SRX'+time.asctime()
    fp.write(str)
    fp.write('\n')
    str='#Start time is '+time.asctime()
    print str
    fp.write(str)
    fp.write('\n')
    str='# x: %(hs)6.4f ; y: %(vs)6.4f ; ROI1 %(roi1i)d:%(roi1a)d ; ROI2 %(roi2i)d:%(roi2a)d ; ROI3 %(roi3i)d:%(roi3a)d'%\
     {"hs":xmot_cur.get(),"vs":ymot_cur.get(), 'roi1i':x3ch1roi0min.get(), 'roi1a':x3ch1roi0max.get(), 'roi2i':x3ch1roi1min.get(), 'roi2a':x3ch1roi1max.get(), 'roi3i':x3ch1roi2min.get(), 'roi3a':x3ch1roi2max.get()}
    print str
    fp.write(str)
    fp.write('\n')
    roits=x3ch3roi3ct.timestamp
    str='# SSA HCEN: %(WBHC)f ; SSA HSIZE: %(WBHS)f ; SSA VCEN: %(WBVC)f ; SSA VSIZE: %(WBVS)f'%\
     {"WBHC":ssa.hcen(), "WBHS":ssa.hsize(), "WBVC":ssa.vcen(), "WBVS":ssa.vsize()}
    print str
    fp.write(str)
    fp.write('\n')
    str='# Bragg: %(B)6.4f ; Energy: %(E)6.4f ; WB HCEN: %(WBHC)f ; WB HSIZE: %(WBHS)f ; WB VCEN: %(WBVC)f ; WB VSIZE: %(WBVS)f'%\
     {"B":bmot_cur.get(), "E": 12398. / (2 * 3.12964794061 * math.sin((bmot_cur.get()+0.323341791985)/180.*3.1416)), "WBHC":wb.hcen(), "WBHS":wb.hsize(), "WBVC":wb.vcen(), "WBVS":wb.vsize()}
    print str
    fp.write(str)
    fp.write('\n')
    str="# --------------------------------------------------------------------    "
    print str
    fp.write(str)
    fp.write('\n')
    str='#[point #]\tX pos\t\tY pos\tch 1\t\tch 2\t\tch 3\t\tch 4\tdBPM1\t\tdBPM2\t\tdBPM3\t\tdBPM4\t\troi0\t\troi1\t\troi2\t\troi3\t\ttime'
    print str
    fp.write(str)
    fp.write('\n')
    if options.sim is True:
        str="      -----simulating motor moves and bursts-----"
        print str
        fp.write(str)
        fp.write('\n')
    else:
        x3h5capture.put(1)
        dett.put(4)
        time.sleep(2)
        thisisstupid=0
        while x3h5capture.get() == 0:
            time.sleep(0.5)
            thisisstupid+=1
            if (thisisstupid%20==0):
                print "waiting for xspress3"
        dett.put(3)
        ic_hist.append(diode1.get())
        

    #number of rows and columns completed by scan
    Ncol=Nrow=0
    LN=0

    #diode readback is now limiting factor for scan speed
    oldsig=0.
    #when the cryocooler kicks in, the beam is unusable for ~3200sec
#    cryo=PV('XF:05IDA-OP:1{Mono:HDCM}T:LN2Out-I')
#    ct=cryo.get()
#    while( ct is None):
#        time.sleep(0.1)
#        ct=cryo.get()
#        print "waiting for cryocooler to respond"
    t0=time.time()
    cryocounter=0
    shut_toggle=False

    #nested loops for scanning z,x,y
    for y in np.linspace(yo,yo+((Ny)*dy),Ny+1):
        tar[1][0]=y
        tar[1][1]=1
        if options.sim is False:
            ymot.put(tar[1][0])
        if indeadband(float(tar[1][0]),float(ymot_cur.get()),dbd)==1:
            tar[1][1] = 0
        if Nrow%2==0:
            xs=0.+xo
            xe=((Nx+1)*dx)+xo-dx
            xi=dx
        else:
            xs=((Nx)*dx)+xo
            xe=0.+xo
            xi=-dx
        for x in np.linspace(xs,xe,Nx+1):
            tar[0][0]=x
            tar[0][1]=1
            if indeadband(float(tar[0][0]),float(xmot_cur.get()),dbd)==1:
                tar[0][1]=0
            if options.sim is False:
                xmot.put(tar[0][0])
                while ((tar[0][1] == 1) or (tar[1][1] == 1)):
                    time.sleep(0.01)
            signal0=signal1=signal2=signal3=0.
            nsig0=nsig1=nsig2=nsig3=0.
            sig0=sig1=sig2=sig3=0.
#            while ( options.checkbeam and (cryo.get() < (ct - 0.1)) ):
#                    print "Stopped.  Detected possible cryocooler activation."
#                    time.sleep(1)
#                    cryocounter=cryocounter+1
            #if the above is true for five cycles, the cryocooler was on, wait another 10min
#            if ( options.checkbeam and cryocounter > 300 ):
#                print "Detected cryocooler activation, waiting 10min"
#                time.sleep(600)
#                cryocounter=0
            #this is my averge IC current
            tavg=np.asarray(ic_hist).mean()
            #check the filling valve status and set flag high if it is open
            while ( options.checkcryo and (v19st.get() > 0.)):
                print "Stopped.  Crycooler valve V19 is open."
                cryocounter=1
                time.sleep(1)
            #while the ion chamber is reading less than 80% of previous history, sleep
            while (cryocounter==1):
                #trigger the 460 and store the ion chamber value
                dett.put(4)
                time.sleep(5+options.acqt)
                oldsig=diode1.get()
                dett.put(3)
                #if the reading is less than 80% of historical value or the valve is open, sleep
                #remember that the reading is negative-going
                if (oldsig > (-1.*0.8*tavg)) and (v19st.get > 0.):
                    print "Beam current has not returned"
                    time.sleep(30)
                else:
                    cryocounter=0
            while ( options.checkbeam and (shut_open == False or beam_current == False)):
                print "Stopped.  Waiting for scan conditions to return to normal."
                if shut_open==False:
                    shut_toggle=True
                time.sleep(10.)
            if shut_toggle==True:
                print "Entering optics conditioning period.  Waiting 5min"
                time.sleep(300)
                shut_toggle=False
            if options.sim is False:
                x3erase.put(1)
                dett.put(4)
                while nsig0==0.:
                    nsig0=float(norm0.get())
                while nsig1==0.:
                    nsig1=float(norm1.get())
                while nsig2==0.:
                    nsig2=float(norm2.get())
                while nsig3==0.:
                    nsig3=float(norm3.get())
                sig0=0
                sig1=0
                sig2=0
                sig3=0
                for i in range(0,options.acqn):
                    x3acq.put(1)
                    while ( x3ch3roi3ct.get()==0.0 or x3ch3roi3ct.timestamp==roits):
                        time.sleep(0.02)
                    sig0=sig0+x3ch1roi0ct.get()+x3ch2roi0ct.get()+x3ch3roi0ct.get()
                    sig1=sig1+x3ch1roi1ct.get()+x3ch2roi1ct.get()+x3ch3roi1ct.get()
                    sig2=sig2+x3ch1roi2ct.get()+x3ch2roi2ct.get()+x3ch3roi2ct.get()
                    sig3=sig3+x3ch1roi3ct.get()+x3ch2roi3ct.get()+x3ch3roi3ct.get()
                    roits=x3ch3roi3ct.timestamp
                signal0=diode0.get()            
                if signal0==oldsig:
                    time.sleep(0.02)
                    signal0=diode0.get()            
                oldsig=signal0
                signal1=diode1.get()
                signal2=diode2.get()            
                signal3=diode3.get()            
                dett.put(3)
                #populate a ring buffer with every 100th ion chamber reading
                #we will use the average of this buffer to determine recovery
                #from a cryocooler activation
                if(Nx%100 ==0):
                    ic_hist.append(signal1)
            time.sleep(twait)
            tn=time.time()-t0
            if options.sim is False:
                str='%(X)06d %(XC)9.4f %(YC)9.4f %(d1)10.7e %(d2)10.7e %(d3)10.7e %(d4)10.7e %(n0)10.7e %(n1)10.7e %(n2)10.7e %(n3)10.7e %(s0)10.7e %(s1)10.7e %(s2)10.7e %(s3)10.7e %(time)9.2f'%{ 'X':Ncol, 'XC':xmot_cur.get(),"YC":ymot_cur.get(), "d1":float(signal0), "d2":float(signal1), "d3":float(signal2),"d4":float(signal3), 'n0':nsig0, 'n1':nsig1, 'n2':nsig2, 'n3':nsig3, "s0":sig0,"s1":sig1,"s2":sig2,"s3":sig3, "time":tn}
                print str
                fp.write(str)
                fp.write('\n')
            else:
                str='%(X)06d %(XC)8.4f  %(YC)8.4f %(d1)10.7e %(d2)10.7e %(d3)10.7e %(d4)10.7e'%{"X":int(Ncol),"XC":tar[0][0], "YC":tar[1][0], "d1":float(signal0), "d2":float(signal1), "d3":float(signal2),"d4":float(signal3)}     
                print str
                fp.write(str)
                fp.write('\n')
    
            Ncol=Ncol+1
        Nrow=Nrow+1

    str='#End time is '+time.asctime()
    print str
    fp.write(str)
    fp.write('\n')
    fp.close()
    xmot_cur.clear_callbacks()
    ymot_cur.clear_callbacks()
    shut_status.clear_callbacks()
    beam_current.clear_callbacks()

    return 0
예제 #6
0
class ADPluginServer:
    """
    Server to mimic some of the plugin records/functionality from AreaDetector.
    The goal was for the user to only need to supply configuration parameters
    and functions to run that take the image np.ndarray as an argument. These
    servers have the following PVs: (set them from the non-_RBV PV)

    Attributes
    ----------
    $(ad_prefix)$(prefix)NDArrayPort{_RBV}:
        In AD this is a port name, but here we have to take from an array pv.
        This is where we store the stream argument e.g. IMAGE1

    $(ad_prefix)$(prefix)EnableCallbacks{_RBV}:
        If this is set to 0, The plugin will be disabled. Otherwise, the plugin
        will be active.

    $(ad_prefix)$(prefix)MinCallbackTime{_RBV}:
        If running the callback took less than this many seconds, we'll sleep
        until that time has expired before running another callback.

    $(ad_prefix)$(prefix)QueueSize{_RBV}:
        Maximum number of arrays kept in the memory queue. This can be useful
        if the source updates at an unstable rate.

    $(ad_prefix)$(prefix)QueueUse{_RBV}:
        Number of arrays currently in the queue.

    $(ad_prefix)$(prefix)DroppedArrays{_RBV}:
        Number of arrays we didn't put into the queue because the queue was
        full.

    $(ad_prefix)$(prefix){USER_DEFINED}:
        Whatever is installed using the ADPluginPV class.
    """
    def __init__(self, prefix, ad_prefix, stream,
                 enable_callbacks=0, min_cbtime=0, queuesize=5):
        """
        Parameters
        ----------
        prefix: str
            The plugin prefix that comes after the areaDetector prefix in the
            PV names.

        ad_prefix: str
            The base areaDetector control prefix. This should match a real
            areaDetector IOC's prefix.

        stream: str
            The image stream to use for the plugins. We'll be using:
                $(ad_prefix)$(stream):ArrayData    for values
                $(ad_prefix)$(stream):UniqueId_RBV for update monitoring

        enable_callbcaks: bool, optional
            If True, start the IOC with callbacks enabled. Start disabled
            otherwise.

        min_cbtime: float, optional
            The initial value for the minimum time for each callback loop.

        queuesize: int, optional
            The initial value for the array queue. The default is 5.
        """
        self.server = PypvServer(ad_prefix + prefix)
        self.ad_prefix = ad_prefix
        self.ad_directory = {}
        self.settings_lock = RLock()
        self.plugins = {}
        self.has_update = Event()
        self.enable_callbacks = int(enable_callbacks)
        self.min_cbtime = float(min_cbtime)
        self.queue = None
        queuesize = int(queuesize)

        self._ndarray_port_cb(value=str(stream))
        self._add_builtin('NDArrayPort', str(stream), cb=self._ndarray_port_cb)
        self._enable_callbacks_cb(value=self.enable_callbacks)
        self._add_builtin('EnableCallbacks', self.enable_callbacks,
                          cb=self._enable_callbacks_cb)
        self._min_cbtime_cb(value=self.min_cbtime)
        self._add_builtin('MinCallbackTime', self.min_cbtime,
                          cb=self._min_cbtime_cb)
        self._queuesize_cb(value=queuesize)
        self._add_builtin('QueueSize', queuesize, cb=self._queuesize_cb)
        self._add_builtin('QueueUse', 0)
        self._add_builtin('DroppedArrays', 0)

        arrays = CAThread(target=self._array_cb_loop, args=(), daemon=True)
        plugins = Thread(target=self._get_queue_loop, args=(), daemon=True)
        arrays.start()
        plugins.start()

    def _add_builtin(self, name, value, cb=None):
        """
        Does setup for the built-in PVs, which are all basically the same.
        """
        rbv = PyPV(name + '_RBV', value=value, server=self.server)
        if cb is None:
            def cb(**kwargs):
                pass

        def callback(value=None, rbv=rbv, cb=cb, **kwargs):
            rbv.put(value)
            cb(value=value, **kwargs)
        setter = PyPV(name, value=value, server=self.server,
                      written_cb=callback)
        self.ad_directory[rbv.name] = rbv
        self.ad_directory[setter.name] = setter

    def install_plugin(self, plugin):
        """
        Called by ADPluginFunction to register itself with the server.
        """
        with self.settings_lock:
            self.plugins[plugin.name] = plugin

    def uninstall_plugin(self, plugin):
        """
        You can call this to remove a plugin. This will not disconnect the PVs,
        it will only stop them from updating.
        """
        with self.settings_lock:
            del self.plugins[plugin.name]

    def _ndarray_port_cb(self, *, value, **kwargs):
        """
        Setter for puts to the enable ndarray port PV.
        When we change the stream, we need new source PVs.
        """
        with self.settings_lock:
            self._initialize_pv(value)

    def _enable_callbacks_cb(self, *, value, **kwargs):
        """
        Setter for puts to the enable callbacks PV.
        """
        with self.settings_lock:
            if value:
                self.enable_callbacks = True
            else:
                self.enable_callbacks = False

    def _min_cbtime_cb(self, *, value, **kwargs):
        """
        Setter for puts to the minimum callback time pv
        """
        with self.settings_lock:
            if value < 0:
                value = 0
            self.min_cbtime = value

    def _queuesize_cb(self, *, value, **kwargs):
        """
        Setter for puts to the queuesize pv.
        """
        with self.settings_lock:
            if value < 1:
                value = 1
            if self.queue is None:
                self.queue = Queue(value)
            else:
                new_queue = Queue(value)
                while not self.queue.empty() and not new_queue.full():
                    new_queue.put(self.queue.get(block=False))
                self.queue = new_queue

    def _initialize_pv(self, stream):
        """
        Set up the data and update monitoring pvs for the chosen stream.
        """
        get_pvname = self.ad_prefix + stream + ':ArrayData'
        logger.debug('getting data from %s', get_pvname)
        self.get_pv = PV(get_pvname)
        self.get_pv.connect(timeout=0)

        mon_pvname = self.ad_prefix + stream + ':UniqueId_RBV'
        logger.debug('monitoring changes from %s', mon_pvname)
        self.mon_pv = PV(mon_pvname, callback=self._mark_has_update,
                         auto_monitor=True)

        width_pvname = self.ad_prefix + stream + ':ArraySize0_RBV'
        width_pv = PV(width_pvname)
        self.width = width_pv.get()

        height_pvname = self.ad_prefix + stream + ':ArraySize1_RBV'
        height_pv = PV(height_pvname)
        self.height = height_pv.get()

    def _mark_has_update(self, **kwargs):
        """
        Callback to indicate that a new value is ready.
        """
        self.has_update.set()

    def _update_queue_use(self):
        """
        Update the QueueUse_RBV PV
        """
        with self.settings_lock:
            queue_use_pv = self.ad_directory['QueueUse_RBV']
            logger.debug('queue has %s elements', self.queue.qsize())
            queue_use_pv.put(self.queue.qsize())

    def _get_queue_loop(self, **kwargs):
        """
        Main event loop for getting arrays from EPICS
        """
        while True:
            start = time()
            logger.debug('start get queue')
            with self.settings_lock:
                queue = self.queue
                if self.enable_callbacks and self.plugins:
                    logger.debug('we will try to get an array from epics')
                    get_array = True
                else:
                    logger.debug('we will not try to get an array from epics,'
                                 + 'enable_callbacks=%s, num_plugins=%s',
                                 self.enable_callbacks, len(self.plugins))
                    get_array = False

            success = False
            if get_array:
                ok = self.has_update.wait(timeout=1.0)
                if ok:
                    if queue.full():
                        logger.debug('queue was full')
                        dropped_pv = self.ad_directory['DroppedArrays_RBV']
                        n_dropped = dropped_pv.get()
                        dropped_pv.put(n_dropped + 1)
                        logger.debug('dropped %s arrays total', n_dropped)
                    else:
                        array = self.get_pv.get()
                        self.has_update.clear()
                        logger.debug('we got an array, stashing into queue')
                        queue.put(array)
                        self._update_queue_use()
                    # Mark success True even if the Queue was full so we hit
                    # the minimum callback sleep and we don't barrage the
                    # python process's cpu usage with dropped array counts
                    success = True
                else:
                    logger.debug('wait for image update timed out after 1s')
            else:
                sleep(1)

            if success:
                elapsed = time() - start
                sleep(max(self.min_cbtime - elapsed, 0))

    def _array_cb_loop(self):
        """
        Main event loop for processing callbacks
        """
        while True:
            start = time()
            logger.debug('start array cb loop')
            array = None
            with self.settings_lock:
                queue = self.queue
                if self.enable_callbacks and self.plugins:
                    logger.debug('lets wait for a queued array...')
                    get_array = True
                else:
                    logger.debug('we will not get a queued array,'
                                 + 'enable_callbacks=%s, num_plugins=%s',
                                 self.enable_callbacks, len(self.plugins))
                    get_array = False

            if get_array:
                try:
                    array = queue.get(timeout=1)
                    logger.debug('got an array of type %s!', type(array))
                    if array is None:
                        logger.warning('No array: Make sure image PV exists!')
                    self._update_queue_use()
                except Empty:
                    pass

            if array is not None:
                logger.debug('run the plugins now')
                with self.settings_lock:
                    all_plugins = list(self.plugins.values())
                for plugin in all_plugins:
                    plugin(array, width=self.width, height=self.height)
                elapsed = time() - start
                logger.debug('post array cb sleep')
                sleep(max(self.min_cbtime - elapsed, 0))

            if not get_array:
                sleep(1)
예제 #7
0
class MCADisplay(wx.Frame):
    default_colors = ((0, 0, 0), (0, 0, 255), (255, 0, 0),
                      (0, 0, 0), (255, 0, 255), (0, 125, 0))

    help_msg =  """Quick help:

 Left-Click:   to display X,Y coordinates
 Left-Drag:    to zoom in on plot region
 Right-Click:  display popup menu with choices:
                Zoom out 1 level
                Zoom all the way out
                --------------------
                Configure
                Save Image

Also, these key bindings can be used
(For Mac OSX, replace 'Ctrl' with 'Apple'):

  Ctrl-S:     save plot image to file
  Ctrl-C:     copy plot image to clipboard
  Ctrl-K:     Configure Plot
  Ctrl-Q:     quit

"""

    about_msg =  """Epics MCA Display  version 0.1
Matt Newville <*****@*****.**>
"""

    def __init__(self, mca_pv=None, parent=None):

        self.mca_pv = '13SDD1:mca1'

        self.mca_pv = 'Py:long2k'
        self.needs_refresh = False
        self.paused = False
        self.mca_data = np.ones(2048)
        self.mca_en = None
        self.mca_data_sum = 0
        self.create_frame(parent)

        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.onUpdatePlot, self.timer)
        self.timer.Start(POLLTIME)
        self.init_epics()

    @EpicsFunction
    def init_epics(self):
        self.pv = PV(self.mca_pv, callback=self.onMCAData)
        self.pv.connect()

    def create_frame(self, parent, size=(750, 450), **kwds):
        self.parent = parent

        kwds['style'] = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL
        kwds['size']  = size
        wx.Frame.__init__(self, parent, -1, 'Epics MCA Display', **kwds)

        self.build_statusbar()

        self.plotpanel = PlotPanel(self, trace_color_callback=self.onTraceColor)
        self.plotpanel.messenger = self.write_message
        self.build_menus()
        self.SetBackgroundColour(wx.Colour(*BGCOL))

        mainsizer = wx.BoxSizer(wx.VERTICAL)

        mainsizer.Add(self.plotpanel, 1, wx.EXPAND, 5)
        self.SetAutoLayout(True)
        self.SetSizer(mainsizer)
        self.Fit()

        try:
            self.SetIcon(wx.Icon(ICON_FILE, wx.BITMAP_TYPE_ICO))
        except:
            pass

        self.Refresh()


    def build_statusbar(self):
        sbar = self.CreateStatusBar(2, wx.CAPTION|wx.THICK_FRAME)
        sfont = sbar.GetFont()
        sfont.SetWeight(wx.BOLD)
        sfont.SetPointSize(10)
        sbar.SetFont(sfont)
        self.SetStatusWidths([-5, -2])
        self.SetStatusText('', 0)

    def write_message(self, s, panel=0):
        """write a message to the Status Bar"""
        self.SetStatusText(s, panel)

    def build_menus(self):
        mbar = wx.MenuBar()

        mfile = wx.Menu()
        mfile.Append(MENU_SAVE_DAT, "&Save Data\tCtrl+S",
                     "Save PNG Image of Plot")
        mfile.Append(MENU_SAVE_IMG, "Save Plot Image\t",
                     "Save PNG Image of Plot")
        mfile.Append(MENU_CLIPB, "&Copy Image to Clipboard\tCtrl+C",
                     "Copy Plot Image to Clipboard")
        mfile.AppendSeparator()
        mfile.Append(MENU_PSETUP, 'Page Setup...', 'Printer Setup')
        mfile.Append(MENU_PREVIEW, 'Print Preview...', 'Print Preview')
        mfile.Append(MENU_PRINT, "&Print\tCtrl+P", "Print Plot")
        mfile.AppendSeparator()
        mfile.Append(MENU_EXIT, "E&xit\tCtrl+Q", "Exit the 2D Plot Window")

        mopt = wx.Menu()
        mopt.Append(MENU_CONFIG, "Configure Plot\tCtrl+K",
                 "Configure Plot styles, colors, labels, etc")
        mopt.AppendSeparator()
        mopt.Append(MENU_UNZOOM, "Zoom Out\tCtrl+Z",
                 "Zoom out to full data range")

        mhelp = wx.Menu()
        mhelp.Append(MENU_HELP, "Quick Reference",  "Quick Reference for MPlot")
        mhelp.Append(MENU_ABOUT, "About", "About MPlot")

        mbar.Append(mfile, "File")
        mbar.Append(mopt, "Options")
        mbar.Append(mhelp, "&Help")

        self.SetMenuBar(mbar)
        self.Bind(wx.EVT_MENU, self.onHelp,     id=MENU_HELP)
        self.Bind(wx.EVT_MENU, self.onAbout,    id=MENU_ABOUT)
        self.Bind(wx.EVT_MENU, self.onExit,     id=MENU_EXIT)
        self.Bind(wx.EVT_CLOSE, self.onExit)

        pp = self.plotpanel
        self.Bind(wx.EVT_MENU, pp.configure,    id=MENU_CONFIG)
        self.Bind(wx.EVT_MENU, pp.unzoom_all,   id=MENU_UNZOOM)
        self.Bind(wx.EVT_MENU, pp.save_figure,  id=MENU_SAVE_IMG)
        self.Bind(wx.EVT_MENU, pp.Print,        id=MENU_PRINT)
        self.Bind(wx.EVT_MENU, pp.PrintSetup,   id=MENU_PSETUP)
        self.Bind(wx.EVT_MENU, pp.PrintPreview, id=MENU_PREVIEW)
        self.Bind(wx.EVT_MENU, pp.canvas.Copy_to_Clipboard, id=MENU_CLIPB)


    def onTraceColor(self, trace, color, **kws):
        irow = self.get_current_traces()[trace][0] - 1
        self.colorsels[irow].SetColour(color)



    @DelayedEpicsCallback
    def onMCAData(self, pvname=None, value=None, timestamp=None, **kw):
        if timestamp is None:
            timestamp = time.time()
        print 'onMCA DATA!! ', len(value), value.sum(), timestamp
        self.mca_data = value[:]
        self.needs_refresh = True


    def onAbout(self, event=None):
        dlg = wx.MessageDialog(self, self.about_msg,
                               "About Epics MCA Display",
                               wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def onHelp(self, event=None):
        dlg = wx.MessageDialog(self, self.help_msg, "Epics MCA Display Help",
                               wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def onExit(self, event=None):
        try:
            self.plotpanel.win_config.Close(True)
            self.plotpanel.win_config.Destroy()
        except:
            pass

        self.Destroy()

    def get_current_traces(self):
        "return list of current traces"
        traces = []   # to be shown
        for irow, s in enumerate(self.pvchoices):
            if s is not None:
                ix = s.GetSelection()
                if ix > 0:
                    name = self.pvlist[ix]
                    logs  = 1 == self.pvwids[irow][0].GetSelection()
                    color = self.pvwids[irow][1].GetColour()
                    ymin  = get_bound(self.pvwids[irow][2].GetValue())
                    ymax  = get_bound(self.pvwids[irow][3].GetValue())
                    traces.append((irow, name, logs, color, ymin, ymax))
        return traces

    def onUpdatePlot(self, event=None):
        if self.paused or not self.needs_refresh:
            return

        if (len(self.mca_data) < 1 or 
            self.mca_data.sum() ==  self.mca_data_sum):
            return
        self.mca_data_sum = self.mca_data.sum()
        ppanel = self.plotpanel
        did_update = False

        if self.mca_en is None: # first plot!
            self.mca_en = np.arange(len(self.mca_data))
            ppanel.plot(self.mca_en*1.0, 1.0*self.mca_data, 
                        xmax=self.mca_en.max(),
                        ylog_scale=True, autoscale=True)
            did_update = True
        else:
            try:
                ppanel.update_line(0, self.mca_en, self.mca_data, 
                                   draw=False, update_limits=False)
                # self.plotpanel.plot(tdat, ydat, draw=False, update_limits=True)    
                # self.plotpanel.set_xylims((self.tmin, 0, ymin, ymax),
                #                          side=side, autoscale=False)
                did_update = True
            except:
                pass

        if did_update:
            self.plotpanel.canvas.draw()
        self.needs_refresh = not did_update
        return
예제 #8
0
class MCADisplay(wx.Frame):
    default_colors = ((0, 0, 0), (0, 0, 255), (255, 0, 0), (0, 0, 0),
                      (255, 0, 255), (0, 125, 0))

    help_msg = """Quick help:

 Left-Click:   to display X,Y coordinates
 Left-Drag:    to zoom in on plot region
 Right-Click:  display popup menu with choices:
                Zoom out 1 level
                Zoom all the way out
                --------------------
                Configure
                Save Image

Also, these key bindings can be used
(For Mac OSX, replace 'Ctrl' with 'Apple'):

  Ctrl-S:     save plot image to file
  Ctrl-C:     copy plot image to clipboard
  Ctrl-K:     Configure Plot
  Ctrl-Q:     quit

"""

    about_msg = """Epics MCA Display  version 0.1
Matt Newville <*****@*****.**>
"""

    def __init__(self, mca_pv=None, parent=None):

        self.mca_pv = '13SDD1:mca1'

        self.mca_pv = 'Py:long2k'
        self.needs_refresh = False
        self.paused = False
        self.mca_data = np.ones(2048)
        self.mca_en = None
        self.mca_data_sum = 0
        self.create_frame(parent)

        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.onUpdatePlot, self.timer)
        self.timer.Start(POLLTIME)
        self.init_epics()

    @EpicsFunction
    def init_epics(self):
        self.pv = PV(self.mca_pv, callback=self.onMCAData)
        self.pv.connect()

    def create_frame(self, parent, size=(750, 450), **kwds):
        self.parent = parent

        kwds['style'] = wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL
        kwds['size'] = size
        wx.Frame.__init__(self, parent, -1, 'Epics MCA Display', **kwds)

        self.build_statusbar()

        self.plotpanel = PlotPanel(self,
                                   trace_color_callback=self.onTraceColor)
        self.plotpanel.messenger = self.write_message
        self.build_menus()
        self.SetBackgroundColour(wx.Colour(*BGCOL))

        mainsizer = wx.BoxSizer(wx.VERTICAL)

        mainsizer.Add(self.plotpanel, 1, wx.EXPAND, 5)
        self.SetAutoLayout(True)
        self.SetSizer(mainsizer)
        self.Fit()

        try:
            self.SetIcon(wx.Icon(ICON_FILE, wx.BITMAP_TYPE_ICO))
        except:
            pass

        self.Refresh()

    def build_statusbar(self):
        sbar = self.CreateStatusBar(2, wx.CAPTION | wx.THICK_FRAME)
        sfont = sbar.GetFont()
        sfont.SetWeight(wx.BOLD)
        sfont.SetPointSize(10)
        sbar.SetFont(sfont)
        self.SetStatusWidths([-5, -2])
        self.SetStatusText('', 0)

    def write_message(self, s, panel=0):
        """write a message to the Status Bar"""
        self.SetStatusText(s, panel)

    def build_menus(self):
        mbar = wx.MenuBar()

        mfile = wx.Menu()
        mfile.Append(MENU_SAVE_DAT, "&Save Data\tCtrl+S",
                     "Save PNG Image of Plot")
        mfile.Append(MENU_SAVE_IMG, "Save Plot Image\t",
                     "Save PNG Image of Plot")
        mfile.Append(MENU_CLIPB, "&Copy Image to Clipboard\tCtrl+C",
                     "Copy Plot Image to Clipboard")
        mfile.AppendSeparator()
        mfile.Append(MENU_PSETUP, 'Page Setup...', 'Printer Setup')
        mfile.Append(MENU_PREVIEW, 'Print Preview...', 'Print Preview')
        mfile.Append(MENU_PRINT, "&Print\tCtrl+P", "Print Plot")
        mfile.AppendSeparator()
        mfile.Append(MENU_EXIT, "E&xit\tCtrl+Q", "Exit the 2D Plot Window")

        mopt = wx.Menu()
        mopt.Append(MENU_CONFIG, "Configure Plot\tCtrl+K",
                    "Configure Plot styles, colors, labels, etc")
        mopt.AppendSeparator()
        mopt.Append(MENU_UNZOOM, "Zoom Out\tCtrl+Z",
                    "Zoom out to full data range")

        mhelp = wx.Menu()
        mhelp.Append(MENU_HELP, "Quick Reference", "Quick Reference for MPlot")
        mhelp.Append(MENU_ABOUT, "About", "About MPlot")

        mbar.Append(mfile, "File")
        mbar.Append(mopt, "Options")
        mbar.Append(mhelp, "&Help")

        self.SetMenuBar(mbar)
        self.Bind(wx.EVT_MENU, self.onHelp, id=MENU_HELP)
        self.Bind(wx.EVT_MENU, self.onAbout, id=MENU_ABOUT)
        self.Bind(wx.EVT_MENU, self.onExit, id=MENU_EXIT)
        self.Bind(wx.EVT_CLOSE, self.onExit)

        pp = self.plotpanel
        self.Bind(wx.EVT_MENU, pp.configure, id=MENU_CONFIG)
        self.Bind(wx.EVT_MENU, pp.unzoom_all, id=MENU_UNZOOM)
        self.Bind(wx.EVT_MENU, pp.save_figure, id=MENU_SAVE_IMG)
        self.Bind(wx.EVT_MENU, pp.Print, id=MENU_PRINT)
        self.Bind(wx.EVT_MENU, pp.PrintSetup, id=MENU_PSETUP)
        self.Bind(wx.EVT_MENU, pp.PrintPreview, id=MENU_PREVIEW)
        self.Bind(wx.EVT_MENU, pp.canvas.Copy_to_Clipboard, id=MENU_CLIPB)

    def onTraceColor(self, trace, color, **kws):
        irow = self.get_current_traces()[trace][0] - 1
        self.colorsels[irow].SetColour(color)

    @DelayedEpicsCallback
    def onMCAData(self, pvname=None, value=None, timestamp=None, **kw):
        if timestamp is None:
            timestamp = time.time()
        print 'onMCA DATA!! ', len(value), value.sum(), timestamp
        self.mca_data = value[:]
        self.needs_refresh = True

    def onAbout(self, event=None):
        dlg = wx.MessageDialog(self, self.about_msg, "About Epics MCA Display",
                               wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def onHelp(self, event=None):
        dlg = wx.MessageDialog(self, self.help_msg, "Epics MCA Display Help",
                               wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def onExit(self, event=None):
        try:
            self.plotpanel.win_config.Close(True)
            self.plotpanel.win_config.Destroy()
        except:
            pass

        self.Destroy()

    def get_current_traces(self):
        "return list of current traces"
        traces = []  # to be shown
        for irow, s in enumerate(self.pvchoices):
            if s is not None:
                ix = s.GetSelection()
                if ix > 0:
                    name = self.pvlist[ix]
                    logs = 1 == self.pvwids[irow][0].GetSelection()
                    color = self.pvwids[irow][1].GetColour()
                    ymin = get_bound(self.pvwids[irow][2].GetValue())
                    ymax = get_bound(self.pvwids[irow][3].GetValue())
                    traces.append((irow, name, logs, color, ymin, ymax))
        return traces

    def onUpdatePlot(self, event=None):
        if self.paused or not self.needs_refresh:
            return

        if (len(self.mca_data) < 1
                or self.mca_data.sum() == self.mca_data_sum):
            return
        self.mca_data_sum = self.mca_data.sum()
        ppanel = self.plotpanel
        did_update = False

        if self.mca_en is None:  # first plot!
            self.mca_en = np.arange(len(self.mca_data))
            ppanel.plot(self.mca_en * 1.0,
                        1.0 * self.mca_data,
                        xmax=self.mca_en.max(),
                        ylog_scale=True,
                        autoscale=True)
            did_update = True
        else:
            try:
                ppanel.update_line(0,
                                   self.mca_en,
                                   self.mca_data,
                                   draw=False,
                                   update_limits=False)
                # self.plotpanel.plot(tdat, ydat, draw=False, update_limits=True)
                # self.plotpanel.set_xylims((self.tmin, 0, ymin, ymax),
                #                          side=side, autoscale=False)
                did_update = True
            except:
                pass

        if did_update:
            self.plotpanel.canvas.draw()
        self.needs_refresh = not did_update
        return