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

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