source: trunk/FACT++/src/drivectrl.cc@ 15213

Last change on this file since 15213 was 15211, checked in by tbretz, 12 years ago
Removed obsoleete includes.
File size: 49.1 KB
Line 
1#include <boost/bind.hpp>
2#include <boost/regex.hpp>
3
4#ifdef HAVE_SQL
5#include "Database.h"
6#endif
7
8#include "FACT.h"
9#include "Dim.h"
10#include "Event.h"
11#include "Shell.h"
12#include "StateMachineDim.h"
13#include "Connection.h"
14#include "LocalControl.h"
15#include "Configuration.h"
16#include "Timers.h"
17#include "Console.h"
18
19#include "HeadersDrive.h"
20
21namespace ba = boost::asio;
22namespace bs = boost::system;
23namespace dummy = ba::placeholders;
24
25using namespace std;
26using namespace Drive;
27
28// ------------------------------------------------------------------------
29
30class ConnectionDrive : public Connection
31{
32 int fState;
33
34 bool fIsVerbose;
35
36 // --verbose
37 // --hex-out
38 // --dynamic-out
39 // --load-file
40 // --leds
41 // --trigger-interval
42 // --physcis-coincidence
43 // --calib-coincidence
44 // --physcis-window
45 // --physcis-window
46 // --trigger-delay
47 // --time-marker-delay
48 // --dead-time
49 // --clock-conditioner-r0
50 // --clock-conditioner-r1
51 // --clock-conditioner-r8
52 // --clock-conditioner-r9
53 // --clock-conditioner-r11
54 // --clock-conditioner-r13
55 // --clock-conditioner-r14
56 // --clock-conditioner-r15
57 // ...
58
59 virtual void UpdatePointing(const Time &, const array<double, 2> &)
60 {
61 }
62
63 virtual void UpdateTracking(const Time &, const array<double, 8> &)
64 {
65 }
66
67 virtual void UpdateStatus(const Time &, const array<uint8_t, 3> &)
68 {
69 }
70
71 virtual void UpdateStarguider(const Time &, const DimStarguider &)
72 {
73 }
74
75 virtual void UpdateTPoint(const Time &, const DimTPoint &, const string &)
76 {
77 }
78
79public:
80 virtual void UpdateSource()
81 {
82 }
83 virtual void UpdateSource(const array<double, 6> &, const string& = "")
84 {
85 }
86
87protected:
88 map<uint16_t, int> fCounter;
89
90 ba::streambuf fBuffer;
91
92public:
93 static Time ReadTime(istream &in)
94 {
95 uint16_t y, m, d, hh, mm, ss, ms;
96 in >> y >> m >> d >> hh >> mm >> ss >> ms;
97
98 return Time(y, m, d, hh, mm, ss, ms*1000);
99 }
100
101 static double ReadAngle(istream &in)
102 {
103 char sgn;
104 uint16_t d, m;
105 float s;
106
107 in >> sgn >> d >> m >> s;
108
109 const double ret = ((60.0 * (60.0 * (double)d + (double)m) + s))/3600.;
110 return sgn=='-' ? -ret : ret;
111 }
112
113 double GetDevAbs(double nomzd, double meszd, double devaz)
114 {
115 nomzd *= M_PI/180;
116 meszd *= M_PI/180;
117 devaz *= M_PI/180;
118
119 const double x = sin(meszd) * sin(nomzd) * cos(devaz);
120 const double y = cos(meszd) * cos(nomzd);
121
122 return acos(x + y) * 180/M_PI;
123 }
124
125 uint16_t fDeviationLimit;
126 uint16_t fDeviationCounter;
127 uint16_t fDeviationMax;
128
129 uint64_t fTrackingCounter;
130
131protected:
132 void HandleReceivedReport(const boost::system::error_code& err, size_t bytes_received)
133 {
134 // Do not schedule a new read if the connection failed.
135 if (bytes_received==0 || err)
136 {
137 if (err==ba::error::eof)
138 Warn("Connection closed by remote host (FTM).");
139
140 // 107: Transport endpoint is not connected (bs::error_code(107, bs::system_category))
141 // 125: Operation canceled
142 if (err && err!=ba::error::eof && // Connection closed by remote host
143 err!=ba::error::basic_errors::not_connected && // Connection closed by remote host
144 err!=ba::error::basic_errors::operation_aborted) // Connection closed by us
145 {
146 ostringstream str;
147 str << "Reading from " << URL() << ": " << err.message() << " (" << err << ")";// << endl;
148 Error(str);
149 }
150 PostClose(err!=ba::error::basic_errors::operation_aborted);
151 return;
152 }
153
154 istream is(&fBuffer);
155
156 string line;
157 getline(is, line);
158
159 if (fIsVerbose)
160 Out() << line << endl;
161
162 StartReadReport();
163
164 if (line.substr(0, 13)=="DRIVE-STATUS ")
165 {
166 Message(line.substr(70));
167 return;
168 }
169
170 if (line.substr(0, 13)=="STARG-REPORT ")
171 {
172 istringstream stream(line.substr(16));
173
174 // 0: Error
175 // 1: Standby
176 // 2: Monitoring
177 uint16_t status1;
178 stream >> status1;
179 /*const Time t1 = */ReadTime(stream);
180
181 uint16_t status2;
182 stream >> status2;
183 /*const Time t2 = */ReadTime(stream);
184
185 double misszd, missaz;
186 stream >> misszd >> missaz;
187
188 const double zd = ReadAngle(stream);
189 const double az = ReadAngle(stream);
190
191 double cx, cy;
192 stream >> cx >> cy;
193
194 int ncor;
195 stream >> ncor;
196
197 double bright, mjd;
198 stream >> bright >> mjd;
199
200 int nled, nring, nstars;
201 stream >> nled >> nring >> nstars;
202
203 if (stream.fail())
204 return;
205
206 DimStarguider data;
207
208 data.fMissZd = misszd;
209 data.fMissAz = missaz;
210 data.fNominalZd = zd;
211 data.fNominalAz = az;
212 data.fCenterX = cx;
213 data.fCenterY = cy;
214 data.fNumCorrelated = ncor;
215 data.fBrightness = bright;
216 data.fNumLeds = nled;
217 data.fNumRings = nring;
218 data.fNumStars = nstars;
219
220 UpdateStarguider(Time(mjd), data);
221
222 return;
223
224 }
225
226 if (line.substr(0, 14)=="TPOINT-REPORT ")
227 {
228 istringstream stream(line.substr(17));
229
230 uint16_t status1;
231 stream >> status1;
232 const Time t1 = ReadTime(stream);
233
234 uint16_t status2;
235 stream >> status2;
236 /*const Time t2 =*/ ReadTime(stream);
237
238 char type;
239 stream >> type;
240 if (type != 'T')
241 return;
242
243 double az1, alt1, az2, alt2, ra, dec, dzd, daz;
244 stream >> az1 >> alt1 >> az2 >> alt2 >> ra >> dec >> dzd >> daz;
245
246 // c: center, s:start
247 double mjd, cmag, smag, cx, cy, sx, sy;
248 stream >> mjd >> cmag >> smag >> cx >> cy >> sx >> sy;
249
250 int nled, nring, nstar, ncor;
251 stream >> nled >> nring >> nstar >> ncor;
252
253 double bright, mag;
254 stream >> bright >> mag;
255
256 string name;
257 stream >> name;
258
259 if (stream.fail())
260 return;
261
262 DimTPoint tpoint;
263
264 tpoint.fRa = ra;
265 tpoint.fDec = dec;
266
267 tpoint.fNominalZd = 90-alt1-dzd;
268 tpoint.fNominalAz = 90-az1 +daz;
269
270 tpoint.fPointingZd = 90-alt1;
271 tpoint.fPointingAz = az1;
272
273 tpoint.fFeedbackZd = 90-alt2;
274 tpoint.fFeedbackAz = az2;
275
276 tpoint.fNumLeds = nled;
277 tpoint.fNumRings = nring;
278
279 tpoint.fCenterX = cx;
280 tpoint.fCenterY = cy;
281 tpoint.fCenterMag = cmag;
282
283 tpoint.fStarX = sx;
284 tpoint.fStarY = sy;
285 tpoint.fStarMag = smag;
286
287 tpoint.fRealMag = mag;
288
289 UpdateTPoint(t1, tpoint, name);
290
291 return;
292 }
293
294 if (line.substr(0, 13)=="DRIVE-REPORT ")
295 {
296 // DRIVE-REPORT M1
297 // 01 2011 05 14 11 31 19 038
298 // 02 1858 11 17 00 00 00 000
299 // + 000 00 000 + 000 00 000
300 // + 000 00 000
301 // 55695.480081
302 // + 000 00 000 + 000 00 000
303 // + 000 00 000 + 000 00 000
304 // 0000.000 0000.000
305 // 0 2
306
307 // status
308 // year month day hour minute seconds millisec
309 // year month day hour minute seconds millisec
310 // ra(+ h m s) dec(+ d m s) ha(+ h m s)
311 // mjd
312 // zd(+ d m s) az(+ d m s)
313 // zd(+ d m s) az(+ d m s)
314 // zd_err az_err
315 // armed(0=unlocked, 1=locked)
316 // stgmd(0=none, 1=starguider, 2=starguider off)
317 istringstream stream(line.substr(16));
318
319 uint16_t status1;
320 stream >> status1;
321 const Time t1 = ReadTime(stream);
322
323 uint16_t status2;
324 stream >> status2;
325 /*const Time t2 =*/ ReadTime(stream);
326
327 const double ra = ReadAngle(stream);
328 const double dec = ReadAngle(stream);
329 const double ha = ReadAngle(stream);
330
331 double mjd;
332 stream >> mjd;
333
334 const double zd1 = ReadAngle(stream); // Nominal (zd/az asynchronous, dev synchronous, mjd synchronous with zd)
335 const double az1 = ReadAngle(stream); // Nominal (zd/az asynchronous, dev synchronous, mjd synchronous with z)
336 const double zd2 = ReadAngle(stream); // Masured (zd/az synchronous, dev asynchronous, mjd asynchronous)
337 const double az2 = ReadAngle(stream); // Measurd (zd/az synchronous, dev asynchronous, mjd asynchronous)
338
339 double zd_err, az_err;
340 stream >> zd_err; // Deviation = Nominal - Measured
341 stream >> az_err; // Deviation = Nominal - Measured
342
343 uint16_t armed, stgmd;
344 stream >> armed;
345 stream >> stgmd;
346
347 uint32_t pdo3;
348 stream >> hex >> pdo3;
349
350 if (stream.fail())
351 return;
352
353 // Status 0: Error
354 // Status 1: Stopped
355 // Status 3: Stopping || Moving
356 // Status 4: Tracking
357 if (status1==0)
358 status1 = StateMachineImp::kSM_Error - Drive::State::kNotReady;
359
360 const bool ready = (pdo3&0xef00ef)==0xef00ef;
361 if (!ready)
362 fState = Drive::State::kNotReady;
363 else
364 fState = status1==1 ?
365 Drive::State::kReady+armed :
366 Drive::State::kNotReady+status1;
367
368 // kDisconnected = 1,
369 // kConnected,
370 // kNotReady,
371 // kReady,
372 // kArmed,
373 // kMoving,
374 // kTracking,
375 // kOnTrack,
376
377 // pdo3:
378 // 1 Ab
379 // 2 1
380 // 4 Emergency
381 // 8 OverVolt
382 // 10 Move (Drehen-soll)
383 // 20 Af
384 // 40 1
385 // 80 Power on Az
386 // ------------------
387 // 100 NOT UPS Alarm
388 // 200 UPS on Battery
389 // 400 UPS charging
390
391 // Power cut: 2ef02ef
392 // charging: 4ef04ef
393
394 // Convert to deg
395 zd_err /= 3600;
396 az_err /= 3600;
397
398 // Calculate absolut deviation on the sky
399 const double dev = GetDevAbs(zd1, zd1-zd_err, az_err)*3600;
400
401 // If any other state than tracking or a deviation
402 // larger than 60, reset the counter
403 if (fState!=State::kTracking || dev>fDeviationLimit)
404 fTrackingCounter = 0;
405 else
406 fTrackingCounter++;
407
408 // If in tracking, at least five consecutive reports (5s)
409 // must be below 60arcsec deviation, this is considered OnTrack
410 if (fState==State::kTracking && fTrackingCounter>=fDeviationCounter)
411 fState = State::kOnTrack;
412
413 // Having th state as Tracking will reset the counter
414 if (fState==State::kOnTrack && dev>fDeviationMax)
415 fState = State::kTracking;
416
417 const array<uint8_t, 3> state = {{ uint8_t(pdo3>>16), uint8_t(pdo3), uint8_t(pdo3>>24) }};
418 UpdateStatus(t1, state);
419
420 const array<double, 2> point = {{ zd2, az2 }};
421 UpdatePointing(t1, point);
422
423 const array<double, 8> track =
424 {{
425 ra, dec, ha,
426 zd1, az1,
427 zd_err, az_err,
428 dev
429 }};
430 if (mjd>0)
431 UpdateTracking(Time(mjd), track);
432
433 // ---- DIM ----> t1 as event time
434 // status1
435 // mjd
436 // ra/dec/ha
437 // zd/az (nominal)
438 // zd/az (current)
439 // err(zd/az)
440 // [armed] [stgmd]
441
442 // Maybe:
443 // POINTING_POSITION --> t1, zd/az (current), [armed, stgmd, status1]
444 //
445 // if (mjd>0)
446 // TRACKING_POSITION --> mjd, zd/az (nominal), err(zd/az)
447 // ra/dec, ha(not well defined),
448 // [Nominal + Error == Current]
449
450 // MJD is the time which corresponds to the nominal position
451 // t1 is the time which corresponds to the current position/HA
452
453 return;
454 }
455 }
456
457 void StartReadReport()
458 {
459 boost::asio::async_read_until(*this, fBuffer, '\n',
460 boost::bind(&ConnectionDrive::HandleReceivedReport, this,
461 dummy::error, dummy::bytes_transferred));
462 }
463
464 boost::asio::deadline_timer fKeepAlive;
465
466 void KeepAlive()
467 {
468 PostMessage(string("KEEP_ALIVE"));
469
470 fKeepAlive.expires_from_now(boost::posix_time::seconds(10));
471 fKeepAlive.async_wait(boost::bind(&ConnectionDrive::HandleKeepAlive,
472 this, dummy::error));
473 }
474
475 void HandleKeepAlive(const bs::error_code &error)
476 {
477 // 125: Operation canceled (bs::error_code(125, bs::system_category))
478 if (error && error!=ba::error::basic_errors::operation_aborted)
479 {
480 ostringstream str;
481 str << "Write timeout of " << URL() << ": " << error.message() << " (" << error << ")";// << endl;
482 Error(str);
483
484 PostClose(false);
485 return;
486 }
487
488 if (!is_open())
489 {
490 // For example: Here we could schedule a new accept if we
491 // would not want to allow two connections at the same time.
492 return;
493 }
494
495 // Check whether the deadline has passed. We compare the deadline
496 // against the current time since a new asynchronous operation
497 // may have moved the deadline before this actor had a chance
498 // to run.
499 if (fKeepAlive.expires_at() > ba::deadline_timer::traits_type::now())
500 return;
501
502 KeepAlive();
503 }
504
505
506private:
507 // This is called when a connection was established
508 void ConnectionEstablished()
509 {
510 StartReadReport();
511 KeepAlive();
512 }
513
514 /*
515 void HandleReadTimeout(const bs::error_code &error)
516 {
517 if (error && error!=ba::error::basic_errors::operation_aborted)
518 {
519 stringstream str;
520 str << "Read timeout of " << URL() << ": " << error.message() << " (" << error << ")";// << endl;
521 Error(str);
522
523 PostClose();
524 return;
525
526 }
527
528 if (!is_open())
529 {
530 // For example: Here we could schedule a new accept if we
531 // would not want to allow two connections at the same time.
532 return;
533 }
534
535 // Check whether the deadline has passed. We compare the deadline
536 // against the current time since a new asynchronous operation
537 // may have moved the deadline before this actor had a chance
538 // to run.
539 if (fInTimeout.expires_at() > ba::deadline_timer::traits_type::now())
540 return;
541
542 Error("Timeout reading data from "+URL());
543
544 PostClose();
545 }*/
546
547
548public:
549
550 static const uint16_t kMaxAddr;
551
552public:
553 ConnectionDrive(ba::io_service& ioservice, MessageImp &imp) : Connection(ioservice, imp()),
554 fState(-1), fIsVerbose(true), fDeviationLimit(120), fDeviationCounter(5), fDeviationMax(240), fTrackingCounter(0), fKeepAlive(ioservice)
555 {
556 SetLogStream(&imp);
557 }
558
559 void SetVerbose(bool b)
560 {
561 fIsVerbose = b;
562 }
563
564 void SetDeviationCondition(uint16_t limit, uint16_t counter, uint16_t max)
565 {
566 fDeviationLimit = limit;
567 fDeviationCounter = counter;
568 fDeviationMax = max;
569 }
570 int GetState() const
571 {
572 if (!IsConnected())
573 return 1;
574 if (IsConnected() && fState<0)
575 return 2;
576 return fState;
577 }
578};
579
580const uint16_t ConnectionkMaxAddr = 0xfff;
581
582// ------------------------------------------------------------------------
583
584#include "DimDescriptionService.h"
585
586class ConnectionDimDrive : public ConnectionDrive
587{
588private:
589 DimDescribedService fDimPointing;
590 DimDescribedService fDimTracking;
591 DimDescribedService fDimSource;
592 DimDescribedService fDimTPoint;
593 DimDescribedService fDimStatus;
594
595 void UpdatePointing(const Time &t, const array<double, 2> &arr)
596 {
597 fDimPointing.setData(arr);
598 fDimPointing.Update(t);
599 }
600
601 void UpdateTracking(const Time &t,const array<double, 8> &arr)
602 {
603 fDimTracking.setData(arr);
604 fDimTracking.Update(t);
605 }
606
607 void UpdateStatus(const Time &t, const array<uint8_t, 3> &arr)
608 {
609 fDimStatus.setData(arr);
610 fDimStatus.Update(t);
611 }
612
613 void UpdateTPoint(const Time &t, const DimTPoint &data,
614 const string &name)
615 {
616 vector<char> dim(sizeof(data)+name.length()+1);
617 memcpy(dim.data(), &data, sizeof(data));
618 memcpy(dim.data()+sizeof(data), name.c_str(), name.length()+1);
619
620 fDimTPoint.setData(dim);
621 fDimTPoint.Update(t);
622 }
623
624public:
625 ConnectionDimDrive(ba::io_service& ioservice, MessageImp &imp) :
626 ConnectionDrive(ioservice, imp),
627 fDimPointing("DRIVE_CONTROL/POINTING_POSITION", "D:1;D:1",
628 "|Zd[deg]:Zenith distance (encoder readout)"
629 "|Az[deg]:Azimuth angle (encoder readout)"),
630 fDimTracking("DRIVE_CONTROL/TRACKING_POSITION", "D:1;D:1;D:1;D:1;D:1;D:1;D:1;D:1",
631 "|Ra[h]:Command right ascension"
632 "|Dec[deg]:Command declination"
633 "|Ha[h]:Corresponding hour angle"
634 "|Zd[deg]:Nominal zenith distance"
635 "|Az[deg]:Nominal azimuth angle"
636 "|dZd[deg]:Control deviation Zd"
637 "|dAz[deg]:Control deviation Az"
638 "|dev[arcsec]:Absolute control deviation"),
639 fDimSource("DRIVE_CONTROL/SOURCE_POSITION", "D:1;D:1;D:1;D:1;D:1;D:1;C:31",
640 "|Ra_src[h]:Source right ascension"
641 "|Dec_src[deg]:Source declination"
642 "|Ra_cmd[h]:Command right ascension"
643 "|Dec_cmd[deg]:Command declination"
644 "|Offset[deg]:Wobble offset"
645 "|Angle[deg]:Wobble angle"
646 "|Name[string]:Source name if available"),
647 fDimTPoint("DRIVE_CONTROL/TPOINT", "D:1;D:1;D:1;D:1;D:1;D:1;D:1;D:1;S:1;D:1;D:1;D:1;D:1;D:1;D:1;D:1;C",
648 "|Ra[h]:Command right ascension"
649 "|Dec[deg]:Command declination"
650 "|Zd_nom[deg]:Nominal zenith distance"
651 "|Az_nom[deg]:Nominal azimuth angle"
652 "|Zd_cur[deg]:Current zenith distance (calculated from image)"
653 "|Az_cur[deg]:Current azimuth angle (calculated from image)"
654 "|Zd_enc[deg]:Feedback zenith axis (from encoder)"
655 "|Az_enc[deg]:Feedback azimuth angle (from encoder)"
656 "|N_leds[cnt]:Number of detected LEDs"
657 "|N_rings[cnt]:Number of rings used to calculate the camera center"
658 "|Xc[pix]:X position of center in CCD camera frame"
659 "|Yc[pix]:Y position of center in CCD camera frame"
660 "|Ic[au]:Average intensity (LED intensity weighted with their frequency of occurance in the calculation)"
661 "|Xs[pix]:X position of start in CCD camera frame"
662 "|Ys[pix]:Y position of star in CCD camera frame"
663 "|Ms[mag]:Artifical magnitude of star (calculated form image))"
664 "|Mc[mag]:Catalog magnitude of star"),
665 fDimStatus("DRIVE_CONTROL/STATUS", "C:2;C:1", "")
666
667 {
668 }
669
670 void UpdateSource()
671 {
672 const vector<char> empty(6*sizeof(double)+31, 0);
673 fDimSource.setQuality(0);
674 fDimSource.Update(empty);
675 }
676
677 void UpdateSource(const array<double, 6> &arr, const string &name="")
678 {
679 vector<char> dat(6*sizeof(double)+31, 0);
680 memcpy(dat.data(), arr.data(), 6*sizeof(double));
681 strncpy(dat.data()+6*sizeof(double), name.c_str(), 30);
682
683 fDimSource.setQuality(1);
684 fDimSource.Update(dat);
685 }
686
687 // A B [C] [D] E [F] G H [I] J K [L] M N O P Q R [S] T U V W [X] Y Z
688};
689
690// ------------------------------------------------------------------------
691
692struct Source
693{
694 Source() : ra(0), dec(0), offset(0)
695 {
696 angle[0] = -90;
697 angle[1] = 90;
698 }
699
700 double ra;
701 double dec;
702 double offset;
703 array<double, 2> angle;
704};
705
706
707template <class T, class S>
708class StateMachineDrive : public T, public ba::io_service, public ba::io_service::work
709{
710private:
711 S fDrive;
712
713 string fDatabase;
714
715 typedef map<string, Source> sources;
716 sources fSources;
717
718 string fLastCommand; // Last tracking (RADEC) command
719 int fAutoResume; // 0: disabled, 1: enables, 2: resuming
720
721 // Status 0: Error
722 // Status 1: Unlocked
723 // Status 2: Locked
724 // Status 3: Stopping || Moving
725 // Status 4: Tracking
726
727 bool CheckEventSize(size_t has, const char *name, size_t size)
728 {
729 if (has==size)
730 return true;
731
732 ostringstream msg;
733 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
734 T::Fatal(msg);
735 return false;
736 }
737
738 enum Coordinates
739 {
740 kPoint,
741 kTrackSlow,
742 kTrackFast
743 };
744
745 string AngleToStr(double angle)
746 {
747 /* Handle sign */
748 const char sgn = angle<0?'-':'+';
749
750 /* Round interval and express in smallest units required */
751 double a = round(3600. * fabs(angle)); // deg to seconds
752
753 /* Separate into fields */
754 const double ad = trunc(a/3600.);
755 a -= ad * 3600.;
756 const double am = trunc(a/60.);
757 a -= am * 60.;
758 const double as = trunc(a);
759
760 /* Return results */
761 ostringstream str;
762 str << sgn << " " << uint16_t(ad) << " " << uint16_t(am) << " " << as;
763 return str.str();
764 }
765
766 int SendCommand(const string &str, bool upd=true)
767 {
768 // This happens if fLastCommand should be send,
769 // but the last command was not a tracking command
770 if (str.empty())
771 {
772 T::Info("Last command was not a tracking command. RESUME ignored.");
773 return T::GetCurrentState();
774 }
775
776 fLastCommand = str.compare(0, 6, "RADEC ")==0 ? str : "";
777
778 fDrive.PostMessage(str);
779 T::Message("Sending: "+str);
780
781 if (upd)
782 fDrive.UpdateSource();
783
784 return T::GetCurrentState();
785 }
786
787 int Park()
788 {
789 SendCommand("PREPS Park", false);
790
791 // FIXME: Go to locked state only when park position properly reached
792 return Drive::State::kLocked;
793 }
794
795 int Resume()
796 {
797 if (fLastCommand.empty())
798 {
799 T::Info("Last command was not a tracking command. RESUME ignored.");
800 return T::GetCurrentState();
801 }
802
803 return SendCommand(fLastCommand, false);
804 }
805
806 int SendCoordinates(const EventImp &evt, const Coordinates type)
807 {
808 if (!CheckEventSize(evt.GetSize(), "SendCoordinates", 16))
809 return T::kSM_FatalError;
810
811 const double *dat = evt.Ptr<double>();
812
813 string command;
814
815 switch (type)
816 {
817 case kPoint: command += "ZDAZ "; break;
818 case kTrackSlow: command += "RADEC "; break;
819 case kTrackFast: command += "GRB "; break;
820 }
821
822 if (type!=kPoint)
823 {
824 const array<double, 6> dim = {{ dat[0], dat[1], dat[0], dat[1], 0, 0 }};
825 fDrive.UpdateSource(dim);
826 }
827
828 command += AngleToStr(dat[0]) + ' ' + AngleToStr(dat[1]);
829 return SendCommand(command, type==kPoint);
830 }
831
832 int StartWobble(const double &srcra, const double &srcdec,
833 const double &woboff, const double &wobang,
834 const string name="")
835 {
836 const double ra = srcra *M_PI/12;
837 const double dec = srcdec*M_PI/180;
838 const double off = woboff*M_PI/180;
839 const double dir = wobang*M_PI/180;
840
841 const double cosdir = cos(dir);
842 const double sindir = sin(dir);
843 const double cosoff = cos(off);
844 const double sinoff = sin(off);
845 const double cosdec = cos(dec);
846 const double sindec = sin(dec);
847
848 if (off==0)
849 {
850 const array<double, 6> dim = {{ srcra, srcdec, srcra, srcdec, 0, 0 }};
851 fDrive.UpdateSource(dim, name);
852
853 string command = "RADEC ";
854 command += AngleToStr(srcra) + ' ' + AngleToStr(srcdec);
855 return SendCommand(command, false);
856 }
857
858 const double sintheta = sindec*cosoff + cosdec*sinoff*cosdir;
859 if (sintheta >= 1)
860 {
861 T::Error("cos(Zd) > 1");
862 return T::GetCurrentState();
863 }
864
865 const double costheta = sqrt(1 - sintheta*sintheta);
866
867 const double cosdeltara = (cosoff - sindec*sintheta)/(cosdec*costheta);
868 const double sindeltara = sindir*sinoff/costheta;
869
870 const double ndec = asin(sintheta)*180/M_PI;
871 const double nra = (atan2(sindeltara, cosdeltara) + ra)*12/M_PI;
872
873 const array<double, 6> dim = {{ srcra, srcdec, nra, ndec, woboff, wobang }};
874 fDrive.UpdateSource(dim, name);
875
876 string command = "RADEC ";
877 command += AngleToStr(nra) + ' ' + AngleToStr(ndec);
878 return SendCommand(command, false);
879 }
880
881 int Wobble(const EventImp &evt)
882 {
883 if (!CheckEventSize(evt.GetSize(), "Wobble", 32))
884 return T::kSM_FatalError;
885
886 const double *dat = evt.Ptr<double>();
887
888 return StartWobble(dat[0], dat[1], dat[2], dat[3]);
889 }
890
891 const sources::const_iterator GetSourceFromDB(const char *ptr, const char *last)
892 {
893 if (find(ptr, last, '\0')==last)
894 {
895 T::Fatal("TrackWobble - The name transmitted by dim is not null-terminated.");
896 throw uint32_t(T::kSM_FatalError);
897 }
898
899 const string name(ptr);
900
901 const sources::const_iterator it = fSources.find(name);
902 if (it==fSources.end())
903 {
904 T::Error("Source '"+name+"' not found in list.");
905 throw uint32_t(T::GetCurrentState());
906 }
907
908 return it;
909 }
910
911 int TrackWobble(const EventImp &evt)
912 {
913 if (evt.GetSize()<=2)
914 {
915 ostringstream msg;
916 msg << "Track - Received event has " << evt.GetSize() << " bytes, but expected at least 3.";
917 T::Fatal(msg);
918 return T::kSM_FatalError;
919 }
920
921 const uint16_t wobble = evt.GetUShort();
922 if (wobble!=1 && wobble!=2)
923 {
924 ostringstream msg;
925 msg << "TrackWobble - Wobble id " << wobble << " undefined, only 1 and 2 allowed.";
926 T::Error(msg);
927 return T::GetCurrentState();
928 }
929
930 const char *ptr = evt.Ptr<char>(2);
931 const char *last = ptr+evt.GetSize()-2;
932
933 try
934 {
935 const sources::const_iterator it = GetSourceFromDB(ptr, last);
936
937 const string &name = it->first;
938 const Source &src = it->second;
939
940 return StartWobble(src.ra, src.dec, src.offset, src.angle[wobble-1], name);
941 }
942 catch (const uint32_t &e)
943 {
944 return e;
945 }
946 }
947
948 int StartTrackWobble(const char *ptr, size_t size, const double &offset=0, const double &angle=0)
949 {
950 const char *last = ptr+size;
951
952 try
953 {
954 const sources::const_iterator it = GetSourceFromDB(ptr, last);
955
956 const string &name = it->first;
957 const Source &src = it->second;
958
959 return StartWobble(src.ra, src.dec, offset, angle, name);
960 }
961 catch (const uint32_t &e)
962 {
963 return e;
964 }
965
966 }
967
968 int Track(const EventImp &evt)
969 {
970 if (evt.GetSize()<=16)
971 {
972 ostringstream msg;
973 msg << "Track - Received event has " << evt.GetSize() << " bytes, but expected at least 17.";
974 T::Fatal(msg);
975 return T::kSM_FatalError;
976 }
977
978 const double *dat = evt.Ptr<double>();
979 const char *ptr = evt.Ptr<char>(16);
980 const size_t size = evt.GetSize()-16;
981
982 return StartTrackWobble(ptr, size, dat[0], dat[1]);
983 }
984
985 int TrackOn(const EventImp &evt)
986 {
987 if (evt.GetSize()==0)
988 {
989 ostringstream msg;
990 msg << "TrackOn - Received event has " << evt.GetSize() << " bytes, but expected at least 1.";
991 T::Fatal(msg);
992 return T::kSM_FatalError;
993 }
994
995 return StartTrackWobble(evt.Ptr<char>(), evt.GetSize());
996 }
997
998
999 int TakeTPoint(const EventImp &evt)
1000 {
1001 if (evt.GetSize()<=4)
1002 {
1003 ostringstream msg;
1004 msg << "TakePoint - Received event has " << evt.GetSize() << " bytes, but expected at least 5.";
1005 T::Fatal(msg);
1006 return T::kSM_FatalError;
1007 }
1008
1009 const float mag = evt.Get<float>();
1010 const char *ptr = evt.Ptr<char>(4);
1011 const size_t size = evt.GetSize()-4;
1012
1013 string src(ptr, size);
1014
1015 while (src.find_first_of(' '))
1016 src.erase(src.find_first_of(' '), 1);
1017
1018 SendCommand("TPOIN "+src+" "+to_string(mag), false);;
1019
1020 return T::GetCurrentState();
1021 }
1022
1023 int SetLedBrightness(const EventImp &evt)
1024 {
1025 if (!CheckEventSize(evt.GetSize(), "SetLedBrightness", 8))
1026 return T::kSM_FatalError;
1027
1028 const uint32_t *led = evt.Ptr<uint32_t>();
1029
1030 ostringstream cmd;
1031 cmd << "LEDS " << led[0] << " " << led[1];
1032 return SendCommand(cmd.str(), false);
1033 }
1034
1035
1036 int SetVerbosity(const EventImp &evt)
1037 {
1038 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
1039 return T::kSM_FatalError;
1040
1041 fDrive.SetVerbose(evt.GetBool());
1042
1043 return T::GetCurrentState();
1044 }
1045
1046 int SetAutoResume(const EventImp &evt)
1047 {
1048 if (!CheckEventSize(evt.GetSize(), "SetAutoResume", 1))
1049 return T::kSM_FatalError;
1050
1051 fAutoResume = evt.GetBool();
1052
1053 return T::GetCurrentState();
1054 }
1055
1056 int Unlock()
1057 {
1058 return Drive::State::kNotReady;
1059 }
1060
1061 int Print()
1062 {
1063 for (auto it=fSources.begin(); it!=fSources.end(); it++)
1064 {
1065 const string &name = it->first;
1066 const Source &src = it->second;
1067
1068 T::Out() << name << ",";
1069 T::Out() << src.ra << "," << src.dec << "," << src.offset << ",";
1070 T::Out() << src.angle[0] << "," << src.angle[1] << endl;
1071 }
1072 return T::GetCurrentState();
1073 }
1074
1075 int ReloadSources()
1076 {
1077 try
1078 {
1079 ReadDatabase();
1080 }
1081 catch (const exception &e)
1082 {
1083 T::Error("Reading sources from databse failed: "+string(e.what()));
1084 }
1085 return T::GetCurrentState();
1086 }
1087
1088 int Disconnect()
1089 {
1090 // Close all connections
1091 fDrive.PostClose(false);
1092
1093 /*
1094 // Now wait until all connection have been closed and
1095 // all pending handlers have been processed
1096 poll();
1097 */
1098
1099 return T::GetCurrentState();
1100 }
1101
1102 int Reconnect(const EventImp &evt)
1103 {
1104 // Close all connections to supress the warning in SetEndpoint
1105 fDrive.PostClose(false);
1106
1107 // Now wait until all connection have been closed and
1108 // all pending handlers have been processed
1109 poll();
1110
1111 if (evt.GetBool())
1112 fDrive.SetEndpoint(evt.GetString());
1113
1114 // Now we can reopen the connection
1115 fDrive.PostClose(true);
1116
1117 return T::GetCurrentState();
1118 }
1119
1120 Time fSunRise;
1121
1122 int ShiftSunRise()
1123 {
1124 const Time sunrise = fSunRise;
1125
1126 fSunRise = Time().GetNextSunRise();
1127
1128 if (sunrise==fSunRise)
1129 return Drive::State::kLocked;
1130
1131 ostringstream msg;
1132 msg << "Next sun-rise will be at " << fSunRise;
1133 T::Info(msg);
1134
1135 return Drive::State::kLocked;
1136 }
1137
1138 int Execute()
1139 {
1140 // Dispatch (execute) at most one handler from the queue. In contrary
1141 // to run_one(), it doesn't wait until a handler is available
1142 // which can be dispatched, so poll_one() might return with 0
1143 // handlers dispatched. The handlers are always dispatched/executed
1144 // synchronously, i.e. within the call to poll_one()
1145 poll_one();
1146
1147 if (T::GetCurrentState()==Drive::State::kLocked)
1148 return ShiftSunRise();
1149
1150 if (T::GetCurrentState()>Drive::State::kLocked)
1151 {
1152 if (Time()>fSunRise)
1153 return Park();
1154 }
1155
1156 const int state = fDrive.GetState();
1157
1158 if (!fLastCommand.empty())
1159 {
1160 // If auto resume is enabled and the drive is in error,
1161 // resume tracking
1162 if (fAutoResume==1 && state==StateMachineImp::kSM_Error)
1163 {
1164 Resume();
1165 fAutoResume = 2;
1166 }
1167
1168 // If drive got out of the error state,
1169 // enable auto resume again
1170 if (fAutoResume==2 && state!=StateMachineImp::kSM_Error)
1171 fAutoResume = 1;
1172 }
1173
1174 return state;
1175 }
1176
1177
1178public:
1179 StateMachineDrive(ostream &out=cout) :
1180 T(out, "DRIVE_CONTROL"), ba::io_service::work(static_cast<ba::io_service&>(*this)),
1181 fDrive(*this, *this), fAutoResume(false), fSunRise(Time().GetNextSunRise())
1182 {
1183 // State names
1184 T::AddStateName(State::kDisconnected, "Disconnected",
1185 "No connection to cosy");
1186
1187 T::AddStateName(State::kConnected, "Connected",
1188 "Cosy connected, drive stopped");
1189
1190 T::AddStateName(State::kNotReady, "NotReady",
1191 "Drive system not ready for movement");
1192
1193 T::AddStateName(State::kLocked, "Locked",
1194 "Drive system is locked (will not accept commands)");
1195
1196 T::AddStateName(State::kReady, "Ready",
1197 "Drive system ready for movement");
1198
1199 T::AddStateName(State::kArmed, "Armed",
1200 "Cosy armed, drive stopped");
1201
1202 T::AddStateName(State::kMoving, "Moving",
1203 "Telescope moving");
1204
1205 T::AddStateName(State::kTracking, "Tracking",
1206 "Telescope is in tracking mode");
1207
1208 T::AddStateName(State::kOnTrack, "OnTrack",
1209 "Telescope tracking stable");
1210
1211 // State::kIdle
1212 // State::kArmed
1213 // State::kMoving
1214 // State::kTracking
1215
1216 // Init
1217 // -----------
1218 // "ARM lock"
1219 // "STGMD off"
1220
1221 /*
1222 [ ] WAIT -> WM_WAIT
1223 [x] STOP! -> WM_STOP
1224 [x] RADEC ra(+ d m s.f) dec(+ d m s.f)
1225 [x] GRB ra(+ d m s.f) dec(+ d m s.f)
1226 [x] ZDAZ zd(+ d m s.f) az (+ d m s.f)
1227 [ ] CELEST id offset angle
1228 [ ] MOON wobble offset
1229 [ ] PREPS string
1230 [ ] TPOIN star mag
1231 [ ] ARM lock/unlock
1232 [ ] STGMD on/off
1233 */
1234
1235 // Drive Commands
1236 T::AddEvent("MOVE_TO", "D:2", State::kArmed) // ->ZDAZ
1237 (bind(&StateMachineDrive::SendCoordinates, this, placeholders::_1, kPoint))
1238 ("Move the telescope to the given local coordinates"
1239 "|Zd[deg]:Zenith distance"
1240 "|Az[deg]:Azimuth");
1241
1242 T::AddEvent("TRACK", "D:2", State::kArmed, State::kTracking, State::kOnTrack) // ->RADEC/GRB
1243 (bind(&StateMachineDrive::SendCoordinates, this, placeholders::_1, kTrackSlow))
1244 ("Move the telescope to the given sky coordinates and start tracking them"
1245 "|Ra[h]:Right ascension"
1246 "|Dec[deg]:Declination");
1247
1248 T::AddEvent("WOBBLE", "D:4", State::kArmed, State::kTracking, State::kOnTrack) // ->RADEC/GRB
1249 (bind(&StateMachineDrive::Wobble, this, placeholders::_1))
1250 ("Move the telescope to the given wobble position around the given sky coordinates and start tracking them"
1251 "|Ra[h]:Right ascension"
1252 "|Dec[deg]:Declination"
1253 "|Offset[deg]:Wobble offset"
1254 "|Angle[deg]:Wobble angle");
1255
1256 T::AddEvent("TRACK_SOURCE", "D:2;C", State::kArmed, State::kTracking, State::kOnTrack) // ->RADEC/GRB
1257 (bind(&StateMachineDrive::Track, this, placeholders::_1))
1258 ("Move the telescope to the given wobble position around the given source and start tracking"
1259 "|Offset[deg]:Wobble offset"
1260 "|Angle[deg]:Wobble angle"
1261 "|Name[string]:Source name");
1262
1263 T::AddEvent("TRACK_WOBBLE", "S:1;C", State::kArmed, State::kTracking, State::kOnTrack) // ->RADEC/GRB
1264 (bind(&StateMachineDrive::TrackWobble, this, placeholders::_1))
1265 ("Move the telescope to the given wobble position around the given source and start tracking"
1266 "|id:Wobble angle id (1 or 2)"
1267 "|Name[string]:Source name");
1268
1269 T::AddEvent("TRACK_ON", "C", State::kArmed, State::kTracking, State::kOnTrack) // ->RADEC/GRB
1270 (bind(&StateMachineDrive::TrackOn, this, placeholders::_1))
1271 ("Move the telescope to the given position and start tracking"
1272 "|Name[string]:Source name");
1273
1274 T::AddEvent("RESUME", StateMachineImp::kSM_Error)
1275 (bind(&StateMachineDrive::Resume, this))
1276 ("If drive is in Error state, this can b used to resume the last tracking command, if the last command sent to cosy was a tracking command.");
1277
1278 T::AddEvent("MOON", State::kArmed, State::kTracking, State::kOnTrack)
1279 (bind(&StateMachineDrive::SendCommand, this, "MOON 0 0", true))
1280 ("Start tracking the moon");
1281 T::AddEvent("VENUS", State::kArmed, State::kTracking, State::kOnTrack)
1282 (bind(&StateMachineDrive::SendCommand, this, "CELEST 2 0 0", true))
1283 ("Start tracking Venus");
1284 T::AddEvent("MARS", State::kArmed, State::kTracking, State::kOnTrack)
1285 (bind(&StateMachineDrive::SendCommand, this, "CELEST 4 0 0", true))
1286 ("Start tracking Mars");
1287 T::AddEvent("JUPITER", State::kArmed, State::kTracking, State::kOnTrack)
1288 (bind(&StateMachineDrive::SendCommand, this, "CELEST 5 0 0", true))
1289 ("Start tracking Jupiter");
1290 T::AddEvent("SATURN", State::kArmed, State::kTracking, State::kOnTrack)
1291 (bind(&StateMachineDrive::SendCommand, this, "CELEST 6 0 0", true))
1292 ("Start tracking Saturn");
1293
1294 T::AddEvent("PARK", State::kArmed, State::kMoving, State::kTracking, State::kOnTrack, 0x100)
1295 (bind(&StateMachineDrive::Park, this))
1296 ("Park the telescope");
1297
1298 T::AddEvent("TAKE_TPOINT")
1299 (bind(&StateMachineDrive::SendCommand, this, "TPOIN FACT 0", false))
1300 ("Take a TPoint");
1301
1302 T::AddEvent("TPOINT", "F:1;C")
1303 (bind(&StateMachineDrive::TakeTPoint, this, placeholders::_1))
1304 ("Take a TPoint (given values will be written to the TPoint files)"
1305 "|mag[float]:Magnitude of the star"
1306 "|name[string]:Name of the star");
1307
1308 T::AddEvent("SET_LED_BRIGHTNESS", "I:2")
1309 (bind(&StateMachineDrive::SetLedBrightness, this, placeholders::_1))
1310 ("Set the LED brightness of the top and bottom leds"
1311 "|top[au]:Allowed range 0-32767 for top LEDs"
1312 "|bot[au]:Allowed range 0-32767 for bottom LEDs");
1313
1314 T::AddEvent("LEDS_OFF")
1315 (bind(&StateMachineDrive::SendCommand, this, "LEDS 0 0", false))
1316 ("Switch off TPoint LEDs");
1317
1318 T::AddEvent("STOP")
1319 (bind(&StateMachineDrive::SendCommand, this, "STOP!", true))
1320 ("Stop any kind of movement.");
1321
1322// T::AddEvent("ARM", State::kConnected)
1323// (bind(&StateMachineSendCommand, this, "ARM lock"))
1324// ("");
1325
1326 T::AddEvent("UNLOCK", Drive::State::kLocked)
1327 (bind(&StateMachineDrive::Unlock, this))
1328 ("Unlock locked state.");
1329
1330 T::AddEvent("SET_AUTORESUME", "B")
1331 (bind(&StateMachineDrive::SetAutoResume, this, placeholders::_1))
1332 ("Enable/disable auto resume"
1333 "|resume[bool]:if enabled, drive is tracking and goes to error state, the last tracking command is repeated automatically.");
1334
1335 // Verbosity commands
1336 T::AddEvent("SET_VERBOSE", "B")
1337 (bind(&StateMachineDrive::SetVerbosity, this, placeholders::_1))
1338 ("Set verbosity state"
1339 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
1340
1341 // Conenction commands
1342 T::AddEvent("DISCONNECT", State::kConnected, State::kArmed)
1343 (bind(&StateMachineDrive::Disconnect, this))
1344 ("disconnect from ethernet");
1345
1346 T::AddEvent("RECONNECT", "O", State::kDisconnected, State::kConnected, State::kArmed)
1347 (bind(&StateMachineDrive::Reconnect, this, placeholders::_1))
1348 ("(Re)connect ethernet connection to FTM, a new address can be given"
1349 "|[host][string]:new ethernet address in the form <host:port>");
1350
1351
1352 T::AddEvent("PRINT")
1353 (bind(&StateMachineDrive::Print, this))
1354 ("Print source list.");
1355
1356 T::AddEvent("RELOAD_SOURCES")
1357 (bind(&StateMachineDrive::ReloadSources, this))
1358 ("Reload sources from database after database has changed..");
1359
1360 fDrive.StartConnect();
1361 }
1362
1363 void SetEndpoint(const string &url)
1364 {
1365 fDrive.SetEndpoint(url);
1366 }
1367
1368 bool AddSource(const string &name, const Source &src)
1369 {
1370 const auto it = fSources.find(name);
1371 if (it!=fSources.end())
1372 T::Warn("Source '"+name+"' already in list... overwriting.");
1373
1374 fSources[name] = src;
1375 return it==fSources.end();
1376 }
1377
1378 void ReadDatabase(bool print=true)
1379 {
1380#ifdef HAVE_SQL
1381 Database db(fDatabase);
1382
1383 T::Message("Connected to '"+db.uri()+"'");
1384
1385 const mysqlpp::StoreQueryResult res =
1386 db.query("SELECT fSourceName, fRightAscension, fDeclination, fWobbleOffset, fWobbleAngle0, fWobbleAngle1 FROM source").store();
1387
1388 fSources.clear();
1389 for (vector<mysqlpp::Row>::const_iterator v=res.begin(); v<res.end(); v++)
1390 {
1391 const string name = (*v)[0].c_str();
1392
1393 Source src;
1394 src.ra = (*v)[1];
1395 src.dec = (*v)[2];
1396 src.offset = (*v)[3];
1397 src.angle[0] = (*v)[4];
1398 src.angle[1] = (*v)[5];
1399 AddSource(name, src);
1400
1401 if (!print)
1402 continue;
1403
1404 ostringstream msg;
1405 msg << " " << name << setprecision(8) << ": Ra=" << src.ra << "h Dec=" << src.dec << "deg";
1406 msg << " Wobble=[" << src.offset << "," << src.angle[0] << "," << src.angle[1] << "]";
1407 T::Message(msg);
1408 }
1409#else
1410 T::Warn("MySQL support not compiled into the program.");
1411#endif
1412 }
1413
1414 int EvalOptions(Configuration &conf)
1415 {
1416 if (!fSunRise)
1417 return 1;
1418
1419 fDrive.SetVerbose(!conf.Get<bool>("quiet"));
1420
1421 const vector<string> &vec = conf.Vec<string>("source");
1422
1423 for (vector<string>::const_iterator it=vec.begin(); it!=vec.end(); it++)
1424 {
1425 istringstream stream(*it);
1426
1427 string name;
1428
1429 int i=0;
1430
1431 Source src;
1432
1433 string buffer;
1434 while (getline(stream, buffer, ','))
1435 {
1436 istringstream is(buffer);
1437
1438 switch (i++)
1439 {
1440 case 0: name = buffer; break;
1441 case 1: src.ra = ConnectionDrive::ReadAngle(is); break;
1442 case 2: src.dec = ConnectionDrive::ReadAngle(is); break;
1443 case 3: is >> src.offset; break;
1444 case 4: is >> src.angle[0]; break;
1445 case 5: is >> src.angle[1]; break;
1446 }
1447
1448 if (is.fail())
1449 break;
1450 }
1451
1452 if (i==3 || i==6)
1453 {
1454 AddSource(name, src);
1455 continue;
1456 }
1457
1458 T::Warn("Resource 'source' not correctly formatted: '"+*it+"'");
1459 }
1460
1461 fDrive.SetDeviationCondition(conf.Get<uint16_t>("deviation-limit"),
1462 conf.Get<uint16_t>("deviation-count"),
1463 conf.Get<uint16_t>("deviation-max"));
1464
1465 fAutoResume = conf.Get<bool>("auto-resume");
1466
1467 if (conf.Has("source-database"))
1468 {
1469 fDatabase = conf.Get<string>("source-database");
1470 ReadDatabase();
1471 }
1472
1473 if (fSunRise.IsValid())
1474 {
1475 ostringstream msg;
1476 msg << "Next sun-rise will be at " << fSunRise;
1477 T::Message(msg);
1478 }
1479
1480 // The possibility to connect should be last, so that
1481 // everything else is already initialized.
1482 SetEndpoint(conf.Get<string>("addr"));
1483
1484 return -1;
1485 }
1486};
1487
1488// ------------------------------------------------------------------------
1489
1490#include "Main.h"
1491
1492
1493template<class T, class S, class R>
1494int RunShell(Configuration &conf)
1495{
1496 return Main::execute<T, StateMachineDrive<S, R>>(conf);
1497}
1498
1499void SetupConfiguration(Configuration &conf)
1500{
1501 const string def = "localhost:7404";
1502
1503 po::options_description control("Drive control options");
1504 control.add_options()
1505 ("no-dim,d", po_switch(), "Disable dim services")
1506 ("addr,a", var<string>(def), "Network address of cosy")
1507 ("quiet,q", po_bool(true), "Disable printing contents of all received messages (except dynamic data) in clear text.")
1508 ("source-database", var<string>(), "Database link as in\n\tuser:password@server[:port]/database.")
1509 ("source", vars<string>(), "Additional source entry in the form \"name,hh:mm:ss,dd:mm:ss\"")
1510 ("deviation-limit", var<uint16_t>(90), "Deviation limit in arcsec to get 'OnTrack'")
1511 ("deviation-count", var<uint16_t>(3), "Minimum number of reported deviation below deviation-limit to get 'OnTrack'")
1512 ("deviation-max", var<uint16_t>(180), "Maximum deviation in arcsec allowed to keep status 'OnTrack'")
1513 ("auto-resume", po_bool(false), "Enable auto result during tracking if connection is lost")
1514 ;
1515
1516 conf.AddOptions(control);
1517}
1518
1519/*
1520 Extract usage clause(s) [if any] for SYNOPSIS.
1521 Translators: "Usage" and "or" here are patterns (regular expressions) which
1522 are used to match the usage synopsis in program output. An example from cp
1523 (GNU coreutils) which contains both strings:
1524 Usage: cp [OPTION]... [-T] SOURCE DEST
1525 or: cp [OPTION]... SOURCE... DIRECTORY
1526 or: cp [OPTION]... -t DIRECTORY SOURCE...
1527 */
1528void PrintUsage()
1529{
1530 cout <<
1531 "The drivectrl is an interface to cosy.\n"
1532 "\n"
1533 "The default is that the program is started without user intercation. "
1534 "All actions are supposed to arrive as DimCommands. Using the -c "
1535 "option, a local shell can be initialized. With h or help a short "
1536 "help message about the usuage can be brought to the screen.\n"
1537 "\n"
1538 "Usage: drivectrl [-c type] [OPTIONS]\n"
1539 " or: drivectrl [OPTIONS]\n";
1540 cout << endl;
1541}
1542
1543void PrintHelp()
1544{
1545 Main::PrintHelp<StateMachineDrive<StateMachine,ConnectionDrive>>();
1546
1547 /* Additional help text which is printed after the configuration
1548 options goes here */
1549
1550 /*
1551 cout << "bla bla bla" << endl << endl;
1552 cout << endl;
1553 cout << "Environment:" << endl;
1554 cout << "environment" << endl;
1555 cout << endl;
1556 cout << "Examples:" << endl;
1557 cout << "test exam" << endl;
1558 cout << endl;
1559 cout << "Files:" << endl;
1560 cout << "files" << endl;
1561 cout << endl;
1562 */
1563}
1564
1565int main(int argc, const char* argv[])
1566{
1567 Configuration conf(argv[0]);
1568 conf.SetPrintUsage(PrintUsage);
1569 Main::SetupConfiguration(conf);
1570 SetupConfiguration(conf);
1571
1572 if (!conf.DoParse(argc, argv, PrintHelp))
1573 return 127;
1574
1575 //try
1576 {
1577 // No console access at all
1578 if (!conf.Has("console"))
1579 {
1580 if (conf.Get<bool>("no-dim"))
1581 return RunShell<LocalStream, StateMachine, ConnectionDrive>(conf);
1582 else
1583 return RunShell<LocalStream, StateMachineDim, ConnectionDimDrive>(conf);
1584 }
1585 // Cosole access w/ and w/o Dim
1586 if (conf.Get<bool>("no-dim"))
1587 {
1588 if (conf.Get<int>("console")==0)
1589 return RunShell<LocalShell, StateMachine, ConnectionDrive>(conf);
1590 else
1591 return RunShell<LocalConsole, StateMachine, ConnectionDrive>(conf);
1592 }
1593 else
1594 {
1595 if (conf.Get<int>("console")==0)
1596 return RunShell<LocalShell, StateMachineDim, ConnectionDimDrive>(conf);
1597 else
1598 return RunShell<LocalConsole, StateMachineDim, ConnectionDimDrive>(conf);
1599 }
1600 }
1601 /*catch (std::exception& e)
1602 {
1603 cerr << "Exception: " << e.what() << endl;
1604 return -1;
1605 }*/
1606
1607 return 0;
1608}
Note: See TracBrowser for help on using the repository browser.