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

Last change on this file since 12650 was 12649, checked in by tbretz, 13 years ago
Do not send tracking reports if there is no tracking (MJD==0)
File size: 31.1 KB
Line 
1#include <boost/bind.hpp>
2
3#include "FACT.h"
4#include "Dim.h"
5#include "Event.h"
6#include "Shell.h"
7#include "StateMachineDim.h"
8#include "Connection.h"
9#include "Configuration.h"
10#include "Timers.h"
11#include "Console.h"
12#include "Converter.h"
13
14#include "tools.h"
15
16
17namespace ba = boost::asio;
18namespace bs = boost::system;
19namespace dummy = ba::placeholders;
20
21using namespace std;
22
23// ------------------------------------------------------------------------
24
25namespace Drive
26{
27 struct DimPointing
28 {
29 } __attribute__((__packed__));
30
31 struct DimTracking
32 {
33 } __attribute__((__packed__));
34
35 struct DimStarguider
36 {
37 double fMissZd;
38 double fMissAz;
39
40 double fNominalZd;
41 double fNominalAz;
42
43 double fCenterX;
44 double fCenterY;
45
46 double fBrightness;
47
48 uint16_t fNumCorrelated;
49 uint16_t fNumLeds;
50 uint16_t fNumRings;
51 uint16_t fNumStars;
52
53 } __attribute__((__packed__));
54
55 struct DimTPoint
56 {
57 double fRa;
58 double fDec;
59
60 double fNominalZd;
61 double fNominalAz;
62
63 double fPointingZd;
64 double fPointingAz;
65
66 double fFeedbackZd;
67 double fFeedbackAz;
68
69 uint16_t fNumLeds;
70 uint16_t fNumRings;
71
72 double fCenterX;
73 double fCenterY;
74 double fCenterMag;
75
76 double fStarX;
77 double fStarY;
78 double fStarMag;
79
80 double fRealMag;
81
82 } __attribute__((__packed__));
83};
84
85
86
87// ------------------------------------------------------------------------
88
89class ConnectionDrive : public Connection
90{
91 int fState;
92
93 bool fIsVerbose;
94
95 // --verbose
96 // --hex-out
97 // --dynamic-out
98 // --load-file
99 // --leds
100 // --trigger-interval
101 // --physcis-coincidence
102 // --calib-coincidence
103 // --physcis-window
104 // --physcis-window
105 // --trigger-delay
106 // --time-marker-delay
107 // --dead-time
108 // --clock-conditioner-r0
109 // --clock-conditioner-r1
110 // --clock-conditioner-r8
111 // --clock-conditioner-r9
112 // --clock-conditioner-r11
113 // --clock-conditioner-r13
114 // --clock-conditioner-r14
115 // --clock-conditioner-r15
116 // ...
117
118 virtual void UpdatePointing(const Time &, const array<double, 2> &)
119 {
120 }
121
122 virtual void UpdateTracking(const Time &, const array<double, 7> &)
123 {
124 }
125
126 virtual void UpdateStatus(const Time &, const array<uint8_t, 3> &)
127 {
128 }
129
130 virtual void UpdateStarguider(const Time &, const Drive::DimStarguider &)
131 {
132 }
133
134 virtual void UpdateTPoint(const Time &, const Drive::DimTPoint &, const string &)
135 {
136 }
137
138
139protected:
140 map<uint16_t, int> fCounter;
141
142 ba::streambuf fBuffer;
143
144 Time ReadTime(istream &in)
145 {
146 uint16_t y, m, d, hh, mm, ss, ms;
147 in >> y >> m >> d >> hh >> mm >> ss >> ms;
148
149 return Time(y, m, d, hh, mm, ss, ms*1000);
150 }
151
152 double ReadAngle(istream &in)
153 {
154 char sgn;
155 uint16_t d, m;
156 float s;
157
158 in >> sgn >> d >> m >> s;
159
160 const double ret = ((60.0 * (60.0 * (double)d + (double)m) + s))/3600.;
161 return sgn=='-' ? -ret : ret;
162 }
163
164 void HandleReceivedReport(const boost::system::error_code& err, size_t bytes_received)
165 {
166 // Do not schedule a new read if the connection failed.
167 if (bytes_received==0 || err)
168 {
169 if (err==ba::error::eof)
170 Warn("Connection closed by remote host (FTM).");
171
172 // 107: Transport endpoint is not connected (bs::error_code(107, bs::system_category))
173 // 125: Operation canceled
174 if (err && err!=ba::error::eof && // Connection closed by remote host
175 err!=ba::error::basic_errors::not_connected && // Connection closed by remote host
176 err!=ba::error::basic_errors::operation_aborted) // Connection closed by us
177 {
178 ostringstream str;
179 str << "Reading from " << URL() << ": " << err.message() << " (" << err << ")";// << endl;
180 Error(str);
181 }
182 PostClose(err!=ba::error::basic_errors::operation_aborted);
183 return;
184 }
185
186 istream is(&fBuffer);
187
188 string line;
189 getline(is, line);
190
191 if (fIsVerbose)
192 Out() << line << endl;
193
194 StartReadReport();
195
196 if (line.substr(0, 13)=="DRIVE-STATUS ")
197 {
198 Message(line.substr(70));
199 return;
200 }
201
202 if (line.substr(0, 13)=="STARG-REPORT ")
203 {
204 istringstream stream(line.substr(16));
205
206 // 0: Error
207 // 1: Standby
208 // 2: Monitoring
209 uint16_t status1;
210 stream >> status1;
211 const Time t1 = ReadTime(stream);
212
213 uint16_t status2;
214 stream >> status2;
215 const Time t2 = ReadTime(stream);
216
217 double misszd, missaz;
218 stream >> misszd >> missaz;
219
220 const double zd = ReadAngle(stream);
221 const double az = ReadAngle(stream);
222
223 double cx, cy;
224 stream >> cx >> cy;
225
226 int ncor;
227 stream >> ncor;
228
229 double bright, mjd;
230 stream >> bright >> mjd;
231
232 int nled, nring, nstars;
233 stream >> nled >> nring >> nstars;
234
235 if (stream.fail())
236 return;
237
238 Drive::DimStarguider data;
239
240 data.fMissZd = misszd;
241 data.fMissAz = missaz;
242 data.fNominalZd = zd;
243 data.fNominalAz = az;
244 data.fCenterX = cx;
245 data.fCenterY = cy;
246 data.fNumCorrelated = ncor;
247 data.fBrightness = bright;
248 data.fNumLeds = nled;
249 data.fNumRings = nring;
250 data.fNumStars = nstars;
251
252 UpdateStarguider(Time(mjd), data);
253
254 return;
255
256 }
257
258 if (line.substr(0, 14)=="TPOINT-REPORT ")
259 {
260 istringstream stream(line.substr(17));
261
262 uint16_t status1;
263 stream >> status1;
264 const Time t1 = ReadTime(stream);
265
266 uint16_t status2;
267 stream >> status2;
268 const Time t2 = ReadTime(stream);
269
270 char type;
271 stream >> type;
272 if (type != 'T')
273 return;
274
275 double az1, alt1, az2, alt2, ra, dec, dzd, daz;
276 stream >> az1 >> alt1 >> az2 >> alt2 >> ra >> dec >> dzd >> daz;
277
278 // c: center, s:start
279 double mjd, cmag, smag, cx, cy, sx, sy;
280 stream >> mjd >> cmag >> smag >> cx >> cy >> sx >> sy;
281
282 int nled, nring, nstar, ncor;
283 stream >> nled >> nring >> nstar >> ncor;
284
285 double bright, mag;
286 stream >> bright >> mag;
287
288 string name;
289 stream >> name;
290
291 if (stream.fail())
292 return;
293
294 Drive::DimTPoint tpoint;
295
296 tpoint.fRa = ra;
297 tpoint.fDec = dec;
298
299 tpoint.fNominalZd = 90-alt1-dzd;
300 tpoint.fNominalAz = 90-az1 +daz;
301
302 tpoint.fPointingZd = 90-alt1;
303 tpoint.fPointingAz = az1;
304
305 tpoint.fFeedbackZd = 90-alt2;
306 tpoint.fFeedbackAz = az2;
307
308 tpoint.fNumLeds = nled;
309 tpoint.fNumRings = nring;
310
311 tpoint.fCenterX = cx;
312 tpoint.fCenterY = cy;
313 tpoint.fCenterMag = cmag;
314
315 tpoint.fStarX = sx;
316 tpoint.fStarY = sy;
317 tpoint.fStarMag = smag;
318
319 tpoint.fRealMag = mag;
320
321 UpdateTPoint(t1, tpoint, name);
322
323 return;
324 }
325
326 if (line.substr(0, 13)=="DRIVE-REPORT ")
327 {
328 // DRIVE-REPORT M1
329 // 01 2011 05 14 11 31 19 038
330 // 02 1858 11 17 00 00 00 000
331 // + 000 00 000 + 000 00 000
332 // + 000 00 000
333 // 55695.480081
334 // + 000 00 000 + 000 00 000
335 // + 000 00 000 + 000 00 000
336 // 0000.000 0000.000
337 // 0 2
338
339 // status
340 // year month day hour minute seconds millisec
341 // year month day hour minute seconds millisec
342 // ra(+ h m s) dec(+ d m s) ha(+ h m s)
343 // mjd
344 // zd(+ d m s) az(+ d m s)
345 // zd(+ d m s) az(+ d m s)
346 // zd_err az_err
347 // armed(0=unlocked, 1=locked)
348 // stgmd(0=none, 1=starguider, 2=starguider off)
349 istringstream stream(line.substr(16));
350
351 uint16_t status1;
352 stream >> status1;
353 const Time t1 = ReadTime(stream);
354
355 uint16_t status2;
356 stream >> status2;
357 const Time t2 = ReadTime(stream);
358
359 const double ra = ReadAngle(stream);
360 const double dec = ReadAngle(stream);
361 const double ha = ReadAngle(stream);
362
363 double mjd;
364 stream >> mjd;
365
366 const double zd1 = ReadAngle(stream);
367 const double az1 = ReadAngle(stream);
368 const double zd2 = ReadAngle(stream);
369 const double az2 = ReadAngle(stream);
370
371 double zd_err, az_err;
372 stream >> zd_err;
373 stream >> az_err;
374
375 uint16_t armed, stgmd;
376 stream >> armed;
377 stream >> stgmd;
378
379 uint32_t pdo3;
380 stream >> hex >> pdo3;
381
382 if (stream.fail())
383 return;
384
385 // Status 0: Error
386 // Status 1: Stopped
387 // Status 3: Stopping || Moving
388 // Status 4: Tracking
389 if (status1==0)
390 status1 = 99;
391
392 const bool ready = (pdo3&0xef00ef)==0xef00ef;
393 if (!ready)
394 fState = 0;
395 else
396 fState = status1==1 ? armed+1 : status1;
397
398 // 1: Not ready
399 // 2: Not armed
400 // 3: Armed
401 // 4: Moving
402 // 5: Tracking
403 // 99: Error
404
405
406
407 // pdo3:
408 // 1 Ab
409 // 2 1
410 // 4 Emergency
411 // 8 OverVolt
412 // 10 Move (Drehen-soll)
413 // 20 Af
414 // 40 1
415 // 80 Power on Az
416 // ------------------
417 // 100 NOT UPS Alarm
418 // 200 UPS on Battery
419 // 400 UPS charging
420
421 // Power cut: 2ef02ef
422 // charging: 4ef04ef
423
424 const array<uint8_t, 3> state = {{ uint8_t(pdo3>>16), uint8_t(pdo3), uint8_t(pdo3>>24) }};
425 UpdateStatus(t1, state);
426
427 const array<double, 2> point = {{ zd2, az2 }};
428 UpdatePointing(t1, point);
429
430 const array<double, 7> track =
431 {{
432 ra, dec, ha,
433 zd1, az1,
434 zd_err/3600, az_err/3600
435 }};
436 if (mjd>0)
437 UpdateTracking(Time(mjd), track);
438
439 // ---- DIM ----> t1 as event time
440 // status1
441 // mjd
442 // ra/dec/ha
443 // zd/az (nominal)
444 // zd/az (current)
445 // err(zd/az)
446 // [armed] [stgmd]
447
448 // Maybe:
449 // POINTING_POSITION --> t1, zd/az (current), [armed, stgmd, status1]
450 //
451 // if (mjd>0)
452 // TRACKING_POSITION --> mjd, zd/az (nominal), err(zd/az)
453 // ra/dec, ha(not well defined),
454 // [Nominal + Error == Current]
455
456 // MJD is the time which corresponds to the nominal position
457 // t1 is the time which corresponds to the current position/HA
458
459 return;
460 }
461 }
462
463 void StartReadReport()
464 {
465 boost::asio::async_read_until(*this, fBuffer, '\n',
466 boost::bind(&ConnectionDrive::HandleReceivedReport, this,
467 dummy::error, dummy::bytes_transferred));
468 }
469
470 boost::asio::deadline_timer fKeepAlive;
471
472 void KeepAlive()
473 {
474 PostMessage(string("KEEP_ALIVE"));
475
476 fKeepAlive.expires_from_now(boost::posix_time::seconds(10));
477 fKeepAlive.async_wait(boost::bind(&ConnectionDrive::HandleKeepAlive,
478 this, dummy::error));
479 }
480
481 void HandleKeepAlive(const bs::error_code &error)
482 {
483 // 125: Operation canceled (bs::error_code(125, bs::system_category))
484 if (error && error!=ba::error::basic_errors::operation_aborted)
485 {
486 ostringstream str;
487 str << "Write timeout of " << URL() << ": " << error.message() << " (" << error << ")";// << endl;
488 Error(str);
489
490 PostClose(false);
491 return;
492 }
493
494 if (!is_open())
495 {
496 // For example: Here we could schedule a new accept if we
497 // would not want to allow two connections at the same time.
498 return;
499 }
500
501 // Check whether the deadline has passed. We compare the deadline
502 // against the current time since a new asynchronous operation
503 // may have moved the deadline before this actor had a chance
504 // to run.
505 if (fKeepAlive.expires_at() > ba::deadline_timer::traits_type::now())
506 return;
507
508 KeepAlive();
509 }
510
511
512private:
513 // This is called when a connection was established
514 void ConnectionEstablished()
515 {
516 StartReadReport();
517 KeepAlive();
518 }
519
520 /*
521 void HandleReadTimeout(const bs::error_code &error)
522 {
523 if (error && error!=ba::error::basic_errors::operation_aborted)
524 {
525 stringstream str;
526 str << "Read timeout of " << URL() << ": " << error.message() << " (" << error << ")";// << endl;
527 Error(str);
528
529 PostClose();
530 return;
531
532 }
533
534 if (!is_open())
535 {
536 // For example: Here we could schedule a new accept if we
537 // would not want to allow two connections at the same time.
538 return;
539 }
540
541 // Check whether the deadline has passed. We compare the deadline
542 // against the current time since a new asynchronous operation
543 // may have moved the deadline before this actor had a chance
544 // to run.
545 if (fInTimeout.expires_at() > ba::deadline_timer::traits_type::now())
546 return;
547
548 Error("Timeout reading data from "+URL());
549
550 PostClose();
551 }*/
552
553
554public:
555
556 static const uint16_t kMaxAddr;
557
558public:
559 ConnectionDrive(ba::io_service& ioservice, MessageImp &imp) : Connection(ioservice, imp()),
560 fState(-1), fIsVerbose(true), fKeepAlive(ioservice)
561 {
562 SetLogStream(&imp);
563 }
564
565 void SetVerbose(bool b)
566 {
567 fIsVerbose = b;
568 }
569
570 int GetState() const
571 {
572 if (!IsConnected())
573 return 1;
574 if (IsConnected() && fState<0)
575 return 2;
576 return fState+3;
577 }
578};
579
580const uint16_t ConnectionDrive::kMaxAddr = 0xfff;
581
582// ------------------------------------------------------------------------
583
584#include "DimDescriptionService.h"
585
586class ConnectionDimDrive : public ConnectionDrive
587{
588private:
589
590 DimDescribedService fDimPointing;
591 DimDescribedService fDimTracking;
592 DimDescribedService fDimTPoint;
593 DimDescribedService fDimStatus;
594
595 virtual void UpdatePointing(const Time &t,
596 const array<double, 2> &arr)
597 {
598 fDimPointing.setData(arr);
599 fDimPointing.Update(t);
600 }
601
602 virtual void UpdateTracking(const Time &t,
603 const array<double, 7> &arr)
604 {
605 fDimTracking.setData(arr);
606 fDimTracking.Update(t);
607 }
608 virtual void UpdateStatus(const Time &t,
609 const array<uint8_t, 3> &arr)
610 {
611 fDimStatus.setData(arr);
612 fDimStatus.Update(t);
613 }
614 virtual void UpdateTPoint(const Time &t,
615 const Drive::DimTPoint &data,
616 const string &name)
617 {
618 vector<char> dim(sizeof(data)+name.length()+1);
619 memcpy(dim.data(), &data, sizeof(data));
620 memcpy(dim.data()+sizeof(data), name.c_str(), name.length()+1);
621
622 fDimTPoint.setData(dim);
623 fDimTPoint.Update(t);
624 }
625
626public:
627 ConnectionDimDrive(ba::io_service& ioservice, MessageImp &imp) :
628 ConnectionDrive(ioservice, imp),
629 fDimPointing("DRIVE_CONTROL/POINTING_POSITION", "D:1;D:1",
630 "|Zd[deg]:Zenith distance (encoder readout)"
631 "|Az[deg]:Azimuth angle (encoder readout)"),
632 fDimTracking("DRIVE_CONTROL/TRACKING_POSITION", "D:1;D:1;D:1;D:1;D:1;D:1;D:1",
633 "|Ra[h]:Command right ascension"
634 "|Dec[deg]:Command declination"
635 "|Ha[h]:Corresponding hour angle"
636 "|Zd[deg]:Nominal zenith distance"
637 "|Az[deg]:Nominal azimuth angle"
638 "|dZd[deg]:Control deviation Zd"
639 "|dAz[deg]:Control deviation Az"),
640 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",
641 "|Ra[h]:Command right ascension"
642 "|Dec[deg]:Command declination"
643 "|Zd_nom[deg]:Nominal zenith distance"
644 "|Az_nom[deg]:Nominal azimuth angle"
645 "|Zd_cur[deg]:Current zenith distance (calculated from image)"
646 "|Az_cur[deg]:Current azimuth angle (calculated from image)"
647 "|Zd_enc[deg]:Feedback zenith axis (from encoder)"
648 "|Az_enc[deg]:Feedback azimuth angle (from encoder)"
649 "|N_leds[cnt]:Number of detected LEDs"
650 "|N_rings[cnt]:Number of rings used to calculate the camera center"
651 "|Xc[pix]:X position of center in CCD camera frame"
652 "|Yc[pix]:Y position of center in CCD camera frame"
653 "|Ic[au]:Average intensity (LED intensity weighted with their frequency of occurance in the calculation)"
654 "|Xs[pix]:X position of start in CCD camera frame"
655 "|Ys[pix]:Y position of star in CCD camera frame"
656 "|Ms[mag]:Artifical magnitude of star (calculated form image))"
657 "|Mc[mag]:Catalog magnitude of star"),
658 fDimStatus("DRIVE_CONTROL/STATUS", "C:2;C:1", "")
659
660 {
661 }
662
663 // 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
664};
665
666// ------------------------------------------------------------------------
667
668template <class T, class S>
669class StateMachineDrive : public T, public ba::io_service, public ba::io_service::work
670{
671 int Wrap(boost::function<void()> f)
672 {
673 f();
674 return T::GetCurrentState();
675 }
676
677 boost::function<int(const EventImp &)> Wrapper(boost::function<void()> func)
678 {
679 return bind(&StateMachineDrive::Wrap, this, func);
680 }
681
682private:
683 S fDrive;
684
685 enum states_t
686 {
687 kStateDisconnected = 1,
688 kStateConnected,
689 kStateNotReady,
690 kStateReady,
691 kStateArmed,
692 kStateMoving,
693 kStateTracking,
694 };
695
696 // Status 0: Error
697 // Status 1: Unlocked
698 // Status 2: Locked
699 // Status 3: Stopping || Moving
700 // Status 4: Tracking
701
702 bool CheckEventSize(size_t has, const char *name, size_t size)
703 {
704 if (has==size)
705 return true;
706
707 ostringstream msg;
708 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
709 T::Fatal(msg);
710 return false;
711 }
712
713 enum Coordinates
714 {
715 kPoint,
716 kTrackSlow,
717 kTrackFast
718 };
719
720 string AngleToStr(double angle)
721 {
722 /* Handle sign */
723 const char sgn = angle<0?'-':'+';
724
725 /* Round interval and express in smallest units required */
726 double a = round(3600. * fabs(angle)); // deg to seconds
727
728 /* Separate into fields */
729 const double ad = trunc(a/3600.);
730 a -= ad * 3600.;
731 const double am = trunc(a/60.);
732 a -= am * 60.;
733 const double as = trunc(a);
734
735 /* Return results */
736 ostringstream str;
737 str << sgn << " " << uint16_t(ad) << " " << uint16_t(am) << " " << as;
738 return str.str();
739 }
740
741 int SendCommand(const string &str)
742 {
743 fDrive.PostMessage(str);
744 T::Message("Sending: "+str);
745 return T::GetCurrentState();
746 }
747
748 int SendCoordinates(const EventImp &evt, const Coordinates type)
749 {
750 if (!CheckEventSize(evt.GetSize(), "SendCoordinates", 16))
751 return T::kSM_FatalError;
752
753 const double *dat = evt.Ptr<double>();
754
755 string command;
756
757 switch (type)
758 {
759 case kPoint: command += "ZDAZ "; break;
760 case kTrackSlow: command += "RADEC "; break;
761 case kTrackFast: command += "GRB "; break;
762 }
763
764 command += AngleToStr(dat[0]) + ' ' + AngleToStr(dat[1]);
765
766 return SendCommand(command);
767 }
768
769 int SetLedBrightness(const EventImp &evt)
770 {
771 if (!CheckEventSize(evt.GetSize(), "SetLedBrightness", 8))
772 return T::kSM_FatalError;
773
774 const uint32_t *led = evt.Ptr<uint32_t>();
775
776 ostringstream cmd;
777 cmd << "LEDS " << led[0] << " " << led[1];
778 return SendCommand(cmd.str());
779 }
780
781
782 int SetVerbosity(const EventImp &evt)
783 {
784 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
785 return T::kSM_FatalError;
786
787 fDrive.SetVerbose(evt.GetBool());
788
789 return T::GetCurrentState();
790 }
791
792 int Disconnect()
793 {
794 // Close all connections
795 fDrive.PostClose(false);
796
797 /*
798 // Now wait until all connection have been closed and
799 // all pending handlers have been processed
800 poll();
801 */
802
803 return T::GetCurrentState();
804 }
805
806 int Reconnect(const EventImp &evt)
807 {
808 // Close all connections to supress the warning in SetEndpoint
809 fDrive.PostClose(false);
810
811 // Now wait until all connection have been closed and
812 // all pending handlers have been processed
813 poll();
814
815 if (evt.GetBool())
816 fDrive.SetEndpoint(evt.GetString());
817
818 // Now we can reopen the connection
819 fDrive.PostClose(true);
820
821 return T::GetCurrentState();
822 }
823
824 int Execute()
825 {
826 // Dispatch (execute) at most one handler from the queue. In contrary
827 // to run_one(), it doesn't wait until a handler is available
828 // which can be dispatched, so poll_one() might return with 0
829 // handlers dispatched. The handlers are always dispatched/executed
830 // synchronously, i.e. within the call to poll_one()
831 poll_one();
832
833 return fDrive.GetState();
834 }
835
836
837public:
838 StateMachineDrive(ostream &out=cout) :
839 T(out, "DRIVE_CONTROL"), ba::io_service::work(static_cast<ba::io_service&>(*this)),
840 fDrive(*this, *this)
841 {
842 // ba::io_service::work is a kind of keep_alive for the loop.
843 // It prevents the io_service to go to stopped state, which
844 // would prevent any consecutive calls to run()
845 // or poll() to do nothing. reset() could also revoke to the
846 // previous state but this might introduce some overhead of
847 // deletion and creation of threads and more.
848
849 // State names
850 AddStateName(kStateDisconnected, "Disconnected",
851 "No connection to cosy");
852
853 AddStateName(kStateConnected, "Connected",
854 "Cosy connected, drive stopped");
855
856 AddStateName(kStateNotReady, "NotReady",
857 "Drive system not ready for movement");
858
859 AddStateName(kStateReady, "Ready",
860 "Drive system ready for movement");
861
862 AddStateName(kStateArmed, "Armed",
863 "Cosy armed, drive stopped");
864
865 AddStateName(kStateMoving, "Moving",
866 "Telescope moving");
867
868 AddStateName(kStateTracking, "Tracking",
869 "Telescope tracking");
870
871 // kStateIdle
872 // kStateArmed
873 // kStateMoving
874 // kStateTracking
875
876 // Init
877 // -----------
878 // "ARM lock"
879 // "STGMD off"
880
881 /*
882 [ ] WAIT -> WM_WAIT
883 [x] STOP! -> WM_STOP
884 [x] RADEC ra(+ d m s.f) dec(+ d m s.f)
885 [x] GRB ra(+ d m s.f) dec(+ d m s.f)
886 [x] ZDAZ zd(+ d m s.f) az (+ d m s.f)
887 [ ] CELEST id offset angle
888 [ ] MOON wobble offset
889 [ ] PREPS string
890 [ ] TPOIN star mag
891 [ ] ARM lock/unlock
892 [ ] STGMD on/off
893 */
894
895 // Drive Commands
896 T::AddEvent("MOVE_TO", "D:2", kStateArmed) // ->ZDAZ
897 (bind(&StateMachineDrive::SendCoordinates, this, placeholders::_1, kPoint))
898 ("Move the telescope to the given local coordinates"
899 "|Zd[deg]:Zenith distance"
900 "|Az[deg]:Azimuth");
901
902 T::AddEvent("TRACK", "D:2", kStateArmed) // ->RADEC/GRB
903 (bind(&StateMachineDrive::SendCoordinates, this, placeholders::_1, kTrackSlow))
904 ("Move the telescope to the given sky coordinates and start tracking them"
905 "|Ra[h]:Right ascension"
906 "|Dec[deg]:Declination");
907
908 T::AddEvent("MOON", kStateArmed)
909 (bind(&StateMachineDrive::SendCommand, this, "MOON 0 0"))
910 ("Start tracking the moon");
911 T::AddEvent("VENUS", kStateArmed)
912 (bind(&StateMachineDrive::SendCommand, this, "CELEST 2 0 0"))
913 ("Start tracking Venus");
914 T::AddEvent("MARS", kStateArmed)
915 (bind(&StateMachineDrive::SendCommand, this, "CELEST 4 0 0"))
916 ("Start tracking Mars");
917 T::AddEvent("JUPITER", kStateArmed)
918 (bind(&StateMachineDrive::SendCommand, this, "CELEST 5 0 0"))
919 ("Start tracking Jupiter");
920 T::AddEvent("SATURN", kStateArmed)
921 (bind(&StateMachineDrive::SendCommand, this, "CELEST 6 0 0"))
922 ("Start tracking Saturn");
923
924 T::AddEvent("TAKE_TPOINT")
925 (bind(&StateMachineDrive::SendCommand, this, "TPOIN FACT 0"))
926 ("Take a TPoint");
927
928 T::AddEvent("SET_LED_BRIGHTNESS", "I:2")
929 (bind(&StateMachineDrive::SetLedBrightness, this, placeholders::_1))
930 ("Set the LED brightness of the top and bottom leds"
931 "|top[au]:Allowed range 0-32767 for top LEDs"
932 "|bot[au]:Allowed range 0-32767 for bottom LEDs");
933
934 T::AddEvent("LEDS_OFF")
935 (bind(&StateMachineDrive::SendCommand, this, "LEDS 0 0"))
936 ("Switch off TPoint LEDs");
937
938 T::AddEvent("STOP")
939 (bind(&StateMachineDrive::SendCommand, this, "STOP!"))
940 ("Stop any kind of movement.");
941
942// T::AddEvent("ARM", kStateConnected)
943// (bind(&StateMachineDrive::SendCommand, this, "ARM lock"))
944// ("");
945
946
947 // Verbosity commands
948 T::AddEvent("SET_VERBOSE", "B")
949 (bind(&StateMachineDrive::SetVerbosity, this, placeholders::_1))
950 ("set verbosity state"
951 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
952
953 // Conenction commands
954 AddEvent("DISCONNECT", kStateConnected, kStateArmed)
955 (bind(&StateMachineDrive::Disconnect, this))
956 ("disconnect from ethernet");
957
958 AddEvent("RECONNECT", "O", kStateDisconnected, kStateConnected, kStateArmed)
959 (bind(&StateMachineDrive::Reconnect, this, placeholders::_1))
960 ("(Re)connect ethernet connection to FTM, a new address can be given"
961 "|[host][string]:new ethernet address in the form <host:port>");
962
963 fDrive.StartConnect();
964 }
965
966 void SetEndpoint(const string &url)
967 {
968 fDrive.SetEndpoint(url);
969 }
970
971 int EvalOptions(Configuration &conf)
972 {
973 SetEndpoint(conf.Get<string>("addr"));
974
975 fDrive.SetVerbose(!conf.Get<bool>("quiet"));
976
977 return -1;
978 }
979};
980
981// ------------------------------------------------------------------------
982
983#include "Main.h"
984
985
986template<class T, class S, class R>
987int RunShell(Configuration &conf)
988{
989 return Main::execute<T, StateMachineDrive<S, R>>(conf);
990}
991
992void SetupConfiguration(Configuration &conf)
993{
994 po::options_description control("Drive control options");
995 control.add_options()
996 ("no-dim,d", po_switch(), "Disable dim services")
997 ("addr,a", var<string>("localhost:7404"), "Network address of Cosy")
998 ("quiet,q", po_bool(true), "Disable printing contents of all received messages (except dynamic data) in clear text.")
999 ;
1000
1001 conf.AddOptions(control);
1002}
1003
1004/*
1005 Extract usage clause(s) [if any] for SYNOPSIS.
1006 Translators: "Usage" and "or" here are patterns (regular expressions) which
1007 are used to match the usage synopsis in program output. An example from cp
1008 (GNU coreutils) which contains both strings:
1009 Usage: cp [OPTION]... [-T] SOURCE DEST
1010 or: cp [OPTION]... SOURCE... DIRECTORY
1011 or: cp [OPTION]... -t DIRECTORY SOURCE...
1012 */
1013void PrintUsage()
1014{
1015 cout <<
1016 "The drivectrl is an interface to cosy.\n"
1017 "\n"
1018 "The default is that the program is started without user intercation. "
1019 "All actions are supposed to arrive as DimCommands. Using the -c "
1020 "option, a local shell can be initialized. With h or help a short "
1021 "help message about the usuage can be brought to the screen.\n"
1022 "\n"
1023 "Usage: drivectrl [-c type] [OPTIONS]\n"
1024 " or: drivectrl [OPTIONS]\n";
1025 cout << endl;
1026}
1027
1028void PrintHelp()
1029{
1030// Main::PrintHelp<StateMachineFTM<StateMachine, ConnectionFTM>>();
1031
1032 /* Additional help text which is printed after the configuration
1033 options goes here */
1034
1035 /*
1036 cout << "bla bla bla" << endl << endl;
1037 cout << endl;
1038 cout << "Environment:" << endl;
1039 cout << "environment" << endl;
1040 cout << endl;
1041 cout << "Examples:" << endl;
1042 cout << "test exam" << endl;
1043 cout << endl;
1044 cout << "Files:" << endl;
1045 cout << "files" << endl;
1046 cout << endl;
1047 */
1048}
1049
1050int main(int argc, const char* argv[])
1051{
1052 Configuration conf(argv[0]);
1053 conf.SetPrintUsage(PrintUsage);
1054 Main::SetupConfiguration(conf);
1055 SetupConfiguration(conf);
1056
1057 if (!conf.DoParse(argc, argv, PrintHelp))
1058 return -1;
1059
1060 //try
1061 {
1062 // No console access at all
1063 if (!conf.Has("console"))
1064 {
1065 if (conf.Get<bool>("no-dim"))
1066 return RunShell<LocalStream, StateMachine, ConnectionDrive>(conf);
1067 else
1068 return RunShell<LocalStream, StateMachineDim, ConnectionDimDrive>(conf);
1069 }
1070 // Cosole access w/ and w/o Dim
1071 if (conf.Get<bool>("no-dim"))
1072 {
1073 if (conf.Get<int>("console")==0)
1074 return RunShell<LocalShell, StateMachine, ConnectionDrive>(conf);
1075 else
1076 return RunShell<LocalConsole, StateMachine, ConnectionDrive>(conf);
1077 }
1078 else
1079 {
1080 if (conf.Get<int>("console")==0)
1081 return RunShell<LocalShell, StateMachineDim, ConnectionDimDrive>(conf);
1082 else
1083 return RunShell<LocalConsole, StateMachineDim, ConnectionDimDrive>(conf);
1084 }
1085 }
1086 /*catch (std::exception& e)
1087 {
1088 cerr << "Exception: " << e.what() << endl;
1089 return -1;
1090 }*/
1091
1092 return 0;
1093}
Note: See TracBrowser for help on using the repository browser.