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

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