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

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