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

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