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

Last change on this file since 13479 was 13479, checked in by tbretz, 12 years ago
Adapted to the latest html/js changes.
File size: 19.3 KB
Line 
1#include <valarray>
2
3#include "Dim.h"
4#include "Event.h"
5#include "Shell.h"
6#include "StateMachineDim.h"
7#include "Connection.h"
8#include "Configuration.h"
9#include "Console.h"
10#include "Converter.h"
11#include "DimServiceInfoList.h"
12#include "PixelMap.h"
13
14#include "tools.h"
15#include "DimData.h"
16
17#include "LocalControl.h"
18
19#include "HeadersFAD.h"
20#include "HeadersBIAS.h"
21
22namespace ba = boost::asio;
23namespace bs = boost::system;
24namespace dummy = ba::placeholders;
25
26using namespace std;
27
28// ------------------------------------------------------------------------
29
30#include "DimDescriptionService.h"
31
32// ------------------------------------------------------------------------
33
34class StateMachineSmartFACT : public StateMachineDim, public DimInfoHandler
35{
36private:
37 enum states_t
38 {
39 kStateDimNetworkNA = 1,
40 kStateRunning,
41 };
42
43 PixelMap fPixelMap;
44
45 DimServiceInfoList fNetwork;
46
47 pair<Time, int> fStatusDim;
48 pair<Time, int> fStatusDriveControl;
49 pair<Time, int> fStatusMagicWeather;
50 pair<Time, int> fStatusBiasControl;
51 pair<Time, int> fStatusFadControl;
52
53 DimStampedInfo fDim;
54
55 DimStampedInfo fDimDriveControl;
56 DimStampedInfo fDimDriveControlPointing;
57 DimStampedInfo fDimDriveControlTracking;
58 DimStampedInfo fDimDriveControlSource;
59
60 DimStampedInfo fDimMagicWeather;
61 DimStampedInfo fDimMagicWeatherData;
62
63 DimStampedInfo fDimBiasControl;
64 DimStampedInfo fDimBiasControlVoltage;
65 DimStampedInfo fDimBiasControlCurrent;
66
67 DimStampedInfo fDimFadControl;
68 DimStampedInfo *fDimFadControlEventData;
69
70 Time fLastUpdate;
71
72 enum weather_t { kTemp = 0, kDew, kHum, kPress, kWind, kGusts, kDir };
73 float fMagicWeatherData[7];
74
75 float fBiasControlVoltageMed;
76 float fBiasControlCurrentMed;
77 float fBiasControlCurrentMax;
78
79 float fDriveControlPointingZd;
80 string fDriveControlPointingAz;
81 float fDriveControlTrackingDev;
82 string fDriveControlSourceName;
83
84 // -------------------------------------------------------------------
85
86 pair<Time, int> GetNewState(DimStampedInfo &info) const
87 {
88 const bool disconnected = info.getSize()==0;
89
90 // Make sure getTimestamp is called _before_ getTimestampMillisecs
91 const int tsec = info.getTimestamp();
92 const int tms = info.getTimestampMillisecs();
93
94 return make_pair(Time(tsec, tms*1000),
95 disconnected ? -2 : info.getQuality());
96 }
97
98 bool UpdateState(DimInfo *curr, DimStampedInfo &service, pair<Time,int> &rc)
99 {
100 if (curr!=&service)
101 return false;
102
103 rc = GetNewState(service);
104 return true;
105 }
106
107 bool HandleService(DimInfo *curr, const DimInfo &service, void (StateMachineSmartFACT::*handle)(const DimData &))
108 {
109 if (curr!=&service)
110 return false;
111
112 (this->*handle)(DimData(curr));
113 return true;
114 }
115
116
117 bool CheckDataSize(const DimData &d, const char *name, size_t size)
118 {
119 if (d.data.size()==size)
120 return true;
121
122 ostringstream msg;
123 msg << name << " - Received service has " << d.data.size() << " bytes, but expected " << size << ".";
124 Warn(msg);
125 return false;
126 }
127
128
129 // -------------------------------------------------------------------
130
131 void HandleMagicWeatherData(const DimData &d)
132 {
133 if (!CheckDataSize(d, "MagicWeather:Data", 7*4+2))
134 return;
135
136 // FIXME: Check size (7*4+2)
137
138 //const uint16_t status = d.get<uint16_t>();
139 memcpy(fMagicWeatherData, d.ptr<float>(2), 7*sizeof(float));
140
141 ostringstream out;
142 out << uint64_t(d.time.UnixTime()*1000) << '\n';
143
144 for (int i=0; i<7; i++)
145 out << "#ffffff\t" << fMagicWeatherData[i] << '\n';
146
147 ofstream fout("www/magicweather.txt");
148 fout << out.str();
149 }
150
151 void HandleDrivePointing(const DimData &d)
152 {
153 if (!CheckDataSize(d, "DriveControl:Pointing", 7*4+2))
154 return;
155
156 fDriveControlPointingZd = d.get<double>();
157
158 const double az = d.get<double>(8);
159
160 static const char *dir[] =
161 {
162 "N", "NNE", "NE", "ENE",
163 "E", "ESE", "SE", "SSE",
164 "S", "SSW", "SW", "WSW",
165 "W", "WNW", "NW", "NNW"
166 };
167
168 const uint16_t i = uint16_t(floor(fmod(az+11.25, 360)/22));
169 fDriveControlPointingAz = dir[i];
170
171 ostringstream out;
172 out << uint64_t(d.time.UnixTime()*1000) << '\n';
173
174 out << setprecision(5);
175 out << fDriveControlPointingZd << '\n';
176 out << az << '\n';
177
178 ofstream fout("www/drive-pointing.txt");
179 fout << out.str();
180 }
181
182 void HandleDriveTracking(const DimData &d)
183 {
184 if (!CheckDataSize(d, "DriveControl:Tracking", 7*4+2))
185 return;
186
187 const double zd = d.get<double>(4*8) * M_PI / 180;
188 const double dzd = d.get<double>(6*8) * M_PI / 180;
189 const double daz = d.get<double>(7*8) * M_PI / 180;
190
191 // Correct:
192 // const double d = cos(del) - sin(zd+dzd)*sin(zd)*(1.-cos(daz));
193
194 // Simplified:
195 const double dev = cos(dzd) - sin(zd)*sin(zd)*(1.-cos(daz));
196 fDriveControlTrackingDev = acos(dev) * 180 / M_PI;
197 }
198
199 void HandleDriveSource(const DimData &d)
200 {
201 if (!CheckDataSize(d, "DriveControl:Source", 7*4+2))
202 return;
203
204 const double *ptr = d.ptr<double>();
205
206 const double ra = ptr[0]; // Ra[h]
207 const double dec = ptr[1]; // Dec[deg]
208 const double woff = ptr[4]; // Wobble offset [deg]
209 const double wang = ptr[5]; // Wobble angle [deg]
210
211 fDriveControlSourceName = d.ptr<char>(6*8);
212
213 ostringstream out;
214 out << uint64_t(d.time.UnixTime()*1000) << '\n';
215
216 out << fDriveControlSourceName << '\n';
217 out << setprecision(5);
218 out << "#ffffff\t" << ra << '\n';
219 out << "#ffffff\t" << dec << '\n';
220 out << setprecision(3);
221 out << "#ffffff\t" << woff << '\n';
222 out << "#ffffff\t" << wang << '\n';
223
224 ofstream fout("www/drive.txt");
225 fout << out.str();
226 }
227
228 void HandleBiasControlVoltage(const DimData &d)
229 {
230 if (!CheckDataSize(d, "BiasControl:Voltage", 1664))
231 return;
232
233 vector<float> v(d.ptr<float>(), d.ptr<float>()+320);
234 sort(v.begin(), v.end());
235
236 fBiasControlVoltageMed = (v[159]+v[160])/2;
237
238 const char *ptr = d.ptr<char>();
239
240 ofstream fout("www/biascontrol-voltage.bin");
241 fout.write(ptr, 320*sizeof(float));
242 }
243
244 void HandleBiasControlCurrent(const DimData &d)
245 {
246 if (!CheckDataSize(d, "BiasControl:Current", 832))
247 return;
248
249 vector<uint16_t> v(d.ptr<uint16_t>(), d.ptr<uint16_t>()+320);
250 sort(v.begin(), v.end());
251
252 // Exclude the three crazy channels
253 fBiasControlCurrentMed = (v[159]+v[160])/2 * 5000./4096;
254 fBiasControlCurrentMax = v[316] * 5000./4096;
255
256 const char *ptr = d.ptr<char>();
257
258 ofstream fout("www/biascontrol-current.bin");
259 fout.write(ptr, 320*sizeof(uint16_t));
260 }
261
262 uint8_t fEventCounter;
263
264 void HandleFadControlEventData(const DimData &d)
265 {
266 if (!CheckDataSize(d, "FadControl:EventData", 23040))
267 return;
268
269 if (fEventCounter++%30)
270 return;
271
272 //const float *avg = d.ptr<float>();
273 //const float *rms = d.ptr<float>(1440*sizeof(float));
274 const float *max = d.ptr<float>(1440*sizeof(float)*2);
275 //const float *pos = d.ptr<float>(1440*sizeof(float)*3);
276
277 vector<float> dat(160, 0);
278 for (int i=0; i<1440; i++)
279 {
280 const int idx = fPixelMap.index(i).hw()/9;
281 if (max[i]>dat[idx])
282 dat[idx]=max[i];
283 //dat[idx] += max[i];
284 }
285
286 vector<uint8_t> val(160, 0);
287 for (int i=0; i<160; i++)
288 {
289 float range = nearbyint(64*dat[i]/2000)+64; // [-2V; 2V]
290 if (range>127)
291 range=127;
292 if (range<0)
293 range=0;
294 val[i] = (uint8_t)range;
295 }
296
297 const char *ptr = reinterpret_cast<char*>(val.data());
298
299 ofstream fout("www/fadcontrol-eventdata.bin");
300 fout.write(ptr, 160*sizeof(int8_t));
301 }
302
303 // -------------------------------------------------------------------
304
305 void infoHandler()
306 {
307 DimInfo *curr = getInfo(); // get current DimInfo address
308 if (!curr)
309 return;
310
311 if (HandleService(curr, fDimMagicWeatherData, &StateMachineSmartFACT::HandleMagicWeatherData))
312 return;
313 if (HandleService(curr, fDimBiasControlVoltage, &StateMachineSmartFACT::HandleBiasControlVoltage))
314 return;
315 if (HandleService(curr, fDimBiasControlCurrent, &StateMachineSmartFACT::HandleBiasControlCurrent))
316 return;
317 if (HandleService(curr, *fDimFadControlEventData, &StateMachineSmartFACT::HandleFadControlEventData))
318 return;
319
320 if (UpdateState(curr, fDimMagicWeather, fStatusMagicWeather))
321 return;
322 if (UpdateState(curr, fDimBiasControl, fStatusBiasControl))
323 return;
324 if (UpdateState(curr, fDimFadControl, fStatusFadControl))
325 return;
326
327 if (curr==&fDim)
328 {
329 fStatusDim = GetNewState(fDim);
330 fStatusDim.second = curr->getSize()==4 ? curr->getInt() : 0;
331 return;
332 }
333 }
334
335 bool CheckEventSize(size_t has, const char *name, size_t size)
336 {
337 if (has==size)
338 return true;
339
340 ostringstream msg;
341 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
342 Fatal(msg);
343 return false;
344 }
345
346 void PrintState(const pair<Time,int> &state, const char *server)
347 {
348 const State rc = fNetwork.GetState(server, state.second);
349
350 Out() << state.first.GetAsStr("%H:%M:%S.%f").substr(0, 12) << " - ";
351 Out() << kBold << server << ": ";
352 if (rc.index==-2)
353 {
354 Out() << kReset << "Offline" << endl;
355 return;
356 }
357 Out() << rc.name << "[" << rc.index << "]";
358 Out() << kReset << " - " << kBlue << rc.comment << endl;
359 }
360
361 int Print()
362 {
363 Out() << fStatusDim.first.GetAsStr("%H:%M:%S.%f").substr(0, 12) << " - ";
364 Out() << kBold << "DIM_DNS: ";
365 if (fStatusDim.second==0)
366 Out() << "Offline" << endl;
367 else
368 Out() << "V" << fStatusDim.second/100 << 'r' << fStatusDim.second%100 << endl;
369
370 PrintState(fStatusMagicWeather, "MAGIC_WEATHER");
371 PrintState(fStatusDriveControl, "DRIVE_CONTROL");
372 PrintState(fStatusBiasControl, "BIAS_CONTROL");
373 PrintState(fStatusFadControl, "FAD_CONTROL");
374
375 return GetCurrentState();
376 }
377
378 int Execute()
379 {
380 // Dispatch (execute) at most one handler from the queue. In contrary
381 // to run_one(), it doesn't wait until a handler is available
382 // which can be dispatched, so poll_one() might return with 0
383 // handlers dispatched. The handlers are always dispatched/executed
384 // synchronously, i.e. within the call to poll_one()
385 //poll_one();
386
387 if (fStatusDim.second==0)
388 return kStateDimNetworkNA;
389
390 Time now;
391 if (now-fLastUpdate<boost::posix_time::seconds(1))
392 return kStateRunning;
393
394 fLastUpdate=now;
395
396 ostringstream out;
397 out << uint64_t(nearbyint(now.UnixTime()*1000)) << '\n';
398 out << setprecision(3);
399
400 // -------------- System status --------------
401 out << "n/a\n";
402
403 // ------------------ Drive -----------------
404 if (fStatusDriveControl.second>=5) // Armed, Moving, Tracking
405 {
406 const State rc = fNetwork.GetState("DRIVE_CONTROL", fStatusDriveControl.second);
407 out << "#ffffff\t";
408 out << rc.name << '\t';
409 out << fDriveControlPointingZd << '\t';
410 out << fDriveControlPointingAz << '\t';
411 out << fDriveControlTrackingDev << '\t';
412 out << fDriveControlSourceName << '\n';
413 }
414 else
415 out << "#ffffff\t\t\t\t\t\n";
416
417 // --------------- MagicWeather -------------
418 if (fStatusMagicWeather.second==3)
419 {
420 const float diff = fMagicWeatherData[kTemp]-fMagicWeatherData[kDew];
421 string col1 = "#fff8f0";
422 if (diff>0.3)
423 col1="#fffff0";
424 if (diff>0.7)
425 col1="#f0fff0";
426
427 const float wind = fMagicWeatherData[kGusts];
428 string col2 = "#f0fff0";
429 if (wind>35)
430 col2="#fffff0";
431 if (wind>50)
432 col2="#fff8f0";
433
434 out << col1 << "\t";
435 out << fMagicWeatherData[kTemp] << '\t';
436 out << fMagicWeatherData[kDew] << '\n';
437 out << col2 << "\t";
438 out << fMagicWeatherData[kGusts] << '\n';
439 }
440 else
441 out << "#ffffff\t\t\n\n";
442
443 // --------------- BiasControl -------------
444 if (fStatusBiasControl.second==5 || // Ramping
445 fStatusBiasControl.second==7 || // On
446 fStatusBiasControl.second==9) // Off
447 {
448 string col = fBiasControlVoltageMed>3?"#fff8f0":"#ffffff";
449 if (fBiasControlCurrentMax>280)
450 col = "#fffff0";
451 if (fBiasControlCurrentMax>350)
452 col = "#fff8f0";
453
454 out << col << "\t";
455 out << fBiasControlCurrentMed << '\t';
456 out << fBiasControlCurrentMax << '\t';
457 out << fBiasControlVoltageMed << '\n';
458 }
459 else
460 out << "#ffffff\t\t\t\n";
461
462
463 // ------------------------------------------
464 ofstream fout("www/fact.txt");
465 fout << out.str();
466
467 return kStateRunning;
468 }
469
470public:
471 StateMachineSmartFACT(ostream &out=cout) : StateMachineDim(out, "SMART_FACT"),
472 fStatusDim (make_pair(Time(), -2)),
473 fStatusDriveControl(make_pair(Time(), -2)),
474 fStatusMagicWeather(make_pair(Time(), -2)),
475 fStatusBiasControl (make_pair(Time(), -2)),
476 fStatusFadControl (make_pair(Time(), -2)),
477 //---
478 fDim ("DIS_DNS/VERSION_NUMBER", (void*)NULL, 0, this),
479 //---
480 fDimDriveControl ("DRIVE_CONTROL/STATE", (void*)NULL, 0, this),
481 fDimDriveControlPointing("DRIVE_CONTROL/POINTING_POSITION", (void*)NULL, 0, this),
482 fDimDriveControlTracking("DRIVE_CONTROL/TRACKING_POSITION", (void*)NULL, 0, this),
483 fDimDriveControlSource ("DRIVE_CONTROL/SOURCE_POSITION", (void*)NULL, 0, this),
484 //---
485 fDimMagicWeather ("MAGIC_WEATHER/STATE", (void*)NULL, 0, this),
486 fDimMagicWeatherData ("MAGIC_WEATHER/DATA", (void*)NULL, 0, this),
487 //---
488 fDimBiasControl ("BIAS_CONTROL/STATE", (void*)NULL, 0, this),
489 fDimBiasControlVoltage ("BIAS_CONTROL/VOLTAGE", (void*)NULL, 0, this),
490 fDimBiasControlCurrent ("BIAS_CONTROL/CURRENT", (void*)NULL, 0, this),
491 //---
492 fDimFadControl ("FAD_CONTROL/STATE", (void*)NULL, 0, this),
493 fDimFadControlEventData(0),
494 //---
495 fEventCounter(0)
496 {
497 // State names
498 AddStateName(kStateDimNetworkNA, "DimNetworkNotAvailable",
499 "The Dim DNS is not reachable.");
500
501 AddStateName(kStateRunning, "Running", "");
502
503 // Verbosity commands
504// AddEvent("SET_VERBOSE", "B:1")
505// (bind(&StateMachineMCP::SetVerbosity, this, placeholders::_1))
506// ("set verbosity state"
507// "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
508
509 AddEvent("PRINT")
510 (bind(&StateMachineSmartFACT::Print, this))
511 ("");
512 }
513 ~StateMachineSmartFACT()
514 {
515 delete fDimFadControlEventData;
516 }
517 int EvalOptions(Configuration &conf)
518 {
519 if (!fPixelMap.Read(conf.Get<string>("pixel-map-file")))
520 {
521 Error("Reading mapping table from "+conf.Get<string>("pixel-map-file")+" failed.");
522 return 1;
523 }
524
525 // Pixel map is needed to deal with this service
526 fDimFadControlEventData=new DimStampedInfo("FAD_CONTROL/EVENT_DATA", (void*)NULL, 0, this);
527
528 return -1;
529 }
530};
531
532// ------------------------------------------------------------------------
533
534#include "Main.h"
535
536template<class T>
537int RunShell(Configuration &conf)
538{
539 return Main::execute<T, StateMachineSmartFACT>(conf);
540}
541
542void SetupConfiguration(Configuration &conf)
543{
544 po::options_description control("Smart FACT");
545 control.add_options()
546 ("pixel-map-file", var<string>("FACTmapV5a.txt"), "Pixel mapping file. Used here to get the default reference voltage.")
547 ;
548
549 conf.AddOptions(control);
550}
551
552/*
553 Extract usage clause(s) [if any] for SYNOPSIS.
554 Translators: "Usage" and "or" here are patterns (regular expressions) which
555 are used to match the usage synopsis in program output. An example from cp
556 (GNU coreutils) which contains both strings:
557 Usage: cp [OPTION]... [-T] SOURCE DEST
558 or: cp [OPTION]... SOURCE... DIRECTORY
559 or: cp [OPTION]... -t DIRECTORY SOURCE...
560 */
561void PrintUsage()
562{
563 cout <<
564 "SmartFACT is a tool writing the files needed for the SmartFACT web interface.\n"
565 "\n"
566 "The default is that the program is started without user intercation. "
567 "All actions are supposed to arrive as DimCommands. Using the -c "
568 "option, a local shell can be initialized. With h or help a short "
569 "help message about the usuage can be brought to the screen.\n"
570 "\n"
571 "Usage: smartfact [-c type] [OPTIONS]\n"
572 " or: smartfact [OPTIONS]\n";
573 cout << endl;
574}
575
576void PrintHelp()
577{
578 Main::PrintHelp<StateMachineSmartFACT>();
579
580 /* Additional help text which is printed after the configuration
581 options goes here */
582
583 /*
584 cout << "bla bla bla" << endl << endl;
585 cout << endl;
586 cout << "Environment:" << endl;
587 cout << "environment" << endl;
588 cout << endl;
589 cout << "Examples:" << endl;
590 cout << "test exam" << endl;
591 cout << endl;
592 cout << "Files:" << endl;
593 cout << "files" << endl;
594 cout << endl;
595 */
596}
597
598int main(int argc, const char* argv[])
599{
600 Configuration conf(argv[0]);
601 conf.SetPrintUsage(PrintUsage);
602 Main::SetupConfiguration(conf);
603 SetupConfiguration(conf);
604
605 if (!conf.DoParse(argc, argv, PrintHelp))
606 return -1;
607
608 //try
609 {
610 // No console access at all
611 if (!conf.Has("console"))
612 {
613// if (conf.Get<bool>("no-dim"))
614// return RunShell<LocalStream, StateMachine, ConnectionFSC>(conf);
615// else
616 return RunShell<LocalStream>(conf);
617 }
618 // Cosole access w/ and w/o Dim
619/* if (conf.Get<bool>("no-dim"))
620 {
621 if (conf.Get<int>("console")==0)
622 return RunShell<LocalShell, StateMachine, ConnectionFSC>(conf);
623 else
624 return RunShell<LocalConsole, StateMachine, ConnectionFSC>(conf);
625 }
626 else
627*/ {
628 if (conf.Get<int>("console")==0)
629 return RunShell<LocalShell>(conf);
630 else
631 return RunShell<LocalConsole>(conf);
632 }
633 }
634 /*catch (std::exception& e)
635 {
636 cerr << "Exception: " << e.what() << endl;
637 return -1;
638 }*/
639
640 return 0;
641}
Note: See TracBrowser for help on using the repository browser.