#Macros for ccdserver spec (quartz?) #=============================================================================== # Modified by: Xuesong Jiao July 05,2005 # # # Modification history: # (as 06/24/2005) -> (1) modified the ccd_series to add the feature to synchron # -ize with the delay generator if one is used. added # ccd_arm, shutter_delay,delay_trig set_delay accordingly. # (2) modified the ccdserver_setup so it always read the # CCD_MODE in short. # (3) added a global variable CCD_THROW, if CCD_THROW not zero # ccd_series will throw first numberof CCD_THROW frames # without saving them. It works for the situation # with and without the delay generator. # (as 07/05/2005) -> (1) changed set_delay so it takes seconds not milliseconds. # ccdbatch in the template do file also changed accordinly. # (2) defined a global variable pvDELAY_CTL to replace the # explicit use of pv 8idi:UnidigBo15.VAL. # (3) Modified the macros for ccd wait and ccd trigger in order # to use the new PV "FrameBuffer" in the new(2.5) version # of the Image Server Program. This will reduce the overhead # during checking the new image. #(as 03/07/2006) -> (1) added pseudo initialize for external trigger mode to make # sure catch the first trigger # # #(as 10/10/2006) -> (1) After 8idi changes it external trigger mode to use hardware handshaking # the ccd trig and wait are the same as the free run mode. This simplifies # the macros siginficantly. Now the same ccdtrig and ccdwait are used no # matter what trigger mode is use. # (2) Defined new ccdtrig_4.0 and ccdwait_4.0 with ImageLeft PVs. # ccdtrig and ccdwait are defined with them. If one wants go back use the # old ccdtrig_fb etc. just def ccdtrig with ccdtrig_fb. # # # #=============================================================================== #### macros for Brian Tieman's CCD Sever by epics ############################## #### ccd control macros list in this file: ############################## #### ccdserversetup #### ccd_trig #### ccd_save #### ccd_wait and ccd_wait_nosleep #### ccd_newfile #### ccd_series #### add_batch_par #### #### other related macros: movesample #### movesamth #### takeflux #### enscript #### ################################################################################ def ccdlive 'ccd_live' def ccdnewfile 'ccd_newfile' def ccdseries 'ccd_series' def ccdsetup 'ccdserver_setup' #####global variables ########################################################## global CCDID global MON_ROI SAVED_ROI global CCD_SPEED CCD_PRESET global XBIN global YBIN global CCD_MODE CCD_KINWINSIZE CCD_SLICETOP global CCD_CHILD_DIR CCD_PARENT_DIR CCD_FILENAME CCD_PREFIX CCD_SUFFIX CCD_N global CCD_SLEEP global INFO_DIR SAMBA_MAP global MULTI_IMGS MULTI_FILENAME global CCD_FBN CCD_TARGET_N global NOSHUTTER _opentime_Reg _closetime_Reg WRITE_LOCAL ################################################################################# #=============================================================================== # global varibales for the delay generator settings #=============================================================================== global USE_DELAY SHUTTER_OPEN_TIME SHUTTER_CLOSE_TIME SHUTTER_TIME CCD_THROW global pvDELAY_CTL _opentime_Reg = "8idi:Reg6" _closetime_Reg = "8idi:Reg7" #SAMBA_MAP["win_dir"]="F:\\data\\" #SAMBA_MAP["lin_dir"]="/mnt/smb/" SAMBA_MAP["win_dir"]="Z:\\" SAMBA_MAP["lin_dir"]="/home/8-idi-d/" CCDID="08IDI:PIDD1" SAVED_ROI=CCDID ".R01" def ccdserver_setup '{ CCDID=getval("The EPICs prefix of the CCD device:",CCDID) p "Version:" epics_get(sprintf("%s.ProgramVersion",CCDID)) p "CCDManufacturer:" epics_get(sprintf("%s.CCDManufacturer",CCDID)) p "CCDModel:" epics_get(sprintf("%s.CCDModel",CCDID)) p "CCDChip Temperature:" epics_get(sprintf("%s.MeasuredTemp",CCDID)) "C" smb_map fileformat #Modified by Suresh to get short value while( epics_get(sprintf("%s.Idle",CCDID),"short")==0) { p "ccd not ready, wait...." sleep(0.1) } CCD_SPEED= getval("ADC Speed 0 (slow), 1 (fast):",epics_get(sprintf("%s.ADC",CCDID))) XBIN=getval("BinX=",epics_get(sprintf("%s.BinX",CCDID))) YBIN=getval("BinY=",epics_get(sprintf("%s.BinY",CCDID))) CCD_MODE=getval("Use Full Frame (0) or Kinetics Mode(3):", epics_get(sprintf("%s.CameraMode",CCDID),"short")) #reset camera general PVs epics_put(sprintf("%s.ADC",CCDID),CCD_SPEED) epics_put(sprintf("%s.BinX",CCDID),XBIN) epics_put(sprintf("%s.BinY",CCDID),YBIN) epics_put(sprintf("%s.CameraMode",CCDID),CCD_MODE) if(CCD_MODE==3) { CCD_KINWINSIZE = getval("Kinetics WindowSize:",CCD_KINWINSIZE) CCD_SLICETOP = getval("Slice top:",CCD_SLICETOP) epics_put(sprintf("%s.KinStripSize",CCDID),CCD_KINWINSIZE) } SAVED_ROI=CCDID "." getval("Saved ROI# (1-50) i.e R35:","R01") set_roi SAVED_ROI p CCDID "reset done" }' def fileformat '{ local parms if($#==0){ MULTI_IMGS=getval("Multiple Images per File 0(off) 1(on)?",epics_get(sprintf("%s.MultiImgFiles",CCDID))) epics_put(sprintf("%s.MultiImgFiles",CCDID),MULTI_IMGS) } if($#==1) { parms=$1 if(parms >1){ p "Usage fileformat 0/1" exit } MULTI_IMGS=parms epics_put(sprintf("%s.MultiImgFiles",CCDID),MULTI_IMGS) if(parms==1) { p "\nMultiple images _will be_ written to _a single_ file\n" } if(parms==0) { p "\nMultiple images _will be_ written to _separate_ files\n" } } }' def set_roi '{ local vstart,hstart,vlength,hlength if($#<1) { p "Usage:set_roi ROI( i.e. TST:ccd.R01) or set_roi ROI vstart vlength hstart hlength" exit } if($#==5) { vstart=$2 vlength=$3 hstart=$4 hlength=$5 } else { p "Set up dimensions for " "$1" vstart=getval(sprintf("%s row_beg:",ROI),epics_get(sprintf("%s.VStart",$1))) vlength=getval(sprintf("%s number of rows:",ROI),epics_get(sprintf("%s.VLength",$1))) hstart=getval(sprintf("%s col_beg:",ROI),epics_get(sprintf("%s.HStart",$1))) hlength=getval(sprintf("%s number of cols:",ROI),epics_get(sprintf("%s.HLength",$1))) } epics_put(sprintf("%s.Use",$1),1) epics_put(sprintf("%s.UseCalcs",$1),1) epics_put(sprintf("%s.Save",$1),0) epics_put(sprintf("%s.VStart",$1),vstart) epics_put(sprintf("%s.HStart",$1),hstart) epics_put(sprintf("%s.VLength",$1),vlength) epics_put(sprintf("%s.HLength",$1),hlength) sleep(1.0) }' def smb_map '{ SAMBA_MAP["win_dir"]=getval("Input the samba share directory in windows format(i.e. ):",SAMBA_MAP["win_dir"]) SAMBA_MAP["lin_dir"]=getval("Input the samba share directory mounted in linux:",SAMBA_MAP["lin_dir"] ) p "data_dir in windows set to " SAMBA_MAP["win_dir"] p "data_dir in linux set to " SAMBA_MAP["lin_dir"] }' def to_win_dir(lin_path) '{ local n str1,str_array,field, win_path,i n=length(SAMBA_MAP["lin_dir"]) str1=substr(lin_path,n+1); n=split(str1,str_array,"/") ; win_path=SAMBA_MAP["win_dir"] for(i=0;i %s",file_path,tmpfile)) if((line=getline(tmpfile))!=-1 ) { printf("Directory: %s is not empty. May overwrite existed file!",file_path) ow=1 sn=epics_get(sprintf("%s.SeqNumber",CCDID)) printf("Start at current Sequence Number %d",sn) } getline(tmpfile,"close") unix(sprintf("/bin/rm -f %s",tmpfile)) epics_put(sprintf("%s.FileTemplate",CCDID),sprintf("%s_\$#.imm",CCD_FILENAME)) epics_put(sprintf("%s.SeqNumber",CCDID),sn) sleep(1.0) CCD_N=epics_get(sprintf("%s.SeqNumber",CCDID)) } }' def newmultifile'{ local nstart,nend if($#!=1) { p "Usage newmultifile #ofimages" exit } nstart=epics_get(sprintf("%s.SeqNumber",CCDID)) nend=nstart+$1-1 MULTI_FILENAME=sprintf("%s_%05d-%05d.imm",CCD_FILENAME,nstart,nend) epics_put(sprintf("%s.FileTemplate",CCDID),MULTI_FILENAME) printf("Create multiple images file: %s",MULTI_FILENAME) }' def closemultifile '{ epics_put(sprintf("%s.CloseMultiImgFile",CCDID),1) printf("\nMultiImage file %s closed.\n",MULTI_FILENAME) MULTIFILENAME="dummy" }' def ccd_series '{ local exposure repeats s if($# !=2) { eprint "Usage: ccd_series repeats exposuretime(in seconds)" exit } rdef cleanup \' undef cleanup epics_put(sprintf("%s.Abort",CCDID),1) epics_put(sprintf("%s.Save",SAVED_ROI),0) closemultifile if(CCD_N>series_pars["ndata0"]) { set_more_series_pars writeinfo series_pars } batch_cleanup; \' repeats=$1 exposure=$2 #set_delay is added to ccd_series so that ccd_series from spec #command line will set the right exposure time (Suresh, Sep. 2006) set_delay exposure if (repeats >=1) { CCD_PRESET=exposure epics_put(sprintf("%s.FocusMode",CCDID),0) # to solve some rounding errors in image_server epics_put(sprintf("%s.Minutes",CCDID),int(exposure/60)) epics_put(sprintf("%s.Seconds",CCDID),int(exposure)%60) epics_put(sprintf("%s.Milliseconds",CCDID),int((exposure-int(exposure))*1000)) if(CCD_THROW) { printf("\nThrowing Frames ...\n") ccdtrig CCD_THROW ccdwait; } epics_put(sprintf("%s.Save",SAVED_ROI),1) CCD_N=epics_get(sprintf("%s.SeqNumber",CCDID)) sleep(0.1); set_series_pars; d0=date(); if(CCD_SLEEP==0) { printf("\nStarting Real Acquisition ...\n\n"); ccdtrig repeats; ccdwait ; } else { printf("\nStarting Real Acquisition ...\n\n"); for(s=0; s4) ? $5 : 1 if(SHORTFILE != "/dev/null") { open(SHORTFILE); open(OUTFILE); on(OUTFILE) } print "" #xccdnewfile CCD_PREFIX CCD_SUFFIX firstframe fprintf(SHORTFILE,"\n\n%s%g ms data%s\t%s\n",ENSCRIPT_CTL,\ xtime*1000,ENSCRIPT_CTL_END,date()) }' def takedata '{ rdef batch_cleanup \' { emptydef batch_cleanup finish_data gateoff; } \' epics_put("8idi:scaler1.TP",$2) epics_put("8idi:scaler1.TP1",$2) gateon; printf("\nMoving bstop to %g\n",bstopdata) umv bstop bstopdata; waitmove CCD_N = epics_get(sprintf("%s.SeqNumber",CCDID)); printf("\nDATA %d - %d (%d) \t%g msec exposures\n",CCD_N,CCD_N-1+$1,$1,$2*1000) showbeam;waitmove ccd_series $1 $2 finish_data gateoff; emptydef batch_cleanup }' def finish_data '{ blockbeam; waitmove # do nothing unless ccdseries got somewhere if (exists("series_pars","ndataend")) { if (!exists("batch_pars","ndataend") && \ !exists("batch_pars","ndarkend")) { # no data or dark has been taken yet, # copy all parameters for (field in series_pars) batch_pars[field] = series_pars[field] batch_pars["nbatch0"] = series_pars["ndata0"] } else { # update only a few specific parameters add_batch_par samx series_pars["samx"] add_batch_par samz series_pars["samz"] add_batch_par samth series_pars["samth"] add_batch_par ring_i_beg series_pars["ring_i_beg"] add_batch_par ring_i_end series_pars["ring_i_end"] add_batch_par ring_i series_pars["ring_i"] add_batch_par start_time series_pars["start_time"] add_batch_par end_time series_pars["end_time"] add_batch_par ndata0 series_pars["ndata0"] add_batch_par ndataend series_pars["ndataend"] add_batch_par preset series_pars["preset"] } batch_pars["nbatchend"] = series_pars["ndataend"] fprintf(SHORTFILE,"\t%sDATA %4d - %4d (%d)%s\t",ENSCRIPT_CTL,\ series_pars["ndata0"],series_pars["ndataend"],\ series_pars["ndataend"]-series_pars["ndata0"]+1,\ ENSCRIPT_CTL_END) fprintf(SHORTFILE,"%s - %s\t%5.2f mA - %5.2f mA\n",\ tod(series_pars["start_time"]),tod(series_pars["end_time"]),\ series_pars["ring_i_beg"],series_pars["ring_i_end"]) } }' def takedark '{ rdef batch_cleanup \'{ emptydef batch_cleanup finish_dark gateoff; }\' epics_put("8idi:scaler1.TP",$2) epics_put("8idi:scaler1.TP1",$2) gateon; CCD_N = epics_get(sprintf("%s.SeqNumber",CCDID)); printf("\ndark %d - %d (%d)\t%g msec exposures\n",\ CCD_N,CCD_N-1+$1,$1,$2*1000) blockbeam; waitmove ccd_series $1 $2 finish_dark gateoff; emptydef batch_cleanup }' def finish_dark '{ local field # do nothing unless ccdseries got somewhere if (exists("series_pars","ndataend")) { if (!exists("batch_pars","ndataend") && \ !exists("batch_pars","ndarkend")) { # no data or dark has been taken yet, # copy all parameters and then remove a few for (field in series_pars) batch_pars[field] = series_pars[field] delete batch_pars["samx"] delete batch_pars["samz"] delete batch_pars["samth"] delete batch_pars["ring_i_beg"] delete batch_pars["ring_i_end"] delete batch_pars["ring_i"] delete batch_pars["start_time"] delete batch_pars["end_time"] delete batch_pars["ndata0"] delete batch_pars["ndataend"] delete batch_pars["preset"] batch_pars["nbatch0"] = series_pars["ndata0"] } # update a few specific parameters add_batch_par dark_start_time series_pars["start_time"] add_batch_par dark_end_time series_pars["end_time"] add_batch_par ndark0 series_pars["ndata0"] add_batch_par ndarkend series_pars["ndataend"] add_batch_par dark_preset series_pars["preset"] batch_pars["nbatchend"] = series_pars["ndataend"] fprintf(SHORTFILE,"\t%sdark %4d - %4d (%d)%s\t",ENSCRIPT_CTL,\ series_pars["ndata0"],series_pars["ndataend"],\ series_pars["ndataend"]-series_pars["ndata0"]+1,\ ENSCRIPT_CTL_END) fprintf(SHORTFILE,"%s - %s\n",tod(series_pars["start_time"]),\ tod(series_pars["end_time"])) } }' def add_batch_par '{ # note: $2 must be a variable name local field varid field = \'$1\' varid = whatis(\'$2\') # if the variable $2 exists at all . . . if (varid && varid != 137363460) { if (!exists("batch_pars",field)) batch_pars[field] = $2 else batch_pars[field] = grow(batch_pars[field],$2) } }' def start_set '{ global batch_pars ENSCRIPT_CTL ENSCRIPT_CTL_END nextpos SHORTFILE OUTFILE if (batch_name == "") { print "ccd_batch: Please define the variable batch_name in the .Do file." exit } if (index(batch_name,"\\")) { print "ccd_batch: Please do not use \ characters in batch_name." exit } ccd_newfile data_dir batch_name CCD_SUFFIX = ".imm" if (log_dir != "") { makedir log_dir SHORTFILE = trailslash(log_dir) batch_name ".short" OUTFILE = trailslash(log_dir) batch_name ".out" print "\nWriting short log to " SHORTFILE } else OUTFILE = SHORTFILE = "/dev/null" # for no enscript tricks, set ENSCRIPT_CTL = ENSCRIPT_CTL_END = "" # otherwise, make sure the first character will not appear anywhere # in the file to be printed (e.g. @ or %) ENSCRIPT_CTL = "@font{Courier-Bold9}" ENSCRIPT_CTL_END = "@font{default}" empty_array batch_pars }' def finish_set '{ # if any data has been taken, make a .batchinfo file if (exists("batch_pars","ndataend")) { writebatchinfo batch_pars } off(OUTFILE); close(OUTFILE); close(SHORTFILE) # print out short log file enscript SHORTFILE garnet #enscript SHORTFILE graphite # enscript SHORTFILE chalk # right now enscript and quartz do not get along printf("\ndisabling counter gating\n"); gateoff; }' def writebatchinfo '{ local field format info_name INFOFILE bp bp = $1 info_name = sprintf("%s%04d-%04d%s",bp["name"],bp["nbatch0"],\ bp["nbatchend"],".batchinfo") INFOFILE = CCD_PARENT_DIR CCD_CHILD_DIR info_name if(WRITE_LOCAL) { tmp = CCD_PARENT_DIR CCD_CHILD_DIR makedir tmp } # delete some parameters that are for internal use only delete bp["nbatch0"] delete bp["nbatchend"] delete bp["norm_vac_flux"] # add " " around strings bp["parent"] = inquotes(bp["parent"]) bp["child"] = inquotes(bp["child"]) bp["name"] = inquotes(bp["name"]) bp["info_name"] = inquotes(info_name) print "\nWriting batch parameters to " INFOFILE open(INFOFILE) format = "%15s = %s\n" for (field in bp) fprintf(INFOFILE,format,field,bp[field]) # make sure these go at the end of the file if (exists("$1","ndarkend")) fprintf(INFOFILE,format,"ndark","ndarkend - ndark0 + 1") if (exists("$1","ndataend")) fprintf(INFOFILE,format,"ndata","ndataend - ndata0 + 1") close(INFOFILE) fprintf(SHORTFILE,"\nbatch parameters in %s\n\n",INFOFILE) }' def writeinfo '{ local field format info_name INFOFILE sp tmp sp = $1 info_name = sprintf("%s%05d-%05d%s", sp["name"], sp["ndata0"],\ sp["ndataend"],".info") INFOFILE = CCD_PARENT_DIR CCD_CHILD_DIR info_name if(WRITE_LOCAL) { tmp = CCD_PARENT_DIR CCD_CHILD_DIR makedir tmp } sp["parent"] = inquotes(sp["parent"]) sp["child"] = inquotes(sp["child"]) sp["name"] = inquotes(sp["name"]) sp["info_name"] = inquotes(info_name) print "Writing series parameters to " INFOFILE open(INFOFILE) format = "%15s = %s\n" for (field in sp) fprintf(INFOFILE,"%15s = %s\n",field,sp[field]) # make sure this goes at the end of the file if (exists("$1","ndataend")) fprintf(INFOFILE,format,"ndata","ndataend - ndata0 + 1") close(INFOFILE) }' ############################################################################################################## #### other macros for ccd_batch ############################################################################################################## def movesample '{ local xi zi xi = nextpos % array_op("cols", samxdata) zi = nextpos % array_op("cols", samzdata) printf("\nMoving samx to %g, samz to %g\n",samxdata[xi],samzdata[zi]) umv samx samxdata[xi]; umv samz samzdata[zi] waitmove fprintf(SHORTFILE,"\nAt samx = %g, samz = %g, ccdx = %g, ccdz = %g, T_%s = %g:\n",A[samx],A[samz], A[ccdx],\ A[ccdz], epics_get("8idi:LS331:TC1:CtlInput.SVAL"), epics_get("8idi:LS331:TC1:Control")); nextpos++ }' def movesamth '{ # designed to run AFTER movesample local thi thi = (nextpos-1) % array_op("cols", samthdata) printf("Moving samth to %g\n", samthdata[thi]) umv samth samthdata[thi] waitmove fprintf(SHORTFILE,"At samth = %g:\n",A[samth]) }' def movesamth0 '{ # designed to run AFTER movesample local thi thi = (nextpos-1) % array_op("cols", samthdata0) printf("Moving samth to %g\n", samthdata0[thi]) umv samth samthdata[thi] waitmove }' def enscript '{ local enscriptcmd if ($# < 1) { print "Usage: enscript filename_variable [printer]" exit } enscriptcmd = "enscript -h -f Courier8" if (ENSCRIPT_CTL != "") enscriptcmd = enscriptcmd " -e" substr(ENSCRIPT_CTL,1,1) if ($# > 1) enscriptcmd = enscriptcmd " -P " "$2" enscriptcmd = enscriptcmd " " $1 print "Running " enscriptcmd if ($1 != "/dev/null") unix(enscriptcmd) # Note that enscript syntax is: # print "enscript -h -f Courier8 --escapes=@ -P garnet " # print "enscript -h -f Courier8 --escapes=@ -P graphite " }' def emptydef 'rdef $1 \'\'' def trailslash(dirname) '{ if (dirname == "." || dirname == "./" || dirname == 0) return("") else if (dirname == "" || substr(dirname,length(dirname))=="/") return(dirname) else return(sprintf("%s/",dirname)) }' def makedir '{ # takes a string or a variable of type string if (unix(sprintf("test -d %s",$1))) { if (unix(sprintf("mkdir -p %s",$1))) exit else printf("Created directory %s.\n",$1) } else if (unix(sprintf("test -w %s",$1))) { printf("Cannot write to directory %s: Permission denied.\n",$1) exit } }' def grow(a,b) '{ # takes 2 strings and returns a string in # the form of a yorick-syntax array; # if the first variable is already a # yorick-syntax array string, appends the # second element to it if (substr(a,1,1) != "[") return( sprintf("[%s,%s]",a,b) ) else return( sprintf("%s,%s]",substr(a,1,length(a)-1),b) ) }' def tod(timestr) '{ if (substr(timestr,1,1)=="\"") return(substr(timestr,13,8)) else return(substr(timestr,12,8)) }' def span '{ if ($# < 4) { print "Usage: span variable min max #points" exit } local npts npts = int($4) array $1[npts] # if npts == 1 use min if (npts == 1) $1[0] = 0 else array_op("fill",$1,($3-($2))/(npts-1)) $1 += $2 }' ###########################control macros for older version Image_server########################## #------------------------------------------------------------------------------- # internal macros for older version of Image_server (<4.0) #------------------------------------------------------------------------------- def ccdwait_2_6 ' { local fbn save_true sn save_true = epics_get(sprintf("%s.Save",SAVED_ROI),"short") while( (fbn=epics_get(sprintf("%s.FrameBuffer",CCDID))) < CCD_TARGET_N) { if(fbn != CCD_FBN ) { CCD_FBN = fbn; if(save_true) { sn = epics_get(sprintf("%s.SeqNumber",CCDID))-1 _ccd_save sn } } #########need to get rid of this sleep sleep(0.005); } }' def ccdtrig_2_6 ' { local x if( $# == 0) x = 1; else x = $1 if(x < 1) { eprint "Usage: Number of Exposures can not be less than 1" exit } epics_put(sprintf("%s.NumExposures",CCDID),x); if( (epics_get(sprintf("%s.FrameBuffer",CCDID))+x )>999999999 ) { # upper limit of framebuffer PV epics_put(sprintf("%s.FrameBuffer",CCDID),0) while(epics_get(sprintf("%s.FrameBuffer",CCDID)) !=0) sleep(0.2); } CCD_TARGET_N = epics_get(sprintf("%s.FrameBuffer",CCDID)) + x epics_put(sprintf("%s.AcquirePOLL",CCDID),1); }'