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

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