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

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