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

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