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

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