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

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