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

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