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

Last change on this file since 11015 was 11014, checked in by tbretz, 13 years ago
Fixed some limits; some improvements to the output
File size: 44.6 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]>maxaddr)
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]>maxval)
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 const int32_t *dat = evt.Ptr<int32_t>();
606
607 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
608 if (!i->second.second->CmdSetRoi(dat[0], dat[1]))
609 {
610 ostringstream msg;
611 msg << hex << "Channel " << dat[0] << " or Value " << dat[1] << " out of range.";
612 T::Error(msg);
613 return false;
614 }
615
616
617 return T::GetCurrentState();
618 }
619
620 int SetDac(const EventImp &evt)
621 {
622 if (!CheckEventSize(evt.GetSize(), "SetDac", 8))
623 return T::kSM_FatalError;
624
625 const uint32_t *dat = evt.Ptr<uint32_t>();
626
627 if (!Check(dat, FAD::kMaxDacAddr, FAD::kMaxDacValue))
628 return T::GetCurrentState();
629
630 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
631 i->second.second->CmdSetDacValue(dat[0], dat[1]);
632
633 return T::GetCurrentState();
634 }
635
636 int Trigger(int n)
637 {
638 for (int nn=0; nn<n; nn++)
639 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
640 i->second.second->Cmd(FAD::kCmdSingleTrigger);
641
642 return T::GetCurrentState();
643 }
644
645 int SendTriggers(const EventImp &evt)
646 {
647 if (!CheckEventSize(evt.GetSize(), "SendTriggers", 4))
648 return T::kSM_FatalError;
649
650 Trigger(evt.GetUInt());
651
652 return T::GetCurrentState();
653 }
654
655 int StartRun(const EventImp &evt, bool start)
656 {
657 if (!CheckEventSize(evt.GetSize(), "StartRun", 0))
658 return T::kSM_FatalError;
659
660 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
661 i->second.second->Cmd(FAD::kCmdRun, start);
662
663 return T::GetCurrentState();
664 }
665
666 int PhaseShift(const EventImp &evt)
667 {
668 if (!CheckEventSize(evt.GetSize(), "PhaseShift", 2))
669 return T::kSM_FatalError;
670
671 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
672 i->second.second->CmdPhaseShift(evt.GetShort());
673
674 return T::GetCurrentState();
675 }
676
677 int SetTriggerRate(const EventImp &evt)
678 {
679 if (!CheckEventSize(evt.GetSize(), "SetTriggerRate", 4))
680 return T::kSM_FatalError;
681
682 if (evt.GetUShort()>0xff)
683 {
684 ostringstream msg;
685 msg << hex << "Value " << evt.GetUShort() << " out of range, max=" << 0xff << "(?)";
686 T::Error(msg);
687 return false;
688 }
689
690 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
691 i->second.second->CmdSetTriggerRate(evt.GetUInt());
692
693 return T::GetCurrentState();
694 }
695
696 int SetRunNumber(const EventImp &evt)
697 {
698 if (!CheckEventSize(evt.GetSize(), "SetRunNumber", 8))
699 return T::kSM_FatalError;
700
701 const uint64_t num = evt.GetUXtra();
702
703 if (num>FAD::kMaxRunNumber)
704 {
705 ostringstream msg;
706 msg << hex << "Value " << num << " out of range, max=" << FAD::kMaxRunNumber;
707 T::Error(msg);
708 return false;
709 }
710
711 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
712 i->second.second->CmdSetRunNumber(num);
713
714 return T::GetCurrentState();
715 }
716
717 int Test(const EventImp &evt)
718 {
719 if (!CheckEventSize(evt.GetSize(), "Test", 2))
720 return T::kSM_FatalError;
721
722
723 SetMode(evt.GetShort());
724
725 return T::GetCurrentState();
726 }
727
728
729 int SetVerbosity(const EventImp &evt)
730 {
731 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
732 return T::kSM_FatalError;
733
734 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
735 i->second.second->SetVerbose(evt.GetBool());
736
737 return T::GetCurrentState();
738 }
739
740 int SetHexOutput(const EventImp &evt)
741 {
742 if (!CheckEventSize(evt.GetSize(), "SetHexOutput", 1))
743 return T::kSM_FatalError;
744
745 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
746 i->second.second->SetHexOutput(evt.GetBool());
747
748 return T::GetCurrentState();
749 }
750
751 int SetDataOutput(const EventImp &evt)
752 {
753 if (!CheckEventSize(evt.GetSize(), "SetDataOutput", 1))
754 return T::kSM_FatalError;
755
756 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
757 i->second.second->SetDataOutput(evt.GetBool());
758
759 return T::GetCurrentState();
760 }
761
762 int AddAddress(const EventImp &evt)
763 {
764 const string addr = Tools::Trim(evt.GetText());
765
766 const tcp::endpoint endpoint = GetEndpoint(addr);
767 if (endpoint==tcp::endpoint())
768 return T::GetCurrentState();
769
770 for (BoardList::const_iterator i=fBoards.begin(); i!=fBoards.end(); i++)
771 {
772 if (i->second.first==endpoint)
773 {
774 T::Warn("Address "+addr+" already known.... ignored.");
775 return T::GetCurrentState();
776 }
777 }
778
779 AddEndpoint(endpoint);
780
781 return T::GetCurrentState();
782 }
783
784 int RemoveSlot(const EventImp &evt)
785 {
786 if (!CheckEventSize(evt.GetSize(), "RemoveSlot", 2))
787 return T::kSM_FatalError;
788
789 const int16_t slot = evt.GetShort();
790
791 const BoardList::iterator it = fBoards.find(slot);
792
793 if (it==fBoards.end())
794 {
795 ostringstream str;
796 str << "Slot " << slot << " not found.";
797 T::Warn(str.str());
798 return T::GetCurrentState();
799 }
800
801 delete it->second.second;
802 fBoards.erase(it);
803
804 return T::GetCurrentState();
805 }
806
807 int ListSlots()
808 {
809 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
810 {
811 const int &idx = i->first;
812 const Connection &slot = i->second;
813
814 ostringstream str;
815 str << "Slot " << setw(2) << idx << ": " << slot.first;
816
817 const ConnectionFAD *c = slot.second;
818
819 if (c->IsConnecting())
820 str << " (0:connecting, ";
821 else
822 {
823 if (c->IsClosed())
824 str << " (0:disconnected, ";
825 if (c->IsConnected())
826 str << " (0:connected, ";
827 }
828
829 switch (fStatus2[idx])
830 {
831 case 0: str << "1-7:not connected)"; break;
832 case 7: str << "1-7:connected)"; break;
833 default: str << "1-7:connecting [" << fStatus2[idx] << "])"; break;
834 }
835
836 T::Out() << str.str() << endl;
837 }
838
839 T::Out() << "Event builder thread:";
840 if (!IsThreadRunning())
841 T::Out() << " not";
842 T::Out() << " running" << endl;
843
844 // FIXME: Output state
845
846 return T::GetCurrentState();
847 }
848
849 void EnableSlot(Connection &c, bool enable=true)
850 {
851 ConnectionFAD *ptr = c.second;
852 if (!ptr)
853 return;
854
855 if (!enable)
856 ptr->PostClose(false);
857 else
858 {
859 ostringstream str;
860 str << c.first;
861 ptr->SetEndpoint(str.str());
862 ptr->StartConnect();
863 }
864 }
865
866 void EnableAll(bool enable=true)
867 {
868 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
869 EnableSlot(i->second, enable);
870 }
871
872 int Disconnect()
873 {
874 Exit();
875 EnableAll(false);
876 return T::GetCurrentState();
877 }
878
879 int ForceDisconnect()
880 {
881 Abort();
882 EnableAll(false);
883 return T::GetCurrentState();
884 }
885
886 int CloseOpenFiles()
887 {
888 EventBuilderWrapper::CloseOpenFiles();
889 return T::GetCurrentState();
890 }
891
892 int Connect()
893 {
894 vector<tcp::endpoint> addr(40);
895
896 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
897 addr[i->first] = i->second.first;
898
899 Start(addr);
900 EnableAll(true);
901
902 return T::GetCurrentState();
903 }
904
905 vector<uint8_t> fStatus1;
906 vector<uint8_t> fStatus2;
907
908 int Execute()
909 {
910 // Dispatch (execute) at most one handler from the queue. In contrary
911 // to run_one(), it doesn't wait until a handler is available
912 // which can be dispatched, so poll_one() might return with 0
913 // handlers dispatched. The handlers are always dispatched/executed
914 // synchronously, i.e. within the call to poll_one()
915 poll_one();
916
917 // ===== Evaluate connection status =====
918
919 uint16_t nconnecting1 = 0;
920 uint16_t nconnecting2 = 0;
921 uint16_t nconnected1 = 0;
922 uint16_t nconnected2 = 0;
923
924 vector<uint8_t> stat1(40);
925 vector<uint8_t> stat2(40);
926
927 int cnt = 0; // counter for enbled board
928
929 for (int idx=0; idx<40; idx++)
930 {
931 // ----- Command socket -----
932 const BoardList::const_iterator &slot = fBoards.find(idx);
933 if (slot!=fBoards.end())
934 {
935 const ConnectionFAD *c = slot->second.second;
936 if (c->IsConnecting())
937 {
938 stat1[idx] = 1;
939 nconnecting1++;
940 }
941 if (c->IsConnected())
942 {
943 stat1[idx] = 2;
944 nconnected1++;
945 }
946
947 cnt++;
948 }
949
950 // ----- Event builder -----
951 stat2[idx] = GetNumConnected(idx);
952
953 if (!IsConnected(idx) && !IsDisconnected(idx))
954 nconnecting2++;
955
956 if (IsConnected(idx))
957 nconnected2++;
958 }
959
960 // ===== Send connection status via dim =====
961
962 if (fStatus1!=stat1 || fStatus2!=stat2)
963 {
964 fStatus1 = stat1;
965 fStatus2 = stat2;
966 UpdateConnectionStatus(stat1, stat2);
967 }
968
969 // ===== Return connection status =====
970
971 // fadctrl: Always connecting if not disabled
972 // event builder:
973
974 // FIXME: Evaluate event builder status
975 if (nconnected1==cnt && nconnected2==cnt && cnt>0)
976 return FAD::kConnected;
977
978 if (nconnected1!=0 || nconnected2!=0)
979 return FAD::kConnecting;
980
981 // nconnected1 == nconnected2 == 0
982 return IsThreadRunning() ? FAD::kDisconnected : FAD::kOffline;
983 }
984
985 void AddEndpoint(const tcp::endpoint &addr)
986 {
987 int i=0;
988 while (i<40)
989 {
990 if (fBoards.find(i)==fBoards.end())
991 break;
992 i++;
993 }
994
995 if (i==40)
996 {
997 T::Warn("Not more than 40 slots allowed.");
998 return;
999 }
1000
1001 fBoards[i] = make_pair(addr, new ConnectionFAD(*this, *this));
1002 fBoards[i].second->SetVerbose(fIsVerbose);
1003 fBoards[i].second->SetHexOutput(fIsHexOutput);
1004 fBoards[i].second->SetDataOutput(fIsDataOutput);
1005 }
1006
1007
1008 DimDescribedService fDimConnection;
1009 /*
1010 template<class T>
1011 void Update(DimDescribedService &svc, const T &data) const
1012 {
1013 //cout << "Update: " << svc.getName() << " (" << sizeof(T) << ")" << endl;
1014 svc.setData(const_cast<T*>(&data), sizeof(T));
1015 svc.updateService();
1016 }
1017 */
1018 void UpdateConnectionStatus(const vector<uint8_t> &stat1, const vector<uint8_t> &stat2)
1019 {
1020 vector<uint8_t> stat(40);
1021
1022 for (int i=0; i<40; i++)
1023 stat[i] = stat1[i]+stat2[i];
1024
1025 fDimConnection.setData(stat.data(), 40);
1026 fDimConnection.updateService();
1027 }
1028
1029public:
1030 StateMachineFAD(ostream &out=cout) :
1031 T(out, "FAD_CONTROL"), EventBuilderWrapper(*static_cast<MessageImp*>(this)), ba::io_service::work(static_cast<ba::io_service&>(*this)),
1032 fStatus1(40), fStatus2(40),
1033 fDimConnection("FAD_CONTROL/CONNECTIONS", "C:41", "")
1034 {
1035 // ba::io_service::work is a kind of keep_alive for the loop.
1036 // It prevents the io_service to go to stopped state, which
1037 // would prevent any consecutive calls to run()
1038 // or poll() to do nothing. reset() could also revoke to the
1039 // previous state but this might introduce some overhead of
1040 // deletion and creation of threads and more.
1041
1042 // State names
1043 T::AddStateName(FAD::kOffline, "Offline",
1044 "All enabled FAD boards are disconnected and the event-builer thread is not running.");
1045
1046 T::AddStateName(FAD::kDisconnected, "Disconnected",
1047 "All enabled FAD boards are disconnected, but the event-builder thread is running.");
1048
1049 T::AddStateName(FAD::kConnected, "Connected",
1050 "All enabled FAD boards are connected..");
1051
1052 T::AddStateName(FAD::kConnecting, "Connecting",
1053 "Only some enabled FAD boards are connected.");
1054
1055 // FAD Commands
1056 T::AddEvent("ENABLE_SRCLK", "B:1")
1057 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdSrclk))
1058 ("Set SRCLK");
1059 T::AddEvent("ENABLE_SCLK", "B:1")
1060 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdSclk))
1061 ("Set SCLK");
1062 T::AddEvent("ENABLE_DRS", "B:1")
1063 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdDrsEnable))
1064 ("Switch Domino wave");
1065 T::AddEvent("ENABLE_DWRITE", "B:1")
1066 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdDwrite))
1067 ("Set Dwrite (possibly high / always low)");
1068 T::AddEvent("SET_DEBUG_MODE", "B:1")
1069 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdSocket))
1070 ("Set debug mode (yes: dump events through command socket, no=dump events through other sockets)");
1071 T::AddEvent("ENABLE_TRIGGER_LINE", "B:1")
1072 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdTriggerLine))
1073 ("Incoming triggers can be accepted/will not be accepted");
1074 T::AddEvent("SET_TRIGGER_RATE", "I:1")
1075 (boost::bind(&StateMachineFAD::SetTriggerRate, this, _1))
1076 ("Enable continous trigger");
1077 T::AddEvent("SEND_SINGLE_TRIGGER")
1078 (boost::bind(&StateMachineFAD::Trigger, this, 1))
1079 ("Issue software triggers");
1080 T::AddEvent("SEND_N_TRIGGERS", "I")
1081 (boost::bind(&StateMachineFAD::SendTriggers, this, _1))
1082 ("Issue software triggers");
1083 T::AddEvent("START", "")
1084 (boost::bind(&StateMachineFAD::StartRun, this, _1, true))
1085 ("Set FAD DAQ mode. when started, no configurations must be send.");
1086 T::AddEvent("STOP")
1087 (boost::bind(&StateMachineFAD::StartRun, this, _1, false))
1088 ("");
1089 T::AddEvent("PHASE_SHIFT", "S:1")
1090 (boost::bind(&StateMachineFAD::PhaseShift, this, _1))
1091 ("Adjust ADC phase (in 'steps')");
1092
1093 T::AddEvent("CONTINOUS_TRIGGER_ON")
1094 (boost::bind(&StateMachineFAD::Cmd, this, FAD::kCmdContTriggerOn))
1095 ("");
1096 T::AddEvent("CONTINOUS_TRIGGER_OFF")
1097 (boost::bind(&StateMachineFAD::Cmd, this, FAD::kCmdContTriggerOff))
1098 ("");
1099
1100 T::AddEvent("RESET_TRIGGER_ID")
1101 (boost::bind(&StateMachineFAD::Cmd, this, FAD::kCmdResetTriggerId))
1102 ("");
1103
1104 T::AddEvent("SET_RUN_NUMBER", "X:1")
1105 (boost::bind(&StateMachineFAD::SetRunNumber, this, _1))
1106 ("");
1107
1108 T::AddEvent("SET_REGISTER", "I:2")
1109 (boost::bind(&StateMachineFAD::SetRegister, this, _1))
1110 ("set register to value"
1111 "|addr[short]:Address of register"
1112 "|val[short]:Value to be set");
1113
1114 // FIXME: Maybe add a mask which channels should be set?
1115 T::AddEvent("SET_REGION_OF_INTEREST", "I:2")
1116 (boost::bind(&StateMachineFAD::SetRoi, this, _1))
1117 ("Set region-of-interest to value"
1118 "|addr[short]:Address of register"
1119 "|val[short]:Value to be set");
1120
1121 // FIXME: Maybe add a mask which channels should be set?
1122 T::AddEvent("SET_DAC_VALUE", "I:2")
1123 (boost::bind(&StateMachineFAD::SetDac, this, _1))
1124 ("Set DAC numbers in range to value"
1125 "|addr[short]:Address of register"
1126 "|val[short]:Value to be set");
1127
1128 // Verbosity commands
1129 T::AddEvent("SET_VERBOSE", "B")
1130 (boost::bind(&StateMachineFAD::SetVerbosity, this, _1))
1131 ("set verbosity state"
1132 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
1133
1134 T::AddEvent("SET_HEX_OUTPUT", "B")
1135 (boost::bind(&StateMachineFAD::SetHexOutput, this, _1))
1136 ("enable or disable hex output for received data"
1137 "|hexout[bool]:disable or enable hex output for received data (yes/no)");
1138
1139 T::AddEvent("SET_DATA_OUTPUT", "B")
1140 (boost::bind(&StateMachineFAD::SetDataOutput, this, _1))
1141 ("");
1142
1143 // Conenction commands
1144 /*
1145 T::AddEvent("ENABLE", "S:1;B:1", FAD::kDisconnected)
1146 (boost::bind(&StateMachineFAD::Enable, this, _1))
1147 ("");*/
1148
1149 T::AddEvent("CONNECT", FAD::kOffline)
1150 (boost::bind(&StateMachineFAD::Connect, this))
1151 ("");
1152
1153 T::AddEvent("DISCONNECT", FAD::kDisconnected, FAD::kConnecting, FAD::kConnected)
1154 (boost::bind(&StateMachineFAD::Disconnect, this))
1155 ("");
1156
1157 T::AddEvent("FORCE_DISCONNECT", FAD::kDisconnected, FAD::kConnecting, FAD::kConnected)
1158 (boost::bind(&StateMachineFAD::ForceDisconnect, this))
1159 ("");
1160
1161 T::AddEvent("CLOSE_OPEN_FILES", FAD::kConnecting, FAD::kConnected)
1162 (boost::bind(&StateMachineFAD::CloseOpenFiles, this))
1163 ("");
1164
1165 T::AddEvent("TEST", "S:1")
1166 (boost::bind(&StateMachineFAD::Test, this, _1))
1167 ("");
1168
1169 T::AddEvent("ADD_ADDRESS", "C", FAD::kOffline)
1170 (boost::bind(&StateMachineFAD::AddAddress, this, _1))
1171 ("Add the address of a DRS4 board to the first free slot"
1172 "|IP[string]:address in the format <address:port>");
1173 T::AddEvent("REMOVE_SLOT", "S:1", FAD::kOffline)
1174 (boost::bind(&StateMachineFAD::RemoveSlot, this, _1))
1175 ("Remove the Iaddress in slot n. For a list see LIST"
1176 "|slot[int]:Remove the address in slot n from the list");
1177 T::AddEvent("LIST_SLOTS")
1178 (boost::bind(&StateMachineFAD::ListSlots, this))
1179 ("Print a list of all available board addressesa and whether they are enabled");
1180 }
1181
1182 ~StateMachineFAD()
1183 {
1184 for (BoardList::const_iterator i=fBoards.begin(); i!=fBoards.end(); i++)
1185 delete i->second.second;
1186 fBoards.clear();
1187 }
1188
1189 tcp::endpoint GetEndpoint(const string &base)
1190 {
1191 const size_t p0 = base.find_first_of(':');
1192 const size_t p1 = base.find_last_of(':');
1193
1194 if (p0==string::npos || p0!=p1)
1195 {
1196 T::Out() << kRed << "GetEndpoint - Wrong format ('host:port' expected)" << endl;
1197 return tcp::endpoint();
1198 }
1199
1200 tcp::resolver resolver(get_io_service());
1201
1202 boost::system::error_code ec;
1203
1204 const tcp::resolver::query query(base.substr(0, p0), base.substr(p0+1));
1205 const tcp::resolver::iterator iterator = resolver.resolve(query, ec);
1206
1207 if (ec)
1208 {
1209 T::Out() << kRed << "GetEndpoint - Couldn't resolve endpoint '" << base << "': " << ec.message();
1210 return tcp::endpoint();
1211 }
1212
1213 return *iterator;
1214 }
1215
1216 bool SetConfiguration(const Configuration &conf)
1217 {
1218 fIsVerbose = !conf.Get<bool>("quiet");
1219 fIsHexOutput = conf.Get<bool>("hex-out");
1220 fIsDataOutput = conf.Get<bool>("data-out");
1221
1222 SetMaxMemory(conf.Get<unsigned int>("max-mem"));
1223
1224 // vvvvv for debugging vvvvv
1225 if (conf.Has("debug-addr"))
1226 {
1227 const string addr = conf.Get<string>("debug-addr");
1228 const int num = conf.Get<unsigned int>("debug-num");
1229
1230 const tcp::endpoint endpoint = GetEndpoint(addr);
1231 if (endpoint==tcp::endpoint())
1232 return false;
1233
1234 for (int i=0; i<num; i++)
1235 AddEndpoint(tcp::endpoint(endpoint.address(), endpoint.port()+8*i));
1236
1237 Connect();
1238 return true;
1239 }
1240 // ^^^^^ for debugging ^^^^^
1241
1242 if (!(conf.Has("base-addr") ^ conf.Has("addr")))
1243 {
1244 T::Out() << kRed << "SetConfiguration - Only --base-addr or --addr allowed." << endl;
1245 return false;
1246 }
1247
1248 if (conf.Has("base-addr"))
1249 {
1250 const string base = conf.Get<string>("base-addr");
1251
1252 const tcp::endpoint endpoint = GetEndpoint(base);
1253 if (endpoint==tcp::endpoint())
1254 return false;
1255
1256 const ba::ip::address_v4::bytes_type ip = endpoint.address().to_v4().to_bytes();
1257
1258 if (ip[2]>250 || ip[3]>244)
1259 {
1260 T::Out() << kRed << "SetConfiguration - IP address given by --base-addr out-of-range." << endl;
1261 return false;
1262 }
1263
1264 for (int crate=0; crate<4; crate++)
1265 for (int board=0; board<10; board++)
1266 {
1267 ba::ip::address_v4::bytes_type target = endpoint.address().to_v4().to_bytes();
1268 target[2] += crate;
1269 target[3] += board;
1270
1271 AddEndpoint(tcp::endpoint(ba::ip::address_v4(target), endpoint.port()));
1272 }
1273 }
1274
1275 if (conf.Has("addr"))
1276 {
1277 const vector<string> addrs = conf.Get<vector<string>>("addr");
1278 for (vector<string>::const_iterator i=addrs.begin(); i<addrs.end(); i++)
1279 {
1280 const tcp::endpoint endpoint = GetEndpoint(*i);
1281 if (endpoint==tcp::endpoint())
1282 return false;
1283
1284 AddEndpoint(endpoint);
1285 }
1286 }
1287
1288 Connect();
1289
1290 return true;
1291 }
1292
1293};
1294
1295// ------------------------------------------------------------------------
1296
1297
1298void RunThread(StateMachineImp *io_service)
1299{
1300 // This is necessary so that the StateMachien Thread can signal the
1301 // Readline to exit
1302 io_service->Run();
1303 Readline::Stop();
1304}
1305
1306template<class S>
1307int RunDim(Configuration &conf)
1308{
1309 /*
1310 initscr(); // Start curses mode
1311 cbreak(); // Line buffering disabled, Pass on
1312 intrflush(stdscr, FALSE);
1313 start_color(); // Initialize ncurses colors
1314 use_default_colors(); // Assign terminal default colors to -1
1315 for (int i=1; i<8; i++)
1316 init_pair(i, i, -1); // -1: def background
1317 scrollok(stdscr, true);
1318 */
1319
1320 WindowLog wout;
1321
1322 ReadlineColor::PrintBootMsg(wout, conf.GetName(), false);
1323
1324 //log.SetWindow(stdscr);
1325 if (conf.Has("log"))
1326 if (!wout.OpenLogFile(conf.Get<string>("log")))
1327 wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
1328
1329 // Start io_service.Run to use the StateMachineImp::Run() loop
1330 // Start io_service.run to only use the commandHandler command detaching
1331 StateMachineFAD<S> io_service(wout);
1332 if (!io_service.SetConfiguration(conf))
1333 return -1;
1334
1335 io_service.Run();
1336
1337 return 0;
1338}
1339
1340template<class T, class S>
1341int RunShell(Configuration &conf)
1342{
1343 static T shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
1344
1345 WindowLog &win = shell.GetStreamIn();
1346 WindowLog &wout = shell.GetStreamOut();
1347
1348 if (conf.Has("log"))
1349 if (!wout.OpenLogFile(conf.Get<string>("log")))
1350 win << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
1351
1352 StateMachineFAD<S> io_service(wout);
1353 if (!io_service.SetConfiguration(conf))
1354 return -1;
1355
1356 shell.SetReceiver(io_service);
1357
1358 boost::thread t(boost::bind(RunThread, &io_service));
1359 //boost::thread t(boost::bind(&StateMachineFAD<S>::Run, &io_service));
1360
1361 shell.Run(); // Run the shell
1362 io_service.Stop(); // Signal Loop-thread to stop
1363
1364 // Wait until the StateMachine has finished its thread
1365 // before returning and destroying the dim objects which might
1366 // still be in use.
1367 t.join();
1368
1369 return 0;
1370}
1371
1372void SetupConfiguration(Configuration &conf)
1373{
1374 const string n = conf.GetName()+".log";
1375
1376 po::options_description config("Program options");
1377 config.add_options()
1378 ("dns", var<string>("localhost"), "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
1379 ("log,l", var<string>(n), "Write log-file")
1380 ("no-dim,d", po_switch(), "Disable dim services")
1381 ("console,c", var<int>(), "Use console (0=shell, 1=simple buffered, X=simple unbuffered)")
1382 ;
1383
1384 po::options_description control("FAD control options");
1385 control.add_options()
1386 ("quiet,q", po_bool(), "Disable printing contents of all received messages in clear text.")
1387 ("hex-out", po_bool(), "Enable printing contents of all printed messages also as hex data.")
1388 ("data-out", po_bool(), "Enable printing received event data.")
1389 ;
1390
1391 po::options_description builder("Event builder options");
1392 builder.add_options()
1393 ("max-mem,m", var<unsigned int>(100), "Maximum memory the event builder thread is allowed to consume for its event buffer")
1394 ;
1395
1396 po::options_description connect("FAD connection options");
1397 connect.add_options()
1398 ("addr", vars<string>(), "Network address of FAD")
1399 ("base-addr", var<string>(), "Base address of all FAD")
1400 ("debug-num,n", var<unsigned int>(40), "Sets the number of fake boards to be connected locally")
1401 ("debug-addr", var<string>(), "")
1402 ;
1403
1404 conf.AddEnv("dns", "DIM_DNS_NODE");
1405
1406 conf.AddOptions(config);
1407 conf.AddOptions(control);
1408 conf.AddOptions(builder);
1409 conf.AddOptions(connect);
1410}
1411
1412void PrintUsage()
1413{
1414 cout <<
1415 "The fadctrl controls the FAD boards.\n"
1416 "\n"
1417 "The default is that the program is started without user intercation. "
1418 "All actions are supposed to arrive as DimCommands. Using the -c "
1419 "option, a local shell can be initialized. With h or help a short "
1420 "help message about the usuage can be brought to the screen.\n"
1421 "\n"
1422 "Usage: fadctrl [-c type] [OPTIONS]\n"
1423 " or: fadctrl [OPTIONS]\n";
1424 cout << endl;
1425}
1426
1427void PrintHelp()
1428{
1429 /* Additional help text which is printed after the configuration
1430 options goes here */
1431}
1432
1433int main(int argc, const char* argv[])
1434{
1435 Configuration conf(argv[0]);
1436 conf.SetPrintUsage(PrintUsage);
1437 SetupConfiguration(conf);
1438
1439 po::variables_map vm;
1440 try
1441 {
1442 vm = conf.Parse(argc, argv);
1443 }
1444#if BOOST_VERSION > 104000
1445 catch (po::multiple_occurrences &e)
1446 {
1447 cerr << "Program options invalid due to: " << e.what() << " of '" << e.get_option_name() << "'." << endl;
1448 return -1;
1449 }
1450#endif
1451 catch (exception& e)
1452 {
1453 cerr << "Program options invalid due to: " << e.what() << endl;
1454 return -1;
1455 }
1456
1457 if (conf.HasVersion() || conf.HasPrint())
1458 return -1;
1459
1460 if (conf.HasHelp())
1461 {
1462 PrintHelp();
1463 return -1;
1464 }
1465
1466 Dim::Setup(conf.Get<string>("dns"));
1467
1468// try
1469 {
1470 // No console access at all
1471 if (!conf.Has("console"))
1472 {
1473 if (conf.Get<bool>("no-dim"))
1474 return RunDim<StateMachine>(conf);
1475 else
1476 return RunDim<StateMachineDim>(conf);
1477 }
1478 // Cosole access w/ and w/o Dim
1479 if (conf.Get<bool>("no-dim"))
1480 {
1481 if (conf.Get<int>("console")==0)
1482 return RunShell<LocalShell, StateMachine>(conf);
1483 else
1484 return RunShell<LocalConsole, StateMachine>(conf);
1485 }
1486 else
1487 {
1488 if (conf.Get<int>("console")==0)
1489 return RunShell<LocalShell, StateMachineDim>(conf);
1490 else
1491 return RunShell<LocalConsole, StateMachineDim>(conf);
1492 }
1493 }
1494/* catch (std::exception& e)
1495 {
1496 cerr << "Exception: " << e.what() << endl;
1497 return -1;
1498 }*/
1499
1500 return 0;
1501}
Note: See TracBrowser for help on using the repository browser.