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

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