#!/bin/env python # # start_daq - starts DAQ based on existing COOL DB # # DL, 07-Mar-2014 # DL, 23-Apr-2014 significant revisions # # # Usage: # start_daq [coda_configuration] # # If the "coda_configuration" option is omitted, # then a list of available configurations is given. # # # This uses gnome-terminal to open windows and # run commands launching all CODA components needed # for a given COOL configuration. It is used # instead of xterm because there were some issues # with interacting with the xterms via VNC that # made them problematic. # # For this to work best, gnome-terminal should # have profiles defined named the following: # # platform # ROC # EB # FCS # ER # rcgui # # Each of these should have the "When command exits:" # menu set to "Hold the terminal open". This is done # via the "Title and Command" tab in the dialog window # used for editing profile preferences. # # The font size (also specified via dialog window) # should be set to: # "Monospace 9" for the platform profile # "Courier 6" for the ROC profile # "Monospace 8" for the EB, FCS, ER and rcgui profiles # # In addition, the colors for each profile can be set # to something different to give visual clues as to what # they host. For example: # # platform dark green # ROC light grey # EB yellow # FCS dark blue # ER dark purple # rcgui light purple # # import sys,os import subprocess import string import time import math import re COOL_HOME = os.getenv("COOL_HOME") EXPID = os.getenv("EXPID") DAQ_HOME = os.getenv("DAQ_HOME") CONFIG = "" if len(sys.argv) > 1 : CONFIG = sys.argv[1] screenwidth = 0 screenheight = 0 rocs = [] # will be filled by GetComponents ts = [] # will be filled by GetComponents dcs = [] # will be filled by GetComponents pebs = [] # will be filled by GetComponents sebs = [] # will be filled by GetComponents ers = [] # will be filled by GetComponents fcss = [] # will be filled by GetComponents files = [] # will be filled by GetComponents hosts = {} # will be filled by GetHosts testmode = False # if set to True, then no windows will be opened. Just commands printed. #------------------ # GetScreenSize #------------------ def GetScreenSize(): global screenwidth, screenheight result = subprocess.Popen(["xwininfo", "-root", "-shape"], stdout=subprocess.PIPE).communicate()[0] lines = result.rstrip().split('\n') for s in lines: if type(s) is not str: continue if "Width:" in s: screenwidth = int(string.split(s)[1]) if "Height:" in s: screenheight = int(string.split(s)[1]) #------------------ # GetWindowID #------------------ def GetWindowID(name): # Odd behavior on VNC is that specifying the name can sometimes fail # even though it still knows the window and can give the info if we # identify it by id. I believe this can be fixed by restarting the # X-server, but that seems a bit extreme. Instead, we try and get the # id from the list of children of the root window. proc = subprocess.Popen(["xwininfo", "-root", "-tree"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) result = proc.communicate()[0] if proc.returncode == 0: lines = result.rstrip().split('\n') for line in lines: words = line.rstrip().split() if '"%s":' % name in words: id = words[0] return id return 0 #------------------ # GetWindowDimensions #------------------ def GetWindowDimensions(name, wait=False): width = 0 height = 0 if wait : sys.stdout.write("Waiting for window %s to open " % (name)) while True: sys.stdout.write('.') id = GetWindowID(name) if id != 0: print '' proc = subprocess.Popen(["xwininfo", "-id", str(id), "-shape"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) result = proc.communicate()[0] if proc.returncode == 0: lines = result.rstrip().split('\n') for s in lines: if type(s) is not str: continue if "Width:" in s: width = int(string.split(s)[1]) if "Height:" in s: height = int(string.split(s)[1]) return [width, height] if wait==False: return [] time.sleep(1) #------------------ # FindExecutable #------------------ def FindExecutable(exename, args=[]): try: proc = subprocess.Popen(["which", exename], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) result = proc.communicate()[0].strip() if proc.returncode == 0: for arg in args: result += " " + arg return result except: print sys.exc_info()[0] return "" #------------------ # LaunchComponent #------------------ def LaunchComponent(profile, component, xpos, ypos, command, lines=10, columns=100): global hosts # If host was specified in hosts file, use it. Otherwise run locally host = "" # empty string means run locally envsetup = "" # don't setup environment if running locally if component in hosts: host = hosts[component] envsetup = 'source ${DAQ_HOME}/../work/online_setup.cshrc && ' # create command to open gnome-terminal title = component if host!="" and host!=component : title += "-%s" % host cmd = string.split('gnome-terminal --geometry %dx%d+%d+%d --profile=%s -t %s -x' % (columns, lines, xpos, ypos, profile, title) ) # create component command componentcmd = '%s%s' % (envsetup, command) # If using ssh to go to remote host, make the command # run by the gnome-terminal be ssh with the remote command # passed as a single string if host!="" : cmd.extend(['ssh', host]) cmd.append(componentcmd) else : # running locally, we should split the command and arguments cmd.extend(componentcmd.split()) # write command to stdout and then run it for s in cmd: sys.stdout.write(s+' ') sys.stdout.write('\n') if not testmode : subprocess.Popen(cmd) return title #------------------ # GetConfigurations #------------------ def GetConfigurations(): confdir = "%s/%s/config/Control" % (COOL_HOME, EXPID) if os.path.exists(confdir): configs = os.listdir(confdir) configs = [x for x in configs if x != '.svn'] return configs else: print "Directory doesn't exist: %s" % confdir print "Check your COOL_HOME and EXPID environment variables!" sys.exit(-1) #------------------ # GetComponents #------------------ def GetComponents(): global rocs, ts, pebs, sebs,ers, fcss, files configdir = "%s/%s/config/Control/%s" % (COOL_HOME, EXPID, CONFIG) fname = "%s/%s.rdf" % (configdir, CONFIG) with open(fname) as f: lines = f.readlines() for line in lines: idx_end = string.rfind(line, '.rdf"/>') if idx_end < 2: continue idx_start = string.rfind(line[0:idx_end], '/') if idx_start < 2: continue cname = line[idx_start+1:idx_end] # Read in specific component file and get type if 'hasType>ROC<' in open('%s/Components/%s.rdf' % (configdir, cname)).read(): rocs.append(cname) if 'hasType>TS<' in open('%s/Components/%s.rdf' % (configdir, cname)).read(): ts.append(cname) if 'hasType>DC<' in open('%s/Components/%s.rdf' % (configdir, cname)).read(): dcs.append(cname) if 'hasType>PEB<' in open('%s/Components/%s.rdf' % (configdir, cname)).read(): pebs.append(cname) if 'hasType>SEB<' in open('%s/Components/%s.rdf' % (configdir, cname)).read(): sebs.append(cname) if 'hasType>ER<' in open('%s/Components/%s.rdf' % (configdir, cname)).read(): ers.append(cname) if 'hasType>FCS<' in open('%s/Components/%s.rdf' % (configdir, cname)).read(): fcss.append(cname) if 'hasType>FILE<' in open('%s/Components/%s.rdf' % (configdir, cname)).read(): files.append(cname) if string.find(cname, "localhost" ) == 0: rocs.append(cname) # for running sandbox test #------------------ # GetHosts #------------------ def GetHosts(): global hosts, rocs, ts # Add all rocs and TS's for roc in rocs : hosts[roc] = roc for roc in ts : hosts[roc] = roc if DAQ_HOME==None: print 'DAQ_HOME not set. All non-ROC hosts will be run locally' return hostsfile = '%s/config/coda/hosts' % DAQ_HOME if not os.path.exists(hostsfile): print 'File %s does not exist. All non-ROC hosts will be run locally' % hostsfile return # Open hosts file and parse it with open(hostsfile) as f: lines = f.readlines() for line in lines: if string.find(line.strip(), '#') == 0 : continue strs = line.strip().split() if len(strs)<2 : continue hosts[strs[0]] = strs[1] #----------------------------------------- # Check that COOL_HOME and EXPID are set if COOL_HOME == None: print "COOL_HOME environment variable not set!" sys.exit(-1) if EXPID == None: print "EXPID environment variable not set!" sys.exit(-1) # Get configuration list configs = GetConfigurations() if not CONFIG in configs: print "\nYou must specify one of the following configurations:\n" for config in configs: sys.stdout.write("%s\n" % config) print "\n" sys.exit(0) # Get the list of ROCs, PEBs, and ERs GetComponents() # Get hosts GetHosts() # Get X-11 screen size GetScreenSize() print "\nX-windows screen size: %d x %d" % (screenwidth,screenheight) print "\n--- Starting all DAQ components ---\n" # Find executables in current PATH platform = FindExecutable('platform') rcgui = FindExecutable('rcgui') coda_dc = FindExecutable('coda_emu_dc64') coda_peb = FindExecutable('coda_emu_peb64') coda_seb = FindExecutable('coda_emu_seb64') coda_er = FindExecutable('coda_emu_er64') coda_fcs = FindExecutable('coda_emu_fcs64') coda_roc = FindExecutable('coda_roc_test') print "CODA executable locations:" print "---------------------------" print " platform: %s" % platform print " rcgui: %s" % rcgui print " coda_dc: %s" % coda_dc print " coda_peb: %s" % coda_peb print " coda_seb: %s" % coda_seb print " coda_er: %s" % coda_er print " coda_fcs: %s" % coda_fcs print " coda_roc: %s" % coda_roc print "" # Print components list print "Components:" print "---------------------------" sys.stdout.write(" TS(%2d): " % len(ts)) print ts sys.stdout.write(" ROC(%2d): " % len(rocs)) print rocs sys.stdout.write(" DC(%2d): " % len(dcs)) print dcs sys.stdout.write(" PEB(%2d): " % len(pebs)) print pebs sys.stdout.write(" SEB(%2d): " % len(sebs)) print sebs sys.stdout.write(" FCS(%2d): " % len(fcss)) print fcss sys.stdout.write(" ER(%2d): " % len(ers)) print ers sys.stdout.write("FILE(%2d): " % len(files)) print files #-------------------------------------------------------- # ----- Launch windows ---- xpos = +1 ypos = 25 title = LaunchComponent('platform', 'platform', xpos, ypos, 'platform', lines=8 ) #cmd = 'gnome-terminal -t platform --geometry 85x15+1+%d --profile=platform -x %s' % (ypos, platform) #print cmd #subprocess.Popen(string.split(cmd)) # wait for the platform window to open so we can # find out how wide it is in pixels dim_platform = GetWindowDimensions(title, True) print "platform: width=%d height=%d" % (dim_platform[0], dim_platform[1]) ypos += dim_platform[1] + 30 # +30 is for frame # Calculate area to use for ROC windows dimROCX = screenwidth - dim_platform[0] dimROCY = screenheight - dim_platform[1] # Launch all DC windows xpos = +1 for dc in dcs: title = LaunchComponent('EB', dc, xpos, ypos, '%s %s' %(coda_dc, dc), lines=8 ) dim_dc = GetWindowDimensions(title, True) ypos += dim_dc[1] + 30 # +30 is for frame # Launch all PEB windows xpos = +1 for peb in pebs: title = LaunchComponent('EB', peb, xpos, ypos, '%s %s' %(coda_peb, peb), lines=8 ) dim_peb = GetWindowDimensions(title, True) ypos += dim_peb[1] + 30 # +30 is for frame # Launch all SEB windows xpos = +1 for seb in sebs: title = LaunchComponent('EB', seb, xpos, ypos, '%s %s' %(coda_seb, seb) ) dim_seb = GetWindowDimensions(title, True) ypos += dim_seb[1] + 30 # +30 is for frame # Launch all FCS windows for fcs in fcss: title = LaunchComponent('FCS', fcs, xpos, ypos, '%s %s' %(coda_fcs, fcs) ) dim_fcs = GetWindowDimensions(title, True) ypos += dim_fcs[1] + 30 # +30 is for frame # Launch all ER windows for er in ers: title = LaunchComponent('ER', er, xpos, ypos, '%s %s' %(coda_er, er) ) dim_er = GetWindowDimensions(title, True) ypos += dim_er[1] + 30 # +30 is for frame # Launch rcgui window (Run Control) title = LaunchComponent('rcgui', 'rcgui', xpos, ypos, rcgui, lines=4) dim_rcgui = GetWindowDimensions(title, True) ypos += dim_rcgui[1] + 30 # +30 is for frame # Launch first ROC window so we can get dimensions xpos = dim_platform[0] + 1 ypos = 25 roc = LaunchComponent('ROC', rocs[0], xpos, ypos, '%s -i -n %s -t ROC' %(coda_roc, rocs[0]), columns=80 ) #roc = LaunchROC(rocs[0], xpos, ypos) dim_roc = GetWindowDimensions(roc, True) dim_roc[0] += 4 # for frame dim_roc[1] += 30 # for frame print "ROC: width=%d height=%d" % (dim_roc[0], dim_roc[1]) # Calculate x and y offsets to lay roc windows # as neatly as possible. # How many rows and columns can we hold without any overlaps maxRows = int(math.floor(dimROCY/dim_roc[1] + 1.0)) maxCols = int(math.floor(dimROCX/dim_roc[0])) xincr = dim_roc[0] yincr = dim_roc[1] yshift = 0 # check if we need to adjust offsets in order to # fit in the screen area reserved for ROCs if maxRows*maxCols < len(rocs): maxCols = int(math.floor(len(rocs)/maxRows+1)) yshift = 25 xincr = int(math.floor((dimROCX-dim_roc[0])/(maxCols-1) + 1.0)) # Report parameters print "dimROCX = %d" % dimROCX print "dimROCY = %d" % dimROCY print "maxRows = %d" % maxRows print "maxCols = %d" % maxCols print " xincr = %d" % xincr print " yincr = %d" % yincr print " yshift = %d" % yshift # Launch remaining ROC windows icol = 0 irow = 1 for roc in rocs[1:]: if irow >= maxRows: irow = 0 icol += 1 xpos = dim_platform[0] + 1 + xincr*icol ypos = 25 + yincr*irow + yshift*icol roc = LaunchComponent('ROC', roc, xpos, ypos, '%s -i -n %s -t ROC' %(coda_roc, roc), columns=80 ) #roc = LaunchROC(roc, xpos, ypos) print " started %s" % roc irow += 1