#ifndef FACT_EventBuilderWrapper #define FACT_EventBuilderWrapper #include #if BOOST_VERSION < 104400 #if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 4)) #undef BOOST_HAS_RVALUE_REFS #endif #endif #include #include #include "DimWriteStatistics.h" #include "DataCalib.h" #include "DataWriteRaw.h" #ifdef HAVE_FITS #include "DataWriteFits.h" #else #define DataWriteFits DataWriteRaw #endif namespace ba = boost::asio; namespace bs = boost::system; using ba::ip::tcp; using namespace std; // ======================================================================== #include "EventBuilder.h" extern "C" { extern void StartEvtBuild(); extern int CloseRunFile(uint32_t runId, uint32_t closeTime, uint32_t maxEvt); } // ======================================================================== class EventBuilderWrapper { public: // FIXME static EventBuilderWrapper *This; MessageImp &fMsg; private: boost::thread fThread; enum CommandStates_t // g_runStat { kAbort = -2, // quit as soon as possible ('abort') kExit = -1, // stop reading, quit when buffered events done ('exit') kInitialize = 0, // 'initialize' (e.g. dim not yet started) kHybernate = 1, // do nothing for long time ('hybernate') [wakeup within ~1sec] kSleep = 2, // do nothing ('sleep') [wakeup within ~10msec] kModeFlush = 10, // read data from camera, but skip them ('flush') kModeTest = 20, // read data and process them, but do not write to disk ('test') kModeFlag = 30, // read data, process and write all to disk ('flag') kModeRun = 40, // read data, process and write selected to disk ('run') }; enum { kCurrent = 0, kTotal = 1, kEventId = 2, kTriggerId = 3, }; enum FileFormat_t { kNone = 0, kDebug, kFits, kRaw, kCalib }; FileFormat_t fFileFormat; uint32_t fMaxRun; uint32_t fLastOpened; uint32_t fLastClosed; uint32_t fNumEvts[4]; DimWriteStatistics fDimWriteStats; DimDescribedService fDimRuns; DimDescribedService fDimEvents; DimDescribedService fDimRawData; DimDescribedService fDimEventData; DimDescribedService fDimFwVersion; DimDescribedService fDimRunNumber; DimDescribedService fDimStatus; DimDescribedService fDimDNA; DimDescribedService fDimTemperature; DimDescribedService fDimPrescaler; DimDescribedService fDimRefClock; DimDescribedService fDimRoi; DimDescribedService fDimDac; DimDescribedService fDimDrsCalibration; DimDescribedService fDimStatistics1; DimDescribedService fDimStatistics2; bool fDebugStream; bool fDebugRead; bool fDebugLog; uint32_t fRunNumber; void InitRunNumber() { // FIXME: Add a check that we are not too close to noon! //const int night = Time().NightAsInt(); fRunNumber = 1000; while (--fRunNumber>0) { const string name = DataProcessorImp::FormFileName(fRunNumber, ""); if (access((name+"bin").c_str(), F_OK) == 0) break; if (access((name+"fits").c_str(), F_OK) == 0) break; if (access((name+"drs.fits").c_str(), F_OK) == 0) break; } fRunNumber++; ostringstream str; str << "Starting with run number " << fRunNumber; fMsg.Message(str); fMsg.Info(" ==> TODO: Run-number detection doesn't work when noon passes!"); fMsg.Info(" ==> TODO: Crosscheck with database!"); } public: EventBuilderWrapper(MessageImp &imp) : fMsg(imp), fFileFormat(kNone), fMaxRun(0), fLastOpened(0), fLastClosed(0), fDimWriteStats ("FAD_CONTROL", imp), fDimRuns ("FAD_CONTROL/RUNS", "I:5;C", ""), fDimEvents ("FAD_CONTROL/EVENTS", "I:4", ""), fDimRawData ("FAD_CONTROL/RAW_DATA", "S:1;I:1;S:1;I:1;I:2;I:40;S:1440;S:160;F", ""), fDimEventData ("FAD_CONTROL/EVENT_DATA", "F:1440;F:1440;F:1440;F:1440", ""), fDimFwVersion ("FAD_CONTROL/FIRMWARE_VERSION", "F:42", ""), fDimRunNumber ("FAD_CONTROL/RUN_NUMBER", "I:42", ""), fDimStatus ("FAD_CONTROL/STATUS", "S:42", ""), fDimDNA ("FAD_CONTROL/DNA", "X:40", ""), fDimTemperature ("FAD_CONTROL/TEMPERATURE", "F:82", ""), fDimPrescaler ("FAD_CONTROL/PRESCALER", "S:42", ""), fDimRefClock ("FAD_CONTROL/REFERENCE_CLOCK", "I:42", ""), fDimRoi ("FAD_CONTROL/REGION_OF_INTEREST", "S:2", ""), fDimDac ("FAD_CONTROL/DAC", "S:336", ""), fDimDrsCalibration("FAD_CONTROL/DRS_CALIBRATION", "I:3;F:1474560;F:1474560;F:1474560;F:1474560;F:1474560;F:1474560", ""), 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", ""), fDimStatistics2 ("FAD_CONTROL/STATISTICS2", "I:1;I:280;X:40;I:40;I:4;I:4;I:2;I:2;I:3;C:40", ""), fDebugStream(false), fDebugRead(false), fDebugLog(false) { if (This) throw logic_error("EventBuilderWrapper cannot be instantiated twice."); This = this; memset(fNumEvts, 0, sizeof(fNumEvts)); fDimEvents.Update(fNumEvts); for (size_t i=0; i<40; i++) ConnectSlot(i, tcp::endpoint()); InitRunNumber(); } virtual ~EventBuilderWrapper() { Abort(); // FIXME: Used timed_join and abort afterwards // What's the maximum time the eb need to abort? fThread.join(); //ffMsg.Info("EventBuilder stopped."); for (vector::iterator it=fFiles.begin(); it!=fFiles.end(); it++) delete *it; } struct RunDescription { uint32_t maxtime; uint32_t maxevt; FAD::Configuration reference; }; map fExpectedRuns; uint32_t StartNewRun(int64_t maxtime, int64_t maxevt, const FAD::Configuration &ref) { if (maxtime<=0 || maxtime>24*60*60) maxtime = 24*60*60; if (maxevt<=0 || maxevt>INT32_MAX) maxevt = INT32_MAX; const RunDescription descr = { uint32_t(maxtime), uint32_t(maxevt), ref }; // FIMXE: Maybe reset an event counter so that the mcp can count events? fExpectedRuns[fRunNumber] = descr; return fRunNumber++; } bool IsThreadRunning() { return !fThread.timed_join(boost::posix_time::microseconds(0)); } void SetMaxMemory(unsigned int mb) const { /* if (mb*1000000 &addr) { if (IsThreadRunning()) { fMsg.Warn("Start - EventBuilder still running"); return; } fLastMessage.clear(); for (size_t i=0; i<40; i++) ConnectSlot(i, addr[i]); g_runStat = kModeRun; fMsg.Message("Starting EventBuilder thread"); fThread = boost::thread(StartEvtBuild); } void ConnectSlot(unsigned int i, const tcp::endpoint &addr) { if (i>39) return; if (addr==tcp::endpoint()) { DisconnectSlot(i); return; } g_port[i].sockAddr.sin_family = AF_INET; g_port[i].sockAddr.sin_addr.s_addr = htonl(addr.address().to_v4().to_ulong()); g_port[i].sockAddr.sin_port = htons(addr.port()); // In this order g_port[i].sockDef = 1; } void DisconnectSlot(unsigned int i) { if (i>39) return; g_port[i].sockDef = 0; // In this order g_port[i].sockAddr.sin_family = AF_INET; g_port[i].sockAddr.sin_addr.s_addr = 0; g_port[i].sockAddr.sin_port = 0; } void IgnoreSlot(unsigned int i) { if (i>39) return; if (g_port[i].sockAddr.sin_port==0) return; g_port[i].sockDef = -1; } void Abort() { fMsg.Message("Signal abort to EventBuilder thread..."); g_runStat = kAbort; } void ResetThread(bool soft) { /* if (g_reset > 0) * suspend reading * reset = g_reset; * g_reset=0 * reset% 10 == 0 leave event Buffers as they are == 1 let all buffers drain (write (incomplete) events) > 1 flush all buffers (do not write buffered events) * (reset/10)%10 > 0 close all sockets and destroy them (also free the allocated read-buffers) recreate before resuming operation [ this is more than just close/open that can be triggered by e.g. close/open the base-socket ] * (reset/100)%10 > 0 close all open run-files * (reset/1000) sleep so many seconds before resuming operation (does not (yet) take into account time left when waiting for buffers getting empty ...) * resume_reading */ fMsg.Message("Signal reset to EventBuilder thread..."); g_reset = soft ? 101 : 102; } void Exit() { fMsg.Message("Signal exit to EventBuilder thread..."); g_runStat = kExit; } /* void Wait() { fThread.join(); ffMsg.Message("EventBuilder stopped."); }*/ void Hybernate() const { g_runStat = kHybernate; } void Sleep() const { g_runStat = kSleep; } void FlushMode() const { g_runStat = kModeFlush; } void TestMode() const { g_runStat = kModeTest; } void FlagMode() const { g_runStat = kModeFlag; } void RunMode() const { g_runStat = kModeRun; } // FIXME: To be removed void SetMode(int mode) const { g_runStat = mode; } bool IsConnected(int i) const { return gi_NumConnect[i]==7; } bool IsConnecting(int i) const { return !IsConnected(i) && !IsDisconnected(i); } bool IsDisconnected(int i) const { return gi_NumConnect[i]<=0 && g_port[i].sockDef==0; } int GetNumConnected(int i) const { return gi_NumConnect[i]; } void SetIgnore(int i, bool b) const { if (g_port[i].sockDef!=0) g_port[i].sockDef=b?-1:1; } bool IsIgnored(int i) const { return g_port[i].sockDef==-1; } void SetOutputFormat(FileFormat_t f) { fFileFormat = f; if (fFileFormat==kCalib) { DataCalib::Restart(); DataCalib::Update(fDimDrsCalibration); fMsg.Message("Resetted DRS calibration."); } } void SetDebugLog(bool b) { fDebugLog = b; } void SetDebugStream(bool b) { fDebugStream = b; if (b) return; for (int i=0; i<40; i++) { if (!fDumpStream[i].is_open()) continue; fDumpStream[i].close(); ostringstream name; name << "socket_dump-" << setfill('0') << setw(2) << i << ".bin"; fMsg.Message("Closed file '"+name.str()+"'"); } } void SetDebugRead(bool b) { fDebugRead = b; if (b || !fDumpRead.is_open()) return; fDumpRead.close(); fMsg.Message("Closed file 'socket_events.txt'"); } // size_t GetUsedMemory() const { return gi_usedMem; } virtual int CloseOpenFiles() { CloseRunFile(0, 0, 0); return 0; } /* struct OpenFileToDim { int code; char fileName[FILENAME_MAX]; }; SignalRunOpened(runid, filename); // Send num open files // Send runid, (more info about the run?), filename via dim SignalEvtWritten(runid); // Send num events written of newest file SignalRunClose(runid); // Send new num open files // Send empty file-name if no file is open */ // -------------- Mapped event builder callbacks ------------------ void UpdateRuns(const string &fname="") { uint32_t values[5] = { static_cast(fFiles.size()), 0xffffffff, 0, fLastOpened, fLastClosed }; for (vector::const_iterator it=fFiles.begin(); it!=fFiles.end(); it++) { const DataProcessorImp *file = *it; if (file->GetRunId()GetRunId(); if (file->GetRunId()>values[2]) values[2] = file->GetRunId(); } fMaxRun = values[2]; vector data(sizeof(values)+fname.size()+1); memcpy(data.data(), values, sizeof(values)); strcpy(data.data()+sizeof(values), fname.c_str()); fDimRuns.Update(data); } vector fFiles; FileHandle_t runOpen(uint32_t runid, RUN_HEAD *h, size_t) { fMsg.Info(" ==> TODO: Update run configuration in database!"); // Check if file already exists... DataProcessorImp *file = 0; switch (fFileFormat) { case kNone: file = new DataDump(runid, fMsg); break; case kDebug: file = new DataDebug(runid, fMsg); break; case kFits: file = new DataWriteFits(runid, fMsg); break; case kRaw: file = new DataWriteRaw(runid, fMsg); break; case kCalib: file = new DataCalib(runid, fDimDrsCalibration, fMsg); break; } try { if (!file->Open(h)) return 0; } catch (const exception &e) { fMsg.Error("Exception trying to open file: "+string(e.what())); return 0; } fFiles.push_back(file); ostringstream str; str << "Opened: " << file->GetFileName() << " (" << file->GetRunId() << ")"; fMsg.Info(str); fDimWriteStats.FileOpened(file->GetFileName()); fLastOpened = runid; UpdateRuns(file->GetFileName()); fNumEvts[kEventId] = 0; fNumEvts[kTriggerId] = 0; fNumEvts[kCurrent] = 0; fDimEvents.Update(fNumEvts); // fDimCurrentEvent.Update(uint32_t(0)); return reinterpret_cast(file); } int runWrite(FileHandle_t handler, EVENT *e, size_t) { DataProcessorImp *file = reinterpret_cast(handler); if (!file->WriteEvt(e)) return -1; if (file->GetRunId()==fMaxRun) { fNumEvts[kCurrent]++; fNumEvts[kEventId] = e->EventNum; fNumEvts[kTriggerId] = e->TriggerNum; } fNumEvts[kTotal]++; static Time oldt(boost::date_time::neg_infin); Time newt; if (newt>oldt+boost::posix_time::seconds(1)) { fDimEvents.Update(fNumEvts); oldt = newt; } // ===> SignalEvtWritten(runid); // Send num events written of newest file /* close run runId (all all runs if runId=0) */ /* return: 0=close scheduled / >0 already closed / <0 does not exist */ //CloseRunFile(file->GetRunId(), time(NULL)+2) ; return 0; } int runClose(FileHandle_t handler, RUN_TAIL *tail, size_t) { fMsg.Info(" ==> TODO: Update run configuration in database!"); DataProcessorImp *file = reinterpret_cast(handler); const vector::iterator it = find(fFiles.begin(), fFiles.end(), file); if (it==fFiles.end()) { ostringstream str; str << "File handler (" << handler << ") requested to close by event builder doesn't exist."; fMsg.Fatal(str); return -1; } fFiles.erase(it); fLastClosed = file->GetRunId(); UpdateRuns(); fDimEvents.Update(fNumEvts); const bool rc = file->Close(tail); if (!rc) { // Error message } ostringstream str; str << "Closed: " << file->GetFileName() << " (" << file->GetRunId() << ")"; fMsg.Info(str); delete file; // ==> SignalRunClose(runid); // Send new num open files // Send empty file-name if no file is open return rc ? 0 : -1; } ofstream fDumpStream[40]; void debugStream(int isock, void *buf, int len) { if (!fDebugStream) return; const int slot = isock/7; if (slot<0 || slot>39) return; if (!fDumpStream[slot].is_open()) { ostringstream name; name << "socket_dump-" << setfill('0') << setw(2) << slot << ".bin"; fDumpStream[slot].open(name.str().c_str(), ios::app); if (!fDumpStream[slot]) { ostringstream str; str << "Open file '" << name << "': " << strerror(errno) << " (errno=" << errno << ")"; fMsg.Error(str); return; } fMsg.Message("Opened file '"+name.str()+"' for writing."); } fDumpStream[slot].write(reinterpret_cast(buf), len); } ofstream fDumpRead; // Stream to possibly dump docket events void debugRead(int isock, int ibyte, uint32_t event, uint32_t ftmevt, uint32_t runno, int state, uint32_t tsec, uint32_t tusec) { // isock = socketID (0-279) // ibyte = #bytes gelesen // event = eventId (oder 0 wenn noch nicht bekannt) // state : 1=finished reading data // 0=reading data // -1=start reading data (header) // -2=start reading data, // eventId not known yet (too little data) // tsec, tusec = time when reading seconds, microseconds // if (!fDebugRead || ibyte==0) return; if (!fDumpRead.is_open()) { fDumpRead.open("socket_events.txt", ios::app); if (!fDumpRead) { ostringstream str; str << "Open file 'socket_events.txt': " << strerror(errno) << " (errno=" << errno << ")"; fMsg.Error(str); return; } fMsg.Message("Opened file 'socket_events.txt' for writing."); fDumpRead << "# START: " << Time().GetAsStr() << endl; fDumpRead << "# state time_sec time_usec socket slot runno event_id trigger_id bytes_received" << endl; } fDumpRead << setw(2) << state << " " << setw(8) << tsec << " " << setw(9) << tusec << " " << setw(3) << isock << " " << setw(2) << isock/7 << " " << runno << " " << event << " " << ftmevt << " " << ibyte << endl; } array fVecRoi; int eventCheck(uint32_t runNr, PEVNT_HEADER *fadhd, EVENT *event) { /* fadhd[i] ist ein array mit den 40 fad-headers (falls ein board nicht gelesen wurde, ist start_package_flag =0 ) event ist die Struktur, die auch die write routine erhaelt; darin sind im header die 'soll-werte' fuer z.B. eventID als auch die ADC-Werte (falls Du die brauchst) Wenn die routine einen negativen Wert liefert, wird das event geloescht (nicht an die write-routine weitergeleitet [mind. im Prinzip] */ const array roi = {{ event->Roi, event->RoiTM }}; if (roi!=fVecRoi) { Update(fDimRoi, roi); fVecRoi = roi; } const FAD::EventHeader *beg = reinterpret_cast(fadhd); const FAD::EventHeader *end = reinterpret_cast(fadhd)+40; for (const FAD::EventHeader *ptr=beg; ptr!=end; ptr++) { // Event incomplete //if (ptr->fStartDelimiter==0) // return -1; // Either one of // * fStatus // * fRunNumber // * fEventCounter // * fAdcClockPhaseShift // * fTriggerGeneratorPrescaler // * fDac // inconsistent // FIXME: Produce some output, only once per run or // minute /* if (*ptr != *beg) return -1; if (ptr->fTriggerType != beg->fTriggerType) return -1; if (ptr->fTriggerId != beg->fTriggerId) return -1; if (ptr->fVersion != beg->fVersion) return -1; */ } // check REFCLK_frequency // check consistency with command configuration // how to log errors? // need gotNewRun/closedRun to know it is finished static Time oldt(boost::date_time::neg_infin); Time newt; // FIXME: Only send events if the have newer run-numbers if (newtRoi*2*1440; vector data(sz+event->Roi*2*1440); memcpy(data.data(), event, sizeof(EVENT)); float *vec = reinterpret_cast(data.data()+sizeof(EVENT)); DataCalib::Apply(vec, event->Adc_Data, event->StartPix, event->Roi); fDimRawData.Update(data); vector data2(1440*4); // Mean, RMS, Max, Pos CalibData::GetPixelStats(data2.data(), vec, event->Roi); fDimEventData.Update(data2); return 0; } bool IsRunStarted() const { return fExpectedRuns.find(fRunNumber-1)==fExpectedRuns.end(); } void gotNewRun(int runnr, PEVNT_HEADER */*headers*/) { // This function is called even when writing is switched off const map::iterator it = fExpectedRuns.find(runnr); if (it==fExpectedRuns.end()) { ostringstream str; str << "gotNewRun - Run " << runnr << " wasn't expected." << endl; return; } CloseRunFile(runnr, time(NULL)+it->second.maxtime, it->second.maxevt); // return: 0=close scheduled / >0 already closed / <0 does not exist fExpectedRuns.erase(it); } map fLastMessage; void factOut(int severity, int err, const char *message) { if (!fDebugLog && severity==99) return; ostringstream str; //str << boost::this_thread::get_id() << " "; str << "EventBuilder("; if (err<0) str << "---"; else str << err; str << "): " << message; string &old = fLastMessage[boost::this_thread::get_id()]; if (str.str()==old) return; old = str.str(); fMsg.Update(str, severity); } /* void factStat(int64_t *stat, int len) { if (len!=7) { fMsg.Warn("factStat received unknown number of values."); return; } vector data(1, g_maxMem); data.insert(data.end(), stat, stat+len); static vector last(8); if (data==last) return; last = data; fDimStatistics.Update(data); // len ist die Laenge des arrays. // array[4] enthaelt wieviele bytes im Buffer aktuell belegt sind; daran // kannst Du pruefen, ob die 100MB voll sind .... ostringstream str; str << "Wait=" << stat[0] << " " << "Skip=" << stat[1] << " " << "Del=" << stat[2] << " " << "Tot=" << stat[3] << " " << "Mem=" << stat[4] << "/" << g_maxMem << " " << "Read=" << stat[5] << " " << "Conn=" << stat[6]; fMsg.Info(str); } */ void factStat(const EVT_STAT &stat) { fDimStatistics2.Update(stat); /* //some info about what happened since start of program (or last 'reset') uint32_t reset ; //#if increased, reset all counters uint32_t numRead[MAX_SOCK] ; //how often succesfull read from N sockets per loop uint64_t gotByte[NBOARDS] ; //#Bytes read per Board uint32_t gotErr[NBOARDS] ; //#Communication Errors per Board uint32_t evtGet; //#new Start of Events read uint32_t evtTot; //#complete Events read uint32_t evtErr; //#Events with Errors uint32_t evtSkp; //#Events incomplete (timeout) uint32_t procTot; //#Events processed uint32_t procErr; //#Events showed problem in processing uint32_t procTrg; //#Events accepted by SW trigger uint32_t procSkp; //#Events rejected by SW trigger uint32_t feedTot; //#Events used for feedBack system uint32_t feedErr; //#Events rejected by feedBack uint32_t wrtTot; //#Events written to disk uint32_t wrtErr; //#Events with write-error uint32_t runOpen; //#Runs opened uint32_t runClose; //#Runs closed uint32_t runErr; //#Runs with open/close errors //info about current connection status uint8_t numConn[NBOARDS] ; //#Sockets succesfully open per board */ } void factStat(const GUI_STAT &stat) { fDimStatistics1.Update(stat); /* //info about status of the main threads int32_t readStat ; //read thread int32_t procStat ; //processing thread(s) int32_t writStat ; //write thread //info about some rates int32_t deltaT ; //time in milli-seconds for rates int32_t readEvt ; //#events read int32_t procEvt ; //#events processed int32_t writEvt ; //#events written int32_t skipEvt ; //#events skipped //some info about current state of event buffer (snapspot) int32_t evtBuf; //#Events currently waiting in Buffer uint64_t totMem; //#Bytes available in Buffer uint64_t usdMem; //#Bytes currently used uint64_t maxMem; //max #Bytes used during past Second */ } array fVecHeader; template array Compare(const S *vec, const T *t) { const int offset = reinterpret_cast(t) - reinterpret_cast(vec); const T *min = NULL; const T *val = NULL; const T *max = NULL; array arr; bool rc = true; for (int i=0; i<40; i++) { const char *base = reinterpret_cast(vec+i); const T *ref = reinterpret_cast(base+offset); arr[i] = *ref; if (gi_NumConnect[i]!=7) { arr[i] = 0; continue; } if (!val) { min = ref; val = ref; max = ref; } if (*ref<*min) min = ref; if (*ref>*max) max = ref; if (*val!=*ref) rc = false; } arr[40] = val ? *min : 1; arr[41] = val ? *max : 0; return arr; } template array CompareBits(const FAD::EventHeader *h, const T *t) { const int offset = reinterpret_cast(t) - reinterpret_cast(h); T val = 0; T rc = 0; array vec; bool first = true; for (int i=0; i<40; i++) { const char *base = reinterpret_cast(&fVecHeader[i]); const T *ref = reinterpret_cast(base+offset); vec[i+2] = *ref; if (gi_NumConnect[i]!=7) { vec[i+2] = 0; continue; } if (first) { first = false; val = *ref; rc = 0; } rc |= val^*ref; } vec[0] = rc; vec[1] = val; return vec; } template void Update(DimDescribedService &svc, const array &data, int n=N) { // svc.setQuality(vec[40]<=vec[41]); svc.setData(const_cast(data.data()), sizeof(T)*n); svc.updateService(); } template void Print(const char *name, const pair> &data) { cout << name << "|" << data.first << "|" << data.second[1] << "|" << data.second[0] << " fNumConnected; void debugHead(int /*socket*/, const FAD::EventHeader &h) { const uint16_t id = h.Id(); if (id>39) return; if (fNumConnected.size()!=40) fNumConnected.resize(40); const vector con(gi_NumConnect, gi_NumConnect+40); const bool changed = con!=fNumConnected || !IsThreadRunning(); fNumConnected = con; const FAD::EventHeader old = fVecHeader[id]; fVecHeader[id] = h; if (old.fVersion != h.fVersion || changed) { const array ver = Compare(&fVecHeader[0], &fVecHeader[0].fVersion); array data; for (int i=0; i<42; i++) { ostringstream str; str << (ver[i]>>8) << '.' << (ver[i]&0xff); data[i] = stof(str.str()); } Update(fDimFwVersion, data); } if (old.fRunNumber != h.fRunNumber || changed) { const array run = Compare(&fVecHeader[0], &fVecHeader[0].fRunNumber); fDimRunNumber.Update(run); } if (old.fTriggerGeneratorPrescaler != h.fTriggerGeneratorPrescaler || changed) { const array pre = Compare(&fVecHeader[0], &fVecHeader[0].fTriggerGeneratorPrescaler); fDimPrescaler.Update(pre); } if (old.fDNA != h.fDNA || changed) { const array dna = Compare(&fVecHeader[0], &fVecHeader[0].fDNA); Update(fDimDNA, dna, 40); } if (old.fStatus != h.fStatus || changed) { const array sts = CompareBits(&fVecHeader[0], &fVecHeader[0].fStatus); Update(fDimStatus, sts); } if (memcmp(old.fDac, h.fDac, sizeof(h.fDac)) || changed) { array dacs; for (int i=0; i dac = Compare(&fVecHeader[0], &fVecHeader[0].fDac[i]); memcpy(&dacs[i*42], &dac[0], sizeof(uint16_t)*42); } Update(fDimDac, dacs); } // ----------- static Time oldt(boost::date_time::neg_infin); Time newt; if (newt>oldt+boost::posix_time::seconds(1)) { oldt = newt; // --- RefClock const array clk = Compare(&fVecHeader[0], &fVecHeader[0].fFreqRefClock); Update(fDimRefClock, clk); // --- Temperatures const array tmp[4] = { Compare(&fVecHeader[0], &fVecHeader[0].fTempDrs[0]), // 0-39:val, 40:min, 41:max Compare(&fVecHeader[0], &fVecHeader[0].fTempDrs[1]), // 0-39:val, 40:min, 41:max Compare(&fVecHeader[0], &fVecHeader[0].fTempDrs[2]), // 0-39:val, 40:min, 41:max Compare(&fVecHeader[0], &fVecHeader[0].fTempDrs[3]) // 0-39:val, 40:min, 41:max }; vector data; data.reserve(82); data.push_back(tmp[0][40]); // min: 0 data.insert(data.end(), tmp[0].data(), tmp[0].data()+40); // val: 1-40 data.push_back(tmp[0][41]); // max: 41 data.insert(data.end(), tmp[0].data(), tmp[0].data()+40); // val: 42-81 for (int j=1; j<=3; j++) { const array &ref = tmp[j]; // Gloabl min if (ref[40]data[41]) // 41=max data[41] = ref[41]; for (int i=0; i<40; i++) { // min per board if (ref[i]data[i+42]) // data: 42-81 data[i+42] = ref[i]; // ref: 0-39 } } vector deg(82); // 0: global min, 1-40: min for (int i=0; i<82; i++) // 41: global max, 42-81: max deg[i] = data[i]/16.; fDimTemperature.Update(deg); } /* uint16_t fTriggerType; uint32_t fTriggerId; uint32_t fEventCounter; uint16_t fAdcClockPhaseShift; uint16_t fNumTriggersToGenerate; uint16_t fTriggerGeneratorPrescaler; uint32_t fTimeStamp; int16_t fTempDrs[kNumTemp]; // In units of 1/16 deg(?) uint16_t fDac[kNumDac]; */ } }; EventBuilderWrapper *EventBuilderWrapper::This = 0; // ----------- Event builder callbacks implementation --------------- extern "C" { FileHandle_t runOpen(uint32_t irun, RUN_HEAD *runhd, size_t len) { return EventBuilderWrapper::This->runOpen(irun, runhd, len); } int runWrite(FileHandle_t fileId, EVENT *event, size_t len) { return EventBuilderWrapper::This->runWrite(fileId, event, len); } int runClose(FileHandle_t fileId, RUN_TAIL *runth, size_t len) { return EventBuilderWrapper::This->runClose(fileId, runth, len); } void factOut(int severity, int err, const char *message) { EventBuilderWrapper::This->factOut(severity, err, message); } void factStat(GUI_STAT stat) { EventBuilderWrapper::This->factStat(stat); } void factStatNew(EVT_STAT stat) { EventBuilderWrapper::This->factStat(stat); } void debugHead(int socket, int/*board*/, void *buf) { const uint16_t *ptr = reinterpret_cast(buf); EventBuilderWrapper::This->debugHead(socket, FAD::EventHeader(ptr)); } void debugStream(int isock, void *buf, int len) { return EventBuilderWrapper::This->debugStream(isock, buf, len); } void debugRead(int isock, int ibyte, int32_t event, int32_t ftmevt, int32_t runno, int state, uint32_t tsec, uint32_t tusec) { EventBuilderWrapper::This->debugRead(isock, ibyte, event, ftmevt, runno, state, tsec, tusec); } int eventCheck(uint32_t runNr, PEVNT_HEADER *fadhd, EVENT *event) { return EventBuilderWrapper::This->eventCheck(runNr, fadhd, event); } void gotNewRun(int runnr, PEVNT_HEADER *headers) { return EventBuilderWrapper::This->gotNewRun(runnr, headers); } int subProcEvt(int threadID, PEVNT_HEADER *fadhd, EVENT *event, int8_t *buffer) { return 100; } } #endif