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

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