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

Last change on this file since 11103 was 11102, checked in by tbretz, 14 years ago
Added possibility to set the clock conditioner's frequency for some selected frequency.
File size: 59.9 KB
Line 
1#include <boost/bind.hpp>
2#include <boost/array.hpp>
3#if BOOST_VERSION < 104400
4#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 4))
5#undef BOOST_HAS_RVALUE_REFS
6#endif
7#endif
8#include <boost/thread.hpp>
9#include <boost/asio/error.hpp>
10#include <boost/asio/deadline_timer.hpp>
11
12#include "Dim.h"
13#include "Event.h"
14#include "Shell.h"
15#include "StateMachineDim.h"
16#include "Connection.h"
17#include "Configuration.h"
18#include "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;S: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*16))
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 freq3000[8] = { 0x00037200, R1, R8, R9, R11, R13, 0x0830400e, 0x1420a30f };
1441 static const uint64_t freq4000[8] = { 0x00032800, R1, R8, R9, R11, R13, 0x0830400e, 0x1400fa0f };
1442 static const uint64_t freq5000[8] = { 0x00032000, R1, R8, R9, R11, R13, 0x0830400e, 0x1400fa0f };
1443
1444 const uint64_t *reg = 0;
1445
1446 switch (freq)
1447 {
1448 case 700: reg = freq0700; break;
1449 case 1000: reg = freq1000; break;
1450 case 2000: reg = freq2000; break;
1451 case 3000: reg = freq3000; break;
1452 case 4000: reg = freq4000; break;
1453 case 5000: reg = freq5000; break;
1454 default:
1455 T::Warn("SetClockFrequency - Frequency not supported.");
1456 return T::GetCurrentState();
1457 }
1458
1459 if (!fFTM.SetClockRegister(reg))
1460 T::Warn("SetClockFrequency - Register values out of range.");
1461
1462 return T::GetCurrentState();
1463 }
1464
1465 int Enable(const EventImp &evt, FTM::StaticData::GeneralSettings type)
1466 {
1467 if (!CheckEventSize(evt.GetSize(), "Enable", 1))
1468 return T::kSM_FatalError;
1469
1470 fFTM.Enable(type, evt.GetBool());
1471
1472 return T::GetCurrentState();
1473 }
1474
1475 int EnablePixel(const EventImp &evt, bool b)
1476 {
1477 if (!CheckEventSize(evt.GetSize(), "EnablePixel", 2))
1478 return T::kSM_FatalError;
1479
1480 if (!fFTM.EnablePixel(evt.GetUShort(), b))
1481 T::Warn("EnablePixel - Value out of range.");
1482
1483 return T::GetCurrentState();
1484 }
1485
1486 int DisableAllPixelsExcept(const EventImp &evt)
1487 {
1488 if (!CheckEventSize(evt.GetSize(), "DisableAllPixelsExcept", 2))
1489 return T::kSM_FatalError;
1490
1491 if (!fFTM.DisableAllPixelsExcept(evt.GetUShort()))
1492 T::Warn("DisableAllPixelsExcept - Value out of range.");
1493
1494 return T::GetCurrentState();
1495 }
1496
1497 int DisableAllPatchesExcept(const EventImp &evt)
1498 {
1499 if (!CheckEventSize(evt.GetSize(), "DisableAllPatchesExcept", 2))
1500 return T::kSM_FatalError;
1501
1502 if (!fFTM.DisableAllPatchesExcept(evt.GetUShort()))
1503 T::Warn("DisableAllPatchesExcept - Value out of range.");
1504
1505 return T::GetCurrentState();
1506 }
1507
1508 int TogglePixel(const EventImp &evt)
1509 {
1510 if (!CheckEventSize(evt.GetSize(), "TogglePixel", 2))
1511 return T::kSM_FatalError;
1512
1513 if (!fFTM.TogglePixel(evt.GetUShort()))
1514 T::Warn("TogglePixel - Value out of range.");
1515
1516 return T::GetCurrentState();
1517 }
1518
1519 int ResetCrate(const EventImp &evt)
1520 {
1521 if (!CheckEventSize(evt.GetSize(), "ResetCrate", 2))
1522 return T::kSM_FatalError;
1523
1524 fFTM.CmdResetCrate(evt.GetUShort());
1525
1526 return T::GetCurrentState();
1527 }
1528
1529 int Disconnect()
1530 {
1531 // Close all connections
1532 fFTM.PostClose(false);
1533
1534 /*
1535 // Now wait until all connection have been closed and
1536 // all pending handlers have been processed
1537 poll();
1538 */
1539
1540 return T::GetCurrentState();
1541 }
1542
1543 int Reconnect(const EventImp &evt)
1544 {
1545 // Close all connections to supress the warning in SetEndpoint
1546 fFTM.PostClose(false);
1547
1548 // Now wait until all connection have been closed and
1549 // all pending handlers have been processed
1550 poll();
1551
1552 if (evt.GetBool())
1553 fFTM.SetEndpoint(evt.GetString());
1554
1555 // Now we can reopen the connection
1556 fFTM.PostClose(true);
1557
1558 return T::GetCurrentState();
1559 }
1560
1561 /*
1562 int Transition(const Event &evt)
1563 {
1564 switch (evt.GetTargetState())
1565 {
1566 case kStateDisconnected:
1567 case kStateConnected:
1568 }
1569
1570 return T::kSM_FatalError;
1571 }*/
1572
1573 int Execute()
1574 {
1575 // Dispatch (execute) at most one handler from the queue. In contrary
1576 // to run_one(), it doesn't wait until a handler is available
1577 // which can be dispatched, so poll_one() might return with 0
1578 // handlers dispatched. The handlers are always dispatched/executed
1579 // synchronously, i.e. within the call to poll_one()
1580 poll_one();
1581
1582 return fFTM.GetState();
1583 }
1584
1585public:
1586 StateMachineFTM(ostream &out=cout) :
1587 T(out, "FTM_CONTROL"), ba::io_service::work(static_cast<ba::io_service&>(*this)),
1588 fFTM(*this, *this)
1589 {
1590 // ba::io_service::work is a kind of keep_alive for the loop.
1591 // It prevents the io_service to go to stopped state, which
1592 // would prevent any consecutive calls to run()
1593 // or poll() to do nothing. reset() could also revoke to the
1594 // previous state but this might introduce some overhead of
1595 // deletion and creation of threads and more.
1596
1597 // State names
1598 AddStateName(kStateDisconnected, "Disconnected",
1599 "FTM board not connected via ethernet.");
1600
1601 AddStateName(kStateConnected, "Connected",
1602 "Ethernet connection to FTM established (no state received yet).");
1603
1604 AddStateName(kStateIdle, "Idle",
1605 "Ethernet connection to FTM established, FTM in idle state.");
1606
1607 AddStateName(kStateTakingData, "TakingData",
1608 "Ethernet connection to FTM established, FTM is in taking data state.");
1609
1610 // FTM Commands
1611 AddEvent("TOGGLE_LED", kStateIdle)
1612 (Wrapper(boost::bind(&ConnectionFTM::CmdToggleLed, &fFTM)))
1613 ("toggle led");
1614
1615 AddEvent("PING", kStateIdle)
1616 (Wrapper(boost::bind(&ConnectionFTM::CmdPing, &fFTM)))
1617 ("send ping");
1618
1619 AddEvent("REQUEST_DYNAMIC_DATA", kStateIdle)
1620 (Wrapper(boost::bind(&ConnectionFTM::CmdReqDynDat, &fFTM)))
1621 ("request transmission of dynamic data block");
1622
1623 AddEvent("REQUEST_STATIC_DATA", kStateIdle)
1624 (Wrapper(boost::bind(&ConnectionFTM::CmdReqStatDat, &fFTM)))
1625 ("request transmission of static data from FTM to memory");
1626
1627 AddEvent("GET_REGISTER", "I", kStateIdle)
1628 (boost::bind(&StateMachineFTM::GetRegister, this, _1))
1629 ("read register from address addr"
1630 "|addr[short]:Address of register");
1631
1632 AddEvent("SET_REGISTER", "I:2", kStateIdle)
1633 (boost::bind(&StateMachineFTM::SetRegister, this, _1))
1634 ("set register to value"
1635 "|addr[short]:Address of register"
1636 "|val[short]:Value to be set");
1637
1638 AddEvent("START_RUN", kStateIdle)
1639 (Wrapper(boost::bind(&ConnectionFTM::CmdStartRun, &fFTM)))
1640 ("start a run (start distributing triggers)");
1641
1642 AddEvent("STOP_RUN", kStateTakingData)
1643 (Wrapper(boost::bind(&ConnectionFTM::CmdStopRun, &fFTM)))
1644 ("stop a run (stop distributing triggers)");
1645
1646 AddEvent("TAKE_N_EVENTS", "I", kStateIdle)
1647 (boost::bind(&StateMachineFTM::TakeNevents, this, _1))
1648 ("take n events (distribute n triggers)|number[int]:Number of events to be taken");
1649
1650 AddEvent("DISABLE_REPORTS", "B", kStateIdle)
1651 (boost::bind(&StateMachineFTM::DisableReports, this, _1))
1652 ("disable sending rate reports"
1653 "|status[bool]:disable or enable that the FTM sends rate reports (yes/no)");
1654
1655 AddEvent("SET_THRESHOLD", "I:2", kStateIdle)
1656 (boost::bind(&StateMachineFTM::SetThreshold, this, _1))
1657 ("Set the comparator threshold"
1658 "|Patch[idx]:Index of the patch (0-159), -1 for all"
1659 "|Threshold[counts]:Threshold to be set in binary counts");
1660
1661 AddEvent("SET_PRESCALING", "I:1", kStateIdle)
1662 (boost::bind(&StateMachineFTM::SetPrescaling, this, _1))
1663 (""
1664 "|[]:");
1665
1666 AddEvent("ENABLE_FTU", "I:1;B:1", kStateIdle)
1667 (boost::bind(&StateMachineFTM::EnableFTU, this, _1))
1668 ("Enable or disable FTU"
1669 "|Board[idx]:Index of the board (0-39), -1 for all"
1670 "|Enable[bool]:Whether FTU should be enabled or disabled (yes/no)");
1671
1672 AddEvent("DISABLE_PIXEL", "S:1", kStateIdle)
1673 (boost::bind(&StateMachineFTM::EnablePixel, this, _1, false))
1674 ("(-1 or all)");
1675
1676 AddEvent("ENABLE_PIXEL", "S:1", kStateIdle)
1677 (boost::bind(&StateMachineFTM::EnablePixel, this, _1, true))
1678 ("(-1 or all)");
1679
1680 AddEvent("DISABLE_ALL_PIXELS_EXCEPT", "S:1", kStateIdle)
1681 (boost::bind(&StateMachineFTM::DisableAllPixelsExcept, this, _1))
1682 ("");
1683
1684 AddEvent("DISABLE_ALL_PATCHES_EXCEPT", "S:1", kStateIdle)
1685 (boost::bind(&StateMachineFTM::DisableAllPatchesExcept, this, _1))
1686 ("");
1687
1688 AddEvent("TOGGLE_PIXEL", "S:1", kStateIdle)
1689 (boost::bind(&StateMachineFTM::TogglePixel, this, _1))
1690 ("");
1691
1692 AddEvent("TOGGLE_FTU", "I:1", kStateIdle)
1693 (boost::bind(&StateMachineFTM::ToggleFTU, this, _1))
1694 ("Toggle status of FTU (this is mainly meant to be used in the GUI)"
1695 "|Board[idx]:Index of the board (0-39)");
1696
1697 AddEvent("SET_TRIGGER_INTERVAL", "I:1", kStateIdle)
1698 (boost::bind(&StateMachineFTM::SetTriggerInterval, this, _1))
1699 ("Sets the trigger interval which is the distance between two consecutive artificial triggers."
1700 "|interval[int]:The applied trigger interval is: interval*4ns+8ns");
1701
1702 AddEvent("SET_TRIGGER_DELAY", "I:1", kStateIdle)
1703 (boost::bind(&StateMachineFTM::SetTriggerDelay, this, _1))
1704 (""
1705 "|delay[int]:The applied trigger delay is: delay*4ns+8ns");
1706
1707 AddEvent("SET_TIME_MARKER_DELAY", "I:1", kStateIdle)
1708 (boost::bind(&StateMachineFTM::SetTimeMarkerDelay, this, _1))
1709 (""
1710 "|delay[int]:The applied time marker delay is: delay*4ns+8ns");
1711
1712 AddEvent("SET_DEAD_TIME", "I:1", kStateIdle)
1713 (boost::bind(&StateMachineFTM::SetDeadTime, this, _1))
1714 (""
1715 "|dead_time[int]:The applied dead time is: dead_time*4ns+8ns");
1716
1717 AddEvent("ENABLE_TRIGGER", "B:1", kStateIdle)
1718 (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kTrigger))
1719 ("Switch on the physics trigger"
1720 "|Enable[bool]:Enable physics trigger (yes/no)");
1721
1722 // FIXME: Switch on/off depending on sequence
1723 AddEvent("ENABLE_EXT1", "B:1", kStateIdle)
1724 (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kExt1))
1725 ("Switch on the triggers through the first external line"
1726 "|Enable[bool]:Enable ext1 trigger (yes/no)");
1727
1728 // FIXME: Switch on/off depending on sequence
1729 AddEvent("ENABLE_EXT2", "B:1", kStateIdle)
1730 (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kExt2))
1731 ("Switch on the triggers through the second external line"
1732 "|Enable[bool]:Enable ext2 trigger (yes/no)");
1733
1734 AddEvent("ENABLE_VETO", "B:1", kStateIdle)
1735 (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kVeto))
1736 ("Enable veto line"
1737 "|Enable[bool]:Enable veto (yes/no)");
1738
1739 AddEvent("ENABLE_CLOCK_CONDITIONER", "B:1", kStateIdle)
1740 (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kClockConditioner))
1741 ("Enable clock conidtioner output in favor of time marker output"
1742 "|Enable[bool]:Enable clock conditioner (yes/no)");
1743
1744 AddEvent("SET_TRIGGER_SEQUENCE", "S:3", kStateIdle)
1745 (boost::bind(&StateMachineFTM::SetTriggerSeq, this, _1))
1746 ("Setup the sequence of artificial triggers produced by the FTM"
1747 "|Ped[short]:number of pedestal triggers in a row"
1748 "|LPext[short]:number of triggers of the external light pulser"
1749 "|LPint[short]:number of triggers of the internal light pulser");
1750
1751 AddEvent("SET_TRIGGER_MULTIPLICITY", "S:1", kStateIdle)
1752 (boost::bind(&StateMachineFTM::SetTriggerMultiplicity, this, _1))
1753 ("Setup the Multiplicity condition for physcis triggers"
1754 "|N[int]:Number of requirered coincident triggers from sum-patches (1-40)");
1755
1756 AddEvent("SET_TRIGGER_WINDOW", "S:1", kStateIdle)
1757 (boost::bind(&StateMachineFTM::SetTriggerWindow, this, _1))
1758 ("");
1759
1760 AddEvent("SET_CALIBRATION_MULTIPLICITY", "S:1", kStateIdle)
1761 (boost::bind(&StateMachineFTM::SetCalibMultiplicity, this, _1))
1762 ("Setup the Multiplicity condition for artificial (calibration) triggers"
1763 "|N[int]:Number of requirered coincident triggers from sum-patches (1-40)");
1764
1765 AddEvent("SET_CALIBRATION_WINDOW", "S:1", kStateIdle)
1766 (boost::bind(&StateMachineFTM::SetCalibWindow, this, _1))
1767 ("");
1768
1769 AddEvent("SET_CLOCK_FREQUENCY", "I:1", kStateIdle)
1770 (boost::bind(&StateMachineFTM::SetClockFrequency, this, _1))
1771 ("");
1772
1773 AddEvent("SET_CLOCK_REGISTER", "X:8", kStateIdle)
1774 (boost::bind(&StateMachineFTM::SetClockRegister, this, _1))
1775 ("");
1776
1777
1778
1779 AddEvent("RESET_CRATE", "S:1", kStateIdle)
1780 (boost::bind(&StateMachineFTM::ResetCrate, this, _1))
1781 ("Reset one of the crates 0-3"
1782 "|crate[short]:Crate number to be reseted (0-3)");
1783
1784 AddEvent("RESET_CAMERA", kStateIdle)
1785 (Wrapper(boost::bind(&ConnectionFTM::CmdResetCamera, &fFTM)))
1786 ("Reset all crates. The commands are sent in the order 0,1,2,3");
1787
1788
1789 // Load/save static data block
1790 T::AddEvent("SAVE", "C", kStateIdle)
1791 (boost::bind(&StateMachineFTM::SaveStaticData, this, _1))
1792 ("Saves the static data (FTM configuration) from memory to a file"
1793 "|filename[string]:Filename (can include a path), .bin is automatically added");
1794
1795 T::AddEvent("LOAD", "C", kStateIdle)
1796 (boost::bind(&StateMachineFTM::LoadStaticData, this, _1))
1797 ("Loads the static data (FTM configuration) from a file into memory and sends it to the FTM"
1798 "|filename[string]:Filename (can include a path), .bin is automatically added");
1799
1800
1801
1802 // Verbosity commands
1803 T::AddEvent("SET_VERBOSE", "B")
1804 (boost::bind(&StateMachineFTM::SetVerbosity, this, _1))
1805 ("set verbosity state"
1806 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
1807
1808 T::AddEvent("SET_HEX_OUTPUT", "B")
1809 (boost::bind(&StateMachineFTM::SetHexOutput, this, _1))
1810 ("enable or disable hex output for received data"
1811 "|hexout[bool]:disable or enable hex output for received data (yes/no)");
1812
1813 T::AddEvent("SET_DYNAMIC_OUTPUT", "B")
1814 (boost::bind(&StateMachineFTM::SetDynamicOut, this, _1))
1815 ("enable or disable output for received dynamic data (data is still broadcasted via Dim)"
1816 "|dynout[bool]:disable or enable output for dynamic data (yes/no)");
1817
1818
1819 // Conenction commands
1820 AddEvent("DISCONNECT", kStateConnected, kStateIdle)
1821 (boost::bind(&StateMachineFTM::Disconnect, this))
1822 ("disconnect from ethernet");
1823
1824 AddEvent("RECONNECT", "O", kStateDisconnected, kStateConnected, kStateIdle)
1825 (boost::bind(&StateMachineFTM::Reconnect, this, _1))
1826 ("(Re)connect ethernet connection to FTM, a new address can be given"
1827 "|[host][string]:new ethernet address in the form <host:port>");
1828
1829 fFTM.StartConnect();
1830 }
1831
1832 void SetEndpoint(const string &url)
1833 {
1834 fFTM.SetEndpoint(url);
1835 }
1836
1837 bool SetConfiguration(const Configuration &conf)
1838 {
1839 SetEndpoint(conf.Get<string>("addr"));
1840
1841 fFTM.SetVerbose(!conf.Get<bool>("quiet"));
1842 fFTM.SetHexOutput(conf.Get<bool>("hex-out"));
1843 fFTM.SetDynamicOut(conf.Get<bool>("dynamic-out"));
1844
1845// fFTM.SetDefaultSetup(conf.Get<string>("default-setup"));
1846
1847 return true;
1848 }
1849};
1850
1851// ------------------------------------------------------------------------
1852
1853void RunThread(StateMachineImp *io_service)
1854{
1855 // This is necessary so that the StateMachien Thread can signal the
1856 // Readline to exit
1857 io_service->Run();
1858 Readline::Stop();
1859}
1860
1861/*
1862template<class S, class T>
1863int RunDim(Configuration &conf)
1864{
1865 WindowLog wout;
1866
1867 ReadlineColor::PrintBootMsg(wout, conf.GetName(), false);
1868
1869 if (conf.Has("log"))
1870 if (!wout.OpenLogFile(conf.Get<string>("log")))
1871 wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
1872
1873 // Start io_service.Run to use the StateMachineImp::Run() loop
1874 // Start io_service.run to only use the commandHandler command detaching
1875 StateMachineFTM<S, T> io_service(wout);
1876 if (!io_service.SetConfiguration(conf))
1877 return -1;
1878
1879 io_service.Run();
1880
1881 return 0;
1882}
1883*/
1884
1885template<class T, class S, class R>
1886int RunShell(Configuration &conf)
1887{
1888 static T shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
1889
1890 WindowLog &win = shell.GetStreamIn();
1891 WindowLog &wout = shell.GetStreamOut();
1892
1893 if (conf.Has("log"))
1894 if (!wout.OpenLogFile(conf.Get<string>("log")))
1895 win << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
1896
1897 StateMachineFTM<S, R> io_service(wout);
1898 if (!io_service.SetConfiguration(conf))
1899 return -1;
1900
1901 shell.SetReceiver(io_service);
1902
1903 boost::thread t(boost::bind(RunThread, &io_service));
1904 // boost::thread t(boost::bind(&StateMachineFTM<S>::Run, &io_service));
1905
1906 if (conf.Has("exec"))
1907 {
1908 const vector<string> v = conf.Get<vector<string>>("exec");
1909 for (vector<string>::const_iterator it=v.begin(); it!=v.end(); it++)
1910 shell.Execute(*it);
1911 }
1912
1913 shell.Run(); // Run the shell
1914 io_service.Stop(); // Signal Loop-thread to stop
1915 // io_service.Close(); // Obsolete, done by the destructor
1916
1917 // Wait until the StateMachine has finished its thread
1918 // before returning and destroying the dim objects which might
1919 // still be in use.
1920 t.join();
1921
1922 return 0;
1923}
1924
1925void SetupConfiguration(Configuration &conf)
1926{
1927 const string n = conf.GetName()+".log";
1928
1929 po::options_description config("Program options");
1930 config.add_options()
1931 ("dns", var<string>("localhost"), "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
1932 ("log,l", var<string>(n), "Write log-file")
1933 ("no-dim,d", po_bool(), "Disable dim services")
1934 ("console,c", var<int>(), "Use console (0=shell, 1=simple buffered, X=simple unbuffered)")
1935 ("exec,e", vars<string>(), "Execute one or more scrips at startup")
1936 ;
1937
1938 po::options_description control("FTM control options");
1939 control.add_options()
1940 ("addr,a", var<string>("localhost:5000"), "Network address of FTM")
1941 ("quiet,q", po_bool(), "Disable printing contents of all received messages (except dynamic data) in clear text.")
1942 ("hex-out", po_bool(), "Enable printing contents of all printed messages also as hex data.")
1943 ("dynamic-out", po_bool(), "Enable printing received dynamic data.")
1944// ("default-setup", var<string>(), "Binary file with static data loaded whenever a connection to the FTM was established.")
1945 ;
1946
1947 conf.AddEnv("dns", "DIM_DNS_NODE");
1948
1949 conf.AddOptions(config);
1950 conf.AddOptions(control);
1951}
1952
1953/*
1954 Extract usage clause(s) [if any] for SYNOPSIS.
1955 Translators: "Usage" and "or" here are patterns (regular expressions) which
1956 are used to match the usage synopsis in program output. An example from cp
1957 (GNU coreutils) which contains both strings:
1958 Usage: cp [OPTION]... [-T] SOURCE DEST
1959 or: cp [OPTION]... SOURCE... DIRECTORY
1960 or: cp [OPTION]... -t DIRECTORY SOURCE...
1961 */
1962void PrintUsage()
1963{
1964 cout <<
1965 "The ftmctrl controls the FTM (FACT Trigger Master) board.\n"
1966 "\n"
1967 "The default is that the program is started without user intercation. "
1968 "All actions are supposed to arrive as DimCommands. Using the -c "
1969 "option, a local shell can be initialized. With h or help a short "
1970 "help message about the usuage can be brought to the screen.\n"
1971 "\n"
1972 "Usage: ftmctrl [-c type] [OPTIONS]\n"
1973 " or: ftmctrl [OPTIONS]\n";
1974 cout << endl;
1975}
1976
1977void PrintHelp()
1978{
1979 /* Additional help text which is printed after the configuration
1980 options goes here */
1981
1982 /*
1983 cout << "bla bla bla" << endl << endl;
1984 cout << endl;
1985 cout << "Environment:" << endl;
1986 cout << "environment" << endl;
1987 cout << endl;
1988 cout << "Examples:" << endl;
1989 cout << "test exam" << endl;
1990 cout << endl;
1991 cout << "Files:" << endl;
1992 cout << "files" << endl;
1993 cout << endl;
1994 */
1995}
1996
1997int main(int argc, const char* argv[])
1998{
1999 Configuration conf(argv[0]);
2000 conf.SetPrintUsage(PrintUsage);
2001 SetupConfiguration(conf);
2002
2003 po::variables_map vm;
2004 try
2005 {
2006 vm = conf.Parse(argc, argv);
2007 }
2008#if BOOST_VERSION > 104000
2009 catch (po::multiple_occurrences &e)
2010 {
2011 cerr << "Program options invalid due to: " << e.what() << " of '" << e.get_option_name() << "'." << endl;
2012 return -1;
2013 }
2014#endif
2015 catch (exception& e)
2016 {
2017 cerr << "Program options invalid due to: " << e.what() << endl;
2018 return -1;
2019 }
2020
2021 if (conf.HasVersion() || conf.HasPrint())
2022 return -1;
2023
2024 if (conf.HasHelp())
2025 {
2026 PrintHelp();
2027 return -1;
2028 }
2029
2030 Dim::Setup(conf.Get<string>("dns"));
2031
2032 //try
2033 {
2034 // No console access at all
2035 if (!conf.Has("console"))
2036 {
2037 if (conf.Get<bool>("no-dim"))
2038 return RunShell<LocalStream, StateMachine, ConnectionFTM>(conf);
2039 else
2040 return RunShell<LocalStream, StateMachineDim, ConnectionDimFTM>(conf);
2041 }
2042 // Cosole access w/ and w/o Dim
2043 if (conf.Get<bool>("no-dim"))
2044 {
2045 if (conf.Get<int>("console")==0)
2046 return RunShell<LocalShell, StateMachine, ConnectionFTM>(conf);
2047 else
2048 return RunShell<LocalConsole, StateMachine, ConnectionFTM>(conf);
2049 }
2050 else
2051 {
2052 if (conf.Get<int>("console")==0)
2053 return RunShell<LocalShell, StateMachineDim, ConnectionDimFTM>(conf);
2054 else
2055 return RunShell<LocalConsole, StateMachineDim, ConnectionDimFTM>(conf);
2056 }
2057 }
2058 /*catch (std::exception& e)
2059 {
2060 cerr << "Exception: " << e.what() << endl;
2061 return -1;
2062 }*/
2063
2064 return 0;
2065}
Note: See TracBrowser for help on using the repository browser.