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

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