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

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