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

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