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

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