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

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