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

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