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