source: trunk/FACT++/src/EventBuilderWrapper.h@ 18623

Last change on this file since 18623 was 18617, checked in by tbretz, 9 years ago
This looks like a solution. I start a second detached thread which does nothing else than wait for the first to finish. In this way, it is joined and joinable returns 0 as soon as the thread has stopped execution.
File size: 49.5 KB
Line 
1#ifndef FACT_EventBuilderWrapper
2#define FACT_EventBuilderWrapper
3
4#include <sstream>
5
6#if BOOST_VERSION < 104400
7#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 4))
8#undef BOOST_HAS_RVALUE_REFS
9#endif
10#endif
11#include <boost/thread.hpp>
12#include <boost/filesystem.hpp>
13#include <boost/date_time/posix_time/posix_time_types.hpp>
14
15#include "DimWriteStatistics.h"
16
17#include "DataCalib.h"
18#include "DataWriteRaw.h"
19
20#ifdef HAVE_FITS
21#include "DataWriteFits.h"
22#else
23#define DataWriteFits DataWriteFits2
24#endif
25
26#include "DataWriteFits2.h"
27
28namespace ba = boost::asio;
29namespace bs = boost::system;
30namespace fs = boost::filesystem;
31
32using ba::ip::tcp;
33
34using namespace std;
35
36// ========================================================================
37
38#include "EventBuilder.h"
39
40void StartEvtBuild();
41void CloseRunFile();
42
43// ========================================================================
44
45class EventBuilderWrapper
46{
47public:
48 // FIXME
49 static EventBuilderWrapper *This;
50
51 MessageImp &fMsg;
52
53private:
54 boost::thread fThreadMain;
55
56 enum
57 {
58 kCurrent = 0,
59 kTotal = 1,
60 kEventId = 2,
61 kTriggerId = 3,
62 };
63
64 FAD::FileFormat_t fFileFormat;
65
66 //uint32_t fMaxRun;
67 uint32_t fLastOpened;
68 uint32_t fLastClosed;
69 array<uint32_t,4> fNumEvts;
70
71 DimWriteStatistics fDimWriteStats;
72 DimDescribedService fDimRuns;
73 DimDescribedService fDimEvents;
74 DimDescribedService fDimTrigger;
75 DimDescribedService fDimRawData;
76 DimDescribedService fDimEventData;
77 DimDescribedService fDimFeedbackData;
78 DimDescribedService fDimFwVersion;
79 DimDescribedService fDimRunNumber;
80 DimDescribedService fDimStatus;
81 DimDescribedService fDimDNA;
82 DimDescribedService fDimTemperature;
83 DimDescribedService fDimPrescaler;
84 DimDescribedService fDimRefClock;
85 DimDescribedService fDimRoi;
86 DimDescribedService fDimDac;
87 DimDescribedService fDimDrsRuns;
88 DimDescribedService fDimDrsCalibration;
89 DimDescribedService fDimStatistics1;
90 //DimDescribedService fDimStatistics2;
91 DimDescribedService fDimFileFormat;
92 DimDescribedService fDimIncomplete;
93
94 Queue<pair<Time,GUI_STAT>> fQueueStatistics1;
95 Queue<tuple<Time,bool,FAD::EventHeader>> fQueueProcHeader;
96 Queue<pair<Time,array<uint32_t,4>>> fQueueEvents;
97 Queue<tuple<Time,char,array<uint32_t,8>>> fQueueTrigger;
98 Queue<pair<Time,array<uint16_t,2>>> fQueueRoi;
99 Queue<vector<char>> fQueueRawData;
100 Queue<tuple<Time,uint32_t,array<float,1440*4>>> fQueueEventData;
101 Queue<tuple<Time, array<uint32_t,40>, array<int16_t,160>>> fQueueTempRefClk;
102
103 string fPath;
104 uint32_t fNightAsInt;
105 uint32_t fRunNumber;
106 int64_t fRunInProgress;
107
108 array<uint16_t,2> fVecRoi;
109 pair<float,array<float, 1440*4>> fMaxEvent; // Maximum event from applyCalib
110
111protected:
112 bool InitRunNumber(const string &path="")
113 {
114 if (!path.empty())
115 {
116 if (!DimWriteStatistics::DoesPathExist(path, fMsg))
117 {
118 fMsg.Error("Data path "+path+" does not exist!");
119 return false;
120 }
121
122 fPath = path;
123 fDimWriteStats.SetCurrentFolder(fPath);
124
125 fMsg.Info("Data path set to "+path+".");
126 }
127
128 // Get current night
129 const Time now;
130
131 const uint32_t night = now.NightAsInt();
132 if (night==fNightAsInt)
133 return true;
134
135 const string crosscheck = now.GetPrevSunRise().GetAsStr("%Y%m%d");
136 if (crosscheck!=to_string(night))
137 {
138 fMsg.Warn("The crosscheck for the night failed. "+crosscheck+" is not equal to "+to_string(night)+"... keeping old one.");
139 fMsg.Warn("This is a severe error. Please restart fadctrl.");
140 return true;
141 }
142
143 // In some circumstances, I do not understand yet (but I guess it can happen
144 // when the shared objects are re-compiled while the program is not
145 // re-started), it can happen that the returned value is wrong by one day.
146 // So this is just another check to avoid problems.
147 const uint32_t night_test = Time(now-boost::posix_time::seconds(1)).NightAsInt();
148 if (night_test != night)
149 return true;
150
151 // And another check. Let's read the clock again.
152 // In both cases a false condition is no error and can happen. But if it happens,
153 // the bahaviour will change a fraction of a second later and the conditon
154 // will be true. No run should be taken just around that moment and if one
155 // is taken, then the date doesn't matter.
156 if (Time().NightAsInt() != night)
157 return true;
158
159 if (night<fNightAsInt)
160 {
161 fMsg.Warn("New night "+to_string(night)+" ["+now.GetAsStr()+"] before current night "+to_string(night)+"... keeping old one.");
162 fMsg.Warn("Please check the system clock.");
163 return true;
164 }
165
166 // Check for run numbers
167 fRunNumber = 1000;
168
169 while (--fRunNumber>0)
170 {
171 const string name = DataProcessorImp::FormFileName(fPath, night, fRunNumber, "");
172
173 if (access((name+"bin").c_str(), F_OK) == 0)
174 break;
175 if (access((name+"fits").c_str(), F_OK) == 0)
176 break;
177 if (access((name+"fits.fz").c_str(), F_OK) == 0)
178 break;
179 if (access((name+"fits.gz").c_str(), F_OK) == 0)
180 break;
181 if (access((name+"drs.fits").c_str(), F_OK) == 0)
182 break;
183 }
184
185 // This is now the first file which does not exist
186 fRunNumber++;
187 fLastOpened = 0;
188
189 // Check if we have exceeded the maximum
190 if (fRunNumber==1000)
191 {
192 fMsg.Error("You have a file with run-number 1000 in "+fPath+" ["+to_string(night)+"]");
193 return false;
194 }
195
196 ostringstream str;
197 if (fNightAsInt==0)
198 str << "First night...";
199 else
200 str << "Night has changed from " << fNightAsInt << " [" << now << "]... ";
201 str << " next run-number is " << night << "-" << setfill('0') << setw(3) << fRunNumber << " [" << (fPath.empty()?".":fPath) << "]";
202 fMsg.Message(str);
203
204 fNightAsInt = night;
205
206 return true;
207 }
208
209public:
210 EventBuilderWrapper(MessageImp &imp) : fMsg(imp),
211 fFileFormat(FAD::kNone), /*fMaxRun(0),*/ fLastOpened(0), fLastClosed(0),
212 fDimWriteStats ("FAD_CONTROL", imp),
213 fDimRuns ("FAD_CONTROL/RUNS", "I:2;C",
214 "Run files statistics"
215 "|stats[int]:last opened or closed run"
216 "|file[string]:filename of last opened file"),
217 fDimEvents ("FAD_CONTROL/EVENTS", "I:4",
218 "Event counts"
219 "|evtsCount[int]:Num evts cur. run, total (all run), evt ID, trig. Num"),
220 fDimTrigger ("FAD_CONTROL/TRIGGER_COUNTER", "I:1;I:1;I:1;I:1;I:1;I:1;I:1;I:1",
221 "Trigger counter"
222 "|N_trg[uint32]:Number of physics triggers"
223 "|N_ped[uint32]:Number of pure pedestal triggers"
224 "|N_lpe[uint32]:Number of external light pulser triggers"
225 "|N_tim[uint32]:Number of time calibration triggers"
226 "|N_lpi[uint32]:Number of internal light pulser triggers"
227 "|N_ext1[uint32]:Number of external triggers at input ext1"
228 "|N_ext2[uint32]:Number of external triggers at input ext2"
229 "|N_misc[uint32]:Number of all other triggers"),
230 fDimRawData ("FAD_CONTROL/RAW_DATA", "S:1;S:1;I:1;I:1;S:1;I:1;I:2;I:40;S:1440;S:160;F",
231 "|roi[uint16]:number of samples per pixel"
232 "|roi_tm[uint16]:number of samples per time-marker channel"
233 "|num_fad[uint32]:event number from FADs"
234 "|num_ftm[uint32]:trigger number from FTM"
235 "|type[uint16]:trigger type from FTM"
236 "|num_boards[uint32]:number of active boards"
237 "|time[uint32]:PC time as unix time stamp"
238 "|time_board[uint32]:Time stamp of FAD boards"
239 "|start_pix[int16]:start sample of pixels"
240 "|start_tm[int16]:start sample of time marker channels"
241 "|adc[int16]:adc data"),
242 fDimEventData ("FAD_CONTROL/EVENT_DATA", "F:1440;F:1440;F:1440;F:1440", "|avg:|rms:|max:|pos"),
243 fDimFeedbackData("FAD_CONTROL/FEEDBACK_DATA", "F:1440", ""),
244 fDimFwVersion ("FAD_CONTROL/FIRMWARE_VERSION", "F:42",
245 "Firmware version number of fad boards"
246 "|firmware[float]:Version number of firmware, for each board. 40=min, 41=max"),
247 fDimRunNumber ("FAD_CONTROL/RUN_NUMBER", "I:42",
248 "Run numbers coming from FAD boards"
249 "|runNumbers[int]:current run number of each FAD board. 40=min, 41=max"),
250 fDimStatus ("FAD_CONTROL/STATUS", "S:42",
251 "Status of FAD boards"
252 "|status[bitpattern]:Status of each FAD board. Maybe buggy"),
253 fDimDNA ("FAD_CONTROL/DNA", "X:40",
254 "DNA of FAD boards"
255 "|DNA[hex]:Hex identifier of each FAD board"),
256 fDimTemperature ("FAD_CONTROL/TEMPERATURE", "S:1;F:160",
257 "DRS temperatures"
258 "|cnt[uint16]:Counter of averaged values"
259 "|temp[deg C]:average temp of all DRS chips"),
260 fDimPrescaler ("FAD_CONTROL/PRESCALER", "S:42",
261 "Trigger generator prescaler of fad boards"
262 "|prescaler[int]:Trigger generator prescaler value, for each board"),
263 fDimRefClock ("FAD_CONTROL/REFERENCE_CLOCK", "S:1;F:40",
264 "Reference clock of FAD boards"
265 "|cnt[uint16]:Counter of averaged values"
266 "|clk[Hz]:Averaged clock of ref clocks of FAD boards"),
267 fDimRoi ("FAD_CONTROL/REGION_OF_INTEREST", "S:2", "roi:|roi_rm:"),
268 fDimDac ("FAD_CONTROL/DAC", "S:336",
269 "DAC settings of each FAD board"
270 "|DAC[int]:DAC counts, sequentially DAC 0 board 0, 0/1, 0/2... (plus min max)"),
271 fDimDrsRuns ("FAD_CONTROL/DRS_RUNS", "I:1;I:3;I:1",
272 "|roi:Region of interest of secondary baseline"
273 "|run:Run numbers of DRS runs (0=none)"
274 "|night:Night as int of the first run (0 if none)"),
275 fDimDrsCalibration("FAD_CONTROL/DRS_CALIBRATION", "I:1;I:3;F:1474560;F:1474560;F:1474560;F:1474560;F:1474560;F:1474560;F:163840;F:163840",
276 "|roi:Region of interest of secondary baseline"
277 "|run:Run numbers of DRS runs (0=none)"),
278 fDimStatistics1 ("FAD_CONTROL/STATISTICS1", "I:5;X:3;I:1;I:2;C:40;I:40;I:40",
279 "Event Builder status for GUI display"
280 "|bufferInfo[int]:Events in buffer, incomp., comp., write, proc., tot."
281 "|memInfo[int]:total mem allocated, used mem, max memory"
282 "|deltaT[ms]:Time in ms for rates"
283 "|rateNew[int]:Number of new start events received"
284 "|numConn[int]:Number of connections per board"
285 "|rateBytes[int]:Bytes read during last cylce"
286 "|relBytes[int]:Relative number of total bytes received (received - released)"),
287 fDimFileFormat("FAD_CONTROL/FILE_FORMAT", "S:1", "|format[int]:Current file format"),
288 fDimIncomplete("FAD_CONTROL/INCOMPLETE", "X:1", "|incomplete[bits]:bit_index=c*10+b. board b(0..3) in crate c(0..9)"),
289 // It is important to instantiate them after the DimServices
290 fQueueStatistics1(std::bind(&EventBuilderWrapper::UpdateDimStatistics1, this, placeholders::_1)),
291 fQueueProcHeader( std::bind(&EventBuilderWrapper::procHeader, this, placeholders::_1)),
292 fQueueEvents( std::bind(&EventBuilderWrapper::UpdateDimEvents, this, placeholders::_1)),
293 fQueueTrigger( std::bind(&EventBuilderWrapper::UpdateDimTrigger, this, placeholders::_1)),
294 fQueueRoi( std::bind(&EventBuilderWrapper::UpdateDimRoi, this, placeholders::_1)),
295 fQueueRawData( std::bind(&EventBuilderWrapper::UpdateDimRawData, this, placeholders::_1)),
296 fQueueEventData( std::bind(&EventBuilderWrapper::UpdateDimEventData, this, placeholders::_1)),
297 fQueueTempRefClk( std::bind(&EventBuilderWrapper::UpdateDimTempRefClk, this, placeholders::_1)),
298 fNightAsInt(0), fRunInProgress(-1),
299 fMaxEvent(make_pair(-FLT_MAX, array<float,1440*4>()))
300 {
301 if (This)
302 throw logic_error("EventBuilderWrapper cannot be instantiated twice.");
303
304 This = this;
305
306 fVecRoi.fill(0);
307
308 memset(fNumEvts.data(), 0, sizeof(fNumEvts));
309 fDimEvents.Update(fNumEvts);
310
311 for (size_t i=0; i<40; i++)
312 ConnectSlot(i, tcp::endpoint());
313 }
314
315 virtual ~EventBuilderWrapper()
316 {
317 Abort();
318
319 // FIXME: Used timed_join and abort afterwards
320 // What's the maximum time the eb need to abort?
321 fThreadMain.join();
322 }
323
324 map<uint32_t, FAD::RunDescription> fExpectedRuns;
325
326 mutex mtx_newrun;
327
328 uint32_t StartNewRun(int64_t maxtime, int64_t maxevt, const pair<string, FAD::Configuration> &ref)
329 {
330 if (maxtime<=0 || maxtime>24*60*60)
331 maxtime = 24*60*60;
332 if (maxevt<=0 || maxevt>INT32_MAX)
333 maxevt = INT32_MAX;
334
335 if (!InitRunNumber())
336 return 0;
337
338 const FAD::RunDescription descr =
339 {
340 uint32_t(maxtime),
341 uint32_t(maxevt),
342 fNightAsInt,
343 ref.first,
344 ref.second,
345 };
346
347 const lock_guard<mutex> lock(mtx_newrun);
348 fExpectedRuns[fRunNumber] = descr;
349 return fRunNumber++;
350 }
351
352 bool IsThreadRunning()
353 {
354 return fThreadMain.joinable();
355 }
356
357 void SetMaxMemory(unsigned int mb) const
358 {
359 g_maxMem = size_t(mb)*1000000;
360 }
361 void SetEventTimeout(uint16_t to) const
362 {
363 g_evtTimeout = to;
364 }
365
366 void StartThread(const vector<tcp::endpoint> &addr)
367 {
368 if (IsThreadRunning())
369 {
370 fMsg.Warn("Start - EventBuilder still running");
371 return;
372 }
373
374 //fLastMessage.clear();
375
376 for (size_t i=0; i<40; i++)
377 ConnectSlot(i, addr[i]);
378
379 fMsg.Message("Starting EventBuilder thread");
380
381 fThreadMain = boost::thread(StartEvtBuild);
382
383 // Run a detached thread which ensures that our thread
384 // is joined so that it is not joinable anymore once
385 // it is finished (I think this is similar to
386 // boost::thread_guard, but I could not figure out
387 // how it works)
388 std::thread([this] { this->fThreadMain.join(); }).detach();
389 }
390
391 void ConnectSlot(unsigned int i, const tcp::endpoint &addr)
392 {
393 if (i>39)
394 return;
395
396 fRunInProgress = -1;
397
398 if (addr==tcp::endpoint())
399 {
400 // In this order
401 g_port[i].sockDef = 0;
402
403 fDimIncomplete.setQuality(0);
404 fDimIncomplete.Update(uint64_t(0));
405 return;
406 }
407
408 struct sockaddr_in sockaddr; //IP for each socket
409 sockaddr.sin_family = AF_INET;
410 sockaddr.sin_addr.s_addr = htonl(addr.address().to_v4().to_ulong());
411 sockaddr.sin_port = htons(addr.port());
412 memcpy(&g_port[i].sockAddr, &sockaddr, sizeof(struct sockaddr_in));
413
414 // In this order
415 g_port[i].sockDef = 1;
416
417 fDimIncomplete.setQuality(0);
418 fDimIncomplete.Update(uint64_t(0));
419 }
420
421 void IgnoreSlot(unsigned int i)
422 {
423 if (i>39)
424 return;
425
426 if (g_port[i].sockAddr.sin_port==0)
427 return;
428
429 g_port[i].sockDef = -1;
430 }
431
432
433 void Abort()
434 {
435 fMsg.Message("Signal abort to EventBuilder thread...");
436 g_reset = 2;
437 }
438
439 void ResetThread(bool soft)
440 {
441 fMsg.Message("Signal reset to EventBuilder thread...");
442 g_reset = soft ? 101 : 102;
443 }
444
445 void Exit()
446 {
447 fMsg.Message("Signal exit to EventBuilder thread...");
448 g_reset = 1;
449 }
450
451 bool IsConnected(int i) const { return gi_NumConnect[i]==1; }
452 bool IsConnecting(int i) const { return gi_NumConnect[i]==0 && g_port[i].sockDef!=0; }
453 bool IsDisconnected(int i) const { return gi_NumConnect[i]==0 && g_port[i].sockDef==0; }
454 bool IsRunInProgress() const { return fRunInProgress>=0; }
455
456 void SetIgnore(int i, bool b) const { if (g_port[i].sockDef!=0) g_port[i].sockDef=b?-1:1; }
457 bool IsIgnored(int i) const { return g_port[i].sockDef==-1; }
458
459 void SetOutputFormat(FAD::FileFormat_t f)
460 {
461 const bool changed = f!=fFileFormat;
462
463 fFileFormat = f;
464 fDimFileFormat.Update(uint16_t(f));
465
466 string msg = "File format set to: ";
467 switch (f)
468 {
469 case FAD::kNone: msg += "kNone."; break;
470 case FAD::kDebug: msg += "kDebug."; break;
471 case FAD::kFits: msg += "kFits."; break;
472 case FAD::kZFits: msg += "kZFits."; break;
473 case FAD::kCfitsio: msg += "kCfitsio"; break;
474 case FAD::kRaw: msg += "kRaw"; break;
475 case FAD::kCalib:
476 DataCalib::Restart();
477 DataCalib::Update(fDimDrsCalibration, fDimDrsRuns);
478 fMsg.Message("Resetted DRS calibration.");
479 return;
480 }
481
482 if (changed)
483 fMsg.Message(msg);
484 }
485
486 virtual int ResetSecondaryDrsBaseline()
487 {
488 if (DataCalib::ResetTrgOff(fDimDrsCalibration, fDimDrsRuns))
489 {
490 fFileFormat = FAD::kCalib;
491 fDimFileFormat.Update(uint16_t(fFileFormat));
492 fMsg.Message("Resetted DRS calibration for secondary baseline.");
493 }
494 else
495 fMsg.Warn("Could not reset DRS calibration of secondary baseline.");
496
497 return 0;
498 }
499
500 void LoadDrsCalibration(const char *fname)
501 {
502 if (!DataCalib::ReadFits(fname, fMsg))
503 return;
504
505 fMsg.Info("Successfully loaded DRS calibration from "+string(fname));
506 DataCalib::Update(fDimDrsCalibration, fDimDrsRuns);
507 }
508
509 virtual int CloseOpenFiles() { CloseRunFile(); fRunInProgress = -1; return 0; }
510
511
512 // -------------- Mapped event builder callbacks ------------------
513
514 void UpdateRuns(const string &fname="")
515 {
516 uint32_t values[2] =
517 {
518 fLastOpened,
519 fLastClosed
520 };
521
522 vector<char> data(sizeof(values)+fname.size()+1);
523 memcpy(data.data(), values, sizeof(values));
524 strcpy(data.data()+sizeof(values), fname.c_str());
525 fDimRuns.setQuality((bool)fFile);
526 fDimRuns.Update(data);
527
528 if (!fname.empty())
529 fDimWriteStats.FileOpened(fname);
530 }
531
532 shared_ptr<DataProcessorImp> fFile;
533
534 bool UpdateDimEvents(const pair<Time,array<uint32_t,4>> &stat)
535 {
536 fDimEvents.setData(stat.second.data(), sizeof(uint32_t)*4);
537 fDimEvents.Update(stat.first);
538 return true;
539 }
540
541 bool UpdateDimTrigger(const tuple<Time,char,array<uint32_t,8>> &stat)
542 {
543 fDimTrigger.setQuality(get<1>(stat));
544 fDimTrigger.setData(get<2>(stat).data(), sizeof(uint32_t)*8);
545 fDimTrigger.Update(get<0>(stat));
546 return true;
547 }
548
549 bool runOpen(const EVT_CTRL2 &evt)
550 {
551 const uint32_t night = evt.runCtrl->night;
552 const uint32_t runid = evt.runNum>0 ? evt.runNum : time(NULL);
553
554 // If there is still an open file: close it
555 if (fFile)
556 runClose(evt);
557
558 // Keep a copy of the currently valid drs calibration
559 // and associate it to the run control structure
560 evt.runCtrl->calib = make_shared<DrsCalibration>(DataCalib::GetCalibration());
561
562 // Crate the file
563 DataProcessorImp *file = 0;
564 switch (fFileFormat)
565 {
566 case FAD::kNone: file = new DataDump(fPath, night, runid, fMsg); break;
567 case FAD::kDebug: file = new DataDebug(fPath, night, runid, fMsg); break;
568 case FAD::kCfitsio: file = new DataWriteFits(fPath, night, runid, fMsg); break;
569 case FAD::kFits: file = new DataWriteFits2(fPath, night, runid, fMsg); break;
570 case FAD::kZFits: file = new DataWriteFits2(fPath, night, runid, *evt.runCtrl->calib, fMsg); break;
571 case FAD::kRaw: file = new DataWriteRaw(fPath, night, runid, fMsg); break;
572 case FAD::kCalib: file = new DataCalib(fPath, night, runid, *evt.runCtrl->calib, fDimDrsCalibration, fDimDrsRuns, fMsg); break;
573 }
574
575 try
576 {
577 // Try to open the file
578 FAD::RunDescription desc;
579 desc.maxevt = evt.runCtrl->maxEvt;
580 desc.maxtime = evt.runCtrl->closeTime - evt.runCtrl->openTime;
581 desc.name = evt.runCtrl->runType;
582
583 if (!file->Open(evt, desc))
584 return false;
585 }
586 catch (const exception &e)
587 {
588 fMsg.Error("Exception trying to open file: "+string(e.what()));
589 return false;
590 }
591
592 fLastOpened = runid;
593
594 // Signal that a file is open
595 fFile = shared_ptr<DataProcessorImp>(file);
596
597 // Now do all the calls which potentially block (dim)
598
599 // Time for update runs before time for update events
600 UpdateRuns(file->GetFileName());
601 fNumEvts[kEventId] = 0;
602 fNumEvts[kTriggerId] = 0;
603 fNumEvts[kCurrent] = 0;
604
605 const Time time;
606
607 fQueueEvents.emplace(time, fNumEvts);
608 fQueueTrigger.emplace(time, 'o', evt.triggerCounter);
609
610 ostringstream str;
611 str << "Opened: " << file->GetFileName() << " (" << file->GetRunId() << ")";
612 fMsg.Info(str);
613
614 return true;
615 }
616
617 bool runWrite(const EVT_CTRL2 &e)
618 {
619 /*
620 const size_t size = sizeof(EVENT)+1440*(evt.Roi+evt.RoiTM)*2;
621 vector evt(e.fEvent, e.fEvent+size);
622
623 const EVENT &evt = *reinterpret_cast<EVENT*>(evt.data());
624
625 int16_t *val = evt.Adc_Data;
626 const int16_t *off = e.runCtrl->zcalib.data();
627 for (const int16_t *start=evt.StartPix; start<evt.StartPix+1440; val+=1024, off+=1024, start++)
628 {
629 if (*start<0)
630 continue;
631
632 for (size_t i=0; i<roi; i++)
633 val[i] -= offset[(*start+i)%1024];
634 }*/
635
636 if (!fFile->WriteEvt(e))
637 return false;
638
639 //const EVENT &evt = *e.fEvent;
640
641 fNumEvts[kCurrent]++;
642 fNumEvts[kEventId] = e.evNum;//evt.EventNum;
643 fNumEvts[kTriggerId] = e.trgNum;//evt.TriggerNum;
644 fNumEvts[kTotal]++;
645
646 static Time oldt(boost::date_time::neg_infin);
647 Time newt;
648 if (newt>oldt+boost::posix_time::seconds(1))
649 {
650 fQueueEvents.emplace(newt, fNumEvts);
651 fQueueTrigger.emplace(newt, 'w', e.triggerCounter);
652 oldt = newt;
653 }
654
655 return true;
656 }
657
658 void runClose(const EVT_CTRL2 &evt)
659 {
660 if (!fFile)
661 return;
662
663 // It can happen that runFinished was never called
664 // (e.g. runWrite failed)
665 if (fRunInProgress==fFile->GetRunId())
666 fRunInProgress = -1;
667
668 // Close the file
669 const bool rc = fFile->Close(evt);
670
671 fLastClosed = fFile->GetRunId();
672
673 ostringstream str;
674 str << "Closed: " << fFile->GetFileName() << " (" << fFile->GetRunId() << ")";
675 if (!rc)
676 str << "... failed!";
677
678 // Signal that the file is closed
679
680 fFile.reset();
681
682 // Now do all the calls which can potentially block (dim)
683
684 CloseRun(fLastClosed);
685
686 // Time for update events before time for update runs
687 const Time time;
688
689 fQueueEvents.emplace(time, fNumEvts);
690 fQueueTrigger.emplace(time, 'c', evt.triggerCounter);
691
692 UpdateRuns();
693
694 // Do the potentially blocking call after all others
695 rc ? fMsg.Info(str) : fMsg.Error(str);
696
697 // If a Drs Calibration has just been finished, all following events
698 // should also be processed with this calibration.
699 // Note that this is a generally dangerous operation. Here, the previous
700 // DRS calibration shared_ptr gets freed and if it is the last in use,
701 // the memory will vanish. If another thread accesses that pointer,
702 // it _must_ make a copy of the shared_ptr first to ensure that
703 // the memory will stay in scope until the end of its operation.
704 const DrsCalibration &cal = DataCalib::GetCalibration();
705
706 RUN_CTRL2 &run = *evt.runCtrl;
707 if (!run.calib || run.calib->fStep != cal.fStep || run.calib->fRoi!=cal.fRoi)
708 run.calib = make_shared<DrsCalibration>(cal);
709 }
710
711 virtual void CloseRun(uint32_t /*runid*/) { }
712
713 bool UpdateDimRoi(const pair<Time, array<uint16_t,2>> &roi)
714 {
715 fDimRoi.setData(roi.second.data(), sizeof(uint16_t)*2);
716 fDimRoi.Update(roi.first);
717 return true;
718 }
719
720 bool UpdateDimTempRefClk(const tuple<Time, array<uint32_t,40>, array<int16_t,160>> &dat)
721 {
722 const auto delay = boost::posix_time::seconds(5);
723
724 const Time &tm = get<0>(dat);
725
726 const array<uint32_t,40> &clk = get<1>(dat);
727 const array<int16_t,160> &tmp = get<2>(dat);
728
729 // --------------- RefClock ---------------
730
731 // history, add current data to history
732 static list<pair<Time,array<uint32_t,40>>> listclk;
733 listclk.emplace_back(tm, clk);
734
735 // --------------- Temperatures ---------------
736
737 // history, add current data to history
738 static list<pair<Time,array<int16_t,160>>> listtmp;
739 listtmp.emplace_back(tm, tmp);
740
741 // ========== Update dim services once a second =========
742
743 static Time oldt(boost::date_time::neg_infin);
744 Time newt;
745
746 if (newt<oldt+delay)
747 return true;
748
749 oldt = newt;
750
751 // --------------- RefClock ---------------
752
753 // remove expired data from history
754 while (1)
755 {
756 auto it=listclk.begin();
757 if (it==listclk.end() || it->first+delay>tm)
758 break;
759 listclk.pop_front();
760 }
761
762 // Structure for dim service
763 struct Clock
764 {
765 uint16_t num;
766 float val[40];
767 Clock() { memset(this, 0, sizeof(Clock)); }
768 } __attribute__((__packed__));
769
770 // Calculate average and fll structure
771 vector<uint16_t> clknum(40);
772
773 Clock avgclk;
774 avgclk.num = listclk.size();
775 for (auto it=listclk.begin(); it!=listclk.end(); it++)
776 for (int i=0; i<40; i++)
777 if (it->second[i]!=UINT32_MAX)
778 {
779 avgclk.val[i] += it->second[i];
780 clknum[i]++;
781 }
782 for (int i=0; i<40; i++)
783 avgclk.val[i] *= 2.048/clknum[i];
784
785 // Update dim service
786 fDimRefClock.setData(avgclk);
787 fDimRefClock.Update(tm);
788
789 listclk.clear();
790
791 // --------------- Temperatures ---------------
792
793 // remove expired data from history
794 while (1)
795 {
796 auto it=listtmp.begin();
797 if (it==listtmp.end() || it->first+delay>tm)
798 break;
799 listtmp.pop_front();
800 }
801
802 // Structure for dim service
803 struct Temp
804 {
805 uint16_t num;
806 float val[160];
807 Temp() { memset(this, 0, sizeof(Temp)); }
808 } __attribute__((__packed__));
809
810 // Calculate average and fll structure
811 vector<uint32_t> tmpnum(160);
812
813 Temp avgtmp;
814 avgtmp.num = listtmp.size();
815 for (auto it=listtmp.begin(); it!=listtmp.end(); it++)
816 for (int i=0; i<160; i++)
817 if (it->second[i]!=INT16_MIN)
818 {
819 avgtmp.val[i] += it->second[i];
820 tmpnum[i]++;
821 }
822 for (int i=0; i<160; i++)
823 avgtmp.val[i] /= tmpnum[i]*16;
824
825 // Update dim service
826 fDimTemperature.setData(avgtmp);
827 fDimTemperature.Update(tm);
828
829 listtmp.clear();
830
831 return true;
832 }
833
834 bool eventCheck(const EVT_CTRL2 &evt)
835 {
836 const EVENT *event = evt.fEvent;
837
838 const Time tm(evt.time);
839
840 const array<uint16_t,2> roi = {{ event->Roi, event->RoiTM }};
841
842 if (roi!=fVecRoi)
843 {
844 fQueueRoi.emplace(tm, roi);
845 fVecRoi = roi;
846 }
847
848 const FAD::EventHeader *beg = reinterpret_cast<const FAD::EventHeader*>(evt.FADhead);
849 const FAD::EventHeader *end = reinterpret_cast<const FAD::EventHeader*>(evt.FADhead)+40;
850
851 // FIMXE: Compare with target configuration
852
853 // Copy data to array
854 array<uint32_t,40> clk;
855 array<int16_t,160> tmp;
856
857 for (int i=0; i<40; i++)
858 clk[i] = UINT32_MAX;
859
860 for (int i=0; i<160; i++)
861 tmp[i] = INT16_MIN;
862
863 //fill(clk.data(), clk.data()+ 40, UINT32_MAX);
864 //fill(tmp.data(), tmp.data()+160, INT16_MIN);
865
866 for (const FAD::EventHeader *ptr=beg; ptr!=end; ptr++)
867 {
868 // FIXME: Compare with expectations!!!
869 if (ptr->fStartDelimiter==0)
870 {
871 if (ptr==beg)
872 beg++;
873 continue;
874 }
875
876 clk[ptr->Id()] = ptr->fFreqRefClock;
877 for (int i=0; i<4; i++)
878 tmp[ptr->Id()*4+i] = ptr->fTempDrs[i];
879
880 if (beg->fStatus != ptr->fStatus)
881 {
882 fMsg.Error("Inconsistency in FAD status detected.... closing run.");
883 return false;
884 }
885
886 if (beg->fRunNumber != ptr->fRunNumber)
887 {
888 fMsg.Error("Inconsistent run number detected.... closing run.");
889 return false;
890 }
891
892 /*
893 if (beg->fVersion != ptr->fVersion)
894 {
895 Error("Inconsist firmware version detected.... closing run.");
896 CloseRunFile(runNr, 0, 0);
897 break;
898 }
899 */
900 if (beg->fEventCounter != ptr->fEventCounter)
901 {
902 fMsg.Error("Inconsistent FAD event number detected.... closing run.");
903 return false;
904 }
905
906 if (beg->fTriggerCounter != ptr->fTriggerCounter)
907 {
908 fMsg.Error("Inconsistent FTM trigger number detected.... closing run.");
909 return false;
910 }
911
912 // FIXME: Check with first event!
913 if (beg->fAdcClockPhaseShift != ptr->fAdcClockPhaseShift)
914 {
915 fMsg.Error("Inconsistent phase shift detected.... closing run.");
916 return false;
917 }
918
919 // FIXME: Check with first event!
920 if (memcmp(beg->fDac, ptr->fDac, sizeof(beg->fDac)))
921 {
922 fMsg.Error("Inconsistent DAC values detected.... closing run.");
923 return false;
924 }
925
926 if (beg->fTriggerType != ptr->fTriggerType)
927 {
928 fMsg.Error("Inconsistent trigger type detected.... closing run.");
929 return false;
930 }
931 }
932
933 // check REFCLK_frequency
934 // check consistency with command configuration
935 // how to log errors?
936 // need gotNewRun/closedRun to know it is finished
937
938 fQueueTempRefClk.emplace(tm, clk, tmp);
939
940 if (evt.runCtrl->fileStat == kFileClosed)
941 {
942 static Time oldt(boost::date_time::neg_infin);
943 if (tm>oldt+boost::posix_time::seconds(1))
944 {
945 fQueueTrigger.emplace(tm, 0, evt.runCtrl->triggerCounter);
946 oldt = tm;
947 }
948 }
949
950 return true;
951 }
952
953 Time fLastDimRawData;
954 Time fLastDimEventData;
955
956 bool UpdateDimRawData(const vector<char> &v)
957 {
958 const EVENT *evt = reinterpret_cast<const EVENT*>(v.data());
959
960 fDimRawData.setData(v);
961 fDimRawData.setQuality(evt->TriggerType);
962 fDimRawData.Update(Time(evt->PCTime, evt->PCUsec));
963
964 return true;
965 }
966
967 bool UpdateDimEventData(const tuple<Time,uint32_t,array<float, 1440*4>> &tup)
968 {
969 fDimEventData.setQuality(get<1>(tup));
970 fDimEventData.setData(get<2>(tup));
971 fDimEventData.Update(get<0>(tup));
972
973 return true;
974 }
975
976 void applyCalib(const EVT_CTRL2 &evt, const size_t &size)
977 {
978 const EVENT *event = evt.fEvent;
979 const int16_t *start = event->StartPix;
980
981 // Get the reference to the run associated information
982 RUN_CTRL2 &run = *evt.runCtrl;
983
984 if (size==1) // If there is more than one event waiting (including this one), throw them away
985 {
986 Time now;
987
988 // ------------------- Copy event data to new memory --------------------
989 // (to make it thread safe; a static buffer might improve memory handling)
990 const uint16_t roi = event->Roi;
991
992 // ------------------- Apply full DRS calibration ------------------------
993 // (Is that necessray, or would a simple offset correct do well already?)
994
995 // This is a very important step. Making a copy of the shared pointer ensures
996 // that another thread (here: runClose) can set a new shared_ptr with new
997 // data without this thread being affected. If we just did run.calib->Apply
998 // the shared_pointer in use here might vanash during the processing, the
999 // memory is freed and we access invalid memory. It is not important
1000 // which memory we acces (the old or the new one) because it is just for
1001 // display purpose anyway.
1002 const shared_ptr<DrsCalibration> cal = run.calib;
1003
1004 // There seems to be a problem using std::array... maybe the size is too big?
1005 // array<float, (1440+160)*1024> vec2;
1006 vector<float> vec((1440+160)*roi);
1007 cal->Apply(vec.data(), event->Adc_Data, start, roi);
1008
1009 // ------------------- Appy DRS-step correction --------------------------
1010 for (auto it=run.prevStart.begin(); it!=run.prevStart.end(); it++)
1011 {
1012 DrsCalibrate::CorrectStep(vec.data(), 1440, roi, it->data(), start, roi+10);
1013 DrsCalibrate::CorrectStep(vec.data(), 1440, roi, it->data(), start, 3);
1014 }
1015
1016 // ------------------------- Remove spikes --------------------------------
1017 DrsCalibrate::RemoveSpikes4(vec.data(), roi);
1018
1019 // -------------- Update raw data dim sevice (VERY SLOW) -----------------
1020 if (fQueueRawData.empty() && now>fLastDimRawData+boost::posix_time::seconds(5))
1021 {
1022 vector<char> data1(sizeof(EVENT)+vec.size()*sizeof(float));
1023 memcpy(data1.data(), event, sizeof(EVENT));
1024 memcpy(data1.data()+sizeof(EVENT), vec.data(), vec.size()*sizeof(float));
1025 fQueueRawData.emplace(data1);
1026
1027 fLastDimRawData = now;
1028 }
1029
1030 // ------------------------- Basic statistics -----------------------------
1031 DrsCalibrate::SlidingAverage(vec.data(), roi, 10);
1032
1033 // If this is a cosmic event
1034 array<float, 1440*4> stats; // Mean, RMS, Max, Pos
1035 const float max = DrsCalibrate::GetPixelStats(stats.data(), vec.data(), roi, 15, 5);
1036 if (evt.trgTyp==0 && max>fMaxEvent.first)
1037 fMaxEvent = make_pair(max, stats);
1038
1039 // ------------------ Update dim service (statistics) ---------------------
1040
1041 if (fQueueEventData.empty() && now>fLastDimEventData+boost::posix_time::milliseconds(4999))
1042 {
1043 fQueueEventData.emplace(evt.time, evt.trgTyp, evt.trgTyp==0 ? fMaxEvent.second : stats);
1044 if (evt.trgTyp==0)
1045 fMaxEvent.first = -FLT_MAX;
1046
1047 fLastDimEventData = now;
1048 }
1049
1050 // === SendFeedbackData(PEVNT_HEADER *fadhd, EVENT *event)
1051 //
1052 // if (!ptr->HasTriggerLPext() && !ptr->HasTriggerLPint())
1053 // return;
1054 //
1055 // vector<float> data2(1440); // Mean, RMS, Max, Pos, first, last
1056 // DrsCalibrate::GetPixelMax(data2.data(), data.data(), event->Roi, 0, event->Roi-1);
1057 //
1058 // fDimFeedbackData.Update(data2);
1059 }
1060
1061 // Keep the start cells of the last five events for further corrections
1062 // As a performance improvement we could also just store the
1063 // pointers to the last five events...
1064 // What if a new run is started? Do we mind?
1065 auto &l = run.prevStart; // History for start cells of previous events (for step calibration)
1066
1067 if (l.size()<5)
1068 l.emplace_front();
1069 else
1070 {
1071 auto it = l.end();
1072 l.splice(l.begin(), l, --it);
1073 }
1074
1075 memcpy(l.front().data(), start, 1440*sizeof(int16_t));
1076 }
1077
1078 bool IsRunWaiting()
1079 {
1080 const lock_guard<mutex> lock(mtx_newrun);
1081 return fExpectedRuns.find(fRunNumber-1)!=fExpectedRuns.end();
1082 }
1083
1084 uint32_t GetRunNumber() const
1085 {
1086 return fRunNumber;
1087 }
1088
1089 bool IncreaseRunNumber(uint32_t run)
1090 {
1091 if (!InitRunNumber())
1092 return false;
1093
1094 if (run<fRunNumber)
1095 {
1096 ostringstream msg;
1097 msg <<
1098 "Run number " << run << " smaller than next available "
1099 "run number " << fRunNumber << " in " << fPath << " [" << fNightAsInt << "]";
1100 fMsg.Error(msg);
1101 return false;
1102 }
1103
1104 fRunNumber = run;
1105
1106 return true;
1107 }
1108
1109 void gotNewRun(RUN_CTRL2 &run)
1110 {
1111 // This is to secure iteration over fExpectedRuns
1112 const lock_guard<mutex> lock(mtx_newrun);
1113
1114 map<uint32_t,FAD::RunDescription>::iterator it = fExpectedRuns.begin();
1115 while (it!=fExpectedRuns.end())
1116 {
1117 if (it->first<run.runId)
1118 {
1119 ostringstream str;
1120 str << "runOpen - Missed run " << it->first << ".";
1121 fMsg.Info(str);
1122
1123 // Increase the iterator first, it becomes invalid with the next call
1124 const auto is = it++;
1125 fExpectedRuns.erase(is);
1126 continue;
1127 }
1128
1129 if (it->first==run.runId)
1130 break;
1131
1132 it++;
1133 }
1134
1135 if (it==fExpectedRuns.end())
1136 {
1137 ostringstream str;
1138 str << "runOpen - Run " << run.runId << " wasn't expected (maybe manual triggers)";
1139 fMsg.Warn(str);
1140
1141 // This is not ideal, but the best we can do
1142 run.night = fNightAsInt;
1143
1144 return;
1145 }
1146
1147 const FAD::RunDescription &conf = it->second;
1148
1149 run.runType = conf.name;
1150 run.maxEvt = conf.maxevt;
1151 run.closeTime = conf.maxtime + run.openTime;
1152 run.night = conf.night;
1153
1154 fExpectedRuns.erase(it);
1155
1156 // Now signal the fadctrl (configuration process that a run is in progress)
1157 // Maybe this could be done earlier, but we are talking about a
1158 // negligible time scale here.
1159 fRunInProgress = run.runId;
1160 }
1161
1162 void runFinished()
1163 {
1164 // This is called when the last event of a run (run time exceeded or
1165 // max number of events exceeded) has been received.
1166 fRunInProgress = -1;
1167 }
1168
1169 //map<boost::thread::id, string> fLastMessage;
1170
1171 void factOut(int severity, const char *message)
1172 {
1173 ostringstream str;
1174 str << "EventBuilder: " << message;
1175
1176 /*
1177 string &old = fLastMessage[boost::this_thread::get_id()];
1178
1179 if (str.str()==old)
1180 return;
1181 old = str.str();
1182 */
1183
1184 fMsg.Update(str, severity);
1185 }
1186
1187/*
1188 void factStat(int64_t *stat, int len)
1189 {
1190 if (len!=7)
1191 {
1192 fMsg.Warn("factStat received unknown number of values.");
1193 return;
1194 }
1195
1196 vector<int64_t> data(1, g_maxMem);
1197 data.insert(data.end(), stat, stat+len);
1198
1199 static vector<int64_t> last(8);
1200 if (data==last)
1201 return;
1202 last = data;
1203
1204 fDimStatistics.Update(data);
1205
1206 // len ist die Laenge des arrays.
1207 // array[4] enthaelt wieviele bytes im Buffer aktuell belegt sind; daran
1208 // kannst Du pruefen, ob die 100MB voll sind ....
1209
1210 ostringstream str;
1211 str
1212 << "Wait=" << stat[0] << " "
1213 << "Skip=" << stat[1] << " "
1214 << "Del=" << stat[2] << " "
1215 << "Tot=" << stat[3] << " "
1216 << "Mem=" << stat[4] << "/" << g_maxMem << " "
1217 << "Read=" << stat[5] << " "
1218 << "Conn=" << stat[6];
1219
1220 fMsg.Info(str);
1221 }
1222 */
1223
1224 bool UpdateDimStatistics1(const pair<Time,GUI_STAT> &stat)
1225 {
1226 fDimStatistics1.setData(&stat.second, sizeof(GUI_STAT));
1227 fDimStatistics1.Update(stat.first);
1228
1229 return true;
1230 }
1231
1232 void factStat(const GUI_STAT &stat)
1233 {
1234 fQueueStatistics1.emplace(Time(), stat);
1235 }
1236
1237 void factReportIncomplete(uint64_t rep)
1238 {
1239 fDimIncomplete.setQuality(1);
1240 fDimIncomplete.Update(rep);
1241 }
1242
1243 array<FAD::EventHeader, 40> fVecHeader;
1244
1245 template<typename T, class S>
1246 array<T, 42> Compare(const S *vec, const T *t)
1247 {
1248 const int offset = reinterpret_cast<const char *>(t) - reinterpret_cast<const char *>(vec);
1249
1250 const T *min = NULL;
1251 const T *val = NULL;
1252 const T *max = NULL;
1253
1254 array<T, 42> arr;
1255
1256 // bool rc = true;
1257 for (int i=0; i<40; i++)
1258 {
1259 const char *base = reinterpret_cast<const char*>(vec+i);
1260 const T *ref = reinterpret_cast<const T*>(base+offset);
1261
1262 arr[i] = *ref;
1263
1264 if (gi_NumConnect[i]==0)
1265 {
1266 arr[i] = 0;
1267 continue;
1268 }
1269
1270 if (!val)
1271 {
1272 min = ref;
1273 val = ref;
1274 max = ref;
1275 }
1276
1277 if (*ref<*min)
1278 min = ref;
1279
1280 if (*ref>*max)
1281 max = ref;
1282
1283 // if (*val!=*ref)
1284 // rc = false;
1285 }
1286
1287 arr[40] = val ? *min : 1;
1288 arr[41] = val ? *max : 0;
1289
1290 return arr;
1291 }
1292
1293 template<typename T>
1294 array<T, 42> CompareBits(const FAD::EventHeader *h, const T *t)
1295 {
1296 const int offset = reinterpret_cast<const char *>(t) - reinterpret_cast<const char *>(h);
1297
1298 T val = 0;
1299 T rc = 0;
1300
1301 array<T, 42> vec;
1302
1303 bool first = true;
1304
1305 for (int i=0; i<40; i++)
1306 {
1307 const char *base = reinterpret_cast<const char*>(&fVecHeader[i]);
1308 const T *ref = reinterpret_cast<const T*>(base+offset);
1309
1310 vec[i+2] = *ref;
1311
1312 if (gi_NumConnect[i]==0)
1313 {
1314 vec[i+2] = 0;
1315 continue;
1316 }
1317
1318 if (first)
1319 {
1320 first = false;
1321 val = *ref;
1322 rc = 0;
1323 }
1324
1325 rc |= val^*ref;
1326 }
1327
1328 vec[0] = rc;
1329 vec[1] = val;
1330
1331 return vec;
1332 }
1333
1334 template<typename T, size_t N>
1335 void Update(DimDescribedService &svc, const array<T, N> &data, const Time &t=Time(), int n=N)
1336 {
1337 svc.setData(const_cast<T*>(data.data()), sizeof(T)*n);
1338 svc.Update(t);
1339 }
1340
1341 template<typename T>
1342 void Print(const char *name, const pair<bool,array<T, 43>> &data)
1343 {
1344 cout << name << "|" << data.first << "|" << data.second[1] << "|" << data.second[0] << "<x<" << data.second[1] << ":";
1345 for (int i=0; i<40;i++)
1346 cout << " " << data.second[i+3];
1347 cout << endl;
1348 }
1349
1350 vector<uint> fNumConnected;
1351
1352 bool procHeader(const tuple<Time,bool,FAD::EventHeader> &dat)
1353 {
1354 const Time &t = get<0>(dat);
1355 const bool changed = get<1>(dat);
1356 const FAD::EventHeader &h = get<2>(dat);
1357
1358 const FAD::EventHeader old = fVecHeader[h.Id()];
1359 fVecHeader[h.Id()] = h;
1360
1361 if (old.fVersion != h.fVersion || changed)
1362 {
1363 const array<uint16_t,42> ver = Compare(&fVecHeader[0], &fVecHeader[0].fVersion);
1364
1365 array<float,42> data;
1366 for (int i=0; i<42; i++)
1367 {
1368 ostringstream str;
1369 str << (ver[i]>>8) << '.' << (ver[i]&0xff);
1370 data[i] = stof(str.str());
1371 }
1372 Update(fDimFwVersion, data, t);
1373 }
1374
1375 if (old.fRunNumber != h.fRunNumber || changed)
1376 {
1377 const array<uint32_t,42> run = Compare(&fVecHeader[0], &fVecHeader[0].fRunNumber);
1378 fDimRunNumber.setData(&run[0], 42*sizeof(uint32_t));
1379 fDimRunNumber.Update(t);
1380 }
1381
1382 if (old.fTriggerGeneratorPrescaler != h.fTriggerGeneratorPrescaler || changed)
1383 {
1384 const array<uint16_t,42> pre = Compare(&fVecHeader[0], &fVecHeader[0].fTriggerGeneratorPrescaler);
1385 fDimPrescaler.setData(&pre[0], 42*sizeof(uint16_t));
1386 fDimPrescaler.Update(t);
1387 }
1388
1389 if (old.fDNA != h.fDNA || changed)
1390 {
1391 const array<uint64_t,42> dna = Compare(&fVecHeader[0], &fVecHeader[0].fDNA);
1392 Update(fDimDNA, dna, t, 40);
1393 }
1394
1395 if (old.fStatus != h.fStatus || changed)
1396 {
1397 const array<uint16_t,42> sts = CompareBits(&fVecHeader[0], &fVecHeader[0].fStatus);
1398 Update(fDimStatus, sts, t);
1399 }
1400
1401 if (memcmp(old.fDac, h.fDac, sizeof(h.fDac)) || changed)
1402 {
1403 array<uint16_t, FAD::kNumDac*42> dacs;
1404
1405 for (int i=0; i<FAD::kNumDac; i++)
1406 {
1407 const array<uint16_t, 42> dac = Compare(&fVecHeader[0], &fVecHeader[0].fDac[i]);
1408 memcpy(&dacs[i*42], &dac[0], sizeof(uint16_t)*42);
1409 }
1410
1411 Update(fDimDac, dacs, t);
1412 }
1413
1414 return true;
1415 }
1416
1417 void debugHead(const FAD::EventHeader &h)
1418 {
1419 const uint16_t id = h.Id();
1420 if (id>39)
1421 return;
1422
1423 if (fNumConnected.size()!=40)
1424 fNumConnected.resize(40);
1425
1426 const vector<uint> con(gi_NumConnect, gi_NumConnect+40);
1427
1428 const bool changed = con!=fNumConnected || !IsThreadRunning();
1429
1430 fNumConnected = con;
1431
1432 fQueueProcHeader.emplace(Time(), changed, h);
1433 }
1434};
1435
1436EventBuilderWrapper *EventBuilderWrapper::This = 0;
1437
1438// ----------- Event builder callbacks implementation ---------------
1439bool runOpen(const EVT_CTRL2 &evt)
1440{
1441 return EventBuilderWrapper::This->runOpen(evt);
1442}
1443
1444bool runWrite(const EVT_CTRL2 &evt)
1445{
1446 return EventBuilderWrapper::This->runWrite(evt);
1447}
1448
1449void runClose(const EVT_CTRL2 &evt)
1450{
1451 EventBuilderWrapper::This->runClose(evt);
1452}
1453
1454bool eventCheck(const EVT_CTRL2 &evt)
1455{
1456 return EventBuilderWrapper::This->eventCheck(evt);
1457}
1458
1459void gotNewRun(RUN_CTRL2 &run)
1460{
1461 EventBuilderWrapper::This->gotNewRun(run);
1462}
1463
1464void runFinished()
1465{
1466 EventBuilderWrapper::This->runFinished();
1467}
1468
1469void applyCalib(const EVT_CTRL2 &evt, const size_t &size)
1470{
1471 EventBuilderWrapper::This->applyCalib(evt, size);
1472}
1473
1474void factOut(int severity, const char *message)
1475{
1476 EventBuilderWrapper::This->factOut(severity, message);
1477}
1478
1479void factStat(const GUI_STAT &stat)
1480{
1481 EventBuilderWrapper::This->factStat(stat);
1482}
1483
1484void factReportIncomplete(uint64_t rep)
1485{
1486 EventBuilderWrapper::This->factReportIncomplete(rep);
1487}
1488
1489// ------
1490
1491void debugHead(void *buf)
1492{
1493 const FAD::EventHeader &h = *reinterpret_cast<FAD::EventHeader*>(buf);
1494 EventBuilderWrapper::This->debugHead(h);
1495}
1496
1497#endif
Note: See TracBrowser for help on using the repository browser.