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

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