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

Last change on this file since 10997 was 10997, checked in by tbretz, 13 years ago
Added boot message to interactive session.
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 ReadlineColor::PrintBootMsg(wout, conf.GetName(), false);
1321
1322 //log.SetWindow(stdscr);
1323 if (conf.Has("log"))
1324 if (!wout.OpenLogFile(conf.Get<string>("log")))
1325 wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
1326
1327 // Start io_service.Run to use the StateMachineImp::Run() loop
1328 // Start io_service.run to only use the commandHandler command detaching
1329 StateMachineFAD<S> io_service(wout);
1330 if (!io_service.SetConfiguration(conf))
1331 return -1;
1332
1333 io_service.Run();
1334
1335 return 0;
1336}
1337
1338template<class T, class S>
1339int RunShell(Configuration &conf)
1340{
1341 static T shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
1342
1343 WindowLog &win = shell.GetStreamIn();
1344 WindowLog &wout = shell.GetStreamOut();
1345
1346 if (conf.Has("log"))
1347 if (!wout.OpenLogFile(conf.Get<string>("log")))
1348 win << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
1349
1350 StateMachineFAD<S> io_service(wout);
1351 if (!io_service.SetConfiguration(conf))
1352 return -1;
1353
1354 shell.SetReceiver(io_service);
1355
1356 boost::thread t(boost::bind(RunThread, &io_service));
1357 //boost::thread t(boost::bind(&StateMachineFAD<S>::Run, &io_service));
1358
1359 shell.Run(); // Run the shell
1360 io_service.Stop(); // Signal Loop-thread to stop
1361
1362 // Wait until the StateMachine has finished its thread
1363 // before returning and destroying the dim objects which might
1364 // still be in use.
1365 t.join();
1366
1367 return 0;
1368}
1369
1370void SetupConfiguration(Configuration &conf)
1371{
1372 const string n = conf.GetName()+".log";
1373
1374 po::options_description config("Program options");
1375 config.add_options()
1376 ("dns", var<string>("localhost"), "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
1377 ("log,l", var<string>(n), "Write log-file")
1378 ("no-dim,d", po_switch(), "Disable dim services")
1379 ("console,c", var<int>(), "Use console (0=shell, 1=simple buffered, X=simple unbuffered)")
1380 ;
1381
1382 po::options_description control("FAD control options");
1383 control.add_options()
1384 ("quiet,q", po_bool(), "Disable printing contents of all received messages in clear text.")
1385 ("hex-out", po_bool(), "Enable printing contents of all printed messages also as hex data.")
1386 ("data-out", po_bool(), "Enable printing received event data.")
1387 ;
1388
1389 po::options_description builder("Event builder options");
1390 builder.add_options()
1391 ("max-mem,m", var<unsigned int>(100), "Maximum memory the event builder thread is allowed to consume for its event buffer")
1392 ;
1393
1394 po::options_description connect("FAD connection options");
1395 connect.add_options()
1396 ("addr", vars<string>(), "Network address of FAD")
1397 ("base-addr", var<string>(), "Base address of all FAD")
1398 ("debug-num,n", var<unsigned int>(40), "Sets the number of fake boards to be connected locally")
1399 ("debug-addr", var<string>(), "")
1400 ;
1401
1402 conf.AddEnv("dns", "DIM_DNS_NODE");
1403
1404 conf.AddOptions(config);
1405 conf.AddOptions(control);
1406 conf.AddOptions(builder);
1407 conf.AddOptions(connect);
1408}
1409
1410void PrintUsage()
1411{
1412 cout <<
1413 "The fadctrl controls the FAD boards.\n"
1414 "\n"
1415 "The default is that the program is started without user intercation. "
1416 "All actions are supposed to arrive as DimCommands. Using the -c "
1417 "option, a local shell can be initialized. With h or help a short "
1418 "help message about the usuage can be brought to the screen.\n"
1419 "\n"
1420 "Usage: fadctrl [-c type] [OPTIONS]\n"
1421 " or: fadctrl [OPTIONS]\n";
1422 cout << endl;
1423}
1424
1425void PrintHelp()
1426{
1427 /* Additional help text which is printed after the configuration
1428 options goes here */
1429}
1430
1431int main(int argc, const char* argv[])
1432{
1433 Configuration conf(argv[0]);
1434 conf.SetPrintUsage(PrintUsage);
1435 SetupConfiguration(conf);
1436
1437 po::variables_map vm;
1438 try
1439 {
1440 vm = conf.Parse(argc, argv);
1441 }
1442#if BOOST_VERSION > 104000
1443 catch (po::multiple_occurrences &e)
1444 {
1445 cerr << "Program options invalid due to: " << e.what() << " of '" << e.get_option_name() << "'." << endl;
1446 return -1;
1447 }
1448#endif
1449 catch (exception& e)
1450 {
1451 cerr << "Program options invalid due to: " << e.what() << endl;
1452 return -1;
1453 }
1454
1455 if (conf.HasVersion() || conf.HasPrint())
1456 return -1;
1457
1458 if (conf.HasHelp())
1459 {
1460 PrintHelp();
1461 return -1;
1462 }
1463
1464 Dim::Setup(conf.Get<string>("dns"));
1465
1466// try
1467 {
1468 // No console access at all
1469 if (!conf.Has("console"))
1470 {
1471 if (conf.Get<bool>("no-dim"))
1472 return RunDim<StateMachine>(conf);
1473 else
1474 return RunDim<StateMachineDim>(conf);
1475 }
1476 // Cosole access w/ and w/o Dim
1477 if (conf.Get<bool>("no-dim"))
1478 {
1479 if (conf.Get<int>("console")==0)
1480 return RunShell<LocalShell, StateMachine>(conf);
1481 else
1482 return RunShell<LocalConsole, StateMachine>(conf);
1483 }
1484 else
1485 {
1486 if (conf.Get<int>("console")==0)
1487 return RunShell<LocalShell, StateMachineDim>(conf);
1488 else
1489 return RunShell<LocalConsole, StateMachineDim>(conf);
1490 }
1491 }
1492/* catch (std::exception& e)
1493 {
1494 cerr << "Exception: " << e.what() << endl;
1495 return -1;
1496 }*/
1497
1498 return 0;
1499}
Note: See TracBrowser for help on using the repository browser.