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

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