source: trunk/FACT++/src/ftmctrl.cc@ 11812

Last change on this file since 11812 was 11777, checked in by tbretz, 13 years ago
Added options to set N/4 threshold; renamed options for thresholds.
File size: 85.1 KB
Line 
1#include <array>
2
3#include "Dim.h"
4#include "Event.h"
5#include "Shell.h"
6#include "StateMachineDim.h"
7#include "Connection.h"
8#include "Configuration.h"
9#include "Console.h"
10#include "Converter.h"
11
12#include "tools.h"
13
14#include "HeadersFTM.h"
15
16
17namespace ba = boost::asio;
18namespace bs = boost::system;
19
20using namespace std;
21using namespace std::placeholders;
22
23// ------------------------------------------------------------------------
24
25class ConnectionFTM : public Connection
26{
27public:
28 enum States
29 {
30 // State Machine states
31 kDisconnected = 1,
32 kConnected,
33 kIdle,
34 kConfigured, // Returned if idle and fBufStaticData==fStaticData
35 kTakingData,
36 };
37
38private:
39 vector<uint16_t> fBuffer;
40
41 bool fHasHeader;
42
43 bool fIsVerbose;
44 bool fIsDynamicOut;
45 bool fIsHexOutput;
46
47// string fDefaultSetup;
48
49 // --verbose
50 // --hex-out
51 // --dynamic-out
52 // --load-file
53 // --leds
54 // --trigger-interval
55 // --physcis-coincidence
56 // --calib-coincidence
57 // --physcis-window
58 // --physcis-window
59 // --trigger-delay
60 // --time-marker-delay
61 // --dead-time
62 // --clock-conditioner-r0
63 // --clock-conditioner-r1
64 // --clock-conditioner-r8
65 // --clock-conditioner-r9
66 // --clock-conditioner-r11
67 // --clock-conditioner-r13
68 // --clock-conditioner-r14
69 // --clock-conditioner-r15
70 // ...
71
72protected:
73 map<uint16_t, uint32_t> fCounter;
74
75 FTM::Header fHeader;
76 FTM::FtuList fFtuList;
77 FTM::StaticData fStaticData;
78 FTM::DynamicData fDynamicData;
79 FTM::Error fError;
80
81 FTM::StaticData fBufStaticData;
82
83 virtual void UpdateFirstHeader()
84 {
85 // FIXME: Message() ?
86 Out() << endl << kBold << "First header received:" << endl;
87 Out() << fHeader;
88 if (fIsHexOutput)
89 Out() << Converter::GetHex<uint16_t>(fHeader, 16) << endl;
90 }
91
92 virtual void UpdateHeader()
93 {
94 // emit service with trigger counter from header
95 if (!fIsVerbose)
96 return;
97
98 if (fHeader.fType==FTM::kDynamicData && !fIsDynamicOut)
99 return;
100
101 Out() << endl << kBold << "Header received:" << endl;
102 Out() << fHeader;
103 if (fIsHexOutput)
104 Out() << Converter::GetHex<uint16_t>(fHeader, 16) << endl;
105 }
106
107 virtual void UpdateFtuList()
108 {
109 if (!fIsVerbose)
110 return;
111
112 Out() << endl << kBold << "FtuList received:" << endl;
113 Out() << fFtuList;
114 if (fIsHexOutput)
115 Out() << Converter::GetHex<uint16_t>(fFtuList, 16) << endl;
116 }
117
118 virtual void UpdateStaticData()
119 {
120 if (!fIsVerbose)
121 return;
122
123 Out() << endl << kBold << "Static data received:" << endl;
124 Out() << fStaticData;
125 if (fIsHexOutput)
126 Out() << Converter::GetHex<uint16_t>(fStaticData, 16) << endl;
127 }
128
129 virtual void UpdateDynamicData()
130 {
131 if (!fIsDynamicOut)
132 return;
133
134 Out() << endl << kBold << "Dynamic data received:" << endl;
135 Out() << fDynamicData;
136 if (fIsHexOutput)
137 Out() << Converter::GetHex<uint16_t>(fDynamicData, 16) << endl;
138 }
139
140 virtual void UpdateError()
141 {
142 if (!fIsVerbose)
143 return;
144
145 Out() << endl << kRed << "Error received:" << endl;
146 Out() << fError;
147 if (fIsHexOutput)
148 Out() << Converter::GetHex<uint16_t>(fError, 16) << endl;
149 }
150
151 virtual void UpdateCounter()
152 {
153 if (!fIsVerbose)
154 return;
155
156 if (!fIsDynamicOut)
157 return;
158
159 Out() << "Received: ";
160 Out() << "H=" << fCounter[FTM::kHeader] << " ";
161 Out() << "S=" << fCounter[FTM::kStaticData] << " ";
162 Out() << "D=" << fCounter[FTM::kDynamicData] << " ";
163 Out() << "F=" << fCounter[FTM::kFtuList] << " ";
164 Out() << "E=" << fCounter[FTM::kErrorList] << " ";
165 Out() << "R=" << fCounter[FTM::kRegister] << endl;
166 }
167
168 bool CheckConsistency(FTM::StaticData &data)
169 {
170 bool warn1 = false;
171 if (data.IsEnabled(FTM::StaticData::kPedestal) != (data.GetSequencePed() >0) ||
172 data.IsEnabled(FTM::StaticData::kLPint) != (data.GetSequenceLPint()>0) ||
173 data.IsEnabled(FTM::StaticData::kLPext) != (data.GetSequenceLPext()>0))
174 {
175 warn1 = true;
176 data.Enable(FTM::StaticData::kPedestal, data.GetSequencePed()>0);
177 data.Enable(FTM::StaticData::kLPint, data.GetSequenceLPint()>0);
178 data.Enable(FTM::StaticData::kLPext, data.GetSequenceLPext()>0);
179 }
180
181 bool warn2 = false;
182 const uint16_t ref = data[0].fPrescaling;
183 for (int i=1; i<40; i++)
184 {
185 if (data[i].fPrescaling != ref)
186 {
187 warn2 = true;
188 data[i].fPrescaling = ref;
189 }
190 }
191
192 bool warn3 = false;
193 for (int i=0; i<4; i++)
194 if (data.fActiveFTU[i]!=0x3ff)
195 {
196 warn3 = true;
197 data.fActiveFTU[i]=0x3ff;
198 }
199
200
201
202 if (warn1)
203 Warn("GeneralSettings not consistent with trigger sequence.");
204 if (warn2)
205 Warn("Prescaling not consistent for all boards.");
206 if (warn3)
207 Warn("Not all FTUs are enabled - enable all FTUs.");
208
209 return !warn1 && !warn2 && !warn3;
210 }
211
212private:
213 void HandleReceivedData(const bs::error_code& err, size_t bytes_received, int /*type*/)
214 {
215 // Do not schedule a new read if the connection failed.
216 if (bytes_received==0 || err)
217 {
218 if (err==ba::error::eof)
219 Warn("Connection closed by remote host (FTM).");
220
221 // 107: Transport endpoint is not connected (bs::error_code(107, bs::system_category))
222 // 125: Operation canceled
223 if (err && err!=ba::error::eof && // Connection closed by remote host
224 err!=ba::error::basic_errors::not_connected && // Connection closed by remote host
225 err!=ba::error::basic_errors::operation_aborted) // Connection closed by us
226 {
227 ostringstream str;
228 str << "Reading from " << URL() << ": " << err.message() << " (" << err << ")";// << endl;
229 Error(str);
230 }
231 PostClose(err!=ba::error::basic_errors::operation_aborted);
232 return;
233 }
234
235 // If we have not yet received a header we expect one now
236 // This could be moved to a HandleReceivedHeader function
237 if (!fHasHeader)
238 {
239 if (bytes_received!=sizeof(FTM::Header))
240 {
241 ostringstream str;
242 str << "Excepted " << sizeof(FTM::Header) << " bytes (FTM::Header) but received " << bytes_received << ".";
243 Error(str);
244 PostClose(false);
245 return;
246 }
247
248 fHeader = fBuffer;
249
250 // Check the data integrity
251 if (fHeader.fDelimiter!=FTM::kDelimiterStart)
252 {
253 ostringstream str;
254 str << "Invalid header received: start delimiter wrong, received ";
255 str << hex << fHeader.fDelimiter << ", expected " << FTM::kDelimiterStart << ".";
256 Error(str);
257 PostClose(false);
258 return;
259 }
260
261 fHasHeader = true;
262
263 // Convert FTM state into FtmCtrl state
264 if (++fCounter[FTM::kHeader]==1)
265 UpdateFirstHeader();
266
267 UpdateCounter();
268 UpdateHeader();
269
270 // Start reading of data
271 switch (fHeader.fType)
272 {
273 case FTM::kStaticData:
274 case FTM::kDynamicData:
275 case FTM::kFtuList:
276 case FTM::kRegister:
277 case FTM::kErrorList:
278 // This is not very efficient because the space is reallocated
279 // maybe we can check if the capacity of the std::vector
280 // is ever decreased. If not, everythign is fine.
281 fBuffer.resize(fHeader.fDataSize);
282 AsyncRead(ba::buffer(fBuffer));
283 AsyncWait(fInTimeout, 50, &Connection::HandleReadTimeout);
284 return;
285
286 default:
287 ostringstream str;
288 str << "Unknonw type " << fHeader.fType << " in received header." << endl;
289 Error(str);
290 PostClose(false);
291 return;
292 }
293
294 return;
295 }
296
297 // Check the data integrity (check end delimiter)
298 if (ntohs(fBuffer.back())!=FTM::kDelimiterEnd)
299 {
300 ostringstream str;
301 str << "Invalid data received: end delimiter wrong, received ";
302 str << hex << ntohs(fBuffer.back()) << ", expected " << FTM::kDelimiterEnd << ".";
303 Error(str);
304 PostClose(false);
305 return;
306 }
307
308 // Remove end delimiter
309 fBuffer.pop_back();
310
311 try
312 {
313 // If we have already received a header this is the data now
314 // This could be moved to a HandleReceivedData function
315
316 fCounter[fHeader.fType]++;
317 UpdateCounter();
318
319 switch (fHeader.fType)
320 {
321 case FTM::kFtuList:
322 fFtuList = fBuffer;
323 UpdateFtuList();
324 break;
325
326 case FTM::kStaticData:
327 if (fCounter[FTM::kStaticData]==1)
328 {
329 // This check is only done at startup
330 FTM::StaticData data(fBuffer);
331 if (!CheckConsistency(data))
332 {
333 CmdSendStatDat(data);
334 CmdPing(); // FIXME: Only needed in case of warn3
335 break;
336 }
337 }
338
339 fStaticData = fBuffer;
340 UpdateStaticData();
341 break;
342
343 case FTM::kDynamicData:
344 fDynamicData = fBuffer;
345 UpdateDynamicData();
346 break;
347
348 case FTM::kRegister:
349 if (fIsVerbose)
350 {
351 Out() << endl << kBold << "Register received: " << endl;
352 Out() << "Addr: " << ntohs(fBuffer[0]) << endl;
353 Out() << "Value: " << ntohs(fBuffer[1]) << endl;
354 }
355 break;
356
357 case FTM::kErrorList:
358 fError = fBuffer;
359 UpdateError();
360 break;
361
362 default:
363 ostringstream str;
364 str << "Unknonw type " << fHeader.fType << " in header." << endl;
365 Error(str);
366 PostClose(false);
367 return;
368 }
369 }
370 catch (const logic_error &e)
371 {
372 ostringstream str;
373 str << "Exception converting buffer into data structure: " << e.what();
374 Error(str);
375 PostClose(false);
376 return;
377 }
378
379 fInTimeout.cancel();
380
381 //fHeader.clear();
382 fHasHeader = false;
383 fBuffer.resize(sizeof(FTM::Header)/2);
384 AsyncRead(ba::buffer(fBuffer));
385 }
386
387 // This is called when a connection was established
388 void ConnectionEstablished()
389 {
390 fCounter.clear();
391 fBufStaticData.clear();
392
393 fHeader.clear();
394 fHasHeader = false;
395 fBuffer.resize(sizeof(FTM::Header)/2);
396 AsyncRead(ba::buffer(fBuffer));
397
398// if (!fDefaultSetup.empty())
399// LoadStaticData(fDefaultSetup);
400
401 // Get a header and configdata!
402 CmdReqStatDat();
403
404 // get the DNA of the FTUs
405 CmdPing();
406 }
407
408 void HandleReadTimeout(const bs::error_code &error)
409 {
410 if (error==ba::error::basic_errors::operation_aborted)
411 return;
412
413 if (error)
414 {
415 ostringstream str;
416 str << "Read timeout of " << URL() << ": " << error.message() << " (" << error << ")";// << endl;
417 Error(str);
418
419 PostClose();
420 return;
421
422 }
423
424 if (!is_open())
425 {
426 // For example: Here we could schedule a new accept if we
427 // would not want to allow two connections at the same time.
428 return;
429 }
430
431 // Check whether the deadline has passed. We compare the deadline
432 // against the current time since a new asynchronous operation
433 // may have moved the deadline before this actor had a chance
434 // to run.
435 if (fInTimeout.expires_at() > ba::deadline_timer::traits_type::now())
436 return;
437
438 Error("Timeout reading data from "+URL());
439
440 PostClose();
441 }
442
443
444 template<size_t N>
445 void PostCmd(array<uint16_t, N> dat, uint16_t u1=0, uint16_t u2=0, uint16_t u3=0, uint16_t u4=0)
446 {
447 array<uint16_t, 5> cmd = {{ '@', u1, u2, u3, u4 }};
448
449 ostringstream msg;
450 msg << "Sending command:" << hex;
451 msg << " 0x" << setw(4) << setfill('0') << cmd[0];
452 msg << " 0x" << setw(4) << setfill('0') << u1;
453 msg << " 0x" << setw(4) << setfill('0') << u2;
454 msg << " 0x" << setw(4) << setfill('0') << u3;
455 msg << " 0x" << setw(4) << setfill('0') << u4;
456 msg << " (+" << dec << dat.size() << " words)";
457 Message(msg);
458
459 vector<uint16_t> out(cmd.size()+dat.size());
460
461 transform(cmd.begin(), cmd.end(), out.begin(), htons);
462 transform(dat.begin(), dat.end(), out.begin()+cmd.size(), htons);
463
464 PostMessage(out);
465 }
466
467 void PostCmd(vector<uint16_t> dat, uint16_t u1=0, uint16_t u2=0, uint16_t u3=0, uint16_t u4=0)
468 {
469 array<uint16_t, 5> cmd = {{ '@', u1, u2, u3, u4 }};
470
471 ostringstream msg;
472 msg << "Sending command:" << hex;
473 msg << " 0x" << setw(4) << setfill('0') << cmd[0];
474 msg << " 0x" << setw(4) << setfill('0') << u1;
475 msg << " 0x" << setw(4) << setfill('0') << u2;
476 msg << " 0x" << setw(4) << setfill('0') << u3;
477 msg << " 0x" << setw(4) << setfill('0') << u4;
478 msg << " (+" << dec << dat.size() << " words)";
479 Message(msg);
480
481 vector<uint16_t> out(cmd.size()+dat.size());
482
483 transform(cmd.begin(), cmd.end(), out.begin(), htons);
484 copy(dat.begin(), dat.end(), out.begin()+cmd.size());
485
486 PostMessage(out);
487 }
488
489 void PostCmd(uint16_t u1=0, uint16_t u2=0, uint16_t u3=0, uint16_t u4=0)
490 {
491 PostCmd(array<uint16_t, 0>(), u1, u2, u3, u4);
492 }
493public:
494
495// static const uint16_t kMaxAddr;
496
497public:
498 ConnectionFTM(ba::io_service& ioservice, MessageImp &imp) : Connection(ioservice, imp()),
499 fIsVerbose(true), fIsDynamicOut(true), fIsHexOutput(true)
500 {
501 SetLogStream(&imp);
502 }
503
504 void CmdToggleLed()
505 {
506 PostCmd(FTM::kCmdToggleLed);
507 }
508
509 void CmdPing()
510 {
511 PostCmd(FTM::kCmdPing);
512 }
513
514 void CmdReqDynDat()
515 {
516 PostCmd(FTM::kCmdRead, FTM::kCmdDynamicData);
517 }
518
519 void CmdReqStatDat()
520 {
521 PostCmd(FTM::kCmdRead, FTM::kCmdStaticData);
522 }
523
524 void CmdSendStatDat(const FTM::StaticData &data)
525 {
526 fBufStaticData = data;
527
528 PostCmd(data.HtoN(), FTM::kCmdWrite, FTM::kCmdStaticData);
529
530 // Request the changed configuration to ensure the
531 // change is distributed in the network
532 CmdReqStatDat();
533 }
534
535 void CmdStartRun()
536 {
537 PostCmd(FTM::kCmdStartRun, FTM::kStartRun);
538
539 // Update state information by requesting a new header
540 CmdGetRegister(0);
541 }
542
543 void CmdStopRun()
544 {
545 PostCmd(FTM::kCmdStopRun);
546
547 // Update state information by requesting a new header
548 CmdGetRegister(0);
549 }
550
551 void CmdTakeNevents(uint32_t n)
552 {
553 const array<uint16_t, 2> data = {{ uint16_t(n>>16), uint16_t(n&0xffff) }};
554 PostCmd(data, FTM::kCmdStartRun, FTM::kTakeNevents);
555
556 // Update state information by requesting a new header
557 CmdGetRegister(0);
558 }
559
560 bool CmdSetRegister(uint16_t addr, uint16_t val)
561 {
562 if (addr>FTM::StaticData::kMaxAddr)
563 return false;
564
565 const array<uint16_t, 2> data = {{ addr, val }};
566 PostCmd(data, FTM::kCmdWrite, FTM::kCmdRegister);
567
568 reinterpret_cast<uint16_t*>(&fBufStaticData)[addr] = val;
569
570 // Request the changed configuration to ensure the
571 // change is distributed in the network
572 CmdReqStatDat();
573
574 return true;
575 }
576
577 bool CmdGetRegister(uint16_t addr)
578 {
579 if (addr>FTM::StaticData::kMaxAddr)
580 return false;
581
582 const array<uint16_t, 1> data = {{ addr }};
583 PostCmd(data, FTM::kCmdRead, FTM::kCmdRegister);
584
585 return true;
586 }
587
588 bool CmdResetCrate(uint16_t addr)
589 {
590 if (addr>3)
591 return false;
592
593 PostCmd(FTM::kCmdCrateReset, 1<<addr);
594
595 return true;
596 }
597
598 bool CmdResetCamera()
599 {
600 PostCmd(FTM::kCmdCrateReset, FTM::kResetCrate0);
601 PostCmd(FTM::kCmdCrateReset, FTM::kResetCrate1);
602 PostCmd(FTM::kCmdCrateReset, FTM::kResetCrate2);
603 PostCmd(FTM::kCmdCrateReset, FTM::kResetCrate3);
604
605 return true;
606 }
607
608 bool CmdDisableReports(bool b)
609 {
610 PostCmd(FTM::kCmdDisableReports, b ? uint16_t(0) : uint16_t(1));
611 return true;
612 }
613
614
615 void SetVerbose(bool b)
616 {
617 fIsVerbose = b;
618 }
619
620 void SetHexOutput(bool b)
621 {
622 fIsHexOutput = b;
623 }
624
625 void SetDynamicOut(bool b)
626 {
627 fIsDynamicOut = b;
628 }
629/*
630 void SetDefaultSetup(const string &file)
631 {
632 fDefaultSetup = file;
633 }
634*/
635
636 bool LoadStaticData(string name)
637 {
638 if (name.rfind(".bin")!=name.length()-4)
639 name += ".bin";
640
641 ifstream fin(name);
642 if (!fin)
643 return false;
644
645 FTM::StaticData data;
646
647 fin.read(reinterpret_cast<char*>(&data), sizeof(FTM::StaticData));
648
649 if (fin.gcount()<streamsize(sizeof(FTM::StaticData)))
650 return false;
651
652 if (fin.fail() || fin.eof())
653 return false;
654
655 if (fin.peek()!=-1)
656 return false;
657
658 CmdSendStatDat(data);
659
660 return true;
661 }
662
663 bool SaveStaticData(string name) const
664 {
665 if (name.rfind(".bin")!=name.length()-4)
666 name += ".bin";
667
668 ofstream fout(name);
669 if (!fout)
670 return false;
671
672 fout.write(reinterpret_cast<const char*>(&fStaticData), sizeof(FTM::StaticData));
673
674 return !fout.bad();
675 }
676
677 bool SetThreshold(int32_t patch, int32_t value)
678 {
679 if (patch>FTM::StaticData::kMaxPatchIdx)
680 return false;
681
682 if (value<0 || value>FTM::StaticData::kMaxDAC)
683 return false;
684
685 if (patch<0)
686 {
687 FTM::StaticData data(fStaticData);
688
689 bool ident = true;
690 for (int i=0; i<=FTM::StaticData::kMaxPatchIdx; i++)
691 if (data[i/4].fDAC[i%4] != value)
692 {
693 ident = false;
694 break;
695 }
696
697 if (ident)
698 return true;
699
700 for (int i=0; i<=FTM::StaticData::kMaxPatchIdx; i++)
701 data[i/4].fDAC[i%4] = value;
702
703 // Maybe move to a "COMMIT" command?
704 CmdSendStatDat(data);
705
706 return true;
707 }
708
709 /*
710 if (data[patch/4].fDAC[patch%4] == value)
711 return true;
712 */
713
714 // Calculate offset in static data block
715 const uint16_t addr = (uintptr_t(&fStaticData[patch/4].fDAC[patch%4])-uintptr_t(&fStaticData))/2;
716
717 // From CmdSetRegister
718 const array<uint16_t, 2> data = {{ addr, uint16_t(value) }};
719 PostCmd(data, FTM::kCmdWrite, FTM::kCmdRegister);
720
721 reinterpret_cast<uint16_t*>(&fBufStaticData)[addr] = value;
722
723 // Now execute change before the static data is requested back
724 PostCmd(FTM::kCmdConfigFTU, (patch/40) | (((patch/4)%10)<<8));
725
726 //CmdGetRegister(addr);
727 CmdReqStatDat();
728
729 return true;
730 }
731
732 bool SetNoutof4(int32_t patch, int32_t value)
733 {
734 if (patch>=FTM::StaticData::kMaxMultiplicity)
735 return false;
736
737 if (value<0 || value>FTM::StaticData::kMaxDAC)
738 return false;
739
740 if (patch<0)
741 {
742 FTM::StaticData data(fStaticData);
743
744 bool ident = true;
745 for (int i=0; i<FTM::StaticData::kMaxMultiplicity; i++)
746 if (data[i].fDAC[4] != value)
747 {
748 ident = false;
749 break;
750 }
751
752 if (ident)
753 return true;
754
755 for (int i=0; i<=FTM::StaticData::kMaxMultiplicity; i++)
756 data[i].fDAC[4] = value;
757
758 // Maybe move to a "COMMIT" command?
759 CmdSendStatDat(data);
760
761 return true;
762 }
763
764 /*
765 if (data[patch/4].fDAC[patch%4] == value)
766 return true;
767
768 data[patch/4].fDAC[patch%4] = value;
769
770 CmdSendStatDat(data);
771 return true;
772 */
773
774 // Calculate offset in static data block
775 const uint16_t addr = (uintptr_t(&fStaticData[patch].fDAC[4])-uintptr_t(&fStaticData))/2;
776
777 // From CmdSetRegister
778 const array<uint16_t, 2> data = {{ addr, uint16_t(value) }};
779 PostCmd(data, FTM::kCmdWrite, FTM::kCmdRegister);
780
781 reinterpret_cast<uint16_t*>(&fBufStaticData)[addr] = value;
782
783 // Now execute change before the static data is requested back
784 PostCmd(FTM::kCmdConfigFTU, (patch/40) | (((patch/4)%10)<<8));
785
786 //CmdGetRegister(addr);
787 CmdReqStatDat();
788
789 return true;
790 }
791
792 bool SetPrescaling(uint32_t value)
793 {
794 if (value>0xffff)
795 return false;
796
797 FTM::StaticData data(fStaticData);
798
799 bool ident = true;
800 for (int i=0; i<40; i++)
801 if (data[i].fPrescaling != value)
802 {
803 ident = false;
804 break;
805 }
806
807 if (ident)
808 return true;
809
810 data.SetPrescaling(value);
811
812 // Maybe move to a "COMMIT" command?
813 CmdSendStatDat(data);
814
815 return true;
816 }
817
818 bool EnableFTU(int32_t board, bool enable)
819 {
820 if (board>39)
821 return false;
822
823 FTM::StaticData data(fStaticData);
824
825 if (board<0)
826 {
827 if (enable)
828 data.EnableAllFTU();
829 else
830 data.DisableAllFTU();
831 }
832 else
833 {
834 if (enable)
835 data.EnableFTU(board);
836 else
837 data.DisableFTU(board);
838
839 }
840
841 // Maybe move to a "COMMIT" command?
842 CmdSendStatDat(data);
843
844 return true;
845 }
846
847 bool ToggleFTU(uint32_t board)
848 {
849 if (board>39)
850 return false;
851
852 FTM::StaticData data(fStaticData);
853
854 data.ToggleFTU(board);
855
856 // Maybe move to a "COMMIT" command?
857 CmdSendStatDat(data);
858
859 return true;
860 }
861
862 bool SetVal(uint16_t *dest, uint32_t val, uint32_t max)
863 {
864 if (val>max)
865 return false;
866
867 if (*dest==val)
868 return true;
869
870 FTM::StaticData data(fStaticData);
871
872 dest = reinterpret_cast<uint16_t*>(&data) + (dest - reinterpret_cast<uint16_t*>(&fStaticData));
873
874 *dest = val;
875
876 CmdSendStatDat(data);
877
878 return true;
879 }
880
881 bool SetTriggerInterval(uint32_t val)
882 {
883 return SetVal(&fStaticData.fTriggerInterval, val,
884 FTM::StaticData::kMaxTriggerInterval);
885 }
886
887 bool SetTriggerDelay(uint32_t val)
888 {
889 return SetVal(&fStaticData.fDelayTrigger, val,
890 FTM::StaticData::kMaxDelayTrigger);
891 }
892
893 bool SetTimeMarkerDelay(uint32_t val)
894 {
895 return SetVal(&fStaticData.fDelayTimeMarker, val,
896 FTM::StaticData::kMaxDelayTimeMarker);
897 }
898
899 bool SetDeadTime(uint32_t val)
900 {
901 return SetVal(&fStaticData.fDeadTime, val,
902 FTM::StaticData::kMaxDeadTime);
903 }
904
905 void Enable(FTM::StaticData::GeneralSettings type, bool enable)
906 {
907 //if (fStaticData.IsEnabled(type)==enable)
908 // return;
909
910 FTM::StaticData data(fStaticData);
911 data.Enable(type, enable);
912 CmdSendStatDat(data);
913 }
914
915 bool SetTriggerSeq(const uint16_t d[3])
916 {
917 if (d[0]>FTM::StaticData::kMaxSequence ||
918 d[1]>FTM::StaticData::kMaxSequence ||
919 d[2]>FTM::StaticData::kMaxSequence)
920 return false;
921
922 FTM::StaticData data(fStaticData);
923
924 /*
925 data.Enable(FTM::StaticData::kPedestal, d[0]>0);
926 data.Enable(FTM::StaticData::kLPext, d[1]>0);
927 data.Enable(FTM::StaticData::kLPint, d[2]>0);
928 */
929
930 data.SetSequence(d[0], d[2], d[1]);
931
932 //if (fStaticData.fTriggerSeq !=data.fTriggerSequence ||
933 // fStaticData.fGeneralSettings!=data.fGeneralSettings)
934 // CmdSendStatDat(data);
935
936 CmdSendStatDat(data);
937
938 return true;
939 }
940
941 bool SetTriggerMultiplicity(uint16_t n)
942 {
943 if (n==0 || n>FTM::StaticData::kMaxMultiplicity)
944 return false;
945
946 if (n==fStaticData.fMultiplicityPhysics)
947 return true;
948
949 FTM::StaticData data(fStaticData);
950
951 data.fMultiplicityPhysics = n;
952
953 CmdSendStatDat(data);
954
955 return true;
956 }
957
958 bool SetTriggerWindow(uint16_t win)
959 {
960 if (win>FTM::StaticData::kMaxWindow)
961 return false;
962
963 if (win==fStaticData.fWindowPhysics)
964 return true;
965
966 FTM::StaticData data(fStaticData);
967
968 data.fWindowPhysics = win;
969
970 CmdSendStatDat(data);
971
972 return true;
973 }
974
975 bool SetCalibMultiplicity(uint16_t n)
976 {
977 if (n==0 || n>FTM::StaticData::kMaxMultiplicity)
978 return false;
979
980 if (n==fStaticData.fMultiplicityCalib)
981 return true;
982
983 FTM::StaticData data(fStaticData);
984
985 data.fMultiplicityCalib = n;
986
987 CmdSendStatDat(data);
988
989 return true;
990 }
991
992 bool SetCalibWindow(uint16_t win)
993 {
994 if (win>FTM::StaticData::kMaxWindow)
995 return false;
996
997 if (win==fStaticData.fWindowCalib)
998 return true;
999
1000 FTM::StaticData data(fStaticData);
1001
1002 data.fWindowCalib = win;
1003
1004 CmdSendStatDat(data);
1005
1006 return true;
1007 }
1008
1009 bool SetClockRegister(const uint64_t reg[])
1010 {
1011 FTM::StaticData data(fStaticData);
1012
1013 for (int i=0; i<8; i++)
1014 if (reg[i]>0xffffffff)
1015 return false;
1016
1017 data.SetClockRegister(reg);
1018
1019 CmdSendStatDat(data);
1020
1021 return true;
1022 }
1023
1024 bool EnableLP(FTM::StaticData::GeneralSettings lp, FTM::StaticData::LightPulserEnable group, bool enable)
1025 {
1026 if (lp!=FTM::StaticData::kLPint && lp!=FTM::StaticData::kLPext)
1027 return false;
1028
1029 FTM::StaticData data(fStaticData);
1030
1031 if (lp==FTM::StaticData::kLPint)
1032 data.EnableLPint(group, enable);
1033
1034 if (lp==FTM::StaticData::kLPext)
1035 data.EnableLPext(group, enable);
1036
1037 CmdSendStatDat(data);
1038
1039 return true;
1040 }
1041
1042 bool SetIntensity(FTM::StaticData::GeneralSettings lp, uint16_t intensity)
1043 {
1044 if (intensity>FTM::StaticData::kMaxIntensity)
1045 return false;
1046
1047 if (lp!=FTM::StaticData::kLPint && lp!=FTM::StaticData::kLPext)
1048 return false;
1049
1050 FTM::StaticData data(fStaticData);
1051
1052 if (lp==FTM::StaticData::kLPint)
1053 data.fIntensityLPint = intensity;
1054
1055 if (lp==FTM::StaticData::kLPext)
1056 data.fIntensityLPext = intensity;
1057
1058 CmdSendStatDat(data);
1059
1060 return true;
1061 }
1062
1063 bool EnablePixel(int16_t idx, bool enable)
1064 {
1065 if (idx<-1 || idx>FTM::StaticData::kMaxPixelIdx)
1066 return false;
1067
1068 if (idx==-1)
1069 {
1070 FTM::StaticData data(fStaticData);
1071
1072 for (int i=0; i<=FTM::StaticData::kMaxPixelIdx; i++)
1073 data.EnablePixel(i, enable);
1074
1075 CmdSendStatDat(data);
1076
1077 return true;
1078 }
1079
1080 /*
1081 data.EnablePixel(idx, enable);
1082 CmdSendStatDat(data);
1083 return true;
1084 */
1085
1086 FTM::StaticData data(fStaticData);
1087
1088 const uintptr_t base = uintptr_t(&data);
1089 const uint16_t *mem = data.EnablePixel(idx, enable);
1090
1091 // Calculate offset in static data block
1092 const uint16_t addr = (uintptr_t(mem)-base)/2;
1093
1094 // From CmdSetRegister
1095 const array<uint16_t, 2> cmd = {{ addr, *mem }};
1096 PostCmd(cmd, FTM::kCmdWrite, FTM::kCmdRegister);
1097
1098 reinterpret_cast<uint16_t*>(&fBufStaticData)[addr] = *mem;
1099
1100 // Now execute change before the static data is requested back
1101 PostCmd(FTM::kCmdConfigFTU, (idx/360) | (((idx/36)%10)<<8));
1102
1103 // Now request the register back to ensure consistency
1104 //CmdGetRegister(addr);
1105 CmdReqStatDat();
1106
1107 return true;
1108 }
1109
1110 bool DisableAllPixelsExcept(uint16_t idx)
1111 {
1112 if (idx>FTM::StaticData::kMaxPixelIdx)
1113 return false;
1114
1115 FTM::StaticData data(fStaticData);
1116
1117 for (int i=0; i<=FTM::StaticData::kMaxPixelIdx; i++)
1118 data.EnablePixel(i, i==idx);
1119
1120 CmdSendStatDat(data);
1121
1122 return true;
1123 }
1124
1125 bool DisableAllPatchesExcept(int16_t idx)
1126 {
1127 if (idx>FTM::StaticData::kMaxPatchIdx)
1128 return false;
1129
1130 FTM::StaticData data(fStaticData);
1131
1132 for (int i=0; i<=FTM::StaticData::kMaxPixelIdx; i++)
1133 data.EnablePixel(i, i<0 || i/9==idx);
1134
1135 CmdSendStatDat(data);
1136
1137 return true;
1138 }
1139
1140 bool TogglePixel(uint16_t idx)
1141 {
1142 if (idx>FTM::StaticData::kMaxPixelIdx)
1143 return false;
1144
1145 FTM::StaticData data(fStaticData);
1146
1147 data.EnablePixel(idx, !fStaticData.Enabled(idx));
1148
1149 CmdSendStatDat(data);
1150
1151 return true;
1152 }
1153
1154 States GetState() const
1155 {
1156 if (!IsConnected())
1157 return kDisconnected;
1158
1159 switch (fHeader.fState&FTM::kFtmStates)
1160 {
1161 case FTM::kFtmUndefined:
1162 return kConnected;
1163
1164 case FTM::kFtmRunning:
1165 case FTM::kFtmCalib:
1166 return kTakingData;
1167
1168 case FTM::kFtmIdle:
1169 case FTM::kFtmConfig:
1170 return fStaticData == fBufStaticData ? kConfigured : kIdle;
1171 }
1172
1173 throw runtime_error("ConnectionFTM::GetState - Impossible code reached.");
1174 }
1175
1176 int GetCounter(FTM::Types type) { return fCounter[type]; }
1177
1178 const FTM::StaticData &GetStaticData() const { return fStaticData; }
1179};
1180
1181//const uint16_t ConnectionFTM::kMaxAddr = 0xfff;
1182
1183// ------------------------------------------------------------------------
1184
1185#include "DimDescriptionService.h"
1186
1187class ConnectionDimFTM : public ConnectionFTM
1188{
1189private:
1190
1191 DimDescribedService fDimPassport;
1192 DimDescribedService fDimTriggerRates;
1193 DimDescribedService fDimError;
1194 DimDescribedService fDimFtuList;
1195 DimDescribedService fDimStaticData;
1196 DimDescribedService fDimDynamicData;
1197 DimDescribedService fDimCounter;
1198
1199 uint64_t fTimeStamp;
1200 uint32_t fTriggerCounter;
1201
1202 void UpdateFirstHeader()
1203 {
1204 ConnectionFTM::UpdateFirstHeader();
1205
1206 const FTM::DimPassport data(fHeader);
1207 fDimPassport.Update(data);
1208 }
1209
1210 /*
1211 void UpdateHeader()
1212 {
1213 ConnectionFTM::UpdateHeader();
1214
1215 if (fHeader.fType!=FTM::kDynamicData)
1216 return;
1217
1218 const FTM::DimTriggerCounter data(fHeader);
1219 fDimTriggerCounter.Update(data);
1220 }*/
1221
1222 void UpdateFtuList()
1223 {
1224 ConnectionFTM::UpdateFtuList();
1225
1226 const FTM::DimFtuList data(fHeader, fFtuList);
1227 fDimFtuList.Update(data);
1228 }
1229
1230 void UpdateStaticData()
1231 {
1232 ConnectionFTM::UpdateStaticData();
1233
1234 const FTM::DimStaticData data(fHeader, fStaticData);
1235 fDimStaticData.Update(data);
1236 }
1237
1238 void UpdateDynamicData()
1239 {
1240 ConnectionFTM::UpdateDynamicData();
1241
1242 const FTM::DimDynamicData data(fHeader, fDynamicData, fStaticData);
1243 fDimDynamicData.Update(data);
1244
1245 float rate = -1;
1246 if (fHeader.fTimeStamp>=fTimeStamp && fHeader.fTriggerCounter>=fTriggerCounter)
1247 {
1248 const uint64_t tdiff = fHeader.fTimeStamp -fTimeStamp;
1249 const uint32_t cdiff = fHeader.fTriggerCounter-fTriggerCounter;
1250
1251 rate = tdiff==0 ? 0 : 1000000*float(cdiff)/tdiff;
1252 }
1253
1254 fTimeStamp = fHeader.fTimeStamp;
1255 fTriggerCounter = fHeader.fTriggerCounter;
1256
1257 const FTM::DimTriggerRates rates(fHeader, fDynamicData, fStaticData, rate);
1258 fDimTriggerRates.Update(rates);
1259 }
1260
1261 void UpdateError()
1262 {
1263 ConnectionFTM::UpdateError();
1264
1265 const FTM::DimError data(fHeader, fError);
1266 fDimError.Update(data);
1267 }
1268
1269 void UpdateCounter()
1270 {
1271 ConnectionFTM::UpdateCounter();
1272
1273 const uint32_t counter[6] =
1274 {
1275 fCounter[FTM::kHeader],
1276 fCounter[FTM::kStaticData],
1277 fCounter[FTM::kDynamicData],
1278 fCounter[FTM::kFtuList],
1279 fCounter[FTM::kErrorList],
1280 fCounter[FTM::kRegister],
1281 };
1282
1283 fDimCounter.Update(counter);
1284 }
1285
1286public:
1287 ConnectionDimFTM(ba::io_service& ioservice, MessageImp &imp) :
1288 ConnectionFTM(ioservice, imp),
1289 fDimPassport ("FTM_CONTROL/PASSPORT", "X:1;S:1", ""),
1290 fDimTriggerRates ("FTM_CONTROL/TRIGGER_RATES", "X:2;I:1;F:1;F:40;F:160", ""),
1291 fDimError ("FTM_CONTROL/ERROR", "X:1;S:1;S:28", ""),
1292 fDimFtuList ("FTM_CONTROL/FTU_LIST", "X:1;X:1;S:1;C:4;X:40;C:40;C:40", ""),
1293 fDimStaticData ("FTM_CONTROL/STATIC_DATA", "X:1;S:1;S:1;X:1;S:1;S:3;C:4;S:1;S:1;S:1;S:1;S:1;S:1;I:1;I:8;S:90;S:160;S:40;S:40", ""),
1294 fDimDynamicData ("FTM_CONTROL/DYNAMIC_DATA", "X:1;X:1;F:4;I:160;I:40;S:40;S:40;S:40;S:1", ""),
1295 fDimCounter ("FTM_CONTROL/COUNTER", "I:6", ""),
1296 fTimeStamp(UINT64_MAX),
1297 fTriggerCounter(UINT32_MAX)
1298 {
1299 }
1300
1301 // A B [C] [D] E [F] G H [I] J K [L] M N O P Q R [S] T U V W [X] Y Z
1302};
1303
1304// ------------------------------------------------------------------------
1305
1306template <class T, class S>
1307class StateMachineFTM : public T, public ba::io_service, public ba::io_service::work
1308{
1309 int Wrap(boost::function<void()> f)
1310 {
1311 f();
1312 return T::GetCurrentState();
1313 }
1314
1315 function<int(const EventImp &)> Wrapper(function<void()> func)
1316 {
1317 return bind(&StateMachineFTM::Wrap, this, func);
1318 }
1319
1320private:
1321 S fFTM;
1322
1323 bool CheckEventSize(size_t has, const char *name, size_t size)
1324 {
1325 if (has==size)
1326 return true;
1327
1328 ostringstream msg;
1329 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
1330 T::Fatal(msg);
1331 return false;
1332 }
1333
1334 int SetRegister(const EventImp &evt)
1335 {
1336 if (!CheckEventSize(evt.GetSize(), "SetRegister", 8))
1337 return T::kSM_FatalError;
1338
1339 const uint32_t *dat = evt.Ptr<uint32_t>();
1340
1341 if (dat[1]>uint16_t(-1))
1342 {
1343 ostringstream msg;
1344 msg << hex << "Value " << dat[1] << " out of range.";
1345 T::Error(msg);
1346 return T::GetCurrentState();
1347 }
1348
1349
1350 if (dat[0]>uint16_t(-1) || !fFTM.CmdSetRegister(dat[0], dat[1]))
1351 {
1352 ostringstream msg;
1353 msg << hex << "Address " << dat[0] << " out of range.";
1354 T::Error(msg);
1355 }
1356
1357 return T::GetCurrentState();
1358 }
1359
1360 int GetRegister(const EventImp &evt)
1361 {
1362 if (!CheckEventSize(evt.GetSize(), "GetRegister", 4))
1363 return T::kSM_FatalError;
1364
1365 const unsigned int addr = evt.GetInt();
1366 if (addr>uint16_t(-1) || !fFTM.CmdGetRegister(addr))
1367 {
1368 ostringstream msg;
1369 msg << hex << "Address " << addr << " out of range.";
1370 T::Error(msg);
1371 }
1372
1373 return T::GetCurrentState();
1374 }
1375
1376 int TakeNevents(const EventImp &evt)
1377 {
1378 if (!CheckEventSize(evt.GetSize(), "TakeNevents", 4))
1379 return T::kSM_FatalError;
1380
1381 const unsigned int dat = evt.GetUInt();
1382
1383 /*
1384 if (dat[1]>uint32_t(-1))
1385 {
1386 ostringstream msg;
1387 msg << hex << "Value " << dat[1] << " out of range.";
1388 T::Error(msg);
1389 return T::GetCurrentState();
1390 }*/
1391
1392 fFTM.CmdTakeNevents(dat);
1393
1394 return T::GetCurrentState();
1395 }
1396
1397 int DisableReports(const EventImp &evt)
1398 {
1399 if (!CheckEventSize(evt.GetSize(), "DisableReports", 1))
1400 return T::kSM_FatalError;
1401
1402 fFTM.CmdDisableReports(evt.GetBool());
1403
1404 return T::GetCurrentState();
1405 }
1406
1407 int SetVerbosity(const EventImp &evt)
1408 {
1409 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
1410 return T::kSM_FatalError;
1411
1412 fFTM.SetVerbose(evt.GetBool());
1413
1414 return T::GetCurrentState();
1415 }
1416
1417 int SetHexOutput(const EventImp &evt)
1418 {
1419 if (!CheckEventSize(evt.GetSize(), "SetHexOutput", 1))
1420 return T::kSM_FatalError;
1421
1422 fFTM.SetHexOutput(evt.GetBool());
1423
1424 return T::GetCurrentState();
1425 }
1426
1427 int SetDynamicOut(const EventImp &evt)
1428 {
1429 if (!CheckEventSize(evt.GetSize(), "SetDynamicOut", 1))
1430 return T::kSM_FatalError;
1431
1432 fFTM.SetDynamicOut(evt.GetBool());
1433
1434 return T::GetCurrentState();
1435 }
1436
1437 int LoadStaticData(const EventImp &evt)
1438 {
1439 if (fFTM.LoadStaticData(evt.GetString()))
1440 return T::GetCurrentState();
1441
1442 ostringstream msg;
1443 msg << "Loading static data from file '" << evt.GetString() << "' failed ";
1444
1445 if (errno)
1446 msg << "(" << strerror(errno) << ")";
1447 else
1448 msg << "(wrong size, expected " << sizeof(FTM::StaticData) << " bytes)";
1449
1450 T::Warn(msg);
1451
1452 return T::GetCurrentState();
1453 }
1454
1455 int SaveStaticData(const EventImp &evt)
1456 {
1457 if (fFTM.SaveStaticData(evt.GetString()))
1458 return T::GetCurrentState();
1459
1460 ostringstream msg;
1461 msg << "Writing static data to file '" << evt.GetString() << "' failed ";
1462 msg << "(" << strerror(errno) << ")";
1463
1464 T::Warn(msg);
1465
1466 return T::GetCurrentState();
1467 }
1468
1469 int SetThreshold(const EventImp &evt)
1470 {
1471 if (!CheckEventSize(evt.GetSize(), "SetThreshold", 8))
1472 return T::kSM_FatalError;
1473
1474 const int32_t *data = evt.Ptr<int32_t>();
1475
1476 if (!fFTM.SetThreshold(data[0], data[1]))
1477 T::Warn("SetThreshold - Maximum allowed patch number 159, valid value range 0-0xffff");
1478
1479 return T::GetCurrentState();
1480 }
1481
1482 int SetNoutof4(const EventImp &evt)
1483 {
1484 if (!CheckEventSize(evt.GetSize(), "SetNoutof4", 8))
1485 return T::kSM_FatalError;
1486
1487 const int32_t *data = evt.Ptr<int32_t>();
1488
1489 if (!fFTM.SetNoutof4(data[0], data[1]))
1490 T::Warn("SetNoutof4 - Maximum allowed board number 39, valid value range 0-0xffff");
1491
1492 return T::GetCurrentState();
1493 }
1494
1495 int EnableFTU(const EventImp &evt)
1496 {
1497 if (!CheckEventSize(evt.GetSize(), "EnableFTU", 5))
1498 return T::kSM_FatalError;
1499
1500 const int32_t &board = evt.Get<int32_t>();
1501 const int8_t &enable = evt.Get<int8_t>(4);
1502
1503 if (!fFTM.EnableFTU(board, enable))
1504 T::Warn("EnableFTU - Board number must be <40.");
1505
1506 return T::GetCurrentState();
1507 }
1508
1509 int ToggleFTU(const EventImp &evt)
1510 {
1511 if (!CheckEventSize(evt.GetSize(), "ToggleFTU", 4))
1512 return T::kSM_FatalError;
1513
1514 if (!fFTM.ToggleFTU(evt.GetInt()))
1515 T::Warn("ToggleFTU - Allowed range of boards 0-39.");
1516
1517 return T::GetCurrentState();
1518 }
1519
1520 int SetTriggerInterval(const EventImp &evt)
1521 {
1522 if (!CheckEventSize(evt.GetSize(), "SetTriggerInterval", 4))
1523 return T::kSM_FatalError;
1524
1525 if (!fFTM.SetTriggerInterval(evt.GetInt()))
1526 T::Warn("SetTriggerInterval - Value out of range.");
1527
1528 return T::GetCurrentState();
1529 }
1530
1531 int SetTriggerDelay(const EventImp &evt)
1532 {
1533 if (!CheckEventSize(evt.GetSize(), "SetTriggerDelay", 4))
1534 return T::kSM_FatalError;
1535
1536 if (!fFTM.SetTriggerDelay(evt.GetInt()))
1537 T::Warn("SetTriggerDealy - Value out of range.");
1538
1539 return T::GetCurrentState();
1540 }
1541
1542 int SetTimeMarkerDelay(const EventImp &evt)
1543 {
1544 if (!CheckEventSize(evt.GetSize(), "SetTimeMarkerDelay", 4))
1545 return T::kSM_FatalError;
1546
1547 if (!fFTM.SetTimeMarkerDelay(evt.GetInt()))
1548 T::Warn("SetTimeMarkerDelay - Value out of range.");
1549
1550 return T::GetCurrentState();
1551 }
1552
1553 int SetPrescaling(const EventImp &evt)
1554 {
1555 if (!CheckEventSize(evt.GetSize(), "SetPrescaling", 4))
1556 return T::kSM_FatalError;
1557
1558 if (!fFTM.SetPrescaling(evt.GetInt()-1))
1559 T::Warn("SetPrescaling - Value out of range.");
1560
1561 return T::GetCurrentState();
1562 }
1563
1564 int SetTriggerSeq(const EventImp &evt)
1565 {
1566 if (!CheckEventSize(evt.GetSize(), "SetTriggerSeq", 6))
1567 return T::kSM_FatalError;
1568
1569 const uint16_t *data = evt.Ptr<uint16_t>();
1570
1571 if (!fFTM.SetTriggerSeq(data))
1572 T::Warn("SetTriggerSeq - Value out of range.");
1573
1574 return T::GetCurrentState();
1575 }
1576
1577 int SetDeadTime(const EventImp &evt)
1578 {
1579 if (!CheckEventSize(evt.GetSize(), "SetDeadTime", 4))
1580 return T::kSM_FatalError;
1581
1582 if (!fFTM.SetDeadTime(evt.GetInt()))
1583 T::Warn("SetDeadTime - Value out of range.");
1584
1585 return T::GetCurrentState();
1586 }
1587
1588 int SetTriggerMultiplicity(const EventImp &evt)
1589 {
1590 if (!CheckEventSize(evt.GetSize(), "SetTriggerMultiplicity", 2))
1591 return T::kSM_FatalError;
1592
1593 if (!fFTM.SetTriggerMultiplicity(evt.GetUShort()))
1594 T::Warn("SetTriggerMultiplicity - Value out of range.");
1595
1596 return T::GetCurrentState();
1597 }
1598
1599 int SetCalibMultiplicity(const EventImp &evt)
1600 {
1601 if (!CheckEventSize(evt.GetSize(), "SetCalibMultiplicity", 2))
1602 return T::kSM_FatalError;
1603
1604 if (!fFTM.SetCalibMultiplicity(evt.GetUShort()))
1605 T::Warn("SetCalibMultiplicity - Value out of range.");
1606
1607 return T::GetCurrentState();
1608 }
1609
1610 int SetTriggerWindow(const EventImp &evt)
1611 {
1612 if (!CheckEventSize(evt.GetSize(), "SetTriggerWindow", 2))
1613 return T::kSM_FatalError;
1614
1615 if (!fFTM.SetTriggerWindow(evt.GetUShort()))
1616 T::Warn("SetTriggerWindow - Value out of range.");
1617
1618 return T::GetCurrentState();
1619 }
1620
1621 int SetCalibWindow(const EventImp &evt)
1622 {
1623 if (!CheckEventSize(evt.GetSize(), "SetCalibWindow", 2))
1624 return T::kSM_FatalError;
1625
1626 if (!fFTM.SetCalibWindow(evt.GetUShort()))
1627 T::Warn("SetCalibWindow - Value out of range.");
1628
1629 return T::GetCurrentState();
1630 }
1631
1632 int SetClockRegister(const EventImp &evt)
1633 {
1634 if (!CheckEventSize(evt.GetSize(), "SetClockRegister", 8*8))
1635 return T::kSM_FatalError;
1636
1637 const uint64_t *reg = evt.Ptr<uint64_t>();
1638
1639 if (!fFTM.SetClockRegister(reg))
1640 T::Warn("SetClockRegister - Value out of range.");
1641
1642 return T::GetCurrentState();
1643 }
1644
1645 int SetClockFrequency(const EventImp &evt)
1646 {
1647 if (!CheckEventSize(evt.GetSize(), "SetClockFrequency", 2))
1648 return T::kSM_FatalError;
1649
1650 const map<uint16_t,array<uint64_t, 8>>::const_iterator it =
1651 fClockCondSetup.find(evt.GetUShort());
1652
1653 if (it==fClockCondSetup.end())
1654 {
1655 T::Warn("SetClockFrequency - Frequency not supported.");
1656 return T::GetCurrentState();
1657 }
1658
1659 if (!fFTM.SetClockRegister(it->second.data()))
1660 T::Warn("SetClockFrequency - Register values out of range.");
1661
1662 return T::GetCurrentState();
1663 }
1664
1665 int EnableLP(const EventImp &evt, FTM::StaticData::GeneralSettings lp, FTM::StaticData::LightPulserEnable group)
1666 {
1667 if (!CheckEventSize(evt.GetSize(), "EnableLP", 1))
1668 return T::kSM_FatalError;
1669
1670 if (!fFTM.EnableLP(lp, group, evt.GetBool()))
1671 T::Warn("EnableLP - Invalid light pulser id.");
1672
1673 return T::GetCurrentState();
1674 }
1675
1676 int SetIntensity(const EventImp &evt, FTM::StaticData::GeneralSettings lp)
1677 {
1678 if (!CheckEventSize(evt.GetSize(), "SetIntensity", 2))
1679 return T::kSM_FatalError;
1680
1681 if (!fFTM.SetIntensity(lp, evt.GetShort()))
1682 T::Warn("SetIntensity - Value out of range.");
1683
1684 return T::GetCurrentState();
1685 }
1686
1687 int Enable(const EventImp &evt, FTM::StaticData::GeneralSettings type)
1688 {
1689 if (!CheckEventSize(evt.GetSize(), "Enable", 1))
1690 return T::kSM_FatalError;
1691
1692 fFTM.Enable(type, evt.GetBool());
1693
1694 return T::GetCurrentState();
1695 }
1696
1697 int EnablePixel(const EventImp &evt, bool b)
1698 {
1699 if (!CheckEventSize(evt.GetSize(), "EnablePixel", 2))
1700 return T::kSM_FatalError;
1701
1702 if (!fFTM.EnablePixel(evt.GetUShort(), b))
1703 T::Warn("EnablePixel - Value out of range.");
1704
1705 return T::GetCurrentState();
1706 }
1707
1708 int DisableAllPixelsExcept(const EventImp &evt)
1709 {
1710 if (!CheckEventSize(evt.GetSize(), "DisableAllPixelsExcept", 2))
1711 return T::kSM_FatalError;
1712
1713 if (!fFTM.DisableAllPixelsExcept(evt.GetUShort()))
1714 T::Warn("DisableAllPixelsExcept - Value out of range.");
1715
1716 return T::GetCurrentState();
1717 }
1718
1719 int DisableAllPatchesExcept(const EventImp &evt)
1720 {
1721 if (!CheckEventSize(evt.GetSize(), "DisableAllPatchesExcept", 2))
1722 return T::kSM_FatalError;
1723
1724 if (!fFTM.DisableAllPatchesExcept(evt.GetUShort()))
1725 T::Warn("DisableAllPatchesExcept - Value out of range.");
1726
1727 return T::GetCurrentState();
1728 }
1729
1730 int TogglePixel(const EventImp &evt)
1731 {
1732 if (!CheckEventSize(evt.GetSize(), "TogglePixel", 2))
1733 return T::kSM_FatalError;
1734
1735 if (!fFTM.TogglePixel(evt.GetUShort()))
1736 T::Warn("TogglePixel - Value out of range.");
1737
1738 return T::GetCurrentState();
1739 }
1740
1741 int ResetCrate(const EventImp &evt)
1742 {
1743 if (!CheckEventSize(evt.GetSize(), "ResetCrate", 2))
1744 return T::kSM_FatalError;
1745
1746 fFTM.CmdResetCrate(evt.GetUShort());
1747
1748 return T::GetCurrentState();
1749 }
1750
1751 int Disconnect()
1752 {
1753 // Close all connections
1754 fFTM.PostClose(false);
1755
1756 /*
1757 // Now wait until all connection have been closed and
1758 // all pending handlers have been processed
1759 poll();
1760 */
1761
1762 return T::GetCurrentState();
1763 }
1764
1765 int Reconnect(const EventImp &evt)
1766 {
1767 // Close all connections to supress the warning in SetEndpoint
1768 fFTM.PostClose(false);
1769
1770 // Now wait until all connection have been closed and
1771 // all pending handlers have been processed
1772 poll();
1773
1774 if (evt.GetBool())
1775 fFTM.SetEndpoint(evt.GetString());
1776
1777 // Now we can reopen the connection
1778 fFTM.PostClose(true);
1779
1780 return T::GetCurrentState();
1781 }
1782
1783 /*
1784 int Transition(const Event &evt)
1785 {
1786 switch (evt.GetTargetState())
1787 {
1788 case kDisconnected:
1789 case kConnected:
1790 }
1791
1792 return T::kSM_FatalError;
1793 }*/
1794
1795 int64_t fCounterReg;
1796 int64_t fCounterStat;
1797
1798 typedef map<string, FTM::StaticData> Configs;
1799 Configs fConfigs;
1800 Configs::const_iterator fTargetConfig;
1801
1802 int ConfigureFTM(const EventImp &evt)
1803 {
1804 const string name = evt.GetText();
1805
1806 fTargetConfig = fConfigs.find(name);
1807 if (fTargetConfig==fConfigs.end())
1808 {
1809 T::Error("ConfigureFTM - Run-type '"+name+"' not found.");
1810 return T::GetCurrentState();
1811 }
1812
1813 T::Message("Starting configuration for '"+name+"'");
1814
1815 fCounterReg = fFTM.GetCounter(FTM::kRegister);
1816 fFTM.CmdStopRun();
1817
1818 return FTM::kConfiguring1;
1819 }
1820
1821 int ResetConfig()
1822 {
1823 return fFTM.GetState();
1824 }
1825
1826 int Execute()
1827 {
1828 // Dispatch (execute) at most one handler from the queue. In contrary
1829 // to run_one(), it doesn't wait until a handler is available
1830 // which can be dispatched, so poll_one() might return with 0
1831 // handlers dispatched. The handlers are always dispatched/executed
1832 // synchronously, i.e. within the call to poll_one()
1833 poll_one();
1834
1835 // If FTM is neither in data taking nor idle,
1836 // leave configuration state
1837 switch (fFTM.GetState())
1838 {
1839 case ConnectionFTM::kDisconnected: return FTM::kDisconnected;
1840 case ConnectionFTM::kConnected: return FTM::kConnected;
1841 default:
1842 break;
1843 }
1844
1845 switch (T::GetCurrentState())
1846 {
1847 case FTM::kConfiguring1:
1848 // If FTM has received an anwer to the stop_run command
1849 // the counter for the registers has been increased
1850 if (fFTM.GetCounter(FTM::kRegister)<=fCounterReg)
1851 break;
1852
1853 // If now the state is not idle as expected this means we had
1854 // an error (maybe old events waiting in the queue)
1855 if (fFTM.GetState()!=ConnectionFTM::kIdle &&
1856 fFTM.GetState()!=ConnectionFTM::kConfigured)
1857 return FTM::kConfigError1;
1858
1859 fCounterStat = fFTM.GetCounter(FTM::kStaticData);
1860
1861 T::Message("Trigger successfully disabled... sending new configuration.");
1862
1863 fFTM.CmdSendStatDat(fTargetConfig->second);
1864
1865 // Next state is: wait for the answer to our configuration
1866 return FTM::kConfiguring2;
1867
1868 case FTM::kConfiguring2:
1869 case FTM::kConfigured:
1870 // If FTM has received an anwer to the stop_run command
1871 // the counter for the registers has been increased
1872 if (fFTM.GetCounter(FTM::kStaticData)<=fCounterStat)
1873 break;
1874
1875 // If now the configuration is not what we expected
1876 // we had an error (maybe old events waiting in the queue?)
1877 // ======================
1878 if (fFTM.GetState()!=ConnectionFTM::kConfigured)
1879 return FTM::kConfigError2;
1880 // ======================
1881
1882 // Check configuration again when a new static data block
1883 // will be received
1884 fCounterStat = fFTM.GetCounter(FTM::kStaticData);
1885
1886 T::Info(" ==> TODO: Update run in database!");
1887 T::Message("Sending new configuration was successfull.");
1888
1889 // Next state is: wait for the answer to our configuration
1890 return FTM::kConfigured;
1891
1892 default:
1893 switch (fFTM.GetState())
1894 {
1895 case ConnectionFTM::kIdle: return FTM::kIdle;
1896 case ConnectionFTM::kConfigured: return FTM::kIdle;
1897 case ConnectionFTM::kTakingData: return FTM::kTakingData;
1898 default:
1899 throw runtime_error("StateMachienFTM - Execute() - Inavlid state.");
1900 }
1901 }
1902
1903 if (T::GetCurrentState()==FTM::kConfigured &&
1904 fFTM.GetState()==ConnectionFTM::kTakingData)
1905 return FTM::kTakingData;
1906
1907 return T::GetCurrentState();
1908 }
1909
1910public:
1911 StateMachineFTM(ostream &out=cout) :
1912 T(out, "FTM_CONTROL"), ba::io_service::work(static_cast<ba::io_service&>(*this)),
1913 fFTM(*this, *this)
1914 {
1915 // ba::io_service::work is a kind of keep_alive for the loop.
1916 // It prevents the io_service to go to stopped state, which
1917 // would prevent any consecutive calls to run()
1918 // or poll() to do nothing. reset() could also revoke to the
1919 // previous state but this might introduce some overhead of
1920 // deletion and creation of threads and more.
1921
1922
1923 // State names
1924 T::AddStateName(FTM::kDisconnected, "Disconnected",
1925 "FTM board not connected via ethernet.");
1926
1927 T::AddStateName(FTM::kConnected, "Connected",
1928 "Ethernet connection to FTM established (no state received yet).");
1929
1930 T::AddStateName(FTM::kIdle, "Idle",
1931 "Ethernet connection to FTM established, FTM in idle state.");
1932
1933 T::AddStateName(FTM::kConfiguring1, "Configuring1",
1934 "Command to diable run sent... waiting for response.");
1935 T::AddStateName(FTM::kConfiguring2, "Configuring2",
1936 "New configuration sent... waiting for response.");
1937 T::AddStateName(FTM::kConfigured, "Configured",
1938 "Received answer identical with target configuration.");
1939
1940 T::AddStateName(FTM::kTakingData, "TakingData",
1941 "Ethernet connection to FTM established, FTM is in taking data state.");
1942
1943 T::AddStateName(FTM::kConfigError1, "ErrorInConfig1", "");
1944 T::AddStateName(FTM::kConfigError2, "ErrorInConfig2", "");
1945
1946 // FTM Commands
1947 T::AddEvent("TOGGLE_LED", FTM::kIdle)
1948 (Wrapper(bind(&ConnectionFTM::CmdToggleLed, &fFTM)))
1949 ("toggle led");
1950
1951 T::AddEvent("PING", FTM::kIdle)
1952 (Wrapper(bind(&ConnectionFTM::CmdPing, &fFTM)))
1953 ("send ping");
1954
1955 T::AddEvent("REQUEST_DYNAMIC_DATA", FTM::kIdle)
1956 (Wrapper(bind(&ConnectionFTM::CmdReqDynDat, &fFTM)))
1957 ("request transmission of dynamic data block");
1958
1959 T::AddEvent("REQUEST_STATIC_DATA", FTM::kIdle)
1960 (Wrapper(bind(&ConnectionFTM::CmdReqStatDat, &fFTM)))
1961 ("request transmission of static data from FTM to memory");
1962
1963 T::AddEvent("GET_REGISTER", "I", FTM::kIdle)
1964 (bind(&StateMachineFTM::GetRegister, this, placeholders::_1))
1965 ("read register from address addr"
1966 "|addr[short]:Address of register");
1967
1968 T::AddEvent("SET_REGISTER", "I:2", FTM::kIdle)
1969 (bind(&StateMachineFTM::SetRegister, this, placeholders::_1))
1970 ("set register to value"
1971 "|addr[short]:Address of register"
1972 "|val[short]:Value to be set");
1973
1974 T::AddEvent("START_RUN", FTM::kIdle, FTM::kConfigured)
1975 (Wrapper(bind(&ConnectionFTM::CmdStartRun, &fFTM)))
1976 ("start a run (start distributing triggers)");
1977
1978 T::AddEvent("STOP_RUN", FTM::kTakingData)
1979 (Wrapper(bind(&ConnectionFTM::CmdStopRun, &fFTM)))
1980 ("stop a run (stop distributing triggers)");
1981
1982 T::AddEvent("TAKE_N_EVENTS", "I", FTM::kIdle)
1983 (bind(&StateMachineFTM::TakeNevents, this, placeholders::_1))
1984 ("take n events (distribute n triggers)|number[int]:Number of events to be taken");
1985
1986 T::AddEvent("DISABLE_REPORTS", "B", FTM::kIdle)
1987 (bind(&StateMachineFTM::DisableReports, this, placeholders::_1))
1988 ("disable sending rate reports"
1989 "|status[bool]:disable or enable that the FTM sends rate reports (yes/no)");
1990
1991 T::AddEvent("SET_THRESHOLD", "I:2", FTM::kIdle, FTM::kTakingData)
1992 (bind(&StateMachineFTM::SetThreshold, this, placeholders::_1))
1993 ("Set the comparator threshold"
1994 "|Patch[idx]:Index of the patch (0-159), -1 for all"
1995 "|Threshold[counts]:Threshold to be set in binary counts");
1996
1997 T::AddEvent("SET_N_OUT_OF_4", "I:2", FTM::kIdle, FTM::kTakingData)
1998 (bind(&StateMachineFTM::SetNoutof4, this, placeholders::_1))
1999 ("Set the comparator threshold"
2000 "|Board[idx]:Index of the board (0-39), -1 for all"
2001 "|Threshold[counts]:Threshold to be set in binary counts");
2002
2003 T::AddEvent("SET_PRESCALING", "I:1", FTM::kIdle)
2004 (bind(&StateMachineFTM::SetPrescaling, this, placeholders::_1))
2005 (""
2006 "|[]:");
2007
2008 T::AddEvent("ENABLE_FTU", "I:1;B:1", FTM::kIdle)
2009 (bind(&StateMachineFTM::EnableFTU, this, placeholders::_1))
2010 ("Enable or disable FTU"
2011 "|Board[idx]:Index of the board (0-39), -1 for all"
2012 "|Enable[bool]:Whether FTU should be enabled or disabled (yes/no)");
2013
2014 T::AddEvent("DISABLE_PIXEL", "S:1", FTM::kIdle, FTM::kTakingData)
2015 (bind(&StateMachineFTM::EnablePixel, this, placeholders::_1, false))
2016 ("(-1 or all)");
2017
2018 T::AddEvent("ENABLE_PIXEL", "S:1", FTM::kIdle, FTM::kTakingData)
2019 (bind(&StateMachineFTM::EnablePixel, this, placeholders::_1, true))
2020 ("(-1 or all)");
2021
2022 T::AddEvent("DISABLE_ALL_PIXELS_EXCEPT", "S:1", FTM::kIdle)
2023 (bind(&StateMachineFTM::DisableAllPixelsExcept, this, placeholders::_1))
2024 ("");
2025
2026 T::AddEvent("DISABLE_ALL_PATCHES_EXCEPT", "S:1", FTM::kIdle)
2027 (bind(&StateMachineFTM::DisableAllPatchesExcept, this, placeholders::_1))
2028 ("");
2029
2030 T::AddEvent("TOGGLE_PIXEL", "S:1", FTM::kIdle)
2031 (bind(&StateMachineFTM::TogglePixel, this, placeholders::_1))
2032 ("");
2033
2034 T::AddEvent("TOGGLE_FTU", "I:1", FTM::kIdle)
2035 (bind(&StateMachineFTM::ToggleFTU, this, placeholders::_1))
2036 ("Toggle status of FTU (this is mainly meant to be used in the GUI)"
2037 "|Board[idx]:Index of the board (0-39)");
2038
2039 T::AddEvent("SET_TRIGGER_INTERVAL", "I:1", FTM::kIdle)
2040 (bind(&StateMachineFTM::SetTriggerInterval, this, placeholders::_1))
2041 ("Sets the trigger interval which is the distance between two consecutive artificial triggers."
2042 "|interval[int]:The applied trigger interval is: interval*4ns+8ns");
2043
2044 T::AddEvent("SET_TRIGGER_DELAY", "I:1", FTM::kIdle)
2045 (bind(&StateMachineFTM::SetTriggerDelay, this, placeholders::_1))
2046 (""
2047 "|delay[int]:The applied trigger delay is: delay*4ns+8ns");
2048
2049 T::AddEvent("SET_TIME_MARKER_DELAY", "I:1", FTM::kIdle)
2050 (bind(&StateMachineFTM::SetTimeMarkerDelay, this, placeholders::_1))
2051 (""
2052 "|delay[int]:The applied time marker delay is: delay*4ns+8ns");
2053
2054 T::AddEvent("SET_DEAD_TIME", "I:1", FTM::kIdle)
2055 (bind(&StateMachineFTM::SetDeadTime, this, placeholders::_1))
2056 (""
2057 "|dead_time[int]:The applied dead time is: dead_time*4ns+8ns");
2058
2059 T::AddEvent("ENABLE_TRIGGER", "B:1", FTM::kIdle)
2060 (bind(&StateMachineFTM::Enable, this, placeholders::_1, FTM::StaticData::kTrigger))
2061 ("Switch on the physics trigger"
2062 "|Enable[bool]:Enable physics trigger (yes/no)");
2063
2064 // FIXME: Switch on/off depending on sequence
2065 T::AddEvent("ENABLE_EXT1", "B:1", FTM::kIdle)
2066 (bind(&StateMachineFTM::Enable, this, placeholders::_1, FTM::StaticData::kExt1))
2067 ("Switch on the triggers through the first external line"
2068 "|Enable[bool]:Enable ext1 trigger (yes/no)");
2069
2070 // FIXME: Switch on/off depending on sequence
2071 T::AddEvent("ENABLE_EXT2", "B:1", FTM::kIdle)
2072 (bind(&StateMachineFTM::Enable, this, placeholders::_1, FTM::StaticData::kExt2))
2073 ("Switch on the triggers through the second external line"
2074 "|Enable[bool]:Enable ext2 trigger (yes/no)");
2075
2076 T::AddEvent("ENABLE_VETO", "B:1", FTM::kIdle)
2077 (bind(&StateMachineFTM::Enable, this, placeholders::_1, FTM::StaticData::kVeto))
2078 ("Enable veto line"
2079 "|Enable[bool]:Enable veto (yes/no)");
2080
2081 T::AddEvent("ENABLE_CLOCK_CONDITIONER", "B:1", FTM::kIdle)
2082 (bind(&StateMachineFTM::Enable, this, placeholders::_1, FTM::StaticData::kClockConditioner))
2083 ("Enable clock conidtioner output in favor of time marker output"
2084 "|Enable[bool]:Enable clock conditioner (yes/no)");
2085
2086 T::AddEvent("ENABLE_GROUP1_LPINT", "B:1", FTM::kIdle)
2087 (bind(&StateMachineFTM::EnableLP, this, placeholders::_1, FTM::StaticData::kLPint, FTM::StaticData::kGroup1))
2088 ("");
2089 T::AddEvent("ENABLE_GROUP1_LPEXT", "B:1", FTM::kIdle)
2090 (bind(&StateMachineFTM::EnableLP, this, placeholders::_1, FTM::StaticData::kLPext, FTM::StaticData::kGroup1))
2091 ("");
2092 T::AddEvent("ENABLE_GROUP2_LPINT", "B:1", FTM::kIdle)
2093 (bind(&StateMachineFTM::EnableLP, this, placeholders::_1, FTM::StaticData::kLPint, FTM::StaticData::kGroup2))
2094 ("");
2095 T::AddEvent("ENABLE_GROUP2_LPEXT", "B:1", FTM::kIdle)
2096 (bind(&StateMachineFTM::EnableLP, this, placeholders::_1, FTM::StaticData::kLPext, FTM::StaticData::kGroup2))
2097 ("");
2098 T::AddEvent("SET_INTENSITY_LPINT", "S:1", FTM::kIdle)
2099 (bind(&StateMachineFTM::SetIntensity, this, placeholders::_1, FTM::StaticData::kLPint))
2100 ("");
2101 T::AddEvent("SET_INTENSITY_LPEXT", "S:1", FTM::kIdle)
2102 (bind(&StateMachineFTM::SetIntensity, this, placeholders::_1, FTM::StaticData::kLPext))
2103 ("");
2104
2105
2106 T::AddEvent("SET_TRIGGER_SEQUENCE", "S:3", FTM::kIdle)
2107 (bind(&StateMachineFTM::SetTriggerSeq, this, placeholders::_1))
2108 ("Setup the sequence of artificial triggers produced by the FTM"
2109 "|Ped[short]:number of pedestal triggers in a row"
2110 "|LPext[short]:number of triggers of the external light pulser"
2111 "|LPint[short]:number of triggers of the internal light pulser");
2112
2113 T::AddEvent("SET_TRIGGER_MULTIPLICITY", "S:1", FTM::kIdle)
2114 (bind(&StateMachineFTM::SetTriggerMultiplicity, this, placeholders::_1))
2115 ("Setup the Multiplicity condition for physcis triggers"
2116 "|N[int]:Number of requirered coincident triggers from sum-patches (1-40)");
2117
2118 T::AddEvent("SET_TRIGGER_WINDOW", "S:1", FTM::kIdle)
2119 (bind(&StateMachineFTM::SetTriggerWindow, this, placeholders::_1))
2120 ("");
2121
2122 T::AddEvent("SET_CALIBRATION_MULTIPLICITY", "S:1", FTM::kIdle)
2123 (bind(&StateMachineFTM::SetCalibMultiplicity, this, placeholders::_1))
2124 ("Setup the Multiplicity condition for artificial (calibration) triggers"
2125 "|N[int]:Number of requirered coincident triggers from sum-patches (1-40)");
2126
2127 T::AddEvent("SET_CALIBRATION_WINDOW", "S:1", FTM::kIdle)
2128 (bind(&StateMachineFTM::SetCalibWindow, this, placeholders::_1))
2129 ("");
2130
2131 T::AddEvent("SET_CLOCK_FREQUENCY", "S:1", FTM::kIdle)
2132 (bind(&StateMachineFTM::SetClockFrequency, this, placeholders::_1))
2133 ("");
2134
2135 T::AddEvent("SET_CLOCK_REGISTER", "X:8", FTM::kIdle)
2136 (bind(&StateMachineFTM::SetClockRegister, this, placeholders::_1))
2137 ("");
2138
2139 // A new configure will first stop the FTM this means
2140 // we can allow it in idle _and_ taking data
2141 T::AddEvent("CONFIGURE", "C", FTM::kIdle, FTM::kConfiguring1, FTM::kConfiguring2, FTM::kConfigured, FTM::kTakingData)
2142 (bind(&StateMachineFTM::ConfigureFTM, this, placeholders::_1))
2143 ("");
2144
2145 T::AddEvent("RESET_CONFIGURE", FTM::kConfiguring1, FTM::kConfiguring2, FTM::kConfigured, FTM::kConfigError1, FTM::kConfigError2)
2146 (bind(&StateMachineFTM::ResetConfig, this))
2147 ("");
2148
2149
2150
2151 T::AddEvent("RESET_CRATE", "S:1", FTM::kIdle)
2152 (bind(&StateMachineFTM::ResetCrate, this, placeholders::_1))
2153 ("Reset one of the crates 0-3"
2154 "|crate[short]:Crate number to be reseted (0-3)");
2155
2156 T::AddEvent("RESET_CAMERA", FTM::kIdle)
2157 (Wrapper(bind(&ConnectionFTM::CmdResetCamera, &fFTM)))
2158 ("Reset all crates. The commands are sent in the order 0,1,2,3");
2159
2160
2161 // Load/save static data block
2162 T::AddEvent("SAVE", "C", FTM::kIdle)
2163 (bind(&StateMachineFTM::SaveStaticData, this, placeholders::_1))
2164 ("Saves the static data (FTM configuration) from memory to a file"
2165 "|filename[string]:Filename (can include a path), .bin is automatically added");
2166
2167 T::AddEvent("LOAD", "C", FTM::kIdle)
2168 (bind(&StateMachineFTM::LoadStaticData, this, placeholders::_1))
2169 ("Loads the static data (FTM configuration) from a file into memory and sends it to the FTM"
2170 "|filename[string]:Filename (can include a path), .bin is automatically added");
2171
2172
2173
2174 // Verbosity commands
2175 T::AddEvent("SET_VERBOSE", "B")
2176 (bind(&StateMachineFTM::SetVerbosity, this, placeholders::_1))
2177 ("set verbosity state"
2178 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
2179
2180 T::AddEvent("SET_HEX_OUTPUT", "B")
2181 (bind(&StateMachineFTM::SetHexOutput, this, placeholders::_1))
2182 ("enable or disable hex output for received data"
2183 "|hexout[bool]:disable or enable hex output for received data (yes/no)");
2184
2185 T::AddEvent("SET_DYNAMIC_OUTPUT", "B")
2186 (bind(&StateMachineFTM::SetDynamicOut, this, placeholders::_1))
2187 ("enable or disable output for received dynamic data (data is still broadcasted via Dim)"
2188 "|dynout[bool]:disable or enable output for dynamic data (yes/no)");
2189
2190
2191 // Conenction commands
2192 T::AddEvent("DISCONNECT", FTM::kConnected, FTM::kIdle)
2193 (bind(&StateMachineFTM::Disconnect, this))
2194 ("disconnect from ethernet");
2195
2196 T::AddEvent("RECONNECT", "O", FTM::kDisconnected, FTM::kConnected, FTM::kIdle, FTM::kConfigured)
2197 (bind(&StateMachineFTM::Reconnect, this, placeholders::_1))
2198 ("(Re)connect ethernet connection to FTM, a new address can be given"
2199 "|[host][string]:new ethernet address in the form <host:port>");
2200
2201 fFTM.StartConnect();
2202 }
2203
2204 void SetEndpoint(const string &url)
2205 {
2206 fFTM.SetEndpoint(url);
2207 }
2208
2209 map<uint16_t, array<uint64_t, 8>> fClockCondSetup;
2210
2211 template<class V>
2212 bool CheckConfigVal(Configuration &conf, V max, const string &name, const string &sub)
2213 {
2214 if (!conf.HasDef(name, sub))
2215 {
2216 T::Error("Neither "+name+"default nor "+name+sub+" found.");
2217 return false;
2218 }
2219
2220 const V val = conf.GetDef<V>(name, sub);
2221
2222 if (val<=max)
2223 return true;
2224
2225 ostringstream str;
2226 str << name << sub << "=" << val << " exceeds allowed maximum of " << max << "!";
2227 T::Error(str);
2228
2229 return false;
2230 }
2231
2232 int EvalOptions(Configuration &conf)
2233 {
2234 // ---------- General setup ----------
2235 fFTM.SetVerbose(!conf.Get<bool>("quiet"));
2236 fFTM.SetHexOutput(conf.Get<bool>("hex-out"));
2237 fFTM.SetDynamicOut(conf.Get<bool>("dynamic-out"));
2238
2239 // ---------- Setup clock conditioner frequencies ----------
2240 const vector<uint16_t> freq = conf.Vec<uint16_t>("clock-conditioner.frequency");
2241 if (freq.size()==0)
2242 T::Warn("No frequencies for the clock-conditioner defined.");
2243 else
2244 T::Message("Defining clock conditioner frequencies");
2245 for (vector<uint16_t>::const_iterator it=freq.begin();
2246 it!=freq.end(); it++)
2247 {
2248 if (fClockCondSetup.count(*it)>0)
2249 {
2250 T::Error("clock-conditioner frequency defined twice.");
2251 return 1;
2252 }
2253
2254 if (!conf.HasDef("clock-conditioner.R0.", *it) ||
2255 !conf.HasDef("clock-conditioner.R1.", *it) ||
2256 !conf.HasDef("clock-conditioner.R8.", *it) ||
2257 !conf.HasDef("clock-conditioner.R9.", *it) ||
2258 !conf.HasDef("clock-conditioner.R11.", *it) ||
2259 !conf.HasDef("clock-conditioner.R13.", *it) ||
2260 !conf.HasDef("clock-conditioner.R14.", *it) ||
2261 !conf.HasDef("clock-conditioner.R15.", *it))
2262 {
2263 T::Error("clock-conditioner values incomplete.");
2264 return 1;
2265 }
2266
2267 array<uint64_t, 8> &arr = fClockCondSetup[*it];
2268
2269 arr[0] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R0.", *it);
2270 arr[1] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R1.", *it);
2271 arr[2] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R8.", *it);
2272 arr[3] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R9.", *it);
2273 arr[4] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R11.", *it);
2274 arr[5] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R13.", *it);
2275 arr[6] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R14.", *it);
2276 arr[7] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R15.", *it);
2277
2278 ostringstream out;
2279 out << " -> " << setw(4) << *it << "MHz:" << hex << setfill('0');
2280 for (int i=0; i<8; i++)
2281 out << " " << setw(8) << arr[i];
2282 T::Message(out.str());
2283 }
2284
2285 // ---------- Setup run types ---------
2286 const vector<string> types = conf.Vec<string>("run-type");
2287 if (types.size()==0)
2288 T::Warn("No run-types defined.");
2289 else
2290 T::Message("Defining run-types");
2291 for (vector<string>::const_iterator it=types.begin();
2292 it!=types.end(); it++)
2293 {
2294 T::Message(" -> "+ *it);
2295
2296 if (fConfigs.count(*it)>0)
2297 {
2298 T::Error("Run-type "+*it+" defined twice.");
2299 return 2;
2300 }
2301
2302 FTM::StaticData data;
2303
2304 const uint16_t frq = conf.GetDef<uint16_t>("sampling-frequency.", *it);
2305 if (fClockCondSetup.count(frq)==0)
2306 {
2307 T::Error("sampling-frequency."+*it+" - frequency not available.");
2308 return 2;
2309 }
2310
2311 data.SetClockRegister(fClockCondSetup[frq].data());
2312
2313 // Trigger sequence ped:lp1:lp2
2314 // (data. is used here as an abbreviation for FTM::StaticData::
2315 if (!CheckConfigVal<bool> (conf, true, "trigger.enable-trigger.", *it) ||
2316 !CheckConfigVal<bool> (conf, true, "trigger.enable-external-1.", *it) ||
2317 !CheckConfigVal<bool> (conf, true, "trigger.enable-external-2.", *it) ||
2318 !CheckConfigVal<bool> (conf, true, "trigger.enable-veto.", *it) ||
2319 !CheckConfigVal<bool> (conf, true, "trigger.enable-clock-conditioner.", *it) ||
2320 !CheckConfigVal<bool> (conf, true, "light-pulser.external.enable-group1.", *it) ||
2321 !CheckConfigVal<bool> (conf, true, "light-pulser.external.enable-group2.", *it) ||
2322 !CheckConfigVal<bool> (conf, true, "light-pulser.internal.enable-group1.", *it) ||
2323 !CheckConfigVal<bool> (conf, true, "light-pulser.internal.enable-group2.", *it) ||
2324 !CheckConfigVal<uint16_t>(conf, data.kMaxSequence, "trigger.sequence.pedestal.", *it) ||
2325 !CheckConfigVal<uint16_t>(conf, data.kMaxSequence, "trigger.sequence.lp-ext.", *it) ||
2326 !CheckConfigVal<uint16_t>(conf, data.kMaxSequence, "trigger.sequence.lp-int.", *it) ||
2327 !CheckConfigVal<uint16_t>(conf, data.kMaxTriggerInterval, "trigger.sequence.interval.", *it) ||
2328 !CheckConfigVal<uint16_t>(conf, data.kMaxMultiplicity, "trigger.multiplicity-physics.", *it) ||
2329 !CheckConfigVal<uint16_t>(conf, data.kMaxMultiplicity, "trigger.multiplicity-calib.", *it) ||
2330 !CheckConfigVal<uint16_t>(conf, data.kMaxWindow, "trigger.coincidence-window-physics.", *it) ||
2331 !CheckConfigVal<uint16_t>(conf, data.kMaxWindow, "trigger.coincidence-window-calib.", *it) ||
2332 !CheckConfigVal<uint16_t>(conf, data.kMaxDeadTime, "trigger.dead-time.", *it) ||
2333 !CheckConfigVal<uint16_t>(conf, data.kMaxDelayTrigger, "trigger.delay.", *it) ||
2334 !CheckConfigVal<uint16_t>(conf, data.kMaxDelayTimeMarker, "trigger.time-marker-delay.", *it) ||
2335 !CheckConfigVal<uint16_t>(conf, 0xffff, "ftu-report-interval.", *it) ||
2336 !CheckConfigVal<uint16_t>(conf, data.kMaxIntensity, "light-pulser.external.intensity.", *it) ||
2337 !CheckConfigVal<uint16_t>(conf, data.kMaxIntensity, "light-pulser.internal.intensity.", *it) ||
2338 !CheckConfigVal<uint16_t>(conf, data.kMaxDAC, "trigger.threshold.patch.", *it) ||
2339 !CheckConfigVal<uint16_t>(conf, data.kMaxDAC, "trigger.threshold.logic.", *it) ||
2340 0)
2341 return 2;
2342
2343 data.Enable(data.kTrigger, conf.GetDef<bool>("trigger.enable-trigger.", *it));
2344 data.Enable(data.kExt1, conf.GetDef<bool>("trigger.enable-external-1.", *it));
2345 data.Enable(data.kExt2, conf.GetDef<bool>("trigger.enable-external-2.", *it));
2346 data.Enable(data.kVeto, conf.GetDef<bool>("trigger.enable-veto.", *it));
2347 data.Enable(data.kClockConditioner, conf.GetDef<bool>("trigger.enable-clock-conditioner.", *it));
2348
2349 data.EnableLPint(data.kGroup1, conf.GetDef<bool>("light-pulser.internal.enable-group1.", *it));
2350 data.EnableLPint(data.kGroup2, conf.GetDef<bool>("light-pulser.internal.enable-group2.", *it));
2351 data.EnableLPext(data.kGroup1, conf.GetDef<bool>("light-pulser.external.enable-group1.", *it));
2352 data.EnableLPext(data.kGroup2, conf.GetDef<bool>("light-pulser.external.enable-group2.", *it));
2353
2354 // [ms] Interval between two artificial triggers (no matter which type) minimum 1ms, 10 bit
2355 data.fIntensityLPint = conf.GetDef<uint16_t>("light-pulser.internal.intensity.", *it);
2356 data.fIntensityLPext = conf.GetDef<uint16_t>("light-pulser.external.intensity.", *it);
2357 data.fTriggerInterval = conf.GetDef<uint16_t>("trigger.sequence.interval.", *it);
2358 data.fMultiplicityPhysics = conf.GetDef<uint16_t>("trigger.multiplicity-physics.", *it);
2359 data.fMultiplicityCalib = conf.GetDef<uint16_t>("trigger.multiplicity-calib.", *it);
2360 data.fWindowPhysics = conf.GetDef<uint16_t>("trigger.coincidence-window-physics.", *it); /// (4ns * x + 8ns)
2361 data.fWindowCalib = conf.GetDef<uint16_t>("trigger.coincidence-window-calib.", *it); /// (4ns * x + 8ns)
2362 data.fDelayTrigger = conf.GetDef<uint16_t>("trigger.delay.", *it); /// (4ns * x + 8ns)
2363 data.fDelayTimeMarker = conf.GetDef<uint16_t>("trigger.time-marker-delay.", *it); /// (4ns * x + 8ns)
2364 data.fDeadTime = conf.GetDef<uint16_t>("trigger.dead-time.", *it); /// (4ns * x + 8ns)
2365
2366 data.SetPrescaling(conf.GetDef<uint16_t>("ftu-report-interval.", *it));
2367
2368 const uint16_t seqped = conf.GetDef<uint16_t>("trigger.sequence.pedestal.", *it);
2369 const uint16_t seqint = conf.GetDef<uint16_t>("trigger.sequence.lp-int.", *it);
2370 const uint16_t seqext = conf.GetDef<uint16_t>("trigger.sequence.lp-ext.", *it);
2371
2372 data.SetSequence(seqped, seqint, seqext);
2373
2374 data.EnableAllFTU();
2375 data.EnableAllPixel();
2376
2377 const vector<uint16_t> pat1 = conf.Vec<uint16_t>("trigger.disable-patch.default");
2378 const vector<uint16_t> pat2 = conf.Vec<uint16_t>("trigger.disable-patch."+*it);
2379
2380 const vector<uint16_t> pix1 = conf.Vec<uint16_t>("trigger.disable-pixel.default");
2381 const vector<uint16_t> pix2 = conf.Vec<uint16_t>("trigger.disable-pixel."+*it);
2382
2383 vector<uint16_t> pat, pix;
2384 pat.insert(pat.end(), pat1.begin(), pat1.end());
2385 pat.insert(pat.end(), pat2.begin(), pat2.end());
2386 pix.insert(pix.end(), pix1.begin(), pix1.end());
2387 pix.insert(pix.end(), pix2.begin(), pix2.end());
2388
2389 for (vector<uint16_t>::const_iterator ip=pat.begin(); ip!=pat.end(); ip++)
2390 {
2391 if (*ip>FTM::StaticData::kMaxPatchIdx)
2392 {
2393 ostringstream str;
2394 str << "trigger.disable-patch.*=" << *ip << " exceeds allowed maximum of " << FTM::StaticData::kMaxPatchIdx << "!";
2395 T::Error(str);
2396 return 2;
2397 }
2398 data.DisableFTU(*ip);
2399 }
2400 for (vector<uint16_t>::const_iterator ip=pix.begin(); ip!=pix.end(); ip++)
2401 {
2402 if (*ip>FTM::StaticData::kMaxPixelIdx)
2403 {
2404 ostringstream str;
2405 str << "trigger.disable-pixel.*=" << *ip << " exceeds allowed maximum of " << FTM::StaticData::kMaxPixelIdx << "!";
2406 T::Error(str);
2407 return 2;
2408 }
2409 data.EnablePixel(*ip, false);
2410 }
2411
2412 const uint16_t th0 = conf.GetDef<uint16_t>("trigger.threshold.patch.", *it);
2413 const uint16_t th1 = conf.GetDef<uint16_t>("trigger.threshold.logic.", *it);
2414
2415 for (int i=0; i<40; i++)
2416 {
2417 data[i].fDAC[0] = th0;
2418 data[i].fDAC[1] = th0;
2419 data[i].fDAC[2] = th0;
2420 data[i].fDAC[3] = th0;
2421 data[i].fDAC[4] = th1;
2422 }
2423
2424 fConfigs[*it] = data;
2425
2426 // trigger.threshold.dac-0:
2427
2428 /*
2429 threshold-A data[n].fDAC[0] = val
2430 threshold-B data[n].fDAC[1] = val
2431 threshold-C data[n].fDAC[2] = val
2432 threshold-D data[n].fDAC[3] = val
2433 threshold-H data[n].fDAC[4] = val
2434 */
2435
2436 // kMaxDAC = 0xfff,
2437 }
2438
2439 // FIXME: Add a check about unsused configurations
2440
2441 // ---------- FOR TESTING PURPOSE ---------
2442
2443 // fFTM.SetDefaultSetup(conf.Get<string>("default-setup"));
2444 fConfigs["test"] = FTM::StaticData();
2445
2446 // ---------- Setup connection endpoint ---------
2447 SetEndpoint(conf.Get<string>("addr"));
2448
2449 return -1;
2450 }
2451};
2452
2453// ------------------------------------------------------------------------
2454
2455#include "Main.h"
2456
2457template<class T, class S, class R>
2458int RunShell(Configuration &conf)
2459{
2460 return Main::execute<T, StateMachineFTM<S, R>>(conf);
2461}
2462
2463void SetupConfiguration(Configuration &conf)
2464{
2465 po::options_description control("Control options");
2466 control.add_options()
2467 ("no-dim", po_bool(), "Disable dim services")
2468 ("addr,a", var<string>("localhost:5000"), "Network address of FTM")
2469 ("quiet,q", po_bool(), "Disable printing contents of all received messages (except dynamic data) in clear text.")
2470 ("hex-out", po_bool(), "Enable printing contents of all printed messages also as hex data.")
2471 ("dynamic-out", po_bool(), "Enable printing received dynamic data.")
2472// ("default-setup", var<string>(), "Binary file with static data loaded whenever a connection to the FTM was established.")
2473 ;
2474
2475 po::options_description freq("Sampling frequency setup");
2476 freq.add_options()
2477 ("clock-conditioner.frequency", vars<uint16_t>(), "Frequencies for which to setup the clock-conditioner (replace the * in the following options by this definition)")
2478 ("clock-conditioner.R0.*", var<Hex<uint32_t>>(), "Clock-conditioner R0")
2479 ("clock-conditioner.R1.*", var<Hex<uint32_t>>(), "Clock-conditioner R1")
2480 ("clock-conditioner.R8.*", var<Hex<uint32_t>>(), "Clock-conditioner R8")
2481 ("clock-conditioner.R9.*", var<Hex<uint32_t>>(), "Clock-conditioner R9")
2482 ("clock-conditioner.R11.*", var<Hex<uint32_t>>(), "Clock-conditioner R11")
2483 ("clock-conditioner.R13.*", var<Hex<uint32_t>>(), "Clock-conditioner R13")
2484 ("clock-conditioner.R14.*", var<Hex<uint32_t>>(), "Clock-conditioner R14")
2485 ("clock-conditioner.R15.*", var<Hex<uint32_t>>(), "Clock-conditioner R15");
2486
2487 po::options_description runtype("Run type configuration");
2488 runtype.add_options()
2489 ("run-type", vars<string>(), "Name of run-types (replace the * in the following configuration by the case-sensitive names defined here)")
2490 ("sampling-frequency.*", var<uint16_t>(), "Sampling frequency as defined in the clock-conditioner.frequency")
2491 ("trigger.enable-trigger.*", var<bool>(), "Enable trigger output of physics trigger")
2492 ("trigger.enable-external-1.*", var<bool>(), "Enable external trigger line 1")
2493 ("trigger.enable-external-2.*", var<bool>(), "Enable external trigger line 2")
2494 ("trigger.enable-veto.*", var<bool>(), "Enable veto line")
2495 ("trigger.enable-clock-conditioner.*", var<bool>(), "")
2496 ("trigger.sequence.interval.*", var<uint16_t>(), "Interval between two artifical triggers in units of n*4ns+8ns")
2497 ("trigger.sequence.pedestal.*", var<uint16_t>(), "Number of pedestal events in the sequence of artificial triggers")
2498 ("trigger.sequence.lp-int.*", var<uint16_t>(), "Number of LPint events in the sequence of artificial triggers")
2499 ("trigger.sequence.lp-ext.*", var<uint16_t>(), "Number of LPext events in the sequence of artificial triggers")
2500 ("trigger.multiplicity-physics.*", var<uint16_t>(), "Multiplicity for physics events (n out of 40)")
2501 ("trigger.multiplicity-calib.*", var<uint16_t>(), "Multiplicity for LPext events (n out of 40)")
2502 ("trigger.coincidence-window-physics.*", var<uint16_t>(), "Coincidence window for physics triggers in units of n*4ns+8ns")
2503 ("trigger.coincidence-window-calib.*", var<uint16_t>(), "Coincidence window for LPext triggers in units of n*4ns+8ns")
2504 ("trigger.dead-time.*", var<uint16_t>(), "Dead time after trigger in units of n*4ns+8ns")
2505 ("trigger.delay.*", var<uint16_t>(), "Delay of the trigger send to the FAD boards after a trigger in units of n*4ns+8ns")
2506 ("trigger.time-marker-delay.*", var<uint16_t>(), "Delay of the time-marker after a trigger in units of n*4ns+8ns")
2507 ("trigger.disable-pixel.*", vars<uint16_t>(), "")
2508 ("trigger.disable-patch.*", vars<uint16_t>(), "")
2509 ("trigger.threshold.patch.*", var<uint16_t>(), "")
2510 ("trigger.threshold.logic.*", var<uint16_t>(), "")
2511 ("ftu-report-interval.*", var<uint16_t>(), "")
2512 ("light-pulser.external.enable-group1.*", var<bool>(), "Enable LED group 1 of external light pulser")
2513 ("light-pulser.external.enable-group2.*", var<bool>(), "Enable LED group 2 of external light pulser")
2514 ("light-pulser.internal.enable-group1.*", var<bool>(), "Enable LED group 1 of internal light pulser")
2515 ("light-pulser.internal.enable-group2.*", var<bool>(), "Enable LED group 2 of internal light pulser")
2516 ("light-pulser.external.intensity.*", var<uint16_t>(), "Intensity of external light pulser")
2517 ("light-pulser.internal.intensity.*", var<uint16_t>(), "Intensity of internal light pulser")
2518 ;
2519
2520 conf.AddOptions(control);
2521 conf.AddOptions(freq);
2522 conf.AddOptions(runtype);
2523}
2524
2525/*
2526 Extract usage clause(s) [if any] for SYNOPSIS.
2527 Translators: "Usage" and "or" here are patterns (regular expressions) which
2528 are used to match the usage synopsis in program output. An example from cp
2529 (GNU coreutils) which contains both strings:
2530 Usage: cp [OPTION]... [-T] SOURCE DEST
2531 or: cp [OPTION]... SOURCE... DIRECTORY
2532 or: cp [OPTION]... -t DIRECTORY SOURCE...
2533 */
2534void PrintUsage()
2535{
2536 cout <<
2537 "The ftmctrl controls the FTM (FACT Trigger Master) board.\n"
2538 "\n"
2539 "The default is that the program is started without user intercation. "
2540 "All actions are supposed to arrive as DimCommands. Using the -c "
2541 "option, a local shell can be initialized. With h or help a short "
2542 "help message about the usuage can be brought to the screen.\n"
2543 "\n"
2544 "Usage: ftmctrl [-c type] [OPTIONS]\n"
2545 " or: ftmctrl [OPTIONS]\n";
2546 cout << endl;
2547}
2548
2549void PrintHelp()
2550{
2551 /* Additional help text which is printed after the configuration
2552 options goes here */
2553
2554 /*
2555 cout << "bla bla bla" << endl << endl;
2556 cout << endl;
2557 cout << "Environment:" << endl;
2558 cout << "environment" << endl;
2559 cout << endl;
2560 cout << "Examples:" << endl;
2561 cout << "test exam" << endl;
2562 cout << endl;
2563 cout << "Files:" << endl;
2564 cout << "files" << endl;
2565 cout << endl;
2566 */
2567}
2568
2569int main(int argc, const char* argv[])
2570{
2571 Configuration conf(argv[0]);
2572 conf.SetPrintUsage(PrintUsage);
2573 Main::SetupConfiguration(conf);
2574 SetupConfiguration(conf);
2575
2576 if (!conf.DoParse(argc, argv, PrintHelp))
2577 return -1;
2578
2579 //try
2580 {
2581 // No console access at all
2582 if (!conf.Has("console"))
2583 {
2584 if (conf.Get<bool>("no-dim"))
2585 return RunShell<LocalStream, StateMachine, ConnectionFTM>(conf);
2586 else
2587 return RunShell<LocalStream, StateMachineDim, ConnectionDimFTM>(conf);
2588 }
2589 // Cosole access w/ and w/o Dim
2590 if (conf.Get<bool>("no-dim"))
2591 {
2592 if (conf.Get<int>("console")==0)
2593 return RunShell<LocalShell, StateMachine, ConnectionFTM>(conf);
2594 else
2595 return RunShell<LocalConsole, StateMachine, ConnectionFTM>(conf);
2596 }
2597 else
2598 {
2599 if (conf.Get<int>("console")==0)
2600 return RunShell<LocalShell, StateMachineDim, ConnectionDimFTM>(conf);
2601 else
2602 return RunShell<LocalConsole, StateMachineDim, ConnectionDimFTM>(conf);
2603 }
2604 }
2605 /*catch (std::exception& e)
2606 {
2607 cerr << "Exception: " << e.what() << endl;
2608 return -1;
2609 }*/
2610
2611 return 0;
2612}
Note: See TracBrowser for help on using the repository browser.