CFEL - ASG Software Suite  2.5.0
CASS
cass.cpp
Go to the documentation of this file.
1 // Copyright (C) 2009,2010 Jochen Küpper
2 // Copyright (C) 2009-2017 Lutz Foucar
3 
4 /**
5  * @file cass.cpp file contains the main cass program
6  *
7  * @author Lutz Foucar
8  */
9 
10 #include <iostream>
11 #include <signal.h>
12 
13 
14 #include <QtCore/QStringList>
15 #include <QtCore/QCoreApplication>
16 
17 #include "cass.h"
18 #include "cass_version.h"
19 #include "log.h"
20 #include "input_base.h"
21 #include "ratemeter.h"
22 #include "rate_plotter.h"
23 #include "ringbuffer.hpp"
24 //#include "test_input.h"
25 #include "tcpserver.h"
26 #include "processor_manager.h"
27 #include "worker.h"
28 #include "cass_settings.h"
29 #include "cl_parser.hpp"
30 #ifdef OFFLINE
31 #include "multifile_input.h"
32 #include "file_input.h"
33 #else
34 #ifdef LCLSLIBRARY
35 #include "sharedmemory_input.h"
36 #endif
37 #include "tcp_input.h"
38 #endif
39 #ifdef HTTPSERVER
40 #include "httpserver.h"
41 #endif
42 #ifdef SACLADATA
43 #ifdef OFFLINE
44 #include "sacla_offline_input.h"
45 #else
46 #include "sacla_online_input.h"
47 #endif
48 #endif
49 #ifdef HDF5
50 #ifdef OFFLINE
51 #include "hdf5_file_input.h"
52 #include "xfel_hdf5_file_input.h"
53 #endif
54 #endif
55 #ifdef ZEROMQ
56 #include "zmq_input.h"
57 #endif
58 #ifdef XFELLIBRARY
59 #include "xfel_online_input.h"
60 #endif
61 
62 
63 using namespace std;
64 using namespace cass;
65 
66 namespace cass
67 {
68 /** end the input thread
69  *
70  * @param unused unused parameter needed to register this callback as signal
71  * handler
72  *
73  * @author Lutz Foucar
74  */
75 void endInputThread(int /*unused*/)
76 {
77  InputBase::reference().end();
78 }
79 
80 /** set up the own handler to react on the sigquit (crtl+ \\) signal
81  *
82  * @author Lutz Foucar
83  */
85 {
86  struct sigaction quit;
87  quit.sa_handler = endInputThread;
88  sigemptyset(&quit.sa_mask);
89  quit.sa_flags = SA_RESTART;
90 
91  if (sigaction(SIGQUIT, &quit, 0))
92  throw runtime_error("setSignalHandler(): could not set up the quit signal");
93 }
94 }//end namespace cass
95 
96 /** The main program.
97  *
98  * @section clpar CASS Commandline Parameters
99  * - -i filename containing filesnames of xtcfiles to process (offline)
100  * - -m enable multifile input (offline)
101  * - -q quit after finished with all files (offline)
102  * - --hdf5 enable the hdf5 file input module (offline)
103  * - -t enable the tcp input (online)
104  * - -p partition tag for accessing the shared memory (online)
105  * - -c client id for shared memory access (online)
106  * - --noSoap disables the soap server
107  * - -s TCP port of the soap server (offline / online)
108  * - -r suppress the rate output
109  * - -o output filename passed to the Processor (offline / online)
110  * - -f optional complete path to the cass.ini to use (offline / online)
111  * - --sacla Enable sacla input (offline / online)
112  * - -h show this help
113  * - --version display the version of cass
114  *
115  * @author Lutz Foucar
116  */
117 int main(int argc, char **argv)
118 {
119  try
120  {
121  /** construct Qt application object to hold the run loop */
122  QCoreApplication app(argc, argv);
123 
124  /** register used types as Qt meta type */
125  qRegisterMetaType< std::string >("std::string");
126  qRegisterMetaType<cass::ProcessorManager::key_t>("cass::ProcessorManager::key_t");
127  qRegisterMetaType<size_t>("size_t");
128 
129  /** set up details for QSettings and Co.*/
130  QCoreApplication::setOrganizationName("CFEL-ASG");
131  QCoreApplication::setOrganizationDomain("endstation.asg.cfel.de");
132  QCoreApplication::setApplicationName("CASS");
133  QSettings::setDefaultFormat(QSettings::IniFormat);
134 
135  /** create a qsettings object from which one can retrieve the default
136  * cass.ini. After parsing one can then set the CASSSettings default
137  * object to the user requested .ini file or the keep the default .ini
138  * file to use
139  */
140  QSettings settings;
141  settings.sync();
142 
143  /** set up parameters to be retrieved from the command line and parse them
144  * with the help of the command line parser object
145  */
147 #ifdef OFFLINE
148  string filelistname("filesToProcess.txt");
149  parser.add("-i","filename of file containing filesnames of files to process",filelistname);
150  bool multifile(false);
151  parser.add("-m","enable the multifile input",multifile);
152  bool quitwhendone(false);
153  parser.add("-q","quit after finished with all files",quitwhendone);
154 #ifdef HDF5
155  bool hdf5file(false);
156  parser.add("--hdf5","use the special hdf5 file parser",hdf5file);
157  bool xfelhdf5file(false);
158  parser.add("--xfelhdf5","use the xfel hdf5 file parser",xfelhdf5file);
159 #endif
160 #else
161  bool tcp(false);
162  parser.add("-t","enable the tcp input",tcp);
163 #ifdef LCLSLIBRARY
164  string partitionTag("0_1_cass_AMO");
165  parser.add("-p","partition tag for accessing the shared memory",partitionTag);
166  int index(0);
167  parser.add("-c","client id for shared memory access",index);
168 #endif
169 #endif
170  bool noSoap(false);
171  parser.add("--noSoap","Disable the Soap Server",noSoap);
172  int soap_port(12321);
173  parser.add("-s","TCP port of the soap server ",soap_port);
174 // bool useDatagenerator(false);
175 // parser.add("-d","Use generated fake data as input",useDatagenerator);
176  string outputfilename("output.ext");
177  parser.add("-o","output filename passed to the Processor",outputfilename);
178  string settingsfilename(settings.fileName().toStdString());
179  parser.add("-f","complete path to the cass.ini to use",settingsfilename);
180 #ifdef SACLADATA
181  bool sacladata(false);
182  parser.add("--sacla","Enable SACLA Input",sacladata);
183 #endif
184 #ifdef ZEROMQ
185  bool zmq(false);
186  parser.add("--zmq","Enable the ZeroMQ Input",zmq);
187 #endif
188 #ifdef XFELLIBRARY
189  bool xfelonlineinput(false);
190  parser.add("--xfelonline","Enable the XFEL-Online Input",xfelonlineinput);
191 #endif
192  bool showUsage(false);
193  parser.add("-h","show this help",showUsage);
194  bool showVersion(false);
195  parser.add("--version","display the version of cass",showVersion);
196 
197  parser(app.arguments());
198 
199 
200  /** show help and exit if requested */
201  if (showUsage)
202  {
203  parser.usage();
204  exit(0);
205  }
206 
207  /** show version and exit if requested */
208  if (showVersion)
209  {
210  cout <<VERSION <<endl;
211  exit(0);
212  }
213 
214  /** set the user requested .ini file name */
215  CASSSettings::setFilename(settingsfilename);
216 
217  /** since the settings for the log are now loaded one can now add things to
218  * the log
219  */
220  Log::add(Log::INFO,"Start CASS");
221 
222 
223  /** create a ratemeter objects for input and worker and the plotter to plot
224  * the rates that are calculated.
225  */
226  Ratemeter inputrate;
227  Ratemeter inputload;
228  Ratemeter workerrate;
229  RatePlotter plotter(inputrate,inputload,workerrate);
230 
231  /** create workers and requested inputs which need a ringbuffer for passing the
232  * the events from one to the other. Once created connect their terminated
233  * and finished signals such that they notify each other about that they are
234  * done processing the events. Also create the processor singleton used
235  * by the worker to process the events.
236  */
238  ProcessorManager::instance(outputfilename);
239  Workers::instance(ringbuffer, workerrate);
240 #ifdef OFFLINE
241  if (multifile)
242  MultiFileInput::instance(filelistname, ringbuffer, inputrate, inputload, quitwhendone);
243 // else if (useDatagenerator)
244 // TestInput::instance(ringbuffer,inputrate, inputload);
245 #ifdef SACLADATA
246  else if (sacladata)
247  SACLAOfflineInput::instance(filelistname,ringbuffer,inputrate,inputload,quitwhendone);
248 #endif
249 #ifdef HDF5
250  else if (hdf5file)
251  HDF5FileInput::instance(filelistname,ringbuffer,inputrate, inputload,quitwhendone);
252  else if (xfelhdf5file)
253  XFELHDF5FileInput::instance(filelistname,ringbuffer,inputrate, inputload,quitwhendone);
254 #endif
255 #ifdef ZEROMQ
256  else if (zmq)
257  ZMQInput::instance(ringbuffer, inputrate, inputload, quitwhendone);
258 #endif
259  else
260  FileInput::instance(filelistname, ringbuffer, inputrate, inputload, quitwhendone);
261 #else
262  if (tcp)
263  TCPInput::instance(ringbuffer,inputrate, inputload);
264 // else if (useDatagenerator)
265 // TestInput::instance(ringbuffer,inputrate, inputload);
266 #ifdef SACLADATA
267  else if (sacladata)
268  SACLAOnlineInput::instance(ringbuffer,inputrate,inputload);
269 #endif
270 #ifdef ZEROMQ
271  else if (zmq)
272  ZMQInput::instance(ringbuffer, inputrate, inputload);
273 #endif
274 #ifdef XFELLIBRARY
275  else if (xfelonlineinput)
276  XFELOnlineInput::instance(ringbuffer, inputrate, inputload);
277 #endif
278 #ifdef LCLSLIBRARY
279  else
280  SharedMemoryInput::instance(partitionTag, index, ringbuffer, inputrate, inputload);
281 #endif
282 #endif
283 
284  /** connect a own signal handler that acts on when sigquit is sent by linux
285  * it will call the end member of the input.
286  */
288 
289  /** set up the TCP/SOAP server */
291  if(!noSoap)
292  server = SoapServer::instance(soap_port);
293 
294  /** set up the optional http server */
295 #ifdef HTTPSERVER
296  httpServer http_server(get_histogram);
297 #endif
298 
299  /** start worker and server threads, then start input and wait until input
300  * is done
301  */
302  Workers::reference().start();
303  if (!noSoap)
304  server->start();
305 #ifdef HTTPSERVER
306  http_server.start();
307 #endif
308  plotter.start();
309  InputBase::reference().start();
310 
311  /** periodically check if the Workers are still running, while the input
312  * is still running. If not all workers are still running quit the input
313  * at this point and wait until it is quitted. Then rethrow the reason
314  * why the worker have quitted running.
315  * @note wait will return false if the input is still running
316  */
317  while (!InputBase::reference().wait(500))
318  {
319  if (!Workers::reference().running())
320  {
321  Log::add(Log::DEBUG4,"main(): One of the workers seem to not be working, quit all workers and then quit the input");
322  InputBase::reference().end();
323  InputBase::reference().wait();
324  Workers::reference().end();
325  Workers::reference().rethrowException();
326  }
327  }
328 
329  /** when the input was shut down gratiously, wait until the ringbuffer is
330  * empty (thus all events have been processed by the workers)
331  */
332  if (InputBase::reference().exceptionThrown() == InputBase::NO_EXCEPTION)
333  InputBase::reference().ringbuffer().waitUntilEmpty();
334 
335  /** now stop the worker threads */
336  Workers::reference().end();
337 
338  /** rethrow the exceptions if any where thrown inside the Input threads */
339  InputBase::reference().rethrowException();
340 
341  /** @todo find out how to stop the other threads */
342  }
343  catch (const invalid_argument &error)
344  {
345  Log::add(Log::ERROR,string("User input is wrong: ") + error.what());
346  cout <<endl<<endl<< "User input is wrong: Please review the log file '"
347  <<Log::filename()<<"'"<<endl;
348  }
349  catch (exception &error)
350  {
351  Log::add(Log::ERROR,string("Exception happened: ") + error.what());
352  cout <<endl<<endl<< "An exception happened: Please review the log file '"
353  <<Log::filename()<<"'"<<endl;
354  }
355  catch (...)
356  {
357  Log::add(Log::ERROR,"main(): something bad happend, quitting the program.");
358  cout <<endl<<endl<< "Bad error: Please review the log file '"
359  <<Log::filename()<<"'"<<endl;
360  }
361  Log::add(Log::INFO,"Quitting CASS");
362  cout << endl;
363 }
void endInputThread(int)
end the input thread
Definition: cass.cpp:75
void usage()
output which commandline parameters are available
Definition: cl_parser.hpp:40
file contains declaration of class Worker and Workers
contains input that uses the sacla online interface
class calculating a rate in Hz.
Definition: ratemeter.h:28
setDefaultFormat(Format format)
file contains declaration of class calculating a rate
file contains declaration of class that interfaces the LCLS shared memory
STL namespace.
contains input that uses ZMQ as interface
a httpserver for serving histograms of cass
contains a hdf5 file reader class
start(Priority priority=InheritPriority)
void start()
Definition: httpserver.h:88
int main(int argc, char **argv)
The main program.
Definition: cass.cpp:117
contains a parser for command line parameters
A Ringbuffer, handles communication between Input and Worker Threads.
Definition: ringbuffer.hpp:52
file contains declaration of class to plot the rate calculated by ratemeters
void add(const std::string &sw, const std::string &desc, bool &val)
add a switch to the switches container
Definition: cl_parser.hpp:122
file contains the ringbuffer class
file contains global definitions for project cass
file contains declaration of file input reading multiple files in parallel.
contains the manager for the processors
contains a xfel hdf5 file reader class
std::tr1::shared_ptr< SoapServer > shared_pointer
a shared pointer of this class
Definition: tcpserver.h:71
command line argument parser
Definition: cl_parser.hpp:27
file contains declaration of xtcfile input
contains the base class for all input modules
Plotting information about the ongoing processing.
Definition: rate_plotter.h:76
void setSignalHandler()
set up the own handler to react on the sigquit (crtl+ \) signal
Definition: cass.cpp:84
file contains specialized class that do the settings for cass
contains input that uses tcp as interface
file contains declaration of sacla offline input
the soap server implementation
contains a logger for cass
const size_t RingBufferSize
global variable to set the ring buffer size
Definition: cass.h:272