From 006a2ce21f277f171c8da9f4455c7299977fd87a Mon Sep 17 00:00:00 2001 From: Christian as GENIVI Maintainer Date: Fri, 30 Sep 2016 08:27:37 -0700 Subject: add actual doxygen documentation Signed-off-by: Christian as GENIVI Maintainer --- main_8cpp_source.html | 575 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 575 insertions(+) create mode 100644 main_8cpp_source.html (limited to 'main_8cpp_source.html') diff --git a/main_8cpp_source.html b/main_8cpp_source.html new file mode 100644 index 0000000..9b9df41 --- /dev/null +++ b/main_8cpp_source.html @@ -0,0 +1,575 @@ + + + + + + +AudioManager: AudioManagerDaemon/src/main.cpp Source File + + + + + + + + + + + + + +
+
+ + + + + + +
+
AudioManager +  7.5.11 +
+
Native Application Runtime Environment
+
+
+ + + + + +
+
+ +
+
+
+ +
+ + + + +
+ +
+ +
+
+
main.cpp
+
+
+Go to the documentation of this file.
1 
+
25 #include "audiomanagerconfig.h"
+
26 
+
27 #ifdef WITH_TELNET
+
28  #include "CAmTelnetServer.h"
+
29 #endif
+
30 
+
31 #ifdef WITH_CAPI_WRAPPER
+
32  #include "CAmCommonAPIWrapper.h"
+
33 #endif
+
34 
+
35 #ifdef WITH_DBUS_WRAPPER
+
36  #include "CAmDbusWrapper.h"
+
37 #endif
+
38 
+
39 
+
40 #ifdef WITH_DATABASE_STORAGE
+
41  #include "CAmDatabaseHandlerSQLite.h"
+
42 #else
+
43  #include "CAmDatabaseHandlerMap.h"
+
44 #endif
+
45 
+
46 #ifdef WITH_SYSTEMD_WATCHDOG
+
47  #include "CAmWatchdog.h"
+
48 #endif
+
49 
+
50 #include <sys/resource.h>
+
51 #include <sys/stat.h>
+
52 #include <unistd.h>
+
53 #include <cstdlib>
+
54 #include <cstdlib>
+
55 #include <cassert>
+
56 #include <fcntl.h>
+
57 #include <csignal>
+
58 #include <cstring>
+
59 #include <cstdio>
+
60 #include <new>
+
61 
+
62 #include "CAmRouter.h"
+
63 #include "CAmControlSender.h"
+
64 #include "CAmCommandSender.h"
+
65 #include "CAmRoutingSender.h"
+
66 #include "CAmRoutingReceiver.h"
+
67 #include "CAmCommandReceiver.h"
+
68 #include "CAmControlReceiver.h"
+
69 #include "CAmDatabaseObserver.h"
+
70 #include "CAmDltWrapper.h"
+
71 #include "CAmSocketHandler.h"
+ +
73 
+
74 
+
75 using namespace am;
+
76 
+
77 //we need these because we parse them beforehand.
+
78 std::vector<std::string> listCommandPluginDirs;
+
79 std::vector<std::string> listRoutingPluginDirs;
+
80 
+
81 //commandline options used by the Audiomanager itself
+
82 TCLAP::ValueArg<std::string> controllerPlugin("c","controllerPlugin","use controllerPlugin full path with .so ending",false,CONTROLLER_PLUGIN_DIR,"string");
+
83 TCLAP::ValueArg<std::string> additionalCommandPluginDirs("L","additionalCommandPluginDirs","additional path for looking for command plugins, can be used after -l option",false," ","string");
+
84 TCLAP::ValueArg<std::string> additionalRoutingPluginDirs("R","additionalRoutingPluginDirs","additional path for looking for routing plugins, can be used after -r option ",false," ","string");
+
85 TCLAP::ValueArg<std::string> routingPluginDir("r","RoutingPluginDir","path for looking for routing plugins",false," ","string");
+
86 TCLAP::ValueArg<std::string> commandPluginDir("l","CommandPluginDir","path for looking for command plugins",false," ","string");
+
87 TCLAP::ValueArg<std::string> dltLogFilename("F","dltLogFilename","the name of the logfile, absolute path. Only if logging is et to file",false," ","string");
+
88 TCLAP::ValueArg<unsigned int> dltOutput ("O","dltOutput","defines where logs are written. 0=dlt-daemon(default), 1=command line, 2=file ",false,0,"int");
+
89 TCLAP::ValueArg<unsigned int> telnetPort ("t","telnetport","The port that is used for telnet",false,DEFAULT_TELNETPORT,"int");
+
90 TCLAP::ValueArg<unsigned int> maxConnections ("m","maxConnections","Maximal number of connections for telnet",false,MAX_TELNETCONNECTIONS,"int");
+
91 TCLAP::SwitchArg dltEnable ("e","dltEnable","Enables or disables dlt logging. Default = enabled",true);
+
92 TCLAP::SwitchArg dbusWrapperTypeBool ("T","dbusType","DbusType to be used by CAmDbusWrapper: if option is selected, DBUS_SYSTEM is used otherwise DBUS_SESSION",false);
+
93 TCLAP::SwitchArg currentSettings("i","currentSettings","print current settings and exit",false);
+
94 TCLAP::SwitchArg daemonizeAM("d","daemonize","daemonize Audiomanager. Better use systemd...",false);
+
95 
+
96 int fd0, fd1, fd2;
+
97 
+
98 #ifdef WITH_DBUS_WRAPPER
+
99  DBusBusType dbusWrapperType=DBUS_BUS_SESSION;
+
100 #endif
+
101 
+ +
106 {
+
107  logError("No more memory - bye");
+
108  throw std::runtime_error(std::string("SocketHandler::start_listenting ppoll returned with error."));
+
109 }
+
110 
+
114 void daemonize()
+
115 {
+
116  umask(0);
+
117  std::string dir = "/";
+
118 
+
119  rlimit rl;
+
120  if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
+
121  {
+
122  logError("can't get file limit ");
+
123  }
+
124 
+
125  pid_t pid;
+
126  if ((pid = fork()) < 0)
+
127  {
+
128  logError("cannot fork!");
+
129  }
+
130  else if (pid != 0)
+
131  {
+
132  exit(0);
+
133  }
+
134 
+
135  setsid();
+
136 
+
137  if (!dir.empty() && chdir(dir.c_str()) < 0)
+
138  {
+
139  logError("couldn't chdir to the new directory");
+
140  }
+
141 
+
142  if (rl.rlim_max == RLIM_INFINITY)
+
143  {
+
144  rl.rlim_max = 1024;
+
145  }
+
146 
+
147  for (unsigned int i = 0; i < rl.rlim_max; i++)
+
148  {
+
149  close(i);
+
150  }
+
151 
+
152  fd0 = open("/dev/null", O_RDONLY);
+
153  fd1 = open("/dev/null", O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
+
154  fd2 = open("/dev/null", O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
+
155 
+
156  if (fd0 != STDIN_FILENO || fd1 != STDOUT_FILENO || fd2 != STDERR_FILENO)
+
157  {
+
158  logError("new standard file descriptors were not opened");
+
159  }
+
160 }
+
161 
+
162 
+
163 
+ +
165 {
+
166  printf("\n\n\nCurrent settings:\n\n");
+
167  printf("\tAudioManagerDaemon Version:\t\t%s\n", DAEMONVERSION);
+
168 #ifdef WITH_TELNET
+
169  printf("\tTelnet portNumber:\t\t\t%i\n", telnetPort.getValue());
+
170  printf("\tTelnet maxConnections:\t\t\t%i\n", maxConnections.getValue());
+
171 #endif
+
172  printf("\tControllerPlugin: \t\t\t%s\n", controllerPlugin.getValue().c_str());
+
173  printf("\tDirectories of CommandPlugins: \t\t\n");
+
174  std::vector<std::string>::const_iterator dirIter = listCommandPluginDirs.begin();
+
175  std::vector<std::string>::const_iterator dirIterEnd = listCommandPluginDirs.end();
+
176  for (; dirIter < dirIterEnd; ++dirIter)
+
177  {
+
178  printf("\t \t\t%s\n", dirIter->c_str());
+
179  }
+
180 
+
181  printf("\tDirectories of RoutingPlugins: \t\t\n");
+
182  dirIter = listRoutingPluginDirs.begin();
+
183  dirIterEnd = listRoutingPluginDirs.end();
+
184  for (; dirIter < dirIterEnd; ++dirIter)
+
185  {
+
186  printf("\t \t\t%s\n", dirIter->c_str());
+
187  }
+
188  exit(0);
+
189 }
+
190 
+
197 static void signalHandler(int sig, siginfo_t *siginfo, void *context)
+
198 {
+
199  (void) sig;
+
200  (void) siginfo;
+
201  (void) context;
+
202  logInfo("signal handler was called, signal",sig);
+
203 
+
204  switch (sig)
+
205  {
+
206  /*ctl +c lets call direct controllerRundown, because we might be blocked at the moment.
+
207  But there is the risk of interrupting something important */https://asc.bmwgroup.net/wiki/display/MGUROTO/Lastest+and+greatest
+
208  case SIGINT:
+ +
210  break;
+
211 
+
212  /* huch- we are getting killed. Better take the fast but risky way: */
+
213  case SIGQUIT:
+ +
215  break;
+
216 
+
217  /* more friendly here assuming systemd wants to stop us, so we can use the mainloop */
+
218  case SIGTERM:
+ +
220  break;
+
221 
+
222  /* looks friendly, too, so lets take the long run */
+
223  case SIGHUP:
+ +
225  break;
+
226  default:
+
227  break;
+
228  }
+
229 }
+
230 
+
231 void mainProgram(int argc, char *argv[])
+
232 {
+
233 
+
234  //initialize the commandline parser, and add all neccessary commands
+
235  try
+
236  {
+
237  TCLAP::CmdLine* cmd(CAmCommandLineSingleton::instanciateOnce("The team of the AudioManager wishes you a nice day!",' ',DAEMONVERSION,true));
+
238  cmd->add(controllerPlugin);
+
239  cmd->add(additionalCommandPluginDirs);
+
240  cmd->add(commandPluginDir);
+
241  cmd->add(additionalRoutingPluginDirs);
+
242  cmd->add(routingPluginDir);
+
243  cmd->add(currentSettings);
+
244  cmd->add(daemonizeAM);
+
245  cmd->add(dltEnable);
+
246  cmd->add(dltLogFilename);
+
247  cmd->add(dltOutput);
+
248 #ifdef WITH_DBUS_WRAPPER
+
249  cmd->add(dbusWrapperTypeBool);
+
250 #endif
+
251 #ifdef WITH_TELNET
+
252  cmd->add(telnetPort);
+
253  cmd->add(maxConnections);
+
254 #endif
+
255 #ifdef WITH_DATABASE_STORAGE
+
256  cmd->add(databasePath);
+
257 #endif
+
258  }
+
259  catch (TCLAP::ArgException &e) // catch any exceptions
+
260  { std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl; }
+
261 
+
262  //hen and egg. We need to parse a part of the commandline options to get the paths of the controller and the plugins.
+
263  //So we do some little parsing first and the real parsing later so that the plugins can profit from that.
+
264  CAmCommandLineSingleton::instance()->preparse(argc,argv);
+
265  if (daemonizeAM.getValue())
+
266  {
+
267  daemonize();
+
268  }
+
269 
+
270  CAmDltWrapper::instanctiateOnce("AUDI", "AudioManager",dltEnable.getValue(),static_cast<am::CAmDltWrapper::logDestination>(dltOutput.getValue()),dltLogFilename.getValue());
+
271 
+
272  //Instantiate all classes. Keep in same order !
+
273  CAmSocketHandler iSocketHandler;
+
274 
+
275  if(commandPluginDir.isSet())
+
276  {
+
277  listCommandPluginDirs.clear();
+
278  listCommandPluginDirs.push_back(commandPluginDir.getValue());
+
279  }
+
280 
+
281  if (additionalCommandPluginDirs.isSet())
+
282  {
+ +
284  }
+
285 
+
286  if(routingPluginDir.isSet())
+
287  {
+
288  listRoutingPluginDirs.clear();
+
289  listRoutingPluginDirs.push_back(routingPluginDir.getValue());
+
290  }
+
291 
+
292  if (additionalRoutingPluginDirs.isSet())
+
293  {
+ +
295  }
+
296 
+
297  //in this place, the plugins can get the gloval commandlineparser via CAmCommandLineSingleton::instance() and add their options to the commandline
+
298  //this must be done in the constructor.
+
299  //later when the plugins are started, the commandline is already parsed and the objects defined before can be used to get the neccesary information
+
300 
+
301  CAmDatabaseHandlerMap iDatabaseHandler;
+
302  IAmDatabaseHandler *pDatabaseHandler = dynamic_cast<IAmDatabaseHandler*>( &iDatabaseHandler );
+
303 
+
304  CAmRoutingSender iRoutingSender(listRoutingPluginDirs,pDatabaseHandler);
+
305  CAmCommandSender iCommandSender(listCommandPluginDirs);
+
306  CAmControlSender iControlSender(controllerPlugin.getValue(),&iSocketHandler);
+
307 
+
308  try
+
309  {
+
310  //parse the commandline options
+ +
312  CAmCommandLineSingleton::instance()->parse(argc,argv);
+
313  if (currentSettings.getValue())
+
314  {
+ +
316  }
+
317  }
+
318  catch (TCLAP::ArgException &e) // catch any exceptions
+
319  { std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl; }
+
320 
+
321  logInfo("The Audiomanager is started");
+
322  logInfo("The version of the Audiomanager", DAEMONVERSION);
+
323 
+
324 #ifdef WITH_CAPI_WRAPPER
+
325  //We instantiate a singleton with the current socket handler, which loads the common-api runtime.
+
326  CAmCommonAPIWrapper *pCAPIWrapper = CAmCommonAPIWrapper::instantiateOnce(&iSocketHandler, "AudioManager");
+
327 #endif /*WITH_CAPI_WRAPPER */
+
328 
+
329 #ifdef WITH_DBUS_WRAPPER
+
330  if (dbusWrapperTypeBool.getValue())
+
331  dbusWrapperType=DBUS_BUS_SYSTEM;
+
332  CAmDbusWrapper iDBusWrapper(&iSocketHandler,dbusWrapperType);
+
333 #endif /*WITH_DBUS_WRAPPER */
+
334 
+
335 #ifdef WITH_SYSTEMD_WATCHDOG
+
336  CAmWatchdog iWatchdog(&iSocketHandler);
+
337 #endif /*WITH_SYSTEMD_WATCHDOG*/
+
338 
+
339 CAmRouter iRouter(pDatabaseHandler, &iControlSender);
+
340 
+
341 #ifdef WITH_DBUS_WRAPPER
+
342  CAmCommandReceiver iCommandReceiver(pDatabaseHandler, &iControlSender, &iSocketHandler, &iDBusWrapper);
+
343  CAmRoutingReceiver iRoutingReceiver(pDatabaseHandler, &iRoutingSender, &iControlSender, &iSocketHandler, &iDBusWrapper);
+
344 #else /*WITH_DBUS_WRAPPER*/
+
345  CAmCommandReceiver iCommandReceiver(pDatabaseHandler,&iControlSender,&iSocketHandler);
+
346  CAmRoutingReceiver iRoutingReceiver(pDatabaseHandler,&iRoutingSender,&iControlSender,&iSocketHandler);
+
347 #endif /*WITH_DBUS_WRAPPER*/
+
348 
+
349 CAmControlReceiver iControlReceiver(pDatabaseHandler,&iRoutingSender,&iCommandSender,&iSocketHandler, &iRouter);
+
350 
+
351 #ifdef WITH_TELNET
+
352  CAmTelnetServer iTelnetServer(&iSocketHandler, &iCommandSender, &iCommandReceiver, &iRoutingSender, &iRoutingReceiver, &iControlSender, &iControlReceiver, pDatabaseHandler, &iRouter, telnetPort.getValue(), maxConnections.getValue());
+
353  CAmDatabaseObserver iObserver(&iCommandSender, &iRoutingSender, &iSocketHandler, &iTelnetServer);
+
354 #else /*WITH_TELNET*/
+
355  CAmDatabaseObserver iObserver(&iCommandSender,&iRoutingSender, &iSocketHandler);
+
356 #endif
+
357 
+
358  iDatabaseHandler.registerObserver(&iObserver);
+
359 
+
360  //startup all the Plugins and Interfaces
+
361  //at this point, commandline arguments can be parsed
+
362  iControlSender.startupController(&iControlReceiver);
+
363  iCommandSender.startupInterfaces(&iCommandReceiver);
+
364  iRoutingSender.startupInterfaces(&iRoutingReceiver);
+
365 
+
366  //when the routingInterface is done, all plugins are loaded:
+
367  iControlSender.setControllerReady();
+
368 
+
369 #ifdef WITH_SYSTEMD_WATCHDOG
+
370  iWatchdog.startWatchdog();
+
371 #endif /*WITH_SYSTEMD_WATCHDOG*/
+
372 
+
373  //start the mainloop here....
+
374  iSocketHandler.start_listenting();
+
375 }
+
376 
+
383 int main(int argc, char *argv[], char** envp)
+
384 {
+
385  (void) envp;
+
386  listCommandPluginDirs.push_back(std::string(DEFAULT_PLUGIN_COMMAND_DIR));
+
387  listRoutingPluginDirs.push_back(std::string(DEFAULT_PLUGIN_ROUTING_DIR));
+
388 
+
389  //now the signal handler:
+
390  struct sigaction signalAction;
+
391  memset(&signalAction, '\0', sizeof(signalAction));
+
392  signalAction.sa_sigaction = &signalHandler;
+
393  signalAction.sa_flags = SA_SIGINFO;
+
394  sigaction(SIGINT, &signalAction, NULL);
+
395  sigaction(SIGQUIT, &signalAction, NULL);
+
396  sigaction(SIGTERM, &signalAction, NULL);
+
397  sigaction(SIGHUP, &signalAction, NULL);
+
398 
+
399  struct sigaction signalChildAction;
+
400  memset(&signalChildAction, '\0', sizeof(signalChildAction));
+
401  signalChildAction.sa_flags = SA_NOCLDWAIT;
+
402  sigaction(SIGCHLD, &signalChildAction, NULL);
+
403 
+
404  //register new out of memory handler
+
405  std::set_new_handler(&OutOfMemoryHandler);
+
406 
+
407  try
+
408  {
+
409  //we do this to catch all exceptions and have a graceful ending just in case
+
410  mainProgram(argc,argv);
+
411  }
+
412 
+
413  catch (std::exception& exc)
+
414  {
+
415  logError("The AudioManager ended by throwing the exception", exc.what());
+
416  std::cerr<<"The AudioManager ended by throwing an exception "<<exc.what()<<std::endl;
+
417  exit(EXIT_FAILURE);
+
418  }
+
419 
+
420  close(fd0);
+
421  close(fd1);
+
422  close(fd2);
+
423  exit(0);
+
424 
+
425 }
+
426 
+
Implements the RoutingSendInterface.
+
int fd0
Definition: main.cpp:96
+
This class realizes the command Interface.
+
SPDX license identifier: MPL-2.0.
+
TCLAP::ValueArg< std::string > commandPluginDir("l","CommandPluginDir","path for looking for command plugins", false," ","string")
+
am_Error_e startupInterfaces(CAmCommandReceiver *iCommandReceiver)
+
int main(int argc, char *argv[], char **envp)
main
Definition: main.cpp:383
+
void daemonize()
daemonizes the AudioManager
Definition: main.cpp:114
+
void logInfo(T value, TArgs...args)
logs given values with infolevel with the default context
+ +
Implements an autorouting algorithm for connecting sinks and sources via different audio domains...
Definition: CAmRouter.h:152
+
TCLAP::ValueArg< std::string > additionalCommandPluginDirs("L","additionalCommandPluginDirs","additional path for looking for command plugins, can be used after -l option", false," ","string")
+
This class is used to receive all commands from the control interface.
+
static CAmCommonAPIWrapper * instantiateOnce(CAmSocketHandler *socketHandler, const std::string &applicationName="")
Creates a singleton instance attached to the provided socket handler object.
+
The am::CAmSocketHandler implements a mainloop for the AudioManager.
+
static CAmDltWrapper * instanctiateOnce(const char *appid, const char *description, const bool debugEnabled=true, const logDestination logDest=logDestination::DAEMON, const std::string Filename="", bool onlyError=false)
Instanciate the Dlt Wrapper.
+
SPDX license identifier: MPL-2.0.
+
static TCLAP::CmdLine * instance()
+
Implements the watchdog of the AudioManager with the help of systemd.
Definition: CAmWatchdog.h:35
+
void printCmdInformation()
Definition: main.cpp:164
+
void registerObserver(CAmDatabaseObserver *iObserver)
registers the Observer at the Database
+
SPDX license identifier: MPL-2.0.
+
SPDX license identifier: MPL-2.0.
+
int fd2
Definition: main.cpp:96
+
Implements the Receiving side of the RoutingPlugins.
+
int fd1
Definition: main.cpp:96
+
SPDX license identifier: MPL-2.0.
+
SPDX license identifier: MPL-2.0.
+
SPDX license identifier: MPL-2.0.
+
void OutOfMemoryHandler()
the out of memory handler
Definition: main.cpp:105
+
SPDX license identifier: MPL-2.0.
+
SPDX license identifier: MPL-2.0.
+
static TCLAP::CmdLine * instanciateOnce(const std::string &message, const char delimiter= ' ', const std::string &version="none", bool helpAndVersion=true)
+ +
TCLAP::ValueArg< std::string > routingPluginDir("r","RoutingPluginDir","path for looking for routing plugins", false," ","string")
+
SPDX license identifier: MPL-2.0.
+
TCLAP::SwitchArg dbusWrapperTypeBool("T","dbusType","DbusType to be used by CAmDbusWrapper: if option is selected, DBUS_SYSTEM is used otherwise DBUS_SESSION", false)
+
TCLAP::ValueArg< std::string > additionalRoutingPluginDirs("R","additionalRoutingPluginDirs","additional path for looking for routing plugins, can be used after -r option ", false," ","string")
+
TCLAP::SwitchArg dltEnable("e","dltEnable","Enables or disables dlt logging. Default = enabled", true)
+
sends data to the commandInterface, takes the file of the library that needs to be loaded ...
+
This class handles and abstracts the database.
+
SPDX license identifier: MPL-2.0.
+
Implements a telnetserver that can be used to connect to the audiomanager, retrieve some information ...
+
void startWatchdog()
starts the watchdog by sending ready to systemD
Definition: CAmWatchdog.cpp:95
+
SPDX license identifier: MPL-2.0.
+
static void CallsetControllerRundownSafe(int16_t signal)
+
TCLAP::ValueArg< unsigned int > dltOutput("O","dltOutput","defines where logs are written. 0=dlt-daemon(default), 1=command line, 2=file ", false, 0,"int")
+
am_Error_e startupInterfaces(CAmRoutingReceiver *iRoutingReceiver)
+
TCLAP::ValueArg< unsigned int > telnetPort("t","telnetport","The port that is used for telnet", false, DEFAULT_TELNETPORT,"int")
+
TCLAP::SwitchArg currentSettings("i","currentSettings","print current settings and exit", false)
+
void logError(T value, TArgs...args)
logs given values with errorlevel with the default context
+
std::vector< std::string > listRoutingPluginDirs
Definition: main.cpp:79
+
TCLAP::SwitchArg daemonizeAM("d","daemonize","daemonize Audiomanager. Better use systemd...", false)
+
SPDX license identifier: MPL-2.0.
+
This wraps dbus and provides everything needed to anyone who wants to use dbus (including plugins)...
+
SPDX license identifier: MPL-2.0.
+
SPDX license identifier: MPL-2.0.
+
static void CallsetControllerRundown(int16_t signal)
+
TCLAP::ValueArg< std::string > dltLogFilename("F","dltLogFilename","the name of the logfile, absolute path. Only if logging is et to file", false," ","string")
+
std::vector< std::string > listCommandPluginDirs
Definition: main.cpp:78
+
void mainProgram(int argc, char *argv[])
Definition: main.cpp:231
+
This class is used to send data to the CommandInterface.
+
This class handles and abstracts the database.
+
SPDX license identifier: MPL-2.0.
+
TCLAP::ValueArg< unsigned int > maxConnections("m","maxConnections","Maximal number of connections for telnet", false, MAX_TELNETCONNECTIONS,"int")
+
This class observes the Database and notifies other classes about important events, mainly the CommandSender.
+
TCLAP::ValueArg< std::string > controllerPlugin("c","controllerPlugin","use controllerPlugin full path with .so ending", false, CONTROLLER_PLUGIN_DIR,"string")
+
+
+ + + + -- cgit v1.2.1