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

Last change on this file since 13667 was 13643, checked in by tbretz, 13 years ago
Some little improvements to statistics and display; new scale for the currents
File size: 37.2 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
21namespace ba = boost::asio;
22namespace bs = boost::system;
23namespace dummy = ba::placeholders;
24
25using namespace std;
26
27// ------------------------------------------------------------------------
28
29#include "DimDescriptionService.h"
30
31// ------------------------------------------------------------------------
32
33const static string kHtmlWhite = "#ffffff";
34const static string kHtmlYellow = "#fffff0";
35const static string kHtmlRed = "#fff8f0";
36const static string kHtmlGreen = "#f0fff0";
37const static string kHtmlBlue = "#f0f0ff";
38
39class StateMachineSmartFACT : public StateMachineDim, public DimInfoHandler
40{
41private:
42 enum states_t
43 {
44 kStateDimNetworkNA = 1,
45 kStateRunning,
46 };
47
48 // ------------------------- Internal variables -----------------------
49
50 PixelMap fPixelMap;
51
52 Time fLastUpdate;
53
54 // ----------------------------- Data storage -------------------------
55
56 uint32_t fMcpConfigurationState;
57 int64_t fMcpConfigurationMaxTime;
58 int64_t fMcpConfigurationMaxEvents;
59 string fMcpConfigurationName;
60 Time fMcpConfigurationRunStart;
61
62 enum weather_t { kWeatherBegin=0, kTemp = kWeatherBegin, kDew, kHum, kPress, kWind, kGusts, kDir, kWeatherEnd = kDir };
63 deque<float> fMagicWeatherHist[kWeatherEnd+1];
64
65 vector<float> fFeedbackCalibration;
66 vector<float> fBiasControlVoltageVec;
67
68 float fBiasControlVoltageMed;
69 float fBiasControlCurrentMed;
70 float fBiasControlCurrentMax;
71
72 deque<float> fBiasControlCurrentHist;
73 deque<float> fFscControlTemperatureHist;
74
75 float fFscControlTemperatureAvg;
76 float fFscControlHumidityAvg;
77
78 float fDriveControlPointingZd;
79 string fDriveControlPointingAz;
80 float fDriveControlTrackingDev;
81 string fDriveControlSourceName;
82
83 float fFtmControlTriggerRateCam;
84 deque<float> fFtmControlTriggerRateHist;
85
86 uint64_t fRateScanDataId;
87 deque<float> fRateScanDataHist;
88
89 // ------------- Initialize variables before the Dim stuff ------------
90
91 DimServiceInfoList fNetwork;
92
93 class DimState : public DimInfoHandler
94 {
95 public:
96 DimState(const string &n, const string s="STATE") :
97 server(n), info(make_pair(Time(), -2)),
98 dim((n+"/"+s).c_str(), (void*)NULL, 0, this) { }
99
100 string server;
101 pair<Time, int> info;
102
103 DimStampedInfo dim;
104
105 void infoHandler()
106 {
107 DimInfo *curr = getInfo(); // get current DimInfo address
108 if (!curr || curr != &dim)
109 return;
110
111 const bool disconnected = dim.getSize()==0;
112
113 // Make sure getTimestamp is called _before_ getTimestampMillisecs
114 const int tsec = dim.getTimestamp();
115 const int tms = dim.getTimestampMillisecs();
116
117 info = make_pair(Time(tsec, tms*1000),
118 disconnected ? -2 : dim.getQuality());
119 }
120
121 const Time &time() const { return info.first; }
122 const int &state() const { return info.second; }
123
124 const string &name() const { return server; }
125 };
126
127 class DimVersion : public DimState
128 {
129 public:
130 DimVersion() : DimState("DIS_DNS", "VERSION_NUMBER") { }
131
132 void infoHandler()
133 {
134 DimInfo *curr = getInfo(); // get current DimInfo address
135 if (!curr || curr != &dim)
136 return;
137
138 DimState::infoHandler();
139
140 info.second = dim.getSize()==4 ? dim.getInt() : 0;
141 }
142
143 string version() const
144 {
145 if (info.second==0)
146 return "Offline";
147
148 ostringstream msg;
149 msg << "V" << info.second/100 << 'r' << info.second%100;
150 return msg.str();
151 }
152 };
153
154
155 DimVersion fDim;
156 DimState fDimMcp;
157 DimState fDimDataLogger;
158 DimState fDimDriveControl;
159 DimState fDimMagicWeather;
160 DimState fDimFeedback;
161 DimState fDimBiasControl;
162 DimState fDimFtmControl;
163 DimState fDimFadControl;
164 DimState fDimFscControl;
165 DimState fDimRateControl;
166 DimState fDimRateScan;
167 DimState fDimChatServer;
168
169 DimStampedInfo fDimMcpConfiguration;
170
171 DimStampedInfo fDimDriveControlPointing;
172 DimStampedInfo fDimDriveControlTracking;
173 DimStampedInfo fDimDriveControlSource;
174
175 DimStampedInfo fDimFscControlTemperature;
176 DimStampedInfo fDimFscControlHumidity;
177
178 DimStampedInfo fDimMagicWeatherData;
179
180 DimStampedInfo fDimFeedbackCalibration;
181
182 DimStampedInfo fDimBiasControlVoltage;
183 DimStampedInfo fDimBiasControlCurrent;
184
185 DimStampedInfo fDimFtmControlTriggerRates;
186
187 DimStampedInfo fDimRateScanData;
188
189 DimStampedInfo *fDimFadControlEventData;
190
191 // -------------------------------------------------------------------
192
193 const State GetState(const DimState &s) const
194 {
195 return fNetwork.GetState(s.name(), s.state());
196 }
197
198 bool HandleService(DimInfo *curr, const DimInfo &service, void (StateMachineSmartFACT::*handle)(const DimData &))
199 {
200 if (curr!=&service)
201 return false;
202
203 (this->*handle)(DimData(curr));
204 return true;
205 }
206
207
208 bool CheckDataSize(const DimData &d, const char *name, size_t size, bool min=false)
209 {
210 if ((!min && d.data.size()==size) || (min && d.data.size()>size))
211 return true;
212
213 ostringstream msg;
214 msg << name << " - Received service has " << d.data.size() << " bytes, but expected ";
215 if (min)
216 msg << "more than ";
217 msg << size << ".";
218 Warn(msg);
219 return false;
220 }
221
222
223 // -------------------------------------------------------------------
224
225 template<class T>
226 void WriteBinary(const string &fname, const T &t, double scale, double offset=0)
227 {
228 vector<uint8_t> val(t.size(), 0);
229 for (uint64_t i=0; i<t.size(); i++)
230 {
231 float range = nearbyint(128*(t[i]-offset)/scale); // [-2V; 2V]
232 if (range>127)
233 range=127;
234 if (range<0)
235 range=0;
236 val[i] = (uint8_t)range;
237 }
238
239 const char *ptr = reinterpret_cast<char*>(val.data());
240
241 ofstream fout("www/"+fname+".bin");
242 fout.write(ptr, val.size()*sizeof(uint8_t));
243 }
244
245 // -------------------------------------------------------------------
246
247 struct Statistics
248 {
249 float min;
250 float max;
251 float med;
252 float avg;
253 //float rms;
254
255 template<class T>
256 Statistics(const T &t, size_t offset_min=0, size_t offset_max=0)
257 {
258 T copy(t);
259 sort(copy.begin(), copy.end());
260
261 if (offset_min>t.size())
262 offset_min = 0;
263 if (offset_max>t.size())
264 offset_max = 0;
265
266 min = copy[offset_min];
267 max = copy[copy.size()-1-offset_max];
268 avg = accumulate (t.begin(), t.end(), 0.)/t.size();
269
270 const size_t p = t.size()/2;
271
272 med = copy[p];
273 }
274 };
275
276 void HandleMcpConfiguration(const DimData &d)
277 {
278 if (!CheckDataSize(d, "Mcp:Configuration", 16, true))
279 return;
280
281 fMcpConfigurationState = d.qos;
282 fMcpConfigurationMaxTime = d.get<uint64_t>();
283 fMcpConfigurationMaxEvents = d.get<uint64_t>(8);
284 fMcpConfigurationName = d.ptr<char>(16);
285
286 if (d.qos==12)
287 fMcpConfigurationRunStart = Time();
288 }
289
290 void WriteWeather(const DimData &d, const string &name, int i, float min, float max)
291 {
292 const Statistics stat(fMagicWeatherHist[i]);
293
294 ostringstream out;
295 out << setprecision(3);
296 out << uint64_t(d.time.UnixTime()*1000) << '\n';
297
298 out << "#ffffff\t" << fMagicWeatherHist[i].back() << '\n';
299 out << "#ffffff\t" << stat.min << '\n';
300 out << "#ffffff\t" << stat.avg << '\n';
301 out << "#ffffff\t" << stat.max << '\n';
302
303 ofstream("www/"+name+".txt") << out.str();
304
305 WriteBinary("magicweather-"+name+"-hist", fMagicWeatherHist[i], max-min, min);
306 }
307
308 void HandleMagicWeatherData(const DimData &d)
309 {
310 if (!CheckDataSize(d, "MagicWeather:Data", 7*4+2))
311 return;
312
313 // Store a history of the last 300 entries
314 for (int i=kWeatherBegin; i<=kWeatherEnd; i++)
315 {
316 fMagicWeatherHist[i].push_back(d.ptr<float>(2)[i]);
317 if (fMagicWeatherHist[i].size()>300)
318 fMagicWeatherHist[i].pop_front();
319 }
320
321 static const char *dir[] =
322 {
323 "N", "NNE", "NE", "ENE",
324 "E", "ESE", "SE", "SSE",
325 "S", "SSW", "SW", "WSW",
326 "W", "WNW", "NW", "NNW"
327 };
328
329 const uint16_t idx = uint16_t(floor(fmod(fMagicWeatherHist[kDir].back()+360+11.25, 360)/22.5));
330
331 ostringstream out;
332 out << uint64_t(d.time.UnixTime()*1000) << '\n';
333 for (int i=0; i<6; i++)
334 out << "#ffffff\t" << fMagicWeatherHist[i].back() << '\n';
335 out << "#ffffff\t" << dir[idx] << '\n';
336
337
338 ofstream("www/magicweather.txt") << out.str();
339
340 WriteWeather(d, "temp", kTemp, -5, 35);
341 WriteWeather(d, "dew", kDew, -5, 35);
342 WriteWeather(d, "hum", kHum, 0, 100);
343 WriteWeather(d, "wind", kWind, 0, 100);
344 WriteWeather(d, "gusts", kGusts, 0, 100);
345 WriteWeather(d, "press", kPress, 700, 1000);
346 }
347
348 void HandleDriveControlPointing(const DimData &d)
349 {
350 if (!CheckDataSize(d, "DriveControl:Pointing", 16))
351 return;
352
353 fDriveControlPointingZd = d.get<double>();
354
355 const double az = d.get<double>(8);
356
357 static const char *dir[] =
358 {
359 "N", "NNE", "NE", "ENE",
360 "E", "ESE", "SE", "SSE",
361 "S", "SSW", "SW", "WSW",
362 "W", "WNW", "NW", "NNW"
363 };
364
365 const uint16_t i = uint16_t(floor(fmod(az+360+11.25, 360)/22.5));
366 fDriveControlPointingAz = dir[i];
367
368 ostringstream out;
369 out << uint64_t(d.time.UnixTime()*1000) << '\n';
370
371 out << setprecision(5);
372 out << fDriveControlPointingZd << '\n';
373 out << az << '\n';
374
375 ofstream fout("www/drive-pointing.txt");
376 fout << out.str();
377 }
378
379 void HandleDriveControlTracking(const DimData &d)
380 {
381 if (!CheckDataSize(d, "DriveControl:Tracking", 56))
382 return;
383
384 const double zd = d.get<double>(4*8) * M_PI / 180;
385 const double dzd = d.get<double>(6*8) * M_PI / 180;
386 const double daz = d.get<double>(7*8) * M_PI / 180;
387
388 // Correct:
389 // const double d = cos(del) - sin(zd+dzd)*sin(zd)*(1.-cos(daz));
390
391 // Simplified:
392 const double dev = cos(dzd) - sin(zd+dzd)*sin(zd)*(1.-cos(daz));
393 fDriveControlTrackingDev = acos(dev) * 180 / M_PI * 3600;
394 if (fDriveControlTrackingDev<0.01)
395 fDriveControlTrackingDev=0;
396 }
397
398 void HandleDriveControlSource(const DimData &d)
399 {
400 if (!CheckDataSize(d, "DriveControl:Source", 7*4+2, true))
401 return;
402
403 const double *ptr = d.ptr<double>();
404
405 const double ra = ptr[0]; // Ra[h]
406 const double dec = ptr[1]; // Dec[deg]
407 const double woff = ptr[4]; // Wobble offset [deg]
408 const double wang = ptr[5]; // Wobble angle [deg]
409
410 fDriveControlSourceName = d.ptr<char>(6*8);
411
412 ostringstream out;
413 out << uint64_t(d.time.UnixTime()*1000) << '\n';
414
415 out << "#ffffff\t" << fDriveControlSourceName << '\n';
416 out << setprecision(5);
417 out << "#ffffff\t" << ra << '\n';
418 out << "#ffffff\t" << dec << '\n';
419 out << setprecision(3);
420 out << "#ffffff\t" << woff << '\n';
421 out << "#ffffff\t" << wang << '\n';
422
423 ofstream fout("www/drive.txt");
424 fout << out.str();
425 }
426
427 void HandleFeedbackCalibration(const DimData &d)
428 {
429 if (!CheckDataSize(d, "Feedback:Calibration", 3*4*416))
430 {
431 fFeedbackCalibration.clear();
432 return;
433 }
434
435 const float *ptr = d.ptr<float>();
436 fFeedbackCalibration.assign(ptr+2*416, ptr+3*416);
437 }
438
439 void HandleBiasControlVoltage(const DimData &d)
440 {
441 if (!CheckDataSize(d, "BiasControl:Voltage", 1664))
442 {
443 fBiasControlVoltageVec.clear();
444 return;
445 }
446
447 fBiasControlVoltageVec.assign(d.ptr<float>(), d.ptr<float>()+320);
448
449 const Statistics stat(fBiasControlVoltageVec);
450
451 fBiasControlVoltageMed = stat.med;
452
453 vector<float> val(320, 0);
454 for (int i=0; i<320; i++)
455 {
456 const int idx = (fPixelMap.hv(i).hw()/9)*2+fPixelMap.hv(i).group();
457 val[idx] = fBiasControlVoltageVec[i];
458 }
459
460 WriteBinary("biascontrol-voltage", val, 75);
461
462 ostringstream out;
463 out << setprecision(3);
464 out << uint64_t(d.time.UnixTime()*1000) << '\n';
465 out << kHtmlWhite << '\t' << stat.min << '\n';
466 out << kHtmlWhite << '\t' << stat.med << '\n';
467 out << kHtmlWhite << '\t' << stat.avg << '\n';
468 out << kHtmlWhite << '\t' << stat.max << '\n';
469 ofstream("www/voltage.txt") << out.str();
470
471 }
472
473 void HandleBiasControlCurrent(const DimData &d)
474 {
475 if (!CheckDataSize(d, "BiasControl:Current", 832))
476 return;
477
478 // Convert dac counts to uA
479 vector<float> v(320);
480 for (int i=0; i<320; i++)
481 v[i] = d.ptr<uint16_t>()[i] * 5000./4096;
482
483 // Calibrate the data (subtract offset)
484 if (fFeedbackCalibration.size()>0 && fBiasControlVoltageVec.size()>0)
485 for (int i=0; i<320; i++)
486 v[i] -= fBiasControlVoltageVec[i]/fFeedbackCalibration[i]*1e6;
487
488 // Get the maximum of each patch
489 vector<float> val(320, 0);
490 for (int i=0; i<320; i++)
491 {
492 const int idx = (fPixelMap.hv(i).hw()/9)*2+fPixelMap.hv(i).group();
493 val[idx] = v[i];
494 }
495
496 // Write the 160 patch values to a file
497 WriteBinary("biascontrol-current", val, 500);
498
499 const Statistics stat(v, 0, 3);
500
501 // Exclude the three crazy channels
502 fBiasControlCurrentMed = stat.med;
503 fBiasControlCurrentMax = stat.max;
504
505 // Store a history of the last 60 entries
506 fBiasControlCurrentHist.push_back(fBiasControlCurrentMed);
507 if (fBiasControlCurrentHist.size()>60)
508 fBiasControlCurrentHist.pop_front();
509
510 // write the history to a file
511 WriteBinary("biascontrol-current-hist", fBiasControlCurrentHist, 500);
512
513 ostringstream out;
514 out << setprecision(3);
515 out << uint64_t(d.time.UnixTime()*1000) << '\n';
516 out << kHtmlWhite << '\t' << stat.min << '\n';
517 out << kHtmlWhite << '\t' << stat.med << '\n';
518 out << kHtmlWhite << '\t' << stat.avg << '\n';
519 out << kHtmlWhite << '\t' << stat.max << '\n';
520 ofstream("www/current.txt") << out.str();
521 }
522
523 void HandleFtmControlTriggerRates(const DimData &d)
524 {
525 if (!CheckDataSize(d, "FtmControl:TriggerRates", 24+160+640+8))
526 return;
527
528 fFtmControlTriggerRateCam = d.get<float>(20);
529
530 const float *brates = d.ptr<float>(24); // Board rate
531 const float *prates = d.ptr<float>(24+160); // Patch rate
532
533 // Store a history of the last 60 entries
534 fFtmControlTriggerRateHist.push_back(fFtmControlTriggerRateCam);
535 if (fFtmControlTriggerRateHist.size()>60)
536 fFtmControlTriggerRateHist.pop_front();
537
538 // FIXME: Add statistics for all kind of rates
539
540 WriteBinary("ftmcontrol-triggerrate-hist",
541 fFtmControlTriggerRateHist, 100);
542 WriteBinary("ftmcontrol-boardrates",
543 vector<float>(brates, brates+40), 10);
544 WriteBinary("ftmcontrol-patchrates",
545 vector<float>(prates, prates+160), 10);
546
547 ostringstream out;
548 out << setprecision(3);
549 out << uint64_t(d.time.UnixTime()*1000) << '\n';
550 out << "#ffffff\t" << fFtmControlTriggerRateCam << '\n';
551
552 ofstream("www/trigger.txt") << out.str();
553
554 const Statistics bstat(vector<float>(brates, brates+40));
555 const Statistics pstat(vector<float>(prates, prates+160));
556
557 out.str("");
558 out << uint64_t(d.time.UnixTime()*1000) << '\n';
559 out << kHtmlWhite << '\t' << bstat.min << '\n';
560 out << kHtmlWhite << '\t' << bstat.med << '\n';
561 out << kHtmlWhite << '\t' << bstat.avg << '\n';
562 out << kHtmlWhite << '\t' << bstat.max << '\n';
563 ofstream("www/boardrates.txt") << out.str();
564
565 out.str("");
566 out << uint64_t(d.time.UnixTime()*1000) << '\n';
567 out << kHtmlWhite << '\t' << pstat.min << '\n';
568 out << kHtmlWhite << '\t' << pstat.med << '\n';
569 out << kHtmlWhite << '\t' << pstat.avg << '\n';
570 out << kHtmlWhite << '\t' << pstat.max << '\n';
571 ofstream("www/patchrates.txt") << out.str();
572
573
574 }
575
576 void HandleFadControlEventData(const DimData &d)
577 {
578 if (!CheckDataSize(d, "FadControl:EventData", 23040))
579 return;
580
581 //const float *avg = d.ptr<float>();
582 //const float *rms = d.ptr<float>(1440*sizeof(float));
583 const float *dat = d.ptr<float>(1440*sizeof(float)*2);
584 //const float *pos = d.ptr<float>(1440*sizeof(float)*3);
585
586 vector<float> max(320, -2000);
587 for (int i=0; i<1440; i++)
588 {
589 if (i%9==8)
590 continue;
591
592 const int idx = (fPixelMap.hw(i).hw()/9)*2+fPixelMap.hw(i).group();
593 if (dat[i]>max[idx])
594 max[idx]=dat[i];
595 }
596
597 switch (d.qos)
598 {
599 case 0: WriteBinary("fadcontrol-eventdata", max, 2000, -1000); break;
600 case 1: WriteBinary("fadcontrol-eventdata", max, 2000, 0); break;
601 default: WriteBinary("fadcontrol-eventdata", max, 250, 0); break;
602 }
603 }
604
605 void HandleFscControlTemperature(const DimData &d)
606 {
607 if (!CheckDataSize(d, "FscControl:Temperature", 240))
608 return;
609
610 const float *ptr = d.ptr<float>(4);
611
612 double avg = 0;
613 double rms = 0;
614 double min = 99;
615 double max = -99;
616
617 int num = 0;
618 for (const float *t=ptr; t<ptr+31; t++)
619 {
620 if (*t==0)
621 continue;
622
623 if (*t>max)
624 max = *t;
625
626 if (*t<min)
627 min = *t;
628
629 avg += *t;
630 rms += *t * *t;
631
632 num++;
633 }
634
635 avg /= num;
636 rms = sqrt(rms/num-avg*avg);
637
638 fFscControlTemperatureAvg = avg;
639
640 fFscControlTemperatureHist.push_back(avg);
641 if (fFscControlTemperatureHist.size()>300)
642 fFscControlTemperatureHist.pop_front();
643
644 const Statistics stat(fFscControlTemperatureHist);
645
646 ostringstream out;
647 out << setprecision(3);
648 out << uint64_t(d.time.UnixTime()*1000) << '\n';
649 out << "#ffffff\t" << min << '\n';
650 out << "#ffffff\t" << avg << '\n';
651 out << "#ffffff\t" << max << '\n';
652 out << "#ffffff\t" << stat.min << '\n';
653 out << "#ffffff\t" << stat.avg << '\n';
654 out << "#ffffff\t" << stat.max << '\n';
655
656 ofstream("www/fsc.txt") << out.str();
657
658 WriteBinary("fsccontrol-temperature-hist",
659 fFscControlTemperatureHist, 30);
660 }
661
662 void HandleFscControlHumidity(const DimData &d)
663 {
664 if (!CheckDataSize(d, "FscControl:Humidity", 5*4))
665 return;
666
667 const float *ptr = d.ptr<float>(4);
668
669 double avg = 0;
670 int num = 0;
671
672 for (const float *t=ptr; t<ptr+4; t++)
673 if (*t>0)
674 {
675 avg += *t;
676 num++;
677 }
678
679 fFscControlHumidityAvg = avg/num;
680 }
681
682 void HandleRateScanData(const DimData &d)
683 {
684 if (!CheckDataSize(d, "RateScan:Data", 24+200*40))
685 return;
686
687 const uint64_t id = d.get<uint64_t>();
688 const float rate = log10(d.get<float>(20));
689
690 if (fRateScanDataId!=id)
691 {
692 fRateScanDataHist.clear();
693 fRateScanDataId = id;
694 }
695 fRateScanDataHist.push_back(rate);
696
697 WriteBinary("ratescan-hist", fRateScanDataHist, 10, -1);
698 }
699
700 // -------------------------------------------------------------------
701
702 void infoHandler()
703 {
704 DimInfo *curr = getInfo(); // get current DimInfo address
705 if (!curr)
706 return;
707
708 if (HandleService(curr, fDimMcpConfiguration, &StateMachineSmartFACT::HandleMcpConfiguration))
709 return;
710 if (HandleService(curr, fDimMagicWeatherData, &StateMachineSmartFACT::HandleMagicWeatherData))
711 return;
712 if (HandleService(curr, fDimDriveControlPointing, &StateMachineSmartFACT::HandleDriveControlPointing))
713 return;
714 if (HandleService(curr, fDimDriveControlTracking, &StateMachineSmartFACT::HandleDriveControlTracking))
715 return;
716 if (HandleService(curr, fDimDriveControlSource, &StateMachineSmartFACT::HandleDriveControlSource))
717 return;
718 if (HandleService(curr, fDimFeedbackCalibration, &StateMachineSmartFACT::HandleFeedbackCalibration))
719 return;
720 if (HandleService(curr, fDimBiasControlVoltage, &StateMachineSmartFACT::HandleBiasControlVoltage))
721 return;
722 if (HandleService(curr, fDimBiasControlCurrent, &StateMachineSmartFACT::HandleBiasControlCurrent))
723 return;
724 if (HandleService(curr, fDimFtmControlTriggerRates, &StateMachineSmartFACT::HandleFtmControlTriggerRates))
725 return;
726 if (HandleService(curr, *fDimFadControlEventData, &StateMachineSmartFACT::HandleFadControlEventData))
727 return;
728 if (HandleService(curr, fDimFscControlTemperature, &StateMachineSmartFACT::HandleFscControlTemperature))
729 return;
730 if (HandleService(curr, fDimFscControlHumidity, &StateMachineSmartFACT::HandleFscControlHumidity))
731 return;
732 if (HandleService(curr, fDimRateScanData, &StateMachineSmartFACT::HandleRateScanData))
733 return;
734 }
735
736 bool CheckEventSize(size_t has, const char *name, size_t size)
737 {
738 if (has==size)
739 return true;
740
741 ostringstream msg;
742 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
743 Fatal(msg);
744 return false;
745 }
746
747 void PrintState(const DimState &state) const
748 {
749 const State rc = GetState(state);
750
751 Out() << state.time().GetAsStr("%H:%M:%S.%f").substr(0, 12) << " - ";
752 Out() << kBold << state.name() << ": ";
753 if (rc.index==-2)
754 {
755 Out() << kReset << "Offline" << endl;
756 return;
757 }
758 Out() << rc.name << "[" << rc.index << "]";
759 Out() << kReset << " - " << kBlue << rc.comment << endl;
760 }
761
762 int Print() const
763 {
764 Out() << fDim.time().GetAsStr("%H:%M:%S.%f").substr(0, 12) << " - ";
765 Out() << kBold << "DIM_DNS: " << fDim.version() << endl;
766
767 PrintState(fDimMcp);
768 PrintState(fDimDataLogger);
769 PrintState(fDimDriveControl);
770 PrintState(fDimFadControl);
771 PrintState(fDimFtmControl);
772 PrintState(fDimBiasControl);
773 PrintState(fDimFeedback);
774 PrintState(fDimRateControl);
775 PrintState(fDimFscControl);
776 PrintState(fDimMagicWeather);
777 PrintState(fDimRateScan);
778 PrintState(fDimChatServer);
779
780 return GetCurrentState();
781 }
782
783 string GetStateHtml(const DimState &state, int green) const
784 {
785 const State rc = GetState(state);
786
787 //ostringstream msg;
788 //msg << kHtmlWhite << '\t' << rc.name << " [" << rc.index << "]\n";
789 //return msg.str();
790
791 if (rc.index<1)
792 return kHtmlWhite + "\t---\n";
793
794
795 return (rc.index<green?kHtmlYellow:kHtmlGreen) + '\t' + rc.name + '\n';
796 }
797
798 int Execute()
799 {
800 // Dispatch (execute) at most one handler from the queue. In contrary
801 // to run_one(), it doesn't wait until a handler is available
802 // which can be dispatched, so poll_one() might return with 0
803 // handlers dispatched. The handlers are always dispatched/executed
804 // synchronously, i.e. within the call to poll_one()
805 //poll_one();
806
807 if (fDim.state()==0)
808 return kStateDimNetworkNA;
809
810 Time now;
811 if (now-fLastUpdate<boost::posix_time::seconds(1))
812 return kStateRunning;
813
814 fLastUpdate=now;
815
816 ostringstream out;
817 out << uint64_t(nearbyint(now.UnixTime()*1000)) << '\n';
818 out << setprecision(3);
819
820 // -------------- System status --------------
821 if (fDimMcp.state()>=5) // Idle
822 {
823 string col = kHtmlBlue;
824 if (fMcpConfigurationState!= 5 &&
825 fMcpConfigurationState!=11 &&
826 fMcpConfigurationState!=12) // 9 e.g. Configuring3
827 col = kHtmlYellow;
828 else
829 if (fDimFadControl.state()==FAD::kWritingData)
830 col = kHtmlGreen;
831
832 out << col << '\t' << fMcpConfigurationName;
833
834 if (fMcpConfigurationMaxEvents>0 || fMcpConfigurationMaxTime>0 || fMcpConfigurationState==12)
835 out << " [";
836 if (fMcpConfigurationMaxEvents>0)
837 out << fMcpConfigurationMaxEvents;
838 if (fMcpConfigurationMaxEvents>0 && (fMcpConfigurationMaxTime>0 || fMcpConfigurationState==12))
839 out << '/';
840 if (fMcpConfigurationMaxTime>0)
841 {
842 if (fMcpConfigurationState==12)
843 out << fMcpConfigurationMaxTime-(Time()-fMcpConfigurationRunStart).total_seconds() << 's';
844 else
845 out << "[" << fMcpConfigurationMaxTime << "s]";
846 }
847 else
848 {
849 if (fMcpConfigurationState==12)
850 {
851 ostringstream d;
852 d << Time()-fMcpConfigurationRunStart;
853 out << d.str().substr(3, 5);
854 }
855 }
856
857 if (fMcpConfigurationMaxEvents>0 || fMcpConfigurationMaxTime>0 || fMcpConfigurationState==12)
858 out << ']';
859 }
860 else
861 out << kHtmlWhite;
862 out << '\n';
863
864 // ------------------ Drive -----------------
865 if (fDimDriveControl.state()>=5) // Armed, Moving, Tracking
866 {
867 const State rc = GetState(fDimDriveControl);
868 string col = kHtmlGreen;
869 if (rc.index==6) // Moving
870 col = kHtmlBlue;
871 if (rc.index==5) // Armed
872 col = kHtmlWhite;
873 out << col << '\t';
874 out << rc.name << '\t';
875 out << fDriveControlPointingZd << '\t';
876 out << fDriveControlPointingAz << '\t';
877 if (fDimDriveControl.state()==7)
878 {
879 out << setprecision(2);
880 out << fDriveControlTrackingDev << '\t';
881 out << setprecision(3);
882 out << fDriveControlSourceName << '\n';
883 }
884 else
885 out << "\t\n";
886 }
887 else
888 out << kHtmlWhite << '\n';
889
890 // ------------------- FSC ------------------
891 if (fDimFscControl.state()>1)
892 {
893 out << kHtmlGreen << '\t' << fFscControlTemperatureAvg << '\n';
894 }
895 else
896 out << kHtmlWhite << '\n';
897
898 // --------------- MagicWeather -------------
899 if (fDimMagicWeather.state()==3)
900 {
901 /*
902 const float diff = fMagicWeatherHist[kTemp].back()-fMagicWeatherHist[kDew].back();
903 string col1 = kHtmlRed;
904 if (diff>0.3)
905 col1 = kHtmlYellow;
906 if (diff>0.7)
907 col1 = kHtmlGreen;
908 */
909
910 const float wind = fMagicWeatherHist[kGusts].back();
911 const float hum = fMagicWeatherHist[kHum].back();
912 string col = kHtmlGreen;
913 if (wind>35 || hum>95)
914 col = kHtmlYellow;
915 if (wind>50 || hum>98)
916 col = kHtmlRed;
917
918 out << col << '\t';
919 out << fMagicWeatherHist[kHum].back() << '\t';
920 out << fMagicWeatherHist[kGusts].back() << '\n';
921 }
922 else
923 out << kHtmlWhite << "\n";
924
925 // --------------- FtmControl -------------
926 if (fDimFtmControl.state()>=FTM::kIdle)
927 {
928 string col = kHtmlGreen;
929 if (fFtmControlTriggerRateCam<15)
930 col = kHtmlYellow;
931 if (fFtmControlTriggerRateCam>100)
932 col = kHtmlRed;
933
934 out << col << '\t' << fFtmControlTriggerRateCam << '\n';
935 }
936 else
937 out << kHtmlWhite << '\n';
938
939 // --------------- BiasControl -------------
940 if (fDimBiasControl.state()==5 || // Ramping
941 fDimBiasControl.state()==7 || // On
942 fDimBiasControl.state()==9) // Off
943 {
944 string col = fBiasControlVoltageMed>3?kHtmlGreen:kHtmlWhite;
945 if (fBiasControlCurrentMax>280)
946 col = kHtmlYellow;
947 if (fBiasControlCurrentMax>350)
948 col = kHtmlRed;
949
950 if (fFeedbackCalibration.size()==0)
951 col = kHtmlBlue;
952
953 if (fDimFeedback.state()==13)
954 {
955 out << kHtmlBlue << '\t';
956 out << "***\t";
957 out << "***\t";
958 out << "---\n";
959 }
960 else
961 {
962 out << col << '\t';
963 out << fBiasControlCurrentMed << '\t';
964 out << fBiasControlCurrentMax << '\t';
965 out << fBiasControlVoltageMed << '\n';
966 }
967 }
968 else
969 out << kHtmlWhite << '\n';
970
971
972 // ------------------------------------------
973
974 ofstream("www/fact.txt") << out.str();
975
976 // ==========================================
977
978 out.str("");
979 out << uint64_t(nearbyint(now.UnixTime()*1000)) << '\n';
980
981 if (fDim.state()==0)
982 out << kHtmlWhite << "\tOffline\n\n\n\n\n\n\n\n\n\n\n\n";
983 else
984 {
985 out << kHtmlGreen << '\t' << fDim.version() << '\n';
986
987 out << GetStateHtml(fDimMcp, 4);
988 out << GetStateHtml(fDimDataLogger, 1);
989 out << GetStateHtml(fDimDriveControl, 2);
990 out << GetStateHtml(fDimFadControl, FAD::kConnected);
991 out << GetStateHtml(fDimFtmControl, FTM::kConnected);
992 out << GetStateHtml(fDimBiasControl, BIAS::kConnected);
993 out << GetStateHtml(fDimFeedback, 4);
994 out << GetStateHtml(fDimRateControl, 4);
995 out << GetStateHtml(fDimFscControl, 2);
996 out << GetStateHtml(fDimMagicWeather, 2);
997 out << GetStateHtml(fDimRateScan, 4);
998 out << GetStateHtml(fDimChatServer, 1);
999 }
1000
1001 ofstream("www/status.txt") << out.str();
1002
1003 return kStateRunning;
1004 }
1005
1006public:
1007 StateMachineSmartFACT(ostream &out=cout) : StateMachineDim(out, "SMART_FACT"),
1008 fMcpConfigurationMaxTime(0),
1009 fMcpConfigurationMaxEvents(0),
1010 fRateScanDataId(0),
1011 //---
1012 fDimMcp ("MCP"),
1013 fDimDataLogger ("DATA_LOGGER"),
1014 fDimDriveControl ("DRIVE_CONTROL"),
1015 fDimMagicWeather ("MAGIC_WEATHER"),
1016 fDimFeedback ("FEEDBACK"),
1017 fDimBiasControl ("BIAS_CONTROL"),
1018 fDimFtmControl ("FTM_CONTROL"),
1019 fDimFadControl ("FAD_CONTROL"),
1020 fDimFscControl ("FSC_CONTROL"),
1021 fDimRateControl ("RATE_CONTROL"),
1022 fDimRateScan ("RATE_SCAN"),
1023 fDimChatServer ("CHAT_SERVER"),
1024 //---
1025 fDimMcpConfiguration ("MCP/CONFIGURATION", (void*)NULL, 0, this),
1026 //---
1027 fDimDriveControlPointing ("DRIVE_CONTROL/POINTING_POSITION", (void*)NULL, 0, this),
1028 fDimDriveControlTracking ("DRIVE_CONTROL/TRACKING_POSITION", (void*)NULL, 0, this),
1029 fDimDriveControlSource ("DRIVE_CONTROL/SOURCE_POSITION", (void*)NULL, 0, this),
1030 //---
1031 fDimFscControlTemperature ("FSC_CONTROL/TEMPERATURE", (void*)NULL, 0, this),
1032 fDimFscControlHumidity ("FSC_CONTROL/HUMIDITY", (void*)NULL, 0, this),
1033 //---
1034 fDimMagicWeatherData ("MAGIC_WEATHER/DATA", (void*)NULL, 0, this),
1035 //---
1036 fDimFeedbackCalibration ("FEEDBACK/CALIBRATION", (void*)NULL, 0, this),
1037 //---
1038 fDimBiasControlVoltage ("BIAS_CONTROL/VOLTAGE", (void*)NULL, 0, this),
1039 fDimBiasControlCurrent ("BIAS_CONTROL/CURRENT", (void*)NULL, 0, this),
1040 //---
1041 fDimFtmControlTriggerRates("FTM_CONTROL/TRIGGER_RATES", (void*)NULL, 0, this),
1042 //-
1043 fDimRateScanData ("RATE_SCAN/DATA", (void*)NULL, 0, this),
1044 //-
1045 fDimFadControlEventData(0)
1046 {
1047 // State names
1048 AddStateName(kStateDimNetworkNA, "DimNetworkNotAvailable",
1049 "The Dim DNS is not reachable.");
1050
1051 AddStateName(kStateRunning, "Running", "");
1052
1053 // Verbosity commands
1054// AddEvent("SET_VERBOSE", "B:1")
1055// (bind(&StateMachineMCP::SetVerbosity, this, placeholders::_1))
1056// ("set verbosity state"
1057// "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
1058
1059 AddEvent("PRINT")
1060 (bind(&StateMachineSmartFACT::Print, this))
1061 ("");
1062 }
1063 ~StateMachineSmartFACT()
1064 {
1065 delete fDimFadControlEventData;
1066 }
1067 int EvalOptions(Configuration &conf)
1068 {
1069 if (!fPixelMap.Read(conf.Get<string>("pixel-map-file")))
1070 {
1071 Error("Reading mapping table from "+conf.Get<string>("pixel-map-file")+" failed.");
1072 return 1;
1073 }
1074
1075 // Pixel map is needed to deal with this service
1076 fDimFadControlEventData=new DimStampedInfo("FAD_CONTROL/EVENT_DATA", (void*)NULL, 0, this);
1077
1078 return -1;
1079 }
1080};
1081
1082// ------------------------------------------------------------------------
1083
1084#include "Main.h"
1085
1086template<class T>
1087int RunShell(Configuration &conf)
1088{
1089 return Main::execute<T, StateMachineSmartFACT>(conf);
1090}
1091
1092void SetupConfiguration(Configuration &conf)
1093{
1094 po::options_description control("Smart FACT");
1095 control.add_options()
1096 ("pixel-map-file", var<string>("FACTmapV5a.txt"), "Pixel mapping file. Used here to get the default reference voltage.")
1097 ;
1098
1099 conf.AddOptions(control);
1100}
1101
1102/*
1103 Extract usage clause(s) [if any] for SYNOPSIS.
1104 Translators: "Usage" and "or" here are patterns (regular expressions) which
1105 are used to match the usage synopsis in program output. An example from cp
1106 (GNU coreutils) which contains both strings:
1107 Usage: cp [OPTION]... [-T] SOURCE DEST
1108 or: cp [OPTION]... SOURCE... DIRECTORY
1109 or: cp [OPTION]... -t DIRECTORY SOURCE...
1110 */
1111void PrintUsage()
1112{
1113 cout <<
1114 "SmartFACT is a tool writing the files needed for the SmartFACT web interface.\n"
1115 "\n"
1116 "The default is that the program is started without user intercation. "
1117 "All actions are supposed to arrive as DimCommands. Using the -c "
1118 "option, a local shell can be initialized. With h or help a short "
1119 "help message about the usuage can be brought to the screen.\n"
1120 "\n"
1121 "Usage: smartfact [-c type] [OPTIONS]\n"
1122 " or: smartfact [OPTIONS]\n";
1123 cout << endl;
1124}
1125
1126void PrintHelp()
1127{
1128 Main::PrintHelp<StateMachineSmartFACT>();
1129
1130 /* Additional help text which is printed after the configuration
1131 options goes here */
1132
1133 /*
1134 cout << "bla bla bla" << endl << endl;
1135 cout << endl;
1136 cout << "Environment:" << endl;
1137 cout << "environment" << endl;
1138 cout << endl;
1139 cout << "Examples:" << endl;
1140 cout << "test exam" << endl;
1141 cout << endl;
1142 cout << "Files:" << endl;
1143 cout << "files" << endl;
1144 cout << endl;
1145 */
1146}
1147
1148int main(int argc, const char* argv[])
1149{
1150 Configuration conf(argv[0]);
1151 conf.SetPrintUsage(PrintUsage);
1152 Main::SetupConfiguration(conf);
1153 SetupConfiguration(conf);
1154
1155 if (!conf.DoParse(argc, argv, PrintHelp))
1156 return -1;
1157
1158 //try
1159 {
1160 // No console access at all
1161 if (!conf.Has("console"))
1162 {
1163// if (conf.Get<bool>("no-dim"))
1164// return RunShell<LocalStream, StateMachine, ConnectionFSC>(conf);
1165// else
1166 return RunShell<LocalStream>(conf);
1167 }
1168 // Cosole access w/ and w/o Dim
1169/* if (conf.Get<bool>("no-dim"))
1170 {
1171 if (conf.Get<int>("console")==0)
1172 return RunShell<LocalShell, StateMachine, ConnectionFSC>(conf);
1173 else
1174 return RunShell<LocalConsole, StateMachine, ConnectionFSC>(conf);
1175 }
1176 else
1177*/ {
1178 if (conf.Get<int>("console")==0)
1179 return RunShell<LocalShell>(conf);
1180 else
1181 return RunShell<LocalConsole>(conf);
1182 }
1183 }
1184 /*catch (std::exception& e)
1185 {
1186 cerr << "Exception: " << e.what() << endl;
1187 return -1;
1188 }*/
1189
1190 return 0;
1191}
Note: See TracBrowser for help on using the repository browser.