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

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