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

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