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

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