source: trunk/FACT++/src/ratecontrol.cc@ 12372

Last change on this file since 12372 was 12355, checked in by tbretz, 13 years ago
File size: 13.9 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
16#include "LocalControl.h"
17
18#include "HeadersFTM.h"
19
20namespace ba = boost::asio;
21namespace bs = boost::system;
22namespace dummy = ba::placeholders;
23
24using namespace std;
25
26// ------------------------------------------------------------------------
27
28#include "DimDescriptionService.h"
29
30// ------------------------------------------------------------------------
31
32class StateMachineRateControl : public StateMachineDim, public DimInfoHandler
33{
34private:
35 enum states_t
36 {
37 kStateDimNetworkNA = 1,
38 kStateDisconnected,
39 kStateConnecting,
40 kStateConnected,
41 kStateInProgress,
42 };
43
44 DimServiceInfoList fNetwork;
45
46 pair<Time, int> fStatusDim;
47 pair<Time, int> fStatusFTM;
48
49 DimStampedInfo fDim;
50 DimStampedInfo fFTM;
51 DimStampedInfo fRates;
52 DimStampedInfo fStatic;
53
54// DimDescribedService fDimData;
55// DimDescribedService fDimProc;
56
57 bool fTriggerOn;
58
59 pair<Time, int> GetNewState(DimStampedInfo &info) const
60 {
61 const bool disconnected = info.getSize()==0;
62
63 // Make sure getTimestamp is called _before_ getTimestampMillisecs
64 const int tsec = info.getTimestamp();
65 const int tms = info.getTimestampMillisecs();
66
67 return make_pair(Time(tsec, tms*1000),
68 disconnected ? -2 : info.getQuality());
69 }
70
71 bool CheckEventSize(size_t has, const char *name, size_t size)
72 {
73 if (has==size)
74 return true;
75
76 if (has==0)
77 return false;
78
79 ostringstream msg;
80 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
81 Fatal(msg);
82 return false;
83 }
84
85 vector<uint16_t> fThresholds;
86
87 void PrintThresholds(const FTM::DimStaticData &sdata)
88 {
89 //if (!fVerbose)
90 // return;
91
92 if (fThresholds.size()==0)
93 return;
94
95 int t=0;
96 for (t=0; t<160; t++)
97 if (sdata.fThreshold[t]!=fThresholds[t])
98 break;
99
100 if (t==160)
101 return;
102
103 for (int j=0; j<10; j++)
104 {
105 for (int k=0; k<16; k+=4)
106 {
107 for (int i=0; i<4; i++)
108 if (fThresholds[j*k+i]!=300)
109 Out() << setw(3) << fThresholds[j*k+i] << " ";
110 else
111 Out() << " - ";
112 Out() << " ";
113 }
114 Out() << endl;
115 }
116 Out() << endl;
117 }
118
119 void Step(int idx, float step)
120 {
121 uint16_t diff = fThresholds[idx]+int16_t(truncf(step));
122 if (diff<300)
123 diff=300;
124
125 if (diff==fThresholds[idx])
126 return;
127
128 if (1/*fVerbose*/)
129 {
130 Out() << idx/40 << "|" << (idx/4)%10 << "|" << idx%4;
131 Out() << (step>0 ? " += " : " -= ");
132 Out() << step << " (" << diff << ")" << endl;
133 }
134
135 const uint32_t val[2] = { idx, diff };
136 DimClient::sendCommandNB("FTM_CONTROL/SET_THRESHOLD", (void*)val, 8);
137 }
138
139 void infoHandler()
140 {
141 DimInfo *curr = getInfo(); // get current DimInfo address
142 if (!curr)
143 return;
144
145 if (curr==&fFTM)
146 {
147 fStatusFTM = GetNewState(fFTM);
148 return;
149 }
150
151 if (curr==&fDim)
152 {
153 fStatusDim = GetNewState(fDim);
154 fStatusDim.second = curr->getSize()==4 ? curr->getInt() : 0;
155 return;
156 }
157
158 static vector<uint8_t> counter(160);
159
160 if (curr==&fStatic)
161 {
162 if (!CheckEventSize(curr->getSize(), "infoHandler[DimStaticData]", sizeof(FTM::DimStaticData)))
163 return;
164
165 const FTM::DimStaticData &sdata = *static_cast<FTM::DimStaticData*>(curr->getData());
166
167 PrintThresholds(sdata);
168
169 fTriggerOn = sdata.HasTrigger();
170
171 fThresholds.assign(sdata.fThreshold, sdata.fThreshold+160);
172
173 return;
174 }
175
176 if (curr==&fRates)
177 {
178 if (fThresholds.size()==0)
179 return;
180
181 if (!fTriggerOn)
182 return;
183
184 if (!CheckEventSize(curr->getSize(), "infoHandler[DimTriggerRates]", sizeof(FTM::DimTriggerRates)))
185 return;
186
187 const FTM::DimTriggerRates &sdata = *static_cast<FTM::DimTriggerRates*>(curr->getData());
188
189 // Caluclate Median and deviation
190 vector<float> medb(sdata.fBoardRate, sdata.fBoardRate+40);
191 vector<float> medp(sdata.fPatchRate, sdata.fPatchRate+160);
192
193 sort(medb.begin(), medb.end());
194 sort(medp.begin(), medp.end());
195
196 vector<float> devb(40);
197 for (int i=0; i<40; i++)
198 devb[i] = fabs(sdata.fBoardRate[i]-medb[i]);
199
200 vector<float> devp(160);
201 for (int i=0; i<160; i++)
202 devp[i] = fabs(sdata.fPatchRate[i]-medp[i]);
203
204 sort(devb.begin(), devb.end());
205 sort(devp.begin(), devp.end());
206
207 double mb = (medb[19]+medb[20])/2;
208 double mp = (medp[79]+medp[80])/2;
209
210 double db = devb[27];
211 double dp = devp[109];
212
213 // If any is zero there is something wrong
214 if (mb==0 || mp==0 || db==0 || dp==0)
215 return;
216
217 if (1/*fVerbose*/)
218 {
219 Out() << "Patch: Median=" << mp << " Dev=" << dp << endl;
220 Out() << "Board: Median=" << mb << " Dev=" << db << endl;
221 }
222
223 for (int i=0; i<40; i++)
224 {
225 int maxi = -1;
226
227 const float dif = fabs(sdata.fBoardRate[i]-mb)/db;
228 if (dif>5)
229 {
230 if (1/*fVerbose*/)
231 Out() << "B" << i << ": " << dif << endl;
232
233 float max = sdata.fPatchRate[i*4];
234 maxi = 0;
235
236 for (int j=1; j<4; j++)
237 if (sdata.fPatchRate[i*4+j]>max)
238 {
239 max = sdata.fPatchRate[i*4+j];
240 maxi = j;
241 }
242 }
243
244 for (int j=0; j<4; j++)
245 {
246 // For the noise pixel correct down to median+3*deviation
247 if (maxi==j)
248 {
249 const float step = (log10(sdata.fPatchRate[i*4+j])-log10(mp+5*dp))/0.039;
250 // * (dif-5)/dif
251 Step(i*4+j, step);
252 continue;
253 }
254
255 // For pixels below the meadian correct also back to median+3*deviation
256 if (sdata.fPatchRate[i*4+j]<mp)
257 {
258 const float step = (log10(sdata.fPatchRate[i*4+j])-log10(mp+3*dp))/0.039;
259 Step(i*4+j, step);
260 continue;
261 }
262
263 const float step = -1.5*(log10(mp+dp)-log10(mp))/0.039;
264 Step(i*4+j, step);
265 }
266 }
267 }
268 }
269
270 void PrintState(const pair<Time,int> &state, const char *server)
271 {
272 const State rc = fNetwork.GetState(server, state.second);
273
274 Out() << state.first.GetAsStr("%H:%M:%S.%f").substr(0, 12) << " - ";
275 Out() << kBold << server << ": ";
276 Out() << rc.name << "[" << rc.index << "]";
277 Out() << kReset << " - " << kBlue << rc.comment << endl;
278 }
279
280 int Print()
281 {
282 Out() << fStatusDim.first.GetAsStr("%H:%M:%S.%f").substr(0, 12) << " - ";
283 Out() << kBold << "DIM_DNS: ";
284 if (fStatusDim.second==0)
285 Out() << "Offline" << endl;
286 else
287 Out() << "V" << fStatusDim.second/100 << 'r' << fStatusDim.second%100 << endl;
288
289 PrintState(fStatusFTM, "FTM_CONTROL");
290
291 return GetCurrentState();
292 }
293
294 int Execute()
295 {
296 // Dispatch (execute) at most one handler from the queue. In contrary
297 // to run_one(), it doesn't wait until a handler is available
298 // which can be dispatched, so poll_one() might return with 0
299 // handlers dispatched. The handlers are always dispatched/executed
300 // synchronously, i.e. within the call to poll_one()
301 //poll_one();
302
303 if (fStatusDim.second==0)
304 return kStateDimNetworkNA;
305
306 // All subsystems are not connected
307 if (fStatusFTM.second<FTM::kConnected)
308 return kStateDisconnected;
309
310 // At least one subsystem is not connected
311 // if (fStatusFTM.second>=FTM::kConnected)
312 return fTriggerOn ? kStateInProgress : kStateConnected;
313 }
314
315public:
316 StateMachineRateControl(ostream &out=cout) : StateMachineDim(out, "RATE_CONTROL"),
317 fStatusDim(make_pair(Time(), -2)),
318 fStatusFTM(make_pair(Time(), -2)),
319 fDim("DIS_DNS/VERSION_NUMBER", (void*)NULL, 0, this),
320 fFTM("FTM_CONTROL/STATE", (void*)NULL, 0, this),
321 fRates("FTM_CONTROL/TRIGGER_RATES", (void*)NULL, 0, this),
322 fStatic("FTM_CONTROL/STATIC_DATA", (void*)NULL, 0, this)/*,
323 fDimData("RATE_SCAN/DATA", "I:1;F:1;F:1;F:1;F:40;F:160", ""),
324 fDimProc("RATE_SCAN/PROCESS_DATA", "I:1;I:1;I:1",
325 "Rate scan process data"
326 "|min[DAC]:Value at which scan was started"
327 "|max[DAC]:Value at which scan will end"
328 "|step[DAC]:Step size for scan")*/,
329 fTriggerOn(false)
330 {
331 // ba::io_service::work is a kind of keep_alive for the loop.
332 // It prevents the io_service to go to stopped state, which
333 // would prevent any consecutive calls to run()
334 // or poll() to do nothing. reset() could also revoke to the
335 // previous state but this might introduce some overhead of
336 // deletion and creation of threads and more.
337
338 // State names
339 AddStateName(kStateDimNetworkNA, "DimNetworkNotAvailable",
340 "The Dim DNS is not reachable.");
341
342 AddStateName(kStateDisconnected, "Disconnected",
343 "The Dim DNS is reachable, but the required subsystems are not available.");
344
345 AddStateName(kStateConnected, "Connected",
346 "All needed subsystems are connected to their hardware, no action is performed.");
347
348 AddStateName(kStateInProgress, "InProgress",
349 "Rate scan in progress.");
350
351// AddEvent("STOP", kStateInProgress)
352// (bind(&StateMachineRateControl::StopRateControl, this))
353// ("Stop a ratescan in progress");
354
355 AddEvent("PRINT")
356 (bind(&StateMachineRateControl::Print, this))
357 ("");
358 }
359
360 int EvalOptions(Configuration &conf)
361 {
362 /*
363 fSecondsMax = conf.Get<uint16_t>("max-wait");
364 fResolution = conf.Get<double>("resolution");
365 */
366 return -1;
367 }
368};
369
370// ------------------------------------------------------------------------
371
372#include "Main.h"
373
374template<class T>
375int RunShell(Configuration &conf)
376{
377 return Main::execute<T, StateMachineRateControl>(conf);
378}
379
380void SetupConfiguration(Configuration &conf)
381{
382 /*
383 po::options_description control("Rate scan options");
384 control.add_options()
385 ("max-wait", var<uint16_t>(150), "The maximum number of seconds to wait to get the anticipated resolution for a point.")
386 ("resolution", var<double>(0.05) , "The minimum resolution required for a single data point.")
387 ;
388
389 conf.AddOptions(control);*/
390}
391
392/*
393 Extract usage clause(s) [if any] for SYNOPSIS.
394 Translators: "Usage" and "or" here are patterns (regular expressions) which
395 are used to match the usage synopsis in program output. An example from cp
396 (GNU coreutils) which contains both strings:
397 Usage: cp [OPTION]... [-T] SOURCE DEST
398 or: cp [OPTION]... SOURCE... DIRECTORY
399 or: cp [OPTION]... -t DIRECTORY SOURCE...
400 */
401void PrintUsage()
402{
403 cout <<
404 "The ratescan program is a tool for automation of rate scans.\n"
405 "\n"
406 "Usage: ratescan [-c type] [OPTIONS]\n"
407 " or: ratescan [OPTIONS]\n";
408 cout << endl;
409}
410
411void PrintHelp()
412{
413 Main::PrintHelp<StateMachineRateControl>();
414
415 /* Additional help text which is printed after the configuration
416 options goes here */
417
418 /*
419 cout << "bla bla bla" << endl << endl;
420 cout << endl;
421 cout << "Environment:" << endl;
422 cout << "environment" << endl;
423 cout << endl;
424 cout << "Examples:" << endl;
425 cout << "test exam" << endl;
426 cout << endl;
427 cout << "Files:" << endl;
428 cout << "files" << endl;
429 cout << endl;
430 */
431}
432
433int main(int argc, const char* argv[])
434{
435 Configuration conf(argv[0]);
436 conf.SetPrintUsage(PrintUsage);
437 Main::SetupConfiguration(conf);
438 SetupConfiguration(conf);
439
440 if (!conf.DoParse(argc, argv, PrintHelp))
441 return -1;
442
443 //try
444 {
445 // No console access at all
446 if (!conf.Has("console"))
447 {
448// if (conf.Get<bool>("no-dim"))
449// return RunShell<LocalStream, StateMachine, ConnectionFSC>(conf);
450// else
451 return RunShell<LocalStream>(conf);
452 }
453 // Cosole access w/ and w/o Dim
454/* if (conf.Get<bool>("no-dim"))
455 {
456 if (conf.Get<int>("console")==0)
457 return RunShell<LocalShell, StateMachine, ConnectionFSC>(conf);
458 else
459 return RunShell<LocalConsole, StateMachine, ConnectionFSC>(conf);
460 }
461 else
462*/ {
463 if (conf.Get<int>("console")==0)
464 return RunShell<LocalShell>(conf);
465 else
466 return RunShell<LocalConsole>(conf);
467 }
468 }
469 /*catch (std::exception& e)
470 {
471 cerr << "Exception: " << e.what() << endl;
472 return -1;
473 }*/
474
475 return 0;
476}
Note: See TracBrowser for help on using the repository browser.