skillet.cpp

00001 
00002 /***************************************************************************
00003  *  skillet.cpp - Skiller console tool
00004  *
00005  *  Created: Sat Mar 15 13:57:22 2008
00006  *  Copyright  2006-2008  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009 
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version.
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU Library General Public License for more details.
00019  *
00020  *  Read the full text in the LICENSE.GPL file in the doc directory.
00021  */
00022 
00023 #include <netcomm/fawkes/client.h>
00024 #include <blackboard/remote.h>
00025 #include <utils/system/argparser.h>
00026 #include <utils/system/signal.h>
00027 #include <core/threading/thread.h>
00028 #include <netcomm/fawkes/client_handler.h>
00029 
00030 #include <cstring>
00031 #include <cstdlib>
00032 #include <cstdio>
00033 #include <unistd.h>
00034 #include <csignal>
00035 #include <string>
00036 
00037 #include <readline/readline.h>
00038 #include <readline/history.h>
00039 
00040 #include <interfaces/SkillerInterface.h>
00041 
00042 using namespace fawkes;
00043 
00044 void
00045 print_usage(const char *program_name)
00046 {
00047   printf("Usage: %s [-h] [-r host[:port]]\n"
00048          " -h              This help message\n"
00049          " -r host[:port]  Remote host (and optionally port) to connect to\n",
00050          program_name);
00051 }
00052 
00053 static int
00054 event_hook()
00055 {
00056   return 0;
00057 }
00058 
00059 
00060 /** Skill shell thread.
00061  * This thread opens a network connection to a host and uses a RemoteBlackBoard
00062  * connection to send skill strings for execution. It also shows Skiller log messages
00063  * and uses the skiller network protocol.
00064  * @author Tim Niemueller
00065  */
00066 class SkillShellThread : public Thread, public FawkesNetworkClientHandler
00067 {
00068  public:
00069   /** Constructor.
00070    * @param argp argument parser
00071    */
00072   SkillShellThread(ArgumentParser *argp)
00073     : Thread("SkillShellThread", Thread::OPMODE_CONTINUOUS)
00074   {
00075     this->argp = argp;
00076     prompt = "-# ";
00077     just_connected = true;
00078     connection_died_recently = false;
00079 
00080     sif = NULL;
00081     using_history();
00082     // this is needed to get rl_done working
00083     rl_event_hook = event_hook;
00084 
00085     continuous = false;
00086 
00087     char *host = (char *)"localhost";
00088     unsigned short int port = 1910;
00089     bool free_host = argp->parse_hostport("r", &host, &port);
00090 
00091     c = new FawkesNetworkClient(host, port);
00092 
00093     if ( free_host )  free(host);
00094 
00095     c->register_handler(this, FAWKES_CID_SKILLER_PLUGIN);
00096     c->connect();
00097   }
00098 
00099   /** Destructor. */
00100   ~SkillShellThread()
00101   {
00102     printf("Finalizing\n");
00103 
00104     SkillerInterface::ReleaseControlMessage *rcm = new SkillerInterface::ReleaseControlMessage();
00105     sif->msgq_enqueue(rcm);
00106 
00107     usleep(500000);
00108 
00109     rbb->close(sif);
00110     delete rbb;
00111     rbb = NULL;
00112 
00113     c->deregister_handler(FAWKES_CID_SKILLER_PLUGIN);
00114     c->disconnect();
00115     delete c;
00116   }
00117 
00118 
00119   virtual void loop()
00120   {
00121     if ( c->connected() ) {
00122       if ( just_connected ) {
00123         just_connected = false;
00124         try {
00125           rbb = new RemoteBlackBoard(c);
00126           sif = rbb->open_for_reading<SkillerInterface>("Skiller");
00127           SkillerInterface::AcquireControlMessage *aqm = new SkillerInterface::AcquireControlMessage();
00128           sif->msgq_enqueue(aqm);
00129           usleep(100000);
00130         } catch (Exception &e) {
00131           e.print_trace();
00132           return;
00133         }
00134       }
00135 
00136       if ( argp->num_items() > 0 ) {
00137         std::string sks = "";
00138         const std::vector< const char * > & items = argp->items();
00139 
00140         std::vector< const char * >::const_iterator i = items.begin();
00141         sks = *i;
00142         ++i;
00143         for (; i != items.end(); ++i) {
00144           sks += " ";
00145           sks += *i;
00146         }
00147 
00148         SkillerInterface::ExecSkillMessage *esm = new SkillerInterface::ExecSkillMessage(sks.c_str());
00149         sif->msgq_enqueue(esm);
00150 
00151         usleep(100000);
00152         exit();
00153       } else {
00154         char *line = NULL;
00155 
00156         line = readline(prompt);
00157         if ( line ) {
00158           if (strcmp(line, "") != 0) {
00159 
00160             if ( strcmp(line, "cont") == 0 ) {
00161               printf("Switching to continuous skill execution mode\n");
00162               continuous = true;
00163             } else if (strcmp(line, "oneshot") == 0 ) {
00164               printf("Switching to one-shot skill execution mode\n");
00165               continuous = false;
00166             } else if (strcmp(line, "stop") == 0 ) {
00167               printf("Stopping continuous skill execution\n");
00168               SkillerInterface::StopExecMessage *sm = new SkillerInterface::StopExecMessage();
00169               sif->msgq_enqueue(sm);
00170             } else {
00171               printf("Executing: %s\n", line);
00172               if ( continuous ) {
00173                 SkillerInterface::ExecSkillContinuousMessage *escm = new SkillerInterface::ExecSkillContinuousMessage(line);
00174                 sif->msgq_enqueue(escm);
00175               } else {
00176                 SkillerInterface::ExecSkillMessage *esm = new SkillerInterface::ExecSkillMessage(line);
00177                 sif->msgq_enqueue(esm);
00178               }
00179             }
00180 
00181             add_history(line);
00182           }
00183         } else {
00184           if ( ! connection_died_recently ) {
00185             exit();
00186           }
00187         }
00188       }
00189     } else {
00190       if ( connection_died_recently ) {
00191         connection_died_recently = false;
00192         printf("Connection died\n");
00193         c->disconnect();
00194       }
00195       try {
00196         c->connect();
00197       } catch (Exception &e) {
00198         printf(".");
00199         fflush(stdout);
00200         sleep(1);
00201       }
00202     }
00203   }
00204 
00205   
00206   virtual void deregistered(unsigned int id) throw()
00207   {
00208   }
00209 
00210 
00211   virtual void inbound_received(FawkesNetworkMessage *m,
00212                                 unsigned int id) throw()
00213   {
00214   }
00215 
00216 
00217   virtual void connection_died(unsigned int id) throw()
00218   {
00219     prompt = "-# ";
00220 
00221     rbb->close(sif);
00222     delete rbb;
00223     rbb = NULL;
00224     sif = NULL;
00225 
00226     connection_died_recently = true;
00227 
00228     //fprintf(stdin, "\n");
00229     //kill(SIGINT);
00230     rl_done = 1;
00231   }
00232 
00233 
00234   virtual void connection_established(unsigned int id) throw()
00235   {
00236     printf("Connection established\n");
00237     just_connected = true;
00238     prompt = "+# ";
00239   }
00240 
00241 
00242  private:
00243   ArgumentParser *argp;
00244   FawkesNetworkClient *c;
00245   BlackBoard *rbb;
00246   SkillerInterface *sif;
00247   const char *prompt;
00248   bool just_connected;
00249   bool connection_died_recently;
00250 
00251   bool continuous;
00252 };
00253 
00254 
00255 /** Config tool main.
00256  * @param argc argument count
00257  * @param argv arguments
00258  */
00259 int
00260 main(int argc, char **argv)
00261 {
00262   ArgumentParser argp(argc, argv, "hr:");
00263 
00264   if ( argp.has_arg("h") ) {
00265     print_usage(argv[0]);
00266     exit(0);
00267   }
00268 
00269   SkillShellThread sst(&argp);
00270   sst.start();
00271   sst.join();
00272 
00273   return 0;
00274 }