source: trunk/FACT++/src/fscctrl.cc @ 19458

Last change on this file since 19458 was 19458, checked in by tbretz, 8 weeks ago
Fixed two typos in some screen output.
File size: 28.3 KB
Line 
1#include <functional>
2
3#include "Dim.h"
4#include "Event.h"
5#include "Shell.h"
6#include "StateMachineDim.h"
7#include "StateMachineAsio.h"
8#include "Connection.h"
9#include "LocalControl.h"
10#include "Configuration.h"
11#include "Console.h"
12#include "Converter.h"
13#include "Interpolator2D.h"
14
15#include "tools.h"
16
17#include "HeadersFSC.h"
18
19namespace ba    = boost::asio;
20namespace bs    = boost::system;
21namespace dummy = ba::placeholders;
22
23using namespace std;
24using namespace FSC;
25
26// ------------------------------------------------------------------------
27
28class ConnectionFSC : public Connection
29{
30    FSC::BinaryOutput_t fMsg;       // A single message
31
32    bool fIsVerbose;
33    bool fIsAutoReconnect;
34
35    size_t fNumConsecutiveErrors;   // Number of consecutive messages with errors
36    size_t fNumConsecutiveMessages; // Number of consecutive message which are ok
37
38    boost::asio::deadline_timer fReconnectTimeout;
39
40protected:
41    vector<Interpolator2D::vec> fPositionsSensors;
42    vector<Interpolator2D::vec> fPositionsBias;
43
44    virtual void UpdateTemp(float, const vector<float> &)
45    {
46    }
47
48    virtual void UpdateHum(float, const vector<float>&) 
49    {
50    }
51
52    virtual void UpdateVolt(float, const vector<float>&) 
53    {
54    }
55
56    virtual void UpdateCur(float, const vector<float>&) 
57    {
58    }
59
60private:
61    //
62    // From: http://de.wikipedia.org/wiki/Pt100
63    //
64    double GetTempPT1000(double R) const 
65    {
66        // This is precise within the range 5degC and 25degC
67        // by 3e-3 degC. At 0degC and 30degC it overestimates the
68        // temperature by 0.025 degC. At -10degC it is ~0.9degC
69        // and at 40degC ~0.05degC.
70        const double x = R/1000;
71        return -193.804 + 96.0651*x + 134.673*x*x - 36.9091*x*x*x;
72
73        //for a reasonable range:
74        // R=970 -> -7.6 degC
75        // R=1300 -> 77.6 degC
76
77        //const double R0 = 1000; // 1kOhm
78        //const double a = 3.893e-3;
79        //return (R/R0 - 1)/a;
80    }
81
82    bool CheckChecksum()
83    {
84        const uint16_t volt_checksum = Tools::Fletcher16(fMsg.adc_values,    kNumVoltageChannels);
85        const uint16_t resi_checksum = Tools::Fletcher16(fMsg.ad7719_values, kNumResistanceChannels);
86
87        const bool volt_ok = volt_checksum == fMsg.adc_values_checksum;
88        const bool resi_ok = resi_checksum == fMsg.ad7719_values_checksum;
89
90        if (volt_ok && resi_ok)
91            return true;
92
93        fNumConsecutiveErrors++;
94
95        ostringstream out;
96        out << "Checksum error (V:";
97        out << hex << setfill('0');
98
99        if (volt_ok)
100            out << "----|----";
101        else
102        {
103            out << setw(4) << volt_checksum;
104            out << "|";
105            out << setw(4) << fMsg.adc_values_checksum;
106        }
107
108        out << ", R:";
109
110        if (resi_ok)
111            out << "----|----";
112        else
113        {
114            out << setw(4) << resi_checksum;
115            out << "|";
116            out << setw(4) << fMsg.ad7719_values_checksum;
117        }
118
119        out << ",  " << dec;
120        out << "Nok=" << fNumConsecutiveMessages << ", ";
121        out << "Nerr=" << fNumConsecutiveErrors << ")";
122
123        Warn(out);
124
125        fNumConsecutiveMessages = 0;
126
127        return false;
128    }
129
130    bool ProcessMessage()
131    {
132        if (fIsVerbose)
133           Out() << "Received one_message of FSC::BinaryOutput_t ... will now process it" << endl;
134
135        if (!CheckChecksum())
136            return false;
137
138        // That looks a bit odd because it copies the values twice for no reason.
139        // This is historical and keeps the following code consistent with the
140        // previous code which was reading ascii data from the fsc
141        vector<float> volt(kNumVoltageChannels);
142        vector<float> resist(kNumResistanceChannels);
143
144        const float time = fMsg.time_sec + fMsg.time_ms/1000.;
145
146        // We want to convert the pure ADC values from the FSC board to mV and kOhm respectively
147        // So we do:
148        for (unsigned int i=0; i<volt.size(); i++)
149            volt[i] = fMsg.adc_values[i]*0.1;
150
151        for (unsigned int i=0; i<resist.size(); i++)
152            resist[i] = fMsg.ad7719_values[i] * (6.25 * 1024) / (1 << 25);
153
154        int mapv[] =
155        {
156            0, 16, 24,  8,
157            1, 17, 25,  9,
158            2, 18, 26, 10,
159            //
160            3, 19, 27, 11,
161            4, 20, 28, 12,
162            5, 21, 29, 13,
163            //
164            32, 36, 33, 34, 37, 38,
165            //
166            -1
167        };
168
169        int mapc[] =
170        {
171            40, 56, 64, 48,
172            41, 57, 65, 49,
173            42, 58, 66, 50,
174            //
175            43, 59, 67, 51,
176            44, 60, 68, 52,
177            45, 61, 69, 53,
178            //
179            72, 76, 73, 74, 77, 78,
180            //
181            -1
182        };
183
184
185        int maprh[] =
186        {
187            80, 81, 82, 83, -1
188        };
189
190        int offrh[] =
191        {
192            821, 822, 816, 822,
193        };
194
195        int mapt[] =
196        {
197            // sensor compartment temperatures
198            0,  1,  2,  3,  4,  5,  6, 56, 57, 58, 59, 60,
199            61, 62, 32, 33, 34, 35, 36, 63, 37, 38, 39, 24,
200            25, 26, 27, 28, 29, 30, 31,
201            // crate temperatures (0-3, back/front)
202            12, 13, 52, 53, 44, 46, 20, 21,
203            //crate power supply temperatures (0-3)
204            8, 9, 48, 49, 40, 41, 16, 17,
205            // aux power supplies (FTM-side top/bot, FSC-side top/bot)
206            45, 50, 19, 42,
207            // backpanel (FTM-side top/bot, FSC-side top/bot)
208            11, 51, 18, 43,
209            // switch boxes (top front/back, bottom front/back)
210            15, 14, 47, 10,
211            //
212            -1
213        };
214
215        vector<float> voltages;
216        vector<float> currents;
217        vector<float> humidities;
218        vector<float> temperatures;
219
220        for (int *pv=mapv; *pv>=0; pv++)
221            voltages.push_back(volt[*pv]*0.001);
222
223        for (int *pc=mapc; *pc>=0; pc++)
224            currents.push_back(volt[*pc]*0.005);
225
226        for (int idx=0; idx<4; idx++)
227        {
228            voltages[idx +8] *= -1;
229            voltages[idx+20] *= -1;
230            currents[idx +8] *= -1;
231            currents[idx+20] *= -1;
232        }
233        voltages[12] *=  2;
234        voltages[13] *=  2;
235        voltages[14] *=  2;
236        voltages[15] *=  2;
237
238        voltages[24] *=  2;
239        voltages[25] *=  2;
240
241        voltages[27] *= -1;
242        voltages[29] *= -1;
243
244        currents[27] *= -1;
245        currents[29] *= -1;
246
247        int idx=0;
248        for (int *ph=maprh; *ph>=0; ph++, idx++)
249            humidities.push_back((volt[*ph]-offrh[idx])*0.0313);
250
251        //1019=4.8
252        //1005=1.3
253        //970=-7.6
254        //1300=76
255        for (int *pt=mapt; *pt>=0; pt++)
256            //temperatures.push_back(resist[*pt]>800&&resist[*pt]<2000 ? GetTempPT1000(resist[*pt]) : 0);
257            temperatures.push_back(resist[*pt]>970&&resist[*pt]<1300 ? GetTempPT1000(resist[*pt]) : 0);
258            //temperatures.push_back(resist[*pt]>1019&&resist[*pt]<1300 ? GetTempPT1000(resist[*pt]) : 0);
259
260        // 0 = 3-(3+0)%4
261        // 3 = 3-(3+1)%4
262        // 2 = 3-(3+2)%4
263        // 1 = 3-(3+3)%4
264
265        /*
266         index  unit    offset  scale   crate   for board:
267         0      mV      0       1       0       FAD  3.3V
268         24     mV      0       1       1       FAD  3.3V
269         16     mV      0       1       2       FAD  3.3V
270         8      mV      0       1       3       FAD  3.3V
271
272         1      mV      0       1       0       FAD  3.3V
273         25     mV      0       1       1       FAD  3.3V
274         17     mV      0       1       2       FAD  3.3V
275         9      mV      0       1       3       FAD  3.3V
276
277         2      mV      0       -1      0       FAD  -2.0V
278         26     mV      0       -1      1       FAD  -2.0V
279         18     mV      0       -1      2       FAD  -2.0V
280         10     mV      0       -1      3       FAD  -2.0V
281
282         --
283
284         3      mV      0       1       0       FPA  5.0V
285         27     mV      0       1       1       FPA  5.0V
286         19     mV      0       1       2       FPA  5.0V
287         11     mV      0       1       3       FPA  5.0V
288
289         4      mV      0       1       0       FPA  3.3V
290         28     mV      0       1       1       FPA  3.3V
291         20     mV      0       1       2       FPA  3.3V
292         12     mV      0       1       3       FPA  3.3V
293
294         5      mV      0       -1      0       FPA  -3.3V
295         29     mV      0       -1      1       FPA  -3.3V
296         21     mV      0       -1      2       FPA  -3.3V
297         13     mV      0       -1      3       FPA  -3.3V
298
299         --
300
301         32     mV      0       1       bottom  ETH   5V
302         36     mV      0       1       top     ETH   5V
303
304         33     mV      0       1       bottom  FTM   3.3V
305         34     mV      0       -1      bottom  FTM  -3.3V
306
307         37     mV      0       1       top     FFC   3.3V
308         38     mV      0       -1      top     FLP  -3.3V
309
310         -----
311
312         40     mA      0       5       0       FAD
313         64     mA      0       5       1       FAD
314         56     mA      0       5       2       FAD
315         48     mA      0       5       3       FAD
316
317         41     mA      0       5       0       FAD
318         65     mA      0       5       1       FAD
319         57     mA      0       5       2       FAD
320         49     mA      0       5       3       FAD
321
322         42     mA      0       -5      0       FAD
323         66     mA      0       -5      1       FAD
324         58     mA      0       -5      2       FAD
325         50     mA      0       -5      3       FAD
326
327         --
328
329         43     mA      0       5       0       FPA
330         67     mA      0       5       1       FPA
331         59     mA      0       5       2       FPA
332         51     mA      0       5       3       FPA
333
334         44     mA      0       5       0       FPA
335         68     mA      0       5       1       FPA
336         60     mA      0       5       2       FPA
337         52     mA      0       5       3       FPA
338
339         45     mA      0       -5      0       FPA
340         69     mA      0       -5      1       FPA
341         61     mA      0       -5      2       FPA
342         53     mA      0       -5      3       FPA
343
344         ---
345
346         72     mA      0       5       bottom  ETH
347         76     mA      0       5       top     ETH
348
349         73     mA      0       5       bottom  FTM
350         74     mA      0       -5      bottom  FTM
351
352         77     mA      0       5       top     FFC
353         78     mA      0       -5      top     FLP
354
355         ----
356
357         80     % RH    -821    0.0313          FSP000
358         81     % RH    -822    0.0313          FSP221
359         82     % RH    -816    0.0313          Sector0
360         83     % RH    -822    0.0313          Sector2
361         */
362
363        // TEMPERATURES
364        // 31 x Sensor plate
365        //  8 x Crate
366        // 12 x PS
367        //  4 x Backpanel
368        //  4 x Switchbox
369
370
371
372        /*
373         0      ohms    FSP     000
374         1      ohms    FSP     010
375         2      ohms    FSP     023
376         3      ohms    FSP     043
377         4      ohms    FSP     072
378         5      ohms    FSP     080
379         6      ohms    FSP     092
380         56     ohms    FSP     103
381         57     ohms    FSP     111
382         58     ohms    FSP     121
383         59     ohms    FSP     152
384         60     ohms    FSP     163
385         61     ohms    FSP     171
386         62     ohms    FSP     192
387         32     ohms    FSP     200
388         33     ohms    FSP     210
389         34     ohms    FSP     223
390         35     ohms    FSP     233
391         36     ohms    FSP     243
392         63     ohms    FSP     252
393         37     ohms    FSP     280
394         38     ohms    FSP     283
395         39     ohms    FSP     293
396         24     ohms    FSP     311
397         25     ohms    FSP     321
398         26     ohms    FSP     343
399         27     ohms    FSP     352
400         28     ohms    FSP     363
401         29     ohms    FSP     371
402         30     ohms    FSP     381
403         31     ohms    FSP     392
404         8      ohms    Crate0  ?
405         9      ohms    Crate0  ?
406         48     ohms    Crate1  ?
407         49     ohms    Crate1  ?
408         40     ohms    Crate2  ?
409         41     ohms    Crate2  ?
410         16     ohms    Crate3  ?
411         17     ohms    Crate3  ?
412         10     ohms    PS      Crate 0
413         11     ohms    PS      Crate 0
414         50     ohms    PS      Crate 1
415         51     ohms    PS      Crate 1
416         42     ohms    PS      Crate 2
417         43     ohms    PS      Crate 2
418         18     ohms    PS      Crate 3
419         19     ohms    PS      Crate 3
420         12     ohms    PS      Aux0
421         52     ohms    PS      Aux0
422         20     ohms    PS      Aux1
423         44     ohms    PS      Aux1
424         13     ohms    Backpanel       ?
425         21     ohms    Backpanel       ?
426         45     ohms    Backpanel       ?
427         53     ohms    Backpanel       ?
428         14     ohms    Switchbox0      ?
429         15     ohms    Switchbox0      ?
430         46     ohms    Switchbox1      ?
431         47     ohms    Switchbox1      ?
432         7      ohms    nc      nc
433         22     ohms    nc      nc
434         23     ohms    nc      nc
435         54     ohms    nc      nc
436         55     ohms    nc      nc
437         */
438
439        if (fIsVerbose)
440        {
441            for (size_t i=0; i<resist.size(); i++)
442                //if (resist[i]>800 && resist[i]<2000)
443                if (resist[i]>970 && resist[i]<1300)
444                //if (resist[i]>1019 && resist[i]<1300)
445                    Out() << setw(2) << i << " - " << setw(4) << (int)resist[i] << ": " << setprecision(1) << fixed << GetTempPT1000(resist[i]) << endl;
446                else
447                    Out() << setw(2) << i << " - " << setw(4) << (int)resist[i] << ": " << "----" << endl;
448        }
449
450        UpdateTemp(time, temperatures);
451        UpdateVolt(time, voltages);
452        UpdateCur( time, currents);
453        UpdateHum( time, humidities);
454
455        fNumConsecutiveErrors = 0;
456        fNumConsecutiveMessages++;
457
458        return true;
459    }
460
461    void StartRead()
462    {
463        ba::async_read(*this, ba::buffer(&fMsg, sizeof(FSC::BinaryOutput_t)),
464                       boost::bind(&ConnectionFSC::HandleRead, this,
465                                   dummy::error, dummy::bytes_transferred));
466
467        AsyncWait(fInTimeout, 35000, &Connection::HandleReadTimeout); // 30s
468    }
469
470    void HandleRead(const boost::system::error_code& err, size_t bytes_received)
471    {
472        // Do not schedule a new read if the connection failed.
473        if (bytes_received==0 || err)
474        {
475            if (err==ba::error::eof)
476                return;
477
478            // 107: Transport endpoint is not connected (bs::error_code(107, bs::system_category))
479            // 125: Operation canceled
480            if (err && err!=ba::error::eof &&                     // Connection closed by remote host
481                err!=ba::error::basic_errors::not_connected &&    // Connection closed by remote host
482                err!=ba::error::basic_errors::operation_aborted)  // Connection closed by us
483            {
484                ostringstream str;
485                str << "Reading from " << URL() << ": " << err.message() << " (" << err << ")";// << endl;
486                Error(str);
487            }
488            if(err!=ba::error::basic_errors::operation_aborted){
489                fIsAutoReconnect = true;
490                fReconnectTimeout.expires_from_now(boost::posix_time::seconds(10));
491                fReconnectTimeout.async_wait(boost::bind(&ConnectionFSC::HandleReconnectTimeout,
492                                                         this, dummy::error));
493                PostClose(true);
494            }else{
495                PostClose(false);
496            }
497            return;
498        }
499
500        if (!ProcessMessage())
501        {
502            fIsAutoReconnect = true;
503            fReconnectTimeout.expires_from_now(boost::posix_time::seconds(10));
504            fReconnectTimeout.async_wait(boost::bind(&ConnectionFSC::HandleReconnectTimeout,
505                                                     this, dummy::error));
506            PostClose(true);
507            return;
508        }
509
510        StartRead();
511    }
512
513    void ConnectionEstablished()
514    {
515        fNumConsecutiveErrors   = 0;
516        fNumConsecutiveMessages = 0;
517        fIsAutoReconnect = false;
518
519        StartRead();
520    }
521
522    void HandleReconnectTimeout(const bs::error_code &)
523    {
524        fIsAutoReconnect = false;
525    }
526
527    void HandleReadTimeout(const bs::error_code &error)
528    {
529        if (error==ba::error::basic_errors::operation_aborted)
530            return;
531
532        if (error)
533        {
534            ostringstream str;
535            str << "Read timeout of " << URL() << ": " << error.message() << " (" << error << ")";// << endl;
536            Error(str);
537
538            PostClose();
539            return;
540
541        }
542
543        if (!is_open())
544        {
545            // For example: Here we could schedule a new accept if we
546            // would not want to allow two connections at the same time.
547            return;
548        }
549
550        // Check whether the deadline has passed. We compare the deadline
551        // against the current time since a new asynchronous operation
552        // may have moved the deadline before this actor had a chance
553        // to run.
554        if (fInTimeout.expires_at() > ba::deadline_timer::traits_type::now())
555            return;
556
557        Error("Timeout reading data from "+URL());
558
559        PostClose();
560    }
561
562public:
563    ConnectionFSC(ba::io_service& ioservice, MessageImp &imp) : Connection(ioservice, imp()),
564        fIsVerbose(false), fIsAutoReconnect(false), fReconnectTimeout(ioservice)
565    {
566        SetLogStream(&imp);
567    }
568
569    void SetVerbose(bool b)
570    {
571        fIsVerbose = b;
572    }
573
574    void SetPositionsSensors(const vector<Interpolator2D::vec> &vec)
575    {
576        fPositionsSensors = vec;
577    }
578
579    void SetPositionsBias(const vector<Interpolator2D::vec> &vec)
580    {
581        fPositionsBias = vec;
582    }
583
584    bool IsOpen() const
585    {
586        return IsConnected() || fIsAutoReconnect;
587    }
588};
589
590// ------------------------------------------------------------------------
591
592#include "DimDescriptionService.h"
593
594class ConnectionDimFSC : public ConnectionFSC
595{
596private:
597
598    vector<double> fLastRms;
599
600    DimDescribedService fDimTemp;
601    DimDescribedService fDimTemp2;
602    DimDescribedService fDimHum;
603    DimDescribedService fDimVolt;
604    DimDescribedService fDimCurrent;
605
606    void Update(DimDescribedService &svc, vector<float> data, float time) const
607    {
608        data.insert(data.begin(), time);
609        svc.Update(data);
610    }
611
612    void UpdateTemp(float time, const vector<float> &temp)
613    {
614        Update(fDimTemp, temp, time);
615
616        vector<double> T;
617        vector<Interpolator2D::vec> xy;
618
619        T.reserve(31);
620        xy.reserve(31);
621
622        double avg = 0;
623        double rms = 0;
624
625        // Create a list of all valid sensors
626        for (int i=0; i<31; i++)
627            if (temp[i]!=0)
628            {
629                T.emplace_back(temp[i]);
630                xy.emplace_back(fPositionsSensors[i]);
631
632                avg += temp[i];
633                rms += temp[i]*temp[i];
634            }
635
636        if (T.size()==0)
637        {
638            Warn("No valid sensor temperatures.");
639            return;
640        }
641
642        avg /= T.size();
643        rms /= T.size();
644        rms -= avg*avg;
645        rms = rms<0 ? 0 : sqrt(rms);
646
647        // Clean broken reports
648        const double cut_val = 0.015;
649        const bool reject = rms>4 || (fabs(fLastRms[0]-fLastRms[1])<=cut_val && fabs(rms-fLastRms[0])>cut_val);
650
651        fLastRms[1] = fLastRms[0];
652        fLastRms[0] = rms;
653
654        if (reject)
655        {
656            Warn("Suspicious temperature values rejecte for BIAS_TEMP.");
657            return;
658        }
659
660        // Create interpolator for the corresponding sensor positions
661        Interpolator2D inter(xy);
662
663        // Calculate weights for the output positions
664        if (!inter.SetOutputGrid(fPositionsBias))
665        {
666            Warn("Temperature values rejecte for BIAS_TEMP (calculation of weights failed).");
667            return;
668        }
669
670        // Interpolate the data
671        T = inter.Interpolate(T);
672
673        avg = 0;
674        rms = 0;
675        for (int i=0; i<320; i++)
676        {
677            avg += T[i];
678            rms += T[i]*T[i];
679        }
680
681        avg /= 320;
682        rms /= 320;
683        rms -= avg*avg;
684        rms = rms<0 ? 0 : sqrt(rms);
685
686        vector<float> out;
687        out.reserve(322);
688        out.assign(T.cbegin(), T.cend());
689        out.emplace_back(avg);
690        out.emplace_back(rms);
691
692        // Update the Dim service with the interpolated positions
693        Update(fDimTemp2, out, time);
694    }
695
696    void UpdateHum(float time, const vector<float> &hum)
697    {
698        Update(fDimHum, hum, time);
699    }
700
701    void UpdateVolt(float time, const vector<float> &volt)
702    {
703        Update(fDimVolt, volt, time);
704    }
705
706    void UpdateCur(float time, const vector<float> &curr)
707    {
708        Update(fDimCurrent, curr, time);
709    }
710
711public:
712    ConnectionDimFSC(ba::io_service& ioservice, MessageImp &imp) :
713        ConnectionFSC(ioservice, imp), fLastRms(2),
714        fDimTemp   ("FSC_CONTROL/TEMPERATURE", "F:1;F:31;F:8;F:8;F:4;F:4;F:4",
715                    "|t[s]:FSC uptime"
716                    "|T_sens[deg C]:Sensor compartment temperatures"
717                    "|T_crate[deg C]:Temperatures crate 0 (back/front), 1 (b/f), 2 (b/f), 3 (b/f)"
718                    "|T_ps[deg C]:Temp power supplies crate 0 (back/front), 1, 2, 3"
719                    "|T_aux[deg C]:Auxiliary power supply temperatures FTM (top/bottom), FSC (t/b)"
720                    "|T_back[deg C]:FTM backpanel temperatures FTM (top/bottom), FSC (top/bottom)"
721                    "|T_eth[deg C]:Ethernet switches temperatures top (front/back), bottom (f/b)"),
722        fDimTemp2  ("FSC_CONTROL/BIAS_TEMP", "F:1;F:320;F:1;F:1",
723                    "|t[s]:FSC uptime"
724                    "|T[deg C]:Interpolated temperatures at bias patch positions"
725                    "|T_avg[deg C]:Average temperature calculated from all patches"
726                    "|T_rms[deg C]:Temperature RMS calculated from all patches"),
727        fDimHum    ("FSC_CONTROL/HUMIDITY", "F:1;F:4",
728                    "|t[s]:FSC uptime"
729                    "|H[%]:Humidity sensors readout"),
730        fDimVolt   ("FSC_CONTROL/VOLTAGE",
731                    "F:1;F:4;F:4;F:4;F:4;F:4;F:4;F:2;F:2;F:1;F:1",
732                    "|t[s]:FSC uptime"
733                    "|FAD_Ud[V]:FAD digital (crate 0-3)"
734                    "|FAD_Up[V]:FAD positive (crate 0-3)"
735                    "|FAD_Un[V]:FAD negative (crate 0-3)"
736                    "|FPA_Ud[V]:FPA digital (crate 0-3)"
737                    "|FPA_Up[V]:FPA positive (crate 0-3)"
738                    "|FPA_Un[V]:FPA negative (crate 0-3)"
739                    "|ETH_U[V]:Ethernet switch (pos/neg)"
740                    "|FTM_U[V]:FTM - trigger master (pos/neg)"
741                    "|FFC_U[V]:FFC"
742                    "|FLP_U[V]:FLP - light pulser"),
743        fDimCurrent("FSC_CONTROL/CURRENT", "F:1;F:4;F:4;F:4;F:4;F:4;F:4;F:2;F:2;F:1;F:1",
744                    "|t[s]:FSC uptime"
745                    "|FAD_Id[A]:FAD digital (crate 0-3)"
746                    "|FAD_Ip[A]:FAD positive (crate 0-3)"
747                    "|FAD_In[A]:FAD negative (crate 0-3)"
748                    "|FPA_Id[A]:FPA digital (crate 0-3)"
749                    "|FPA_Ip[A]:FPA positive (crate 0-3)"
750                    "|FPA_In[A]:FPA negative (crate 0-3)"
751                    "|ETH_I[A]:Ethernet switch (pos/neg)"
752                    "|FTM_I[A]:FTM - trigger master (pos/neg)"
753                    "|FFC_I[A]:FFC"
754                    "|FLP_I[A]:FLP - light pulser")
755    {
756        fLastRms[0] = 1.5;
757    }
758
759    // A B [C] [D] E [F] G H [I] J K [L] M N O P Q R [S] T U V W [X] Y Z
760};
761
762// ------------------------------------------------------------------------
763
764template <class T, class S>
765class StateMachineFSC : public StateMachineAsio<T>
766{
767private:
768    S fFSC;
769
770    int Disconnect()
771    {
772        // Close all connections
773        fFSC.PostClose(false);
774
775        return T::GetCurrentState();
776    }
777
778    int Reconnect(const EventImp &evt)
779    {
780        // Close all connections to supress the warning in SetEndpoint
781        fFSC.PostClose(false);
782
783        // Now wait until all connection have been closed and
784        // all pending handlers have been processed
785        ba::io_service::poll();
786
787        if (evt.GetBool())
788            fFSC.SetEndpoint(evt.GetString());
789
790        // Now we can reopen the connection
791        fFSC.PostClose(true);
792
793        return T::GetCurrentState();
794    }
795
796    int Execute()
797    {
798        return fFSC.IsOpen() ? State::kConnected : State::kDisconnected;
799    }
800
801    bool CheckEventSize(size_t has, const char *name, size_t size)
802    {
803        if (has==size)
804            return true;
805
806        ostringstream msg;
807        msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
808        T::Fatal(msg);
809        return false;
810    }
811
812    int SetVerbosity(const EventImp &evt)
813    {
814        if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
815            return T::kSM_FatalError;
816
817        fFSC.SetVerbose(evt.GetBool());
818
819        return T::GetCurrentState();
820    }
821
822public:
823    StateMachineFSC(ostream &out=cout) :
824        StateMachineAsio<T>(out, "FSC_CONTROL"), fFSC(*this, *this)
825    {
826        // State names
827        T::AddStateName(State::kDisconnected, "Disconnected",
828                     "FSC board not connected via ethernet.");
829
830        T::AddStateName(State::kConnected, "Connected",
831                     "Ethernet connection to FSC established.");
832
833        // Verbosity commands
834        T::AddEvent("SET_VERBOSE", "B:1")
835            (bind(&StateMachineFSC::SetVerbosity, this, placeholders::_1))
836            ("set verbosity state"
837             "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
838
839        // Conenction commands
840        T::AddEvent("DISCONNECT", State::kConnected)
841            (bind(&StateMachineFSC::Disconnect, this))
842            ("disconnect from ethernet");
843
844        T::AddEvent("RECONNECT", "O", State::kDisconnected, State::kConnected)
845            (bind(&StateMachineFSC::Reconnect, this, placeholders::_1))
846            ("(Re)connect ethernet connection to FSC, a new address can be given"
847             "|[host][string]:new ethernet address in the form <host:port>");
848
849        fFSC.StartConnect();
850    }
851
852    void SetEndpoint(const string &url)
853    {
854        fFSC.SetEndpoint(url);
855    }
856
857    int EvalOptions(Configuration &conf)
858    {
859        fFSC.SetVerbose(!conf.Get<bool>("quiet"));
860
861        const string fname1 = conf.GetPrefixedString("sensor-pos-file");
862        const auto v1 = Interpolator2D::ReadGrid(fname1);
863        if (v1.size() != 31)
864        {
865            T::Error("Reading sensor positions from "+fname1+" failed ("+to_string(v1.size())+")");
866            return 1;
867        }
868
869        const string fname2 = conf.GetPrefixedString("patch-pos-file");
870        const auto v2 = Interpolator2D::ReadGrid(fname2);
871        if (v2.size() != 320)
872        {
873            T::Error("Reading bias patch positions from "+fname2+" failed ("+to_string(v2.size())+")");
874            return 1;
875        }
876
877        fFSC.SetPositionsSensors(v1);
878        fFSC.SetPositionsBias(v2);
879
880        SetEndpoint(conf.Get<string>("addr"));
881
882        return -1;
883    }
884};
885
886// ------------------------------------------------------------------------
887
888#include "Main.h"
889
890template<class T, class S, class R>
891int RunShell(Configuration &conf)
892{
893    return Main::execute<T, StateMachineFSC<S, R>>(conf);
894}
895
896void SetupConfiguration(Configuration &conf)
897{
898    po::options_description control("FSC control options");
899    control.add_options()
900        ("no-dim",        po_bool(),  "Disable dim services")
901        ("addr,a",        var<string>("localhost:5000"),  "Network address of FSC")
902        ("sensor-pos-file", var<string>()->required(),  "File with the positions of the 31 temperature sensors")
903        ("patch-pos-file",  var<string>()->required(),  "File with the positions of the 320 bias patches")
904        ("quiet,q",       po_bool(true),  "Disable printing contents of all received messages (except dynamic data) in clear text.")
905        ;
906
907    conf.AddOptions(control);
908}
909
910/*
911 Extract usage clause(s) [if any] for SYNOPSIS.
912 Translators: "Usage" and "or" here are patterns (regular expressions) which
913 are used to match the usage synopsis in program output.  An example from cp
914 (GNU coreutils) which contains both strings:
915  Usage: cp [OPTION]... [-T] SOURCE DEST
916    or:  cp [OPTION]... SOURCE... DIRECTORY
917    or:  cp [OPTION]... -t DIRECTORY SOURCE...
918 */
919void PrintUsage()
920{
921    cout <<
922        "The fscctrl controls the FSC (FACT Slow Control) board.\n"
923        "\n"
924        "The default is that the program is started without user intercation. "
925        "All actions are supposed to arrive as DimCommands. Using the -c "
926        "option, a local shell can be initialized. With h or help a short "
927        "help message about the usuage can be brought to the screen.\n"
928        "\n"
929        "Usage: fscctrl [-c type] [OPTIONS]\n"
930        "  or:  fscctrl [OPTIONS]\n";
931    cout << endl;
932}
933
934void PrintHelp()
935{
936    Main::PrintHelp<StateMachineFSC<StateMachine, ConnectionFSC>>();
937
938    /* Additional help text which is printed after the configuration
939     options goes here */
940
941    /*
942     cout << "bla bla bla" << endl << endl;
943     cout << endl;
944     cout << "Environment:" << endl;
945     cout << "environment" << endl;
946     cout << endl;
947     cout << "Examples:" << endl;
948     cout << "test exam" << endl;
949     cout << endl;
950     cout << "Files:" << endl;
951     cout << "files" << endl;
952     cout << endl;
953     */
954}
955
956int main(int argc, const char* argv[])
957{
958    Configuration conf(argv[0]);
959    conf.SetPrintUsage(PrintUsage);
960    Main::SetupConfiguration(conf);
961    SetupConfiguration(conf);
962
963    if (!conf.DoParse(argc, argv, PrintHelp))
964        return 127;
965
966    //try
967    {
968        // No console access at all
969        if (!conf.Has("console"))
970        {
971            if (conf.Get<bool>("no-dim"))
972                return RunShell<LocalStream, StateMachine, ConnectionFSC>(conf);
973            else
974                return RunShell<LocalStream, StateMachineDim, ConnectionDimFSC>(conf);
975        }
976        // Cosole access w/ and w/o Dim
977        if (conf.Get<bool>("no-dim"))
978        {
979            if (conf.Get<int>("console")==0)
980                return RunShell<LocalShell, StateMachine, ConnectionFSC>(conf);
981            else
982                return RunShell<LocalConsole, StateMachine, ConnectionFSC>(conf);
983        }
984        else
985        {
986            if (conf.Get<int>("console")==0)
987                return RunShell<LocalShell, StateMachineDim, ConnectionDimFSC>(conf);
988            else
989                return RunShell<LocalConsole, StateMachineDim, ConnectionDimFSC>(conf);
990        }
991    }
992    /*catch (std::exception& e)
993    {
994        cerr << "Exception: " << e.what() << endl;
995        return -1;
996    }*/
997
998    return 0;
999}
Note: See TracBrowser for help on using the repository browser.