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

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