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 | |
---|
21 | namespace ba = boost::asio; |
---|
22 | namespace bs = boost::system; |
---|
23 | |
---|
24 | using namespace std; |
---|
25 | |
---|
26 | // ------------------------------------------------------------------------ |
---|
27 | |
---|
28 | #include "DimDescriptionService.h" |
---|
29 | #include "DimState.h" |
---|
30 | |
---|
31 | // ------------------------------------------------------------------------ |
---|
32 | |
---|
33 | class StateMachineEventServer : public StateMachineDim |
---|
34 | { |
---|
35 | public: |
---|
36 | static bool fIsServer; |
---|
37 | |
---|
38 | private: |
---|
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 | |
---|
252 | public: |
---|
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 | |
---|
300 | bool StateMachineEventServer::fIsServer = false; |
---|
301 | |
---|
302 | // ------------------------------------------------------------------------ |
---|
303 | |
---|
304 | #include "Main.h" |
---|
305 | |
---|
306 | template<class T> |
---|
307 | int RunShell(Configuration &conf) |
---|
308 | { |
---|
309 | StateMachineEventServer::fIsServer = !conf.Get<bool>("client"); |
---|
310 | return Main::execute<T, StateMachineEventServer>(conf); |
---|
311 | } |
---|
312 | |
---|
313 | void 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 | */ |
---|
335 | void 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 | |
---|
345 | void 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 | |
---|
367 | int 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 | } |
---|