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

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