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

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