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

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