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

Last change on this file since 10652 was 10651, checked in by tbretz, 14 years ago
Removed sending static data 100 times when loaded from file which was put there for testing purpose.
File size: 54.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 "Dim.h"
13#include "Event.h"
14#include "Shell.h"
15#include "StateMachineDim.h"
16#include "Connection.h"
17#include "Configuration.h"
18#include "Timers.h"
19#include "Console.h"
20#include "Converter.h"
21
22#include "FACT.h"
23#include "tools.h"
24
25#include "LocalControl.h"
26#include "HeadersFTM.h"
27
28
29namespace ba = boost::asio;
30namespace bs = boost::system;
31
32using namespace std;
33
34// ------------------------------------------------------------------------
35
36class ConnectionFTM : public Connection
37{
38 vector<uint16_t> fBuffer;
39
40 bool fHasHeader;
41 int fState;
42
43 bool fIsVerbose;
44 bool fIsDynamicOut;
45 bool fIsHexOutput;
46
47 // --verbose
48 // --hex-out
49 // --dynamic-out
50 // --load-file
51 // --leds
52 // --trigger-interval
53 // --physcis-coincidence
54 // --calib-coincidence
55 // --physcis-window
56 // --physcis-window
57 // --trigger-delay
58 // --time-marker-delay
59 // --dead-time
60 // --clock-conditioner-r0
61 // --clock-conditioner-r1
62 // --clock-conditioner-r8
63 // --clock-conditioner-r9
64 // --clock-conditioner-r11
65 // --clock-conditioner-r13
66 // --clock-conditioner-r14
67 // --clock-conditioner-r15
68 // ...
69
70protected:
71 map<uint16_t, int> fCounter;
72
73 FTM::Header fHeader;
74 FTM::FtuList fFtuList;
75 FTM::StaticData fStaticData;
76 FTM::DynamicData fDynamicData;
77 FTM::Error fError;
78
79 virtual void UpdateFirstHeader()
80 {
81 // FIXME: Message() ?
82 Out() << endl << kBold << "First header received:" << endl;
83 Out() << fHeader;
84 if (fIsHexOutput)
85 Out() << Converter::GetHex<uint16_t>(fHeader, sizeof(fHeader), 16) << endl;
86 }
87
88 virtual void UpdateHeader()
89 {
90 // emit service with trigger counter from header
91 if (!fIsVerbose)
92 return;
93
94 if (fHeader.fType==FTM::kDynamicData && !fIsDynamicOut)
95 return;
96
97 Out() << endl << kBold << "Header received:" << endl;
98 Out() << fHeader;
99 if (fIsHexOutput)
100 Out() << Converter::GetHex<uint16_t>(fHeader, sizeof(fHeader), 16) << endl;
101 }
102
103 virtual void UpdateFtuList()
104 {
105 if (!fIsVerbose)
106 return;
107
108 Out() << endl << kBold << "FtuList received:" << endl;
109 Out() << fFtuList;
110 if (fIsHexOutput)
111 Out() << Converter::GetHex<uint16_t>(fFtuList, 16) << endl;
112 }
113
114 virtual void UpdateStaticData()
115 {
116 if (!fIsVerbose)
117 return;
118
119 Out() << endl << kBold << "Static data received:" << endl;
120 Out() << fStaticData;
121 if (fIsHexOutput)
122 Out() << Converter::GetHex<uint16_t>(fStaticData, 16) << endl;
123 }
124
125 virtual void UpdateDynamicData()
126 {
127 if (!fIsDynamicOut)
128 return;
129
130 Out() << endl << kBold << "Dynamic data received:" << endl;
131 Out() << fDynamicData;
132 if (fIsHexOutput)
133 Out() << Converter::GetHex<uint16_t>(fDynamicData, 16) << endl;
134 }
135
136 virtual void UpdateError()
137 {
138 if (!fIsVerbose)
139 return;
140
141 Out() << endl << kRed << "Error received:" << endl;
142 Out() << fError;
143 if (fIsHexOutput)
144 Out() << Converter::GetHex<uint16_t>(fError, 16) << endl;
145 }
146
147 virtual void UpdateCounter()
148 {
149 if (!fIsVerbose)
150 return;
151
152 if (!fIsDynamicOut)
153 return;
154
155 Out() << "Received: ";
156 Out() << "H=" << fCounter[FTM::kHeader] << " ";
157 Out() << "S=" << fCounter[FTM::kStaticData] << " ";
158 Out() << "D=" << fCounter[FTM::kDynamicData] << " ";
159 Out() << "F=" << fCounter[FTM::kFtuList] << " ";
160 Out() << "E=" << fCounter[FTM::kErrorList] << " ";
161 Out() << "R=" << fCounter[FTM::kRegister] << endl;
162 }
163
164 bool CheckConsistency()
165 {
166 bool warn1 = false;
167 if (fStaticData.IsEnabled(FTM::StaticData::kPedestal) != (fStaticData.GetSequencePed() >0) ||
168 fStaticData.IsEnabled(FTM::StaticData::kLPint) != (fStaticData.GetSequenceLPint()>0) ||
169 fStaticData.IsEnabled(FTM::StaticData::kLPext) != (fStaticData.GetSequenceLPext()>0))
170 {
171 warn1 = true;
172 fStaticData.Enable(FTM::StaticData::kPedestal, fStaticData.GetSequencePed()>0);
173 fStaticData.Enable(FTM::StaticData::kLPint, fStaticData.GetSequenceLPint()>0);
174 fStaticData.Enable(FTM::StaticData::kLPext, fStaticData.GetSequenceLPext()>0);
175 }
176
177 bool warn2 = false;
178 const uint16_t ref = fStaticData[0].fPrescaling;
179 for (int i=1; i<40; i++)
180 {
181 if (fStaticData[i].fPrescaling != ref)
182 {
183 warn2 = true;
184 fStaticData[i].fPrescaling = ref;
185 }
186 }
187
188 if (warn1)
189 Warn("GeneralSettings not consistent with trigger sequence.");
190 if (warn2)
191 Warn("Prescaling not consistent for all boards.");
192
193 return !warn1 && !warn2;
194 }
195
196private:
197 void HandleReceivedData(const bs::error_code& err, size_t bytes_received, int /*type*/)
198 {
199 cout << "Data received " << err << " " << bytes_received << endl;
200
201 // Do not schedule a new read if the connection failed.
202 if (bytes_received==0 || err)
203 {
204 if (err==ba::error::eof)
205 Warn("Connection closed by remote host (FTM).");
206
207 // 107: Transport endpoint is not connected (bs::error_code(107, bs::system_category))
208 // 125: Operation canceled
209 if (err && err!=ba::error::eof && // Connection closed by remote host
210 err!=ba::error::basic_errors::not_connected && // Connection closed by remote host
211 err!=ba::error::basic_errors::operation_aborted) // Connection closed by us
212 {
213 stringstream str;
214 str << "Reading from " << URL() << ": " << err.message() << " (" << err << ")";// << endl;
215 Error(str);
216 }
217 PostClose(err!=ba::error::basic_errors::operation_aborted);
218 return;
219 }
220
221 // If we have not yet received a header we expect one now
222 // This could be moved to a HandleReceivedHeader function
223 if (!fHasHeader)
224 {
225 if (bytes_received!=sizeof(FTM::Header))
226 {
227 stringstream str;
228 str << "Excepted " << sizeof(FTM::Header) << " bytes (FTM::Header) but received " << bytes_received << ".";
229 Error(str);
230 PostClose(false);
231 return;
232 }
233
234 fHeader = fBuffer;
235
236 // Check the data integrity
237 if (fHeader.fDelimiter!=FTM::kDelimiterStart)
238 {
239 stringstream str;
240 str << "Invalid header received: start delimiter wrong, received " << hex << fHeader.fDelimiter << " expected " << FTM::kDelimiterStart << ".";
241 Error(str);
242 PostClose(false);
243 return;
244 }
245
246 fHasHeader = true;
247
248 // Convert FTM state into FtmCtrl state
249 switch (fHeader.fState)
250 {
251 case FTM::kFtmIdle:
252 case FTM::kFtmConfig:
253 fState = FTM::kIdle;
254 break;
255
256 case FTM::kFtmCalib:
257 case FTM::kFtmRunning:
258 fState = FTM::kTakingData;
259 break;
260 }
261
262 if (++fCounter[FTM::kHeader]==1)
263 UpdateFirstHeader();
264
265 UpdateCounter();
266 UpdateHeader();
267
268 // Start reading of data
269 switch (fHeader.fType)
270 {
271 case FTM::kStaticData:
272 case FTM::kDynamicData:
273 case FTM::kFtuList:
274 case FTM::kRegister:
275 case FTM::kErrorList:
276 // This is not very efficient because the space is reallocated
277 // maybe we can check if the capacity of the std::vector
278 // is ever decreased. If not, everythign is fine.
279 fBuffer.resize(fHeader.fDataSize);
280 AsyncRead(ba::buffer(fBuffer));
281 AsyncWait(fInTimeout, 50, &Connection::HandleReadTimeout);
282 return;
283
284 default:
285 stringstream str;
286 str << "Unknonw type " << fHeader.fType << " in received header." << endl;
287 Error(str);
288 PostClose(false);
289 return;
290 }
291
292 return;
293 }
294
295 // Check the data integrity (check end delimiter)
296 if (ntohs(fBuffer.back())!=FTM::kDelimiterEnd)
297 {
298 stringstream str;
299 str << "Invalid data received: end delimiter wrong, received ";
300 str << hex << ntohs(fBuffer.back()) << " expected " << FTM::kDelimiterEnd << ".";
301 Error(str);
302 PostClose(false);
303 return;
304 }
305
306 // Remove end delimiter
307 fBuffer.pop_back();
308
309 try
310 {
311 // If we have already received a header this is the data now
312 // This could be moved to a HandleReceivedData function
313
314 fCounter[fHeader.fType]++;
315 UpdateCounter();
316
317 cout << "TYPE=" << fHeader.fType << endl;
318
319 switch (fHeader.fType)
320 {
321 case FTM::kFtuList:
322 fFtuList = fBuffer;
323 UpdateFtuList();
324 break;
325
326 case FTM::kStaticData:
327 fStaticData = fBuffer;
328
329 if (fCounter[FTM::kStaticData]==1)
330 if (!CheckConsistency())
331 {
332 CmdSendStatDat();
333 break;
334 }
335
336 UpdateStaticData();
337 break;
338
339 case FTM::kDynamicData:
340 fDynamicData = fBuffer;
341 UpdateDynamicData();
342 break;
343
344 case FTM::kRegister:
345 if (fIsVerbose)
346 {
347 Out() << endl << kBold << "Register received: " << endl;
348 Out() << "Addr: " << ntohs(fBuffer[0]) << endl;
349 Out() << "Value: " << ntohs(fBuffer[1]) << endl;
350 }
351 break;
352
353 case FTM::kErrorList:
354 fError = fBuffer;
355 UpdateError();
356 break;
357
358 default:
359 stringstream str;
360 str << "Unknonw type " << fHeader.fType << " in header." << endl;
361 Error(str);
362 PostClose(false);
363 return;
364 }
365 }
366 catch (const logic_error &e)
367 {
368 stringstream str;
369 str << "Exception converting buffer into data structure: " << e.what();
370 Error(str);
371 PostClose(false);
372 return;
373 }
374
375 fInTimeout.cancel();
376
377 fHeader.clear();
378 fHasHeader = false;
379 fBuffer.resize(sizeof(FTM::Header)/2);
380 AsyncRead(ba::buffer(fBuffer));
381 }
382
383 // This is called when a connection was established
384 void ConnectionEstablished()
385 {
386 fState = FTM::kConnected;
387 fCounter.clear();
388
389 fHeader.clear();
390 fHasHeader = false;
391 fBuffer.resize(sizeof(FTM::Header)/2);
392 AsyncRead(ba::buffer(fBuffer));
393
394 // Get a header and configdata!
395 CmdReqStatDat();
396
397 // get the DNA of the FTUs
398 CmdPing();
399 }
400
401 void HandleReadTimeout(const bs::error_code &error)
402 {
403 if (error && error!=ba::error::basic_errors::operation_aborted)
404 {
405 stringstream str;
406 str << "Read timeout of " << URL() << ": " << error.message() << " (" << error << ")";// << endl;
407 Error(str);
408
409 PostClose();
410 return;
411
412 }
413
414 if (!is_open())
415 {
416 // For example: Here we could schedule a new accept if we
417 // would not want to allow two connections at the same time.
418 return;
419 }
420
421 // Check whether the deadline has passed. We compare the deadline
422 // against the current time since a new asynchronous operation
423 // may have moved the deadline before this actor had a chance
424 // to run.
425 if (fInTimeout.expires_at() > ba::deadline_timer::traits_type::now())
426 return;
427
428 Error("Timeout reading data from "+URL());
429
430 PostClose();
431 }
432
433
434 template<size_t N>
435 void PostCmd(boost::array<uint16_t, N> dat, uint16_t u1=0, uint16_t u2=0, uint16_t u3=0, uint16_t u4=0)
436 {
437 boost::array<uint16_t, 5> cmd = {{ '@', u1, u2, u3, u4 }};
438
439 stringstream msg;
440 msg << "Sending command:" << hex;
441 msg << " 0x" << setw(4) << setfill('0') << cmd[0];
442 msg << " 0x" << setw(4) << setfill('0') << u1;
443 msg << " 0x" << setw(4) << setfill('0') << u2;
444 msg << " 0x" << setw(4) << setfill('0') << u3;
445 msg << " 0x" << setw(4) << setfill('0') << u4;
446 msg << " (+" << dec << dat.size() << " words)";
447 Message(msg);
448
449 vector<uint16_t> out(cmd.size()+dat.size());
450
451 transform(cmd.begin(), cmd.end(), out.begin(), htons);
452 transform(dat.begin(), dat.end(), out.begin()+cmd.size(), htons);
453
454 PostMessage(out);
455 }
456
457 void PostCmd(vector<uint16_t> dat, uint16_t u1=0, uint16_t u2=0, uint16_t u3=0, uint16_t u4=0)
458 {
459 boost::array<uint16_t, 5> cmd = {{ '@', u1, u2, u3, u4 }};
460
461 stringstream msg;
462 msg << "Sending command:" << hex;
463 msg << " 0x" << setw(4) << setfill('0') << cmd[0];
464 msg << " 0x" << setw(4) << setfill('0') << u1;
465 msg << " 0x" << setw(4) << setfill('0') << u2;
466 msg << " 0x" << setw(4) << setfill('0') << u3;
467 msg << " 0x" << setw(4) << setfill('0') << u4;
468 msg << " (+" << dec << dat.size() << " words)";
469 Message(msg);
470
471 vector<uint16_t> out(cmd.size()+dat.size());
472
473 transform(cmd.begin(), cmd.end(), out.begin(), htons);
474 copy(dat.begin(), dat.end(), out.begin()+cmd.size());
475
476 PostMessage(out);
477 }
478
479 void PostCmd(uint16_t u1=0, uint16_t u2=0, uint16_t u3=0, uint16_t u4=0)
480 {
481 PostCmd(boost::array<uint16_t, 0>(), u1, u2, u3, u4);
482 }
483public:
484
485 static const uint16_t kMaxAddr;
486
487public:
488 ConnectionFTM(ba::io_service& ioservice, MessageImp &imp) : Connection(ioservice, imp()),
489 fIsVerbose(true), fIsDynamicOut(true), fIsHexOutput(true)
490 {
491 SetLogStream(&imp);
492 }
493
494 void CmdToggleLed()
495 {
496 PostCmd(FTM::kCmdToggleLed);
497 }
498
499 void CmdPing()
500 {
501 PostCmd(FTM::kCmdPing);
502 }
503
504 void CmdReqDynDat()
505 {
506 PostCmd(FTM::kCmdRead, FTM::kReadDynamicData);
507 }
508
509 void CmdReqStatDat()
510 {
511 PostCmd(FTM::kCmdRead, FTM::kReadStaticData);
512 }
513
514 void CmdSendStatDat()
515 {
516 PostCmd(fStaticData.HtoN(), FTM::kCmdWrite, FTM::kWriteStaticData);
517
518 // Request the changed configuration to ensure the
519 // change is distributed in the network
520 CmdReqStatDat();
521 }
522
523 void CmdStartRun()
524 {
525 PostCmd(FTM::kCmdStartRun, FTM::kStartRun);
526
527 // Update state information by requesting a new header
528 CmdGetRegister(0);
529 }
530
531 void CmdStopRun()
532 {
533 PostCmd(FTM::kCmdStopRun);
534
535 // Update state information by requesting a new header
536 CmdGetRegister(0);
537 }
538
539 void CmdTakeNevents(uint32_t n)
540 {
541 const boost::array<uint16_t, 2> data = {{ uint16_t(n>>16), uint16_t(n&0xffff) }};
542 PostCmd(data, FTM::kCmdStartRun, FTM::kTakeNevents);
543
544 // Update state information by requesting a new header
545 CmdGetRegister(0);
546 }
547
548 bool CmdSetRegister(uint16_t addr, uint16_t val)
549 {
550 if (addr>kMaxAddr)
551 return false;
552
553 const boost::array<uint16_t, 2> data = {{ addr, val }};
554 PostCmd(data, FTM::kCmdWrite, FTM::kWriteRegister);
555
556 // Request the changed configuration to ensure the
557 // change is distributed in the network
558 CmdReqStatDat();
559
560 return true;
561 }
562
563 bool CmdGetRegister(uint16_t addr)
564 {
565 if (addr>kMaxAddr)
566 return false;
567
568 const boost::array<uint16_t, 1> data = {{ addr }};
569 PostCmd(data, FTM::kCmdRead, FTM::kReadRegister);
570
571 return true;
572 }
573
574 bool CmdDisableReports(bool b)
575 {
576 PostCmd(FTM::kCmdDisableReports, b ? uint16_t(0) : uint16_t(1));
577 return true;
578 }
579
580 void SetVerbose(bool b)
581 {
582 fIsVerbose = b;
583 }
584
585 void SetHexOutput(bool b)
586 {
587 fIsHexOutput = b;
588 }
589
590 void SetDynamicOut(bool b)
591 {
592 fIsDynamicOut = b;
593 }
594
595 bool LoadStaticData(string name)
596 {
597 if (name.rfind(".bin")!=name.length()-5)
598 name += ".bin";
599
600 ifstream fin(name);
601 if (!fin)
602 return false;
603
604 FTM::StaticData data;
605
606 fin.read(reinterpret_cast<char*>(&data), sizeof(FTM::StaticData));
607
608 if (fin.gcount()<streamsize(sizeof(FTM::StaticData)))
609 return false;
610
611 if (fin.fail() || fin.eof())
612 return false;
613
614 if (fin.peek()!=-1)
615 return false;
616
617 fStaticData = data;
618
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 ("Sets the trigger interval which is the distance between two consecutive artificial triggers."
1423 "|interval[int]:The applied trigger interval is: interval*4ns+8ns");
1424
1425 AddConfiguration("SET_TRIGGER_DELAY", "I:1", kStateIdle)
1426 (boost::bind(&StateMachineFTM::SetTriggerDelay, this, _1))
1427 (""
1428 "|delay[int]:The applied trigger delay is: delay*4ns+8ns");
1429
1430 AddConfiguration("SET_TIME_MARKER_DELAY", "I:1", kStateIdle)
1431 (boost::bind(&StateMachineFTM::SetTimeMarkerDelay, this, _1))
1432 (""
1433 "|delay[int]:The applied time marker delay is: delay*4ns+8ns");
1434
1435 AddConfiguration("SET_DEAD_TIME", "I:1", kStateIdle)
1436 (boost::bind(&StateMachineFTM::SetDeadTime, this, _1))
1437 (""
1438 "|dead_time[int]:The applied dead time is: dead_time*4ns+8ns");
1439
1440 AddConfiguration("ENABLE_TRIGGER", "B:1", kStateIdle)
1441 (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kTrigger))
1442 ("Switch on the physics trigger"
1443 "|Enable[bool]:Enable physics trigger (yes/no)");
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 ("Switch on the triggers through the first external line"
1449 "|Enable[bool]:Enable ext1 trigger (yes/no)");
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 ("Switch on the triggers through the second external line"
1455 "|Enable[bool]:Enable ext2 trigger (yes/no)");
1456
1457 AddConfiguration("ENABLE_VETO", "B:1", kStateIdle)
1458 (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kVeto))
1459 ("Enable veto line"
1460 "|Enable[bool]:Enable veto (yes/no)");
1461
1462 AddConfiguration("SET_TRIGGER_SEQUENCE", "C:3", kStateIdle)
1463 (boost::bind(&StateMachineFTM::SetTriggerSeq, this, _1))
1464 ("Setup the sequence of artificial triggers produced by the FTM"
1465 "|Ped[int]:number of pedestal triggers in a row"
1466 "|LPint[int]:number of triggers of the internal light pulser"
1467 "|LPext[int]:number of triggers of the external light pulser");
1468
1469 AddConfiguration("SET_TRIGGER_COINCIDENCE", "S:2", kStateIdle)
1470 (boost::bind(&StateMachineFTM::SetTriggerCoincidence, this, _1))
1471 ("Setup the coincidence condition for physcis triggers"
1472 "|N[int]:Number of requirered coincident triggers from sum-patches (1-40)");
1473
1474 AddConfiguration("SET_CALIBRATION_COINCIDENCE", "S:2", kStateIdle)
1475 (boost::bind(&StateMachineFTM::SetCalibCoincidence, this, _1))
1476 ("Setup the coincidence condition for artificial (calibration) triggers"
1477 "|N[int]:Number of requirered coincident triggers from sum-patches (1-40)");
1478
1479
1480 // Load/save static data block
1481 T::AddConfiguration("SAVE", "C", kStateIdle)
1482 (boost::bind(&StateMachineFTM::SaveStaticData, this, _1))
1483 ("Saves the static data (FTM configuration) from memory to a file"
1484 "|filename[string]:Filename (can include a path), .bin is automatically added");
1485
1486 T::AddConfiguration("LOAD", "C", kStateIdle)
1487 (boost::bind(&StateMachineFTM::LoadStaticData, this, _1))
1488 ("Loads the static data (FTM configuration) from a file into memory and sends it to the FTM"
1489 "|filename[string]:Filename (can include a path), .bin is automatically added");
1490
1491
1492
1493 // Verbosity commands
1494 T::AddConfiguration("SET_VERBOSE", "B")
1495 (boost::bind(&StateMachineFTM::SetVerbosity, this, _1))
1496 ("set verbosity state"
1497 "|verbosity[bool]:disable or enable verbosity for received data (yes/no)");
1498
1499 T::AddConfiguration("SET_HEX_OUTPUT", "B")
1500 (boost::bind(&StateMachineFTM::SetHexOutput, this, _1))
1501 ("enable or disable hex output for received data"
1502 "|hexout[bool]:disable or enable hex output for verbose and received data (yes/no)");
1503
1504 T::AddConfiguration("SET_DYNAMIC_OUTPUT", "B")
1505 (boost::bind(&StateMachineFTM::SetDynamicOut, this, _1))
1506 ("enable or disable output for received dynamic data (data is still broadcasted via Dim)"
1507 "|dynout[bool]:disable or enable output for dynamic data (yes/no)");
1508
1509
1510 // Conenction commands
1511 AddConfiguration("DISCONNECT", kStateConnected, kStateIdle)
1512 (boost::bind(&StateMachineFTM::Disconnect, this))
1513 ("disconnect from ethernet");
1514
1515 AddConfiguration("RECONNECT", "O", kStateDisconnected, kStateConnected, kStateIdle)
1516 (boost::bind(&StateMachineFTM::Reconnect, this, _1))
1517 ("(Re)connect ethernet connection to FTM, a new address can be given"
1518 "|[host][string]:new ethernet address in the form <host:port>");
1519
1520 // Other
1521 AddTransition(kCmdTest, "TEST", "O")
1522 (boost::bind(&StateMachineFTM::Test, this, _1))
1523 ("Just for test purpose, do not use");
1524
1525 fFTM.StartConnect();
1526 }
1527
1528 /// Just for test purpose, do not touch
1529 int Test(const Event &evt)
1530 {
1531 const Converter conv(T::Out(), evt.GetFormat(), false);
1532 T::Out() << kBlue << evt.GetName();
1533 T::Out() << " " << conv.GetString(evt.GetData(), evt.GetSize());
1534 T::Out() << endl;
1535
1536 return T::GetCurrentState();
1537 }
1538
1539 void SetEndpoint(const string &url)
1540 {
1541 fFTM.SetEndpoint(url);
1542 }
1543
1544 bool SetConfiguration(const Configuration &conf)
1545 {
1546 SetEndpoint(conf.Get<string>("addr"));
1547
1548 fFTM.SetVerbose(!conf.Get<bool>("quiet"));
1549 fFTM.SetHexOutput(conf.Get<bool>("hex-out"));
1550 fFTM.SetDynamicOut(conf.Get<bool>("dynamic-out"));
1551
1552 return true;
1553 }
1554};
1555
1556// ------------------------------------------------------------------------
1557
1558void RunThread(StateMachineImp *io_service)
1559{
1560 // This is necessary so that the StateMachien Thread can signal the
1561 // Readline to exit
1562 io_service->Run();
1563 Readline::Stop();
1564}
1565
1566template<class S, class T>
1567int RunDim(Configuration &conf)
1568{
1569 WindowLog wout;
1570
1571 /*
1572 static Test shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
1573
1574 WindowLog &win = shell.GetStreamIn();
1575 WindowLog &wout = shell.GetStreamOut();
1576 */
1577
1578 if (conf.Has("log"))
1579 if (!wout.OpenLogFile(conf.Get<string>("log")))
1580 wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
1581
1582 // Start io_service.Run to use the StateMachineImp::Run() loop
1583 // Start io_service.run to only use the commandHandler command detaching
1584 StateMachineFTM<S, T> io_service(wout);
1585 if (!io_service.SetConfiguration(conf))
1586 return -1;
1587
1588 io_service.Run();
1589
1590 /*
1591 shell.SetReceiver(io_service);
1592
1593 boost::thread t(boost::bind(RunThread, &io_service));
1594 // boost::thread t(boost::bind(&StateMachineFTM<S>::Run, &io_service));
1595
1596 shell.Run(); // Run the shell
1597 io_service.Stop(); // Signal Loop-thread to stop
1598 // io_service.Close(); // Obsolete, done by the destructor
1599
1600 // Wait until the StateMachine has finished its thread
1601 // before returning and destroying the dim objects which might
1602 // still be in use.
1603 t.join();
1604 */
1605
1606 return 0;
1607}
1608
1609template<class T, class S, class R>
1610int RunShell(Configuration &conf)
1611{
1612 static T shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
1613
1614 WindowLog &win = shell.GetStreamIn();
1615 WindowLog &wout = shell.GetStreamOut();
1616
1617 if (conf.Has("log"))
1618 if (!wout.OpenLogFile(conf.Get<string>("log")))
1619 win << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
1620
1621 StateMachineFTM<S, R> io_service(wout);
1622 if (!io_service.SetConfiguration(conf))
1623 return -1;
1624
1625 shell.SetReceiver(io_service);
1626
1627 boost::thread t(boost::bind(RunThread, &io_service));
1628 // boost::thread t(boost::bind(&StateMachineFTM<S>::Run, &io_service));
1629
1630 shell.Run(); // Run the shell
1631 io_service.Stop(); // Signal Loop-thread to stop
1632 // io_service.Close(); // Obsolete, done by the destructor
1633
1634 // Wait until the StateMachine has finished its thread
1635 // before returning and destroying the dim objects which might
1636 // still be in use.
1637 t.join();
1638
1639 return 0;
1640}
1641
1642void SetupConfiguration(Configuration &conf)
1643{
1644 const string n = conf.GetName()+".log";
1645
1646 po::options_description config("Program options");
1647 config.add_options()
1648 ("dns", var<string>("localhost"), "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
1649 ("log,l", var<string>(n), "Write log-file")
1650 ("no-dim,d", po_switch(), "Disable dim services")
1651 ("console,c", var<int>(), "Use console (0=shell, 1=simple buffered, X=simple unbuffered)")
1652 ;
1653
1654 po::options_description control("FTM control options");
1655 control.add_options()
1656 ("addr,a", var<string>("localhost:5000"), "Network address of FTM")
1657 ("quiet,q", po_switch(), "Disable printing contents of all received messages (except dynamic data) in clear text.")
1658 ("hex-out", po_switch(), "Enable printing contents of all printed messages also as hex data.")
1659 ("dynamic-out", po_switch(), "Enable printing received dynamic data.")
1660 ;
1661
1662 conf.AddEnv("dns", "DIM_DNS_NODE");
1663
1664 conf.AddOptions(config);
1665 conf.AddOptions(control);
1666}
1667
1668/*
1669 Extract usage clause(s) [if any] for SYNOPSIS.
1670 Translators: "Usage" and "or" here are patterns (regular expressions) which
1671 are used to match the usage synopsis in program output. An example from cp
1672 (GNU coreutils) which contains both strings:
1673 Usage: cp [OPTION]... [-T] SOURCE DEST
1674 or: cp [OPTION]... SOURCE... DIRECTORY
1675 or: cp [OPTION]... -t DIRECTORY SOURCE...
1676 */
1677void PrintUsage()
1678{
1679 cout <<
1680 "The ftmctrl controls the FTM (FACT Trigger Master) board.\n"
1681 "\n"
1682 "The default is that the program is started without user intercation. "
1683 "All actions are supposed to arrive as DimCommands. Using the -c "
1684 "option, a local shell can be initialized. With h or help a short "
1685 "help message about the usuage can be brought to the screen.\n"
1686 "\n"
1687 "Usage: ftmctrl [-c type] [OPTIONS]\n"
1688 " or: ftmctrl [OPTIONS]\n";
1689 cout << endl;
1690}
1691
1692void PrintHelp()
1693{
1694 /* Additional help text which is printed after the configuration
1695 options goes here */
1696
1697 /*
1698 cout << "bla bla bla" << endl << endl;
1699 cout << endl;
1700 cout << "Environment:" << endl;
1701 cout << "environment" << endl;
1702 cout << endl;
1703 cout << "Examples:" << endl;
1704 cout << "test exam" << endl;
1705 cout << endl;
1706 cout << "Files:" << endl;
1707 cout << "files" << endl;
1708 cout << endl;
1709 */
1710}
1711
1712/*
1713string GetLocalIp()
1714{
1715 const char *kDnsIp = getenv("DIM_DNS_NODE");
1716
1717 struct addrinfo hints, *servinfo, *p;
1718
1719 memset(&hints, 0, sizeof hints);
1720 hints.ai_family = AF_INET; //AF_UNSPEC; // use AF_INET6 to force IPv6
1721 hints.ai_socktype = SOCK_STREAM;
1722
1723 int rv;
1724 if ((rv = getaddrinfo(kDnsIp, NULL, &hints, &servinfo)) != 0)
1725 {
1726 cout << "WARNING - getaddrinfo: " << gai_strerror(rv) << endl;
1727 return kDnsIp;
1728 }
1729
1730 // loop through all the results and connect to the first we can
1731 for (p=servinfo; p; p=p->ai_next)
1732 {
1733 const int sock = socket(AF_INET, SOCK_DGRAM, 0);
1734 if (sock==-1)
1735 continue;
1736
1737 if (connect(sock, p->ai_addr, p->ai_addrlen)==-1)
1738 {
1739 cout << "WARNING - connect: " << strerror(errno) << endl;
1740 close(sock);
1741 continue;
1742 }
1743
1744 sockaddr_in name;
1745 socklen_t namelen = sizeof(name);
1746 if (getsockname(sock, (sockaddr*)&name, &namelen)==-1)
1747 {
1748 cout << "WARNING - getsockname: " << strerror(errno) << endl;
1749 close(sock);
1750 continue;
1751 }
1752
1753 char buffer[16];
1754 if (!inet_ntop(AF_INET, &name.sin_addr, buffer, 16))
1755 {
1756 cout << "WARNING - inet_ntop: " << strerror(errno) << endl;
1757 close(sock);
1758 continue;
1759 }
1760
1761 close(sock);
1762
1763 freeaddrinfo(servinfo); // all done with this structure
1764
1765 cout << "DIM_HOST_NODE=" << buffer << endl;
1766 return buffer;
1767 }
1768
1769 freeaddrinfo(servinfo); // all done with this structure
1770 return kDnsIp;
1771}
1772*/
1773
1774int main(int argc, const char* argv[])
1775{
1776 Configuration conf(argv[0]);
1777 conf.SetPrintUsage(PrintUsage);
1778 SetupConfiguration(conf);
1779
1780 po::variables_map vm;
1781 try
1782 {
1783 vm = conf.Parse(argc, argv);
1784 }
1785#if BOOST_VERSION > 104000
1786 catch (po::multiple_occurrences &e)
1787 {
1788 cout << "Error: " << e.what() << " of '" << e.get_option_name() << "' option." << endl;
1789 cout << endl;
1790 return -1;
1791 }
1792#endif
1793 catch (std::exception &e)
1794 {
1795 cout << "Error: " << e.what() << endl;
1796 cout << endl;
1797
1798 return -1;
1799 }
1800
1801 if (conf.HasPrint())
1802 return -1;
1803
1804 if (conf.HasVersion())
1805 {
1806 FACT::PrintVersion(argv[0]);
1807 return -1;
1808 }
1809
1810 if (conf.HasHelp())
1811 {
1812 PrintHelp();
1813 return -1;
1814 }
1815
1816 Dim::Setup(conf.Get<string>("dns"));
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.