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

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