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

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