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

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