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

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