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

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