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

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