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

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