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

Last change on this file since 11116 was 11107, checked in by tbretz, 13 years ago
Changed clock conditioner values.
File size: 60.1 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 SetClockRegister(const uint64_t reg[])
901 {
902 for (int i=0; i<8; i++)
903 {
904 if (reg[i]>0xffffffff)
905 return false;
906
907 fStaticData.fClockConditioner[i] = reg[i];
908 }
909
910 CmdSendStatDat();
911
912 return true;
913 }
914
915 bool EnablePixel(int16_t idx, bool enable)
916 {
917 if (idx<-1 || idx>FTM::StaticData::kMaxPixelIdx)
918 return false;
919
920 if (idx==-1)
921 for (int i=0; i<=FTM::StaticData::kMaxPixelIdx; i++)
922 fStaticData.EnablePixel(i, enable);
923 else
924 fStaticData.EnablePixel(idx, enable);
925
926 CmdSendStatDat();
927
928 return true;
929 }
930
931 bool DisableAllPixelsExcept(uint16_t idx)
932 {
933 if (idx>FTM::StaticData::kMaxPixelIdx)
934 return false;
935
936 for (int i=0; i<=FTM::StaticData::kMaxPixelIdx; i++)
937 fStaticData.EnablePixel(i, i==idx);
938
939 CmdSendStatDat();
940
941 return true;
942 }
943
944 bool DisableAllPatchesExcept(uint16_t idx)
945 {
946 if (idx>FTM::StaticData::kMaxPatchIdx)
947 return false;
948
949 for (int i=0; i<=FTM::StaticData::kMaxPixelIdx; i++)
950 fStaticData.EnablePixel(i, i/9==idx);
951
952 CmdSendStatDat();
953
954 return true;
955 }
956
957 bool TogglePixel(uint16_t idx)
958 {
959 if (idx>FTM::StaticData::kMaxPixelIdx)
960 return false;
961
962 fStaticData.EnablePixel(idx, !fStaticData.Enabled(idx));
963
964 CmdSendStatDat();
965
966 return true;
967 }
968
969 int GetState() const { return IsConnected() ? fState : (int)FTM::kDisconnected; }
970};
971
972//const uint16_t ConnectionFTM::kMaxAddr = 0xfff;
973
974// ------------------------------------------------------------------------
975
976#include "DimDescriptionService.h"
977
978class ConnectionDimFTM : public ConnectionFTM
979{
980private:
981
982 DimDescribedService fDimPassport;
983 DimDescribedService fDimTriggerCounter;
984 DimDescribedService fDimError;
985 DimDescribedService fDimFtuList;
986 DimDescribedService fDimStaticData;
987 DimDescribedService fDimDynamicData;
988 DimDescribedService fDimCounter;
989
990 template<class T>
991 void Update(DimDescribedService &svc, const T &data) const
992 {
993 //cout << "Update: " << svc.getName() << " (" << sizeof(T) << ")" << endl;
994 svc.setData(const_cast<T*>(&data), sizeof(T));
995 svc.updateService();
996 }
997
998 void UpdateFirstHeader()
999 {
1000 ConnectionFTM::UpdateFirstHeader();
1001
1002 const FTM::DimPassport data(fHeader);
1003 Update(fDimPassport, data);
1004 }
1005
1006 void UpdateHeader()
1007 {
1008 ConnectionFTM::UpdateHeader();
1009
1010 if (fHeader.fType!=FTM::kDynamicData)
1011 return;
1012
1013 const FTM::DimTriggerCounter data(fHeader);
1014 Update(fDimTriggerCounter, data);
1015 }
1016
1017 void UpdateFtuList()
1018 {
1019 ConnectionFTM::UpdateFtuList();
1020
1021 const FTM::DimFtuList data(fHeader, fFtuList);
1022 Update(fDimFtuList, data);
1023 }
1024
1025 void UpdateStaticData()
1026 {
1027 ConnectionFTM::UpdateStaticData();
1028
1029 const FTM::DimStaticData data(fHeader, fStaticData);
1030 Update(fDimStaticData, data);
1031 }
1032
1033 void UpdateDynamicData()
1034 {
1035 ConnectionFTM::UpdateDynamicData();
1036
1037 const FTM::DimDynamicData data(fHeader, fDynamicData);
1038 Update(fDimDynamicData, data);
1039 }
1040
1041 void UpdateError()
1042 {
1043 ConnectionFTM::UpdateError();
1044
1045 const FTM::DimError data(fHeader, fError);
1046 Update(fDimError, data);
1047 }
1048
1049 void UpdateCounter()
1050 {
1051 ConnectionFTM::UpdateCounter();
1052
1053 const uint32_t counter[6] =
1054 {
1055 fCounter[FTM::kHeader],
1056 fCounter[FTM::kStaticData],
1057 fCounter[FTM::kDynamicData],
1058 fCounter[FTM::kFtuList],
1059 fCounter[FTM::kErrorList],
1060 fCounter[FTM::kRegister],
1061 };
1062
1063 Update(fDimCounter, counter);
1064 }
1065
1066public:
1067 ConnectionDimFTM(ba::io_service& ioservice, MessageImp &imp) :
1068 ConnectionFTM(ioservice, imp),
1069 fDimPassport ("FTM_CONTROL/PASSPORT", "X:1;S:1", ""),
1070 fDimTriggerCounter("FTM_CONTROL/TRIGGER_COUNTER", "X:1;I:1", ""),
1071 fDimError ("FTM_CONTROL/ERROR", "X:1;S:1;S:28", ""),
1072 fDimFtuList ("FTM_CONTROL/FTU_LIST", "X:1;X:1;S:1;C:4;X:40;C:40;C:40", ""),
1073 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;I:8;S:90;S:160;S:40;S:40", ""),
1074 fDimDynamicData ("FTM_CONTROL/DYNAMIC_DATA", "X:1;X:1;F:4;I:160;I:40;S:40;S:40", ""),
1075 fDimCounter ("FTM_CONTROL/COUNTER", "I:6", "")
1076 {
1077 }
1078
1079 // 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
1080};
1081
1082// ------------------------------------------------------------------------
1083
1084template <class T, class S>
1085class StateMachineFTM : public T, public ba::io_service, public ba::io_service::work
1086{
1087 int Wrap(boost::function<void()> f)
1088 {
1089 f();
1090 return T::GetCurrentState();
1091 }
1092
1093 boost::function<int(const EventImp &)> Wrapper(boost::function<void()> func)
1094 {
1095 return boost::bind(&StateMachineFTM::Wrap, this, func);
1096 }
1097
1098private:
1099 S fFTM;
1100
1101 enum states_t
1102 {
1103 kStateDisconnected = FTM::kDisconnected,
1104 kStateConnected = FTM::kConnected,
1105 kStateIdle = FTM::kIdle,
1106 kStateTakingData = FTM::kTakingData,
1107
1108 kCmdTest
1109 };
1110
1111 bool CheckEventSize(size_t has, const char *name, size_t size)
1112 {
1113 if (has==size)
1114 return true;
1115
1116 ostringstream msg;
1117 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
1118 T::Fatal(msg);
1119 return false;
1120 }
1121
1122 int SetRegister(const EventImp &evt)
1123 {
1124 if (!CheckEventSize(evt.GetSize(), "SetRegister", 8))
1125 return T::kSM_FatalError;
1126
1127 const uint32_t *dat = evt.Ptr<uint32_t>();
1128
1129 if (dat[1]>uint16_t(-1))
1130 {
1131 ostringstream msg;
1132 msg << hex << "Value " << dat[1] << " out of range.";
1133 T::Error(msg);
1134 return T::GetCurrentState();
1135 }
1136
1137
1138 if (dat[0]>uint16_t(-1) || !fFTM.CmdSetRegister(dat[0], dat[1]))
1139 {
1140 ostringstream msg;
1141 msg << hex << "Address " << dat[0] << " out of range.";
1142 T::Error(msg);
1143 }
1144
1145 return T::GetCurrentState();
1146 }
1147
1148 int GetRegister(const EventImp &evt)
1149 {
1150 if (!CheckEventSize(evt.GetSize(), "GetRegister", 4))
1151 return T::kSM_FatalError;
1152
1153 const unsigned int addr = evt.GetInt();
1154 if (addr>uint16_t(-1) || !fFTM.CmdGetRegister(addr))
1155 {
1156 ostringstream msg;
1157 msg << hex << "Address " << addr << " out of range.";
1158 T::Error(msg);
1159 }
1160
1161 return T::GetCurrentState();
1162 }
1163
1164 int TakeNevents(const EventImp &evt)
1165 {
1166 if (!CheckEventSize(evt.GetSize(), "TakeNevents", 4))
1167 return T::kSM_FatalError;
1168
1169 const unsigned int dat = evt.GetUInt();
1170
1171 /*
1172 if (dat[1]>uint32_t(-1))
1173 {
1174 ostringstream msg;
1175 msg << hex << "Value " << dat[1] << " out of range.";
1176 T::Error(msg);
1177 return T::GetCurrentState();
1178 }*/
1179
1180 fFTM.CmdTakeNevents(dat);
1181
1182 return T::GetCurrentState();
1183 }
1184
1185 int DisableReports(const EventImp &evt)
1186 {
1187 if (!CheckEventSize(evt.GetSize(), "DisableReports", 1))
1188 return T::kSM_FatalError;
1189
1190 fFTM.CmdDisableReports(evt.GetBool());
1191
1192 return T::GetCurrentState();
1193 }
1194
1195 int SetVerbosity(const EventImp &evt)
1196 {
1197 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
1198 return T::kSM_FatalError;
1199
1200 fFTM.SetVerbose(evt.GetBool());
1201
1202 return T::GetCurrentState();
1203 }
1204
1205 int SetHexOutput(const EventImp &evt)
1206 {
1207 if (!CheckEventSize(evt.GetSize(), "SetHexOutput", 1))
1208 return T::kSM_FatalError;
1209
1210 fFTM.SetHexOutput(evt.GetBool());
1211
1212 return T::GetCurrentState();
1213 }
1214
1215 int SetDynamicOut(const EventImp &evt)
1216 {
1217 if (!CheckEventSize(evt.GetSize(), "SetDynamicOut", 1))
1218 return T::kSM_FatalError;
1219
1220 fFTM.SetDynamicOut(evt.GetBool());
1221
1222 return T::GetCurrentState();
1223 }
1224
1225 int LoadStaticData(const EventImp &evt)
1226 {
1227 if (fFTM.LoadStaticData(evt.GetString()))
1228 return T::GetCurrentState();
1229
1230 ostringstream msg;
1231 msg << "Loading static data from file '" << evt.GetString() << "' failed ";
1232
1233 if (errno)
1234 msg << "(" << strerror(errno) << ")";
1235 else
1236 msg << "(wrong size, expected " << sizeof(FTM::StaticData) << " bytes)";
1237
1238 T::Warn(msg);
1239
1240 return T::GetCurrentState();
1241 }
1242
1243 int SaveStaticData(const EventImp &evt)
1244 {
1245 if (fFTM.SaveStaticData(evt.GetString()))
1246 return T::GetCurrentState();
1247
1248 ostringstream msg;
1249 msg << "Writing static data to file '" << evt.GetString() << "' failed ";
1250 msg << "(" << strerror(errno) << ")";
1251
1252 T::Warn(msg);
1253
1254 return T::GetCurrentState();
1255 }
1256
1257 int SetThreshold(const EventImp &evt)
1258 {
1259 if (!CheckEventSize(evt.GetSize(), "SetThreshold", 8))
1260 return T::kSM_FatalError;
1261
1262 const int32_t *data = evt.Ptr<int32_t>();
1263
1264 if (!fFTM.SetThreshold(data[0], data[1]))
1265 T::Warn("SetThreshold - Maximum allowed patch number 159, valid value range 0-0xffff");
1266
1267 return T::GetCurrentState();
1268 }
1269
1270 int EnableFTU(const EventImp &evt)
1271 {
1272 if (!CheckEventSize(evt.GetSize(), "EnableFTU", 5))
1273 return T::kSM_FatalError;
1274
1275 const int32_t &board = evt.Get<int32_t>();
1276 const int8_t &enable = evt.Get<int8_t>(4);
1277
1278 if (!fFTM.EnableFTU(board, enable))
1279 T::Warn("EnableFTU - Board number must be <40.");
1280
1281 return T::GetCurrentState();
1282 }
1283
1284 int ToggleFTU(const EventImp &evt)
1285 {
1286 if (!CheckEventSize(evt.GetSize(), "ToggleFTU", 4))
1287 return T::kSM_FatalError;
1288
1289 if (!fFTM.ToggleFTU(evt.GetInt()))
1290 T::Warn("ToggleFTU - Allowed range of boards 0-39.");
1291
1292 return T::GetCurrentState();
1293 }
1294
1295 int SetTriggerInterval(const EventImp &evt)
1296 {
1297 if (!CheckEventSize(evt.GetSize(), "SetTriggerInterval", 4))
1298 return T::kSM_FatalError;
1299
1300 if (!fFTM.SetTriggerInterval(evt.GetInt()))
1301 T::Warn("SetTriggerInterval - Value out of range.");
1302
1303 return T::GetCurrentState();
1304 }
1305
1306 int SetTriggerDelay(const EventImp &evt)
1307 {
1308 if (!CheckEventSize(evt.GetSize(), "SetTriggerDelay", 4))
1309 return T::kSM_FatalError;
1310
1311 if (!fFTM.SetTriggerDelay(evt.GetInt()))
1312 T::Warn("SetTriggerDealy - Value out of range.");
1313
1314 return T::GetCurrentState();
1315 }
1316
1317 int SetTimeMarkerDelay(const EventImp &evt)
1318 {
1319 if (!CheckEventSize(evt.GetSize(), "SetTimeMarkerDelay", 4))
1320 return T::kSM_FatalError;
1321
1322 if (!fFTM.SetTimeMarkerDelay(evt.GetInt()))
1323 T::Warn("SetTimeMarkerDelay - Value out of range.");
1324
1325 return T::GetCurrentState();
1326 }
1327
1328 int SetPrescaling(const EventImp &evt)
1329 {
1330 if (!CheckEventSize(evt.GetSize(), "SetPrescaling", 4))
1331 return T::kSM_FatalError;
1332
1333 if (!fFTM.SetPrescaling(evt.GetInt()-1))
1334 T::Warn("SetPrescaling - Value out of range.");
1335
1336 return T::GetCurrentState();
1337 }
1338
1339 int SetTriggerSeq(const EventImp &evt)
1340 {
1341 if (!CheckEventSize(evt.GetSize(), "SetTriggerSeq", 6))
1342 return T::kSM_FatalError;
1343
1344 const uint16_t *data = evt.Ptr<uint16_t>();
1345
1346 if (!fFTM.SetTriggerSeq(data))
1347 T::Warn("SetTriggerSeq - Value out of range.");
1348
1349 return T::GetCurrentState();
1350 }
1351
1352 int SetDeadTime(const EventImp &evt)
1353 {
1354 if (!CheckEventSize(evt.GetSize(), "SetDeadTime", 4))
1355 return T::kSM_FatalError;
1356
1357 if (!fFTM.SetDeadTime(evt.GetInt()))
1358 T::Warn("SetDeadTime - Value out of range.");
1359
1360 return T::GetCurrentState();
1361 }
1362
1363 int SetTriggerMultiplicity(const EventImp &evt)
1364 {
1365 if (!CheckEventSize(evt.GetSize(), "SetTriggerMultiplicity", 2))
1366 return T::kSM_FatalError;
1367
1368 if (!fFTM.SetTriggerMultiplicity(evt.GetUShort()))
1369 T::Warn("SetTriggerMultiplicity - Value out of range.");
1370
1371 return T::GetCurrentState();
1372 }
1373
1374 int SetCalibMultiplicity(const EventImp &evt)
1375 {
1376 if (!CheckEventSize(evt.GetSize(), "SetCalibMultiplicity", 2))
1377 return T::kSM_FatalError;
1378
1379 if (!fFTM.SetCalibMultiplicity(evt.GetUShort()))
1380 T::Warn("SetCalibMultiplicity - Value out of range.");
1381
1382 return T::GetCurrentState();
1383 }
1384
1385 int SetTriggerWindow(const EventImp &evt)
1386 {
1387 if (!CheckEventSize(evt.GetSize(), "SetTriggerWindow", 2))
1388 return T::kSM_FatalError;
1389
1390 if (!fFTM.SetTriggerWindow(evt.GetUShort()))
1391 T::Warn("SetTriggerWindow - Value out of range.");
1392
1393 return T::GetCurrentState();
1394 }
1395
1396 int SetCalibWindow(const EventImp &evt)
1397 {
1398 if (!CheckEventSize(evt.GetSize(), "SetCalibWindow", 2))
1399 return T::kSM_FatalError;
1400
1401 if (!fFTM.SetCalibWindow(evt.GetUShort()))
1402 T::Warn("SetCalibWindow - Value out of range.");
1403
1404 return T::GetCurrentState();
1405 }
1406
1407 int SetClockRegister(const EventImp &evt)
1408 {
1409 if (!CheckEventSize(evt.GetSize(), "SetClockRegister", 8*8))
1410 return T::kSM_FatalError;
1411
1412 const uint64_t *reg = evt.Ptr<uint64_t>();
1413
1414 if (!fFTM.SetClockRegister(reg))
1415 T::Warn("SetClockRegister - Value out of range.");
1416
1417 return T::GetCurrentState();
1418 }
1419
1420 //map<uint32_t, uint32_t> fClockConditionerMap;
1421
1422 int SetClockFrequency(const EventImp &evt)
1423 {
1424 if (!CheckEventSize(evt.GetSize(), "SetClockFrequency", 4))
1425 return T::kSM_FatalError;
1426
1427 const uint32_t freq = evt.GetUInt();
1428
1429 //map<uint32_t,uint32_t>::const_iterator = fClockConditionerMap.find(freq);
1430
1431 static const uint64_t R1 = 0x00010101;
1432 static const uint64_t R8 = 0x10000908;
1433 static const uint64_t R9 = 0xa0032a09;
1434 static const uint64_t R11 = 0x0082000b;
1435 static const uint64_t R13 = 0x020a000d;
1436
1437 static const uint64_t freq0700[8] = { 0x0003e000, R1, R8, R9, R11, R13, 0x0830400e, 0x1400f50f };
1438 static const uint64_t freq1000[8] = { 0x0003a000, R1, R8, R9, R11, R13, 0x0830400e, 0x1400fa0f };
1439 static const uint64_t freq2000[8] = { 0x00035000, R1, R8, R9, R11, R13, 0x0830400e, 0x1400fa0f };
1440 static const uint64_t freq2001[8] = { 0x00038000, R1, R8, R9, R11, R13, 0x0830280e, 0x1400fa0f };
1441 static const uint64_t freq3000[8] = { 0x00037200, R1, R8, R9, R11, R13, 0x0830400e, 0x1420a30f };
1442// static const uint64_t freq4000[8] = { 0x00032800, R1, R8, R9, R11, R13, 0x0830400e, 0x1400fa0f };
1443 static const uint64_t freq4000[8] = { 0x00034000, R1, R8, R9, R11, R13, 0x0830280e, 0x1400fa0f };
1444 static const uint64_t freq5000[8] = { 0x00032000, R1, R8, R9, R11, R13, 0x0830400e, 0x1400fa0f };
1445
1446 const uint64_t *reg = 0;
1447
1448 switch (freq)
1449 {
1450 case 700: reg = freq0700; break;
1451 case 1000: reg = freq1000; break;
1452 case 2000: reg = freq2000; break;
1453 case 2001: reg = freq2001; break;
1454 case 3000: reg = freq3000; break;
1455 case 4000: reg = freq4000; break;
1456 case 5000: reg = freq5000; break;
1457 default:
1458 T::Warn("SetClockFrequency - Frequency not supported.");
1459 return T::GetCurrentState();
1460 }
1461
1462 if (!fFTM.SetClockRegister(reg))
1463 T::Warn("SetClockFrequency - Register values out of range.");
1464
1465 return T::GetCurrentState();
1466 }
1467
1468 int Enable(const EventImp &evt, FTM::StaticData::GeneralSettings type)
1469 {
1470 if (!CheckEventSize(evt.GetSize(), "Enable", 1))
1471 return T::kSM_FatalError;
1472
1473 fFTM.Enable(type, evt.GetBool());
1474
1475 return T::GetCurrentState();
1476 }
1477
1478 int EnablePixel(const EventImp &evt, bool b)
1479 {
1480 if (!CheckEventSize(evt.GetSize(), "EnablePixel", 2))
1481 return T::kSM_FatalError;
1482
1483 if (!fFTM.EnablePixel(evt.GetUShort(), b))
1484 T::Warn("EnablePixel - Value out of range.");
1485
1486 return T::GetCurrentState();
1487 }
1488
1489 int DisableAllPixelsExcept(const EventImp &evt)
1490 {
1491 if (!CheckEventSize(evt.GetSize(), "DisableAllPixelsExcept", 2))
1492 return T::kSM_FatalError;
1493
1494 if (!fFTM.DisableAllPixelsExcept(evt.GetUShort()))
1495 T::Warn("DisableAllPixelsExcept - Value out of range.");
1496
1497 return T::GetCurrentState();
1498 }
1499
1500 int DisableAllPatchesExcept(const EventImp &evt)
1501 {
1502 if (!CheckEventSize(evt.GetSize(), "DisableAllPatchesExcept", 2))
1503 return T::kSM_FatalError;
1504
1505 if (!fFTM.DisableAllPatchesExcept(evt.GetUShort()))
1506 T::Warn("DisableAllPatchesExcept - Value out of range.");
1507
1508 return T::GetCurrentState();
1509 }
1510
1511 int TogglePixel(const EventImp &evt)
1512 {
1513 if (!CheckEventSize(evt.GetSize(), "TogglePixel", 2))
1514 return T::kSM_FatalError;
1515
1516 if (!fFTM.TogglePixel(evt.GetUShort()))
1517 T::Warn("TogglePixel - Value out of range.");
1518
1519 return T::GetCurrentState();
1520 }
1521
1522 int ResetCrate(const EventImp &evt)
1523 {
1524 if (!CheckEventSize(evt.GetSize(), "ResetCrate", 2))
1525 return T::kSM_FatalError;
1526
1527 fFTM.CmdResetCrate(evt.GetUShort());
1528
1529 return T::GetCurrentState();
1530 }
1531
1532 int Disconnect()
1533 {
1534 // Close all connections
1535 fFTM.PostClose(false);
1536
1537 /*
1538 // Now wait until all connection have been closed and
1539 // all pending handlers have been processed
1540 poll();
1541 */
1542
1543 return T::GetCurrentState();
1544 }
1545
1546 int Reconnect(const EventImp &evt)
1547 {
1548 // Close all connections to supress the warning in SetEndpoint
1549 fFTM.PostClose(false);
1550
1551 // Now wait until all connection have been closed and
1552 // all pending handlers have been processed
1553 poll();
1554
1555 if (evt.GetBool())
1556 fFTM.SetEndpoint(evt.GetString());
1557
1558 // Now we can reopen the connection
1559 fFTM.PostClose(true);
1560
1561 return T::GetCurrentState();
1562 }
1563
1564 /*
1565 int Transition(const Event &evt)
1566 {
1567 switch (evt.GetTargetState())
1568 {
1569 case kStateDisconnected:
1570 case kStateConnected:
1571 }
1572
1573 return T::kSM_FatalError;
1574 }*/
1575
1576 int Execute()
1577 {
1578 // Dispatch (execute) at most one handler from the queue. In contrary
1579 // to run_one(), it doesn't wait until a handler is available
1580 // which can be dispatched, so poll_one() might return with 0
1581 // handlers dispatched. The handlers are always dispatched/executed
1582 // synchronously, i.e. within the call to poll_one()
1583 poll_one();
1584
1585 return fFTM.GetState();
1586 }
1587
1588public:
1589 StateMachineFTM(ostream &out=cout) :
1590 T(out, "FTM_CONTROL"), ba::io_service::work(static_cast<ba::io_service&>(*this)),
1591 fFTM(*this, *this)
1592 {
1593 // ba::io_service::work is a kind of keep_alive for the loop.
1594 // It prevents the io_service to go to stopped state, which
1595 // would prevent any consecutive calls to run()
1596 // or poll() to do nothing. reset() could also revoke to the
1597 // previous state but this might introduce some overhead of
1598 // deletion and creation of threads and more.
1599
1600 // State names
1601 AddStateName(kStateDisconnected, "Disconnected",
1602 "FTM board not connected via ethernet.");
1603
1604 AddStateName(kStateConnected, "Connected",
1605 "Ethernet connection to FTM established (no state received yet).");
1606
1607 AddStateName(kStateIdle, "Idle",
1608 "Ethernet connection to FTM established, FTM in idle state.");
1609
1610 AddStateName(kStateTakingData, "TakingData",
1611 "Ethernet connection to FTM established, FTM is in taking data state.");
1612
1613 // FTM Commands
1614 AddEvent("TOGGLE_LED", kStateIdle)
1615 (Wrapper(boost::bind(&ConnectionFTM::CmdToggleLed, &fFTM)))
1616 ("toggle led");
1617
1618 AddEvent("PING", kStateIdle)
1619 (Wrapper(boost::bind(&ConnectionFTM::CmdPing, &fFTM)))
1620 ("send ping");
1621
1622 AddEvent("REQUEST_DYNAMIC_DATA", kStateIdle)
1623 (Wrapper(boost::bind(&ConnectionFTM::CmdReqDynDat, &fFTM)))
1624 ("request transmission of dynamic data block");
1625
1626 AddEvent("REQUEST_STATIC_DATA", kStateIdle)
1627 (Wrapper(boost::bind(&ConnectionFTM::CmdReqStatDat, &fFTM)))
1628 ("request transmission of static data from FTM to memory");
1629
1630 AddEvent("GET_REGISTER", "I", kStateIdle)
1631 (boost::bind(&StateMachineFTM::GetRegister, this, _1))
1632 ("read register from address addr"
1633 "|addr[short]:Address of register");
1634
1635 AddEvent("SET_REGISTER", "I:2", kStateIdle)
1636 (boost::bind(&StateMachineFTM::SetRegister, this, _1))
1637 ("set register to value"
1638 "|addr[short]:Address of register"
1639 "|val[short]:Value to be set");
1640
1641 AddEvent("START_RUN", kStateIdle)
1642 (Wrapper(boost::bind(&ConnectionFTM::CmdStartRun, &fFTM)))
1643 ("start a run (start distributing triggers)");
1644
1645 AddEvent("STOP_RUN", kStateTakingData)
1646 (Wrapper(boost::bind(&ConnectionFTM::CmdStopRun, &fFTM)))
1647 ("stop a run (stop distributing triggers)");
1648
1649 AddEvent("TAKE_N_EVENTS", "I", kStateIdle)
1650 (boost::bind(&StateMachineFTM::TakeNevents, this, _1))
1651 ("take n events (distribute n triggers)|number[int]:Number of events to be taken");
1652
1653 AddEvent("DISABLE_REPORTS", "B", kStateIdle)
1654 (boost::bind(&StateMachineFTM::DisableReports, this, _1))
1655 ("disable sending rate reports"
1656 "|status[bool]:disable or enable that the FTM sends rate reports (yes/no)");
1657
1658 AddEvent("SET_THRESHOLD", "I:2", kStateIdle)
1659 (boost::bind(&StateMachineFTM::SetThreshold, this, _1))
1660 ("Set the comparator threshold"
1661 "|Patch[idx]:Index of the patch (0-159), -1 for all"
1662 "|Threshold[counts]:Threshold to be set in binary counts");
1663
1664 AddEvent("SET_PRESCALING", "I:1", kStateIdle)
1665 (boost::bind(&StateMachineFTM::SetPrescaling, this, _1))
1666 (""
1667 "|[]:");
1668
1669 AddEvent("ENABLE_FTU", "I:1;B:1", kStateIdle)
1670 (boost::bind(&StateMachineFTM::EnableFTU, this, _1))
1671 ("Enable or disable FTU"
1672 "|Board[idx]:Index of the board (0-39), -1 for all"
1673 "|Enable[bool]:Whether FTU should be enabled or disabled (yes/no)");
1674
1675 AddEvent("DISABLE_PIXEL", "S:1", kStateIdle)
1676 (boost::bind(&StateMachineFTM::EnablePixel, this, _1, false))
1677 ("(-1 or all)");
1678
1679 AddEvent("ENABLE_PIXEL", "S:1", kStateIdle)
1680 (boost::bind(&StateMachineFTM::EnablePixel, this, _1, true))
1681 ("(-1 or all)");
1682
1683 AddEvent("DISABLE_ALL_PIXELS_EXCEPT", "S:1", kStateIdle)
1684 (boost::bind(&StateMachineFTM::DisableAllPixelsExcept, this, _1))
1685 ("");
1686
1687 AddEvent("DISABLE_ALL_PATCHES_EXCEPT", "S:1", kStateIdle)
1688 (boost::bind(&StateMachineFTM::DisableAllPatchesExcept, this, _1))
1689 ("");
1690
1691 AddEvent("TOGGLE_PIXEL", "S:1", kStateIdle)
1692 (boost::bind(&StateMachineFTM::TogglePixel, this, _1))
1693 ("");
1694
1695 AddEvent("TOGGLE_FTU", "I:1", kStateIdle)
1696 (boost::bind(&StateMachineFTM::ToggleFTU, this, _1))
1697 ("Toggle status of FTU (this is mainly meant to be used in the GUI)"
1698 "|Board[idx]:Index of the board (0-39)");
1699
1700 AddEvent("SET_TRIGGER_INTERVAL", "I:1", kStateIdle)
1701 (boost::bind(&StateMachineFTM::SetTriggerInterval, this, _1))
1702 ("Sets the trigger interval which is the distance between two consecutive artificial triggers."
1703 "|interval[int]:The applied trigger interval is: interval*4ns+8ns");
1704
1705 AddEvent("SET_TRIGGER_DELAY", "I:1", kStateIdle)
1706 (boost::bind(&StateMachineFTM::SetTriggerDelay, this, _1))
1707 (""
1708 "|delay[int]:The applied trigger delay is: delay*4ns+8ns");
1709
1710 AddEvent("SET_TIME_MARKER_DELAY", "I:1", kStateIdle)
1711 (boost::bind(&StateMachineFTM::SetTimeMarkerDelay, this, _1))
1712 (""
1713 "|delay[int]:The applied time marker delay is: delay*4ns+8ns");
1714
1715 AddEvent("SET_DEAD_TIME", "I:1", kStateIdle)
1716 (boost::bind(&StateMachineFTM::SetDeadTime, this, _1))
1717 (""
1718 "|dead_time[int]:The applied dead time is: dead_time*4ns+8ns");
1719
1720 AddEvent("ENABLE_TRIGGER", "B:1", kStateIdle)
1721 (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kTrigger))
1722 ("Switch on the physics trigger"
1723 "|Enable[bool]:Enable physics trigger (yes/no)");
1724
1725 // FIXME: Switch on/off depending on sequence
1726 AddEvent("ENABLE_EXT1", "B:1", kStateIdle)
1727 (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kExt1))
1728 ("Switch on the triggers through the first external line"
1729 "|Enable[bool]:Enable ext1 trigger (yes/no)");
1730
1731 // FIXME: Switch on/off depending on sequence
1732 AddEvent("ENABLE_EXT2", "B:1", kStateIdle)
1733 (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kExt2))
1734 ("Switch on the triggers through the second external line"
1735 "|Enable[bool]:Enable ext2 trigger (yes/no)");
1736
1737 AddEvent("ENABLE_VETO", "B:1", kStateIdle)
1738 (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kVeto))
1739 ("Enable veto line"
1740 "|Enable[bool]:Enable veto (yes/no)");
1741
1742 AddEvent("ENABLE_CLOCK_CONDITIONER", "B:1", kStateIdle)
1743 (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kClockConditioner))
1744 ("Enable clock conidtioner output in favor of time marker output"
1745 "|Enable[bool]:Enable clock conditioner (yes/no)");
1746
1747 AddEvent("SET_TRIGGER_SEQUENCE", "S:3", kStateIdle)
1748 (boost::bind(&StateMachineFTM::SetTriggerSeq, this, _1))
1749 ("Setup the sequence of artificial triggers produced by the FTM"
1750 "|Ped[short]:number of pedestal triggers in a row"
1751 "|LPext[short]:number of triggers of the external light pulser"
1752 "|LPint[short]:number of triggers of the internal light pulser");
1753
1754 AddEvent("SET_TRIGGER_MULTIPLICITY", "S:1", kStateIdle)
1755 (boost::bind(&StateMachineFTM::SetTriggerMultiplicity, this, _1))
1756 ("Setup the Multiplicity condition for physcis triggers"
1757 "|N[int]:Number of requirered coincident triggers from sum-patches (1-40)");
1758
1759 AddEvent("SET_TRIGGER_WINDOW", "S:1", kStateIdle)
1760 (boost::bind(&StateMachineFTM::SetTriggerWindow, this, _1))
1761 ("");
1762
1763 AddEvent("SET_CALIBRATION_MULTIPLICITY", "S:1", kStateIdle)
1764 (boost::bind(&StateMachineFTM::SetCalibMultiplicity, this, _1))
1765 ("Setup the Multiplicity condition for artificial (calibration) triggers"
1766 "|N[int]:Number of requirered coincident triggers from sum-patches (1-40)");
1767
1768 AddEvent("SET_CALIBRATION_WINDOW", "S:1", kStateIdle)
1769 (boost::bind(&StateMachineFTM::SetCalibWindow, this, _1))
1770 ("");
1771
1772 AddEvent("SET_CLOCK_FREQUENCY", "I:1", kStateIdle)
1773 (boost::bind(&StateMachineFTM::SetClockFrequency, this, _1))
1774 ("");
1775
1776 AddEvent("SET_CLOCK_REGISTER", "X:8", kStateIdle)
1777 (boost::bind(&StateMachineFTM::SetClockRegister, this, _1))
1778 ("");
1779
1780
1781
1782 AddEvent("RESET_CRATE", "S:1", kStateIdle)
1783 (boost::bind(&StateMachineFTM::ResetCrate, this, _1))
1784 ("Reset one of the crates 0-3"
1785 "|crate[short]:Crate number to be reseted (0-3)");
1786
1787 AddEvent("RESET_CAMERA", kStateIdle)
1788 (Wrapper(boost::bind(&ConnectionFTM::CmdResetCamera, &fFTM)))
1789 ("Reset all crates. The commands are sent in the order 0,1,2,3");
1790
1791
1792 // Load/save static data block
1793 T::AddEvent("SAVE", "C", kStateIdle)
1794 (boost::bind(&StateMachineFTM::SaveStaticData, this, _1))
1795 ("Saves the static data (FTM configuration) from memory to a file"
1796 "|filename[string]:Filename (can include a path), .bin is automatically added");
1797
1798 T::AddEvent("LOAD", "C", kStateIdle)
1799 (boost::bind(&StateMachineFTM::LoadStaticData, this, _1))
1800 ("Loads the static data (FTM configuration) from a file into memory and sends it to the FTM"
1801 "|filename[string]:Filename (can include a path), .bin is automatically added");
1802
1803
1804
1805 // Verbosity commands
1806 T::AddEvent("SET_VERBOSE", "B")
1807 (boost::bind(&StateMachineFTM::SetVerbosity, this, _1))
1808 ("set verbosity state"
1809 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
1810
1811 T::AddEvent("SET_HEX_OUTPUT", "B")
1812 (boost::bind(&StateMachineFTM::SetHexOutput, this, _1))
1813 ("enable or disable hex output for received data"
1814 "|hexout[bool]:disable or enable hex output for received data (yes/no)");
1815
1816 T::AddEvent("SET_DYNAMIC_OUTPUT", "B")
1817 (boost::bind(&StateMachineFTM::SetDynamicOut, this, _1))
1818 ("enable or disable output for received dynamic data (data is still broadcasted via Dim)"
1819 "|dynout[bool]:disable or enable output for dynamic data (yes/no)");
1820
1821
1822 // Conenction commands
1823 AddEvent("DISCONNECT", kStateConnected, kStateIdle)
1824 (boost::bind(&StateMachineFTM::Disconnect, this))
1825 ("disconnect from ethernet");
1826
1827 AddEvent("RECONNECT", "O", kStateDisconnected, kStateConnected, kStateIdle)
1828 (boost::bind(&StateMachineFTM::Reconnect, this, _1))
1829 ("(Re)connect ethernet connection to FTM, a new address can be given"
1830 "|[host][string]:new ethernet address in the form <host:port>");
1831
1832 fFTM.StartConnect();
1833 }
1834
1835 void SetEndpoint(const string &url)
1836 {
1837 fFTM.SetEndpoint(url);
1838 }
1839
1840 bool SetConfiguration(const Configuration &conf)
1841 {
1842 SetEndpoint(conf.Get<string>("addr"));
1843
1844 fFTM.SetVerbose(!conf.Get<bool>("quiet"));
1845 fFTM.SetHexOutput(conf.Get<bool>("hex-out"));
1846 fFTM.SetDynamicOut(conf.Get<bool>("dynamic-out"));
1847
1848// fFTM.SetDefaultSetup(conf.Get<string>("default-setup"));
1849
1850 return true;
1851 }
1852};
1853
1854// ------------------------------------------------------------------------
1855
1856void RunThread(StateMachineImp *io_service)
1857{
1858 // This is necessary so that the StateMachien Thread can signal the
1859 // Readline to exit
1860 io_service->Run();
1861 Readline::Stop();
1862}
1863
1864/*
1865template<class S, class T>
1866int RunDim(Configuration &conf)
1867{
1868 WindowLog wout;
1869
1870 ReadlineColor::PrintBootMsg(wout, conf.GetName(), false);
1871
1872 if (conf.Has("log"))
1873 if (!wout.OpenLogFile(conf.Get<string>("log")))
1874 wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
1875
1876 // Start io_service.Run to use the StateMachineImp::Run() loop
1877 // Start io_service.run to only use the commandHandler command detaching
1878 StateMachineFTM<S, T> io_service(wout);
1879 if (!io_service.SetConfiguration(conf))
1880 return -1;
1881
1882 io_service.Run();
1883
1884 return 0;
1885}
1886*/
1887
1888template<class T, class S, class R>
1889int RunShell(Configuration &conf)
1890{
1891 static T shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
1892
1893 WindowLog &win = shell.GetStreamIn();
1894 WindowLog &wout = shell.GetStreamOut();
1895
1896 if (conf.Has("log"))
1897 if (!wout.OpenLogFile(conf.Get<string>("log")))
1898 win << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
1899
1900 StateMachineFTM<S, R> io_service(wout);
1901 if (!io_service.SetConfiguration(conf))
1902 return -1;
1903
1904 shell.SetReceiver(io_service);
1905
1906 boost::thread t(boost::bind(RunThread, &io_service));
1907 // boost::thread t(boost::bind(&StateMachineFTM<S>::Run, &io_service));
1908
1909 if (conf.Has("exec"))
1910 {
1911 const vector<string> v = conf.Get<vector<string>>("exec");
1912 for (vector<string>::const_iterator it=v.begin(); it!=v.end(); it++)
1913 shell.Execute(*it);
1914 }
1915
1916 shell.Run(); // Run the shell
1917 io_service.Stop(); // Signal Loop-thread to stop
1918 // io_service.Close(); // Obsolete, done by the destructor
1919
1920 // Wait until the StateMachine has finished its thread
1921 // before returning and destroying the dim objects which might
1922 // still be in use.
1923 t.join();
1924
1925 return 0;
1926}
1927
1928void SetupConfiguration(Configuration &conf)
1929{
1930 const string n = conf.GetName()+".log";
1931
1932 po::options_description config("Program options");
1933 config.add_options()
1934 ("dns", var<string>("localhost"), "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
1935 ("log,l", var<string>(n), "Write log-file")
1936 ("no-dim,d", po_bool(), "Disable dim services")
1937 ("console,c", var<int>(), "Use console (0=shell, 1=simple buffered, X=simple unbuffered)")
1938 ("exec,e", vars<string>(), "Execute one or more scrips at startup")
1939 ;
1940
1941 po::options_description control("FTM control options");
1942 control.add_options()
1943 ("addr,a", var<string>("localhost:5000"), "Network address of FTM")
1944 ("quiet,q", po_bool(), "Disable printing contents of all received messages (except dynamic data) in clear text.")
1945 ("hex-out", po_bool(), "Enable printing contents of all printed messages also as hex data.")
1946 ("dynamic-out", po_bool(), "Enable printing received dynamic data.")
1947// ("default-setup", var<string>(), "Binary file with static data loaded whenever a connection to the FTM was established.")
1948 ;
1949
1950 conf.AddEnv("dns", "DIM_DNS_NODE");
1951
1952 conf.AddOptions(config);
1953 conf.AddOptions(control);
1954}
1955
1956/*
1957 Extract usage clause(s) [if any] for SYNOPSIS.
1958 Translators: "Usage" and "or" here are patterns (regular expressions) which
1959 are used to match the usage synopsis in program output. An example from cp
1960 (GNU coreutils) which contains both strings:
1961 Usage: cp [OPTION]... [-T] SOURCE DEST
1962 or: cp [OPTION]... SOURCE... DIRECTORY
1963 or: cp [OPTION]... -t DIRECTORY SOURCE...
1964 */
1965void PrintUsage()
1966{
1967 cout <<
1968 "The ftmctrl controls the FTM (FACT Trigger Master) board.\n"
1969 "\n"
1970 "The default is that the program is started without user intercation. "
1971 "All actions are supposed to arrive as DimCommands. Using the -c "
1972 "option, a local shell can be initialized. With h or help a short "
1973 "help message about the usuage can be brought to the screen.\n"
1974 "\n"
1975 "Usage: ftmctrl [-c type] [OPTIONS]\n"
1976 " or: ftmctrl [OPTIONS]\n";
1977 cout << endl;
1978}
1979
1980void PrintHelp()
1981{
1982 /* Additional help text which is printed after the configuration
1983 options goes here */
1984
1985 /*
1986 cout << "bla bla bla" << endl << endl;
1987 cout << endl;
1988 cout << "Environment:" << endl;
1989 cout << "environment" << endl;
1990 cout << endl;
1991 cout << "Examples:" << endl;
1992 cout << "test exam" << endl;
1993 cout << endl;
1994 cout << "Files:" << endl;
1995 cout << "files" << endl;
1996 cout << endl;
1997 */
1998}
1999
2000int main(int argc, const char* argv[])
2001{
2002 Configuration conf(argv[0]);
2003 conf.SetPrintUsage(PrintUsage);
2004 SetupConfiguration(conf);
2005
2006 po::variables_map vm;
2007 try
2008 {
2009 vm = conf.Parse(argc, argv);
2010 }
2011#if BOOST_VERSION > 104000
2012 catch (po::multiple_occurrences &e)
2013 {
2014 cerr << "Program options invalid due to: " << e.what() << " of '" << e.get_option_name() << "'." << endl;
2015 return -1;
2016 }
2017#endif
2018 catch (exception& e)
2019 {
2020 cerr << "Program options invalid due to: " << e.what() << endl;
2021 return -1;
2022 }
2023
2024 if (conf.HasVersion() || conf.HasPrint())
2025 return -1;
2026
2027 if (conf.HasHelp())
2028 {
2029 PrintHelp();
2030 return -1;
2031 }
2032
2033 Dim::Setup(conf.Get<string>("dns"));
2034
2035 //try
2036 {
2037 // No console access at all
2038 if (!conf.Has("console"))
2039 {
2040 if (conf.Get<bool>("no-dim"))
2041 return RunShell<LocalStream, StateMachine, ConnectionFTM>(conf);
2042 else
2043 return RunShell<LocalStream, StateMachineDim, ConnectionDimFTM>(conf);
2044 }
2045 // Cosole access w/ and w/o Dim
2046 if (conf.Get<bool>("no-dim"))
2047 {
2048 if (conf.Get<int>("console")==0)
2049 return RunShell<LocalShell, StateMachine, ConnectionFTM>(conf);
2050 else
2051 return RunShell<LocalConsole, StateMachine, ConnectionFTM>(conf);
2052 }
2053 else
2054 {
2055 if (conf.Get<int>("console")==0)
2056 return RunShell<LocalShell, StateMachineDim, ConnectionDimFTM>(conf);
2057 else
2058 return RunShell<LocalConsole, StateMachineDim, ConnectionDimFTM>(conf);
2059 }
2060 }
2061 /*catch (std::exception& e)
2062 {
2063 cerr << "Exception: " << e.what() << endl;
2064 return -1;
2065 }*/
2066
2067 return 0;
2068}
Note: See TracBrowser for help on using the repository browser.