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

Last change on this file since 13477 was 13462, checked in by tbretz, 14 years ago
First version of a dim client writing input for the SmartFACT++ web-page.
File size: 18.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> 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 << 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 << ra << '\n';
219 out << dec << '\n';
220 out << setprecision(3);
221 out << woff << '\n';
222 out << wang << '\n';
223
224 ofstream fout("www/drive-source.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 ostringstream out;
395 out << uint64_t(nearbyint(now.UnixTime()*1000)) << '\n';
396 out << setprecision(3);
397
398 // --------------- MagicWeather -------------
399 if (fStatusMagicWeather.second==3)
400 {
401 out << fMagicWeatherData[kTemp] << '\n';
402 out << fMagicWeatherData[kDew] << '\n';
403 out << fMagicWeatherData[kGusts] << '\n';
404 }
405 else
406 out << "\n\n\n";
407
408 // --------------- BiasControl -------------
409 if (fStatusBiasControl.second==5 || // Ramping
410 fStatusBiasControl.second==7 || // On
411 fStatusBiasControl.second==9) // Off
412 {
413 out << fBiasControlVoltageMed << '\n';
414 out << fBiasControlCurrentMed << '\n';
415 out << fBiasControlCurrentMax << '\n';
416 }
417 else
418 out << "\n\n\n";
419
420 // ------------------ Drive -----------------
421 if (fStatusDriveControl.second>=5) // Armed, Moving, Tracking
422 {
423 const State rc = fNetwork.GetState("DRIVE_CONTROL", fStatusDriveControl.second);
424 out << rc.name << '\n';
425 out << fDriveControlPointingZd << '\n';
426 out << fDriveControlPointingAz << '\n';
427 out << fDriveControlTrackingDev << '\n';
428 out << fDriveControlSourceName << '\n';
429 }
430 else
431 out << "\n\n\n\n\n";
432
433 // ------------------------------------------
434 ofstream fout("www/status.txt");
435 fout << out.str();
436
437 return kStateRunning;
438 }
439
440public:
441 StateMachineSmartFACT(ostream &out=cout) : StateMachineDim(out, "SMART_FACT"),
442 fStatusDim (make_pair(Time(), -2)),
443 fStatusDriveControl(make_pair(Time(), -2)),
444 fStatusMagicWeather(make_pair(Time(), -2)),
445 fStatusBiasControl (make_pair(Time(), -2)),
446 fStatusFadControl (make_pair(Time(), -2)),
447 //---
448 fDim ("DIS_DNS/VERSION_NUMBER", (void*)NULL, 0, this),
449 //---
450 fDimDriveControl ("DRIVE_CONTROL/STATE", (void*)NULL, 0, this),
451 fDimDriveControlPointing("DRIVE_CONTROL/POINTING_POSITION", (void*)NULL, 0, this),
452 fDimDriveControlTracking("DRIVE_CONTROL/TRACKING_POSITION", (void*)NULL, 0, this),
453 fDimDriveControlSource ("DRIVE_CONTROL/SOURCE_POSITION", (void*)NULL, 0, this),
454 //---
455 fDimMagicWeather ("MAGIC_WEATHER/STATE", (void*)NULL, 0, this),
456 fDimMagicWeatherData ("MAGIC_WEATHER/DATA", (void*)NULL, 0, this),
457 //---
458 fDimBiasControl ("BIAS_CONTROL/STATE", (void*)NULL, 0, this),
459 fDimBiasControlVoltage ("BIAS_CONTROL/VOLTAGE", (void*)NULL, 0, this),
460 fDimBiasControlCurrent ("BIAS_CONTROL/CURRENT", (void*)NULL, 0, this),
461 //---
462 fDimFadControl ("FAD_CONTROL/STATE", (void*)NULL, 0, this),
463 fDimFadControlEventData(0),
464 //---
465 fEventCounter(0)
466 {
467 // State names
468 AddStateName(kStateDimNetworkNA, "DimNetworkNotAvailable",
469 "The Dim DNS is not reachable.");
470
471 AddStateName(kStateRunning, "Running", "");
472
473 // Verbosity commands
474// AddEvent("SET_VERBOSE", "B:1")
475// (bind(&StateMachineMCP::SetVerbosity, this, placeholders::_1))
476// ("set verbosity state"
477// "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
478
479 AddEvent("PRINT")
480 (bind(&StateMachineSmartFACT::Print, this))
481 ("");
482 }
483 ~StateMachineSmartFACT()
484 {
485 delete fDimFadControlEventData;
486 }
487 int EvalOptions(Configuration &conf)
488 {
489 if (!fPixelMap.Read(conf.Get<string>("pixel-map-file")))
490 {
491 Error("Reading mapping table from "+conf.Get<string>("pixel-map-file")+" failed.");
492 return 1;
493 }
494
495 // Pixel map is needed to deal with this service
496 fDimFadControlEventData=new DimStampedInfo("FAD_CONTROL/EVENT_DATA", (void*)NULL, 0, this);
497
498 return -1;
499 }
500};
501
502// ------------------------------------------------------------------------
503
504#include "Main.h"
505
506template<class T>
507int RunShell(Configuration &conf)
508{
509 return Main::execute<T, StateMachineSmartFACT>(conf);
510}
511
512void SetupConfiguration(Configuration &conf)
513{
514 po::options_description control("Smart FACT");
515 control.add_options()
516 ("pixel-map-file", var<string>("FACTmapV5a.txt"), "Pixel mapping file. Used here to get the default reference voltage.")
517 ;
518
519 conf.AddOptions(control);
520}
521
522/*
523 Extract usage clause(s) [if any] for SYNOPSIS.
524 Translators: "Usage" and "or" here are patterns (regular expressions) which
525 are used to match the usage synopsis in program output. An example from cp
526 (GNU coreutils) which contains both strings:
527 Usage: cp [OPTION]... [-T] SOURCE DEST
528 or: cp [OPTION]... SOURCE... DIRECTORY
529 or: cp [OPTION]... -t DIRECTORY SOURCE...
530 */
531void PrintUsage()
532{
533 cout <<
534 "SmartFACT is a tool writing the files needed for the SmartFACT web interface.\n"
535 "\n"
536 "The default is that the program is started without user intercation. "
537 "All actions are supposed to arrive as DimCommands. Using the -c "
538 "option, a local shell can be initialized. With h or help a short "
539 "help message about the usuage can be brought to the screen.\n"
540 "\n"
541 "Usage: smartfact [-c type] [OPTIONS]\n"
542 " or: smartfact [OPTIONS]\n";
543 cout << endl;
544}
545
546void PrintHelp()
547{
548 Main::PrintHelp<StateMachineSmartFACT>();
549
550 /* Additional help text which is printed after the configuration
551 options goes here */
552
553 /*
554 cout << "bla bla bla" << endl << endl;
555 cout << endl;
556 cout << "Environment:" << endl;
557 cout << "environment" << endl;
558 cout << endl;
559 cout << "Examples:" << endl;
560 cout << "test exam" << endl;
561 cout << endl;
562 cout << "Files:" << endl;
563 cout << "files" << endl;
564 cout << endl;
565 */
566}
567
568int main(int argc, const char* argv[])
569{
570 Configuration conf(argv[0]);
571 conf.SetPrintUsage(PrintUsage);
572 Main::SetupConfiguration(conf);
573 SetupConfiguration(conf);
574
575 if (!conf.DoParse(argc, argv, PrintHelp))
576 return -1;
577
578 //try
579 {
580 // No console access at all
581 if (!conf.Has("console"))
582 {
583// if (conf.Get<bool>("no-dim"))
584// return RunShell<LocalStream, StateMachine, ConnectionFSC>(conf);
585// else
586 return RunShell<LocalStream>(conf);
587 }
588 // Cosole access w/ and w/o Dim
589/* if (conf.Get<bool>("no-dim"))
590 {
591 if (conf.Get<int>("console")==0)
592 return RunShell<LocalShell, StateMachine, ConnectionFSC>(conf);
593 else
594 return RunShell<LocalConsole, StateMachine, ConnectionFSC>(conf);
595 }
596 else
597*/ {
598 if (conf.Get<int>("console")==0)
599 return RunShell<LocalShell>(conf);
600 else
601 return RunShell<LocalConsole>(conf);
602 }
603 }
604 /*catch (std::exception& e)
605 {
606 cerr << "Exception: " << e.what() << endl;
607 return -1;
608 }*/
609
610 return 0;
611}
Note: See TracBrowser for help on using the repository browser.