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

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