source: trunk/FACT++/src/scheduler.cc@ 11323

Last change on this file since 11323 was 11255, checked in by tbretz, 13 years ago
Updated regex to evaluate schedule-database.
File size: 32.4 KB
Line 
1#include <vector>
2
3#include <boost/bind.hpp>
4#if BOOST_VERSION < 104400
5#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 4))
6#undef BOOST_HAS_RVALUE_REFS
7#endif
8#endif
9#include <boost/thread.hpp>
10#include <boost/regex.hpp>
11
12#include <mysql++/mysql++.h>
13
14#include "Dim.h"
15#include "Time.h"
16#include "Event.h"
17#include "Shell.h"
18#include "StateMachineDim.h"
19#include "Connection.h"
20#include "Configuration.h"
21#include "Timers.h"
22#include "Console.h"
23#include "Converter.h"
24#include "LocalControl.h"
25
26#include "tools.h"
27
28using namespace std;
29using namespace boost::gregorian;
30using namespace boost::posix_time;
31
32// things to be done/checked/changed
33// * --schedule-database should be required
34// * move definition of config parameters to AutoScheduler class
35// + read in from config
36// * in some (all?) loops iterator over vector can be replaced by counter
37
38// other things to do
39//
40// define what to transmit as info/warn/error
41
42
43// config parameters:
44// mintime
45// runtimec
46// runtimep
47// repostime
48
49// missing:
50//
51// calculate time for std obs
52// calculate sun set/rise
53//
54// return errors and other otherput from sendcommand to webinterface
55
56// in which cases should the scheduler go in error state?
57// when db is unavailable
58// does one also need a 'set scheduler to ready' function then?
59// do we want any error state at all?
60
61
62// =========================================================================
63
64template <class T>
65class AutoScheduler : public T
66{
67 bool fNextIsPreview;
68public:
69 enum states_t
70 {
71 kSM_Scheduling=1,
72 kSM_Comitting,
73 };
74
75 struct ObservationParameters
76 {
77 int obskey;
78 int obsmode;
79 int obstype;
80 int splitflag;
81 int telsetup;
82 float fluxweight;
83 float slope;
84 float flux;
85 float ra;
86 float dec;
87 ptime start;
88 ptime stop;
89 time_duration duration_db;
90 string sourcename;
91 int sourcekey;
92 };
93
94 struct FixedObs
95 {
96 int obskey;
97 int sourcekey;
98 string sourcename;
99 int obsmode;
100 int obstype;
101 int telsetup;
102 float ra;
103 float dec;
104 ptime start;
105 ptime stop;
106 };
107
108 // will need other types of obs
109 // FloatingObs (duration < stop-start + splitflag no)
110 // FloatingSplittedObs (duration < stop-start + splitflag yes)
111 // FixedSlot, i.e. just block a time slot
112
113 struct StdObs
114 {
115 int obskey_std;
116 int sourcekey_std;
117 string sourcename_std;
118 int obsmode_std;
119 int obstype_std;
120 int telsetup_std;
121 float fluxweight_std;
122 float slope_std;
123 float flux_std;
124 float ra_std;
125 float dec_std;
126 ptime obsstdstart;
127 ptime obsstdstop;
128 };
129
130 struct ScheduledObs
131 {
132 int obskey_obs;
133 int sourcekey_obs;
134 string sourcename_obs;
135 int obsmode_obs;
136 int obstype_obs;
137 int telsetup_obs;
138 ptime obsstart;
139 ptime obsstop;
140 };
141
142 struct ScheduledRun
143 {
144 //int runnumber; // to be seen, if runnumber is needed
145 int obskey_run;
146 int runtype;
147 int sourcekey_run;
148 string sourcename_run;//for convenience
149 int obsmode_run;
150 int obstype_run;
151 int telsetup_run;
152 ptime runstart;
153 ptime runstop;
154 };
155
156 string fDatabase;
157 string fDBName;
158 int fDurationCalRun; //unit: minutes
159 int fDurationPedRun; //unit: minutes
160 int fDurationRepos; //unit: minutes
161
162 int Schedule()
163 {
164 bool error = false;
165
166 time_duration runtimec(0, fDurationCalRun, 0);
167 time_duration runtimep(0, fDurationPedRun, 0);
168 time_duration repostime(0, fDurationRepos, 0);
169 time_duration mintime(1, 0, 0);
170
171 const ptime startsched(microsec_clock::local_time());
172 const ptime stopsched=startsched+years(1);
173
174 ostringstream str;
175 str << "Scheduling for the period from " << startsched << " to " << stopsched;
176 T::Message(str);
177
178 static const boost::regex expr("([[:word:].-]+):(.+)@([[:word:].-]+)(:([[:digit:]]+))?/([[:word:].-]+)");
179 // 2: user
180 // 4: pass
181 // 5: server
182 // 7: port
183 // 9: db
184
185 boost::smatch what;
186 if (!boost::regex_match(fDatabase, what, expr, boost::match_extra))
187 {
188 ostringstream msg;
189 msg << "Regex to parse database '" << fDatabase << "' empty.";
190 T::Error(msg);
191 return T::kSM_Error;
192 }
193
194 if (what.size()!=7)
195 {
196 ostringstream msg;
197 msg << "Parsing database name failed: '" << fDatabase << "'";
198 T::Error(msg);
199 return T::kSM_Error;
200 }
201
202 const string user = what[1];
203 const string passwd = what[2];
204 const string server = what[3];
205 const string db = fDBName.empty() ? what[6] : fDBName;
206 const int port = atoi(string(what[5]).c_str());
207
208 ostringstream dbnamemsg;
209 dbnamemsg << "Scheduling started -> using database " << db << ".";
210 T::Message(dbnamemsg);
211
212 str.str("");
213 str << "Connecting to '";
214 if (!user.empty())
215 str << user << "@";
216 str << server;
217 if (port)
218 str << ":" << port;
219 if (!db.empty())
220 str << "/" << db;
221 str << "'";
222 T::Info(str);
223
224 mysqlpp::Connection conn(db.c_str(), server.c_str(), user.c_str(), passwd.c_str(), port);
225 /* throws exceptions
226 if (!conn.connected())
227 {
228 ostringstream msg;
229 msg << "MySQL connection error: " << conn.error();
230 T::Error(msg);
231 return T::kSM_Error;
232 }*/
233
234 // get observation parameters from DB
235 // maybe order by priority?
236 const mysqlpp::StoreQueryResult res =
237 conn.query("SELECT fObservationKEY, fStartTime, fStopTime, fDuration, fSourceName, fSourceKEY, fSplitFlag, fFluxWeight, fSlope, fFlux, fRightAscension, fDeclination, fObservationModeKEY, fObservationTypeKEY , fTelescopeSetupKEY FROM ObservationParameters LEFT JOIN Source USING(fSourceKEY) ORDER BY fStartTime").store();
238 // FIXME: Maybe we have to check for a successfull
239 // query but an empty result
240 /* thorws exceptions?
241 if (!res)
242 {
243 ostringstream msg;
244 msg << "MySQL query failed: " << query.error();
245 T::Error(msg);
246 return T::kSM_Error;
247 }*/
248
249 str.str("");
250 str << "Found " << res.num_rows() << " Observation Parameter sets.";
251 T::Debug(str);
252
253 ObservationParameters olist[res.num_rows()];
254 vector<FixedObs> obsfixedlist;
255 vector<StdObs> obsstdlist;
256 vector<ScheduledObs> obslist;
257 vector<ScheduledRun> runlist;
258
259 // loop over observation parameters from DB
260 // fill these parameters into FixedObs and StdObs
261 int counter=0;
262 int counter2=0;
263 int counter3=0;
264 cout << "Obs: <obskey> <sourcename>(<sourcekey>, <fluxweight>) from <starttime> to <stoptime>" << endl;
265 for (vector<mysqlpp::Row>::const_iterator v=res.begin(); v<res.end(); v++)
266 {
267 cout << " Obs: " << (*v)[0].c_str() << " " << (*v)[4].c_str() << "(" << (*v)[5].c_str() << flush;
268 cout << ", " << (*v)[7].c_str() << ")" << flush;
269 cout << " from " << (*v)[1].c_str() << " to " << (*v)[2].c_str() << endl;
270
271 //0: obskey
272 //1: startime
273 //2: stoptime
274 //3: duration
275 //4: sourcename
276 //5: sourcekey
277 //6: splitflag
278 //7: fluxweight
279 //8: slope
280 //9: flux
281 //10: ra
282 //11: dec
283 //12: obsmode
284 //13: obstype
285 //14: telsetup
286 stringstream t1;
287 stringstream t2;
288 stringstream t3;
289 t1 << (*v)[1].c_str();
290 t2 << (*v)[2].c_str();
291 t3 << (*v)[3].c_str();
292
293 //boost::posix_time::time_duration mintime(0,conf.Get<int>("mintime"), 0);
294 t1 >> Time::sql >> olist[counter].start;
295 t2 >> Time::sql >> olist[counter].stop;
296 t3 >> olist[counter].duration_db;
297 const time_period period(olist[counter].start, olist[counter].stop);
298
299 olist[counter].sourcename=(*v)[4].c_str();
300 olist[counter].sourcekey=(*v)[5];
301
302 if (!(*v)[0].is_null())
303 olist[counter].obskey=(*v)[0];
304 if (!(*v)[12].is_null())
305 olist[counter].obsmode=(*v)[12];
306 if (!(*v)[13].is_null())
307 olist[counter].obstype=(*v)[13];
308 if (!(*v)[14].is_null())
309 olist[counter].telsetup=(*v)[14];
310 if (!(*v)[6].is_null())
311 olist[counter].splitflag=(*v)[6];
312 if (!(*v)[7].is_null())
313 olist[counter].fluxweight=(*v)[7];
314 else
315 olist[counter].fluxweight=0;//set fluxweight to 0 for check below
316 if (!(*v)[8].is_null())
317 olist[counter].slope=(*v)[8];
318 if (!(*v)[9].is_null())
319 olist[counter].flux=(*v)[9];
320 if (!(*v)[10].is_null())
321 olist[counter].ra=(*v)[10];
322 if (!(*v)[11].is_null())
323 olist[counter].dec=(*v)[11];
324
325 // time_duration cannot be used, as only up to 99 hours are handeled
326 const time_duration duration = period.length();
327
328 /*
329 if (olist[counter].stoptime < olist[counter].starttime+mintime)
330 cout << " ====> WARN: Observation too short. " << endl;
331
332 if (olist[counter].starttime.is_not_a_date_time())
333 cout << " WARN: starttime not a date_time. " << endl;
334 else
335 cout << " start: " << Time::sql << olist[counter].starttime << endl;
336 if (olist[counter].stoptime.is_not_a_date_time())
337 cout << " WARN: stoptime not a date_time. " << endl;
338 else
339 cout << " stop: " << Time::sql << olist[counter].stoptime << endl;
340 if (!(olist[counter].starttime.is_not_a_date_time() || olist[counter].stoptime.is_not_a_date_time()))
341 cout << " diff: " << period << endl;
342 if (olist[counter].stoptime < olist[counter].starttime)
343 cout << " ====> WARN: stop time (" << olist[counter].stoptime << ") < start time (" << olist[counter].starttime << "). " << endl;
344 cout << "diff: " << duration << flush;
345 cout << "dur_db: " << olist[counter].duration_db << endl;
346 */
347
348 // always filled: obstype
349 //
350 // fixed observations:
351 // filled: starttime, stoptime
352 // not filled: fluxweight
353 // maybe filled: obsmode, telsetup, source (not filled for FixedSlotObs)
354 // maybe filled: duration (filled for FloatingObs and FloatingSplittedObs)
355 // maybe filled: splitflag (filled for FloatingSplittedObs)
356 //
357 // std observations:
358 // filled: fluxweight, telsetup, obsmore, source
359 // not filled: starttime, stoptime, duration
360
361 // fixed observations
362 if (!(olist[counter].stop.is_not_a_date_time()
363 && olist[counter].start.is_not_a_date_time())
364 && olist[counter].fluxweight==0
365 )
366 {
367 obsfixedlist.resize(counter2+1);
368 obsfixedlist[counter2].start=olist[counter].start;
369 obsfixedlist[counter2].stop=olist[counter].stop;
370 obsfixedlist[counter2].sourcename=olist[counter].sourcename;
371 obsfixedlist[counter2].obskey=olist[counter].obskey;
372 obsfixedlist[counter2].obstype=olist[counter].obstype;
373 obsfixedlist[counter2].obsmode=olist[counter].obsmode;
374 obsfixedlist[counter2].telsetup=olist[counter].telsetup;
375 obsfixedlist[counter2].sourcekey=olist[counter].sourcekey;
376 obsfixedlist[counter2].ra=olist[counter].ra;
377 obsfixedlist[counter2].dec=olist[counter].dec;
378 counter2++;
379 }
380
381 // std obs
382 if (olist[counter].stop.is_not_a_date_time()
383 && olist[counter].start.is_not_a_date_time()
384 && olist[counter].fluxweight>0
385 )
386 {
387 obsstdlist.resize(counter3+1);
388 obsstdlist[counter3].sourcename_std=olist[counter].sourcename;
389 obsstdlist[counter3].obskey_std=olist[counter].obskey;
390 obsstdlist[counter3].obsmode_std=olist[counter].obsmode;
391 obsstdlist[counter3].obstype_std=olist[counter].obstype;
392 obsstdlist[counter3].telsetup_std=olist[counter].telsetup;
393 obsstdlist[counter3].sourcekey_std=olist[counter].sourcekey;
394 obsstdlist[counter3].fluxweight_std=olist[counter].fluxweight;
395 obsstdlist[counter3].flux_std=olist[counter].flux;
396 obsstdlist[counter3].slope_std=olist[counter].slope;
397 obsstdlist[counter3].ra_std=olist[counter].ra;
398 obsstdlist[counter3].dec_std=olist[counter].dec;
399 counter3++;
400 }
401
402 counter++;
403 }
404 ostringstream fixedobsmsg;
405 fixedobsmsg << obsfixedlist.size() << " fixed observations found. ";
406 T::Message(fixedobsmsg);
407 cout << obsfixedlist.size() << " fixed observations found. " << endl;
408
409 ostringstream stdobsmsg;
410 stdobsmsg << obsstdlist.size() << " standard observations found. ";
411 T::Message(stdobsmsg);
412 cout << obsstdlist.size() << " standard observations found. " << endl;
413
414 // loop to add the fixed observations to the ScheduledObs list
415 // performed checks:
416 // * overlap of fixed observations: the overlap is split half-half
417 // * check for scheduling time range: only take into account fixed obs within the range
418 // missing checks and evaluation
419 // * check for mintime (pb with overlap checks)
420 // * check for sun
421 // * check for moon
422 counter2=0;
423 int skipcounter=0;
424 ptime finalobsfixedstart;
425 ptime finalobsfixedstop;
426 time_duration delta0(0,0,0);
427
428 cout << "Fixed Observations: " << endl;
429 for (struct vector<FixedObs>::const_iterator vobs=obsfixedlist.begin(); vobs!=obsfixedlist.end(); vobs++)
430 {
431 if (obsfixedlist[counter2].start < startsched
432 || obsfixedlist[counter2].stop > stopsched)
433 {
434 ostringstream skipfixedobsmsg;
435 skipfixedobsmsg << "Skip 1 fixed observation (obskey ";
436 skipfixedobsmsg << obsfixedlist[counter2].obskey;
437 skipfixedobsmsg << ") as it is out of scheduling time range.";
438 T::Message(skipfixedobsmsg);
439
440 counter2++;
441 skipcounter++;
442 continue;
443 }
444 counter3=0;
445
446 time_duration delta1=delta0;
447 time_duration delta2=delta0;
448
449 finalobsfixedstart=obsfixedlist[counter2].start;
450 finalobsfixedstop=obsfixedlist[counter2].stop;
451
452 for (struct vector<FixedObs>::const_iterator vobs5=obsfixedlist.begin(); vobs5!=obsfixedlist.end(); vobs5++)
453 {
454 if (vobs5->start < obsfixedlist[counter2].stop
455 && obsfixedlist[counter2].stop <= vobs5->stop
456 && obsfixedlist[counter2].start <= vobs5->start
457 && counter2!=counter3)
458 {
459 delta1=(obsfixedlist[counter2].stop-vobs5->start)/2;
460 finalobsfixedstop=obsfixedlist[counter2].stop-delta1;
461
462 ostringstream warndelta1;
463 warndelta1 << "Overlap between two fixed observations (";
464 warndelta1 << obsfixedlist[counter2].obskey << " ";
465 warndelta1 << vobs5->obskey << "). The stoptime of ";
466 warndelta1 << obsfixedlist[counter2].obskey << " has been changed.";
467 T::Warn(warndelta1);
468 }
469 if (vobs5->start <= obsfixedlist[counter2].start
470 && obsfixedlist[counter2].start < vobs5->stop
471 && obsfixedlist[counter2].stop >= vobs5->stop
472 && counter2!=counter3)
473 {
474 delta2=(vobs5->stop-obsfixedlist[counter2].start)/2;
475 finalobsfixedstart=obsfixedlist[counter2].start+delta2;
476
477 ostringstream warndelta2;
478 warndelta2 << "Overlap between two fixed observations (";
479 warndelta2 << obsfixedlist[counter2].obskey << " ";
480 warndelta2 << vobs5->obskey << "). The starttime of ";
481 warndelta2 << obsfixedlist[counter2].obskey << " has been changed.";
482
483 T::Warn(warndelta2);
484 }
485 counter3++;
486 }
487
488 const int num=counter2-skipcounter;
489 obslist.resize(num+1);
490 obslist[num].obsstart=finalobsfixedstart;
491 obslist[num].obsstop=finalobsfixedstop;
492 obslist[num].sourcename_obs=obsfixedlist[counter2].sourcename;
493 obslist[num].obsmode_obs=obsfixedlist[counter2].obsmode;
494 obslist[num].obstype_obs=obsfixedlist[counter2].obstype;
495 obslist[num].telsetup_obs=obsfixedlist[counter2].telsetup;
496 obslist[num].sourcekey_obs=obsfixedlist[counter2].sourcekey;
497 obslist[num].obskey_obs=obsfixedlist[counter2].obskey;
498 counter2++;
499
500 cout << " " << vobs->sourcename << " " << vobs->start;
501 cout << " - " << vobs->stop << endl;
502 }
503 ostringstream obsmsg;
504 obsmsg << "Added " << obslist.size() << " fixed observations to ScheduledObs. ";
505 T::Message(obsmsg);
506 cout << "Added " << obslist.size() << " fixed observations to ScheduledObs. " << endl;
507
508 for (int i=0; i<(int)obsstdlist.size(); i++)
509 {
510 for (int j=0; j<(int)obsstdlist.size(); j++)
511 {
512 if (obsstdlist[i].sourcekey_std == obsstdlist[j].sourcekey_std && i!=j)
513 {
514 cout << "One double sourcekey in std observations: " << obsstdlist[j].sourcekey_std << endl;
515 ostringstream errdoublestd;
516 errdoublestd << "One double sourcekey in std observations: " << obsstdlist[j].sourcekey_std << " (" << obsstdlist[j].sourcename_std << ").";
517 T::Error(errdoublestd);
518 T::Message("Scheduling stopped.");
519 return error ? T::kSM_Error : T::kSM_Ready;
520 }
521 }
522 }
523
524 // loop over nights
525 // calculate sunset and sunrise
526 // check if there is already scheduled obs in that night
527 //
528
529 // in this loop the standard observations shall be
530 // checked, evaluated
531 // the observation times shall be calculated
532 // and the observations added to the ScheduledObs list
533 cout << "Standard Observations: " << endl;
534 for (struct vector<StdObs>::const_iterator vobs2=obsstdlist.begin(); vobs2!=obsstdlist.end(); vobs2++)
535 {
536 cout << " " << vobs2->sourcename_std << endl;
537 }
538
539 // in this loop the ScheduledRuns are filled
540 // (only data runs -> no runtype yet)
541 // might be merged with next loop
542 counter2=0;
543 for (struct vector<ScheduledObs>::const_iterator vobs3=obslist.begin(); vobs3!=obslist.end(); vobs3++)
544 {
545 runlist.resize(counter2+1);
546 runlist[counter2].runstart=obslist[counter2].obsstart;
547 runlist[counter2].runstop=obslist[counter2].obsstop;
548 runlist[counter2].sourcename_run=obslist[counter2].sourcename_obs;
549 runlist[counter2].obsmode_run=obslist[counter2].obsmode_obs;
550 runlist[counter2].obstype_run=obslist[counter2].obstype_obs;
551 runlist[counter2].telsetup_run=obslist[counter2].telsetup_obs;
552 runlist[counter2].sourcekey_run=obslist[counter2].sourcekey_obs;
553 runlist[counter2].obskey_run=obslist[counter2].obskey_obs;
554 counter2++;
555 //cout << (*vobs3).sourcename_obs << endl;
556 }
557
558 //delete old scheduled runs from the DB
559 const mysqlpp::SimpleResult res0 =
560 conn.query("DELETE FROM ScheduledRun").execute();
561 // FIXME: Maybe we have to check for a successfull
562 // query but an empty result
563 /* throws exceptions
564 if (!res0)
565 {
566 ostringstream msg;
567 msg << "MySQL query failed: " << query0.error();
568 T::Error(msg);
569 return T::kSM_Error;
570 }*/
571
572 // in this loop the ScheduledRuns are inserted to the DB
573 // before the runtimes are adapted according to
574 // duration of P-Run, C-Run and repositioning
575 counter3=0;
576 int insertcount=0;
577 ptime finalstarttime;
578 ptime finalstoptime;
579 for (struct vector<ScheduledRun>::const_iterator vobs4=runlist.begin(); vobs4!=runlist.end(); vobs4++)
580 {
581 for (int i=2; i<5; i++)
582 {
583 switch(i)
584 {
585 case 2:
586 finalstarttime=runlist[counter3].runstart+repostime+runtimec+runtimep;
587 finalstoptime=runlist[counter3].runstop;
588 break;
589 case 3:
590 finalstarttime=runlist[counter3].runstart+repostime;
591 finalstoptime=runlist[counter3].runstart+runtimep+repostime;
592 break;
593 case 4:
594 finalstarttime=runlist[counter3].runstart+runtimep+repostime;
595 finalstoptime=runlist[counter3].runstart+repostime+runtimep+runtimec;
596 break;
597 }
598 ostringstream q1;
599 //cout << (*vobs4).sourcename_run << endl;
600 q1 << "INSERT ScheduledRun set fStartTime='" << Time::sql << finalstarttime;
601 q1 << "', fStopTime='" << Time::sql << finalstoptime;
602 q1 << "', fSourceKEY='" << (*vobs4).sourcekey_run;
603 q1 << "', fObservationKEY='" << (*vobs4).obskey_run;
604 q1 << "', fRunTypeKEY='" << i;
605 q1 << "', fTelescopeSetupKEY='" << (*vobs4).telsetup_run;
606 q1 << "', fObservationTypeKEY='" << (*vobs4).obstype_run;
607 q1 << "', fObservationModeKEY='" << (*vobs4).obsmode_run;
608 q1 << "'";
609
610 //cout << "executing query: " << q1.str() << endl;
611
612 const mysqlpp::SimpleResult res1 = conn.query(q1.str()).execute();
613 // FIXME: Maybe we have to check for a successfull
614 // query but an empty result
615 /* throws exceptions
616 if (!res1)
617 {
618 ostringstream msg;
619 msg << "MySQL query failed: " << query1.error();
620 T::Error(str);
621 return T::kSM_Error;
622 }*/
623 insertcount++;
624 }
625 counter3++;
626 }
627 ostringstream insertmsg;
628 insertmsg << "Inserted " << insertcount << " runs into the DB.";
629 T::Message(insertmsg);
630 //usleep(3000000);
631 T::Message("Scheduling done.");
632
633 return error;
634 }
635
636 /*
637 // commit probably done by webinterface
638 int Commit()
639 {
640 ostringstream str;
641 str << "Comitting preview (id=" << fSessionId << ")";
642 T::Message(str);
643
644 usleep(3000000);
645 T::Message("Comitted.");
646
647 fSessionId = -1;
648
649 bool error = false;
650 return error ? T::kSM_Error : T::kSM_Ready;
651 }
652 */
653
654 AutoScheduler(ostream &out=cout) : T(out, "SCHEDULER"), fNextIsPreview(true), fDBName("")
655 {
656 AddStateName(kSM_Scheduling, "Scheduling", "Scheduling in progress.");
657
658 AddEvent(kSM_Scheduling, "SCHEDULE", "C", T::kSM_Ready)
659 ("FIXME FIXME FIXME (explanation for the command)"
660 "|database[string]:FIXME FIXME FIMXE (meaning and format)");
661
662 AddEvent(T::kSM_Ready, "RESET", T::kSM_Error)
663 ("Reset command to get out of the error state");
664
665 //AddEvent(kSM_Comitting, "COMMIT", T::kSM_Ready);
666
667 T::PrintListOfEvents();
668 }
669
670 int Execute()
671 {
672 switch (T::GetCurrentState())
673 {
674 case kSM_Scheduling:
675 try
676 {
677 return Schedule() ? T::kSM_Error : T::kSM_Ready;
678 }
679 catch (const mysqlpp::Exception &e)
680 {
681 T::Error(string("MySQL: ")+e.what());
682 return T::kSM_Error;
683 }
684
685 // This does an autmatic reset (FOR TESTING ONLY)
686 case T::kSM_Error:
687 return T::kSM_Ready;
688 }
689 return T::GetCurrentState();
690 }
691
692 int Transition(const Event &evt)
693 {
694 switch (evt.GetTargetState())
695 {
696 case kSM_Scheduling:
697 if (evt.GetSize()>0)
698 fDBName = evt.GetText();
699 break;
700 }
701
702 return evt.GetTargetState();
703 }
704
705 int EvalConfiguration(const Configuration &conf)
706 {
707 fDatabase = conf.Get<string>("schedule-database");
708 fDurationCalRun = conf.Get<int>("duration-cal-run");
709 fDurationPedRun = conf.Get<int>("duration-ped-run");
710 fDurationRepos = conf.Get<int>("duration-repos");
711
712 if (!conf.Has("schedule"))
713 return -1;
714
715 fDBName = conf.Get<string>("schedule");
716 return Schedule();
717 }
718
719};
720
721
722// ------------------------------------------------------------------------
723#include "Main.h"
724/*
725void RunThread(StateMachineImp *io_service)
726{
727 // This is necessary so that the StateMachien Thread can signal the
728 // Readline to exit
729 io_service->Run();
730 Readline::Stop();
731}
732*/
733/*
734template<class S>
735int RunDim(Configuration &conf)
736{
737 WindowLog wout;
738
739 ReadlineColor::PrintBootMsg(wout, conf.GetName(), false);
740
741 //log.SetWindow(stdscr);
742 if (conf.Has("log"))
743 if (!wout.OpenLogFile(conf.Get<string>("log")))
744 wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
745
746 // Start io_service.Run to use the StateMachineImp::Run() loop
747 // Start io_service.run to only use the commandHandler command detaching
748 AutoScheduler<S> io_service(wout);
749 if (!io_service.EvalConfiguration(conf))
750 return -1;
751
752 io_service.Run();
753
754 return 0;
755}
756*/
757
758template<class T, class S>
759int RunShell(Configuration &conf)
760{
761 return Main<T, AutoScheduler<S>>(conf);
762 /*
763 static T shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
764
765 WindowLog &win = shell.GetStreamIn();
766 WindowLog &wout = shell.GetStreamOut();
767
768 if (conf.Has("log"))
769 if (!wout.OpenLogFile(conf.Get<string>("log")))
770 win << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
771
772 AutoScheduler<S> io_service(wout);
773 if (!io_service.EvalConfiguration(conf))
774 return -1;
775
776 shell.SetReceiver(io_service);
777
778// boost::thread t(boost::bind(&AutoScheduler<S>::Run, &io_service));
779 boost::thread t(boost::bind(RunThread, &io_service));
780
781 if (conf.Has("cmd"))
782 {
783 const vector<string> v = conf.Get<vector<string>>("cmd");
784 for (vector<string>::const_iterator it=v.begin(); it!=v.end(); it++)
785 shell.ProcessLine(*it);
786 }
787
788 if (conf.Has("exec"))
789 {
790 const vector<string> v = conf.Get<vector<string>>("exec");
791 for (vector<string>::const_iterator it=v.begin(); it!=v.end(); it++)
792 shell.Execute(*it);
793 }
794
795 if (conf.Get<bool>("quit"))
796 shell.Stop();
797
798 shell.Run(); // Run the shell
799 io_service.Stop(); // Signal Loop-thread to stop
800 // io_service.Close(); // Obsolete, done by the destructor
801 // wout << "join: " << t.timed_join(boost::posix_time::milliseconds(0)) << endl;
802
803 // Wait until the StateMachine has finished its thread
804 // before returning and destroying the dim objects which might
805 // still be in use.
806 t.join();
807
808 return 0;
809*/
810}
811
812void SetupConfiguration(Configuration &conf)
813{
814 const string n = conf.GetName()+".log";
815
816 //po::options_description config("Program options");
817 po::options_description config("Configuration");
818 config.add_options()
819 ("dns", var<string>("localhost"), "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
820 ("log,l", var<string>(n), "Write log-file")
821 ("no-dim,d", po_switch(), "Disable dim services")
822 ("console,c", var<int>(), "Use console (0=shell, 1=simple buffered, X=simple unbuffered)")
823 ("cmd", vars<string>(), "Execute one or more commands at startup")
824 ("exec,e", vars<string>(), "Execute one or more scrips at startup")
825 ("quit", po_switch(), "Quit after startup");
826
827 po::options_description control("Scheduler options");
828 control.add_options()
829 ("schedule-database", var<string>()
830#if BOOST_VERSION >= 104200
831 ->required()
832#endif
833 , "Database link as in\n\tuser:password@server[:port]/database\nOverwrites options from the default configuration file.")
834 ("schedule", var<string>(), "")
835 ("mintime", var<int>(), "minimum observation time")
836 ("duration-cal-run", var<int>()
837#if BOOST_VERSION >= 104200
838 ->required()
839#endif
840 , "duration of calibration run [min]")
841 ("duration-ped-run", var<int>()
842#if BOOST_VERSION >= 104200
843 ->required()
844#endif
845 , "duration of pedestal run [min]")
846 ("duration-repos", var<int>()
847#if BOOST_VERSION >= 104200
848 ->required()
849#endif
850 , "duration of repositioning [min]")
851 ;
852
853 po::positional_options_description p;
854 p.add("schedule", 1); // The first positional options
855
856 conf.AddEnv("dns", "DIM_DNS_NODE");
857 conf.AddOptions(config);
858 conf.AddOptions(control);
859 conf.SetArgumentPositions(p);
860}
861
862void PrintUsage()
863{
864 cout <<
865 "The scheduler... TEXT MISSING\n"
866 "\n"
867 "The default is that the program is started without user intercation. "
868 "All actions are supposed to arrive as DimCommands. Using the -c "
869 "option, a local shell can be initialized. With h or help a short "
870 "help message about the usuage can be brought to the screen.\n"
871 "\n"
872 "Usage: scheduler [-c type] [OPTIONS] <schedule-database>\n"
873 " or: scheduler [OPTIONS] <schedule-database>\n";
874 cout << endl;
875}
876
877void PrintHelp()
878{
879 /* Additional help text which is printed after the configuration
880 options goes here */
881}
882
883int main(int argc, const char* argv[])
884{
885 Configuration conf(argv[0]);
886 conf.SetPrintUsage(PrintUsage);
887 SetupConfiguration(conf);
888
889 po::variables_map vm;
890 try
891 {
892 vm = conf.Parse(argc, argv);
893 }
894#if BOOST_VERSION > 104000
895 catch (po::multiple_occurrences &e)
896 {
897 cerr << "Program options invalid due to: " << e.what() << " of '" << e.get_option_name() << "'." << endl;
898 return -1;
899 }
900#endif
901 catch (exception& e)
902 {
903 cerr << "Program options invalid due to: " << e.what() << endl;
904 return -1;
905 }
906
907 if (conf.HasVersion() || conf.HasPrint())
908 return -1;
909
910 if (conf.HasHelp())
911 {
912 PrintHelp();
913 return -1;
914 }
915
916 Dim::Setup(conf.Get<string>("dns"));
917
918// try
919 {
920 // No console access at all
921 if (!conf.Has("console"))
922 {
923 if (conf.Get<bool>("no-dim"))
924 return RunShell<LocalStream, StateMachine>(conf);
925 else
926 return RunShell<LocalStream, StateMachineDim>(conf);
927 }
928 // Cosole access w/ and w/o Dim
929 if (conf.Get<bool>("no-dim"))
930 {
931 if (conf.Get<int>("console")==0)
932 return RunShell<LocalShell, StateMachine>(conf);
933 else
934 return RunShell<LocalConsole, StateMachine>(conf);
935 }
936 else
937 {
938 if (conf.Get<int>("console")==0)
939 return RunShell<LocalShell, StateMachineDim>(conf);
940 else
941 return RunShell<LocalConsole, StateMachineDim>(conf);
942 }
943 }
944/* catch (std::exception& e)
945 {
946 std::cerr << "Exception: " << e.what() << "\n";
947 }*/
948
949 return 0;
950}
Note: See TracBrowser for help on using the repository browser.