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

Last change on this file since 19125 was 19125, checked in by tbretz, 11 months 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.