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

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