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

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