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

Last change on this file since 13662 was 13561, checked in by tbretz, 13 years ago
Send the drs step as quality with the data so that it can be detected if it is calibrated data or not.
File size: 45.4 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
40extern "C" {
41 extern void StartEvtBuild();
42 extern int CloseRunFile(uint32_t runId, uint32_t closeTime, uint32_t maxEvt);
43}
44
45// ========================================================================
46
47class EventBuilderWrapper
48{
49public:
50 // FIXME
51 static EventBuilderWrapper *This;
52
53 MessageImp &fMsg;
54
55private:
56 boost::thread fThread;
57
58 enum CommandStates_t // g_runStat
59 {
60 kAbort = -2, // quit as soon as possible ('abort')
61 kExit = -1, // stop reading, quit when buffered events done ('exit')
62 kInitialize = 0, // 'initialize' (e.g. dim not yet started)
63 kHybernate = 1, // do nothing for long time ('hybernate') [wakeup within ~1sec]
64 kSleep = 2, // do nothing ('sleep') [wakeup within ~10msec]
65 kModeFlush = 10, // read data from camera, but skip them ('flush')
66 kModeTest = 20, // read data and process them, but do not write to disk ('test')
67 kModeFlag = 30, // read data, process and write all to disk ('flag')
68 kModeRun = 40, // read data, process and write selected to disk ('run')
69 };
70
71 enum
72 {
73 kCurrent = 0,
74 kTotal = 1,
75 kEventId = 2,
76 kTriggerId = 3,
77 };
78
79 FAD::FileFormat_t fFileFormat;
80
81 uint32_t fMaxRun;
82 uint32_t fLastOpened;
83 uint32_t fLastClosed;
84 uint32_t fNumEvts[4];
85
86 DimWriteStatistics fDimWriteStats;
87 DimDescribedService fDimRuns;
88 DimDescribedService fDimEvents;
89 DimDescribedService fDimRawData;
90 DimDescribedService fDimEventData;
91 DimDescribedService fDimFeedbackData;
92 DimDescribedService fDimFwVersion;
93 DimDescribedService fDimRunNumber;
94 DimDescribedService fDimStatus;
95 DimDescribedService fDimDNA;
96 DimDescribedService fDimTemperature;
97 DimDescribedService fDimPrescaler;
98 DimDescribedService fDimRefClock;
99 DimDescribedService fDimRoi;
100 DimDescribedService fDimDac;
101 DimDescribedService fDimDrsCalibration;
102 DimDescribedService fDimStatistics1;
103 DimDescribedService fDimStatistics2;
104 DimDescribedService fDimFileFormat;
105
106 bool fDebugStream;
107 bool fDebugRead;
108 bool fDebugLog;
109
110 string fPath;
111 uint32_t fRunNumber;
112
113protected:
114 int64_t InitRunNumber()
115 {
116 fRunNumber = 1000;
117
118 // Ensure that the night doesn't change during our check
119 const int check = Time().NightAsInt();
120
121 while (--fRunNumber>0)
122 {
123 const string name = DataProcessorImp::FormFileName(fPath, fRunNumber, "");
124
125 if (access((name+"bin").c_str(), F_OK) == 0)
126 break;
127 if (access((name+"fits").c_str(), F_OK) == 0)
128 break;
129 if (access((name+"drs.fits").c_str(), F_OK) == 0)
130 break;
131
132 }
133
134 if (check != Time().NightAsInt())
135 return InitRunNumber();
136
137 fRunNumber++;
138
139 if (fRunNumber==1000)
140 {
141 fMsg.Error("You have a file with run-number 1000 in "+fPath);
142 return -1;
143 }
144
145 ostringstream str;
146 str << "Set next run-number to " << fRunNumber << " determined from '" << (fPath.empty()?".":fPath) << "'";
147 fMsg.Message(str);
148
149 //fMsg.Info(" ==> TODO: Crosscheck with database!");
150
151 return check;
152 }
153
154 int64_t InitRunNumber(const string &path)
155 {
156 if (!DimWriteStatistics::DoesPathExist(path, fMsg))
157 {
158 fMsg.Error("Data path "+path+" does not exist!");
159 return -1;
160 }
161
162 //const fs::path fullPath = fs::system_complete(fs::path(path));
163
164 fPath = path;
165
166 fDimWriteStats.SetCurrentFolder(fPath);
167
168 return InitRunNumber();
169 }
170
171public:
172 EventBuilderWrapper(MessageImp &imp) : fMsg(imp),
173 fFileFormat(FAD::kNone), fMaxRun(0), fLastOpened(0), fLastClosed(0),
174 fDimWriteStats ("FAD_CONTROL", imp),
175 fDimRuns ("FAD_CONTROL/RUNS", "I:5;C",
176 "Run files statistics"
177 "|stats[int]:num of open run files, min/max run no, lastest opened or closed run"
178 "|file[string]:filename of last opened file"),
179 fDimEvents ("FAD_CONTROL/EVENTS", "I:4",
180 "Event counts"
181 "|evtsCount[int]:Num evts cur. run, total (all run), evt ID, trig. Num"),
182 fDimRawData ("FAD_CONTROL/RAW_DATA", "S:1;I:1;S:1;I:1;I:2;I:40;S:1440;S:160;F", ""),
183 fDimEventData ("FAD_CONTROL/EVENT_DATA", "F:1440;F:1440;F:1440;F:1440", ""),
184 fDimFeedbackData("FAD_CONTROL/FEEDBACK_DATA", "F:1440", ""),
185 fDimFwVersion ("FAD_CONTROL/FIRMWARE_VERSION", "F:42",
186 "Firmware version number of fad boards"
187 "|firmware[float]:Version number of firmware, for each board. 40=min, 41=max"),
188 fDimRunNumber ("FAD_CONTROL/RUN_NUMBER", "I:42",
189 "Run numbers coming from FAD boards"
190 "|runNumbers[int]:current run number of each FAD board. 40=min, 41=max"),
191 fDimStatus ("FAD_CONTROL/STATUS", "S:42",
192 "Status of FAD boards"
193 "|status[bitpattern]:Status of each FAD board. Maybe buggy"),
194 fDimDNA ("FAD_CONTROL/DNA", "X:40",
195 "DNA of FAD boards"
196 "|DNA[hex]:Hex identifier of each FAD board"),
197 fDimTemperature ("FAD_CONTROL/TEMPERATURE", "F:82",
198 "FADs temperatures"
199 "|temp[deg. C]:0 global min, 1-40 min, 41 global max, 42-81 max"),
200 fDimPrescaler ("FAD_CONTROL/PRESCALER", "S:42",
201 "Trigger generator prescaler of fad boards"
202 "|prescaler[int]:Trigger generator prescaler value, for each board"),
203 fDimRefClock ("FAD_CONTROL/REFERENCE_CLOCK", "I:42",
204 "Reference clock of FAD boards"
205 "|refClocks[t]:ref clocks of FAD boards. 40=min, 41=max"),
206 fDimRoi ("FAD_CONTROL/REGION_OF_INTEREST", "S:2", ""),
207 fDimDac ("FAD_CONTROL/DAC", "S:336",
208 "DAC settings of each FAD board"
209 "|DAC[int]:DAC counts, sequentially DAC 0 board 0, 0/1, 0/2... (plus min max)"),
210 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", ""),
211 fDimStatistics1 ("FAD_CONTROL/STATISTICS1", "I:3;I:5;X:4;I:3;I:3;I:40;I:1;I:2;C:40;I:40;I:40;X:40",
212 "Event Builder status for GUI display"
213 "|threadInfo[int]:Number of read, proc and writes"
214 "|bufferInfo[int]:Events in buffer, incomp., comp., tot., max past cycle, total"
215 "|memInfo[int]:total buf. mem, used mem, max used, max past cycle"
216 "|EvtCnt[int]:Number of events skipped, written, with errors"
217 "|badRoi[int]:Num boards with wrong ROI in event, run or board"
218 "|badRoiBoard[int]:Num boards with wrong ROI"
219 "|deltaT[ms]:Time in ms for rates"
220 "|rateNew[int]:Number of new start events received"
221 "|numConn[int]:Number of connections per board"
222 "|errConn[int]:IO errors per board"
223 "|rateBytes[int]:Bytes read this cycle"
224 "|totBytes[int]:Bytes read (counter)"),
225 fDimStatistics2 ("FAD_CONTROL/STATISTICS2", "I:1;I:280;X:40;I:40;I:4;I:4;I:2;I:2;I:3;C:40",
226 "Event Builder status, events oriented"
227 "|reset[int]:If increased, reset all counters"
228 "|numRead[int]:How often sucessful read from N sockets per loop"
229 "|gotByte[int]:number of bytes read per board"
230 "|gotErr[int]:number of com. errors per board"
231 "|evtStat[int]:number of evts read, completed, with errors, incomplete"
232 "|procStat[int]:num. of evts proc., w probs, acc. or rej. by SW trigger"
233 "|feedStat[int]:number of evts used or rejected by feedback system"
234 "|wrtStat[int]:number of evts written to disk, with errors"
235 "|runStat[int]:number of run opened, closed, with open or close errors"
236 "|numConn[int]:number of sockets successfully opened per board"),
237 fDimFileFormat ("FAD_CONTROL/FILE_FORMAT", "S:1", ""),
238 fDebugStream(false), fDebugRead(false), fDebugLog(false)
239 {
240 if (This)
241 throw logic_error("EventBuilderWrapper cannot be instantiated twice.");
242
243 This = this;
244
245 memset(fNumEvts, 0, sizeof(fNumEvts));
246 fDimEvents.Update(fNumEvts);
247
248 for (size_t i=0; i<40; i++)
249 ConnectSlot(i, tcp::endpoint());
250 }
251 virtual ~EventBuilderWrapper()
252 {
253 Abort();
254
255 // FIXME: Used timed_join and abort afterwards
256 // What's the maximum time the eb need to abort?
257 fThread.join();
258 //ffMsg.Info("EventBuilder stopped.");
259
260 for (vector<DataProcessorImp*>::iterator it=fFiles.begin(); it!=fFiles.end(); it++)
261 delete *it;
262 }
263
264 set<uint32_t> fIsRunStarted;
265 map<uint32_t, FAD::RunDescription> fExpectedRuns;
266
267 uint32_t StartNewRun(int64_t maxtime, int64_t maxevt, const pair<string, FAD::Configuration> &ref)
268 {
269 if (maxtime<=0 || maxtime>24*60*60)
270 maxtime = 24*60*60;
271 if (maxevt<=0 || maxevt>INT32_MAX)
272 maxevt = INT32_MAX;
273
274 const FAD::RunDescription descr =
275 {
276 uint32_t(maxtime),
277 uint32_t(maxevt),
278 ref.first,
279 ref.second,
280 };
281
282 // FIMXE: Maybe reset an event counter so that the mcp can count events?
283
284 //fMsg.Info(" ==> TODO: Set a limit on the size of fExpectedRuns!");
285
286 fExpectedRuns[fRunNumber] = descr;
287 fIsRunStarted.insert(fRunNumber);
288 return fRunNumber++;
289 }
290
291 bool IsThreadRunning()
292 {
293 return !fThread.timed_join(boost::posix_time::microseconds(0));
294 }
295
296 void SetMaxMemory(unsigned int mb) const
297 {
298 /*
299 if (mb*1000000<GetUsedMemory())
300 {
301 // ffMsg.Warn("...");
302 return;
303 }*/
304
305 g_maxMem = size_t(mb)*1000000;
306 }
307
308 void StartThread(const vector<tcp::endpoint> &addr)
309 {
310 if (IsThreadRunning())
311 {
312 fMsg.Warn("Start - EventBuilder still running");
313 return;
314 }
315
316 fLastMessage.clear();
317
318 for (size_t i=0; i<40; i++)
319 ConnectSlot(i, addr[i]);
320
321 g_runStat = kModeRun;
322 g_maxProc = 3;
323
324 fMsg.Message("Starting EventBuilder thread");
325
326 fThread = boost::thread(StartEvtBuild);
327 }
328 void ConnectSlot(unsigned int i, const tcp::endpoint &addr)
329 {
330 if (i>39)
331 return;
332
333 if (addr==tcp::endpoint())
334 {
335 DisconnectSlot(i);
336 return;
337 }
338
339 g_port[i].sockAddr.sin_family = AF_INET;
340 g_port[i].sockAddr.sin_addr.s_addr = htonl(addr.address().to_v4().to_ulong());
341 g_port[i].sockAddr.sin_port = htons(addr.port());
342 // In this order
343 g_port[i].sockDef = 1;
344 }
345 void DisconnectSlot(unsigned int i)
346 {
347 if (i>39)
348 return;
349
350 g_port[i].sockDef = 0;
351 // In this order
352 g_port[i].sockAddr.sin_family = AF_INET;
353 g_port[i].sockAddr.sin_addr.s_addr = 0;
354 g_port[i].sockAddr.sin_port = 0;
355 }
356 void IgnoreSlot(unsigned int i)
357 {
358 if (i>39)
359 return;
360 if (g_port[i].sockAddr.sin_port==0)
361 return;
362
363 g_port[i].sockDef = -1;
364 }
365
366
367 void Abort()
368 {
369 fMsg.Message("Signal abort to EventBuilder thread...");
370 g_runStat = kAbort;
371 }
372
373 void ResetThread(bool soft)
374 {
375 /*
376 if (g_reset > 0)
377
378 * suspend reading
379 * reset = g_reset;
380 * g_reset=0
381
382 * reset% 10
383 == 0 leave event Buffers as they are
384 == 1 let all buffers drain (write (incomplete) events)
385 > 1 flush all buffers (do not write buffered events)
386
387 * (reset/10)%10
388 > 0 close all sockets and destroy them (also free the
389 allocated read-buffers)
390 recreate before resuming operation
391 [ this is more than just close/open that can be
392 triggered by e.g. close/open the base-socket ]
393
394 * (reset/100)%10
395 > 0 close all open run-files
396
397 * (reset/1000)
398 sleep so many seconds before resuming operation
399 (does not (yet) take into account time left when waiting
400 for buffers getting empty ...)
401
402 * resume_reading
403
404 */
405 fMsg.Message("Signal reset to EventBuilder thread...");
406 g_reset = soft ? 101 : 102;
407 }
408
409 void Exit()
410 {
411 fMsg.Message("Signal exit to EventBuilder thread...");
412 g_runStat = kExit;
413 }
414
415 /*
416 void Wait()
417 {
418 fThread.join();
419 ffMsg.Message("EventBuilder stopped.");
420 }*/
421
422 void Hybernate() const { g_runStat = kHybernate; }
423 void Sleep() const { g_runStat = kSleep; }
424 void FlushMode() const { g_runStat = kModeFlush; }
425 void TestMode() const { g_runStat = kModeTest; }
426 void FlagMode() const { g_runStat = kModeFlag; }
427 void RunMode() const { g_runStat = kModeRun; }
428
429 // FIXME: To be removed
430 //void SetMode(int mode) const { g_runStat = mode; }
431
432 bool IsConnected(int i) const { return gi_NumConnect[i]==7; }
433 bool IsConnecting(int i) const { return !IsConnected(i) && !IsDisconnected(i); }
434 bool IsDisconnected(int i) const { return gi_NumConnect[i]<=0 && g_port[i].sockDef==0; }
435 int GetNumConnected(int i) const { return gi_NumConnect[i]; }
436 int GetNumFilesOpen() const { return fFiles.size(); }
437
438 /*
439 bool IsConnected(int i) const { return gi_NumConnect[i]>0; }
440 bool IsConnecting(int i) const { return !IsConnected(i) && !IsDisconnected(i); }
441 bool IsDisconnected(int i) const { return gi_NumConnect[i]<=0 && g_port[i].sockDef==0; }
442 int GetNumConnected(int i) const { return gi_NumConnect[i]; }
443 */
444
445 void SetIgnore(int i, bool b) const { if (g_port[i].sockDef!=0) g_port[i].sockDef=b?-1:1; }
446 bool IsIgnored(int i) const { return g_port[i].sockDef==-1; }
447
448 void SetOutputFormat(FAD::FileFormat_t f)
449 {
450 fFileFormat = f;
451 fDimFileFormat.Update(uint16_t(f));
452 if (fFileFormat==FAD::kCalib)
453 {
454 DataCalib::Restart();
455 DataCalib::Update(fDimDrsCalibration);
456 fMsg.Message("Resetted DRS calibration.");
457 }
458 }
459
460 virtual int ResetSecondaryDrsBaseline()
461 {
462 if (DataCalib::ResetTrgOff(fDimDrsCalibration))
463 {
464 fFileFormat = FAD::kCalib;
465 fDimFileFormat.Update(uint16_t(fFileFormat));
466 fMsg.Message("Resetted DRS calibration for secondary baseline.");
467 }
468 else
469 fMsg.Warn("Could not reset DRS calibration of secondary baseline.");
470
471 return 0;
472 }
473
474 void SetDebugLog(bool b) { fDebugLog = b; }
475
476 void SetDebugStream(bool b)
477 {
478 fDebugStream = b;
479 if (b)
480 return;
481
482 for (int i=0; i<40; i++)
483 {
484 if (!fDumpStream[i].is_open())
485 continue;
486
487 fDumpStream[i].close();
488
489 ostringstream name;
490 name << "socket_dump-" << setfill('0') << setw(2) << i << ".bin";
491 fMsg.Message("Closed file '"+name.str()+"'");
492 }
493 }
494
495 void SetDebugRead(bool b)
496 {
497 fDebugRead = b;
498 if (b || !fDumpRead.is_open())
499 return;
500
501 fDumpRead.close();
502 fMsg.Message("Closed file 'socket_events.txt'");
503 }
504
505// size_t GetUsedMemory() const { return gi_usedMem; }
506
507 void LoadDrsCalibration(const char *fname)
508 {
509 if (!DataCalib::ReadFits(fname, fMsg))
510 return;
511 fMsg.Info("Successfully loaded DRS calibration from "+string(fname));
512 DataCalib::Update(fDimDrsCalibration);
513 }
514
515 virtual int CloseOpenFiles() { CloseRunFile(0, 0, 0); return 0; }
516
517
518 /*
519 struct OpenFileToDim
520 {
521 int code;
522 char fileName[FILENAME_MAX];
523 };
524
525 SignalRunOpened(runid, filename);
526 // Send num open files
527 // Send runid, (more info about the run?), filename via dim
528
529 SignalEvtWritten(runid);
530 // Send num events written of newest file
531
532 SignalRunClose(runid);
533 // Send new num open files
534 // Send empty file-name if no file is open
535
536 */
537
538 // -------------- Mapped event builder callbacks ------------------
539
540 void UpdateRuns(const string &fname="")
541 {
542 uint32_t values[5] =
543 {
544 static_cast<uint32_t>(fFiles.size()),
545 0xffffffff,
546 0,
547 fLastOpened,
548 fLastClosed
549 };
550
551 for (vector<DataProcessorImp*>::const_iterator it=fFiles.begin();
552 it!=fFiles.end(); it++)
553 {
554 const DataProcessorImp *file = *it;
555
556 if (file->GetRunId()<values[1])
557 values[1] = file->GetRunId();
558
559 if (file->GetRunId()>values[2])
560 values[2] = file->GetRunId();
561 }
562
563 fMaxRun = values[2];
564
565 vector<char> data(sizeof(values)+fname.size()+1);
566 memcpy(data.data(), values, sizeof(values));
567 strcpy(data.data()+sizeof(values), fname.c_str());
568
569 fDimRuns.Update(data);
570 }
571
572 vector<DataProcessorImp*> fFiles;
573
574 FileHandle_t runOpen(uint32_t runid, RUN_HEAD *h, size_t)
575 {
576 //fMsg.Info(" ==> TODO: Update run configuration in database!");
577
578 map<uint32_t,FAD::RunDescription>::iterator it = fExpectedRuns.begin();
579 while (it!=fExpectedRuns.end())
580 {
581 if (it->first<runid)
582 {
583 ostringstream str;
584 str << "runOpen - Missed run " << it->first << ".";
585 fMsg.Info(str);
586
587 fExpectedRuns.erase(it++);
588 continue;
589 }
590 if (it->first==runid)
591 break;
592 it++;
593 }
594
595 FAD::RunDescription desc;
596
597 if (it==fExpectedRuns.end())
598 {
599 ostringstream str;
600 str << "runOpen - Run " << runid << " wasn't expected (maybe manual triggers)";
601 fMsg.Warn(str);
602 }
603 else
604 {
605 desc = it->second;
606 fExpectedRuns.erase(it);
607 }
608
609 // Check if file already exists...
610 DataProcessorImp *file = 0;
611 switch (fFileFormat)
612 {
613 case FAD::kNone: file = new DataDump(fPath, runid, fMsg); break;
614 case FAD::kDebug: file = new DataDebug(fPath, runid, fMsg); break;
615 case FAD::kCfitsio: file = new DataWriteFits(fPath, runid, fMsg); break;
616 case FAD::kFits: file = new DataWriteFits2(fPath, runid, fMsg); break;
617 case FAD::kRaw: file = new DataWriteRaw(fPath, runid, fMsg); break;
618 case FAD::kCalib: file = new DataCalib(fPath, runid, fDimDrsCalibration, fMsg); break;
619 }
620
621 try
622 {
623 if (!file->Open(h, desc))
624 return 0;
625 }
626 catch (const exception &e)
627 {
628 fMsg.Error("Exception trying to open file: "+string(e.what()));
629 return 0;
630 }
631
632 fFiles.push_back(file);
633
634 ostringstream str;
635 str << "Opened: " << file->GetFileName() << " (" << file->GetRunId() << ")";
636 fMsg.Info(str);
637
638 fDimWriteStats.FileOpened(file->GetFileName());
639
640 fLastOpened = runid;
641 UpdateRuns(file->GetFileName());
642
643 fNumEvts[kEventId] = 0;
644 fNumEvts[kTriggerId] = 0;
645
646 fNumEvts[kCurrent] = 0;
647 fDimEvents.Update(fNumEvts);
648 // fDimCurrentEvent.Update(uint32_t(0));
649
650 return reinterpret_cast<FileHandle_t>(file);
651 }
652
653 int runWrite(FileHandle_t handler, EVENT *e, size_t /*sz*/)
654 {
655 DataProcessorImp *file = reinterpret_cast<DataProcessorImp*>(handler);
656
657 if (!file->WriteEvt(e))
658 return -1;
659
660 if (file->GetRunId()==fMaxRun)
661 {
662 fNumEvts[kCurrent]++;
663 fNumEvts[kEventId] = e->EventNum;
664 fNumEvts[kTriggerId] = e->TriggerNum;
665 }
666
667 fNumEvts[kTotal]++;
668
669 static Time oldt(boost::date_time::neg_infin);
670 Time newt;
671 if (newt>oldt+boost::posix_time::seconds(1))
672 {
673 fDimEvents.Update(fNumEvts);
674 oldt = newt;
675 }
676
677
678 // ===> SignalEvtWritten(runid);
679 // Send num events written of newest file
680
681 /* close run runId (all all runs if runId=0) */
682 /* return: 0=close scheduled / >0 already closed / <0 does not exist */
683 //CloseRunFile(file->GetRunId(), time(NULL)+2) ;
684
685 return 0;
686 }
687
688 virtual void CloseRun(uint32_t /*runid*/) { }
689
690 int runClose(FileHandle_t handler, RUN_TAIL *tail, size_t)
691 {
692 //fMsg.Info(" ==> TODO: Update run configuration in database!");
693
694 DataProcessorImp *file = reinterpret_cast<DataProcessorImp*>(handler);
695
696 const vector<DataProcessorImp*>::iterator it = find(fFiles.begin(), fFiles.end(), file);
697 if (it==fFiles.end())
698 {
699 ostringstream str;
700 str << "File handler (" << handler << ") requested to close by event builder doesn't exist.";
701 fMsg.Fatal(str);
702 return -1;
703 }
704
705 fFiles.erase(it);
706
707 fLastClosed = file->GetRunId();
708 CloseRun(fLastClosed);
709 UpdateRuns();
710
711 fDimEvents.Update(fNumEvts);
712
713 const bool rc = file->Close(tail);
714 if (!rc)
715 {
716 // Error message
717 }
718
719 ostringstream str;
720 str << "Closed: " << file->GetFileName() << " (" << file->GetRunId() << ")";
721 fMsg.Info(str);
722
723 delete file;
724
725 // ==> SignalRunClose(runid);
726 // Send new num open files
727 // Send empty file-name if no file is open
728
729 return rc ? 0 : -1;
730 }
731
732 ofstream fDumpStream[40];
733
734 void debugStream(int isock, void *buf, int len)
735 {
736 if (!fDebugStream)
737 return;
738
739 const int slot = isock/7;
740 if (slot<0 || slot>39)
741 return;
742
743 if (!fDumpStream[slot].is_open())
744 {
745 ostringstream name;
746 name << "socket_dump-" << setfill('0') << setw(2) << slot << ".bin";
747
748 fDumpStream[slot].open(name.str().c_str(), ios::app);
749 if (!fDumpStream[slot])
750 {
751 ostringstream str;
752 str << "Open file '" << name << "': " << strerror(errno) << " (errno=" << errno << ")";
753 fMsg.Error(str);
754
755 return;
756 }
757
758 fMsg.Message("Opened file '"+name.str()+"' for writing.");
759 }
760
761 fDumpStream[slot].write(reinterpret_cast<const char*>(buf), len);
762 }
763
764 ofstream fDumpRead; // Stream to possibly dump docket events
765
766 void debugRead(int isock, int ibyte, uint32_t event, uint32_t ftmevt, uint32_t runno, int state, uint32_t tsec, uint32_t tusec)
767 {
768 // isock = socketID (0-279)
769 // ibyte = #bytes gelesen
770 // event = eventId (oder 0 wenn noch nicht bekannt)
771 // state : 1=finished reading data
772 // 0=reading data
773 // -1=start reading data (header)
774 // -2=start reading data,
775 // eventId not known yet (too little data)
776 // tsec, tusec = time when reading seconds, microseconds
777 //
778 if (!fDebugRead || ibyte==0)
779 return;
780
781 if (!fDumpRead.is_open())
782 {
783 fDumpRead.open("socket_events.txt", ios::app);
784 if (!fDumpRead)
785 {
786 ostringstream str;
787 str << "Open file 'socket_events.txt': " << strerror(errno) << " (errno=" << errno << ")";
788 fMsg.Error(str);
789
790 return;
791 }
792
793 fMsg.Message("Opened file 'socket_events.txt' for writing.");
794
795 fDumpRead << "# START: " << Time().GetAsStr() << endl;
796 fDumpRead << "# state time_sec time_usec socket slot runno event_id trigger_id bytes_received" << endl;
797 }
798
799 fDumpRead
800 << setw(2) << state << " "
801 << setw(8) << tsec << " "
802 << setw(9) << tusec << " "
803 << setw(3) << isock << " "
804 << setw(2) << isock/7 << " "
805 << runno << " "
806 << event << " "
807 << ftmevt << " "
808 << ibyte << endl;
809 }
810
811 array<uint16_t,2> fVecRoi;
812
813 int eventCheck(uint32_t runNr, PEVNT_HEADER *fadhd, EVENT *event, int /*iboard*/)
814 {
815 /*
816 fadhd[i] ist ein array mit den 40 fad-headers
817 (falls ein board nicht gelesen wurde, ist start_package_flag =0 )
818
819 event ist die Struktur, die auch die write routine erhaelt;
820 darin sind im header die 'soll-werte' fuer z.B. eventID
821 als auch die ADC-Werte (falls Du die brauchst)
822
823 Wenn die routine einen negativen Wert liefert, wird das event
824 geloescht (nicht an die write-routine weitergeleitet [mind. im Prinzip]
825 */
826
827 const array<uint16_t,2> roi = {{ event->Roi, event->RoiTM }};
828
829 if (roi!=fVecRoi)
830 {
831 Update(fDimRoi, roi);
832 fVecRoi = roi;
833 }
834
835 const FAD::EventHeader *beg = reinterpret_cast<FAD::EventHeader*>(fadhd);
836 const FAD::EventHeader *end = reinterpret_cast<FAD::EventHeader*>(fadhd)+40;
837
838 // FIMXE: Compare with target configuration
839
840 for (const FAD::EventHeader *ptr=beg; ptr!=end; ptr++)
841 {
842 // FIXME: Compare with expectations!!!
843 if (ptr->fStartDelimiter==0)
844 {
845 if (ptr==beg)
846 beg++;
847 continue;
848 }
849
850 if (beg->fStatus != ptr->fStatus)
851 {
852 fMsg.Error("Inconsistency in FAD status detected.... closing run.");
853 CloseRunFile(runNr, 0, 0);
854 return -1;
855 }
856
857 if (beg->fRunNumber != ptr->fRunNumber)
858 {
859 fMsg.Error("Inconsistent run number detected.... closing run.");
860 CloseRunFile(runNr, 0, 0);
861 return -1;
862 }
863
864 /*
865 if (beg->fVersion != ptr->fVersion)
866 {
867 Error("Inconsist firmware version detected.... closing run.");
868 CloseRunFile(runNr, 0, 0);
869 break;
870 }
871 */
872 if (beg->fEventCounter != ptr->fEventCounter)
873 {
874 fMsg.Error("Inconsistent FAD event number detected.... closing run.");
875 CloseRunFile(runNr, 0, 0);
876 return -1;
877 }
878
879 if (beg->fTriggerCounter != ptr->fTriggerCounter)
880 {
881 fMsg.Error("Inconsistent FTM trigger number detected.... closing run.");
882 CloseRunFile(runNr, 0, 0);
883 return -1;
884 }
885
886 if (beg->fAdcClockPhaseShift != ptr->fAdcClockPhaseShift)
887 {
888 fMsg.Error("Inconsistent phase shift detected.... closing run.");
889 CloseRunFile(runNr, 0, 0);
890 return -1;
891 }
892
893 if (memcmp(beg->fDac, ptr->fDac, sizeof(beg->fDac)))
894 {
895 fMsg.Error("Inconsistent DAC values detected.... closing run.");
896 CloseRunFile(runNr, 0, 0);
897 return -1;
898 }
899
900 if (beg->fTriggerType != ptr->fTriggerType)
901 {
902 fMsg.Error("Inconsistent trigger type detected.... closing run.");
903 CloseRunFile(runNr, 0, 0);
904 return -1;
905 }
906 }
907
908 // check REFCLK_frequency
909 // check consistency with command configuration
910 // how to log errors?
911 // need gotNewRun/closedRun to know it is finished
912
913 return 0;
914 }
915
916 void SendRawData(PEVNT_HEADER */*fadhd*/, EVENT *event)
917 {
918 // Currently we send any event no matter what its trigger id is...
919 // To be changed.
920 static Time oldt(boost::date_time::neg_infin);
921 Time newt;
922
923 // FIXME: Only send events if the have newer run-numbers
924 if (newt<oldt+boost::posix_time::seconds(1))
925 return;
926
927 oldt = newt;
928
929 vector<char> data(sizeof(EVENT)+event->Roi*sizeof(float)*(1440+160));
930 memcpy(data.data(), event, sizeof(EVENT));
931
932 float *vec = reinterpret_cast<float*>(data.data()+sizeof(EVENT));
933
934 DataCalib::Apply(vec, event->Adc_Data, event->StartPix, event->Roi);
935 fDimRawData.setQuality(DataCalib::GetStep());
936 fDimRawData.Update(data);
937
938 DrsCalibrate::RemoveSpikes(vec, event->Roi);
939
940 vector<float> data2(1440*4); // Mean, RMS, Max, Pos
941 DrsCalibrate::GetPixelStats(data2.data(), vec, event->Roi);
942
943 fDimEventData.setQuality(DataCalib::GetStep());
944 fDimEventData.Update(data2);
945 }
946
947 void SendFeedbackData(PEVNT_HEADER *fadhd, EVENT *event)
948 {
949 if (!DataCalib::IsValid())
950 return;
951
952 // Workaround to find a valid header.....
953 const FAD::EventHeader *beg = reinterpret_cast<FAD::EventHeader*>(fadhd);
954 const FAD::EventHeader *end = reinterpret_cast<FAD::EventHeader*>(fadhd)+40;
955
956 // FIMXE: Compare with target configuration
957
958 const FAD::EventHeader *ptr=beg;
959 for (; ptr!=end; ptr++)
960 {
961 if (ptr->fStartDelimiter==0)
962 continue;
963
964 if (!ptr->HasTriggerLPext() && !ptr->HasTriggerLPint())
965 return;
966 }
967
968 if (ptr->fStartDelimiter==0)
969 return;
970
971 vector<float> data(event->Roi*1440);
972 DataCalib::Apply(data.data(), event->Adc_Data, event->StartPix, event->Roi);
973
974 DrsCalibrate::RemoveSpikes(data.data(), event->Roi);
975
976 vector<float> data2(1440); // Mean, RMS, Max, Pos, first, last
977 DrsCalibrate::GetPixelMax(data2.data(), data.data(), event->Roi, 0, event->Roi-1);
978
979 fDimFeedbackData.Update(data2);
980 }
981
982 int subProcEvt(int threadID, PEVNT_HEADER *fadhd, EVENT *event, int16_t /*iboard*/, void */*buffer*/)
983 {
984 switch (threadID)
985 {
986 case 0:
987 SendRawData(fadhd, event);
988 return 1;
989 case 1:
990 SendFeedbackData(fadhd, event);
991 return 2;
992 }
993 return 100;
994 }
995
996
997 bool IsRunStarted() const
998 {
999 const set<uint32_t>::const_iterator it = fIsRunStarted.find(fRunNumber-1);
1000 return it==fIsRunStarted.end();// ? true : it->second.started;
1001 }
1002
1003 uint32_t GetRunNumber() const
1004 {
1005 return fRunNumber;
1006 }
1007
1008 void IncreaseRunNumber(uint32_t run)
1009 {
1010 if (run>fRunNumber)
1011 fRunNumber = run;
1012 }
1013
1014 void gotNewRun(uint32_t runnr, PEVNT_HEADER */*headers*/)
1015 {
1016 // This function is called even when writing is switched off
1017 set<uint32_t>::iterator it = fIsRunStarted.begin();
1018 while (it!=fIsRunStarted.end())
1019 {
1020 if (*it<runnr)
1021 {
1022 ostringstream str;
1023 str << "gotNewRun - Missed run " << *it << ".";
1024 fMsg.Info(str);
1025
1026 fIsRunStarted.erase(it++);
1027 continue;
1028 }
1029 if (*it==runnr)
1030 break;
1031 it++;
1032 }
1033 if (it==fIsRunStarted.end())
1034 {
1035 ostringstream str;
1036 str << "gotNewRun - Not waiting for run " << runnr << ".";
1037 fMsg.Warn(str);
1038 return;
1039 }
1040
1041 map<uint32_t,FAD::RunDescription>::iterator i2 = fExpectedRuns.find(runnr);
1042 if (i2==fExpectedRuns.end())
1043 {
1044 ostringstream str;
1045 str << "gotNewRun - Run " << runnr << " wasn't expected.";
1046 fMsg.Warn(str);
1047 return;
1048 }
1049
1050 CloseRunFile(runnr, time(NULL)+i2->second.maxtime, i2->second.maxevt);
1051 // return: 0=close scheduled / >0 already closed / <0 does not exist
1052
1053 // FIXME: Move configuration from expected runs to runs which will soon
1054 // be opened/closed
1055
1056 fIsRunStarted.erase(it);
1057 }
1058
1059 map<boost::thread::id, string> fLastMessage;
1060
1061 void factOut(int severity, int err, const char *message)
1062 {
1063 if (!fDebugLog && severity==99)
1064 return;
1065
1066 ostringstream str;
1067 //str << boost::this_thread::get_id() << " ";
1068 str << "EventBuilder(";
1069 if (err<0)
1070 str << "---";
1071 else
1072 str << err;
1073 str << "): " << message;
1074
1075 string &old = fLastMessage[boost::this_thread::get_id()];
1076
1077 if (str.str()==old)
1078 return;
1079 old = str.str();
1080
1081 fMsg.Update(str, severity);
1082 }
1083/*
1084 void factStat(int64_t *stat, int len)
1085 {
1086 if (len!=7)
1087 {
1088 fMsg.Warn("factStat received unknown number of values.");
1089 return;
1090 }
1091
1092 vector<int64_t> data(1, g_maxMem);
1093 data.insert(data.end(), stat, stat+len);
1094
1095 static vector<int64_t> last(8);
1096 if (data==last)
1097 return;
1098 last = data;
1099
1100 fDimStatistics.Update(data);
1101
1102 // len ist die Laenge des arrays.
1103 // array[4] enthaelt wieviele bytes im Buffer aktuell belegt sind; daran
1104 // kannst Du pruefen, ob die 100MB voll sind ....
1105
1106 ostringstream str;
1107 str
1108 << "Wait=" << stat[0] << " "
1109 << "Skip=" << stat[1] << " "
1110 << "Del=" << stat[2] << " "
1111 << "Tot=" << stat[3] << " "
1112 << "Mem=" << stat[4] << "/" << g_maxMem << " "
1113 << "Read=" << stat[5] << " "
1114 << "Conn=" << stat[6];
1115
1116 fMsg.Info(str);
1117 }
1118 */
1119
1120 void factStat(const EVT_STAT &stat)
1121 {
1122 fDimStatistics2.Update(stat);
1123 }
1124
1125 void factStat(const GUI_STAT &stat)
1126 {
1127 fDimStatistics1.Update(stat);
1128 }
1129
1130
1131 array<FAD::EventHeader, 40> fVecHeader;
1132
1133 template<typename T, class S>
1134 array<T, 42> Compare(const S *vec, const T *t)
1135 {
1136 const int offset = reinterpret_cast<const char *>(t) - reinterpret_cast<const char *>(vec);
1137
1138 const T *min = NULL;
1139 const T *val = NULL;
1140 const T *max = NULL;
1141
1142 array<T, 42> arr;
1143
1144 // bool rc = true;
1145 for (int i=0; i<40; i++)
1146 {
1147 const char *base = reinterpret_cast<const char*>(vec+i);
1148 const T *ref = reinterpret_cast<const T*>(base+offset);
1149
1150 arr[i] = *ref;
1151
1152 if (gi_NumConnect[i]!=7)
1153 {
1154 arr[i] = 0;
1155 continue;
1156 }
1157
1158 if (!val)
1159 {
1160 min = ref;
1161 val = ref;
1162 max = ref;
1163 }
1164
1165 if (*ref<*min)
1166 min = ref;
1167
1168 if (*ref>*max)
1169 max = ref;
1170
1171 // if (*val!=*ref)
1172 // rc = false;
1173 }
1174
1175 arr[40] = val ? *min : 1;
1176 arr[41] = val ? *max : 0;
1177
1178 return arr;
1179 }
1180
1181 template<typename T>
1182 array<T, 42> CompareBits(const FAD::EventHeader *h, const T *t)
1183 {
1184 const int offset = reinterpret_cast<const char *>(t) - reinterpret_cast<const char *>(h);
1185
1186 T val = 0;
1187 T rc = 0;
1188
1189 array<T, 42> vec;
1190
1191 bool first = true;
1192
1193 for (int i=0; i<40; i++)
1194 {
1195 const char *base = reinterpret_cast<const char*>(&fVecHeader[i]);
1196 const T *ref = reinterpret_cast<const T*>(base+offset);
1197
1198 vec[i+2] = *ref;
1199
1200 if (gi_NumConnect[i]!=7)
1201 {
1202 vec[i+2] = 0;
1203 continue;
1204 }
1205
1206 if (first)
1207 {
1208 first = false;
1209 val = *ref;
1210 rc = 0;
1211 }
1212
1213 rc |= val^*ref;
1214 }
1215
1216 vec[0] = rc;
1217 vec[1] = val;
1218
1219 return vec;
1220 }
1221
1222 template<typename T, size_t N>
1223 void Update(DimDescribedService &svc, const array<T, N> &data, int n=N)
1224 {
1225// svc.setQuality(vec[40]<=vec[41]);
1226 svc.setData(const_cast<T*>(data.data()), sizeof(T)*n);
1227 svc.Update();
1228 }
1229
1230 template<typename T>
1231 void Print(const char *name, const pair<bool,array<T, 43>> &data)
1232 {
1233 cout << name << "|" << data.first << "|" << data.second[1] << "|" << data.second[0] << "<x<" << data.second[1] << ":";
1234 for (int i=0; i<40;i++)
1235 cout << " " << data.second[i+3];
1236 cout << endl;
1237 }
1238
1239 vector<uint> fNumConnected;
1240
1241 void debugHead(int /*socket*/, const FAD::EventHeader &h)
1242 {
1243 const uint16_t id = h.Id();
1244 if (id>39)
1245 return;
1246
1247 if (fNumConnected.size()!=40)
1248 fNumConnected.resize(40);
1249
1250 const vector<uint> con(gi_NumConnect, gi_NumConnect+40);
1251
1252 const bool changed = con!=fNumConnected || !IsThreadRunning();
1253
1254 fNumConnected = con;
1255
1256 const FAD::EventHeader old = fVecHeader[id];
1257 fVecHeader[id] = h;
1258
1259 if (old.fVersion != h.fVersion || changed)
1260 {
1261 const array<uint16_t,42> ver = Compare(&fVecHeader[0], &fVecHeader[0].fVersion);
1262
1263 array<float,42> data;
1264 for (int i=0; i<42; i++)
1265 {
1266 ostringstream str;
1267 str << (ver[i]>>8) << '.' << (ver[i]&0xff);
1268 data[i] = stof(str.str());
1269 }
1270 Update(fDimFwVersion, data);
1271 }
1272
1273 if (old.fRunNumber != h.fRunNumber || changed)
1274 {
1275 const array<uint32_t,42> run = Compare(&fVecHeader[0], &fVecHeader[0].fRunNumber);
1276 fDimRunNumber.Update(run);
1277 }
1278
1279 if (old.fTriggerGeneratorPrescaler != h.fTriggerGeneratorPrescaler || changed)
1280 {
1281 const array<uint16_t,42> pre = Compare(&fVecHeader[0], &fVecHeader[0].fTriggerGeneratorPrescaler);
1282 fDimPrescaler.Update(pre);
1283 }
1284
1285 if (old.fDNA != h.fDNA || changed)
1286 {
1287 const array<uint64_t,42> dna = Compare(&fVecHeader[0], &fVecHeader[0].fDNA);
1288 Update(fDimDNA, dna, 40);
1289 }
1290
1291 if (old.fStatus != h.fStatus || changed)
1292 {
1293 const array<uint16_t,42> sts = CompareBits(&fVecHeader[0], &fVecHeader[0].fStatus);
1294 Update(fDimStatus, sts);
1295 }
1296
1297 if (memcmp(old.fDac, h.fDac, sizeof(h.fDac)) || changed)
1298 {
1299 array<uint16_t, FAD::kNumDac*42> dacs;
1300
1301 for (int i=0; i<FAD::kNumDac; i++)
1302 {
1303 const array<uint16_t, 42> dac = Compare(&fVecHeader[0], &fVecHeader[0].fDac[i]);
1304 memcpy(&dacs[i*42], &dac[0], sizeof(uint16_t)*42);
1305 }
1306
1307 Update(fDimDac, dacs);
1308 }
1309
1310 // -----------
1311
1312 static Time oldt(boost::date_time::neg_infin);
1313 Time newt;
1314
1315 if (newt>oldt+boost::posix_time::seconds(1))
1316 {
1317 oldt = newt;
1318
1319 // --- RefClock
1320
1321 const array<uint32_t,42> clk = Compare(&fVecHeader[0], &fVecHeader[0].fFreqRefClock);
1322 Update(fDimRefClock, clk);
1323
1324 // --- Temperatures
1325
1326 const array<int16_t,42> tmp[4] =
1327 {
1328 Compare(&fVecHeader[0], &fVecHeader[0].fTempDrs[0]), // 0-39:val, 40:min, 41:max
1329 Compare(&fVecHeader[0], &fVecHeader[0].fTempDrs[1]), // 0-39:val, 40:min, 41:max
1330 Compare(&fVecHeader[0], &fVecHeader[0].fTempDrs[2]), // 0-39:val, 40:min, 41:max
1331 Compare(&fVecHeader[0], &fVecHeader[0].fTempDrs[3]) // 0-39:val, 40:min, 41:max
1332 };
1333
1334 vector<int16_t> data;
1335 data.reserve(82);
1336 data.push_back(tmp[0][40]); // min: 0
1337 data.insert(data.end(), tmp[0].data(), tmp[0].data()+40); // val: 1-40
1338 data.push_back(tmp[0][41]); // max: 41
1339 data.insert(data.end(), tmp[0].data(), tmp[0].data()+40); // val: 42-81
1340
1341 for (int j=1; j<=3; j++)
1342 {
1343 const array<int16_t,42> &ref = tmp[j];
1344
1345 // Gloabl min
1346 if (ref[40]<data[0]) // 40=min
1347 data[0] = ref[40];
1348
1349 // Global max
1350 if (ref[41]>data[41]) // 41=max
1351 data[41] = ref[41];
1352
1353 for (int i=0; i<40; i++)
1354 {
1355 // min per board
1356 if (ref[i]<data[i+1]) // data: 1-40
1357 data[i+1] = ref[i]; // ref: 0-39
1358
1359 // max per board
1360 if (ref[i]>data[i+42]) // data: 42-81
1361 data[i+42] = ref[i]; // ref: 0-39
1362 }
1363
1364
1365 }
1366
1367 vector<float> deg(82); // 0: global min, 1-40: min
1368 for (int i=0; i<82; i++) // 41: global max, 42-81: max
1369 deg[i] = data[i]/16.;
1370 fDimTemperature.Update(deg);
1371 }
1372 }
1373};
1374
1375EventBuilderWrapper *EventBuilderWrapper::This = 0;
1376
1377// ----------- Event builder callbacks implementation ---------------
1378extern "C"
1379{
1380 FileHandle_t runOpen(uint32_t irun, RUN_HEAD *runhd, size_t len)
1381 {
1382 return EventBuilderWrapper::This->runOpen(irun, runhd, len);
1383 }
1384
1385 int runWrite(FileHandle_t fileId, EVENT *event, size_t len)
1386 {
1387 return EventBuilderWrapper::This->runWrite(fileId, event, len);
1388 }
1389
1390 int runClose(FileHandle_t fileId, RUN_TAIL *runth, size_t len)
1391 {
1392 return EventBuilderWrapper::This->runClose(fileId, runth, len);
1393 }
1394
1395 // -----
1396
1397 //void *runStart(uint32_t /*irun*/, RUN_HEAD */*runhd*/, size_t /*len*/)
1398 //{
1399 // return NULL;
1400 //}
1401
1402 int subProcEvt(int threadID, PEVNT_HEADER *fadhd, EVENT *event, int16_t mboard, void *runPtr)
1403 {
1404 return EventBuilderWrapper::This->subProcEvt(threadID, fadhd, event, mboard, runPtr);
1405 }
1406
1407 int runEnd(uint32_t, void */*runPtr*/)
1408 {
1409 return 0;
1410 }
1411
1412 // -----
1413
1414 int eventCheck(uint32_t runNr, PEVNT_HEADER *fadhd, EVENT *event, int mboard)
1415 {
1416 return EventBuilderWrapper::This->eventCheck(runNr, fadhd, event, mboard);
1417 }
1418
1419 void gotNewRun(uint32_t runnr, PEVNT_HEADER *headers)
1420 {
1421 return EventBuilderWrapper::This->gotNewRun(runnr, headers);
1422 }
1423
1424 // -----
1425
1426 void factOut(int severity, int err, const char *message)
1427 {
1428 EventBuilderWrapper::This->factOut(severity, err, message);
1429 }
1430
1431 void factStat(GUI_STAT stat)
1432 {
1433 EventBuilderWrapper::This->factStat(stat);
1434 }
1435
1436 void factStatNew(EVT_STAT stat)
1437 {
1438 EventBuilderWrapper::This->factStat(stat);
1439 }
1440
1441 // ------
1442
1443 void debugHead(int socket, int/*board*/, void *buf)
1444 {
1445 const FAD::EventHeader &h = *reinterpret_cast<FAD::EventHeader*>(buf);
1446 EventBuilderWrapper::This->debugHead(socket, h);
1447 }
1448
1449 void debugStream(int isock, void *buf, int len)
1450 {
1451 return EventBuilderWrapper::This->debugStream(isock, buf, len);
1452 }
1453
1454 void debugRead(int isock, int ibyte, int32_t event, int32_t ftmevt, int32_t runno, int state, uint32_t tsec, uint32_t tusec)
1455 {
1456 EventBuilderWrapper::This->debugRead(isock, ibyte, event, ftmevt, runno, state, tsec, tusec);
1457 }
1458}
1459
1460#endif
Note: See TracBrowser for help on using the repository browser.