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

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