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

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