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

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