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

Last change on this file since 10739 was 10735, checked in by tbretz, 14 years ago
Added DISABLE_PIXEL
File size: 53.5 KB
Line 
1#include <boost/bind.hpp>
2#include <boost/array.hpp>
3#if BOOST_VERSION < 104400
4#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 4))
5#undef BOOST_HAS_RVALUE_REFS
6#endif
7#endif
8#include <boost/thread.hpp>
9#include <boost/asio/error.hpp>
10#include <boost/asio/deadline_timer.hpp>
11
12#include "Dim.h"
13#include "Event.h"
14#include "Shell.h"
15#include "StateMachineDim.h"
16#include "Connection.h"
17#include "Configuration.h"
18#include "Timers.h"
19#include "Console.h"
20#include "Converter.h"
21
22#include "FACT.h"
23#include "tools.h"
24
25#include "LocalControl.h"
26#include "HeadersFTM.h"
27
28
29namespace ba = boost::asio;
30namespace bs = boost::system;
31
32using namespace std;
33
34// ------------------------------------------------------------------------
35
36class ConnectionFTM : public Connection
37{
38 vector<uint16_t> fBuffer;
39
40 bool fHasHeader;
41 int fState;
42
43 bool fIsVerbose;
44 bool fIsDynamicOut;
45 bool fIsHexOutput;
46
47// string fDefaultSetup;
48
49 // --verbose
50 // --hex-out
51 // --dynamic-out
52 // --load-file
53 // --leds
54 // --trigger-interval
55 // --physcis-coincidence
56 // --calib-coincidence
57 // --physcis-window
58 // --physcis-window
59 // --trigger-delay
60 // --time-marker-delay
61 // --dead-time
62 // --clock-conditioner-r0
63 // --clock-conditioner-r1
64 // --clock-conditioner-r8
65 // --clock-conditioner-r9
66 // --clock-conditioner-r11
67 // --clock-conditioner-r13
68 // --clock-conditioner-r14
69 // --clock-conditioner-r15
70 // ...
71
72protected:
73 map<uint16_t, int> fCounter;
74
75 FTM::Header fHeader;
76 FTM::FtuList fFtuList;
77 FTM::StaticData fStaticData;
78 FTM::DynamicData fDynamicData;
79 FTM::Error fError;
80
81 virtual void UpdateFirstHeader()
82 {
83 // FIXME: Message() ?
84 Out() << endl << kBold << "First header received:" << endl;
85 Out() << fHeader;
86 if (fIsHexOutput)
87 Out() << Converter::GetHex<uint16_t>(fHeader, 16) << endl;
88 }
89
90 virtual void UpdateHeader()
91 {
92 // emit service with trigger counter from header
93 if (!fIsVerbose)
94 return;
95
96 if (fHeader.fType==FTM::kDynamicData && !fIsDynamicOut)
97 return;
98
99 Out() << endl << kBold << "Header received:" << endl;
100 Out() << fHeader;
101 if (fIsHexOutput)
102 Out() << Converter::GetHex<uint16_t>(fHeader, 16) << endl;
103 }
104
105 virtual void UpdateFtuList()
106 {
107 if (!fIsVerbose)
108 return;
109
110 Out() << endl << kBold << "FtuList received:" << endl;
111 Out() << fFtuList;
112 if (fIsHexOutput)
113 Out() << Converter::GetHex<uint16_t>(fFtuList, 16) << endl;
114 }
115
116 virtual void UpdateStaticData()
117 {
118 if (!fIsVerbose)
119 return;
120
121 Out() << endl << kBold << "Static data received:" << endl;
122 Out() << fStaticData;
123 if (fIsHexOutput)
124 Out() << Converter::GetHex<uint16_t>(fStaticData, 16) << endl;
125 }
126
127 virtual void UpdateDynamicData()
128 {
129 if (!fIsDynamicOut)
130 return;
131
132 Out() << endl << kBold << "Dynamic data received:" << endl;
133 Out() << fDynamicData;
134 if (fIsHexOutput)
135 Out() << Converter::GetHex<uint16_t>(fDynamicData, 16) << endl;
136 }
137
138 virtual void UpdateError()
139 {
140 if (!fIsVerbose)
141 return;
142
143 Out() << endl << kRed << "Error received:" << endl;
144 Out() << fError;
145 if (fIsHexOutput)
146 Out() << Converter::GetHex<uint16_t>(fError, 16) << endl;
147 }
148
149 virtual void UpdateCounter()
150 {
151 if (!fIsVerbose)
152 return;
153
154 if (!fIsDynamicOut)
155 return;
156
157 Out() << "Received: ";
158 Out() << "H=" << fCounter[FTM::kHeader] << " ";
159 Out() << "S=" << fCounter[FTM::kStaticData] << " ";
160 Out() << "D=" << fCounter[FTM::kDynamicData] << " ";
161 Out() << "F=" << fCounter[FTM::kFtuList] << " ";
162 Out() << "E=" << fCounter[FTM::kErrorList] << " ";
163 Out() << "R=" << fCounter[FTM::kRegister] << endl;
164 }
165
166 bool CheckConsistency()
167 {
168 bool warn1 = false;
169 if (fStaticData.IsEnabled(FTM::StaticData::kPedestal) != (fStaticData.GetSequencePed() >0) ||
170 fStaticData.IsEnabled(FTM::StaticData::kLPint) != (fStaticData.GetSequenceLPint()>0) ||
171 fStaticData.IsEnabled(FTM::StaticData::kLPext) != (fStaticData.GetSequenceLPext()>0))
172 {
173 warn1 = true;
174 fStaticData.Enable(FTM::StaticData::kPedestal, fStaticData.GetSequencePed()>0);
175 fStaticData.Enable(FTM::StaticData::kLPint, fStaticData.GetSequenceLPint()>0);
176 fStaticData.Enable(FTM::StaticData::kLPext, fStaticData.GetSequenceLPext()>0);
177 }
178
179 bool warn2 = false;
180 const uint16_t ref = fStaticData[0].fPrescaling;
181 for (int i=1; i<40; i++)
182 {
183 if (fStaticData[i].fPrescaling != ref)
184 {
185 warn2 = true;
186 fStaticData[i].fPrescaling = ref;
187 }
188 }
189
190 if (warn1)
191 Warn("GeneralSettings not consistent with trigger sequence.");
192 if (warn2)
193 Warn("Prescaling not consistent for all boards.");
194
195 return !warn1 && !warn2;
196 }
197
198private:
199 void HandleReceivedData(const bs::error_code& err, size_t bytes_received, int /*type*/)
200 {
201 // Do not schedule a new read if the connection failed.
202 if (bytes_received==0 || err)
203 {
204 if (err==ba::error::eof)
205 Warn("Connection closed by remote host (FTM).");
206
207 // 107: Transport endpoint is not connected (bs::error_code(107, bs::system_category))
208 // 125: Operation canceled
209 if (err && err!=ba::error::eof && // Connection closed by remote host
210 err!=ba::error::basic_errors::not_connected && // Connection closed by remote host
211 err!=ba::error::basic_errors::operation_aborted) // Connection closed by us
212 {
213 stringstream str;
214 str << "Reading from " << URL() << ": " << err.message() << " (" << err << ")";// << endl;
215 Error(str);
216 }
217 PostClose(err!=ba::error::basic_errors::operation_aborted);
218 return;
219 }
220
221 // If we have not yet received a header we expect one now
222 // This could be moved to a HandleReceivedHeader function
223 if (!fHasHeader)
224 {
225 if (bytes_received!=sizeof(FTM::Header))
226 {
227 stringstream str;
228 str << "Excepted " << sizeof(FTM::Header) << " bytes (FTM::Header) but received " << bytes_received << ".";
229 Error(str);
230 PostClose(false);
231 return;
232 }
233
234 fHeader = fBuffer;
235
236 // Check the data integrity
237 if (fHeader.fDelimiter!=FTM::kDelimiterStart)
238 {
239 stringstream str;
240 str << "Invalid header received: start delimiter wrong, received " << hex << fHeader.fDelimiter << " expected " << FTM::kDelimiterStart << ".";
241 Error(str);
242 PostClose(false);
243 return;
244 }
245
246 fHasHeader = true;
247
248 // Convert FTM state into FtmCtrl state
249 switch (fHeader.fState)
250 {
251 case FTM::kFtmIdle:
252 case FTM::kFtmConfig:
253 fState = FTM::kIdle;
254 break;
255
256 case FTM::kFtmCalib:
257 case FTM::kFtmRunning:
258 fState = FTM::kTakingData;
259 break;
260 }
261
262 if (++fCounter[FTM::kHeader]==1)
263 UpdateFirstHeader();
264
265 UpdateCounter();
266 UpdateHeader();
267
268 // Start reading of data
269 switch (fHeader.fType)
270 {
271 case FTM::kStaticData:
272 case FTM::kDynamicData:
273 case FTM::kFtuList:
274 case FTM::kRegister:
275 case FTM::kErrorList:
276 // This is not very efficient because the space is reallocated
277 // maybe we can check if the capacity of the std::vector
278 // is ever decreased. If not, everythign is fine.
279 fBuffer.resize(fHeader.fDataSize);
280 AsyncRead(ba::buffer(fBuffer));
281 AsyncWait(fInTimeout, 50, &Connection::HandleReadTimeout);
282 return;
283
284 default:
285 stringstream str;
286 str << "Unknonw type " << fHeader.fType << " in received header." << endl;
287 Error(str);
288 PostClose(false);
289 return;
290 }
291
292 return;
293 }
294
295 // Check the data integrity (check end delimiter)
296 if (ntohs(fBuffer.back())!=FTM::kDelimiterEnd)
297 {
298 stringstream str;
299 str << "Invalid data received: end delimiter wrong, received ";
300 str << hex << ntohs(fBuffer.back()) << " expected " << FTM::kDelimiterEnd << ".";
301 Error(str);
302 PostClose(false);
303 return;
304 }
305
306 // Remove end delimiter
307 fBuffer.pop_back();
308
309 try
310 {
311 // If we have already received a header this is the data now
312 // This could be moved to a HandleReceivedData function
313
314 fCounter[fHeader.fType]++;
315 UpdateCounter();
316
317 switch (fHeader.fType)
318 {
319 case FTM::kFtuList:
320 fFtuList = fBuffer;
321 UpdateFtuList();
322 break;
323
324 case FTM::kStaticData:
325 fStaticData = fBuffer;
326
327 if (fCounter[FTM::kStaticData]==1)
328 if (!CheckConsistency())
329 {
330 CmdSendStatDat();
331 break;
332 }
333
334 UpdateStaticData();
335 break;
336
337 case FTM::kDynamicData:
338 fDynamicData = fBuffer;
339 UpdateDynamicData();
340 break;
341
342 case FTM::kRegister:
343 if (fIsVerbose)
344 {
345 Out() << endl << kBold << "Register received: " << endl;
346 Out() << "Addr: " << ntohs(fBuffer[0]) << endl;
347 Out() << "Value: " << ntohs(fBuffer[1]) << endl;
348 }
349 break;
350
351 case FTM::kErrorList:
352 fError = fBuffer;
353 UpdateError();
354 break;
355
356 default:
357 stringstream str;
358 str << "Unknonw type " << fHeader.fType << " in header." << endl;
359 Error(str);
360 PostClose(false);
361 return;
362 }
363 }
364 catch (const logic_error &e)
365 {
366 stringstream str;
367 str << "Exception converting buffer into data structure: " << e.what();
368 Error(str);
369 PostClose(false);
370 return;
371 }
372
373 fInTimeout.cancel();
374
375 fHeader.clear();
376 fHasHeader = false;
377 fBuffer.resize(sizeof(FTM::Header)/2);
378 AsyncRead(ba::buffer(fBuffer));
379 }
380
381 // This is called when a connection was established
382 void ConnectionEstablished()
383 {
384 fState = FTM::kConnected;
385 fCounter.clear();
386
387 fHeader.clear();
388 fHasHeader = false;
389 fBuffer.resize(sizeof(FTM::Header)/2);
390 AsyncRead(ba::buffer(fBuffer));
391
392// if (!fDefaultSetup.empty())
393// LoadStaticData(fDefaultSetup);
394
395 // Get a header and configdata!
396 CmdReqStatDat();
397
398 // get the DNA of the FTUs
399 CmdPing();
400 }
401
402 void HandleReadTimeout(const bs::error_code &error)
403 {
404 if (error && error!=ba::error::basic_errors::operation_aborted)
405 {
406 stringstream str;
407 str << "Read timeout of " << URL() << ": " << error.message() << " (" << error << ")";// << endl;
408 Error(str);
409
410 PostClose();
411 return;
412
413 }
414
415 if (!is_open())
416 {
417 // For example: Here we could schedule a new accept if we
418 // would not want to allow two connections at the same time.
419 return;
420 }
421
422 // Check whether the deadline has passed. We compare the deadline
423 // against the current time since a new asynchronous operation
424 // may have moved the deadline before this actor had a chance
425 // to run.
426 if (fInTimeout.expires_at() > ba::deadline_timer::traits_type::now())
427 return;
428
429 Error("Timeout reading data from "+URL());
430
431 PostClose();
432 }
433
434
435 template<size_t N>
436 void PostCmd(boost::array<uint16_t, N> dat, uint16_t u1=0, uint16_t u2=0, uint16_t u3=0, uint16_t u4=0)
437 {
438 boost::array<uint16_t, 5> cmd = {{ '@', u1, u2, u3, u4 }};
439
440 stringstream msg;
441 msg << "Sending command:" << hex;
442 msg << " 0x" << setw(4) << setfill('0') << cmd[0];
443 msg << " 0x" << setw(4) << setfill('0') << u1;
444 msg << " 0x" << setw(4) << setfill('0') << u2;
445 msg << " 0x" << setw(4) << setfill('0') << u3;
446 msg << " 0x" << setw(4) << setfill('0') << u4;
447 msg << " (+" << dec << dat.size() << " words)";
448 Message(msg);
449
450 vector<uint16_t> out(cmd.size()+dat.size());
451
452 transform(cmd.begin(), cmd.end(), out.begin(), htons);
453 transform(dat.begin(), dat.end(), out.begin()+cmd.size(), htons);
454
455 PostMessage(out);
456 }
457
458 void PostCmd(vector<uint16_t> dat, uint16_t u1=0, uint16_t u2=0, uint16_t u3=0, uint16_t u4=0)
459 {
460 boost::array<uint16_t, 5> cmd = {{ '@', u1, u2, u3, u4 }};
461
462 stringstream msg;
463 msg << "Sending command:" << hex;
464 msg << " 0x" << setw(4) << setfill('0') << cmd[0];
465 msg << " 0x" << setw(4) << setfill('0') << u1;
466 msg << " 0x" << setw(4) << setfill('0') << u2;
467 msg << " 0x" << setw(4) << setfill('0') << u3;
468 msg << " 0x" << setw(4) << setfill('0') << u4;
469 msg << " (+" << dec << dat.size() << " words)";
470 Message(msg);
471
472 vector<uint16_t> out(cmd.size()+dat.size());
473
474 transform(cmd.begin(), cmd.end(), out.begin(), htons);
475 copy(dat.begin(), dat.end(), out.begin()+cmd.size());
476
477 PostMessage(out);
478 }
479
480 void PostCmd(uint16_t u1=0, uint16_t u2=0, uint16_t u3=0, uint16_t u4=0)
481 {
482 PostCmd(boost::array<uint16_t, 0>(), u1, u2, u3, u4);
483 }
484public:
485
486 static const uint16_t kMaxAddr;
487
488public:
489 ConnectionFTM(ba::io_service& ioservice, MessageImp &imp) : Connection(ioservice, imp()),
490 fState(0), fIsVerbose(true), fIsDynamicOut(true), fIsHexOutput(true)
491 {
492 SetLogStream(&imp);
493 }
494
495 void CmdToggleLed()
496 {
497 PostCmd(FTM::kCmdToggleLed);
498 }
499
500 void CmdPing()
501 {
502 PostCmd(FTM::kCmdPing);
503 }
504
505 void CmdReqDynDat()
506 {
507 PostCmd(FTM::kCmdRead, FTM::kCmdDynamicData);
508 }
509
510 void CmdReqStatDat()
511 {
512 PostCmd(FTM::kCmdRead, FTM::kCmdStaticData);
513 }
514
515 void CmdSendStatDat()
516 {
517 PostCmd(fStaticData.HtoN(), FTM::kCmdWrite, FTM::kCmdStaticData);
518
519 // Request the changed configuration to ensure the
520 // change is distributed in the network
521 CmdReqStatDat();
522 }
523
524 void CmdStartRun()
525 {
526 PostCmd(FTM::kCmdStartRun, FTM::kStartRun);
527
528 // Update state information by requesting a new header
529 CmdGetRegister(0);
530 }
531
532 void CmdStopRun()
533 {
534 PostCmd(FTM::kCmdStopRun);
535
536 // Update state information by requesting a new header
537 CmdGetRegister(0);
538 }
539
540 void CmdTakeNevents(uint32_t n)
541 {
542 const boost::array<uint16_t, 2> data = {{ uint16_t(n>>16), uint16_t(n&0xffff) }};
543 PostCmd(data, FTM::kCmdStartRun, FTM::kTakeNevents);
544
545 // Update state information by requesting a new header
546 CmdGetRegister(0);
547 }
548
549 bool CmdSetRegister(uint16_t addr, uint16_t val)
550 {
551 if (addr>kMaxAddr)
552 return false;
553
554 const boost::array<uint16_t, 2> data = {{ addr, val }};
555 PostCmd(data, FTM::kCmdWrite, FTM::kCmdRegister);
556
557 // Request the changed configuration to ensure the
558 // change is distributed in the network
559 CmdReqStatDat();
560
561 return true;
562 }
563
564 bool CmdGetRegister(uint16_t addr)
565 {
566 if (addr>kMaxAddr)
567 return false;
568
569 const boost::array<uint16_t, 1> data = {{ addr }};
570 PostCmd(data, FTM::kCmdRead, FTM::kCmdRegister);
571
572 return true;
573 }
574
575 bool CmdDisableReports(bool b)
576 {
577 PostCmd(FTM::kCmdDisableReports, b ? uint16_t(0) : uint16_t(1));
578 return true;
579 }
580
581 void SetVerbose(bool b)
582 {
583 fIsVerbose = b;
584 }
585
586 void SetHexOutput(bool b)
587 {
588 fIsHexOutput = b;
589 }
590
591 void SetDynamicOut(bool b)
592 {
593 fIsDynamicOut = b;
594 }
595/*
596 void SetDefaultSetup(const string &file)
597 {
598 fDefaultSetup = file;
599 }
600*/
601 bool LoadStaticData(string name)
602 {
603 if (name.rfind(".bin")!=name.length()-5)
604 name += ".bin";
605
606 ifstream fin(name);
607 if (!fin)
608 return false;
609
610 FTM::StaticData data;
611
612 fin.read(reinterpret_cast<char*>(&data), sizeof(FTM::StaticData));
613
614 if (fin.gcount()<streamsize(sizeof(FTM::StaticData)))
615 return false;
616
617 if (fin.fail() || fin.eof())
618 return false;
619
620 if (fin.peek()!=-1)
621 return false;
622
623 fStaticData = data;
624
625 CmdSendStatDat();
626
627 return true;
628 }
629
630 bool SaveStaticData(string name) const
631 {
632 if (name.rfind(".bin")!=name.length()-5)
633 name += ".bin";
634
635 ofstream fout(name);
636 if (!fout)
637 return false;
638
639 fout.write(reinterpret_cast<const char*>(&fStaticData), sizeof(FTM::StaticData));
640
641 return !fout.bad();
642 }
643
644 bool SetThreshold(int32_t patch, int32_t value)
645 {
646 if (patch>159)
647 return false;
648
649 if (value<0 || value>0xffff)
650 return false;
651
652 if (patch<0)
653 {
654 bool ident = true;
655 for (int i=0; i<160; i++)
656 if (fStaticData[i/4].fDAC[patch%4] != value)
657 {
658 ident = false;
659 break;
660 }
661
662 if (ident)
663 return true;
664
665 for (int i=0; i<160; i++)
666 fStaticData[i/4].fDAC[i%4] = value;
667 }
668 else
669 {
670 if (fStaticData[patch/4].fDAC[patch%4] == value)
671 return true;
672
673 fStaticData[patch/4].fDAC[patch%4] = value;
674 }
675
676 // Maybe move to a "COMMIT" command?
677 CmdSendStatDat();
678
679 return true;
680 }
681
682 bool SetPrescaling(uint32_t value)
683 {
684 if (value>0xffff)
685 return false;
686
687 bool ident = true;
688 for (int i=0; i<40; i++)
689 if (fStaticData[i].fPrescaling != value)
690 {
691 ident = false;
692 break;
693 }
694
695 if (ident)
696 return true;
697
698 for (int i=0; i<40; i++)
699 fStaticData[i].fPrescaling = value;
700
701 // Maybe move to a "COMMIT" command?
702 CmdSendStatDat();
703
704 return true;
705 }
706
707 bool EnableFTU(int32_t board, bool enable)
708 {
709 if (board>39)
710 return false;
711
712 if (board<0)
713 {
714 if (enable)
715 fStaticData.EnableAllFTU();
716 else
717 fStaticData.DisableAllFTU();
718 }
719 else
720 {
721 if (enable)
722 fStaticData.EnableFTU(board);
723 else
724 fStaticData.DisableFTU(board);
725
726 }
727
728 // Maybe move to a "COMMIT" command?
729 CmdSendStatDat();
730
731 return true;
732 }
733
734 bool ToggleFTU(uint32_t board)
735 {
736 if (board>39)
737 return false;
738
739 fStaticData.ToggleFTU(board);
740
741 // Maybe move to a "COMMIT" command?
742 CmdSendStatDat();
743
744 return true;
745 }
746
747 bool SetVal(uint16_t *dest, uint32_t val, uint32_t max)
748 {
749 if (val>max)
750 return false;
751
752 if (*dest==val)
753 return true;
754
755 *dest = val;
756
757 CmdSendStatDat();
758
759 return true;
760 }
761
762 bool SetTriggerInterval(uint32_t val)
763 {
764 return SetVal(&fStaticData.fTriggerInterval, val,
765 FTM::StaticData::kMaxTriggerInterval);
766 }
767
768 bool SetTriggerDelay(uint32_t val)
769 {
770 return SetVal(&fStaticData.fDelayTrigger, val,
771 FTM::StaticData::kMaxDelayTrigger);
772 }
773
774 bool SetTimeMarkerDelay(uint32_t val)
775 {
776 return SetVal(&fStaticData.fDelayTimeMarker, val,
777 FTM::StaticData::kMaxDelayTimeMarker);
778 }
779
780 bool SetDeadTime(uint32_t val)
781 {
782 return SetVal(&fStaticData.fDeadTime, val,
783 FTM::StaticData::kMaxDeadTime);
784 }
785
786 void Enable(FTM::StaticData::GeneralSettings type, bool enable)
787 {
788 fStaticData.Enable(type, enable);
789 }
790
791 bool SetTriggerSeq(const uint8_t d[3])
792 {
793 const uint16_t oldset = fStaticData.fGeneralSettings;
794 const uint16_t oldseq = fStaticData.fTriggerSequence;
795
796 if (d[0]>FTM::StaticData::kMaxSequence ||
797 d[1]>FTM::StaticData::kMaxSequence ||
798 d[2]>FTM::StaticData::kMaxSequence)
799 return false;
800
801 fStaticData.Enable(FTM::StaticData::kPedestal, d[0]>0);
802 fStaticData.Enable(FTM::StaticData::kLPext, d[1]>0);
803 fStaticData.Enable(FTM::StaticData::kLPint, d[2]>0);
804
805 fStaticData.fTriggerSequence =
806 (uint16_t(d[0])<<10) | (uint16_t(d[2])<<5) | uint16_t(d[1]);
807
808 if (oldseq!=fStaticData.fTriggerSequence || oldset!=fStaticData.fGeneralSettings)
809 CmdSendStatDat();
810
811 return true;
812 }
813
814 bool SetTriggerMultiplicity(uint16_t n)
815 {
816 if (n==0 || n>FTM::StaticData::kMaxMultiplicity)
817 return false;
818
819 if (n==fStaticData.fMultiplicityPhysics)
820 return true;
821
822 fStaticData.fMultiplicityPhysics = n;
823
824 CmdSendStatDat();
825
826 return true;
827 }
828
829 bool SetTriggerWindow(uint16_t win)
830 {
831 if (win>FTM::StaticData::kMaxWindow)
832 return false;
833
834 if (win==fStaticData.fWindowPhysics)
835 return true;
836
837 fStaticData.fWindowPhysics = win;
838
839 CmdSendStatDat();
840
841 return true;
842 }
843
844 bool SetCalibMultiplicity(uint16_t n)
845 {
846 if (n==0 || n>FTM::StaticData::kMaxMultiplicity)
847 return false;
848
849 if (n==fStaticData.fMultiplicityCalib)
850 return true;
851
852 fStaticData.fMultiplicityCalib = n;
853
854 CmdSendStatDat();
855
856 return true;
857 }
858
859 bool SetCalibWindow(uint16_t win)
860 {
861 if (win>FTM::StaticData::kMaxWindow)
862 return false;
863
864 if (win==fStaticData.fWindowCalib)
865 return true;
866
867 fStaticData.fWindowCalib = win;
868
869 CmdSendStatDat();
870
871 return true;
872 }
873
874 bool DisablePixel(uint16_t idx, bool disable)
875 {
876 if (idx>FTM::StaticData::kMaxPixelIdx)
877 return false;
878
879 fStaticData.EnablePixel(idx, !disable);
880
881 CmdSendStatDat();
882
883 return true;
884 }
885
886 int GetState() const { return IsConnected() ? fState : (int)FTM::kDisconnected; }
887};
888
889const uint16_t ConnectionFTM::kMaxAddr = 0xfff;
890
891// ------------------------------------------------------------------------
892
893#include "DimDescriptionService.h"
894
895class ConnectionDimFTM : public ConnectionFTM
896{
897private:
898
899 DimDescribedService fDimPassport;
900 DimDescribedService fDimTriggerCounter;
901 DimDescribedService fDimError;
902 DimDescribedService fDimFtuList;
903 DimDescribedService fDimStaticData;
904 DimDescribedService fDimDynamicData;
905 DimDescribedService fDimCounter;
906
907 template<class T>
908 void Update(DimDescribedService &svc, const T &data) const
909 {
910 //cout << "Update: " << svc.getName() << " (" << sizeof(T) << ")" << endl;
911 svc.setData(const_cast<T*>(&data), sizeof(T));
912 svc.updateService();
913 }
914
915 void UpdateFirstHeader()
916 {
917 ConnectionFTM::UpdateFirstHeader();
918
919 const FTM::DimPassport data(fHeader);
920 Update(fDimPassport, data);
921 }
922
923 void UpdateHeader()
924 {
925 ConnectionFTM::UpdateHeader();
926
927 const FTM::DimTriggerCounter data(fHeader);
928 Update(fDimTriggerCounter, data);
929 }
930
931 void UpdateFtuList()
932 {
933 ConnectionFTM::UpdateFtuList();
934
935 const FTM::DimFtuList data(fHeader, fFtuList);
936 Update(fDimFtuList, data);
937 }
938
939 void UpdateStaticData()
940 {
941 ConnectionFTM::UpdateStaticData();
942
943 const FTM::DimStaticData data(fHeader, fStaticData);
944 Update(fDimStaticData, data);
945 }
946
947 void UpdateDynamicData()
948 {
949 ConnectionFTM::UpdateDynamicData();
950
951 const FTM::DimDynamicData data(fHeader, fDynamicData);
952 Update(fDimDynamicData, data);
953 }
954
955 void UpdateError()
956 {
957 ConnectionFTM::UpdateError();
958
959 const FTM::DimError data(fHeader, fError);
960 Update(fDimError, data);
961 }
962
963 void UpdateCounter()
964 {
965 ConnectionFTM::UpdateCounter();
966
967 const uint32_t counter[6] =
968 {
969 fCounter[FTM::kHeader],
970 fCounter[FTM::kStaticData],
971 fCounter[FTM::kDynamicData],
972 fCounter[FTM::kFtuList],
973 fCounter[FTM::kErrorList],
974 fCounter[FTM::kRegister],
975 };
976
977 Update(fDimCounter, counter);
978 }
979
980public:
981 ConnectionDimFTM(ba::io_service& ioservice, MessageImp &imp) :
982 ConnectionFTM(ioservice, imp),
983 fDimPassport ("FTM_CONTROL/PASSPORT", "X:1;S:1", ""),
984 fDimTriggerCounter("FTM_CONTROL/TRIGGER_COUNTER", "X:1;I:1", ""),
985 fDimError ("FTM_CONTROL/ERROR", "X:1;S:1;S:28", ""),
986 fDimFtuList ("FTM_CONTROL/FTU_LIST", "X:1;X:1;S:1;C:4;X:40;C:40;C:40", ""),
987 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;S:8;S:90;S:160;S:40;S:40", ""),
988 fDimDynamicData ("FTM_CONTROL/DYNAMIC_DATA", "X:1;X:1;F:4;I:160;I:40;S:40;S:40", ""),
989 fDimCounter ("FTM_CONTROL/COUNTER", "I:6", "")
990 {
991 }
992
993 // 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
994};
995
996// ------------------------------------------------------------------------
997
998template <class T, class S>
999class StateMachineFTM : public T, public ba::io_service, public ba::io_service::work
1000{
1001 int Wrap(boost::function<void()> f)
1002 {
1003 f();
1004 return T::GetCurrentState();
1005 }
1006
1007 boost::function<int(const EventImp &)> Wrapper(boost::function<void()> func)
1008 {
1009 return boost::bind(&StateMachineFTM::Wrap, this, func);
1010 }
1011
1012private:
1013 S fFTM;
1014
1015 enum states_t
1016 {
1017 kStateDisconnected = FTM::kDisconnected,
1018 kStateConnected = FTM::kConnected,
1019 kStateIdle = FTM::kIdle,
1020 kStateTakingData = FTM::kTakingData,
1021
1022 kCmdTest
1023 };
1024
1025 bool CheckEventSize(size_t has, const char *name, size_t size)
1026 {
1027 if (has==size)
1028 return true;
1029
1030 stringstream msg;
1031 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
1032 T::Fatal(msg);
1033 return false;
1034 }
1035
1036 int SetRegister(const EventImp &evt)
1037 {
1038 if (!CheckEventSize(evt.GetSize(), "SetRegister", 8))
1039 return T::kSM_FatalError;
1040
1041 const unsigned int *dat = reinterpret_cast<const unsigned int*>(evt.GetData());
1042
1043 if (dat[1]>uint16_t(-1))
1044 {
1045 stringstream msg;
1046 msg << hex << "Value " << dat[1] << " out of range.";
1047 T::Error(msg);
1048 return T::GetCurrentState();
1049 }
1050
1051
1052 if (dat[0]>uint16_t(-1) || !fFTM.CmdSetRegister(dat[0], dat[1]))
1053 {
1054 stringstream msg;
1055 msg << hex << "Address " << dat[0] << " out of range.";
1056 T::Error(msg);
1057 }
1058
1059 return T::GetCurrentState();
1060 }
1061
1062 int GetRegister(const EventImp &evt)
1063 {
1064 if (!CheckEventSize(evt.GetSize(), "GetRegister", 4))
1065 return T::kSM_FatalError;
1066
1067 const unsigned int addr = evt.GetInt();
1068 if (addr>uint16_t(-1) || !fFTM.CmdGetRegister(addr))
1069 {
1070 stringstream msg;
1071 msg << hex << "Address " << addr << " out of range.";
1072 T::Error(msg);
1073 }
1074
1075 return T::GetCurrentState();
1076 }
1077
1078 int TakeNevents(const EventImp &evt)
1079 {
1080 if (!CheckEventSize(evt.GetSize(), "TakeNevents", 4))
1081 return T::kSM_FatalError;
1082
1083 const unsigned int dat = evt.GetUInt();
1084
1085 /*
1086 if (dat[1]>uint32_t(-1))
1087 {
1088 stringstream msg;
1089 msg << hex << "Value " << dat[1] << " out of range.";
1090 T::Error(msg);
1091 return T::GetCurrentState();
1092 }*/
1093
1094 fFTM.CmdTakeNevents(dat);
1095
1096 return T::GetCurrentState();
1097 }
1098
1099 int DisableReports(const EventImp &evt)
1100 {
1101 if (!CheckEventSize(evt.GetSize(), "DisableReports", 1))
1102 return T::kSM_FatalError;
1103
1104 fFTM.CmdDisableReports(evt.GetText()[0]!=0);
1105
1106 return T::GetCurrentState();
1107 }
1108
1109 int SetVerbosity(const EventImp &evt)
1110 {
1111 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
1112 return T::kSM_FatalError;
1113
1114 fFTM.SetVerbose(evt.GetText()[0]!=0);
1115
1116 return T::GetCurrentState();
1117 }
1118
1119 int SetHexOutput(const EventImp &evt)
1120 {
1121 if (!CheckEventSize(evt.GetSize(), "SetHexOutput", 1))
1122 return T::kSM_FatalError;
1123
1124 fFTM.SetHexOutput(evt.GetText()[0]!=0);
1125
1126 return T::GetCurrentState();
1127 }
1128
1129 int SetDynamicOut(const EventImp &evt)
1130 {
1131 if (!CheckEventSize(evt.GetSize(), "SetDynamicOut", 1))
1132 return T::kSM_FatalError;
1133
1134 fFTM.SetDynamicOut(evt.GetText()[0]!=0);
1135
1136 return T::GetCurrentState();
1137 }
1138
1139 int LoadStaticData(const EventImp &evt)
1140 {
1141 if (fFTM.LoadStaticData(evt.GetString()))
1142 return T::GetCurrentState();
1143
1144 stringstream msg;
1145 msg << "Loading static data from file '" << evt.GetString() << "' failed ";
1146
1147 if (errno)
1148 msg << "(" << strerror(errno) << ")";
1149 else
1150 msg << "(wrong size, expected " << sizeof(FTM::StaticData) << " bytes)";
1151
1152 T::Warn(msg);
1153
1154 return T::GetCurrentState();
1155 }
1156
1157 int SaveStaticData(const EventImp &evt)
1158 {
1159 if (fFTM.SaveStaticData(evt.GetString()))
1160 return T::GetCurrentState();
1161
1162 stringstream msg;
1163 msg << "Writing static data to file '" << evt.GetString() << "' failed ";
1164 msg << "(" << strerror(errno) << ")";
1165
1166 T::Warn(msg);
1167
1168 return T::GetCurrentState();
1169 }
1170
1171 int SetThreshold(const EventImp &evt)
1172 {
1173 if (!CheckEventSize(evt.GetSize(), "SetThreshold", 8))
1174 return T::kSM_FatalError;
1175
1176 const int32_t *data = reinterpret_cast<const int32_t*>(evt.GetData());
1177
1178 if (!fFTM.SetThreshold(data[0], data[1]))
1179 T::Warn("SetThreshold - Maximum allowed patch number 159, valid value range 0-0xffff");
1180
1181 return T::GetCurrentState();
1182 }
1183
1184 int EnableFTU(const EventImp &evt)
1185 {
1186 if (!CheckEventSize(evt.GetSize(), "EnableFTU", 5))
1187 return T::kSM_FatalError;
1188
1189 const int32_t &board = *reinterpret_cast<const int32_t*>(evt.GetText());
1190 const int8_t &enable = *reinterpret_cast<const int8_t*>(evt.GetText()+4);
1191
1192 if (!fFTM.EnableFTU(board, enable))
1193 T::Warn("EnableFTU - Board number must be <40.");
1194
1195 return T::GetCurrentState();
1196 }
1197
1198 int ToggleFTU(const EventImp &evt)
1199 {
1200 if (!CheckEventSize(evt.GetSize(), "ToggleFTU", 4))
1201 return T::kSM_FatalError;
1202
1203 if (!fFTM.ToggleFTU(evt.GetInt()))
1204 T::Warn("ToggleFTU - Allowed range of boards 0-39.");
1205
1206 return T::GetCurrentState();
1207 }
1208
1209 int SetTriggerInterval(const EventImp &evt)
1210 {
1211 if (!CheckEventSize(evt.GetSize(), "SetTriggerInterval", 4))
1212 return T::kSM_FatalError;
1213
1214 if (!fFTM.SetTriggerInterval(evt.GetInt()))
1215 T::Warn("SetTriggerInterval - Value out of range.");
1216
1217 return T::GetCurrentState();
1218 }
1219
1220 int SetTriggerDelay(const EventImp &evt)
1221 {
1222 if (!CheckEventSize(evt.GetSize(), "SetTriggerDelay", 4))
1223 return T::kSM_FatalError;
1224
1225 if (!fFTM.SetTriggerDelay(evt.GetInt()))
1226 T::Warn("SetTriggerDealy - Value out of range.");
1227
1228 return T::GetCurrentState();
1229 }
1230
1231 int SetTimeMarkerDelay(const EventImp &evt)
1232 {
1233 if (!CheckEventSize(evt.GetSize(), "SetTimeMarkerDelay", 4))
1234 return T::kSM_FatalError;
1235
1236 if (!fFTM.SetTimeMarkerDelay(evt.GetInt()))
1237 T::Warn("SetTimeMarkerDelay - Value out of range.");
1238
1239 return T::GetCurrentState();
1240 }
1241
1242 int SetPrescaling(const EventImp &evt)
1243 {
1244 if (!CheckEventSize(evt.GetSize(), "SetPrescaling", 4))
1245 return T::kSM_FatalError;
1246
1247 if (!fFTM.SetPrescaling(evt.GetInt()-1))
1248 T::Warn("SetPrescaling - Value out of range.");
1249
1250 return T::GetCurrentState();
1251 }
1252
1253 int SetTriggerSeq(const EventImp &evt)
1254 {
1255 if (!CheckEventSize(evt.GetSize(), "SetTriggerSeq", 3))
1256 return T::kSM_FatalError;
1257
1258 const uint8_t *data = reinterpret_cast<const uint8_t*>(evt.GetData());
1259
1260 if (!fFTM.SetTriggerSeq(data))
1261 T::Warn("SetTriggerSeq - Value out of range.");
1262
1263 return T::GetCurrentState();
1264 }
1265
1266 int SetDeadTime(const EventImp &evt)
1267 {
1268 if (!CheckEventSize(evt.GetSize(), "SetDeadTime", 4))
1269 return T::kSM_FatalError;
1270
1271 if (!fFTM.SetDeadTime(evt.GetInt()))
1272 T::Warn("SetDeadTime - Value out of range.");
1273
1274 return T::GetCurrentState();
1275 }
1276
1277 int SetTriggerMultiplicity(const EventImp &evt)
1278 {
1279 if (!CheckEventSize(evt.GetSize(), "SetTriggerMultiplicity", 2))
1280 return T::kSM_FatalError;
1281
1282 if (!fFTM.SetTriggerMultiplicity(evt.GetUShort()))
1283 T::Warn("SetTriggerMultiplicity - Value out of range.");
1284
1285 return T::GetCurrentState();
1286 }
1287
1288 int SetCalibMultiplicity(const EventImp &evt)
1289 {
1290 if (!CheckEventSize(evt.GetSize(), "SetCalibMultiplicity", 2))
1291 return T::kSM_FatalError;
1292
1293 if (!fFTM.SetCalibMultiplicity(evt.GetUShort()))
1294 T::Warn("SetCalibMultiplicity - Value out of range.");
1295
1296 return T::GetCurrentState();
1297 }
1298
1299 int SetTriggerWindow(const EventImp &evt)
1300 {
1301 if (!CheckEventSize(evt.GetSize(), "SetTriggerWindow", 2))
1302 return T::kSM_FatalError;
1303
1304 if (!fFTM.SetTriggerWindow(evt.GetUShort()))
1305 T::Warn("SetTriggerWindow - Value out of range.");
1306
1307 return T::GetCurrentState();
1308 }
1309
1310 int SetCalibWindow(const EventImp &evt)
1311 {
1312 if (!CheckEventSize(evt.GetSize(), "SetCalibWindow", 2))
1313 return T::kSM_FatalError;
1314
1315 if (!fFTM.SetCalibWindow(evt.GetUShort()))
1316 T::Warn("SetCalibWindow - Value out of range.");
1317
1318 return T::GetCurrentState();
1319 }
1320
1321
1322 int Enable(const EventImp &evt, FTM::StaticData::GeneralSettings type)
1323 {
1324 if (!CheckEventSize(evt.GetSize(), "Enable", 1))
1325 return T::kSM_FatalError;
1326
1327 fFTM.Enable(type, evt.GetText()[0]!=0);
1328
1329 return T::GetCurrentState();
1330 }
1331
1332 int DisablePixel(const EventImp &evt)
1333 {
1334 if (!CheckEventSize(evt.GetSize(), "DisablePixel", 3))
1335 return T::kSM_FatalError;
1336
1337 fFTM.DisablePixel(evt.GetUShort(), evt.GetText()[2]!=0);
1338
1339 return T::GetCurrentState();
1340 }
1341
1342 int Disconnect()
1343 {
1344 // Close all connections
1345 fFTM.PostClose(false);
1346
1347 /*
1348 // Now wait until all connection have been closed and
1349 // all pending handlers have been processed
1350 poll();
1351 */
1352
1353 return T::GetCurrentState();
1354 }
1355
1356 int Reconnect(const EventImp &evt)
1357 {
1358 // Close all connections to supress the warning in SetEndpoint
1359 fFTM.PostClose(false);
1360
1361 // Now wait until all connection have been closed and
1362 // all pending handlers have been processed
1363 poll();
1364
1365 if (evt.GetText()[0]!=0)
1366 fFTM.SetEndpoint(evt.GetString());
1367
1368 // Now we can reopen the connection
1369 fFTM.PostClose(true);
1370
1371 return T::GetCurrentState();
1372 }
1373
1374 /*
1375 int Transition(const Event &evt)
1376 {
1377 switch (evt.GetTargetState())
1378 {
1379 case kStateDisconnected:
1380 case kStateConnected:
1381 }
1382
1383 return T::kSM_FatalError;
1384 }*/
1385
1386 int Execute()
1387 {
1388 // Dispatch (execute) at most one handler from the queue. In contrary
1389 // to run_one(), it doesn't wait until a handler is available
1390 // which can be dispatched, so poll_one() might return with 0
1391 // handlers dispatched. The handlers are always dispatched/executed
1392 // synchronously, i.e. within the call to poll_one()
1393 poll_one();
1394
1395 return fFTM.GetState();
1396 }
1397
1398public:
1399 StateMachineFTM(ostream &out=cout) :
1400 T(out, "FTM_CONTROL"), ba::io_service::work(static_cast<ba::io_service&>(*this)),
1401 fFTM(*this, *this)
1402 {
1403 // ba::io_service::work is a kind of keep_alive for the loop.
1404 // It prevents the io_service to go to stopped state, which
1405 // would prevent any consecutive calls to run()
1406 // or poll() to do nothing. reset() could also revoke to the
1407 // previous state but this might introduce some overhead of
1408 // deletion and creation of threads and more.
1409
1410 // State names
1411 AddStateName(kStateDisconnected, "Disconnected",
1412 "FTM board not connected via ethernet.");
1413
1414 AddStateName(kStateConnected, "Connected",
1415 "Ethernet connection to FTM established (no state received yet).");
1416
1417 AddStateName(kStateIdle, "Idle",
1418 "Ethernet connection to FTM established, FTM in idle state.");
1419
1420 AddStateName(kStateTakingData, "TakingData",
1421 "Ethernet connection to FTM established, FTM is in taking data state.");
1422
1423 // FTM Commands
1424 AddEvent("TOGGLE_LED", kStateIdle)
1425 (Wrapper(boost::bind(&ConnectionFTM::CmdToggleLed, &fFTM)))
1426 ("toggle led");
1427
1428 AddEvent("PING", kStateIdle)
1429 (Wrapper(boost::bind(&ConnectionFTM::CmdPing, &fFTM)))
1430 ("send ping");
1431
1432 AddEvent("REQUEST_DYNAMIC_DATA", kStateIdle)
1433 (Wrapper(boost::bind(&ConnectionFTM::CmdReqDynDat, &fFTM)))
1434 ("request transmission of dynamic data block");
1435
1436 AddEvent("REQUEST_STATIC_DATA", kStateIdle)
1437 (Wrapper(boost::bind(&ConnectionFTM::CmdReqStatDat, &fFTM)))
1438 ("request transmission of static data from FTM to memory");
1439
1440 AddEvent("GET_REGISTER", "I", kStateIdle)
1441 (boost::bind(&StateMachineFTM::GetRegister, this, _1))
1442 ("read register from address addr"
1443 "|addr[short]:Address of register");
1444
1445 AddEvent("SET_REGISTER", "I:2", kStateIdle)
1446 (boost::bind(&StateMachineFTM::SetRegister, this, _1))
1447 ("set register to value"
1448 "|addr[short]:Address of register"
1449 "|val[short]:Value to be set");
1450
1451 AddEvent("START_RUN", kStateIdle)
1452 (Wrapper(boost::bind(&ConnectionFTM::CmdStartRun, &fFTM)))
1453 ("start a run (start distributing triggers)");
1454
1455 AddEvent("STOP_RUN", kStateTakingData)
1456 (Wrapper(boost::bind(&ConnectionFTM::CmdStopRun, &fFTM)))
1457 ("stop a run (stop distributing triggers)");
1458
1459 AddEvent("TAKE_N_EVENTS", "I", kStateIdle)
1460 (boost::bind(&StateMachineFTM::TakeNevents, this, _1))
1461 ("take n events (distribute n triggers)|number[int]:Number of events to be taken");
1462
1463 AddEvent("DISABLE_REPORTS", "B", kStateIdle)
1464 (boost::bind(&StateMachineFTM::DisableReports, this, _1))
1465 ("disable sending rate reports"
1466 "|status[bool]:disable or enable that the FTM sends rate reports (yes/no)");
1467
1468 AddEvent("SET_THRESHOLD", "I:2", kStateIdle)
1469 (boost::bind(&StateMachineFTM::SetThreshold, this, _1))
1470 ("Set the comparator threshold"
1471 "|Patch[idx]:Index of the patch (0-159), -1 for all"
1472 "|Threshold[counts]:Threshold to be set in binary counts");
1473
1474 AddEvent("SET_PRESCALING", "I:1", kStateIdle)
1475 (boost::bind(&StateMachineFTM::SetPrescaling, this, _1))
1476 (""
1477 "|[]:");
1478
1479 AddEvent("ENABLE_FTU", "I:1;B:1", kStateIdle)
1480 (boost::bind(&StateMachineFTM::EnableFTU, this, _1))
1481 ("Enable or disable FTU"
1482 "|Board[idx]:Index of the board (0-39), -1 for all"
1483 "|Enable[bool]:Whether FTU should be enabled or disabled (yes/no)");
1484
1485 AddEvent("DISABLE_PIXEL", "S:1;B:1", kStateIdle)
1486 (boost::bind(&StateMachineFTM::DisablePixel, this, _1))
1487 ("");
1488
1489 AddEvent("TOGGLE_FTU", "I:1", kStateIdle)
1490 (boost::bind(&StateMachineFTM::ToggleFTU, this, _1))
1491 ("Toggle status of FTU (this is mainly meant to be used in the GUI)"
1492 "|Board[idx]:Index of the board (0-39)");
1493
1494 AddEvent("SET_TRIGGER_INTERVAL", "I:1", kStateIdle)
1495 (boost::bind(&StateMachineFTM::SetTriggerInterval, this, _1))
1496 ("Sets the trigger interval which is the distance between two consecutive artificial triggers."
1497 "|interval[int]:The applied trigger interval is: interval*4ns+8ns");
1498
1499 AddEvent("SET_TRIGGER_DELAY", "I:1", kStateIdle)
1500 (boost::bind(&StateMachineFTM::SetTriggerDelay, this, _1))
1501 (""
1502 "|delay[int]:The applied trigger delay is: delay*4ns+8ns");
1503
1504 AddEvent("SET_TIME_MARKER_DELAY", "I:1", kStateIdle)
1505 (boost::bind(&StateMachineFTM::SetTimeMarkerDelay, this, _1))
1506 (""
1507 "|delay[int]:The applied time marker delay is: delay*4ns+8ns");
1508
1509 AddEvent("SET_DEAD_TIME", "I:1", kStateIdle)
1510 (boost::bind(&StateMachineFTM::SetDeadTime, this, _1))
1511 (""
1512 "|dead_time[int]:The applied dead time is: dead_time*4ns+8ns");
1513
1514 AddEvent("ENABLE_TRIGGER", "B:1", kStateIdle)
1515 (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kTrigger))
1516 ("Switch on the physics trigger"
1517 "|Enable[bool]:Enable physics trigger (yes/no)");
1518
1519 // FIXME: Switch on/off depending on sequence
1520 AddEvent("ENABLE_EXT1", "B:1", kStateIdle)
1521 (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kExt1))
1522 ("Switch on the triggers through the first external line"
1523 "|Enable[bool]:Enable ext1 trigger (yes/no)");
1524
1525 // FIXME: Switch on/off depending on sequence
1526 AddEvent("ENABLE_EXT2", "B:1", kStateIdle)
1527 (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kExt2))
1528 ("Switch on the triggers through the second external line"
1529 "|Enable[bool]:Enable ext2 trigger (yes/no)");
1530
1531 AddEvent("ENABLE_VETO", "B:1", kStateIdle)
1532 (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kVeto))
1533 ("Enable veto line"
1534 "|Enable[bool]:Enable veto (yes/no)");
1535
1536 AddEvent("SET_TRIGGER_SEQUENCE", "C:3", kStateIdle)
1537 (boost::bind(&StateMachineFTM::SetTriggerSeq, this, _1))
1538 ("Setup the sequence of artificial triggers produced by the FTM"
1539 "|Ped[int]:number of pedestal triggers in a row"
1540 "|LPint[int]:number of triggers of the internal light pulser"
1541 "|LPext[int]:number of triggers of the external light pulser");
1542
1543 AddEvent("SET_TRIGGER_MULTIPLICITY", "S:1", kStateIdle)
1544 (boost::bind(&StateMachineFTM::SetTriggerMultiplicity, this, _1))
1545 ("Setup the Multiplicity condition for physcis triggers"
1546 "|N[int]:Number of requirered coincident triggers from sum-patches (1-40)");
1547
1548 AddEvent("SET_TRIGGER_WINDOW", "S:1", kStateIdle)
1549 (boost::bind(&StateMachineFTM::SetTriggerWindow, this, _1))
1550 ("");
1551
1552 AddEvent("SET_CALIBRATION_MULTIPLICITY", "S:1", kStateIdle)
1553 (boost::bind(&StateMachineFTM::SetCalibMultiplicity, this, _1))
1554 ("Setup the Multiplicity condition for artificial (calibration) triggers"
1555 "|N[int]:Number of requirered coincident triggers from sum-patches (1-40)");
1556
1557 AddEvent("SET_CALIBRATION_WINDOW", "S:1", kStateIdle)
1558 (boost::bind(&StateMachineFTM::SetCalibWindow, this, _1))
1559 ("");
1560
1561
1562 // Load/save static data block
1563 T::AddEvent("SAVE", "C", kStateIdle)
1564 (boost::bind(&StateMachineFTM::SaveStaticData, this, _1))
1565 ("Saves the static data (FTM configuration) from memory to a file"
1566 "|filename[string]:Filename (can include a path), .bin is automatically added");
1567
1568 T::AddEvent("LOAD", "C", kStateIdle)
1569 (boost::bind(&StateMachineFTM::LoadStaticData, this, _1))
1570 ("Loads the static data (FTM configuration) from a file into memory and sends it to the FTM"
1571 "|filename[string]:Filename (can include a path), .bin is automatically added");
1572
1573
1574
1575 // Verbosity commands
1576 T::AddEvent("SET_VERBOSE", "B")
1577 (boost::bind(&StateMachineFTM::SetVerbosity, this, _1))
1578 ("set verbosity state"
1579 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
1580
1581 T::AddEvent("SET_HEX_OUTPUT", "B")
1582 (boost::bind(&StateMachineFTM::SetHexOutput, this, _1))
1583 ("enable or disable hex output for received data"
1584 "|hexout[bool]:disable or enable hex output for received data (yes/no)");
1585
1586 T::AddEvent("SET_DYNAMIC_OUTPUT", "B")
1587 (boost::bind(&StateMachineFTM::SetDynamicOut, this, _1))
1588 ("enable or disable output for received dynamic data (data is still broadcasted via Dim)"
1589 "|dynout[bool]:disable or enable output for dynamic data (yes/no)");
1590
1591
1592 // Conenction commands
1593 AddEvent("DISCONNECT", kStateConnected, kStateIdle)
1594 (boost::bind(&StateMachineFTM::Disconnect, this))
1595 ("disconnect from ethernet");
1596
1597 AddEvent("RECONNECT", "O", kStateDisconnected, kStateConnected, kStateIdle)
1598 (boost::bind(&StateMachineFTM::Reconnect, this, _1))
1599 ("(Re)connect ethernet connection to FTM, a new address can be given"
1600 "|[host][string]:new ethernet address in the form <host:port>");
1601
1602 fFTM.StartConnect();
1603 }
1604
1605 void SetEndpoint(const string &url)
1606 {
1607 fFTM.SetEndpoint(url);
1608 }
1609
1610 bool SetConfiguration(const Configuration &conf)
1611 {
1612 SetEndpoint(conf.Get<string>("addr"));
1613
1614 fFTM.SetVerbose(!conf.Get<bool>("quiet"));
1615 fFTM.SetHexOutput(conf.Get<bool>("hex-out"));
1616 fFTM.SetDynamicOut(conf.Get<bool>("dynamic-out"));
1617
1618// fFTM.SetDefaultSetup(conf.Get<string>("default-setup"));
1619
1620 return true;
1621 }
1622};
1623
1624// ------------------------------------------------------------------------
1625
1626void RunThread(StateMachineImp *io_service)
1627{
1628 // This is necessary so that the StateMachien Thread can signal the
1629 // Readline to exit
1630 io_service->Run();
1631 Readline::Stop();
1632}
1633
1634template<class S, class T>
1635int RunDim(Configuration &conf)
1636{
1637 WindowLog wout;
1638
1639 /*
1640 static Test shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
1641
1642 WindowLog &win = shell.GetStreamIn();
1643 WindowLog &wout = shell.GetStreamOut();
1644 */
1645
1646 if (conf.Has("log"))
1647 if (!wout.OpenLogFile(conf.Get<string>("log")))
1648 wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
1649
1650 // Start io_service.Run to use the StateMachineImp::Run() loop
1651 // Start io_service.run to only use the commandHandler command detaching
1652 StateMachineFTM<S, T> io_service(wout);
1653 if (!io_service.SetConfiguration(conf))
1654 return -1;
1655
1656 io_service.Run();
1657
1658 /*
1659 shell.SetReceiver(io_service);
1660
1661 boost::thread t(boost::bind(RunThread, &io_service));
1662 // boost::thread t(boost::bind(&StateMachineFTM<S>::Run, &io_service));
1663
1664 shell.Run(); // Run the shell
1665 io_service.Stop(); // Signal Loop-thread to stop
1666 // io_service.Close(); // Obsolete, done by the destructor
1667
1668 // Wait until the StateMachine has finished its thread
1669 // before returning and destroying the dim objects which might
1670 // still be in use.
1671 t.join();
1672 */
1673
1674 return 0;
1675}
1676
1677template<class T, class S, class R>
1678int RunShell(Configuration &conf)
1679{
1680 static T shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
1681
1682 WindowLog &win = shell.GetStreamIn();
1683 WindowLog &wout = shell.GetStreamOut();
1684
1685 if (conf.Has("log"))
1686 if (!wout.OpenLogFile(conf.Get<string>("log")))
1687 win << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
1688
1689 StateMachineFTM<S, R> io_service(wout);
1690 if (!io_service.SetConfiguration(conf))
1691 return -1;
1692
1693 shell.SetReceiver(io_service);
1694
1695 boost::thread t(boost::bind(RunThread, &io_service));
1696 // boost::thread t(boost::bind(&StateMachineFTM<S>::Run, &io_service));
1697
1698 shell.Run(); // Run the shell
1699 io_service.Stop(); // Signal Loop-thread to stop
1700 // io_service.Close(); // Obsolete, done by the destructor
1701
1702 // Wait until the StateMachine has finished its thread
1703 // before returning and destroying the dim objects which might
1704 // still be in use.
1705 t.join();
1706
1707 return 0;
1708}
1709
1710void SetupConfiguration(Configuration &conf)
1711{
1712 const string n = conf.GetName()+".log";
1713
1714 po::options_description config("Program options");
1715 config.add_options()
1716 ("dns", var<string>("localhost"), "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
1717 ("log,l", var<string>(n), "Write log-file")
1718 ("no-dim,d", po_bool(), "Disable dim services")
1719 ("console,c", var<int>(), "Use console (0=shell, 1=simple buffered, X=simple unbuffered)")
1720 ;
1721
1722 po::options_description control("FTM control options");
1723 control.add_options()
1724 ("addr,a", var<string>("localhost:5000"), "Network address of FTM")
1725 ("quiet,q", po_bool(), "Disable printing contents of all received messages (except dynamic data) in clear text.")
1726 ("hex-out", po_bool(), "Enable printing contents of all printed messages also as hex data.")
1727 ("dynamic-out", po_bool(), "Enable printing received dynamic data.")
1728// ("default-setup", var<string>(), "Binary file with static data loaded whenever a connection to the FTM was established.")
1729 ;
1730
1731 conf.AddEnv("dns", "DIM_DNS_NODE");
1732
1733 conf.AddOptions(config);
1734 conf.AddOptions(control);
1735}
1736
1737/*
1738 Extract usage clause(s) [if any] for SYNOPSIS.
1739 Translators: "Usage" and "or" here are patterns (regular expressions) which
1740 are used to match the usage synopsis in program output. An example from cp
1741 (GNU coreutils) which contains both strings:
1742 Usage: cp [OPTION]... [-T] SOURCE DEST
1743 or: cp [OPTION]... SOURCE... DIRECTORY
1744 or: cp [OPTION]... -t DIRECTORY SOURCE...
1745 */
1746void PrintUsage()
1747{
1748 cout <<
1749 "The ftmctrl controls the FTM (FACT Trigger Master) board.\n"
1750 "\n"
1751 "The default is that the program is started without user intercation. "
1752 "All actions are supposed to arrive as DimCommands. Using the -c "
1753 "option, a local shell can be initialized. With h or help a short "
1754 "help message about the usuage can be brought to the screen.\n"
1755 "\n"
1756 "Usage: ftmctrl [-c type] [OPTIONS]\n"
1757 " or: ftmctrl [OPTIONS]\n";
1758 cout << endl;
1759}
1760
1761void PrintHelp()
1762{
1763 /* Additional help text which is printed after the configuration
1764 options goes here */
1765
1766 /*
1767 cout << "bla bla bla" << endl << endl;
1768 cout << endl;
1769 cout << "Environment:" << endl;
1770 cout << "environment" << endl;
1771 cout << endl;
1772 cout << "Examples:" << endl;
1773 cout << "test exam" << endl;
1774 cout << endl;
1775 cout << "Files:" << endl;
1776 cout << "files" << endl;
1777 cout << endl;
1778 */
1779}
1780
1781int main(int argc, const char* argv[])
1782{
1783 Configuration conf(argv[0]);
1784 conf.SetPrintUsage(PrintUsage);
1785 SetupConfiguration(conf);
1786
1787 po::variables_map vm;
1788 try
1789 {
1790 vm = conf.Parse(argc, argv);
1791 }
1792#if BOOST_VERSION > 104000
1793 catch (po::multiple_occurrences &e)
1794 {
1795 cout << "Error: " << e.what() << " of '" << e.get_option_name() << "' option." << endl;
1796 cout << endl;
1797 return -1;
1798 }
1799#endif
1800 catch (std::exception &e)
1801 {
1802 cout << "Error: " << e.what() << endl;
1803 cout << endl;
1804
1805 return -1;
1806 }
1807
1808 if (conf.HasPrint())
1809 return -1;
1810
1811 if (conf.HasVersion())
1812 {
1813 FACT::PrintVersion(argv[0]);
1814 return -1;
1815 }
1816
1817 if (conf.HasHelp())
1818 {
1819 PrintHelp();
1820 return -1;
1821 }
1822
1823 Dim::Setup(conf.Get<string>("dns"));
1824
1825 //try
1826 {
1827 // No console access at all
1828 if (!conf.Has("console"))
1829 {
1830 if (conf.Get<bool>("no-dim"))
1831 return RunDim<StateMachine, ConnectionFTM>(conf);
1832 else
1833 return RunDim<StateMachineDim, ConnectionDimFTM>(conf);
1834 }
1835 // Cosole access w/ and w/o Dim
1836 if (conf.Get<bool>("no-dim"))
1837 {
1838 if (conf.Get<int>("console")==0)
1839 return RunShell<LocalShell, StateMachine, ConnectionFTM>(conf);
1840 else
1841 return RunShell<LocalConsole, StateMachine, ConnectionFTM>(conf);
1842 }
1843 else
1844 {
1845 if (conf.Get<int>("console")==0)
1846 return RunShell<LocalShell, StateMachineDim, ConnectionDimFTM>(conf);
1847 else
1848 return RunShell<LocalConsole, StateMachineDim, ConnectionDimFTM>(conf);
1849 }
1850 }
1851 /*catch (std::exception& e)
1852 {
1853 cerr << "Exception: " << e.what() << endl;
1854 return -1;
1855 }*/
1856
1857 return 0;
1858}
Note: See TracBrowser for help on using the repository browser.