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

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