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

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