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

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