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

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