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

Last change on this file since 10780 was 10777, checked in by tbretz, 14 years ago
Fixed boost problem with Ubuntu 11.04
File size: 47.0 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 stringstream 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 stringstream 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 stringstream 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 stringstream 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 stringstream 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 stringstream 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 stringstream 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{
591 boost::thread fThread;
592
593 enum CommandStates_t // g_runStat
594 {
595 kAbort = -2, // quit as soon as possible ('abort')
596 kExit = -1, // stop reading, quit when buffered events done ('exit')
597 kInitialize = 0, // 'initialize' (e.g. dim not yet started)
598 kHybernate = 1, // do nothing for long time ('hybernate') [wakeup within ~1sec]
599 kSleep = 2, // do nothing ('sleep') [wakeup within ~10msec]
600 kModeFlush = 10, // read data from camera, but skip them ('flush')
601 kModeTest = 20, // read data and process them, but do not write to disk ('test')
602 kModeFlag = 30, // read data, process and write all to disk ('flag')
603 kModeRun = 40, // read data, process and write selected to disk ('run')
604 };
605
606 MessageImp &fMsg;
607
608public:
609 EventBuilderWrapper(MessageImp &msg) : fMsg(msg)
610 {
611 Start();
612 }
613
614 void Start()
615 {
616 if (fThread.joinable())
617 {
618 fMsg.Warn("Start - EventBuilder still running");
619 return;
620 }
621
622 fMsg.Message("Initializing EventBuilder");
623 initReadFAD();
624
625 g_runStat = kHybernate;
626 fThread = boost::thread(readFAD, (void*)NULL);
627
628 fMsg.Message("EventBuilder started");
629 }
630 void Abort()
631 {
632 fMsg.Message("Waiting for EventBuilder to abort...");
633 g_runStat = kAbort;
634 fThread.join();
635 fMsg.Message("EventBuilder stopped.");
636 }
637
638 void Exit()
639 {
640 fMsg.Message("Waiting for EventBuilder to exit - be patient...");
641 g_runStat = kExit;
642 }
643
644 void Wait()
645 {
646 fThread.join();
647 fMsg.Message("EventBuilder stopped.");
648 }
649
650 void Hybernate() { g_runStat = kHybernate; }
651 void Sleep() { g_runStat = kSleep; }
652 void FlushMode() { g_runStat = kModeFlush; }
653 void TestMode() { g_runStat = kModeTest; }
654 void FlagMode() { g_runStat = kModeFlag; }
655 void RunMode() { g_runStat = kModeRun; }
656
657 // FIXME: To be removed
658 void SetMode(int mode) { g_runStat = mode; }
659
660 bool IsConnected(int i) const { return gi_NumConnect[i]==7; }
661 bool IsDisconnected(int i) const { return gi_NumConnect[i]==0; }
662 int GetNumConnected(int i) const { return gi_NumConnect[i]; }
663
664 void Restart()
665 {
666 Abort();
667 Start();
668 }
669
670 ~EventBuilderWrapper()
671 {
672 Abort();
673 }
674
675};
676
677// ------------------------------------------------------------------------
678
679template <class T>
680class StateMachineFAD : public T, public EventBuilderWrapper, public ba::io_service, public ba::io_service::work
681{
682private:
683 typedef pair<string, ConnectionFAD*> Connection;
684 typedef pair<const uint8_t, Connection> Board;
685 typedef map<uint8_t, Connection> BoardList;
686
687 BoardList fBoards;
688
689 bool fIsVerbose;
690 bool fIsHexOutput;
691 bool fIsDataOutput;
692
693 bool CheckEventSize(size_t has, const char *name, size_t size)
694 {
695 if (has==size)
696 return true;
697
698 stringstream msg;
699 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
700 T::Fatal(msg);
701 return false;
702 }
703
704 int Cmd(ConnectionFAD::Enable_t command)
705 {
706 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
707 i->second.second->Cmd(command);
708
709 return T::GetCurrentState();
710 }
711
712 int CmdEnable(const EventImp &evt, ConnectionFAD::Enable_t command)
713 {
714 if (!CheckEventSize(evt.GetSize(), "CmdEnable", 1))
715 return T::kSM_FatalError;
716
717 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
718 i->second.second->Cmd(command, evt.GetBool());
719
720 return T::GetCurrentState();
721 }
722
723 bool Check(const uint32_t *dat, uint32_t maxaddr, uint32_t maxval)
724 {
725 if (dat[0]>FAD::kMaxRegAddr)
726 {
727 stringstream msg;
728 msg << hex << "Address " << dat[0] << " out of range, max=" << maxaddr << ".";
729 T::Error(msg);
730 return false;
731 }
732
733 if (dat[1]>FAD::kMaxRegValue)
734 {
735 stringstream msg;
736 msg << hex << "Value " << dat[1] << " out of range, max=" << maxval << ".";
737 T::Error(msg);
738 return false;
739 }
740
741 return true;
742 }
743
744 int SetRegister(const EventImp &evt)
745 {
746 if (!CheckEventSize(evt.GetSize(), "SetRegister", 8))
747 return T::kSM_FatalError;
748
749 const uint32_t *dat = reinterpret_cast<const uint32_t*>(evt.GetData());
750
751 if (!Check(dat, FAD::kMaxRegAddr, FAD::kMaxRegValue))
752 return T::GetCurrentState();
753
754 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
755 i->second.second->CmdSetRegister(dat[0], dat[1]);
756
757 return T::GetCurrentState();
758 }
759
760 int SetRoi(const EventImp &evt)
761 {
762 if (!CheckEventSize(evt.GetSize(), "SetRoi", 8))
763 return T::kSM_FatalError;
764
765 // ---- was uint32_t
766 const int32_t *dat = reinterpret_cast<const int32_t*>(evt.GetData());
767
768 // ---- -1 for all
769 //if (!Check(dat, FAD::kMaxRoiAddr, FAD::kMaxRoiValue))
770 // return T::GetCurrentState();
771
772 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
773 i->second.second->CmdSetRoi(dat[0], dat[1]);
774
775 return T::GetCurrentState();
776 }
777
778 int SetDac(const EventImp &evt)
779 {
780 if (!CheckEventSize(evt.GetSize(), "SetDac", 8))
781 return T::kSM_FatalError;
782
783 const uint32_t *dat = reinterpret_cast<const uint32_t*>(evt.GetData());
784
785 if (!Check(dat, FAD::kMaxDacAddr, FAD::kMaxDacValue))
786 return T::GetCurrentState();
787
788 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
789 i->second.second->CmdSetDacValue(dat[0], dat[1]);
790
791 return T::GetCurrentState();
792 }
793
794 int Trigger(int n)
795 {
796 for (int nn=0; nn<n; nn++)
797 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
798 i->second.second->Cmd(ConnectionFAD::kCmdSingleTrigger);
799
800 return T::GetCurrentState();
801 }
802
803 int SendTriggers(const EventImp &evt)
804 {
805 if (!CheckEventSize(evt.GetSize(), "SendTriggers", 4))
806 return T::kSM_FatalError;
807
808 Trigger(evt.GetUInt());
809
810 return T::GetCurrentState();
811 }
812
813 int StartRun(const EventImp &evt, bool start)
814 {
815 if (!CheckEventSize(evt.GetSize(), "StartRun", 0))
816 return T::kSM_FatalError;
817
818 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
819 i->second.second->Cmd(ConnectionFAD::kCmdRun, start);
820
821 return T::GetCurrentState();
822 }
823
824 int PhaseShift(const EventImp &evt)
825 {
826 if (!CheckEventSize(evt.GetSize(), "PhaseShift", 2))
827 return T::kSM_FatalError;
828
829 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
830 i->second.second->CmdPhaseShift(evt.GetShort());
831
832 return T::GetCurrentState();
833 }
834
835 int SetTriggerRate(const EventImp &evt)
836 {
837 if (!CheckEventSize(evt.GetSize(), "SetTriggerRate", 4))
838 return T::kSM_FatalError;
839
840 if (evt.GetUShort()>0xff)
841 {
842 stringstream msg;
843 msg << hex << "Value " << evt.GetUShort() << " out of range, max=" << 0xff << "(?)";
844 T::Error(msg);
845 return false;
846 }
847
848 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
849 i->second.second->CmdSetTriggerRate(evt.GetUInt());
850
851 return T::GetCurrentState();
852 }
853
854 int Test(const EventImp &evt)
855 {
856 if (!CheckEventSize(evt.GetSize(), "Test", 2))
857 return T::kSM_FatalError;
858
859
860 SetMode(evt.GetShort());
861
862 return T::GetCurrentState();
863 }
864
865
866 int SetVerbosity(const EventImp &evt)
867 {
868 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
869 return T::kSM_FatalError;
870
871 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
872 i->second.second->SetVerbose(evt.GetText()[0]!=0);
873
874 return T::GetCurrentState();
875 }
876
877 int SetHexOutput(const EventImp &evt)
878 {
879 if (!CheckEventSize(evt.GetSize(), "SetHexOutput", 1))
880 return T::kSM_FatalError;
881
882 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
883 i->second.second->SetHexOutput(evt.GetText()[0]!=0);
884
885 return T::GetCurrentState();
886 }
887
888 int SetDataOutput(const EventImp &evt)
889 {
890 if (!CheckEventSize(evt.GetSize(), "SetDataOutput", 1))
891 return T::kSM_FatalError;
892
893 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
894 i->second.second->SetDataOutput(evt.GetText()[0]!=0);
895
896 return T::GetCurrentState();
897 }
898
899 const BoardList::iterator GetSlot(int slot)
900 {
901 const BoardList::iterator i = fBoards.find(slot);
902 if (i!=fBoards.end())
903 return i;
904
905 ostringstream str;
906 str << "Slot " << slot << " not found.";
907 T::Warn(str.str());
908 return fBoards.end();
909 }
910
911 int AddAddress(const EventImp &evt)
912 {
913 const string addr = Tools::Trim(evt.GetText());
914
915 for (BoardList::const_iterator i=fBoards.begin(); i!=fBoards.end(); i++)
916 {
917 if (i->second.first==addr)
918 {
919 T::Warn("Address "+addr+" already known.... ignored.");
920 return T::GetCurrentState();
921 }
922 }
923
924 AddEndpoint(addr);
925
926 return T::GetCurrentState();
927 }
928
929 int RemoveSlot(const EventImp &evt)
930 {
931 if (!CheckEventSize(evt.GetSize(), "RemoveSlot", 2))
932 return T::kSM_FatalError;
933
934 const int16_t slot = evt.GetShort();
935
936 const BoardList::iterator v = GetSlot(slot);
937 if (v!=fBoards.end())
938 {
939 delete v->second.second;
940 fBoards.erase(v);
941 }
942
943 return T::GetCurrentState();
944 }
945
946 int ListSlots()
947 {
948 for (BoardList::const_iterator i=fBoards.begin(); i!=fBoards.end(); i++)
949 {
950 ostringstream str;
951 str << "Slot " << setw(2) << (int)i->first << ": " << i->second.first;
952
953 const ConnectionFAD *c = i->second.second;
954
955 if (c->IsConnecting())
956 str << " (0:connecting, ";
957 else
958 {
959 if (c->IsClosed())
960 str << " (0:disconnected, ";
961 if (c->IsConnected())
962 str << " (0:connected, ";
963 }
964
965 switch (fStatus2[i->first])
966 {
967 case 0: str << "1-7:disconnected)"; break;
968 case 1: str << "1-7:connecting [" << GetNumConnected(i->first) << "])"; break;
969 case 2: str << "1-7:connected)"; break;
970 }
971
972 T::Message(str.str());
973 }
974
975 return T::GetCurrentState();
976 }
977
978 void EnableSlot(BoardList::iterator i, bool enable=true)
979 {
980 if (i==fBoards.end())
981 return;
982
983 ConnectionFAD* &ptr = i->second.second;
984
985 if (!enable)
986 ptr->PostClose(false);
987 else
988 {
989 ptr->SetEndpoint(i->second.first);
990 ptr->StartConnect();
991 }
992 }
993
994 void EnableAll(bool enable=true)
995 {
996 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
997 EnableSlot(i, enable);
998 }
999
1000 /*
1001 int Enable(const EventImp &evt)
1002 {
1003 if (!CheckEventSize(evt.GetSize(), "Enable", 3))
1004 return T::kSM_FatalError;
1005
1006 const int16_t slot = evt.GetShort();
1007 const bool enable = evt.GetText()[2]>0;
1008
1009 if (slot<0)
1010 {
1011 EnableAll(enable);
1012 return T::GetCurrentState();
1013 }
1014
1015 EnableSlot(GetSlot(slot), enable);
1016
1017 return T::GetCurrentState();
1018 }*/
1019
1020 int Disconnect()
1021 {
1022 Exit();
1023 EnableAll(false);
1024 return T::GetCurrentState();
1025 }
1026
1027 int Connect()
1028 {
1029 T::Error("FIXME - Propagate IP Addresses to EventBuilder");
1030
1031 Start();
1032 EnableAll(true);
1033
1034 return T::GetCurrentState();
1035 }
1036
1037 /*
1038 int Reconnect(const EventImp &evt)
1039 {
1040 if (!CheckEventSize(evt.GetSize(), "Reconnect", 2))
1041 return T::kSM_FatalError;
1042
1043 const int16_t slot = evt.GetShort();
1044
1045 if (slot<0)
1046 {
1047 // Close all connections to supress the warning in SetEndpoint
1048 for (BoardList::const_iterator i=fBoards.begin(); i!=fBoards.end(); i++)
1049 i->second.second->PostClose(false);
1050
1051 // Now wait until all connection have been closed and
1052 // all pending handlers have been processed
1053 poll();
1054
1055 // Now we can reopen the connection
1056 for (BoardList::const_iterator i=fBoards.begin(); i!=fBoards.end(); i++)
1057 i->second.second->PostClose(true);
1058
1059 return T::GetCurrentState();
1060 }
1061
1062 const BoardList::const_iterator v = GetSlot(slot);
1063 if (v==fBoards.end())
1064 return T::GetCurrentState();
1065
1066 // Close all connections to supress the warning in SetEndpoint
1067 v->second.second->PostClose(false);
1068
1069 // Now wait until all connection have been closed and
1070 // all pending handlers have been processed
1071 poll();
1072
1073 // Now we can reopen the connection
1074 v->second.second->PostClose(true);
1075
1076 return T::GetCurrentState();
1077 }*/
1078
1079 virtual void UpdateConnectionStatus()
1080 {
1081 //cout << "Connection Status changed prop to Dim." << endl;
1082 }
1083
1084 vector<char> fStatus1;
1085 vector<char> fStatus2;
1086
1087 int Execute()
1088 {
1089 // Dispatch (execute) at most one handler from the queue. In contrary
1090 // to run_one(), it doesn't wait until a handler is available
1091 // which can be dispatched, so poll_one() might return with 0
1092 // handlers dispatched. The handlers are always dispatched/executed
1093 // synchronously, i.e. within the call to poll_one()
1094 poll_one();
1095
1096 // ===== Evaluate connection status =====
1097
1098 uint16_t nconnecting1 = 0;
1099 uint16_t nconnecting2 = 0;
1100 uint16_t nconnected1 = 0;
1101 uint16_t nconnected2 = 0;
1102
1103 vector<char> stat1(40);
1104 vector<char> stat2(40);
1105 for (BoardList::const_iterator i=fBoards.begin(); i!=fBoards.end(); i++)
1106 {
1107 const ConnectionFAD &c = *i->second.second;
1108
1109 const int &idx = i->first;
1110
1111 // FIXME: There is a difference between
1112 // "connecting" and "disconnected"
1113
1114 // Check conistency eb/fadctrl
1115
1116 // ----- Command socket -----
1117 if (c.IsConnecting())
1118 {
1119 stat1[idx] = 1;
1120 nconnecting1++;
1121 }
1122 if (c.IsConnected())
1123 {
1124 stat1[idx] = 2;
1125 nconnected1++;
1126 }
1127
1128 // ----- Event builder -----
1129 if (!IsConnected(idx) && !IsDisconnected(idx))
1130 {
1131 stat2[idx] = 1;
1132 nconnecting2++;
1133 }
1134
1135 if (IsConnected(idx))
1136 {
1137 stat2[idx] = 2;
1138 nconnected2++;
1139 }
1140 }
1141
1142 // ===== Send connection status via dim =====
1143
1144 if (fStatus1!=stat1 || fStatus2!=stat2)
1145 {
1146 fStatus1 = stat1;
1147 fStatus2 = stat2;
1148 UpdateConnectionStatus();
1149 }
1150
1151 // ===== Return connection status =====
1152
1153 if (nconnected1==fBoards.size() && nconnected2==fBoards.size())
1154 return FAD::kConnected;
1155
1156 if (nconnected1==0 && nconnected2==0)
1157 return FAD::kDisconnected;
1158
1159 // FIXME: Evaluate event builder status
1160 return FAD::kConnecting;
1161 }
1162
1163 void AddEndpoint(const string &addr)
1164 {
1165 if (fBoards.size()==40)
1166 {
1167 T::Warn("Not more than 40 slots allowed.");
1168 return;
1169 }
1170
1171 int i=0;
1172 while (1)
1173 {
1174 const BoardList::const_iterator v = fBoards.find(i);
1175 if (v==fBoards.end())
1176 break;
1177 i++;
1178 }
1179
1180 fBoards[i] = make_pair(addr, new ConnectionFAD(*this, *this));
1181 fBoards[i].second->SetVerbose(fIsVerbose);
1182 fBoards[i].second->SetHexOutput(fIsHexOutput);
1183 fBoards[i].second->SetDataOutput(fIsDataOutput);
1184 }
1185
1186
1187
1188public:
1189 StateMachineFAD(ostream &out=cout) :
1190 T(out, "FAD_CONTROL"), EventBuilderWrapper(static_cast<MessageImp&>(*this)), ba::io_service::work(static_cast<ba::io_service&>(*this)),
1191 fStatus1(40), fStatus2(40)
1192 {
1193 // ba::io_service::work is a kind of keep_alive for the loop.
1194 // It prevents the io_service to go to stopped state, which
1195 // would prevent any consecutive calls to run()
1196 // or poll() to do nothing. reset() could also revoke to the
1197 // previous state but this might introduce some overhead of
1198 // deletion and creation of threads and more.
1199
1200 // State names
1201 T::AddStateName(FAD::kDisconnected, "Disconnected",
1202 "All enabled FAD boards are disconnected.");
1203
1204 T::AddStateName(FAD::kConnected, "Connected",
1205 "All enabled FAD boards are connected..");
1206
1207 T::AddStateName(FAD::kConnecting, "Connecting",
1208 "Only some enabled FAD boards are connected.");
1209
1210 // FAD Commands
1211 T::AddEvent("ENABLE_SRCLK", "B:1")
1212 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, ConnectionFAD::kCmdSrclk))
1213 ("Set SRCLK");
1214 T::AddEvent("ENABLE_SCLK", "B:1")
1215 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, ConnectionFAD::kCmdSclk))
1216 ("Set SCLK");
1217 T::AddEvent("ENABLE_DRS", "B:1")
1218 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, ConnectionFAD::kCmdDrsEnable))
1219 ("Switch Domino wave");
1220 T::AddEvent("ENABLE_DWRITE", "B:1")
1221 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, ConnectionFAD::kCmdDwrite))
1222 ("Set Dwrite (possibly high / always low)");
1223 T::AddEvent("SET_DEBUG_MODE", "B:1")
1224 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, ConnectionFAD::kCmdSocket))
1225 ("Set debug mode (yes: dump events through command socket, no=dump events through other sockets)");
1226 T::AddEvent("ENABLE_TRIGGER_LINE", "B:1")
1227 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, ConnectionFAD::kCmdTriggerLine))
1228 ("Incoming triggers can be accepted/will not be accepted");
1229 T::AddEvent("SET_TRIGGER_RATE", "I:1")
1230 (boost::bind(&StateMachineFAD::SetTriggerRate, this, _1))
1231 ("Enable continous trigger");
1232 T::AddEvent("SEND_SINGLE_TRIGGER")
1233 (boost::bind(&StateMachineFAD::Trigger, this, 1))
1234 ("Issue software triggers");
1235 T::AddEvent("SEND_N_TRIGGERS", "I")
1236 (boost::bind(&StateMachineFAD::SendTriggers, this, _1))
1237 ("Issue software triggers");
1238 T::AddEvent("START", "")
1239 (boost::bind(&StateMachineFAD::StartRun, this, _1, true))
1240 ("Set FAD DAQ mode. when started, no configurations must be send.");
1241 T::AddEvent("STOP")
1242 (boost::bind(&StateMachineFAD::StartRun, this, _1, false))
1243 ("");
1244 T::AddEvent("PHASE_SHIFT", "S:1")
1245 (boost::bind(&StateMachineFAD::PhaseShift, this, _1))
1246 ("Adjust ADC phase (in 'steps')");
1247
1248 T::AddEvent("CONTINOUS_TRIGGER_ON")
1249 (boost::bind(&StateMachineFAD::Cmd, this, ConnectionFAD::kCmdContTriggerOn))
1250 ("");
1251 T::AddEvent("CONTINOUS_TRIGGER_OFF")
1252 (boost::bind(&StateMachineFAD::Cmd, this, ConnectionFAD::kCmdContTriggerOff))
1253 ("");
1254
1255 T::AddEvent("RESET_TRIGGER_ID")
1256 (boost::bind(&StateMachineFAD::Cmd, this, ConnectionFAD::kCmdResetTriggerId))
1257 ("");
1258
1259 T::AddEvent("SET_REGISTER", "I:2")
1260 (boost::bind(&StateMachineFAD::SetRegister, this, _1))
1261 ("set register to value"
1262 "|addr[short]:Address of register"
1263 "|val[short]:Value to be set");
1264
1265 // FIXME: Maybe add a mask which channels should be set?
1266 T::AddEvent("SET_REGION_OF_INTEREST", "I:2")
1267 (boost::bind(&StateMachineFAD::SetRoi, this, _1))
1268 ("Set region-of-interest to value"
1269 "|addr[short]:Address of register"
1270 "|val[short]:Value to be set");
1271
1272 // FIXME: Maybe add a mask which channels should be set?
1273 T::AddEvent("SET_DAC_VALUE", "I:2")
1274 (boost::bind(&StateMachineFAD::SetDac, this, _1))
1275 ("Set DAC numbers in range to value"
1276 "|addr[short]:Address of register"
1277 "|val[short]:Value to be set");
1278
1279 // Verbosity commands
1280 T::AddEvent("SET_VERBOSE", "B")
1281 (boost::bind(&StateMachineFAD::SetVerbosity, this, _1))
1282 ("set verbosity state"
1283 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
1284
1285 T::AddEvent("SET_HEX_OUTPUT", "B")
1286 (boost::bind(&StateMachineFAD::SetHexOutput, this, _1))
1287 ("enable or disable hex output for received data"
1288 "|hexout[bool]:disable or enable hex output for received data (yes/no)");
1289
1290 T::AddEvent("SET_DATA_OUTPUT", "B")
1291 (boost::bind(&StateMachineFAD::SetDataOutput, this, _1))
1292 ("");
1293
1294 // Conenction commands
1295 /*
1296 T::AddEvent("ENABLE", "S:1;B:1", FAD::kDisconnected)
1297 (boost::bind(&StateMachineFAD::Enable, this, _1))
1298 ("");*/
1299
1300 T::AddEvent("CONNECT", FAD::kDisconnected)
1301 (boost::bind(&StateMachineFAD::Connect, this))
1302 ("");
1303
1304 T::AddEvent("DISCONNECT")
1305 (boost::bind(&StateMachineFAD::Disconnect, this))
1306 ("");
1307
1308 T::AddEvent("TEST", "S:1")
1309 (boost::bind(&StateMachineFAD::Test, this, _1))
1310 ("");
1311
1312 T::AddEvent("ADD_ADDRESS", "C", FAD::kDisconnected)
1313 (boost::bind(&StateMachineFAD::AddAddress, this, _1))
1314 ("Add the address of a DRS4 board to the first free slot"
1315 "|IP[string]:address in the format <address:port>");
1316 T::AddEvent("REMOVE_SLOT", "S:1", FAD::kDisconnected)
1317 (boost::bind(&StateMachineFAD::RemoveSlot, this, _1))
1318 ("Remove the Iaddress in slot n. For a list see LIST"
1319 "|slot[int]:Remove the address in slot n from the list");
1320 T::AddEvent("LIST_SLOTS")
1321 (boost::bind(&StateMachineFAD::ListSlots, this))
1322 ("Print a list of all available board addressesa and whether they are enabled");
1323 }
1324
1325 ~StateMachineFAD()
1326 {
1327 for (BoardList::const_iterator i=fBoards.begin(); i!=fBoards.end(); i++)
1328 delete i->second.second;
1329 fBoards.clear();
1330 }
1331
1332 bool SetConfiguration(const Configuration &conf)
1333 {
1334 fIsVerbose = !conf.Get<bool>("quiet");
1335 fIsHexOutput = conf.Get<bool>("hex-out");
1336 fIsDataOutput = conf.Get<bool>("data-out");
1337
1338 if (!(conf.Has("base-addr") ^ conf.Has("addr")))
1339 {
1340 T::Out() << kRed << "SetConfiguration - Only --base-addr or --addr allowed." << endl;
1341 return false;
1342 }
1343
1344 if (conf.Has("base-addr"))
1345 {
1346 const string base = conf.Get<string>("base-addr");
1347
1348 const size_t p0 = base.find_first_of(':');
1349 const size_t p1 = base.find_last_of(':');
1350
1351 if (p0==string::npos || p0!=p1)
1352 {
1353 T::Out() << kRed << "SetConfiguration - Wrong format of argument --base-addr ('host:port' expected)" << endl;
1354 return false;
1355 }
1356
1357 tcp::resolver resolver(get_io_service());
1358
1359 boost::system::error_code ec;
1360
1361 const tcp::resolver::query query(base.substr(0, p0), base.substr(p0+1));
1362 const tcp::resolver::iterator iterator = resolver.resolve(query, ec);
1363
1364 if (ec)
1365 {
1366 T::Out() << " " << ec.message() << " (" << ec << ")";
1367 return false;
1368 }
1369
1370 const tcp::endpoint endpoint = *iterator;
1371
1372 const ba::ip::address_v4::bytes_type ip = endpoint.address().to_v4().to_bytes();
1373
1374 if (ip[2]>250 || ip[3]>244)
1375 {
1376 T::Out() << kRed << "SetConfiguration - IP address given by --base-addr out-of-range." << endl;
1377 return false;
1378 }
1379
1380 for (int crate=0; crate<2; crate++)
1381 for (int board=0; board<10; board++)
1382 {
1383 //if (crate==0 && board==2)
1384 // continue;
1385
1386 ostringstream str;
1387 str << (int)ip[0] << "." << (int)ip[1] << ".";
1388 str << (int)(ip[2]+crate) << "." << (int)(ip[3]+board) << ":";
1389 str << endpoint.port();
1390
1391 AddEndpoint(str.str());
1392 }
1393 }
1394
1395 if (conf.Has("addr"))
1396 {
1397 const vector<string> addrs = conf.Get<vector<string>>("addr");
1398 for (vector<string>::const_iterator i=addrs.begin(); i<addrs.end(); i++)
1399 AddEndpoint(*i);
1400 }
1401
1402 EnableAll();
1403
1404 return true;
1405 }
1406
1407};
1408
1409// ------------------------------------------------------------------------
1410
1411
1412void RunThread(StateMachineImp *io_service)
1413{
1414 // This is necessary so that the StateMachien Thread can signal the
1415 // Readline to exit
1416 io_service->Run();
1417 Readline::Stop();
1418}
1419
1420template<class S>
1421int RunDim(Configuration &conf)
1422{
1423 /*
1424 initscr(); // Start curses mode
1425 cbreak(); // Line buffering disabled, Pass on
1426 intrflush(stdscr, FALSE);
1427 start_color(); // Initialize ncurses colors
1428 use_default_colors(); // Assign terminal default colors to -1
1429 for (int i=1; i<8; i++)
1430 init_pair(i, i, -1); // -1: def background
1431 scrollok(stdscr, true);
1432 */
1433
1434 WindowLog wout;
1435
1436 //log.SetWindow(stdscr);
1437 if (conf.Has("log"))
1438 if (!wout.OpenLogFile(conf.Get<string>("log")))
1439 wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
1440
1441 // Start io_service.Run to use the StateMachineImp::Run() loop
1442 // Start io_service.run to only use the commandHandler command detaching
1443 StateMachineFAD<S> io_service(wout);
1444 if (!io_service.SetConfiguration(conf))
1445 return -1;
1446
1447 io_service.Run();
1448
1449 return 0;
1450}
1451
1452template<class T, class S>
1453int RunShell(Configuration &conf)
1454{
1455 static T shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
1456
1457 WindowLog &win = shell.GetStreamIn();
1458 WindowLog &wout = shell.GetStreamOut();
1459
1460 if (conf.Has("log"))
1461 if (!wout.OpenLogFile(conf.Get<string>("log")))
1462 win << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
1463
1464 StateMachineFAD<S> io_service(wout);
1465 if (!io_service.SetConfiguration(conf))
1466 return -1;
1467
1468 shell.SetReceiver(io_service);
1469
1470 boost::thread t(boost::bind(RunThread, &io_service));
1471 //boost::thread t(boost::bind(&StateMachineFAD<S>::Run, &io_service));
1472
1473 shell.Run(); // Run the shell
1474 io_service.Stop(); // Signal Loop-thread to stop
1475
1476 // Wait until the StateMachine has finished its thread
1477 // before returning and destroying the dim objects which might
1478 // still be in use.
1479 t.join();
1480
1481 return 0;
1482}
1483
1484void SetupConfiguration(Configuration &conf)
1485{
1486 const string n = conf.GetName()+".log";
1487
1488 po::options_description config("Program options");
1489 config.add_options()
1490 ("dns", var<string>("localhost"), "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
1491 ("log,l", var<string>(n), "Write log-file")
1492 ("no-dim,d", po_switch(), "Disable dim services")
1493 ("console,c", var<int>(), "Use console (0=shell, 1=simple buffered, X=simple unbuffered)")
1494 ;
1495
1496 po::options_description control("FTM control options");
1497 control.add_options()
1498// ("addr,a", var<string>("localhost:5000"), "Network address of FTM")
1499 ("quiet,q", po_bool(), "Disable printing contents of all received messages in clear text.")
1500 ("hex-out", po_bool(), "Enable printing contents of all printed messages also as hex data.")
1501 ("data-out", po_bool(), "Enable printing received event data.")
1502 ("addr", vars<string>(), "Network address of FAD")
1503 ("base-addr", var<string>(), "Base address of all FAD")
1504 ;
1505
1506 conf.AddEnv("dns", "DIM_DNS_NODE");
1507
1508 conf.AddOptions(config);
1509 conf.AddOptions(control);
1510}
1511
1512void PrintUsage()
1513{
1514 cout <<
1515 "The fadctrl controls the FAD boards.\n"
1516 "\n"
1517 "The default is that the program is started without user intercation. "
1518 "All actions are supposed to arrive as DimCommands. Using the -c "
1519 "option, a local shell can be initialized. With h or help a short "
1520 "help message about the usuage can be brought to the screen.\n"
1521 "\n"
1522 "Usage: fadctrl [-c type] [OPTIONS]\n"
1523 " or: fadctrl [OPTIONS]\n";
1524 cout << endl;
1525}
1526
1527void PrintHelp()
1528{
1529 /* Additional help text which is printed after the configuration
1530 options goes here */
1531}
1532
1533int main(int argc, const char* argv[])
1534{
1535 Configuration conf(argv[0]);
1536 SetupConfiguration(conf);
1537
1538 po::variables_map vm;
1539 try
1540 {
1541 vm = conf.Parse(argc, argv);
1542 }
1543#if BOOST_VERSION > 104000
1544 catch (po::multiple_occurrences &e)
1545 {
1546 cout << "Error: " << e.what() << " of '" << e.get_option_name() << "' option." << endl;
1547 cout << endl;
1548 return -1;
1549 }
1550#endif
1551 catch (std::exception &e)
1552 {
1553 cout << "Error: " << e.what() << endl;
1554 cout << endl;
1555
1556 return -1;
1557 }
1558
1559 if (conf.HasPrint())
1560 return -1;
1561
1562 if (conf.HasVersion())
1563 {
1564 FACT::PrintVersion(argv[0]);
1565 return -1;
1566 }
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.