Author: [log in to unmask] Date: Fri Nov 13 11:11:25 2015 New Revision: 3957 Log: Updated DAQ configuration driver such that it can now load DAQ settings directly from text files containing the EvIO DAQ configuration data banks. Modified: java/trunk/record-util/src/main/java/org/hps/record/daqconfig/DAQConfigDriver.java Modified: java/trunk/record-util/src/main/java/org/hps/record/daqconfig/DAQConfigDriver.java ============================================================================= --- java/trunk/record-util/src/main/java/org/hps/record/daqconfig/DAQConfigDriver.java (original) +++ java/trunk/record-util/src/main/java/org/hps/record/daqconfig/DAQConfigDriver.java Fri Nov 13 11:11:25 2015 @@ -1,16 +1,36 @@ package org.hps.record.daqconfig; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; import java.util.List; import org.lcsim.event.EventHeader; import org.lcsim.util.Driver; /** - * Class <code>DAQConfigDriver</code> is responsible for checking events - * for DAQ configuration settings, and then passing them to the associated + * Class <code>DAQConfigDriver</code> is responsible for accessing the + * DAQ configuration settings, and then passing them to the associated * class <code>ConfigurationManager</code> so that they can be accessed * by other classes.<br/> * <br/> + * The driver may accomplish this by two means. By default, it will + * check each event for an <code>EvioDAQParser</code> object which + * contains all of the DAQ configuration information and pass this to + * the <code>ConfigurationManager</code>. It will continue to update + * the <code>ConfigurationManager</code> during the run if new parser + * objects appear, and can thusly account for changing DAQ conditions. + * <br/><br/> + * The driver may also be set to read a DAQ configuration from text + * files containing the DAQ configuration bank information. To enable + * this mode, the parameter <code>readDataFiles</code> must be set to + * <code>true</code> and the parameters <code>runNumber</code> and also + * <code>filepath</code> must be defined. <code>runNumber</code> defines + * the run number of the configuration to be loaded and the parameter + * <code>filepath</code> defines the location of the data file repository. + * <br/><br/> * This driver must be included in the driver chain if any other drivers * in the chain rely on <code>ConfigurationManager</code>, as it can * not be initialized otherwise. @@ -19,15 +39,88 @@ * @see ConfigurationManager */ public class DAQConfigDriver extends Driver { + private int runNumber = -1; + private String filepath = null; + private boolean firstEvent = true; + private boolean readDataFiles = false; + private File[] dataFiles = new File[3]; + private int[] crateNumber = { 46, 37, 39 }; + + /** + * Verifies the parameter <code>filepath</code> for the data file + * repository and checks that appropriate data files exist for the + * requested run number if the driver is set to read from data files. + * Otherwise, this does nothing. + */ + @Override + public void startOfData() { + // Check whether to use stored data files or the EvIO data stream + // as the source of the DAQ settings. Nothing needs to be done + // in the latter case. + if(readDataFiles) { + // The user must define a data file prefix and repository + // location for this option to be used. + if(filepath == null) { + throw new NullPointerException("DAQ settings repository filepath must be defined."); + } if(runNumber == -1) { + throw new NullPointerException("Run number must be defined."); + } + + // Verify that the repository actually exist. + File repository = new File(filepath); + if(!repository.exists() || !repository.isDirectory()) { + throw new IllegalArgumentException("Repository location \"" + filepath + "\" must be an existing directory."); + } + + // Define the data file objects. + for(int i = 0; i < dataFiles.length; i++) { + try { + dataFiles[i] = new File(repository.getCanonicalPath() + "/" + runNumber + "_" + crateNumber[i] + ".txt"); + } catch(IOException e) { + throw new RuntimeException("Error resolving absolute repository filepath."); + } + } + + // Verify that the data files actually exist. + for(File dataFile : dataFiles) { + if(!dataFile.exists() || !dataFile.canRead()) { + throw new IllegalArgumentException("Data file \"" + dataFile.getName() + "\" does not exist or can not be read."); + } + } + } + } + /** * Checks an event for the DAQ configuration banks and passes them - * to the <code>ConfigurationManager</code>. - * @param - The event to check. + * to the <code>ConfigurationManager</code> if the driver is set to + * read from the EvIO data stream. Otherwise, this will parse the + * data files on the first event and then do nothing. + * @param event - The current LCIO event. */ @Override public void process(EventHeader event) { + // If this is the first event and data files are to be read, + // import the data files and generate the DAQ information. + if(firstEvent && readDataFiles) { + // Get the data files in the form of a data array. + String[][] data; + try { data = getDataFileArrays(dataFiles); } + catch(IOException e) { + throw new RuntimeException("An error occurred when processing the data files."); + } + + // Instantiate an EvIO DAQ parser and feed it the data. + EvioDAQParser daqConfig = new EvioDAQParser(); + for(int i = 0; i < dataFiles.length; i++) { + daqConfig.parse(crateNumber[i], runNumber, data[i]); + } + + // Update the configuration manager. + ConfigurationManager.updateConfiguration(daqConfig); + } + // Check if a trigger configuration bank exists. - if(event.hasCollection(EvioDAQParser.class, "TriggerConfig")) { + if(!readDataFiles && event.hasCollection(EvioDAQParser.class, "TriggerConfig")) { // Get the trigger configuration bank. There should only be // one in the list. List<EvioDAQParser> configList = event.get(EvioDAQParser.class, "TriggerConfig"); @@ -37,5 +130,87 @@ // configuration object. ConfigurationManager.updateConfiguration(daqConfig); } + + // Note that it is no longer the first event. + firstEvent = false; + } + + /** + * Converts DAQ configuration data files into an array of strings + * where each array entry represents a line in the configuration + * file. The first array index of the returned object corresponds + * to the file, and the second array index corresponds to the line. + * @param dataFiles - An array of <code>File</code> objects pointing + * to the data files that are to be converted. These are expected + * to be plain text files. + * @return Returns a two-dimensional array of <code>String</code> + * objects where the first array index corresponds to the object + * of the same index in the <code>File</code> array and the second + * array index corresponds to the lines in the file referenced by + * the <code>File</code> object. + * @throws IOException Occurs if there is an issue with accessing + * or reading the objects in the objects referred to by the files + * pointed to in the <code>dataFiles</code> array. + */ + private static final String[][] getDataFileArrays(File[] dataFiles) throws IOException { + // Create file readers to process the data files. + FileReader[] fr = new FileReader[dataFiles.length]; + BufferedReader[] reader = new BufferedReader[dataFiles.length]; + for(int i = 0; i < dataFiles.length; i++) { + fr[i] = new FileReader(dataFiles[i]); + reader[i] = new BufferedReader(fr[i]); + } + + // Generate String arrays where each entry in the array is + // a line from the data file. + String[][] data = new String[dataFiles.length][0]; + for(int i = 0; i < dataFiles.length; i++) { + // Create a list to hold the raw strings. + List<String> rawData = new ArrayList<String>(); + + // Add each line from the current data file to the list + // as a single entry. + String curLine = null; + while((curLine = reader[i].readLine()) != null) { + rawData.add(curLine); + } + + // Convert the list into a String array. + data[i] = rawData.toArray(new String[rawData.size()]); + } + + // Return the data array. + return data; + } + + /** + * Sets the run number of the DAQ configuration being processed. + * This is only used when reading from data files. + * @param run - The run number of the data files to be used. + */ + public void setRunNumber(int run) { + runNumber = run; + } + + /** + * Sets the location of the DAQ configuration data files. This is + * only used when reading from the data files. + * @param filepath - The file path of the data file repository. + */ + public void setDataFileRepository(String filepath) { + this.filepath = filepath; + } + + /** + * Sets whether or not to read the DAQ configuration directly from + * the EvIO data stream or whether to read the configuration from + * data files. Parameters <code>runNumber</code> and <code>filepath</code> + * must also be defined if this is set to <code>true</code>. + * @param state - <code>true</code> indicates that the configuration + * should be read from data files, and <code>false</code> that it + * should be read from the EvIO stream. + */ + public void setReadDataFiles(boolean state) { + readDataFiles = state; } }