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

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