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

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