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

Last change on this file since 11481 was 11481, checked in by tbretz, 13 years ago
Replaced boost::thread by std::thread and boost::bind by std::bind from the C++0x standard
File size: 69.0 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
590// ------------------------------------------------------------------------
591
592template <class T>
593class StateMachineFAD : public T, public EventBuilderWrapper, public ba::io_service, public ba::io_service::work
594{
595private:
596 typedef map<uint8_t, ConnectionFAD*> BoardList;
597
598 BoardList fBoards;
599
600 bool fIsVerbose;
601 bool fIsHexOutput;
602 bool fIsDataOutput;
603 bool fDebugTx;
604
605 bool CheckEventSize(size_t has, const char *name, size_t size)
606 {
607 if (has==size)
608 return true;
609
610 ostringstream msg;
611 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
612 T::Fatal(msg);
613 return false;
614 }
615
616 int Cmd(FAD::Enable command)
617 {
618 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
619 i->second->Cmd(command);
620
621 return T::GetCurrentState();
622 }
623
624 int SendCmd(const EventImp &evt)
625 {
626 if (!CheckEventSize(evt.GetSize(), "SendCmd", 4))
627 return T::kSM_FatalError;
628
629 if (evt.GetUInt()>0xffff)
630 {
631 T::Warn("Command value out of range (0-65535).");
632 return T::GetCurrentState();
633 }
634
635 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
636 i->second->PostCmd(evt.GetUInt());
637
638 return T::GetCurrentState();
639 }
640
641 int SendCmdData(const EventImp &evt)
642 {
643 if (!CheckEventSize(evt.GetSize(), "SendCmdData", 8))
644 return T::kSM_FatalError;
645
646 const uint32_t *ptr = evt.Ptr<uint32_t>();
647
648 if (ptr[0]>0xffff)
649 {
650 T::Warn("Command value out of range (0-65535).");
651 return T::GetCurrentState();
652 }
653
654 if (ptr[1]>0xffff)
655 {
656 T::Warn("Data value out of range (0-65535).");
657 return T::GetCurrentState();
658 }
659
660 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
661 i->second->PostCmd(ptr[0], ptr[1]);
662
663 return T::GetCurrentState();
664 }
665
666 int CmdEnable(const EventImp &evt, FAD::Enable command)
667 {
668 if (!CheckEventSize(evt.GetSize(), "CmdEnable", 1))
669 return T::kSM_FatalError;
670
671 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
672 i->second->Cmd(command, evt.GetBool());
673
674 return T::GetCurrentState();
675 }
676
677 bool Check(const uint32_t *dat, uint32_t maxaddr, uint32_t maxval)
678 {
679 if (dat[0]>maxaddr)
680 {
681 ostringstream msg;
682 msg << hex << "Address " << dat[0] << " out of range, max=" << maxaddr << ".";
683 T::Error(msg);
684 return false;
685 }
686
687 if (dat[1]>maxval)
688 {
689 ostringstream msg;
690 msg << hex << "Value " << dat[1] << " out of range, max=" << maxval << ".";
691 T::Error(msg);
692 return false;
693 }
694
695 return true;
696 }
697
698 int SetRegister(const EventImp &evt)
699 {
700 if (!CheckEventSize(evt.GetSize(), "SetRegister", 8))
701 return T::kSM_FatalError;
702
703 const uint32_t *dat = evt.Ptr<uint32_t>();
704
705 if (!Check(dat, FAD::kMaxRegAddr, FAD::kMaxRegValue))
706 return T::GetCurrentState();
707
708 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
709 i->second->CmdSetRegister(dat[0], dat[1]);
710
711 return T::GetCurrentState();
712 }
713
714 int SetRoi(const EventImp &evt)
715 {
716 if (!CheckEventSize(evt.GetSize(), "SetRoi", 8))
717 return T::kSM_FatalError;
718
719 const int32_t *dat = evt.Ptr<int32_t>();
720
721 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
722 if (!i->second->CmdSetRoi(dat[0], dat[1]))
723 {
724 ostringstream msg;
725 msg << hex << "Channel " << dat[0] << " or Value " << dat[1] << " out of range.";
726 T::Error(msg);
727 return false;
728 }
729
730
731 return T::GetCurrentState();
732 }
733
734 int SetDac(const EventImp &evt)
735 {
736 if (!CheckEventSize(evt.GetSize(), "SetDac", 8))
737 return T::kSM_FatalError;
738
739 const int32_t *dat = evt.Ptr<int32_t>();
740
741 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
742 if (!i->second->CmdSetDacValue(dat[0], dat[1]))
743 {
744 ostringstream msg;
745 msg << hex << "Channel " << dat[0] << " or Value " << dat[1] << " out of range.";
746 T::Error(msg);
747 return false;
748 }
749
750 return T::GetCurrentState();
751 }
752
753 int Trigger(int n)
754 {
755 for (int nn=0; nn<n; nn++)
756 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
757 i->second->Cmd(FAD::kCmdSingleTrigger);
758
759 return T::GetCurrentState();
760 }
761
762 int SendTriggers(const EventImp &evt)
763 {
764 if (!CheckEventSize(evt.GetSize(), "SendTriggers", 4))
765 return T::kSM_FatalError;
766
767 Trigger(evt.GetUInt());
768
769 return T::GetCurrentState();
770 }
771
772 int StartRun(const EventImp &evt, bool start)
773 {
774 if (!CheckEventSize(evt.GetSize(), "StartRun", 0))
775 return T::kSM_FatalError;
776
777 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
778 i->second->Cmd(FAD::kCmdRun, start);
779
780 return T::GetCurrentState();
781 }
782
783 int PhaseShift(const EventImp &evt)
784 {
785 if (!CheckEventSize(evt.GetSize(), "PhaseShift", 2))
786 return T::kSM_FatalError;
787
788 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
789 i->second->CmdPhaseShift(evt.GetShort());
790
791 return T::GetCurrentState();
792 }
793
794 int SetTriggerRate(const EventImp &evt)
795 {
796 if (!CheckEventSize(evt.GetSize(), "SetTriggerRate", 4))
797 return T::kSM_FatalError;
798
799 if (evt.GetUInt()>0xffff)
800 {
801 ostringstream msg;
802 msg << hex << "Value " << evt.GetUShort() << " out of range, max=" << 0xffff << "(?)";
803 T::Error(msg);
804 return false;
805 }
806
807 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
808 i->second->CmdSetTriggerRate(evt.GetUInt());
809
810 return T::GetCurrentState();
811 }
812
813 int SetRunNumber(const EventImp &evt)
814 {
815 if (!CheckEventSize(evt.GetSize(), "SetRunNumber", 8))
816 return T::kSM_FatalError;
817
818 const uint64_t num = evt.GetUXtra();
819
820 if (num>FAD::kMaxRunNumber)
821 {
822 ostringstream msg;
823 msg << hex << "Value " << num << " out of range, max=" << FAD::kMaxRunNumber;
824 T::Error(msg);
825 return false;
826 }
827
828 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
829 i->second->CmdSetRunNumber(num);
830
831 return T::GetCurrentState();
832 }
833
834 int SetMaxMemoryBuffer(const EventImp &evt)
835 {
836 if (!CheckEventSize(evt.GetSize(), "SetMaxMemoryBuffer", 2))
837 return T::kSM_FatalError;
838
839 const int16_t mem = evt.GetShort();
840
841 if (mem<=0)
842 {
843 ostringstream msg;
844 msg << hex << "Value " << mem << " out of range.";
845 T::Error(msg);
846 return false;
847 }
848
849 SetMaxMemory(mem);
850
851 return T::GetCurrentState();
852 }
853
854 int SetFileFormat(const EventImp &evt)
855 {
856 if (!CheckEventSize(evt.GetSize(), "SetFileFormat", 2))
857 return T::kSM_FatalError;
858
859 const uint16_t fmt = evt.GetUShort();
860
861 switch (fmt)
862 {
863 case 0: SetOutputFormat(kNone); break;
864 case 1: SetOutputFormat(kDebug); break;
865 case 2: SetOutputFormat(kFits); break;
866 case 3: SetOutputFormat(kRaw); break;
867 default:
868 T::Error("File format unknonw.");
869 return false;
870 }
871
872 return T::GetCurrentState();
873 }
874
875 int Test(const EventImp &evt)
876 {
877 if (!CheckEventSize(evt.GetSize(), "Test", 2))
878 return T::kSM_FatalError;
879
880
881 SetMode(evt.GetShort());
882
883 return T::GetCurrentState();
884 }
885
886
887 int SetVerbosity(const EventImp &evt)
888 {
889 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
890 return T::kSM_FatalError;
891
892 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
893 i->second->SetVerbose(evt.GetBool());
894
895 return T::GetCurrentState();
896 }
897
898 int SetHexOutput(const EventImp &evt)
899 {
900 if (!CheckEventSize(evt.GetSize(), "SetHexOutput", 1))
901 return T::kSM_FatalError;
902
903 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
904 i->second->SetHexOutput(evt.GetBool());
905
906 return T::GetCurrentState();
907 }
908
909 int SetDataOutput(const EventImp &evt)
910 {
911 if (!CheckEventSize(evt.GetSize(), "SetDataOutput", 1))
912 return T::kSM_FatalError;
913
914 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
915 i->second->SetDataOutput(evt.GetBool());
916
917 return T::GetCurrentState();
918 }
919
920 int SetDebugTx(const EventImp &evt)
921 {
922 if (!CheckEventSize(evt.GetSize(), "SetDebugTx", 1))
923 return T::kSM_FatalError;
924
925 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
926 i->second->SetDebugTx(evt.GetBool());
927
928 return T::GetCurrentState();
929 }
930
931 int SetDebugEb(const EventImp &evt)
932 {
933 if (!CheckEventSize(evt.GetSize(), "SetDebugEb", 1))
934 return T::kSM_FatalError;
935
936 SetDebugLog(evt.GetBool());
937
938 return T::GetCurrentState();
939 }
940
941 const BoardList::iterator GetSlot(uint16_t slot)
942 {
943 const BoardList::iterator it=fBoards.find(slot);
944 if (it==fBoards.end())
945 {
946 ostringstream str;
947 str << "Slot " << slot << " not found.";
948 T::Warn(str);
949 }
950
951 return it;
952 }
953
954 int PrintEvent(const EventImp &evt)
955 {
956 if (!CheckEventSize(evt.GetSize(), "PrintEvent", 2))
957 return T::kSM_FatalError;
958
959 const int16_t slot = evt.Get<int16_t>();
960
961 if (slot<0)
962 {
963 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
964 i->second->PrintEvent();
965 }
966 else
967 {
968 const BoardList::iterator it=GetSlot(slot);
969 if (it!=fBoards.end())
970 it->second->PrintEvent();
971 }
972
973 return T::GetCurrentState();
974 }
975
976 int SetBlockTransmission(const EventImp &evt)
977 {
978 if (!CheckEventSize(evt.GetSize(), "SetBlockTransmission", 3))
979 return T::kSM_FatalError;
980
981 const int16_t slot = evt.Get<int32_t>();
982
983 const BoardList::iterator it=GetSlot(slot);
984 if (it!=fBoards.end())
985 it->second->SetBlockTransmission(evt.Get<uint8_t>(2));
986
987 return T::GetCurrentState();
988 }
989
990 int SetBlockTransmissionRange(const EventImp &evt)
991 {
992 if (!CheckEventSize(evt.GetSize(), "SetBlockTransmissionRange", 5))
993 return T::kSM_FatalError;
994
995 const int16_t *slot = evt.Ptr<int16_t>();
996 const bool block = evt.Get<uint8_t>(4);
997
998 for (int i=slot[0]; i<=slot[1]; i++)
999 {
1000 const BoardList::iterator it=GetSlot(i);
1001 if (it!=fBoards.end())
1002 it->second->SetBlockTransmission(block);
1003 }
1004
1005 return T::GetCurrentState();
1006 }
1007
1008 int SetIgnoreSlot(const EventImp &evt)
1009 {
1010 if (!CheckEventSize(evt.GetSize(), "SetIgnoreSlot", 3))
1011 return T::kSM_FatalError;
1012
1013 const uint16_t slot = evt.Get<uint16_t>();
1014
1015 if (slot>39)
1016 {
1017 T::Warn("Slot out of range (0-39).");
1018 return T::GetCurrentState();
1019 }
1020
1021 SetIgnore(slot, evt.Get<uint8_t>(2));
1022
1023 return T::GetCurrentState();
1024 }
1025
1026 int SetIgnoreSlots(const EventImp &evt)
1027 {
1028 if (!CheckEventSize(evt.GetSize(), "SetIgnoreSlots", 5))
1029 return T::kSM_FatalError;
1030
1031 const int16_t *slot = evt.Ptr<int16_t>();
1032 const bool block = evt.Get<uint8_t>(4);
1033
1034 if (slot[0]<0 || slot[1]>39 || slot[0]>slot[1])
1035 {
1036 T::Warn("Slot out of range.");
1037 return T::GetCurrentState();
1038 }
1039
1040 for (int i=slot[0]; i<=slot[1]; i++)
1041 SetIgnore(i, block);
1042
1043 return T::GetCurrentState();
1044 }
1045
1046 int SetDumpStream(const EventImp &evt)
1047 {
1048 if (!CheckEventSize(evt.GetSize(), "SetDumpStream", 1))
1049 return T::kSM_FatalError;
1050
1051 SetDebugStream(evt.Get<uint8_t>());
1052
1053 return T::GetCurrentState();
1054 }
1055
1056 int SetDumpRecv(const EventImp &evt)
1057 {
1058 if (!CheckEventSize(evt.GetSize(), "SetDumpRecv", 1))
1059 return T::kSM_FatalError;
1060
1061 SetDebugRead(evt.Get<uint8_t>());
1062
1063 return T::GetCurrentState();
1064 }
1065
1066 int StartConfigure(const EventImp &evt)
1067 {
1068 const string name = evt.GetText();
1069
1070 fTargetConfig = fConfigs.find(name);
1071 if (fTargetConfig==fConfigs.end())
1072 {
1073 T::Error("StartConfigure - Run-type '"+name+"' not found.");
1074 return T::GetCurrentState();
1075 }
1076
1077 const uint32_t runno = StartNewRun();
1078
1079 ostringstream str;
1080 str << "Starting configuration for run " << runno << " (" << name << ")";
1081 T::Message(str.str());
1082
1083 for (BoardList::iterator it=fBoards.begin(); it!=fBoards.end(); it++)
1084 {
1085 const FAD::Configuration &conf = fTargetConfig->second;
1086
1087 ConnectionFAD &fad = *it->second;
1088
1089 fad.Cmd(FAD::kCmdTriggerLine, false);
1090 fad.Cmd(FAD::kCmdContTrigger, false);
1091 fad.Cmd(FAD::kCmdSocket, true);
1092 fad.Cmd(FAD::kCmdBusy, false);
1093
1094 fad.Cmd(FAD::kCmdDwrite, conf.fDenable);
1095 fad.Cmd(FAD::kCmdDrsEnable, conf.fDwrite);
1096 fad.Cmd(FAD::kCmdContTrigger, conf.fContinousTrigger);
1097
1098 for (int i=0; i<FAD::kNumDac; i++)
1099 fad.CmdSetDacValue(i, conf.fDac[i]);
1100
1101 for (int i=0; i<FAD::kNumChips; i++)
1102 for (int j=0; j<FAD::kNumChannelsPerChip; j++)
1103 fad.CmdSetRoi(i*FAD::kNumChannelsPerChip+j, conf.fRoi[j]);
1104
1105 fad.CmdSetTriggerRate(conf.fTriggerRate);
1106 fad.CmdSetRunNumber(runno);
1107 fad.Cmd(FAD::kCmdResetEventCounter);
1108 fad.Cmd(FAD::kCmdSingleTrigger);
1109 }
1110
1111 return FAD::kConfiguring;
1112 }
1113
1114 int ResetConfig()
1115 {
1116 return FAD::kConnected;
1117 }
1118
1119 int AddAddress(const EventImp &evt)
1120 {
1121 const string addr = Tools::Trim(evt.GetText());
1122
1123 const tcp::endpoint endpoint = GetEndpoint(addr);
1124 if (endpoint==tcp::endpoint())
1125 return T::GetCurrentState();
1126
1127 for (BoardList::const_iterator i=fBoards.begin(); i!=fBoards.end(); i++)
1128 {
1129 if (i->second->GetEndpoint()==endpoint)
1130 {
1131 T::Warn("Address "+addr+" already known.... ignored.");
1132 return T::GetCurrentState();
1133 }
1134 }
1135
1136 AddEndpoint(endpoint);
1137
1138 return T::GetCurrentState();
1139 }
1140
1141 int RemoveSlot(const EventImp &evt)
1142 {
1143 if (!CheckEventSize(evt.GetSize(), "RemoveSlot", 2))
1144 return T::kSM_FatalError;
1145
1146 const int16_t slot = evt.GetShort();
1147
1148 const BoardList::iterator it = GetSlot(slot);
1149
1150 if (it==fBoards.end())
1151 return T::GetCurrentState();
1152
1153 ConnectSlot(slot, tcp::endpoint());
1154
1155 delete it->second;
1156 fBoards.erase(it);
1157
1158 return T::GetCurrentState();
1159 }
1160
1161 int ListSlots()
1162 {
1163 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
1164 {
1165 const int &idx = i->first;
1166 const ConnectionFAD *fad = i->second;
1167
1168 ostringstream str;
1169 str << "Slot " << setw(2) << idx << ": " << fad->GetEndpoint();
1170
1171 if (fad->IsConnecting())
1172 str << " (0:connecting, ";
1173 else
1174 {
1175 if (fad->IsClosed())
1176 str << " (0:disconnected, ";
1177 if (fad->IsConnected())
1178 str << " (0:connected, ";
1179 }
1180
1181 switch (fStatus2[idx])
1182 {
1183 case 0: str << "1-7:not connected)"; break;
1184 case 8: str << "1-7:connected)"; break;
1185 default: str << "1-7:connecting [" << (int)(fStatus2[idx]-1) << "])"; break;
1186 }
1187
1188 if (fad->IsTransmissionBlocked())
1189 str << " [cmd_blocked]";
1190
1191 if (fStatus2[idx]==8 && IsIgnored(idx))
1192 str << " [data_ignored]";
1193
1194 if (fStatusC[idx])
1195 str << " [configured]";
1196
1197 T::Out() << str.str() << endl;
1198 }
1199
1200 T::Out() << "Event builder thread:";
1201 if (!IsThreadRunning())
1202 T::Out() << " not";
1203 T::Out() << " running" << endl;
1204
1205 // FIXME: Output state
1206
1207 return T::GetCurrentState();
1208 }
1209
1210 void EnableConnection(ConnectionFAD *ptr, bool enable=true)
1211 {
1212 if (!enable)
1213 {
1214 ptr->PostClose(false);
1215 return;
1216 }
1217
1218 if (!ptr->IsDisconnected())
1219 {
1220 ostringstream str;
1221 str << ptr->GetEndpoint();
1222
1223 T::Warn("Connection to "+str.str()+" already in progress.");
1224 return;
1225 }
1226
1227 ptr->StartConnect();
1228 }
1229
1230 void EnableAll(bool enable=true)
1231 {
1232 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
1233 EnableConnection(i->second, enable);
1234 }
1235
1236 int CloseOpenFiles()
1237 {
1238 EventBuilderWrapper::CloseOpenFiles();
1239 return T::GetCurrentState();
1240 }
1241
1242 int EnableSlot(const EventImp &evt, bool enable)
1243 {
1244 if (!CheckEventSize(evt.GetSize(), "EnableSlot", 2))
1245 return T::kSM_FatalError;
1246
1247 const int16_t slot = evt.GetShort();
1248
1249 const BoardList::iterator it = GetSlot(slot);
1250 if (it==fBoards.end())
1251 return T::GetCurrentState();
1252
1253 EnableConnection(it->second, enable);
1254 ConnectSlot(it->first, enable ? it->second->GetEndpoint() : tcp::endpoint());
1255
1256 return T::GetCurrentState();
1257 }
1258
1259 int ToggleSlot(const EventImp &evt)
1260 {
1261 if (!CheckEventSize(evt.GetSize(), "ToggleSlot", 2))
1262 return T::kSM_FatalError;
1263
1264 const int16_t slot = evt.GetShort();
1265
1266 const BoardList::iterator it = GetSlot(slot);
1267 if (it==fBoards.end())
1268 return T::GetCurrentState();
1269
1270 const bool enable = it->second->IsDisconnected();
1271
1272 EnableConnection(it->second, enable);
1273 ConnectSlot(it->first, enable ? it->second->GetEndpoint() : tcp::endpoint());
1274
1275 return T::GetCurrentState();
1276 }
1277
1278 int StartConnection()
1279 {
1280 vector<tcp::endpoint> addr(40);
1281
1282 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
1283 addr[i->first] = i->second->GetEndpoint();
1284
1285 StartThread(addr);
1286 EnableAll(true);
1287
1288 return T::GetCurrentState();
1289 }
1290
1291 int StopConnection()
1292 {
1293 Exit();
1294 EnableAll(false);
1295 return T::GetCurrentState();
1296 }
1297
1298 int AbortConnection()
1299 {
1300 Abort();
1301 EnableAll(false);
1302 return T::GetCurrentState();
1303 }
1304
1305 int Reset(bool soft)
1306 {
1307 ResetThread(soft);
1308 return T::GetCurrentState();
1309 }
1310
1311 vector<uint8_t> fStatus1;
1312 vector<uint8_t> fStatus2;
1313 vector<uint8_t> fStatusC;
1314 bool fStatusT;
1315
1316 int Execute()
1317 {
1318 // Dispatch (execute) at most one handler from the queue. In contrary
1319 // to run_one(), it doesn't wait until a handler is available
1320 // which can be dispatched, so poll_one() might return with 0
1321 // handlers dispatched. The handlers are always dispatched/executed
1322 // synchronously, i.e. within the call to poll_one()
1323 poll_one();
1324
1325 // ===== Evaluate connection status =====
1326
1327 uint16_t nclosed1 = 0;
1328 uint16_t nconnecting1 = 0;
1329 uint16_t nconnecting2 = 0;
1330 uint16_t nconnected1 = 0;
1331 uint16_t nconnected2 = 0;
1332 uint16_t nconfigured = 0;
1333
1334 vector<uint8_t> stat1(40);
1335 vector<uint8_t> stat2(40);
1336 vector<bool> statC(40);
1337
1338 int cnt = 0; // counter for enabled board
1339
1340 const bool runs = IsThreadRunning();
1341
1342 for (int idx=0; idx<40; idx++)
1343 {
1344 // ----- Command socket -----
1345 const BoardList::const_iterator &slot = fBoards.find(idx);
1346 if (slot!=fBoards.end())
1347 {
1348 const ConnectionFAD *c = slot->second;
1349 if (c->IsDisconnected())
1350 {
1351 stat1[idx] = 0;
1352 nclosed1++;
1353
1354 //DisconnectSlot(idx);
1355 }
1356 if (c->IsConnecting())
1357 {
1358 stat1[idx] = 1;
1359 nconnecting1++;
1360 }
1361 if (c->IsConnected())
1362 {
1363 stat1[idx] = 2;
1364 nconnected1++;
1365
1366 if (c->IsConfigured())
1367 {
1368 statC[idx] = 1;
1369 nconfigured++;
1370 }
1371 }
1372
1373 cnt++;
1374 }
1375
1376 // ----- Event builder -----
1377
1378 if (!runs)
1379 continue;
1380
1381 stat2[idx] = GetNumConnected(idx);
1382
1383 if (IsConnecting(idx))
1384 {
1385 nconnecting2++;
1386 stat2[idx]++;
1387 }
1388
1389 if (IsConnected(idx))
1390 {
1391 stat2[idx]++;
1392 nconnected2++;
1393 }
1394 }
1395
1396 // ===== Send connection status via dim =====
1397
1398 if (fStatus1!=stat1 || fStatus2!=stat2 || fStatusT!=IsThreadRunning())
1399 {
1400 fStatus1 = stat1;
1401 fStatus2 = stat2;
1402 fStatusT = runs;
1403 UpdateConnectionStatus(stat1, stat2, IsThreadRunning());
1404 }
1405
1406 // ===== Return connection status =====
1407
1408 // fadctrl: Always connecting if not disabled
1409 // event builder:
1410 if (nconnecting1==0 && nconnected1>0 && nconnected2==nconnected1)
1411 {
1412 if (T::GetCurrentState()==FAD::kConfigured && IsRunStarted())
1413 return FAD::kConnected;
1414
1415 if (nconfigured!=nconnected1)
1416 {
1417
1418 if (T::GetCurrentState()==FAD::kConfiguring ||
1419 T::GetCurrentState()==FAD::kConfigured)
1420 // Stay in Configured until at least one new
1421 // event has been received
1422 return T::GetCurrentState();
1423
1424 return FAD::kConnected;
1425 }
1426
1427 if (T::GetCurrentState()==FAD::kConfiguring)
1428 {
1429 for (BoardList::iterator it=fBoards.begin(); it!=fBoards.end(); it++)
1430 {
1431 //const Configuration &conf = fTargetConfig->second;
1432
1433 ConnectionFAD &fad = *it->second;
1434
1435 fad.Cmd(FAD::kCmdResetEventCounter);
1436 fad.Cmd(FAD::kCmdSocket, false);
1437 fad.Cmd(FAD::kCmdTriggerLine, true);
1438
1439 // FIXME: How do we find out when the FADs
1440 // successfully enabled the trigger lines?
1441 }
1442 return FAD::kConfigured;
1443 }
1444
1445 return FAD::kConnected;
1446 }
1447
1448 if (nconnecting1>0 || nconnecting2>0 || nconnected1!=nconnected2)
1449 return FAD::kConnecting;
1450
1451 // nconnected1 == nconnected2 == 0
1452 return IsThreadRunning() ? FAD::kDisconnected : FAD::kOffline;
1453 }
1454
1455 void AddEndpoint(const tcp::endpoint &addr)
1456 {
1457 int i=0;
1458 while (i<40)
1459 {
1460 if (fBoards.find(i)==fBoards.end())
1461 break;
1462 i++;
1463 }
1464
1465 if (i==40)
1466 {
1467 T::Warn("Not more than 40 slots allowed.");
1468 return;
1469 }
1470
1471 ConnectionFAD *fad = new ConnectionFAD(*this, *this, i);
1472
1473 fad->SetEndpoint(addr);
1474 fad->SetVerbose(fIsVerbose);
1475 fad->SetHexOutput(fIsHexOutput);
1476 fad->SetDataOutput(fIsDataOutput);
1477 fad->SetDebugTx(fDebugTx);
1478
1479 fBoards[i] = fad;
1480 }
1481
1482
1483 DimDescribedService fDimConnection;
1484
1485 void UpdateConnectionStatus(const vector<uint8_t> &stat1, const vector<uint8_t> &stat2, bool thread)
1486 {
1487 vector<uint8_t> stat(41);
1488
1489 for (int i=0; i<40; i++)
1490 stat[i] = stat1[i]|(stat2[i]<<3);
1491
1492 stat[40] = thread;
1493
1494 fDimConnection.setData(stat.data(), 41);
1495 fDimConnection.updateService();
1496 }
1497
1498public:
1499 StateMachineFAD(ostream &out=cout) :
1500 T(out, "FAD_CONTROL"), EventBuilderWrapper(*static_cast<MessageImp*>(this)), ba::io_service::work(static_cast<ba::io_service&>(*this)),
1501 fStatus1(40), fStatus2(40), fStatusC(40), fStatusT(false),
1502 fDimConnection("FAD_CONTROL/CONNECTIONS", "C:40;C:1", "")
1503 {
1504 // ba::io_service::work is a kind of keep_alive for the loop.
1505 // It prevents the io_service to go to stopped state, which
1506 // would prevent any consecutive calls to run()
1507 // or poll() to do nothing. reset() could also revoke to the
1508 // previous state but this might introduce some overhead of
1509 // deletion and creation of threads and more.
1510
1511 // State names
1512 T::AddStateName(FAD::kOffline, "Disengaged",
1513 "All enabled FAD boards are disconnected and the event-builer thread is not running.");
1514
1515 T::AddStateName(FAD::kDisconnected, "Disconnected",
1516 "All enabled FAD boards are disconnected, but the event-builder thread is running.");
1517
1518 T::AddStateName(FAD::kConnecting, "Connecting",
1519 "Only some enabled FAD boards are connected.");
1520
1521 T::AddStateName(FAD::kConnected, "Connected",
1522 "All enabled FAD boards are connected..");
1523
1524 T::AddStateName(FAD::kConfiguring, "Configuring",
1525 ".");
1526
1527 T::AddStateName(FAD::kConfigured, "Configured",
1528 "The last header received through the command socket fits the requested configureation and has EventCounter==0.");
1529
1530 // FAD Commands
1531 T::AddEvent("SEND_CMD", "I:1")
1532 (bind(&StateMachineFAD::SendCmd, this, placeholders::_1))
1533 ("Send a command to the FADs. Values between 0 and 0xffff are allowed."
1534 "|command[uint16]:Command to be transmittted.");
1535 T::AddEvent("SEND_DATA", "I:2")
1536 (bind(&StateMachineFAD::SendCmdData, this, placeholders::_1))
1537 ("Send a command with data to the FADs. Values between 0 and 0xffff are allowed."
1538 "|command[uint16]:Command to be transmittted."
1539 "|data[uint16]:Data to be sent with the command.");
1540
1541 T::AddEvent("ENABLE_SRCLK", "B:1")
1542 (bind(&StateMachineFAD::CmdEnable, this, placeholders::_1, FAD::kCmdSrclk))
1543 ("Set SRCLK");
1544 T::AddEvent("ENABLE_BUSY", "B:1")
1545 (bind(&StateMachineFAD::CmdEnable, this, placeholders::_1, FAD::kCmdBusy))
1546 ("Set BUSY");
1547 T::AddEvent("ENABLE_SCLK", "B:1")
1548 (bind(&StateMachineFAD::CmdEnable, this, placeholders::_1, FAD::kCmdSclk))
1549 ("Set SCLK");
1550 T::AddEvent("ENABLE_DRS", "B:1")
1551 (bind(&StateMachineFAD::CmdEnable, this, placeholders::_1, FAD::kCmdDrsEnable))
1552 ("Switch Domino wave");
1553 T::AddEvent("ENABLE_DWRITE", "B:1")
1554 (bind(&StateMachineFAD::CmdEnable, this, placeholders::_1, FAD::kCmdDwrite))
1555 ("Set Dwrite (possibly high / always low)");
1556 T::AddEvent("ENABLE_CONTINOUS_TRIGGER", "B:1")
1557 (bind(&StateMachineFAD::CmdEnable, this, placeholders::_1, FAD::kCmdContTrigger))
1558 ("Enable continous (internal) trigger.");
1559 T::AddEvent("ENABLE_TRIGGER_LINE", "B:1")
1560 (bind(&StateMachineFAD::CmdEnable, this, placeholders::_1, FAD::kCmdTriggerLine))
1561 ("Incoming triggers can be accepted/will not be accepted");
1562 T::AddEvent("ENABLE_COMMAND_SOCKET_MODE", "B:1")
1563 (bind(&StateMachineFAD::CmdEnable, this, placeholders::_1, FAD::kCmdSocket))
1564 ("Set debug mode (yes: dump events through command socket, no=dump events through other sockets)");
1565
1566 T::AddEvent("SET_TRIGGER_RATE", "I:1")
1567 (bind(&StateMachineFAD::SetTriggerRate, this, placeholders::_1))
1568 ("Enable continous trigger");
1569 T::AddEvent("SEND_SINGLE_TRIGGER")
1570 (bind(&StateMachineFAD::Trigger, this, 1))
1571 ("Issue software triggers");
1572 T::AddEvent("SEND_N_TRIGGERS", "I")
1573 (bind(&StateMachineFAD::SendTriggers, this, placeholders::_1))
1574 ("Issue software triggers");
1575 T::AddEvent("START_RUN", "")
1576 (bind(&StateMachineFAD::StartRun, this, placeholders::_1, true))
1577 ("Set FAD DAQ mode. when started, no configurations must be send.");
1578 T::AddEvent("STOP_RUN")
1579 (bind(&StateMachineFAD::StartRun, this, placeholders::_1, false))
1580 ("");
1581 T::AddEvent("PHASE_SHIFT", "S:1")
1582 (bind(&StateMachineFAD::PhaseShift, this, placeholders::_1))
1583 ("Adjust ADC phase (in 'steps')");
1584
1585 T::AddEvent("RESET_EVENT_COUNTER")
1586 (bind(&StateMachineFAD::Cmd, this, FAD::kCmdResetEventCounter))
1587 ("");
1588
1589 T::AddEvent("SET_RUN_NUMBER", "X:1")
1590 (bind(&StateMachineFAD::SetRunNumber, this, placeholders::_1))
1591 ("");
1592
1593 T::AddEvent("SET_MAX_MEMORY", "S:1")
1594 (bind(&StateMachineFAD::SetMaxMemoryBuffer, this, placeholders::_1))
1595 ("Set maximum memory buffer size allowed to be consumed by the EventBuilder to buffer events."
1596 "|memory[short]:Buffer size in Mega-bytes.");
1597
1598 T::AddEvent("SET_REGISTER", "I:2")
1599 (bind(&StateMachineFAD::SetRegister, this, placeholders::_1))
1600 ("set register to value"
1601 "|addr[short]:Address of register"
1602 "|val[short]:Value to be set");
1603
1604 // FIXME: Maybe add a mask which channels should be set?
1605 T::AddEvent("SET_REGION_OF_INTEREST", "I:2")
1606 (bind(&StateMachineFAD::SetRoi, this, placeholders::_1))
1607 ("Set region-of-interest to value"
1608 "|addr[short]:Address of register"
1609 "|val[short]:Value to be set");
1610
1611 // FIXME: Maybe add a mask which channels should be set?
1612 T::AddEvent("SET_DAC_VALUE", "I:2")
1613 (bind(&StateMachineFAD::SetDac, this, placeholders::_1))
1614 ("Set DAC numbers in range to value"
1615 "|addr[short]:Address of register (-1 for all)"
1616 "|val[short]:Value to be set");
1617
1618 T::AddEvent("CONFIGURE", "C", FAD::kConnected, FAD::kConfigured)
1619 (bind(&StateMachineFAD::StartConfigure, this, placeholders::_1))
1620 ("");
1621
1622 T::AddEvent("RESET_CONFIGURE", FAD::kConfiguring, FAD::kConfigured)
1623 (bind(&StateMachineFAD::ResetConfig, this))
1624 ("");
1625
1626 // Verbosity commands
1627 T::AddEvent("SET_VERBOSE", "B:1")
1628 (bind(&StateMachineFAD::SetVerbosity, this, placeholders::_1))
1629 ("Set verbosity state"
1630 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
1631
1632 T::AddEvent("SET_HEX_OUTPUT", "B:1")
1633 (bind(&StateMachineFAD::SetHexOutput, this, placeholders::_1))
1634 ("Enable or disable hex output for received data"
1635 "|hexout[bool]:disable or enable hex output for received data (yes/no)");
1636
1637 T::AddEvent("SET_DATA_OUTPUT", "B:1")
1638 (bind(&StateMachineFAD::SetDataOutput, this, placeholders::_1))
1639 ("");
1640
1641 T::AddEvent("SET_DEBUG_TX", "B:1")
1642 (bind(&StateMachineFAD::SetDebugTx, this, placeholders::_1))
1643 ("Enable or disable the output of messages in case of successfull data transmission to the boards."
1644 "|debug[bool]:disable or enable debug output for transmitted data (yes/no)");
1645
1646 T::AddEvent("SET_DEBUG_EVENT_BUILDER_OUT", "B:1")
1647 (bind(&StateMachineFAD::SetDebugEb, this, placeholders::_1))
1648 ("");
1649
1650 T::AddEvent("PRINT_EVENT", "S:1")
1651 (bind(&StateMachineFAD::PrintEvent, this, placeholders::_1))
1652 ("Print (last) event"
1653 "|board[short]:slot from which the event should be printed (-1 for all)");
1654
1655 T::AddEvent("DUMP_STREAM", "B:1")
1656 (bind(&StateMachineFAD::SetDumpStream, this, placeholders::_1))
1657 ("For debugging purpose: the binary data stream read from the sockets 0-7 can be dumped to files."
1658 "|switch[bool]:Enable (yes) or disable (no)");
1659
1660 T::AddEvent("DUMP_RECV", "B:1")
1661 (bind(&StateMachineFAD::SetDumpRecv, this, placeholders::_1))
1662 ("For debugging purpose: the times when data has been receives are dumped to a file."
1663 "|switch[bool]:Enable (yes) or disable (no)");
1664
1665 T::AddEvent("BLOCK_TRANSMISSION", "S:1;B:1")
1666 (bind(&StateMachineFAD::SetBlockTransmission, this, placeholders::_1))
1667 ("Blocks the transmission of commands to the given slot. Use with care! For debugging pupose only!"
1668 "|slot[short]:Slot to which the command transmission should be blocked (0-39)"
1669 "|enable[bool]:Whether the command transmission should be blockes (yes) or allowed (no)");
1670
1671 T::AddEvent("BLOCK_TRANSMISSION_RANGE", "S:2;B:1")
1672 (bind(&StateMachineFAD::SetBlockTransmissionRange, this, placeholders::_1))
1673 ("Blocks the transmission of commands to the given range of slots. Use with care! For debugging pupose only!"
1674 "|first[short]:First slot to which the command transmission should be blocked (0-39)"
1675 "|last[short]:Last slot to which the command transmission should be blocked (0-39)"
1676 "|enable[bool]:Whether the command transmission should be blockes (yes) or allowed (no)");
1677
1678 T::AddEvent("IGNORE_EVENTS", "S:1;B:1")
1679 (bind(&StateMachineFAD::SetIgnoreSlot, this, placeholders::_1))
1680 ("Instructs the event-builder to ignore events from the given slot but still read the data from the socket."
1681 "|slot[short]:Slot from which the data should be ignored when building events"
1682 "|enable[bool]:Whether the event builder should ignore data from this slot (yes) or allowed (no)");
1683
1684 T::AddEvent("IGNORE_EVENTS_RANGE", "S:2;B:1")
1685 (bind(&StateMachineFAD::SetIgnoreSlots, this, placeholders::_1))
1686 ("Instructs the event-builder to ignore events from the given slot but still read the data from the socket."
1687 "|first[short]:First slot from which the data should be ignored when building events"
1688 "|last[short]:Last slot from which the data should be ignored when building events"
1689 "|enable[bool]:Whether the event builder should ignore data from this slot (yes) or allowed (no)");
1690
1691 T::AddEvent("CLOSE_OPEN_FILES", FAD::kConnecting, FAD::kConnected)
1692 (bind(&StateMachineFAD::CloseOpenFiles, this))
1693 ("Close all run files opened by the EventBuilder.");
1694
1695 T::AddEvent("TEST", "S:1")
1696 (bind(&StateMachineFAD::Test, this, placeholders::_1))
1697 ("");
1698
1699
1700
1701 // Conenction commands
1702 T::AddEvent("START", FAD::kOffline)
1703 (bind(&StateMachineFAD::StartConnection, this))
1704 ("Start EventBuilder thread and connect all valid slots.");
1705
1706 T::AddEvent("STOP", FAD::kDisconnected, FAD::kConnecting, FAD::kConnected)
1707 (bind(&StateMachineFAD::StopConnection, this))
1708 ("Stop EventBuilder thread (still write buffered events) and disconnect all slots.");
1709
1710 T::AddEvent("ABORT", FAD::kDisconnected, FAD::kConnecting, FAD::kConnected)
1711 (bind(&StateMachineFAD::AbortConnection, this))
1712 ("Immediately abort EventBuilder thread and disconnect all slots.");
1713
1714 T::AddEvent("SOFT_RESET", FAD::kConnected)
1715 (bind(&StateMachineFAD::Reset, this, true))
1716 ("Wait for buffers to drain, close all files and reinitialize event builder thread.");
1717
1718 T::AddEvent("HARD_RESET", FAD::kConnected)
1719 (bind(&StateMachineFAD::Reset, this, false))
1720 ("Free all buffers, close all files and reinitialize event builder thread.");
1721
1722 T::AddEvent("CONNECT", "S:1", FAD::kDisconnected, FAD::kConnecting, FAD::kConnected)
1723 (bind(&StateMachineFAD::EnableSlot, this, placeholders::_1, true))
1724 ("Connect a disconnected slot.");
1725
1726 T::AddEvent("DISCONNECT", "S:1", FAD::kConnecting, FAD::kConnected)
1727 (bind(&StateMachineFAD::EnableSlot, this, placeholders::_1, false))
1728 ("Disconnect a connected slot.");
1729
1730 T::AddEvent("TOGGLE", "S:1", FAD::kDisconnected, FAD::kConnecting, FAD::kConnected)
1731 (bind(&StateMachineFAD::ToggleSlot, this, placeholders::_1))
1732 ("");
1733
1734 T::AddEvent("SET_FILE_FORMAT", "S:1")
1735 (bind(&StateMachineFAD::SetFileFormat, this, placeholders::_1))
1736 ("");
1737
1738
1739 T::AddEvent("ADD_ADDRESS", "C", FAD::kOffline)
1740 (bind(&StateMachineFAD::AddAddress, this, placeholders::_1))
1741 ("Add the address of a DRS4 board to the first free slot"
1742 "|IP[string]:address in the format <address:port>");
1743 T::AddEvent("REMOVE_SLOT", "S:1", FAD::kOffline)
1744 (bind(&StateMachineFAD::RemoveSlot, this, placeholders::_1))
1745 ("Remove the Iaddress in slot n. For a list see LIST"
1746 "|slot[short]:Remove the address in slot n from the list");
1747 T::AddEvent("LIST_SLOTS")
1748 (bind(&StateMachineFAD::ListSlots, this))
1749 ("Print a list of all available board addressesa and whether they are enabled");
1750 }
1751
1752 ~StateMachineFAD()
1753 {
1754 for (BoardList::const_iterator i=fBoards.begin(); i!=fBoards.end(); i++)
1755 delete i->second;
1756 fBoards.clear();
1757 }
1758
1759 tcp::endpoint GetEndpoint(const string &base)
1760 {
1761 const size_t p0 = base.find_first_of(':');
1762 const size_t p1 = base.find_last_of(':');
1763
1764 if (p0==string::npos || p0!=p1)
1765 {
1766 T::Out() << kRed << "GetEndpoint - Wrong format ('host:port' expected)" << endl;
1767 return tcp::endpoint();
1768 }
1769
1770 tcp::resolver resolver(get_io_service());
1771
1772 boost::system::error_code ec;
1773
1774 const tcp::resolver::query query(base.substr(0, p0), base.substr(p0+1));
1775 const tcp::resolver::iterator iterator = resolver.resolve(query, ec);
1776
1777 if (ec)
1778 {
1779 T::Out() << kRed << "GetEndpoint - Couldn't resolve endpoint '" << base << "': " << ec.message();
1780 return tcp::endpoint();
1781 }
1782
1783 return *iterator;
1784 }
1785
1786 typedef map<string, FAD::Configuration> Configs;
1787 Configs fConfigs;
1788 Configs::const_iterator fTargetConfig;
1789
1790
1791 template<class V>
1792 bool CheckConfigVal(const Configuration &conf, V max, const string &name, const string &sub)
1793 {
1794 if (!conf.HasDef(name, sub))
1795 {
1796 T::Error("Neither "+name+"default nor "+name+sub+" found.");
1797 return false;
1798 }
1799
1800 const V val = conf.GetDef<V>(name, sub);
1801
1802 if (val<=max)
1803 return true;
1804
1805 ostringstream str;
1806 str << name << sub << "=" << val << " exceeds allowed maximum of " << max << "!";
1807 T::Error(str);
1808
1809 return false;
1810 }
1811
1812 int EvalConfiguration(const Configuration &conf)
1813 {
1814 // ---------- General setup ---------
1815 fIsVerbose = !conf.Get<bool>("quiet");
1816 fIsHexOutput = conf.Get<bool>("hex-out");
1817 fIsDataOutput = conf.Get<bool>("data-out");
1818 fDebugTx = conf.Get<bool>("debug-tx");
1819
1820 // ---------- Setup event builder ---------
1821 SetMaxMemory(conf.Get<unsigned int>("max-mem"));
1822
1823 // ---------- Setup run types ---------
1824 const vector<string> types = conf.Vec<string>("run-type");
1825 if (types.size()==0)
1826 T::Warn("No run-types defined.");
1827 else
1828 T::Message("Defining run-types");
1829 for (vector<string>::const_iterator it=types.begin();
1830 it!=types.end(); it++)
1831 {
1832 T::Message(" -> "+ *it);
1833
1834 if (fConfigs.count(*it)>0)
1835 {
1836 T::Error("Run-type "+*it+" defined twice.");
1837 return 1;
1838 }
1839
1840 FAD::Configuration target;
1841
1842 if (!CheckConfigVal<bool>(conf, true, "enable-drs.", *it) ||
1843 !CheckConfigVal<bool>(conf, true, "enable-dwrite.", *it) ||
1844 !CheckConfigVal<bool>(conf, true, "enable-continous-trigger.", *it))
1845 return 2;
1846
1847 target.fDenable = conf.GetDef<bool>("enable-drs.", *it);
1848 target.fDwrite = conf.GetDef<bool>("enable-dwrite.", *it);
1849 target.fContinousTrigger = conf.GetDef<bool>("enable-continous-trigger.", *it);
1850
1851 target.fTriggerRate = 0;
1852 //if (target.fContinousTrigger)
1853 {
1854 if (!CheckConfigVal<uint16_t>(conf, 0xffff, "trigger-rate.", *it))
1855 return 3;
1856
1857 target.fTriggerRate = conf.GetDef<uint16_t>("trigger-rate.", *it);
1858 }
1859
1860 for (int i=0; i<FAD::kNumChannelsPerChip; i++)
1861 {
1862 ostringstream str;
1863 str << "roi-ch" << i << '.';
1864
1865 if (!CheckConfigVal<uint16_t>(conf, FAD::kMaxRoiValue, "roi.", *it) &&
1866 !CheckConfigVal<uint16_t>(conf, FAD::kMaxRoiValue, str.str(), *it))
1867 return 4;
1868
1869 target.fRoi[i] = conf.HasDef(str.str(), *it) ?
1870 conf.GetDef<uint16_t>(str.str(), *it) :
1871 conf.GetDef<uint16_t>("roi.", *it);
1872 }
1873
1874 for (int i=0; i<FAD::kNumDac; i++)
1875 {
1876 ostringstream str;
1877 str << "dac-" << i << '.';
1878
1879 if (!CheckConfigVal<uint16_t>(conf, FAD::kMaxDacValue, "dac.", *it) &&
1880 !CheckConfigVal<uint16_t>(conf, FAD::kMaxDacValue, str.str(), *it))
1881 return 5;
1882
1883 target.fDac[i] = conf.HasDef(str.str(), *it) ?
1884 conf.GetDef<uint16_t>(str.str(), *it) :
1885 conf.GetDef<uint16_t>("dac.", *it);
1886 }
1887
1888 fConfigs[*it] = target;
1889 }
1890
1891 // FIXME: Add a check about unsused configurations
1892
1893 // ---------- Setup board addresses for fake-fad ---------
1894
1895 if (conf.Has("debug-addr"))
1896 {
1897 const string addr = conf.Get<string>("debug-addr");
1898 const int num = conf.Get<unsigned int>("debug-num");
1899
1900 const tcp::endpoint endpoint = GetEndpoint(addr);
1901 if (endpoint==tcp::endpoint())
1902 return 1;
1903
1904 for (int i=0; i<num; i++)
1905 AddEndpoint(tcp::endpoint(endpoint.address(), endpoint.port()+8*i));
1906
1907 StartConnection();
1908 return -1;
1909 }
1910
1911 // ---------- Setup board addresses for the real camera ---------
1912
1913 if (conf.Has("base-addr"))
1914 {
1915 string base = conf.Get<string>("base-addr");
1916
1917 if (base=="def" || base =="default")
1918 base = "10.0.128.128:31919";
1919
1920 const tcp::endpoint endpoint = GetEndpoint(base);
1921 if (endpoint==tcp::endpoint())
1922 return 10;
1923
1924 const ba::ip::address_v4::bytes_type ip = endpoint.address().to_v4().to_bytes();
1925
1926 if (ip[2]>250 || ip[3]>244)
1927 {
1928 T::Out() << kRed << "EvalConfiguration - IP address given by --base-addr out-of-range." << endl;
1929 return 11;
1930 }
1931
1932 for (int crate=0; crate<4; crate++)
1933 for (int board=0; board<10; board++)
1934 {
1935 ba::ip::address_v4::bytes_type target = endpoint.address().to_v4().to_bytes();
1936 target[2] += crate;
1937 target[3] += board;
1938
1939 AddEndpoint(tcp::endpoint(ba::ip::address_v4(target), endpoint.port()));
1940 }
1941
1942 StartConnection();
1943 return -1;
1944
1945 }
1946
1947 // ---------- Setup board addresses one by one ---------
1948
1949 if (conf.Has("addr"))
1950 {
1951 const vector<string> addrs = conf.Get<vector<string>>("addr");
1952 for (vector<string>::const_iterator i=addrs.begin(); i<addrs.end(); i++)
1953 {
1954 const tcp::endpoint endpoint = GetEndpoint(*i);
1955 if (endpoint==tcp::endpoint())
1956 return 12;
1957
1958 AddEndpoint(endpoint);
1959 }
1960
1961 StartConnection();
1962 return -1;
1963 }
1964
1965 return -1;
1966 }
1967
1968};
1969
1970// ------------------------------------------------------------------------
1971
1972#include "Main.h"
1973
1974/*
1975void RunThread(StateMachineImp *io_service)
1976{
1977 // This is necessary so that the StateMachien Thread can signal the
1978 // Readline to exit
1979 io_service->Run();
1980 Readline::Stop();
1981}
1982*/
1983/*
1984template<class S>
1985int RunDim(Configuration &conf)
1986{
1987 WindowLog wout;
1988
1989 ReadlineColor::PrintBootMsg(wout, conf.GetName(), false);
1990
1991 if (conf.Has("log"))
1992 if (!wout.OpenLogFile(conf.Get<string>("log")))
1993 wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
1994
1995 // Start io_service.Run to use the StateMachineImp::Run() loop
1996 // Start io_service.run to only use the commandHandler command detaching
1997 StateMachineFAD<S> io_service(wout);
1998 if (!io_service.EvalConfiguration(conf))
1999 return -1;
2000
2001 io_service.Run();
2002
2003 return 0;
2004}
2005*/
2006
2007template<class T, class S>
2008int RunShell(Configuration &conf)
2009{
2010 return Main<T, StateMachineFAD<S>>(conf);
2011/*
2012 static T shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
2013
2014 WindowLog &win = shell.GetStreamIn();
2015 WindowLog &wout = shell.GetStreamOut();
2016
2017 if (conf.Has("log"))
2018 if (!wout.OpenLogFile(conf.Get<string>("log")))
2019 win << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
2020
2021 StateMachineFAD<S> io_service(wout);
2022 if (!io_service.EvalConfiguration(conf))
2023 return -1;
2024
2025 shell.SetReceiver(io_service);
2026
2027 boost::thread t(bind(RunThread, &io_service));
2028 //boost::thread t(bind(&StateMachineFAD<S>::Run, &io_service));
2029
2030 if (conf.Has("cmd"))
2031 {
2032 const vector<string> v = conf.Get<vector<string>>("cmd");
2033 for (vector<string>::const_iterator it=v.begin(); it!=v.end(); it++)
2034 shell.ProcessLine(*it);
2035 }
2036
2037 if (conf.Has("exec"))
2038 {
2039 const vector<string> v = conf.Get<vector<string>>("exec");
2040 for (vector<string>::const_iterator it=v.begin(); it!=v.end(); it++)
2041 shell.Execute(*it);
2042 }
2043
2044 if (conf.Get<bool>("quit"))
2045 shell.Stop();
2046
2047 shell.Run(); // Run the shell
2048 io_service.Stop(); // Signal Loop-thread to stop
2049
2050 // Wait until the StateMachine has finished its thread
2051 // before returning and destroying the dim objects which might
2052 // still be in use.
2053 t.join();
2054
2055 return 0;
2056 */
2057}
2058
2059void SetupConfiguration(Configuration &conf)
2060{
2061 const string n = conf.GetName()+".log";
2062
2063 po::options_description config("Program options");
2064 config.add_options()
2065 ("dns", var<string>("localhost"), "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
2066 ("log,l", var<string>(n), "Write log-file")
2067// ("no-dim,d", po_switch(), "Disable dim services")
2068 ("console,c", var<int>(), "Use console (0=shell, 1=simple buffered, X=simple unbuffered)")
2069 ("cmd", vars<string>(), "Execute one or more commands at startup")
2070 ("exec,e", vars<string>(), "Execute one or more scrips at startup")
2071 ("quit", po_switch(), "Quit after startup");
2072 ;
2073
2074 po::options_description control("FAD control options");
2075 control.add_options()
2076 ("quiet,q", po_bool(), "Disable printing contents of all received messages in clear text.")
2077 ("hex-out", po_bool(), "Enable printing contents of all printed messages also as hex data.")
2078 ("data-out", po_bool(), "Enable printing received event data.")
2079 ("debug-tx", po_bool(), "Enable debugging of ethernet transmission.")
2080 ;
2081
2082 po::options_description connect("FAD connection options");
2083 connect.add_options()
2084 ("addr", vars<string>(), "Network address of FAD")
2085 ("base-addr", var<string>(), "Base address of all FAD")
2086 ("debug-num,n", var<unsigned int>(40), "Sets the number of fake boards to be connected locally")
2087 ("debug-addr", var<string>(), "")
2088 ;
2089
2090 po::options_description builder("Event builder options");
2091 builder.add_options()
2092 ("max-mem,m", var<unsigned int>(100), "Maximum memory the event builder thread is allowed to consume for its event buffer")
2093 ;
2094
2095
2096 po::options_description runtype("Run type configuration");
2097 runtype.add_options()
2098 ("run-type", vars<string>(), "")
2099 ("enable-dwrite.*", var<bool>(), "")
2100 ("enable-drs.*", var<bool>(), "")
2101 ("enable-continous-trigger.*", var<bool>(), "")
2102 ("trigger-rate.*", var<uint16_t>(), "")
2103 ("dac.*", var<uint16_t>(), "")
2104 ("dac-0.*", var<uint16_t>(), "")
2105 ("dac-1.*", var<uint16_t>(), "")
2106 ("dac-2.*", var<uint16_t>(), "")
2107 ("dac-3.*", var<uint16_t>(), "")
2108 ("dac-4.*", var<uint16_t>(), "")
2109 ("dac-5.*", var<uint16_t>(), "")
2110 ("dac-6.*", var<uint16_t>(), "")
2111 ("dac-7.*", var<uint16_t>(), "")
2112 ("roi.*", var<uint16_t>(), "")
2113 ("roi-ch0.*", var<uint16_t>(), "")
2114 ("roi-ch1.*", var<uint16_t>(), "")
2115 ("roi-ch2.*", var<uint16_t>(), "")
2116 ("roi-ch3.*", var<uint16_t>(), "")
2117 ("roi-ch4.*", var<uint16_t>(), "")
2118 ("roi-ch5.*", var<uint16_t>(), "")
2119 ("roi-ch6.*", var<uint16_t>(), "")
2120 ("roi-ch7.*", var<uint16_t>(), "")
2121 ("roi-ch8.*", var<uint16_t>(), "")
2122 ;
2123
2124 conf.AddEnv("dns", "DIM_DNS_NODE");
2125
2126 conf.AddOptions(config);
2127 conf.AddOptions(control);
2128 conf.AddOptions(connect);
2129 conf.AddOptions(builder);
2130 conf.AddOptions(runtype);
2131}
2132
2133void PrintUsage()
2134{
2135 cout <<
2136 "The fadctrl controls the FAD boards.\n"
2137 "\n"
2138 "The default is that the program is started without user intercation. "
2139 "All actions are supposed to arrive as DimCommands. Using the -c "
2140 "option, a local shell can be initialized. With h or help a short "
2141 "help message about the usuage can be brought to the screen.\n"
2142 "\n"
2143 "Usage: fadctrl [-c type] [OPTIONS]\n"
2144 " or: fadctrl [OPTIONS]\n";
2145 cout << endl;
2146}
2147
2148void PrintHelp()
2149{
2150 /* Additional help text which is printed after the configuration
2151 options goes here */
2152}
2153
2154int main(int argc, const char* argv[])
2155{
2156 Configuration conf(argv[0]);
2157 conf.SetPrintUsage(PrintUsage);
2158 SetupConfiguration(conf);
2159
2160 po::variables_map vm;
2161 try
2162 {
2163 vm = conf.Parse(argc, argv);
2164 }
2165#if BOOST_VERSION > 104000
2166 catch (po::multiple_occurrences &e)
2167 {
2168 cerr << "Program options invalid due to: " << e.what() << " of '" << e.get_option_name() << "'." << endl;
2169 return -1;
2170 }
2171#endif
2172 catch (exception& e)
2173 {
2174 cerr << "Program options invalid due to: " << e.what() << endl;
2175 return -1;
2176 }
2177
2178 if (conf.HasVersion() || conf.HasPrint())
2179 return -1;
2180
2181 if (conf.HasHelp())
2182 {
2183 PrintHelp();
2184 return -1;
2185 }
2186
2187 Dim::Setup(conf.Get<string>("dns"));
2188
2189// try
2190 {
2191 // No console access at all
2192 if (!conf.Has("console"))
2193 {
2194// if (conf.Get<bool>("no-dim"))
2195// return RunShell<LocalStream, StateMachine>(conf);
2196// else
2197 return RunShell<LocalStream, StateMachineDim>(conf);
2198 }
2199 // Cosole access w/ and w/o Dim
2200/* if (conf.Get<bool>("no-dim"))
2201 {
2202 if (conf.Get<int>("console")==0)
2203 return RunShell<LocalShell, StateMachine>(conf);
2204 else
2205 return RunShell<LocalConsole, StateMachine>(conf);
2206 }
2207 else
2208*/ {
2209 if (conf.Get<int>("console")==0)
2210 return RunShell<LocalShell, StateMachineDim>(conf);
2211 else
2212 return RunShell<LocalConsole, StateMachineDim>(conf);
2213 }
2214 }
2215/* catch (std::exception& e)
2216 {
2217 cerr << "Exception: " << e.what() << endl;
2218 return -1;
2219 }*/
2220
2221 return 0;
2222}
Note: See TracBrowser for help on using the repository browser.