source: trunk/FACT++/gui/FactGui.h @ 10750

Last change on this file since 10750 was 10750, checked in by tbretz, 9 years ago
Added FAD control widgets; added graphs for all rates delivered by FTM.
File size: 61.5 KB
Line 
1#ifndef FACT_FactGui
2#define FACT_FactGui
3
4#include "MainWindow.h"
5
6#include <iomanip>
7#include <valarray>
8
9#include <boost/bind.hpp>
10
11#include <QTimer>
12#include <QStandardItemModel>
13
14#include "CheckBoxDelegate.h"
15
16#include "src/Dim.h"
17#include "src/Converter.h"
18#include "src/HeadersFTM.h"
19#include "src/HeadersFAD.h"
20#include "src/DimNetwork.h"
21#include "src/tools.h"
22
23#include "TROOT.h"
24#include "TSystem.h"
25#include "TGraph.h"
26#include "TH1.h"
27#include "TStyle.h"
28#include "TMarker.h"
29#include "TColor.h"
30
31using namespace std;
32
33// #########################################################################
34
35class Camera : public TObject
36{
37    typedef pair<double,double> Position;
38    typedef vector<Position> Positions;
39
40    Positions fGeom;
41
42    void CreatePalette()
43    {
44        /*
45         double ss[5] = {0., 0.10, 0.45, 0.75, 1.00};
46         double rr[5] = {0., 0.35, 0.85, 1.00, 1.00};
47         double gg[5] = {0., 0.10, 0.20, 0.73, 1.00};
48         double bb[5] = {0., 0.03, 0.06, 0.00, 1.00};
49         */
50        double ss[5] = {0., 0.25, 0.50, 0.75, 1.00};
51        double rr[5] = {0., 0.00, 0.00, 1.00, 1.00};
52        double gg[5] = {0., 0.00, 1.00, 0.00, 1.00};
53        double bb[5] = {0., 1.00, 0.00, 0.00, 1.00};
54
55        const Int_t nn = 1440;
56
57        Int_t idx = TColor::CreateGradientColorTable(5, ss, rr, gg, bb, nn);
58        for (int i=0; i<nn; i++)
59            fPalette.push_back(idx++);
60    }
61
62    void CreateGeometry()
63    {
64        const double gsSin60 = sqrt(3.)/2;
65
66        const int rings = 23;
67
68        //  add the first pixel to the list
69
70        fGeom.push_back(make_pair(0, -0.5));
71
72        for (int ring=1; ring<=rings; ring++)
73        {
74            for (int s=0; s<6; s++)
75            {
76                for (int i=1; i<=ring; i++)
77                {
78                    double xx, yy;
79                    switch (s)
80                    {
81                    case 0: // Direction South East
82                        xx = (ring+i)*0.5;
83                        yy = (-ring+i)*gsSin60;
84                        break;
85
86                    case 1: // Direction North East
87                        xx = ring-i*0.5;
88                        yy = i*gsSin60;
89                        break;
90
91                    case 2: // Direction North
92                        xx = ring*0.5-i;
93                        yy = ring*gsSin60;
94                        break;
95
96                    case 3: // Direction North West
97                        xx = -(ring+i)*0.5;
98                        yy = (ring-i)*gsSin60;
99                        break;
100
101                    case 4: // Direction South West
102                        xx = 0.5*i-ring;
103                        yy = -i*gsSin60;
104                        break;
105
106                    case 5: // Direction South
107                        xx = i-ring*0.5;
108                        yy = -ring*gsSin60;
109                        break;
110                    }
111
112                    if (xx*xx + yy*yy - xx > 395.75)
113                        continue;
114
115                    fGeom.push_back(make_pair(yy, xx-0.5));
116                }
117            }
118        }
119    }
120
121    valarray<double> fData;
122    vector<bool>   fBold;
123    vector<bool>   fEnable;
124
125    int fWhite;
126
127public:
128    Camera() : fData(1440), fBold(1440), fEnable(1440), fWhite(-1)
129    {
130        CreatePalette();
131        CreateGeometry();
132
133        for (int i=0; i<1440; i++)
134        {
135            fData[i] = i;
136            fBold[i]=false;
137            fEnable[i]=true;
138        }
139    }
140
141    void Reset() { fBold.assign(1440, false); }
142
143    void SetBold(int idx) { fBold[idx]=true; }
144    void SetWhite(int idx) { fWhite=idx; }
145    void SetEnable(int idx, bool b) { fEnable[idx]=b; }
146    void Toggle(int idx) { fEnable[idx]=!fEnable[idx]; }
147    double GetData(int idx) const { return fData[idx]; }
148
149    const char *GetName() const { return "Camera"; }
150
151    vector<Int_t> fPalette;
152
153    void Paint(const Position &p)
154    {
155        static const Double_t fgCos60 = 0.5;        // TMath::Cos(60/TMath::RadToDeg());
156        static const Double_t fgSin60 = sqrt(3.)/2; // TMath::Sin(60/TMath::RadToDeg());
157
158        static const Double_t fgDy[6] = { fgCos60,   0.,         -fgCos60,   -fgCos60,    0.,           fgCos60   };
159        static const Double_t fgDx[6] = { fgSin60/3, fgSin60*2/3, fgSin60/3, -fgSin60/3, -fgSin60*2/3, -fgSin60/3 };
160
161        //
162        //  calculate the positions of the pixel corners
163        //
164        Double_t x[7], y[7];
165        for (Int_t i=0; i<7; i++)
166        {
167            x[i] = p.first  + fgDx[i%6];
168            y[i] = p.second + fgDy[i%6];
169        }
170
171        gPad->PaintFillArea(6, x, y);
172        gPad->PaintPolyLine(7, x, y);
173
174    }
175
176    void Paint(Option_t *)
177    {
178        gStyle->SetPalette(fPalette.size(), fPalette.data());
179
180
181        const double r   = double(gPad->GetWw())/gPad->GetWh();
182        const double max = 20.5; // 20.5 rings in x and y
183
184        if (r>1)
185            gPad->Range(-r*max, -max, r*max, max);
186        else
187            gPad->Range(-max, -max/r, max, max/r);
188
189
190        const double min   = fData.min();
191        const double scale = fData.max()==fData.min() ? 1 : fData.max()-fData.min();
192
193        TAttFill fill(0, 1001);
194        TAttLine line;
195
196        int cnt=0;
197        for (Positions::iterator p=fGeom.begin(); p!=fGeom.end(); p++, cnt++)
198        {
199            if (fBold[cnt])
200                continue;
201
202            const int col = (fData[cnt]-min)/scale*(fPalette.size()-1);
203
204            if (fEnable[cnt])
205                fill.SetFillColor(gStyle->GetColorPalette(col));
206            else
207                fill.SetFillColor(kWhite);
208
209            fill.Modify();
210
211            Paint(*p);
212        }
213
214        line.SetLineWidth(2);
215        line.Modify();
216
217        cnt = 0;
218        for (Positions::iterator p=fGeom.begin(); p!=fGeom.end(); p++, cnt++)
219        {
220            if (!fBold[cnt])
221                continue;
222
223            const int col = (fData[cnt]-min)/scale*(fPalette.size()-1);
224
225            if (fEnable[cnt])
226                fill.SetFillColor(gStyle->GetColorPalette(col));
227            else
228                fill.SetFillColor(kWhite);
229            fill.Modify();
230
231            Paint(*p);
232        }
233
234        TMarker m(0,0,kStar);
235        m.DrawMarker(0, 0);
236
237        if (fWhite<0)
238            return;
239
240        const Position &p = fGeom[fWhite];
241
242        line.SetLineColor(kWhite);
243        line.Modify();
244
245        const int col = (fData[fWhite]-min)/scale*(fPalette.size()-1);
246
247        if (fEnable[fWhite])
248            fill.SetFillColor(gStyle->GetColorPalette(col));
249        else
250            fill.SetFillColor(kWhite);
251        fill.Modify();
252
253        Paint(p);
254    }
255
256    int GetIdx(float px, float py) const
257    {
258        static const double sqrt3 = sqrt(3);
259
260        int idx = 0;
261        for (Positions::const_iterator p=fGeom.begin(); p!=fGeom.end(); p++, idx++)
262        {
263            const Double_t dy = py - p->second;
264            if (fabs(dy)>0.5)
265                continue;
266
267            const Double_t dx = px - p->first;
268
269            if  (TMath::Abs(dy + dx*sqrt3) > 1)
270                continue;
271
272            if  (TMath::Abs(dy - dx*sqrt3) > 1)
273                continue;
274
275            return idx;
276        }
277        return -1;
278    }
279
280    char* GetObjectInfo(Int_t px, Int_t py) const
281    {
282        static stringstream stream;
283        static string       str;
284
285        const float x = gPad->PadtoX(gPad->AbsPixeltoX(px));
286        const float y = gPad->PadtoY(gPad->AbsPixeltoY(py));
287
288        const int idx = GetIdx(x, y);
289
290        stream.seekp(0);
291        if (idx>=0)
292            stream << "Pixel=" << idx << "   Data=" << fData[idx] << '\0';
293
294        str = stream.str();
295        return const_cast<char*>(str.c_str());
296    }
297
298    Int_t DistancetoPrimitive(Int_t px, Int_t py)
299    {
300        const float x = gPad->PadtoX(gPad->AbsPixeltoX(px));
301        const float y = gPad->PadtoY(gPad->AbsPixeltoY(py));
302
303        return GetIdx(x, y)>=0 ? 0 : 99999;
304    }
305
306    void SetData(const valarray<double> &data)
307    {
308        fData = data;
309    }
310};
311
312// #########################################################################
313
314
315class FactGui : public MainWindow, public DimNetwork
316{
317private:
318    class FunctionEvent : public QEvent
319    {
320    public:
321        boost::function<void(const QEvent &)> fFunction;
322
323        FunctionEvent(const boost::function<void(const QEvent &)> &f)
324            : QEvent((QEvent::Type)QEvent::registerEventType()),
325            fFunction(f) { }
326
327        bool Exec() { fFunction(*this); return true; }
328    };
329
330    valarray<int8_t> fFtuStatus;
331
332    DimStampedInfo fDimDNS;
333
334    DimStampedInfo fDimLoggerStats;
335    DimStampedInfo fDimLoggerFilenameNight;
336    DimStampedInfo fDimLoggerFilenameRun;
337    DimStampedInfo fDimLoggerNumSubs;
338
339    DimStampedInfo fDimFtmPassport;
340    DimStampedInfo fDimFtmTriggerCounter;
341    DimStampedInfo fDimFtmError;
342    DimStampedInfo fDimFtmFtuList;
343    DimStampedInfo fDimFtmStaticData;
344    DimStampedInfo fDimFtmDynamicData;
345    DimStampedInfo fDimFtmCounter;
346
347    DimStampedInfo fDimFadPassport;
348    DimStampedInfo fDimFadTemperatures;
349    DimStampedInfo fDimFadSetup;
350
351    map<string, DimInfo*> fServices;
352
353    // ========================== LED Colors ================================
354
355    enum LedColor_t
356    {
357        kLedRed,
358        kLedGreen,
359        kLedYellow,
360        kLedOrange,
361        kLedGray
362    };
363
364    void SetLedColor(QPushButton *button, LedColor_t col, const Time &t)
365    {
366        switch (col)
367        {
368        case kLedRed:
369            button->setIcon(QIcon(":/Resources/icons/red circle 1.png"));
370            break;
371
372        case kLedGreen:
373            button->setIcon(QIcon(":/Resources/icons/green circle 1.png"));
374            break;
375
376        case kLedYellow:
377            button->setIcon(QIcon(":/Resources/icons/yellow circle 1.png"));
378            break;
379
380        case kLedOrange:
381            button->setIcon(QIcon(":/Resources/icons/orange circle 1.png"));
382            break;
383
384        case kLedGray:
385            button->setIcon(QIcon(":/Resources/icons/gray circle 1.png"));
386            break;
387        }
388
389        //button->setToolTip("Last change: "+QDateTime::currentDateTimeUtc().toString()+" UTC");
390        button->setToolTip(("Last change: "+t.GetAsStr()+" UTC").c_str());
391    }
392
393    // ===================== Services and Commands ==========================
394
395    QStandardItem *AddServiceItem(const std::string &server, const std::string &service, bool iscmd)
396    {
397        QListView *servers     = iscmd ? fDimCmdServers     : fDimSvcServers;
398        QListView *services    = iscmd ? fDimCmdCommands    : fDimSvcServices;
399        QListView *description = iscmd ? fDimCmdDescription : fDimSvcDescription;
400
401        QStandardItemModel *m = dynamic_cast<QStandardItemModel*>(servers->model());
402        if (!m)
403        {
404            m = new QStandardItemModel(this);
405            servers->setModel(m);
406            services->setModel(m);
407            description->setModel(m);
408        }
409
410        QList<QStandardItem*> l = m->findItems(server.c_str());
411
412        if (l.size()>1)
413        {
414            cout << "hae" << endl;
415            return 0;
416        }
417
418        QStandardItem *col = l.size()==0 ? NULL : l[0];
419
420        if (!col)
421        {
422            col = new QStandardItem(server.c_str());
423            m->appendRow(col);
424
425            if (!services->rootIndex().isValid())
426            {
427                services->setRootIndex(col->index());
428                servers->setCurrentIndex(col->index());
429            }
430        }
431
432        QStandardItem *item = 0;
433        for (int i=0; i<col->rowCount(); i++)
434        {
435            QStandardItem *coli = col->child(i);
436            if (coli->text().toStdString()==service)
437                return coli;
438        }
439
440        item = new QStandardItem(service.c_str());
441        col->appendRow(item);
442        col->sortChildren(0);
443
444        if (!description->rootIndex().isValid())
445        {
446            description->setRootIndex(item->index());
447            services->setCurrentIndex(item->index());
448        }
449
450        if (!iscmd)
451            item->setCheckable(true);
452
453        return item;
454    }
455
456    void AddDescription(QStandardItem *item, const vector<Description> &vec)
457    {
458        if (!item)
459            return;
460        if (vec.size()==0)
461            return;
462
463        item->setToolTip(vec[0].comment.c_str());
464
465        const string str = Description::GetHtmlDescription(vec);
466
467        QStandardItem *desc = new QStandardItem(str.c_str());
468        desc->setSelectable(false);
469        item->setChild(0, 0, desc);
470    }
471
472    void AddServer(const std::string &s)
473    {
474        DimNetwork::AddServer(s);
475
476        QApplication::postEvent(this,
477           new FunctionEvent(boost::bind(&FactGui::handleAddServer, this, s)));
478    }
479
480    void RemoveServer(const std::string &s)
481    {
482        UnsubscribeServer(s);
483
484        DimNetwork::RemoveServer(s);
485
486        QApplication::postEvent(this,
487           new FunctionEvent(boost::bind(&FactGui::handleRemoveServer, this, s)));
488    }
489
490    void RemoveAllServers()
491    {
492        UnsubscribeAllServers();
493
494        vector<string> v = GetServerList();
495        for (vector<string>::iterator i=v.begin(); i<v.end(); i++)
496            QApplication::postEvent(this,
497                                    new FunctionEvent(boost::bind(&FactGui::handleStateOffline, this, *i)));
498
499        DimNetwork::RemoveAllServers();
500
501        QApplication::postEvent(this,
502           new FunctionEvent(boost::bind(&FactGui::handleRemoveAllServers, this)));
503    }
504
505    void AddService(const std::string &server, const std::string &service, const std::string &fmt, bool iscmd)
506    {
507        QApplication::postEvent(this,
508           new FunctionEvent(boost::bind(&FactGui::handleAddService, this, server, service, fmt, iscmd)));
509    }
510
511    void RemoveService(const std::string &server, const std::string &service, bool iscmd)
512    {
513        if (fServices.find(server+'/'+service)!=fServices.end())
514            UnsubscribeService(server+'/'+service);
515
516        QApplication::postEvent(this,
517           new FunctionEvent(boost::bind(&FactGui::handleRemoveService, this, server, service, iscmd)));
518    }
519
520    void RemoveAllServices(const std::string &server)
521    {
522        UnsubscribeServer(server);
523
524        QApplication::postEvent(this,
525           new FunctionEvent(boost::bind(&FactGui::handleRemoveAllServices, this, server)));
526    }
527
528    void AddDescription(const std::string &server, const std::string &service, const vector<Description> &vec)
529    {
530        QApplication::postEvent(this,
531           new FunctionEvent(boost::bind(&FactGui::handleAddDescription, this, server, service, vec)));
532    }
533
534    // ======================================================================
535
536    void handleAddServer(const std::string &server)
537    {
538        const State s = GetState(server, GetCurrentState(server));
539        handleStateChanged(Time(), server, s);
540    }
541
542    void handleRemoveServer(const string &server)
543    {
544        handleStateOffline(server);
545        handleRemoveAllServices(server);
546    }
547
548    void handleRemoveAllServers()
549    {
550        QStandardItemModel *m = 0;
551        if ((m=dynamic_cast<QStandardItemModel*>(fDimCmdServers->model())))
552            m->removeRows(0, m->rowCount());
553
554        if ((m = dynamic_cast<QStandardItemModel*>(fDimSvcServers->model())))
555            m->removeRows(0, m->rowCount());
556    }
557
558    void handleAddService(const std::string &server, const std::string &service, const std::string &/*fmt*/, bool iscmd)
559    {
560        QStandardItem *item = AddServiceItem(server, service, iscmd);
561        const vector<Description> v = GetDescription(server, service);
562        AddDescription(item, v);
563    }
564
565    void handleRemoveService(const std::string &server, const std::string &service, bool iscmd)
566    {
567        QListView *servers = iscmd ? fDimCmdServers : fDimSvcServers;
568
569        QStandardItemModel *m = dynamic_cast<QStandardItemModel*>(servers->model());
570        if (!m)
571            return;
572
573        QList<QStandardItem*> l = m->findItems(server.c_str());
574        if (l.size()!=1)
575            return;
576
577        for (int i=0; i<l[0]->rowCount(); i++)
578        {
579            QStandardItem *row = l[0]->child(i);
580            if (row->text().toStdString()==service)
581            {
582                l[0]->removeRow(row->index().row());
583                return;
584            }
585        }
586    }
587
588    void handleRemoveAllServices(const std::string &server)
589    {
590        QStandardItemModel *m = 0;
591        if ((m=dynamic_cast<QStandardItemModel*>(fDimCmdServers->model())))
592        {
593            QList<QStandardItem*> l = m->findItems(server.c_str());
594            if (l.size()==1)
595                m->removeRow(l[0]->index().row());
596        }
597
598        if ((m = dynamic_cast<QStandardItemModel*>(fDimSvcServers->model())))
599        {
600            QList<QStandardItem*> l = m->findItems(server.c_str());
601            if (l.size()==1)
602                m->removeRow(l[0]->index().row());
603        }
604    }
605
606    void handleAddDescription(const std::string &server, const std::string &service, const vector<Description> &vec)
607    {
608        const bool iscmd = IsCommand(server, service)==true;
609
610        QStandardItem *item = AddServiceItem(server, service, iscmd);
611        AddDescription(item, vec);
612    }
613
614    // ======================================================================
615
616    void SubscribeService(const string &service)
617    {
618        if (fServices.find(service)!=fServices.end())
619        {
620            cout << "ERROR - We are already subscribed to " << service << endl;
621            return;
622        }
623
624        fServices[service] = new DimStampedInfo(service.c_str(), (void*)NULL, 0, this);
625    }
626
627    void UnsubscribeService(const string &service)
628    {
629        const map<string,DimInfo*>::iterator i=fServices.find(service);
630
631        if (i==fServices.end())
632        {
633            cout << "ERROR - We are not subscribed to " << service << endl;
634            return;
635        }
636
637        delete i->second;
638
639        fServices.erase(i);
640    }
641
642    void UnsubscribeServer(const string &server)
643    {
644        for (map<string,DimInfo*>::iterator i=fServices.begin();
645             i!=fServices.end(); i++)
646            if (i->first.substr(0, server.length()+1)==server+'/')
647            {
648                delete i->second;
649                fServices.erase(i);
650            }
651    }
652
653    void UnsubscribeAllServers()
654    {
655        for (map<string,DimInfo*>::iterator i=fServices.begin();
656             i!=fServices.end(); i++)
657            delete i->second;
658
659        fServices.clear();
660    }
661
662    // ======================================================================
663
664    struct DimData
665    {
666        Time time;
667        int  qos;
668        string name;
669        string format;
670        vector<char> data;
671
672        DimInfo *info;  // this is ONLY for a fast check of the type of the DimData!!
673
674        DimData(DimInfo *inf) :
675            qos(inf->getQuality()),
676            name(inf->getName()),
677            format(inf->getFormat()),
678            data(inf->getString(), inf->getString()+inf->getSize()),
679            info(inf)
680        {
681            // Must be called in exactly this order!
682            const int tsec = inf->getTimestamp();
683            const int tms  = inf->getTimestampMillisecs();
684
685            time = Time(tsec, tms*1000);
686        }
687
688        template<typename T>
689                T get() const { return *reinterpret_cast<const T*>(data.data()); }
690
691            vector<char> vec(int b) const { return vector<char>(data.begin()+b, data.end()); }
692            string str(unsigned int b) const { return b>=data.size()?string():string(data.data()+b, data.size()-b); }
693            const char *c_str() const { return (char*)data.data(); }
694
695            vector<boost::any> any() const
696            {
697                const Converter conv(format);
698                conv.Print();
699                return conv.GetAny(data.data(), data.size());
700            }
701            int size() const { return data.size(); }
702            const void *ptr() const { return data.data(); }
703    };
704
705    // ======================= DNS ==========================================
706
707    void handleDimDNS(const DimData &d)
708    {
709        const int version = d.get<unsigned int>();
710
711        ostringstream str;
712        str << "V" << version/100 << 'r' << version%100;
713
714        SetLedColor(fStatusDNSLed, version==0 ? kLedRed : kLedGreen, Time());
715
716        fStatusDNSLabel->setText(version==0?"Offline":str.str().c_str());
717        fStatusDNSLabel->setToolTip(version==0?"No connection to DIM DNS.":"Connection to DIM DNS established.");
718    }
719
720
721    // ======================= Logger =======================================
722
723    void handleLoggerStats(const DimData &d)
724    {
725        const bool connected = d.size()!=0;
726
727        fLoggerET->setEnabled(connected);
728        fLoggerRate->setEnabled(connected);
729        fLoggerWritten->setEnabled(connected);
730        fLoggerFreeSpace->setEnabled(connected);
731        fLoggerSpaceLeft->setEnabled(connected);
732
733        if (!connected)
734            return;
735
736        const uint64_t *vals = reinterpret_cast<const uint64_t*>(d.ptr());
737
738        const size_t written = vals[0];
739        const size_t space   = vals[1];
740        const size_t rate    = vals[2];
741
742        fLoggerFreeSpace->setSuffix(" MB");
743        fLoggerFreeSpace->setDecimals(0);
744        fLoggerFreeSpace->setValue(space*1e-6);
745
746        if (space>   1000000)  // > 1GB
747        {
748            fLoggerFreeSpace->setSuffix(" GB");
749            fLoggerFreeSpace->setDecimals(2);
750            fLoggerFreeSpace->setValue(space*1e-9);
751        }
752        if (space>=  3000000)  // >= 3GB
753        {
754            fLoggerFreeSpace->setSuffix(" GB");
755            fLoggerFreeSpace->setDecimals(1);
756            fLoggerFreeSpace->setValue(space*1e-9);
757        }
758        if (space>=100000000)  // >= 100GB
759        {
760            fLoggerFreeSpace->setSuffix(" GB");
761            fLoggerFreeSpace->setDecimals(0);
762            fLoggerFreeSpace->setValue(space*1e-9);
763        }
764
765        fLoggerET->setTime(QTime().addSecs(rate>0?space/rate:0));
766        fLoggerRate->setValue(rate*1e-3); // kB/s
767        fLoggerWritten->setValue(written*1e-6);
768
769        fLoggerRate->setSuffix(" kB/s");
770        fLoggerRate->setDecimals(2);
771        fLoggerRate->setValue(rate*1e-3);
772        if (rate>   2000)  // > 2kB/s
773        {
774            fLoggerRate->setSuffix(" kB/s");
775            fLoggerRate->setDecimals(1);
776            fLoggerRate->setValue(rate*1e-3);
777        }
778        if (rate>=100000)  // >100kB/s
779        {
780            fLoggerRate->setSuffix(" kB/s");
781            fLoggerRate->setDecimals(0);
782            fLoggerRate->setValue(rate*1e-3);
783        }
784        if (rate>=1000000)  // >100kB/s
785        {
786            fLoggerRate->setSuffix(" MB/s");
787            fLoggerRate->setDecimals(2);
788            fLoggerRate->setValue(rate*1e-6);
789        }
790        if (rate>=10000000)  // >1MB/s
791        {
792            fLoggerRate->setSuffix(" MB/s");
793            fLoggerRate->setDecimals(1);
794            fLoggerRate->setValue(rate*1e-6);
795        }
796        if (rate>=100000000)  // >10MB/s
797        {
798            fLoggerRate->setSuffix(" MB/s");
799            fLoggerRate->setDecimals(0);
800            fLoggerRate->setValue(rate*1e-6);
801        }
802
803        if (space/1000000>static_cast<size_t>(fLoggerSpaceLeft->maximum()))
804            fLoggerSpaceLeft->setValue(fLoggerSpaceLeft->maximum());  // GB
805        else
806            fLoggerSpaceLeft->setValue(space/1000000);  // MB
807    }
808
809    void handleLoggerFilenameNight(const DimData &d)
810    {
811        const bool connected = d.size()!=0;
812
813        fLoggerFilenameNight->setEnabled(connected);
814        if (!connected)
815            return;
816
817        fLoggerFilenameNight->setText(d.c_str()+4);
818
819        const uint32_t files = d.get<uint32_t>();
820
821        SetLedColor(fLoggerLedLog,  files&1 ? kLedGreen : kLedGray, d.time);
822        SetLedColor(fLoggerLedRep,  files&2 ? kLedGreen : kLedGray, d.time);
823        SetLedColor(fLoggerLedFits, files&4 ? kLedGreen : kLedGray, d.time);
824    }
825
826    void handleLoggerFilenameRun(const DimData &d)
827    {
828        const bool connected = d.size()!=0;
829
830        fLoggerFilenameRun->setEnabled(connected);
831        if (!connected)
832            return;
833
834        fLoggerFilenameRun->setText(d.c_str()+4);
835
836        const uint32_t files = d.get<uint32_t>();
837
838        SetLedColor(fLoggerLedLog,  files&1 ? kLedGreen : kLedGray, d.time);
839        SetLedColor(fLoggerLedRep,  files&2 ? kLedGreen : kLedGray, d.time);
840        SetLedColor(fLoggerLedFits, files&4 ? kLedGreen : kLedGray, d.time);
841    }
842
843    void handleLoggerNumSubs(const DimData &d)
844    {
845        const bool connected = d.size()!=0;
846
847        fLoggerSubscriptions->setEnabled(connected);
848        fLoggerOpenFiles->setEnabled(connected);
849        if (!connected)
850            return;
851
852        const uint32_t *vals = reinterpret_cast<const uint32_t*>(d.ptr());
853
854        fLoggerSubscriptions->setValue(vals[0]);
855        fLoggerOpenFiles->setValue(vals[1]);
856    }
857
858    // ===================== FAD ============================================
859
860    void handleFadPassport(const DimData &d)
861    {
862        if (d.size()==0)
863            return;
864
865        if (d.size()!=sizeof(FAD::DimPassport))
866        {
867            cout << "Size mismatch: " << d.size() << " " << sizeof(FAD::DimPassport) << endl;
868            return;
869        }
870
871        const FAD::DimPassport &sdata = *reinterpret_cast<const FAD::DimPassport*>(d.ptr());
872
873        stringstream str1;
874        str1 << hex << "0x" << setfill('0') << setw(16) << sdata.fDNA;
875
876        fFadVersion->setValue(sdata.fVersion);
877        fFadBoardId->setValue(sdata.fBoardId);
878        fFadDNA->setText(str1.str().c_str());
879    }
880
881    void handleFadTemperatures(const DimData &d)
882    {
883        if (d.size()==0)
884            return;
885
886        if (d.size()!=sizeof(FAD::DimTemperatures))
887        {
888            cout << "Size mismatch: " << d.size() << " " << sizeof(FAD::DimTemperatures) << endl;
889            return;
890        }
891
892        const FAD::DimTemperatures &sdata = *reinterpret_cast<const FAD::DimTemperatures*>(d.ptr());
893
894        fFadTemp0->setValue(sdata.fTempDrs[0]);
895        fFadTemp1->setValue(sdata.fTempDrs[1]);
896        fFadTemp2->setValue(sdata.fTempDrs[2]);
897        fFadTemp3->setValue(sdata.fTempDrs[3]);
898    }
899
900    void handleFadSetup(const DimData &d)
901    {
902        if (d.size()==0)
903            return;
904
905        if (d.size()!=sizeof(FAD::DimSetup))
906        {
907            cout << "Size mismatch: " << d.size() << " " << sizeof(FAD::DimSetup) << endl;
908            return;
909        }
910
911
912    }
913
914    // ===================== FTM ============================================
915
916    void handleFtmTriggerCounter(const DimData &d)
917    {
918        if (d.size()==0)
919            return;
920
921        if (d.size()!=sizeof(FTM::DimTriggerCounter))
922        {
923            cout << "Size mismatch: " << d.size() << " " << sizeof(FTM::DimTriggerCounter) << endl;
924            return;
925        }
926
927        const FTM::DimTriggerCounter &sdata = *reinterpret_cast<const FTM::DimTriggerCounter*>(d.ptr());
928
929        fFtmTime->setText(QString::number(sdata.fTimeStamp));
930        fTriggerCounter->setText(QString::number(sdata.fTriggerCounter));
931
932
933        // ----------------------------------------------
934#ifdef HAVE_ROOT
935
936        if (fTriggerCounter0<0)
937        {
938            fTriggerCounter0 = sdata.fTriggerCounter;
939            return;
940        }
941
942        TCanvas *c = fFtmRateCanv->GetCanvas();
943
944        TH1 *h = (TH1*)c->FindObject("TimeFrame");
945
946        const double rate = sdata.fTriggerCounter-fTriggerCounter0;
947        fTriggerCounter0 = sdata.fTriggerCounter;
948
949        if (rate<0)
950        {
951            fGraphFtmRate.Set(0);
952
953            const double tm = Time().RootTime();
954
955            h->SetBins(1, tm, tm+60);
956            h->GetXaxis()->SetTimeFormat("%M'%S\"");
957            h->GetXaxis()->SetTitle("Time");
958
959            c->Modified();
960            c->Update();
961            return;
962        }
963
964        const double avgrate = sdata.fTimeStamp>0 ? double(sdata.fTriggerCounter)/sdata.fTimeStamp : 1;
965
966        const double t1 = h->GetXaxis()->GetXmax();
967        const double t0 = h->GetXaxis()->GetXmin();
968
969        h->SetBins(h->GetNbinsX()+1, t0, t0+sdata.fTimeStamp+1);
970        fGraphFtmRate.SetPoint(fGraphFtmRate.GetN(),
971                               t0+sdata.fTimeStamp, rate);
972
973        if (t1-t0>60)
974        {
975            h->GetXaxis()->SetTimeFormat("%Hh%M'");
976            h->GetXaxis()->SetTitle("Time");
977        }
978
979        h->SetMinimum(0);
980        h->SetMaximum(2*avgrate);
981
982        c->Modified();
983        c->Update();
984#endif
985        // ----------------------------------------------
986    }
987
988    void handleFtmCounter(const DimData &d)
989    {
990        if (d.size()==0)
991            return;
992
993        if (d.size()!=sizeof(uint32_t)*6)
994        {
995            cout << "Size mismatch: " << d.size() << " " << sizeof(uint32_t)*6 << endl;
996            return;
997        }
998
999        const uint32_t *sdata = reinterpret_cast<const uint32_t*>(d.ptr());
1000
1001        fFtmCounterH->setValue(sdata[0]);
1002        fFtmCounterS->setValue(sdata[1]);
1003        fFtmCounterD->setValue(sdata[2]);
1004        fFtmCounterF->setValue(sdata[3]);
1005        fFtmCounterE->setValue(sdata[4]);
1006        fFtmCounterR->setValue(sdata[5]);
1007    }
1008
1009    int64_t fTriggerCounter0;
1010    int64_t fTimeStamp0;
1011
1012    void handleFtmDynamicData(const DimData &d)
1013    {
1014        if (d.size()==0)
1015            return;
1016
1017        if (d.size()!=sizeof(FTM::DimDynamicData))
1018        {
1019            cout << "Size mismatch: " << d.size() << " " << sizeof(FTM::DimDynamicData) << endl;
1020            return;
1021        }
1022
1023        const FTM::DimDynamicData &sdata = *reinterpret_cast<const FTM::DimDynamicData*>(d.ptr());
1024
1025        fFtmTime->setText(QString::number(sdata.fTimeStamp));
1026        fOnTime->setText(QString::number(sdata.fOnTimeCounter));
1027
1028        fFtmTemp0->setValue(sdata.fTempSensor[0]*0.1);
1029        fFtmTemp1->setValue(sdata.fTempSensor[1]*0.1);
1030        fFtmTemp2->setValue(sdata.fTempSensor[2]*0.1);
1031        fFtmTemp3->setValue(sdata.fTempSensor[3]*0.1);
1032
1033
1034#ifdef HAVE_ROOT
1035
1036        // ----------------------------------------------
1037/*
1038        TCanvas *c = fFtmTempCanv->GetCanvas();
1039
1040//        static int cntr = 0;
1041//        double_t tm = cntr++;//Time().RootTime();
1042
1043        double tm = d.time.RootTime();
1044
1045        TH1 *h = (TH1*)c->FindObject("TimeFrame");
1046        h->FindBin(tm);
1047
1048        fGraphFtmTemp[0].SetPoint(fGraphFtmTemp[0].GetN(), tm, sdata.fTempSensor[0]*0.1);
1049        fGraphFtmTemp[1].SetPoint(fGraphFtmTemp[1].GetN(), tm, sdata.fTempSensor[1]*0.1);
1050        fGraphFtmTemp[2].SetPoint(fGraphFtmTemp[2].GetN(), tm, sdata.fTempSensor[2]*0.1);
1051        fGraphFtmTemp[3].SetPoint(fGraphFtmTemp[3].GetN(), tm, sdata.fTempSensor[3]*0.1);
1052
1053        c->Modified();
1054        c->Update();
1055*/
1056        // ----------------------------------------------
1057
1058        if (fTimeStamp0<0)
1059        {
1060            fTimeStamp0 = sdata.fTimeStamp;
1061            return;
1062        }
1063
1064        TCanvas *c = fFtmRateCanv->GetCanvas();
1065
1066        TH1 *h = (TH1*)c->FindObject("TimeFrame");
1067
1068        const double tdiff = sdata.fTimeStamp-fTimeStamp0;
1069        fTimeStamp0 = sdata.fTimeStamp;
1070
1071        if (tdiff<0)
1072        {
1073            for (int i=0; i<160; i++)
1074                fGraphPatchRate[i].Set(0);
1075            for (int i=0; i<40; i++)
1076                fGraphBoardRate[i].Set(0);
1077
1078            return;
1079        }
1080
1081        const double t1 = h->GetXaxis()->GetXmax();
1082        const double t0 = h->GetXaxis()->GetXmin();
1083
1084        for (int i=0; i<160; i++)
1085            fGraphPatchRate[i].SetPoint(fGraphPatchRate[i].GetN(),
1086                                       t0+sdata.fTimeStamp, float(sdata.fRatePatch[i])/fFtmStaticData.fPrescaling[i]/1000);
1087        for (int i=0; i<40; i++)
1088            fGraphBoardRate[i].SetPoint(fGraphBoardRate[i].GetN(),
1089                                       t0+sdata.fTimeStamp, float(sdata.fRateBoard[i])/fFtmStaticData.fPrescaling[i]/1000);
1090
1091        c->Modified();
1092        c->Update();
1093
1094        // ----------------------------------------------
1095
1096        if (fThresholdIdx->value()>=0)
1097            fPatchRate->setValue(sdata.fRatePatch[fThresholdIdx->value()]);
1098
1099        valarray<double> dat(0., 1440);
1100
1101        for (int i=0; i<1440; i++)
1102            dat[i] = sdata.fRatePatch[fPatch[i]];
1103
1104        c = fRatesCanv->GetCanvas();
1105        Camera *cam = (Camera*)c->FindObject("Camera");
1106
1107        cam->SetData(dat);
1108
1109        c->Modified();
1110        c->Update();
1111#endif
1112    }
1113
1114    void DisplayRates()
1115    {
1116#ifdef HAVE_ROOT
1117        TCanvas *c = fFtmRateCanv->GetCanvas();
1118
1119        while (c->FindObject("PatchRate"))
1120            c->GetListOfPrimitives()->Remove(c->FindObject("PatchRate"));
1121
1122        while (c->FindObject("BoardRate"))
1123            c->GetListOfPrimitives()->Remove(c->FindObject("BoardRate"));
1124
1125        if (fRatePatch1->value()>=0)
1126            fGraphPatchRate[fRatePatch1->value()].Draw("PL");
1127        if (fRatePatch2->value()>=0)
1128            fGraphPatchRate[fRatePatch2->value()].Draw("PL");
1129        if (fRateBoard1->value()>=0)
1130            fGraphBoardRate[fRateBoard1->value()].Draw("PL");
1131        if (fRateBoard2->value()>=0)
1132            fGraphBoardRate[fRateBoard2->value()].Draw("PL");
1133#endif
1134    }
1135
1136    void on_fRatePatch1_valueChanged(int idx)
1137    {
1138        DisplayRates();
1139    }
1140
1141    void on_fRatePatch2_valueChanged(int idx)
1142    {
1143        DisplayRates();
1144    }
1145
1146    void on_fRateBoard1_valueChanged(int idx)
1147    {
1148        DisplayRates();
1149    }
1150
1151    void on_fRateBoard2_valueChanged(int idx)
1152    {
1153        DisplayRates();
1154    }
1155
1156    FTM::DimStaticData fFtmStaticData;
1157
1158    void SetFtuLed(int idx, int counter, const Time &t)
1159    {
1160        if (counter==0 || counter>3)
1161            counter = 3;
1162
1163        if (counter<0)
1164            counter = 0;
1165
1166        const LedColor_t col[4] = { kLedGray, kLedGreen, kLedOrange, kLedRed };
1167
1168        SetLedColor(fFtuLED[idx], col[counter], t);
1169
1170        fFtuStatus[idx] = counter;
1171    }
1172
1173    void SetFtuStatusLed(const Time &t)
1174    {
1175        const int max = fFtuStatus.max();
1176
1177        switch (max)
1178        {
1179        case 0:
1180            SetLedColor(fStatusFTULed, kLedGray, t);
1181            fStatusFTULabel->setText("All disabled");
1182            fStatusFTULabel->setToolTip("All FTUs are disabled");
1183            break;
1184
1185        case 1:
1186            SetLedColor(fStatusFTULed, kLedGreen, t);
1187            fStatusFTULabel->setToolTip("Communication with FTU is smooth.");
1188            fStatusFTULabel->setText("ok");
1189            break;
1190
1191        case 2:
1192            SetLedColor(fStatusFTULed, kLedOrange, t);
1193            fStatusFTULabel->setText("Warning");
1194            fStatusFTULabel->setToolTip("At least one FTU didn't answer immediately");
1195            break;
1196
1197        case 3:
1198            SetLedColor(fStatusFTULed, kLedRed, t);
1199            fStatusFTULabel->setToolTip("At least one FTU didn't answer!");
1200            fStatusFTULabel->setText("ERROR");
1201            break;
1202        }
1203    }
1204
1205    void handleFtmStaticData(const DimData &d)
1206    {
1207        if (d.size()==0)
1208            return;
1209
1210        if (d.size()!=sizeof(FTM::DimStaticData))
1211        {
1212            cout << "Size mismatch: " << d.size() << " " << sizeof(FTM::DimStaticData) << endl;
1213            return;
1214        }
1215
1216        const FTM::DimStaticData &sdata = *reinterpret_cast<const FTM::DimStaticData*>(d.ptr());
1217
1218        fTriggerInterval->setValue(sdata.fTriggerInterval);
1219        fPhysicsCoincidence->setValue(sdata.fMultiplicityPhysics);
1220        fCalibCoincidence->setValue(sdata.fMultiplicityCalib);
1221        fPhysicsWindow->setValue(sdata.fWindowPhysics);
1222        fCalibWindow->setValue(sdata.fWindowCalib);
1223
1224        fTriggerDelay->setValue(sdata.fDelayTrigger);
1225        fTimeMarkerDelay->setValue(sdata.fDelayTimeMarker);
1226        fDeadTime->setValue(sdata.fDeadTime);
1227
1228        fClockCondR0->setValue(sdata.fClockConditioner[0]);
1229        fClockCondR1->setValue(sdata.fClockConditioner[1]);
1230        fClockCondR8->setValue(sdata.fClockConditioner[2]);
1231        fClockCondR9->setValue(sdata.fClockConditioner[3]);
1232        fClockCondR11->setValue(sdata.fClockConditioner[4]);
1233        fClockCondR13->setValue(sdata.fClockConditioner[5]);
1234        fClockCondR14->setValue(sdata.fClockConditioner[6]);
1235        fClockCondR15->setValue(sdata.fClockConditioner[7]);
1236
1237        fTriggerSeqPed->setValue(sdata.fTriggerSeqPed);
1238        fTriggerSeqLPint->setValue(sdata.fTriggerSeqLPint);
1239        fTriggerSeqLPext->setValue(sdata.fTriggerSeqLPext);
1240
1241        fEnableTrigger->setChecked(sdata.HasTrigger());
1242        fEnableVeto->setChecked(sdata.HasVeto());
1243        fEnableExt1->setChecked(sdata.HasExt1());
1244        fEnableExt2->setChecked(sdata.HasExt2());
1245        fEnableClockCond->setChecked(sdata.HasClockConditioner());
1246
1247        for (int i=0; i<40; i++)
1248        {
1249            if (!sdata.IsActive(i))
1250                SetFtuLed(i, -1, d.time);
1251            else
1252            {
1253                if (fFtuStatus[i]==0)
1254                    SetFtuLed(i, 1, d.time);
1255            }
1256            fFtuLED[i]->setChecked(false);
1257        }
1258        SetFtuStatusLed(d.time);
1259
1260#ifdef HAVE_ROOT
1261        Camera *cam = (Camera*)fRatesCanv->GetCanvas()->FindObject("Camera");
1262        for (int i=0; i<1440; i++)
1263            cam->SetEnable(i, sdata.IsEnabled(i));
1264#endif
1265
1266        fPixelEnable->setChecked(sdata.IsEnabled(fPixelIdx->value()));
1267
1268        const int patch1 = fThresholdIdx->value();
1269        if (patch1>=0)
1270            fThresholdVal->setValue(sdata.fThreshold[patch1]);
1271
1272        fPrescalingVal->setValue(sdata.fPrescaling[0]);
1273
1274        fFtmStaticData = sdata;
1275    }
1276
1277    void handleFtmPassport(const DimData &d)
1278    {
1279        if (d.size()==0)
1280            return;
1281
1282        if (d.size()!=sizeof(FTM::DimPassport))
1283        {
1284            cout << "Size mismatch: " << d.size() << " " << sizeof(FTM::DimPassport) << endl;
1285            return;
1286        }
1287
1288        const FTM::DimPassport &sdata = *reinterpret_cast<const FTM::DimPassport*>(d.ptr());
1289
1290        stringstream str1, str2;
1291        str1 << hex << "0x" << setfill('0') << setw(16) << sdata.fBoardId;
1292        str2 << sdata.fFirmwareId;
1293
1294        fFtmBoardId->setText(str1.str().c_str());
1295        fFtmFirmwareId->setText(str2.str().c_str());
1296    }
1297
1298    void handleFtmFtuList(const DimData &d)
1299    {
1300        if (d.size()==0)
1301            return;
1302
1303        if (d.size()!=sizeof(FTM::DimFtuList))
1304        {
1305            cout << "Size mismatch: " << d.size() << " " << sizeof(FTM::DimFtuList) << endl;
1306            return;
1307        }
1308
1309        fPing->setChecked(false);
1310
1311        const FTM::DimFtuList &sdata = *reinterpret_cast<const FTM::DimFtuList*>(d.ptr());
1312
1313        stringstream str;
1314        str << "<table width='100%'>" << setfill('0');
1315        str << "<tr><th>Num</th><th></th><th>Addr</th><th></th><th>DNA</th></tr>";
1316        for (int i=0; i<40; i++)
1317        {
1318            str << "<tr>";
1319            str << "<td align='center'>"   << dec << i << hex << "</td>";
1320            str << "<td align='center'>:</td>";
1321            str << "<td align='center'>0x" << setw(2)  << (int)sdata.fAddr[i] << "</td>";
1322            str << "<td align='center'>:</td>";
1323            str << "<td align='center'>0x" << setw(16) << sdata.fDNA[i] << "</td>";
1324            str << "</tr>";
1325        }
1326        str << "</table>";
1327
1328        fFtuDNA->setText(str.str().c_str());
1329
1330        fFtuAnswersTotal->setValue(sdata.fNumBoards);
1331        fFtuAnswersCrate0->setValue(sdata.fNumBoardsCrate[0]);
1332        fFtuAnswersCrate1->setValue(sdata.fNumBoardsCrate[1]);
1333        fFtuAnswersCrate2->setValue(sdata.fNumBoardsCrate[2]);
1334        fFtuAnswersCrate3->setValue(sdata.fNumBoardsCrate[3]);
1335
1336        for (int i=0; i<40; i++)
1337            SetFtuLed(i, sdata.IsActive(i) ? sdata.fPing[i] : -1, d.time);
1338
1339        SetFtuStatusLed(d.time);
1340    }
1341
1342    void handleFtmError(const DimData &d)
1343    {
1344        if (d.size()==0)
1345            return;
1346
1347        const FTM::DimError &sdata = *reinterpret_cast<const FTM::DimError*>(d.ptr());
1348
1349        SetFtuLed(sdata.fError.fDestAddress , sdata.fError.fNumCalls, d.time);
1350        SetFtuStatusLed(d.time);
1351
1352        // Write to special window!
1353        Out() << "Error:" << endl;
1354        Out() << sdata.fError << endl;
1355    }
1356
1357    // ====================== MessageImp ====================================
1358
1359    bool fChatOnline;
1360
1361    void handleStateChanged(const Time &time, const std::string &server,
1362                            const State &s)
1363    {
1364        // FIXME: Prefix tooltip with time
1365        if (server=="FTM_CONTROL")
1366        {
1367            fStatusFTMLabel->setText(s.name.c_str());
1368            fStatusFTMLabel->setToolTip(s.comment.c_str());
1369
1370            bool enable = false;
1371
1372            if (s.index<FTM::kDisconnected) // No Dim connection
1373                SetLedColor(fStatusFTMLed, kLedGray, time);
1374            if (s.index==FTM::kDisconnected) // Dim connection / FTM disconnected
1375                SetLedColor(fStatusFTMLed, kLedYellow, time);
1376            if (s.index==FTM::kConnected || s.index==FTM::kIdle || s.index==FTM::kTakingData) // Dim connection / FTM connected
1377            {
1378                SetLedColor(fStatusFTMLed, kLedGreen, time);
1379                enable = true;
1380            }
1381
1382            fTriggerWidget->setEnabled(enable);
1383            fFtuWidget->setEnabled(enable);
1384            fRatesWidget->setEnabled(enable);
1385
1386            if (!enable)
1387            {
1388                SetLedColor(fStatusFTULed, kLedGray, time);
1389                fStatusFTULabel->setText("Offline");
1390                fStatusFTULabel->setToolTip("FTM is not online.");
1391            }
1392    }
1393
1394        if (server=="FAD_CONTROL")
1395        {
1396            fStatusFADLabel->setText(s.name.c_str());
1397            fStatusFADLabel->setToolTip(s.comment.c_str());
1398
1399            bool enable = false;
1400
1401            if (s.index<FAD::kDisconnected) // No Dim connection
1402                SetLedColor(fStatusFADLed, kLedGray, time);
1403            if (s.index==FAD::kDisconnected) // Dim connection / FTM disconnected
1404                SetLedColor(fStatusFADLed, kLedYellow, time);
1405            if (s.index==FAD::kConnected) // Dim connection / FTM connected
1406            {
1407                SetLedColor(fStatusFADLed, kLedGreen, time);
1408                enable = true;
1409            }
1410
1411            fFadWidget->setEnabled(enable);
1412        }
1413
1414        if (server=="DATA_LOGGER")
1415        {
1416            fStatusLoggerLabel->setText(s.name.c_str());
1417            fStatusLoggerLabel->setToolTip(s.comment.c_str());
1418
1419            bool enable = true;
1420
1421            if (s.index<=30)   // Ready/Waiting
1422                SetLedColor(fStatusLoggerLed, kLedYellow, time);
1423            if (s.index<-1)     // Offline
1424            {
1425                SetLedColor(fStatusLoggerLed, kLedGray, time);
1426                enable = false;
1427            }
1428            if (s.index>=0x100) // Error
1429                SetLedColor(fStatusLoggerLed, kLedRed, time);
1430            if (s.index==40)   // Logging
1431                SetLedColor(fStatusLoggerLed, kLedGreen, time);
1432
1433            fLoggerWidget->setEnabled(enable);
1434        }
1435
1436        if (server=="CHAT")
1437        {
1438            fStatusChatLabel->setText(s.name.c_str());
1439
1440            fChatOnline = s.index==0;
1441
1442            SetLedColor(fStatusChatLed, fChatOnline ? kLedGreen : kLedRed, time);
1443
1444            fChatSend->setEnabled(fChatOnline);
1445            fChatMessage->setEnabled(fChatOnline);
1446        }
1447
1448        if (server=="SCHEDULER")
1449        {
1450            fStatusSchedulerLabel->setText(s.name.c_str());
1451
1452            SetLedColor(fStatusSchedulerLed, s.index>=0 ? kLedGreen : kLedRed, time);
1453        }
1454    }
1455
1456    void handleStateOffline(const string &server)
1457    {
1458        handleStateChanged(Time(), server, State(-2, "Offline", "No connection via DIM."));
1459    }
1460
1461    void on_fTabWidget_currentChanged(int which)
1462    {
1463        if (fTabWidget->tabText(which)=="Chat")
1464            fTabWidget->setTabIcon(which, QIcon());
1465    }
1466
1467    void handleWrite(const Time &time, const string &text, int qos)
1468    {
1469        stringstream out;
1470
1471        if (text.substr(0, 6)=="CHAT: ")
1472        {
1473            out << "<font size='-1' color='navy'>[<B>";
1474            out << Time::fmt("%H:%M:%S") << time << "</B>]</FONT>  ";
1475            out << text.substr(6);
1476            fChatText->append(out.str().c_str());
1477
1478            if (fTabWidget->tabText(fTabWidget->currentIndex())=="Chat")
1479                return;
1480
1481            static int num = 0;
1482            if (num++<2)
1483                return;
1484
1485            for (int i=0; i<fTabWidget->count(); i++)
1486                if (fTabWidget->tabText(i)=="Chat")
1487                {
1488                    fTabWidget->setTabIcon(i, QIcon(":/Resources/icons/warning 3.png"));
1489                    break;
1490                }
1491
1492            return;
1493        }
1494
1495
1496        out << "<font style='font-family:monospace' color='";
1497
1498        switch (qos)
1499        {
1500        case kMessage: out << "black";   break;
1501        case kInfo:    out << "green";   break;
1502        case kWarn:    out << "#FF6600"; break;
1503        case kError:   out << "maroon";  break;
1504        case kFatal:   out << "maroon";  break;
1505        case kDebug:   out << "navy";    break;
1506        default:       out << "navy";    break;
1507        }
1508        out << "'>" << time.GetAsStr() << " - " << text << "</font>";
1509
1510        fLogText->append(out.str().c_str());
1511
1512        if (qos>=kWarn)
1513            fTextEdit->append(out.str().c_str());
1514    }
1515
1516    void IndicateStateChange(const Time &time, const std::string &server)
1517    {
1518        const State s = GetState(server, GetCurrentState(server));
1519
1520        QApplication::postEvent(this,
1521           new FunctionEvent(boost::bind(&FactGui::handleStateChanged, this, time, server, s)));
1522    }
1523
1524    int Write(const Time &time, const string &txt, int qos)
1525    {
1526        QApplication::postEvent(this,
1527           new FunctionEvent(boost::bind(&FactGui::handleWrite, this, time, txt, qos)));
1528
1529        return 0;
1530    }
1531
1532    // ====================== Dim infoHandler================================
1533
1534    void handleDimService(const string &txt)
1535    {
1536        fDimSvcText->append(txt.c_str());
1537    }
1538
1539    void infoHandlerService(DimInfo &info)
1540    {
1541        const string fmt = string(info.getFormat()).empty() ? "C" : info.getFormat();
1542
1543        stringstream dummy;
1544        const Converter conv(dummy, fmt, false);
1545
1546        const Time tm(info.getTimestamp(), info.getTimestampMillisecs()*1000);
1547
1548        stringstream out;
1549        out << "<font size'-1' color='navy'>[" << Time::fmt("%H:%M:%S.%f") << tm << "]</font>   <B>" << info.getName() << "</B> - ";
1550
1551        bool iserr = true;
1552        if (!conv)
1553        {
1554            out << "Compilation of format string '" << fmt << "' failed!";
1555        }
1556        else
1557        {
1558            try
1559            {
1560                const string dat = conv.GetString(info.getData(), info.getSize());
1561                out << dat;
1562                iserr = false;
1563            }
1564            catch (const runtime_error &e)
1565            {
1566                out << "Conversion to string failed!<pre>" << e.what() << "</pre>";
1567            }
1568        }
1569
1570        // srand(hash<string>()(string(info.getName())));
1571        // int bg = rand()&0xffffff;
1572
1573        int bg = hash<string>()(string(info.getName()));
1574
1575        // allow only light colors
1576        bg = ~(bg&0x1f1f1f)&0xffffff;
1577
1578        if (iserr)
1579            bg = 0xffffff;
1580
1581        stringstream bgcol;
1582        bgcol << hex << setfill('0') << setw(6) << bg;
1583
1584        const string col = iserr ? "red" : "black";
1585        const string str = "<table width='100%' bgcolor=#"+bgcol.str()+"><tr><td><font color='"+col+"'>"+out.str()+"</font></td></tr></table>";
1586
1587        QApplication::postEvent(this,
1588                                new FunctionEvent(boost::bind(&FactGui::handleDimService, this, str)));
1589    }
1590
1591    void CallInfoHandler(void (FactGui::*handler)(const DimData&), const DimData &d)
1592    {
1593        fInHandler = true;
1594        (this->*handler)(d);
1595        fInHandler = false;
1596    }
1597
1598    /*
1599    void CallInfoHandler(const boost::function<void()> &func)
1600    {
1601        // This ensures that newly received values are not sent back to the emitter
1602        // because changing the value emits the valueChanged signal (or similar)
1603        fInHandler = true;
1604        func();
1605        fInHandler = false;
1606    }*/
1607
1608    void PostInfoHandler(void (FactGui::*handler)(const DimData&))
1609    {
1610        //const boost::function<void()> f = boost::bind(handler, this, DimData(getInfo()));
1611
1612        FunctionEvent *evt = new FunctionEvent(boost::bind(&FactGui::CallInfoHandler, this, handler, DimData(getInfo())));
1613        // FunctionEvent *evt = new FunctionEvent(boost::bind(&FactGui::CallInfoHandler, this, f));
1614        // FunctionEvent *evt = new FunctionEvent(boost::bind(handler, this, DimData(getInfo()))));
1615
1616        QApplication::postEvent(this, evt);
1617    }
1618
1619    void infoHandler()
1620    {
1621        // Initialize the time-stamp (what a weird workaround...)
1622        if (getInfo())
1623            getInfo()->getTimestamp();
1624
1625        if (getInfo()==&fDimDNS)
1626            return PostInfoHandler(&FactGui::handleDimDNS);
1627
1628        cout << "HandleDimInfo " << getInfo()->getName() << endl;
1629
1630        if (getInfo()==&fDimLoggerStats)
1631            return PostInfoHandler(&FactGui::handleLoggerStats);
1632
1633        if (getInfo()==&fDimFadTemperatures)
1634            return PostInfoHandler(&FactGui::handleFadTemperatures);
1635
1636        if (getInfo()==&fDimFadSetup)
1637            return PostInfoHandler(&FactGui::handleFadSetup);
1638
1639        if (getInfo()==&fDimLoggerFilenameNight)
1640            return PostInfoHandler(&FactGui::handleLoggerFilenameNight);
1641
1642        if (getInfo()==&fDimLoggerNumSubs)
1643            return PostInfoHandler(&FactGui::handleLoggerNumSubs);
1644
1645        if (getInfo()==&fDimLoggerFilenameRun)
1646            return PostInfoHandler(&FactGui::handleLoggerFilenameRun);
1647
1648        if (getInfo()==&fDimFtmTriggerCounter)
1649            return PostInfoHandler(&FactGui::handleFtmTriggerCounter);
1650
1651        if (getInfo()==&fDimFtmCounter)
1652            return PostInfoHandler(&FactGui::handleFtmCounter);
1653
1654        if (getInfo()==&fDimFtmDynamicData)
1655            return PostInfoHandler(&FactGui::handleFtmDynamicData);
1656
1657        if (getInfo()==&fDimFtmPassport)
1658            return PostInfoHandler(&FactGui::handleFtmPassport);
1659
1660        if (getInfo()==&fDimFtmFtuList)
1661            return PostInfoHandler(&FactGui::handleFtmFtuList);
1662
1663        if (getInfo()==&fDimFtmStaticData)
1664            return PostInfoHandler(&FactGui::handleFtmStaticData);
1665
1666        if (getInfo()==&fDimFtmError)
1667            return PostInfoHandler(&FactGui::handleFtmError);
1668
1669        for (map<string,DimInfo*>::iterator i=fServices.begin(); i!=fServices.end(); i++)
1670            if (i->second==getInfo())
1671            {
1672                infoHandlerService(*i->second);
1673                return;
1674            }
1675
1676        DimNetwork::infoHandler();
1677    }
1678
1679
1680    // ======================================================================
1681
1682    bool event(QEvent *evt)
1683    {
1684        if (dynamic_cast<FunctionEvent*>(evt))
1685            return static_cast<FunctionEvent*>(evt)->Exec();
1686
1687        if (dynamic_cast<CheckBoxEvent*>(evt))
1688        {
1689            const QStandardItem &item = static_cast<CheckBoxEvent*>(evt)->item;
1690            const QStandardItem *par  = item.parent();
1691            if (par)
1692            {
1693                const QString server  = par->text();
1694                const QString service = item.text();
1695
1696                const string s = (server+'/'+service).toStdString();
1697
1698                if (item.checkState()==Qt::Checked)
1699                    SubscribeService(s);
1700                else
1701                    UnsubscribeService(s);
1702            }
1703        }
1704
1705        return MainWindow::event(evt); // unrecognized
1706    }
1707
1708    void on_fDimCmdSend_clicked()
1709    {
1710        const QString server    = fDimCmdServers->currentIndex().data().toString();
1711        const QString command   = fDimCmdCommands->currentIndex().data().toString();
1712        const QString arguments = fDimCmdLineEdit->displayText();
1713
1714        // FIXME: Sending a command exactly when the info Handler changes
1715        //        the list it might lead to confusion.
1716        try
1717        {
1718            SendDimCommand(server.toStdString(), command.toStdString()+" "+arguments.toStdString());
1719            fTextEdit->append("<font color='green'>Command '"+server+'/'+command+"' successfully emitted.</font>");
1720            fDimCmdLineEdit->clear();
1721        }
1722        catch (const runtime_error &e)
1723        {
1724            stringstream txt;
1725            txt << e.what();
1726
1727            string buffer;
1728            while (getline(txt, buffer, '\n'))
1729                fTextEdit->append(("<font color='red'><pre>"+buffer+"</pre></font>").c_str());
1730        }
1731    }
1732    void ChoosePatch(Camera &cam, int idx)
1733    {
1734        cam.Reset();
1735
1736        fThresholdIdx->setValue(idx);
1737
1738        //fThresholdVal->setEnabled(idx>=0);
1739        //fThresholdVolt->setEnabled(idx>=0);
1740        fPatchRate->setEnabled(idx>=0);
1741        if (idx<0)
1742            return;
1743
1744        fThresholdVal->setValue(fFtmStaticData.fThreshold[idx]);
1745        fPatchRate->setValue(cam.GetData(idx));
1746
1747        for (unsigned int i=0; i<fPatch.size(); i++)
1748            if (fPatch[i]==idx)
1749                cam.SetBold(i);
1750    }
1751
1752    void ChoosePixel(Camera &cam, int idx)
1753    {
1754        cam.SetWhite(idx);
1755        ChoosePatch(cam, fPatch[idx]);
1756
1757        fPixelEnable->setChecked(fFtmStaticData.IsEnabled(idx));
1758    }
1759
1760#ifdef HAVE_ROOT
1761    void slot_RootEventProcessed(TObject *obj, unsigned int evt, TCanvas *)
1762    {
1763        // kMousePressEvent       // TCanvas processed QEvent mousePressEvent
1764        // kMouseMoveEvent        // TCanvas processed QEvent mouseMoveEvent
1765        // kMouseReleaseEvent     // TCanvas processed QEvent mouseReleaseEvent
1766        // kMouseDoubleClickEvent // TCanvas processed QEvent mouseDoubleClickEvent
1767        // kKeyPressEvent         // TCanvas processed QEvent keyPressEvent
1768        // kEnterEvent            // TCanvas processed QEvent enterEvent
1769        // kLeaveEvent            // TCanvas processed QEvent leaveEvent
1770        if (dynamic_cast<TCanvas*>(obj))
1771            return;
1772
1773        TQtWidget *tipped = static_cast<TQtWidget*>(sender());
1774
1775        if (evt==11/*kMouseReleaseEvent*/)
1776        {
1777            if (dynamic_cast<Camera*>(obj))
1778            {
1779                const float xx = gPad->PadtoX(gPad->AbsPixeltoX(tipped->GetEventX()));
1780                const float yy = gPad->PadtoY(gPad->AbsPixeltoY(tipped->GetEventY()));
1781
1782                Camera *cam = static_cast<Camera*>(obj);
1783                const int idx = cam->GetIdx(xx, yy);
1784
1785                ChoosePixel(*cam, idx);
1786
1787                fPixelIdx->setValue(idx);
1788            }
1789            return;
1790        }
1791
1792        if (evt==61/*kMouseDoubleClickEvent*/)
1793        {
1794            if (dynamic_cast<Camera*>(obj))
1795            {
1796                const float xx = gPad->PadtoX(gPad->AbsPixeltoX(tipped->GetEventX()));
1797                const float yy = gPad->PadtoY(gPad->AbsPixeltoY(tipped->GetEventY()));
1798
1799                Camera *cam = static_cast<Camera*>(obj);
1800                const int idx = cam->GetIdx(xx, yy);
1801
1802                //cam->Toggle(idx);
1803
1804                Dim::SendCommand("FTM_CONTROL/TOGGLE_PIXEL", uint16_t(idx));
1805            }
1806            return;
1807        }
1808
1809        // Find the object which will get picked by the GetObjectInfo
1810        // due to buffer overflows in many root-versions
1811        // in TH1 and TProfile we have to work around and implement
1812        // our own GetObjectInfo which make everything a bit more
1813        // complicated.
1814#if ROOT_VERSION_CODE > ROOT_VERSION(5,22,00)
1815        const char *objectInfo =
1816            obj->GetObjectInfo(tipped->GetEventX(),tipped->GetEventY());
1817#else
1818        const char *objectInfo = dynamic_cast<TH1*>(obj) ?
1819            "" : obj->GetObjectInfo(tipped->GetEventX(),tipped->GetEventY());
1820#endif
1821
1822        QString tipText;
1823        tipText += obj->GetName();
1824        tipText += " [";
1825        tipText += obj->ClassName();
1826        tipText += "]: ";
1827        tipText += objectInfo;
1828
1829        if (dynamic_cast<Camera*>(obj))
1830        {
1831            const float xx = gPad->PadtoX(gPad->AbsPixeltoX(tipped->GetEventX()));
1832            const float yy = gPad->PadtoY(gPad->AbsPixeltoY(tipped->GetEventY()));
1833
1834            Camera *cam = static_cast<Camera*>(obj);
1835            int idx = fPatch[cam->GetIdx(xx, yy)];
1836
1837            tipText+="  Patch=";
1838            tipText+=QString::number(idx);
1839        }
1840
1841
1842        fStatusBar->showMessage(tipText, 3000);
1843
1844        gSystem->ProcessEvents();
1845        //QWhatsThis::display(tipText)
1846    }
1847
1848    void slot_RootUpdate()
1849    {
1850        gSystem->ProcessEvents();
1851        QTimer::singleShot(0, this, SLOT(slot_RootUpdate()));
1852    }
1853
1854    void on_fThresholdIdx_valueChanged(int idx)
1855    {
1856        Camera *cam = (Camera*)fRatesCanv->GetCanvas()->FindObject("Camera");
1857        ChoosePatch(*cam, idx);
1858    }
1859
1860    void on_fPixelIdx_valueChanged(int idx)
1861    {
1862        Camera *cam = (Camera*)fRatesCanv->GetCanvas()->FindObject("Camera");
1863        ChoosePixel(*cam, idx);
1864    }
1865#endif
1866
1867    TGraph fGraphFtmTemp[4];
1868    TGraph fGraphFtmRate;
1869    TGraph fGraphPatchRate[160];
1870    TGraph fGraphBoardRate[40];
1871
1872    map<int, int> fPatch;
1873
1874#ifdef HAVE_ROOT
1875    void DrawTimeFrame(const char *ytitle)
1876    {
1877        const double tm = Time().RootTime();
1878
1879        TH1F h("TimeFrame", "", 1, tm, tm+60);//Time().RootTime()-1./24/60/60, Time().RootTime());
1880        h.SetDirectory(0);
1881//        h.SetBit(TH1::kCanRebin);
1882        h.SetStats(kFALSE);
1883//        h.SetMinimum(0);
1884//        h.SetMaximum(1);
1885        h.SetXTitle("Time");
1886        h.SetYTitle(ytitle);
1887        h.GetXaxis()->CenterTitle();
1888        h.GetYaxis()->CenterTitle();
1889        h.GetXaxis()->SetTimeDisplay(true);
1890        h.GetXaxis()->SetTimeFormat("%Mh%S'");
1891        h.GetXaxis()->SetLabelSize(0.025);
1892        h.GetYaxis()->SetLabelSize(0.025);
1893        h.GetYaxis()->SetTitleOffset(1.2);
1894//        h.GetYaxis()->SetTitleSize(1.2);
1895        h.DrawCopy()->SetDirectory(0);
1896    }
1897#endif
1898
1899public:
1900    FactGui() :
1901        fFtuStatus(40),
1902        fDimDNS("DIS_DNS/VERSION_NUMBER", 1, int(0), this),
1903
1904        fDimLoggerStats        ("DATA_LOGGER/STATS", (void*)NULL, 0, this),
1905        fDimLoggerFilenameNight("DATA_LOGGER/FILENAME_NIGHTLY", const_cast<char*>(""), 0, this),
1906        fDimLoggerFilenameRun  ("DATA_LOGGER/FILENAME_RUN",     const_cast<char*>(""), 0, this),
1907        fDimLoggerNumSubs      ("DATA_LOGGER/NUM_SUBS",         const_cast<char*>(""), 0, this),
1908
1909        fDimFtmPassport      ("FTM_CONTROL/PASSPORT",        (void*)NULL, 0, this),
1910        fDimFtmTriggerCounter("FTM_CONTROL/TRIGGER_COUNTER", (void*)NULL, 0, this),
1911        fDimFtmError         ("FTM_CONTROL/ERROR",           (void*)NULL, 0, this),
1912        fDimFtmFtuList       ("FTM_CONTROL/FTU_LIST",        (void*)NULL, 0, this),
1913        fDimFtmStaticData    ("FTM_CONTROL/STATIC_DATA",     (void*)NULL, 0, this),
1914        fDimFtmDynamicData   ("FTM_CONTROL/DYNAMIC_DATA",    (void*)NULL, 0, this),
1915        fDimFtmCounter       ("FTM_CONTROL/COUNTER",         (void*)NULL, 0, this),
1916        fDimFadPassport      ("FAD_CONTROL/PASSPORT",        (void*)NULL, 0, this),
1917        fDimFadTemperatures  ("FAD_CONTROL/TEMPERATURES",    (void*)NULL, 0, this),
1918        fDimFadSetup         ("FAD_CONTROL/SETUP",           (void*)NULL, 0, this)
1919    {
1920        fTriggerWidget->setEnabled(false);
1921        fFtuWidget->setEnabled(false);
1922        fRatesWidget->setEnabled(false);
1923        fFadWidget->setEnabled(false);
1924        fLoggerWidget->setEnabled(false);
1925
1926        fChatSend->setEnabled(false);
1927        fChatMessage->setEnabled(false);
1928
1929        DimClient::sendCommand("CHAT/MSG", "GUI online.");
1930        // + MessageDimRX
1931
1932        // --------------------------------------------------------------------------
1933
1934        ifstream fin("fact-trigger-all.txt");
1935
1936        int l = 0;
1937
1938        string buf;
1939        while (getline(fin, buf, '\n'))
1940        {
1941            buf = Tools::Trim(buf);
1942            if (buf[0]=='#')
1943                continue;
1944
1945            stringstream str(buf);
1946            for (int i=0; i<9; i++)
1947            {
1948                int n;
1949                str >> n;
1950
1951                fPatch[n] = l;
1952            }
1953            l++;
1954        }
1955
1956        // --------------------------------------------------------------------------
1957#ifdef HAVE_ROOT
1958
1959        for (int i=0; i<160; i++)
1960            fGraphPatchRate[i].SetName("PatchRate");
1961        for (int i=0; i<40; i++)
1962            fGraphBoardRate[i].SetName("BoardRate");
1963        /*
1964        TCanvas *c = fFtmTempCanv->GetCanvas();
1965        c->SetBit(TCanvas::kNoContextMenu);
1966        c->SetBorderMode(0);
1967        c->SetFrameBorderMode(0);
1968        c->SetFillColor(kWhite);
1969        c->SetRightMargin(0.03);
1970        c->SetTopMargin(0.03);
1971        c->cd();
1972        */
1973        //CreateTimeFrame("Temperature / °C");
1974
1975        fGraphFtmTemp[0].SetMarkerStyle(kFullDotSmall);
1976        fGraphFtmTemp[1].SetMarkerStyle(kFullDotSmall);
1977        fGraphFtmTemp[2].SetMarkerStyle(kFullDotSmall);
1978        fGraphFtmTemp[3].SetMarkerStyle(kFullDotSmall);
1979
1980        fGraphFtmTemp[1].SetLineColor(kBlue);
1981        fGraphFtmTemp[2].SetLineColor(kRed);
1982        fGraphFtmTemp[3].SetLineColor(kGreen);
1983
1984        fGraphFtmTemp[1].SetMarkerColor(kBlue);
1985        fGraphFtmTemp[2].SetMarkerColor(kRed);
1986        fGraphFtmTemp[3].SetMarkerColor(kGreen);
1987
1988        //fGraphFtmTemp[0].Draw("LP");
1989        //fGraphFtmTemp[1].Draw("LP");
1990        //fGraphFtmTemp[2].Draw("LP");
1991        //fGraphFtmTemp[3].Draw("LP");
1992
1993        // --------------------------------------------------------------------------
1994
1995        TCanvas *c = fFtmRateCanv->GetCanvas();
1996        c->SetBit(TCanvas::kNoContextMenu);
1997        c->SetBorderMode(0);
1998        c->SetFrameBorderMode(0);
1999        c->SetFillColor(kWhite);
2000        c->SetRightMargin(0.03);
2001        c->SetTopMargin(0.03);
2002        c->SetGrid();
2003        c->cd();
2004
2005        DrawTimeFrame("Trigger rate [Hz]");
2006
2007        fTriggerCounter0 = -1;
2008
2009        fGraphFtmRate.SetMarkerStyle(kFullDotSmall);
2010        fGraphFtmRate.Draw("LP");
2011
2012        // --------------------------------------------------------------------------
2013
2014        c = fRatesCanv->GetCanvas();
2015        c->SetBit(TCanvas::kNoContextMenu);
2016        c->SetBorderMode(0);
2017        c->SetFrameBorderMode(0);
2018        c->SetFillColor(kWhite);
2019        c->cd();
2020
2021        Camera *cam = new Camera;
2022        cam->SetBit(kCanDelete);
2023        cam->Draw();
2024
2025        ChoosePixel(*cam, 1);
2026
2027//        QTimer::singleShot(0, this, SLOT(slot_RootUpdate()));
2028
2029        //widget->setMouseTracking(true);
2030        //widget->EnableSignalEvents(kMouseMoveEvent);
2031
2032        fFtmRateCanv->setMouseTracking(true);
2033        fFtmRateCanv->EnableSignalEvents(kMouseMoveEvent);
2034
2035        fRatesCanv->setMouseTracking(true);
2036        fRatesCanv->EnableSignalEvents(kMouseMoveEvent|kMouseReleaseEvent|kMouseDoubleClickEvent);
2037
2038        connect(fRatesCanv,   SIGNAL(     RootEventProcessed(TObject*, unsigned int, TCanvas*)),
2039                this,         SLOT  (slot_RootEventProcessed(TObject*, unsigned int, TCanvas*)));
2040        connect(fFtmRateCanv, SIGNAL(     RootEventProcessed(TObject*, unsigned int, TCanvas*)),
2041                this,         SLOT  (slot_RootEventProcessed(TObject*, unsigned int, TCanvas*)));
2042#endif
2043    }
2044
2045    ~FactGui()
2046    {
2047        UnsubscribeAllServers();
2048    }
2049};
2050
2051#endif
Note: See TracBrowser for help on using the repository browser.