source: trunk/FACT++/src/smartfact.cc@ 13796

Last change on this file since 13796 was 13795, checked in by tbretz, 13 years ago
Improved the system status; implemented the display of some astronomy data.
File size: 60.0 KB
Line 
1#ifdef HAVE_LIBNOVA
2#include <libnova/solar.h>
3#include <libnova/lunar.h>
4#include <libnova/rise_set.h>
5#endif
6
7#include "Dim.h"
8#include "Event.h"
9#include "Shell.h"
10#include "StateMachineDim.h"
11#include "Connection.h"
12#include "Configuration.h"
13#include "Console.h"
14#include "Converter.h"
15#include "DimServiceInfoList.h"
16#include "PixelMap.h"
17
18#include "tools.h"
19#include "DimData.h"
20
21#include "LocalControl.h"
22
23#include "HeadersFAD.h"
24#include "HeadersBIAS.h"
25#include "HeadersFTM.h"
26
27using namespace std;
28
29// ------------------------------------------------------------------------
30
31#include "DimDescriptionService.h"
32
33// ------------------------------------------------------------------------
34
35const static string kHtmlWhite = "#ffffff";
36const static string kHtmlYellow = "#fffff0";
37const static string kHtmlRed = "#fff8f0";
38const static string kHtmlGreen = "#f0fff0";
39const static string kHtmlBlue = "#f0f0ff";
40
41#ifdef HAVE_LIBNOVA
42
43class Astro
44{
45public:
46 Time time;
47
48 Time fSunRiseDayTime;
49 Time fSunRiseCivil;
50 Time fSunRiseAstronomical;
51 Time fSunRiseDarkTime;
52
53 Time fSunSetDayTime;
54 Time fSunSetCivil;
55 Time fSunSetAstronomical;
56 Time fSunSetDarkTime;
57
58 int state;
59 string description;
60 string color;
61
62 bool isday;
63
64public:
65 Astro(double lon, double lat, const Time &t=Time()) : time(t)
66 {
67 ln_lnlat_posn observer;
68 observer.lng = lon;
69 observer.lat = lat;
70
71 // get Julian day from local time
72 const double JD = time.JD();
73
74 ln_rst_time sun_day;
75 ln_rst_time sun_civil;
76 ln_rst_time sun_astronomical;
77 ln_rst_time sun_dark;
78
79 // Warning: return code of 1 means circumpolar and is not checked!
80 //ln_get_lunar_rst (JD-0.5, &observer, &moon);
81 ln_get_solar_rst (JD-0.5, &observer, &sun_day);
82 ln_get_solar_rst_horizon(JD-0.5, &observer, - 6, &sun_civil);
83 ln_get_solar_rst_horizon(JD-0.5, &observer, -12, &sun_astronomical);
84 ln_get_solar_rst_horizon(JD-0.5, &observer, -18, &sun_dark);
85
86 fSunSetDayTime = Time(sun_day.set);
87 fSunSetCivil = Time(sun_civil.set);
88 fSunSetAstronomical = Time(sun_astronomical.set);
89 fSunSetDarkTime = Time(sun_dark.set);
90
91 fSunRiseDayTime = Time(sun_day.rise);
92 fSunRiseCivil = Time(sun_civil.rise);
93 fSunRiseAstronomical = Time(sun_astronomical.rise);
94 fSunRiseDarkTime = Time(sun_dark.rise);
95
96 const bool is_day = JD>sun_day.rise;
97 const bool is_night = JD>sun_dark.set;
98
99 //ln_get_lunar_rst (JD+0.5, &observer, &moon);
100 ln_get_solar_rst (JD+0.5, &observer, &sun_day);
101 ln_get_solar_rst_horizon(JD+0.5, &observer, - 6, &sun_civil);
102 ln_get_solar_rst_horizon(JD+0.5, &observer, -12, &sun_astronomical);
103 ln_get_solar_rst_horizon(JD+0.5, &observer, -18, &sun_dark);
104
105 if (is_day)
106 {
107 fSunRiseDayTime = Time(sun_day.rise);
108 fSunRiseCivil = Time(sun_civil.rise);
109 fSunRiseAstronomical = Time(sun_astronomical.rise);
110 fSunRiseDarkTime = Time(sun_dark.rise);
111 }
112
113 if (is_night)
114 {
115 fSunSetDayTime = Time(sun_day.set);
116 fSunSetCivil = Time(sun_civil.set);
117 fSunSetAstronomical = Time(sun_astronomical.set);
118 fSunSetDarkTime = Time(sun_dark.set);
119 }
120
121 // case 0: midnight to sun-rise | !is_day && !is_night | rise/set
122 // case 1: sun-rise to sun-set | is_day && !is_night | set /rise
123 // case 2: sun-set to midnight | is_day && is_night | rise/set
124 /*
125 if (is_day^is_night)
126 {
127 cout << "SunSet: " << fSunSetDayTime << endl;
128 cout << "SunRise: " << fSunRiseDayTime << endl;
129 }
130 else
131 {
132 cout << "SunRise: " << fSunRiseDayTime << endl;
133 cout << "SunSet: " << fSunSetDayTime << endl;
134 }*/
135
136 isday = is_day^is_night;
137
138 state = isday ? 4 : 0;
139 if (time>fSunSetDayTime) state++;
140 if (time>fSunSetCivil) state++;
141 if (time>fSunSetAstronomical) state++;
142 if (time>fSunSetDarkTime) state++;
143
144 if (time>fSunRiseDarkTime) state++;
145 if (time>fSunRiseAstronomical) state++;
146 if (time>fSunRiseCivil) state++;
147 if (time>fSunRiseDayTime) state++;
148
149 string name[] =
150 {
151 "dark time",
152 "astron. twilight",
153 "civil twilight",
154 "sunrise",
155 "day time",
156 "sunset",
157 "civil twilight",
158 "astron. twilight",
159 "dark time"
160 };
161
162 description = state[name];
163
164 string arr;
165 ostringstream out;
166 if (isday)
167 {
168 out << fSunSetDarkTime-time;
169 arr = "&darr;";
170 }
171 else
172 {
173 out << fSunRiseDayTime-time;
174 arr = "&uarr;";
175 }
176
177 description += " ["+out.str().substr(0, 5)+arr+"]";
178
179 switch (state)
180 {
181 case 0: case 1: color = kHtmlGreen; break;
182 case 2: case 3: color = kHtmlYellow; break;
183 case 4: color = kHtmlRed; break;
184 case 5: case 6: color = kHtmlYellow; break;
185 case 7: case 8: color = kHtmlGreen; break;
186 }
187 }
188};
189
190class Moon
191{
192public:
193 double ra;
194 double dec;
195
196 double disk;
197
198 bool visible;
199
200 Time fMoonRise;
201 Time fMoonTransit;
202 Time fMoonSet;
203
204 string description;
205 string color;
206
207 Time time;
208
209 Moon(double lon, double lat, const Time &t=Time()) : time(t)
210 {
211 const double JD = time.JD();
212
213 ln_lnlat_posn observer;
214 observer.lng = lon;
215 observer.lat = lat;
216
217 ln_rst_time moon;
218 ln_get_lunar_rst(JD-0.5, &observer, &moon);
219
220 fMoonRise = Time(moon.rise);
221 fMoonTransit = Time(moon.transit);
222 fMoonSet = Time(moon.set);
223
224 visible =
225 (JD>moon.rise && JD<moon.set && moon.rise<moon.set) ||
226 ((JD<moon.set || JD>moon.rise) && moon.rise>moon.set);
227
228 const bool is_up = JD>moon.rise;
229 const bool is_sinking = JD>moon.transit;
230 const bool is_dn = JD>moon.set;
231
232 ln_get_lunar_rst(JD+0.5, &observer, &moon);
233 if (is_up)
234 fMoonRise = Time(moon.rise);
235 if (is_sinking)
236 fMoonTransit = Time(moon.transit);
237 if (is_dn)
238 fMoonSet = Time(moon.set);
239
240 ln_equ_posn pos;
241 ln_get_lunar_equ_coords(JD, &pos);
242
243 ra = pos.ra/15;
244 dec = pos.dec;
245
246 disk = ln_get_lunar_disk(JD)*100;
247
248 if (!visible || disk<25)
249 color = kHtmlGreen;
250 else
251 color = disk>75 ? kHtmlRed : kHtmlYellow;
252
253 string arr;
254 ostringstream dt;
255 if (fMoonSet<fMoonRise)
256 {
257 dt << fMoonSet-time;
258 arr = "&darr;";
259 }
260 else
261 {
262 dt << fMoonRise-time;
263 arr = "&uarr;";
264 }
265
266 ostringstream out;
267 out << setprecision(2);
268 out << (visible?"visible ":"") << disk << "% [" << dt.str().substr(0,5) << arr << "]";
269
270 description = out.str();
271 }
272
273 double Angle(double r, double d)
274 {
275 const double theta0 = M_PI/2-d*M_PI/180;
276 const double phi0 = r*M_PI/12;
277
278 const double theta1 = M_PI/2-dec*M_PI/180;
279 const double phi1 = ra*M_PI/12;
280
281 const double x0 = sin(theta0) * cos(phi0);
282 const double y0 = sin(theta0) * sin(phi0);
283 const double z0 = cos(theta0);
284
285 const double x1 = sin(theta1) * cos(phi1);
286 const double y1 = sin(theta1) * sin(phi1);
287 const double z1 = cos(theta1);
288
289 double arg = x0*x1 + y0*y1 + z0*z1;
290 if(arg > 1.0) arg = 1.0;
291 if(arg < -1.0) arg = -1.0;
292
293 return acos(arg) * 180/M_PI;
294 }
295};
296
297#endif
298
299// ------------------------------------------------------------------------
300
301
302class StateMachineSmartFACT : public StateMachineDim, public DimInfoHandler
303{
304private:
305 enum states_t
306 {
307 kStateDimNetworkNA = 1,
308 kStateRunning,
309 };
310
311 // ------------------------- Internal variables -----------------------
312
313 PixelMap fPixelMap;
314
315 Time fLastUpdate;
316
317 string fPath;
318
319 // ----------------------------- Data storage -------------------------
320
321 uint32_t fMcpConfigurationState;
322 int64_t fMcpConfigurationMaxTime;
323 int64_t fMcpConfigurationMaxEvents;
324 string fMcpConfigurationName;
325 Time fMcpConfigurationRunStart;
326
327 enum weather_t { kWeatherBegin=0, kTemp = kWeatherBegin, kDew, kHum, kPress, kWind, kGusts, kDir, kWeatherEnd = kDir+1 };
328 deque<float> fMagicWeatherHist[kWeatherEnd];
329
330 vector<float> fFeedbackCalibration;
331
332 float fFeedbackTempOffset;
333 float fFeedbackUserOffset;
334
335 vector<float> fBiasControlVoltageVec;
336
337 float fBiasControlVoltageMed;
338 float fBiasControlCurrentMed;
339 float fBiasControlCurrentMax;
340
341 deque<float> fBiasControlCurrentHist;
342 deque<float> fFscControlTemperatureHist;
343
344 float fFscControlHumidityAvg;
345
346 float fDriveControlPointingZd;
347 string fDriveControlPointingAz;
348 string fDriveControlSourceName;
349
350 deque<float> fDriveControlTrackingDevHist;
351
352 int64_t fFadControlNumEvents;
353
354 float fFtmControlTriggerRateCam;
355 deque<float> fFtmControlTriggerRateHist;
356
357 vector<float> fFtmPatchThresholds;
358
359 uint64_t fRateScanDataId;
360 deque<float> fRateScanDataHist;
361
362 // ------------- Initialize variables before the Dim stuff ------------
363
364 DimServiceInfoList fNetwork;
365
366 class DimState : public DimInfoHandler
367 {
368 public:
369 DimState(const string &n, const string s="STATE") :
370 server(n), info(make_pair(Time(), -4)),
371 dim((n+"/"+s).c_str(), (void*)NULL, 0, this) { }
372
373 string server;
374 pair<Time, int> info;
375 string msg;
376
377 DimStampedInfo dim;
378
379 void infoHandler()
380 {
381 DimInfo *curr = getInfo(); // get current DimInfo address
382 if (!curr || curr != &dim)
383 return;
384
385 const bool disconnected = dim.getSize()==0;
386
387 // Make sure getTimestamp is called _before_ getTimestampMillisecs
388 const int tsec = dim.getTimestamp();
389 const int tms = dim.getTimestampMillisecs();
390
391 info = make_pair(Time(tsec, tms*1000),
392 disconnected ? -4 : dim.getQuality());
393
394 msg = disconnected ? "" : dim.getString();
395 }
396
397 const Time &time() const { return info.first; }
398 const int &state() const { return info.second; }
399
400 bool online() const { return info.second>-4; }
401
402 const string &name() const { return server; }
403 };
404
405 class DimVersion : public DimState
406 {
407 public:
408 DimVersion() : DimState("DIS_DNS", "VERSION_NUMBER") { }
409
410 void infoHandler()
411 {
412 DimInfo *curr = getInfo(); // get current DimInfo address
413 if (!curr || curr != &dim)
414 return;
415
416 DimState::infoHandler();
417
418 info.second = dim.getSize()==4 ? dim.getInt() : 0;
419 }
420
421 string version() const
422 {
423 if (info.second==0)
424 return "Offline";
425
426 ostringstream out;
427 out << "V" << info.second/100 << 'r' << info.second%100;
428 return out.str();
429 }
430 };
431
432 class DimControl : public DimState
433 {
434 typedef function<void(const DimData &)> callback;
435 map<string, callback> fCallbacks;
436 public:
437 DimControl() : DimState("DIM_CONTROL") { }
438
439 void AddCallback(const string &script, const callback &cb)
440 {
441 fCallbacks[script] = cb;
442 }
443
444 void infoHandler()
445 {
446 DimInfo *curr = getInfo(); // get current DimInfo address
447 if (!curr || curr != &dim)
448 return;
449
450 DimState::infoHandler();
451
452 // Evaluate msg
453 const size_t p0 = msg.find_first_of(':');
454 if (p0==string::npos)
455 return;
456
457 const size_t p1 = msg.find_last_of('[');
458 if (p1==string::npos)
459 return;
460
461 const size_t p2 = msg.find_first_of(':', p0+1);
462
463 const size_t p3 = p2==string::npos || p2>p1 ? p1-1 : p2;
464
465 const string file = msg.substr(p0+2, p3-p0-2);
466
467 const auto func = fCallbacks.find(file);
468 if (func==fCallbacks.end())
469 return;
470
471 // Call callback
472 func->second(DimData(curr));
473 }
474 };
475
476
477
478 DimVersion fDim;
479 DimControl fDimControl;
480 DimState fDimMcp;
481 DimState fDimDataLogger;
482 DimState fDimDriveControl;
483 DimState fDimMagicWeather;
484 DimState fDimFeedback;
485 DimState fDimBiasControl;
486 DimState fDimFtmControl;
487 DimState fDimFadControl;
488 DimState fDimFscControl;
489 DimState fDimRateControl;
490 DimState fDimRateScan;
491 DimState fDimChatServer;
492
493 DimStampedInfo fDimMcpConfiguration;
494
495 DimStampedInfo fDimDriveControlPointing;
496 DimStampedInfo fDimDriveControlTracking;
497 DimStampedInfo fDimDriveControlSource;
498
499 DimStampedInfo fDimFscControlTemperature;
500 DimStampedInfo fDimFscControlHumidity;
501
502 DimStampedInfo fDimMagicWeatherData;
503
504 DimStampedInfo fDimFeedbackDeviation;
505 DimStampedInfo fDimFeedbackCalibration;
506
507 DimStampedInfo fDimBiasControlVoltage;
508 DimStampedInfo fDimBiasControlCurrent;
509
510 DimStampedInfo fDimFadConnections;
511 DimStampedInfo fDimFadEvents;
512
513 DimStampedInfo fDimFtmControlTriggerRates;
514 DimStampedInfo fDimFtmControlStaticData;
515
516 DimStampedInfo fDimRateScanData;
517
518 DimStampedInfo *fDimFadControlEventData;
519
520 // -------------------------------------------------------------------
521
522 const State GetState(const DimState &s) const
523 {
524 return fNetwork.GetState(s.name(), s.state());
525 }
526
527 // -------------------------------------------------------------------
528
529 bool HandleService(DimInfo *curr, const DimInfo &service, void (StateMachineSmartFACT::*handle)(const DimData &))
530 {
531 if (curr!=&service)
532 return false;
533
534 (this->*handle)(DimData(curr));
535 return true;
536 }
537
538
539 bool CheckDataSize(const DimData &d, const char *name, size_t size, bool min=false)
540 {
541 if ((!min && d.data.size()==size) || (min && d.data.size()>size))
542 return true;
543
544 ostringstream msg;
545 msg << name << " - Received service has " << d.data.size() << " bytes, but expected ";
546 if (min)
547 msg << "more than ";
548 msg << size << ".";
549 Warn(msg);
550 return false;
551 }
552
553
554 // -------------------------------------------------------------------
555
556 template<class T>
557 void WriteBinary(const DimData &d, const string &fname, const T &t, double scale, double offset=0)
558 {
559 vector<uint8_t> val(t.size(), 0);
560 for (uint64_t i=0; i<t.size(); i++)
561 {
562 float range = nearbyint(128*(t[i]-offset)/scale); // [-2V; 2V]
563 if (range>127)
564 range=127;
565 if (range<0)
566 range=0;
567 val[i] = (uint8_t)range;
568 }
569
570 const char *ptr = reinterpret_cast<char*>(val.data());
571
572 ostringstream out;
573 out << d.time.JavaDate() << '\n';
574 out << offset << '\n';
575 out << offset+scale << '\n';
576 out.write(ptr, val.size()*sizeof(uint8_t));
577
578 ofstream(fPath+"/"+fname+".bin") << out.str();
579 }
580
581 // -------------------------------------------------------------------
582
583 struct Statistics
584 {
585 float min;
586 float max;
587 float med;
588 float avg;
589 //float rms;
590
591 template<class T>
592 Statistics(const T &t, size_t offset_min=0, size_t offset_max=0)
593 : min(0), max(0), med(0), avg(0)
594 {
595 if (t.size()==0)
596 return;
597
598 T copy(t);
599 sort(copy.begin(), copy.end());
600
601 if (offset_min>t.size())
602 offset_min = 0;
603 if (offset_max>t.size())
604 offset_max = 0;
605
606 min = copy[offset_min];
607 max = copy[copy.size()-1-offset_max];
608 avg = accumulate (t.begin(), t.end(), 0.)/t.size();
609
610 const size_t p = t.size()/2;
611
612 med = copy[p];
613 }
614 };
615
616 void HandleMcpConfiguration(const DimData &d)
617 {
618 if (!CheckDataSize(d, "Mcp:Configuration", 16, true))
619 return;
620
621 fMcpConfigurationState = d.qos;
622 fMcpConfigurationMaxTime = d.get<uint64_t>();
623 fMcpConfigurationMaxEvents = d.get<uint64_t>(8);
624 fMcpConfigurationName = d.ptr<char>(16);
625
626 if (d.qos==12)
627 fMcpConfigurationRunStart = Time();
628 }
629
630 void WriteWeather(const DimData &d, const string &name, int i, float min, float max)
631 {
632 const Statistics stat(fMagicWeatherHist[i]);
633
634 ostringstream out;
635 out << setprecision(3);
636 out << d.time.JavaDate() << '\n';
637
638 out << "#ffffff\t" << fMagicWeatherHist[i].back() << '\n';
639 out << "#ffffff\t" << stat.min << '\n';
640 out << "#ffffff\t" << stat.avg << '\n';
641 out << "#ffffff\t" << stat.max << '\n';
642
643 ofstream(fPath+"/"+name+".txt") << out.str();
644
645 WriteBinary(d, "magicweather-"+name+"-hist", fMagicWeatherHist[i], max-min, min);
646 }
647
648 void HandleMagicWeatherData(const DimData &d)
649 {
650 if (!CheckDataSize(d, "MagicWeather:Data", 7*4+2))
651 return;
652
653 // Store a history of the last 300 entries
654 for (int i=kWeatherBegin; i<kWeatherEnd; i++)
655 {
656 fMagicWeatherHist[i].push_back(d.ptr<float>(2)[i]);
657 if (fMagicWeatherHist[i].size()>300)
658 fMagicWeatherHist[i].pop_front();
659 }
660
661 static const char *dir[] =
662 {
663 "N", "NNE", "NE", "ENE",
664 "E", "ESE", "SE", "SSE",
665 "S", "SSW", "SW", "WSW",
666 "W", "WNW", "NW", "NNW"
667 };
668
669 const uint16_t idx = uint16_t(floor(fmod(fMagicWeatherHist[kDir].back()+360+11.25, 360)/22.5));
670
671 Astro astro(-(17.+53./60+26.525/3600), 28.+45./60+42.462/3600);
672 Moon moon(-(17.+53./60+26.525/3600), 28.+45./60+42.462/3600);
673
674 ostringstream out;
675 out << d.time.JavaDate() << '\n';
676 out << astro.color << '\t' << astro.description << '\n';
677 out << setprecision(2);
678 out << (astro.isday?kHtmlWhite:moon.color) << '\t' << moon.description << '\n';
679 out << setprecision(3);
680 for (int i=0; i<6; i++)
681 out << "#ffffff\t" << fMagicWeatherHist[i].back() << '\n';
682 out << "#ffffff\t" << dir[idx] << '\n';
683
684 ofstream(fPath+"/magicweather.txt") << out.str();
685
686 out.str("");
687 out << astro.time.JavaDate() << '\n';
688 out << kHtmlWhite << '\t' << astro.fSunRiseDarkTime.GetAsStr("%H:%M") << '\n';
689 out << kHtmlWhite << '\t' << astro.fSunRiseAstronomical.GetAsStr("%H:%M") << '\n';
690 out << kHtmlWhite << '\t' << astro.fSunRiseCivil.GetAsStr("%H:%M") << '\n';
691 out << kHtmlWhite << '\t' << astro.fSunRiseDayTime.GetAsStr("%H:%M") << '\n';
692
693 out << kHtmlWhite << '\t' << astro.fSunSetDayTime.GetAsStr("%H:%M") << '\n';
694 out << kHtmlWhite << '\t' << astro.fSunSetCivil.GetAsStr("%H:%M") << '\n';
695 out << kHtmlWhite << '\t' << astro.fSunSetAstronomical.GetAsStr("%H:%M") << '\n';
696 out << kHtmlWhite << '\t' << astro.fSunSetDarkTime.GetAsStr("%H:%M") << '\n';
697
698 out << kHtmlWhite << '\t' << moon.fMoonRise.GetAsStr("%H:%M") << '\n';
699 out << kHtmlWhite << '\t' << moon.fMoonTransit.GetAsStr("%H:%M") << '\n';
700 out << kHtmlWhite << '\t' << moon.fMoonSet.GetAsStr("%H:%M") << '\n';
701
702 ofstream(fPath+"/astro.txt") << out.str();
703
704 WriteWeather(d, "temp", kTemp, -5, 35);
705 WriteWeather(d, "dew", kDew, -5, 35);
706 WriteWeather(d, "hum", kHum, 0, 100);
707 WriteWeather(d, "wind", kWind, 0, 100);
708 WriteWeather(d, "gusts", kGusts, 0, 100);
709 WriteWeather(d, "press", kPress, 700, 1000);
710 }
711
712 void HandleDriveControlPointing(const DimData &d)
713 {
714 if (!CheckDataSize(d, "DriveControl:Pointing", 16))
715 return;
716
717 fDriveControlPointingZd = d.get<double>();
718
719 const double az = d.get<double>(8);
720
721 static const char *dir[] =
722 {
723 "N", "NNE", "NE", "ENE",
724 "E", "ESE", "SE", "SSE",
725 "S", "SSW", "SW", "WSW",
726 "W", "WNW", "NW", "NNW"
727 };
728
729 const uint16_t i = uint16_t(floor(fmod(az+360+11.25, 360)/22.5));
730 fDriveControlPointingAz = dir[i];
731
732 ostringstream out;
733 out << d.time.JavaDate() << '\n';
734
735 out << setprecision(5);
736 out << fDriveControlPointingZd << '\n';
737 out << az << '\n';
738
739 ofstream(fPath+"/drive-pointing.txt") << out.str();
740 }
741
742 void HandleDriveControlTracking(const DimData &d)
743 {
744 if (!CheckDataSize(d, "DriveControl:Tracking", 56))
745 return;
746
747 const double Ra = d.get<double>(0*8);
748 const double Dec = d.get<double>(1*8);
749 const double Zd = d.get<double>(3*8);
750 const double Az = d.get<double>(4*8);
751
752 const double zd = Zd * M_PI / 180;
753 const double dzd = d.get<double>(5*8) * M_PI / 180;
754 const double daz = d.get<double>(6*8) * M_PI / 180;
755
756 // Correct:
757 // const double d = cos(del) - sin(zd+dzd)*sin(zd)*(1.-cos(daz));
758
759 // Simplified:
760 double dev = cos(dzd) - sin(zd+dzd)*sin(zd)*(1.-cos(daz));
761 dev = acos(dev) * 180 / M_PI * 3600;
762
763 fDriveControlTrackingDevHist.push_back(dev);
764 if (fDriveControlTrackingDevHist.size()>300)
765 fDriveControlTrackingDevHist.pop_front();
766
767 WriteBinary(d, "control-deviation-hist", fDriveControlTrackingDevHist, 120);
768
769 ostringstream out;
770 out << d.time.JavaDate() << '\n';
771
772 out << kHtmlWhite << '\t' << fDriveControlSourceName << '\n';
773 out << setprecision(5);
774 out << kHtmlWhite << '\t' << Ra << '\n';
775 out << kHtmlWhite << '\t' << Dec << '\n';
776 out << setprecision(3);
777 out << kHtmlWhite << '\t' << Zd << '\n';
778 out << kHtmlWhite << '\t' << Az << '\n';
779 out << kHtmlWhite << '\t' << dev << '\n';
780
781 Moon moon(-(17.+53./60+26.525/3600), 28.+45./60+42.462/3600);
782 if (moon.visible)
783 {
784 const double angle = moon.Angle(Ra, Dec);
785
786 string col = kHtmlGreen;
787 if (angle<35 || angle>145)
788 col = kHtmlYellow;
789 if (angle<25 || angle>155)
790 col = kHtmlRed;
791 out << col << '\t' << setprecision(3) << angle << '\n';
792 }
793 else
794 out << kHtmlWhite << "\t&mdash; \n";
795
796 ofstream(fPath+"/tracking.txt") << out.str();
797 }
798
799 void HandleDriveControlSource(const DimData &d)
800 {
801 if (!CheckDataSize(d, "DriveControl:Source", 7*4+2, true))
802 return;
803
804 const double *ptr = d.ptr<double>();
805
806 const double ra = ptr[0]; // Ra[h]
807 const double dec = ptr[1]; // Dec[deg]
808 const double woff = ptr[4]; // Wobble offset [deg]
809 const double wang = ptr[5]; // Wobble angle [deg]
810
811 fDriveControlSourceName = d.ptr<char>(6*8);
812
813 ostringstream out;
814 out << d.time.JavaDate() << '\n';
815
816 out << "#ffffff\t" << fDriveControlSourceName << '\n';
817 out << setprecision(5);
818 out << "#ffffff\t" << ra << '\n';
819 out << "#ffffff\t" << dec << '\n';
820 out << setprecision(3);
821 out << "#ffffff\t" << woff << '\n';
822 out << "#ffffff\t" << wang << '\n';
823
824 ofstream(fPath+"/source.txt") << out.str();
825 }
826
827 void HandleFeedbackCalibration(const DimData &d)
828 {
829 if (!CheckDataSize(d, "Feedback:Calibration", 3*4*416))
830 {
831 fFeedbackCalibration.clear();
832 return;
833 }
834
835 const float *ptr = d.ptr<float>();
836 fFeedbackCalibration.assign(ptr+2*416, ptr+3*416);
837 }
838
839 void HandleFeedbackDeviation(const DimData &d)
840 {
841 if (!CheckDataSize(d, "Feedback:Deviation", 2*4*416+8))
842 return;
843
844 const float *ptr = d.ptr<float>();
845 vector<float> dev(ptr+416, ptr+416+320);
846
847 fFeedbackTempOffset = ptr[2*416];
848 fFeedbackUserOffset = ptr[2*416+1];
849
850 for (int i=0; i<320; i++)
851 dev[i] -= fFeedbackTempOffset+fFeedbackUserOffset;
852
853 // Write the 160 patch values to a file
854 WriteBinary(d, "feedback-deviation", dev, 1);
855
856 const Statistics stat(dev, 3);
857
858 ostringstream out;
859 out << d.time.JavaDate() << '\n';
860 out << kHtmlWhite << '\t' << fFeedbackUserOffset << '\n';
861 out << setprecision(3);
862 out << kHtmlWhite << '\t' << fFeedbackTempOffset << '\n';
863 out << kHtmlWhite << '\t' << stat.min << '\n';
864 out << kHtmlWhite << '\t' << stat.med << '\n';
865 out << kHtmlWhite << '\t' << stat.avg << '\n';
866 out << kHtmlWhite << '\t' << stat.max << '\n';
867 ofstream(fPath+"/feedback.txt") << out.str();
868 }
869
870 void HandleBiasControlVoltage(const DimData &d)
871 {
872 if (!CheckDataSize(d, "BiasControl:Voltage", 1664))
873 {
874 fBiasControlVoltageVec.clear();
875 return;
876 }
877
878 fBiasControlVoltageVec.assign(d.ptr<float>(), d.ptr<float>()+320);
879
880 const Statistics stat(fBiasControlVoltageVec);
881
882 fBiasControlVoltageMed = stat.med;
883
884 vector<float> val(320, 0);
885 for (int i=0; i<320; i++)
886 {
887 const int idx = (fPixelMap.hv(i).hw()/9)*2+fPixelMap.hv(i).group();
888 val[idx] = fBiasControlVoltageVec[i];
889 }
890
891 if (fDimBiasControl.state()==BIAS::kVoltageOn)
892 WriteBinary(d, "biascontrol-voltage", val, 10, 65);
893 else
894 WriteBinary(d, "biascontrol-voltage", val, 75);
895
896 ostringstream out;
897 out << setprecision(3);
898 out << d.time.JavaDate() << '\n';
899 out << kHtmlWhite << '\t' << stat.min << '\n';
900 out << kHtmlWhite << '\t' << stat.med << '\n';
901 out << kHtmlWhite << '\t' << stat.avg << '\n';
902 out << kHtmlWhite << '\t' << stat.max << '\n';
903 ofstream(fPath+"/voltage.txt") << out.str();
904
905 }
906
907 void HandleBiasControlCurrent(const DimData &d)
908 {
909 if (!CheckDataSize(d, "BiasControl:Current", 832))
910 return;
911
912 // Convert dac counts to uA
913 vector<float> v(320);
914 for (int i=0; i<320; i++)
915 v[i] = d.ptr<uint16_t>()[i] * 5000./4096;
916
917 const bool cal = fFeedbackCalibration.size()>0 && fBiasControlVoltageVec.size()>0;
918
919 double power_tot = 0;
920 double power_apd = 0;
921
922 // 3900 Ohm/n + 1000 Ohm + 1100 Ohm (with n=4 or n=5)
923 const double R[2] = { 3075, 2870 };
924
925 // Calibrate the data (subtract offset)
926 if (cal)
927 for (int i=0; i<320; i++)
928 {
929 // Measued current minus leakage current (bias crate calibration)
930 v[i] -= fBiasControlVoltageVec[i]/fFeedbackCalibration[i]*1e6;
931
932 // Total power participated in the camera at the G-APD
933 // and the serial resistors (total voltage minus voltage
934 // drop at resistors in bias crate)
935 power_tot += v[i]*(fBiasControlVoltageVec[i] - 1100e-6*v[i])*1e-6;
936
937 // Group index (0 or 1) of the of the pixel (4 or 5 pixel patch)
938 const int g = fPixelMap.hv(i).group();
939
940 // Current per G-APD
941 v[i] /= g ? 5 : 4;
942
943 // Power consumption per G-APD
944 if (i!=66 && i!=191 && i!=193)
945 power_apd += v[i]*(fBiasControlVoltageVec[i]-R[g]*v[i]*1e-6)*1e-6;
946 }
947
948 // Divide by number of summed channels, concert to mW
949 power_apd /= 317e-3; // [mW]
950
951 if (power_tot<1e-3)
952 power_tot = 0;
953 if (power_apd<1e-3)
954 power_apd = 0;
955
956 // Get the maximum of each patch
957 vector<float> val(320, 0);
958 for (int i=0; i<320; i++)
959 {
960 const int idx = (fPixelMap.hv(i).hw()/9)*2+fPixelMap.hv(i).group();
961 val[idx] = v[i];
962 }
963
964 // Write the 160 patch values to a file
965 WriteBinary(d, "biascontrol-current", val, 100);
966
967 const Statistics stat(v, 0, 3);
968
969 // Exclude the three crazy channels
970 fBiasControlCurrentMed = stat.med;
971 fBiasControlCurrentMax = stat.max;
972
973 // Store a history of the last 60 entries
974 fBiasControlCurrentHist.push_back(fBiasControlCurrentMed);
975 if (fBiasControlCurrentHist.size()>360)
976 fBiasControlCurrentHist.pop_front();
977
978 // write the history to a file
979 WriteBinary(d, "biascontrol-current-hist", fBiasControlCurrentHist, 100);
980
981 const string col0 = cal ? kHtmlGreen : kHtmlWhite;
982
983 string col1 = col0;
984 string col2 = col0;
985 string col3 = col0;
986 string col4 = col0;
987
988 if (cal && stat.min>65)
989 col1 = kYellow;
990 if (cal && stat.min>80)
991 col1 = kRed;
992
993 if (cal && stat.med>65)
994 col2 = kYellow;
995 if (cal && stat.med>80)
996 col2 = kRed;
997
998 if (cal && stat.avg>65)
999 col3 = kYellow;
1000 if (cal && stat.avg>80)
1001 col3 = kRed;
1002
1003 if (cal && stat.max>65)
1004 col4 = kYellow;
1005 if (cal && stat.max>80)
1006 col4 = kRed;
1007
1008 ostringstream out;
1009 out << setprecision(2);
1010 out << d.time.JavaDate() << '\n';
1011 out << col0 << '\t' << (cal?"yes":"no") << '\n';
1012 out << col1 << '\t' << stat.min << '\n';
1013 out << col2 << '\t' << stat.med << '\n';
1014 out << col3 << '\t' << stat.avg << '\n';
1015 out << col4 << '\t' << stat.max << '\n';
1016 out << kHtmlWhite << '\t' << power_tot << "W [" << power_apd << "mW]\n";
1017 ofstream(fPath+"/current.txt") << out.str();
1018 }
1019
1020 void HandleFadEvents(const DimData &d)
1021 {
1022 if (!CheckDataSize(d, "FadControl:Events", 4*4))
1023 {
1024 fFadControlNumEvents = -1;
1025 return;
1026 }
1027
1028 fFadControlNumEvents = d.get<uint32_t>();
1029 }
1030
1031 void HandleFadConnections(const DimData &d)
1032 {
1033 if (!CheckDataSize(d, "FadControl:Connections", 41))
1034 {
1035 //fStatusEventBuilderLabel->setText("Offline");
1036 return;
1037 }
1038
1039 string rc(40, '-'); // orange/red [45]
1040
1041 const uint8_t *ptr = d.ptr<uint8_t>();
1042
1043 int c[4] = { '.', '.', '.', '.' };
1044
1045 for (int i=0; i<40; i++)
1046 {
1047 const uint8_t stat1 = ptr[i]&3;
1048 const uint8_t stat2 = ptr[i]>>3;
1049
1050 if (stat1==0 && stat2==0)
1051 rc[i] = '.'; // gray [46]
1052 else
1053 if (stat1>=2 && stat2==8)
1054 rc[i] = stat1==2?'+':'*'; // green [43] : check [42]
1055
1056 if (rc[i]<c[i/10])
1057 c[i/10] = rc[i];
1058 }
1059
1060 string col[4];
1061 for (int i=0; i<4; i++)
1062 switch (c[i])
1063 {
1064 case '.': col[i]=kHtmlWhite; break;
1065 case '-': col[i]=kHtmlRed; break;
1066 case '+': col[i]=kHtmlYellow; break;
1067 case '*': col[i]=kHtmlGreen; break;
1068 }
1069
1070 ostringstream out;
1071 out << setprecision(3);
1072 out << d.time.JavaDate() << '\n';
1073 out << col[0] << '\t' << rc.substr( 0, 10) << '\n';
1074 out << col[1] << '\t' << rc.substr(10, 10) << '\n';
1075 out << col[2] << '\t' << rc.substr(20, 10) << '\n';
1076 out << col[3] << '\t' << rc.substr(30, 10) << '\n';
1077 ofstream(fPath+"/fad.txt") << out.str();
1078 }
1079
1080 void HandleFtmControlTriggerRates(const DimData &d)
1081 {
1082 if (!CheckDataSize(d, "FtmControl:TriggerRates", 24+160+640+8))
1083 return;
1084
1085 // New run started
1086 if (d.get<float>(20)<0)
1087 return;
1088
1089 fFtmControlTriggerRateCam = d.get<float>(20);
1090
1091 const float *brates = d.ptr<float>(24); // Board rate
1092 const float *prates = d.ptr<float>(24+160); // Patch rate
1093
1094 // Store a history of the last 60 entries
1095 fFtmControlTriggerRateHist.push_back(fFtmControlTriggerRateCam);
1096 if (fFtmControlTriggerRateHist.size()>60)
1097 fFtmControlTriggerRateHist.pop_front();
1098
1099 // FIXME: Add statistics for all kind of rates
1100
1101 WriteBinary(d, "ftmcontrol-triggerrate-hist",
1102 fFtmControlTriggerRateHist, 100);
1103 WriteBinary(d, "ftmcontrol-boardrates",
1104 vector<float>(brates, brates+40), 10);
1105 WriteBinary(d, "ftmcontrol-patchrates",
1106 vector<float>(prates, prates+160), 10);
1107
1108 ostringstream out;
1109 out << setprecision(3);
1110 out << d.time.JavaDate() << '\n';
1111 out << "#ffffff\t" << fFtmControlTriggerRateCam << '\n';
1112
1113 ofstream(fPath+"/trigger.txt") << out.str();
1114
1115 const Statistics bstat(vector<float>(brates, brates+40));
1116 const Statistics pstat(vector<float>(prates, prates+160));
1117
1118 out.str("");
1119 out << d.time.JavaDate() << '\n';
1120 out << kHtmlWhite << '\t' << bstat.min << '\n';
1121 out << kHtmlWhite << '\t' << bstat.med << '\n';
1122 out << kHtmlWhite << '\t' << bstat.avg << '\n';
1123 out << kHtmlWhite << '\t' << bstat.max << '\n';
1124 ofstream(fPath+"/boardrates.txt") << out.str();
1125
1126 out.str("");
1127 out << d.time.JavaDate() << '\n';
1128 out << kHtmlWhite << '\t' << pstat.min << '\n';
1129 out << kHtmlWhite << '\t' << pstat.med << '\n';
1130 out << kHtmlWhite << '\t' << pstat.avg << '\n';
1131 out << kHtmlWhite << '\t' << pstat.max << '\n';
1132 ofstream(fPath+"/patchrates.txt") << out.str();
1133 }
1134
1135 void HandleFtmControlStaticData(const DimData &d)
1136 {
1137 if (!CheckDataSize(d, "FtmControl:StaticData", 740))
1138 return;
1139
1140 const uint16_t *ptr = d.ptr<uint16_t>(260);
1141 vector<uint16_t> vec(ptr, ptr+160);
1142
1143 WriteBinary(d, "ftmcontrol-thresholds", vec, 1000);
1144
1145 const Statistics stat(vec);
1146
1147 ostringstream out;
1148 out << d.time.JavaDate() << '\n';
1149 out << kHtmlWhite << '\t' << stat.min << '\n';
1150 out << kHtmlWhite << '\t' << stat.med << '\n';
1151 out << kHtmlWhite << '\t' << stat.avg << '\n';
1152 out << kHtmlWhite << '\t' << stat.max << '\n';
1153 ofstream(fPath+"/thresholds.txt") << out.str();
1154 }
1155
1156 void HandleFadControlEventData(const DimData &d)
1157 {
1158 if (!CheckDataSize(d, "FadControl:EventData", 23040))
1159 return;
1160
1161 //const float *avg = d.ptr<float>();
1162 //const float *rms = d.ptr<float>(1440*sizeof(float));
1163 const float *dat = d.ptr<float>(1440*sizeof(float)*2);
1164 //const float *pos = d.ptr<float>(1440*sizeof(float)*3);
1165
1166 vector<float> max(320, -2);
1167 for (int i=0; i<1440; i++)
1168 {
1169 if (i%9==8)
1170 continue;
1171
1172 const int idx = (fPixelMap.hw(i).hw()/9)*2+fPixelMap.hw(i).group();
1173 const double v = dat[i]/1000;
1174 if (v>max[idx])
1175 max[idx]=v;
1176 }
1177
1178 switch (d.qos)
1179 {
1180 case 0: WriteBinary(d, "fadcontrol-eventdata", max, 2, -1); break;
1181 case 1: WriteBinary(d, "fadcontrol-eventdata", max, 2, 0); break;
1182 default: WriteBinary(d, "fadcontrol-eventdata", max, 0.25, 0); break;
1183 }
1184 }
1185
1186 void HandleFscControlTemperature(const DimData &d)
1187 {
1188 if (!CheckDataSize(d, "FscControl:Temperature", 240))
1189 return;
1190
1191 const float *ptr = d.ptr<float>(4);
1192
1193 double avg = 0;
1194 double rms = 0;
1195 double min = 99;
1196 double max = -99;
1197
1198 int num = 0;
1199 for (const float *t=ptr; t<ptr+31; t++)
1200 {
1201 if (*t==0)
1202 continue;
1203
1204 if (*t>max)
1205 max = *t;
1206
1207 if (*t<min)
1208 min = *t;
1209
1210 avg += *t;
1211 rms += *t * *t;
1212
1213 num++;
1214 }
1215
1216 avg /= num;
1217 rms = sqrt(rms/num-avg*avg);
1218
1219 fFscControlTemperatureHist.push_back(avg-fMagicWeatherHist[kTemp].back());
1220 if (fFscControlTemperatureHist.size()>300)
1221 fFscControlTemperatureHist.pop_front();
1222
1223 const Statistics stat(fFscControlTemperatureHist);
1224
1225 ostringstream out;
1226 out << setprecision(3);
1227 out << d.time.JavaDate() << '\n';
1228 out << "#ffffff\t" << fFscControlHumidityAvg << '\n';
1229 out << "#ffffff\t" << min << '\n';
1230 out << "#ffffff\t" << avg << '\n';
1231 out << "#ffffff\t" << max << '\n';
1232 out << "#ffffff\t" << stat.min << '\n';
1233 out << "#ffffff\t" << stat.avg << '\n';
1234 out << "#ffffff\t" << stat.max << '\n';
1235
1236 ofstream(fPath+"/fsc.txt") << out.str();
1237
1238 WriteBinary(d, "fsccontrol-temperature-hist",
1239 fFscControlTemperatureHist, 10);
1240 }
1241
1242 void HandleFscControlHumidity(const DimData &d)
1243 {
1244 if (!CheckDataSize(d, "FscControl:Humidity", 5*4))
1245 return;
1246
1247 const float *ptr = d.ptr<float>(4);
1248
1249 double avg = 0;
1250 int num = 0;
1251
1252 for (const float *t=ptr; t<ptr+4; t++)
1253 if (*t>0)
1254 {
1255 avg += *t;
1256 num++;
1257 }
1258
1259 fFscControlHumidityAvg = avg/num;
1260 }
1261
1262 void HandleRateScanData(const DimData &d)
1263 {
1264 if (!CheckDataSize(d, "RateScan:Data", 824))
1265 return;
1266
1267 const uint64_t id = d.get<uint64_t>();
1268 const float rate = log10(d.get<float>(20));
1269
1270 if (fRateScanDataId!=id)
1271 {
1272 fRateScanDataHist.clear();
1273 fRateScanDataId = id;
1274 }
1275 fRateScanDataHist.push_back(rate);
1276
1277 WriteBinary(d, "ratescan-hist", fRateScanDataHist, 10, -2);
1278 }
1279
1280 // -------------------------------------------------------------------
1281
1282 void HandleDoTest(const DimData &d)
1283 {
1284 ostringstream out;
1285 out << d.time.JavaDate() << '\t' << fDimControl.online() << '\n';
1286 switch (d.qos)
1287 {
1288 case -3: out << kHtmlWhite << "\tNot running\n"; break;
1289 case -2: out << kHtmlBlue << "\tLoading\n"; break;
1290 case -1: out << kHtmlBlue << "\tStarted\n"; break;
1291 default: out << kHtmlGreen << "\tRunning [" << d.qos << "]\n"; break;
1292 }
1293
1294 ofstream(fPath+"/dotest.txt") << out.str();
1295 }
1296
1297 // -------------------------------------------------------------------
1298
1299 void infoHandler()
1300 {
1301 DimInfo *curr = getInfo(); // get current DimInfo address
1302 if (!curr)
1303 return;
1304
1305 if (HandleService(curr, fDimMcpConfiguration, &StateMachineSmartFACT::HandleMcpConfiguration))
1306 return;
1307 if (HandleService(curr, fDimMagicWeatherData, &StateMachineSmartFACT::HandleMagicWeatherData))
1308 return;
1309 if (HandleService(curr, fDimDriveControlPointing, &StateMachineSmartFACT::HandleDriveControlPointing))
1310 return;
1311 if (HandleService(curr, fDimDriveControlTracking, &StateMachineSmartFACT::HandleDriveControlTracking))
1312 return;
1313 if (HandleService(curr, fDimDriveControlSource, &StateMachineSmartFACT::HandleDriveControlSource))
1314 return;
1315 if (HandleService(curr, fDimFeedbackDeviation, &StateMachineSmartFACT::HandleFeedbackDeviation))
1316 return;
1317 if (HandleService(curr, fDimFeedbackCalibration, &StateMachineSmartFACT::HandleFeedbackCalibration))
1318 return;
1319 if (HandleService(curr, fDimBiasControlVoltage, &StateMachineSmartFACT::HandleBiasControlVoltage))
1320 return;
1321 if (HandleService(curr, fDimBiasControlCurrent, &StateMachineSmartFACT::HandleBiasControlCurrent))
1322 return;
1323 if (HandleService(curr, fDimFadConnections, &StateMachineSmartFACT::HandleFadConnections))
1324 return;
1325 if (HandleService(curr, fDimFadEvents, &StateMachineSmartFACT::HandleFadEvents))
1326 return;
1327 if (HandleService(curr, fDimFtmControlTriggerRates, &StateMachineSmartFACT::HandleFtmControlTriggerRates))
1328 return;
1329 if (HandleService(curr, fDimFtmControlStaticData, &StateMachineSmartFACT::HandleFtmControlStaticData))
1330 return;
1331 if (HandleService(curr, *fDimFadControlEventData, &StateMachineSmartFACT::HandleFadControlEventData))
1332 return;
1333 if (HandleService(curr, fDimFscControlTemperature, &StateMachineSmartFACT::HandleFscControlTemperature))
1334 return;
1335 if (HandleService(curr, fDimFscControlHumidity, &StateMachineSmartFACT::HandleFscControlHumidity))
1336 return;
1337 if (HandleService(curr, fDimRateScanData, &StateMachineSmartFACT::HandleRateScanData))
1338 return;
1339 }
1340
1341 bool CheckEventSize(size_t has, const char *name, size_t size)
1342 {
1343 if (has==size)
1344 return true;
1345
1346 ostringstream msg;
1347 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
1348 Fatal(msg);
1349 return false;
1350 }
1351
1352 void PrintState(const DimState &state) const
1353 {
1354 const State rc = GetState(state);
1355
1356 Out() << state.time().GetAsStr("%H:%M:%S.%f").substr(0, 12) << " - ";
1357 Out() << kBold << state.name() << ": ";
1358 if (rc.index==-3)
1359 {
1360 Out() << kReset << "Offline" << endl;
1361 return;
1362 }
1363 if (rc.index==-2)
1364 Out() << state.state();
1365 else
1366 Out() << rc.name << "[" << rc.index << "]";
1367 Out() << kReset << " - " << kBlue << rc.comment << endl;
1368 }
1369
1370 int Print() const
1371 {
1372 Out() << fDim.time().GetAsStr("%H:%M:%S.%f").substr(0, 12) << " - ";
1373 Out() << kBold << "DIM_DNS: " << fDim.version() << endl;
1374
1375 PrintState(fDimMcp);
1376 PrintState(fDimControl);
1377 PrintState(fDimDataLogger);
1378 PrintState(fDimDriveControl);
1379 PrintState(fDimFadControl);
1380 PrintState(fDimFtmControl);
1381 PrintState(fDimBiasControl);
1382 PrintState(fDimFeedback);
1383 PrintState(fDimRateControl);
1384 PrintState(fDimFscControl);
1385 PrintState(fDimMagicWeather);
1386 PrintState(fDimRateScan);
1387 PrintState(fDimChatServer);
1388
1389 return GetCurrentState();
1390 }
1391
1392 string GetStateHtml(const DimState &state, int green) const
1393 {
1394 if (!state.online())
1395 return kHtmlWhite+"\t&mdash;\n";
1396
1397 if (&state==&fDimControl)
1398 {
1399 ostringstream out;
1400 out << kHtmlGreen << '\t';
1401 return kHtmlGreen+'\t'+(state.state()==-3?"Idle":state.msg)+'\n';
1402 }
1403
1404 const State rc = GetState(state);
1405
1406 // Sate not found in list, server online (-3: offline; -2: not found)
1407 if (rc.index==-2)
1408 {
1409 ostringstream out;
1410 out << kHtmlWhite << '\t' << state.state() << '\n';
1411 return out.str();
1412 }
1413
1414 //ostringstream msg;
1415 //msg << kHtmlWhite << '\t' << rc.name << " [" << rc.index << "]\n";
1416 //return msg.str();
1417
1418 if (rc.index<1)
1419 return kHtmlWhite + "\t&mdash;\n";
1420
1421
1422 return (rc.index<green?kHtmlYellow:kHtmlGreen) + '\t' + rc.name + '\n';
1423 }
1424
1425 int Execute()
1426 {
1427 // Dispatch (execute) at most one handler from the queue. In contrary
1428 // to run_one(), it doesn't wait until a handler is available
1429 // which can be dispatched, so poll_one() might return with 0
1430 // handlers dispatched. The handlers are always dispatched/executed
1431 // synchronously, i.e. within the call to poll_one()
1432 //poll_one();
1433
1434 if (fDim.state()==0)
1435 return kStateDimNetworkNA;
1436
1437 Time now;
1438 if (now-fLastUpdate<boost::posix_time::seconds(1))
1439 return kStateRunning;
1440
1441 fLastUpdate=now;
1442
1443 ostringstream out;
1444 out << now.JavaDate() << '\t' << fDimControl.online() << '\n';
1445 out << setprecision(3);
1446
1447 // -------------- System status --------------
1448 if (fDimMcp.state()>=5) // Idle
1449 {
1450 string col = kHtmlBlue;
1451 /*
1452 if (fMcpConfigurationState!= 5 && // Idle
1453 fMcpConfigurationState!=11 && // Trigger On
1454 fMcpConfigurationState!=12) // Taking Data*/
1455 if (fDimMcp.state()!= 5 && // Idle
1456 fDimMcp.state()!=11 && // Trigger On
1457 fDimMcp.state()!=12) // Taking Data
1458 col = kHtmlYellow;
1459 else
1460 if (fDimFadControl.state()==FAD::kWritingData)
1461 col = kHtmlGreen;
1462
1463 out << col << '\t';
1464
1465 if (fDimRateControl.state()!=5 && fDimRateScan.state()!=5)
1466 {
1467 switch (fDimMcp.state()/*fMcpConfigurationState*/)
1468 {
1469 // kStateIdle
1470 case 5: out << "Idle [" << fMcpConfigurationName << "]"; break;
1471 // Configuring1 - Configuring3
1472 case 7:
1473 case 8:
1474 case 9: out << "Configuring [" << fMcpConfigurationName << "]"; break;
1475 // Configured
1476 case 10: out << "Configured [" << fMcpConfigurationName << "]"; break;
1477 // TriggerOn / Taking Data
1478 case 11:
1479 case 12: out << fMcpConfigurationName; break;
1480 }
1481 }
1482 else
1483 if (fDimRateControl.state()==5/*kStateSettingGlobalThreshold*/)
1484 out << "Calibrating threshold";
1485 else
1486
1487 if (fDimRateScan.state()==5/*kStateSettingGlobalThreshold*/)
1488 out << "Rate scan in progress";
1489
1490 if (fDimMcp.state()>10 && fDimRateControl.state()!=5)
1491 {
1492 if (fMcpConfigurationMaxEvents>0 || fMcpConfigurationMaxTime>0 || fMcpConfigurationState==12)
1493 out << " [";
1494 if (fMcpConfigurationMaxEvents>0)
1495 {
1496 if (fFadControlNumEvents>0 && fMcpConfigurationState==12)
1497 out << fMcpConfigurationMaxEvents-fFadControlNumEvents;
1498 else
1499 out << fMcpConfigurationMaxEvents;
1500 }
1501 if (fMcpConfigurationMaxEvents>0 && (fMcpConfigurationMaxTime>0 || fMcpConfigurationState==12))
1502 out << '/';
1503 if (fMcpConfigurationMaxTime>0)
1504 {
1505 if (fMcpConfigurationState==12)
1506 {
1507
1508 const uint32_t dt = (Time()-fMcpConfigurationRunStart).total_seconds();
1509 if (dt>fMcpConfigurationMaxTime)
1510 out << "---";
1511 else
1512 out << fMcpConfigurationMaxTime-dt << 's';
1513 }
1514 else
1515 out << fMcpConfigurationMaxTime << 's';
1516 }
1517 else
1518 {
1519 if (fMcpConfigurationState==12)
1520 {
1521 ostringstream d;
1522 d << Time()-fMcpConfigurationRunStart;
1523 out << d.str().substr(3, 5);
1524 }
1525 }
1526
1527 if (fMcpConfigurationMaxEvents>0 || fMcpConfigurationMaxTime>0 || fMcpConfigurationState==12)
1528 out << ']';
1529 }
1530 }
1531 else
1532 out << kHtmlWhite;
1533 out << '\n';
1534
1535 // ------------------ Drive -----------------
1536 if (fDimDriveControl.state()>=5) // Armed, Moving, Tracking
1537 {
1538 const double dev = fDriveControlTrackingDevHist.size()>0 ? fDriveControlTrackingDevHist.back() : 0;
1539 const State rc = GetState(fDimDriveControl);
1540 string col = kHtmlGreen;
1541 if (rc.index==6) // Moving
1542 col = kHtmlBlue;
1543 if (rc.index==5) // Armed
1544 col = kHtmlWhite;
1545 if (rc.index==7) // Tracking
1546 {
1547 if (dev>60) // ~1.5mm
1548 col = kHtmlYellow;
1549 if (dev>100) // ~1/4 of a pixel ~ 2.5mm
1550 col = kHtmlRed;
1551 }
1552 out << col << '\t';
1553
1554 //out << rc.name << '\t';
1555 out << fDriveControlPointingZd << '\t';
1556 out << fDriveControlPointingAz << '\t';
1557 if (fDimDriveControl.state()==7)
1558 {
1559 out << fDriveControlSourceName << '\t';
1560 out << setprecision(2);
1561 out << dev << '\n';
1562 out << setprecision(3);
1563 }
1564 else
1565 out << "\t\n";
1566 }
1567 else
1568 out << kHtmlWhite << '\n';
1569
1570 // ------------------- FSC ------------------
1571 if (fDimFscControl.state()>1 && fFscControlTemperatureHist.size()>0)
1572 {
1573 out << kHtmlGreen << '\t' << fFscControlTemperatureHist.back() << '\n';
1574 }
1575 else
1576 out << kHtmlWhite << '\n';
1577
1578 // --------------- MagicWeather -------------
1579 if (fDimMagicWeather.state()==3 && fMagicWeatherHist[kWeatherBegin].size()>0)
1580 {
1581 /*
1582 const float diff = fMagicWeatherHist[kTemp].back()-fMagicWeatherHist[kDew].back();
1583 string col1 = kHtmlRed;
1584 if (diff>0.3)
1585 col1 = kHtmlYellow;
1586 if (diff>0.7)
1587 col1 = kHtmlGreen;
1588 */
1589
1590 const float wind = fMagicWeatherHist[kGusts].back();
1591 const float hum = fMagicWeatherHist[kHum].back();
1592 string col = kHtmlGreen;
1593 if (wind>35 || hum>95)
1594 col = kHtmlYellow;
1595 if (wind>50 || hum>98)
1596 col = kHtmlRed;
1597
1598 out << col << '\t';
1599 out << fMagicWeatherHist[kHum].back() << '\t';
1600 out << setprecision(2);
1601 out << fMagicWeatherHist[kGusts].back() << '\n';
1602 out << setprecision(3);
1603 }
1604 else
1605 out << kHtmlWhite << "\n";
1606
1607 // --------------- FtmControl -------------
1608 if (fDimFtmControl.state()==FTM::kTriggerOn)
1609 {
1610 string col = kHtmlGreen;
1611 if (fFtmControlTriggerRateCam<15)
1612 col = kHtmlYellow;
1613 if (fFtmControlTriggerRateCam>100)
1614 col = kHtmlRed;
1615
1616 out << col << '\t' << fFtmControlTriggerRateCam << '\n';
1617 }
1618 else
1619 out << kHtmlWhite << '\n';
1620
1621 // --------------- BiasControl -------------
1622 if (fDimBiasControl.state()==BIAS::kRamping ||
1623 fDimBiasControl.state()==BIAS::kOverCurrent ||
1624 fDimBiasControl.state()==BIAS::kVoltageOn ||
1625 fDimBiasControl.state()==BIAS::kVoltageOff)
1626 {
1627 const bool off = fDimBiasControl.state()==BIAS::kVoltageOff;
1628 const bool oc = fDimBiasControl.state()==BIAS::kOverCurrent;
1629
1630 string col = fBiasControlVoltageMed>3?kHtmlGreen:kHtmlWhite;
1631 if (fBiasControlCurrentMax>65)
1632 col = kHtmlYellow;
1633 if (fBiasControlCurrentMax>80)
1634 col = kHtmlRed;
1635
1636 // Bias in overcurrent => Red
1637 if (fDimBiasControl.state()==BIAS::kOverCurrent)
1638 col = kHtmlRed;
1639
1640 // MCP in ReadyForDatataking/Configuring/Configured/TriggerOn/TakingData
1641 // and Bias not in "data-taking state' => Red
1642 if (fDimMcp.state()>5 &&
1643 fDimBiasControl.state()!=BIAS::kVoltageOn &&
1644 fDimBiasControl.state()!=BIAS::kVoltageOff)
1645 col = kHtmlRed;
1646
1647 const bool cal = fFeedbackCalibration.size();
1648
1649 // Feedback is currently calibrating => Blue
1650 if (fDimFeedback.state()==13)
1651 {
1652 out << kHtmlBlue << '\t';
1653 out << "***\t";
1654 out << "***\t";
1655 }
1656 else
1657 {
1658 out << setprecision(2);
1659 out << col << '\t';
1660 out << (off ? 0 : fBiasControlCurrentMed) << '\t';
1661 if (oc)
1662 out << "(OC) ";
1663 else
1664 {
1665 if (cal)
1666 out << (off ? 0 : fBiasControlCurrentMax);
1667 else
1668 out << "&mdash; ";
1669 }
1670 out << '\t';
1671 out << setprecision(3);
1672 }
1673 out << (off ? 0 : fBiasControlVoltageMed) << '\n';
1674 }
1675 else
1676 out << kHtmlWhite << '\n';
1677
1678
1679 // ------------------------------------------
1680
1681 ofstream(fPath+"/fact.txt") << out.str();
1682
1683 // ==========================================
1684
1685 out.str("");
1686 out << now.JavaDate() << '\t' << fDimControl.online() << '\n';
1687
1688 if (fDim.state()==0)
1689 out << kHtmlWhite << "\tOffline\n\n\n\n\n\n\n\n\n\n\n\n";
1690 else
1691 {
1692 out << kHtmlGreen << '\t' << fDim.version() << '\n';
1693
1694 out << GetStateHtml(fDimMcp, 4);
1695 out << GetStateHtml(fDimControl, 0);
1696 out << GetStateHtml(fDimDataLogger, 1);
1697 out << GetStateHtml(fDimDriveControl, 2);
1698 out << GetStateHtml(fDimFadControl, FAD::kConnected);
1699 out << GetStateHtml(fDimFtmControl, FTM::kConnected);
1700 out << GetStateHtml(fDimBiasControl, BIAS::kConnected);
1701 out << GetStateHtml(fDimFeedback, 4);
1702 out << GetStateHtml(fDimRateControl, 4);
1703 out << GetStateHtml(fDimFscControl, 2);
1704 out << GetStateHtml(fDimMagicWeather, 2);
1705 out << GetStateHtml(fDimRateScan, 4);
1706 out << GetStateHtml(fDimChatServer, 1);
1707 }
1708
1709 ofstream(fPath+"/status.txt") << out.str();
1710
1711 return kStateRunning;
1712 }
1713
1714public:
1715 StateMachineSmartFACT(ostream &out=cout) : StateMachineDim(out, "SMART_FACT"),
1716 fPath("www/smartfact/data"),
1717 fMcpConfigurationMaxTime(0),
1718 fMcpConfigurationMaxEvents(0),
1719 fRateScanDataId(0),
1720 //---
1721 fDimMcp ("MCP"),
1722 fDimDataLogger ("DATA_LOGGER"),
1723 fDimDriveControl ("DRIVE_CONTROL"),
1724 fDimMagicWeather ("MAGIC_WEATHER"),
1725 fDimFeedback ("FEEDBACK"),
1726 fDimBiasControl ("BIAS_CONTROL"),
1727 fDimFtmControl ("FTM_CONTROL"),
1728 fDimFadControl ("FAD_CONTROL"),
1729 fDimFscControl ("FSC_CONTROL"),
1730 fDimRateControl ("RATE_CONTROL"),
1731 fDimRateScan ("RATE_SCAN"),
1732 fDimChatServer ("CHAT_SERVER"),
1733 //---
1734 fDimMcpConfiguration ("MCP/CONFIGURATION", (void*)NULL, 0, this),
1735 //---
1736 fDimDriveControlPointing ("DRIVE_CONTROL/POINTING_POSITION", (void*)NULL, 0, this),
1737 fDimDriveControlTracking ("DRIVE_CONTROL/TRACKING_POSITION", (void*)NULL, 0, this),
1738 fDimDriveControlSource ("DRIVE_CONTROL/SOURCE_POSITION", (void*)NULL, 0, this),
1739 //---
1740 fDimFscControlTemperature ("FSC_CONTROL/TEMPERATURE", (void*)NULL, 0, this),
1741 fDimFscControlHumidity ("FSC_CONTROL/HUMIDITY", (void*)NULL, 0, this),
1742 //---
1743 fDimMagicWeatherData ("MAGIC_WEATHER/DATA", (void*)NULL, 0, this),
1744 //---
1745 fDimFeedbackDeviation ("FEEDBACK/DEVIATION", (void*)NULL, 0, this),
1746 fDimFeedbackCalibration ("FEEDBACK/CALIBRATION", (void*)NULL, 0, this),
1747 //---
1748 fDimBiasControlVoltage ("BIAS_CONTROL/VOLTAGE", (void*)NULL, 0, this),
1749 fDimBiasControlCurrent ("BIAS_CONTROL/CURRENT", (void*)NULL, 0, this),
1750 //---
1751 fDimFadConnections ("FAD_CONTROL/CONNECTIONS", (void*)NULL, 0, this),
1752 fDimFadEvents ("FAD_CONTROL/EVENTS", (void*)NULL, 0, this),
1753 //---
1754 fDimFtmControlTriggerRates("FTM_CONTROL/TRIGGER_RATES", (void*)NULL, 0, this),
1755 fDimFtmControlStaticData ("FTM_CONTROL/STATIC_DATA", (void*)NULL, 0, this),
1756 //-
1757 fDimRateScanData ("RATE_SCAN/DATA", (void*)NULL, 0, this),
1758 //-
1759 fDimFadControlEventData(0)
1760 {
1761 // State names
1762 AddStateName(kStateDimNetworkNA, "DimNetworkNotAvailable",
1763 "The Dim DNS is not reachable.");
1764
1765 AddStateName(kStateRunning, "Running", "");
1766
1767 AddEvent("PRINT")
1768 (bind(&StateMachineSmartFACT::Print, this))
1769 ("");
1770
1771 fDimControl.AddCallback("dotest.dim", bind(&StateMachineSmartFACT::HandleDoTest, this, placeholders::_1));
1772 }
1773 ~StateMachineSmartFACT()
1774 {
1775 delete fDimFadControlEventData;
1776 }
1777 int EvalOptions(Configuration &conf)
1778 {
1779 if (!fPixelMap.Read(conf.Get<string>("pixel-map-file")))
1780 {
1781 Error("Reading mapping table from "+conf.Get<string>("pixel-map-file")+" failed.");
1782 return 1;
1783 }
1784
1785 // First move all the dim services to another class so that
1786 // they can be instatiated all at once _after_ path was set
1787 //fPath = conf.Get<string>("path");
1788
1789 // Pixel map is needed to deal with this service
1790 fDimFadControlEventData=new DimStampedInfo("FAD_CONTROL/EVENT_DATA", (void*)NULL, 0, this);
1791
1792 return -1;
1793 }
1794};
1795
1796// ------------------------------------------------------------------------
1797
1798#include "Main.h"
1799
1800template<class T>
1801int RunShell(Configuration &conf)
1802{
1803 return Main::execute<T, StateMachineSmartFACT>(conf);
1804}
1805
1806void SetupConfiguration(Configuration &conf)
1807{
1808 po::options_description control("Smart FACT");
1809 control.add_options()
1810 ("pixel-map-file", var<string>("FACTmapV5a.txt"), "Pixel mapping file. Used here to get the default reference voltage")
1811 ("path", var<string>("www/smartfact/data"), "Output path for the data-files")
1812 ;
1813
1814 conf.AddOptions(control);
1815}
1816
1817/*
1818 Extract usage clause(s) [if any] for SYNOPSIS.
1819 Translators: "Usage" and "or" here are patterns (regular expressions) which
1820 are used to match the usage synopsis in program output. An example from cp
1821 (GNU coreutils) which contains both strings:
1822 Usage: cp [OPTION]... [-T] SOURCE DEST
1823 or: cp [OPTION]... SOURCE... DIRECTORY
1824 or: cp [OPTION]... -t DIRECTORY SOURCE...
1825 */
1826void PrintUsage()
1827{
1828 cout <<
1829 "SmartFACT is a tool writing the files needed for the SmartFACT web interface.\n"
1830 "\n"
1831 "The default is that the program is started without user intercation. "
1832 "All actions are supposed to arrive as DimCommands. Using the -c "
1833 "option, a local shell can be initialized. With h or help a short "
1834 "help message about the usuage can be brought to the screen.\n"
1835 "\n"
1836 "Usage: smartfact [-c type] [OPTIONS]\n"
1837 " or: smartfact [OPTIONS]\n";
1838 cout << endl;
1839}
1840
1841void PrintHelp()
1842{
1843 Main::PrintHelp<StateMachineSmartFACT>();
1844
1845 /* Additional help text which is printed after the configuration
1846 options goes here */
1847
1848 /*
1849 cout << "bla bla bla" << endl << endl;
1850 cout << endl;
1851 cout << "Environment:" << endl;
1852 cout << "environment" << endl;
1853 cout << endl;
1854 cout << "Examples:" << endl;
1855 cout << "test exam" << endl;
1856 cout << endl;
1857 cout << "Files:" << endl;
1858 cout << "files" << endl;
1859 cout << endl;
1860 */
1861}
1862
1863int main(int argc, const char* argv[])
1864{
1865 Configuration conf(argv[0]);
1866 conf.SetPrintUsage(PrintUsage);
1867 Main::SetupConfiguration(conf);
1868 SetupConfiguration(conf);
1869
1870 if (!conf.DoParse(argc, argv, PrintHelp))
1871 return -1;
1872
1873 //try
1874 {
1875 // No console access at all
1876 if (!conf.Has("console"))
1877 {
1878// if (conf.Get<bool>("no-dim"))
1879// return RunShell<LocalStream, StateMachine, ConnectionFSC>(conf);
1880// else
1881 return RunShell<LocalStream>(conf);
1882 }
1883 // Cosole access w/ and w/o Dim
1884/* if (conf.Get<bool>("no-dim"))
1885 {
1886 if (conf.Get<int>("console")==0)
1887 return RunShell<LocalShell, StateMachine, ConnectionFSC>(conf);
1888 else
1889 return RunShell<LocalConsole, StateMachine, ConnectionFSC>(conf);
1890 }
1891 else
1892*/ {
1893 if (conf.Get<int>("console")==0)
1894 return RunShell<LocalShell>(conf);
1895 else
1896 return RunShell<LocalConsole>(conf);
1897 }
1898 }
1899 /*catch (std::exception& e)
1900 {
1901 cerr << "Exception: " << e.what() << endl;
1902 return -1;
1903 }*/
1904
1905 return 0;
1906}
Note: See TracBrowser for help on using the repository browser.