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

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