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

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