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

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