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

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