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

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