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

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