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

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