00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include "Component/ModelManager.H"
00039 #include "Devices/BeoChip.H"
00040
00041 #include <fcntl.h>
00042 #include <stdio.h>
00043 #include <sys/stat.h>
00044 #include <sys/types.h>
00045 #include <unistd.h>
00046
00047
00048 struct BeobotLauncherApp {
00049 char *descrip1, *descrip2;
00050 char *name;
00051 char *cmd;
00052 };
00053
00054
00055 BeobotLauncherApp apps[100];
00056 int napps = 0;
00057
00058
00059 class BeobotLauncherListener : public BeoChipListener
00060 {
00061 public:
00062 BeobotLauncherListener(nub::soft_ref<BeoChip> beoc) :
00063 keepgoing(true), action(-1), idx(0), beochip(beoc) { }
00064
00065 virtual ~BeobotLauncherListener() { }
00066
00067 virtual void event(const BeoChipEventType t, const int valint,
00068 const float valfloat)
00069 {
00070 if (t == KBD)
00071 {
00072 if ((valint & 0x1) == 0 && idx > 0)
00073 display(--idx);
00074 if ((valint & 0x10) == 0 && idx < napps-1)
00075 display(++idx);
00076 if ((valint & 0x4) == 0) {
00077 LINFO("Launching: %s", apps[idx].cmd);
00078
00079 beochip->lcdClear();
00080 beochip->lcdPrintf(0, 0, " Launching: ");
00081 beochip->lcdPrintf(0, 2, "%s", apps[idx].name);
00082 usleep(800000);
00083 action = idx;
00084 }
00085 }
00086 }
00087
00088 virtual void display(const int i)
00089 {
00090 beochip->lcdPrintf(0, 1, "%s", apps[i].descrip1);
00091 beochip->lcdPrintf(0, 2, "%s", apps[i].descrip2);
00092 beochip->lcdPrintf(0, 3, "%s Start! %s",
00093 i > 0 ? "<<<<" : " ",
00094 i < napps-1 ? ">>>>" : " ");
00095 }
00096
00097 volatile bool keepgoing;
00098 volatile int action;
00099 volatile int idx;
00100 nub::soft_ref<BeoChip> beochip;
00101 };
00102
00103
00104 /*! This launcher should be placed in a cron or init script so that it
00105 will permanently be running. To prevent multiple copies of it from
00106 running at the same time, we use an flock on a file in /tmp, as
00107 suggested on a linuxquestions.org post (so even if the launcher dies
00108 badly, which may leave the temp file behind, it will be unlocked and
00109 will not prevent a new instance from starting). Here we use the
00110 BeoChip to let the user decide what to run. Just before we launch
00111 and monitor a new program, we clear and release the BeoChip so that
00112 the launched program can use it. Once the launched program
00113 terminates, we take the BeoChip over again and show our launch
00114 menu. */
00115 int main(const int argc, const char **argv)
00116 {
00117 MYLOGVERB = LOG_INFO;
00118
00119 // obtain a lock and check whether other instances of BeobotLauncher
00120 // are running; if so, abort:
00121 int fdlock; struct flock fl;
00122 fl.l_type = F_WRLCK; fl.l_whence = SEEK_SET;
00123 fl.l_start = 0; fl.l_len = 1;
00124
00125 if ( (fdlock = open("/tmp/BeobotLauncher.lock",
00126 O_WRONLY | O_CREAT, 0666)) == -1 )
00127 PLFATAL("Cannot open /tmp/BeobotLauncher.lock");
00128 if (fcntl(fdlock, F_SETLK, &fl) == -1)
00129 PLFATAL("Cannot lock /tmp/BeobotLauncher.lock");
00130
00131 // load our config file (list of possible actions):
00132 char buf[1000];
00133 FILE *f = fopen("/etc/BeobotLauncher.conf", "r");
00134 if (f == NULL) PLFATAL("Cannot open /etc/BeobotLauncher.conf");
00135 while(fgets(buf, 999, f)) {
00136 if (buf[0] == '#') continue;
00137 char *data = new char[strlen(buf)+1];
00138 strcpy(data, buf);
00139 apps[napps].descrip1 = data; data[20] = '\0';
00140 apps[napps].descrip2 = &data[21]; data[41] = '\0';
00141 apps[napps].name = &data[42]; data[62] = '\0';
00142 apps[napps].cmd = &data[63];
00143 napps ++;
00144 }
00145 fclose(f);
00146
00147 // instantiate a model manager:
00148 ModelManager manager("Beobot Launcher");
00149
00150 // Instantiate our various ModelComponents:
00151 nub::soft_ref<BeoChip> b(new BeoChip(manager));
00152 manager.addSubComponent(b);
00153
00154 // Parse command-line:
00155 if (manager.parseCommandLine(argc, argv, "<serdev>", 1, 1) == false)
00156 return(1);
00157
00158 // let's configure our serial device:
00159 b->setModelParamVal("BeoChipDeviceName", manager.getExtraArg(0));
00160
00161 // let's register our listener:
00162 rutz::shared_ptr<BeobotLauncherListener> lis(new BeobotLauncherListener(b));
00163 rutz::shared_ptr<BeoChipListener> lis2; lis2.dynCastFrom(lis); // cast down
00164 b->setListener(lis2);
00165 bool blinkon = false;
00166
00167 // let's get all our ModelComponent instances started:
00168 manager.start();
00169 b->lcdClear();
00170 b->lcdPrintf(0, 0, "-- BeobotLauncher --");
00171 b->debounceKeyboard(true);
00172 b->captureKeyboard(true);
00173 lis->display(0);
00174
00175 // main loop:
00176 while(lis->keepgoing)
00177 {
00178 // wait for an action code or a termination condition while we
00179 // blink out tail lights:
00180 while(lis->action == -1 && lis->keepgoing == true)
00181 {
00182 if (blinkon)
00183 { b->setDigitalOut(2, false); b->setDigitalOut(3, false);
00184 blinkon = false; }
00185 else
00186 { b->setDigitalOut(2, true); b->setDigitalOut(3, true);
00187 blinkon = true; }
00188
00189 usleep(250000);
00190 }
00191
00192 // if it's an action, let's execute it:
00193 if (lis->action != -1)
00194 {
00195 // first stop the manager to release the beochip:
00196 b->lcdClear();
00197 b->setDigitalOut(2, false); b->setDigitalOut(3, false);
00198 manager.stop();
00199 lis->idx = 0;
00200
00201 // now execute:
00202 if (system(apps[lis->action].cmd)) LERROR("Error in system()");
00203
00204 // let's get all our ModelComponent instances re-started:
00205 manager.start();
00206 b->lcdClear();
00207 b->lcdPrintf(0, 0, " Done with: ");
00208 b->lcdPrintf(0, 2, "%s", apps[lis->action].name);
00209
00210 usleep(800000);
00211
00212 b->lcdClear();
00213 b->lcdPrintf(0, 0, "-- BeobotLauncher --");
00214 b->debounceKeyboard(true);
00215 b->captureKeyboard(true);
00216 lis->display(0);
00217
00218 // done with this action:
00219 lis->action = -1;
00220 }
00221 }
00222
00223 // release our lock:
00224 fl.l_type = F_UNLCK;
00225 if (fcntl(fdlock, F_SETLK, &fl) == -1)
00226 PLERROR("Error unlocking /tmp/BeobotLauncher.lock");
00227 if (close(fdlock) == -1)
00228 PLERROR("Error closing /tmp/BeobotLauncher.lock");
00229 if (unlink("/tmp/BeobotLauncher.lock") == -1)
00230 PLERROR("Error deleting /tmp/BeobotLauncher.lock");
00231 return 0;
00232 }
00233
00234 // ######################################################################
00235 /* So things look consistent in everyone's emacs... */
00236 /* Local Variables: */
00237 /* indent-tabs-mode: nil */
00238 /* End: */