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

Last change on this file since 11421 was 11421, checked in by tbretz, 13 years ago
Fall back from configured to connected as soon as the corresponding run has been opened.
File size: 69.0 KB
Line 
1#include <boost/bind.hpp>
2#include <boost/array.hpp>
3//#include <boost/foreach.hpp>
4#include <boost/asio/error.hpp>
5#include <boost/asio/deadline_timer.hpp>
6#include <boost/date_time/posix_time/posix_time_types.hpp>
7
8#include "Dim.h"
9#include "Event.h"
10#include "Shell.h"
11#include "StateMachineDim.h"
12#include "Connection.h"
13#include "Configuration.h"
14#include "Console.h"
15#include "Converter.h"
16#include "HeadersFAD.h"
17
18#include "tools.h"
19
20#include "DimDescriptionService.h"
21#include "EventBuilderWrapper.h"
22
23namespace ba = boost::asio;
24namespace bs = boost::system;
25
26using ba::ip::tcp;
27
28using namespace std;
29
30// ------------------------------------------------------------------------
31
32class ConnectionFAD : public Connection
33{
34 uint16_t fSlot;
35// tcp::endpoint fEndpoint;
36
37 vector<uint16_t> fBuffer;
38
39protected:
40 FAD::EventHeader fEventHeader;
41 FAD::ChannelHeader fChannelHeader[FAD::kNumChannels];
42
43private:
44 bool fIsVerbose;
45 bool fIsHexOutput;
46 bool fIsDataOutput;
47 bool fBlockTransmission;
48
49 uint64_t fCounter;
50
51 FAD::EventHeader fBufEventHeader;
52 vector<uint16_t> fTargetRoi;
53
54protected:
55 void PrintEventHeader()
56 {
57 Out() << endl << kBold << "Header received (N=" << dec << fCounter << "):" << endl;
58 Out() << fEventHeader;
59 if (fIsHexOutput)
60 Out() << Converter::GetHex<uint16_t>(fEventHeader, 16) << endl;
61 }
62
63 void PrintChannelHeaders()
64 {
65 Out() << dec << endl;
66
67 for (unsigned int c=0; c<FAD::kNumChips; c++)
68 {
69 Out() << "ROI|" << fEventHeader.Crate() << ":" << fEventHeader.Board() << ":" << c << ":";
70 for (unsigned int ch=0; ch<FAD::kNumChannelsPerChip; ch++)
71 Out() << " " << setw(4) << fChannelHeader[c+ch*FAD::kNumChips].fRegionOfInterest;
72 Out() << endl;
73 }
74
75 Out() << "CEL|" << fEventHeader.Crate() << ":" <<fEventHeader.Board() << ": ";
76 for (unsigned int c=0; c<FAD::kNumChips; c++)
77 {
78 if (0)//fIsFullChannelHeader)
79 {
80 for (unsigned int ch=0; ch<FAD::kNumChannelsPerChip; ch++)
81 Out() << " " << setw(4) << fChannelHeader[c+ch*FAD::kNumChips].fStartCell;
82 Out() << endl;
83 }
84 else
85 {
86 Out() << " ";
87 const uint16_t cel = fChannelHeader[c*FAD::kNumChannelsPerChip].fStartCell;
88 for (unsigned int ch=1; ch<FAD::kNumChannelsPerChip; ch++)
89 if (cel!=fChannelHeader[c+ch*FAD::kNumChips].fStartCell)
90 {
91 Out() << "!";
92 break;
93 }
94 Out() << cel;
95 }
96 }
97 Out() << endl;
98
99 if (fIsHexOutput)
100 Out() << Converter::GetHex<uint16_t>(fChannelHeader, 16) << endl;
101
102 }
103
104 virtual void UpdateFirstHeader()
105 {
106 }
107
108 virtual void UpdateEventHeader()
109 {
110 // emit service with trigger counter from header
111 if (fIsVerbose)
112 PrintEventHeader();
113 }
114
115 virtual void UpdateChannelHeaders()
116 {
117 // emit service with trigger counter from header
118 if (fIsVerbose)
119 PrintChannelHeaders();
120
121 }
122
123 virtual void UpdateData(const uint16_t *data, size_t sz)
124 {
125 // emit service with trigger counter from header
126 if (fIsVerbose && fIsDataOutput)
127 Out() << Converter::GetHex<uint16_t>(data, sz, 16, true) << endl;
128 }
129
130private:
131 enum
132 {
133 kReadHeader = 1,
134 kReadData = 2,
135 };
136
137 void HandleReceivedData(const bs::error_code& err, size_t bytes_received, int type)
138 {
139 // Do not schedule a new read if the connection failed.
140 if (bytes_received==0 || err)
141 {
142 if (err==ba::error::eof)
143 Warn("Connection closed by remote host (FAD).");
144
145 // 107: Transport endpoint is not connected (bs::error_code(107, bs::system_category))
146 // 125: Operation canceled
147 if (err && err!=ba::error::eof && // Connection closed by remote host
148 err!=ba::error::basic_errors::not_connected && // Connection closed by remote host
149 err!=ba::error::basic_errors::operation_aborted) // Connection closed by us
150 {
151 ostringstream str;
152 str << "Reading from " << URL() << ": " << err.message() << " (" << err << ")";// << endl;
153 Error(str);
154 }
155 PostClose(err!=ba::error::basic_errors::operation_aborted);
156 return;
157 }
158
159 EventBuilderWrapper::This->debugStream(fSlot*7, fBuffer.data(), bytes_received);
160
161 if (type==kReadHeader)
162 {
163 if (bytes_received!=sizeof(FAD::EventHeader))
164 {
165 ostringstream str;
166 str << "Bytes received (" << bytes_received << " don't match header size " << sizeof(FAD::EventHeader);
167 Error(str);
168 PostClose(false);
169 return;
170 }
171
172 fEventHeader = fBuffer;
173
174 if (fEventHeader.fStartDelimiter!=FAD::kDelimiterStart)
175 {
176 ostringstream str;
177 str << "Invalid header received: start delimiter wrong, received ";
178 str << hex << fEventHeader.fStartDelimiter << ", expected " << FAD::kDelimiterStart << ".";
179 Error(str);
180 PostClose(false);
181 return;
182 }
183
184 if (fCounter==0)
185 UpdateFirstHeader();
186
187 UpdateEventHeader();
188
189 EventBuilderWrapper::This->debugHead(fSlot*7, fEventHeader);
190
191 fBuffer.resize(fEventHeader.fPackageLength-sizeof(FAD::EventHeader)/2);
192 AsyncRead(ba::buffer(fBuffer), kReadData);
193 AsyncWait(fInTimeout, 2000, &Connection::HandleReadTimeout);
194
195 return;
196 }
197
198 fInTimeout.cancel();
199
200 if (ntohs(fBuffer.back())!=FAD::kDelimiterEnd)
201 {
202 ostringstream str;
203 str << "Invalid data received: end delimiter wrong, received ";
204 str << hex << ntohs(fBuffer.back()) << ", expected " << FAD::kDelimiterEnd << ".";
205 Error(str);
206 PostClose(false);
207 return;
208 }
209
210 uint8_t *ptr = reinterpret_cast<uint8_t*>(fBuffer.data());
211 uint8_t *end = ptr + fBuffer.size()*2;
212 for (unsigned int i=0; i<FAD::kNumChannels; i++)
213 {
214 if (ptr+sizeof(FAD::ChannelHeader) > end)
215 {
216 Error("Channel header exceeds buffer size.");
217 PostClose(false);
218 return;
219 }
220
221 fChannelHeader[i] = vector<uint16_t>((uint16_t*)ptr, (uint16_t*)ptr+sizeof(FAD::ChannelHeader)/2);
222 ptr += sizeof(FAD::ChannelHeader);
223
224 //UpdateChannelHeader(i);
225
226 if (ptr+fChannelHeader[i].fRegionOfInterest*2 > end)
227 {
228 Error("Data block exceeds buffer size.");
229 PostClose(false);
230 return;
231 }
232
233 const uint16_t *data = reinterpret_cast<uint16_t*>(ptr);
234 UpdateData(data, fChannelHeader[i].fRegionOfInterest*2);
235 ptr += fChannelHeader[i].fRegionOfInterest*2;
236 }
237
238 if (fIsVerbose)
239 UpdateChannelHeaders();
240
241 fCounter++;
242
243 fBuffer.resize(sizeof(FAD::EventHeader)/2);
244 AsyncRead(ba::buffer(fBuffer), kReadHeader);
245 }
246
247 void HandleReadTimeout(const bs::error_code &error)
248 {
249 if (error==ba::error::basic_errors::operation_aborted)
250 return;
251
252 if (error)
253 {
254 ostringstream str;
255 str << "Read timeout of " << URL() << ": " << error.message() << " (" << error << ")";// << endl;
256 Error(str);
257
258 PostClose();
259 return;
260
261 }
262
263 if (!is_open())
264 {
265 // For example: Here we could schedule a new accept if we
266 // would not want to allow two connections at the same time.
267 return;
268 }
269
270 // Check whether the deadline has passed. We compare the deadline
271 // against the current time since a new asynchronous operation
272 // may have moved the deadline before this actor had a chance
273 // to run.
274 if (fInTimeout.expires_at() > ba::deadline_timer::traits_type::now())
275 return;
276
277 Error("Timeout reading data from "+URL());
278 PostClose();
279 }
280
281 // This is called when a connection was established
282 void ConnectionEstablished()
283 {
284 fBufEventHeader.clear();
285 fBufEventHeader.fEventCounter = 1;
286 fBufEventHeader.fStatus = 0xf000|
287 FAD::EventHeader::kDenable|
288 FAD::EventHeader::kDwrite|
289 FAD::EventHeader::kDcmLocked|
290 FAD::EventHeader::kDcmReady|
291 FAD::EventHeader::kSpiSclk;
292
293 fEventHeader.clear();
294 for (unsigned int i=0; i<FAD::kNumChannels; i++)
295 fChannelHeader[i].clear();
296
297 fCounter = 0;
298
299 fBuffer.resize(sizeof(FAD::EventHeader)/2);
300 AsyncRead(ba::buffer(fBuffer), kReadHeader);
301
302// for (int i=0; i<36; i++)
303// CmdSetRoi(i, 100);
304
305// Cmd(FAD::kCmdTriggerLine, true);
306// Cmd(FAD::kCmdSingleTrigger);
307 }
308
309public:
310 void PostCmd(std::vector<uint16_t> cmd)
311 {
312 if (fBlockTransmission || !IsConnected())
313 return;
314
315#ifdef DEBUG_TX
316 ostringstream msg;
317 msg << "Sending command:" << hex;
318 msg << " 0x" << setw(4) << setfill('0') << cmd[0];
319 msg << " (+ " << cmd.size()-1 << " bytes data)";
320 Message(msg);
321#endif
322 transform(cmd.begin(), cmd.end(), cmd.begin(), htons);
323
324 PostMessage(cmd);
325 }
326
327 void PostCmd(uint16_t cmd)
328 {
329 if (fBlockTransmission || !IsConnected())
330 return;
331
332#ifdef DEBUG_TX
333 ostringstream msg;
334 msg << "Sending command:" << hex;
335 msg << " 0x" << setw(4) << setfill('0') << cmd;
336 Message(msg);
337#endif
338 cmd = htons(cmd);
339 PostMessage(&cmd, sizeof(uint16_t));
340 }
341
342 void PostCmd(uint16_t cmd, uint16_t data)
343 {
344 if (fBlockTransmission || !IsConnected())
345 return;
346
347#ifdef DEBUG_TX
348 ostringstream msg;
349 msg << "Sending command:" << hex;
350 msg << " 0x" << setw(4) << setfill('0') << cmd;
351 msg << " 0x" << setw(4) << setfill('0') << data;
352 Message(msg);
353#endif
354 const uint16_t d[2] = { htons(cmd), htons(data) };
355 PostMessage(d, sizeof(d));
356 }
357
358public:
359 ConnectionFAD(ba::io_service& ioservice, MessageImp &imp, uint16_t slot) :
360 Connection(ioservice, imp()), fSlot(slot),
361 fIsVerbose(false), fIsHexOutput(false), fIsDataOutput(false),
362 fBlockTransmission(false), fCounter(0),
363 fTargetRoi(FAD::kNumChannels)
364 {
365 // Maximum possible needed space:
366 // The full header, all channels with all DRS bins
367 // Two trailing shorts
368 fBuffer.reserve(sizeof(FAD::EventHeader) + FAD::kNumChannels*(sizeof(FAD::ChannelHeader) + FAD::kMaxBins*sizeof(uint16_t)) + 2*sizeof(uint16_t));
369
370 SetLogStream(&imp);
371 }
372
373 void Cmd(FAD::Enable cmd, bool on=true)
374 {
375 switch (cmd)
376 {
377 case FAD::kCmdDrsEnable: fBufEventHeader.Enable(FAD::EventHeader::kDenable, on); break;
378 case FAD::kCmdDwrite: fBufEventHeader.Enable(FAD::EventHeader::kDwrite, on); break;
379 case FAD::kCmdTriggerLine: fBufEventHeader.Enable(FAD::EventHeader::kTriggerLine, on); break;
380 case FAD::kCmdBusy: fBufEventHeader.Enable(FAD::EventHeader::kBusy, on); break;
381 case FAD::kCmdContTrigger: fBufEventHeader.Enable(FAD::EventHeader::kContTrigger, on); break;
382 case FAD::kCmdSocket: fBufEventHeader.Enable(FAD::EventHeader::kSock17, !on); break;
383 default:
384 break;
385 }
386
387 PostCmd(cmd + (on ? 0 : 0x100));
388 }
389
390 // ------------------------------
391
392 // IMPLEMENT: Abs/Rel
393 void CmdPhaseShift(int16_t val)
394 {
395 vector<uint16_t> cmd(abs(val)+2, FAD::kCmdPhaseApply);
396 cmd[0] = FAD::kCmdPhaseReset;
397 cmd[1] = val<0 ? FAD::kCmdPhaseDecrease : FAD::kCmdPhaseIncrease;
398 PostCmd(cmd);
399 }
400
401 bool CmdSetTriggerRate(int32_t val)
402 {
403 if (val<0 || val>0xffff)
404 return false;
405
406 fBufEventHeader.fTriggerGeneratorPrescaler = val;
407 PostCmd(FAD::kCmdWriteRate, val);//uint8_t(1000./val/12.5));
408 //PostCmd(FAD::kCmdWriteExecute);
409
410 return true;
411 }
412
413 void CmdSetRunNumber(uint32_t num)
414 {
415 fBufEventHeader.fRunNumber = num;
416
417 PostCmd(FAD::kCmdWriteRunNumberLSW, num&0xffff);
418 PostCmd(FAD::kCmdWriteRunNumberMSW, num>>16);
419 PostCmd(FAD::kCmdWriteExecute);
420 }
421
422 void CmdSetRegister(uint8_t addr, uint16_t val)
423 {
424 // Allowed addr: [0, MAX_ADDR]
425 // Allowed value: [0, MAX_VAL]
426 PostCmd(FAD::kCmdWrite + addr, val);
427 PostCmd(FAD::kCmdWriteExecute);
428 }
429
430 bool CmdSetDacValue(int8_t addr, uint16_t val)
431 {
432 if (addr<0)
433 {
434 for (unsigned int i=0; i<=FAD::kMaxDacAddr; i++)
435 {
436 fBufEventHeader.fDac[i] = val;
437 PostCmd(FAD::kCmdWriteDac + i, val);
438 }
439 PostCmd(FAD::kCmdWriteExecute);
440 return true;
441 }
442
443 if (uint8_t(addr)>FAD::kMaxDacAddr) // NDAC
444 return false;
445
446 fBufEventHeader.fDac[addr] = val;
447
448 PostCmd(FAD::kCmdWriteDac + addr, val);
449 PostCmd(FAD::kCmdWriteExecute);
450 return true;
451 }
452
453 bool CmdSetRoi(int8_t addr, uint16_t val)
454 {
455 if (val>FAD::kMaxRoiValue)
456 return false;
457
458 if (addr<0)
459 {
460 for (unsigned int i=0; i<=FAD::kMaxRoiAddr; i++)
461 {
462 fTargetRoi[i] = val;
463 PostCmd(FAD::kCmdWriteRoi + i, val);
464 }
465 PostCmd(FAD::kCmdWriteExecute);
466 return true;
467 }
468
469 if (uint8_t(addr)>FAD::kMaxRoiAddr)
470 return false;
471
472 fTargetRoi[addr] = val;
473
474 PostCmd(FAD::kCmdWriteRoi + addr, val);
475 PostCmd(FAD::kCmdWriteExecute);
476 return true;
477 }
478
479 bool CmdSetRoi(uint16_t val) { return CmdSetRoi(-1, val); }
480
481 void AmplitudeCalibration()
482 {
483 // ------------- case baseline -----------------
484
485 CmdSetRoi(-1, FAD::kMaxBins);
486
487 CmdSetDacValue(1, 0);
488 CmdSetDacValue(2, 0);
489 CmdSetDacValue(3, 0);
490
491 // Take N events
492
493 /*
494 // ====== Part B: Baseline calibration =====
495
496 // Loop over all channels(ch) and time-slices (t)
497 T0 = TriggerCell[chip]
498 Sum[ch][(t+T0) % kMaxBins] += Data[ch][t];
499 // FIXME: Determine median instead of average
500
501 Baseline[ch][slice] = MEDIAN( sum[ch][slice] )
502 */
503
504 // --------------- case gain -------------------
505
506 // Set new DAC values and start accumulation
507 CmdSetDacValue(1, 50000);
508 CmdSetDacValue(2, 50000);
509 CmdSetDacValue(3, 50000);
510
511 // Take N events
512
513 /*
514 // ====== Part C: Gain calibration =====
515
516 T0 = TriggerCell[chip]
517 Sum[ch][(t+T0) % kMaxBins] += Data[ch][t];
518 // FIXME: Determine median instead of average
519
520 Gain[ch][slice] = MEDIAN( sum[ch][slice] ) - Baseline[ch][slice]
521 */
522
523 // --------------- secondary ------------------
524
525 // FIXME: Can most probably be done together with the baseline calibration
526 // FIXME: Why does the secondary baseline not influence the baseline?
527
528 CmdSetDacValue(1, 0);
529 CmdSetDacValue(2, 0);
530 CmdSetDacValue(3, 0);
531
532 // Take N events
533
534 /*
535 // ====== Part D: Secondary calibration =====
536
537 T0 = TriggerCell[chip]
538 Sum[ch][t] = Data[ch][t] - Baseline[ch][(i-T0) % kMaxBins];
539
540 // Determine secondary baseline if integration finished
541 SecondaryBaseline[ch][t] = MEDIAN( Sum[ch][t] )
542 */
543 }
544
545 void SetVerbose(bool b)
546 {
547 fIsVerbose = b;
548 }
549
550 void SetHexOutput(bool b)
551 {
552 fIsHexOutput = b;
553 }
554
555 void SetDataOutput(bool b)
556 {
557 fIsDataOutput = b;
558 }
559
560 void SetBlockTransmission(bool b)
561 {
562 fBlockTransmission = b;
563 }
564
565 bool IsTransmissionBlocked() const
566 {
567 return fBlockTransmission;
568 }
569
570 void PrintEvent()
571 {
572 if (fCounter>0)
573 {
574 PrintEventHeader();
575 PrintChannelHeaders();
576 }
577 else
578 Out() << "No event received yet." << endl;
579 }
580
581 bool IsConfigured() const
582 {
583 bool identical = true;
584 for (int i=0; i<FAD::kNumChannels; i++)
585 if (fTargetRoi[i]!=fChannelHeader[i].fRegionOfInterest)
586 {
587 identical = false;
588 break;
589 }
590
591 return fEventHeader==fBufEventHeader && identical;
592 }
593};
594
595// ------------------------------------------------------------------------
596
597template <class T>
598class StateMachineFAD : public T, public EventBuilderWrapper, public ba::io_service, public ba::io_service::work
599{
600private:
601 typedef map<uint8_t, ConnectionFAD*> BoardList;
602
603 BoardList fBoards;
604
605 bool fIsVerbose;
606 bool fIsHexOutput;
607 bool fIsDataOutput;
608 bool fDebugTx;
609
610 bool CheckEventSize(size_t has, const char *name, size_t size)
611 {
612 if (has==size)
613 return true;
614
615 ostringstream msg;
616 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
617 T::Fatal(msg);
618 return false;
619 }
620
621 int Cmd(FAD::Enable command)
622 {
623 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
624 i->second->Cmd(command);
625
626 return T::GetCurrentState();
627 }
628
629 int SendCmd(const EventImp &evt)
630 {
631 if (!CheckEventSize(evt.GetSize(), "SendCmd", 4))
632 return T::kSM_FatalError;
633
634 if (evt.GetUInt()>0xffff)
635 {
636 T::Warn("Command value out of range (0-65535).");
637 return T::GetCurrentState();
638 }
639
640 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
641 i->second->PostCmd(evt.GetUInt());
642
643 return T::GetCurrentState();
644 }
645
646 int SendCmdData(const EventImp &evt)
647 {
648 if (!CheckEventSize(evt.GetSize(), "SendCmdData", 8))
649 return T::kSM_FatalError;
650
651 const uint32_t *ptr = evt.Ptr<uint32_t>();
652
653 if (ptr[0]>0xffff)
654 {
655 T::Warn("Command value out of range (0-65535).");
656 return T::GetCurrentState();
657 }
658
659 if (ptr[1]>0xffff)
660 {
661 T::Warn("Data value out of range (0-65535).");
662 return T::GetCurrentState();
663 }
664
665 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
666 i->second->PostCmd(ptr[0], ptr[1]);
667
668 return T::GetCurrentState();
669 }
670
671 int CmdEnable(const EventImp &evt, FAD::Enable command)
672 {
673 if (!CheckEventSize(evt.GetSize(), "CmdEnable", 1))
674 return T::kSM_FatalError;
675
676 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
677 i->second->Cmd(command, evt.GetBool());
678
679 return T::GetCurrentState();
680 }
681
682 bool Check(const uint32_t *dat, uint32_t maxaddr, uint32_t maxval)
683 {
684 if (dat[0]>maxaddr)
685 {
686 ostringstream msg;
687 msg << hex << "Address " << dat[0] << " out of range, max=" << maxaddr << ".";
688 T::Error(msg);
689 return false;
690 }
691
692 if (dat[1]>maxval)
693 {
694 ostringstream msg;
695 msg << hex << "Value " << dat[1] << " out of range, max=" << maxval << ".";
696 T::Error(msg);
697 return false;
698 }
699
700 return true;
701 }
702
703 int SetRegister(const EventImp &evt)
704 {
705 if (!CheckEventSize(evt.GetSize(), "SetRegister", 8))
706 return T::kSM_FatalError;
707
708 const uint32_t *dat = evt.Ptr<uint32_t>();
709
710 if (!Check(dat, FAD::kMaxRegAddr, FAD::kMaxRegValue))
711 return T::GetCurrentState();
712
713 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
714 i->second->CmdSetRegister(dat[0], dat[1]);
715
716 return T::GetCurrentState();
717 }
718
719 int SetRoi(const EventImp &evt)
720 {
721 if (!CheckEventSize(evt.GetSize(), "SetRoi", 8))
722 return T::kSM_FatalError;
723
724 const int32_t *dat = evt.Ptr<int32_t>();
725
726 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
727 if (!i->second->CmdSetRoi(dat[0], dat[1]))
728 {
729 ostringstream msg;
730 msg << hex << "Channel " << dat[0] << " or Value " << dat[1] << " out of range.";
731 T::Error(msg);
732 return false;
733 }
734
735
736 return T::GetCurrentState();
737 }
738
739 int SetDac(const EventImp &evt)
740 {
741 if (!CheckEventSize(evt.GetSize(), "SetDac", 8))
742 return T::kSM_FatalError;
743
744 const int32_t *dat = evt.Ptr<int32_t>();
745
746 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
747 if (!i->second->CmdSetDacValue(dat[0], dat[1]))
748 {
749 ostringstream msg;
750 msg << hex << "Channel " << dat[0] << " or Value " << dat[1] << " out of range.";
751 T::Error(msg);
752 return false;
753 }
754
755 return T::GetCurrentState();
756 }
757
758 int Trigger(int n)
759 {
760 for (int nn=0; nn<n; nn++)
761 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
762 i->second->Cmd(FAD::kCmdSingleTrigger);
763
764 return T::GetCurrentState();
765 }
766
767 int SendTriggers(const EventImp &evt)
768 {
769 if (!CheckEventSize(evt.GetSize(), "SendTriggers", 4))
770 return T::kSM_FatalError;
771
772 Trigger(evt.GetUInt());
773
774 return T::GetCurrentState();
775 }
776
777 int StartRun(const EventImp &evt, bool start)
778 {
779 if (!CheckEventSize(evt.GetSize(), "StartRun", 0))
780 return T::kSM_FatalError;
781
782 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
783 i->second->Cmd(FAD::kCmdRun, start);
784
785 return T::GetCurrentState();
786 }
787
788 int PhaseShift(const EventImp &evt)
789 {
790 if (!CheckEventSize(evt.GetSize(), "PhaseShift", 2))
791 return T::kSM_FatalError;
792
793 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
794 i->second->CmdPhaseShift(evt.GetShort());
795
796 return T::GetCurrentState();
797 }
798
799 int SetTriggerRate(const EventImp &evt)
800 {
801 if (!CheckEventSize(evt.GetSize(), "SetTriggerRate", 4))
802 return T::kSM_FatalError;
803
804 if (evt.GetUInt()>0xffff)
805 {
806 ostringstream msg;
807 msg << hex << "Value " << evt.GetUShort() << " out of range, max=" << 0xffff << "(?)";
808 T::Error(msg);
809 return false;
810 }
811
812 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
813 i->second->CmdSetTriggerRate(evt.GetUInt());
814
815 return T::GetCurrentState();
816 }
817
818 int SetRunNumber(const EventImp &evt)
819 {
820 if (!CheckEventSize(evt.GetSize(), "SetRunNumber", 8))
821 return T::kSM_FatalError;
822
823 const uint64_t num = evt.GetUXtra();
824
825 if (num>FAD::kMaxRunNumber)
826 {
827 ostringstream msg;
828 msg << hex << "Value " << num << " out of range, max=" << FAD::kMaxRunNumber;
829 T::Error(msg);
830 return false;
831 }
832
833 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
834 i->second->CmdSetRunNumber(num);
835
836 return T::GetCurrentState();
837 }
838
839 int SetMaxMemoryBuffer(const EventImp &evt)
840 {
841 if (!CheckEventSize(evt.GetSize(), "SetMaxMemoryBuffer", 2))
842 return T::kSM_FatalError;
843
844 const int16_t mem = evt.GetShort();
845
846 if (mem<=0)
847 {
848 ostringstream msg;
849 msg << hex << "Value " << mem << " out of range.";
850 T::Error(msg);
851 return false;
852 }
853
854 SetMaxMemory(mem);
855
856 return T::GetCurrentState();
857 }
858
859 int SetFileFormat(const EventImp &evt)
860 {
861 if (!CheckEventSize(evt.GetSize(), "SetFileFormat", 2))
862 return T::kSM_FatalError;
863
864 const uint16_t fmt = evt.GetUShort();
865
866 switch (fmt)
867 {
868 case 0: SetOutputFormat(kNone); break;
869 case 1: SetOutputFormat(kDebug); break;
870 case 2: SetOutputFormat(kFits); break;
871 case 3: SetOutputFormat(kRaw); break;
872 default:
873 T::Error("File format unknonw.");
874 return false;
875 }
876
877 return T::GetCurrentState();
878 }
879
880 int Test(const EventImp &evt)
881 {
882 if (!CheckEventSize(evt.GetSize(), "Test", 2))
883 return T::kSM_FatalError;
884
885
886 SetMode(evt.GetShort());
887
888 return T::GetCurrentState();
889 }
890
891
892 int SetVerbosity(const EventImp &evt)
893 {
894 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
895 return T::kSM_FatalError;
896
897 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
898 i->second->SetVerbose(evt.GetBool());
899
900 return T::GetCurrentState();
901 }
902
903 int SetHexOutput(const EventImp &evt)
904 {
905 if (!CheckEventSize(evt.GetSize(), "SetHexOutput", 1))
906 return T::kSM_FatalError;
907
908 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
909 i->second->SetHexOutput(evt.GetBool());
910
911 return T::GetCurrentState();
912 }
913
914 int SetDataOutput(const EventImp &evt)
915 {
916 if (!CheckEventSize(evt.GetSize(), "SetDataOutput", 1))
917 return T::kSM_FatalError;
918
919 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
920 i->second->SetDataOutput(evt.GetBool());
921
922 return T::GetCurrentState();
923 }
924
925 int SetDebugTx(const EventImp &evt)
926 {
927 if (!CheckEventSize(evt.GetSize(), "SetDebugTx", 1))
928 return T::kSM_FatalError;
929
930 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
931 i->second->SetDebugTx(evt.GetBool());
932
933 return T::GetCurrentState();
934 }
935
936 int SetDebugEb(const EventImp &evt)
937 {
938 if (!CheckEventSize(evt.GetSize(), "SetDebugEb", 1))
939 return T::kSM_FatalError;
940
941 SetDebugLog(evt.GetBool());
942
943 return T::GetCurrentState();
944 }
945
946 const BoardList::iterator GetSlot(uint16_t slot)
947 {
948 const BoardList::iterator it=fBoards.find(slot);
949 if (it==fBoards.end())
950 {
951 ostringstream str;
952 str << "Slot " << slot << " not found.";
953 T::Warn(str);
954 }
955
956 return it;
957 }
958
959 int PrintEvent(const EventImp &evt)
960 {
961 if (!CheckEventSize(evt.GetSize(), "PrintEvent", 2))
962 return T::kSM_FatalError;
963
964 const int16_t slot = evt.Get<int16_t>();
965
966 if (slot<0)
967 {
968 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
969 i->second->PrintEvent();
970 }
971 else
972 {
973 const BoardList::iterator it=GetSlot(slot);
974 if (it!=fBoards.end())
975 it->second->PrintEvent();
976 }
977
978 return T::GetCurrentState();
979 }
980
981 int SetBlockTransmission(const EventImp &evt)
982 {
983 if (!CheckEventSize(evt.GetSize(), "SetBlockTransmission", 3))
984 return T::kSM_FatalError;
985
986 const int16_t slot = evt.Get<int32_t>();
987
988 const BoardList::iterator it=GetSlot(slot);
989 if (it!=fBoards.end())
990 it->second->SetBlockTransmission(evt.Get<uint8_t>(2));
991
992 return T::GetCurrentState();
993 }
994
995 int SetBlockTransmissionRange(const EventImp &evt)
996 {
997 if (!CheckEventSize(evt.GetSize(), "SetBlockTransmissionRange", 5))
998 return T::kSM_FatalError;
999
1000 const int16_t *slot = evt.Ptr<int16_t>();
1001 const bool block = evt.Get<uint8_t>(4);
1002
1003 for (int i=slot[0]; i<=slot[1]; i++)
1004 {
1005 const BoardList::iterator it=GetSlot(i);
1006 if (it!=fBoards.end())
1007 it->second->SetBlockTransmission(block);
1008 }
1009
1010 return T::GetCurrentState();
1011 }
1012
1013 int SetIgnoreSlot(const EventImp &evt)
1014 {
1015 if (!CheckEventSize(evt.GetSize(), "SetIgnoreSlot", 3))
1016 return T::kSM_FatalError;
1017
1018 const uint16_t slot = evt.Get<uint16_t>();
1019
1020 if (slot>39)
1021 {
1022 T::Warn("Slot out of range (0-39).");
1023 return T::GetCurrentState();
1024 }
1025
1026 SetIgnore(slot, evt.Get<uint8_t>(2));
1027
1028 return T::GetCurrentState();
1029 }
1030
1031 int SetIgnoreSlots(const EventImp &evt)
1032 {
1033 if (!CheckEventSize(evt.GetSize(), "SetIgnoreSlots", 5))
1034 return T::kSM_FatalError;
1035
1036 const int16_t *slot = evt.Ptr<int16_t>();
1037 const bool block = evt.Get<uint8_t>(4);
1038
1039 if (slot[0]<0 || slot[1]>39 || slot[0]>slot[1])
1040 {
1041 T::Warn("Slot out of range.");
1042 return T::GetCurrentState();
1043 }
1044
1045 for (int i=slot[0]; i<=slot[1]; i++)
1046 SetIgnore(i, block);
1047
1048 return T::GetCurrentState();
1049 }
1050
1051 int SetDumpStream(const EventImp &evt)
1052 {
1053 if (!CheckEventSize(evt.GetSize(), "SetDumpStream", 1))
1054 return T::kSM_FatalError;
1055
1056 SetDebugStream(evt.Get<uint8_t>());
1057
1058 return T::GetCurrentState();
1059 }
1060
1061 int SetDumpRecv(const EventImp &evt)
1062 {
1063 if (!CheckEventSize(evt.GetSize(), "SetDumpRecv", 1))
1064 return T::kSM_FatalError;
1065
1066 SetDebugRead(evt.Get<uint8_t>());
1067
1068 return T::GetCurrentState();
1069 }
1070
1071 int StartConfigure(const EventImp &evt)
1072 {
1073 const string name = evt.GetText();
1074
1075 fTargetConfig = fConfigs.find(name);
1076 if (fTargetConfig==fConfigs.end())
1077 {
1078 T::Error("StartConfigure - Run-type '"+name+"' not found.");
1079 return T::GetCurrentState();
1080 }
1081
1082 ostringstream str;
1083 str << "Starting configuration for run " << GetRunNumber() << " (" << name << ")";
1084 T::Message(str.str());
1085
1086 const uint32_t runno = IncreaseRunNumber();
1087
1088 for (BoardList::iterator it=fBoards.begin(); it!=fBoards.end(); it++)
1089 {
1090 const FAD::Configuration &conf = fTargetConfig->second;
1091
1092 ConnectionFAD &fad = *it->second;
1093
1094 fad.Cmd(FAD::kCmdTriggerLine, false);
1095 fad.Cmd(FAD::kCmdContTrigger, false);
1096 fad.Cmd(FAD::kCmdSocket, true);
1097 fad.Cmd(FAD::kCmdBusy, false);
1098
1099 fad.Cmd(FAD::kCmdDwrite, conf.fDenable);
1100 fad.Cmd(FAD::kCmdDrsEnable, conf.fDwrite);
1101 fad.Cmd(FAD::kCmdContTrigger, conf.fContinousTrigger);
1102
1103 for (int i=0; i<FAD::kNumDac; i++)
1104 fad.CmdSetDacValue(i, conf.fDac[i]);
1105
1106 for (int i=0; i<FAD::kNumChips; i++)
1107 for (int j=0; j<FAD::kNumChannelsPerChip; j++)
1108 fad.CmdSetRoi(i*FAD::kNumChannelsPerChip+j, conf.fRoi[j]);
1109
1110 fad.CmdSetTriggerRate(conf.fTriggerRate);
1111 fad.CmdSetRunNumber(runno);
1112 fad.Cmd(FAD::kCmdResetEventCounter);
1113 fad.Cmd(FAD::kCmdSingleTrigger);
1114 }
1115
1116 return FAD::kConfiguring;
1117 }
1118
1119 int ResetConfig()
1120 {
1121 return FAD::kConnected;
1122 }
1123
1124 int AddAddress(const EventImp &evt)
1125 {
1126 const string addr = Tools::Trim(evt.GetText());
1127
1128 const tcp::endpoint endpoint = GetEndpoint(addr);
1129 if (endpoint==tcp::endpoint())
1130 return T::GetCurrentState();
1131
1132 for (BoardList::const_iterator i=fBoards.begin(); i!=fBoards.end(); i++)
1133 {
1134 if (i->second->GetEndpoint()==endpoint)
1135 {
1136 T::Warn("Address "+addr+" already known.... ignored.");
1137 return T::GetCurrentState();
1138 }
1139 }
1140
1141 AddEndpoint(endpoint);
1142
1143 return T::GetCurrentState();
1144 }
1145
1146 int RemoveSlot(const EventImp &evt)
1147 {
1148 if (!CheckEventSize(evt.GetSize(), "RemoveSlot", 2))
1149 return T::kSM_FatalError;
1150
1151 const int16_t slot = evt.GetShort();
1152
1153 const BoardList::iterator it = GetSlot(slot);
1154
1155 if (it==fBoards.end())
1156 return T::GetCurrentState();
1157
1158 ConnectSlot(slot, tcp::endpoint());
1159
1160 delete it->second;
1161 fBoards.erase(it);
1162
1163 return T::GetCurrentState();
1164 }
1165
1166 int ListSlots()
1167 {
1168 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
1169 {
1170 const int &idx = i->first;
1171 const ConnectionFAD *fad = i->second;
1172
1173 ostringstream str;
1174 str << "Slot " << setw(2) << idx << ": " << fad->GetEndpoint();
1175
1176 if (fad->IsConnecting())
1177 str << " (0:connecting, ";
1178 else
1179 {
1180 if (fad->IsClosed())
1181 str << " (0:disconnected, ";
1182 if (fad->IsConnected())
1183 str << " (0:connected, ";
1184 }
1185
1186 switch (fStatus2[idx])
1187 {
1188 case 0: str << "1-7:not connected)"; break;
1189 case 8: str << "1-7:connected)"; break;
1190 default: str << "1-7:connecting [" << (int)(fStatus2[idx]-1) << "])"; break;
1191 }
1192
1193 if (fad->IsTransmissionBlocked())
1194 str << " [cmd_blocked]";
1195
1196 if (fStatus2[idx]==8 && IsIgnored(idx))
1197 str << " [data_ignored]";
1198
1199 if (fStatusC[idx])
1200 str << " [configured]";
1201
1202 T::Out() << str.str() << endl;
1203 }
1204
1205 T::Out() << "Event builder thread:";
1206 if (!IsThreadRunning())
1207 T::Out() << " not";
1208 T::Out() << " running" << endl;
1209
1210 // FIXME: Output state
1211
1212 return T::GetCurrentState();
1213 }
1214
1215 void EnableConnection(ConnectionFAD *ptr, bool enable=true)
1216 {
1217 if (!enable)
1218 {
1219 ptr->PostClose(false);
1220 return;
1221 }
1222
1223 if (!ptr->IsDisconnected())
1224 {
1225 ostringstream str;
1226 str << ptr->GetEndpoint();
1227
1228 T::Warn("Connection to "+str.str()+" already in progress.");
1229 return;
1230 }
1231
1232 ptr->StartConnect();
1233 }
1234
1235 void EnableAll(bool enable=true)
1236 {
1237 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
1238 EnableConnection(i->second, enable);
1239 }
1240
1241 int CloseOpenFiles()
1242 {
1243 EventBuilderWrapper::CloseOpenFiles();
1244 return T::GetCurrentState();
1245 }
1246
1247 int EnableSlot(const EventImp &evt, bool enable)
1248 {
1249 if (!CheckEventSize(evt.GetSize(), "EnableSlot", 2))
1250 return T::kSM_FatalError;
1251
1252 const int16_t slot = evt.GetShort();
1253
1254 const BoardList::iterator it = GetSlot(slot);
1255 if (it==fBoards.end())
1256 return T::GetCurrentState();
1257
1258 EnableConnection(it->second, enable);
1259 ConnectSlot(it->first, enable ? it->second->GetEndpoint() : tcp::endpoint());
1260
1261 return T::GetCurrentState();
1262 }
1263
1264 int ToggleSlot(const EventImp &evt)
1265 {
1266 if (!CheckEventSize(evt.GetSize(), "ToggleSlot", 2))
1267 return T::kSM_FatalError;
1268
1269 const int16_t slot = evt.GetShort();
1270
1271 const BoardList::iterator it = GetSlot(slot);
1272 if (it==fBoards.end())
1273 return T::GetCurrentState();
1274
1275 const bool enable = it->second->IsDisconnected();
1276
1277 EnableConnection(it->second, enable);
1278 ConnectSlot(it->first, enable ? it->second->GetEndpoint() : tcp::endpoint());
1279
1280 return T::GetCurrentState();
1281 }
1282
1283 int StartConnection()
1284 {
1285 vector<tcp::endpoint> addr(40);
1286
1287 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
1288 addr[i->first] = i->second->GetEndpoint();
1289
1290 StartThread(addr);
1291 EnableAll(true);
1292
1293 return T::GetCurrentState();
1294 }
1295
1296 int StopConnection()
1297 {
1298 Exit();
1299 EnableAll(false);
1300 return T::GetCurrentState();
1301 }
1302
1303 int AbortConnection()
1304 {
1305 Abort();
1306 EnableAll(false);
1307 return T::GetCurrentState();
1308 }
1309
1310 int Reset(bool soft)
1311 {
1312 ResetThread(soft);
1313 return T::GetCurrentState();
1314 }
1315
1316 vector<uint8_t> fStatus1;
1317 vector<uint8_t> fStatus2;
1318 vector<uint8_t> fStatusC;
1319 bool fStatusT;
1320
1321 int Execute()
1322 {
1323 // Dispatch (execute) at most one handler from the queue. In contrary
1324 // to run_one(), it doesn't wait until a handler is available
1325 // which can be dispatched, so poll_one() might return with 0
1326 // handlers dispatched. The handlers are always dispatched/executed
1327 // synchronously, i.e. within the call to poll_one()
1328 poll_one();
1329
1330 // ===== Evaluate connection status =====
1331
1332 uint16_t nclosed1 = 0;
1333 uint16_t nconnecting1 = 0;
1334 uint16_t nconnecting2 = 0;
1335 uint16_t nconnected1 = 0;
1336 uint16_t nconnected2 = 0;
1337 uint16_t nconfigured = 0;
1338
1339 vector<uint8_t> stat1(40);
1340 vector<uint8_t> stat2(40);
1341 vector<bool> statC(40);
1342
1343 int cnt = 0; // counter for enabled board
1344
1345 const bool runs = IsThreadRunning();
1346
1347 for (int idx=0; idx<40; idx++)
1348 {
1349 // ----- Command socket -----
1350 const BoardList::const_iterator &slot = fBoards.find(idx);
1351 if (slot!=fBoards.end())
1352 {
1353 const ConnectionFAD *c = slot->second;
1354 if (c->IsDisconnected())
1355 {
1356 stat1[idx] = 0;
1357 nclosed1++;
1358
1359 //DisconnectSlot(idx);
1360 }
1361 if (c->IsConnecting())
1362 {
1363 stat1[idx] = 1;
1364 nconnecting1++;
1365 }
1366 if (c->IsConnected())
1367 {
1368 stat1[idx] = 2;
1369 nconnected1++;
1370
1371 if (c->IsConfigured())
1372 {
1373 statC[idx] = 1;
1374 nconfigured++;
1375 }
1376 }
1377
1378 cnt++;
1379 }
1380
1381 // ----- Event builder -----
1382
1383 if (!runs)
1384 continue;
1385
1386 stat2[idx] = GetNumConnected(idx);
1387
1388 if (IsConnecting(idx))
1389 {
1390 nconnecting2++;
1391 stat2[idx]++;
1392 }
1393
1394 if (IsConnected(idx))
1395 {
1396 stat2[idx]++;
1397 nconnected2++;
1398 }
1399 }
1400
1401 // ===== Send connection status via dim =====
1402
1403 if (fStatus1!=stat1 || fStatus2!=stat2 || fStatusT!=IsThreadRunning())
1404 {
1405 fStatus1 = stat1;
1406 fStatus2 = stat2;
1407 fStatusT = runs;
1408 UpdateConnectionStatus(stat1, stat2, IsThreadRunning());
1409 }
1410
1411 // ===== Return connection status =====
1412
1413 // fadctrl: Always connecting if not disabled
1414 // event builder:
1415 if (nconnecting1==0 && nconnected1>0 && nconnected2==nconnected1)
1416 {
1417 if (T::GetCurrentState()==FAD::kConfigured && IsRunStarted(GetRunNumber()-1))
1418 return FAD::kConnected;
1419
1420 if (nconfigured!=nconnected1)
1421 {
1422
1423 if (T::GetCurrentState()==FAD::kConfiguring ||
1424 T::GetCurrentState()==FAD::kConfigured)
1425 // Stay in Configured until at least one new
1426 // event has been received
1427 return T::GetCurrentState();
1428
1429 return FAD::kConnected;
1430 }
1431
1432 if (T::GetCurrentState()==FAD::kConfiguring)
1433 {
1434 for (BoardList::iterator it=fBoards.begin(); it!=fBoards.end(); it++)
1435 {
1436 //const Configuration &conf = fTargetConfig->second;
1437
1438 ConnectionFAD &fad = *it->second;
1439
1440 fad.Cmd(FAD::kCmdResetEventCounter);
1441 fad.Cmd(FAD::kCmdSocket, false);
1442 fad.Cmd(FAD::kCmdTriggerLine, true);
1443
1444 // FIXME: How do we find out when the FADs
1445 // successfully enabled the trigger lines?
1446 }
1447 return FAD::kConfigured;
1448 }
1449
1450 return FAD::kConnected;
1451 }
1452
1453 if (nconnecting1>0 || nconnecting2>0 || nconnected1!=nconnected2)
1454 return FAD::kConnecting;
1455
1456 // nconnected1 == nconnected2 == 0
1457 return IsThreadRunning() ? FAD::kDisconnected : FAD::kOffline;
1458 }
1459
1460 void AddEndpoint(const tcp::endpoint &addr)
1461 {
1462 int i=0;
1463 while (i<40)
1464 {
1465 if (fBoards.find(i)==fBoards.end())
1466 break;
1467 i++;
1468 }
1469
1470 if (i==40)
1471 {
1472 T::Warn("Not more than 40 slots allowed.");
1473 return;
1474 }
1475
1476 ConnectionFAD *fad = new ConnectionFAD(*this, *this, i);
1477
1478 fad->SetEndpoint(addr);
1479 fad->SetVerbose(fIsVerbose);
1480 fad->SetHexOutput(fIsHexOutput);
1481 fad->SetDataOutput(fIsDataOutput);
1482 fad->SetDebugTx(fDebugTx);
1483
1484 fBoards[i] = fad;
1485 }
1486
1487
1488 DimDescribedService fDimConnection;
1489
1490 void UpdateConnectionStatus(const vector<uint8_t> &stat1, const vector<uint8_t> &stat2, bool thread)
1491 {
1492 vector<uint8_t> stat(41);
1493
1494 for (int i=0; i<40; i++)
1495 stat[i] = stat1[i]|(stat2[i]<<3);
1496
1497 stat[40] = thread;
1498
1499 fDimConnection.setData(stat.data(), 41);
1500 fDimConnection.updateService();
1501 }
1502
1503public:
1504 StateMachineFAD(ostream &out=cout) :
1505 T(out, "FAD_CONTROL"), EventBuilderWrapper(*static_cast<MessageImp*>(this)), ba::io_service::work(static_cast<ba::io_service&>(*this)),
1506 fStatus1(40), fStatus2(40), fStatusC(40), fStatusT(false),
1507 fDimConnection("FAD_CONTROL/CONNECTIONS", "C:40;C:1", "")
1508 {
1509 // ba::io_service::work is a kind of keep_alive for the loop.
1510 // It prevents the io_service to go to stopped state, which
1511 // would prevent any consecutive calls to run()
1512 // or poll() to do nothing. reset() could also revoke to the
1513 // previous state but this might introduce some overhead of
1514 // deletion and creation of threads and more.
1515
1516 // State names
1517 T::AddStateName(FAD::kOffline, "Disengaged",
1518 "All enabled FAD boards are disconnected and the event-builer thread is not running.");
1519
1520 T::AddStateName(FAD::kDisconnected, "Disconnected",
1521 "All enabled FAD boards are disconnected, but the event-builder thread is running.");
1522
1523 T::AddStateName(FAD::kConnecting, "Connecting",
1524 "Only some enabled FAD boards are connected.");
1525
1526 T::AddStateName(FAD::kConnected, "Connected",
1527 "All enabled FAD boards are connected..");
1528
1529 T::AddStateName(FAD::kConfiguring, "Configuring",
1530 ".");
1531
1532 T::AddStateName(FAD::kConfigured, "Configured",
1533 "The last header received through the command socket fits the requested configureation and has EventCounter==0.");
1534
1535 // FAD Commands
1536 T::AddEvent("SEND_CMD", "I:1")
1537 (boost::bind(&StateMachineFAD::SendCmd, this, _1))
1538 ("Send a command to the FADs. Values between 0 and 0xffff are allowed."
1539 "|command[uint16]:Command to be transmittted.");
1540 T::AddEvent("SEND_DATA", "I:2")
1541 (boost::bind(&StateMachineFAD::SendCmdData, this, _1))
1542 ("Send a command with data to the FADs. Values between 0 and 0xffff are allowed."
1543 "|command[uint16]:Command to be transmittted."
1544 "|data[uint16]:Data to be sent with the command.");
1545
1546 T::AddEvent("ENABLE_SRCLK", "B:1")
1547 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdSrclk))
1548 ("Set SRCLK");
1549 T::AddEvent("ENABLE_BUSY", "B:1")
1550 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdBusy))
1551 ("Set BUSY");
1552 T::AddEvent("ENABLE_SCLK", "B:1")
1553 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdSclk))
1554 ("Set SCLK");
1555 T::AddEvent("ENABLE_DRS", "B:1")
1556 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdDrsEnable))
1557 ("Switch Domino wave");
1558 T::AddEvent("ENABLE_DWRITE", "B:1")
1559 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdDwrite))
1560 ("Set Dwrite (possibly high / always low)");
1561 T::AddEvent("ENABLE_CONTINOUS_TRIGGER", "B:1")
1562 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdContTrigger))
1563 ("Enable continous (internal) trigger.");
1564 T::AddEvent("ENABLE_TRIGGER_LINE", "B:1")
1565 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdTriggerLine))
1566 ("Incoming triggers can be accepted/will not be accepted");
1567 T::AddEvent("ENABLE_COMMAND_SOCKET_MODE", "B:1")
1568 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdSocket))
1569 ("Set debug mode (yes: dump events through command socket, no=dump events through other sockets)");
1570
1571 T::AddEvent("SET_TRIGGER_RATE", "I:1")
1572 (boost::bind(&StateMachineFAD::SetTriggerRate, this, _1))
1573 ("Enable continous trigger");
1574 T::AddEvent("SEND_SINGLE_TRIGGER")
1575 (boost::bind(&StateMachineFAD::Trigger, this, 1))
1576 ("Issue software triggers");
1577 T::AddEvent("SEND_N_TRIGGERS", "I")
1578 (boost::bind(&StateMachineFAD::SendTriggers, this, _1))
1579 ("Issue software triggers");
1580 T::AddEvent("START_RUN", "")
1581 (boost::bind(&StateMachineFAD::StartRun, this, _1, true))
1582 ("Set FAD DAQ mode. when started, no configurations must be send.");
1583 T::AddEvent("STOP_RUN")
1584 (boost::bind(&StateMachineFAD::StartRun, this, _1, false))
1585 ("");
1586 T::AddEvent("PHASE_SHIFT", "S:1")
1587 (boost::bind(&StateMachineFAD::PhaseShift, this, _1))
1588 ("Adjust ADC phase (in 'steps')");
1589
1590 T::AddEvent("RESET_EVENT_COUNTER")
1591 (boost::bind(&StateMachineFAD::Cmd, this, FAD::kCmdResetEventCounter))
1592 ("");
1593
1594 T::AddEvent("SET_RUN_NUMBER", "X:1")
1595 (boost::bind(&StateMachineFAD::SetRunNumber, this, _1))
1596 ("");
1597
1598 T::AddEvent("SET_MAX_MEMORY", "S:1")
1599 (boost::bind(&StateMachineFAD::SetMaxMemoryBuffer, this, _1))
1600 ("Set maximum memory buffer size allowed to be consumed by the EventBuilder to buffer events."
1601 "|memory[short]:Buffer size in Mega-bytes.");
1602
1603 T::AddEvent("SET_REGISTER", "I:2")
1604 (boost::bind(&StateMachineFAD::SetRegister, this, _1))
1605 ("set register to value"
1606 "|addr[short]:Address of register"
1607 "|val[short]:Value to be set");
1608
1609 // FIXME: Maybe add a mask which channels should be set?
1610 T::AddEvent("SET_REGION_OF_INTEREST", "I:2")
1611 (boost::bind(&StateMachineFAD::SetRoi, this, _1))
1612 ("Set region-of-interest to value"
1613 "|addr[short]:Address of register"
1614 "|val[short]:Value to be set");
1615
1616 // FIXME: Maybe add a mask which channels should be set?
1617 T::AddEvent("SET_DAC_VALUE", "I:2")
1618 (boost::bind(&StateMachineFAD::SetDac, this, _1))
1619 ("Set DAC numbers in range to value"
1620 "|addr[short]:Address of register (-1 for all)"
1621 "|val[short]:Value to be set");
1622
1623 T::AddEvent("CONFIGURE", "C", FAD::kConnected, FAD::kConfigured)
1624 (boost::bind(&StateMachineFAD::StartConfigure, this, _1))
1625 ("");
1626
1627 T::AddEvent("RESET_CONFIGURE", FAD::kConfiguring, FAD::kConfigured)
1628 (boost::bind(&StateMachineFAD::ResetConfig, this))
1629 ("");
1630
1631 // Verbosity commands
1632 T::AddEvent("SET_VERBOSE", "B:1")
1633 (boost::bind(&StateMachineFAD::SetVerbosity, this, _1))
1634 ("Set verbosity state"
1635 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
1636
1637 T::AddEvent("SET_HEX_OUTPUT", "B:1")
1638 (boost::bind(&StateMachineFAD::SetHexOutput, this, _1))
1639 ("Enable or disable hex output for received data"
1640 "|hexout[bool]:disable or enable hex output for received data (yes/no)");
1641
1642 T::AddEvent("SET_DATA_OUTPUT", "B:1")
1643 (boost::bind(&StateMachineFAD::SetDataOutput, this, _1))
1644 ("");
1645
1646 T::AddEvent("SET_DEBUG_TX", "B:1")
1647 (boost::bind(&StateMachineFAD::SetDebugTx, this, _1))
1648 ("Enable or disable the output of messages in case of successfull data transmission to the boards."
1649 "|debug[bool]:disable or enable debug output for transmitted data (yes/no)");
1650
1651 T::AddEvent("SET_DEBUG_EVENT_BUILDER_OUT", "B:1")
1652 (boost::bind(&StateMachineFAD::SetDebugEb, this, _1))
1653 ("");
1654
1655 T::AddEvent("PRINT_EVENT", "S:1")
1656 (boost::bind(&StateMachineFAD::PrintEvent, this, _1))
1657 ("Print (last) event"
1658 "|board[short]:slot from which the event should be printed (-1 for all)");
1659
1660 T::AddEvent("DUMP_STREAM", "B:1")
1661 (boost::bind(&StateMachineFAD::SetDumpStream, this, _1))
1662 ("For debugging purpose: the binary data stream read from the sockets 0-7 can be dumped to files."
1663 "|switch[bool]:Enable (yes) or disable (no)");
1664
1665 T::AddEvent("DUMP_RECV", "B:1")
1666 (boost::bind(&StateMachineFAD::SetDumpRecv, this, _1))
1667 ("For debugging purpose: the times when data has been receives are dumped to a file."
1668 "|switch[bool]:Enable (yes) or disable (no)");
1669
1670 T::AddEvent("BLOCK_TRANSMISSION", "S:1;B:1")
1671 (boost::bind(&StateMachineFAD::SetBlockTransmission, this, _1))
1672 ("Blocks the transmission of commands to the given slot. Use with care! For debugging pupose only!"
1673 "|slot[short]:Slot to which the command transmission should be blocked (0-39)"
1674 "|enable[bool]:Whether the command transmission should be blockes (yes) or allowed (no)");
1675
1676 T::AddEvent("BLOCK_TRANSMISSION_RANGE", "S:2;B:1")
1677 (boost::bind(&StateMachineFAD::SetBlockTransmissionRange, this, _1))
1678 ("Blocks the transmission of commands to the given range of slots. Use with care! For debugging pupose only!"
1679 "|first[short]:First slot to which the command transmission should be blocked (0-39)"
1680 "|last[short]:Last slot to which the command transmission should be blocked (0-39)"
1681 "|enable[bool]:Whether the command transmission should be blockes (yes) or allowed (no)");
1682
1683 T::AddEvent("IGNORE_EVENTS", "S:1;B:1")
1684 (boost::bind(&StateMachineFAD::SetIgnoreSlot, this, _1))
1685 ("Instructs the event-builder to ignore events from the given slot but still read the data from the socket."
1686 "|slot[short]:Slot from which the data should be ignored when building events"
1687 "|enable[bool]:Whether the event builder should ignore data from this slot (yes) or allowed (no)");
1688
1689 T::AddEvent("IGNORE_EVENTS_RANGE", "S:2;B:1")
1690 (boost::bind(&StateMachineFAD::SetIgnoreSlots, this, _1))
1691 ("Instructs the event-builder to ignore events from the given slot but still read the data from the socket."
1692 "|first[short]:First slot from which the data should be ignored when building events"
1693 "|last[short]:Last slot from which the data should be ignored when building events"
1694 "|enable[bool]:Whether the event builder should ignore data from this slot (yes) or allowed (no)");
1695
1696 T::AddEvent("CLOSE_OPEN_FILES", FAD::kConnecting, FAD::kConnected)
1697 (boost::bind(&StateMachineFAD::CloseOpenFiles, this))
1698 ("Close all run files opened by the EventBuilder.");
1699
1700 T::AddEvent("TEST", "S:1")
1701 (boost::bind(&StateMachineFAD::Test, this, _1))
1702 ("");
1703
1704
1705
1706 // Conenction commands
1707 T::AddEvent("START", FAD::kOffline)
1708 (boost::bind(&StateMachineFAD::StartConnection, this))
1709 ("Start EventBuilder thread and connect all valid slots.");
1710
1711 T::AddEvent("STOP", FAD::kDisconnected, FAD::kConnecting, FAD::kConnected)
1712 (boost::bind(&StateMachineFAD::StopConnection, this))
1713 ("Stop EventBuilder thread (still write buffered events) and disconnect all slots.");
1714
1715 T::AddEvent("ABORT", FAD::kDisconnected, FAD::kConnecting, FAD::kConnected)
1716 (boost::bind(&StateMachineFAD::AbortConnection, this))
1717 ("Immediately abort EventBuilder thread and disconnect all slots.");
1718
1719 T::AddEvent("SOFT_RESET", FAD::kConnected)
1720 (boost::bind(&StateMachineFAD::Reset, this, true))
1721 ("Wait for buffers to drain, close all files and reinitialize event builder thread.");
1722
1723 T::AddEvent("HARD_RESET", FAD::kConnected)
1724 (boost::bind(&StateMachineFAD::Reset, this, false))
1725 ("Free all buffers, close all files and reinitialize event builder thread.");
1726
1727 T::AddEvent("CONNECT", "S:1", FAD::kDisconnected, FAD::kConnecting, FAD::kConnected)
1728 (boost::bind(&StateMachineFAD::EnableSlot, this, _1, true))
1729 ("Connect a disconnected slot.");
1730
1731 T::AddEvent("DISCONNECT", "S:1", FAD::kConnecting, FAD::kConnected)
1732 (boost::bind(&StateMachineFAD::EnableSlot, this, _1, false))
1733 ("Disconnect a connected slot.");
1734
1735 T::AddEvent("TOGGLE", "S:1", FAD::kDisconnected, FAD::kConnecting, FAD::kConnected)
1736 (boost::bind(&StateMachineFAD::ToggleSlot, this, _1))
1737 ("");
1738
1739 T::AddEvent("SET_FILE_FORMAT", "S:1")
1740 (boost::bind(&StateMachineFAD::SetFileFormat, this, _1))
1741 ("");
1742
1743
1744 T::AddEvent("ADD_ADDRESS", "C", FAD::kOffline)
1745 (boost::bind(&StateMachineFAD::AddAddress, this, _1))
1746 ("Add the address of a DRS4 board to the first free slot"
1747 "|IP[string]:address in the format <address:port>");
1748 T::AddEvent("REMOVE_SLOT", "S:1", FAD::kOffline)
1749 (boost::bind(&StateMachineFAD::RemoveSlot, this, _1))
1750 ("Remove the Iaddress in slot n. For a list see LIST"
1751 "|slot[short]:Remove the address in slot n from the list");
1752 T::AddEvent("LIST_SLOTS")
1753 (boost::bind(&StateMachineFAD::ListSlots, this))
1754 ("Print a list of all available board addressesa and whether they are enabled");
1755 }
1756
1757 ~StateMachineFAD()
1758 {
1759 for (BoardList::const_iterator i=fBoards.begin(); i!=fBoards.end(); i++)
1760 delete i->second;
1761 fBoards.clear();
1762 }
1763
1764 tcp::endpoint GetEndpoint(const string &base)
1765 {
1766 const size_t p0 = base.find_first_of(':');
1767 const size_t p1 = base.find_last_of(':');
1768
1769 if (p0==string::npos || p0!=p1)
1770 {
1771 T::Out() << kRed << "GetEndpoint - Wrong format ('host:port' expected)" << endl;
1772 return tcp::endpoint();
1773 }
1774
1775 tcp::resolver resolver(get_io_service());
1776
1777 boost::system::error_code ec;
1778
1779 const tcp::resolver::query query(base.substr(0, p0), base.substr(p0+1));
1780 const tcp::resolver::iterator iterator = resolver.resolve(query, ec);
1781
1782 if (ec)
1783 {
1784 T::Out() << kRed << "GetEndpoint - Couldn't resolve endpoint '" << base << "': " << ec.message();
1785 return tcp::endpoint();
1786 }
1787
1788 return *iterator;
1789 }
1790
1791 typedef map<string, FAD::Configuration> Configs;
1792 Configs fConfigs;
1793 Configs::const_iterator fTargetConfig;
1794
1795
1796 template<class V>
1797 bool CheckConfigVal(const Configuration &conf, V max, const string &name, const string &sub)
1798 {
1799 if (!conf.HasDef(name, sub))
1800 {
1801 T::Error("Neither "+name+"default nor "+name+sub+" found.");
1802 return false;
1803 }
1804
1805 const V val = conf.GetDef<V>(name, sub);
1806
1807 if (val<=max)
1808 return true;
1809
1810 ostringstream str;
1811 str << name << sub << "=" << val << " exceeds allowed maximum of " << max << "!";
1812 T::Error(str);
1813
1814 return false;
1815 }
1816
1817 int EvalConfiguration(const Configuration &conf)
1818 {
1819 // ---------- General setup ---------
1820 fIsVerbose = !conf.Get<bool>("quiet");
1821 fIsHexOutput = conf.Get<bool>("hex-out");
1822 fIsDataOutput = conf.Get<bool>("data-out");
1823 fDebugTx = conf.Get<bool>("debug-tx");
1824
1825 // ---------- Setup event builder ---------
1826 SetMaxMemory(conf.Get<unsigned int>("max-mem"));
1827
1828 // ---------- Setup run types ---------
1829 const vector<string> types = conf.Vec<string>("run-type");
1830 if (types.size()==0)
1831 T::Warn("No run-types defined.");
1832 else
1833 T::Message("Defining run-types");
1834 for (vector<string>::const_iterator it=types.begin();
1835 it!=types.end(); it++)
1836 {
1837 T::Message(" -> "+ *it);
1838
1839 if (fConfigs.count(*it)>0)
1840 {
1841 T::Error("Run-type "+*it+" defined twice.");
1842 return 1;
1843 }
1844
1845 FAD::Configuration target;
1846
1847 if (!CheckConfigVal<bool>(conf, true, "enable-drs.", *it) ||
1848 !CheckConfigVal<bool>(conf, true, "enable-dwrite.", *it) ||
1849 !CheckConfigVal<bool>(conf, true, "enable-continous-trigger.", *it))
1850 return 2;
1851
1852 target.fDenable = conf.GetDef<bool>("enable-drs.", *it);
1853 target.fDwrite = conf.GetDef<bool>("enable-dwrite.", *it);
1854 target.fContinousTrigger = conf.GetDef<bool>("enable-continous-trigger.", *it);
1855
1856 target.fTriggerRate = 0;
1857 //if (target.fContinousTrigger)
1858 {
1859 if (!CheckConfigVal<uint16_t>(conf, 0xffff, "trigger-rate.", *it))
1860 return 3;
1861
1862 target.fTriggerRate = conf.GetDef<uint16_t>("trigger-rate.", *it);
1863 }
1864
1865 for (int i=0; i<FAD::kNumChannelsPerChip; i++)
1866 {
1867 ostringstream str;
1868 str << "roi-ch" << i << '.';
1869
1870 if (!CheckConfigVal<uint16_t>(conf, FAD::kMaxRoiValue, "roi.", *it) &&
1871 !CheckConfigVal<uint16_t>(conf, FAD::kMaxRoiValue, str.str(), *it))
1872 return 4;
1873
1874 target.fRoi[i] = conf.HasDef(str.str(), *it) ?
1875 conf.GetDef<uint16_t>(str.str(), *it) :
1876 conf.GetDef<uint16_t>("roi.", *it);
1877 }
1878
1879 for (int i=0; i<FAD::kNumDac; i++)
1880 {
1881 ostringstream str;
1882 str << "dac-" << i << '.';
1883
1884 if (!CheckConfigVal<uint16_t>(conf, FAD::kMaxDacValue, "dac.", *it) &&
1885 !CheckConfigVal<uint16_t>(conf, FAD::kMaxDacValue, str.str(), *it))
1886 return 5;
1887
1888 target.fDac[i] = conf.HasDef(str.str(), *it) ?
1889 conf.GetDef<uint16_t>(str.str(), *it) :
1890 conf.GetDef<uint16_t>("dac.", *it);
1891 }
1892
1893 fConfigs[*it] = target;
1894 }
1895
1896 // FIXME: Add a check about unsused configurations
1897
1898 // ---------- Setup board addresses for fake-fad ---------
1899
1900 if (conf.Has("debug-addr"))
1901 {
1902 const string addr = conf.Get<string>("debug-addr");
1903 const int num = conf.Get<unsigned int>("debug-num");
1904
1905 const tcp::endpoint endpoint = GetEndpoint(addr);
1906 if (endpoint==tcp::endpoint())
1907 return 1;
1908
1909 for (int i=0; i<num; i++)
1910 AddEndpoint(tcp::endpoint(endpoint.address(), endpoint.port()+8*i));
1911
1912 StartConnection();
1913 return -1;
1914 }
1915
1916 // ---------- Setup board addresses for the real camera ---------
1917
1918 if (conf.Has("base-addr"))
1919 {
1920 string base = conf.Get<string>("base-addr");
1921
1922 if (base=="def" || base =="default")
1923 base = "10.0.128.128:31919";
1924
1925 const tcp::endpoint endpoint = GetEndpoint(base);
1926 if (endpoint==tcp::endpoint())
1927 return 10;
1928
1929 const ba::ip::address_v4::bytes_type ip = endpoint.address().to_v4().to_bytes();
1930
1931 if (ip[2]>250 || ip[3]>244)
1932 {
1933 T::Out() << kRed << "EvalConfiguration - IP address given by --base-addr out-of-range." << endl;
1934 return 11;
1935 }
1936
1937 for (int crate=0; crate<4; crate++)
1938 for (int board=0; board<10; board++)
1939 {
1940 ba::ip::address_v4::bytes_type target = endpoint.address().to_v4().to_bytes();
1941 target[2] += crate;
1942 target[3] += board;
1943
1944 AddEndpoint(tcp::endpoint(ba::ip::address_v4(target), endpoint.port()));
1945 }
1946
1947 StartConnection();
1948 return -1;
1949
1950 }
1951
1952 // ---------- Setup board addresses one by one ---------
1953
1954 if (conf.Has("addr"))
1955 {
1956 const vector<string> addrs = conf.Get<vector<string>>("addr");
1957 for (vector<string>::const_iterator i=addrs.begin(); i<addrs.end(); i++)
1958 {
1959 const tcp::endpoint endpoint = GetEndpoint(*i);
1960 if (endpoint==tcp::endpoint())
1961 return 12;
1962
1963 AddEndpoint(endpoint);
1964 }
1965
1966 StartConnection();
1967 return -1;
1968 }
1969
1970 return -1;
1971 }
1972
1973};
1974
1975// ------------------------------------------------------------------------
1976
1977#include "Main.h"
1978
1979/*
1980void RunThread(StateMachineImp *io_service)
1981{
1982 // This is necessary so that the StateMachien Thread can signal the
1983 // Readline to exit
1984 io_service->Run();
1985 Readline::Stop();
1986}
1987*/
1988/*
1989template<class S>
1990int RunDim(Configuration &conf)
1991{
1992 WindowLog wout;
1993
1994 ReadlineColor::PrintBootMsg(wout, conf.GetName(), false);
1995
1996 if (conf.Has("log"))
1997 if (!wout.OpenLogFile(conf.Get<string>("log")))
1998 wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
1999
2000 // Start io_service.Run to use the StateMachineImp::Run() loop
2001 // Start io_service.run to only use the commandHandler command detaching
2002 StateMachineFAD<S> io_service(wout);
2003 if (!io_service.EvalConfiguration(conf))
2004 return -1;
2005
2006 io_service.Run();
2007
2008 return 0;
2009}
2010*/
2011
2012template<class T, class S>
2013int RunShell(Configuration &conf)
2014{
2015 return Main<T, StateMachineFAD<S>>(conf);
2016/*
2017 static T shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
2018
2019 WindowLog &win = shell.GetStreamIn();
2020 WindowLog &wout = shell.GetStreamOut();
2021
2022 if (conf.Has("log"))
2023 if (!wout.OpenLogFile(conf.Get<string>("log")))
2024 win << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
2025
2026 StateMachineFAD<S> io_service(wout);
2027 if (!io_service.EvalConfiguration(conf))
2028 return -1;
2029
2030 shell.SetReceiver(io_service);
2031
2032 boost::thread t(boost::bind(RunThread, &io_service));
2033 //boost::thread t(boost::bind(&StateMachineFAD<S>::Run, &io_service));
2034
2035 if (conf.Has("cmd"))
2036 {
2037 const vector<string> v = conf.Get<vector<string>>("cmd");
2038 for (vector<string>::const_iterator it=v.begin(); it!=v.end(); it++)
2039 shell.ProcessLine(*it);
2040 }
2041
2042 if (conf.Has("exec"))
2043 {
2044 const vector<string> v = conf.Get<vector<string>>("exec");
2045 for (vector<string>::const_iterator it=v.begin(); it!=v.end(); it++)
2046 shell.Execute(*it);
2047 }
2048
2049 if (conf.Get<bool>("quit"))
2050 shell.Stop();
2051
2052 shell.Run(); // Run the shell
2053 io_service.Stop(); // Signal Loop-thread to stop
2054
2055 // Wait until the StateMachine has finished its thread
2056 // before returning and destroying the dim objects which might
2057 // still be in use.
2058 t.join();
2059
2060 return 0;
2061 */
2062}
2063
2064void SetupConfiguration(Configuration &conf)
2065{
2066 const string n = conf.GetName()+".log";
2067
2068 po::options_description config("Program options");
2069 config.add_options()
2070 ("dns", var<string>("localhost"), "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
2071 ("log,l", var<string>(n), "Write log-file")
2072// ("no-dim,d", po_switch(), "Disable dim services")
2073 ("console,c", var<int>(), "Use console (0=shell, 1=simple buffered, X=simple unbuffered)")
2074 ("cmd", vars<string>(), "Execute one or more commands at startup")
2075 ("exec,e", vars<string>(), "Execute one or more scrips at startup")
2076 ("quit", po_switch(), "Quit after startup");
2077 ;
2078
2079 po::options_description control("FAD control options");
2080 control.add_options()
2081 ("quiet,q", po_bool(), "Disable printing contents of all received messages in clear text.")
2082 ("hex-out", po_bool(), "Enable printing contents of all printed messages also as hex data.")
2083 ("data-out", po_bool(), "Enable printing received event data.")
2084 ("debug-tx", po_bool(), "Enable debugging of ethernet transmission.")
2085 ;
2086
2087 po::options_description connect("FAD connection options");
2088 connect.add_options()
2089 ("addr", vars<string>(), "Network address of FAD")
2090 ("base-addr", var<string>(), "Base address of all FAD")
2091 ("debug-num,n", var<unsigned int>(40), "Sets the number of fake boards to be connected locally")
2092 ("debug-addr", var<string>(), "")
2093 ;
2094
2095 po::options_description builder("Event builder options");
2096 builder.add_options()
2097 ("max-mem,m", var<unsigned int>(100), "Maximum memory the event builder thread is allowed to consume for its event buffer")
2098 ;
2099
2100
2101 po::options_description runtype("Run type configuration");
2102 runtype.add_options()
2103 ("run-type", vars<string>(), "")
2104 ("enable-dwrite.*", var<bool>(), "")
2105 ("enable-drs.*", var<bool>(), "")
2106 ("enable-continous-trigger.*", var<bool>(), "")
2107 ("trigger-rate.*", var<uint16_t>(), "")
2108 ("dac.*", var<uint16_t>(), "")
2109 ("dac-0.*", var<uint16_t>(), "")
2110 ("dac-1.*", var<uint16_t>(), "")
2111 ("dac-2.*", var<uint16_t>(), "")
2112 ("dac-3.*", var<uint16_t>(), "")
2113 ("dac-4.*", var<uint16_t>(), "")
2114 ("dac-5.*", var<uint16_t>(), "")
2115 ("dac-6.*", var<uint16_t>(), "")
2116 ("dac-7.*", var<uint16_t>(), "")
2117 ("roi.*", var<uint16_t>(), "")
2118 ("roi-ch0.*", var<uint16_t>(), "")
2119 ("roi-ch1.*", var<uint16_t>(), "")
2120 ("roi-ch2.*", var<uint16_t>(), "")
2121 ("roi-ch3.*", var<uint16_t>(), "")
2122 ("roi-ch4.*", var<uint16_t>(), "")
2123 ("roi-ch5.*", var<uint16_t>(), "")
2124 ("roi-ch6.*", var<uint16_t>(), "")
2125 ("roi-ch7.*", var<uint16_t>(), "")
2126 ("roi-ch8.*", var<uint16_t>(), "")
2127 ;
2128
2129 conf.AddEnv("dns", "DIM_DNS_NODE");
2130
2131 conf.AddOptions(config);
2132 conf.AddOptions(control);
2133 conf.AddOptions(connect);
2134 conf.AddOptions(builder);
2135 conf.AddOptions(runtype);
2136}
2137
2138void PrintUsage()
2139{
2140 cout <<
2141 "The fadctrl controls the FAD boards.\n"
2142 "\n"
2143 "The default is that the program is started without user intercation. "
2144 "All actions are supposed to arrive as DimCommands. Using the -c "
2145 "option, a local shell can be initialized. With h or help a short "
2146 "help message about the usuage can be brought to the screen.\n"
2147 "\n"
2148 "Usage: fadctrl [-c type] [OPTIONS]\n"
2149 " or: fadctrl [OPTIONS]\n";
2150 cout << endl;
2151}
2152
2153void PrintHelp()
2154{
2155 /* Additional help text which is printed after the configuration
2156 options goes here */
2157}
2158
2159int main(int argc, const char* argv[])
2160{
2161 Configuration conf(argv[0]);
2162 conf.SetPrintUsage(PrintUsage);
2163 SetupConfiguration(conf);
2164
2165 po::variables_map vm;
2166 try
2167 {
2168 vm = conf.Parse(argc, argv);
2169 }
2170#if BOOST_VERSION > 104000
2171 catch (po::multiple_occurrences &e)
2172 {
2173 cerr << "Program options invalid due to: " << e.what() << " of '" << e.get_option_name() << "'." << endl;
2174 return -1;
2175 }
2176#endif
2177 catch (exception& e)
2178 {
2179 cerr << "Program options invalid due to: " << e.what() << endl;
2180 return -1;
2181 }
2182
2183 if (conf.HasVersion() || conf.HasPrint())
2184 return -1;
2185
2186 if (conf.HasHelp())
2187 {
2188 PrintHelp();
2189 return -1;
2190 }
2191
2192 Dim::Setup(conf.Get<string>("dns"));
2193
2194// try
2195 {
2196 // No console access at all
2197 if (!conf.Has("console"))
2198 {
2199// if (conf.Get<bool>("no-dim"))
2200// return RunShell<LocalStream, StateMachine>(conf);
2201// else
2202 return RunShell<LocalStream, StateMachineDim>(conf);
2203 }
2204 // Cosole access w/ and w/o Dim
2205/* if (conf.Get<bool>("no-dim"))
2206 {
2207 if (conf.Get<int>("console")==0)
2208 return RunShell<LocalShell, StateMachine>(conf);
2209 else
2210 return RunShell<LocalConsole, StateMachine>(conf);
2211 }
2212 else
2213*/ {
2214 if (conf.Get<int>("console")==0)
2215 return RunShell<LocalShell, StateMachineDim>(conf);
2216 else
2217 return RunShell<LocalConsole, StateMachineDim>(conf);
2218 }
2219 }
2220/* catch (std::exception& e)
2221 {
2222 cerr << "Exception: " << e.what() << endl;
2223 return -1;
2224 }*/
2225
2226 return 0;
2227}
Note: See TracBrowser for help on using the repository browser.