source: trunk/FACT++/src/ftmctrl.cc @ 10799

Last change on this file since 10799 was 10799, checked in by tbretz, 9 years ago
Simplified program options handling; only send enable of a general settings register if it changed at all; only sent trigger counter if the received report was dynamic data.
File size: 55.9 KB
Line 
1#include <boost/bind.hpp>
2#include <boost/array.hpp>
3#if BOOST_VERSION < 104400
4#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 4))
5#undef BOOST_HAS_RVALUE_REFS
6#endif
7#endif
8#include <boost/thread.hpp>
9#include <boost/asio/error.hpp>
10#include <boost/asio/deadline_timer.hpp>
11
12#include "Dim.h"
13#include "Event.h"
14#include "Shell.h"
15#include "StateMachineDim.h"
16#include "Connection.h"
17#include "Configuration.h"
18#include "Timers.h"
19#include "Console.h"
20#include "Converter.h"
21
22#include "tools.h"
23
24#include "LocalControl.h"
25#include "HeadersFTM.h"
26
27
28namespace ba = boost::asio;
29namespace bs = boost::system;
30
31using namespace std;
32
33// ------------------------------------------------------------------------
34
35class ConnectionFTM : public Connection
36{
37    vector<uint16_t> fBuffer;
38
39    bool fHasHeader;
40    int  fState;
41
42    bool fIsVerbose;
43    bool fIsDynamicOut;
44    bool fIsHexOutput;
45
46//    string fDefaultSetup;
47
48    // --verbose
49    // --hex-out
50    // --dynamic-out
51    // --load-file
52    // --leds
53    // --trigger-interval
54    // --physcis-coincidence
55    // --calib-coincidence
56    // --physcis-window
57    // --physcis-window
58    // --trigger-delay
59    // --time-marker-delay
60    // --dead-time
61    // --clock-conditioner-r0
62    // --clock-conditioner-r1
63    // --clock-conditioner-r8
64    // --clock-conditioner-r9
65    // --clock-conditioner-r11
66    // --clock-conditioner-r13
67    // --clock-conditioner-r14
68    // --clock-conditioner-r15
69    // ...
70
71protected:
72    map<uint16_t, int> fCounter;
73
74    FTM::Header      fHeader;
75    FTM::FtuList     fFtuList;
76    FTM::StaticData  fStaticData;
77    FTM::DynamicData fDynamicData;
78    FTM::Error       fError;
79
80    virtual void UpdateFirstHeader()
81    {
82        // FIXME: Message() ?
83        Out() << endl << kBold << "First header received:" << endl;
84        Out() << fHeader;
85        if (fIsHexOutput)
86            Out() << Converter::GetHex<uint16_t>(fHeader, 16) << endl;
87    }
88
89    virtual void UpdateHeader()
90    {
91        // emit service with trigger counter from header
92        if (!fIsVerbose)
93            return;
94
95        if (fHeader.fType==FTM::kDynamicData && !fIsDynamicOut)
96            return;
97
98        Out() << endl << kBold << "Header received:" << endl;
99        Out() << fHeader;
100        if (fIsHexOutput)
101            Out() << Converter::GetHex<uint16_t>(fHeader, 16) << endl;
102    }
103
104    virtual void UpdateFtuList()
105    {
106        if (!fIsVerbose)
107            return;
108
109        Out() << endl << kBold << "FtuList received:" << endl;
110        Out() << fFtuList;
111        if (fIsHexOutput)
112            Out() << Converter::GetHex<uint16_t>(fFtuList, 16) << endl;
113    }
114
115    virtual void UpdateStaticData()
116    {
117        if (!fIsVerbose)
118            return;
119
120        Out() << endl << kBold << "Static data received:" << endl;
121        Out() << fStaticData;
122        if (fIsHexOutput)
123            Out() << Converter::GetHex<uint16_t>(fStaticData, 16) << endl;
124    }
125
126    virtual void UpdateDynamicData()
127    {
128        if (!fIsDynamicOut)
129            return;
130
131        Out() << endl << kBold << "Dynamic data received:" << endl;
132        Out() << fDynamicData;
133        if (fIsHexOutput)
134            Out() << Converter::GetHex<uint16_t>(fDynamicData, 16) << endl;
135    }
136
137    virtual void UpdateError()
138    {
139        if (!fIsVerbose)
140            return;
141
142        Out() << endl << kRed << "Error received:" << endl;
143        Out() << fError;
144        if (fIsHexOutput)
145            Out() << Converter::GetHex<uint16_t>(fError, 16) << endl;
146    }
147
148    virtual void UpdateCounter()
149    {
150        if (!fIsVerbose)
151            return;
152
153        if (!fIsDynamicOut)
154            return;
155
156        Out() << "Received: ";
157        Out() << "H=" << fCounter[FTM::kHeader] << "  ";
158        Out() << "S=" << fCounter[FTM::kStaticData] << "  ";
159        Out() << "D=" << fCounter[FTM::kDynamicData] << "  ";
160        Out() << "F=" << fCounter[FTM::kFtuList] << "  ";
161        Out() << "E=" << fCounter[FTM::kErrorList] << "  ";
162        Out() << "R=" << fCounter[FTM::kRegister] << endl;
163    }
164
165    bool CheckConsistency()
166    {
167        bool warn1 = false;
168        if (fStaticData.IsEnabled(FTM::StaticData::kPedestal) != (fStaticData.GetSequencePed()  >0) ||
169            fStaticData.IsEnabled(FTM::StaticData::kLPint)    != (fStaticData.GetSequenceLPint()>0) ||
170            fStaticData.IsEnabled(FTM::StaticData::kLPext)    != (fStaticData.GetSequenceLPext()>0))
171        {
172            warn1 = true;
173            fStaticData.Enable(FTM::StaticData::kPedestal, fStaticData.GetSequencePed()>0);
174            fStaticData.Enable(FTM::StaticData::kLPint,    fStaticData.GetSequenceLPint()>0);
175            fStaticData.Enable(FTM::StaticData::kLPext,    fStaticData.GetSequenceLPext()>0);
176        }
177
178        bool warn2 = false;
179        const uint16_t ref = fStaticData[0].fPrescaling;
180        for (int i=1; i<40; i++)
181        {
182            if (fStaticData[i].fPrescaling != ref)
183            {
184                warn2 = true;
185                fStaticData[i].fPrescaling = ref;
186            }
187        }
188
189        if (warn1)
190            Warn("GeneralSettings not consistent with trigger sequence.");
191        if (warn2)
192            Warn("Prescaling not consistent for all boards.");
193
194        return !warn1 && !warn2;
195    }
196
197private:
198    void HandleReceivedData(const bs::error_code& err, size_t bytes_received, int /*type*/)
199    {
200        // Do not schedule a new read if the connection failed.
201        if (bytes_received==0 || err)
202        {
203            if (err==ba::error::eof)
204                Warn("Connection closed by remote host (FTM).");
205
206            // 107: Transport endpoint is not connected (bs::error_code(107, bs::system_category))
207            // 125: Operation canceled
208            if (err && err!=ba::error::eof &&                     // Connection closed by remote host
209                err!=ba::error::basic_errors::not_connected &&    // Connection closed by remote host
210                err!=ba::error::basic_errors::operation_aborted)  // Connection closed by us
211            {
212                ostringstream str;
213                str << "Reading from " << URL() << ": " << err.message() << " (" << err << ")";// << endl;
214                Error(str);
215            }
216            PostClose(err!=ba::error::basic_errors::operation_aborted);
217            return;
218        }
219
220        // If we have not yet received a header we expect one now
221        // This could be moved to a HandleReceivedHeader function
222        if (!fHasHeader)
223        {
224            if (bytes_received!=sizeof(FTM::Header))
225            {
226                ostringstream str;
227                str << "Excepted " << sizeof(FTM::Header) << " bytes (FTM::Header) but received " << bytes_received << ".";
228                Error(str);
229                PostClose(false);
230                return;
231            }
232
233            fHeader = fBuffer;
234
235            // Check the data integrity
236            if (fHeader.fDelimiter!=FTM::kDelimiterStart)
237            {
238                ostringstream str;
239                str << "Invalid header received: start delimiter wrong, received ";
240                str << hex << fHeader.fDelimiter << ", expected " << FTM::kDelimiterStart << ".";
241                Error(str);
242                PostClose(false);
243                return;
244            }
245
246            fHasHeader = true;
247
248            // Convert FTM state into FtmCtrl state
249            switch (fHeader.fState)
250            {
251            case FTM::kFtmIdle:
252            case FTM::kFtmConfig:
253                fState = FTM::kIdle;
254                break;
255
256            case FTM::kFtmCalib:
257            case FTM::kFtmRunning:
258                fState = FTM::kTakingData;
259                break;
260            }
261
262            if (++fCounter[FTM::kHeader]==1)
263                UpdateFirstHeader();
264
265            UpdateCounter();
266            UpdateHeader();
267
268            // Start reading of data
269            switch (fHeader.fType)
270            {
271            case FTM::kStaticData:
272            case FTM::kDynamicData:
273            case FTM::kFtuList:
274            case FTM::kRegister:
275            case FTM::kErrorList:
276                // This is not very efficient because the space is reallocated
277                // maybe we can check if the capacity of the std::vector
278                // is ever decreased. If not, everythign is fine.
279                fBuffer.resize(fHeader.fDataSize);
280                AsyncRead(ba::buffer(fBuffer));
281                AsyncWait(fInTimeout, 50, &Connection::HandleReadTimeout);
282                return;
283
284            default:
285                ostringstream str;
286                str << "Unknonw type " << fHeader.fType << " in received header." << endl;
287                Error(str);
288                PostClose(false);
289                return;
290            }
291
292            return;
293        }
294
295        // Check the data integrity (check end delimiter)
296        if (ntohs(fBuffer.back())!=FTM::kDelimiterEnd)
297        {
298            ostringstream str;
299            str << "Invalid data received: end delimiter wrong, received ";
300            str << hex << ntohs(fBuffer.back()) << ", expected " << FTM::kDelimiterEnd << ".";
301            Error(str);
302            PostClose(false);
303            return;
304        }
305
306        // Remove end delimiter
307        fBuffer.pop_back();
308
309        try
310        {
311            // If we have already received a header this is the data now
312            // This could be moved to a HandleReceivedData function
313
314            fCounter[fHeader.fType]++;
315            UpdateCounter();
316
317            switch (fHeader.fType)
318            {
319            case FTM::kFtuList:
320                fFtuList = fBuffer;
321                UpdateFtuList();
322                break;
323
324            case FTM::kStaticData:
325                fStaticData = fBuffer;
326
327                if (fCounter[FTM::kStaticData]==1)
328                    if (!CheckConsistency())
329                    {
330                        CmdSendStatDat();
331                        break;
332                    }
333
334                UpdateStaticData();
335                break;
336
337            case FTM::kDynamicData:
338                fDynamicData = fBuffer;
339                UpdateDynamicData();
340                break;
341
342            case FTM::kRegister:
343                if (fIsVerbose)
344                {
345                    Out() << endl << kBold << "Register received: " << endl;
346                    Out() << "Addr:  " << ntohs(fBuffer[0]) << endl;
347                    Out() << "Value: " << ntohs(fBuffer[1]) << endl;
348                }
349                break;
350
351            case FTM::kErrorList:
352                fError = fBuffer;
353                UpdateError();
354                break;
355
356            default:
357                ostringstream str;
358                str << "Unknonw type " << fHeader.fType << " in header." << endl;
359                Error(str);
360                PostClose(false);
361                return;
362            }
363        }
364        catch (const logic_error &e)
365        {
366            ostringstream str;
367            str << "Exception converting buffer into data structure: " << e.what();
368            Error(str);
369            PostClose(false);
370            return;
371        }
372
373        fInTimeout.cancel();
374
375        fHeader.clear();
376        fHasHeader = false;
377        fBuffer.resize(sizeof(FTM::Header)/2);
378        AsyncRead(ba::buffer(fBuffer));
379    }
380
381    // This is called when a connection was established
382    void ConnectionEstablished()
383    {
384        fState = FTM::kConnected;
385        fCounter.clear();
386
387        fHeader.clear();
388        fHasHeader = false;
389        fBuffer.resize(sizeof(FTM::Header)/2);
390        AsyncRead(ba::buffer(fBuffer));
391
392//        if (!fDefaultSetup.empty())
393//            LoadStaticData(fDefaultSetup);
394
395        // Get a header and configdata!
396        CmdReqStatDat();
397
398        // get the DNA of the FTUs
399        CmdPing();
400    }
401
402    void HandleReadTimeout(const bs::error_code &error)
403    {
404        if (error && error!=ba::error::basic_errors::operation_aborted)
405        {
406            ostringstream str;
407            str << "Read timeout of " << URL() << ": " << error.message() << " (" << error << ")";// << endl;
408            Error(str);
409
410            PostClose();
411            return;
412
413        }
414
415        if (!is_open())
416        {
417            // For example: Here we could schedule a new accept if we
418            // would not want to allow two connections at the same time.
419            return;
420        }
421
422        // Check whether the deadline has passed. We compare the deadline
423        // against the current time since a new asynchronous operation
424        // may have moved the deadline before this actor had a chance
425        // to run.
426        if (fInTimeout.expires_at() > ba::deadline_timer::traits_type::now())
427            return;
428
429        Error("Timeout reading data from "+URL());
430
431        PostClose();
432    }
433
434
435    template<size_t N>
436    void PostCmd(boost::array<uint16_t, N> dat, uint16_t u1=0, uint16_t u2=0, uint16_t u3=0, uint16_t u4=0)
437    {
438        boost::array<uint16_t, 5> cmd = {{ '@', u1, u2, u3, u4 }};
439
440        ostringstream msg;
441        msg << "Sending command:" << hex;
442        msg << " 0x" << setw(4) << setfill('0') << cmd[0];
443        msg << " 0x" << setw(4) << setfill('0') << u1;
444        msg << " 0x" << setw(4) << setfill('0') << u2;
445        msg << " 0x" << setw(4) << setfill('0') << u3;
446        msg << " 0x" << setw(4) << setfill('0') << u4;
447        msg << " (+" << dec << dat.size() << " words)";
448        Message(msg);
449
450        vector<uint16_t> out(cmd.size()+dat.size());
451
452        transform(cmd.begin(), cmd.end(), out.begin(), htons);
453        transform(dat.begin(), dat.end(), out.begin()+cmd.size(), htons);
454
455        PostMessage(out);
456    }
457
458    void PostCmd(vector<uint16_t> dat, uint16_t u1=0, uint16_t u2=0, uint16_t u3=0, uint16_t u4=0)
459    {
460        boost::array<uint16_t, 5> cmd = {{ '@', u1, u2, u3, u4 }};
461
462        ostringstream msg;
463        msg << "Sending command:" << hex;
464        msg << " 0x" << setw(4) << setfill('0') << cmd[0];
465        msg << " 0x" << setw(4) << setfill('0') << u1;
466        msg << " 0x" << setw(4) << setfill('0') << u2;
467        msg << " 0x" << setw(4) << setfill('0') << u3;
468        msg << " 0x" << setw(4) << setfill('0') << u4;
469        msg << " (+" << dec << dat.size() << " words)";
470        Message(msg);
471
472        vector<uint16_t> out(cmd.size()+dat.size());
473
474        transform(cmd.begin(), cmd.end(), out.begin(), htons);
475        copy(dat.begin(), dat.end(), out.begin()+cmd.size());
476
477        PostMessage(out);
478    }
479
480    void PostCmd(uint16_t u1=0, uint16_t u2=0, uint16_t u3=0, uint16_t u4=0)
481    {
482        PostCmd(boost::array<uint16_t, 0>(), u1, u2, u3, u4);
483    }
484public:
485
486//    static const uint16_t kMaxAddr;
487
488public:
489    ConnectionFTM(ba::io_service& ioservice, MessageImp &imp) : Connection(ioservice, imp()),
490        fState(0), fIsVerbose(true), fIsDynamicOut(true), fIsHexOutput(true)
491    {
492        SetLogStream(&imp);
493    }
494
495    void CmdToggleLed()
496    {
497        PostCmd(FTM::kCmdToggleLed);
498    }
499
500    void CmdPing()
501    {
502        PostCmd(FTM::kCmdPing);
503    }
504
505    void CmdReqDynDat()
506    {
507        PostCmd(FTM::kCmdRead, FTM::kCmdDynamicData);
508    }
509
510    void CmdReqStatDat()
511    {
512        PostCmd(FTM::kCmdRead, FTM::kCmdStaticData);
513    }
514
515    void CmdSendStatDat()
516    {
517        PostCmd(fStaticData.HtoN(), FTM::kCmdWrite, FTM::kCmdStaticData);
518
519        // Request the changed configuration to ensure the
520        // change is distributed in the network
521        CmdReqStatDat();
522    }
523
524    void CmdStartRun()
525    {
526        PostCmd(FTM::kCmdStartRun, FTM::kStartRun);
527
528        // Update state information by requesting a new header
529        CmdGetRegister(0);
530    }
531
532    void CmdStopRun()
533    {
534        PostCmd(FTM::kCmdStopRun);
535
536        // Update state information by requesting a new header
537        CmdGetRegister(0);
538    }
539
540    void CmdTakeNevents(uint32_t n)
541    {
542        const boost::array<uint16_t, 2> data = {{ uint16_t(n>>16), uint16_t(n&0xffff) }};
543        PostCmd(data, FTM::kCmdStartRun, FTM::kTakeNevents);
544
545        // Update state information by requesting a new header
546        CmdGetRegister(0);
547    }
548
549    bool CmdSetRegister(uint16_t addr, uint16_t val)
550    {
551        if (addr>FTM::StaticData::kMaxAddr)
552            return false;
553
554        const boost::array<uint16_t, 2> data = {{ addr, val }};
555        PostCmd(data, FTM::kCmdWrite, FTM::kCmdRegister);
556
557        // Request the changed configuration to ensure the
558        // change is distributed in the network
559        CmdReqStatDat();
560
561        return true;
562    }
563
564    bool CmdGetRegister(uint16_t addr)
565    {
566        if (addr>FTM::StaticData::kMaxAddr)
567            return false;
568
569        const boost::array<uint16_t, 1> data = {{ addr }};
570        PostCmd(data, FTM::kCmdRead, FTM::kCmdRegister);
571
572        return true;
573    }
574
575    bool CmdResetCrate(uint16_t addr)
576    {
577        if (addr>3)
578            return false;
579
580        PostCmd(FTM::kCmdCrateReset, 1<<addr);
581
582        return true;
583    }
584
585    bool CmdResetCamera()
586    {
587        PostCmd(FTM::kCmdCrateReset, FTM::kResetCrate0);
588        PostCmd(FTM::kCmdCrateReset, FTM::kResetCrate1);
589        PostCmd(FTM::kCmdCrateReset, FTM::kResetCrate2);
590        PostCmd(FTM::kCmdCrateReset, FTM::kResetCrate3);
591
592        return true;
593    }
594
595    bool CmdDisableReports(bool b)
596    {
597        PostCmd(FTM::kCmdDisableReports, b ? uint16_t(0) : uint16_t(1));
598        return true;
599    }
600
601    void SetVerbose(bool b)
602    {
603        fIsVerbose = b;
604    }
605
606    void SetHexOutput(bool b)
607    {
608        fIsHexOutput = b;
609    }
610
611    void SetDynamicOut(bool b)
612    {
613        fIsDynamicOut = b;
614    }
615/*
616    void SetDefaultSetup(const string &file)
617    {
618        fDefaultSetup = file;
619    }
620*/
621    bool LoadStaticData(string name)
622    {
623        if (name.rfind(".bin")!=name.length()-5)
624            name += ".bin";
625
626        ifstream fin(name);
627        if (!fin)
628            return false;
629
630        FTM::StaticData data;
631
632        fin.read(reinterpret_cast<char*>(&data), sizeof(FTM::StaticData));
633
634        if (fin.gcount()<streamsize(sizeof(FTM::StaticData)))
635            return false;
636
637        if (fin.fail() || fin.eof())
638            return false;
639
640        if (fin.peek()!=-1)
641            return false;
642
643        fStaticData = data;
644
645        CmdSendStatDat();
646
647        return true;
648    }
649
650    bool SaveStaticData(string name) const
651    {
652        if (name.rfind(".bin")!=name.length()-5)
653            name += ".bin";
654
655        ofstream fout(name);
656        if (!fout)
657            return false;
658
659        fout.write(reinterpret_cast<const char*>(&fStaticData), sizeof(FTM::StaticData));
660
661        return !fout.bad();
662    }
663
664    bool SetThreshold(int32_t patch, int32_t value)
665    {
666        if (patch>159)
667            return false;
668
669        if (value<0 || value>0xffff)
670            return false;
671
672        if (patch<0)
673        {
674            bool ident = true;
675            for (int i=0; i<160; i++)
676                if (fStaticData[i/4].fDAC[patch%4] != value)
677                {
678                    ident = false;
679                    break;
680                }
681
682            if (ident)
683                return true;
684
685            for (int i=0; i<160; i++)
686                fStaticData[i/4].fDAC[i%4] = value;
687        }
688        else
689        {
690            if (fStaticData[patch/4].fDAC[patch%4] == value)
691                return true;
692
693            fStaticData[patch/4].fDAC[patch%4] = value;
694        }
695
696        // Maybe move to a "COMMIT" command?
697        CmdSendStatDat();
698
699        return true;
700    }
701
702    bool SetPrescaling(uint32_t value)
703    {
704        if (value>0xffff)
705            return false;
706
707        bool ident = true;
708        for (int i=0; i<40; i++)
709            if (fStaticData[i].fPrescaling != value)
710            {
711                ident = false;
712                break;
713            }
714
715        if (ident)
716            return true;
717
718        for (int i=0; i<40; i++)
719            fStaticData[i].fPrescaling = value;
720
721        // Maybe move to a "COMMIT" command?
722        CmdSendStatDat();
723
724        return true;
725    }
726
727    bool EnableFTU(int32_t board, bool enable)
728    {
729        if (board>39)
730            return false;
731
732        if (board<0)
733        {
734            if (enable)
735                fStaticData.EnableAllFTU();
736            else
737                fStaticData.DisableAllFTU();
738        }
739        else
740        {
741            if (enable)
742                fStaticData.EnableFTU(board);
743            else
744                fStaticData.DisableFTU(board);
745
746        }
747
748        // Maybe move to a "COMMIT" command?
749        CmdSendStatDat();
750
751        return true;
752    }
753
754    bool ToggleFTU(uint32_t board)
755    {
756        if (board>39)
757            return false;
758
759        fStaticData.ToggleFTU(board);
760
761        // Maybe move to a "COMMIT" command?
762        CmdSendStatDat();
763
764        return true;
765    }
766
767    bool SetVal(uint16_t *dest, uint32_t val, uint32_t max)
768    {
769        if (val>max)
770            return false;
771
772        if (*dest==val)
773            return true;
774
775        *dest = val;
776
777        CmdSendStatDat();
778
779        return true;
780    }
781
782    bool SetTriggerInterval(uint32_t val)
783    {
784        return SetVal(&fStaticData.fTriggerInterval, val,
785                      FTM::StaticData::kMaxTriggerInterval);
786    }
787
788    bool SetTriggerDelay(uint32_t val)
789    {
790        return SetVal(&fStaticData.fDelayTrigger, val,
791                      FTM::StaticData::kMaxDelayTrigger);
792    }
793
794    bool SetTimeMarkerDelay(uint32_t val)
795    {
796        return SetVal(&fStaticData.fDelayTimeMarker, val,
797                      FTM::StaticData::kMaxDelayTimeMarker);
798    }
799
800    bool SetDeadTime(uint32_t val)
801    {
802        return SetVal(&fStaticData.fDeadTime, val,
803                      FTM::StaticData::kMaxDeadTime);
804    }
805
806    void Enable(FTM::StaticData::GeneralSettings type, bool enable)
807    {
808        if (fStaticData.IsEnabled(type)!=enable)
809        {
810            fStaticData.Enable(type, enable);
811            CmdSendStatDat();
812        }
813    }
814
815    bool SetTriggerSeq(const uint16_t d[3])
816    {
817        const uint16_t oldset = fStaticData.fGeneralSettings;
818        const uint16_t oldseq = fStaticData.fTriggerSequence;
819
820        if (d[0]>FTM::StaticData::kMaxSequence ||
821            d[1]>FTM::StaticData::kMaxSequence ||
822            d[2]>FTM::StaticData::kMaxSequence)
823            return false;
824
825        fStaticData.Enable(FTM::StaticData::kPedestal, d[0]>0);
826        fStaticData.Enable(FTM::StaticData::kLPext,    d[1]>0);
827        fStaticData.Enable(FTM::StaticData::kLPint,    d[2]>0);
828
829        fStaticData.fTriggerSequence =
830            (uint16_t(d[0])<<10) | (uint16_t(d[2])<<5) | uint16_t(d[1]);
831
832        if (oldseq!=fStaticData.fTriggerSequence || oldset!=fStaticData.fGeneralSettings)
833            CmdSendStatDat();
834
835        return true;
836    }
837
838    bool SetTriggerMultiplicity(uint16_t n)
839    {
840        if (n==0 || n>FTM::StaticData::kMaxMultiplicity)
841            return false;
842
843        if (n==fStaticData.fMultiplicityPhysics)
844            return true;
845
846        fStaticData.fMultiplicityPhysics = n;
847
848        CmdSendStatDat();
849
850        return true;
851    }
852
853    bool SetTriggerWindow(uint16_t win)
854    {
855        if (win>FTM::StaticData::kMaxWindow)
856            return false;
857
858        if (win==fStaticData.fWindowPhysics)
859            return true;
860
861        fStaticData.fWindowPhysics = win;
862
863        CmdSendStatDat();
864
865        return true;
866    }
867
868    bool SetCalibMultiplicity(uint16_t n)
869    {
870        if (n==0 || n>FTM::StaticData::kMaxMultiplicity)
871            return false;
872
873        if (n==fStaticData.fMultiplicityCalib)
874            return true;
875
876        fStaticData.fMultiplicityCalib = n;
877
878        CmdSendStatDat();
879
880        return true;
881    }
882
883    bool SetCalibWindow(uint16_t win)
884    {
885        if (win>FTM::StaticData::kMaxWindow)
886            return false;
887
888        if (win==fStaticData.fWindowCalib)
889            return true;
890
891        fStaticData.fWindowCalib = win;
892
893        CmdSendStatDat();
894
895        return true;
896    }
897
898    bool EnablePixel(uint16_t idx, bool enable)
899    {
900        if (idx>FTM::StaticData::kMaxPixelIdx)
901            return false;
902
903        cout << "ENABLE " << idx << " " << enable << endl;
904        fStaticData.EnablePixel(idx, enable);
905
906        CmdSendStatDat();
907
908        return true;
909    }
910
911    bool TogglePixel(uint16_t idx)
912    {
913        if (idx>FTM::StaticData::kMaxPixelIdx)
914            return false;
915
916        cout << "TOGGLE " << idx << endl;
917
918        fStaticData.EnablePixel(idx, !fStaticData.Enabled(idx));
919
920        CmdSendStatDat();
921
922        return true;
923    }
924
925    int GetState() const { return IsConnected() ? fState : (int)FTM::kDisconnected; }
926};
927
928//const uint16_t ConnectionFTM::kMaxAddr = 0xfff;
929
930// ------------------------------------------------------------------------
931
932#include "DimDescriptionService.h"
933
934class ConnectionDimFTM : public ConnectionFTM
935{
936private:
937
938    DimDescribedService fDimPassport;
939    DimDescribedService fDimTriggerCounter;
940    DimDescribedService fDimError;
941    DimDescribedService fDimFtuList;
942    DimDescribedService fDimStaticData;
943    DimDescribedService fDimDynamicData;
944    DimDescribedService fDimCounter;
945
946    template<class T>
947        void Update(DimDescribedService &svc, const T &data) const
948    {
949        //cout << "Update: " << svc.getName() << " (" << sizeof(T) << ")" << endl;
950        svc.setData(const_cast<T*>(&data), sizeof(T));
951        svc.updateService();
952    }
953
954    void UpdateFirstHeader()
955    {
956        ConnectionFTM::UpdateFirstHeader();
957
958        const FTM::DimPassport data(fHeader);
959        Update(fDimPassport, data);
960    }
961
962    void UpdateHeader()
963    {
964        ConnectionFTM::UpdateHeader();
965
966        if (fHeader.fType!=FTM::kDynamicData)
967            return;
968
969        const FTM::DimTriggerCounter data(fHeader);
970        Update(fDimTriggerCounter, data);
971    }
972
973    void UpdateFtuList()
974    {
975        ConnectionFTM::UpdateFtuList();
976
977        const FTM::DimFtuList data(fHeader, fFtuList);
978        Update(fDimFtuList, data);
979    }
980
981    void UpdateStaticData()
982    {
983        ConnectionFTM::UpdateStaticData();
984
985        const FTM::DimStaticData data(fHeader, fStaticData);
986        Update(fDimStaticData, data);
987    }
988
989    void UpdateDynamicData()
990    {
991        ConnectionFTM::UpdateDynamicData();
992
993        const FTM::DimDynamicData data(fHeader, fDynamicData);
994        Update(fDimDynamicData, data);
995    }
996
997    void UpdateError()
998    {
999        ConnectionFTM::UpdateError();
1000
1001        const FTM::DimError data(fHeader, fError);
1002        Update(fDimError, data);
1003    }
1004
1005    void UpdateCounter()
1006    {
1007        ConnectionFTM::UpdateCounter();
1008
1009        const uint32_t counter[6] =
1010        {
1011            fCounter[FTM::kHeader],
1012            fCounter[FTM::kStaticData],
1013            fCounter[FTM::kDynamicData],
1014            fCounter[FTM::kFtuList],
1015            fCounter[FTM::kErrorList],
1016            fCounter[FTM::kRegister],
1017        };
1018
1019        Update(fDimCounter, counter);
1020    }
1021
1022public:
1023    ConnectionDimFTM(ba::io_service& ioservice, MessageImp &imp) :
1024        ConnectionFTM(ioservice, imp),
1025        fDimPassport      ("FTM_CONTROL/PASSPORT",        "X:1;S:1", ""),
1026        fDimTriggerCounter("FTM_CONTROL/TRIGGER_COUNTER", "X:1;I:1", ""),
1027        fDimError         ("FTM_CONTROL/ERROR",           "X:1;S:1;S:28", ""),
1028        fDimFtuList       ("FTM_CONTROL/FTU_LIST",        "X:1;X:1;S:1;C:4;X:40;C:40;C:40",  ""),
1029        fDimStaticData    ("FTM_CONTROL/STATIC_DATA",     "X:1;S:1;S:1;X:1;S:1;S:3;S:1;S:1;S:1;S:1;S:1;S:1;I:1;S:8;S:90;S:160;S:40;S:40", ""),
1030        fDimDynamicData   ("FTM_CONTROL/DYNAMIC_DATA",    "X:1;X:1;F:4;I:160;I:40;S:40;S:40", ""),
1031        fDimCounter       ("FTM_CONTROL/COUNTER",         "I:6", "")
1032    {
1033    }
1034
1035    // 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
1036};
1037
1038// ------------------------------------------------------------------------
1039
1040template <class T, class S>
1041class StateMachineFTM : public T, public ba::io_service, public ba::io_service::work
1042{
1043    int Wrap(boost::function<void()> f)
1044    {
1045        f();
1046        return T::GetCurrentState();
1047    }
1048
1049    boost::function<int(const EventImp &)> Wrapper(boost::function<void()> func)
1050    {
1051        return boost::bind(&StateMachineFTM::Wrap, this, func);
1052    }
1053
1054private:
1055    S fFTM;
1056
1057    enum states_t
1058    {
1059        kStateDisconnected = FTM::kDisconnected,
1060        kStateConnected    = FTM::kConnected,
1061        kStateIdle         = FTM::kIdle,
1062        kStateTakingData   = FTM::kTakingData,
1063
1064        kCmdTest
1065    };
1066
1067    bool CheckEventSize(size_t has, const char *name, size_t size)
1068    {
1069        if (has==size)
1070            return true;
1071
1072        ostringstream msg;
1073        msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
1074        T::Fatal(msg);
1075        return false;
1076    }
1077
1078    int SetRegister(const EventImp &evt)
1079    {
1080        if (!CheckEventSize(evt.GetSize(), "SetRegister", 8))
1081            return T::kSM_FatalError;
1082
1083        const unsigned int *dat = reinterpret_cast<const unsigned int*>(evt.GetData());
1084
1085        if (dat[1]>uint16_t(-1))
1086        {
1087            ostringstream msg;
1088            msg << hex << "Value " << dat[1] << " out of range.";
1089            T::Error(msg);
1090            return T::GetCurrentState();
1091        }
1092
1093
1094        if (dat[0]>uint16_t(-1) || !fFTM.CmdSetRegister(dat[0], dat[1]))
1095        {
1096            ostringstream msg;
1097            msg << hex << "Address " << dat[0] << " out of range.";
1098            T::Error(msg);
1099        }
1100
1101        return T::GetCurrentState();
1102    }
1103
1104    int GetRegister(const EventImp &evt)
1105    {
1106        if (!CheckEventSize(evt.GetSize(), "GetRegister", 4))
1107            return T::kSM_FatalError;
1108
1109        const unsigned int addr = evt.GetInt();
1110        if (addr>uint16_t(-1) || !fFTM.CmdGetRegister(addr))
1111        {
1112            ostringstream msg;
1113            msg << hex << "Address " << addr << " out of range.";
1114            T::Error(msg);
1115        }
1116
1117        return T::GetCurrentState();
1118    }
1119
1120    int TakeNevents(const EventImp &evt)
1121    {
1122        if (!CheckEventSize(evt.GetSize(), "TakeNevents", 4))
1123            return T::kSM_FatalError;
1124
1125        const unsigned int dat = evt.GetUInt();
1126
1127        /*
1128        if (dat[1]>uint32_t(-1))
1129        {
1130            ostringstream msg;
1131            msg << hex << "Value " << dat[1] << " out of range.";
1132            T::Error(msg);
1133            return T::GetCurrentState();
1134        }*/
1135
1136        fFTM.CmdTakeNevents(dat);
1137
1138        return T::GetCurrentState();
1139    }
1140
1141    int DisableReports(const EventImp &evt)
1142    {
1143        if (!CheckEventSize(evt.GetSize(), "DisableReports", 1))
1144            return T::kSM_FatalError;
1145
1146        fFTM.CmdDisableReports(evt.GetText()[0]!=0);
1147
1148        return T::GetCurrentState();
1149    }
1150
1151    int SetVerbosity(const EventImp &evt)
1152    {
1153        if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
1154            return T::kSM_FatalError;
1155
1156        fFTM.SetVerbose(evt.GetText()[0]!=0);
1157
1158        return T::GetCurrentState();
1159    }
1160
1161    int SetHexOutput(const EventImp &evt)
1162    {
1163        if (!CheckEventSize(evt.GetSize(), "SetHexOutput", 1))
1164            return T::kSM_FatalError;
1165
1166        fFTM.SetHexOutput(evt.GetText()[0]!=0);
1167
1168        return T::GetCurrentState();
1169    }
1170
1171    int SetDynamicOut(const EventImp &evt)
1172    {
1173        if (!CheckEventSize(evt.GetSize(), "SetDynamicOut", 1))
1174            return T::kSM_FatalError;
1175
1176        fFTM.SetDynamicOut(evt.GetText()[0]!=0);
1177
1178        return T::GetCurrentState();
1179    }
1180
1181    int LoadStaticData(const EventImp &evt)
1182    {
1183        if (fFTM.LoadStaticData(evt.GetString()))
1184            return T::GetCurrentState();
1185
1186        ostringstream msg;
1187        msg << "Loading static data from file '" << evt.GetString() << "' failed ";
1188
1189        if (errno)
1190            msg << "(" << strerror(errno) << ")";
1191        else
1192            msg << "(wrong size, expected " << sizeof(FTM::StaticData) << " bytes)";
1193
1194        T::Warn(msg);
1195
1196        return T::GetCurrentState();
1197    }
1198
1199    int SaveStaticData(const EventImp &evt)
1200    {
1201        if (fFTM.SaveStaticData(evt.GetString()))
1202            return T::GetCurrentState();
1203
1204        ostringstream msg;
1205        msg << "Writing static data to file '" << evt.GetString() << "' failed ";
1206        msg << "(" << strerror(errno) << ")";
1207
1208        T::Warn(msg);
1209
1210        return T::GetCurrentState();
1211    }
1212
1213    int SetThreshold(const EventImp &evt)
1214    {
1215        if (!CheckEventSize(evt.GetSize(), "SetThreshold", 8))
1216            return T::kSM_FatalError;
1217
1218        const int32_t *data = reinterpret_cast<const int32_t*>(evt.GetData());
1219
1220        if (!fFTM.SetThreshold(data[0], data[1]))
1221            T::Warn("SetThreshold - Maximum allowed patch number 159, valid value range 0-0xffff");
1222
1223        return T::GetCurrentState();
1224    }
1225
1226    int EnableFTU(const EventImp &evt)
1227    {
1228        if (!CheckEventSize(evt.GetSize(), "EnableFTU", 5))
1229            return T::kSM_FatalError;
1230
1231        const int32_t &board  = *reinterpret_cast<const int32_t*>(evt.GetText());
1232        const int8_t  &enable = *reinterpret_cast<const int8_t*>(evt.GetText()+4);
1233
1234        if (!fFTM.EnableFTU(board, enable))
1235            T::Warn("EnableFTU - Board number must be <40.");
1236
1237        return T::GetCurrentState();
1238    }
1239
1240    int ToggleFTU(const EventImp &evt)
1241    {
1242        if (!CheckEventSize(evt.GetSize(), "ToggleFTU", 4))
1243            return T::kSM_FatalError;
1244
1245        if (!fFTM.ToggleFTU(evt.GetInt()))
1246            T::Warn("ToggleFTU - Allowed range of boards 0-39.");
1247
1248        return T::GetCurrentState();
1249    }
1250
1251    int SetTriggerInterval(const EventImp &evt)
1252    {
1253        if (!CheckEventSize(evt.GetSize(), "SetTriggerInterval", 4))
1254            return T::kSM_FatalError;
1255
1256        if (!fFTM.SetTriggerInterval(evt.GetInt()))
1257            T::Warn("SetTriggerInterval - Value out of range.");
1258
1259        return T::GetCurrentState();
1260    }
1261
1262    int SetTriggerDelay(const EventImp &evt)
1263    {
1264        if (!CheckEventSize(evt.GetSize(), "SetTriggerDelay", 4))
1265            return T::kSM_FatalError;
1266
1267        if (!fFTM.SetTriggerDelay(evt.GetInt()))
1268            T::Warn("SetTriggerDealy - Value out of range.");
1269
1270        return T::GetCurrentState();
1271    }
1272
1273    int SetTimeMarkerDelay(const EventImp &evt)
1274    {
1275        if (!CheckEventSize(evt.GetSize(), "SetTimeMarkerDelay", 4))
1276            return T::kSM_FatalError;
1277
1278        if (!fFTM.SetTimeMarkerDelay(evt.GetInt()))
1279            T::Warn("SetTimeMarkerDelay - Value out of range.");
1280
1281        return T::GetCurrentState();
1282    }
1283
1284    int SetPrescaling(const EventImp &evt)
1285    {
1286        if (!CheckEventSize(evt.GetSize(), "SetPrescaling", 4))
1287            return T::kSM_FatalError;
1288
1289        if (!fFTM.SetPrescaling(evt.GetInt()-1))
1290            T::Warn("SetPrescaling - Value out of range.");
1291
1292        return T::GetCurrentState();
1293    }
1294
1295    int SetTriggerSeq(const EventImp &evt)
1296    {
1297        if (!CheckEventSize(evt.GetSize(), "SetTriggerSeq", 6))
1298            return T::kSM_FatalError;
1299
1300        const uint16_t *data = reinterpret_cast<const uint16_t*>(evt.GetData());
1301
1302        if (!fFTM.SetTriggerSeq(data))
1303            T::Warn("SetTriggerSeq - Value out of range.");
1304
1305        return T::GetCurrentState();
1306    }
1307
1308    int SetDeadTime(const EventImp &evt)
1309    {
1310        if (!CheckEventSize(evt.GetSize(), "SetDeadTime", 4))
1311            return T::kSM_FatalError;
1312
1313        if (!fFTM.SetDeadTime(evt.GetInt()))
1314            T::Warn("SetDeadTime - Value out of range.");
1315
1316        return T::GetCurrentState();
1317    }
1318
1319    int SetTriggerMultiplicity(const EventImp &evt)
1320    {
1321        if (!CheckEventSize(evt.GetSize(), "SetTriggerMultiplicity", 2))
1322            return T::kSM_FatalError;
1323
1324        if (!fFTM.SetTriggerMultiplicity(evt.GetUShort()))
1325            T::Warn("SetTriggerMultiplicity -  Value out of range.");
1326
1327        return T::GetCurrentState();
1328    }
1329
1330    int SetCalibMultiplicity(const EventImp &evt)
1331    {
1332        if (!CheckEventSize(evt.GetSize(), "SetCalibMultiplicity", 2))
1333            return T::kSM_FatalError;
1334
1335        if (!fFTM.SetCalibMultiplicity(evt.GetUShort()))
1336            T::Warn("SetCalibMultiplicity -  Value out of range.");
1337
1338        return T::GetCurrentState();
1339    }
1340
1341    int SetTriggerWindow(const EventImp &evt)
1342    {
1343        if (!CheckEventSize(evt.GetSize(), "SetTriggerWindow", 2))
1344            return T::kSM_FatalError;
1345
1346        if (!fFTM.SetTriggerWindow(evt.GetUShort()))
1347            T::Warn("SetTriggerWindow -  Value out of range.");
1348
1349        return T::GetCurrentState();
1350    }
1351
1352    int SetCalibWindow(const EventImp &evt)
1353    {
1354        if (!CheckEventSize(evt.GetSize(), "SetCalibWindow", 2))
1355            return T::kSM_FatalError;
1356
1357        if (!fFTM.SetCalibWindow(evt.GetUShort()))
1358            T::Warn("SetCalibWindow -  Value out of range.");
1359
1360        return T::GetCurrentState();
1361    }
1362
1363
1364    int Enable(const EventImp &evt, FTM::StaticData::GeneralSettings type)
1365    {
1366        if (!CheckEventSize(evt.GetSize(), "Enable", 1))
1367            return T::kSM_FatalError;
1368
1369        fFTM.Enable(type, evt.GetText()[0]!=0);
1370
1371        return T::GetCurrentState();
1372    }
1373
1374    int EnablePixel(const EventImp &evt, bool b)
1375    {
1376        if (!CheckEventSize(evt.GetSize(), "EnablePixel", 2))
1377            return T::kSM_FatalError;
1378
1379        fFTM.EnablePixel(evt.GetUShort(), b);
1380
1381        return T::GetCurrentState();
1382    }
1383
1384    int TogglePixel(const EventImp &evt)
1385    {
1386        if (!CheckEventSize(evt.GetSize(), "TogglePixel", 2))
1387            return T::kSM_FatalError;
1388
1389        fFTM.TogglePixel(evt.GetUShort());
1390
1391        return T::GetCurrentState();
1392    }
1393
1394    int ResetCrate(const EventImp &evt)
1395    {
1396        if (!CheckEventSize(evt.GetSize(), "ResetCrate", 2))
1397            return T::kSM_FatalError;
1398
1399        fFTM.CmdResetCrate(evt.GetUShort());
1400
1401        return T::GetCurrentState();
1402    }
1403
1404    int Disconnect()
1405    {
1406        // Close all connections
1407        fFTM.PostClose(false);
1408
1409        /*
1410         // Now wait until all connection have been closed and
1411         // all pending handlers have been processed
1412         poll();
1413         */
1414
1415        return T::GetCurrentState();
1416    }
1417
1418    int Reconnect(const EventImp &evt)
1419    {
1420        // Close all connections to supress the warning in SetEndpoint
1421        fFTM.PostClose(false);
1422
1423        // Now wait until all connection have been closed and
1424        // all pending handlers have been processed
1425        poll();
1426
1427        if (evt.GetText()[0]!=0)
1428            fFTM.SetEndpoint(evt.GetString());
1429
1430        // Now we can reopen the connection
1431        fFTM.PostClose(true);
1432
1433        return T::GetCurrentState();
1434    }
1435
1436    /*
1437    int Transition(const Event &evt)
1438    {
1439        switch (evt.GetTargetState())
1440        {
1441        case kStateDisconnected:
1442        case kStateConnected:
1443        }
1444
1445        return T::kSM_FatalError;
1446    }*/
1447
1448    int Execute()
1449    {
1450        // Dispatch (execute) at most one handler from the queue. In contrary
1451        // to run_one(), it doesn't wait until a handler is available
1452        // which can be dispatched, so poll_one() might return with 0
1453        // handlers dispatched. The handlers are always dispatched/executed
1454        // synchronously, i.e. within the call to poll_one()
1455        poll_one();
1456
1457        return fFTM.GetState();
1458    }
1459
1460public:
1461    StateMachineFTM(ostream &out=cout) :
1462        T(out, "FTM_CONTROL"), ba::io_service::work(static_cast<ba::io_service&>(*this)),
1463        fFTM(*this, *this)
1464    {
1465        // ba::io_service::work is a kind of keep_alive for the loop.
1466        // It prevents the io_service to go to stopped state, which
1467        // would prevent any consecutive calls to run()
1468        // or poll() to do nothing. reset() could also revoke to the
1469        // previous state but this might introduce some overhead of
1470        // deletion and creation of threads and more.
1471
1472        // State names
1473        AddStateName(kStateDisconnected, "Disconnected",
1474                     "FTM board not connected via ethernet.");
1475
1476        AddStateName(kStateConnected, "Connected",
1477                     "Ethernet connection to FTM established (no state received yet).");
1478
1479        AddStateName(kStateIdle, "Idle",
1480                     "Ethernet connection to FTM established, FTM in idle state.");
1481
1482        AddStateName(kStateTakingData, "TakingData",
1483                     "Ethernet connection to FTM established, FTM is in taking data state.");
1484
1485        // FTM Commands
1486        AddEvent("TOGGLE_LED", kStateIdle)
1487            (Wrapper(boost::bind(&ConnectionFTM::CmdToggleLed, &fFTM)))
1488            ("toggle led");
1489
1490        AddEvent("PING", kStateIdle)
1491            (Wrapper(boost::bind(&ConnectionFTM::CmdPing, &fFTM)))
1492            ("send ping");
1493
1494        AddEvent("REQUEST_DYNAMIC_DATA", kStateIdle)
1495            (Wrapper(boost::bind(&ConnectionFTM::CmdReqDynDat, &fFTM)))
1496            ("request transmission of dynamic data block");
1497
1498        AddEvent("REQUEST_STATIC_DATA", kStateIdle)
1499            (Wrapper(boost::bind(&ConnectionFTM::CmdReqStatDat, &fFTM)))
1500            ("request transmission of static data from FTM to memory");
1501
1502        AddEvent("GET_REGISTER", "I", kStateIdle)
1503            (boost::bind(&StateMachineFTM::GetRegister, this, _1))
1504            ("read register from address addr"
1505            "|addr[short]:Address of register");
1506
1507        AddEvent("SET_REGISTER", "I:2", kStateIdle)
1508            (boost::bind(&StateMachineFTM::SetRegister, this, _1))
1509            ("set register to value"
1510            "|addr[short]:Address of register"
1511            "|val[short]:Value to be set");
1512
1513        AddEvent("START_RUN", kStateIdle)
1514            (Wrapper(boost::bind(&ConnectionFTM::CmdStartRun, &fFTM)))
1515            ("start a run (start distributing triggers)");
1516
1517        AddEvent("STOP_RUN", kStateTakingData)
1518            (Wrapper(boost::bind(&ConnectionFTM::CmdStopRun, &fFTM)))
1519            ("stop a run (stop distributing triggers)");
1520
1521        AddEvent("TAKE_N_EVENTS", "I", kStateIdle)
1522            (boost::bind(&StateMachineFTM::TakeNevents, this, _1))
1523            ("take n events (distribute n triggers)|number[int]:Number of events to be taken");
1524
1525        AddEvent("DISABLE_REPORTS", "B", kStateIdle)
1526            (boost::bind(&StateMachineFTM::DisableReports, this, _1))
1527            ("disable sending rate reports"
1528             "|status[bool]:disable or enable that the FTM sends rate reports (yes/no)");
1529
1530        AddEvent("SET_THRESHOLD", "I:2", kStateIdle)
1531            (boost::bind(&StateMachineFTM::SetThreshold, this, _1))
1532            ("Set the comparator threshold"
1533             "|Patch[idx]:Index of the patch (0-159), -1 for all"
1534             "|Threshold[counts]:Threshold to be set in binary counts");
1535
1536        AddEvent("SET_PRESCALING", "I:1", kStateIdle)
1537            (boost::bind(&StateMachineFTM::SetPrescaling, this, _1))
1538            (""
1539             "|[]:");
1540
1541        AddEvent("ENABLE_FTU", "I:1;B:1", kStateIdle)
1542            (boost::bind(&StateMachineFTM::EnableFTU, this, _1))
1543            ("Enable or disable FTU"
1544             "|Board[idx]:Index of the board (0-39), -1 for all"
1545             "|Enable[bool]:Whether FTU should be enabled or disabled (yes/no)");
1546
1547        AddEvent("DISABLE_PIXEL", "S:1", kStateIdle)
1548            (boost::bind(&StateMachineFTM::EnablePixel, this, _1, false))
1549            ("");
1550
1551        AddEvent("ENABLE_PIXEL", "S:1", kStateIdle)
1552            (boost::bind(&StateMachineFTM::EnablePixel, this, _1, true))
1553            ("");
1554
1555        AddEvent("TOGGLE_PIXEL", "S:1", kStateIdle)
1556            (boost::bind(&StateMachineFTM::TogglePixel, this, _1))
1557            ("");
1558
1559        AddEvent("TOGGLE_FTU", "I:1", kStateIdle)
1560            (boost::bind(&StateMachineFTM::ToggleFTU, this, _1))
1561            ("Toggle status of FTU (this is mainly meant to be used in the GUI)"
1562             "|Board[idx]:Index of the board (0-39)");
1563
1564        AddEvent("SET_TRIGGER_INTERVAL", "I:1", kStateIdle)
1565            (boost::bind(&StateMachineFTM::SetTriggerInterval, this, _1))
1566            ("Sets the trigger interval which is the distance between two consecutive artificial triggers."
1567             "|interval[int]:The applied trigger interval is: interval*4ns+8ns");
1568
1569        AddEvent("SET_TRIGGER_DELAY", "I:1", kStateIdle)
1570            (boost::bind(&StateMachineFTM::SetTriggerDelay, this, _1))
1571            (""
1572             "|delay[int]:The applied trigger delay is: delay*4ns+8ns");
1573
1574        AddEvent("SET_TIME_MARKER_DELAY", "I:1", kStateIdle)
1575            (boost::bind(&StateMachineFTM::SetTimeMarkerDelay, this, _1))
1576            (""
1577            "|delay[int]:The applied time marker delay is: delay*4ns+8ns");
1578
1579        AddEvent("SET_DEAD_TIME", "I:1", kStateIdle)
1580            (boost::bind(&StateMachineFTM::SetDeadTime, this, _1))
1581            (""
1582            "|dead_time[int]:The applied dead time is: dead_time*4ns+8ns");
1583
1584        AddEvent("ENABLE_TRIGGER", "B:1", kStateIdle)
1585            (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kTrigger))
1586            ("Switch on the physics trigger"
1587             "|Enable[bool]:Enable physics trigger (yes/no)");
1588
1589        // FIXME: Switch on/off depending on sequence
1590        AddEvent("ENABLE_EXT1", "B:1", kStateIdle)
1591            (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kExt1))
1592            ("Switch on the triggers through the first external line"
1593             "|Enable[bool]:Enable ext1 trigger (yes/no)");
1594
1595        // FIXME: Switch on/off depending on sequence
1596        AddEvent("ENABLE_EXT2", "B:1", kStateIdle)
1597            (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kExt2))
1598            ("Switch on the triggers through the second external line"
1599             "|Enable[bool]:Enable ext2 trigger (yes/no)");
1600
1601        AddEvent("ENABLE_VETO", "B:1", kStateIdle)
1602            (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kVeto))
1603            ("Enable veto line"
1604             "|Enable[bool]:Enable veto (yes/no)");
1605
1606        AddEvent("ENABLE_CLOCK_CONDITIONER", "B:1", kStateIdle)
1607            (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kClockConditioner))
1608            ("Enable clock conidtioner output in favor of time marker output"
1609             "|Enable[bool]:Enable clock conditioner (yes/no)");
1610
1611        AddEvent("SET_TRIGGER_SEQUENCE", "S:3", kStateIdle)
1612            (boost::bind(&StateMachineFTM::SetTriggerSeq, this, _1))
1613            ("Setup the sequence of artificial triggers produced by the FTM"
1614             "|Ped[short]:number of pedestal triggers in a row"
1615             "|LPext[short]:number of triggers of the external light pulser"
1616             "|LPint[short]:number of triggers of the internal light pulser");
1617
1618        AddEvent("SET_TRIGGER_MULTIPLICITY", "S:1", kStateIdle)
1619            (boost::bind(&StateMachineFTM::SetTriggerMultiplicity, this, _1))
1620            ("Setup the Multiplicity condition for physcis triggers"
1621             "|N[int]:Number of requirered coincident triggers from sum-patches (1-40)");
1622
1623        AddEvent("SET_TRIGGER_WINDOW", "S:1", kStateIdle)
1624            (boost::bind(&StateMachineFTM::SetTriggerWindow, this, _1))
1625            ("");
1626
1627        AddEvent("SET_CALIBRATION_MULTIPLICITY", "S:1", kStateIdle)
1628            (boost::bind(&StateMachineFTM::SetCalibMultiplicity, this, _1))
1629            ("Setup the Multiplicity condition for artificial (calibration) triggers"
1630             "|N[int]:Number of requirered coincident triggers from sum-patches (1-40)");
1631
1632        AddEvent("SET_CALIBRATION_WINDOW", "S:1", kStateIdle)
1633            (boost::bind(&StateMachineFTM::SetCalibWindow, this, _1))
1634            ("");
1635
1636        AddEvent("RESET_CRATE", "S:1", kStateIdle)
1637            (boost::bind(&StateMachineFTM::ResetCrate, this, _1))
1638            ("Reset one of the crates 0-3"
1639             "|crate[short]:Crate number to be reseted (0-3)");
1640
1641        AddEvent("RESET_CAMERA", kStateIdle)
1642            (Wrapper(boost::bind(&ConnectionFTM::CmdResetCamera, &fFTM)))
1643            ("Reset all crates. The commands are sent in the order 0,1,2,3");
1644
1645
1646        // Load/save static data block
1647        T::AddEvent("SAVE", "C", kStateIdle)
1648            (boost::bind(&StateMachineFTM::SaveStaticData, this, _1))
1649            ("Saves the static data (FTM configuration) from memory to a file"
1650             "|filename[string]:Filename (can include a path), .bin is automatically added");
1651
1652        T::AddEvent("LOAD", "C", kStateIdle)
1653            (boost::bind(&StateMachineFTM::LoadStaticData, this, _1))
1654            ("Loads the static data (FTM configuration) from a file into memory and sends it to the FTM"
1655             "|filename[string]:Filename (can include a path), .bin is automatically added");
1656
1657
1658
1659        // Verbosity commands
1660        T::AddEvent("SET_VERBOSE", "B")
1661            (boost::bind(&StateMachineFTM::SetVerbosity, this, _1))
1662            ("set verbosity state"
1663             "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
1664
1665        T::AddEvent("SET_HEX_OUTPUT", "B")
1666            (boost::bind(&StateMachineFTM::SetHexOutput, this, _1))
1667            ("enable or disable hex output for received data"
1668             "|hexout[bool]:disable or enable hex output for received data (yes/no)");
1669
1670        T::AddEvent("SET_DYNAMIC_OUTPUT", "B")
1671            (boost::bind(&StateMachineFTM::SetDynamicOut, this, _1))
1672            ("enable or disable output for received dynamic data (data is still broadcasted via Dim)"
1673             "|dynout[bool]:disable or enable output for dynamic data (yes/no)");
1674
1675
1676        // Conenction commands
1677        AddEvent("DISCONNECT", kStateConnected, kStateIdle)
1678            (boost::bind(&StateMachineFTM::Disconnect, this))
1679            ("disconnect from ethernet");
1680
1681        AddEvent("RECONNECT", "O", kStateDisconnected, kStateConnected, kStateIdle)
1682            (boost::bind(&StateMachineFTM::Reconnect, this, _1))
1683            ("(Re)connect ethernet connection to FTM, a new address can be given"
1684             "|[host][string]:new ethernet address in the form <host:port>");
1685
1686        fFTM.StartConnect();
1687    }
1688
1689    void SetEndpoint(const string &url)
1690    {
1691        fFTM.SetEndpoint(url);
1692    }
1693
1694    bool SetConfiguration(const Configuration &conf)
1695    {
1696        SetEndpoint(conf.Get<string>("addr"));
1697
1698        fFTM.SetVerbose(!conf.Get<bool>("quiet"));
1699        fFTM.SetHexOutput(conf.Get<bool>("hex-out"));
1700        fFTM.SetDynamicOut(conf.Get<bool>("dynamic-out"));
1701
1702//        fFTM.SetDefaultSetup(conf.Get<string>("default-setup"));
1703
1704        return true;
1705    }
1706};
1707
1708// ------------------------------------------------------------------------
1709
1710void RunThread(StateMachineImp *io_service)
1711{
1712    // This is necessary so that the StateMachien Thread can signal the
1713    // Readline to exit
1714    io_service->Run();
1715    Readline::Stop();
1716}
1717
1718template<class S, class T>
1719int RunDim(Configuration &conf)
1720{
1721    WindowLog wout;
1722
1723    /*
1724    static Test shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
1725
1726    WindowLog &win  = shell.GetStreamIn();
1727    WindowLog &wout = shell.GetStreamOut();
1728    */
1729
1730    if (conf.Has("log"))
1731        if (!wout.OpenLogFile(conf.Get<string>("log")))
1732            wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
1733
1734    // Start io_service.Run to use the StateMachineImp::Run() loop
1735    // Start io_service.run to only use the commandHandler command detaching
1736    StateMachineFTM<S, T> io_service(wout);
1737    if (!io_service.SetConfiguration(conf))
1738        return -1;
1739
1740    io_service.Run();
1741
1742    /*
1743    shell.SetReceiver(io_service);
1744
1745    boost::thread t(boost::bind(RunThread, &io_service));
1746    // boost::thread t(boost::bind(&StateMachineFTM<S>::Run, &io_service));
1747
1748    shell.Run();                 // Run the shell
1749    io_service.Stop();           // Signal Loop-thread to stop
1750    // io_service.Close();       // Obsolete, done by the destructor
1751
1752    // Wait until the StateMachine has finished its thread
1753    // before returning and destroying the dim objects which might
1754    // still be in use.
1755    t.join();
1756    */
1757
1758    return 0;
1759}
1760
1761template<class T, class S, class R>
1762int RunShell(Configuration &conf)
1763{
1764    static T shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
1765
1766    WindowLog &win  = shell.GetStreamIn();
1767    WindowLog &wout = shell.GetStreamOut();
1768
1769    if (conf.Has("log"))
1770        if (!wout.OpenLogFile(conf.Get<string>("log")))
1771            win << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
1772
1773    StateMachineFTM<S, R> io_service(wout);
1774    if (!io_service.SetConfiguration(conf))
1775        return -1;
1776
1777    shell.SetReceiver(io_service);
1778
1779    boost::thread t(boost::bind(RunThread, &io_service));
1780    // boost::thread t(boost::bind(&StateMachineFTM<S>::Run, &io_service));
1781
1782    shell.Run();                 // Run the shell
1783    io_service.Stop();           // Signal Loop-thread to stop
1784    // io_service.Close();       // Obsolete, done by the destructor
1785
1786    // Wait until the StateMachine has finished its thread
1787    // before returning and destroying the dim objects which might
1788    // still be in use.
1789    t.join();
1790
1791    return 0;
1792}
1793
1794void SetupConfiguration(Configuration &conf)
1795{
1796    const string n = conf.GetName()+".log";
1797
1798    po::options_description config("Program options");
1799    config.add_options()
1800        ("dns",       var<string>("localhost"), "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
1801        ("log,l",     var<string>(n), "Write log-file")
1802        ("no-dim,d",  po_bool(),      "Disable dim services")
1803        ("console,c", var<int>(),     "Use console (0=shell, 1=simple buffered, X=simple unbuffered)")
1804        ;
1805
1806    po::options_description control("FTM control options");
1807    control.add_options()
1808        ("addr,a",        var<string>("localhost:5000"),  "Network address of FTM")
1809        ("quiet,q",       po_bool(),  "Disable printing contents of all received messages (except dynamic data) in clear text.")
1810        ("hex-out",       po_bool(),  "Enable printing contents of all printed messages also as hex data.")
1811        ("dynamic-out",   po_bool(),  "Enable printing received dynamic data.")
1812//        ("default-setup", var<string>(), "Binary file with static data loaded whenever a connection to the FTM was established.")
1813        ;
1814
1815    conf.AddEnv("dns", "DIM_DNS_NODE");
1816
1817    conf.AddOptions(config);
1818    conf.AddOptions(control);
1819}
1820
1821/*
1822 Extract usage clause(s) [if any] for SYNOPSIS.
1823 Translators: "Usage" and "or" here are patterns (regular expressions) which
1824 are used to match the usage synopsis in program output.  An example from cp
1825 (GNU coreutils) which contains both strings:
1826  Usage: cp [OPTION]... [-T] SOURCE DEST
1827    or:  cp [OPTION]... SOURCE... DIRECTORY
1828    or:  cp [OPTION]... -t DIRECTORY SOURCE...
1829 */
1830void PrintUsage()
1831{
1832    cout <<
1833        "The ftmctrl controls the FTM (FACT Trigger Master) board.\n"
1834        "\n"
1835        "The default is that the program is started without user intercation. "
1836        "All actions are supposed to arrive as DimCommands. Using the -c "
1837        "option, a local shell can be initialized. With h or help a short "
1838        "help message about the usuage can be brought to the screen.\n"
1839        "\n"
1840        "Usage: ftmctrl [-c type] [OPTIONS]\n"
1841        "  or:  ftmctrl [OPTIONS]\n";
1842    cout << endl;
1843}
1844
1845void PrintHelp()
1846{
1847    /* Additional help text which is printed after the configuration
1848     options goes here */
1849
1850    /*
1851     cout << "bla bla bla" << endl << endl;
1852     cout << endl;
1853     cout << "Environment:" << endl;
1854     cout << "environment" << endl;
1855     cout << endl;
1856     cout << "Examples:" << endl;
1857     cout << "test exam" << endl;
1858     cout << endl;
1859     cout << "Files:" << endl;
1860     cout << "files" << endl;
1861     cout << endl;
1862     */
1863}
1864
1865int main(int argc, const char* argv[])
1866{
1867    Configuration conf(argv[0]);
1868    conf.SetPrintUsage(PrintUsage);
1869    SetupConfiguration(conf);
1870
1871    po::variables_map vm;
1872    try
1873    {
1874        vm = conf.Parse(argc, argv);
1875    }
1876#if BOOST_VERSION > 104000
1877    catch (po::multiple_occurrences &e)
1878    {
1879        cerr << "Program options invalid due to: " << e.what() << " of '" << e.get_option_name() << "'." << endl;
1880        return -1;
1881    }
1882#endif
1883    catch (exception& e)
1884    {
1885        cerr << "Program options invalid due to: " << e.what() << endl;
1886        return -1;
1887    }
1888
1889    if (conf.HasVersion() || conf.HasPrint())
1890        return -1;
1891
1892    if (conf.HasHelp())
1893    {
1894        PrintHelp();
1895        return -1;
1896    }
1897
1898    Dim::Setup(conf.Get<string>("dns"));
1899
1900    //try
1901    {
1902        // No console access at all
1903        if (!conf.Has("console"))
1904        {
1905            if (conf.Get<bool>("no-dim"))
1906                return RunDim<StateMachine, ConnectionFTM>(conf);
1907            else
1908                return RunDim<StateMachineDim, ConnectionDimFTM>(conf);
1909        }
1910        // Cosole access w/ and w/o Dim
1911        if (conf.Get<bool>("no-dim"))
1912        {
1913            if (conf.Get<int>("console")==0)
1914                return RunShell<LocalShell, StateMachine, ConnectionFTM>(conf);
1915            else
1916                return RunShell<LocalConsole, StateMachine, ConnectionFTM>(conf);
1917        }
1918        else
1919        {
1920            if (conf.Get<int>("console")==0)
1921                return RunShell<LocalShell, StateMachineDim, ConnectionDimFTM>(conf);
1922            else
1923                return RunShell<LocalConsole, StateMachineDim, ConnectionDimFTM>(conf);
1924        }
1925    }
1926    /*catch (std::exception& e)
1927    {
1928        cerr << "Exception: " << e.what() << endl;
1929        return -1;
1930    }*/
1931
1932    return 0;
1933}
Note: See TracBrowser for help on using the repository browser.