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

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