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

Last change on this file since 14634 was 14596, checked in by tbretz, 12 years ago
Make sure that state machin will stay in the error state if an error occurs during configuration.
File size: 95.2 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 bool IsLocked() const { return fHeader.fState&FTM::kFtmLocked; }
1168
1169 int GetCounter(FTM::Types type) { return fCounter[type]; }
1170
1171 const FTM::StaticData &GetStaticData() const { return fStaticData; }
1172};
1173
1174//const uint16_t ConnectionFTM::kMaxAddr = 0xfff;
1175
1176// ------------------------------------------------------------------------
1177
1178#include "DimDescriptionService.h"
1179
1180class ConnectionDimFTM : public ConnectionFTM
1181{
1182private:
1183
1184 DimDescribedService fDimPassport;
1185 DimDescribedService fDimTriggerRates;
1186 DimDescribedService fDimError;
1187 DimDescribedService fDimFtuList;
1188 DimDescribedService fDimStaticData;
1189 DimDescribedService fDimDynamicData;
1190 DimDescribedService fDimCounter;
1191
1192 uint64_t fTimeStamp;
1193 uint64_t fTimeStampOn;
1194 uint32_t fTriggerCounter;
1195
1196 void UpdateFirstHeader()
1197 {
1198 ConnectionFTM::UpdateFirstHeader();
1199
1200 const FTM::DimPassport data(fHeader);
1201 fDimPassport.Update(data);
1202 }
1203
1204 /*
1205 void UpdateHeader()
1206 {
1207 ConnectionFTM::UpdateHeader();
1208
1209 if (fHeader.fType!=FTM::kDynamicData)
1210 return;
1211
1212 const FTM::DimTriggerCounter data(fHeader);
1213 fDimTriggerCounter.Update(data);
1214 }*/
1215
1216 void UpdateFtuList()
1217 {
1218 ConnectionFTM::UpdateFtuList();
1219
1220 const FTM::DimFtuList data(fHeader, fFtuList);
1221 fDimFtuList.Update(data);
1222 }
1223
1224 void UpdateStaticData()
1225 {
1226 ConnectionFTM::UpdateStaticData();
1227
1228 const FTM::DimStaticData data(fHeader, fStaticData);
1229 fDimStaticData.setQuality(fHeader.fState);
1230 fDimStaticData.Update(data);
1231 }
1232
1233 void UpdateDynamicData()
1234 {
1235 ConnectionFTM::UpdateDynamicData();
1236
1237 const FTM::DimDynamicData data(fHeader, fDynamicData, fStaticData);
1238 fDimDynamicData.setQuality(fHeader.fState);
1239 fDimDynamicData.Update(data);
1240
1241 float rate = -1;
1242 uint64_t tdiff = 0;
1243 uint64_t odiff = 0;
1244 if (fHeader.fTimeStamp>=fTimeStamp && fHeader.fTriggerCounter>=fTriggerCounter)
1245 {
1246 tdiff = fHeader.fTimeStamp -fTimeStamp;
1247 odiff = fDynamicData.fOnTimeCounter -fTimeStampOn;
1248
1249 const uint32_t cdiff = fHeader.fTriggerCounter-fTriggerCounter;
1250 rate = tdiff==0 ? 0 : 1000000*float(cdiff)/tdiff;
1251 }
1252
1253 fTimeStamp = fHeader.fTimeStamp;
1254 fTimeStampOn = fDynamicData.fOnTimeCounter;
1255 fTriggerCounter = fHeader.fTriggerCounter;
1256
1257 const FTM::DimTriggerRates rates(fHeader, fDynamicData, fStaticData,
1258 rate, tdiff*1e-6, odiff*1e-6);
1259
1260 fDimTriggerRates.setQuality(fHeader.fState);
1261 fDimTriggerRates.Update(rates);
1262 }
1263
1264 void UpdateError()
1265 {
1266 ConnectionFTM::UpdateError();
1267
1268 const FTM::DimError data(fHeader, fError);
1269 fDimError.Update(data);
1270 }
1271
1272 void UpdateCounter()
1273 {
1274 ConnectionFTM::UpdateCounter();
1275
1276 const uint32_t counter[6] =
1277 {
1278 fCounter[FTM::kHeader],
1279 fCounter[FTM::kStaticData],
1280 fCounter[FTM::kDynamicData],
1281 fCounter[FTM::kFtuList],
1282 fCounter[FTM::kErrorList],
1283 fCounter[FTM::kRegister],
1284 };
1285
1286 fDimCounter.setQuality(fHeader.fState);
1287 fDimCounter.Update(counter);
1288 }
1289
1290public:
1291 ConnectionDimFTM(ba::io_service& ioservice, MessageImp &imp) :
1292 ConnectionFTM(ioservice, imp),
1293 fDimPassport ("FTM_CONTROL/PASSPORT", "X:1;S:1",
1294 "Info about the FTM and FPGA version"
1295 "|BoardId[int]:BoardId, hexCode"
1296 "|DNA[int]:DNA of the FTM board"),
1297 fDimTriggerRates ("FTM_CONTROL/TRIGGER_RATES", "X:1;X:1;I:1;F:1;F:40;F:160;F:1;F:1",
1298 "Patch,Board,Camera trigger rates"
1299 "|FTMtimeStamp[us]:Time in microseconds, since trigger enabled or disabled"
1300 "|OnTimeCounter[us]:Effective on-time, ie. FTM triggers (eg. w/o busy)"
1301 "|TriggerCounter[int]:Counter of triggers since enabled or disabled"
1302 "|TriggerRate[Hz]:Trigger rate"
1303 "|BoardRate[Hz]:Trigger rate of individual FTUs"
1304 "|PatchRate[Hz]:Trigger rate of individual patches"
1305 "|ElapsedTime[sec]:Time elapsed since previous report"
1306 "|OnTime[sec]:OnTime elapsed since previous report"),
1307 fDimError ("FTM_CONTROL/ERROR", "X:1;S:1;S:28", ""),
1308 fDimFtuList ("FTM_CONTROL/FTU_LIST", "X:1;X:1;S:1;C:4;X:40;C:40;C:40",
1309 "Logs the changes of status of the FTUs"
1310 "|FTMtimeStamp[us]:Time in microseconds"
1311 "|ActiveFTU[bitpattern]:Description of enabled FTUs"
1312 "|NumBoards[int]:Total number of enabled FTUs"
1313 "|NumBoardsCrate[int]:Total number of enabled FTUs per crate"
1314 "|DNA[hexCode]:Hex code identifier of FTUs"
1315 "|Addr[bitpattern]:Crate address (hardware) of FTUs"
1316 "|Ping[int]:Number of pings until FTU response"),
1317 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",
1318 "Configuration of FTM and FTUs"
1319 "|FTMtimeStamp[us]:Time in microseconds, since trigger enabled or disabled"
1320 "|GeneralSettings[bitpattern]:Status of the FTM settings (cf. FTM doc)"
1321 "|LEDStatus[bitpattern]:Not Used"
1322 "|ActiveFTU[bitpattern]:List of enabled FTUs"
1323 "|TriggerInterval[bitpattern]:Period of cal. and ped. events (cf. FTM doc)"
1324 "|TriggerSeq[int]:Sequence of calib. and pedestal events (LPint, LPext, Ped)"
1325 "|LPSettings[bitpattern]:Settings of LP, enabled int, ext, intensity int, ext"
1326 "|PhysTrigMult[int]:N for N out of 40 logic on FTM (Physics)"
1327 "|CalibTrigMult[int]: N for N out of 40 logic on FTM (Calib)"
1328 "|PhysTrigWindow[ns]:Coincidence window for N out of 40 (Physics)"
1329 "|CalibTrigWindow[ns]:Coincidence window for N out of 40 (Calib)"
1330 "|TrigDelay[ns]:Trigger delay applied on FTM"
1331 "|TMDelay[ns]:TM delay applied on FTM"
1332 "|DeadTime[ns]:Dead time applied after each event on the FTM"
1333 "|ClkCond[bitpattern]:Clock conditionner settings on the FTM (DRS sampling freq.)"
1334 "|PixEnabled[bitpattern]:Enabled pixels, pckd in 90 shorts (160*9bits=180bytes)"
1335 "|PatchThresh[DACcounts]:Threshold of the trigger patches"
1336 "|Multiplicity[DACcounts]:N out of 4 logic settings per FTU"
1337 "|Prescaling[500ms]:Update rate of the rate counter"),
1338 fDimDynamicData ("FTM_CONTROL/DYNAMIC_DATA", "X:1;X:1;F:4;I:160;I:40;S:40;S:40;S:40;S:1",
1339 "Regular reports sent by FTM"
1340 "|FTMtimeStamp[us]:Time in microseconds, since trigger enabled or disabled"
1341 "|OnTimeCounter[us]:Ontime, i.e. FTM processes triggers (e.g. No FAD busy)"
1342 "|Temperatures[Nan]:not yet defined nor used (wanna be FTM onboard temps)"
1343 "|TriggerPatchCounter[int]:counting since last update (prescaling)"
1344 "|BoardsCounter[int]:FTU board counting after N out of 4 and since last update"
1345 "|RateOverflow[bitpattern]:bits 0-4=patches overflow, 5=board overflow, 1 per board"
1346 "|Prescaling[500ms]:Update rate of the rate counter"
1347 "|CrcError[int]:Number of checksum error in RS485 communication"
1348 "|State[int]:State value of the FTM firmware (cf. FTM doc)"),
1349 fDimCounter ("FTM_CONTROL/COUNTER", "I:1;I:1;I:1;I:1;I:1;I:1",
1350 "Communication statistics to or from FTM control and FTM"
1351 "|NumHeaders[int]:Num. of headers (any header) received by ftm control"
1352 "|NumStaticData[int]:Num. of static data blocks (ftm and ftu settings)"
1353 "|NumDynamicData[int]:Num. of dynamic data blocks (e.g. rates)"
1354 "|NumFtuList[int]:Num. of FTU list (FTU identifiers, answer from ping)"
1355 "|NumErrors[int]:Num. of error messages"
1356 "|NumRegister[int]:Num. of answers from a single register accesess"),
1357 fTimeStamp(UINT64_MAX),
1358 fTriggerCounter(UINT32_MAX)
1359 {
1360 }
1361
1362 // 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
1363};
1364
1365// ------------------------------------------------------------------------
1366
1367template <class T, class S>
1368class StateMachineFTM : public T, public ba::io_service, public ba::io_service::work
1369{
1370 int Wrap(function<void()> f)
1371 {
1372 f();
1373 return T::GetCurrentState();
1374 }
1375
1376 function<int(const EventImp &)> Wrapper(function<void()> func)
1377 {
1378 return bind(&StateMachineFTM::Wrap, this, func);
1379 }
1380
1381private:
1382 S fFTM;
1383
1384 bool CheckEventSize(size_t has, const char *name, size_t size)
1385 {
1386 if (has==size)
1387 return true;
1388
1389 ostringstream msg;
1390 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
1391 T::Fatal(msg);
1392 return false;
1393 }
1394
1395 int SetRegister(const EventImp &evt)
1396 {
1397 if (!CheckEventSize(evt.GetSize(), "SetRegister", 8))
1398 return T::kSM_FatalError;
1399
1400 const uint32_t *dat = evt.Ptr<uint32_t>();
1401
1402 if (dat[1]>uint16_t(-1))
1403 {
1404 ostringstream msg;
1405 msg << hex << "Value " << dat[1] << " out of range.";
1406 T::Error(msg);
1407 return T::GetCurrentState();
1408 }
1409
1410
1411 if (dat[0]>uint16_t(-1) || !fFTM.CmdSetRegister(dat[0], dat[1]))
1412 {
1413 ostringstream msg;
1414 msg << hex << "Address " << dat[0] << " out of range.";
1415 T::Error(msg);
1416 }
1417
1418 return T::GetCurrentState();
1419 }
1420
1421 int GetRegister(const EventImp &evt)
1422 {
1423 if (!CheckEventSize(evt.GetSize(), "GetRegister", 4))
1424 return T::kSM_FatalError;
1425
1426 const unsigned int addr = evt.GetInt();
1427 if (addr>uint16_t(-1) || !fFTM.CmdGetRegister(addr))
1428 {
1429 ostringstream msg;
1430 msg << hex << "Address " << addr << " out of range.";
1431 T::Error(msg);
1432 }
1433
1434 return T::GetCurrentState();
1435 }
1436
1437 int TakeNevents(const EventImp &evt)
1438 {
1439 if (!CheckEventSize(evt.GetSize(), "TakeNevents", 4))
1440 return T::kSM_FatalError;
1441
1442 const unsigned int dat = evt.GetUInt();
1443
1444 /*
1445 if (dat[1]>uint32_t(-1))
1446 {
1447 ostringstream msg;
1448 msg << hex << "Value " << dat[1] << " out of range.";
1449 T::Error(msg);
1450 return T::GetCurrentState();
1451 }*/
1452
1453 fFTM.CmdTakeNevents(dat);
1454
1455 return T::GetCurrentState();
1456 }
1457
1458 int DisableReports(const EventImp &evt)
1459 {
1460 if (!CheckEventSize(evt.GetSize(), "DisableReports", 1))
1461 return T::kSM_FatalError;
1462
1463 fFTM.CmdDisableReports(evt.GetBool());
1464
1465 return T::GetCurrentState();
1466 }
1467
1468 int SetVerbosity(const EventImp &evt)
1469 {
1470 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
1471 return T::kSM_FatalError;
1472
1473 fFTM.SetVerbose(evt.GetBool());
1474
1475 return T::GetCurrentState();
1476 }
1477
1478 int SetHexOutput(const EventImp &evt)
1479 {
1480 if (!CheckEventSize(evt.GetSize(), "SetHexOutput", 1))
1481 return T::kSM_FatalError;
1482
1483 fFTM.SetHexOutput(evt.GetBool());
1484
1485 return T::GetCurrentState();
1486 }
1487
1488 int SetDynamicOut(const EventImp &evt)
1489 {
1490 if (!CheckEventSize(evt.GetSize(), "SetDynamicOut", 1))
1491 return T::kSM_FatalError;
1492
1493 fFTM.SetDynamicOut(evt.GetBool());
1494
1495 return T::GetCurrentState();
1496 }
1497
1498 int LoadStaticData(const EventImp &evt)
1499 {
1500 if (fFTM.LoadStaticData(evt.GetString()))
1501 return T::GetCurrentState();
1502
1503 ostringstream msg;
1504 msg << "Loading static data from file '" << evt.GetString() << "' failed ";
1505
1506 if (errno)
1507 msg << "(" << strerror(errno) << ")";
1508 else
1509 msg << "(wrong size, expected " << sizeof(FTM::StaticData) << " bytes)";
1510
1511 T::Warn(msg);
1512
1513 return T::GetCurrentState();
1514 }
1515
1516 int SaveStaticData(const EventImp &evt)
1517 {
1518 if (fFTM.SaveStaticData(evt.GetString()))
1519 return T::GetCurrentState();
1520
1521 ostringstream msg;
1522 msg << "Writing static data to file '" << evt.GetString() << "' failed ";
1523 msg << "(" << strerror(errno) << ")";
1524
1525 T::Warn(msg);
1526
1527 return T::GetCurrentState();
1528 }
1529
1530 int SetThreshold(const EventImp &evt)
1531 {
1532 if (!CheckEventSize(evt.GetSize(), "SetThreshold", 8))
1533 return T::kSM_FatalError;
1534
1535 const int32_t *data = evt.Ptr<int32_t>();
1536
1537 if (!fFTM.SetThreshold(data[0], data[1]))
1538 {
1539 ostringstream msg;
1540 msg << "SetThreshold - Maximum allowed patch number 159, valid value range 0-0xffff (got: " << data[0] << " " << data[1] << ")";
1541 T::Warn(msg);
1542 }
1543
1544 return T::GetCurrentState();
1545 }
1546
1547 int SetNoutof4(const EventImp &evt)
1548 {
1549 if (!CheckEventSize(evt.GetSize(), "SetNoutof4", 8))
1550 return T::kSM_FatalError;
1551
1552 const int32_t *data = evt.Ptr<int32_t>();
1553
1554 if (!fFTM.SetNoutof4(data[0], data[1]))
1555 T::Warn("SetNoutof4 - Maximum allowed board number 39, valid value range 0-0xffff");
1556
1557 return T::GetCurrentState();
1558 }
1559
1560 int EnableFTU(const EventImp &evt)
1561 {
1562 if (!CheckEventSize(evt.GetSize(), "EnableFTU", 5))
1563 return T::kSM_FatalError;
1564
1565 const int32_t &board = evt.Get<int32_t>();
1566 const int8_t &enable = evt.Get<int8_t>(4);
1567
1568 if (!fFTM.EnableFTU(board, enable))
1569 T::Warn("EnableFTU - Board number must be <40.");
1570
1571 return T::GetCurrentState();
1572 }
1573
1574 int ToggleFTU(const EventImp &evt)
1575 {
1576 if (!CheckEventSize(evt.GetSize(), "ToggleFTU", 4))
1577 return T::kSM_FatalError;
1578
1579 if (!fFTM.ToggleFTU(evt.GetInt()))
1580 T::Warn("ToggleFTU - Allowed range of boards 0-39.");
1581
1582 return T::GetCurrentState();
1583 }
1584
1585 int SetTriggerInterval(const EventImp &evt)
1586 {
1587 if (!CheckEventSize(evt.GetSize(), "SetTriggerInterval", 4))
1588 return T::kSM_FatalError;
1589
1590 if (!fFTM.SetTriggerInterval(evt.GetInt()))
1591 T::Warn("SetTriggerInterval - Value out of range.");
1592
1593 return T::GetCurrentState();
1594 }
1595
1596 int SetTriggerDelay(const EventImp &evt)
1597 {
1598 if (!CheckEventSize(evt.GetSize(), "SetTriggerDelay", 4))
1599 return T::kSM_FatalError;
1600
1601 if (!fFTM.SetTriggerDelay(evt.GetInt()))
1602 T::Warn("SetTriggerDealy - Value out of range.");
1603
1604 return T::GetCurrentState();
1605 }
1606
1607 int SetTimeMarkerDelay(const EventImp &evt)
1608 {
1609 if (!CheckEventSize(evt.GetSize(), "SetTimeMarkerDelay", 4))
1610 return T::kSM_FatalError;
1611
1612 if (!fFTM.SetTimeMarkerDelay(evt.GetInt()))
1613 T::Warn("SetTimeMarkerDelay - Value out of range.");
1614
1615 return T::GetCurrentState();
1616 }
1617
1618 int SetPrescaling(const EventImp &evt)
1619 {
1620 if (!CheckEventSize(evt.GetSize(), "SetPrescaling", 4))
1621 return T::kSM_FatalError;
1622
1623 if (!fFTM.SetPrescaling(evt.GetInt()-1))
1624 T::Warn("SetPrescaling - Value out of range.");
1625
1626 return T::GetCurrentState();
1627 }
1628
1629 int SetTriggerSeq(const EventImp &evt)
1630 {
1631 if (!CheckEventSize(evt.GetSize(), "SetTriggerSeq", 6))
1632 return T::kSM_FatalError;
1633
1634 const uint16_t *data = evt.Ptr<uint16_t>();
1635
1636 if (!fFTM.SetTriggerSeq(data))
1637 T::Warn("SetTriggerSeq - Value out of range.");
1638
1639 return T::GetCurrentState();
1640 }
1641
1642 int SetDeadTime(const EventImp &evt)
1643 {
1644 if (!CheckEventSize(evt.GetSize(), "SetDeadTime", 4))
1645 return T::kSM_FatalError;
1646
1647 if (!fFTM.SetDeadTime(evt.GetInt()))
1648 T::Warn("SetDeadTime - Value out of range.");
1649
1650 return T::GetCurrentState();
1651 }
1652
1653 int SetTriggerMultiplicity(const EventImp &evt)
1654 {
1655 if (!CheckEventSize(evt.GetSize(), "SetTriggerMultiplicity", 2))
1656 return T::kSM_FatalError;
1657
1658 if (!fFTM.SetTriggerMultiplicity(evt.GetUShort()))
1659 T::Warn("SetTriggerMultiplicity - Value out of range.");
1660
1661 return T::GetCurrentState();
1662 }
1663
1664 int SetCalibMultiplicity(const EventImp &evt)
1665 {
1666 if (!CheckEventSize(evt.GetSize(), "SetCalibMultiplicity", 2))
1667 return T::kSM_FatalError;
1668
1669 if (!fFTM.SetCalibMultiplicity(evt.GetUShort()))
1670 T::Warn("SetCalibMultiplicity - Value out of range.");
1671
1672 return T::GetCurrentState();
1673 }
1674
1675 int SetTriggerWindow(const EventImp &evt)
1676 {
1677 if (!CheckEventSize(evt.GetSize(), "SetTriggerWindow", 2))
1678 return T::kSM_FatalError;
1679
1680 if (!fFTM.SetTriggerWindow(evt.GetUShort()))
1681 T::Warn("SetTriggerWindow - Value out of range.");
1682
1683 return T::GetCurrentState();
1684 }
1685
1686 int SetCalibWindow(const EventImp &evt)
1687 {
1688 if (!CheckEventSize(evt.GetSize(), "SetCalibWindow", 2))
1689 return T::kSM_FatalError;
1690
1691 if (!fFTM.SetCalibWindow(evt.GetUShort()))
1692 T::Warn("SetCalibWindow - Value out of range.");
1693
1694 return T::GetCurrentState();
1695 }
1696
1697 int SetClockRegister(const EventImp &evt)
1698 {
1699 if (!CheckEventSize(evt.GetSize(), "SetClockRegister", 8*8))
1700 return T::kSM_FatalError;
1701
1702 const uint64_t *reg = evt.Ptr<uint64_t>();
1703
1704 if (!fFTM.SetClockRegister(reg))
1705 T::Warn("SetClockRegister - Value out of range.");
1706
1707 return T::GetCurrentState();
1708 }
1709
1710 int SetClockFrequency(const EventImp &evt)
1711 {
1712 if (!CheckEventSize(evt.GetSize(), "SetClockFrequency", 2))
1713 return T::kSM_FatalError;
1714
1715 const map<uint16_t,array<uint64_t, 8>>::const_iterator it =
1716 fClockCondSetup.find(evt.GetUShort());
1717
1718 if (it==fClockCondSetup.end())
1719 {
1720 T::Warn("SetClockFrequency - Frequency not supported.");
1721 return T::GetCurrentState();
1722 }
1723
1724 if (!fFTM.SetClockRegister(it->second.data()))
1725 T::Warn("SetClockFrequency - Register values out of range.");
1726
1727 return T::GetCurrentState();
1728 }
1729
1730 int EnableLP(const EventImp &evt, FTM::StaticData::GeneralSettings lp, FTM::StaticData::LightPulserEnable group)
1731 {
1732 if (!CheckEventSize(evt.GetSize(), "EnableLP", 1))
1733 return T::kSM_FatalError;
1734
1735 if (!fFTM.EnableLP(lp, group, evt.GetBool()))
1736 T::Warn("EnableLP - Invalid light pulser id.");
1737
1738 return T::GetCurrentState();
1739 }
1740
1741 int SetIntensity(const EventImp &evt, FTM::StaticData::GeneralSettings lp)
1742 {
1743 if (!CheckEventSize(evt.GetSize(), "SetIntensity", 2))
1744 return T::kSM_FatalError;
1745
1746 if (!fFTM.SetIntensity(lp, evt.GetShort()))
1747 T::Warn("SetIntensity - Value out of range.");
1748
1749 return T::GetCurrentState();
1750 }
1751
1752 int Enable(const EventImp &evt, FTM::StaticData::GeneralSettings type)
1753 {
1754 if (!CheckEventSize(evt.GetSize(), "Enable", 1))
1755 return T::kSM_FatalError;
1756
1757 fFTM.Enable(type, evt.GetBool());
1758
1759 return T::GetCurrentState();
1760 }
1761
1762 int EnablePixel(const EventImp &evt, bool b)
1763 {
1764 if (!CheckEventSize(evt.GetSize(), "EnablePixel", 2))
1765 return T::kSM_FatalError;
1766
1767 if (!fFTM.EnablePixel(evt.GetUShort(), b))
1768 T::Warn("EnablePixel - Value out of range.");
1769
1770 return T::GetCurrentState();
1771 }
1772
1773 int DisableAllPixelsExcept(const EventImp &evt)
1774 {
1775 if (!CheckEventSize(evt.GetSize(), "DisableAllPixelsExcept", 2))
1776 return T::kSM_FatalError;
1777
1778 if (!fFTM.DisableAllPixelsExcept(evt.GetUShort()))
1779 T::Warn("DisableAllPixelsExcept - Value out of range.");
1780
1781 return T::GetCurrentState();
1782 }
1783
1784 int DisableAllPatchesExcept(const EventImp &evt)
1785 {
1786 if (!CheckEventSize(evt.GetSize(), "DisableAllPatchesExcept", 2))
1787 return T::kSM_FatalError;
1788
1789 if (!fFTM.DisableAllPatchesExcept(evt.GetUShort()))
1790 T::Warn("DisableAllPatchesExcept - Value out of range.");
1791
1792 return T::GetCurrentState();
1793 }
1794
1795 int EnablePatch(const EventImp &evt, bool enable)
1796 {
1797 if (!CheckEventSize(evt.GetSize(), "EnablePatch", 2))
1798 return T::kSM_FatalError;
1799
1800 if (!fFTM.EnablePatch(evt.GetUShort(), enable))
1801 T::Warn("EnablePatch - Value out of range.");
1802
1803 return T::GetCurrentState();
1804 }
1805
1806 int TogglePixel(const EventImp &evt)
1807 {
1808 if (!CheckEventSize(evt.GetSize(), "TogglePixel", 2))
1809 return T::kSM_FatalError;
1810
1811 if (!fFTM.TogglePixel(evt.GetUShort()))
1812 T::Warn("TogglePixel - Value out of range.");
1813
1814 return T::GetCurrentState();
1815 }
1816
1817 int ResetCrate(const EventImp &evt)
1818 {
1819 if (!CheckEventSize(evt.GetSize(), "ResetCrate", 2))
1820 return T::kSM_FatalError;
1821
1822 fFTM.CmdResetCrate(evt.GetUShort());
1823
1824 return T::GetCurrentState();
1825 }
1826
1827 int Disconnect()
1828 {
1829 // Close all connections
1830 fFTM.PostClose(false);
1831
1832 /*
1833 // Now wait until all connection have been closed and
1834 // all pending handlers have been processed
1835 poll();
1836 */
1837
1838 return T::GetCurrentState();
1839 }
1840
1841 int Reconnect(const EventImp &evt)
1842 {
1843 // Close all connections to supress the warning in SetEndpoint
1844 fFTM.PostClose(false);
1845
1846 // Now wait until all connection have been closed and
1847 // all pending handlers have been processed
1848 poll();
1849
1850 if (evt.GetBool())
1851 fFTM.SetEndpoint(evt.GetString());
1852
1853 // Now we can reopen the connection
1854 fFTM.PostClose(true);
1855
1856 return T::GetCurrentState();
1857 }
1858
1859 /*
1860 int Transition(const Event &evt)
1861 {
1862 switch (evt.GetTargetState())
1863 {
1864 case kDisconnected:
1865 case kConnected:
1866 }
1867
1868 return T::kSM_FatalError;
1869 }*/
1870
1871 int64_t fCounterReg;
1872 int64_t fCounterStat;
1873
1874 typedef map<string, FTM::StaticData> Configs;
1875 Configs fConfigs;
1876 Configs::const_iterator fTargetConfig;
1877
1878 int ConfigureFTM(const EventImp &evt)
1879 {
1880 const string name = evt.GetText();
1881
1882 fTargetConfig = fConfigs.find(name);
1883 if (fTargetConfig==fConfigs.end())
1884 {
1885 T::Error("ConfigureFTM - Run-type '"+name+"' not found.");
1886 return T::GetCurrentState();
1887 }
1888
1889 T::Message("Starting configuration for '"+name+"'");
1890
1891 fCounterReg = fFTM.GetCounter(FTM::kRegister);
1892 fFTM.CmdStopRun();
1893
1894 return FTM::State::kConfiguring1;
1895 }
1896
1897 int ResetConfig()
1898 {
1899 return fFTM.GetState();
1900 }
1901
1902 int Execute()
1903 {
1904 // Dispatch (execute) at most one handler from the queue. In contrary
1905 // to run_one(), it doesn't wait until a handler is available
1906 // which can be dispatched, so poll_one() might return with 0
1907 // handlers dispatched. The handlers are always dispatched/executed
1908 // synchronously, i.e. within the call to poll_one()
1909 poll_one();
1910
1911 // If FTM is neither in data taking nor idle,
1912 // leave configuration state
1913 switch (fFTM.GetState())
1914 {
1915 case ConnectionFTM::kDisconnected: return FTM::State::kDisconnected;
1916 case ConnectionFTM::kConnected: return FTM::State::kConnected;
1917 default:
1918 break;
1919 }
1920
1921 // FIXME: Add timeouts and go to error state
1922 // so that a configuration error can be handled
1923 switch (T::GetCurrentState())
1924 {
1925 case FTM::State::kConfiguring1:
1926 // If FTM has received an anwer to the stop_run command
1927 // the counter for the registers has been increased
1928 if (fFTM.GetCounter(FTM::kRegister)<=fCounterReg)
1929 break;
1930
1931 // If now the state is not idle as expected this means we had
1932 // an error (maybe old events waiting in the queue)
1933 if (fFTM.GetState()!=ConnectionFTM::kIdle &&
1934 fFTM.GetState()!=ConnectionFTM::kConfigured)
1935 return FTM::State::kConfigError1;
1936
1937 fCounterStat = fFTM.GetCounter(FTM::kStaticData);
1938
1939 T::Message("Trigger successfully disabled... sending new configuration.");
1940
1941 fFTM.CmdSendStatDat(fTargetConfig->second);
1942
1943 // Next state is: wait for the answer to our configuration
1944 return FTM::State::kConfiguring2;
1945
1946 case FTM::State::kConfiguring2:
1947 case FTM::State::kConfigured:
1948 // If FTM has received an anwer to the stop_run command
1949 // the counter for the registers has been increased
1950 if (fFTM.GetCounter(FTM::kStaticData)<=fCounterStat)
1951 break;
1952
1953 // If now the configuration is not what we expected
1954 // we had an error (maybe old events waiting in the queue?)
1955 // ======================
1956 if (fFTM.GetState()!=ConnectionFTM::kConfigured)
1957 return FTM::State::kConfigError2;
1958 // ======================
1959 if (!fFTM.IsLocked())
1960 {
1961 T::Warn("Configuration successfull, but clock conditioner not locked.");
1962 return FTM::State::kConfigError3;
1963 }
1964 // ======================
1965
1966 // Check configuration again when a new static data block
1967 // will be received
1968 fCounterStat = fFTM.GetCounter(FTM::kStaticData);
1969
1970 T::Info(" ==> TODO: Update run in database!");
1971 T::Message("Sending new configuration was successfull.");
1972
1973 // Next state is: wait for the answer to our configuration
1974 return FTM::State::kConfigured;
1975
1976 case FTM::State::kConfigError1:
1977 case FTM::State::kConfigError2:
1978 case FTM::State::kConfigError3:
1979 return T::GetCurrentState();
1980
1981 default:
1982 switch (fFTM.GetState())
1983 {
1984 case ConnectionFTM::kIdle: return FTM::State::kIdle;
1985 case ConnectionFTM::kConfigured: return FTM::State::kIdle;
1986 case ConnectionFTM::kTriggerOn: return FTM::State::kTriggerOn;
1987 default:
1988 throw runtime_error("StateMachienFTM - Execute() - Inavlid state.");
1989 }
1990 }
1991
1992 // FIXME: Do we have to check the state of the clock conditioner here?
1993
1994 if (T::GetCurrentState()==FTM::State::kConfigured &&
1995 fFTM.GetState()==ConnectionFTM::kTriggerOn)
1996 return FTM::State::kTriggerOn;
1997
1998 return T::GetCurrentState();
1999 }
2000
2001public:
2002 StateMachineFTM(ostream &out=cout) :
2003 T(out, "FTM_CONTROL"), ba::io_service::work(static_cast<ba::io_service&>(*this)),
2004 fFTM(*this, *this)
2005 {
2006 // ba::io_service::work is a kind of keep_alive for the loop.
2007 // It prevents the io_service to go to stopped state, which
2008 // would prevent any consecutive calls to run()
2009 // or poll() to do nothing. reset() could also revoke to the
2010 // previous state but this might introduce some overhead of
2011 // deletion and creation of threads and more.
2012
2013
2014 // State names
2015 T::AddStateName(FTM::State::kDisconnected, "Disconnected",
2016 "FTM board not connected via ethernet.");
2017
2018 T::AddStateName(FTM::State::kConnected, "Connected",
2019 "Ethernet connection to FTM established (no state received yet).");
2020
2021 T::AddStateName(FTM::State::kIdle, "Idle",
2022 "Ethernet connection to FTM established, FTM in idle state.");
2023
2024 T::AddStateName(FTM::State::kConfiguring1, "Configuring1",
2025 "Command to diable run sent... waiting for response.");
2026 T::AddStateName(FTM::State::kConfiguring2, "Configuring2",
2027 "New configuration sent... waiting for response.");
2028 T::AddStateName(FTM::State::kConfigured, "Configured",
2029 "Received answer identical with target configuration.");
2030
2031 T::AddStateName(FTM::State::kTriggerOn, "TriggerOn",
2032 "Ethernet connection to FTM established, FTM trigger output to FADs enabled.");
2033
2034 T::AddStateName(FTM::State::kConfigError1, "ErrorInConfig1", "Unexpected state received from FTM");
2035 T::AddStateName(FTM::State::kConfigError2, "ErrorInConfig2", "Unexpected state received from FTM");
2036 T::AddStateName(FTM::State::kConfigError3, "ClockCondError", "Clock conditioner not locked");
2037
2038 // FTM Commands
2039 T::AddEvent("TOGGLE_LED", FTM::State::kIdle)
2040 (Wrapper(bind(&ConnectionFTM::CmdToggleLed, &fFTM)))
2041 ("toggle led");
2042
2043 T::AddEvent("PING", FTM::State::kIdle)
2044 (Wrapper(bind(&ConnectionFTM::CmdPing, &fFTM)))
2045 ("send ping");
2046
2047 T::AddEvent("REQUEST_DYNAMIC_DATA", FTM::State::kIdle)
2048 (Wrapper(bind(&ConnectionFTM::CmdReqDynDat, &fFTM)))
2049 ("request transmission of dynamic data block");
2050
2051 T::AddEvent("REQUEST_STATIC_DATA", FTM::State::kIdle)
2052 (Wrapper(bind(&ConnectionFTM::CmdReqStatDat, &fFTM)))
2053 ("request transmission of static data from FTM to memory");
2054
2055 T::AddEvent("GET_REGISTER", "I", FTM::State::kIdle)
2056 (bind(&StateMachineFTM::GetRegister, this, placeholders::_1))
2057 ("read register from address addr"
2058 "|addr[short]:Address of register");
2059
2060 T::AddEvent("SET_REGISTER", "I:2", FTM::State::kIdle)
2061 (bind(&StateMachineFTM::SetRegister, this, placeholders::_1))
2062 ("set register to value"
2063 "|addr[short]:Address of register"
2064 "|val[short]:Value to be set");
2065
2066 T::AddEvent("START_TRIGGER", FTM::State::kIdle, FTM::State::kConfigured)
2067 (Wrapper(bind(&ConnectionFTM::CmdStartRun, &fFTM)))
2068 ("start a run (start distributing triggers)");
2069
2070 T::AddEvent("STOP_TRIGGER", FTM::State::kTriggerOn)
2071 (Wrapper(bind(&ConnectionFTM::CmdStopRun, &fFTM)))
2072 ("stop a run (stop distributing triggers)");
2073
2074 T::AddEvent("TAKE_N_EVENTS", "I", FTM::State::kIdle)
2075 (bind(&StateMachineFTM::TakeNevents, this, placeholders::_1))
2076 ("take n events (distribute n triggers)|number[int]:Number of events to be taken");
2077
2078 T::AddEvent("DISABLE_REPORTS", "B", FTM::State::kIdle)
2079 (bind(&StateMachineFTM::DisableReports, this, placeholders::_1))
2080 ("disable sending rate reports"
2081 "|status[bool]:disable or enable that the FTM sends rate reports (yes/no)");
2082
2083 T::AddEvent("SET_THRESHOLD", "I:2", FTM::State::kIdle, FTM::State::kConfigured, FTM::State::kTriggerOn)
2084 (bind(&StateMachineFTM::SetThreshold, this, placeholders::_1))
2085 ("Set the comparator threshold"
2086 "|Patch[idx]:Index of the patch (0-159), -1 for all"
2087 "|Threshold[counts]:Threshold to be set in binary counts");
2088
2089 T::AddEvent("SET_N_OUT_OF_4", "I:2", FTM::State::kIdle, FTM::State::kTriggerOn)
2090 (bind(&StateMachineFTM::SetNoutof4, this, placeholders::_1))
2091 ("Set the comparator threshold"
2092 "|Board[idx]:Index of the board (0-39), -1 for all"
2093 "|Threshold[counts]:Threshold to be set in binary counts");
2094
2095 T::AddEvent("SET_PRESCALING", "I:1", FTM::State::kIdle)
2096 (bind(&StateMachineFTM::SetPrescaling, this, placeholders::_1))
2097 ("Sets the FTU readout time intervals"
2098 "|time[0.5s]:The interval is given in units of 0.5s, i.e. 1 means 0.5s, 2 means 1s, ...");
2099
2100 T::AddEvent("ENABLE_FTU", "I:1;B:1", FTM::State::kIdle, FTM::State::kConfigured)
2101 (bind(&StateMachineFTM::EnableFTU, this, placeholders::_1))
2102 ("Enable or disable FTU"
2103 "|Board[idx]:Index of the board (0-39), -1 for all"
2104 "|Enable[bool]:Whether FTU should be enabled or disabled (yes/no)");
2105
2106 T::AddEvent("DISABLE_PIXEL", "S:1", FTM::State::kIdle, FTM::State::kTriggerOn)
2107 (bind(&StateMachineFTM::EnablePixel, this, placeholders::_1, false))
2108 ("(-1 or all)");
2109
2110 T::AddEvent("ENABLE_PIXEL", "S:1", FTM::State::kIdle, FTM::State::kTriggerOn)
2111 (bind(&StateMachineFTM::EnablePixel, this, placeholders::_1, true))
2112 ("(-1 or all)");
2113
2114 T::AddEvent("DISABLE_ALL_PIXELS_EXCEPT", "S:1", FTM::State::kIdle)
2115 (bind(&StateMachineFTM::DisableAllPixelsExcept, this, placeholders::_1))
2116 ("");
2117
2118 T::AddEvent("DISABLE_ALL_PATCHES_EXCEPT", "S:1", FTM::State::kIdle)
2119 (bind(&StateMachineFTM::DisableAllPatchesExcept, this, placeholders::_1))
2120 ("");
2121
2122 T::AddEvent("ENABLE_PATCH", "S:1", FTM::State::kIdle)
2123 (bind(&StateMachineFTM::EnablePatch, this, placeholders::_1, true))
2124 ("");
2125
2126 T::AddEvent("DISABLE_PATCH", "S:1", FTM::State::kIdle)
2127 (bind(&StateMachineFTM::EnablePatch, this, placeholders::_1, false))
2128 ("");
2129
2130 T::AddEvent("TOGGLE_PIXEL", "S:1", FTM::State::kIdle)
2131 (bind(&StateMachineFTM::TogglePixel, this, placeholders::_1))
2132 ("");
2133
2134 T::AddEvent("TOGGLE_FTU", "I:1", FTM::State::kIdle)
2135 (bind(&StateMachineFTM::ToggleFTU, this, placeholders::_1))
2136 ("Toggle status of FTU (this is mainly meant to be used in the GUI)"
2137 "|Board[idx]:Index of the board (0-39)");
2138
2139 T::AddEvent("SET_TRIGGER_INTERVAL", "I:1", FTM::State::kIdle)
2140 (bind(&StateMachineFTM::SetTriggerInterval, this, placeholders::_1))
2141 ("Sets the trigger interval which is the distance between two consecutive artificial triggers."
2142 "|interval[ms]:The applied trigger interval in millisecond (min 1ms / 10bit)");
2143
2144 T::AddEvent("SET_TRIGGER_DELAY", "I:1", FTM::State::kIdle)
2145 (bind(&StateMachineFTM::SetTriggerDelay, this, placeholders::_1))
2146 (""
2147 "|delay[int]:The applied trigger delay is: delay*4ns+8ns");
2148
2149 T::AddEvent("SET_TIME_MARKER_DELAY", "I:1", FTM::State::kIdle)
2150 (bind(&StateMachineFTM::SetTimeMarkerDelay, this, placeholders::_1))
2151 (""
2152 "|delay[int]:The applied time marker delay is: delay*4ns+8ns");
2153
2154 T::AddEvent("SET_DEAD_TIME", "I:1", FTM::State::kIdle)
2155 (bind(&StateMachineFTM::SetDeadTime, this, placeholders::_1))
2156 (""
2157 "|dead_time[int]:The applied dead time is: dead_time*4ns+8ns");
2158
2159 T::AddEvent("ENABLE_TRIGGER", "B:1", FTM::State::kIdle)
2160 (bind(&StateMachineFTM::Enable, this, placeholders::_1, FTM::StaticData::kTrigger))
2161 ("Switch on the physics trigger"
2162 "|Enable[bool]:Enable physics trigger (yes/no)");
2163
2164 // FIXME: Switch on/off depending on sequence
2165 T::AddEvent("ENABLE_EXT1", "B:1", FTM::State::kIdle)
2166 (bind(&StateMachineFTM::Enable, this, placeholders::_1, FTM::StaticData::kExt1))
2167 ("Switch on the triggers through the first external line"
2168 "|Enable[bool]:Enable ext1 trigger (yes/no)");
2169
2170 // FIXME: Switch on/off depending on sequence
2171 T::AddEvent("ENABLE_EXT2", "B:1", FTM::State::kIdle)
2172 (bind(&StateMachineFTM::Enable, this, placeholders::_1, FTM::StaticData::kExt2))
2173 ("Switch on the triggers through the second external line"
2174 "|Enable[bool]:Enable ext2 trigger (yes/no)");
2175
2176 T::AddEvent("ENABLE_VETO", "B:1", FTM::State::kIdle)
2177 (bind(&StateMachineFTM::Enable, this, placeholders::_1, FTM::StaticData::kVeto))
2178 ("Enable veto line"
2179 "|Enable[bool]:Enable veto (yes/no)");
2180
2181 T::AddEvent("ENABLE_CLOCK_CONDITIONER", "B:1", FTM::State::kIdle)
2182 (bind(&StateMachineFTM::Enable, this, placeholders::_1, FTM::StaticData::kClockConditioner))
2183 ("Enable clock conidtioner output in favor of time marker output"
2184 "|Enable[bool]:Enable clock conditioner (yes/no)");
2185
2186 T::AddEvent("ENABLE_GROUP1_LPINT", "B:1", FTM::State::kIdle)
2187 (bind(&StateMachineFTM::EnableLP, this, placeholders::_1, FTM::StaticData::kLPint, FTM::StaticData::kGroup1))
2188 ("");
2189 T::AddEvent("ENABLE_GROUP1_LPEXT", "B:1", FTM::State::kIdle)
2190 (bind(&StateMachineFTM::EnableLP, this, placeholders::_1, FTM::StaticData::kLPext, FTM::StaticData::kGroup1))
2191 ("");
2192 T::AddEvent("ENABLE_GROUP2_LPINT", "B:1", FTM::State::kIdle)
2193 (bind(&StateMachineFTM::EnableLP, this, placeholders::_1, FTM::StaticData::kLPint, FTM::StaticData::kGroup2))
2194 ("");
2195 T::AddEvent("ENABLE_GROUP2_LPEXT", "B:1", FTM::State::kIdle)
2196 (bind(&StateMachineFTM::EnableLP, this, placeholders::_1, FTM::StaticData::kLPext, FTM::StaticData::kGroup2))
2197 ("");
2198 T::AddEvent("SET_INTENSITY_LPINT", "S:1", FTM::State::kIdle)
2199 (bind(&StateMachineFTM::SetIntensity, this, placeholders::_1, FTM::StaticData::kLPint))
2200 ("");
2201 T::AddEvent("SET_INTENSITY_LPEXT", "S:1", FTM::State::kIdle)
2202 (bind(&StateMachineFTM::SetIntensity, this, placeholders::_1, FTM::StaticData::kLPext))
2203 ("");
2204
2205
2206 T::AddEvent("SET_TRIGGER_SEQUENCE", "S:3", FTM::State::kIdle)
2207 (bind(&StateMachineFTM::SetTriggerSeq, this, placeholders::_1))
2208 ("Setup the sequence of artificial triggers produced by the FTM"
2209 "|Ped[short]:number of pedestal triggers in a row"
2210 "|LPext[short]:number of triggers of the external light pulser"
2211 "|LPint[short]:number of triggers of the internal light pulser");
2212
2213 T::AddEvent("SET_TRIGGER_MULTIPLICITY", "S:1", FTM::State::kIdle)
2214 (bind(&StateMachineFTM::SetTriggerMultiplicity, this, placeholders::_1))
2215 ("Setup the Multiplicity condition for physcis triggers"
2216 "|N[int]:Number of requirered coincident triggers from sum-patches (1-40)");
2217
2218 T::AddEvent("SET_TRIGGER_WINDOW", "S:1", FTM::State::kIdle)
2219 (bind(&StateMachineFTM::SetTriggerWindow, this, placeholders::_1))
2220 ("");
2221
2222 T::AddEvent("SET_CALIBRATION_MULTIPLICITY", "S:1", FTM::State::kIdle)
2223 (bind(&StateMachineFTM::SetCalibMultiplicity, this, placeholders::_1))
2224 ("Setup the Multiplicity condition for artificial (calibration) triggers"
2225 "|N[int]:Number of requirered coincident triggers from sum-patches (1-40)");
2226
2227 T::AddEvent("SET_CALIBRATION_WINDOW", "S:1", FTM::State::kIdle)
2228 (bind(&StateMachineFTM::SetCalibWindow, this, placeholders::_1))
2229 ("");
2230
2231 T::AddEvent("SET_CLOCK_FREQUENCY", "S:1", FTM::State::kIdle)
2232 (bind(&StateMachineFTM::SetClockFrequency, this, placeholders::_1))
2233 ("");
2234
2235 T::AddEvent("SET_CLOCK_REGISTER", "X:8", FTM::State::kIdle)
2236 (bind(&StateMachineFTM::SetClockRegister, this, placeholders::_1))
2237 ("");
2238
2239 // A new configure will first stop the FTM this means
2240 // we can allow it in idle _and_ taking data
2241 T::AddEvent("CONFIGURE", "C", FTM::State::kIdle, FTM::State::kConfiguring1, FTM::State::kConfiguring2, FTM::State::kConfigured, FTM::State::kTriggerOn)
2242 (bind(&StateMachineFTM::ConfigureFTM, this, placeholders::_1))
2243 ("");
2244
2245 T::AddEvent("RESET_CONFIGURE")(FTM::State::kConfiguring1)(FTM::State::kConfiguring2)(FTM::State::kConfigured)(FTM::State::kConfigError1)(FTM::State::kConfigError2)(FTM::State::kConfigError2)
2246 (bind(&StateMachineFTM::ResetConfig, this))
2247 ("Reset states during a configuration or in case of configuration error");
2248
2249
2250
2251 T::AddEvent("RESET_CRATE", "S:1", FTM::State::kIdle, FTM::State::kConfigured)
2252 (bind(&StateMachineFTM::ResetCrate, this, placeholders::_1))
2253 ("Reset one of the crates 0-3"
2254 "|crate[short]:Crate number to be reseted (0-3)");
2255
2256 T::AddEvent("RESET_CAMERA", FTM::State::kIdle)
2257 (Wrapper(bind(&ConnectionFTM::CmdResetCamera, &fFTM)))
2258 ("Reset all crates. The commands are sent in the order 0,1,2,3");
2259
2260
2261 // Load/save static data block
2262 T::AddEvent("SAVE", "C", FTM::State::kIdle)
2263 (bind(&StateMachineFTM::SaveStaticData, this, placeholders::_1))
2264 ("Saves the static data (FTM configuration) from memory to a file"
2265 "|filename[string]:Filename (can include a path), .bin is automatically added");
2266
2267 T::AddEvent("LOAD", "C", FTM::State::kIdle)
2268 (bind(&StateMachineFTM::LoadStaticData, this, placeholders::_1))
2269 ("Loads the static data (FTM configuration) from a file into memory and sends it to the FTM"
2270 "|filename[string]:Filename (can include a path), .bin is automatically added");
2271
2272
2273
2274 // Verbosity commands
2275 T::AddEvent("SET_VERBOSE", "B")
2276 (bind(&StateMachineFTM::SetVerbosity, this, placeholders::_1))
2277 ("set verbosity state"
2278 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
2279
2280 T::AddEvent("SET_HEX_OUTPUT", "B")
2281 (bind(&StateMachineFTM::SetHexOutput, this, placeholders::_1))
2282 ("enable or disable hex output for received data"
2283 "|hexout[bool]:disable or enable hex output for received data (yes/no)");
2284
2285 T::AddEvent("SET_DYNAMIC_OUTPUT", "B")
2286 (bind(&StateMachineFTM::SetDynamicOut, this, placeholders::_1))
2287 ("enable or disable output for received dynamic data (data is still broadcasted via Dim)"
2288 "|dynout[bool]:disable or enable output for dynamic data (yes/no)");
2289
2290
2291 // Conenction commands
2292 T::AddEvent("DISCONNECT", FTM::State::kConnected, FTM::State::kIdle)
2293 (bind(&StateMachineFTM::Disconnect, this))
2294 ("disconnect from ethernet");
2295
2296 T::AddEvent("RECONNECT", "O", FTM::State::kDisconnected, FTM::State::kConnected, FTM::State::kIdle, FTM::State::kConfigured)
2297 (bind(&StateMachineFTM::Reconnect, this, placeholders::_1))
2298 ("(Re)connect ethernet connection to FTM, a new address can be given"
2299 "|[host][string]:new ethernet address in the form <host:port>");
2300
2301 fFTM.StartConnect();
2302 }
2303
2304 void SetEndpoint(const string &url)
2305 {
2306 fFTM.SetEndpoint(url);
2307 }
2308
2309 map<uint16_t, array<uint64_t, 8>> fClockCondSetup;
2310
2311 template<class V>
2312 bool CheckConfigVal(Configuration &conf, V max, const string &name, const string &sub)
2313 {
2314 if (!conf.HasDef(name, sub))
2315 {
2316 T::Error("Neither "+name+"default nor "+name+sub+" found.");
2317 return false;
2318 }
2319
2320 const V val = conf.GetDef<V>(name, sub);
2321
2322 if (val<=max)
2323 return true;
2324
2325 ostringstream str;
2326 str << name << sub << "=" << val << " exceeds allowed maximum of " << max << "!";
2327 T::Error(str);
2328
2329 return false;
2330 }
2331
2332 int EvalOptions(Configuration &conf)
2333 {
2334 // ---------- General setup ----------
2335 fFTM.SetVerbose(!conf.Get<bool>("quiet"));
2336 fFTM.SetHexOutput(conf.Get<bool>("hex-out"));
2337 fFTM.SetDynamicOut(conf.Get<bool>("dynamic-out"));
2338
2339 // ---------- Setup clock conditioner frequencies ----------
2340 const vector<uint16_t> freq = conf.Vec<uint16_t>("clock-conditioner.frequency");
2341 if (freq.size()==0)
2342 T::Warn("No frequencies for the clock-conditioner defined.");
2343 else
2344 T::Message("Defining clock conditioner frequencies");
2345 for (vector<uint16_t>::const_iterator it=freq.begin();
2346 it!=freq.end(); it++)
2347 {
2348 if (fClockCondSetup.count(*it)>0)
2349 {
2350 T::Error("clock-conditioner frequency defined twice.");
2351 return 1;
2352 }
2353
2354 if (!conf.HasDef("clock-conditioner.R0.", *it) ||
2355 !conf.HasDef("clock-conditioner.R1.", *it) ||
2356 !conf.HasDef("clock-conditioner.R8.", *it) ||
2357 !conf.HasDef("clock-conditioner.R9.", *it) ||
2358 !conf.HasDef("clock-conditioner.R11.", *it) ||
2359 !conf.HasDef("clock-conditioner.R13.", *it) ||
2360 !conf.HasDef("clock-conditioner.R14.", *it) ||
2361 !conf.HasDef("clock-conditioner.R15.", *it))
2362 {
2363 T::Error("clock-conditioner values incomplete.");
2364 return 1;
2365 }
2366
2367 array<uint64_t, 8> &arr = fClockCondSetup[*it];
2368
2369 arr[0] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R0.", *it);
2370 arr[1] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R1.", *it);
2371 arr[2] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R8.", *it);
2372 arr[3] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R9.", *it);
2373 arr[4] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R11.", *it);
2374 arr[5] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R13.", *it);
2375 arr[6] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R14.", *it);
2376 arr[7] = conf.GetDef<Hex<uint32_t>>("clock-conditioner.R15.", *it);
2377
2378 ostringstream out;
2379 out << " -> " << setw(4) << *it << "MHz:" << hex << setfill('0');
2380 for (int i=0; i<8; i++)
2381 out << " " << setw(8) << arr[i];
2382 T::Message(out.str());
2383 }
2384
2385 // ---------- Setup run types ---------
2386 const vector<string> types = conf.Vec<string>("run-type");
2387 if (types.size()==0)
2388 T::Warn("No run-types defined.");
2389 else
2390 T::Message("Defining run-types");
2391 for (vector<string>::const_iterator it=types.begin();
2392 it!=types.end(); it++)
2393 {
2394 T::Message(" -> "+ *it);
2395
2396 if (fConfigs.count(*it)>0)
2397 {
2398 T::Error("Run-type "+*it+" defined twice.");
2399 return 2;
2400 }
2401
2402 if (!conf.HasDef("sampling-frequency.", *it))
2403 {
2404 T::Error("Neither sampling-frequency."+*it+" nor sampling-frequency.default found.");
2405 return 2;
2406 }
2407
2408 const uint16_t frq = conf.GetDef<uint16_t>("sampling-frequency.", *it);
2409
2410 FTM::StaticData data;
2411 data.SetClockRegister(fClockCondSetup[frq].data());
2412
2413 // Trigger sequence ped:lp1:lp2
2414 // (data. is used here as an abbreviation for FTM::StaticData::
2415 if (!CheckConfigVal<bool> (conf, true, "trigger.enable-trigger.", *it) ||
2416 !CheckConfigVal<bool> (conf, true, "trigger.enable-external-1.", *it) ||
2417 !CheckConfigVal<bool> (conf, true, "trigger.enable-external-2.", *it) ||
2418 !CheckConfigVal<bool> (conf, true, "trigger.enable-veto.", *it) ||
2419 !CheckConfigVal<bool> (conf, true, "trigger.enable-clock-conditioner.", *it) ||
2420 !CheckConfigVal<bool> (conf, true, "light-pulser.external.enable-group1.", *it) ||
2421 !CheckConfigVal<bool> (conf, true, "light-pulser.external.enable-group2.", *it) ||
2422 !CheckConfigVal<bool> (conf, true, "light-pulser.internal.enable-group1.", *it) ||
2423 !CheckConfigVal<bool> (conf, true, "light-pulser.internal.enable-group2.", *it) ||
2424 !CheckConfigVal<uint16_t>(conf, data.kMaxSequence, "trigger.sequence.pedestal.", *it) ||
2425 !CheckConfigVal<uint16_t>(conf, data.kMaxSequence, "trigger.sequence.lp-ext.", *it) ||
2426 !CheckConfigVal<uint16_t>(conf, data.kMaxSequence, "trigger.sequence.lp-int.", *it) ||
2427 !CheckConfigVal<uint16_t>(conf, data.kMaxTriggerInterval, "trigger.sequence.interval.", *it) ||
2428 !CheckConfigVal<uint16_t>(conf, data.kMaxMultiplicity, "trigger.multiplicity-physics.", *it) ||
2429 !CheckConfigVal<uint16_t>(conf, data.kMaxMultiplicity, "trigger.multiplicity-calib.", *it) ||
2430 !CheckConfigVal<uint16_t>(conf, data.kMaxWindow, "trigger.coincidence-window-physics.", *it) ||
2431 !CheckConfigVal<uint16_t>(conf, data.kMaxWindow, "trigger.coincidence-window-calib.", *it) ||
2432 !CheckConfigVal<uint16_t>(conf, data.kMaxDeadTime, "trigger.dead-time.", *it) ||
2433 !CheckConfigVal<uint16_t>(conf, data.kMaxDelayTrigger, "trigger.delay.", *it) ||
2434 !CheckConfigVal<uint16_t>(conf, data.kMaxDelayTimeMarker, "trigger.time-marker-delay.", *it) ||
2435 !CheckConfigVal<uint16_t>(conf, 0xffff, "ftu-report-interval.", *it) ||
2436 !CheckConfigVal<uint16_t>(conf, data.kMaxIntensity, "light-pulser.external.intensity.", *it) ||
2437 !CheckConfigVal<uint16_t>(conf, data.kMaxIntensity, "light-pulser.internal.intensity.", *it) ||
2438 !CheckConfigVal<uint16_t>(conf, data.kMaxDAC, "trigger.threshold.patch.", *it) ||
2439 !CheckConfigVal<uint16_t>(conf, data.kMaxDAC, "trigger.threshold.logic.", *it) ||
2440 0)
2441 return 2;
2442
2443 data.Enable(data.kTrigger, conf.GetDef<bool>("trigger.enable-trigger.", *it));
2444 data.Enable(data.kExt1, conf.GetDef<bool>("trigger.enable-external-1.", *it));
2445 data.Enable(data.kExt2, conf.GetDef<bool>("trigger.enable-external-2.", *it));
2446 data.Enable(data.kVeto, conf.GetDef<bool>("trigger.enable-veto.", *it));
2447 data.Enable(data.kClockConditioner, conf.GetDef<bool>("trigger.enable-clock-conditioner.", *it));
2448
2449 data.EnableLPint(data.kGroup1, conf.GetDef<bool>("light-pulser.internal.enable-group1.", *it));
2450 data.EnableLPint(data.kGroup2, conf.GetDef<bool>("light-pulser.internal.enable-group2.", *it));
2451 data.EnableLPext(data.kGroup1, conf.GetDef<bool>("light-pulser.external.enable-group1.", *it));
2452 data.EnableLPext(data.kGroup2, conf.GetDef<bool>("light-pulser.external.enable-group2.", *it));
2453
2454 // [ms] Interval between two artificial triggers (no matter which type) minimum 1ms, 10 bit
2455 data.fIntensityLPint = conf.GetDef<uint16_t>("light-pulser.internal.intensity.", *it);
2456 data.fIntensityLPext = conf.GetDef<uint16_t>("light-pulser.external.intensity.", *it);
2457 data.fTriggerInterval = conf.GetDef<uint16_t>("trigger.sequence.interval.", *it);
2458 data.fMultiplicityPhysics = conf.GetDef<uint16_t>("trigger.multiplicity-physics.", *it);
2459 data.fMultiplicityCalib = conf.GetDef<uint16_t>("trigger.multiplicity-calib.", *it);
2460 data.fWindowPhysics = conf.GetDef<uint16_t>("trigger.coincidence-window-physics.", *it); /// (4ns * x + 8ns)
2461 data.fWindowCalib = conf.GetDef<uint16_t>("trigger.coincidence-window-calib.", *it); /// (4ns * x + 8ns)
2462 data.fDelayTrigger = conf.GetDef<uint16_t>("trigger.delay.", *it); /// (4ns * x + 8ns)
2463 data.fDelayTimeMarker = conf.GetDef<uint16_t>("trigger.time-marker-delay.", *it); /// (4ns * x + 8ns)
2464 data.fDeadTime = conf.GetDef<uint16_t>("trigger.dead-time.", *it); /// (4ns * x + 8ns)
2465
2466 data.SetPrescaling(conf.GetDef<uint16_t>("ftu-report-interval.", *it));
2467
2468 const uint16_t seqped = conf.GetDef<uint16_t>("trigger.sequence.pedestal.", *it);
2469 const uint16_t seqint = conf.GetDef<uint16_t>("trigger.sequence.lp-int.", *it);
2470 const uint16_t seqext = conf.GetDef<uint16_t>("trigger.sequence.lp-ext.", *it);
2471
2472 data.SetSequence(seqped, seqint, seqext);
2473
2474 data.EnableAllFTU();
2475 data.EnableAllPixel();
2476
2477 const vector<uint16_t> pat1 = conf.Vec<uint16_t>("trigger.disable-patch.default");
2478 const vector<uint16_t> pat2 = conf.Vec<uint16_t>("trigger.disable-patch."+*it);
2479
2480 const vector<uint16_t> pix1 = conf.Vec<uint16_t>("trigger.disable-pixel.default");
2481 const vector<uint16_t> pix2 = conf.Vec<uint16_t>("trigger.disable-pixel."+*it);
2482
2483 const vector<uint16_t> ftu1 = conf.Vec<uint16_t>("disable-ftu.default");
2484 const vector<uint16_t> ftu2 = conf.Vec<uint16_t>("disable-ftu."+*it);
2485
2486 vector<uint16_t> ftu, pat, pix;
2487 ftu.insert(ftu.end(), ftu1.begin(), ftu1.end());
2488 ftu.insert(ftu.end(), ftu2.begin(), ftu2.end());
2489 pat.insert(pat.end(), pat1.begin(), pat1.end());
2490 pat.insert(pat.end(), pat2.begin(), pat2.end());
2491 pix.insert(pix.end(), pix1.begin(), pix1.end());
2492 pix.insert(pix.end(), pix2.begin(), pix2.end());
2493
2494 for (vector<uint16_t>::const_iterator ip=ftu.begin(); ip!=ftu.end(); ip++)
2495 {
2496 if (*ip>FTM::StaticData::kMaxPatchIdx)
2497 {
2498 ostringstream str;
2499 str << "disable-ftu.*=" << *ip << " exceeds allowed maximum of " << FTM::StaticData::kMaxPatchIdx << "!";
2500 T::Error(str);
2501 return 2;
2502 }
2503 data.DisableFTU(*ip);
2504 }
2505 for (vector<uint16_t>::const_iterator ip=pat.begin(); ip!=pat.end(); ip++)
2506 {
2507 if (*ip>FTM::StaticData::kMaxPatchIdx)
2508 {
2509 ostringstream str;
2510 str << "trigger.disable-patch.*=" << *ip << " exceeds allowed maximum of " << FTM::StaticData::kMaxPatchIdx << "!";
2511 T::Error(str);
2512 return 2;
2513 }
2514 data.EnablePatch(*ip, false);
2515 }
2516 for (vector<uint16_t>::const_iterator ip=pix.begin(); ip!=pix.end(); ip++)
2517 {
2518 if (*ip>FTM::StaticData::kMaxPixelIdx)
2519 {
2520 ostringstream str;
2521 str << "trigger.disable-pixel.*=" << *ip << " exceeds allowed maximum of " << FTM::StaticData::kMaxPixelIdx << "!";
2522 T::Error(str);
2523 return 2;
2524 }
2525 data.EnablePixel(*ip, false);
2526 }
2527
2528 const uint16_t th0 = conf.GetDef<uint16_t>("trigger.threshold.patch.", *it);
2529 const uint16_t th1 = conf.GetDef<uint16_t>("trigger.threshold.logic.", *it);
2530
2531 for (int i=0; i<40; i++)
2532 {
2533 data[i].fDAC[0] = th0;
2534 data[i].fDAC[1] = th0;
2535 data[i].fDAC[2] = th0;
2536 data[i].fDAC[3] = th0;
2537 data[i].fDAC[4] = th1;
2538 }
2539
2540 fConfigs[*it] = data;
2541
2542 // trigger.threshold.dac-0:
2543
2544 /*
2545 threshold-A data[n].fDAC[0] = val
2546 threshold-B data[n].fDAC[1] = val
2547 threshold-C data[n].fDAC[2] = val
2548 threshold-D data[n].fDAC[3] = val
2549 threshold-H data[n].fDAC[4] = val
2550 */
2551
2552 // kMaxDAC = 0xfff,
2553 }
2554
2555 // FIXME: Add a check about unsused configurations
2556
2557 // ---------- FOR TESTING PURPOSE ---------
2558
2559 // fFTM.SetDefaultSetup(conf.Get<string>("default-setup"));
2560 fConfigs["test"] = FTM::StaticData();
2561
2562 // ---------- Setup connection endpoint ---------
2563 SetEndpoint(conf.Get<string>("addr"));
2564
2565 return -1;
2566 }
2567};
2568
2569// ------------------------------------------------------------------------
2570
2571#include "Main.h"
2572
2573template<class T, class S, class R>
2574int RunShell(Configuration &conf)
2575{
2576 return Main::execute<T, StateMachineFTM<S, R>>(conf);
2577}
2578
2579void SetupConfiguration(Configuration &conf)
2580{
2581 po::options_description control("Control options");
2582 control.add_options()
2583 ("no-dim", po_bool(), "Disable dim services")
2584 ("addr,a", var<string>("localhost:5000"), "Network address of FTM")
2585 ("quiet,q", po_bool(), "Disable printing contents of all received messages (except dynamic data) in clear text.")
2586 ("hex-out", po_bool(), "Enable printing contents of all printed messages also as hex data.")
2587 ("dynamic-out", po_bool(), "Enable printing received dynamic data.")
2588// ("default-setup", var<string>(), "Binary file with static data loaded whenever a connection to the FTM was established.")
2589 ;
2590
2591 po::options_description freq("Sampling frequency setup");
2592 freq.add_options()
2593 ("clock-conditioner.frequency", vars<uint16_t>(), "Frequencies for which to setup the clock-conditioner (replace the * in the following options by this definition)")
2594 ("clock-conditioner.R0.*", var<Hex<uint32_t>>(), "Clock-conditioner R0")
2595 ("clock-conditioner.R1.*", var<Hex<uint32_t>>(), "Clock-conditioner R1")
2596 ("clock-conditioner.R8.*", var<Hex<uint32_t>>(), "Clock-conditioner R8")
2597 ("clock-conditioner.R9.*", var<Hex<uint32_t>>(), "Clock-conditioner R9")
2598 ("clock-conditioner.R11.*", var<Hex<uint32_t>>(), "Clock-conditioner R11")
2599 ("clock-conditioner.R13.*", var<Hex<uint32_t>>(), "Clock-conditioner R13")
2600 ("clock-conditioner.R14.*", var<Hex<uint32_t>>(), "Clock-conditioner R14")
2601 ("clock-conditioner.R15.*", var<Hex<uint32_t>>(), "Clock-conditioner R15");
2602
2603 po::options_description runtype("Run type configuration");
2604 runtype.add_options()
2605 ("run-type", vars<string>(), "Name of run-types (replace the * in the following configuration by the case-sensitive names defined here)")
2606 ("sampling-frequency.*", var<uint16_t>(), "Sampling frequency as defined in the clock-conditioner.frequency")
2607 ("trigger.enable-trigger.*", var<bool>(), "Enable trigger output of physics trigger")
2608 ("trigger.enable-external-1.*", var<bool>(), "Enable external trigger line 1")
2609 ("trigger.enable-external-2.*", var<bool>(), "Enable external trigger line 2")
2610 ("trigger.enable-veto.*", var<bool>(), "Enable veto line")
2611 ("trigger.enable-clock-conditioner.*", var<bool>(), "")
2612 ("trigger.sequence.interval.*", var<uint16_t>(), "Interval between two artifical triggers in units of n*4ns+8ns")
2613 ("trigger.sequence.pedestal.*", var<uint16_t>(), "Number of pedestal events in the sequence of artificial triggers")
2614 ("trigger.sequence.lp-int.*", var<uint16_t>(), "Number of LPint events in the sequence of artificial triggers")
2615 ("trigger.sequence.lp-ext.*", var<uint16_t>(), "Number of LPext events in the sequence of artificial triggers")
2616 ("trigger.multiplicity-physics.*", var<uint16_t>(), "Multiplicity for physics events (n out of 40)")
2617 ("trigger.multiplicity-calib.*", var<uint16_t>(), "Multiplicity for LPext events (n out of 40)")
2618 ("trigger.coincidence-window-physics.*", var<uint16_t>(), "Coincidence window for physics triggers in units of n*4ns+8ns")
2619 ("trigger.coincidence-window-calib.*", var<uint16_t>(), "Coincidence window for LPext triggers in units of n*4ns+8ns")
2620 ("trigger.dead-time.*", var<uint16_t>(), "Dead time after trigger in units of n*4ns+8ns")
2621 ("trigger.delay.*", var<uint16_t>(), "Delay of the trigger send to the FAD boards after a trigger in units of n*4ns+8ns")
2622 ("trigger.time-marker-delay.*", var<uint16_t>(), "Delay of the time-marker after a trigger in units of n*4ns+8ns")
2623 ("trigger.disable-pixel.*", vars<uint16_t>(), "")
2624 ("trigger.disable-patch.*", vars<uint16_t>(), "")
2625 ("trigger.threshold.patch.*", var<uint16_t>(), "")
2626 ("trigger.threshold.logic.*", var<uint16_t>(), "")
2627 ("ftu-report-interval.*", var<uint16_t>(), "")
2628 ("disable-ftu.*", var<uint16_t>(), "")
2629 ("light-pulser.external.enable-group1.*", var<bool>(), "Enable LED group 1 of external light pulser")
2630 ("light-pulser.external.enable-group2.*", var<bool>(), "Enable LED group 2 of external light pulser")
2631 ("light-pulser.internal.enable-group1.*", var<bool>(), "Enable LED group 1 of internal light pulser")
2632 ("light-pulser.internal.enable-group2.*", var<bool>(), "Enable LED group 2 of internal light pulser")
2633 ("light-pulser.external.intensity.*", var<uint16_t>(), "Intensity of external light pulser")
2634 ("light-pulser.internal.intensity.*", var<uint16_t>(), "Intensity of internal light pulser")
2635 ;
2636
2637 conf.AddOptions(control);
2638 conf.AddOptions(freq);
2639 conf.AddOptions(runtype);
2640}
2641
2642/*
2643 Extract usage clause(s) [if any] for SYNOPSIS.
2644 Translators: "Usage" and "or" here are patterns (regular expressions) which
2645 are used to match the usage synopsis in program output. An example from cp
2646 (GNU coreutils) which contains both strings:
2647 Usage: cp [OPTION]... [-T] SOURCE DEST
2648 or: cp [OPTION]... SOURCE... DIRECTORY
2649 or: cp [OPTION]... -t DIRECTORY SOURCE...
2650 */
2651void PrintUsage()
2652{
2653 cout <<
2654 "The ftmctrl controls the FTM (FACT Trigger Master) board.\n"
2655 "\n"
2656 "The default is that the program is started without user intercation. "
2657 "All actions are supposed to arrive as DimCommands. Using the -c "
2658 "option, a local shell can be initialized. With h or help a short "
2659 "help message about the usuage can be brought to the screen.\n"
2660 "\n"
2661 "Usage: ftmctrl [-c type] [OPTIONS]\n"
2662 " or: ftmctrl [OPTIONS]\n";
2663 cout << endl;
2664}
2665
2666void PrintHelp()
2667{
2668 Main::PrintHelp<StateMachineFTM<StateMachine, ConnectionFTM>>();
2669
2670 /* Additional help text which is printed after the configuration
2671 options goes here */
2672
2673 /*
2674 cout << "bla bla bla" << endl << endl;
2675 cout << endl;
2676 cout << "Environment:" << endl;
2677 cout << "environment" << endl;
2678 cout << endl;
2679 cout << "Examples:" << endl;
2680 cout << "test exam" << endl;
2681 cout << endl;
2682 cout << "Files:" << endl;
2683 cout << "files" << endl;
2684 cout << endl;
2685 */
2686}
2687
2688int main(int argc, const char* argv[])
2689{
2690 Configuration conf(argv[0]);
2691 conf.SetPrintUsage(PrintUsage);
2692 Main::SetupConfiguration(conf);
2693 SetupConfiguration(conf);
2694
2695 if (!conf.DoParse(argc, argv, PrintHelp))
2696 return 127;
2697
2698 //try
2699 {
2700 // No console access at all
2701 if (!conf.Has("console"))
2702 {
2703 if (conf.Get<bool>("no-dim"))
2704 return RunShell<LocalStream, StateMachine, ConnectionFTM>(conf);
2705 else
2706 return RunShell<LocalStream, StateMachineDim, ConnectionDimFTM>(conf);
2707 }
2708 // Cosole access w/ and w/o Dim
2709 if (conf.Get<bool>("no-dim"))
2710 {
2711 if (conf.Get<int>("console")==0)
2712 return RunShell<LocalShell, StateMachine, ConnectionFTM>(conf);
2713 else
2714 return RunShell<LocalConsole, StateMachine, ConnectionFTM>(conf);
2715 }
2716 else
2717 {
2718 if (conf.Get<int>("console")==0)
2719 return RunShell<LocalShell, StateMachineDim, ConnectionDimFTM>(conf);
2720 else
2721 return RunShell<LocalConsole, StateMachineDim, ConnectionDimFTM>(conf);
2722 }
2723 }
2724 /*catch (std::exception& e)
2725 {
2726 cerr << "Exception: " << e.what() << endl;
2727 return -1;
2728 }*/
2729
2730 return 0;
2731}
Note: See TracBrowser for help on using the repository browser.