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

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