All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
triggerPacketParser.cxx
Go to the documentation of this file.
1 /**
2  * @file icaruscode/Decode/DecoderTools/triggerPacketParser.cxx
3  * @brief Simple parser for trigger raw data packets.
4  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
5  * @date March 4, 2022
6  */
7 
8 // ICARUS libraries
10 
11 
12 // C++/Boost libraries
13 #include "boost/program_options.hpp"
14 #include <iostream>
15 #include <fstream>
16 #include <string>
17 #include <vector>
18 #include <optional>
19 #include <cstdlib> // std::exit()
20 
21 /*
22  * Notable changes here:
23  *
24  * [20220304] (petrillo@slac.stanford.edu) [1.0]
25  * initial version
26  *
27  */
28 static std::string const ProgramVersion = "v1.0";
29 
30 // -----------------------------------------------------------------------------
31 boost::program_options::variables_map parseCommandLine(int argc, char** argv) {
32 
33  namespace po = boost::program_options;
34 
35  //
36  // Declare the supported options.
37  //
38  po::options_description inputopt("Input/output");
39  inputopt.add_options()
40  ("input", po::value<std::vector<std::string>>(), "input file")
41  ;
42 
43  po::options_description genopt("General");
44  genopt.add_options()
45  ("help,?", "print usage instructions and exit")
46  ("version,V", "print usage instructions")
47  ;
48 
49  po::options_description allopt("Options");
50  allopt.add(inputopt).add(genopt);
51 
52  po::positional_options_description pos;
53  pos.add("input", -1); // all positional parameters get option name "input"
54 
55  //
56  // proceed with parsing
57  //
58  po::variables_map optmap;
59  po::store(
60  po::command_line_parser(argc, argv)
61  .options(allopt).positional(pos).run(),
62  optmap
63  );
64  po::notify(optmap);
65 
66  //
67  // deal with general options
68  //
69  std::optional<int> exitWithCode;
70  if (optmap.count("verbose")) {
71  // C++17 (with supporting Clang/GCC): use std::filesystem::path{ argv[0] }.filename()
72  std::cout << argv[0] << " version " << ProgramVersion << std::endl;
73  exitWithCode = 0;
74  }
75  if (optmap.count("help")) {
76  std::cout
77  << "Parses the trigger packet strings from the input file(s) and prints its interpretation."
78  << "\nIf no file is specified in the command line (option or positional argument),"
79  << "\nstrings are read from the standard input stream."
80  << "\n" << allopt
81  << std::endl
82  ;
83  exitWithCode = 0;
84  }
85 
86  if (exitWithCode) std::exit(*exitWithCode);
87  return optmap;
88 
89 } // parseCommandLine()
90 
91 
92 // -----------------------------------------------------------------------------
93 int processTriggerData(std::string const& triggerString) {
94 
95  //
96  // parse
97  //
98 
100 
101  parser.addPatterns({
102  { "Cryo. (EAST|WEST) Connector . and .", 1U }
103  , { "Trigger Type", 1U }
104  });
105 
106  icarus::KeyValuesData parsedData;
107  try {
108  parsedData = parser(triggerString);
109  }
111 
112  std::cerr << "Error parsing trigger data:\n" << std::string(80, '-')
113  << "\n" << triggerString << "\n" << std::string(80, '-')
114  << "Error: " << e.what() << std::endl;
115  return 1;
116 
117  }
118 
119 
120  //
121  // dump
122  //
123 
124  // for this printout, all keys are treated as lists of integers or,
125  // if that conversion fails, vectors of strings;
126  // exceptions are listed here:
127 
128  std::map<std::string, std::vector<std::string>> typeKeys = {
129  {
130  "hex64", {
131  "Cryo1 EAST Connector 0 and 1"
132  , "Cryo1 EAST Connector 2 and 3"
133  , "Cryo2 WEST Connector 0 and 1"
134  , "Cryo2 WEST Connector 2 and 3"
135  }
136  }
137  };
138 
139  // reversed map
140  std::map<std::string, std::string> keyType;
141  for (auto const& [ type, keys ]: typeKeys)
142  for (std::string const& key: keys) keyType[key] = type;
143 
144  std::cout
145  << "Trigger data (" << triggerString.length() << " char):"
146  << "\n" << triggerString
147  << "\nParsed as:";
148  for (icarus::KeyValuesData::Item const& item: parsedData.items()) {
149 
150  std::cout << "\n '" << item.key() << "':";
151 
152  std::string type = keyType.count(item.key())? keyType[item.key()]: "auto";
153  if (type.empty()) type = "auto";
154 
155  if (type == "hex64") {
156 
157  std::vector<std::uint64_t> const& values = item.getVector<std::uint64_t>
159  if (values.empty()) std::cout << " <no number>";
160  else if (values.size() == 1) std::cout << " " << std::hex << values[0];
161  else {
162  auto iValue = values.begin(), vend = values.end();
163  std::cout << " (" << values.size() << " numbers) "
164  << std::hex << *iValue;
165  while (++iValue != vend) std::cout << " , " << *iValue;
166  }
167  std::cout << std::dec << " (" << type << ")";
168  continue;
169  } // hex
170 
171  if (type != "str") {
172 
173  try { // we try `int`
174 
175  std::vector<int> values = item.getVector<int>();
176  if (values.empty()) std::cout << " <no number>";
177  else if (values.size() == 1) std::cout << " " << values[0];
178  else {
179  auto iValue = values.begin(), vend = values.end();
180  std::cout << " (" << values.size() << " numbers) " << *iValue;
181  while (++iValue != vend) std::cout << " , " << *iValue;
182  }
183  std::cout << " (" << type << ")";
184  continue;
185 
186  }
187  catch (icarus::KeyValuesData::Error const& e) { // ... nope
188  if (type == "int") {
189  std::cout << " <error: not int>";
190  }
191  else if (type != "auto") type = "?";
192  }
193  }
194 
195  // as strings, at last
196  std::vector<std::string> const& values = item.values();
197  if (values.empty()) std::cout << " <no value>";
198  else if (values.size() == 1) std::cout << " " << values[0];
199  else {
200  auto iValue = values.begin(), vend = values.end();
201  std::cout << " (" << values.size() << " values) " << *iValue;
202  while (++iValue != vend) std::cout << " , " << *iValue;
203  }
204 
205  std::cout << " (" << type << ")";
206 
207  } // for
208  std::cout << std::endl;
209 
210  return 0; // happy
211 
212 } // processTriggerData()
213 
214 
215 // -----------------------------------------------------------------------------
216 int main(int argc, char** argv) {
217 
218  boost::program_options::variables_map const options
219  = parseCommandLine(argc, argv);
220 
221  std::vector<std::string> inputFilePaths;
222  if (options.count("input"))
223  inputFilePaths = options["input"].as<std::vector<std::string>>();
224  if (inputFilePaths.empty()) inputFilePaths.push_back("");
225 
226  unsigned int nErrors = 0U;
227  unsigned int lineCount = 0U;
228  for (std::string const& inputFilePath: inputFilePaths) {
229 
230  // select and open the input file
231  std::optional<std::ifstream> realInputFile;
232  if (inputFilePath.empty())
233  std::clog << "Reading data from standard input." << std::endl;
234  else {
235  realInputFile.emplace(inputFilePath);
236  if (!realInputFile->good()) {
237  std::cerr << "FATAL: can't open input file '" << inputFilePath << "'."
238  << std::endl;
239  return 2;
240  }
241  std::clog << "Reading data from '" << inputFilePath << "'." << std::endl;
242  }
243  std::istream& inputFile = realInputFile? *realInputFile: std::cin;
244 
245  unsigned int fileLineCount = 0U;
246  std::string line;
247  while (std::getline(inputFile, line)) {
248  ++fileLineCount;
249 
250  if (processTriggerData(line) != 0) ++nErrors;
251 
252  } // while
253 
254  lineCount += fileLineCount;
255 
256 
257  } // for inputFilePaths
258 
259  if (nErrors > 0) {
260  std::cerr << "Parsing failed for " << nErrors << "/" << lineCount
261  << " lines." << std::endl;
262  }
263 
264  return (nErrors == 0)? 0: 1;
265 } // main()
266 
267 
268 // -----------------------------------------------------------------------------
Parser to fill a KeyValuesData structure out of a character buffer.
decltype(auto) items() const noexcept
Returns a forward-iterable list of references to items.
BEGIN_PROLOG could also be cerr
process_name opflash opflashana store
static std::string const ProgramVersion
Simple parser for comma-separated text.
int processTriggerData(std::string const &triggerString)
Representation of a single item of data: a key and several values.
Collection of items with key/values structure.
KeyedCSVparser & addPatterns(std::initializer_list< std::pair< std::regex, unsigned int >> patterns)
Adds known patterns.
then echo echo For and will not be changed by echo further linking echo echo B echo The symbol is in the uninitialized data multiple common symbols may appear with the echo same name If the symbol is defined the common echo symbols are treated as undefined references For more echo details on common see the discussion of warn common echo in *Note Linker options
do i e
boost::program_options::variables_map parseCommandLine(int argc, char **argv)
int main(int argc, char **argv)
BEGIN_PROLOG could also be cout