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

Last change on this file since 12326 was 12313, checked in by tbretz, 14 years ago
Added an option to disable whole patches. fixed scaling factor in instaniation of Drim TriggerRates.
File size: 86.7 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/9==idx);
1109
1110 CmdSendStatDat(data);
1111
1112 return true;
1113 }
1114
1115 bool EnablePatch(int16_t idx, bool enable)
1116 {
1117 if (idx>FTM::StaticData::kMaxPatchIdx)
1118 return false;
1119
1120 FTM::StaticData data(fStaticData);
1121
1122 for (int i=0; i<=FTM::StaticData::kMaxPixelIdx; i++)
1123 if (i/9==idx)
1124 data.EnablePixel(i, enable);
1125
1126 CmdSendStatDat(data);
1127
1128 return true;
1129 }
1130
1131 bool TogglePixel(uint16_t idx)
1132 {
1133 if (idx>FTM::StaticData::kMaxPixelIdx)
1134 return false;
1135
1136 FTM::StaticData data(fStaticData);
1137
1138 data.EnablePixel(idx, !fStaticData.Enabled(idx));
1139
1140 CmdSendStatDat(data);
1141
1142 return true;
1143 }
1144
1145 States GetState() const
1146 {
1147 if (!IsConnected())
1148 return kDisconnected;
1149
1150 switch (fHeader.fState&FTM::kFtmStates)
1151 {
1152 case FTM::kFtmUndefined:
1153 return kConnected;
1154
1155 case FTM::kFtmRunning:
1156 case FTM::kFtmCalib:
1157 return kTakingData;
1158
1159 case FTM::kFtmIdle:
1160 case FTM::kFtmConfig:
1161 return fStaticData == fBufStaticData ? kConfigured : kIdle;
1162 }
1163
1164 throw runtime_error("ConnectionFTM::GetState - Impossible code reached.");
1165 }
1166
1167 int GetCounter(FTM::Types type) { return fCounter[type]; }
1168
1169 const FTM::StaticData &GetStaticData() const { return fStaticData; }
1170};
1171
1172//const uint16_t ConnectionFTM::kMaxAddr = 0xfff;
1173
1174// ------------------------------------------------------------------------
1175
1176#include "DimDescriptionService.h"
1177
1178class ConnectionDimFTM : public ConnectionFTM
1179{
1180private:
1181
1182 DimDescribedService fDimPassport;
1183 DimDescribedService fDimTriggerRates;
1184 DimDescribedService fDimError;
1185 DimDescribedService fDimFtuList;
1186 DimDescribedService fDimStaticData;
1187 DimDescribedService fDimDynamicData;
1188 DimDescribedService fDimCounter;
1189
1190 uint64_t fTimeStamp;
1191 uint64_t fTimeStampOn;
1192 uint32_t fTriggerCounter;
1193
1194 void UpdateFirstHeader()
1195 {
1196 ConnectionFTM::UpdateFirstHeader();
1197
1198 const FTM::DimPassport data(fHeader);
1199 fDimPassport.Update(data);
1200 }
1201
1202 /*
1203 void UpdateHeader()
1204 {
1205 ConnectionFTM::UpdateHeader();
1206
1207 if (fHeader.fType!=FTM::kDynamicData)
1208 return;
1209
1210 const FTM::DimTriggerCounter data(fHeader);
1211 fDimTriggerCounter.Update(data);
1212 }*/
1213
1214 void UpdateFtuList()
1215 {
1216 ConnectionFTM::UpdateFtuList();
1217
1218 const FTM::DimFtuList data(fHeader, fFtuList);
1219 fDimFtuList.Update(data);
1220 }
1221
1222 void UpdateStaticData()
1223 {
1224 ConnectionFTM::UpdateStaticData();
1225
1226 const FTM::DimStaticData data(fHeader, fStaticData);
1227 fDimStaticData.Update(data);
1228 }
1229
1230 void UpdateDynamicData()
1231 {
1232 ConnectionFTM::UpdateDynamicData();
1233
1234 const FTM::DimDynamicData data(fHeader, fDynamicData, fStaticData);
1235 fDimDynamicData.Update(data);
1236
1237 float rate = -1;
1238 uint64_t tdiff = 0;
1239 uint64_t odiff = 0;
1240 if (fHeader.fTimeStamp>=fTimeStamp && fHeader.fTriggerCounter>=fTriggerCounter)
1241 {
1242 tdiff = fHeader.fTimeStamp -fTimeStamp;
1243 odiff = fDynamicData.fOnTimeCounter -fTimeStampOn;
1244
1245 const uint32_t cdiff = fHeader.fTriggerCounter-fTriggerCounter;
1246 rate = tdiff==0 ? 0 : 1000000*float(cdiff)/tdiff;
1247 }
1248
1249 fTimeStamp = fHeader.fTimeStamp;
1250 fTimeStampOn = fDynamicData.fOnTimeCounter;
1251 fTriggerCounter = fHeader.fTriggerCounter;
1252
1253 const FTM::DimTriggerRates rates(fHeader, fDynamicData, fStaticData,
1254 rate, tdiff*1e-6, odiff*1e-6);
1255
1256 fDimTriggerRates.Update(rates);
1257 }
1258
1259 void UpdateError()
1260 {
1261 ConnectionFTM::UpdateError();
1262
1263 const FTM::DimError data(fHeader, fError);
1264 fDimError.Update(data);
1265 }
1266
1267 void UpdateCounter()
1268 {
1269 ConnectionFTM::UpdateCounter();
1270
1271 const uint32_t counter[6] =
1272 {
1273 fCounter[FTM::kHeader],
1274 fCounter[FTM::kStaticData],
1275 fCounter[FTM::kDynamicData],
1276 fCounter[FTM::kFtuList],
1277 fCounter[FTM::kErrorList],
1278 fCounter[FTM::kRegister],
1279 };
1280
1281 fDimCounter.Update(counter);
1282 }
1283
1284public:
1285 ConnectionDimFTM(ba::io_service& ioservice, MessageImp &imp) :
1286 ConnectionFTM(ioservice, imp),
1287 fDimPassport ("FTM_CONTROL/PASSPORT", "X:1;S:1", ""),
1288 fDimTriggerRates ("FTM_CONTROL/TRIGGER_RATES", "X:2;I:1;F:1;F:40;F:160;F:1;F:1", ""),
1289 fDimError ("FTM_CONTROL/ERROR", "X:1;S:1;S:28", ""),
1290 fDimFtuList ("FTM_CONTROL/FTU_LIST", "X:1;X:1;S:1;C:4;X:40;C:40;C:40", ""),
1291 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", ""),
1292 fDimDynamicData ("FTM_CONTROL/DYNAMIC_DATA", "X:1;X:1;F:4;I:160;I:40;S:40;S:40;S:40;S:1", ""),
1293 fDimCounter ("FTM_CONTROL/COUNTER", "I:6", ""),
1294 fTimeStamp(UINT64_MAX),
1295 fTriggerCounter(UINT32_MAX)
1296 {
1297 }
1298
1299 // 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
1300};
1301
1302// ------------------------------------------------------------------------
1303
1304template <class T, class S>
1305class StateMachineFTM : public T, public ba::io_service, public ba::io_service::work
1306{
1307 int Wrap(boost::function<void()> f)
1308 {
1309 f();
1310 return T::GetCurrentState();
1311 }
1312
1313 function<int(const EventImp &)> Wrapper(function<void()> func)
1314 {
1315 return bind(&StateMachineFTM::Wrap, this, func);
1316 }
1317
1318private:
1319 S fFTM;
1320
1321 bool CheckEventSize(size_t has, const char *name, size_t size)
1322 {
1323 if (has==size)
1324 return true;
1325
1326 ostringstream msg;
1327 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
1328 T::Fatal(msg);
1329 return false;
1330 }
1331
1332 int SetRegister(const EventImp &evt)
1333 {
1334 if (!CheckEventSize(evt.GetSize(), "SetRegister", 8))
1335 return T::kSM_FatalError;
1336
1337 const uint32_t *dat = evt.Ptr<uint32_t>();
1338
1339 if (dat[1]>uint16_t(-1))
1340 {
1341 ostringstream msg;
1342 msg << hex << "Value " << dat[1] << " out of range.";
1343 T::Error(msg);
1344 return T::GetCurrentState();
1345 }
1346
1347
1348 if (dat[0]>uint16_t(-1) || !fFTM.CmdSetRegister(dat[0], dat[1]))
1349 {
1350 ostringstream msg;
1351 msg << hex << "Address " << dat[0] << " out of range.";
1352 T::Error(msg);
1353 }
1354
1355 return T::GetCurrentState();
1356 }
1357
1358 int GetRegister(const EventImp &evt)
1359 {
1360 if (!CheckEventSize(evt.GetSize(), "GetRegister", 4))
1361 return T::kSM_FatalError;
1362
1363 const unsigned int addr = evt.GetInt();
1364 if (addr>uint16_t(-1) || !fFTM.CmdGetRegister(addr))
1365 {
1366 ostringstream msg;
1367 msg << hex << "Address " << addr << " out of range.";
1368 T::Error(msg);
1369 }
1370
1371 return T::GetCurrentState();
1372 }
1373
1374 int TakeNevents(const EventImp &evt)
1375 {
1376 if (!CheckEventSize(evt.GetSize(), "TakeNevents", 4))
1377 return T::kSM_FatalError;
1378
1379 const unsigned int dat = evt.GetUInt();
1380
1381 /*
1382 if (dat[1]>uint32_t(-1))
1383 {
1384 ostringstream msg;
1385 msg << hex << "Value " << dat[1] << " out of range.";
1386 T::Error(msg);
1387 return T::GetCurrentState();
1388 }*/
1389
1390 fFTM.CmdTakeNevents(dat);
1391
1392 return T::GetCurrentState();
1393 }
1394
1395 int DisableReports(const EventImp &evt)
1396 {
1397 if (!CheckEventSize(evt.GetSize(), "DisableReports", 1))
1398 return T::kSM_FatalError;
1399
1400 fFTM.CmdDisableReports(evt.GetBool());
1401
1402 return T::GetCurrentState();
1403 }
1404
1405 int SetVerbosity(const EventImp &evt)
1406 {
1407 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
1408 return T::kSM_FatalError;
1409
1410 fFTM.SetVerbose(evt.GetBool());
1411
1412 return T::GetCurrentState();
1413 }
1414
1415 int SetHexOutput(const EventImp &evt)
1416 {
1417 if (!CheckEventSize(evt.GetSize(), "SetHexOutput", 1))
1418 return T::kSM_FatalError;
1419
1420 fFTM.SetHexOutput(evt.GetBool());
1421
1422 return T::GetCurrentState();
1423 }
1424
1425 int SetDynamicOut(const EventImp &evt)
1426 {
1427 if (!CheckEventSize(evt.GetSize(), "SetDynamicOut", 1))
1428 return T::kSM_FatalError;
1429
1430 fFTM.SetDynamicOut(evt.GetBool());
1431
1432 return T::GetCurrentState();
1433 }
1434
1435 int LoadStaticData(const EventImp &evt)
1436 {
1437 if (fFTM.LoadStaticData(evt.GetString()))
1438 return T::GetCurrentState();
1439
1440 ostringstream msg;
1441 msg << "Loading static data from file '" << evt.GetString() << "' failed ";
1442
1443 if (errno)
1444 msg << "(" << strerror(errno) << ")";
1445 else
1446 msg << "(wrong size, expected " << sizeof(FTM::StaticData) << " bytes)";
1447
1448 T::Warn(msg);
1449
1450 return T::GetCurrentState();
1451 }
1452
1453 int SaveStaticData(const EventImp &evt)
1454 {
1455 if (fFTM.SaveStaticData(evt.GetString()))
1456 return T::GetCurrentState();
1457
1458 ostringstream msg;
1459 msg << "Writing static data to file '" << evt.GetString() << "' failed ";
1460 msg << "(" << strerror(errno) << ")";
1461
1462 T::Warn(msg);
1463
1464 return T::GetCurrentState();
1465 }
1466
1467 int SetThreshold(const EventImp &evt)
1468 {
1469 if (!CheckEventSize(evt.GetSize(), "SetThreshold", 8))
1470 return T::kSM_FatalError;
1471
1472 const int32_t *data = evt.Ptr<int32_t>();
1473
1474 if (!fFTM.SetThreshold(data[0], data[1]))
1475 T::Warn("SetThreshold - Maximum allowed patch number 159, valid value range 0-0xffff");
1476
1477 return T::GetCurrentState();
1478 }
1479
1480 int SetNoutof4(const EventImp &evt)
1481 {
1482 if (!CheckEventSize(evt.GetSize(), "SetNoutof4", 8))
1483 return T::kSM_FatalError;
1484
1485 const int32_t *data = evt.Ptr<int32_t>();
1486
1487 if (!fFTM.SetNoutof4(data[0], data[1]))
1488 T::Warn("SetNoutof4 - Maximum allowed board number 39, valid value range 0-0xffff");
1489
1490 return T::GetCurrentState();
1491 }
1492
1493 int EnableFTU(const EventImp &evt)
1494 {
1495 if (!CheckEventSize(evt.GetSize(), "EnableFTU", 5))
1496 return T::kSM_FatalError;
1497
1498 const int32_t &board = evt.Get<int32_t>();
1499 const int8_t &enable = evt.Get<int8_t>(4);
1500
1501 if (!fFTM.EnableFTU(board, enable))
1502 T::Warn("EnableFTU - Board number must be <40.");
1503
1504 return T::GetCurrentState();
1505 }
1506
1507 int ToggleFTU(const EventImp &evt)
1508 {
1509 if (!CheckEventSize(evt.GetSize(), "ToggleFTU", 4))
1510 return T::kSM_FatalError;
1511
1512 if (!fFTM.ToggleFTU(evt.GetInt()))
1513 T::Warn("ToggleFTU - Allowed range of boards 0-39.");
1514
1515 return T::GetCurrentState();
1516 }
1517
1518 int SetTriggerInterval(const EventImp &evt)
1519 {
1520 if (!CheckEventSize(evt.GetSize(), "SetTriggerInterval", 4))
1521 return T::kSM_FatalError;
1522
1523 if (!fFTM.SetTriggerInterval(evt.GetInt()))
1524 T::Warn("SetTriggerInterval - Value out of range.");
1525
1526 return T::GetCurrentState();
1527 }
1528
1529 int SetTriggerDelay(const EventImp &evt)
1530 {
1531 if (!CheckEventSize(evt.GetSize(), "SetTriggerDelay", 4))
1532 return T::kSM_FatalError;
1533
1534 if (!fFTM.SetTriggerDelay(evt.GetInt()))
1535 T::Warn("SetTriggerDealy - Value out of range.");
1536
1537 return T::GetCurrentState();
1538 }
1539
1540 int SetTimeMarkerDelay(const EventImp &evt)
1541 {
1542 if (!CheckEventSize(evt.GetSize(), "SetTimeMarkerDelay", 4))
1543 return T::kSM_FatalError;
1544
1545 if (!fFTM.SetTimeMarkerDelay(evt.GetInt()))
1546 T::Warn("SetTimeMarkerDelay - Value out of range.");
1547
1548 return T::GetCurrentState();
1549 }
1550
1551 int SetPrescaling(const EventImp &evt)
1552 {
1553 if (!CheckEventSize(evt.GetSize(), "SetPrescaling", 4))
1554 return T::kSM_FatalError;
1555
1556 if (!fFTM.SetPrescaling(evt.GetInt()-1))
1557 T::Warn("SetPrescaling - Value out of range.");
1558
1559 return T::GetCurrentState();
1560 }
1561
1562 int SetTriggerSeq(const EventImp &evt)
1563 {
1564 if (!CheckEventSize(evt.GetSize(), "SetTriggerSeq", 6))
1565 return T::kSM_FatalError;
1566
1567 const uint16_t *data = evt.Ptr<uint16_t>();
1568
1569 if (!fFTM.SetTriggerSeq(data))
1570 T::Warn("SetTriggerSeq - Value out of range.");
1571
1572 return T::GetCurrentState();
1573 }
1574
1575 int SetDeadTime(const EventImp &evt)
1576 {
1577 if (!CheckEventSize(evt.GetSize(), "SetDeadTime", 4))
1578 return T::kSM_FatalError;
1579
1580 if (!fFTM.SetDeadTime(evt.GetInt()))
1581 T::Warn("SetDeadTime - Value out of range.");
1582
1583 return T::GetCurrentState();
1584 }
1585
1586 int SetTriggerMultiplicity(const EventImp &evt)
1587 {
1588 if (!CheckEventSize(evt.GetSize(), "SetTriggerMultiplicity", 2))
1589 return T::kSM_FatalError;
1590
1591 if (!fFTM.SetTriggerMultiplicity(evt.GetUShort()))
1592 T::Warn("SetTriggerMultiplicity - Value out of range.");
1593
1594 return T::GetCurrentState();
1595 }
1596
1597 int SetCalibMultiplicity(const EventImp &evt)
1598 {
1599 if (!CheckEventSize(evt.GetSize(), "SetCalibMultiplicity", 2))
1600 return T::kSM_FatalError;
1601
1602 if (!fFTM.SetCalibMultiplicity(evt.GetUShort()))
1603 T::Warn("SetCalibMultiplicity - Value out of range.");
1604
1605 return T::GetCurrentState();
1606 }
1607
1608 int SetTriggerWindow(const EventImp &evt)
1609 {
1610 if (!CheckEventSize(evt.GetSize(), "SetTriggerWindow", 2))
1611 return T::kSM_FatalError;
1612
1613 if (!fFTM.SetTriggerWindow(evt.GetUShort()))
1614 T::Warn("SetTriggerWindow - Value out of range.");
1615
1616 return T::GetCurrentState();
1617 }
1618
1619 int SetCalibWindow(const EventImp &evt)
1620 {
1621 if (!CheckEventSize(evt.GetSize(), "SetCalibWindow", 2))
1622 return T::kSM_FatalError;
1623
1624 if (!fFTM.SetCalibWindow(evt.GetUShort()))
1625 T::Warn("SetCalibWindow - Value out of range.");
1626
1627 return T::GetCurrentState();
1628 }
1629
1630 int SetClockRegister(const EventImp &evt)
1631 {
1632 if (!CheckEventSize(evt.GetSize(), "SetClockRegister", 8*8))
1633 return T::kSM_FatalError;
1634
1635 const uint64_t *reg = evt.Ptr<uint64_t>();
1636
1637 if (!fFTM.SetClockRegister(reg))
1638 T::Warn("SetClockRegister - Value out of range.");
1639
1640 return T::GetCurrentState();
1641 }
1642
1643 int SetClockFrequency(const EventImp &evt)
1644 {
1645 if (!CheckEventSize(evt.GetSize(), "SetClockFrequency", 2))
1646 return T::kSM_FatalError;
1647
1648 const map<uint16_t,array<uint64_t, 8>>::const_iterator it =
1649 fClockCondSetup.find(evt.GetUShort());
1650
1651 if (it==fClockCondSetup.end())
1652 {
1653 T::Warn("SetClockFrequency - Frequency not supported.");
1654 return T::GetCurrentState();
1655 }
1656
1657 if (!fFTM.SetClockRegister(it->second.data()))
1658 T::Warn("SetClockFrequency - Register values out of range.");
1659
1660 return T::GetCurrentState();
1661 }
1662
1663 int EnableLP(const EventImp &evt, FTM::StaticData::GeneralSettings lp, FTM::StaticData::LightPulserEnable group)
1664 {
1665 if (!CheckEventSize(evt.GetSize(), "EnableLP", 1))
1666 return T::kSM_FatalError;
1667
1668 if (!fFTM.EnableLP(lp, group, evt.GetBool()))
1669 T::Warn("EnableLP - Invalid light pulser id.");
1670
1671 return T::GetCurrentState();
1672 }
1673
1674 int SetIntensity(const EventImp &evt, FTM::StaticData::GeneralSettings lp)
1675 {
1676 if (!CheckEventSize(evt.GetSize(), "SetIntensity", 2))
1677 return T::kSM_FatalError;
1678
1679 if (!fFTM.SetIntensity(lp, evt.GetShort()))
1680 T::Warn("SetIntensity - Value out of range.");
1681
1682 return T::GetCurrentState();
1683 }
1684
1685 int Enable(const EventImp &evt, FTM::StaticData::GeneralSettings type)
1686 {
1687 if (!CheckEventSize(evt.GetSize(), "Enable", 1))
1688 return T::kSM_FatalError;
1689
1690 fFTM.Enable(type, evt.GetBool());
1691
1692 return T::GetCurrentState();
1693 }
1694
1695 int EnablePixel(const EventImp &evt, bool b)
1696 {
1697 if (!CheckEventSize(evt.GetSize(), "EnablePixel", 2))
1698 return T::kSM_FatalError;
1699
1700 if (!fFTM.EnablePixel(evt.GetUShort(), b))
1701 T::Warn("EnablePixel - Value out of range.");
1702
1703 return T::GetCurrentState();
1704 }
1705
1706 int DisableAllPixelsExcept(const EventImp &evt)
1707 {
1708 if (!CheckEventSize(evt.GetSize(), "DisableAllPixelsExcept", 2))
1709 return T::kSM_FatalError;
1710
1711 if (!fFTM.DisableAllPixelsExcept(evt.GetUShort()))
1712 T::Warn("DisableAllPixelsExcept - Value out of range.");
1713
1714 return T::GetCurrentState();
1715 }
1716
1717 int DisableAllPatchesExcept(const EventImp &evt)
1718 {
1719 if (!CheckEventSize(evt.GetSize(), "DisableAllPatchesExcept", 2))
1720 return T::kSM_FatalError;
1721
1722 if (!fFTM.DisableAllPatchesExcept(evt.GetUShort()))
1723 T::Warn("DisableAllPatchesExcept - Value out of range.");
1724
1725 return T::GetCurrentState();
1726 }
1727
1728 int EnablePatch(const EventImp &evt, bool enable)
1729 {
1730 if (!CheckEventSize(evt.GetSize(), "EnablePatch", 2))
1731 return T::kSM_FatalError;
1732
1733 if (!fFTM.EnablePatch(evt.GetUShort(), enable))
1734 T::Warn("EnablePatch - Value out of range.");
1735
1736 return T::GetCurrentState();
1737 }
1738
1739 int TogglePixel(const EventImp &evt)
1740 {
1741 if (!CheckEventSize(evt.GetSize(), "TogglePixel", 2))
1742 return T::kSM_FatalError;
1743
1744 if (!fFTM.TogglePixel(evt.GetUShort()))
1745 T::Warn("TogglePixel - Value out of range.");
1746
1747 return T::GetCurrentState();
1748 }
1749
1750 int ResetCrate(const EventImp &evt)
1751 {
1752 if (!CheckEventSize(evt.GetSize(), "ResetCrate", 2))
1753 return T::kSM_FatalError;
1754
1755 fFTM.CmdResetCrate(evt.GetUShort());
1756
1757 return T::GetCurrentState();
1758 }
1759
1760 int Disconnect()
1761 {
1762 // Close all connections
1763 fFTM.PostClose(false);
1764
1765 /*
1766 // Now wait until all connection have been closed and
1767 // all pending handlers have been processed
1768 poll();
1769 */
1770
1771 return T::GetCurrentState();
1772 }
1773
1774 int Reconnect(const EventImp &evt)
1775 {
1776 // Close all connections to supress the warning in SetEndpoint
1777 fFTM.PostClose(false);
1778
1779 // Now wait until all connection have been closed and
1780 // all pending handlers have been processed
1781 poll();
1782
1783 if (evt.GetBool())
1784 fFTM.SetEndpoint(evt.GetString());
1785
1786 // Now we can reopen the connection
1787 fFTM.PostClose(true);
1788
1789 return T::GetCurrentState();
1790 }
1791
1792 /*
1793 int Transition(const Event &evt)
1794 {
1795 switch (evt.GetTargetState())
1796 {
1797 case kDisconnected:
1798 case kConnected:
1799 }
1800
1801 return T::kSM_FatalError;
1802 }*/
1803
1804 int64_t fCounterReg;
1805 int64_t fCounterStat;
1806
1807 typedef map<string, FTM::StaticData> Configs;
1808 Configs fConfigs;
1809 Configs::const_iterator fTargetConfig;
1810
1811 int ConfigureFTM(const EventImp &evt)
1812 {
1813 const string name = evt.GetText();
1814
1815 fTargetConfig = fConfigs.find(name);
1816 if (fTargetConfig==fConfigs.end())
1817 {
1818 T::Error("ConfigureFTM - Run-type '"+name+"' not found.");
1819 return T::GetCurrentState();
1820 }
1821
1822 T::Message("Starting configuration for '"+name+"'");
1823
1824 fCounterReg = fFTM.GetCounter(FTM::kRegister);
1825 fFTM.CmdStopRun();
1826
1827 return FTM::kConfiguring1;
1828 }
1829
1830 int ResetConfig()
1831 {
1832 return fFTM.GetState();
1833 }
1834
1835 int Execute()
1836 {
1837 // Dispatch (execute) at most one handler from the queue. In contrary
1838 // to run_one(), it doesn't wait until a handler is available
1839 // which can be dispatched, so poll_one() might return with 0
1840 // handlers dispatched. The handlers are always dispatched/executed
1841 // synchronously, i.e. within the call to poll_one()
1842 poll_one();
1843
1844 // If FTM is neither in data taking nor idle,
1845 // leave configuration state
1846 switch (fFTM.GetState())
1847 {
1848 case ConnectionFTM::kDisconnected: return FTM::kDisconnected;
1849 case ConnectionFTM::kConnected: return FTM::kConnected;
1850 default:
1851 break;
1852 }
1853
1854 switch (T::GetCurrentState())
1855 {
1856 case FTM::kConfiguring1:
1857 // If FTM has received an anwer to the stop_run command
1858 // the counter for the registers has been increased
1859 if (fFTM.GetCounter(FTM::kRegister)<=fCounterReg)
1860 break;
1861
1862 // If now the state is not idle as expected this means we had
1863 // an error (maybe old events waiting in the queue)
1864 if (fFTM.GetState()!=ConnectionFTM::kIdle &&
1865 fFTM.GetState()!=ConnectionFTM::kConfigured)
1866 return FTM::kConfigError1;
1867
1868 fCounterStat = fFTM.GetCounter(FTM::kStaticData);
1869
1870 T::Message("Trigger successfully disabled... sending new configuration.");
1871
1872 fFTM.CmdSendStatDat(fTargetConfig->second);
1873
1874 // Next state is: wait for the answer to our configuration
1875 return FTM::kConfiguring2;
1876
1877 case FTM::kConfiguring2:
1878 case FTM::kConfigured:
1879 // If FTM has received an anwer to the stop_run command
1880 // the counter for the registers has been increased
1881 if (fFTM.GetCounter(FTM::kStaticData)<=fCounterStat)
1882 break;
1883
1884 // If now the configuration is not what we expected
1885 // we had an error (maybe old events waiting in the queue?)
1886 // ======================
1887 if (fFTM.GetState()!=ConnectionFTM::kConfigured)
1888 return FTM::kConfigError2;
1889 // ======================
1890
1891 // Check configuration again when a new static data block
1892 // will be received
1893 fCounterStat = fFTM.GetCounter(FTM::kStaticData);
1894
1895 T::Info(" ==> TODO: Update run in database!");
1896 T::Message("Sending new configuration was successfull.");
1897
1898 // Next state is: wait for the answer to our configuration
1899 return FTM::kConfigured;
1900
1901 default:
1902 switch (fFTM.GetState())
1903 {
1904 case ConnectionFTM::kIdle: return FTM::kIdle;
1905 case ConnectionFTM::kConfigured: return FTM::kIdle;
1906 case ConnectionFTM::kTakingData: return FTM::kTakingData;
1907 default:
1908 throw runtime_error("StateMachienFTM - Execute() - Inavlid state.");
1909 }
1910 }
1911
1912 if (T::GetCurrentState()==FTM::kConfigured &&
1913 fFTM.GetState()==ConnectionFTM::kTakingData)
1914 return FTM::kTakingData;
1915
1916 return T::GetCurrentState();
1917 }
1918
1919public:
1920 StateMachineFTM(ostream &out=cout) :
1921 T(out, "FTM_CONTROL"), ba::io_service::work(static_cast<ba::io_service&>(*this)),
1922 fFTM(*this, *this)
1923 {
1924 // ba::io_service::work is a kind of keep_alive for the loop.
1925 // It prevents the io_service to go to stopped state, which
1926 // would prevent any consecutive calls to run()
1927 // or poll() to do nothing. reset() could also revoke to the
1928 // previous state but this might introduce some overhead of
1929 // deletion and creation of threads and more.
1930
1931
1932 // State names
1933 T::AddStateName(FTM::kDisconnected, "Disconnected",
1934 "FTM board not connected via ethernet.");
1935
1936 T::AddStateName(FTM::kConnected, "Connected",
1937 "Ethernet connection to FTM established (no state received yet).");
1938
1939 T::AddStateName(FTM::kIdle, "Idle",
1940 "Ethernet connection to FTM established, FTM in idle state.");
1941
1942 T::AddStateName(FTM::kConfiguring1, "Configuring1",
1943 "Command to diable run sent... waiting for response.");
1944 T::AddStateName(FTM::kConfiguring2, "Configuring2",
1945 "New configuration sent... waiting for response.");
1946 T::AddStateName(FTM::kConfigured, "Configured",
1947 "Received answer identical with target configuration.");
1948
1949 T::AddStateName(FTM::kTakingData, "TriggerOn",
1950 "Ethernet connection to FTM established, FTM is in taking data state (trigger switched on).");
1951
1952 T::AddStateName(FTM::kConfigError1, "ErrorInConfig1", "");
1953 T::AddStateName(FTM::kConfigError2, "ErrorInConfig2", "");
1954
1955 // FTM Commands
1956 T::AddEvent("TOGGLE_LED", FTM::kIdle)
1957 (Wrapper(bind(&ConnectionFTM::CmdToggleLed, &fFTM)))
1958 ("toggle led");
1959
1960 T::AddEvent("PING", FTM::kIdle)
1961 (Wrapper(bind(&ConnectionFTM::CmdPing, &fFTM)))
1962 ("send ping");
1963
1964 T::AddEvent("REQUEST_DYNAMIC_DATA", FTM::kIdle)
1965 (Wrapper(bind(&ConnectionFTM::CmdReqDynDat, &fFTM)))
1966 ("request transmission of dynamic data block");
1967
1968 T::AddEvent("REQUEST_STATIC_DATA", FTM::kIdle)
1969 (Wrapper(bind(&ConnectionFTM::CmdReqStatDat, &fFTM)))
1970 ("request transmission of static data from FTM to memory");
1971
1972 T::AddEvent("GET_REGISTER", "I", FTM::kIdle)
1973 (bind(&StateMachineFTM::GetRegister, this, placeholders::_1))
1974 ("read register from address addr"
1975 "|addr[short]:Address of register");
1976
1977 T::AddEvent("SET_REGISTER", "I:2", FTM::kIdle)
1978 (bind(&StateMachineFTM::SetRegister, this, placeholders::_1))
1979 ("set register to value"
1980 "|addr[short]:Address of register"
1981 "|val[short]:Value to be set");
1982
1983 T::AddEvent("START_RUN", FTM::kIdle, FTM::kConfigured)
1984 (Wrapper(bind(&ConnectionFTM::CmdStartRun, &fFTM)))
1985 ("start a run (start distributing triggers)");
1986
1987 T::AddEvent("STOP_RUN", FTM::kTakingData)
1988 (Wrapper(bind(&ConnectionFTM::CmdStopRun, &fFTM)))
1989 ("stop a run (stop distributing triggers)");
1990
1991 T::AddEvent("TAKE_N_EVENTS", "I", FTM::kIdle)
1992 (bind(&StateMachineFTM::TakeNevents, this, placeholders::_1))
1993 ("take n events (distribute n triggers)|number[int]:Number of events to be taken");
1994
1995 T::AddEvent("DISABLE_REPORTS", "B", FTM::kIdle)
1996 (bind(&StateMachineFTM::DisableReports, this, placeholders::_1))
1997 ("disable sending rate reports"
1998 "|status[bool]:disable or enable that the FTM sends rate reports (yes/no)");
1999
2000 T::AddEvent("SET_THRESHOLD", "I:2", FTM::kIdle, FTM::kTakingData)
2001 (bind(&StateMachineFTM::SetThreshold, this, placeholders::_1))
2002 ("Set the comparator threshold"
2003 "|Patch[idx]:Index of the patch (0-159), -1 for all"
2004 "|Threshold[counts]:Threshold to be set in binary counts");
2005
2006 T::AddEvent("SET_N_OUT_OF_4", "I:2", FTM::kIdle, FTM::kTakingData)
2007 (bind(&StateMachineFTM::SetNoutof4, this, placeholders::_1))
2008 ("Set the comparator threshold"
2009 "|Board[idx]:Index of the board (0-39), -1 for all"
2010 "|Threshold[counts]:Threshold to be set in binary counts");
2011
2012 T::AddEvent("SET_PRESCALING", "I:1", FTM::kIdle)
2013 (bind(&StateMachineFTM::SetPrescaling, this, placeholders::_1))
2014 ("");
2015
2016 T::AddEvent("ENABLE_FTU", "I:1;B:1", FTM::kIdle)
2017 (bind(&StateMachineFTM::EnableFTU, this, placeholders::_1))
2018 ("Enable or disable FTU"
2019 "|Board[idx]:Index of the board (0-39), -1 for all"
2020 "|Enable[bool]:Whether FTU should be enabled or disabled (yes/no)");
2021
2022 T::AddEvent("DISABLE_PIXEL", "S:1", FTM::kIdle, FTM::kTakingData)
2023 (bind(&StateMachineFTM::EnablePixel, this, placeholders::_1, false))
2024 ("(-1 or all)");
2025
2026 T::AddEvent("ENABLE_PIXEL", "S:1", FTM::kIdle, FTM::kTakingData)
2027 (bind(&StateMachineFTM::EnablePixel, this, placeholders::_1, true))
2028 ("(-1 or all)");
2029
2030 T::AddEvent("DISABLE_ALL_PIXELS_EXCEPT", "S:1", FTM::kIdle)
2031 (bind(&StateMachineFTM::DisableAllPixelsExcept, this, placeholders::_1))
2032 ("");
2033
2034 T::AddEvent("DISABLE_ALL_PATCHES_EXCEPT", "S:1", FTM::kIdle)
2035 (bind(&StateMachineFTM::DisableAllPatchesExcept, this, placeholders::_1))
2036 ("");
2037
2038 T::AddEvent("ENABLE_PATCH", "S:1", FTM::kIdle)
2039 (bind(&StateMachineFTM::EnablePatch, this, placeholders::_1, true))
2040 ("");
2041
2042 T::AddEvent("DISABLE_PATCH", "S:1", FTM::kIdle)
2043 (bind(&StateMachineFTM::EnablePatch, this, placeholders::_1, false))
2044 ("");
2045
2046 T::AddEvent("TOGGLE_PIXEL", "S:1", FTM::kIdle)
2047 (bind(&StateMachineFTM::TogglePixel, this, placeholders::_1))
2048 ("");
2049
2050 T::AddEvent("TOGGLE_FTU", "I:1", FTM::kIdle)
2051 (bind(&StateMachineFTM::ToggleFTU, this, placeholders::_1))
2052 ("Toggle status of FTU (this is mainly meant to be used in the GUI)"
2053 "|Board[idx]:Index of the board (0-39)");
2054
2055 T::AddEvent("SET_TRIGGER_INTERVAL", "I:1", FTM::kIdle)
2056 (bind(&StateMachineFTM::SetTriggerInterval, this, placeholders::_1))
2057 ("Sets the trigger interval which is the distance between two consecutive artificial triggers."
2058 "|interval[int]:The applied trigger interval is: interval*4ns+8ns");
2059
2060 T::AddEvent("SET_TRIGGER_DELAY", "I:1", FTM::kIdle)
2061 (bind(&StateMachineFTM::SetTriggerDelay, this, placeholders::_1))
2062 (""
2063 "|delay[int]:The applied trigger delay is: delay*4ns+8ns");
2064
2065 T::AddEvent("SET_TIME_MARKER_DELAY", "I:1", FTM::kIdle)
2066 (bind(&StateMachineFTM::SetTimeMarkerDelay, this, placeholders::_1))
2067 (""
2068 "|delay[int]:The applied time marker delay is: delay*4ns+8ns");
2069
2070 T::AddEvent("SET_DEAD_TIME", "I:1", FTM::kIdle)
2071 (bind(&StateMachineFTM::SetDeadTime, this, placeholders::_1))
2072 (""
2073 "|dead_time[int]:The applied dead time is: dead_time*4ns+8ns");
2074
2075 T::AddEvent("ENABLE_TRIGGER", "B:1", FTM::kIdle)
2076 (bind(&StateMachineFTM::Enable, this, placeholders::_1, FTM::StaticData::kTrigger))
2077 ("Switch on the physics trigger"
2078 "|Enable[bool]:Enable physics trigger (yes/no)");
2079
2080 // FIXME: Switch on/off depending on sequence
2081 T::AddEvent("ENABLE_EXT1", "B:1", FTM::kIdle)
2082 (bind(&StateMachineFTM::Enable, this, placeholders::_1, FTM::StaticData::kExt1))
2083 ("Switch on the triggers through the first external line"
2084 "|Enable[bool]:Enable ext1 trigger (yes/no)");
2085
2086 // FIXME: Switch on/off depending on sequence
2087 T::AddEvent("ENABLE_EXT2", "B:1", FTM::kIdle)
2088 (bind(&StateMachineFTM::Enable, this, placeholders::_1, FTM::StaticData::kExt2))
2089 ("Switch on the triggers through the second external line"
2090 "|Enable[bool]:Enable ext2 trigger (yes/no)");
2091
2092 T::AddEvent("ENABLE_VETO", "B:1", FTM::kIdle)
2093 (bind(&StateMachineFTM::Enable, this, placeholders::_1, FTM::StaticData::kVeto))
2094 ("Enable veto line"
2095 "|Enable[bool]:Enable veto (yes/no)");
2096
2097 T::AddEvent("ENABLE_CLOCK_CONDITIONER", "B:1", FTM::kIdle)
2098 (bind(&StateMachineFTM::Enable, this, placeholders::_1, FTM::StaticData::kClockConditioner))
2099 ("Enable clock conidtioner output in favor of time marker output"
2100 "|Enable[bool]:Enable clock conditioner (yes/no)");
2101
2102 T::AddEvent("ENABLE_GROUP1_LPINT", "B:1", FTM::kIdle)
2103 (bind(&StateMachineFTM::EnableLP, this, placeholders::_1, FTM::StaticData::kLPint, FTM::StaticData::kGroup1))
2104 ("");
2105 T::AddEvent("ENABLE_GROUP1_LPEXT", "B:1", FTM::kIdle)
2106 (bind(&StateMachineFTM::EnableLP, this, placeholders::_1, FTM::StaticData::kLPext, FTM::StaticData::kGroup1))
2107 ("");
2108 T::AddEvent("ENABLE_GROUP2_LPINT", "B:1", FTM::kIdle)
2109 (bind(&StateMachineFTM::EnableLP, this, placeholders::_1, FTM::StaticData::kLPint, FTM::StaticData::kGroup2))
2110 ("");
2111 T::AddEvent("ENABLE_GROUP2_LPEXT", "B:1", FTM::kIdle)
2112 (bind(&StateMachineFTM::EnableLP, this, placeholders::_1, FTM::StaticData::kLPext, FTM::StaticData::kGroup2))
2113 ("");
2114 T::AddEvent("SET_INTENSITY_LPINT", "S:1", FTM::kIdle)
2115 (bind(&StateMachineFTM::SetIntensity, this, placeholders::_1, FTM::StaticData::kLPint))
2116 ("");
2117 T::AddEvent("SET_INTENSITY_LPEXT", "S:1", FTM::kIdle)
2118 (bind(&StateMachineFTM::SetIntensity, this, placeholders::_1, FTM::StaticData::kLPext))
2119 ("");
2120
2121
2122 T::AddEvent("SET_TRIGGER_SEQUENCE", "S:3", FTM::kIdle)
2123 (bind(&StateMachineFTM::SetTriggerSeq, this, placeholders::_1))
2124 ("Setup the sequence of artificial triggers produced by the FTM"
2125 "|Ped[short]:number of pedestal triggers in a row"
2126 "|LPext[short]:number of triggers of the external light pulser"
2127 "|LPint[short]:number of triggers of the internal light pulser");
2128
2129 T::AddEvent("SET_TRIGGER_MULTIPLICITY", "S:1", FTM::kIdle)
2130 (bind(&StateMachineFTM::SetTriggerMultiplicity, this, placeholders::_1))
2131 ("Setup the Multiplicity condition for physcis triggers"
2132 "|N[int]:Number of requirered coincident triggers from sum-patches (1-40)");
2133
2134 T::AddEvent("SET_TRIGGER_WINDOW", "S:1", FTM::kIdle)
2135 (bind(&StateMachineFTM::SetTriggerWindow, this, placeholders::_1))
2136 ("");
2137
2138 T::AddEvent("SET_CALIBRATION_MULTIPLICITY", "S:1", FTM::kIdle)
2139 (bind(&StateMachineFTM::SetCalibMultiplicity, this, placeholders::_1))
2140 ("Setup the Multiplicity condition for artificial (calibration) triggers"
2141 "|N[int]:Number of requirered coincident triggers from sum-patches (1-40)");
2142
2143 T::AddEvent("SET_CALIBRATION_WINDOW", "S:1", FTM::kIdle)
2144 (bind(&StateMachineFTM::SetCalibWindow, this, placeholders::_1))
2145 ("");
2146
2147 T::AddEvent("SET_CLOCK_FREQUENCY", "S:1", FTM::kIdle)
2148 (bind(&StateMachineFTM::SetClockFrequency, this, placeholders::_1))
2149 ("");
2150
2151 T::AddEvent("SET_CLOCK_REGISTER", "X:8", FTM::kIdle)
2152 (bind(&StateMachineFTM::SetClockRegister, this, placeholders::_1))
2153 ("");
2154
2155 // A new configure will first stop the FTM this means
2156 // we can allow it in idle _and_ taking data
2157 T::AddEvent("CONFIGURE", "C", FTM::kIdle, FTM::kConfiguring1, FTM::kConfiguring2, FTM::kConfigured, FTM::kTakingData)
2158 (bind(&StateMachineFTM::ConfigureFTM, this, placeholders::_1))
2159 ("");
2160
2161 T::AddEvent("RESET_CONFIGURE", FTM::kConfiguring1, FTM::kConfiguring2, FTM::kConfigured, FTM::kConfigError1, FTM::kConfigError2)
2162 (bind(&StateMachineFTM::ResetConfig, this))
2163 ("");
2164
2165
2166
2167 T::AddEvent("RESET_CRATE", "S:1", FTM::kIdle)
2168 (bind(&StateMachineFTM::ResetCrate, this, placeholders::_1))
2169 ("Reset one of the crates 0-3"
2170 "|crate[short]:Crate number to be reseted (0-3)");
2171
2172 T::AddEvent("RESET_CAMERA", FTM::kIdle)
2173 (Wrapper(bind(&ConnectionFTM::CmdResetCamera, &fFTM)))
2174 ("Reset all crates. The commands are sent in the order 0,1,2,3");
2175
2176
2177 // Load/save static data block
2178 T::AddEvent("SAVE", "C", FTM::kIdle)
2179 (bind(&StateMachineFTM::SaveStaticData, this, placeholders::_1))
2180 ("Saves the static data (FTM configuration) from memory to a file"
2181 "|filename[string]:Filename (can include a path), .bin is automatically added");
2182
2183 T::AddEvent("LOAD", "C", FTM::kIdle)
2184 (bind(&StateMachineFTM::LoadStaticData, this, placeholders::_1))
2185 ("Loads the static data (FTM configuration) from a file into memory and sends it to the FTM"
2186 "|filename[string]:Filename (can include a path), .bin is automatically added");
2187
2188
2189
2190 // Verbosity commands
2191 T::AddEvent("SET_VERBOSE", "B")
2192 (bind(&StateMachineFTM::SetVerbosity, this, placeholders::_1))
2193 ("set verbosity state"
2194 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
2195
2196 T::AddEvent("SET_HEX_OUTPUT", "B")
2197 (bind(&StateMachineFTM::SetHexOutput, this, placeholders::_1))
2198 ("enable or disable hex output for received data"
2199 "|hexout[bool]:disable or enable hex output for received data (yes/no)");
2200
2201 T::AddEvent("SET_DYNAMIC_OUTPUT", "B")
2202 (bind(&StateMachineFTM::SetDynamicOut, this, placeholders::_1))
2203 ("enable or disable output for received dynamic data (data is still broadcasted via Dim)"
2204 "|dynout[bool]:disable or enable output for dynamic data (yes/no)");
2205
2206
2207 // Conenction commands
2208 T::AddEvent("DISCONNECT", FTM::kConnected, FTM::kIdle)
2209 (bind(&StateMachineFTM::Disconnect, this))
2210 ("disconnect from ethernet");
2211
2212 T::AddEvent("RECONNECT", "O", FTM::kDisconnected, FTM::kConnected, FTM::kIdle, FTM::kConfigured)
2213 (bind(&StateMachineFTM::Reconnect, this, placeholders::_1))
2214 ("(Re)connect ethernet connection to FTM, a new address can be given"
2215 "|[host][string]:new ethernet address in the form <host:port>");
2216
2217 fFTM.StartConnect();
2218 }
2219
2220 void SetEndpoint(const string &url)
2221 {
2222 fFTM.SetEndpoint(url);
2223 }
2224
2225 map<uint16_t, array<uint64_t, 8>> fClockCondSetup;
2226
2227 template<class V>
2228 bool CheckConfigVal(Configuration &conf, V max, const string &name, const string &sub)
2229 {
2230 if (!conf.HasDef(name, sub))
2231 {
2232 T::Error("Neither "+name+"default nor "+name+sub+" found.");
2233 return false;
2234 }
2235
2236 const V val = conf.GetDef<V>(name, sub);
2237
2238 if (val<=max)
2239 return true;
2240
2241 ostringstream str;
2242 str << name << sub << "=" << val << " exceeds allowed maximum of " << max << "!";
2243 T::Error(str);
2244
2245 return false;
2246 }
2247
2248 int EvalOptions(Configuration &conf)
2249 {
2250 // ---------- General setup ----------
2251 fFTM.SetVerbose(!conf.Get<bool>("quiet"));
2252 fFTM.SetHexOutput(conf.Get<bool>("hex-out"));
2253 fFTM.SetDynamicOut(conf.Get<bool>("dynamic-out"));
2254
2255 // ---------- Setup clock conditioner frequencies ----------
2256 const vector<uint16_t> freq = conf.Vec<uint16_t>("clock-conditioner.frequency");
2257 if (freq.size()==0)
2258 T::Warn("No frequencies for the clock-conditioner defined.");
2259 else
2260 T::Message("Defining clock conditioner frequencies");
2261 for (vector<uint16_t>::const_iterator it=freq.begin();
2262 it!=freq.end(); it++)
2263 {
2264 if (fClockCondSetup.count(*it)>0)
2265 {
2266 T::Error("clock-conditioner frequency defined twice.");
2267 return 1;
2268 }
2269
2270 if (!conf.HasDef("clock-conditioner.R0.", *it) ||
2271 !conf.HasDef("clock-conditioner.R1.", *it) ||
2272 !conf.HasDef("clock-conditioner.R8.", *it) ||
2273 !conf.HasDef("clock-conditioner.R9.", *it) ||
2274 !conf.HasDef("clock-conditioner.R11.", *it) ||
2275 !conf.HasDef("clock-conditioner.R13.", *it) ||
2276 !conf.HasDef("clock-conditioner.R14.", *it) ||
2277 !conf.HasDef("clock-conditioner.R15.", *it))
2278 {
2279 T::Error("clock-conditioner values incomplete.");
2280 return 1;
2281 }
2282
2283 array<uint64_t, 8> &arr = fClockCondSetup[*it];
2284
2285 arr[0] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R0.", *it);
2286 arr[1] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R1.", *it);
2287 arr[2] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R8.", *it);
2288 arr[3] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R9.", *it);
2289 arr[4] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R11.", *it);
2290 arr[5] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R13.", *it);
2291 arr[6] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R14.", *it);
2292 arr[7] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R15.", *it);
2293
2294 ostringstream out;
2295 out << " -> " << setw(4) << *it << "MHz:" << hex << setfill('0');
2296 for (int i=0; i<8; i++)
2297 out << " " << setw(8) << arr[i];
2298 T::Message(out.str());
2299 }
2300
2301 // ---------- Setup run types ---------
2302 const vector<string> types = conf.Vec<string>("run-type");
2303 if (types.size()==0)
2304 T::Warn("No run-types defined.");
2305 else
2306 T::Message("Defining run-types");
2307 for (vector<string>::const_iterator it=types.begin();
2308 it!=types.end(); it++)
2309 {
2310 T::Message(" -> "+ *it);
2311
2312 if (fConfigs.count(*it)>0)
2313 {
2314 T::Error("Run-type "+*it+" defined twice.");
2315 return 2;
2316 }
2317
2318 if (!conf.HasDef("sampling-frequency.", *it))
2319 {
2320 T::Error("Neither sampling-frequency."+*it+" nor sampling-frequency.default found.");
2321 return 2;
2322 }
2323
2324 const uint16_t frq = conf.GetDef<uint16_t>("sampling-frequency.", *it);
2325
2326 FTM::StaticData data;
2327 data.SetClockRegister(fClockCondSetup[frq].data());
2328
2329 // Trigger sequence ped:lp1:lp2
2330 // (data. is used here as an abbreviation for FTM::StaticData::
2331 if (!CheckConfigVal<bool> (conf, true, "trigger.enable-trigger.", *it) ||
2332 !CheckConfigVal<bool> (conf, true, "trigger.enable-external-1.", *it) ||
2333 !CheckConfigVal<bool> (conf, true, "trigger.enable-external-2.", *it) ||
2334 !CheckConfigVal<bool> (conf, true, "trigger.enable-veto.", *it) ||
2335 !CheckConfigVal<bool> (conf, true, "trigger.enable-clock-conditioner.", *it) ||
2336 !CheckConfigVal<bool> (conf, true, "light-pulser.external.enable-group1.", *it) ||
2337 !CheckConfigVal<bool> (conf, true, "light-pulser.external.enable-group2.", *it) ||
2338 !CheckConfigVal<bool> (conf, true, "light-pulser.internal.enable-group1.", *it) ||
2339 !CheckConfigVal<bool> (conf, true, "light-pulser.internal.enable-group2.", *it) ||
2340 !CheckConfigVal<uint16_t>(conf, data.kMaxSequence, "trigger.sequence.pedestal.", *it) ||
2341 !CheckConfigVal<uint16_t>(conf, data.kMaxSequence, "trigger.sequence.lp-ext.", *it) ||
2342 !CheckConfigVal<uint16_t>(conf, data.kMaxSequence, "trigger.sequence.lp-int.", *it) ||
2343 !CheckConfigVal<uint16_t>(conf, data.kMaxTriggerInterval, "trigger.sequence.interval.", *it) ||
2344 !CheckConfigVal<uint16_t>(conf, data.kMaxMultiplicity, "trigger.multiplicity-physics.", *it) ||
2345 !CheckConfigVal<uint16_t>(conf, data.kMaxMultiplicity, "trigger.multiplicity-calib.", *it) ||
2346 !CheckConfigVal<uint16_t>(conf, data.kMaxWindow, "trigger.coincidence-window-physics.", *it) ||
2347 !CheckConfigVal<uint16_t>(conf, data.kMaxWindow, "trigger.coincidence-window-calib.", *it) ||
2348 !CheckConfigVal<uint16_t>(conf, data.kMaxDeadTime, "trigger.dead-time.", *it) ||
2349 !CheckConfigVal<uint16_t>(conf, data.kMaxDelayTrigger, "trigger.delay.", *it) ||
2350 !CheckConfigVal<uint16_t>(conf, data.kMaxDelayTimeMarker, "trigger.time-marker-delay.", *it) ||
2351 !CheckConfigVal<uint16_t>(conf, 0xffff, "ftu-report-interval.", *it) ||
2352 !CheckConfigVal<uint16_t>(conf, data.kMaxIntensity, "light-pulser.external.intensity.", *it) ||
2353 !CheckConfigVal<uint16_t>(conf, data.kMaxIntensity, "light-pulser.internal.intensity.", *it) ||
2354 !CheckConfigVal<uint16_t>(conf, data.kMaxDAC, "trigger.threshold.patch.", *it) ||
2355 !CheckConfigVal<uint16_t>(conf, data.kMaxDAC, "trigger.threshold.logic.", *it) ||
2356 0)
2357 return 2;
2358
2359 data.Enable(data.kTrigger, conf.GetDef<bool>("trigger.enable-trigger.", *it));
2360 data.Enable(data.kExt1, conf.GetDef<bool>("trigger.enable-external-1.", *it));
2361 data.Enable(data.kExt2, conf.GetDef<bool>("trigger.enable-external-2.", *it));
2362 data.Enable(data.kVeto, conf.GetDef<bool>("trigger.enable-veto.", *it));
2363 data.Enable(data.kClockConditioner, conf.GetDef<bool>("trigger.enable-clock-conditioner.", *it));
2364
2365 data.EnableLPint(data.kGroup1, conf.GetDef<bool>("light-pulser.internal.enable-group1.", *it));
2366 data.EnableLPint(data.kGroup2, conf.GetDef<bool>("light-pulser.internal.enable-group2.", *it));
2367 data.EnableLPext(data.kGroup1, conf.GetDef<bool>("light-pulser.external.enable-group1.", *it));
2368 data.EnableLPext(data.kGroup2, conf.GetDef<bool>("light-pulser.external.enable-group2.", *it));
2369
2370 // [ms] Interval between two artificial triggers (no matter which type) minimum 1ms, 10 bit
2371 data.fIntensityLPint = conf.GetDef<uint16_t>("light-pulser.internal.intensity.", *it);
2372 data.fIntensityLPext = conf.GetDef<uint16_t>("light-pulser.external.intensity.", *it);
2373 data.fTriggerInterval = conf.GetDef<uint16_t>("trigger.sequence.interval.", *it);
2374 data.fMultiplicityPhysics = conf.GetDef<uint16_t>("trigger.multiplicity-physics.", *it);
2375 data.fMultiplicityCalib = conf.GetDef<uint16_t>("trigger.multiplicity-calib.", *it);
2376 data.fWindowPhysics = conf.GetDef<uint16_t>("trigger.coincidence-window-physics.", *it); /// (4ns * x + 8ns)
2377 data.fWindowCalib = conf.GetDef<uint16_t>("trigger.coincidence-window-calib.", *it); /// (4ns * x + 8ns)
2378 data.fDelayTrigger = conf.GetDef<uint16_t>("trigger.delay.", *it); /// (4ns * x + 8ns)
2379 data.fDelayTimeMarker = conf.GetDef<uint16_t>("trigger.time-marker-delay.", *it); /// (4ns * x + 8ns)
2380 data.fDeadTime = conf.GetDef<uint16_t>("trigger.dead-time.", *it); /// (4ns * x + 8ns)
2381
2382 data.SetPrescaling(conf.GetDef<uint16_t>("ftu-report-interval.", *it));
2383
2384 const uint16_t seqped = conf.GetDef<uint16_t>("trigger.sequence.pedestal.", *it);
2385 const uint16_t seqint = conf.GetDef<uint16_t>("trigger.sequence.lp-int.", *it);
2386 const uint16_t seqext = conf.GetDef<uint16_t>("trigger.sequence.lp-ext.", *it);
2387
2388 data.SetSequence(seqped, seqint, seqext);
2389
2390 data.EnableAllFTU();
2391 data.EnableAllPixel();
2392
2393 const vector<uint16_t> pat1 = conf.Vec<uint16_t>("trigger.disable-patch.default");
2394 const vector<uint16_t> pat2 = conf.Vec<uint16_t>("trigger.disable-patch."+*it);
2395
2396 const vector<uint16_t> pix1 = conf.Vec<uint16_t>("trigger.disable-pixel.default");
2397 const vector<uint16_t> pix2 = conf.Vec<uint16_t>("trigger.disable-pixel."+*it);
2398
2399 const vector<uint16_t> ftu1 = conf.Vec<uint16_t>("disable-ftu.default");
2400 const vector<uint16_t> ftu2 = conf.Vec<uint16_t>("disable-ftu."+*it);
2401
2402 vector<uint16_t> ftu, pat, pix;
2403 ftu.insert(ftu.end(), ftu1.begin(), ftu1.end());
2404 ftu.insert(ftu.end(), ftu2.begin(), ftu2.end());
2405 pat.insert(pat.end(), pat1.begin(), pat1.end());
2406 pat.insert(pat.end(), pat2.begin(), pat2.end());
2407 pix.insert(pix.end(), pix1.begin(), pix1.end());
2408 pix.insert(pix.end(), pix2.begin(), pix2.end());
2409
2410 for (vector<uint16_t>::const_iterator ip=ftu.begin(); ip!=ftu.end(); ip++)
2411 {
2412 if (*ip>FTM::StaticData::kMaxPatchIdx)
2413 {
2414 ostringstream str;
2415 str << "disable-ftu.*=" << *ip << " exceeds allowed maximum of " << FTM::StaticData::kMaxPatchIdx << "!";
2416 T::Error(str);
2417 return 2;
2418 }
2419 data.DisableFTU(*ip);
2420 }
2421 for (vector<uint16_t>::const_iterator ip=pat.begin(); ip!=pat.end(); ip++)
2422 {
2423 if (*ip>FTM::StaticData::kMaxPatchIdx)
2424 {
2425 ostringstream str;
2426 str << "trigger.disable-patch.*=" << *ip << " exceeds allowed maximum of " << FTM::StaticData::kMaxPatchIdx << "!";
2427 T::Error(str);
2428 return 2;
2429 }
2430 data.EnablePatch(*ip, false);
2431 }
2432 for (vector<uint16_t>::const_iterator ip=pix.begin(); ip!=pix.end(); ip++)
2433 {
2434 if (*ip>FTM::StaticData::kMaxPixelIdx)
2435 {
2436 ostringstream str;
2437 str << "trigger.disable-pixel.*=" << *ip << " exceeds allowed maximum of " << FTM::StaticData::kMaxPixelIdx << "!";
2438 T::Error(str);
2439 return 2;
2440 }
2441 data.EnablePixel(*ip, false);
2442 }
2443
2444 const uint16_t th0 = conf.GetDef<uint16_t>("trigger.threshold.patch.", *it);
2445 const uint16_t th1 = conf.GetDef<uint16_t>("trigger.threshold.logic.", *it);
2446
2447 for (int i=0; i<40; i++)
2448 {
2449 data[i].fDAC[0] = th0;
2450 data[i].fDAC[1] = th0;
2451 data[i].fDAC[2] = th0;
2452 data[i].fDAC[3] = th0;
2453 data[i].fDAC[4] = th1;
2454 }
2455
2456 fConfigs[*it] = data;
2457
2458 // trigger.threshold.dac-0:
2459
2460 /*
2461 threshold-A data[n].fDAC[0] = val
2462 threshold-B data[n].fDAC[1] = val
2463 threshold-C data[n].fDAC[2] = val
2464 threshold-D data[n].fDAC[3] = val
2465 threshold-H data[n].fDAC[4] = val
2466 */
2467
2468 // kMaxDAC = 0xfff,
2469 }
2470
2471 // FIXME: Add a check about unsused configurations
2472
2473 // ---------- FOR TESTING PURPOSE ---------
2474
2475 // fFTM.SetDefaultSetup(conf.Get<string>("default-setup"));
2476 fConfigs["test"] = FTM::StaticData();
2477
2478 // ---------- Setup connection endpoint ---------
2479 SetEndpoint(conf.Get<string>("addr"));
2480
2481 return -1;
2482 }
2483};
2484
2485// ------------------------------------------------------------------------
2486
2487#include "Main.h"
2488
2489template<class T, class S, class R>
2490int RunShell(Configuration &conf)
2491{
2492 return Main::execute<T, StateMachineFTM<S, R>>(conf);
2493}
2494
2495void SetupConfiguration(Configuration &conf)
2496{
2497 po::options_description control("Control options");
2498 control.add_options()
2499 ("no-dim", po_bool(), "Disable dim services")
2500 ("addr,a", var<string>("localhost:5000"), "Network address of FTM")
2501 ("quiet,q", po_bool(), "Disable printing contents of all received messages (except dynamic data) in clear text.")
2502 ("hex-out", po_bool(), "Enable printing contents of all printed messages also as hex data.")
2503 ("dynamic-out", po_bool(), "Enable printing received dynamic data.")
2504// ("default-setup", var<string>(), "Binary file with static data loaded whenever a connection to the FTM was established.")
2505 ;
2506
2507 po::options_description freq("Sampling frequency setup");
2508 freq.add_options()
2509 ("clock-conditioner.frequency", vars<uint16_t>(), "Frequencies for which to setup the clock-conditioner (replace the * in the following options by this definition)")
2510 ("clock-conditioner.R0.*", var<Hex<uint32_t>>(), "Clock-conditioner R0")
2511 ("clock-conditioner.R1.*", var<Hex<uint32_t>>(), "Clock-conditioner R1")
2512 ("clock-conditioner.R8.*", var<Hex<uint32_t>>(), "Clock-conditioner R8")
2513 ("clock-conditioner.R9.*", var<Hex<uint32_t>>(), "Clock-conditioner R9")
2514 ("clock-conditioner.R11.*", var<Hex<uint32_t>>(), "Clock-conditioner R11")
2515 ("clock-conditioner.R13.*", var<Hex<uint32_t>>(), "Clock-conditioner R13")
2516 ("clock-conditioner.R14.*", var<Hex<uint32_t>>(), "Clock-conditioner R14")
2517 ("clock-conditioner.R15.*", var<Hex<uint32_t>>(), "Clock-conditioner R15");
2518
2519 po::options_description runtype("Run type configuration");
2520 runtype.add_options()
2521 ("run-type", vars<string>(), "Name of run-types (replace the * in the following configuration by the case-sensitive names defined here)")
2522 ("sampling-frequency.*", var<uint16_t>(), "Sampling frequency as defined in the clock-conditioner.frequency")
2523 ("trigger.enable-trigger.*", var<bool>(), "Enable trigger output of physics trigger")
2524 ("trigger.enable-external-1.*", var<bool>(), "Enable external trigger line 1")
2525 ("trigger.enable-external-2.*", var<bool>(), "Enable external trigger line 2")
2526 ("trigger.enable-veto.*", var<bool>(), "Enable veto line")
2527 ("trigger.enable-clock-conditioner.*", var<bool>(), "")
2528 ("trigger.sequence.interval.*", var<uint16_t>(), "Interval between two artifical triggers in units of n*4ns+8ns")
2529 ("trigger.sequence.pedestal.*", var<uint16_t>(), "Number of pedestal events in the sequence of artificial triggers")
2530 ("trigger.sequence.lp-int.*", var<uint16_t>(), "Number of LPint events in the sequence of artificial triggers")
2531 ("trigger.sequence.lp-ext.*", var<uint16_t>(), "Number of LPext events in the sequence of artificial triggers")
2532 ("trigger.multiplicity-physics.*", var<uint16_t>(), "Multiplicity for physics events (n out of 40)")
2533 ("trigger.multiplicity-calib.*", var<uint16_t>(), "Multiplicity for LPext events (n out of 40)")
2534 ("trigger.coincidence-window-physics.*", var<uint16_t>(), "Coincidence window for physics triggers in units of n*4ns+8ns")
2535 ("trigger.coincidence-window-calib.*", var<uint16_t>(), "Coincidence window for LPext triggers in units of n*4ns+8ns")
2536 ("trigger.dead-time.*", var<uint16_t>(), "Dead time after trigger in units of n*4ns+8ns")
2537 ("trigger.delay.*", var<uint16_t>(), "Delay of the trigger send to the FAD boards after a trigger in units of n*4ns+8ns")
2538 ("trigger.time-marker-delay.*", var<uint16_t>(), "Delay of the time-marker after a trigger in units of n*4ns+8ns")
2539 ("trigger.disable-pixel.*", vars<uint16_t>(), "")
2540 ("trigger.disable-patch.*", vars<uint16_t>(), "")
2541 ("trigger.threshold.patch.*", var<uint16_t>(), "")
2542 ("trigger.threshold.logic.*", var<uint16_t>(), "")
2543 ("ftu-report-interval.*", var<uint16_t>(), "")
2544 ("disable-ftu.*", var<uint16_t>(), "")
2545 ("light-pulser.external.enable-group1.*", var<bool>(), "Enable LED group 1 of external light pulser")
2546 ("light-pulser.external.enable-group2.*", var<bool>(), "Enable LED group 2 of external light pulser")
2547 ("light-pulser.internal.enable-group1.*", var<bool>(), "Enable LED group 1 of internal light pulser")
2548 ("light-pulser.internal.enable-group2.*", var<bool>(), "Enable LED group 2 of internal light pulser")
2549 ("light-pulser.external.intensity.*", var<uint16_t>(), "Intensity of external light pulser")
2550 ("light-pulser.internal.intensity.*", var<uint16_t>(), "Intensity of internal light pulser")
2551 ;
2552
2553 conf.AddOptions(control);
2554 conf.AddOptions(freq);
2555 conf.AddOptions(runtype);
2556}
2557
2558/*
2559 Extract usage clause(s) [if any] for SYNOPSIS.
2560 Translators: "Usage" and "or" here are patterns (regular expressions) which
2561 are used to match the usage synopsis in program output. An example from cp
2562 (GNU coreutils) which contains both strings:
2563 Usage: cp [OPTION]... [-T] SOURCE DEST
2564 or: cp [OPTION]... SOURCE... DIRECTORY
2565 or: cp [OPTION]... -t DIRECTORY SOURCE...
2566 */
2567void PrintUsage()
2568{
2569 cout <<
2570 "The ftmctrl controls the FTM (FACT Trigger Master) board.\n"
2571 "\n"
2572 "The default is that the program is started without user intercation. "
2573 "All actions are supposed to arrive as DimCommands. Using the -c "
2574 "option, a local shell can be initialized. With h or help a short "
2575 "help message about the usuage can be brought to the screen.\n"
2576 "\n"
2577 "Usage: ftmctrl [-c type] [OPTIONS]\n"
2578 " or: ftmctrl [OPTIONS]\n";
2579 cout << endl;
2580}
2581
2582void PrintHelp()
2583{
2584 Main::PrintHelp<StateMachineFTM<StateMachine, ConnectionFTM>>();
2585
2586 /* Additional help text which is printed after the configuration
2587 options goes here */
2588
2589 /*
2590 cout << "bla bla bla" << endl << endl;
2591 cout << endl;
2592 cout << "Environment:" << endl;
2593 cout << "environment" << endl;
2594 cout << endl;
2595 cout << "Examples:" << endl;
2596 cout << "test exam" << endl;
2597 cout << endl;
2598 cout << "Files:" << endl;
2599 cout << "files" << endl;
2600 cout << endl;
2601 */
2602}
2603
2604int main(int argc, const char* argv[])
2605{
2606 Configuration conf(argv[0]);
2607 conf.SetPrintUsage(PrintUsage);
2608 Main::SetupConfiguration(conf);
2609 SetupConfiguration(conf);
2610
2611 if (!conf.DoParse(argc, argv, PrintHelp))
2612 return -1;
2613
2614 //try
2615 {
2616 // No console access at all
2617 if (!conf.Has("console"))
2618 {
2619 if (conf.Get<bool>("no-dim"))
2620 return RunShell<LocalStream, StateMachine, ConnectionFTM>(conf);
2621 else
2622 return RunShell<LocalStream, StateMachineDim, ConnectionDimFTM>(conf);
2623 }
2624 // Cosole access w/ and w/o Dim
2625 if (conf.Get<bool>("no-dim"))
2626 {
2627 if (conf.Get<int>("console")==0)
2628 return RunShell<LocalShell, StateMachine, ConnectionFTM>(conf);
2629 else
2630 return RunShell<LocalConsole, StateMachine, ConnectionFTM>(conf);
2631 }
2632 else
2633 {
2634 if (conf.Get<int>("console")==0)
2635 return RunShell<LocalShell, StateMachineDim, ConnectionDimFTM>(conf);
2636 else
2637 return RunShell<LocalConsole, StateMachineDim, ConnectionDimFTM>(conf);
2638 }
2639 }
2640 /*catch (std::exception& e)
2641 {
2642 cerr << "Exception: " << e.what() << endl;
2643 return -1;
2644 }*/
2645
2646 return 0;
2647}
Note: See TracBrowser for help on using the repository browser.