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

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