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

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