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

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