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

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