The VisAO Camera
VisAOApp_standalone.cpp
Go to the documentation of this file.
1 /************************************************************
2 * VisAOApp_standalone.cpp
3 *
4 * Author: Jared R. Males (jrmales@email.arizona.edu)
5 *
6 * Definitions for the standalone VisAO application.
7 *
8 * Developed as part of the Magellan Adaptive Optics system.
9 ************************************************************/
10 
11 /** \file VisAOApp_standalone.cpp
12  * \author Jared R. Males
13  * \brief Definitions for the standalone VisAO application.
14  *
15 */
16 
17 
18 
19 #include "VisAOApp_standalone.h"
20 
21 #include "AOApp.h"
22 #include "AOStates.h"
23 
24 namespace VisAO
25 {
26 
27 int VisAOApp_standalone::CONFIG_LOADER_LOG_LEVEL = Logger::LOG_LEV_INFO;
28 int VisAOApp_standalone::DEFAULT_LOG_LEVEL = Logger::LOG_LEV_INFO;
29 
30 Logger* VisAOApp_standalone::_logger = NULL;
31 
32 Config_File* VisAOApp_standalone::_cfg = NULL;
33 
34 std::string VisAOApp_standalone::_configFile;
35 std::string VisAOApp_standalone::_logFile;
36 std::string VisAOApp_standalone::_myName;
37 int VisAOApp_standalone::_ID;
38 std::string VisAOApp_standalone::_myFullName;
39 
40 
42 {
43  // Before all, temporary initialize the singleton logger (named "MAIN")
44  initTempLog();
45 
46  // Init status
47  _cfg = NULL;
48  _myName = "noname";
49  _ID = 0;
50 
51 
52  // Complete the initialization
53  CreateVisAOApp_standalone(Logger::LOG_LEV_INFO);
54 }
55 
56 VisAOApp_standalone::VisAOApp_standalone( string name, int id, int logLevel) throw (AOException) : VisAOApp_base()
57 {
58  // Before all, temporary initialize the singleton logger (named "MAIN")
59  initTempLog();
60 
61  // Init status
62  _cfg = NULL;
63  _myName = name;
64  _ID = id;
65 
66 
67  // Complete the initialization
68  CreateVisAOApp_standalone(logLevel);
69 }
70 
71 void VisAOApp_standalone::set_conffile( std::string name) throw (AOException)
72 {
73  std::string conffile = getConffile(name);
74 
75  set_conffile(name, conffile);
76 }
77 
78 VisAOApp_standalone::VisAOApp_standalone( std::string name, const std::string& conffile) throw (AOException) : VisAOApp_base()
79 {
80  set_conffile(name, conffile);
81 }
82 
83 void VisAOApp_standalone::set_conffile(std::string name, const std::string& conffile) throw (AOException)
84 {
85  _myName = name;
86  set_app_name(_myName);
87 
88  // Before all, temporary initialize the singleton logger (named "MAIN")
89  initTempLog();
90 
91  // Init the AOApp status using the configuration file
92  _cfg = NULL;
93 
94 
95  try
96  {
97  std::cerr << "=====> " << conffile << "\n";
98  SetConfigFile(conffile);
99  }
100  catch(Config_File_Exception &e)
101  {
102  // This is a fatal error
103  throw AOException("config File Exception in AOApp c'tor");
104  }
105 
106  // Get the log level
107  int logLevel = 0;
108 
109  try
110  {
111  // Try to get the level from config file...
112  if(_cfg != NULL)
113  {
114  logLevel = Logger::stringToLevel((*_cfg)["LogLevel"]);
115  }
116  }
117  catch(Config_File_Exception& e)
118  {
119  //...otherwise use a default value
120  logLevel=Logger::LOG_LEV_INFO;
121  }
122 
123  // Complete the initialization
124  CreateVisAOApp_standalone(logLevel);
125 }
126 
127 VisAOApp_standalone::VisAOApp_standalone( int argc, char**argv) throw (AOException) : VisAOApp_base()
128 {
129  char c;
130 
131  // Init the AOApp status using the command line
132  std::string conffile = "";
133  int log_modifier = 0;
134 
135  opterr = 0;
136  while ((c = getopt (argc, argv, "i:f:hvq")) != -1)
137  {
138  switch (c)
139  {
140  case 'i':
141  _myName = optarg;
142  break;
143  case 'f':
144  conffile = optarg;
145  break;
146  case 'v':
147  log_modifier++;
148  break;
149  case 'q':
150  log_modifier--;
151  break;
152  case 'h':
153  usage();
154  exit(0);
155  case '?':
156  // Do not want to exit in case of unknown option: can be a valid
157  // option for a subclass!!!
158  //if (isprint (optopt))
159  // fprintf (stderr, "Unknown option `-%c'.\n", optopt);
160  //else
161  // fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt);
162  //exit(0);
163  break;
164  }
165  }
166 
167  // Before all, instantiate the singleton logger (named "MAIN")
168  initTempLog();
169 
170  // If no config. file specified, use the identity to find it
171  if (conffile == "")
172  conffile = getConffile(_myName);
173  try
174  {
175  SetConfigFile(conffile);
176 
177  set_app_name(_myName);
178  }
179  catch(Config_File_Exception &e)
180  {
181  // This is a fatal error
182  throw AOException("config File Exception in VisAOApp constructor");
183  }
184 
185  // Get the logging level
186  int llevel=Logger::LOG_LEV_INFO;
187  if(log_modifier > 0) llevel=Logger::LOG_LEV_INFO + log_modifier;
188 
189  std::cout << "0.\n";
190  // Complete the initialization
191  CreateVisAOApp_standalone(llevel);
192 }
193 
194 VisAOApp_standalone::~VisAOApp_standalone()
195 {
196  Logger::get()->log(Logger::LOG_LEV_FATAL, "VisAOApp terminated.");
197  std::cerr << app_name << ": VisAOApp terminated." << std::endl;
198  // Destroy the loggers pool
199  Logger::destroy();
200 }
201 
202 string VisAOApp_standalone::getConffile( string identity)
203 {
204  std::cerr << "Conf. file: " << Utils::getConffile(identity) << std::endl;
205 
206  return Utils::getConffile(identity);
207 }
208 
209 void VisAOApp_standalone::usage()
210 {
211  string vId;
212  vId=GetVersionID();
213  cout << endl << "VisAOApp: " << _myName << " " << vId << endl << endl;
214  cout << endl << "Standard options:" << endl << endl;
215  cout << " -i <identity>: identity, used for config lookup etc." << endl;
216  cout << " -f <file> : configuration file (if not specified, takes the identity as prefix)" << endl;
217  cout << " -v : increase verbosity over default level (can appear multiple times)" << endl;
218  cout << " -q : decrease verbosity from default level (can appear multiple times)" << endl;
219  cout << " -h : prints this message and exits" << endl;
220  cout << endl;
221 }
222 
223 
224 void VisAOApp_standalone::CreateVisAOApp_standalone(int logLevel) throw (AOException)
225 {
226  std::string pathtmp;
227 
228  // Useful
229  _myFullName = _myName + "." + Utils::getAdoptSide();
230 
231  Logger::setParentName(_myFullName);
232 
233  // This way the log file is unique
234  _logFile = _myFullName;
235 
236  ////////////////// INIT THE LOGGER /////////////////
237 
238  // --- Setup the LOGGER POOL --- //
239 
240  // Setup the logging path
241  setLogFile(_logFile);
242 
243 
244  // --- Setup the logger MAIN --- //
245  _logger->setGlobalLevel(logLevel);
246 
247  //Set the realtime priority from config
248  try
249  {
250  if(_cfg != NULL)
251  {
252  set_RT_priority((int)(*_cfg)["RT_priority"]);
253  }
254  else
255  {
256  set_RT_priority(0);
257  }
258  }
259  catch(Config_File_Exception& e)
260  {
261  //Otherwise don't do anything.
262  set_RT_priority(0);
263  }
264 
265  //Set the wait time from config
266  try
267  {
268  if(_cfg != NULL)
269  {
270  set_wait_to((double)(*_cfg)["wait_to"]);
271  }
272  }
273  catch(Config_File_Exception& e)
274  {
275  //Otherwise don't do anything.
276  }
277 
278  //Set up the com_paths
279  try
280  {
281  if(_cfg != NULL)
282  {
283  pathtmp = (std::string)(*_cfg)["com_path"];
284  }
285  else pathtmp = "fifos";
286  }
287  catch(Config_File_Exception)
288  {
289  pathtmp = "fifos";
290  }
291  com_path = std::string(getenv("VISAO_ROOT")) + "/" + pathtmp + "/" + _myName;
292 
293  //Set up the default_control_mode
294  try
295  {
296  if(_cfg != NULL)
297  {
298  std::string dfc = (std::string)(*_cfg)["default_control_mode"];
299  if(dfc[0] == 'N') default_control_mode = CMODE_NONE;
300  else if(dfc[0] == 'R') default_control_mode = CMODE_REMOTE;
301  else if(dfc[0] == 'L') default_control_mode = CMODE_LOCAL;
302  else if(dfc[0] == 'S') default_control_mode = CMODE_SCRIPT;
303  else if(dfc[0] == 'A') default_control_mode = CMODE_AUTO;
304  else
305  {
306  Logger::get()->log(Logger::LOG_LEV_ERROR, "Uknown control mode in config default_control_mode");
307  }
308  }
309 
310  if(default_control_mode > -1) request_control(default_control_mode,1);
311  }
312  catch(Config_File_Exception)
313  {
314  //do nuthin'
315  }
316 
317  //Set up the profile_path
318  try
319  {
320  if(_cfg != NULL)
321  {
322  pathtmp = (std::string)(*_cfg)["profile_path"];
323  }
324  else pathtmp = "profile";
325  }
326  catch(Config_File_Exception)
327  {
328  pathtmp = "profile";
329  }
330  profile_path = std::string(getenv("VISAO_ROOT")) + "/" + pathtmp + "/" + MyFullName();
331 
332  profile->set_base_path(profile_path);
333 
334 
335  //Set use_profile
336  try
337  {
338  if(_cfg != NULL)
339  {
340  use_profiler = (int)(*_cfg)["use_profiler"];
341  }
342  else use_profiler = 0;
343  }
344  catch(Config_File_Exception)
345  {
346  use_profiler = 0;
347  }
348  if(use_profiler != 0) use_profiler = 1;
349 
350  //Set pause_time
351  try
352  {
353  if(_cfg != NULL)
354  {
355  pause_time = (double)(*_cfg)["pause_time"];
356  }
357  else pause_time = 1.0;
358  }
359  catch(Config_File_Exception)
360  {
361  pause_time = 1.0;
362  }
363 
364 
365  //Check for initialization file
366  try
367  {
368  if(_cfg != NULL)
369  {
370  init_file = (std::string)(*_cfg)["init_path"];
371  }
372  else init_file = "init";
373  }
374  catch(Config_File_Exception)
375  {
376  init_file = "init";
377  }
378 
379  init_file = init_file + "/"+ _myName+".init";
380 
381  try
382  {
383  init_vars = new Config_File(init_file);
384  }
385  catch(Config_File_Exception)
386  {
387  init_vars = 0;
388  }
389 
390 
391  pthread_cond_init(&signal_cond, NULL);
392  pthread_mutex_init(&signal_mutex, NULL);
393 
394  //Set up the data file paths
395  if(_cfg != NULL)
396  {
397  try
398  {
399  data_save_path = (std::string)(*_cfg)["data_save_path"];
400  }
401  catch(Config_File_Exception)
402  {
403  data_save_path = "data/syslogs";
404  }
405 
406  try
407  {
408  data_log_time_length = (double)(*_cfg)["data_log_time_length"];
409  }
410  catch(Config_File_Exception)
411  {
412  data_log_time_length = 120.;
413  }
414 
415  try
416  {
417  data_file_prefix = (std::string)(*_cfg)["data_file_prefix"];
418  }
419  catch(Config_File_Exception)
420  {
421  data_file_prefix = _myFullName;
422  }
423  }
424  else
425  {
426  data_save_path = "data/syslogs";
427  data_log_time_length = 120.;
428  data_file_prefix = _myFullName;
429  }
430 
431 
432 
433  #ifdef VISAO_SIMDEV
434  signalth_sleeptime = 1000.;
435  #else
436 
437  try
438  {
439  if(_cfg != NULL)
440  {
441  signalth_sleeptime = (double)(*_cfg)["signalth_sleeptime"];
442  }
443  else
444  {
445  signalth_sleeptime = 1000.;
446  }
447  }
448  catch(Config_File_Exception)
449  {
450  signalth_sleeptime = 1000.;
451  }
452 
453  #endif
454 
455 
456 }
457 
458 void VisAOApp_standalone::setLogFile(string fileName)
459 {
460  _logger->rename( fileName);
461 }
462 
463 void VisAOApp_standalone::initTempLog()
464 {
465  Logger::enableFileLog();
466 
467  // Before configuration read, the logging file name is unknown:
468  // a temp name is used, and then the method CreateApp(), which
469  // knows the correct name will rename it
470 
471  _logger = Logger::get();
472  setLogFile(Utils::uniqueFileName("aoapp_"));
473 }
474 
475 void VisAOApp_standalone::SetConfigFile(const std::string& conffile) throw (Config_File_Exception)
476 {
477 
478  Config_File::setLogLevel(CONFIG_LOADER_LOG_LEVEL);
479 
480  _configFile = conffile;
481 
482  try
483  {
484 
485  _cfg = new Config_File(_configFile);
486 
487  }
488  catch (Config_File_Exception &e)
489  {
490  Logger::get()->log(Logger::LOG_LEV_ERROR, e.what().c_str());
491  throw;
492  }
493 
494 }
495 
496 void VisAOApp_standalone::log_msg(int LogLevel, std::string lmsg)
497 {
498  Logger::get()->log(LogLevel, lmsg);
499 }
500 
501 
503 {
504  struct sigaction act;
505  sigset_t set;
506 
507  act.sa_sigaction = &sigterm_handler;
508  act.sa_flags = SA_SIGINFO;
509  sigemptyset(&set);
510  act.sa_mask = set;
511 
512  sigaction(SIGTERM, &act, 0);
513  sigaction(SIGQUIT, &act, 0);
514  sigaction(SIGINT, &act, 0);
515 
516  return Run();
517 }
518 
520 {
521  logss.str("");
522  logss << "Run() not yet reimplemented. No main loop to execute.";
523  error_report(Logger::LOG_LEV_FATAL, logss.str());
524  return -1;
525 }
526 
528 {
529  double dt, t0;
530 
531  //if(connect_fifo_list_nolock() == 0)
532  if(connect_fifo_list() == 0)
533  {
534  //log_msg(Logger::LOG_LEV_DEBUG, "fifo_list connected.");
535  logss.str("");
536  logss << "fifo_list connected.";
537  log_msg(Logger::LOG_LEV_INFO, logss.str());
538  }
539  else
540  {
541  //error_report(Logger::LOG_LEV_FATAL, "Error connecting the fifo list.");
542  error_report(Logger::LOG_LEV_FATAL, "Error connecting the fifo list.");
543  TimeToDie = 1;
544  return;
545  }
546 
547  global_fifo_list = &fl;
548 
549  setup_RTsigio();
550 
551  block_signal(RTSIGPING); //We block this here, so a main thread can catch it.
552 
553  while(!TimeToDie)
554  {
555  t0 = get_curr_time();
556 
557  while((dt = get_curr_time() - t0) < pause_time && !TimeToDie)
558  {
559 
561 
562  pthread_cond_broadcast(&signal_cond);
563 
564  usleep((int) signalth_sleeptime);
565  //if(pause_time - dt >= 1) sleep((int)(pause_time - dt));
566  //else usleep((int)((pause_time-dt)*1e6 * .99));
567  }
568 
570 
571  pthread_cond_broadcast(&signal_cond);
572 
574 
575  }
576 
577  pthread_cond_broadcast(&signal_cond);
578 
579  kill_me();
580 
581 }
582 
584 {
585  struct sched_param schedpar;
586  pthread_attr_t attr;
587 
588  pthread_attr_init(&attr);
589 
590  if(!inherit_sched)
591  {
592  //Start the signal catcher as a lower priority thread.
593 
594  schedpar.sched_priority = 0;
595 
596  pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
597  pthread_attr_setschedpolicy(&attr, SCHED_OTHER);
598  pthread_attr_setschedparam(&attr, &schedpar);
599  }
600  else
601  {
602  //Start with inherit sched, use the same priority as the main thread
603  pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
604  }
605 
606  //This is weird, but the doc for pthread_create says it returns an "error number" instead of -1
607  if(pthread_create(&signal_thread, &attr, &__start_signal_catcher, (void *) this) == 0) return 0;
608  else return -1;
609 
610 }
611 
613 {
614  struct sigaction act;
615  sigset_t set;
616 
617  //Install the main thread handler for signals from the signal catcher
618  main_thread = pthread_self();
619  act.sa_sigaction = &sig_mainthread_catcher;
620  act.sa_flags = SA_SIGINFO;
621  sigemptyset(&set);
622  act.sa_mask = set;
623 
624  return sigaction(SIG_MAINTHREAD, &act, 0);
625 
626 }
627 
629 {
630  sigset_t set;
631 
632  sigemptyset(&set);
633  sigaddset(&set, signum);
634 
635  errno = 0;
636  if(pthread_sigmask(SIG_BLOCK, &set, 0) == 0) return 0;
637  else
638  {
639  perror("block_signal");
640  return -1;
641  }
642 }
643 
644 
646 {
647  //sigset_t set;
648 
649  //sigemptyset(&set);
650  //sigaddset(&set, SIGIO);
651  //sigaddset(&set, RTSIGIO);
652 
653  if(block_signal(SIGIO) < 0) return -1;
654  if(block_signal(RTSIGIO) < 0) return -1;
655  //if(pthread_sigmask(SIG_BLOCK, &set, 0) == 0) return 0;
656  //else return -1;
657 
658  return 0;
659 }
660 
662 {
663  return 0;
664 }
665 
666 void * __start_signal_catcher(void * ptr)
667 {
668  ((VisAOApp_standalone *) ptr)->signal_catcher();
669  return 0;
670 }
671 
672 void sig_mainthread_catcher(int signum __attribute__((unused)), siginfo_t *siginf __attribute__((unused)), void *ucont __attribute__((unused)))
673 {
674  //do nothing
675  return;
676 }
677 
678 void sigterm_handler(int signum, siginfo_t *siginf __attribute__((unused)), void *ucont __attribute__((unused)))
679 {
680  std::string signame;
681  TimeToDie = 1;
682 
683  switch(signum)
684  {
685  case SIGTERM:
686  signame = "SIGTERM";
687  break;
688  case SIGINT:
689  signame = "SIGINT";
690  break;
691  case SIGQUIT:
692  signame = "SIGQUIT";
693  break;
694  default:
695  signame = "OTHER";
696  }
697 
698  Logger::get()->log(Logger::LOG_LEV_FATAL, "Caught signal %s. TimeToDie is set.", signame.c_str());
699  std::cerr << "Caught signal " << signame << " TimeToDie is set." << std::endl;
700  return;
701 }
702 
703 } //namespace VisAO
704 
705 /// Error reporting function for global_error_report.
706 void error_report(const char* er, const char* file, int lno)
707 {
708 
709  Logger::get()->log(Logger::LOG_LEV_ERROR, "%s. File: %s Line: %i", er, file, lno);
710  std::cerr << er << " File: " << file << " Line: " << lno << std::endl;
711 }
712 
713 /// Info logging function for global_log_info.
714 void log_info(const char* li)
715 {
716 
717  Logger::get()->log(Logger::LOG_LEV_INFO, "%s", li);
718  std::cout << li << "\n";
719 }
720 
722 
724 
725 
#define set_global_log_info(li)
Macro for declaring and setting the info logging global.
Definition: libvisao.h:71
VisAOApp_standalone()
Default constructor.
void log_msg(int LogLevel, std::string lmsg)
Report an error. Also calls log_msg. Overloaded from VisAOApp_base.
virtual int Run()
The application main loop, to be re-implemented in derived classes.
fifo_list * global_fifo_list
The global fifo_list, for signal handling.
Definition: dioserver.cpp:19
double get_curr_time(void)
Gets the current CLOCK_REALTIME time, returns it in seconds to double precision.
Definition: libvisaoc.c:40
void error_report(const char *er, const char *file, int lno)
Error reporting function for global_error_report.
virtual int start_signal_catcher(bool inherit_sched=true)
Starts the signal catching loop.
The standalone VisAO application, does not interface with the AO Supervisor.
std::ostringstream logss
Conveninence string stream for building log messages.
virtual void error_report(int LogLevel, std::string emsg)
Report an error. Also calls log_msg.
void signal_catcher()
Signal loop, normally won't need to be overridden.
Declarations for the standalone VisAO application.
virtual int update_statusboard()
Update the status board.
int check_fifo_list_RTpending()
Check for pending reads for the fifo list while using the RT signals.
std::string app_name
The name of the application.
Definition: VisAOApp_base.h:82
void * __start_signal_catcher(void *ptr)
Thread starter for the signal catcher.
pthread_cond_t signal_cond
Condition for telling main thread that something changed.
virtual int block_signal(int signum)
Sets the signal mask to block signal signum.
pthread_t signal_thread
Identifier for the separate signal handling thread.
virtual int block_sigio()
Sets the signal mask to block SIGIO and RTSIGIO.
int TimeToDie
Global set by SIGTERM.
static string getConffile(string identity)
Return configuration file path based on identity.
fifo_list fl
The list of named-pipe fifos used for inter-process comms.
The base class for VisAO applications.
Definition: VisAOApp_base.h:48
double pause_time
Time to pause during application main loop.
Definition: VisAOApp_base.h:84
int connect_fifo_list()
Connect the fifo_list with exclusive locking.
int setup_RTsigio()
Setup SIGIO signal handling using realtime signals.
virtual int install_sig_mainthread_catcher()
Install the SIG_MAINTHREAD signal catcher.
virtual int Exec()
Installs the term and XXXX signal handlers, and calls Run().
The namespace of VisAO software.
pthread_t main_thread
Identifier for the main thread.
virtual int kill_me()
Handle a timetodie condition upon exiting the signal catcher thread (e.g. tell main thread it is abou...
#define set_global_error_report(er)
Macro for declaring and setting the error reporting global.
Definition: libvisao.h:63
void log_info(const char *li)
Info logging function for global_log_info.