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

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