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

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