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

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