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

Last change on this file since 15091 was 15055, checked in by tbretz, 12 years ago
Removed the code dealing with the clock conditioner. There is now easy way to check that during configuration. This check has to be done continously somewhere else.
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 /*
1999 if (T::GetCurrentState()==FTM::State::kConfigured)
2000 fFTM.GetState()==ConnectionFTM::kTriggerOn)
2001 {
2002 if (!fFTM.IsLocked())
2003 {
2004 T::Warn("Configuration successfull, but clock conditioner not locked.");
2005 return FTM::State::kConfigError3;
2006 }
2007
2008 return FTM::State::kTriggerOn;
2009 }
2010 */
2011 return T::GetCurrentState();
2012 }
2013
2014public:
2015 StateMachineFTM(ostream &out=cout) :
2016 T(out, "FTM_CONTROL"), ba::io_service::work(static_cast<ba::io_service&>(*this)),
2017 fFTM(*this, *this)
2018 {
2019 // ba::io_service::work is a kind of keep_alive for the loop.
2020 // It prevents the io_service to go to stopped state, which
2021 // would prevent any consecutive calls to run()
2022 // or poll() to do nothing. reset() could also revoke to the
2023 // previous state but this might introduce some overhead of
2024 // deletion and creation of threads and more.
2025
2026
2027 // State names
2028 T::AddStateName(FTM::State::kDisconnected, "Disconnected",
2029 "FTM board not connected via ethernet.");
2030
2031 T::AddStateName(FTM::State::kConnected, "Connected",
2032 "Ethernet connection to FTM established (no state received yet).");
2033
2034 T::AddStateName(FTM::State::kIdle, "Idle",
2035 "Ethernet connection to FTM established, FTM in idle state.");
2036
2037 T::AddStateName(FTM::State::kConfiguring1, "Configuring1",
2038 "Command to diable run sent... waiting for response.");
2039 T::AddStateName(FTM::State::kConfiguring2, "Configuring2",
2040 "New configuration sent... waiting for response.");
2041 T::AddStateName(FTM::State::kConfigured, "Configured",
2042 "Received answer identical with target configuration.");
2043
2044 T::AddStateName(FTM::State::kTriggerOn, "TriggerOn",
2045 "Ethernet connection to FTM established, FTM trigger output to FADs enabled.");
2046
2047 T::AddStateName(FTM::State::kConfigError1, "ErrorInConfig1", "Unexpected state received from FTM");
2048 T::AddStateName(FTM::State::kConfigError2, "ErrorInConfig2", "Unexpected state received from FTM");
2049 //T::AddStateName(FTM::State::kConfigError3, "ClockCondError", "Clock conditioner not locked");
2050
2051 // FTM Commands
2052 T::AddEvent("TOGGLE_LED", FTM::State::kIdle)
2053 (Wrapper(bind(&ConnectionFTM::CmdToggleLed, &fFTM)))
2054 ("toggle led");
2055
2056 T::AddEvent("PING", FTM::State::kIdle)
2057 (Wrapper(bind(&ConnectionFTM::CmdPing, &fFTM)))
2058 ("send ping");
2059
2060 T::AddEvent("REQUEST_DYNAMIC_DATA", FTM::State::kIdle)
2061 (Wrapper(bind(&ConnectionFTM::CmdReqDynDat, &fFTM)))
2062 ("request transmission of dynamic data block");
2063
2064 T::AddEvent("REQUEST_STATIC_DATA", FTM::State::kIdle)
2065 (Wrapper(bind(&ConnectionFTM::CmdReqStatDat, &fFTM)))
2066 ("request transmission of static data from FTM to memory");
2067
2068 T::AddEvent("GET_REGISTER", "I", FTM::State::kIdle)
2069 (bind(&StateMachineFTM::GetRegister, this, placeholders::_1))
2070 ("read register from address addr"
2071 "|addr[short]:Address of register");
2072
2073 T::AddEvent("SET_REGISTER", "I:2", FTM::State::kIdle)
2074 (bind(&StateMachineFTM::SetRegister, this, placeholders::_1))
2075 ("set register to value"
2076 "|addr[short]:Address of register"
2077 "|val[short]:Value to be set");
2078
2079 T::AddEvent("START_TRIGGER", FTM::State::kIdle, FTM::State::kConfigured)
2080 (Wrapper(bind(&ConnectionFTM::CmdStartRun, &fFTM)))
2081 ("start a run (start distributing triggers)");
2082
2083 T::AddEvent("STOP_TRIGGER", FTM::State::kTriggerOn)
2084 (Wrapper(bind(&ConnectionFTM::CmdStopRun, &fFTM)))
2085 ("stop a run (stop distributing triggers)");
2086
2087 T::AddEvent("TAKE_N_EVENTS", "I", FTM::State::kIdle)
2088 (bind(&StateMachineFTM::TakeNevents, this, placeholders::_1))
2089 ("take n events (distribute n triggers)|number[int]:Number of events to be taken");
2090
2091 T::AddEvent("DISABLE_REPORTS", "B", FTM::State::kIdle)
2092 (bind(&StateMachineFTM::DisableReports, this, placeholders::_1))
2093 ("disable sending rate reports"
2094 "|status[bool]:disable or enable that the FTM sends rate reports (yes/no)");
2095
2096 T::AddEvent("SET_THRESHOLD", "I:2", FTM::State::kIdle, FTM::State::kConfigured, FTM::State::kTriggerOn)
2097 (bind(&StateMachineFTM::SetThreshold, this, placeholders::_1))
2098 ("Set the comparator threshold"
2099 "|Patch[idx]:Index of the patch (0-159), -1 for all"
2100 "|Threshold[counts]:Threshold to be set in binary counts");
2101
2102 T::AddEvent("SET_N_OUT_OF_4", "I:2", FTM::State::kIdle, FTM::State::kTriggerOn)
2103 (bind(&StateMachineFTM::SetNoutof4, this, placeholders::_1))
2104 ("Set the comparator threshold"
2105 "|Board[idx]:Index of the board (0-39), -1 for all"
2106 "|Threshold[counts]:Threshold to be set in binary counts");
2107
2108 T::AddEvent("SET_PRESCALING", "I:1", FTM::State::kIdle)
2109 (bind(&StateMachineFTM::SetPrescaling, this, placeholders::_1))
2110 ("Sets the FTU readout time intervals"
2111 "|time[0.5s]:The interval is given in units of 0.5s, i.e. 1 means 0.5s, 2 means 1s, ...");
2112
2113 T::AddEvent("ENABLE_FTU", "I:1;B:1", FTM::State::kIdle, FTM::State::kConfigured)
2114 (bind(&StateMachineFTM::EnableFTU, this, placeholders::_1))
2115 ("Enable or disable FTU"
2116 "|Board[idx]:Index of the board (0-39), -1 for all"
2117 "|Enable[bool]:Whether FTU should be enabled or disabled (yes/no)");
2118
2119 T::AddEvent("DISABLE_PIXEL", "S:1", FTM::State::kIdle, FTM::State::kTriggerOn)
2120 (bind(&StateMachineFTM::EnablePixel, this, placeholders::_1, false))
2121 ("(-1 or all)");
2122
2123 T::AddEvent("ENABLE_PIXEL", "S:1", FTM::State::kIdle, FTM::State::kTriggerOn)
2124 (bind(&StateMachineFTM::EnablePixel, this, placeholders::_1, true))
2125 ("(-1 or all)");
2126
2127 T::AddEvent("DISABLE_ALL_PIXELS_EXCEPT", "S:1", FTM::State::kIdle)
2128 (bind(&StateMachineFTM::DisableAllPixelsExcept, this, placeholders::_1))
2129 ("");
2130
2131 T::AddEvent("DISABLE_ALL_PATCHES_EXCEPT", "S:1", FTM::State::kIdle)
2132 (bind(&StateMachineFTM::DisableAllPatchesExcept, this, placeholders::_1))
2133 ("");
2134
2135 T::AddEvent("ENABLE_PATCH", "S:1", FTM::State::kIdle)
2136 (bind(&StateMachineFTM::EnablePatch, this, placeholders::_1, true))
2137 ("");
2138
2139 T::AddEvent("DISABLE_PATCH", "S:1", FTM::State::kIdle)
2140 (bind(&StateMachineFTM::EnablePatch, this, placeholders::_1, false))
2141 ("");
2142
2143 T::AddEvent("TOGGLE_PIXEL", "S:1", FTM::State::kIdle)
2144 (bind(&StateMachineFTM::TogglePixel, this, placeholders::_1))
2145 ("");
2146
2147 T::AddEvent("TOGGLE_FTU", "I:1", FTM::State::kIdle)
2148 (bind(&StateMachineFTM::ToggleFTU, this, placeholders::_1))
2149 ("Toggle status of FTU (this is mainly meant to be used in the GUI)"
2150 "|Board[idx]:Index of the board (0-39)");
2151
2152 T::AddEvent("SET_TRIGGER_INTERVAL", "I:1", FTM::State::kIdle)
2153 (bind(&StateMachineFTM::SetTriggerInterval, this, placeholders::_1))
2154 ("Sets the trigger interval which is the distance between two consecutive artificial triggers."
2155 "|interval[ms]:The applied trigger interval in millisecond (min 1ms / 10bit)");
2156
2157 T::AddEvent("SET_TRIGGER_DELAY", "I:1", FTM::State::kIdle)
2158 (bind(&StateMachineFTM::SetTriggerDelay, this, placeholders::_1))
2159 (""
2160 "|delay[int]:The applied trigger delay is: delay*4ns+8ns");
2161
2162 T::AddEvent("SET_TIME_MARKER_DELAY", "I:1", FTM::State::kIdle)
2163 (bind(&StateMachineFTM::SetTimeMarkerDelay, this, placeholders::_1))
2164 (""
2165 "|delay[int]:The applied time marker delay is: delay*4ns+8ns");
2166
2167 T::AddEvent("SET_DEAD_TIME", "I:1", FTM::State::kIdle)
2168 (bind(&StateMachineFTM::SetDeadTime, this, placeholders::_1))
2169 (""
2170 "|dead_time[int]:The applied dead time is: dead_time*4ns+8ns");
2171
2172 T::AddEvent("ENABLE_TRIGGER", "B:1", FTM::State::kIdle)
2173 (bind(&StateMachineFTM::Enable, this, placeholders::_1, FTM::StaticData::kTrigger))
2174 ("Switch on the physics trigger"
2175 "|Enable[bool]:Enable physics trigger (yes/no)");
2176
2177 // FIXME: Switch on/off depending on sequence
2178 T::AddEvent("ENABLE_EXT1", "B:1", FTM::State::kIdle)
2179 (bind(&StateMachineFTM::Enable, this, placeholders::_1, FTM::StaticData::kExt1))
2180 ("Switch on the triggers through the first external line"
2181 "|Enable[bool]:Enable ext1 trigger (yes/no)");
2182
2183 // FIXME: Switch on/off depending on sequence
2184 T::AddEvent("ENABLE_EXT2", "B:1", FTM::State::kIdle)
2185 (bind(&StateMachineFTM::Enable, this, placeholders::_1, FTM::StaticData::kExt2))
2186 ("Switch on the triggers through the second external line"
2187 "|Enable[bool]:Enable ext2 trigger (yes/no)");
2188
2189 T::AddEvent("ENABLE_VETO", "B:1", FTM::State::kIdle)
2190 (bind(&StateMachineFTM::Enable, this, placeholders::_1, FTM::StaticData::kVeto))
2191 ("Enable veto line"
2192 "|Enable[bool]:Enable veto (yes/no)");
2193
2194 T::AddEvent("ENABLE_CLOCK_CONDITIONER", "B:1", FTM::State::kIdle)
2195 (bind(&StateMachineFTM::Enable, this, placeholders::_1, FTM::StaticData::kClockConditioner))
2196 ("Enable clock conidtioner output in favor of time marker output"
2197 "|Enable[bool]:Enable clock conditioner (yes/no)");
2198
2199 T::AddEvent("ENABLE_GROUP1_LPINT", "B:1", FTM::State::kIdle)
2200 (bind(&StateMachineFTM::EnableLP, this, placeholders::_1, FTM::StaticData::kLPint, FTM::StaticData::kGroup1))
2201 ("");
2202 T::AddEvent("ENABLE_GROUP1_LPEXT", "B:1", FTM::State::kIdle)
2203 (bind(&StateMachineFTM::EnableLP, this, placeholders::_1, FTM::StaticData::kLPext, FTM::StaticData::kGroup1))
2204 ("");
2205 T::AddEvent("ENABLE_GROUP2_LPINT", "B:1", FTM::State::kIdle)
2206 (bind(&StateMachineFTM::EnableLP, this, placeholders::_1, FTM::StaticData::kLPint, FTM::StaticData::kGroup2))
2207 ("");
2208 T::AddEvent("ENABLE_GROUP2_LPEXT", "B:1", FTM::State::kIdle)
2209 (bind(&StateMachineFTM::EnableLP, this, placeholders::_1, FTM::StaticData::kLPext, FTM::StaticData::kGroup2))
2210 ("");
2211 T::AddEvent("SET_INTENSITY_LPINT", "S:1", FTM::State::kIdle)
2212 (bind(&StateMachineFTM::SetIntensity, this, placeholders::_1, FTM::StaticData::kLPint))
2213 ("");
2214 T::AddEvent("SET_INTENSITY_LPEXT", "S:1", FTM::State::kIdle)
2215 (bind(&StateMachineFTM::SetIntensity, this, placeholders::_1, FTM::StaticData::kLPext))
2216 ("");
2217
2218
2219 T::AddEvent("SET_TRIGGER_SEQUENCE", "S:3", FTM::State::kIdle)
2220 (bind(&StateMachineFTM::SetTriggerSeq, this, placeholders::_1))
2221 ("Setup the sequence of artificial triggers produced by the FTM"
2222 "|Ped[short]:number of pedestal triggers in a row"
2223 "|LPext[short]:number of triggers of the external light pulser"
2224 "|LPint[short]:number of triggers of the internal light pulser");
2225
2226 T::AddEvent("SET_TRIGGER_MULTIPLICITY", "S:1", FTM::State::kIdle)
2227 (bind(&StateMachineFTM::SetTriggerMultiplicity, this, placeholders::_1))
2228 ("Setup the Multiplicity condition for physcis triggers"
2229 "|N[int]:Number of requirered coincident triggers from sum-patches (1-40)");
2230
2231 T::AddEvent("SET_TRIGGER_WINDOW", "S:1", FTM::State::kIdle)
2232 (bind(&StateMachineFTM::SetTriggerWindow, this, placeholders::_1))
2233 ("");
2234
2235 T::AddEvent("SET_CALIBRATION_MULTIPLICITY", "S:1", FTM::State::kIdle)
2236 (bind(&StateMachineFTM::SetCalibMultiplicity, this, placeholders::_1))
2237 ("Setup the Multiplicity condition for artificial (calibration) triggers"
2238 "|N[int]:Number of requirered coincident triggers from sum-patches (1-40)");
2239
2240 T::AddEvent("SET_CALIBRATION_WINDOW", "S:1", FTM::State::kIdle)
2241 (bind(&StateMachineFTM::SetCalibWindow, this, placeholders::_1))
2242 ("");
2243
2244 T::AddEvent("SET_CLOCK_FREQUENCY", "S:1", FTM::State::kIdle)
2245 (bind(&StateMachineFTM::SetClockFrequency, this, placeholders::_1))
2246 ("");
2247
2248 T::AddEvent("SET_CLOCK_REGISTER", "X:8", FTM::State::kIdle)
2249 (bind(&StateMachineFTM::SetClockRegister, this, placeholders::_1))
2250 ("");
2251
2252 // A new configure will first stop the FTM this means
2253 // we can allow it in idle _and_ taking data
2254 T::AddEvent("CONFIGURE", "C", FTM::State::kIdle, FTM::State::kConfiguring1, FTM::State::kConfiguring2, FTM::State::kConfigured, FTM::State::kTriggerOn)
2255 (bind(&StateMachineFTM::ConfigureFTM, this, placeholders::_1))
2256 ("");
2257
2258 T::AddEvent("RESET_CONFIGURE")(FTM::State::kConfiguring1)(FTM::State::kConfiguring2)(FTM::State::kConfigured)(FTM::State::kConfigError1)(FTM::State::kConfigError2)(FTM::State::kConfigError2)
2259 (bind(&StateMachineFTM::ResetConfig, this))
2260 ("Reset states during a configuration or in case of configuration error");
2261
2262
2263
2264 T::AddEvent("RESET_CRATE", "S:1", FTM::State::kIdle, FTM::State::kConfigured)
2265 (bind(&StateMachineFTM::ResetCrate, this, placeholders::_1))
2266 ("Reset one of the crates 0-3"
2267 "|crate[short]:Crate number to be reseted (0-3)");
2268
2269 T::AddEvent("RESET_CAMERA", FTM::State::kIdle)
2270 (Wrapper(bind(&ConnectionFTM::CmdResetCamera, &fFTM)))
2271 ("Reset all crates. The commands are sent in the order 0,1,2,3");
2272
2273
2274 // Load/save static data block
2275 T::AddEvent("SAVE", "C", FTM::State::kIdle)
2276 (bind(&StateMachineFTM::SaveStaticData, this, placeholders::_1))
2277 ("Saves the static data (FTM configuration) from memory to a file"
2278 "|filename[string]:Filename (can include a path), .bin is automatically added");
2279
2280 T::AddEvent("LOAD", "C", FTM::State::kIdle)
2281 (bind(&StateMachineFTM::LoadStaticData, this, placeholders::_1))
2282 ("Loads the static data (FTM configuration) from a file into memory and sends it to the FTM"
2283 "|filename[string]:Filename (can include a path), .bin is automatically added");
2284
2285
2286
2287 // Verbosity commands
2288 T::AddEvent("SET_VERBOSE", "B")
2289 (bind(&StateMachineFTM::SetVerbosity, this, placeholders::_1))
2290 ("set verbosity state"
2291 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
2292
2293 T::AddEvent("SET_HEX_OUTPUT", "B")
2294 (bind(&StateMachineFTM::SetHexOutput, this, placeholders::_1))
2295 ("enable or disable hex output for received data"
2296 "|hexout[bool]:disable or enable hex output for received data (yes/no)");
2297
2298 T::AddEvent("SET_DYNAMIC_OUTPUT", "B")
2299 (bind(&StateMachineFTM::SetDynamicOut, this, placeholders::_1))
2300 ("enable or disable output for received dynamic data (data is still broadcasted via Dim)"
2301 "|dynout[bool]:disable or enable output for dynamic data (yes/no)");
2302
2303
2304 // Conenction commands
2305 T::AddEvent("DISCONNECT", FTM::State::kConnected, FTM::State::kIdle)
2306 (bind(&StateMachineFTM::Disconnect, this))
2307 ("disconnect from ethernet");
2308
2309 T::AddEvent("RECONNECT", "O", FTM::State::kDisconnected, FTM::State::kConnected, FTM::State::kIdle, FTM::State::kConfigured)
2310 (bind(&StateMachineFTM::Reconnect, this, placeholders::_1))
2311 ("(Re)connect ethernet connection to FTM, a new address can be given"
2312 "|[host][string]:new ethernet address in the form <host:port>");
2313
2314 fFTM.StartConnect();
2315 }
2316
2317 void SetEndpoint(const string &url)
2318 {
2319 fFTM.SetEndpoint(url);
2320 }
2321
2322 map<uint16_t, array<uint64_t, 8>> fClockCondSetup;
2323
2324 template<class V>
2325 bool CheckConfigVal(Configuration &conf, V max, const string &name, const string &sub)
2326 {
2327 if (!conf.HasDef(name, sub))
2328 {
2329 T::Error("Neither "+name+"default nor "+name+sub+" found.");
2330 return false;
2331 }
2332
2333 const V val = conf.GetDef<V>(name, sub);
2334
2335 if (val<=max)
2336 return true;
2337
2338 ostringstream str;
2339 str << name << sub << "=" << val << " exceeds allowed maximum of " << max << "!";
2340 T::Error(str);
2341
2342 return false;
2343 }
2344
2345 int EvalOptions(Configuration &conf)
2346 {
2347 // ---------- General setup ----------
2348 fFTM.SetVerbose(!conf.Get<bool>("quiet"));
2349 fFTM.SetHexOutput(conf.Get<bool>("hex-out"));
2350 fFTM.SetDynamicOut(conf.Get<bool>("dynamic-out"));
2351
2352 // ---------- Setup clock conditioner frequencies ----------
2353 const vector<uint16_t> freq = conf.Vec<uint16_t>("clock-conditioner.frequency");
2354 if (freq.size()==0)
2355 T::Warn("No frequencies for the clock-conditioner defined.");
2356 else
2357 T::Message("Defining clock conditioner frequencies");
2358 for (vector<uint16_t>::const_iterator it=freq.begin();
2359 it!=freq.end(); it++)
2360 {
2361 if (fClockCondSetup.count(*it)>0)
2362 {
2363 T::Error("clock-conditioner frequency defined twice.");
2364 return 1;
2365 }
2366
2367 if (!conf.HasDef("clock-conditioner.R0.", *it) ||
2368 !conf.HasDef("clock-conditioner.R1.", *it) ||
2369 !conf.HasDef("clock-conditioner.R8.", *it) ||
2370 !conf.HasDef("clock-conditioner.R9.", *it) ||
2371 !conf.HasDef("clock-conditioner.R11.", *it) ||
2372 !conf.HasDef("clock-conditioner.R13.", *it) ||
2373 !conf.HasDef("clock-conditioner.R14.", *it) ||
2374 !conf.HasDef("clock-conditioner.R15.", *it))
2375 {
2376 T::Error("clock-conditioner values incomplete.");
2377 return 1;
2378 }
2379
2380 array<uint64_t, 8> &arr = fClockCondSetup[*it];
2381
2382 arr[0] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R0.", *it);
2383 arr[1] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R1.", *it);
2384 arr[2] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R8.", *it);
2385 arr[3] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R9.", *it);
2386 arr[4] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R11.", *it);
2387 arr[5] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R13.", *it);
2388 arr[6] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R14.", *it);
2389 arr[7] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R15.", *it);
2390
2391 ostringstream out;
2392 out << " -> " << setw(4) << *it << "MHz:" << hex << setfill('0');
2393 for (int i=0; i<8; i++)
2394 out << " " << setw(8) << arr[i];
2395 T::Message(out.str());
2396 }
2397
2398 // ---------- Setup run types ---------
2399 const vector<string> types = conf.Vec<string>("run-type");
2400 if (types.size()==0)
2401 T::Warn("No run-types defined.");
2402 else
2403 T::Message("Defining run-types");
2404 for (vector<string>::const_iterator it=types.begin();
2405 it!=types.end(); it++)
2406 {
2407 T::Message(" -> "+ *it);
2408
2409 if (fConfigs.count(*it)>0)
2410 {
2411 T::Error("Run-type "+*it+" defined twice.");
2412 return 2;
2413 }
2414
2415 if (!conf.HasDef("sampling-frequency.", *it))
2416 {
2417 T::Error("Neither sampling-frequency."+*it+" nor sampling-frequency.default found.");
2418 return 2;
2419 }
2420
2421 const uint16_t frq = conf.GetDef<uint16_t>("sampling-frequency.", *it);
2422
2423 FTM::StaticData data;
2424 data.SetClockRegister(fClockCondSetup[frq].data());
2425
2426 // Trigger sequence ped:lp1:lp2
2427 // (data. is used here as an abbreviation for FTM::StaticData::
2428 if (!CheckConfigVal<bool> (conf, true, "trigger.enable-trigger.", *it) ||
2429 !CheckConfigVal<bool> (conf, true, "trigger.enable-external-1.", *it) ||
2430 !CheckConfigVal<bool> (conf, true, "trigger.enable-external-2.", *it) ||
2431 !CheckConfigVal<bool> (conf, true, "trigger.enable-veto.", *it) ||
2432 !CheckConfigVal<bool> (conf, true, "trigger.enable-clock-conditioner.", *it) ||
2433 !CheckConfigVal<bool> (conf, true, "light-pulser.external.enable-group1.", *it) ||
2434 !CheckConfigVal<bool> (conf, true, "light-pulser.external.enable-group2.", *it) ||
2435 !CheckConfigVal<bool> (conf, true, "light-pulser.internal.enable-group1.", *it) ||
2436 !CheckConfigVal<bool> (conf, true, "light-pulser.internal.enable-group2.", *it) ||
2437 !CheckConfigVal<uint16_t>(conf, data.kMaxSequence, "trigger.sequence.pedestal.", *it) ||
2438 !CheckConfigVal<uint16_t>(conf, data.kMaxSequence, "trigger.sequence.lp-ext.", *it) ||
2439 !CheckConfigVal<uint16_t>(conf, data.kMaxSequence, "trigger.sequence.lp-int.", *it) ||
2440 !CheckConfigVal<uint16_t>(conf, data.kMaxTriggerInterval, "trigger.sequence.interval.", *it) ||
2441 !CheckConfigVal<uint16_t>(conf, data.kMaxMultiplicity, "trigger.multiplicity-physics.", *it) ||
2442 !CheckConfigVal<uint16_t>(conf, data.kMaxMultiplicity, "trigger.multiplicity-calib.", *it) ||
2443 !CheckConfigVal<uint16_t>(conf, data.kMaxWindow, "trigger.coincidence-window-physics.", *it) ||
2444 !CheckConfigVal<uint16_t>(conf, data.kMaxWindow, "trigger.coincidence-window-calib.", *it) ||
2445 !CheckConfigVal<uint16_t>(conf, data.kMaxDeadTime, "trigger.dead-time.", *it) ||
2446 !CheckConfigVal<uint16_t>(conf, data.kMaxDelayTrigger, "trigger.delay.", *it) ||
2447 !CheckConfigVal<uint16_t>(conf, data.kMaxDelayTimeMarker, "trigger.time-marker-delay.", *it) ||
2448 !CheckConfigVal<uint16_t>(conf, 0xffff, "ftu-report-interval.", *it) ||
2449 !CheckConfigVal<uint16_t>(conf, data.kMaxIntensity, "light-pulser.external.intensity.", *it) ||
2450 !CheckConfigVal<uint16_t>(conf, data.kMaxIntensity, "light-pulser.internal.intensity.", *it) ||
2451 !CheckConfigVal<uint16_t>(conf, data.kMaxDAC, "trigger.threshold.patch.", *it) ||
2452 !CheckConfigVal<uint16_t>(conf, data.kMaxDAC, "trigger.threshold.logic.", *it) ||
2453 0)
2454 return 2;
2455
2456 data.Enable(data.kTrigger, conf.GetDef<bool>("trigger.enable-trigger.", *it));
2457 data.Enable(data.kExt1, conf.GetDef<bool>("trigger.enable-external-1.", *it));
2458 data.Enable(data.kExt2, conf.GetDef<bool>("trigger.enable-external-2.", *it));
2459 data.Enable(data.kVeto, conf.GetDef<bool>("trigger.enable-veto.", *it));
2460 data.Enable(data.kClockConditioner, conf.GetDef<bool>("trigger.enable-clock-conditioner.", *it));
2461
2462 data.EnableLPint(data.kGroup1, conf.GetDef<bool>("light-pulser.internal.enable-group1.", *it));
2463 data.EnableLPint(data.kGroup2, conf.GetDef<bool>("light-pulser.internal.enable-group2.", *it));
2464 data.EnableLPext(data.kGroup1, conf.GetDef<bool>("light-pulser.external.enable-group1.", *it));
2465 data.EnableLPext(data.kGroup2, conf.GetDef<bool>("light-pulser.external.enable-group2.", *it));
2466
2467 // [ms] Interval between two artificial triggers (no matter which type) minimum 1ms, 10 bit
2468 data.fIntensityLPint = conf.GetDef<uint16_t>("light-pulser.internal.intensity.", *it);
2469 data.fIntensityLPext = conf.GetDef<uint16_t>("light-pulser.external.intensity.", *it);
2470 data.fTriggerInterval = conf.GetDef<uint16_t>("trigger.sequence.interval.", *it);
2471 data.fMultiplicityPhysics = conf.GetDef<uint16_t>("trigger.multiplicity-physics.", *it);
2472 data.fMultiplicityCalib = conf.GetDef<uint16_t>("trigger.multiplicity-calib.", *it);
2473 data.fWindowPhysics = conf.GetDef<uint16_t>("trigger.coincidence-window-physics.", *it); /// (4ns * x + 8ns)
2474 data.fWindowCalib = conf.GetDef<uint16_t>("trigger.coincidence-window-calib.", *it); /// (4ns * x + 8ns)
2475 data.fDelayTrigger = conf.GetDef<uint16_t>("trigger.delay.", *it); /// (4ns * x + 8ns)
2476 data.fDelayTimeMarker = conf.GetDef<uint16_t>("trigger.time-marker-delay.", *it); /// (4ns * x + 8ns)
2477 data.fDeadTime = conf.GetDef<uint16_t>("trigger.dead-time.", *it); /// (4ns * x + 8ns)
2478
2479 data.SetPrescaling(conf.GetDef<uint16_t>("ftu-report-interval.", *it));
2480
2481 const uint16_t seqped = conf.GetDef<uint16_t>("trigger.sequence.pedestal.", *it);
2482 const uint16_t seqint = conf.GetDef<uint16_t>("trigger.sequence.lp-int.", *it);
2483 const uint16_t seqext = conf.GetDef<uint16_t>("trigger.sequence.lp-ext.", *it);
2484
2485 data.SetSequence(seqped, seqint, seqext);
2486
2487 data.EnableAllFTU();
2488 data.EnableAllPixel();
2489
2490 const vector<uint16_t> pat1 = conf.Vec<uint16_t>("trigger.disable-patch.default");
2491 const vector<uint16_t> pat2 = conf.Vec<uint16_t>("trigger.disable-patch."+*it);
2492
2493 const vector<uint16_t> pix1 = conf.Vec<uint16_t>("trigger.disable-pixel.default");
2494 const vector<uint16_t> pix2 = conf.Vec<uint16_t>("trigger.disable-pixel."+*it);
2495
2496 const vector<uint16_t> ftu1 = conf.Vec<uint16_t>("disable-ftu.default");
2497 const vector<uint16_t> ftu2 = conf.Vec<uint16_t>("disable-ftu."+*it);
2498
2499 vector<uint16_t> ftu, pat, pix;
2500 ftu.insert(ftu.end(), ftu1.begin(), ftu1.end());
2501 ftu.insert(ftu.end(), ftu2.begin(), ftu2.end());
2502 pat.insert(pat.end(), pat1.begin(), pat1.end());
2503 pat.insert(pat.end(), pat2.begin(), pat2.end());
2504 pix.insert(pix.end(), pix1.begin(), pix1.end());
2505 pix.insert(pix.end(), pix2.begin(), pix2.end());
2506
2507 for (vector<uint16_t>::const_iterator ip=ftu.begin(); ip!=ftu.end(); ip++)
2508 {
2509 if (*ip>FTM::StaticData::kMaxPatchIdx)
2510 {
2511 ostringstream str;
2512 str << "disable-ftu.*=" << *ip << " exceeds allowed maximum of " << FTM::StaticData::kMaxPatchIdx << "!";
2513 T::Error(str);
2514 return 2;
2515 }
2516 data.DisableFTU(*ip);
2517 }
2518 for (vector<uint16_t>::const_iterator ip=pat.begin(); ip!=pat.end(); ip++)
2519 {
2520 if (*ip>FTM::StaticData::kMaxPatchIdx)
2521 {
2522 ostringstream str;
2523 str << "trigger.disable-patch.*=" << *ip << " exceeds allowed maximum of " << FTM::StaticData::kMaxPatchIdx << "!";
2524 T::Error(str);
2525 return 2;
2526 }
2527 data.EnablePatch(*ip, false);
2528 }
2529 for (vector<uint16_t>::const_iterator ip=pix.begin(); ip!=pix.end(); ip++)
2530 {
2531 if (*ip>FTM::StaticData::kMaxPixelIdx)
2532 {
2533 ostringstream str;
2534 str << "trigger.disable-pixel.*=" << *ip << " exceeds allowed maximum of " << FTM::StaticData::kMaxPixelIdx << "!";
2535 T::Error(str);
2536 return 2;
2537 }
2538 data.EnablePixel(*ip, false);
2539 }
2540
2541 const uint16_t th0 = conf.GetDef<uint16_t>("trigger.threshold.patch.", *it);
2542 const uint16_t th1 = conf.GetDef<uint16_t>("trigger.threshold.logic.", *it);
2543
2544 for (int i=0; i<40; i++)
2545 {
2546 data[i].fDAC[0] = th0;
2547 data[i].fDAC[1] = th0;
2548 data[i].fDAC[2] = th0;
2549 data[i].fDAC[3] = th0;
2550 data[i].fDAC[4] = th1;
2551 }
2552
2553 fConfigs[*it] = data;
2554
2555 // trigger.threshold.dac-0:
2556
2557 /*
2558 threshold-A data[n].fDAC[0] = val
2559 threshold-B data[n].fDAC[1] = val
2560 threshold-C data[n].fDAC[2] = val
2561 threshold-D data[n].fDAC[3] = val
2562 threshold-H data[n].fDAC[4] = val
2563 */
2564
2565 // kMaxDAC = 0xfff,
2566 }
2567
2568 // FIXME: Add a check about unsused configurations
2569
2570 // ---------- FOR TESTING PURPOSE ---------
2571
2572 // fFTM.SetDefaultSetup(conf.Get<string>("default-setup"));
2573 fConfigs["test"] = FTM::StaticData();
2574
2575 // ---------- Setup connection endpoint ---------
2576 SetEndpoint(conf.Get<string>("addr"));
2577
2578 return -1;
2579 }
2580};
2581
2582// ------------------------------------------------------------------------
2583
2584#include "Main.h"
2585
2586template<class T, class S, class R>
2587int RunShell(Configuration &conf)
2588{
2589 return Main::execute<T, StateMachineFTM<S, R>>(conf);
2590}
2591
2592void SetupConfiguration(Configuration &conf)
2593{
2594 po::options_description control("Control options");
2595 control.add_options()
2596 ("no-dim", po_bool(), "Disable dim services")
2597 ("addr,a", var<string>("localhost:5000"), "Network address of FTM")
2598 ("quiet,q", po_bool(), "Disable printing contents of all received messages (except dynamic data) in clear text.")
2599 ("hex-out", po_bool(), "Enable printing contents of all printed messages also as hex data.")
2600 ("dynamic-out", po_bool(), "Enable printing received dynamic data.")
2601// ("default-setup", var<string>(), "Binary file with static data loaded whenever a connection to the FTM was established.")
2602 ;
2603
2604 po::options_description freq("Sampling frequency setup");
2605 freq.add_options()
2606 ("clock-conditioner.frequency", vars<uint16_t>(), "Frequencies for which to setup the clock-conditioner (replace the * in the following options by this definition)")
2607 ("clock-conditioner.R0.*", var<Hex<uint32_t>>(), "Clock-conditioner R0")
2608 ("clock-conditioner.R1.*", var<Hex<uint32_t>>(), "Clock-conditioner R1")
2609 ("clock-conditioner.R8.*", var<Hex<uint32_t>>(), "Clock-conditioner R8")
2610 ("clock-conditioner.R9.*", var<Hex<uint32_t>>(), "Clock-conditioner R9")
2611 ("clock-conditioner.R11.*", var<Hex<uint32_t>>(), "Clock-conditioner R11")
2612 ("clock-conditioner.R13.*", var<Hex<uint32_t>>(), "Clock-conditioner R13")
2613 ("clock-conditioner.R14.*", var<Hex<uint32_t>>(), "Clock-conditioner R14")
2614 ("clock-conditioner.R15.*", var<Hex<uint32_t>>(), "Clock-conditioner R15");
2615
2616 po::options_description runtype("Run type configuration");
2617 runtype.add_options()
2618 ("run-type", vars<string>(), "Name of run-types (replace the * in the following configuration by the case-sensitive names defined here)")
2619 ("sampling-frequency.*", var<uint16_t>(), "Sampling frequency as defined in the clock-conditioner.frequency")
2620 ("trigger.enable-trigger.*", var<bool>(), "Enable trigger output of physics trigger")
2621 ("trigger.enable-external-1.*", var<bool>(), "Enable external trigger line 1")
2622 ("trigger.enable-external-2.*", var<bool>(), "Enable external trigger line 2")
2623 ("trigger.enable-veto.*", var<bool>(), "Enable veto line")
2624 ("trigger.enable-clock-conditioner.*", var<bool>(), "")
2625 ("trigger.sequence.interval.*", var<uint16_t>(), "Interval between two artifical triggers in units of n*4ns+8ns")
2626 ("trigger.sequence.pedestal.*", var<uint16_t>(), "Number of pedestal events in the sequence of artificial triggers")
2627 ("trigger.sequence.lp-int.*", var<uint16_t>(), "Number of LPint events in the sequence of artificial triggers")
2628 ("trigger.sequence.lp-ext.*", var<uint16_t>(), "Number of LPext events in the sequence of artificial triggers")
2629 ("trigger.multiplicity-physics.*", var<uint16_t>(), "Multiplicity for physics events (n out of 40)")
2630 ("trigger.multiplicity-calib.*", var<uint16_t>(), "Multiplicity for LPext events (n out of 40)")
2631 ("trigger.coincidence-window-physics.*", var<uint16_t>(), "Coincidence window for physics triggers in units of n*4ns+8ns")
2632 ("trigger.coincidence-window-calib.*", var<uint16_t>(), "Coincidence window for LPext triggers in units of n*4ns+8ns")
2633 ("trigger.dead-time.*", var<uint16_t>(), "Dead time after trigger in units of n*4ns+8ns")
2634 ("trigger.delay.*", var<uint16_t>(), "Delay of the trigger send to the FAD boards after a trigger in units of n*4ns+8ns")
2635 ("trigger.time-marker-delay.*", var<uint16_t>(), "Delay of the time-marker after a trigger in units of n*4ns+8ns")
2636 ("trigger.disable-pixel.*", vars<uint16_t>(), "")
2637 ("trigger.disable-patch.*", vars<uint16_t>(), "")
2638 ("trigger.threshold.patch.*", var<uint16_t>(), "")
2639 ("trigger.threshold.logic.*", var<uint16_t>(), "")
2640 ("ftu-report-interval.*", var<uint16_t>(), "")
2641 ("disable-ftu.*", var<uint16_t>(), "")
2642 ("light-pulser.external.enable-group1.*", var<bool>(), "Enable LED group 1 of external light pulser")
2643 ("light-pulser.external.enable-group2.*", var<bool>(), "Enable LED group 2 of external light pulser")
2644 ("light-pulser.internal.enable-group1.*", var<bool>(), "Enable LED group 1 of internal light pulser")
2645 ("light-pulser.internal.enable-group2.*", var<bool>(), "Enable LED group 2 of internal light pulser")
2646 ("light-pulser.external.intensity.*", var<uint16_t>(), "Intensity of external light pulser")
2647 ("light-pulser.internal.intensity.*", var<uint16_t>(), "Intensity of internal light pulser")
2648 ;
2649
2650 conf.AddOptions(control);
2651 conf.AddOptions(freq);
2652 conf.AddOptions(runtype);
2653}
2654
2655/*
2656 Extract usage clause(s) [if any] for SYNOPSIS.
2657 Translators: "Usage" and "or" here are patterns (regular expressions) which
2658 are used to match the usage synopsis in program output. An example from cp
2659 (GNU coreutils) which contains both strings:
2660 Usage: cp [OPTION]... [-T] SOURCE DEST
2661 or: cp [OPTION]... SOURCE... DIRECTORY
2662 or: cp [OPTION]... -t DIRECTORY SOURCE...
2663 */
2664void PrintUsage()
2665{
2666 cout <<
2667 "The ftmctrl controls the FTM (FACT Trigger Master) board.\n"
2668 "\n"
2669 "The default is that the program is started without user intercation. "
2670 "All actions are supposed to arrive as DimCommands. Using the -c "
2671 "option, a local shell can be initialized. With h or help a short "
2672 "help message about the usuage can be brought to the screen.\n"
2673 "\n"
2674 "Usage: ftmctrl [-c type] [OPTIONS]\n"
2675 " or: ftmctrl [OPTIONS]\n";
2676 cout << endl;
2677}
2678
2679void PrintHelp()
2680{
2681 Main::PrintHelp<StateMachineFTM<StateMachine, ConnectionFTM>>();
2682
2683 /* Additional help text which is printed after the configuration
2684 options goes here */
2685
2686 /*
2687 cout << "bla bla bla" << endl << endl;
2688 cout << endl;
2689 cout << "Environment:" << endl;
2690 cout << "environment" << endl;
2691 cout << endl;
2692 cout << "Examples:" << endl;
2693 cout << "test exam" << endl;
2694 cout << endl;
2695 cout << "Files:" << endl;
2696 cout << "files" << endl;
2697 cout << endl;
2698 */
2699}
2700
2701int main(int argc, const char* argv[])
2702{
2703 Configuration conf(argv[0]);
2704 conf.SetPrintUsage(PrintUsage);
2705 Main::SetupConfiguration(conf);
2706 SetupConfiguration(conf);
2707
2708 if (!conf.DoParse(argc, argv, PrintHelp))
2709 return 127;
2710
2711 //try
2712 {
2713 // No console access at all
2714 if (!conf.Has("console"))
2715 {
2716 if (conf.Get<bool>("no-dim"))
2717 return RunShell<LocalStream, StateMachine, ConnectionFTM>(conf);
2718 else
2719 return RunShell<LocalStream, StateMachineDim, ConnectionDimFTM>(conf);
2720 }
2721 // Cosole access w/ and w/o Dim
2722 if (conf.Get<bool>("no-dim"))
2723 {
2724 if (conf.Get<int>("console")==0)
2725 return RunShell<LocalShell, StateMachine, ConnectionFTM>(conf);
2726 else
2727 return RunShell<LocalConsole, StateMachine, ConnectionFTM>(conf);
2728 }
2729 else
2730 {
2731 if (conf.Get<int>("console")==0)
2732 return RunShell<LocalShell, StateMachineDim, ConnectionDimFTM>(conf);
2733 else
2734 return RunShell<LocalConsole, StateMachineDim, ConnectionDimFTM>(conf);
2735 }
2736 }
2737 /*catch (std::exception& e)
2738 {
2739 cerr << "Exception: " << e.what() << endl;
2740 return -1;
2741 }*/
2742
2743 return 0;
2744}
Note: See TracBrowser for help on using the repository browser.