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

Last change on this file since 11692 was 11689, checked in by tbretz, 14 years ago
Added latest changes in the EventBuilder; consequently added TriggerNum and NumBoards to Event Header in FITS.
File size: 60.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/date_time/posix_time/posix_time_types.hpp>
13
14
15#include <CCfits/CCfits>
16
17#include "EventBuilder.h"
18
19extern "C" {
20 extern void StartEvtBuild();
21 extern int CloseRunFile(uint32_t runId, uint32_t closeTime, uint32_t maxEvt);
22}
23
24namespace ba = boost::asio;
25namespace bs = boost::system;
26
27using ba::ip::tcp;
28
29using namespace std;
30
31class DataFileImp : public MessageImp
32{
33 uint32_t fRunId;
34
35 int Write(const Time &time, const std::string &txt, int qos)
36 {
37 return fMsg.Write(time, txt, qos);
38 }
39
40protected:
41 MessageImp &fMsg;
42 string fFileName;
43
44public:
45 DataFileImp(uint32_t id, MessageImp &imp) : fRunId(id), fMsg(imp) { }
46 virtual ~DataFileImp() { }
47
48 virtual bool OpenFile(RUN_HEAD* h) = 0;
49 virtual bool WriteEvt(EVENT *) = 0;
50 virtual bool Close(RUN_TAIL * = 0) = 0;
51
52 const string &GetFileName() const { return fFileName; }
53
54 uint32_t GetRunId() const { return fRunId; }
55
56 // --------------------------------------------------------------------------
57 //
58 //! This creates an appropriate file name for a particular run number and type
59 //! @param runNumber the run number for which a filename is to be created
60 //! @param runType an int describing the kind of run. 0=Data, 1=Pedestal, 2=Calibration, 3=Calibrated data
61 //! @param extension a string containing the extension to be appened to the file name
62 //
63 static string FormFileName(uint32_t runid, string extension)
64 {
65 ostringstream name;
66 name << Time().NightAsInt() << '_' << setfill('0') << setw(3) << runid << '.' << extension;
67 return name.str();
68 }
69};
70
71class DataFileNone : public DataFileImp
72{
73public:
74 DataFileNone(uint32_t id, MessageImp &imp) : DataFileImp(id, imp) { }
75
76 Time fTime;
77
78 bool OpenFile(RUN_HEAD* h)
79 {
80 fFileName = "/dev/null";
81
82 ostringstream str;
83 str << this << " - "
84 << "OPEN_FILE #" << GetRunId() << ":"
85 << " Ver=" << h->Version
86 << " Typ=" << h->RunType
87 << " Nb=" << h->NBoard
88 << " Np=" << h->NPix
89 << " NTm=" << h->NTm
90 << " roi=" << h->Nroi;
91
92 Debug(str);
93
94 fTime = Time();
95
96 return true;
97 }
98 bool WriteEvt(EVENT *e)
99 {
100 const Time now;
101 if (now-fTime<boost::posix_time::seconds(5))
102 return true;
103
104 fTime = now;
105
106 ostringstream str;
107 str << this << " - EVENT #" << e->EventNum << " / " << e->TriggerNum;
108 Debug(str);
109
110 return true;
111 }
112 bool Close(RUN_TAIL * = 0)
113 {
114 ostringstream str;
115 str << this << " - CLOSE FILE #" << GetRunId();
116
117 Debug(str);
118
119 return true;
120 }
121};
122
123#include "DrsCalib.h"
124
125class DataFileCalib : public DataFileImp, CalibData
126{
127 static vector<int32_t> fOffset;
128 static vector<int32_t> fGain;
129 static vector<int32_t> fTrgOff;
130
131 static uint32_t fNumOffset;
132 static uint32_t fNumGain;
133 static uint32_t fNumTrgOff;
134
135 static int fStep;
136
137public:
138 DataFileCalib(uint32_t id, MessageImp &imp) : DataFileImp(id, imp)
139 {
140 }
141
142 static void Restart() { fStep = 0; }
143
144 bool OpenFile(RUN_HEAD* h)
145 {
146 if (fStep==4)
147 {
148 fMsg.Warn("DRS Calibration already finished... please restart!");
149 return false;
150 }
151
152 if (h->NPix != 1440)
153 {
154 fMsg.Error("Number of pixels in header not 1440.");
155 return false;
156 }
157
158 if (h->Nroi != 1024)
159 {
160 fMsg.Error("Region of interest not 1024.");
161 return false;
162 }
163
164 ostringstream name;
165 name << "drs-calib-" << fStep;
166 fFileName = name.str();
167
168 Reset();
169 InitSize(1440, 1024);
170
171 if (fStep==0)
172 {
173 // Default gain:
174 // 0.575*[45590]*2.5V / 2^16 = 0.99999 V
175 fOffset.assign(1440*1024, 0);
176 fGain.assign (1440*1024, 2);
177 fTrgOff.assign(1440*1024, 0);
178
179 fNumOffset = 1;
180 fNumGain = 1;
181 fNumTrgOff = 1;
182 }
183
184 return true;
185 }
186 bool WriteEvt(EVENT *e)
187 {
188 // FIXME: SET StartPix to 0 if StartPix is -1
189
190 if (fStep==0)
191 {
192 AddRel(e->Adc_Data, e->StartPix);
193 }
194 if (fStep==1)
195 {
196 AddRel(e->Adc_Data, e->StartPix, fOffset.data(), fNumOffset);
197 }
198 if (fStep==2)
199 {
200 AddAbs(e->Adc_Data, e->StartPix, fOffset.data(), fNumOffset);
201 }
202
203 return true;
204 }
205 bool Close(RUN_TAIL * = 0)
206 {
207 if (fStep==0)
208 {
209 fOffset.assign(fSum.begin(), fSum.end());
210 fNumOffset = fNumEntries;
211 }
212 if (fStep==1)
213 {
214 fGain.assign(fSum.begin(), fSum.end());
215 fNumGain = fNumEntries*1000;
216 // Scale from Volt to Millivolt
217 }
218 if (fStep==2)
219 {
220 fTrgOff.assign(fSum.begin(), fSum.end());
221 fNumTrgOff = fNumEntries;
222 }
223 fStep++;
224
225 return true;
226 }
227
228 static void Apply(int16_t *val, const int16_t *start, uint32_t roi)
229 {
230 CalibData::Apply(val, start, roi,
231 fOffset.data(), fNumOffset,
232 fGain.data(), fNumGain,
233 fTrgOff.data(), fNumTrgOff);
234 }
235
236 static void Apply(float *vec, int16_t *val, const int16_t *start, uint32_t roi)
237 {
238 CalibData::Apply(vec, val, start, roi,
239 fOffset.data(), fNumOffset,
240 fGain.data(), fNumGain,
241 fTrgOff.data(), fNumTrgOff);
242 }
243};
244
245int DataFileCalib::fStep = 0;
246
247vector<int32_t> DataFileCalib::fOffset(1440*1024, 0);
248vector<int32_t> DataFileCalib::fGain (1440*1024, 2);
249vector<int32_t> DataFileCalib::fTrgOff(1440*1024, 0);
250
251uint32_t DataFileCalib::fNumOffset = 1;
252uint32_t DataFileCalib::fNumGain = 1;
253uint32_t DataFileCalib::fNumTrgOff = 1;
254
255
256class DataFileDebug : public DataFileNone
257{
258public:
259 DataFileDebug(uint32_t id, MessageImp &imp) : DataFileNone(id, imp) { }
260
261 bool WriteEvt(EVENT *e)
262 {
263 cout << "WRITE_EVENT #" << GetRunId() << " (" << e->EventNum << ")" << endl;
264 cout << " Typ=" << e->TriggerType << endl;
265 cout << " roi=" << e->Roi << endl;
266 cout << " trg=" << e->SoftTrig << endl;
267 cout << " tim=" << e->PCTime << endl;
268
269 return true;
270 }
271};
272
273#include "FAD.h"
274
275class DataFileRaw : public DataFileImp
276{
277 ofstream fOut;
278
279 off_t fPosTail;
280
281 uint32_t fCounter;
282
283
284 // WRITE uint32_t 0xFAC77e1e (FACT Tele)
285 // ===
286 // WRITE uint32_t TYPE(>0) == 1
287 // WRITE uint32_t ID(>0) == 0
288 // WRITE uint32_t VERSION(>0) == 1
289 // WRITE uint32_t LENGTH
290 // -
291 // WRITE uint32_t TELESCOPE ID
292 // WRITE uint32_t RUNID
293 // ===
294 // WRITE uint32_t TYPE(>0) == 2
295 // WRITE uint32_t ID(>0) == 0
296 // WRITE uint32_t VERSION(>0) == 1
297 // WRITE uint32_t LENGTH
298 // -
299 // WRITE HEADER
300 // ===
301 // [ 40 TIMES
302 // WRITE uint32_t TYPE(>0) == 3
303 // WRITE uint32_t ID(>0) == 0..39
304 // WRITE uint32_t VERSION(>0) == 1
305 // WRITE uint32_t LENGTH
306 // -
307 // WRITE BOARD-HEADER
308 // ]
309 // ===
310 // WRITE uint32_t TYPE(>0) == 4
311 // WRITE uint32_t ID(>0) == 0
312 // WRITE uint32_t VERSION(>0) == 1
313 // WRITE uint32_t LENGTH
314 // -
315 // WRITE FOOTER (empty)
316 // ===
317 // [ N times
318 // WRITE uint32_t TYPE(>0) == 10
319 // WRITE uint32_t ID(>0) == counter
320 // WRITE uint32_t VERSION(>0) == 1
321 // WRITE uint32_t LENGTH HEADER
322 // -
323 // WRITE HEADER+DATA
324 // ]
325 // ===
326 // WRITE uint32_t TYPE ==0
327 // WRITE uint32_t VERSION==0
328 // WRITE uint32_t LENGTH ==0
329 // ===
330 // Go back and write footer
331
332public:
333 DataFileRaw(uint32_t id, MessageImp &imp) : DataFileImp(id, imp), fPosTail(0) { }
334 ~DataFileRaw() { if (fOut.is_open()) Close(); }
335
336 void WriteBlockHeader(uint32_t type, uint32_t ver, uint32_t cnt, uint32_t len)
337 {
338 const uint32_t val[4] = { type, ver, cnt, len };
339
340 fOut.write(reinterpret_cast<const char*>(val), sizeof(val));
341 }
342
343 template<typename T>
344 void WriteValue(const T &t)
345 {
346 fOut.write(reinterpret_cast<const char*>(&t), sizeof(T));
347 }
348
349 enum
350 {
351 kEndOfFile = 0,
352 kIdentifier = 1,
353 kRunHeader,
354 kBoardHeader,
355 kRunSummary,
356 kEvent,
357 };
358
359 bool OpenFile(RUN_HEAD *h)
360 {
361 const string name = FormFileName(GetRunId(), "bin");
362 if (access(name.c_str(), F_OK)==0)
363 {
364 Error("File '"+name+"' already exists.");
365 return false;
366 }
367
368 fFileName = name;
369
370 errno = 0;
371 fOut.open(name.c_str(), ios_base::out);
372 if (!fOut)
373 {
374 ostringstream str;
375 str << "ofstream::open() failed for '" << name << "': " << strerror(errno) << " [errno=" << errno << "]";
376 Error(str);
377
378 return false;
379 }
380
381 fCounter = 0;
382
383 static uint32_t FACT = 0xFAC77e1e;
384
385 fOut.write(reinterpret_cast<char*>(&FACT), 4);
386
387 WriteBlockHeader(kIdentifier, 1, 0, 8);
388 WriteValue(uint32_t(0));
389 WriteValue(GetRunId());
390
391 WriteBlockHeader(kRunHeader, 1, 0, sizeof(RUN_HEAD)-sizeof(PEVNT_HEADER*));
392 fOut.write(reinterpret_cast<char*>(h), sizeof(RUN_HEAD)-sizeof(PEVNT_HEADER*));
393
394 for (int i=0; i<40; i++)
395 {
396 WriteBlockHeader(kBoardHeader, 1, i, sizeof(PEVNT_HEADER));
397 fOut.write(reinterpret_cast<char*>(h->FADhead+i), sizeof(PEVNT_HEADER));
398 }
399
400 // FIXME: Split this
401 const vector<char> block(sizeof(uint32_t)+sizeof(RUN_TAIL));
402 WriteBlockHeader(kRunSummary, 1, 0, block.size());
403
404 fPosTail = fOut.tellp();
405 fOut.write(block.data(), block.size());
406
407 if (!fOut)
408 {
409 ostringstream str;
410 str << "ofstream::write() failed for '" << name << "': " << strerror(errno) << " [errno=" << errno << "]";
411 Error(str);
412
413 return false;
414 }
415
416 return true;
417 }
418 bool WriteEvt(EVENT *evt)
419 {
420 const int sh = sizeof(EVENT)-2 + NPIX*evt->Roi*2;
421
422 WriteBlockHeader(kEvent, 1, fCounter++, sh);
423 fOut.write(reinterpret_cast<char*>(evt)+2, sh);
424 return true;
425 }
426 bool Close(RUN_TAIL *tail= 0)
427 {
428 WriteBlockHeader(kEndOfFile, 0, 0, 0);
429
430 if (tail)
431 {
432 fOut.seekp(fPosTail);
433
434 WriteValue(uint32_t(1));
435 fOut.write(reinterpret_cast<char*>(tail), sizeof(RUN_TAIL));
436 }
437
438 if (!fOut)
439 {
440 ostringstream str;
441
442 str << "ofstream::write() failed for '" << GetFileName() << "': " << strerror(errno) << " [errno=" << errno << "]";
443 Error(str);
444
445 return false;
446 }
447
448 fOut.close();
449
450 if (!fOut)
451 {
452 ostringstream str;
453 str << "ofstream::close() failed for '" << GetFileName() << "': " << strerror(errno) << " [errno=" << errno << "]";
454 Error(str);
455
456 return false;
457 }
458
459 return true;
460 }
461};
462
463#ifdef HAVE_FITS
464class DataFileFits : public DataFileImp
465{
466 CCfits::FITS* fFile; /// The pointer to the CCfits FITS file
467 CCfits::Table* fTable; /// The pointer to the CCfits binary table
468
469 uint64_t fNumRows; ///the number of rows that have been written already to the FITS file.
470
471 Converter *fConv;
472
473public:
474 DataFileFits(uint32_t runid, MessageImp &imp) :
475 DataFileImp(runid, imp), fFile(0), fNumRows(0), fConv(0)
476 {
477 }
478
479 // --------------------------------------------------------------------------
480 //
481 //! Default destructor
482 //! The Fits file SHOULD have been closed already, otherwise the informations
483 //! related to the RUN_TAIL will NOT be written to the file.
484 //
485 ~DataFileFits() { Close(); delete fConv; }
486
487 // --------------------------------------------------------------------------
488 //
489 //! Add a new column to the vectors storing the column data.
490 //! @param names the vector of string storing the columns names
491 //! @param types the vector of string storing the FITS data format
492 //! @param numElems the number of elements in this column
493 //! @param type the char describing the FITS data format
494 //! @param name the name of the particular column to be added.
495 //
496 inline void AddColumnEntry(vector<string>& names, vector<string>& types, int numElems, char type, string name)
497 {
498 names.push_back(name);
499
500 ostringstream str;
501 if (numElems != 1)
502 str << numElems;
503 str << type;
504 types.push_back(str.str());
505 }
506
507 // --------------------------------------------------------------------------
508 //
509 //! Writes a single header key entry
510 //! @param name the name of the key
511 //! @param value its value
512 //! @param comment the comment associated to that key
513 //
514 //FIXME this function is a duplicate from the class Fits. should we try to merge it ?
515 template <typename T>
516 void WriteKey(const string &name, const T &value, const string &comment)
517 {
518 try
519 {
520 fTable->addKey(name, value, comment);
521 }
522 catch (CCfits::FitsException e)
523 {
524 ostringstream str;
525 str << "Could not add header key " << name;
526 Error(str);
527 }
528 }
529
530 template <typename T>
531 void WriteKey(const string &name, const int idx, const T &value, const string &comment)
532 {
533 ostringstream str;
534 str << name << idx;
535
536 ostringstream com;
537 com << "Board " << setw(2) << idx << ": " << comment;
538
539 WriteKey(str.str(), value, com.str());
540 }
541
542 // --------------------------------------------------------------------------
543 //
544 //! DataFileFits constructor. This is the one that should be used, not the default one (parameter-less)
545 //! @param runid This parameter should probably be removed. I first thought it was the run number, but apparently it is not
546 //! @param h a pointer to the RUN_HEAD structure that contains the informations relative to this run
547 //
548 bool OpenFile(RUN_HEAD* h)
549 {
550 //Form filename, based on runid and run-type
551 const string fileName = FormFileName(GetRunId(), "fits");
552 if (access(fileName.c_str(), F_OK)==0)
553 {
554 Error("File '"+fileName+"' already exists.");
555 return false;
556 }
557
558 fFileName = fileName;
559
560 /*
561 out <<
562 "SIMPLE = T / file does conform to FITS standard "
563 "BITPIX = 8 / number of bits per data pixel "
564 "NAXIS = 0 / number of data axes "
565 "EXTEND = T / FITS dataset may contain extensions "
566 "COMMENT FITS (Flexible Image Transport System) format is defined in 'Astronomy"
567 "COMMENT and Astrophysics', volume 376, page 359; bibcode: 2001A&A...376..359H "
568 "END ";
569 for (int i=0; i<29; i++)
570 out << " "
571 */
572
573 //create the FITS object
574 try
575 {
576 fFile = new CCfits::FITS(fileName, CCfits::RWmode::Write);
577 }
578 catch (CCfits::FitsException e)
579 {
580 ostringstream str;
581 str << "Could not open FITS file " << fileName << ": " << e.message();
582 Error(str);
583 return false;
584 }
585
586 h->NroiTM = 0;
587
588 vector<string> colNames;
589 vector<string> dataTypes;
590 AddColumnEntry(colNames, dataTypes, 1, 'J', "EventNum");
591 AddColumnEntry(colNames, dataTypes, 1, 'J', "TriggerNum");
592 AddColumnEntry(colNames, dataTypes, 1, 'I', "TriggerType");
593 AddColumnEntry(colNames, dataTypes, 1, 'J', "NumBoards");
594 AddColumnEntry(colNames, dataTypes, 1, 'J', "Errors");
595 AddColumnEntry(colNames, dataTypes, 1, 'J', "reserved");
596 AddColumnEntry(colNames, dataTypes, 1, 'J', "SoftTrig");
597 AddColumnEntry(colNames, dataTypes, 2, 'J', "PCTime");
598 AddColumnEntry(colNames, dataTypes, h->NBoard, 'J', "BoardTime");
599 AddColumnEntry(colNames, dataTypes, h->NPix, 'I', "StartCellData");
600 AddColumnEntry(colNames, dataTypes, h->NTm, 'I', "StartCellTimeMarker");
601 AddColumnEntry(colNames, dataTypes, h->NPix*h->Nroi, 'I', "Data");
602 AddColumnEntry(colNames, dataTypes, h->NTm*h->NroiTM, 'I', "TimeMarker");
603
604 // Write length of physical pipeline (1024)
605
606 /*
607 ostringstream fmt;
608 fmt << "I:1"; // uint32_t EventNum
609 fmt << ";S:1"; // uint16_t TriggerType
610 fmt << ";I:5"; // uint32_t NumBoards, reserved, SoftTrig, PCTime, PCUsec
611 fmt << ";I:" << h->NBoard; // uint32_t BoardTime[NBOARDS]
612 fmt << ";S:" << h->NPix+h->NTm; // int16_t StartPix[NPIX], StartTM[NTMARK]
613 fmt << ";S:" << h->NPix*h->Nroi + h->NTm*h->NroiTM; // int16_t Adc_Data[]
614 */
615 fConv = new Converter(Converter::ToFormat(dataTypes));
616
617 //actually create the table
618 try
619 {
620 fTable = fFile->addTable("Events", 0, colNames, dataTypes);
621 }
622 catch (const CCfits::FitsException &e)
623 {
624 ostringstream str;
625 str << "Could not create FITS table 'Events' in file " << fileName << " reason: " << e.message();
626 Error(str);
627 return false;
628 }
629
630 if (fTable->rows() != 0)
631 {
632 Error("FITS table created on the fly looks non-empty.");
633 return false;
634 }
635
636 //write header data
637 //first the "standard" keys
638 WriteKey("EXTREL", 1.0f, "Release Number");
639 WriteKey("TELESCOP", "FACT", "Telescope that acquired this data");
640 WriteKey("ORIGIN", "ISDC", "Institution that wrote the file");
641 WriteKey("CREATOR", "fadctrl", "Program that wrote this file (FACT++ Event Builder)");
642
643 WriteKey("PACKAGE", PACKAGE_NAME, "Package name");
644 WriteKey("VERSION", PACKAGE_VERSION, "Package description");
645 WriteKey("COMPILED", __DATE__" "__TIME__, "Compile time");
646 WriteKey("REVISION", REVISION, "SVN revision");
647 //WriteKey("CONTACT", PACKAGE_BUGREPORT, "Current package maintainer");
648 //WriteKey("URL", PACKAGE_URL, "Current repositiory location");
649
650 WriteKey("BLDVER", h->Version, "Builder version");
651 WriteKey("RUNID", GetRunId(), "Run number");
652 WriteKey("RUNTYPE", h->RunType, "Type of run");
653 WriteKey("NBOARD", h->NBoard, "Number of acquisition boards");
654 WriteKey("NPIX", h->NPix, "Number of pixels");
655 WriteKey("NTMARK", h->NTm, "Number of Time marks");
656 WriteKey("NROI", h->Nroi, "Number of slices per pixels");
657 WriteKey("NROITM", h->NroiTM, "Number of slices per time-marker");
658
659 const Time now;
660 WriteKey("TIMESYS", "UTC", "Time system");
661 WriteKey("DATE", now.Iso(), "File creation date");
662 WriteKey("NIGHT", now.NightAsInt(), "Night as int");
663
664 //FIXME should we also put the start and stop time of the received data ?
665 //now the events header related variables
666 WriteKey("CAMERA", "MGeomCamFACT", "");
667 WriteKey("DAQ", "DRS4", "");
668
669 WriteKey("ADCCOUNT", 2.0f, "ADC Counts per milliVolt");
670
671 Info("==> TODO: Write sampling frequency...");
672
673 // Write a single key for:
674 // -----------------------
675 // Start package flag
676 // package length
677 // version number
678 // status
679 // Prescaler
680
681 // Write 40 kays for (?)
682 // Phaseshift
683 // DAC
684
685 for (int i=0; i<h->NBoard; i++)
686 {
687 const PEVNT_HEADER &hh = h->FADhead[i];
688
689 // Header values whihc won't change during the run
690 WriteKey("ID", i, hh.board_id, "Board ID");
691 WriteKey("DNA", i, hh.DNA, "DNA");
692 WriteKey("FWVER", i, hh.version_no, "Firmware Version");
693 }
694
695
696 /*
697 //now the boards related keywords
698 for (int i=0; i<h->NBoard; i++)
699 {
700 const PEVNT_HEADER &hh = h->FADhead[i];
701
702 WriteKey("STPKGFG", i, hh.start_package_flag, "Start package flag");
703 WriteKey("PKGLEN", i, hh.package_length, "Package length");
704 WriteKey("STATUS", i, hh.PLLLCK, "");
705
706// WriteKey("TRIGCRC", i, hh.trigger_crc, "Trigger CRC");
707// WriteKey("TRIGTYP", i, hh.trigger_type, "Trigger type");
708// WriteKey("TRIGID", i, hh.trigger_id, "Trigger ID");
709// WriteKey("EVTCNTR", i, hh.fad_evt_counter, "FAD Event Counter");
710// WriteKey("REFCLK", i, hh.REFCLK_frequency, "Reference Clock Frequency");
711
712 WriteKey("PHASESH", i, hh.adc_clock_phase_shift, "ADC clock phase shift");
713 WriteKey("TRGGEN", i, hh.number_of_triggers_to_generate, "Number of triggers to generate");
714 WriteKey("PRESC", i, hh.trigger_generator_prescaler, "Trigger generator prescaler");
715 WriteKey("RUNNB", i, hh.runnumber, "Run number");
716
717 WriteKey("TIME", i, hh.time, "Time");
718
719// for (int j=0;j<NTemp;j++)
720// {
721// str.str(""); str2.str("");
722// str << "DRS_T" << i << j;
723// str2 << "DRS temperature #" << i << " " << j;
724// WriteKey(str.str(), h->FADhead[i].drs_temperature[j], str2.str());
725// }
726 for (int j=0;j<NDAC;j++)
727 WriteKey("DAC", i*NDAC+j, hh.dac[j], "DAC");
728 }
729*/
730
731 //Last but not least, add header keys that will be updated when closing the file
732 WriteFooter(NULL);
733
734 return true;
735 }
736
737
738 int WriteColumns(size_t &start, size_t size, const void *e)
739 {
740 int status = 0;
741 fits_write_tblbytes(fFile->fitsPointer(), fNumRows, start, size,
742 (unsigned char*)e, &status);
743 if (status)
744 {
745 char text[30];//max length of cfitsio error strings (from doc)
746 fits_get_errstatus(status, text);
747
748 ostringstream str;
749 str << "Writing FITS row " << fNumRows << ": " << text << " (file_write_tblbytes, rc=" << status << ")";
750 Error(str);
751 }
752
753 start += size;
754 return status;
755 }
756
757 // --------------------------------------------------------------------------
758 //
759 //! This writes one event to the file
760 //! @param e the pointer to the EVENT
761 //
762 virtual bool WriteEvt(EVENT *e)
763 {
764 //FIXME As discussed earlier, we do not swap the bytes yet.
765 fTable->makeThisCurrent();
766
767 //insert a new row
768 int status(0);
769 if (fits_insert_rows(fTable->fitsPointer(), fNumRows, 1, &status))
770 {
771 char text[30];//max length of cfitsio error strings (from doc)
772 fits_get_errstatus(status, text);
773
774 ostringstream str;
775 str << "Inserting row " << fNumRows << " into " << fFileName << ": " << text << " (fits_insert_rows, rc=" << status << ")";
776 Error(str);
777
778 return false;
779 }
780 fNumRows++;
781
782 // FIXME: Get NPIX and NTMARK from header
783 const size_t sz = sizeof(EVENT) + sizeof(e->StartPix)*e->Roi+sizeof(e->StartTM)*e->RoiTM;
784
785 const vector<char> data = fConv->ToFits(reinterpret_cast<char*>(e)+4, sz-4);
786
787 // column size pointer
788 size_t col = 1;
789 if (!WriteColumns(col, data.size(), data.data()))
790 return true;
791
792 //TODO output an error
793 return false;
794
795 /*
796 //write the data, chunk by chunk
797 //FIXME hard-coded size corresponds to current variables of the event, in bytes.
798 //FIXME no padding was taken into account. Because smallest member is 2 bytes, I don't think that this should be a problem.
799 const long sizeInBytesOfEventBeforePointers = 16;
800
801 long col = 1;
802 if (FitsWriteTblBytes(col, sizeInBytesOfEventBeforePointers, e))
803 {
804 //TODO output an error
805 return false;
806 }
807 if (FitsWriteTblBytes(col, NBOARDS*2, e->BoardTime))
808 {
809 //TODO output an error
810 return false;
811 }
812 if (FitsWriteTblBytes(col, NPIX*2, e->StartPix))
813 {
814 //TODO output an error
815 return false;
816 }
817 if (FitsWriteTblBytes(col, NTMARK*2, e->StartTM))
818 {
819 //TODO output an error
820 return false;
821 }
822 if (FitsWriteTblBytes(col, NPIX*fRoi*2, e->Adc_Data))
823 {
824 //TODO output an error
825 return false;
826 }
827 return true;*/
828 }
829
830 void WriteFooter(RUN_TAIL *rt)
831 {
832 //write final header keys
833 fTable->makeThisCurrent();
834
835 WriteKey("NBEVTOK", rt ? rt->nEventsOk : uint32_t(0),
836 "How many events were written");
837
838 WriteKey("NBEVTREJ", rt ? rt->nEventsRej : uint32_t(0),
839 "How many events were rejected by SW-trig");
840
841 WriteKey("NBEVTBAD", rt ? rt->nEventsBad : uint32_t(0),
842 "How many events were rejected by Error");
843
844 //FIXME shouldn't we convert start and stop time to MjD first ?
845 //FIXME shouldn't we also add an MjD reference ?
846
847 WriteKey("TSTART", rt ? rt->PCtime0 : uint32_t(0),
848 "Time when first event received");
849
850 WriteKey("TSTOP", rt ? rt->PCtimeX : uint32_t(0),
851 "Time when last event received");
852 }
853
854 // --------------------------------------------------------------------------
855 //
856 //! Closes the file, and before this it write the TAIL data
857 //! @param rt the pointer to the RUN_TAIL data structure
858 //
859 virtual bool Close(RUN_TAIL *rt = 0)
860 {
861 if (!fFile)
862 return false;
863
864 WriteFooter(rt);
865
866 delete fFile;
867 fFile = NULL;
868
869 return true;
870 }
871
872};
873#else
874#define DataFileFits DataFileRaw
875#endif
876
877#include "DimWriteStatistics.h"
878
879class EventBuilderWrapper
880{
881public:
882 // FIXME
883 static EventBuilderWrapper *This;
884
885 MessageImp &fMsg;
886
887private:
888 boost::thread fThread;
889
890 enum CommandStates_t // g_runStat
891 {
892 kAbort = -2, // quit as soon as possible ('abort')
893 kExit = -1, // stop reading, quit when buffered events done ('exit')
894 kInitialize = 0, // 'initialize' (e.g. dim not yet started)
895 kHybernate = 1, // do nothing for long time ('hybernate') [wakeup within ~1sec]
896 kSleep = 2, // do nothing ('sleep') [wakeup within ~10msec]
897 kModeFlush = 10, // read data from camera, but skip them ('flush')
898 kModeTest = 20, // read data and process them, but do not write to disk ('test')
899 kModeFlag = 30, // read data, process and write all to disk ('flag')
900 kModeRun = 40, // read data, process and write selected to disk ('run')
901 };
902
903 enum
904 {
905 kCurrent = 0,
906 kTotal = 1,
907 kEventId = 2,
908 kTriggerId = 3,
909 };
910
911 enum FileFormat_t
912 {
913 kNone = 0,
914 kDebug,
915 kFits,
916 kRaw,
917 kCalib
918 };
919
920 FileFormat_t fFileFormat;
921
922
923 uint32_t fMaxRun;
924 uint32_t fLastOpened;
925 uint32_t fLastClosed;
926 uint32_t fNumEvts[4];
927
928 DimWriteStatistics fDimWriteStats;
929 DimDescribedService fDimRuns;
930 DimDescribedService fDimEvents;
931 DimDescribedService fDimEventData;
932 DimDescribedService fDimFwVersion;
933 DimDescribedService fDimRunNumber;
934 DimDescribedService fDimStatus;
935 DimDescribedService fDimDNA;
936 DimDescribedService fDimTemperature;
937 DimDescribedService fDimPrescaler;
938 DimDescribedService fDimRefClock;
939 DimDescribedService fDimRoi;
940 DimDescribedService fDimDac;
941 DimDescribedService fDimStatistics1;
942 DimDescribedService fDimStatistics2;
943
944 bool fDebugStream;
945 bool fDebugRead;
946 bool fDebugLog;
947
948 uint32_t fRunNumber;
949
950 void InitRunNumber()
951 {
952 // FIXME: Add a check that we are not too close to noon!
953 //const int night = Time().NightAsInt();
954
955 fRunNumber = 1000;
956
957 while (--fRunNumber>0)
958 {
959 const string name = DataFileImp::FormFileName(fRunNumber, "");
960
961 if (access((name+"bin").c_str(), F_OK) == 0)
962 break;
963 if (access((name+"fits").c_str(), F_OK) == 0)
964 break;
965 }
966
967 fRunNumber++;
968
969 ostringstream str;
970 str << "Starting with run number " << fRunNumber;
971 fMsg.Message(str);
972
973 fMsg.Info(" ==> TODO: Run-number detection doesn't work when noon passes!");
974 fMsg.Info(" ==> TODO: Crosscheck with database!");
975 }
976
977public:
978 EventBuilderWrapper(MessageImp &imp) : fMsg(imp),
979 fFileFormat(kNone), fMaxRun(0), fLastOpened(0), fLastClosed(0),
980 fDimWriteStats ("FAD_CONTROL", imp),
981 fDimRuns ("FAD_CONTROL/RUNS", "I:5;C", ""),
982 fDimEvents ("FAD_CONTROL/EVENTS", "I:4", ""),
983 fDimEventData ("FAD_CONTROL/EVENT_DATA", "S:1;I:1;S:1;I:1;I:2;I:40;S:1440;S:160;F", ""),
984 fDimFwVersion ("FAD_CONTROL/FIRMWARE_VERSION", "F:42", ""),
985 fDimRunNumber ("FAD_CONTROL/RUN_NUMBER", "I:42", ""),
986 fDimStatus ("FAD_CONTROL/STATUS", "S:42", ""),
987 fDimDNA ("FAD_CONTROL/DNA", "X:40", ""),
988 fDimTemperature ("FAD_CONTROL/TEMPERATURE", "F:82", ""),
989 fDimPrescaler ("FAD_CONTROL/PRESCALER", "S:42", ""),
990 fDimRefClock ("FAD_CONTROL/REFERENCE_CLOCK", "I:42", ""),
991 fDimRoi ("FAD_CONTROL/REGION_OF_INTEREST", "S:2", ""),
992 fDimDac ("FAD_CONTROL/DAC", "S:336", ""),
993 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", ""),
994 fDimStatistics2 ("FAD_CONTROL/STATISTICS2", "I:1;I:280;X:40;I:40;I:4;I:4;I:2;I:2;I:3;C:40", ""),
995 fDebugStream(false), fDebugRead(false), fDebugLog(false)
996 {
997 if (This)
998 throw logic_error("EventBuilderWrapper cannot be instantiated twice.");
999
1000 This = this;
1001
1002 memset(fNumEvts, 0, sizeof(fNumEvts));
1003
1004 fDimEvents.Update(fNumEvts);
1005
1006 for (size_t i=0; i<40; i++)
1007 ConnectSlot(i, tcp::endpoint());
1008
1009 InitRunNumber();
1010 }
1011 virtual ~EventBuilderWrapper()
1012 {
1013 Abort();
1014
1015 // FIXME: Used timed_join and abort afterwards
1016 // What's the maximum time the eb need to abort?
1017 fThread.join();
1018 //ffMsg.Info("EventBuilder stopped.");
1019
1020 for (vector<DataFileImp*>::iterator it=fFiles.begin(); it!=fFiles.end(); it++)
1021 delete *it;
1022 }
1023
1024 struct RunDescription
1025 {
1026 uint32_t maxtime;
1027 uint32_t maxevt;
1028
1029 FAD::Configuration reference;
1030 };
1031
1032 map<uint32_t, RunDescription> fExpectedRuns;
1033
1034 uint32_t StartNewRun(int64_t maxtime, int64_t maxevt, const FAD::Configuration &ref)
1035 {
1036 if (maxtime<=0 || maxtime>24*60*60)
1037 maxtime = 24*60*60;
1038 if (maxevt<=0 || maxevt>INT32_MAX)
1039 maxevt = INT32_MAX;
1040
1041 const RunDescription descr =
1042 {
1043 uint32_t(maxtime),
1044 uint32_t(maxevt),
1045 ref
1046 };
1047
1048 // FIMXE: Maybe reset an event counter so that the mcp can count events?
1049
1050 fExpectedRuns[fRunNumber] = descr;
1051 return fRunNumber++;
1052 }
1053
1054 bool IsThreadRunning()
1055 {
1056 return !fThread.timed_join(boost::posix_time::microseconds(0));
1057 }
1058
1059 void SetMaxMemory(unsigned int mb) const
1060 {
1061 /*
1062 if (mb*1000000<GetUsedMemory())
1063 {
1064 // ffMsg.Warn("...");
1065 return;
1066 }*/
1067
1068 g_maxMem = size_t(mb)*1000000;
1069 }
1070
1071 void StartThread(const vector<tcp::endpoint> &addr)
1072 {
1073 if (IsThreadRunning())
1074 {
1075 fMsg.Warn("Start - EventBuilder still running");
1076 return;
1077 }
1078
1079 fLastMessage.clear();
1080
1081 for (size_t i=0; i<40; i++)
1082 ConnectSlot(i, addr[i]);
1083
1084 g_runStat = kModeRun;
1085
1086 fMsg.Message("Starting EventBuilder thread");
1087
1088 fThread = boost::thread(StartEvtBuild);
1089 }
1090 void ConnectSlot(unsigned int i, const tcp::endpoint &addr)
1091 {
1092 if (i>39)
1093 return;
1094
1095 if (addr==tcp::endpoint())
1096 {
1097 DisconnectSlot(i);
1098 return;
1099 }
1100
1101 g_port[i].sockAddr.sin_family = AF_INET;
1102 g_port[i].sockAddr.sin_addr.s_addr = htonl(addr.address().to_v4().to_ulong());
1103 g_port[i].sockAddr.sin_port = htons(addr.port());
1104 // In this order
1105 g_port[i].sockDef = 1;
1106 }
1107 void DisconnectSlot(unsigned int i)
1108 {
1109 if (i>39)
1110 return;
1111
1112 g_port[i].sockDef = 0;
1113 // In this order
1114 g_port[i].sockAddr.sin_family = AF_INET;
1115 g_port[i].sockAddr.sin_addr.s_addr = 0;
1116 g_port[i].sockAddr.sin_port = 0;
1117 }
1118 void IgnoreSlot(unsigned int i)
1119 {
1120 if (i>39)
1121 return;
1122 if (g_port[i].sockAddr.sin_port==0)
1123 return;
1124
1125 g_port[i].sockDef = -1;
1126 }
1127
1128
1129 void Abort()
1130 {
1131 fMsg.Message("Signal abort to EventBuilder thread...");
1132 g_runStat = kAbort;
1133 }
1134
1135 void ResetThread(bool soft)
1136 {
1137 /*
1138 if (g_reset > 0)
1139
1140 * suspend reading
1141 * reset = g_reset;
1142 * g_reset=0
1143
1144 * reset% 10
1145 == 0 leave event Buffers as they are
1146 == 1 let all buffers drain (write (incomplete) events)
1147 > 1 flush all buffers (do not write buffered events)
1148
1149 * (reset/10)%10
1150 > 0 close all sockets and destroy them (also free the
1151 allocated read-buffers)
1152 recreate before resuming operation
1153 [ this is more than just close/open that can be
1154 triggered by e.g. close/open the base-socket ]
1155
1156 * (reset/100)%10
1157 > 0 close all open run-files
1158
1159 * (reset/1000)
1160 sleep so many seconds before resuming operation
1161 (does not (yet) take into account time left when waiting
1162 for buffers getting empty ...)
1163
1164 * resume_reading
1165
1166 */
1167 fMsg.Message("Signal reset to EventBuilder thread...");
1168 g_reset = soft ? 101 : 102;
1169 }
1170
1171 void Exit()
1172 {
1173 fMsg.Message("Signal exit to EventBuilder thread...");
1174 g_runStat = kExit;
1175 }
1176
1177 /*
1178 void Wait()
1179 {
1180 fThread.join();
1181 ffMsg.Message("EventBuilder stopped.");
1182 }*/
1183
1184 void Hybernate() const { g_runStat = kHybernate; }
1185 void Sleep() const { g_runStat = kSleep; }
1186 void FlushMode() const { g_runStat = kModeFlush; }
1187 void TestMode() const { g_runStat = kModeTest; }
1188 void FlagMode() const { g_runStat = kModeFlag; }
1189 void RunMode() const { g_runStat = kModeRun; }
1190
1191 // FIXME: To be removed
1192 void SetMode(int mode) const { g_runStat = mode; }
1193
1194 bool IsConnected(int i) const { return gi_NumConnect[i]==7; }
1195 bool IsConnecting(int i) const { return !IsConnected(i) && !IsDisconnected(i); }
1196 bool IsDisconnected(int i) const { return gi_NumConnect[i]<=0 && g_port[i].sockDef==0; }
1197 int GetNumConnected(int i) const { return gi_NumConnect[i]; }
1198
1199 void SetIgnore(int i, bool b) const { if (g_port[i].sockDef!=0) g_port[i].sockDef=b?-1:1; }
1200 bool IsIgnored(int i) const { return g_port[i].sockDef==-1; }
1201
1202 void SetOutputFormat(FileFormat_t f)
1203 {
1204 fFileFormat = f;
1205 if (fFileFormat==kCalib)
1206 DataFileCalib::Restart();
1207 }
1208
1209 void SetDebugLog(bool b) { fDebugLog = b; }
1210
1211 void SetDebugStream(bool b)
1212 {
1213 fDebugStream = b;
1214 if (b)
1215 return;
1216
1217 for (int i=0; i<40; i++)
1218 {
1219 if (!fDumpStream[i].is_open())
1220 continue;
1221
1222 fDumpStream[i].close();
1223
1224 ostringstream name;
1225 name << "socket_dump-" << setfill('0') << setw(2) << i << ".bin";
1226 fMsg.Message("Closed file '"+name.str()+"'");
1227 }
1228 }
1229
1230 void SetDebugRead(bool b)
1231 {
1232 fDebugRead = b;
1233 if (b || !fDumpRead.is_open())
1234 return;
1235
1236 fDumpRead.close();
1237 fMsg.Message("Closed file 'socket_events.txt'");
1238 }
1239
1240// size_t GetUsedMemory() const { return gi_usedMem; }
1241
1242 virtual int CloseOpenFiles() { CloseRunFile(0, 0, 0); return 0; }
1243
1244
1245 /*
1246 struct OpenFileToDim
1247 {
1248 int code;
1249 char fileName[FILENAME_MAX];
1250 };
1251
1252 SignalRunOpened(runid, filename);
1253 // Send num open files
1254 // Send runid, (more info about the run?), filename via dim
1255
1256 SignalEvtWritten(runid);
1257 // Send num events written of newest file
1258
1259 SignalRunClose(runid);
1260 // Send new num open files
1261 // Send empty file-name if no file is open
1262
1263 */
1264
1265 // -------------- Mapped event builder callbacks ------------------
1266
1267 void UpdateRuns(const string &fname="")
1268 {
1269 uint32_t values[5] =
1270 {
1271 static_cast<uint32_t>(fFiles.size()),
1272 0xffffffff,
1273 0,
1274 fLastOpened,
1275 fLastClosed
1276 };
1277
1278 for (vector<DataFileImp*>::const_iterator it=fFiles.begin();
1279 it!=fFiles.end(); it++)
1280 {
1281 const DataFileImp *file = *it;
1282
1283 if (file->GetRunId()<values[1])
1284 values[1] = file->GetRunId();
1285
1286 if (file->GetRunId()>values[2])
1287 values[2] = file->GetRunId();
1288 }
1289
1290 fMaxRun = values[2];
1291
1292 vector<char> data(sizeof(values)+fname.size()+1);
1293 memcpy(data.data(), values, sizeof(values));
1294 strcpy(data.data()+sizeof(values), fname.c_str());
1295
1296 fDimRuns.Update(data);
1297 }
1298
1299 vector<DataFileImp*> fFiles;
1300
1301 FileHandle_t runOpen(uint32_t runid, RUN_HEAD *h, size_t)
1302 {
1303 fMsg.Info(" ==> TODO: Update run configuration in database!");
1304
1305 // Check if file already exists...
1306 DataFileImp *file = 0;
1307 switch (fFileFormat)
1308 {
1309 case kNone: file = new DataFileNone(runid, fMsg); break;
1310 case kDebug: file = new DataFileDebug(runid, fMsg); break;
1311 case kFits: file = new DataFileFits(runid, fMsg); break;
1312 case kRaw: file = new DataFileRaw(runid, fMsg); break;
1313 case kCalib: file = new DataFileCalib(runid, fMsg); break;
1314 }
1315
1316 try
1317 {
1318 if (!file->OpenFile(h))
1319 return 0;
1320 }
1321 catch (const exception &e)
1322 {
1323 fMsg.Error("Exception trying to open file: "+string(e.what()));
1324 return 0;
1325 }
1326
1327 fFiles.push_back(file);
1328
1329 ostringstream str;
1330 str << "Opened: " << file->GetFileName() << " (" << file->GetRunId() << ")";
1331 fMsg.Info(str);
1332
1333 fDimWriteStats.FileOpened(file->GetFileName());
1334
1335 fLastOpened = runid;
1336 UpdateRuns(file->GetFileName());
1337
1338 fNumEvts[kEventId] = 0;
1339 fNumEvts[kTriggerId] = 0;
1340
1341 fNumEvts[kCurrent] = 0;
1342 fDimEvents.Update(fNumEvts);
1343 // fDimCurrentEvent.Update(uint32_t(0));
1344
1345 return reinterpret_cast<FileHandle_t>(file);
1346 }
1347
1348 int runWrite(FileHandle_t handler, EVENT *e, size_t)
1349 {
1350 DataFileImp *file = reinterpret_cast<DataFileImp*>(handler);
1351
1352 if (!file->WriteEvt(e))
1353 return -1;
1354
1355 if (file->GetRunId()==fMaxRun)
1356 {
1357 fNumEvts[kCurrent]++;
1358 fNumEvts[kEventId] = e->EventNum;
1359 fNumEvts[kTriggerId] = e->TriggerNum;
1360 }
1361
1362 fNumEvts[kTotal]++;
1363
1364 static Time oldt(boost::date_time::neg_infin);
1365 Time newt;
1366 if (newt>oldt+boost::posix_time::seconds(1))
1367 {
1368 fDimEvents.Update(fNumEvts);
1369 oldt = newt;
1370 }
1371
1372
1373 // ===> SignalEvtWritten(runid);
1374 // Send num events written of newest file
1375
1376 /* close run runId (all all runs if runId=0) */
1377 /* return: 0=close scheduled / >0 already closed / <0 does not exist */
1378 //CloseRunFile(file->GetRunId(), time(NULL)+2) ;
1379
1380 return 0;
1381 }
1382
1383 int runClose(FileHandle_t handler, RUN_TAIL *tail, size_t)
1384 {
1385 fMsg.Info(" ==> TODO: Update run configuration in database!");
1386
1387 DataFileImp *file = reinterpret_cast<DataFileImp*>(handler);
1388
1389 const vector<DataFileImp*>::iterator it = find(fFiles.begin(), fFiles.end(), file);
1390 if (it==fFiles.end())
1391 {
1392 ostringstream str;
1393 str << "File handler (" << handler << ") requested to close by event builder doesn't exist.";
1394 fMsg.Fatal(str);
1395 return -1;
1396 }
1397
1398 fFiles.erase(it);
1399
1400 fLastClosed = file->GetRunId();
1401 UpdateRuns();
1402
1403 fDimEvents.Update(fNumEvts);
1404
1405 const bool rc = file->Close(tail);
1406 if (!rc)
1407 {
1408 // Error message
1409 }
1410
1411 ostringstream str;
1412 str << "Closed: " << file->GetFileName() << " (" << file->GetRunId() << ")";
1413 fMsg.Info(str);
1414
1415 delete file;
1416
1417 // ==> SignalRunClose(runid);
1418 // Send new num open files
1419 // Send empty file-name if no file is open
1420
1421 return rc ? 0 : -1;
1422 }
1423
1424 ofstream fDumpStream[40];
1425
1426 void debugStream(int isock, void *buf, int len)
1427 {
1428 if (!fDebugStream)
1429 return;
1430
1431 const int slot = isock/7;
1432 if (slot<0 || slot>39)
1433 return;
1434
1435 if (!fDumpStream[slot].is_open())
1436 {
1437 ostringstream name;
1438 name << "socket_dump-" << setfill('0') << setw(2) << slot << ".bin";
1439
1440 fDumpStream[slot].open(name.str().c_str(), ios::app);
1441 if (!fDumpStream[slot])
1442 {
1443 ostringstream str;
1444 str << "Open file '" << name << "': " << strerror(errno) << " (errno=" << errno << ")";
1445 fMsg.Error(str);
1446
1447 return;
1448 }
1449
1450 fMsg.Message("Opened file '"+name.str()+"' for writing.");
1451 }
1452
1453 fDumpStream[slot].write(reinterpret_cast<const char*>(buf), len);
1454 }
1455
1456 ofstream fDumpRead; // Stream to possibly dump docket events
1457
1458 void debugRead(int isock, int ibyte, uint32_t event, uint32_t ftmevt, uint32_t runno, int state, uint32_t tsec, uint32_t tusec)
1459 {
1460 // isock = socketID (0-279)
1461 // ibyte = #bytes gelesen
1462 // event = eventId (oder 0 wenn noch nicht bekannt)
1463 // state : 1=finished reading data
1464 // 0=reading data
1465 // -1=start reading data (header)
1466 // -2=start reading data,
1467 // eventId not known yet (too little data)
1468 // tsec, tusec = time when reading seconds, microseconds
1469 //
1470 if (!fDebugRead || ibyte==0)
1471 return;
1472
1473 if (!fDumpRead.is_open())
1474 {
1475 fDumpRead.open("socket_events.txt", ios::app);
1476 if (!fDumpRead)
1477 {
1478 ostringstream str;
1479 str << "Open file 'socket_events.txt': " << strerror(errno) << " (errno=" << errno << ")";
1480 fMsg.Error(str);
1481
1482 return;
1483 }
1484
1485 fMsg.Message("Opened file 'socket_events.txt' for writing.");
1486
1487 fDumpRead << "# START: " << Time().GetAsStr() << endl;
1488 fDumpRead << "# state time_sec time_usec socket slot runno event_id trigger_id bytes_received" << endl;
1489 }
1490
1491 fDumpRead
1492 << setw(2) << state << " "
1493 << setw(8) << tsec << " "
1494 << setw(9) << tusec << " "
1495 << setw(3) << isock << " "
1496 << setw(2) << isock/7 << " "
1497 << runno << " "
1498 << event << " "
1499 << ftmevt << " "
1500 << ibyte << endl;
1501 }
1502
1503 array<uint16_t,2> fVecRoi;
1504
1505 int eventCheck(PEVNT_HEADER *fadhd, EVENT *event)
1506 {
1507 /*
1508 fadhd[i] ist ein array mit den 40 fad-headers
1509 (falls ein board nicht gelesen wurde, ist start_package_flag =0 )
1510
1511 event ist die Struktur, die auch die write routine erhaelt;
1512 darin sind im header die 'soll-werte' fuer z.B. eventID
1513 als auch die ADC-Werte (falls Du die brauchst)
1514
1515 Wenn die routine einen negativen Wert liefert, wird das event
1516 geloescht (nicht an die write-routine weitergeleitet [mind. im Prinzip]
1517 */
1518
1519 const array<uint16_t,2> roi = {{ event->Roi, event->RoiTM }};
1520
1521 if (roi!=fVecRoi)
1522 {
1523 Update(fDimRoi, roi);
1524 fVecRoi = roi;
1525 }
1526
1527 const FAD::EventHeader *beg = reinterpret_cast<FAD::EventHeader*>(fadhd);
1528 const FAD::EventHeader *end = reinterpret_cast<FAD::EventHeader*>(fadhd)+40;
1529
1530 for (const FAD::EventHeader *ptr=beg; ptr!=end; ptr++)
1531 {
1532 // Event incomplete
1533 //if (ptr->fStartDelimiter==0)
1534 // return -1;
1535
1536 // Either one of
1537 // * fStatus
1538 // * fRunNumber
1539 // * fEventCounter
1540 // * fAdcClockPhaseShift
1541 // * fTriggerGeneratorPrescaler
1542 // * fDac
1543 // inconsistent
1544
1545 // FIXME: Produce some output, only once per run or
1546 // minute
1547
1548 /*
1549 if (*ptr != *beg)
1550 return -1;
1551
1552 if (ptr->fTriggerType != beg->fTriggerType)
1553 return -1;
1554 if (ptr->fTriggerId != beg->fTriggerId)
1555 return -1;
1556 if (ptr->fVersion != beg->fVersion)
1557 return -1;
1558 */
1559 }
1560
1561 // check REFCLK_frequency
1562 // check consistency with command configuration
1563 // how to log errors?
1564 // need gotNewRun/closedRun to know it is finished
1565
1566 static Time oldt(boost::date_time::neg_infin);
1567 Time newt;
1568
1569 if (newt<oldt+boost::posix_time::seconds(1))
1570 return 0;
1571
1572 oldt = newt;
1573
1574 const size_t sz = sizeof(EVENT)+event->Roi*2*1440;
1575
1576 vector<char> data(sz+event->Roi*2*1440);
1577 memcpy(data.data(), event, sizeof(EVENT));
1578
1579 DataFileCalib::Apply(reinterpret_cast<float*>(data.data()+sizeof(EVENT)),
1580 event->Adc_Data, event->StartPix, event->Roi);
1581
1582 fDimEventData.Update(data);
1583
1584 return 0;
1585 }
1586
1587 bool IsRunStarted() const
1588 {
1589 return fExpectedRuns.find(fRunNumber-1)==fExpectedRuns.end();
1590 }
1591
1592 void gotNewRun(int runnr, PEVNT_HEADER */*headers*/)
1593 {
1594 // This function is called even when writing is switched off
1595 const map<uint32_t,RunDescription>::iterator it = fExpectedRuns.find(runnr);
1596 if (it==fExpectedRuns.end())
1597 {
1598 ostringstream str;
1599 str << "gotNewRun - Run " << runnr << " wasn't expected." << endl;
1600 return;
1601 }
1602
1603 CloseRunFile(runnr, time(NULL)+it->second.maxtime, it->second.maxevt);
1604 // return: 0=close scheduled / >0 already closed / <0 does not exist
1605
1606 fExpectedRuns.erase(it);
1607 }
1608
1609 map<boost::thread::id, string> fLastMessage;
1610
1611 void factOut(int severity, int err, const char *message)
1612 {
1613 if (!fDebugLog && severity==99)
1614 return;
1615
1616 ostringstream str;
1617 //str << boost::this_thread::get_id() << " ";
1618 str << "EventBuilder(";
1619 if (err<0)
1620 str << "---";
1621 else
1622 str << err;
1623 str << "): " << message;
1624
1625 string &old = fLastMessage[boost::this_thread::get_id()];
1626
1627 if (str.str()==old)
1628 return;
1629 old = str.str();
1630
1631 fMsg.Update(str, severity);
1632 }
1633/*
1634 void factStat(int64_t *stat, int len)
1635 {
1636 if (len!=7)
1637 {
1638 fMsg.Warn("factStat received unknown number of values.");
1639 return;
1640 }
1641
1642 vector<int64_t> data(1, g_maxMem);
1643 data.insert(data.end(), stat, stat+len);
1644
1645 static vector<int64_t> last(8);
1646 if (data==last)
1647 return;
1648 last = data;
1649
1650 fDimStatistics.Update(data);
1651
1652 // len ist die Laenge des arrays.
1653 // array[4] enthaelt wieviele bytes im Buffer aktuell belegt sind; daran
1654 // kannst Du pruefen, ob die 100MB voll sind ....
1655
1656 ostringstream str;
1657 str
1658 << "Wait=" << stat[0] << " "
1659 << "Skip=" << stat[1] << " "
1660 << "Del=" << stat[2] << " "
1661 << "Tot=" << stat[3] << " "
1662 << "Mem=" << stat[4] << "/" << g_maxMem << " "
1663 << "Read=" << stat[5] << " "
1664 << "Conn=" << stat[6];
1665
1666 fMsg.Info(str);
1667 }
1668 */
1669
1670 void factStat(const EVT_STAT &stat)
1671 {
1672 fDimStatistics2.Update(stat);
1673 /*
1674 //some info about what happened since start of program (or last 'reset')
1675 uint32_t reset ; //#if increased, reset all counters
1676 uint32_t numRead[MAX_SOCK] ; //how often succesfull read from N sockets per loop
1677
1678 uint64_t gotByte[NBOARDS] ; //#Bytes read per Board
1679 uint32_t gotErr[NBOARDS] ; //#Communication Errors per Board
1680 uint32_t evtGet; //#new Start of Events read
1681 uint32_t evtTot; //#complete Events read
1682 uint32_t evtErr; //#Events with Errors
1683 uint32_t evtSkp; //#Events incomplete (timeout)
1684
1685 uint32_t procTot; //#Events processed
1686 uint32_t procErr; //#Events showed problem in processing
1687 uint32_t procTrg; //#Events accepted by SW trigger
1688 uint32_t procSkp; //#Events rejected by SW trigger
1689
1690 uint32_t feedTot; //#Events used for feedBack system
1691 uint32_t feedErr; //#Events rejected by feedBack
1692
1693 uint32_t wrtTot; //#Events written to disk
1694 uint32_t wrtErr; //#Events with write-error
1695
1696 uint32_t runOpen; //#Runs opened
1697 uint32_t runClose; //#Runs closed
1698 uint32_t runErr; //#Runs with open/close errors
1699
1700
1701 //info about current connection status
1702 uint8_t numConn[NBOARDS] ; //#Sockets succesfully open per board
1703 */
1704 }
1705
1706 void factStat(const GUI_STAT &stat)
1707 {
1708 fDimStatistics1.Update(stat);
1709 /*
1710 //info about status of the main threads
1711 int32_t readStat ; //read thread
1712 int32_t procStat ; //processing thread(s)
1713 int32_t writStat ; //write thread
1714
1715 //info about some rates
1716 int32_t deltaT ; //time in milli-seconds for rates
1717 int32_t readEvt ; //#events read
1718 int32_t procEvt ; //#events processed
1719 int32_t writEvt ; //#events written
1720 int32_t skipEvt ; //#events skipped
1721
1722 //some info about current state of event buffer (snapspot)
1723 int32_t evtBuf; //#Events currently waiting in Buffer
1724 uint64_t totMem; //#Bytes available in Buffer
1725 uint64_t usdMem; //#Bytes currently used
1726 uint64_t maxMem; //max #Bytes used during past Second
1727 */
1728 }
1729
1730
1731 array<FAD::EventHeader, 40> fVecHeader;
1732
1733 template<typename T, class S>
1734 array<T, 42> Compare(const S *vec, const T *t)
1735 {
1736 const int offset = reinterpret_cast<const char *>(t) - reinterpret_cast<const char *>(vec);
1737
1738 const T *min = NULL;
1739 const T *val = NULL;
1740 const T *max = NULL;
1741
1742 array<T, 42> arr;
1743
1744 bool rc = true;
1745 for (int i=0; i<40; i++)
1746 {
1747 const char *base = reinterpret_cast<const char*>(vec+i);
1748 const T *ref = reinterpret_cast<const T*>(base+offset);
1749
1750 arr[i] = *ref;
1751
1752 if (gi_NumConnect[i]!=7)
1753 {
1754 arr[i] = 0;
1755 continue;
1756 }
1757
1758 if (!val)
1759 {
1760 min = ref;
1761 val = ref;
1762 max = ref;
1763 }
1764
1765 if (*ref<*min)
1766 min = ref;
1767
1768 if (*ref>*max)
1769 max = ref;
1770
1771 if (*val!=*ref)
1772 rc = false;
1773 }
1774
1775 arr[40] = val ? *min : 1;
1776 arr[41] = val ? *max : 0;
1777
1778 return arr;
1779 }
1780
1781 template<typename T>
1782 array<T, 42> CompareBits(const FAD::EventHeader *h, const T *t)
1783 {
1784 const int offset = reinterpret_cast<const char *>(t) - reinterpret_cast<const char *>(h);
1785
1786 T val = 0;
1787 T rc = 0;
1788
1789 array<T, 42> vec;
1790
1791 bool first = true;
1792
1793 for (int i=0; i<40; i++)
1794 {
1795 const char *base = reinterpret_cast<const char*>(&fVecHeader[i]);
1796 const T *ref = reinterpret_cast<const T*>(base+offset);
1797
1798 vec[i+2] = *ref;
1799
1800 if (gi_NumConnect[i]!=7)
1801 {
1802 vec[i+2] = 0;
1803 continue;
1804 }
1805
1806 if (first)
1807 {
1808 first = false;
1809 val = *ref;
1810 rc = 0;
1811 }
1812
1813 rc |= val^*ref;
1814 }
1815
1816 vec[0] = rc;
1817 vec[1] = val;
1818
1819 return vec;
1820 }
1821
1822 template<typename T, size_t N>
1823 void Update(DimDescribedService &svc, const array<T, N> &data, int n=N)
1824 {
1825// svc.setQuality(vec[40]<=vec[41]);
1826 svc.setData(const_cast<T*>(data.data()), sizeof(T)*n);
1827 svc.updateService();
1828 }
1829
1830 template<typename T>
1831 void Print(const char *name, const pair<bool,array<T, 43>> &data)
1832 {
1833 cout << name << "|" << data.first << "|" << data.second[1] << "|" << data.second[0] << "<x<" << data.second[1] << ":";
1834 for (int i=0; i<40;i++)
1835 cout << " " << data.second[i+3];
1836 cout << endl;
1837 }
1838
1839 vector<uint> fNumConnected;
1840
1841 void debugHead(int /*socket*/, const FAD::EventHeader &h)
1842 {
1843 const uint16_t id = h.Id();
1844 if (id>39)
1845 return;
1846
1847 if (fNumConnected.size()!=40)
1848 fNumConnected.resize(40);
1849
1850 const vector<uint> con(gi_NumConnect, gi_NumConnect+40);
1851
1852 const bool changed = con!=fNumConnected || !IsThreadRunning();
1853
1854 fNumConnected = con;
1855
1856 const FAD::EventHeader old = fVecHeader[id];
1857 fVecHeader[id] = h;
1858
1859 if (old.fVersion != h.fVersion || changed)
1860 {
1861 const array<uint16_t,42> ver = Compare(&fVecHeader[0], &fVecHeader[0].fVersion);
1862
1863 array<float,42> data;
1864 for (int i=0; i<42; i++)
1865 {
1866 ostringstream str;
1867 str << (ver[i]>>8) << '.' << (ver[i]&0xff);
1868 data[i] = stof(str.str());
1869 }
1870 Update(fDimFwVersion, data);
1871 }
1872
1873 if (old.fRunNumber != h.fRunNumber || changed)
1874 {
1875 const array<uint32_t,42> run = Compare(&fVecHeader[0], &fVecHeader[0].fRunNumber);
1876 fDimRunNumber.Update(run);
1877 }
1878
1879 if (old.fTriggerGeneratorPrescaler != h.fTriggerGeneratorPrescaler || changed)
1880 {
1881 const array<uint16_t,42> pre = Compare(&fVecHeader[0], &fVecHeader[0].fTriggerGeneratorPrescaler);
1882 fDimPrescaler.Update(pre);
1883 }
1884
1885 if (old.fDNA != h.fDNA || changed)
1886 {
1887 const array<uint64_t,42> dna = Compare(&fVecHeader[0], &fVecHeader[0].fDNA);
1888 Update(fDimDNA, dna, 40);
1889 }
1890
1891 if (old.fStatus != h.fStatus || changed)
1892 {
1893 const array<uint16_t,42> sts = CompareBits(&fVecHeader[0], &fVecHeader[0].fStatus);
1894 Update(fDimStatus, sts);
1895 }
1896
1897 if (memcmp(old.fDac, h.fDac, sizeof(h.fDac)) || changed)
1898 {
1899 array<uint16_t, FAD::kNumDac*42> dacs;
1900
1901 for (int i=0; i<FAD::kNumDac; i++)
1902 {
1903 const array<uint16_t, 42> dac = Compare(&fVecHeader[0], &fVecHeader[0].fDac[i]);
1904 memcpy(&dacs[i*42], &dac[0], sizeof(uint16_t)*42);
1905 }
1906
1907 Update(fDimDac, dacs);
1908 }
1909
1910 // -----------
1911
1912 static Time oldt(boost::date_time::neg_infin);
1913 Time newt;
1914
1915 if (newt>oldt+boost::posix_time::seconds(1))
1916 {
1917 oldt = newt;
1918
1919 // --- RefClock
1920
1921 const array<uint32_t,42> clk = Compare(&fVecHeader[0], &fVecHeader[0].fFreqRefClock);
1922 Update(fDimRefClock, clk);
1923
1924 // --- Temperatures
1925
1926 const array<int16_t,42> tmp[4] =
1927 {
1928 Compare(&fVecHeader[0], &fVecHeader[0].fTempDrs[0]), // 0-39:val, 40:min, 41:max
1929 Compare(&fVecHeader[0], &fVecHeader[0].fTempDrs[1]), // 0-39:val, 40:min, 41:max
1930 Compare(&fVecHeader[0], &fVecHeader[0].fTempDrs[2]), // 0-39:val, 40:min, 41:max
1931 Compare(&fVecHeader[0], &fVecHeader[0].fTempDrs[3]) // 0-39:val, 40:min, 41:max
1932 };
1933
1934 vector<int16_t> data;
1935 data.reserve(82);
1936 data.push_back(tmp[0][40]); // min: 0
1937 data.insert(data.end(), tmp[0].data(), tmp[0].data()+40); // val: 1-40
1938 data.push_back(tmp[0][41]); // max: 41
1939 data.insert(data.end(), tmp[0].data(), tmp[0].data()+40); // val: 42-81
1940
1941 for (int j=1; j<=3; j++)
1942 {
1943 const array<int16_t,42> &ref = tmp[j];
1944
1945 // Gloabl min
1946 if (ref[40]<data[0]) // 40=min
1947 data[0] = ref[40];
1948
1949 // Global max
1950 if (ref[41]>data[41]) // 41=max
1951 data[41] = ref[41];
1952
1953 for (int i=0; i<40; i++)
1954 {
1955 // min per board
1956 if (ref[i]<data[i+1]) // data: 1-40
1957 data[i+1] = ref[i]; // ref: 0-39
1958
1959 // max per board
1960 if (ref[i]>data[i+42]) // data: 42-81
1961 data[i+42] = ref[i]; // ref: 0-39
1962 }
1963
1964
1965 }
1966
1967 vector<float> deg(82); // 0: global min, 1-40: min
1968 for (int i=0; i<82; i++) // 41: global max, 42-81: max
1969 deg[i] = data[i]/16.;
1970 fDimTemperature.Update(deg);
1971 }
1972
1973 /*
1974 uint16_t fTriggerType;
1975 uint32_t fTriggerId;
1976 uint32_t fEventCounter;
1977 uint16_t fAdcClockPhaseShift;
1978 uint16_t fNumTriggersToGenerate;
1979 uint16_t fTriggerGeneratorPrescaler;
1980 uint32_t fTimeStamp;
1981 int16_t fTempDrs[kNumTemp]; // In units of 1/16 deg(?)
1982 uint16_t fDac[kNumDac];
1983 */
1984 }
1985};
1986
1987EventBuilderWrapper *EventBuilderWrapper::This = 0;
1988
1989// ----------- Event builder callbacks implementation ---------------
1990extern "C"
1991{
1992 FileHandle_t runOpen(uint32_t irun, RUN_HEAD *runhd, size_t len)
1993 {
1994 return EventBuilderWrapper::This->runOpen(irun, runhd, len);
1995 }
1996
1997 int runWrite(FileHandle_t fileId, EVENT *event, size_t len)
1998 {
1999 return EventBuilderWrapper::This->runWrite(fileId, event, len);
2000 }
2001
2002 int runClose(FileHandle_t fileId, RUN_TAIL *runth, size_t len)
2003 {
2004 return EventBuilderWrapper::This->runClose(fileId, runth, len);
2005 }
2006
2007 void factOut(int severity, int err, const char *message)
2008 {
2009 EventBuilderWrapper::This->factOut(severity, err, message);
2010 }
2011
2012 void factStat(GUI_STAT stat)
2013 {
2014 EventBuilderWrapper::This->factStat(stat);
2015 }
2016
2017 void factStatNew(EVT_STAT stat)
2018 {
2019 EventBuilderWrapper::This->factStat(stat);
2020 }
2021
2022 void debugHead(int socket, int/*board*/, void *buf)
2023 {
2024 const uint16_t *ptr = reinterpret_cast<uint16_t*>(buf);
2025
2026 EventBuilderWrapper::This->debugHead(socket, FAD::EventHeader(ptr));
2027 }
2028
2029 void debugStream(int isock, void *buf, int len)
2030 {
2031 return EventBuilderWrapper::This->debugStream(isock, buf, len);
2032 }
2033
2034 void debugRead(int isock, int ibyte, int32_t event, int32_t ftmevt, int32_t runno, int state, uint32_t tsec, uint32_t tusec)
2035 {
2036 EventBuilderWrapper::This->debugRead(isock, ibyte, event, ftmevt, runno, state, tsec, tusec);
2037 }
2038
2039 int eventCheck(PEVNT_HEADER *fadhd, EVENT *event)
2040 {
2041 return EventBuilderWrapper::This->eventCheck(fadhd, event);
2042 }
2043
2044 void gotNewRun( int runnr, PEVNT_HEADER *headers )
2045 {
2046 return EventBuilderWrapper::This->gotNewRun(runnr, headers);
2047 }
2048}
2049
2050#endif
Note: See TracBrowser for help on using the repository browser.