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

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