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

Last change on this file since 10648 was 10647, checked in by tbretz, 14 years ago
Initialize DIM's environment variables through Dim::Setup; made command line switches in a way they give reasonable defaults.
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 for (int i=0; i<100; i++)
620 CmdSendStatDat();
621
622 return true;
623 }
624
625 bool SaveStaticData(string name) const
626 {
627 if (name.rfind(".bin")!=name.length()-5)
628 name += ".bin";
629
630 ofstream fout(name);
631 if (!fout)
632 return false;
633
634 fout.write(reinterpret_cast<const char*>(&fStaticData), sizeof(FTM::StaticData));
635
636 return !fout.bad();
637 }
638
639 bool SetThreshold(int32_t patch, int32_t value)
640 {
641 if (patch>159)
642 return false;
643
644 if (value<0 || value>0xffff)
645 return false;
646
647 if (patch<0)
648 {
649 bool ident = true;
650 for (int i=0; i<160; i++)
651 if (fStaticData[i/4].fDAC[patch%4] != value)
652 {
653 ident = false;
654 break;
655 }
656
657 if (ident)
658 return true;
659
660 for (int i=0; i<160; i++)
661 fStaticData[i/4].fDAC[i%4] = value;
662 }
663 else
664 {
665 if (fStaticData[patch/4].fDAC[patch%4] == value)
666 return true;
667
668 fStaticData[patch/4].fDAC[patch%4] = value;
669 }
670
671 // Maybe move to a "COMMIT" command?
672 CmdSendStatDat();
673
674 return true;
675 }
676
677 bool SetPrescaling(uint32_t value)
678 {
679 if (value>0xffff)
680 return false;
681
682
683 bool ident = true;
684 for (int i=0; i<40; i++)
685 if (fStaticData[i].fPrescaling != value)
686 {
687 ident = false;
688 break;
689 }
690
691 if (ident)
692 return true;
693
694 for (int i=0; i<40; i++)
695 fStaticData[i].fPrescaling = value;
696
697 // Maybe move to a "COMMIT" command?
698 CmdSendStatDat();
699
700 return true;
701 }
702
703 bool EnableFTU(int32_t board, bool enable)
704 {
705 if (board>39)
706 return false;
707
708 if (board<0)
709 {
710 if (enable)
711 fStaticData.EnableAllFTU();
712 else
713 fStaticData.DisableAllFTU();
714 }
715 else
716 {
717 if (enable)
718 fStaticData.EnableFTU(board);
719 else
720 fStaticData.DisableFTU(board);
721
722 }
723
724 // Maybe move to a "COMMIT" command?
725 CmdSendStatDat();
726
727 return true;
728 }
729
730 bool ToggleFTU(uint32_t board)
731 {
732 if (board>39)
733 return false;
734
735 fStaticData.ToggleFTU(board);
736
737 // Maybe move to a "COMMIT" command?
738 CmdSendStatDat();
739
740 return true;
741 }
742
743 bool SetVal(uint16_t *dest, uint32_t val, uint32_t max)
744 {
745 if (val>max)
746 return false;
747
748 if (*dest==val)
749 return true;
750
751 *dest = val;
752
753 CmdSendStatDat();
754
755 return true;
756 }
757
758 bool SetTriggerInterval(uint32_t val)
759 {
760 return SetVal(&fStaticData.fTriggerInterval, val,
761 FTM::StaticData::kMaxTriggerInterval);
762 }
763
764 bool SetTriggerDelay(uint32_t val)
765 {
766 return SetVal(&fStaticData.fDelayTrigger, val,
767 FTM::StaticData::kMaxDelayTrigger);
768 }
769
770 bool SetTimeMarkerDelay(uint32_t val)
771 {
772 return SetVal(&fStaticData.fDelayTimeMarker, val,
773 FTM::StaticData::kMaxDelayTimeMarker);
774 }
775
776 bool SetDeadTime(uint32_t val)
777 {
778 return SetVal(&fStaticData.fDeadTime, val,
779 FTM::StaticData::kMaxDeadTime);
780 }
781
782 void Enable(FTM::StaticData::GeneralSettings type, bool enable)
783 {
784 fStaticData.Enable(type, enable);
785 }
786
787 bool SetTriggerSeq(const uint8_t d[3])
788 {
789 const uint16_t oldset = fStaticData.fGeneralSettings;
790 const uint16_t oldseq = fStaticData.fTriggerSequence;
791
792 fStaticData.Enable(FTM::StaticData::kPedestal, d[0]>0);
793 fStaticData.Enable(FTM::StaticData::kLPext, d[1]>0);
794 fStaticData.Enable(FTM::StaticData::kLPint, d[2]>0);
795
796 if (d[0]>FTM::StaticData::kMaxSequence ||
797 d[1]>FTM::StaticData::kMaxSequence ||
798 d[2]>FTM::StaticData::kMaxSequence)
799 return false;
800
801 fStaticData.fTriggerSequence =
802 (d[0]<<10) | (d[1]<<5) || d[2];
803
804 if (oldseq!=fStaticData.fTriggerSequence || oldset!=fStaticData.fGeneralSettings)
805 CmdSendStatDat();
806
807 return true;
808 }
809
810 bool SetTriggerCoincidence(uint16_t n, uint16_t win)
811 {
812 if (n==0 || n>FTM::StaticData::kMaxCoincidence ||
813 win>FTM::StaticData::kMaxWindow)
814 return false;
815
816 if (n ==fStaticData.fCoincidencePhysics &&
817 win==fStaticData.fWindowPhysics)
818 return true;
819
820 fStaticData.fCoincidencePhysics = n;
821 fStaticData.fWindowPhysics = win;
822
823 CmdSendStatDat();
824
825 return true;
826 }
827
828 bool SetCalibCoincidence(uint16_t n, uint16_t win)
829 {
830 if (n==0 || n>FTM::StaticData::kMaxCoincidence ||
831 win>FTM::StaticData::kMaxWindow)
832 return false;
833
834 if (n ==fStaticData.fCoincidenceCalib &&
835 win==fStaticData.fWindowCalib)
836 return true;
837
838 fStaticData.fCoincidenceCalib = n;
839 fStaticData.fWindowCalib = win;
840
841 CmdSendStatDat();
842
843 return true;
844 }
845
846 int GetState() const { return IsConnected() ? fState : (int)FTM::kDisconnected; }
847};
848
849const uint16_t ConnectionFTM::kMaxAddr = 0xfff;
850
851// ------------------------------------------------------------------------
852
853#include "DimDescriptionService.h"
854
855class ConnectionDimFTM : public ConnectionFTM
856{
857private:
858
859 DimDescribedService fDimPassport;
860 DimDescribedService fDimTriggerCounter;
861 DimDescribedService fDimError;
862 DimDescribedService fDimFtuList;
863 DimDescribedService fDimStaticData;
864 DimDescribedService fDimDynamicData;
865 DimDescribedService fDimCounter;
866
867 template<class T>
868 void Update(DimDescribedService &svc, const T &data) const
869 {
870 //cout << "Update: " << svc.getName() << " (" << sizeof(T) << ")" << endl;
871 svc.setData(const_cast<T*>(&data), sizeof(T));
872 svc.updateService();
873 }
874
875 void UpdateFirstHeader()
876 {
877 ConnectionFTM::UpdateFirstHeader();
878
879 const FTM::DimPassport data(fHeader);
880 Update(fDimPassport, data);
881 }
882
883 void UpdateHeader()
884 {
885 ConnectionFTM::UpdateHeader();
886
887 const FTM::DimTriggerCounter data(fHeader);
888 Update(fDimTriggerCounter, data);
889 }
890
891 void UpdateFtuList()
892 {
893 ConnectionFTM::UpdateFtuList();
894
895 const FTM::DimFtuList data(fHeader, fFtuList);
896 Update(fDimFtuList, data);
897 }
898
899 void UpdateStaticData()
900 {
901 ConnectionFTM::UpdateStaticData();
902
903 const FTM::DimStaticData data(fHeader, fStaticData);
904 Update(fDimStaticData, data);
905 }
906
907 void UpdateDynamicData()
908 {
909 ConnectionFTM::UpdateDynamicData();
910
911 const FTM::DimDynamicData data(fHeader, fDynamicData);
912 Update(fDimDynamicData, data);
913 }
914
915 void UpdateError()
916 {
917 ConnectionFTM::UpdateError();
918
919 const FTM::DimError data(fHeader, fError);
920 Update(fDimError, data);
921 }
922
923 void UpdateCounter()
924 {
925 ConnectionFTM::UpdateCounter();
926
927 const uint32_t counter[6] =
928 {
929 fCounter[FTM::kHeader],
930 fCounter[FTM::kStaticData],
931 fCounter[FTM::kDynamicData],
932 fCounter[FTM::kFtuList],
933 fCounter[FTM::kErrorList],
934 fCounter[FTM::kRegister],
935 };
936
937 Update(fDimCounter, counter);
938 }
939
940public:
941 ConnectionDimFTM(ba::io_service& ioservice, MessageImp &imp) :
942 ConnectionFTM(ioservice, imp),
943 fDimPassport ("FTM_CONTROL/PASSPORT", "X:1;S:1", ""),
944 fDimTriggerCounter("FTM_CONTROL/TRIGGER_COUNTER", "X:1;S:1;S:1;S:2;S:1;S:1;S:21;S:1;S:1", ""),
945 fDimError ("FTM_CONTROL/ERROR", "X:1;S:1;S:28", ""),
946 fDimFtuList ("FTM_CONTROL/FTU_LIST", "X:1;X:1;S:1;C:4;X:40;C:40;C:40", ""),
947 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", ""),
948 fDimDynamicData ("FTM_CONTROL/DYNAMIC_DATA", "X:1;X:1;F:4;I:160;I:40;S:40;S:40", ""),
949 fDimCounter ("FTM_CONTROL/COUNTER", "I:6", "")
950 {
951 }
952
953 // 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
954};
955
956// ------------------------------------------------------------------------
957
958template <class T, class S>
959class StateMachineFTM : public T, public ba::io_service, public ba::io_service::work
960{
961 int Wrap(boost::function<void()> f)
962 {
963 f();
964 return T::GetCurrentState();
965 }
966
967 boost::function<int(const EventImp &)> Wrapper(boost::function<void()> func)
968 {
969 return boost::bind(&StateMachineFTM::Wrap, this, func);
970 }
971
972private:
973 S fFTM;
974
975 enum states_t
976 {
977 kStateDisconnected = FTM::kDisconnected,
978 kStateConnected = FTM::kConnected,
979 kStateIdle = FTM::kIdle,
980 kStateTakingData = FTM::kTakingData,
981
982 kCmdTest
983 };
984
985 bool CheckEventSize(size_t has, const char *name, size_t size)
986 {
987 if (has==size)
988 return true;
989
990 stringstream msg;
991 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
992 T::Fatal(msg);
993 return false;
994 }
995
996 int SetRegister(const EventImp &evt)
997 {
998 if (!CheckEventSize(evt.GetSize(), "SetRegister", 8))
999 return T::kSM_FatalError;
1000
1001 const unsigned int *dat = reinterpret_cast<const unsigned int*>(evt.GetData());
1002
1003 if (dat[1]>uint16_t(-1))
1004 {
1005 stringstream msg;
1006 msg << hex << "Value " << dat[1] << " out of range.";
1007 T::Error(msg);
1008 return T::GetCurrentState();
1009 }
1010
1011
1012 if (dat[0]>uint16_t(-1) || !fFTM.CmdSetRegister(dat[0], dat[1]))
1013 {
1014 stringstream msg;
1015 msg << hex << "Address " << dat[0] << " out of range.";
1016 T::Error(msg);
1017 }
1018
1019 return T::GetCurrentState();
1020 }
1021
1022 int GetRegister(const EventImp &evt)
1023 {
1024 if (!CheckEventSize(evt.GetSize(), "GetRegister", 4))
1025 return T::kSM_FatalError;
1026
1027 const unsigned int addr = evt.GetInt();
1028 if (addr>uint16_t(-1) || !fFTM.CmdGetRegister(addr))
1029 {
1030 stringstream msg;
1031 msg << hex << "Address " << addr << " out of range.";
1032 T::Error(msg);
1033 }
1034
1035 return T::GetCurrentState();
1036 }
1037
1038 int TakeNevents(const EventImp &evt)
1039 {
1040 if (!CheckEventSize(evt.GetSize(), "TakeNevents", 4))
1041 return T::kSM_FatalError;
1042
1043 const unsigned int dat = evt.GetUInt();
1044
1045 /*
1046 if (dat[1]>uint32_t(-1))
1047 {
1048 stringstream msg;
1049 msg << hex << "Value " << dat[1] << " out of range.";
1050 T::Error(msg);
1051 return T::GetCurrentState();
1052 }*/
1053
1054 fFTM.CmdTakeNevents(dat);
1055
1056 return T::GetCurrentState();
1057 }
1058
1059 int DisableReports(const EventImp &evt)
1060 {
1061 if (!CheckEventSize(evt.GetSize(), "DisableReports", 1))
1062 return T::kSM_FatalError;
1063
1064 fFTM.CmdDisableReports(evt.GetText()[0]!=0);
1065
1066 return T::GetCurrentState();
1067 }
1068
1069 int SetVerbosity(const EventImp &evt)
1070 {
1071 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
1072 return T::kSM_FatalError;
1073
1074 fFTM.SetVerbose(evt.GetText()[0]!=0);
1075
1076 return T::GetCurrentState();
1077 }
1078
1079 int SetHexOutput(const EventImp &evt)
1080 {
1081 if (!CheckEventSize(evt.GetSize(), "SetHexOutput", 1))
1082 return T::kSM_FatalError;
1083
1084 fFTM.SetHexOutput(evt.GetText()[0]!=0);
1085
1086 return T::GetCurrentState();
1087 }
1088
1089 int SetDynamicOut(const EventImp &evt)
1090 {
1091 if (!CheckEventSize(evt.GetSize(), "SetDynamicOut", 1))
1092 return T::kSM_FatalError;
1093
1094 fFTM.SetDynamicOut(evt.GetText()[0]!=0);
1095
1096 return T::GetCurrentState();
1097 }
1098
1099 int LoadStaticData(const EventImp &evt)
1100 {
1101 if (fFTM.LoadStaticData(evt.GetString()))
1102 return T::GetCurrentState();
1103
1104 stringstream msg;
1105 msg << "Loading static data from file '" << evt.GetString() << "' failed ";
1106
1107 if (errno)
1108 msg << "(" << strerror(errno) << ")";
1109 else
1110 msg << "(wrong size, expected " << sizeof(FTM::StaticData) << " bytes)";
1111
1112 T::Warn(msg);
1113
1114 return T::GetCurrentState();
1115 }
1116
1117 int SaveStaticData(const EventImp &evt)
1118 {
1119 if (fFTM.SaveStaticData(evt.GetString()))
1120 return T::GetCurrentState();
1121
1122 stringstream msg;
1123 msg << "Writing static data to file '" << evt.GetString() << "' failed ";
1124 msg << "(" << strerror(errno) << ")";
1125
1126 T::Warn(msg);
1127
1128 return T::GetCurrentState();
1129 }
1130
1131 int SetThreshold(const EventImp &evt)
1132 {
1133 if (!CheckEventSize(evt.GetSize(), "SetThreshold", 8))
1134 return T::kSM_FatalError;
1135
1136 const int32_t *data = reinterpret_cast<const int32_t*>(evt.GetData());
1137
1138 if (!fFTM.SetThreshold(data[0], data[1]))
1139 T::Warn("SetThreshold - Maximum allowed patch number 159, valid value range 0-0xffff");
1140
1141 return T::GetCurrentState();
1142 }
1143
1144 int EnableFTU(const EventImp &evt)
1145 {
1146 if (!CheckEventSize(evt.GetSize(), "EnableFTU", 5))
1147 return T::kSM_FatalError;
1148
1149 const int32_t &board = *reinterpret_cast<const int32_t*>(evt.GetText());
1150 const int8_t &enable = *reinterpret_cast<const int8_t*>(evt.GetText()+4);
1151
1152 if (!fFTM.EnableFTU(board, enable))
1153 T::Warn("EnableFTU - Board number must be <40.");
1154
1155 return T::GetCurrentState();
1156 }
1157
1158 int ToggleFTU(const EventImp &evt)
1159 {
1160 if (!CheckEventSize(evt.GetSize(), "ToggleFTU", 4))
1161 return T::kSM_FatalError;
1162
1163 if (!fFTM.ToggleFTU(evt.GetInt()))
1164 T::Warn("ToggleFTU - Allowed range of boards 0-39.");
1165
1166 return T::GetCurrentState();
1167 }
1168
1169 int SetTriggerInterval(const EventImp &evt)
1170 {
1171 if (!CheckEventSize(evt.GetSize(), "SetTriggerInterval", 4))
1172 return T::kSM_FatalError;
1173
1174 if (!fFTM.SetTriggerInterval(evt.GetInt()))
1175 T::Warn("SetTriggerInterval - Value out of range.");
1176
1177 return T::GetCurrentState();
1178 }
1179
1180 int SetTriggerDelay(const EventImp &evt)
1181 {
1182 if (!CheckEventSize(evt.GetSize(), "SetTriggerDelay", 4))
1183 return T::kSM_FatalError;
1184
1185 if (!fFTM.SetTriggerDelay(evt.GetInt()))
1186 T::Warn("SetTriggerDealy - Value out of range.");
1187
1188 return T::GetCurrentState();
1189 }
1190
1191 int SetTimeMarkerDelay(const EventImp &evt)
1192 {
1193 if (!CheckEventSize(evt.GetSize(), "SetTimeMarkerDelay", 4))
1194 return T::kSM_FatalError;
1195
1196 if (!fFTM.SetTimeMarkerDelay(evt.GetInt()))
1197 T::Warn("SetTimeMarkerDelay - Value out of range.");
1198
1199 return T::GetCurrentState();
1200 }
1201
1202 int SetPrescaling(const EventImp &evt)
1203 {
1204 if (!CheckEventSize(evt.GetSize(), "SetPrescaling", 4))
1205 return T::kSM_FatalError;
1206
1207 if (!fFTM.SetPrescaling(evt.GetInt()))
1208 T::Warn("SetPrescaling - Value out of range.");
1209
1210 return T::GetCurrentState();
1211 }
1212
1213 int SetTriggerSeq(const EventImp &evt)
1214 {
1215 if (!CheckEventSize(evt.GetSize(), "SetTriggerSeq", 3))
1216 return T::kSM_FatalError;
1217
1218 const uint8_t *data = reinterpret_cast<const uint8_t*>(evt.GetData());
1219
1220 if (!fFTM.SetTriggerSeq(data))
1221 T::Warn("SetTriggerSeq - Value out of range.");
1222
1223 return T::GetCurrentState();
1224 }
1225
1226 int SetDeadTime(const EventImp &evt)
1227 {
1228 if (!CheckEventSize(evt.GetSize(), "SetDeadTime", 4))
1229 return T::kSM_FatalError;
1230
1231 if (!fFTM.SetDeadTime(evt.GetInt()))
1232 T::Warn("SetDeadTime - Value out of range.");
1233
1234 return T::GetCurrentState();
1235 }
1236
1237 int SetTriggerCoincidence(const EventImp &evt)
1238 {
1239 if (!CheckEventSize(evt.GetSize(), "SetTriggerCoincidence", 4))
1240 return T::kSM_FatalError;
1241
1242 const uint16_t *d = reinterpret_cast<const uint16_t*>(evt.GetText());;
1243
1244 if (!fFTM.SetTriggerCoincidence(d[0], d[1]))
1245 T::Warn("SetTriggerCoincidence - Value out of range.");
1246
1247 return T::GetCurrentState();
1248 }
1249
1250 int SetCalibCoincidence(const EventImp &evt)
1251 {
1252 if (!CheckEventSize(evt.GetSize(), "SetCalibCoincidence", 4))
1253 return T::kSM_FatalError;
1254
1255 const uint16_t *d = reinterpret_cast<const uint16_t*>(evt.GetText());;
1256
1257 if (!fFTM.SetCalibCoincidence(d[0], d[1]))
1258 T::Warn("SetCalibCoincidence - Value out of range.");
1259
1260 return T::GetCurrentState();
1261 }
1262
1263 int Enable(const EventImp &evt, FTM::StaticData::GeneralSettings type)
1264 {
1265 if (!CheckEventSize(evt.GetSize(), "Enable", 1))
1266 return T::kSM_FatalError;
1267
1268 fFTM.Enable(type, evt.GetText()[0]!=0);
1269
1270 return T::GetCurrentState();
1271 }
1272
1273 int Disconnect()
1274 {
1275 // Close all connections
1276 fFTM.PostClose(false);
1277
1278 /*
1279 // Now wait until all connection have been closed and
1280 // all pending handlers have been processed
1281 poll();
1282 */
1283
1284 return T::GetCurrentState();
1285 }
1286
1287 int Reconnect(const EventImp &evt)
1288 {
1289 // Close all connections to supress the warning in SetEndpoint
1290 fFTM.PostClose(false);
1291
1292 // Now wait until all connection have been closed and
1293 // all pending handlers have been processed
1294 poll();
1295
1296 if (evt.GetText()[0]!=0)
1297 fFTM.SetEndpoint(evt.GetString());
1298
1299 // Now we can reopen the connection
1300 fFTM.PostClose(true);
1301
1302 return T::GetCurrentState();
1303 }
1304
1305 /*
1306 int Transition(const Event &evt)
1307 {
1308 switch (evt.GetTargetState())
1309 {
1310 case kStateDisconnected:
1311 case kStateConnected:
1312 }
1313
1314 return T::kSM_FatalError;
1315 }*/
1316
1317 int Execute()
1318 {
1319 // Dispatch (execute) at most one handler from the queue. In contrary
1320 // to run_one(), it doesn't wait until a handler is available
1321 // which can be dispatched, so poll_one() might return with 0
1322 // handlers dispatched. The handlers are always dispatched/executed
1323 // synchronously, i.e. within the call to poll_one()
1324 poll_one();
1325
1326 return fFTM.GetState();
1327 }
1328
1329public:
1330 StateMachineFTM(ostream &out=cout) :
1331 T(out, "FTM_CONTROL"), ba::io_service::work(static_cast<ba::io_service&>(*this)),
1332 fFTM(*this, *this)
1333 {
1334 // ba::io_service::work is a kind of keep_alive for the loop.
1335 // It prevents the io_service to go to stopped state, which
1336 // would prevent any consecutive calls to run()
1337 // or poll() to do nothing. reset() could also revoke to the
1338 // previous state but this might introduce some overhead of
1339 // deletion and creation of threads and more.
1340
1341 // State names
1342 AddStateName(kStateDisconnected, "Disconnected",
1343 "FTM board not connected via ethernet.");
1344
1345 AddStateName(kStateConnected, "Connected",
1346 "Ethernet connection to FTM established (no state received yet).");
1347
1348 AddStateName(kStateIdle, "Idle",
1349 "Ethernet connection to FTM established, FTM in idle state.");
1350
1351 AddStateName(kStateTakingData, "TakingData",
1352 "Ethernet connection to FTM established, FTM is in taking data state.");
1353
1354 // FTM Commands
1355 AddConfiguration("TOGGLE_LED", kStateIdle)
1356 (Wrapper(boost::bind(&ConnectionFTM::CmdToggleLed, &fFTM)))
1357 ("toggle led");
1358
1359 AddConfiguration("PING", kStateIdle)
1360 (Wrapper(boost::bind(&ConnectionFTM::CmdPing, &fFTM)))
1361 ("send ping");
1362
1363 AddConfiguration("REQUEST_DYNAMIC_DATA", kStateIdle)
1364 (Wrapper(boost::bind(&ConnectionFTM::CmdReqDynDat, &fFTM)))
1365 ("request transmission of dynamic data block");
1366
1367 AddConfiguration("REQUEST_STATIC_DATA", kStateIdle)
1368 (Wrapper(boost::bind(&ConnectionFTM::CmdReqStatDat, &fFTM)))
1369 ("request transmission of static data from FTM to memory");
1370
1371 AddConfiguration("GET_REGISTER", "I", kStateIdle)
1372 (boost::bind(&StateMachineFTM::GetRegister, this, _1))
1373 ("read register from address addr"
1374 "|addr[short]:Address of register");
1375
1376 AddConfiguration("SET_REGISTER", "I:2", kStateIdle)
1377 (boost::bind(&StateMachineFTM::SetRegister, this, _1))
1378 ("set register to value"
1379 "|addr[short]:Address of register"
1380 "|val[short]:Value to be set");
1381
1382 AddConfiguration("START_RUN", kStateIdle)
1383 (Wrapper(boost::bind(&ConnectionFTM::CmdStartRun, &fFTM)))
1384 ("start a run (start distributing triggers)");
1385
1386 AddConfiguration("STOP_RUN", kStateTakingData)
1387 (Wrapper(boost::bind(&ConnectionFTM::CmdStopRun, &fFTM)))
1388 ("stop a run (stop distributing triggers)");
1389
1390 AddConfiguration("TAKE_N_EVENTS", "I", kStateIdle)
1391 (boost::bind(&StateMachineFTM::TakeNevents, this, _1))
1392 ("take n events (distribute n triggers)|number[int]:Number of events to be taken");
1393
1394 AddConfiguration("DISABLE_REPORTS", "B", kStateIdle)
1395 (boost::bind(&StateMachineFTM::DisableReports, this, _1))
1396 ("disable sending rate reports"
1397 "|status[bool]:disable or enable that the FTM sends rate reports (yes/no)");
1398
1399 AddConfiguration("SET_THRESHOLD", "I:2", kStateIdle)
1400 (boost::bind(&StateMachineFTM::SetThreshold, this, _1))
1401 ("Set the comparator threshold"
1402 "|Patch[idx]:Index of the patch (0-159), -1 for all"
1403 "|Threshold[counts]:Threshold to be set in binary counts");
1404
1405 AddConfiguration("SET_PRESCALING", "I:1", kStateIdle)
1406 (boost::bind(&StateMachineFTM::SetPrescaling, this, _1))
1407 (""
1408 "|[]:");
1409
1410 AddConfiguration("ENABLE_FTU", "I:1;B:1", kStateIdle)
1411 (boost::bind(&StateMachineFTM::EnableFTU, this, _1))
1412 ("Enable or disable FTU"
1413 "|Board[idx]:Index of the board (0-39), -1 for all"
1414 "|Enable[bool]:Whether FTU should be enabled or disabled (yes/no)");
1415
1416 AddConfiguration("TOGGLE_FTU", "I:1", kStateIdle)
1417 (boost::bind(&StateMachineFTM::ToggleFTU, this, _1))
1418 ("Toggle status of FTU (this is mainly meant to be used in the GUI)"
1419 "|Board[idx]:Index of the board (0-39)");
1420
1421 AddConfiguration("SET_TRIGGER_INTERVAL", "I:1", kStateIdle)
1422 (boost::bind(&StateMachineFTM::SetTriggerInterval, this, _1))
1423 ("Sets the trigger interval which is the distance between two consecutive artificial triggers."
1424 "|interval[int]:The applied trigger interval is: interval*4ns+8ns");
1425
1426 AddConfiguration("SET_TRIGGER_DELAY", "I:1", kStateIdle)
1427 (boost::bind(&StateMachineFTM::SetTriggerDelay, this, _1))
1428 (""
1429 "|delay[int]:The applied trigger delay is: delay*4ns+8ns");
1430
1431 AddConfiguration("SET_TIME_MARKER_DELAY", "I:1", kStateIdle)
1432 (boost::bind(&StateMachineFTM::SetTimeMarkerDelay, this, _1))
1433 (""
1434 "|delay[int]:The applied time marker delay is: delay*4ns+8ns");
1435
1436 AddConfiguration("SET_DEAD_TIME", "I:1", kStateIdle)
1437 (boost::bind(&StateMachineFTM::SetDeadTime, this, _1))
1438 (""
1439 "|dead_time[int]:The applied dead time is: dead_time*4ns+8ns");
1440
1441 AddConfiguration("ENABLE_TRIGGER", "B:1", kStateIdle)
1442 (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kTrigger))
1443 ("Switch on the physics trigger"
1444 "|Enable[bool]:Enable physics trigger (yes/no)");
1445
1446 // FIXME: Switch on/off depending on sequence
1447 AddConfiguration("ENABLE_EXT1", "B:1", kStateIdle)
1448 (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kExt1))
1449 ("Switch on the triggers through the first external line"
1450 "|Enable[bool]:Enable ext1 trigger (yes/no)");
1451
1452 // FIXME: Switch on/off depending on sequence
1453 AddConfiguration("ENABLE_EXT2", "B:1", kStateIdle)
1454 (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kExt2))
1455 ("Switch on the triggers through the second external line"
1456 "|Enable[bool]:Enable ext2 trigger (yes/no)");
1457
1458 AddConfiguration("ENABLE_VETO", "B:1", kStateIdle)
1459 (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kVeto))
1460 ("Enable veto line"
1461 "|Enable[bool]:Enable veto (yes/no)");
1462
1463 AddConfiguration("SET_TRIGGER_SEQUENCE", "C:3", kStateIdle)
1464 (boost::bind(&StateMachineFTM::SetTriggerSeq, this, _1))
1465 ("Setup the sequence of artificial triggers produced by the FTM"
1466 "|Ped[int]:number of pedestal triggers in a row"
1467 "|LPint[int]:number of triggers of the internal light pulser"
1468 "|LPext[int]:number of triggers of the external light pulser");
1469
1470 AddConfiguration("SET_TRIGGER_COINCIDENCE", "S:2", kStateIdle)
1471 (boost::bind(&StateMachineFTM::SetTriggerCoincidence, this, _1))
1472 ("Setup the coincidence condition for physcis triggers"
1473 "|N[int]:Number of requirered coincident triggers from sum-patches (1-40)");
1474
1475 AddConfiguration("SET_CALIBRATION_COINCIDENCE", "S:2", kStateIdle)
1476 (boost::bind(&StateMachineFTM::SetCalibCoincidence, this, _1))
1477 ("Setup the coincidence condition for artificial (calibration) triggers"
1478 "|N[int]:Number of requirered coincident triggers from sum-patches (1-40)");
1479
1480
1481 // Load/save static data block
1482 T::AddConfiguration("SAVE", "C", kStateIdle)
1483 (boost::bind(&StateMachineFTM::SaveStaticData, this, _1))
1484 ("Saves the static data (FTM configuration) from memory to a file"
1485 "|filename[string]:Filename (can include a path), .bin is automatically added");
1486
1487 T::AddConfiguration("LOAD", "C", kStateIdle)
1488 (boost::bind(&StateMachineFTM::LoadStaticData, this, _1))
1489 ("Loads the static data (FTM configuration) from a file into memory and sends it to the FTM"
1490 "|filename[string]:Filename (can include a path), .bin is automatically added");
1491
1492
1493
1494 // Verbosity commands
1495 T::AddConfiguration("SET_VERBOSE", "B")
1496 (boost::bind(&StateMachineFTM::SetVerbosity, this, _1))
1497 ("set verbosity state"
1498 "|verbosity[bool]:disable or enable verbosity for received data (yes/no)");
1499
1500 T::AddConfiguration("SET_HEX_OUTPUT", "B")
1501 (boost::bind(&StateMachineFTM::SetHexOutput, this, _1))
1502 ("enable or disable hex output for received data"
1503 "|hexout[bool]:disable or enable hex output for verbose and received data (yes/no)");
1504
1505 T::AddConfiguration("SET_DYNAMIC_OUTPUT", "B")
1506 (boost::bind(&StateMachineFTM::SetDynamicOut, this, _1))
1507 ("enable or disable output for received dynamic data (data is still broadcasted via Dim)"
1508 "|dynout[bool]:disable or enable output for dynamic data (yes/no)");
1509
1510
1511 // Conenction commands
1512 AddConfiguration("DISCONNECT", kStateConnected, kStateIdle)
1513 (boost::bind(&StateMachineFTM::Disconnect, this))
1514 ("disconnect from ethernet");
1515
1516 AddConfiguration("RECONNECT", "O", kStateDisconnected, kStateConnected, kStateIdle)
1517 (boost::bind(&StateMachineFTM::Reconnect, this, _1))
1518 ("(Re)connect ethernet connection to FTM, a new address can be given"
1519 "|[host][string]:new ethernet address in the form <host:port>");
1520
1521 // Other
1522 AddTransition(kCmdTest, "TEST", "O")
1523 (boost::bind(&StateMachineFTM::Test, this, _1))
1524 ("Just for test purpose, do not use");
1525
1526 fFTM.StartConnect();
1527 }
1528
1529 /// Just for test purpose, do not touch
1530 int Test(const Event &evt)
1531 {
1532 const Converter conv(T::Out(), evt.GetFormat(), false);
1533 T::Out() << kBlue << evt.GetName();
1534 T::Out() << " " << conv.GetString(evt.GetData(), evt.GetSize());
1535 T::Out() << endl;
1536
1537 return T::GetCurrentState();
1538 }
1539
1540 void SetEndpoint(const string &url)
1541 {
1542 fFTM.SetEndpoint(url);
1543 }
1544
1545 bool SetConfiguration(const Configuration &conf)
1546 {
1547 SetEndpoint(conf.Get<string>("addr"));
1548
1549 fFTM.SetVerbose(!conf.Get<bool>("quiet"));
1550 fFTM.SetHexOutput(conf.Get<bool>("hex-out"));
1551 fFTM.SetDynamicOut(conf.Get<bool>("dynamic-out"));
1552
1553 return true;
1554 }
1555};
1556
1557// ------------------------------------------------------------------------
1558
1559void RunThread(StateMachineImp *io_service)
1560{
1561 // This is necessary so that the StateMachien Thread can signal the
1562 // Readline to exit
1563 io_service->Run();
1564 Readline::Stop();
1565}
1566
1567template<class S, class T>
1568int RunDim(Configuration &conf)
1569{
1570 WindowLog wout;
1571
1572 /*
1573 static Test shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
1574
1575 WindowLog &win = shell.GetStreamIn();
1576 WindowLog &wout = shell.GetStreamOut();
1577 */
1578
1579 if (conf.Has("log"))
1580 if (!wout.OpenLogFile(conf.Get<string>("log")))
1581 wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
1582
1583 // Start io_service.Run to use the StateMachineImp::Run() loop
1584 // Start io_service.run to only use the commandHandler command detaching
1585 StateMachineFTM<S, T> io_service(wout);
1586 if (!io_service.SetConfiguration(conf))
1587 return -1;
1588
1589 io_service.Run();
1590
1591 /*
1592 shell.SetReceiver(io_service);
1593
1594 boost::thread t(boost::bind(RunThread, &io_service));
1595 // boost::thread t(boost::bind(&StateMachineFTM<S>::Run, &io_service));
1596
1597 shell.Run(); // Run the shell
1598 io_service.Stop(); // Signal Loop-thread to stop
1599 // io_service.Close(); // Obsolete, done by the destructor
1600
1601 // Wait until the StateMachine has finished its thread
1602 // before returning and destroying the dim objects which might
1603 // still be in use.
1604 t.join();
1605 */
1606
1607 return 0;
1608}
1609
1610template<class T, class S, class R>
1611int RunShell(Configuration &conf)
1612{
1613 static T shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
1614
1615 WindowLog &win = shell.GetStreamIn();
1616 WindowLog &wout = shell.GetStreamOut();
1617
1618 if (conf.Has("log"))
1619 if (!wout.OpenLogFile(conf.Get<string>("log")))
1620 win << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
1621
1622 StateMachineFTM<S, R> io_service(wout);
1623 if (!io_service.SetConfiguration(conf))
1624 return -1;
1625
1626 shell.SetReceiver(io_service);
1627
1628 boost::thread t(boost::bind(RunThread, &io_service));
1629 // boost::thread t(boost::bind(&StateMachineFTM<S>::Run, &io_service));
1630
1631 shell.Run(); // Run the shell
1632 io_service.Stop(); // Signal Loop-thread to stop
1633 // io_service.Close(); // Obsolete, done by the destructor
1634
1635 // Wait until the StateMachine has finished its thread
1636 // before returning and destroying the dim objects which might
1637 // still be in use.
1638 t.join();
1639
1640 return 0;
1641}
1642
1643void SetupConfiguration(Configuration &conf)
1644{
1645 const string n = conf.GetName()+".log";
1646
1647 po::options_description config("Program options");
1648 config.add_options()
1649 ("dns", var<string>("localhost"), "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
1650 ("log,l", var<string>(n), "Write log-file")
1651 ("no-dim,d", po_switch(), "Disable dim services")
1652 ("console,c", var<int>(), "Use console (0=shell, 1=simple buffered, X=simple unbuffered)")
1653 ;
1654
1655 po::options_description control("FTM control options");
1656 control.add_options()
1657 ("addr,a", var<string>("localhost:5000"), "Network address of FTM")
1658 ("quiet,q", po_switch(), "Disable printing contents of all received messages (except dynamic data) in clear text.")
1659 ("hex-out", po_switch(), "Enable printing contents of all printed messages also as hex data.")
1660 ("dynamic-out", po_switch(), "Enable printing received dynamic data.")
1661 ;
1662
1663 conf.AddEnv("dns", "DIM_DNS_NODE");
1664
1665 conf.AddOptions(config);
1666 conf.AddOptions(control);
1667}
1668
1669/*
1670 Extract usage clause(s) [if any] for SYNOPSIS.
1671 Translators: "Usage" and "or" here are patterns (regular expressions) which
1672 are used to match the usage synopsis in program output. An example from cp
1673 (GNU coreutils) which contains both strings:
1674 Usage: cp [OPTION]... [-T] SOURCE DEST
1675 or: cp [OPTION]... SOURCE... DIRECTORY
1676 or: cp [OPTION]... -t DIRECTORY SOURCE...
1677 */
1678void PrintUsage()
1679{
1680 cout <<
1681 "The ftmctrl controls the FTM (FACT Trigger Master) board.\n"
1682 "\n"
1683 "The default is that the program is started without user intercation. "
1684 "All actions are supposed to arrive as DimCommands. Using the -c "
1685 "option, a local shell can be initialized. With h or help a short "
1686 "help message about the usuage can be brought to the screen.\n"
1687 "\n"
1688 "Usage: ftmctrl [-c type] [OPTIONS]\n"
1689 " or: ftmctrl [OPTIONS]\n";
1690 cout << endl;
1691}
1692
1693void PrintHelp()
1694{
1695 /* Additional help text which is printed after the configuration
1696 options goes here */
1697
1698 /*
1699 cout << "bla bla bla" << endl << endl;
1700 cout << endl;
1701 cout << "Environment:" << endl;
1702 cout << "environment" << endl;
1703 cout << endl;
1704 cout << "Examples:" << endl;
1705 cout << "test exam" << endl;
1706 cout << endl;
1707 cout << "Files:" << endl;
1708 cout << "files" << endl;
1709 cout << endl;
1710 */
1711}
1712
1713/*
1714string GetLocalIp()
1715{
1716 const char *kDnsIp = getenv("DIM_DNS_NODE");
1717
1718 struct addrinfo hints, *servinfo, *p;
1719
1720 memset(&hints, 0, sizeof hints);
1721 hints.ai_family = AF_INET; //AF_UNSPEC; // use AF_INET6 to force IPv6
1722 hints.ai_socktype = SOCK_STREAM;
1723
1724 int rv;
1725 if ((rv = getaddrinfo(kDnsIp, NULL, &hints, &servinfo)) != 0)
1726 {
1727 cout << "WARNING - getaddrinfo: " << gai_strerror(rv) << endl;
1728 return kDnsIp;
1729 }
1730
1731 // loop through all the results and connect to the first we can
1732 for (p=servinfo; p; p=p->ai_next)
1733 {
1734 const int sock = socket(AF_INET, SOCK_DGRAM, 0);
1735 if (sock==-1)
1736 continue;
1737
1738 if (connect(sock, p->ai_addr, p->ai_addrlen)==-1)
1739 {
1740 cout << "WARNING - connect: " << strerror(errno) << endl;
1741 close(sock);
1742 continue;
1743 }
1744
1745 sockaddr_in name;
1746 socklen_t namelen = sizeof(name);
1747 if (getsockname(sock, (sockaddr*)&name, &namelen)==-1)
1748 {
1749 cout << "WARNING - getsockname: " << strerror(errno) << endl;
1750 close(sock);
1751 continue;
1752 }
1753
1754 char buffer[16];
1755 if (!inet_ntop(AF_INET, &name.sin_addr, buffer, 16))
1756 {
1757 cout << "WARNING - inet_ntop: " << strerror(errno) << endl;
1758 close(sock);
1759 continue;
1760 }
1761
1762 close(sock);
1763
1764 freeaddrinfo(servinfo); // all done with this structure
1765
1766 cout << "DIM_HOST_NODE=" << buffer << endl;
1767 return buffer;
1768 }
1769
1770 freeaddrinfo(servinfo); // all done with this structure
1771 return kDnsIp;
1772}
1773*/
1774
1775int main(int argc, const char* argv[])
1776{
1777 Configuration conf(argv[0]);
1778 conf.SetPrintUsage(PrintUsage);
1779 SetupConfiguration(conf);
1780
1781 po::variables_map vm;
1782 try
1783 {
1784 vm = conf.Parse(argc, argv);
1785 }
1786#if BOOST_VERSION > 104000
1787 catch (po::multiple_occurrences &e)
1788 {
1789 cout << "Error: " << e.what() << " of '" << e.get_option_name() << "' option." << endl;
1790 cout << endl;
1791 return -1;
1792 }
1793#endif
1794 catch (std::exception &e)
1795 {
1796 cout << "Error: " << e.what() << endl;
1797 cout << endl;
1798
1799 return -1;
1800 }
1801
1802 if (conf.HasPrint())
1803 return -1;
1804
1805 if (conf.HasVersion())
1806 {
1807 FACT::PrintVersion(argv[0]);
1808 return -1;
1809 }
1810
1811 if (conf.HasHelp())
1812 {
1813 PrintHelp();
1814 return -1;
1815 }
1816
1817 Dim::Setup(conf.Get<string>("dns"));
1818
1819 //try
1820 {
1821 // No console access at all
1822 if (!conf.Has("console"))
1823 {
1824 if (conf.Get<bool>("no-dim"))
1825 return RunDim<StateMachine, ConnectionFTM>(conf);
1826 else
1827 return RunDim<StateMachineDim, ConnectionDimFTM>(conf);
1828 }
1829 // Cosole access w/ and w/o Dim
1830 if (conf.Get<bool>("no-dim"))
1831 {
1832 if (conf.Get<int>("console")==0)
1833 return RunShell<LocalShell, StateMachine, ConnectionFTM>(conf);
1834 else
1835 return RunShell<LocalConsole, StateMachine, ConnectionFTM>(conf);
1836 }
1837 else
1838 {
1839 if (conf.Get<int>("console")==0)
1840 return RunShell<LocalShell, StateMachineDim, ConnectionDimFTM>(conf);
1841 else
1842 return RunShell<LocalConsole, StateMachineDim, ConnectionDimFTM>(conf);
1843 }
1844 }
1845 /*catch (std::exception& e)
1846 {
1847 cerr << "Exception: " << e.what() << endl;
1848 return -1;
1849 }*/
1850
1851 return 0;
1852}
Note: See TracBrowser for help on using the repository browser.