source: trunk/FACT++/src/fadctrl.cc @ 10811

Last change on this file since 10811 was 10811, checked in by tbretz, 8 years ago
Removed fake connections. We hav ethe event builder now.
File size: 46.8 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/foreach.hpp>
10#include <boost/asio/error.hpp>
11#include <boost/asio/deadline_timer.hpp>
12
13#include "Dim.h"
14#include "Event.h"
15#include "Shell.h"
16#include "StateMachineDim.h"
17#include "Connection.h"
18#include "Configuration.h"
19#include "Timers.h"
20#include "Console.h"
21#include "Converter.h"
22#include "LocalControl.h"
23#include "HeadersFAD.h"
24
25#include "tools.h"
26
27namespace ba = boost::asio;
28namespace bs = boost::system;
29
30using ba::ip::tcp;
31
32using namespace std;
33
34// ------------------------------------------------------------------------
35
36class ConnectionFAD : public Connection
37{
38    vector<uint16_t> fBuffer;
39
40protected:
41    FAD::EventHeader   fEventHeader;
42    FAD::ChannelHeader fChannelHeader[FAD::kNumChannels];
43
44private:
45    bool fIsVerbose;
46    bool fIsHexOutput;
47    bool fIsDataOutput;
48
49    uint64_t fCounter;
50
51protected:
52    virtual void UpdateFirstHeader()
53    {
54    }
55
56    virtual void UpdateEventHeader()
57    {
58        // emit service with trigger counter from header
59        if (!fIsVerbose)
60            return;
61
62        Out() << endl << kBold << "Header received (N=" << dec << fCounter << "):" << endl;
63        Out() << fEventHeader;
64        if (fIsHexOutput)
65            Out() << Converter::GetHex<uint16_t>(fEventHeader, 16) << endl;
66    }
67
68    virtual void UpdateChannelHeader(int i)
69    {
70        // emit service with trigger counter from header
71        if (!fIsVerbose)
72            return;
73
74        Out() << fChannelHeader[i];
75        if (fIsHexOutput)
76            Out() << Converter::GetHex<uint16_t>(fChannelHeader, 16) << endl;
77    }
78
79    virtual void UpdateData(const uint16_t *data, size_t sz)
80    {
81        // emit service with trigger counter from header
82        if (fIsVerbose && fIsDataOutput)
83            Out() << Converter::GetHex<uint16_t>(data, sz, 16, true) << endl;
84    }
85
86private:
87    void HandleReceivedData(const bs::error_code& err, size_t bytes_received, int/* type*/)
88    {
89        // Do not schedule a new read if the connection failed.
90        if (bytes_received==0 || err)
91        {
92            if (err==ba::error::eof)
93                Warn("Connection closed by remote host (FAD).");
94
95            // 107: Transport endpoint is not connected (bs::error_code(107, bs::system_category))
96            // 125: Operation canceled
97            if (err && err!=ba::error::eof &&                     // Connection closed by remote host
98                err!=ba::error::basic_errors::not_connected &&    // Connection closed by remote host
99                err!=ba::error::basic_errors::operation_aborted)  // Connection closed by us
100            {
101                ostringstream str;
102                str << "Reading from " << URL() << ": " << err.message() << " (" << err << ")";// << endl;
103                Error(str);
104            }
105            PostClose(err!=ba::error::basic_errors::operation_aborted);
106            return;
107        }
108
109        if (bytes_received == sizeof(FAD::EventHeader))
110        {
111            fEventHeader = fBuffer;
112
113            if (fEventHeader.fStartDelimiter!=FAD::kDelimiterStart)
114            {
115                ostringstream str;
116                str << "Invalid header received: start delimiter wrong, received ";
117                str << hex << fEventHeader.fStartDelimiter << ", expected " << FAD::kDelimiterStart << ".";
118                Error(str);
119                PostClose(false);
120                return;
121            }
122
123            if (fCounter==0)
124                UpdateFirstHeader();
125
126            UpdateEventHeader();
127
128            fCounter++;
129
130            fBuffer.resize(fEventHeader.fPackageLength-sizeof(FAD::EventHeader)/2);
131            AsyncRead(ba::buffer(fBuffer));
132
133            return;
134        }
135
136        if (ntohs(fBuffer.back())!=FAD::kDelimiterEnd)
137        {
138            ostringstream str;
139            str << "Invalid data received: end delimiter wrong, received ";
140            str << hex << ntohs(fBuffer.back()) << ", expected " << FAD::kDelimiterEnd << ".";
141            Error(str);
142            PostClose(false);
143            return;
144        }
145
146        /*
147        uint8_t *ptr = reinterpret_cast<uint8_t*>(fBuffer.data());
148        for (unsigned int i=0; i<FAD::kNumChannels; i++)
149        {
150            if (ptr+sizeof(FAD::ChannelHeader)/2 > reinterpret_cast<uint8_t*>(fBuffer.data())+fBuffer.size()*2)
151            {
152                Error("WRONG SIZE1");
153                break;
154            }
155
156            // FIXME: Size consistency check!!!!
157            fChannelHeader[i] = vector<uint16_t>((uint16_t*)ptr, (uint16_t*)ptr+sizeof(FAD::ChannelHeader)/2);
158            ptr += sizeof(FAD::ChannelHeader);
159
160            // FIXME CHECK: Event Size vs ROI
161
162            UpdateChannelHeader(i);
163
164            if (ptr+fChannelHeader[i].fRegionOfInterest*2 > reinterpret_cast<uint8_t*>(fBuffer.data())+fBuffer.size()*2)
165            {
166                Error("WRONG SIZE2");
167                break;
168            }
169
170            uint16_t *data = reinterpret_cast<uint16_t*>(ptr);
171            for (uint16_t *d=data; d<data+fChannelHeader[i].fRegionOfInterest; d++)
172            {
173                const bool sign     = *d & 0x2000;
174                const bool overflow = *d & 0x1000;
175
176                if (sign)
177                    *d |= 0xf000;   // no overflow, nagative
178                else
179                    *d &= 0x07ff;   // no overlow,  positive
180
181                // max = [-2047;2048]
182
183                if (overflow)
184                {
185                    if (sign)
186                        *d = 0xF800;   // overflow, negative
187                    else
188                        *d = 0x0800;   // overflow, positive
189                }
190            }
191
192            UpdateData(data, fChannelHeader[i].fRegionOfInterest*2);
193            ptr += fChannelHeader[i].fRegionOfInterest*2;
194        }*/
195
196        fBuffer.resize(sizeof(FAD::EventHeader)/2);
197        AsyncRead(ba::buffer(fBuffer));
198    }
199
200    // This is called when a connection was established
201    void ConnectionEstablished()
202    {
203        fEventHeader.clear();
204        for (unsigned int i=0; i<FAD::kNumChannels; i++)
205            fChannelHeader[i].clear();
206
207        fCounter = 0;
208
209        fBuffer.resize(sizeof(FAD::EventHeader)/2);
210        AsyncRead(ba::buffer(fBuffer));
211
212//        for (int i=0; i<36; i++)
213//            CmdSetRoi(i, 100);
214
215        Cmd(ConnectionFAD::kCmdTriggerLine, true);
216        Cmd(ConnectionFAD::kCmdSingleTrigger);
217    }
218
219    void HandleReadTimeout(const bs::error_code &error)
220    {
221        /*
222        return;
223        Warn("Reading header timed-out... restarting.");
224        StartReadHeader();
225        return;
226         */
227        if (error && error!=ba::error::basic_errors::operation_aborted)
228        {
229            ostringstream str;
230            str << "Read timeout of " << URL() << ": " << error.message() << " (" << error << ")";// << endl;
231            Error(str);
232
233            PostClose();
234            return;
235
236        }
237
238        if (!is_open())
239        {
240            // For example: Here we could schedule a new accept if we
241            // would not want to allow two connections at the same time.
242            return;
243        }
244
245        // Check whether the deadline has passed. We compare the deadline
246        // against the current time since a new asynchronous operation
247        // may have moved the deadline before this actor had a chance
248        // to run.
249        if (fInTimeout.expires_at() > ba::deadline_timer::traits_type::now())
250            return;
251
252        Error("Timeout reading data from "+URL());
253
254        PostClose();
255    }
256
257    void PostCmd(std::vector<uint16_t> cmd)
258    {
259        ostringstream msg;
260        msg << "Sending command:" << hex;
261        msg << " 0x" << setw(4) << setfill('0') << cmd[0];
262        Message(msg);
263
264        transform(cmd.begin(), cmd.end(), cmd.begin(), htons);
265
266        PostMessage(cmd);
267    }
268
269    void PostCmd(uint16_t cmd)
270    {
271        ostringstream msg;
272        msg << "Sending command:" << hex;
273        msg << " 0x" << setw(4) << setfill('0') << cmd;
274        Message(msg);
275
276        cmd = htons(cmd);
277        PostMessage(&cmd, sizeof(uint16_t));
278    }
279
280    void PostCmd(uint16_t cmd, uint16_t data)
281    {
282        ostringstream msg;
283        msg << "Sending command:" << hex;
284        msg << " 0x" << setw(4) << setfill('0') << cmd;
285        msg << " 0x" << setw(4) << setfill('0') << data;
286        Message(msg);
287
288        const uint16_t d[2] = { htons(cmd), htons(data) };
289        PostMessage(d, sizeof(d));
290    }
291
292public:
293    enum Enable_t
294    {
295        kCmdDrsEnable       = 0x0600,  // CMD_DENABLE/CMD_DISABLE
296        kCmdDwrite          = 0x0800,  // CMD_DWRITE_RUN/CMD_DWRITE_STOP
297        kCmdSclk            = 0x1000,  // CMD_SCLK_ON/OFF
298        kCmdSrclk           = 0x1500,  // CMD_SRCLK_ON/OFF
299        kCmdTriggerLine     = 0x1800,  // CMD_TRIGGERS_ON/CMD_TRIGGERS_OFF
300        //kCmdContTrigger  = 0x1f00,
301        kCmdContTriggerOff  = 0x2000,
302        kCmdRun             = 0x2200,  // CMD_Start/Stop
303        kCmdResetTriggerId  = 0x2A00,  //
304        kCmdSocket          = 0x3000,  // CMD_mode_command/CMD_mode_all_sockets
305        kCmdSingleTrigger   = 0xA000,  // CMD_Trigger
306        kCmdContTriggerOn   = 0xB000,
307    };
308
309private:
310    enum
311    {
312        kCmdWrite           = 0x0500,         // write to Config-RAM
313        kCmdWriteRoi        = kCmdWrite|0x00, // Baseaddress ROI-Values
314        kCmdWriteDac        = kCmdWrite|0x24, // Baseaddress DAC-Values
315
316        kCmdWriteRate       = kCmdWrite|0x2c, // Continous trigger rate
317        kCmdWriteRunNumber  = kCmdWrite|0x2d, //
318
319        /*
320         kCmdRead            = 0x0a00,         // read from Config-RAM
321         kCmdReadRoi         = kCmdRead|0x00,  // Baseaddress ROI-Values
322         kCmdReadDac         = kCmdRead|0x24,  // Baseaddress DAC-Values
323         */
324
325        kCmdPhaseIncrease   = 0x1200,         // CMD_PS_DIRINC
326        kCmdPhaseDecrease   = 0x1300,         // CMD_PS_DIRDEC
327        kCmdPhaseApply      = 0x1400,         // CMD_PS_DO
328        kCmdPhaseReset      = 0x1700,         // CMD_PS_RESET
329    };
330
331public:
332    ConnectionFAD(ba::io_service& ioservice, MessageImp &imp) :
333    Connection(ioservice, imp()),
334    fIsVerbose(true), fIsHexOutput(false), fIsDataOutput(false), fCounter(0)
335
336    {
337        SetLogStream(&imp);
338    }
339
340    void Cmd(Enable_t cmd, bool on=true)
341    {
342        PostCmd(cmd + (on ? 0 : 0x100));
343    }
344
345    // ------------------------------
346
347    // IMPLEMENT: Abs/Rel
348    void CmdPhaseShift(int16_t val)
349    {
350        vector<uint16_t> cmd(abs(val)+2, kCmdPhaseApply);
351        cmd[0] = kCmdPhaseReset;
352        cmd[1] = val<0 ? kCmdPhaseDecrease : kCmdPhaseIncrease;
353        PostCmd(cmd);
354    }
355
356    bool CmdSetTriggerRate(int32_t val)
357    {
358        if (val<0 || val>0xffff)
359            return false;
360
361        PostCmd(kCmdWriteRate, val);//uint8_t(1000./val/12.5));
362        //PostCmd(kCmdContTriggerRate, uint8_t(80/val));
363
364        return true;
365    }
366
367    void CmdSetRegister(uint8_t addr, uint16_t val)
368    {
369        // Allowed addr:  [0, MAX_ADDR]
370        // Allowed value: [0, MAX_VAL]
371        PostCmd(kCmdWrite + addr, val);
372    }
373
374    bool CmdSetDacValue(uint8_t addr, uint16_t val)
375    {
376        if (addr>FAD::kMaxDacAddr) // NDAC
377            return false;
378
379        PostCmd(kCmdWriteDac + addr, val);
380        return true;
381    }
382
383    bool CmdSetRoi(int8_t addr, uint16_t val)
384    {
385        if (addr>FAD::kMaxRoiAddr)
386            return false;
387
388        if (val>FAD::kMaxRoiValue)
389            return false;
390
391        if (addr<0)
392            for (int i=0; i<FAD::kMaxRoiAddr; i++)
393                PostCmd(kCmdWriteRoi + i, val);
394        else
395            PostCmd(kCmdWriteRoi + addr, val);
396
397        return true;
398    }
399
400    bool CmdSetRoi(uint16_t val) { return CmdSetRoi(-1, val); }
401
402    void AmplitudeCalibration()
403    {
404        // ------------- case baseline -----------------
405
406        CmdSetRoi(-1, FAD::kMaxBins);
407
408        CmdSetDacValue(1, 0);
409        CmdSetDacValue(2, 0);
410        CmdSetDacValue(3, 0);
411
412        // Take N events
413
414        /*
415         // ====== Part B: Baseline calibration =====
416
417         // Loop over all channels(ch) and time-slices (t)
418         T0 = TriggerCell[chip]
419         Sum[ch][(t+T0) % kMaxBins] += Data[ch][t];
420         // FIXME: Determine median instead of average
421
422         Baseline[ch][slice] = MEDIAN( sum[ch][slice] )
423         */
424
425        // --------------- case gain -------------------
426
427        // Set new DAC values and start accumulation
428        CmdSetDacValue(1, 50000);
429        CmdSetDacValue(2, 50000);
430        CmdSetDacValue(3, 50000);
431
432        // Take N events
433
434        /*
435         // ====== Part C: Gain calibration =====
436
437         T0 = TriggerCell[chip]
438         Sum[ch][(t+T0) % kMaxBins] += Data[ch][t];
439         // FIXME: Determine median instead of average
440
441         Gain[ch][slice] = MEDIAN( sum[ch][slice] ) - Baseline[ch][slice]
442         */
443
444        // --------------- secondary ------------------
445
446        // FIXME: Can most probably be done together with the baseline calibration
447        // FIXME: Why does the secondary baseline not influence the baseline?
448
449        CmdSetDacValue(1, 0);
450        CmdSetDacValue(2, 0);
451        CmdSetDacValue(3, 0);
452
453        // Take N events
454
455        /*
456         // ====== Part D: Secondary calibration =====
457
458         T0 = TriggerCell[chip]
459         Sum[ch][t] = Data[ch][t] - Baseline[ch][(i-T0) % kMaxBins];
460
461         // Determine secondary baseline if integration finished
462         SecondaryBaseline[ch][t] = MEDIAN( Sum[ch][t] )
463         */
464    }
465
466    void SetVerbose(bool b)
467    {
468        fIsVerbose = b;
469    }
470
471    void SetHexOutput(bool b)
472    {
473        fIsHexOutput = b;
474    }
475
476    void SetDataOutput(bool b)
477    {
478        fIsDataOutput = b;
479    }
480
481};
482
483// ------------------------------------------------------------------------
484/*
485#include "DimDescriptionService.h"
486
487class ConnectionDimFAD : public ConnectionFAD
488{
489private:
490
491    DimDescribedService fDimPassport;
492    DimDescribedService fDimTemperatures;
493    DimDescribedService fDimSetup;
494    DimDescribedService fDimEventHeader;
495
496    template<class T>
497        void Update(DimDescribedService &svc, const T &data) const
498    {
499        //cout << "Update: " << svc.getName() << " (" << sizeof(T) << ")" << endl;
500        svc.setData(const_cast<T*>(&data), sizeof(T));
501        svc.updateService();
502    }
503
504    void UpdateFirstHeader()
505    {
506        ConnectionFAD::UpdateFirstHeader();
507
508        const FAD::DimPassport data(fEventHeader);
509        Update(fDimPassport, data);
510    }
511
512    void UpdateEventHeader()
513    {
514        ConnectionFAD::UpdateEventHeader();
515
516        const FAD::DimTemperatures data0(fEventHeader);
517        const FAD::DimSetup        data1(fEventHeader);
518        const FAD::DimEventHeader  data2(fEventHeader);
519
520        Update(fDimTemperatures, data0);
521        Update(fDimSetup,        data1);
522        Update(fDimEventHeader,  data2);
523    }
524
525public:
526    ConnectionDimFAD(ba::io_service& ioservice, MessageImp &imp) :
527        ConnectionFAD(ioservice, imp),
528        fDimPassport    ("FAD_CONTROL/PASSPORT",     "I:1;S:2;X:1", ""),
529        fDimTemperatures("FAD_CONTROL/TEMPERATURES", "I:1;F:4",     ""),
530        fDimSetup       ("FAD_CONTROL/SETUP",        "I:2;S:12",    ""),
531        fDimEventHeader ("FAD_CONTROL/EVENT_HEADER", "C",           "")
532    {
533    }
534
535    // 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
536};
537*/
538// ------------------------------------------------------------------------
539extern "C"
540{
541    extern void *readFAD(void*);
542    extern void *procEvt(void*);
543    extern void *writeEvt(void*);
544    extern void initReadFAD();
545};
546
547#include "EventBuilder.h"
548
549class EventBuilderWrapper
550{
551public:
552    // FIXME
553    static EventBuilderWrapper *This;
554
555private:
556    boost::thread fThread;
557
558    enum CommandStates_t // g_runStat
559    {
560        kAbort      = -2,  // quit as soon as possible ('abort')
561        kExit       = -1,  // stop reading, quit when buffered events done ('exit')
562        kInitialize =  0,  // 'initialize' (e.g. dim not yet started)
563        kHybernate  =  1,  // do nothing for long time ('hybernate') [wakeup within ~1sec]
564        kSleep      =  2,  // do nothing ('sleep')                   [wakeup within ~10msec]
565        kModeFlush  = 10,  // read data from camera, but skip them ('flush')
566        kModeTest   = 20,  // read data and process them, but do not write to disk ('test')
567        kModeFlag   = 30,  // read data, process and write all to disk ('flag')
568        kModeRun    = 40,  // read data, process and write selected to disk ('run')
569    };
570
571    MessageImp &fMsg;
572
573public:
574    EventBuilderWrapper(MessageImp &msg) : fMsg(msg)
575    {
576        if (This)
577            throw runtime_error("EventBuilderWrapper cannot be instantiated twice.");
578
579        This = this;
580        Start();
581    }
582
583    void Update(ostringstream &out, int severity)
584    {
585        fMsg.Update(out, severity);
586    }
587
588    void Start()
589    {
590        if (fThread.joinable())
591        {
592            fMsg.Warn("Start - EventBuilder still running");
593            return;
594        }
595
596        fMsg.Message("Initializing EventBuilder");
597        initReadFAD();
598
599        g_runStat = kHybernate;
600        fThread = boost::thread(readFAD, (void*)NULL);
601
602        fMsg.Message("EventBuilder started");
603    }
604    void Abort()
605    {
606        fMsg.Message("Waiting for EventBuilder to abort...");
607        g_runStat = kAbort;
608        fThread.join();
609        fMsg.Message("EventBuilder stopped.");
610    }
611
612    void Exit()
613    {
614        fMsg.Message("Waiting for EventBuilder to exit - be patient...");
615        g_runStat = kExit;
616    }
617
618    void Wait()
619    {
620        fThread.join();
621        fMsg.Message("EventBuilder stopped.");
622    }
623
624    void Hybernate() { g_runStat = kHybernate; }
625    void Sleep()     { g_runStat = kSleep;     }
626    void FlushMode() { g_runStat = kModeFlush; }
627    void TestMode()  { g_runStat = kModeTest;  }
628    void FlagMode()  { g_runStat = kModeFlag;  }
629    void RunMode()   { g_runStat = kModeRun;   }
630
631    // FIXME: To be removed
632    void SetMode(int mode) { g_runStat = mode; }
633
634    bool IsConnected(int i) const     { return gi_NumConnect[i]==7; }
635    bool IsDisconnected(int i) const  { return gi_NumConnect[i]==0; }
636    int  GetNumConnected(int i) const { return gi_NumConnect[i]; }
637
638    void Restart()
639    {
640        Abort();
641        Start();
642    }
643
644    ~EventBuilderWrapper()
645    {
646        Abort();
647    }
648};
649/*
650extern "C" {
651
652void Error(int severity, int errnum, const char *fmt, ...)
653{
654    va_list ap;
655    va_start(ap, fmt);
656
657    int n=256;
658
659    char *ret=0;
660    while (1)
661    {
662        ret = new char[n+1];
663
664        const int sz = vsnprintf(ret, n, fmt, ap);
665        if (sz<=n)
666            break;
667
668        n *= 2;
669        delete [] ret;
670    };
671
672    va_end(ap);
673
674    ostringstream str;
675    str << ret << " (" << errnum << ":" << strerror(errnum) << ")";
676
677    delete [] ret;
678
679    EventBuilderWrapper::This->Update(str, severity);
680}
681
682}
683*/
684
685EventBuilderWrapper *EventBuilderWrapper::This = 0;
686
687// ------------------------------------------------------------------------
688
689template <class T>
690class StateMachineFAD : public T, public EventBuilderWrapper, public ba::io_service, public ba::io_service::work
691{
692private:
693    typedef pair<string, ConnectionFAD*>    Connection;
694    typedef pair<const uint8_t, Connection> Board;
695    typedef map<uint8_t, Connection>        BoardList;
696
697    BoardList fBoards;
698
699    bool fIsVerbose;
700    bool fIsHexOutput;
701    bool fIsDataOutput;
702
703    bool CheckEventSize(size_t has, const char *name, size_t size)
704    {
705        if (has==size)
706            return true;
707
708        ostringstream msg;
709        msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
710        T::Fatal(msg);
711        return false;
712    }
713
714    int Cmd(ConnectionFAD::Enable_t command)
715    {
716        for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
717            i->second.second->Cmd(command);
718
719        return T::GetCurrentState();
720    }
721
722    int CmdEnable(const EventImp &evt, ConnectionFAD::Enable_t command)
723    {
724        if (!CheckEventSize(evt.GetSize(), "CmdEnable", 1))
725            return T::kSM_FatalError;
726
727        for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
728            i->second.second->Cmd(command, evt.GetBool());
729
730        return T::GetCurrentState();
731    }
732
733    bool Check(const uint32_t *dat, uint32_t maxaddr, uint32_t maxval)
734    {
735        if (dat[0]>FAD::kMaxRegAddr)
736        {
737            ostringstream msg;
738            msg << hex << "Address " << dat[0] << " out of range, max=" << maxaddr << ".";
739            T::Error(msg);
740            return false;
741        }
742
743        if (dat[1]>FAD::kMaxRegValue)
744        {
745            ostringstream msg;
746            msg << hex << "Value " << dat[1] << " out of range, max=" << maxval << ".";
747            T::Error(msg);
748            return false;
749        }
750
751        return true;
752    }
753
754    int SetRegister(const EventImp &evt)
755    {
756        if (!CheckEventSize(evt.GetSize(), "SetRegister", 8))
757            return T::kSM_FatalError;
758
759        const uint32_t *dat = reinterpret_cast<const uint32_t*>(evt.GetData());
760
761        if (!Check(dat, FAD::kMaxRegAddr, FAD::kMaxRegValue))
762            return T::GetCurrentState();
763
764        for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
765            i->second.second->CmdSetRegister(dat[0], dat[1]);
766
767        return T::GetCurrentState();
768    }
769
770    int SetRoi(const EventImp &evt)
771    {
772        if (!CheckEventSize(evt.GetSize(), "SetRoi", 8))
773            return T::kSM_FatalError;
774
775        // ---- was uint32_t
776        const int32_t *dat = reinterpret_cast<const int32_t*>(evt.GetData());
777
778        // ---- -1 for all
779        //if (!Check(dat, FAD::kMaxRoiAddr, FAD::kMaxRoiValue))
780        //            return T::GetCurrentState();
781
782        for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
783            i->second.second->CmdSetRoi(dat[0], dat[1]);
784
785        return T::GetCurrentState();
786    }
787
788    int SetDac(const EventImp &evt)
789    {
790        if (!CheckEventSize(evt.GetSize(), "SetDac", 8))
791            return T::kSM_FatalError;
792
793        const uint32_t *dat = reinterpret_cast<const uint32_t*>(evt.GetData());
794
795        if (!Check(dat, FAD::kMaxDacAddr, FAD::kMaxDacValue))
796            return T::GetCurrentState();
797
798        for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
799            i->second.second->CmdSetDacValue(dat[0], dat[1]);
800
801        return T::GetCurrentState();
802    }
803
804    int Trigger(int n)
805    {
806        for (int nn=0; nn<n; nn++)
807            for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
808                i->second.second->Cmd(ConnectionFAD::kCmdSingleTrigger);
809
810        return T::GetCurrentState();
811    }
812
813    int SendTriggers(const EventImp &evt)
814    {
815        if (!CheckEventSize(evt.GetSize(), "SendTriggers", 4))
816            return T::kSM_FatalError;
817
818        Trigger(evt.GetUInt());
819
820        return T::GetCurrentState();
821    }
822
823    int StartRun(const EventImp &evt, bool start)
824    {
825        if (!CheckEventSize(evt.GetSize(), "StartRun", 0))
826            return T::kSM_FatalError;
827
828        for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
829            i->second.second->Cmd(ConnectionFAD::kCmdRun, start);
830
831        return T::GetCurrentState();
832    }
833
834    int PhaseShift(const EventImp &evt)
835    {
836        if (!CheckEventSize(evt.GetSize(), "PhaseShift", 2))
837            return T::kSM_FatalError;
838
839        for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
840            i->second.second->CmdPhaseShift(evt.GetShort());
841
842        return T::GetCurrentState();
843    }
844
845    int SetTriggerRate(const EventImp &evt)
846    {
847        if (!CheckEventSize(evt.GetSize(), "SetTriggerRate", 4))
848            return T::kSM_FatalError;
849
850        if (evt.GetUShort()>0xff)
851        {
852            ostringstream msg;
853            msg << hex << "Value " << evt.GetUShort() << " out of range, max=" << 0xff << "(?)";
854            T::Error(msg);
855            return false;
856        }
857
858        for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
859            i->second.second->CmdSetTriggerRate(evt.GetUInt());
860
861        return T::GetCurrentState();
862    }
863
864    int Test(const EventImp &evt)
865    {
866        if (!CheckEventSize(evt.GetSize(), "Test", 2))
867            return T::kSM_FatalError;
868
869
870        SetMode(evt.GetShort());
871
872        return T::GetCurrentState();
873    }
874
875
876    int SetVerbosity(const EventImp &evt)
877    {
878        if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
879            return T::kSM_FatalError;
880
881        for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
882            i->second.second->SetVerbose(evt.GetText()[0]!=0);
883
884        return T::GetCurrentState();
885    }
886
887    int SetHexOutput(const EventImp &evt)
888    {
889        if (!CheckEventSize(evt.GetSize(), "SetHexOutput", 1))
890            return T::kSM_FatalError;
891
892        for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
893            i->second.second->SetHexOutput(evt.GetText()[0]!=0);
894
895        return T::GetCurrentState();
896    }
897
898    int SetDataOutput(const EventImp &evt)
899    {
900        if (!CheckEventSize(evt.GetSize(), "SetDataOutput", 1))
901            return T::kSM_FatalError;
902
903       for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
904            i->second.second->SetDataOutput(evt.GetText()[0]!=0);
905
906        return T::GetCurrentState();
907    }
908
909    const BoardList::iterator GetSlot(int slot)
910    {
911        const BoardList::iterator i = fBoards.find(slot);
912        if (i!=fBoards.end())
913            return i;
914
915        ostringstream str;
916        str << "Slot " << slot << " not found.";
917        T::Warn(str.str());
918        return fBoards.end();
919    }
920
921    int AddAddress(const EventImp &evt)
922    {
923        const string addr = Tools::Trim(evt.GetText());
924
925        for (BoardList::const_iterator i=fBoards.begin(); i!=fBoards.end(); i++)
926        {
927            if (i->second.first==addr)
928            {
929               T::Warn("Address "+addr+" already known.... ignored.");
930               return T::GetCurrentState();
931            }
932        }
933
934        AddEndpoint(addr);
935
936        return T::GetCurrentState();
937    }
938
939    int RemoveSlot(const EventImp &evt)
940    {
941        if (!CheckEventSize(evt.GetSize(), "RemoveSlot", 2))
942            return T::kSM_FatalError;
943
944        const int16_t slot = evt.GetShort();
945
946        const BoardList::iterator v = GetSlot(slot);
947        if (v!=fBoards.end())
948        {
949            delete v->second.second;
950            fBoards.erase(v);
951        }
952
953        return T::GetCurrentState();
954    }
955
956    int ListSlots()
957    {
958        for (BoardList::const_iterator i=fBoards.begin(); i!=fBoards.end(); i++)
959        {
960            ostringstream str;
961            str << "Slot " << setw(2) << (int)i->first << ": " << i->second.first;
962
963            const ConnectionFAD *c = i->second.second;
964
965            if (c->IsConnecting())
966                str << " (0:connecting, ";
967            else
968            {
969                if (c->IsClosed())
970                    str << " (0:disconnected, ";
971                if (c->IsConnected())
972                    str << " (0:connected, ";
973            }
974
975            switch (fStatus2[i->first])
976            {
977            case 0: str << "1-7:disconnected)"; break;
978            case 1: str << "1-7:connecting [" << GetNumConnected(i->first) << "])";   break;
979            case 2: str << "1-7:connected)";    break;
980            }
981
982            T::Message(str.str());
983        }
984
985        return T::GetCurrentState();
986    }
987
988    void EnableSlot(BoardList::iterator i, bool enable=true)
989    {
990        if (i==fBoards.end())
991            return;
992
993        ConnectionFAD* &ptr = i->second.second;
994
995        if (!enable)
996            ptr->PostClose(false);
997        else
998        {
999            ptr->SetEndpoint(i->second.first);
1000            ptr->StartConnect();
1001        }
1002    }
1003
1004    void EnableAll(bool enable=true)
1005    {
1006        for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
1007            EnableSlot(i, enable);
1008    }
1009
1010    /*
1011    int Enable(const EventImp &evt)
1012    {
1013        if (!CheckEventSize(evt.GetSize(), "Enable", 3))
1014            return T::kSM_FatalError;
1015
1016        const int16_t slot   = evt.GetShort();
1017        const bool    enable = evt.GetText()[2]>0;
1018
1019        if (slot<0)
1020        {
1021            EnableAll(enable);
1022            return T::GetCurrentState();
1023        }
1024
1025        EnableSlot(GetSlot(slot), enable);
1026
1027        return T::GetCurrentState();
1028    }*/
1029
1030    int Disconnect()
1031    {
1032        Exit();
1033        EnableAll(false);
1034        return T::GetCurrentState();
1035    }
1036
1037    int Connect()
1038    {
1039        T::Error("FIXME - Propagate IP Addresses to EventBuilder");
1040
1041        Start();
1042        EnableAll(true);
1043
1044        return T::GetCurrentState();
1045   }
1046
1047    /*
1048    int Reconnect(const EventImp &evt)
1049    {
1050        if (!CheckEventSize(evt.GetSize(), "Reconnect", 2))
1051            return T::kSM_FatalError;
1052
1053        const int16_t slot = evt.GetShort();
1054
1055        if (slot<0)
1056        {
1057            // Close all connections to supress the warning in SetEndpoint
1058            for (BoardList::const_iterator i=fBoards.begin(); i!=fBoards.end(); i++)
1059                i->second.second->PostClose(false);
1060
1061            // Now wait until all connection have been closed and
1062            // all pending handlers have been processed
1063            poll();
1064
1065            // Now we can reopen the connection
1066            for (BoardList::const_iterator i=fBoards.begin(); i!=fBoards.end(); i++)
1067                i->second.second->PostClose(true);
1068
1069            return T::GetCurrentState();
1070        }
1071
1072        const BoardList::const_iterator v = GetSlot(slot);
1073        if (v==fBoards.end())
1074            return T::GetCurrentState();
1075
1076        // Close all connections to supress the warning in SetEndpoint
1077        v->second.second->PostClose(false);
1078
1079        // Now wait until all connection have been closed and
1080        // all pending handlers have been processed
1081        poll();
1082
1083        // Now we can reopen the connection
1084        v->second.second->PostClose(true);
1085
1086        return T::GetCurrentState();
1087    }*/
1088
1089    virtual void UpdateConnectionStatus()
1090    {
1091        //cout << "Connection Status changed prop to Dim." << endl;
1092    }
1093
1094    vector<char> fStatus1;
1095    vector<char> fStatus2;
1096
1097    int Execute()
1098    {
1099        // Dispatch (execute) at most one handler from the queue. In contrary
1100        // to run_one(), it doesn't wait until a handler is available
1101        // which can be dispatched, so poll_one() might return with 0
1102        // handlers dispatched. The handlers are always dispatched/executed
1103        // synchronously, i.e. within the call to poll_one()
1104        poll_one();
1105
1106        // ===== Evaluate connection status =====
1107
1108        uint16_t nconnecting1 = 0;
1109        uint16_t nconnecting2 = 0;
1110        uint16_t nconnected1  = 0;
1111        uint16_t nconnected2  = 0;
1112
1113        vector<char> stat1(40);
1114        vector<char> stat2(40);
1115        for (BoardList::const_iterator i=fBoards.begin(); i!=fBoards.end(); i++)
1116        {
1117            const ConnectionFAD &c = *i->second.second;
1118
1119            const int &idx = i->first;
1120
1121            // ----- Command socket -----
1122            if (c.IsConnecting())
1123            {
1124                stat1[idx] = 1;
1125                nconnecting1++;
1126            }
1127            if (c.IsConnected())
1128            {
1129                stat1[idx] = 2;
1130                nconnected1++;
1131            }
1132
1133            // ----- Event builder -----
1134            if (!IsConnected(idx) && !IsDisconnected(idx))
1135            {
1136                stat2[idx] = 1;
1137                nconnecting2++;
1138            }
1139
1140            if (IsConnected(idx))
1141            {
1142                stat2[idx] = 2;
1143                nconnected2++;
1144            }
1145        }
1146
1147        // ===== Send connection status via dim =====
1148
1149        if (fStatus1!=stat1 || fStatus2!=stat2)
1150        {
1151            fStatus1 = stat1;
1152            fStatus2 = stat2;
1153            UpdateConnectionStatus();
1154        }
1155
1156        // ===== Return connection status =====
1157
1158        // fadctrl:       Always connecting if not disabled
1159        // event builder:
1160
1161        if (nconnected1==fBoards.size() && nconnected2==fBoards.size())
1162            return FAD::kConnected;
1163
1164        if (nconnected1==0 && nconnected2==0)
1165            return FAD::kDisconnected;
1166
1167        // FIXME: Evaluate event builder status
1168        return FAD::kConnecting;
1169    }
1170
1171    void AddEndpoint(const string &addr)
1172    {
1173        if (fBoards.size()==40)
1174        {
1175            T::Warn("Not more than 40 slots allowed.");
1176            return;
1177        }
1178
1179        int i=0;
1180        while (1)
1181        {
1182            const BoardList::const_iterator v = fBoards.find(i);
1183            if (v==fBoards.end())
1184                break;
1185            i++;
1186        }
1187
1188        fBoards[i] = make_pair(addr, new ConnectionFAD(*this, *this));
1189        fBoards[i].second->SetVerbose(fIsVerbose);
1190        fBoards[i].second->SetHexOutput(fIsHexOutput);
1191        fBoards[i].second->SetDataOutput(fIsDataOutput);
1192    }
1193
1194
1195
1196public:
1197    StateMachineFAD(ostream &out=cout) :
1198        T(out, "FAD_CONTROL"), EventBuilderWrapper(static_cast<MessageImp&>(*this)), ba::io_service::work(static_cast<ba::io_service&>(*this)),
1199        fStatus1(40), fStatus2(40)
1200    {
1201        // ba::io_service::work is a kind of keep_alive for the loop.
1202        // It prevents the io_service to go to stopped state, which
1203        // would prevent any consecutive calls to run()
1204        // or poll() to do nothing. reset() could also revoke to the
1205        // previous state but this might introduce some overhead of
1206        // deletion and creation of threads and more.
1207
1208        // State names
1209        T::AddStateName(FAD::kDisconnected, "Disconnected",
1210                        "All enabled FAD boards are disconnected.");
1211
1212        T::AddStateName(FAD::kConnected, "Connected",
1213                        "All enabled FAD boards are connected..");
1214
1215        T::AddStateName(FAD::kConnecting, "Connecting",
1216                        "Only some enabled FAD boards are connected.");
1217
1218        // FAD Commands
1219        T::AddEvent("ENABLE_SRCLK", "B:1")
1220            (boost::bind(&StateMachineFAD::CmdEnable, this, _1, ConnectionFAD::kCmdSrclk))
1221            ("Set SRCLK");
1222        T::AddEvent("ENABLE_SCLK", "B:1")
1223            (boost::bind(&StateMachineFAD::CmdEnable, this, _1, ConnectionFAD::kCmdSclk))
1224            ("Set SCLK");
1225        T::AddEvent("ENABLE_DRS", "B:1")
1226            (boost::bind(&StateMachineFAD::CmdEnable, this, _1, ConnectionFAD::kCmdDrsEnable))
1227            ("Switch Domino wave");
1228        T::AddEvent("ENABLE_DWRITE", "B:1")
1229            (boost::bind(&StateMachineFAD::CmdEnable, this, _1, ConnectionFAD::kCmdDwrite))
1230            ("Set Dwrite (possibly high / always low)");
1231        T::AddEvent("SET_DEBUG_MODE", "B:1")
1232            (boost::bind(&StateMachineFAD::CmdEnable, this, _1, ConnectionFAD::kCmdSocket))
1233            ("Set debug mode (yes: dump events through command socket, no=dump events through other sockets)");
1234        T::AddEvent("ENABLE_TRIGGER_LINE", "B:1")
1235            (boost::bind(&StateMachineFAD::CmdEnable, this, _1, ConnectionFAD::kCmdTriggerLine))
1236            ("Incoming triggers can be accepted/will not be accepted");
1237        T::AddEvent("SET_TRIGGER_RATE", "I:1")
1238            (boost::bind(&StateMachineFAD::SetTriggerRate, this, _1))
1239            ("Enable continous trigger");
1240        T::AddEvent("SEND_SINGLE_TRIGGER")
1241            (boost::bind(&StateMachineFAD::Trigger, this, 1))
1242            ("Issue software triggers");
1243        T::AddEvent("SEND_N_TRIGGERS", "I")
1244            (boost::bind(&StateMachineFAD::SendTriggers, this, _1))
1245            ("Issue software triggers");
1246        T::AddEvent("START", "")
1247            (boost::bind(&StateMachineFAD::StartRun, this, _1, true))
1248            ("Set FAD DAQ mode. when started, no configurations must be send.");
1249        T::AddEvent("STOP")
1250            (boost::bind(&StateMachineFAD::StartRun, this, _1, false))
1251            ("");
1252        T::AddEvent("PHASE_SHIFT", "S:1")
1253            (boost::bind(&StateMachineFAD::PhaseShift, this, _1))
1254            ("Adjust ADC phase (in 'steps')");
1255
1256        T::AddEvent("CONTINOUS_TRIGGER_ON")
1257            (boost::bind(&StateMachineFAD::Cmd, this, ConnectionFAD::kCmdContTriggerOn))
1258            ("");
1259        T::AddEvent("CONTINOUS_TRIGGER_OFF")
1260            (boost::bind(&StateMachineFAD::Cmd, this, ConnectionFAD::kCmdContTriggerOff))
1261            ("");
1262
1263        T::AddEvent("RESET_TRIGGER_ID")
1264            (boost::bind(&StateMachineFAD::Cmd, this, ConnectionFAD::kCmdResetTriggerId))
1265            ("");
1266
1267        T::AddEvent("SET_REGISTER", "I:2")
1268            (boost::bind(&StateMachineFAD::SetRegister, this, _1))
1269            ("set register to value"
1270            "|addr[short]:Address of register"
1271            "|val[short]:Value to be set");
1272
1273        // FIXME:  Maybe add a mask which channels should be set?
1274        T::AddEvent("SET_REGION_OF_INTEREST", "I:2")
1275            (boost::bind(&StateMachineFAD::SetRoi, this, _1))
1276            ("Set region-of-interest to value"
1277            "|addr[short]:Address of register"
1278            "|val[short]:Value to be set");
1279
1280        // FIXME:  Maybe add a mask which channels should be set?
1281        T::AddEvent("SET_DAC_VALUE", "I:2")
1282            (boost::bind(&StateMachineFAD::SetDac, this, _1))
1283            ("Set DAC numbers in range to value"
1284            "|addr[short]:Address of register"
1285            "|val[short]:Value to be set");
1286
1287        // Verbosity commands
1288        T::AddEvent("SET_VERBOSE", "B")
1289            (boost::bind(&StateMachineFAD::SetVerbosity, this, _1))
1290            ("set verbosity state"
1291             "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
1292
1293        T::AddEvent("SET_HEX_OUTPUT", "B")
1294            (boost::bind(&StateMachineFAD::SetHexOutput, this, _1))
1295            ("enable or disable hex output for received data"
1296             "|hexout[bool]:disable or enable hex output for received data (yes/no)");
1297
1298        T::AddEvent("SET_DATA_OUTPUT", "B")
1299            (boost::bind(&StateMachineFAD::SetDataOutput, this, _1))
1300            ("");
1301
1302        // Conenction commands
1303        /*
1304        T::AddEvent("ENABLE", "S:1;B:1", FAD::kDisconnected)
1305            (boost::bind(&StateMachineFAD::Enable, this, _1))
1306            ("");*/
1307
1308        T::AddEvent("CONNECT", FAD::kDisconnected)
1309            (boost::bind(&StateMachineFAD::Connect, this))
1310            ("");
1311
1312        T::AddEvent("DISCONNECT")
1313            (boost::bind(&StateMachineFAD::Disconnect, this))
1314            ("");
1315
1316        T::AddEvent("TEST", "S:1")
1317            (boost::bind(&StateMachineFAD::Test, this, _1))
1318            ("");
1319
1320        T::AddEvent("ADD_ADDRESS", "C", FAD::kDisconnected)
1321            (boost::bind(&StateMachineFAD::AddAddress, this, _1))
1322            ("Add the address of a DRS4 board to the first free slot"
1323             "|IP[string]:address in the format <address:port>");
1324        T::AddEvent("REMOVE_SLOT", "S:1", FAD::kDisconnected)
1325            (boost::bind(&StateMachineFAD::RemoveSlot, this, _1))
1326            ("Remove the Iaddress in slot n. For a list see LIST"
1327             "|slot[int]:Remove the address in slot n from the list");
1328        T::AddEvent("LIST_SLOTS")
1329            (boost::bind(&StateMachineFAD::ListSlots, this))
1330            ("Print a list of all available board addressesa and whether they are enabled");
1331    }
1332
1333    ~StateMachineFAD()
1334    {
1335        for (BoardList::const_iterator i=fBoards.begin(); i!=fBoards.end(); i++)
1336            delete i->second.second;
1337        fBoards.clear();
1338    }
1339
1340    bool SetConfiguration(const Configuration &conf)
1341    {
1342        fIsVerbose = !conf.Get<bool>("quiet");
1343        fIsHexOutput = conf.Get<bool>("hex-out");
1344        fIsDataOutput = conf.Get<bool>("data-out");
1345
1346        if (!(conf.Has("base-addr") ^ conf.Has("addr")))
1347        {
1348           T::Out() << kRed << "SetConfiguration - Only --base-addr or --addr allowed." << endl;
1349           return false;
1350        }
1351
1352        if (conf.Has("base-addr"))
1353        {
1354            const string base = conf.Get<string>("base-addr");
1355
1356            const size_t p0 = base.find_first_of(':');
1357            const size_t p1 = base.find_last_of(':');
1358
1359            if (p0==string::npos || p0!=p1)
1360            {
1361                T::Out() << kRed << "SetConfiguration - Wrong format of argument --base-addr ('host:port' expected)" << endl;
1362                return false;
1363            }
1364
1365            tcp::resolver resolver(get_io_service());
1366
1367            boost::system::error_code ec;
1368
1369            const tcp::resolver::query query(base.substr(0, p0), base.substr(p0+1));
1370            const tcp::resolver::iterator iterator = resolver.resolve(query, ec);
1371
1372            if (ec)
1373            {
1374               T::Out() << " " << ec.message() << " (" << ec << ")";
1375               return false;
1376            }
1377
1378            const tcp::endpoint endpoint = *iterator;
1379
1380            const ba::ip::address_v4::bytes_type ip = endpoint.address().to_v4().to_bytes();
1381
1382            if (ip[2]>250 || ip[3]>244)
1383            {
1384                T::Out() << kRed << "SetConfiguration - IP address given by --base-addr out-of-range." << endl;
1385                return false;
1386            }
1387
1388            for (int crate=0; crate<2; crate++)
1389                for (int board=0; board<10; board++)
1390                {
1391                    //if (crate==0 && board==2)
1392                    //    continue;
1393
1394                    ostringstream str;
1395                    str << (int)ip[0] << "." << (int)ip[1] << ".";
1396                    str << (int)(ip[2]+crate) << "." << (int)(ip[3]+board) << ":";
1397                    str << endpoint.port();
1398
1399                    AddEndpoint(str.str());
1400                }
1401        }
1402
1403        if (conf.Has("addr"))
1404        {
1405            const vector<string> addrs = conf.Get<vector<string>>("addr");
1406            for (vector<string>::const_iterator i=addrs.begin(); i<addrs.end(); i++)
1407                AddEndpoint(*i);
1408        }
1409
1410        EnableAll();
1411
1412        return true;
1413    }
1414
1415};
1416
1417// ------------------------------------------------------------------------
1418
1419
1420void RunThread(StateMachineImp *io_service)
1421{
1422    // This is necessary so that the StateMachien Thread can signal the
1423    // Readline to exit
1424    io_service->Run();
1425    Readline::Stop();
1426}
1427
1428template<class S>
1429int RunDim(Configuration &conf)
1430{
1431    /*
1432     initscr();               // Start curses mode
1433     cbreak();                // Line buffering disabled, Pass on
1434     intrflush(stdscr, FALSE);
1435     start_color();            // Initialize ncurses colors
1436     use_default_colors();     // Assign terminal default colors to -1
1437     for (int i=1; i<8; i++)
1438        init_pair(i, i, -1);  // -1: def background
1439        scrollok(stdscr, true);
1440        */
1441
1442    WindowLog wout;
1443
1444    //log.SetWindow(stdscr);
1445    if (conf.Has("log"))
1446        if (!wout.OpenLogFile(conf.Get<string>("log")))
1447            wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
1448
1449    // Start io_service.Run to use the StateMachineImp::Run() loop
1450    // Start io_service.run to only use the commandHandler command detaching
1451    StateMachineFAD<S> io_service(wout);
1452    if (!io_service.SetConfiguration(conf))
1453        return -1;
1454
1455    io_service.Run();
1456
1457    return 0;
1458}
1459
1460template<class T, class S>
1461int RunShell(Configuration &conf)
1462{
1463    static T shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
1464
1465    WindowLog &win  = shell.GetStreamIn();
1466    WindowLog &wout = shell.GetStreamOut();
1467
1468    if (conf.Has("log"))
1469        if (!wout.OpenLogFile(conf.Get<string>("log")))
1470            win << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
1471
1472    StateMachineFAD<S> io_service(wout);
1473    if (!io_service.SetConfiguration(conf))
1474        return -1;
1475
1476    shell.SetReceiver(io_service);
1477
1478    boost::thread t(boost::bind(RunThread, &io_service));
1479    //boost::thread t(boost::bind(&StateMachineFAD<S>::Run, &io_service));
1480
1481    shell.Run();                 // Run the shell
1482    io_service.Stop();           // Signal Loop-thread to stop
1483
1484    // Wait until the StateMachine has finished its thread
1485    // before returning and destroying the dim objects which might
1486    // still be in use.
1487    t.join();
1488
1489    return 0;
1490}
1491
1492void SetupConfiguration(Configuration &conf)
1493{
1494    const string n = conf.GetName()+".log";
1495
1496    po::options_description config("Program options");
1497    config.add_options()
1498        ("dns",       var<string>("localhost"),       "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
1499        ("log,l",     var<string>(n), "Write log-file")
1500        ("no-dim,d",  po_switch(),    "Disable dim services")
1501        ("console,c", var<int>(),     "Use console (0=shell, 1=simple buffered, X=simple unbuffered)")
1502        ;
1503
1504    po::options_description control("FAD control options");
1505    control.add_options()
1506//        ("addr,a",        var<string>("localhost:5000"),  "Network address of FTM")
1507        ("quiet,q",    po_bool(),  "Disable printing contents of all received messages in clear text.")
1508        ("hex-out",    po_bool(),  "Enable printing contents of all printed messages also as hex data.")
1509        ("data-out",   po_bool(),  "Enable printing received event data.")
1510        ("addr",       vars<string>(), "Network address of FAD")
1511        ("base-addr",  var<string>(),  "Base address of all FAD")
1512        ;
1513
1514    conf.AddEnv("dns", "DIM_DNS_NODE");
1515
1516    conf.AddOptions(config);
1517    conf.AddOptions(control);
1518}
1519
1520void PrintUsage()
1521{
1522    cout <<
1523        "The fadctrl controls the FAD boards.\n"
1524        "\n"
1525        "The default is that the program is started without user intercation. "
1526        "All actions are supposed to arrive as DimCommands. Using the -c "
1527        "option, a local shell can be initialized. With h or help a short "
1528        "help message about the usuage can be brought to the screen.\n"
1529        "\n"
1530        "Usage: fadctrl [-c type] [OPTIONS]\n"
1531        "  or:  fadctrl [OPTIONS]\n";
1532    cout << endl;
1533}
1534
1535void PrintHelp()
1536{
1537    /* Additional help text which is printed after the configuration
1538     options goes here */
1539}
1540
1541int main(int argc, const char* argv[])
1542{
1543    Configuration conf(argv[0]);
1544    conf.SetPrintUsage(PrintUsage);
1545    SetupConfiguration(conf);
1546
1547    po::variables_map vm;
1548    try
1549    {
1550        vm = conf.Parse(argc, argv);
1551    }
1552#if BOOST_VERSION > 104000
1553    catch (po::multiple_occurrences &e)
1554    {
1555        cerr << "Program options invalid due to: " << e.what() << " of '" << e.get_option_name() << "'." << endl;
1556        return -1;
1557    }
1558#endif
1559    catch (exception& e)
1560    {
1561        cerr << "Program options invalid due to: " << e.what() << endl;
1562        return -1;
1563    }
1564
1565    if (conf.HasVersion() || conf.HasPrint())
1566        return -1;
1567
1568    if (conf.HasHelp())
1569    {
1570        PrintHelp();
1571        return -1;
1572    }
1573
1574    Dim::Setup(conf.Get<string>("dns"));
1575
1576//    try
1577    {
1578        // No console access at all
1579        if (!conf.Has("console"))
1580        {
1581            if (conf.Get<bool>("no-dim"))
1582                return RunDim<StateMachine>(conf);
1583            else
1584                return RunDim<StateMachineDim>(conf);
1585        }
1586        // Cosole access w/ and w/o Dim
1587        if (conf.Get<bool>("no-dim"))
1588        {
1589            if (conf.Get<int>("console")==0)
1590                return RunShell<LocalShell, StateMachine>(conf);
1591            else
1592                return RunShell<LocalConsole, StateMachine>(conf);
1593        }
1594        else
1595        {
1596            if (conf.Get<int>("console")==0)
1597                return RunShell<LocalShell, StateMachineDim>(conf);
1598            else
1599                return RunShell<LocalConsole, StateMachineDim>(conf);
1600        }
1601    }
1602/*    catch (std::exception& e)
1603    {
1604        cerr << "Exception: " << e.what() << endl;
1605        return -1;
1606    }*/
1607
1608    return 0;
1609}
Note: See TracBrowser for help on using the repository browser.