source: branches/FACT++_lidctrl_usb/src/fadctrl.cc@ 20115

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