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

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