source: trunk/FACT++/src/evtserver.cc@ 19438

Last change on this file since 19438 was 19381, checked in by tbretz, 6 years ago
Added PRINT command and --client option. No need anymore to skip the TM channel.
File size: 11.6 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
11#include "tools.h"
12
13#include "LocalControl.h"
14
15#include "HeadersFAD.h"
16#include "HeadersEventServer.h"
17
18#include "fits.h"
19#include "nova.h"
20
21namespace ba = boost::asio;
22namespace bs = boost::system;
23
24using namespace std;
25
26// ------------------------------------------------------------------------
27
28#include "DimDescriptionService.h"
29#include "DimState.h"
30
31// ------------------------------------------------------------------------
32
33class StateMachineEventServer : public StateMachineDim
34{
35public:
36 static bool fIsServer;
37
38private:
39
40 DimDescribedState fDimFadControl;
41
42 string fAuxPath;
43 string fOutPath;
44 uint32_t fStartDate;
45 uint32_t fNight;
46 uint32_t fInterval;
47
48 fits *fIn;
49
50 uint32_t fQoS;
51 double fTime;
52 uint32_t fRun;
53 uint32_t fEvt;
54 //vector<float> fAvg;
55 //vector<float> fRms;
56 vector<float> fMax;
57 //vector<float> fPos;
58
59 Time fTimer;
60
61 int Execute()
62 {
63 if (GetCurrentState()==StateMachineImp::kSM_Ready)
64 return EventServer::State::kRunning;
65
66 // Nothing to do if not started
67 if (GetCurrentState()==EventServer::State::kIdle)
68 return EventServer::State::kIdle;
69
70 if (fDimFadControl.state()==FAD::State::kRunInProgress)
71 return EventServer::State::kStandby;
72
73 // Run only once in 5s
74 const Time now;
75 if (now<fTimer+boost::posix_time::milliseconds(fInterval))
76 return GetCurrentState();
77 fTimer = now;
78
79 // Running is only allowed when sun is up
80 const Nova::RstTime rst = Nova::GetSolarRst(now.JD()-0.5);
81 const bool isUp =
82 (rst.rise<rst.set && (now.JD()>rst.rise && now.JD()<rst.set)) ||
83 (rst.rise>rst.set && (now.JD()<rst.set || now.JD()>rst.rise));
84
85 // FIXME: What about errors?
86 if (!isUp)
87 return EventServer::State::kStandby;
88
89 // Check if file has to be changed
90 const uint32_t night = fStartDate>0 ? fStartDate : Time(Time().Mjd()-1).NightAsInt();
91
92 if (fNight!=night)
93 {
94 fNight = night;
95
96 delete fIn;
97
98 const string name = fAuxPath + Tools::Form("/%04d/%02d/%02d/%08d.FAD_CONTROL_EVENT_DATA.fits", night/10000, (night/100)%100, night%100, night);
99
100 fIn = new fits(name);
101 if (!fIn->is_open())
102 {
103 Error(string("Failed to open "+name+": ")+strerror(errno));
104 return StateMachineImp::kSM_Error;
105 }
106
107 // Requiered columns
108 try
109 {
110 fIn->SetRefAddress("QoS", fQoS);
111 fIn->SetRefAddress("Time", fTime);
112 fIn->SetVecAddress("max", fMax);
113 //fIn->SetVecAddress(fRms);
114 //fIn->SetVecAddress(fMax);
115 //fIn->SetVecAddress(fPos);
116 }
117 catch (const runtime_error &e)
118 {
119 delete fIn;
120 fIn = 0;
121
122 Error("Failed to open "+name+": "+e.what());
123 return StateMachineImp::kSM_Error;
124 }
125
126 // Non requiered columns
127 fRun = 0;
128 fEvt = 0;
129 try
130 {
131 fIn->SetRefAddress("run", fRun);
132 fIn->SetRefAddress("evt", fEvt);
133 }
134 catch (const runtime_error &e) { }
135
136 Info("File "+name+" open.");
137 }
138
139 if (GetCurrentState()==StateMachineImp::kSM_Error)
140 return StateMachineImp::kSM_Error;
141
142 // Get next data event
143 vector<float> sorted;
144 while (1)
145 {
146 if (!fIn->GetNextRow())
147 {
148 fNight = 0;
149 return EventServer::State::kRunning;
150 }
151
152 // Select a
153 if (fQoS & FAD::EventHeader::kAll)
154 continue;
155
156 for (int i=0; i<1440; i++)
157 fMax[i] /= 1000;
158
159 //for (int i=8; i<1440; i+=9)
160 // fMax[i] = fMax[i-2];
161
162 // construct output
163 sorted = fMax;
164 sort(sorted.begin(), sorted.end());
165
166 const double med = sorted[719];
167
168 vector<float> dev(1440);
169 for (int i=0; i<1440; i++)
170 dev[i] = fabs(sorted[i]-med);
171 sort(dev.begin(), dev.end());
172
173 const double deviation = dev[uint32_t(0.682689477208650697*1440)];
174
175 // In a typical shower or muon ring, the first
176 // few pixels will have comparable brightness,
177 // in a NSB event not. Therefore, the 4th brightest
178 // pixel is a good reference.
179 if (sorted[1439-3]>med+deviation*5)
180 break;
181 }
182
183 const double scale = max(0.25f, sorted[1436]);
184
185 ostringstream out;
186 out << Time(fTime+40587).JavaDate() << '\n';
187 out << "0\n";
188 out << scale << '\n';
189 out << setprecision(3);
190 if (fRun>0)
191 //out << "DEMO [" << fEvt << "]\nDEMO [" << fRun << "]\nDEMO\x7f";
192 out << fEvt << '\n' << fRun << "\nDEMO\x7f";
193 else
194 out << "DEMO\nDEMO\nDEMO\x7f";
195
196 //out << sorted[1439] << '\n';
197 //out << sorted[719] << '\n';
198 //out << sorted[0] << '\x7f';
199
200 // The valid range is from 1 to 127
201 // \0 is used to seperate different curves
202 vector<uint8_t> val(1440);
203 for (uint64_t i=0; i<1440; i++)
204 {
205 float range = nearbyint(126*fMax[i]/scale); // [-2V; 2V]
206 if (range>126)
207 range=126;
208 if (range<0)
209 range=0;
210 val[i] = (uint8_t)range;
211 }
212
213 const char *ptr = reinterpret_cast<char*>(val.data());
214 out.write(ptr, val.size()*sizeof(uint8_t));
215 out << '\x7f';
216
217 if (fOutPath=="-")
218 Out() << out.str();
219 else
220 ofstream(fOutPath+"/cam-fadcontrol-eventdata.bin") << out.str();
221
222 return EventServer::State::kRunning;
223 }
224
225 int StartServer()
226 {
227 fStartDate = 0;
228 return EventServer::State::kRunning;
229 }
230
231 int StopServer()
232 {
233 delete fIn;
234 fIn = 0;
235
236 return EventServer::State::kIdle;
237 }
238
239 int StartDate(const EventImp &evt)
240 {
241 fStartDate = evt.GetUInt();
242 return EventServer::State::kRunning;
243 }
244
245 int Print() const
246 {
247 Out() << fDimFadControl << endl;
248 return GetCurrentState();
249 }
250
251
252public:
253 StateMachineEventServer(ostream &out=cout) : StateMachineDim(out, fIsServer?"EVENT_SERVER":""),
254 fDimFadControl("FAD_CONTROL"), fStartDate(0), fNight(0), fIn(0), fMax(1440)
255
256 {
257 fDimFadControl.Subscribe(*this);
258
259 // State names
260 AddStateName(EventServer::State::kIdle, "Idle",
261 "Event server stopped.");
262 AddStateName(EventServer::State::kRunning, "Running",
263 "Reading events file and writing to output.");
264 AddStateName(EventServer::State::kStandby, "Standby",
265 "No events are processed, either the sun is down or fadctrl in kRunInProgress.");
266
267
268 AddEvent("START", EventServer::State::kIdle, EventServer::State::kRunning, StateMachineImp::kSM_Error)
269 (bind(&StateMachineEventServer::StartServer, this))
270 ("Start serving the smartfact camera file");
271
272 AddEvent("START_DATE", "I:1", EventServer::State::kIdle, EventServer::State::kRunning, StateMachineImp::kSM_Error)
273 (bind(&StateMachineEventServer::StartDate, this, placeholders::_1))
274 ("Start serving the smartfact camera file with the events from the given date"
275 "|uint32[yyyymmdd]:Integer representing the date from which the data should be read");
276
277 AddEvent("STOP", EventServer::State::kRunning, EventServer::State::kStandby, StateMachineImp::kSM_Error)
278 (bind(&StateMachineEventServer::StopServer, this))
279 ("Stop serving the smartfact camera file");
280
281 AddEvent("PRINT")
282 (bind(&StateMachineEventServer::Print, this))
283 ("Print current status");
284 }
285 ~StateMachineEventServer()
286 {
287 delete fIn;
288 }
289
290 int EvalOptions(Configuration &conf)
291 {
292 fAuxPath = conf.Get<string>("aux-path");
293 fOutPath = conf.Get<string>("out-path");
294 fInterval = conf.Get<uint32_t>("interval");
295
296 return -1;
297 }
298};
299
300bool StateMachineEventServer::fIsServer = false;
301
302// ------------------------------------------------------------------------
303
304#include "Main.h"
305
306template<class T>
307int RunShell(Configuration &conf)
308{
309 StateMachineEventServer::fIsServer = !conf.Get<bool>("client");
310 return Main::execute<T, StateMachineEventServer>(conf);
311}
312
313void SetupConfiguration(Configuration &conf)
314{
315 po::options_description control("Event server options");
316 control.add_options()
317 ("aux-path", var<string>("/fact/aux"), "The root path to the auxilary files.")
318 ("out-path", var<string>("www/smartfact/data"), "Path where the output camera file should be written.")
319 ("interval", var<uint32_t>(5000), "Interval of updates in milliseconds.")
320 ("client", po_bool(false), "For a standalone client choose this option.")
321 ;
322
323 conf.AddOptions(control);
324}
325
326/*
327 Extract usage clause(s) [if any] for SYNOPSIS.
328 Translators: "Usage" and "or" here are patterns (regular expressions) which
329 are used to match the usage synopsis in program output. An example from cp
330 (GNU coreutils) which contains both strings:
331 Usage: cp [OPTION]... [-T] SOURCE DEST
332 or: cp [OPTION]... SOURCE... DIRECTORY
333 or: cp [OPTION]... -t DIRECTORY SOURCE...
334 */
335void PrintUsage()
336{
337 cout <<
338 "The event server copies events from fits files to the smartfact data.\n"
339 "\n"
340 "Usage: evtserver [-c type] [OPTIONS]\n"
341 " or: evtserver [OPTIONS]\n";
342 cout << endl;
343}
344
345void PrintHelp()
346{
347 Main::PrintHelp<StateMachineEventServer>();
348
349 /* Additional help text which is printed after the configuration
350 options goes here */
351
352 /*
353 cout << "bla bla bla" << endl << endl;
354 cout << endl;
355 cout << "Environment:" << endl;
356 cout << "environment" << endl;
357 cout << endl;
358 cout << "Examples:" << endl;
359 cout << "test exam" << endl;
360 cout << endl;
361 cout << "Files:" << endl;
362 cout << "files" << endl;
363 cout << endl;
364 */
365}
366
367int main(int argc, const char* argv[])
368{
369 Configuration conf(argv[0]);
370 conf.SetPrintUsage(PrintUsage);
371 Main::SetupConfiguration(conf);
372 SetupConfiguration(conf);
373
374 if (!conf.DoParse(argc, argv, PrintHelp))
375 return 127;
376
377 //try
378 {
379 // No console access at all
380 if (!conf.Has("console"))
381 {
382// if (conf.Get<bool>("no-dim"))
383// return RunShell<LocalStream, StateMachine, ConnectionFSC>(conf);
384// else
385 return RunShell<LocalStream>(conf);
386 }
387 // Cosole access w/ and w/o Dim
388/* if (conf.Get<bool>("no-dim"))
389 {
390 if (conf.Get<int>("console")==0)
391 return RunShell<LocalShell, StateMachine, ConnectionFSC>(conf);
392 else
393 return RunShell<LocalConsole, StateMachine, ConnectionFSC>(conf);
394 }
395 else
396*/ {
397 if (conf.Get<int>("console")==0)
398 return RunShell<LocalShell>(conf);
399 else
400 return RunShell<LocalConsole>(conf);
401 }
402 }
403 /*catch (std::exception& e)
404 {
405 cerr << "Exception: " << e.what() << endl;
406 return -1;
407 }*/
408
409 return 0;
410}
Note: See TracBrowser for help on using the repository browser.