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

Last change on this file since 11287 was 11264, checked in by tbretz, 13 years ago
Removed includes which are now in Main.h
File size: 60.1 KB
Line 
1#include <boost/bind.hpp>
2#include <boost/array.hpp>
3#include <boost/asio/error.hpp>
4#include <boost/asio/deadline_timer.hpp>
5
6#include "Dim.h"
7#include "Event.h"
8#include "Shell.h"
9#include "StateMachineDim.h"
10#include "Connection.h"
11#include "Configuration.h"
12#include "Console.h"
13#include "Converter.h"
14
15#include "tools.h"
16
17#include "HeadersFTM.h"
18
19
20namespace ba = boost::asio;
21namespace bs = boost::system;
22
23using namespace std;
24
25// ------------------------------------------------------------------------
26
27class ConnectionFTM : public Connection
28{
29 vector<uint16_t> fBuffer;
30
31 bool fHasHeader;
32 int fState;
33
34 bool fIsVerbose;
35 bool fIsDynamicOut;
36 bool fIsHexOutput;
37
38// string fDefaultSetup;
39
40 // --verbose
41 // --hex-out
42 // --dynamic-out
43 // --load-file
44 // --leds
45 // --trigger-interval
46 // --physcis-coincidence
47 // --calib-coincidence
48 // --physcis-window
49 // --physcis-window
50 // --trigger-delay
51 // --time-marker-delay
52 // --dead-time
53 // --clock-conditioner-r0
54 // --clock-conditioner-r1
55 // --clock-conditioner-r8
56 // --clock-conditioner-r9
57 // --clock-conditioner-r11
58 // --clock-conditioner-r13
59 // --clock-conditioner-r14
60 // --clock-conditioner-r15
61 // ...
62
63protected:
64 map<uint16_t, int> fCounter;
65
66 FTM::Header fHeader;
67 FTM::FtuList fFtuList;
68 FTM::StaticData fStaticData;
69 FTM::DynamicData fDynamicData;
70 FTM::Error fError;
71
72 virtual void UpdateFirstHeader()
73 {
74 // FIXME: Message() ?
75 Out() << endl << kBold << "First header received:" << endl;
76 Out() << fHeader;
77 if (fIsHexOutput)
78 Out() << Converter::GetHex<uint16_t>(fHeader, 16) << endl;
79 }
80
81 virtual void UpdateHeader()
82 {
83 // emit service with trigger counter from header
84 if (!fIsVerbose)
85 return;
86
87 if (fHeader.fType==FTM::kDynamicData && !fIsDynamicOut)
88 return;
89
90 Out() << endl << kBold << "Header received:" << endl;
91 Out() << fHeader;
92 if (fIsHexOutput)
93 Out() << Converter::GetHex<uint16_t>(fHeader, 16) << endl;
94 }
95
96 virtual void UpdateFtuList()
97 {
98 if (!fIsVerbose)
99 return;
100
101 Out() << endl << kBold << "FtuList received:" << endl;
102 Out() << fFtuList;
103 if (fIsHexOutput)
104 Out() << Converter::GetHex<uint16_t>(fFtuList, 16) << endl;
105 }
106
107 virtual void UpdateStaticData()
108 {
109 if (!fIsVerbose)
110 return;
111
112 Out() << endl << kBold << "Static data received:" << endl;
113 Out() << fStaticData;
114 if (fIsHexOutput)
115 Out() << Converter::GetHex<uint16_t>(fStaticData, 16) << endl;
116 }
117
118 virtual void UpdateDynamicData()
119 {
120 if (!fIsDynamicOut)
121 return;
122
123 Out() << endl << kBold << "Dynamic data received:" << endl;
124 Out() << fDynamicData;
125 if (fIsHexOutput)
126 Out() << Converter::GetHex<uint16_t>(fDynamicData, 16) << endl;
127 }
128
129 virtual void UpdateError()
130 {
131 if (!fIsVerbose)
132 return;
133
134 Out() << endl << kRed << "Error received:" << endl;
135 Out() << fError;
136 if (fIsHexOutput)
137 Out() << Converter::GetHex<uint16_t>(fError, 16) << endl;
138 }
139
140 virtual void UpdateCounter()
141 {
142 if (!fIsVerbose)
143 return;
144
145 if (!fIsDynamicOut)
146 return;
147
148 Out() << "Received: ";
149 Out() << "H=" << fCounter[FTM::kHeader] << " ";
150 Out() << "S=" << fCounter[FTM::kStaticData] << " ";
151 Out() << "D=" << fCounter[FTM::kDynamicData] << " ";
152 Out() << "F=" << fCounter[FTM::kFtuList] << " ";
153 Out() << "E=" << fCounter[FTM::kErrorList] << " ";
154 Out() << "R=" << fCounter[FTM::kRegister] << endl;
155 }
156
157 bool CheckConsistency()
158 {
159 bool warn1 = false;
160 if (fStaticData.IsEnabled(FTM::StaticData::kPedestal) != (fStaticData.GetSequencePed() >0) ||
161 fStaticData.IsEnabled(FTM::StaticData::kLPint) != (fStaticData.GetSequenceLPint()>0) ||
162 fStaticData.IsEnabled(FTM::StaticData::kLPext) != (fStaticData.GetSequenceLPext()>0))
163 {
164 warn1 = true;
165 fStaticData.Enable(FTM::StaticData::kPedestal, fStaticData.GetSequencePed()>0);
166 fStaticData.Enable(FTM::StaticData::kLPint, fStaticData.GetSequenceLPint()>0);
167 fStaticData.Enable(FTM::StaticData::kLPext, fStaticData.GetSequenceLPext()>0);
168 }
169
170 bool warn2 = false;
171 const uint16_t ref = fStaticData[0].fPrescaling;
172 for (int i=1; i<40; i++)
173 {
174 if (fStaticData[i].fPrescaling != ref)
175 {
176 warn2 = true;
177 fStaticData[i].fPrescaling = ref;
178 }
179 }
180
181 if (warn1)
182 Warn("GeneralSettings not consistent with trigger sequence.");
183 if (warn2)
184 Warn("Prescaling not consistent for all boards.");
185
186 return !warn1 && !warn2;
187 }
188
189private:
190 void HandleReceivedData(const bs::error_code& err, size_t bytes_received, int /*type*/)
191 {
192 // Do not schedule a new read if the connection failed.
193 if (bytes_received==0 || err)
194 {
195 if (err==ba::error::eof)
196 Warn("Connection closed by remote host (FTM).");
197
198 // 107: Transport endpoint is not connected (bs::error_code(107, bs::system_category))
199 // 125: Operation canceled
200 if (err && err!=ba::error::eof && // Connection closed by remote host
201 err!=ba::error::basic_errors::not_connected && // Connection closed by remote host
202 err!=ba::error::basic_errors::operation_aborted) // Connection closed by us
203 {
204 ostringstream str;
205 str << "Reading from " << URL() << ": " << err.message() << " (" << err << ")";// << endl;
206 Error(str);
207 }
208 PostClose(err!=ba::error::basic_errors::operation_aborted);
209 return;
210 }
211
212 // If we have not yet received a header we expect one now
213 // This could be moved to a HandleReceivedHeader function
214 if (!fHasHeader)
215 {
216 if (bytes_received!=sizeof(FTM::Header))
217 {
218 ostringstream str;
219 str << "Excepted " << sizeof(FTM::Header) << " bytes (FTM::Header) but received " << bytes_received << ".";
220 Error(str);
221 PostClose(false);
222 return;
223 }
224
225 fHeader = fBuffer;
226
227 // Check the data integrity
228 if (fHeader.fDelimiter!=FTM::kDelimiterStart)
229 {
230 ostringstream str;
231 str << "Invalid header received: start delimiter wrong, received ";
232 str << hex << fHeader.fDelimiter << ", expected " << FTM::kDelimiterStart << ".";
233 Error(str);
234 PostClose(false);
235 return;
236 }
237
238 fHasHeader = true;
239
240 // Convert FTM state into FtmCtrl state
241 switch (fHeader.fState)
242 {
243 case FTM::kFtmIdle:
244 case FTM::kFtmConfig:
245 fState = FTM::kIdle;
246 break;
247
248 case FTM::kFtmCalib:
249 case FTM::kFtmRunning:
250 fState = FTM::kTakingData;
251 break;
252 }
253
254 if (++fCounter[FTM::kHeader]==1)
255 UpdateFirstHeader();
256
257 UpdateCounter();
258 UpdateHeader();
259
260 // Start reading of data
261 switch (fHeader.fType)
262 {
263 case FTM::kStaticData:
264 case FTM::kDynamicData:
265 case FTM::kFtuList:
266 case FTM::kRegister:
267 case FTM::kErrorList:
268 // This is not very efficient because the space is reallocated
269 // maybe we can check if the capacity of the std::vector
270 // is ever decreased. If not, everythign is fine.
271 fBuffer.resize(fHeader.fDataSize);
272 AsyncRead(ba::buffer(fBuffer));
273 AsyncWait(fInTimeout, 50, &Connection::HandleReadTimeout);
274 return;
275
276 default:
277 ostringstream str;
278 str << "Unknonw type " << fHeader.fType << " in received header." << endl;
279 Error(str);
280 PostClose(false);
281 return;
282 }
283
284 return;
285 }
286
287 // Check the data integrity (check end delimiter)
288 if (ntohs(fBuffer.back())!=FTM::kDelimiterEnd)
289 {
290 ostringstream str;
291 str << "Invalid data received: end delimiter wrong, received ";
292 str << hex << ntohs(fBuffer.back()) << ", expected " << FTM::kDelimiterEnd << ".";
293 Error(str);
294 PostClose(false);
295 return;
296 }
297
298 // Remove end delimiter
299 fBuffer.pop_back();
300
301 try
302 {
303 // If we have already received a header this is the data now
304 // This could be moved to a HandleReceivedData function
305
306 fCounter[fHeader.fType]++;
307 UpdateCounter();
308
309 switch (fHeader.fType)
310 {
311 case FTM::kFtuList:
312 fFtuList = fBuffer;
313 UpdateFtuList();
314 break;
315
316 case FTM::kStaticData:
317 fStaticData = fBuffer;
318
319 if (fCounter[FTM::kStaticData]==1)
320 if (!CheckConsistency())
321 {
322 CmdSendStatDat();
323 break;
324 }
325
326 UpdateStaticData();
327 break;
328
329 case FTM::kDynamicData:
330 fDynamicData = fBuffer;
331 UpdateDynamicData();
332 break;
333
334 case FTM::kRegister:
335 if (fIsVerbose)
336 {
337 Out() << endl << kBold << "Register received: " << endl;
338 Out() << "Addr: " << ntohs(fBuffer[0]) << endl;
339 Out() << "Value: " << ntohs(fBuffer[1]) << endl;
340 }
341 break;
342
343 case FTM::kErrorList:
344 fError = fBuffer;
345 UpdateError();
346 break;
347
348 default:
349 ostringstream str;
350 str << "Unknonw type " << fHeader.fType << " in header." << endl;
351 Error(str);
352 PostClose(false);
353 return;
354 }
355 }
356 catch (const logic_error &e)
357 {
358 ostringstream str;
359 str << "Exception converting buffer into data structure: " << e.what();
360 Error(str);
361 PostClose(false);
362 return;
363 }
364
365 fInTimeout.cancel();
366
367 fHeader.clear();
368 fHasHeader = false;
369 fBuffer.resize(sizeof(FTM::Header)/2);
370 AsyncRead(ba::buffer(fBuffer));
371 }
372
373 // This is called when a connection was established
374 void ConnectionEstablished()
375 {
376 fState = FTM::kConnected;
377 fCounter.clear();
378
379 fHeader.clear();
380 fHasHeader = false;
381 fBuffer.resize(sizeof(FTM::Header)/2);
382 AsyncRead(ba::buffer(fBuffer));
383
384// if (!fDefaultSetup.empty())
385// LoadStaticData(fDefaultSetup);
386
387 // Get a header and configdata!
388 CmdReqStatDat();
389
390 // get the DNA of the FTUs
391 CmdPing();
392 }
393
394 void HandleReadTimeout(const bs::error_code &error)
395 {
396 if (error==ba::error::basic_errors::operation_aborted)
397 return;
398
399 if (error)
400 {
401 ostringstream str;
402 str << "Read timeout of " << URL() << ": " << error.message() << " (" << error << ")";// << endl;
403 Error(str);
404
405 PostClose();
406 return;
407
408 }
409
410 if (!is_open())
411 {
412 // For example: Here we could schedule a new accept if we
413 // would not want to allow two connections at the same time.
414 return;
415 }
416
417 // Check whether the deadline has passed. We compare the deadline
418 // against the current time since a new asynchronous operation
419 // may have moved the deadline before this actor had a chance
420 // to run.
421 if (fInTimeout.expires_at() > ba::deadline_timer::traits_type::now())
422 return;
423
424 Error("Timeout reading data from "+URL());
425
426 PostClose();
427 }
428
429
430 template<size_t N>
431 void PostCmd(boost::array<uint16_t, N> dat, uint16_t u1=0, uint16_t u2=0, uint16_t u3=0, uint16_t u4=0)
432 {
433 boost::array<uint16_t, 5> cmd = {{ '@', u1, u2, u3, u4 }};
434
435 ostringstream msg;
436 msg << "Sending command:" << hex;
437 msg << " 0x" << setw(4) << setfill('0') << cmd[0];
438 msg << " 0x" << setw(4) << setfill('0') << u1;
439 msg << " 0x" << setw(4) << setfill('0') << u2;
440 msg << " 0x" << setw(4) << setfill('0') << u3;
441 msg << " 0x" << setw(4) << setfill('0') << u4;
442 msg << " (+" << dec << dat.size() << " words)";
443 Message(msg);
444
445 vector<uint16_t> out(cmd.size()+dat.size());
446
447 transform(cmd.begin(), cmd.end(), out.begin(), htons);
448 transform(dat.begin(), dat.end(), out.begin()+cmd.size(), htons);
449
450 PostMessage(out);
451 }
452
453 void PostCmd(vector<uint16_t> dat, uint16_t u1=0, uint16_t u2=0, uint16_t u3=0, uint16_t u4=0)
454 {
455 boost::array<uint16_t, 5> cmd = {{ '@', u1, u2, u3, u4 }};
456
457 ostringstream msg;
458 msg << "Sending command:" << hex;
459 msg << " 0x" << setw(4) << setfill('0') << cmd[0];
460 msg << " 0x" << setw(4) << setfill('0') << u1;
461 msg << " 0x" << setw(4) << setfill('0') << u2;
462 msg << " 0x" << setw(4) << setfill('0') << u3;
463 msg << " 0x" << setw(4) << setfill('0') << u4;
464 msg << " (+" << dec << dat.size() << " words)";
465 Message(msg);
466
467 vector<uint16_t> out(cmd.size()+dat.size());
468
469 transform(cmd.begin(), cmd.end(), out.begin(), htons);
470 copy(dat.begin(), dat.end(), out.begin()+cmd.size());
471
472 PostMessage(out);
473 }
474
475 void PostCmd(uint16_t u1=0, uint16_t u2=0, uint16_t u3=0, uint16_t u4=0)
476 {
477 PostCmd(boost::array<uint16_t, 0>(), u1, u2, u3, u4);
478 }
479public:
480
481// static const uint16_t kMaxAddr;
482
483public:
484 ConnectionFTM(ba::io_service& ioservice, MessageImp &imp) : Connection(ioservice, imp()),
485 fState(0), fIsVerbose(true), fIsDynamicOut(true), fIsHexOutput(true)
486 {
487 SetLogStream(&imp);
488 }
489
490 void CmdToggleLed()
491 {
492 PostCmd(FTM::kCmdToggleLed);
493 }
494
495 void CmdPing()
496 {
497 PostCmd(FTM::kCmdPing);
498 }
499
500 void CmdReqDynDat()
501 {
502 PostCmd(FTM::kCmdRead, FTM::kCmdDynamicData);
503 }
504
505 void CmdReqStatDat()
506 {
507 PostCmd(FTM::kCmdRead, FTM::kCmdStaticData);
508 }
509
510 void CmdSendStatDat()
511 {
512 PostCmd(fStaticData.HtoN(), FTM::kCmdWrite, FTM::kCmdStaticData);
513
514 // Request the changed configuration to ensure the
515 // change is distributed in the network
516 CmdReqStatDat();
517 }
518
519 void CmdStartRun()
520 {
521 PostCmd(FTM::kCmdStartRun, FTM::kStartRun);
522
523 // Update state information by requesting a new header
524 CmdGetRegister(0);
525 }
526
527 void CmdStopRun()
528 {
529 PostCmd(FTM::kCmdStopRun);
530
531 // Update state information by requesting a new header
532 CmdGetRegister(0);
533 }
534
535 void CmdTakeNevents(uint32_t n)
536 {
537 const boost::array<uint16_t, 2> data = {{ uint16_t(n>>16), uint16_t(n&0xffff) }};
538 PostCmd(data, FTM::kCmdStartRun, FTM::kTakeNevents);
539
540 // Update state information by requesting a new header
541 CmdGetRegister(0);
542 }
543
544 bool CmdSetRegister(uint16_t addr, uint16_t val)
545 {
546 if (addr>FTM::StaticData::kMaxAddr)
547 return false;
548
549 const boost::array<uint16_t, 2> data = {{ addr, val }};
550 PostCmd(data, FTM::kCmdWrite, FTM::kCmdRegister);
551
552 // Request the changed configuration to ensure the
553 // change is distributed in the network
554 CmdReqStatDat();
555
556 return true;
557 }
558
559 bool CmdGetRegister(uint16_t addr)
560 {
561 if (addr>FTM::StaticData::kMaxAddr)
562 return false;
563
564 const boost::array<uint16_t, 1> data = {{ addr }};
565 PostCmd(data, FTM::kCmdRead, FTM::kCmdRegister);
566
567 return true;
568 }
569
570 bool CmdResetCrate(uint16_t addr)
571 {
572 if (addr>3)
573 return false;
574
575 PostCmd(FTM::kCmdCrateReset, 1<<addr);
576
577 return true;
578 }
579
580 bool CmdResetCamera()
581 {
582 PostCmd(FTM::kCmdCrateReset, FTM::kResetCrate0);
583 PostCmd(FTM::kCmdCrateReset, FTM::kResetCrate1);
584 PostCmd(FTM::kCmdCrateReset, FTM::kResetCrate2);
585 PostCmd(FTM::kCmdCrateReset, FTM::kResetCrate3);
586
587 return true;
588 }
589
590 bool CmdDisableReports(bool b)
591 {
592 PostCmd(FTM::kCmdDisableReports, b ? uint16_t(0) : uint16_t(1));
593 return true;
594 }
595
596 void SetVerbose(bool b)
597 {
598 fIsVerbose = b;
599 }
600
601 void SetHexOutput(bool b)
602 {
603 fIsHexOutput = b;
604 }
605
606 void SetDynamicOut(bool b)
607 {
608 fIsDynamicOut = b;
609 }
610/*
611 void SetDefaultSetup(const string &file)
612 {
613 fDefaultSetup = file;
614 }
615*/
616 bool LoadStaticData(string name)
617 {
618 if (name.rfind(".bin")!=name.length()-4)
619 name += ".bin";
620
621 ifstream fin(name);
622 if (!fin)
623 return false;
624
625 FTM::StaticData data;
626
627 fin.read(reinterpret_cast<char*>(&data), sizeof(FTM::StaticData));
628
629 if (fin.gcount()<streamsize(sizeof(FTM::StaticData)))
630 return false;
631
632 if (fin.fail() || fin.eof())
633 return false;
634
635 if (fin.peek()!=-1)
636 return false;
637
638 fStaticData = data;
639
640 CmdSendStatDat();
641
642 return true;
643 }
644
645 bool SaveStaticData(string name) const
646 {
647 if (name.rfind(".bin")!=name.length()-4)
648 name += ".bin";
649
650 ofstream fout(name);
651 if (!fout)
652 return false;
653
654 fout.write(reinterpret_cast<const char*>(&fStaticData), sizeof(FTM::StaticData));
655
656 return !fout.bad();
657 }
658
659 bool SetThreshold(int32_t patch, int32_t value)
660 {
661 if (patch>159)
662 return false;
663
664 if (value<0 || value>0xffff)
665 return false;
666
667 if (patch<0)
668 {
669 bool ident = true;
670 for (int i=0; i<160; i++)
671 if (fStaticData[i/4].fDAC[patch%4] != value)
672 {
673 ident = false;
674 break;
675 }
676
677 if (ident)
678 return true;
679
680 for (int i=0; i<160; i++)
681 fStaticData[i/4].fDAC[i%4] = value;
682 }
683 else
684 {
685 if (fStaticData[patch/4].fDAC[patch%4] == value)
686 return true;
687
688 fStaticData[patch/4].fDAC[patch%4] = value;
689 }
690
691 // Maybe move to a "COMMIT" command?
692 CmdSendStatDat();
693
694 return true;
695 }
696
697 bool SetPrescaling(uint32_t value)
698 {
699 if (value>0xffff)
700 return false;
701
702 bool ident = true;
703 for (int i=0; i<40; i++)
704 if (fStaticData[i].fPrescaling != value)
705 {
706 ident = false;
707 break;
708 }
709
710 if (ident)
711 return true;
712
713 for (int i=0; i<40; i++)
714 fStaticData[i].fPrescaling = value;
715
716 // Maybe move to a "COMMIT" command?
717 CmdSendStatDat();
718
719 return true;
720 }
721
722 bool EnableFTU(int32_t board, bool enable)
723 {
724 if (board>39)
725 return false;
726
727 if (board<0)
728 {
729 if (enable)
730 fStaticData.EnableAllFTU();
731 else
732 fStaticData.DisableAllFTU();
733 }
734 else
735 {
736 if (enable)
737 fStaticData.EnableFTU(board);
738 else
739 fStaticData.DisableFTU(board);
740
741 }
742
743 // Maybe move to a "COMMIT" command?
744 CmdSendStatDat();
745
746 return true;
747 }
748
749 bool ToggleFTU(uint32_t board)
750 {
751 if (board>39)
752 return false;
753
754 fStaticData.ToggleFTU(board);
755
756 // Maybe move to a "COMMIT" command?
757 CmdSendStatDat();
758
759 return true;
760 }
761
762 bool SetVal(uint16_t *dest, uint32_t val, uint32_t max)
763 {
764 if (val>max)
765 return false;
766
767 if (*dest==val)
768 return true;
769
770 *dest = val;
771
772 CmdSendStatDat();
773
774 return true;
775 }
776
777 bool SetTriggerInterval(uint32_t val)
778 {
779 return SetVal(&fStaticData.fTriggerInterval, val,
780 FTM::StaticData::kMaxTriggerInterval);
781 }
782
783 bool SetTriggerDelay(uint32_t val)
784 {
785 return SetVal(&fStaticData.fDelayTrigger, val,
786 FTM::StaticData::kMaxDelayTrigger);
787 }
788
789 bool SetTimeMarkerDelay(uint32_t val)
790 {
791 return SetVal(&fStaticData.fDelayTimeMarker, val,
792 FTM::StaticData::kMaxDelayTimeMarker);
793 }
794
795 bool SetDeadTime(uint32_t val)
796 {
797 return SetVal(&fStaticData.fDeadTime, val,
798 FTM::StaticData::kMaxDeadTime);
799 }
800
801 void Enable(FTM::StaticData::GeneralSettings type, bool enable)
802 {
803 if (fStaticData.IsEnabled(type)!=enable)
804 {
805 fStaticData.Enable(type, enable);
806 CmdSendStatDat();
807 }
808 }
809
810 bool SetTriggerSeq(const uint16_t d[3])
811 {
812 const uint16_t oldset = fStaticData.fGeneralSettings;
813 const uint16_t oldseq = fStaticData.fTriggerSequence;
814
815 if (d[0]>FTM::StaticData::kMaxSequence ||
816 d[1]>FTM::StaticData::kMaxSequence ||
817 d[2]>FTM::StaticData::kMaxSequence)
818 return false;
819
820 fStaticData.Enable(FTM::StaticData::kPedestal, d[0]>0);
821 fStaticData.Enable(FTM::StaticData::kLPext, d[1]>0);
822 fStaticData.Enable(FTM::StaticData::kLPint, d[2]>0);
823
824 fStaticData.fTriggerSequence =
825 (uint16_t(d[0])<<10) | (uint16_t(d[2])<<5) | uint16_t(d[1]);
826
827 if (oldseq!=fStaticData.fTriggerSequence || oldset!=fStaticData.fGeneralSettings)
828 CmdSendStatDat();
829
830 return true;
831 }
832
833 bool SetTriggerMultiplicity(uint16_t n)
834 {
835 if (n==0 || n>FTM::StaticData::kMaxMultiplicity)
836 return false;
837
838 if (n==fStaticData.fMultiplicityPhysics)
839 return true;
840
841 fStaticData.fMultiplicityPhysics = n;
842
843 CmdSendStatDat();
844
845 return true;
846 }
847
848 bool SetTriggerWindow(uint16_t win)
849 {
850 if (win>FTM::StaticData::kMaxWindow)
851 return false;
852
853 if (win==fStaticData.fWindowPhysics)
854 return true;
855
856 fStaticData.fWindowPhysics = win;
857
858 CmdSendStatDat();
859
860 return true;
861 }
862
863 bool SetCalibMultiplicity(uint16_t n)
864 {
865 if (n==0 || n>FTM::StaticData::kMaxMultiplicity)
866 return false;
867
868 if (n==fStaticData.fMultiplicityCalib)
869 return true;
870
871 fStaticData.fMultiplicityCalib = n;
872
873 CmdSendStatDat();
874
875 return true;
876 }
877
878 bool SetCalibWindow(uint16_t win)
879 {
880 if (win>FTM::StaticData::kMaxWindow)
881 return false;
882
883 if (win==fStaticData.fWindowCalib)
884 return true;
885
886 fStaticData.fWindowCalib = win;
887
888 CmdSendStatDat();
889
890 return true;
891 }
892
893 bool SetClockRegister(const uint64_t reg[])
894 {
895 for (int i=0; i<8; i++)
896 {
897 if (reg[i]>0xffffffff)
898 return false;
899
900 fStaticData.fClockConditioner[i] = reg[i];
901 }
902
903 CmdSendStatDat();
904
905 return true;
906 }
907
908 bool EnablePixel(int16_t idx, bool enable)
909 {
910 if (idx<-1 || idx>FTM::StaticData::kMaxPixelIdx)
911 return false;
912
913 if (idx==-1)
914 for (int i=0; i<=FTM::StaticData::kMaxPixelIdx; i++)
915 fStaticData.EnablePixel(i, enable);
916 else
917 fStaticData.EnablePixel(idx, enable);
918
919 CmdSendStatDat();
920
921 return true;
922 }
923
924 bool DisableAllPixelsExcept(uint16_t idx)
925 {
926 if (idx>FTM::StaticData::kMaxPixelIdx)
927 return false;
928
929 for (int i=0; i<=FTM::StaticData::kMaxPixelIdx; i++)
930 fStaticData.EnablePixel(i, i==idx);
931
932 CmdSendStatDat();
933
934 return true;
935 }
936
937 bool DisableAllPatchesExcept(uint16_t idx)
938 {
939 if (idx>FTM::StaticData::kMaxPatchIdx)
940 return false;
941
942 for (int i=0; i<=FTM::StaticData::kMaxPixelIdx; i++)
943 fStaticData.EnablePixel(i, i/9==idx);
944
945 CmdSendStatDat();
946
947 return true;
948 }
949
950 bool TogglePixel(uint16_t idx)
951 {
952 if (idx>FTM::StaticData::kMaxPixelIdx)
953 return false;
954
955 fStaticData.EnablePixel(idx, !fStaticData.Enabled(idx));
956
957 CmdSendStatDat();
958
959 return true;
960 }
961
962 int GetState() const { return IsConnected() ? fState : (int)FTM::kDisconnected; }
963};
964
965//const uint16_t ConnectionFTM::kMaxAddr = 0xfff;
966
967// ------------------------------------------------------------------------
968
969#include "DimDescriptionService.h"
970
971class ConnectionDimFTM : public ConnectionFTM
972{
973private:
974
975 DimDescribedService fDimPassport;
976 DimDescribedService fDimTriggerCounter;
977 DimDescribedService fDimError;
978 DimDescribedService fDimFtuList;
979 DimDescribedService fDimStaticData;
980 DimDescribedService fDimDynamicData;
981 DimDescribedService fDimCounter;
982
983 void UpdateFirstHeader()
984 {
985 ConnectionFTM::UpdateFirstHeader();
986
987 const FTM::DimPassport data(fHeader);
988 fDimPassport.Update(data);
989 }
990
991 void UpdateHeader()
992 {
993 ConnectionFTM::UpdateHeader();
994
995 if (fHeader.fType!=FTM::kDynamicData)
996 return;
997
998 const FTM::DimTriggerCounter data(fHeader);
999 fDimTriggerCounter.Update(data);
1000 }
1001
1002 void UpdateFtuList()
1003 {
1004 ConnectionFTM::UpdateFtuList();
1005
1006 const FTM::DimFtuList data(fHeader, fFtuList);
1007 fDimFtuList.Update(data);
1008 }
1009
1010 void UpdateStaticData()
1011 {
1012 ConnectionFTM::UpdateStaticData();
1013
1014 const FTM::DimStaticData data(fHeader, fStaticData);
1015 fDimStaticData.Update(data);
1016 }
1017
1018 void UpdateDynamicData()
1019 {
1020 ConnectionFTM::UpdateDynamicData();
1021
1022 const FTM::DimDynamicData data(fHeader, fDynamicData);
1023 fDimDynamicData.Update(data);
1024 }
1025
1026 void UpdateError()
1027 {
1028 ConnectionFTM::UpdateError();
1029
1030 const FTM::DimError data(fHeader, fError);
1031 fDimError.Update(data);
1032 }
1033
1034 void UpdateCounter()
1035 {
1036 ConnectionFTM::UpdateCounter();
1037
1038 const uint32_t counter[6] =
1039 {
1040 fCounter[FTM::kHeader],
1041 fCounter[FTM::kStaticData],
1042 fCounter[FTM::kDynamicData],
1043 fCounter[FTM::kFtuList],
1044 fCounter[FTM::kErrorList],
1045 fCounter[FTM::kRegister],
1046 };
1047
1048 fDimCounter.Update(counter);
1049 }
1050
1051public:
1052 ConnectionDimFTM(ba::io_service& ioservice, MessageImp &imp) :
1053 ConnectionFTM(ioservice, imp),
1054 fDimPassport ("FTM_CONTROL/PASSPORT", "X:1;S:1", ""),
1055 fDimTriggerCounter("FTM_CONTROL/TRIGGER_COUNTER", "X:1;I:1", ""),
1056 fDimError ("FTM_CONTROL/ERROR", "X:1;S:1;S:28", ""),
1057 fDimFtuList ("FTM_CONTROL/FTU_LIST", "X:1;X:1;S:1;C:4;X:40;C:40;C:40", ""),
1058 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", ""),
1059 fDimDynamicData ("FTM_CONTROL/DYNAMIC_DATA", "X:1;X:1;F:4;I:160;I:40;S:40;S:40", ""),
1060 fDimCounter ("FTM_CONTROL/COUNTER", "I:6", "")
1061 {
1062 }
1063
1064 // 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
1065};
1066
1067// ------------------------------------------------------------------------
1068
1069template <class T, class S>
1070class StateMachineFTM : public T, public ba::io_service, public ba::io_service::work
1071{
1072 int Wrap(boost::function<void()> f)
1073 {
1074 f();
1075 return T::GetCurrentState();
1076 }
1077
1078 boost::function<int(const EventImp &)> Wrapper(boost::function<void()> func)
1079 {
1080 return boost::bind(&StateMachineFTM::Wrap, this, func);
1081 }
1082
1083private:
1084 S fFTM;
1085
1086 enum states_t
1087 {
1088 kStateDisconnected = FTM::kDisconnected,
1089 kStateConnected = FTM::kConnected,
1090 kStateIdle = FTM::kIdle,
1091 kStateTakingData = FTM::kTakingData,
1092
1093 kCmdTest
1094 };
1095
1096 bool CheckEventSize(size_t has, const char *name, size_t size)
1097 {
1098 if (has==size)
1099 return true;
1100
1101 ostringstream msg;
1102 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
1103 T::Fatal(msg);
1104 return false;
1105 }
1106
1107 int SetRegister(const EventImp &evt)
1108 {
1109 if (!CheckEventSize(evt.GetSize(), "SetRegister", 8))
1110 return T::kSM_FatalError;
1111
1112 const uint32_t *dat = evt.Ptr<uint32_t>();
1113
1114 if (dat[1]>uint16_t(-1))
1115 {
1116 ostringstream msg;
1117 msg << hex << "Value " << dat[1] << " out of range.";
1118 T::Error(msg);
1119 return T::GetCurrentState();
1120 }
1121
1122
1123 if (dat[0]>uint16_t(-1) || !fFTM.CmdSetRegister(dat[0], dat[1]))
1124 {
1125 ostringstream msg;
1126 msg << hex << "Address " << dat[0] << " out of range.";
1127 T::Error(msg);
1128 }
1129
1130 return T::GetCurrentState();
1131 }
1132
1133 int GetRegister(const EventImp &evt)
1134 {
1135 if (!CheckEventSize(evt.GetSize(), "GetRegister", 4))
1136 return T::kSM_FatalError;
1137
1138 const unsigned int addr = evt.GetInt();
1139 if (addr>uint16_t(-1) || !fFTM.CmdGetRegister(addr))
1140 {
1141 ostringstream msg;
1142 msg << hex << "Address " << addr << " out of range.";
1143 T::Error(msg);
1144 }
1145
1146 return T::GetCurrentState();
1147 }
1148
1149 int TakeNevents(const EventImp &evt)
1150 {
1151 if (!CheckEventSize(evt.GetSize(), "TakeNevents", 4))
1152 return T::kSM_FatalError;
1153
1154 const unsigned int dat = evt.GetUInt();
1155
1156 /*
1157 if (dat[1]>uint32_t(-1))
1158 {
1159 ostringstream msg;
1160 msg << hex << "Value " << dat[1] << " out of range.";
1161 T::Error(msg);
1162 return T::GetCurrentState();
1163 }*/
1164
1165 fFTM.CmdTakeNevents(dat);
1166
1167 return T::GetCurrentState();
1168 }
1169
1170 int DisableReports(const EventImp &evt)
1171 {
1172 if (!CheckEventSize(evt.GetSize(), "DisableReports", 1))
1173 return T::kSM_FatalError;
1174
1175 fFTM.CmdDisableReports(evt.GetBool());
1176
1177 return T::GetCurrentState();
1178 }
1179
1180 int SetVerbosity(const EventImp &evt)
1181 {
1182 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
1183 return T::kSM_FatalError;
1184
1185 fFTM.SetVerbose(evt.GetBool());
1186
1187 return T::GetCurrentState();
1188 }
1189
1190 int SetHexOutput(const EventImp &evt)
1191 {
1192 if (!CheckEventSize(evt.GetSize(), "SetHexOutput", 1))
1193 return T::kSM_FatalError;
1194
1195 fFTM.SetHexOutput(evt.GetBool());
1196
1197 return T::GetCurrentState();
1198 }
1199
1200 int SetDynamicOut(const EventImp &evt)
1201 {
1202 if (!CheckEventSize(evt.GetSize(), "SetDynamicOut", 1))
1203 return T::kSM_FatalError;
1204
1205 fFTM.SetDynamicOut(evt.GetBool());
1206
1207 return T::GetCurrentState();
1208 }
1209
1210 int LoadStaticData(const EventImp &evt)
1211 {
1212 if (fFTM.LoadStaticData(evt.GetString()))
1213 return T::GetCurrentState();
1214
1215 ostringstream msg;
1216 msg << "Loading static data from file '" << evt.GetString() << "' failed ";
1217
1218 if (errno)
1219 msg << "(" << strerror(errno) << ")";
1220 else
1221 msg << "(wrong size, expected " << sizeof(FTM::StaticData) << " bytes)";
1222
1223 T::Warn(msg);
1224
1225 return T::GetCurrentState();
1226 }
1227
1228 int SaveStaticData(const EventImp &evt)
1229 {
1230 if (fFTM.SaveStaticData(evt.GetString()))
1231 return T::GetCurrentState();
1232
1233 ostringstream msg;
1234 msg << "Writing static data to file '" << evt.GetString() << "' failed ";
1235 msg << "(" << strerror(errno) << ")";
1236
1237 T::Warn(msg);
1238
1239 return T::GetCurrentState();
1240 }
1241
1242 int SetThreshold(const EventImp &evt)
1243 {
1244 if (!CheckEventSize(evt.GetSize(), "SetThreshold", 8))
1245 return T::kSM_FatalError;
1246
1247 const int32_t *data = evt.Ptr<int32_t>();
1248
1249 if (!fFTM.SetThreshold(data[0], data[1]))
1250 T::Warn("SetThreshold - Maximum allowed patch number 159, valid value range 0-0xffff");
1251
1252 return T::GetCurrentState();
1253 }
1254
1255 int EnableFTU(const EventImp &evt)
1256 {
1257 if (!CheckEventSize(evt.GetSize(), "EnableFTU", 5))
1258 return T::kSM_FatalError;
1259
1260 const int32_t &board = evt.Get<int32_t>();
1261 const int8_t &enable = evt.Get<int8_t>(4);
1262
1263 if (!fFTM.EnableFTU(board, enable))
1264 T::Warn("EnableFTU - Board number must be <40.");
1265
1266 return T::GetCurrentState();
1267 }
1268
1269 int ToggleFTU(const EventImp &evt)
1270 {
1271 if (!CheckEventSize(evt.GetSize(), "ToggleFTU", 4))
1272 return T::kSM_FatalError;
1273
1274 if (!fFTM.ToggleFTU(evt.GetInt()))
1275 T::Warn("ToggleFTU - Allowed range of boards 0-39.");
1276
1277 return T::GetCurrentState();
1278 }
1279
1280 int SetTriggerInterval(const EventImp &evt)
1281 {
1282 if (!CheckEventSize(evt.GetSize(), "SetTriggerInterval", 4))
1283 return T::kSM_FatalError;
1284
1285 if (!fFTM.SetTriggerInterval(evt.GetInt()))
1286 T::Warn("SetTriggerInterval - Value out of range.");
1287
1288 return T::GetCurrentState();
1289 }
1290
1291 int SetTriggerDelay(const EventImp &evt)
1292 {
1293 if (!CheckEventSize(evt.GetSize(), "SetTriggerDelay", 4))
1294 return T::kSM_FatalError;
1295
1296 if (!fFTM.SetTriggerDelay(evt.GetInt()))
1297 T::Warn("SetTriggerDealy - Value out of range.");
1298
1299 return T::GetCurrentState();
1300 }
1301
1302 int SetTimeMarkerDelay(const EventImp &evt)
1303 {
1304 if (!CheckEventSize(evt.GetSize(), "SetTimeMarkerDelay", 4))
1305 return T::kSM_FatalError;
1306
1307 if (!fFTM.SetTimeMarkerDelay(evt.GetInt()))
1308 T::Warn("SetTimeMarkerDelay - Value out of range.");
1309
1310 return T::GetCurrentState();
1311 }
1312
1313 int SetPrescaling(const EventImp &evt)
1314 {
1315 if (!CheckEventSize(evt.GetSize(), "SetPrescaling", 4))
1316 return T::kSM_FatalError;
1317
1318 if (!fFTM.SetPrescaling(evt.GetInt()-1))
1319 T::Warn("SetPrescaling - Value out of range.");
1320
1321 return T::GetCurrentState();
1322 }
1323
1324 int SetTriggerSeq(const EventImp &evt)
1325 {
1326 if (!CheckEventSize(evt.GetSize(), "SetTriggerSeq", 6))
1327 return T::kSM_FatalError;
1328
1329 const uint16_t *data = evt.Ptr<uint16_t>();
1330
1331 if (!fFTM.SetTriggerSeq(data))
1332 T::Warn("SetTriggerSeq - Value out of range.");
1333
1334 return T::GetCurrentState();
1335 }
1336
1337 int SetDeadTime(const EventImp &evt)
1338 {
1339 if (!CheckEventSize(evt.GetSize(), "SetDeadTime", 4))
1340 return T::kSM_FatalError;
1341
1342 if (!fFTM.SetDeadTime(evt.GetInt()))
1343 T::Warn("SetDeadTime - Value out of range.");
1344
1345 return T::GetCurrentState();
1346 }
1347
1348 int SetTriggerMultiplicity(const EventImp &evt)
1349 {
1350 if (!CheckEventSize(evt.GetSize(), "SetTriggerMultiplicity", 2))
1351 return T::kSM_FatalError;
1352
1353 if (!fFTM.SetTriggerMultiplicity(evt.GetUShort()))
1354 T::Warn("SetTriggerMultiplicity - Value out of range.");
1355
1356 return T::GetCurrentState();
1357 }
1358
1359 int SetCalibMultiplicity(const EventImp &evt)
1360 {
1361 if (!CheckEventSize(evt.GetSize(), "SetCalibMultiplicity", 2))
1362 return T::kSM_FatalError;
1363
1364 if (!fFTM.SetCalibMultiplicity(evt.GetUShort()))
1365 T::Warn("SetCalibMultiplicity - Value out of range.");
1366
1367 return T::GetCurrentState();
1368 }
1369
1370 int SetTriggerWindow(const EventImp &evt)
1371 {
1372 if (!CheckEventSize(evt.GetSize(), "SetTriggerWindow", 2))
1373 return T::kSM_FatalError;
1374
1375 if (!fFTM.SetTriggerWindow(evt.GetUShort()))
1376 T::Warn("SetTriggerWindow - Value out of range.");
1377
1378 return T::GetCurrentState();
1379 }
1380
1381 int SetCalibWindow(const EventImp &evt)
1382 {
1383 if (!CheckEventSize(evt.GetSize(), "SetCalibWindow", 2))
1384 return T::kSM_FatalError;
1385
1386 if (!fFTM.SetCalibWindow(evt.GetUShort()))
1387 T::Warn("SetCalibWindow - Value out of range.");
1388
1389 return T::GetCurrentState();
1390 }
1391
1392 int SetClockRegister(const EventImp &evt)
1393 {
1394 if (!CheckEventSize(evt.GetSize(), "SetClockRegister", 8*8))
1395 return T::kSM_FatalError;
1396
1397 const uint64_t *reg = evt.Ptr<uint64_t>();
1398
1399 if (!fFTM.SetClockRegister(reg))
1400 T::Warn("SetClockRegister - Value out of range.");
1401
1402 return T::GetCurrentState();
1403 }
1404
1405 //map<uint32_t, uint32_t> fClockConditionerMap;
1406
1407 int SetClockFrequency(const EventImp &evt)
1408 {
1409 if (!CheckEventSize(evt.GetSize(), "SetClockFrequency", 4))
1410 return T::kSM_FatalError;
1411
1412 const uint32_t freq = evt.GetUInt();
1413
1414 //map<uint32_t,uint32_t>::const_iterator = fClockConditionerMap.find(freq);
1415
1416 static const uint64_t R0hi = 0x00030000;
1417 static const uint64_t R8 = 0x10000908;
1418 static const uint64_t R9 = 0xa0032a09;
1419 static const uint64_t R11 = 0x0082000b;
1420 static const uint64_t R13 = 0x020a000d;
1421 static const uint64_t R14hi = 0x08300000;
1422
1423 static const uint64_t freq0800[8] = { R0hi|0xfe00, 0x00010101, R8, R9, R11, R13, R14hi|0x800e, 0x18017b0f };
1424 static const uint64_t freq1000[8] = { R0hi|0xd000, 0x00010101, R8, R9, R11, R13, R14hi|0x400e, 0x1801450f };
1425 static const uint64_t freq2000[8] = { R0hi|0x8000, 0x00010101, R8, R9, R11, R13, R14hi|0x280e, 0x1400fa0f };
1426 static const uint64_t freq3000[8] = { R0hi|0x9000, 0x00030100, R8, R9, R11, R13, R14hi|0x400e, 0x0602a30f };
1427 static const uint64_t freq4000[8] = { R0hi|0x4000, 0x00010101, R8, R9, R11, R13, R14hi|0x280e, 0x1400fa0f };
1428 static const uint64_t freq5000[8] = { R0hi|0x8000, 0x00030200, R8, R9, R11, R13, R14hi|0x280e, 0x0802710f };
1429
1430 const uint64_t *reg = 0;
1431
1432 switch (freq)
1433 {
1434 case 800: reg = freq0800; break;
1435 case 1000: reg = freq1000; break;
1436 case 2000: reg = freq2000; break;
1437 case 3000: reg = freq3000; break;
1438 case 4000: reg = freq4000; break;
1439 case 5000: reg = freq5000; break;
1440 default:
1441 T::Warn("SetClockFrequency - Frequency not supported.");
1442 return T::GetCurrentState();
1443 }
1444
1445 if (!fFTM.SetClockRegister(reg))
1446 T::Warn("SetClockFrequency - Register values out of range.");
1447
1448 return T::GetCurrentState();
1449 }
1450
1451 int Enable(const EventImp &evt, FTM::StaticData::GeneralSettings type)
1452 {
1453 if (!CheckEventSize(evt.GetSize(), "Enable", 1))
1454 return T::kSM_FatalError;
1455
1456 fFTM.Enable(type, evt.GetBool());
1457
1458 return T::GetCurrentState();
1459 }
1460
1461 int EnablePixel(const EventImp &evt, bool b)
1462 {
1463 if (!CheckEventSize(evt.GetSize(), "EnablePixel", 2))
1464 return T::kSM_FatalError;
1465
1466 if (!fFTM.EnablePixel(evt.GetUShort(), b))
1467 T::Warn("EnablePixel - Value out of range.");
1468
1469 return T::GetCurrentState();
1470 }
1471
1472 int DisableAllPixelsExcept(const EventImp &evt)
1473 {
1474 if (!CheckEventSize(evt.GetSize(), "DisableAllPixelsExcept", 2))
1475 return T::kSM_FatalError;
1476
1477 if (!fFTM.DisableAllPixelsExcept(evt.GetUShort()))
1478 T::Warn("DisableAllPixelsExcept - Value out of range.");
1479
1480 return T::GetCurrentState();
1481 }
1482
1483 int DisableAllPatchesExcept(const EventImp &evt)
1484 {
1485 if (!CheckEventSize(evt.GetSize(), "DisableAllPatchesExcept", 2))
1486 return T::kSM_FatalError;
1487
1488 if (!fFTM.DisableAllPatchesExcept(evt.GetUShort()))
1489 T::Warn("DisableAllPatchesExcept - Value out of range.");
1490
1491 return T::GetCurrentState();
1492 }
1493
1494 int TogglePixel(const EventImp &evt)
1495 {
1496 if (!CheckEventSize(evt.GetSize(), "TogglePixel", 2))
1497 return T::kSM_FatalError;
1498
1499 if (!fFTM.TogglePixel(evt.GetUShort()))
1500 T::Warn("TogglePixel - Value out of range.");
1501
1502 return T::GetCurrentState();
1503 }
1504
1505 int ResetCrate(const EventImp &evt)
1506 {
1507 if (!CheckEventSize(evt.GetSize(), "ResetCrate", 2))
1508 return T::kSM_FatalError;
1509
1510 fFTM.CmdResetCrate(evt.GetUShort());
1511
1512 return T::GetCurrentState();
1513 }
1514
1515 int Disconnect()
1516 {
1517 // Close all connections
1518 fFTM.PostClose(false);
1519
1520 /*
1521 // Now wait until all connection have been closed and
1522 // all pending handlers have been processed
1523 poll();
1524 */
1525
1526 return T::GetCurrentState();
1527 }
1528
1529 int Reconnect(const EventImp &evt)
1530 {
1531 // Close all connections to supress the warning in SetEndpoint
1532 fFTM.PostClose(false);
1533
1534 // Now wait until all connection have been closed and
1535 // all pending handlers have been processed
1536 poll();
1537
1538 if (evt.GetBool())
1539 fFTM.SetEndpoint(evt.GetString());
1540
1541 // Now we can reopen the connection
1542 fFTM.PostClose(true);
1543
1544 return T::GetCurrentState();
1545 }
1546
1547 /*
1548 int Transition(const Event &evt)
1549 {
1550 switch (evt.GetTargetState())
1551 {
1552 case kStateDisconnected:
1553 case kStateConnected:
1554 }
1555
1556 return T::kSM_FatalError;
1557 }*/
1558
1559 int Execute()
1560 {
1561 // Dispatch (execute) at most one handler from the queue. In contrary
1562 // to run_one(), it doesn't wait until a handler is available
1563 // which can be dispatched, so poll_one() might return with 0
1564 // handlers dispatched. The handlers are always dispatched/executed
1565 // synchronously, i.e. within the call to poll_one()
1566 poll_one();
1567
1568 return fFTM.GetState();
1569 }
1570
1571public:
1572 StateMachineFTM(ostream &out=cout) :
1573 T(out, "FTM_CONTROL"), ba::io_service::work(static_cast<ba::io_service&>(*this)),
1574 fFTM(*this, *this)
1575 {
1576 // ba::io_service::work is a kind of keep_alive for the loop.
1577 // It prevents the io_service to go to stopped state, which
1578 // would prevent any consecutive calls to run()
1579 // or poll() to do nothing. reset() could also revoke to the
1580 // previous state but this might introduce some overhead of
1581 // deletion and creation of threads and more.
1582
1583 // State names
1584 AddStateName(kStateDisconnected, "Disconnected",
1585 "FTM board not connected via ethernet.");
1586
1587 AddStateName(kStateConnected, "Connected",
1588 "Ethernet connection to FTM established (no state received yet).");
1589
1590 AddStateName(kStateIdle, "Idle",
1591 "Ethernet connection to FTM established, FTM in idle state.");
1592
1593 AddStateName(kStateTakingData, "TakingData",
1594 "Ethernet connection to FTM established, FTM is in taking data state.");
1595
1596 // FTM Commands
1597 AddEvent("TOGGLE_LED", kStateIdle)
1598 (Wrapper(boost::bind(&ConnectionFTM::CmdToggleLed, &fFTM)))
1599 ("toggle led");
1600
1601 AddEvent("PING", kStateIdle)
1602 (Wrapper(boost::bind(&ConnectionFTM::CmdPing, &fFTM)))
1603 ("send ping");
1604
1605 AddEvent("REQUEST_DYNAMIC_DATA", kStateIdle)
1606 (Wrapper(boost::bind(&ConnectionFTM::CmdReqDynDat, &fFTM)))
1607 ("request transmission of dynamic data block");
1608
1609 AddEvent("REQUEST_STATIC_DATA", kStateIdle)
1610 (Wrapper(boost::bind(&ConnectionFTM::CmdReqStatDat, &fFTM)))
1611 ("request transmission of static data from FTM to memory");
1612
1613 AddEvent("GET_REGISTER", "I", kStateIdle)
1614 (boost::bind(&StateMachineFTM::GetRegister, this, _1))
1615 ("read register from address addr"
1616 "|addr[short]:Address of register");
1617
1618 AddEvent("SET_REGISTER", "I:2", kStateIdle)
1619 (boost::bind(&StateMachineFTM::SetRegister, this, _1))
1620 ("set register to value"
1621 "|addr[short]:Address of register"
1622 "|val[short]:Value to be set");
1623
1624 AddEvent("START_RUN", kStateIdle)
1625 (Wrapper(boost::bind(&ConnectionFTM::CmdStartRun, &fFTM)))
1626 ("start a run (start distributing triggers)");
1627
1628 AddEvent("STOP_RUN", kStateTakingData)
1629 (Wrapper(boost::bind(&ConnectionFTM::CmdStopRun, &fFTM)))
1630 ("stop a run (stop distributing triggers)");
1631
1632 AddEvent("TAKE_N_EVENTS", "I", kStateIdle)
1633 (boost::bind(&StateMachineFTM::TakeNevents, this, _1))
1634 ("take n events (distribute n triggers)|number[int]:Number of events to be taken");
1635
1636 AddEvent("DISABLE_REPORTS", "B", kStateIdle)
1637 (boost::bind(&StateMachineFTM::DisableReports, this, _1))
1638 ("disable sending rate reports"
1639 "|status[bool]:disable or enable that the FTM sends rate reports (yes/no)");
1640
1641 AddEvent("SET_THRESHOLD", "I:2", kStateIdle)
1642 (boost::bind(&StateMachineFTM::SetThreshold, this, _1))
1643 ("Set the comparator threshold"
1644 "|Patch[idx]:Index of the patch (0-159), -1 for all"
1645 "|Threshold[counts]:Threshold to be set in binary counts");
1646
1647 AddEvent("SET_PRESCALING", "I:1", kStateIdle)
1648 (boost::bind(&StateMachineFTM::SetPrescaling, this, _1))
1649 (""
1650 "|[]:");
1651
1652 AddEvent("ENABLE_FTU", "I:1;B:1", kStateIdle)
1653 (boost::bind(&StateMachineFTM::EnableFTU, this, _1))
1654 ("Enable or disable FTU"
1655 "|Board[idx]:Index of the board (0-39), -1 for all"
1656 "|Enable[bool]:Whether FTU should be enabled or disabled (yes/no)");
1657
1658 AddEvent("DISABLE_PIXEL", "S:1", kStateIdle)
1659 (boost::bind(&StateMachineFTM::EnablePixel, this, _1, false))
1660 ("(-1 or all)");
1661
1662 AddEvent("ENABLE_PIXEL", "S:1", kStateIdle)
1663 (boost::bind(&StateMachineFTM::EnablePixel, this, _1, true))
1664 ("(-1 or all)");
1665
1666 AddEvent("DISABLE_ALL_PIXELS_EXCEPT", "S:1", kStateIdle)
1667 (boost::bind(&StateMachineFTM::DisableAllPixelsExcept, this, _1))
1668 ("");
1669
1670 AddEvent("DISABLE_ALL_PATCHES_EXCEPT", "S:1", kStateIdle)
1671 (boost::bind(&StateMachineFTM::DisableAllPatchesExcept, this, _1))
1672 ("");
1673
1674 AddEvent("TOGGLE_PIXEL", "S:1", kStateIdle)
1675 (boost::bind(&StateMachineFTM::TogglePixel, this, _1))
1676 ("");
1677
1678 AddEvent("TOGGLE_FTU", "I:1", kStateIdle)
1679 (boost::bind(&StateMachineFTM::ToggleFTU, this, _1))
1680 ("Toggle status of FTU (this is mainly meant to be used in the GUI)"
1681 "|Board[idx]:Index of the board (0-39)");
1682
1683 AddEvent("SET_TRIGGER_INTERVAL", "I:1", kStateIdle)
1684 (boost::bind(&StateMachineFTM::SetTriggerInterval, this, _1))
1685 ("Sets the trigger interval which is the distance between two consecutive artificial triggers."
1686 "|interval[int]:The applied trigger interval is: interval*4ns+8ns");
1687
1688 AddEvent("SET_TRIGGER_DELAY", "I:1", kStateIdle)
1689 (boost::bind(&StateMachineFTM::SetTriggerDelay, this, _1))
1690 (""
1691 "|delay[int]:The applied trigger delay is: delay*4ns+8ns");
1692
1693 AddEvent("SET_TIME_MARKER_DELAY", "I:1", kStateIdle)
1694 (boost::bind(&StateMachineFTM::SetTimeMarkerDelay, this, _1))
1695 (""
1696 "|delay[int]:The applied time marker delay is: delay*4ns+8ns");
1697
1698 AddEvent("SET_DEAD_TIME", "I:1", kStateIdle)
1699 (boost::bind(&StateMachineFTM::SetDeadTime, this, _1))
1700 (""
1701 "|dead_time[int]:The applied dead time is: dead_time*4ns+8ns");
1702
1703 AddEvent("ENABLE_TRIGGER", "B:1", kStateIdle)
1704 (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kTrigger))
1705 ("Switch on the physics trigger"
1706 "|Enable[bool]:Enable physics trigger (yes/no)");
1707
1708 // FIXME: Switch on/off depending on sequence
1709 AddEvent("ENABLE_EXT1", "B:1", kStateIdle)
1710 (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kExt1))
1711 ("Switch on the triggers through the first external line"
1712 "|Enable[bool]:Enable ext1 trigger (yes/no)");
1713
1714 // FIXME: Switch on/off depending on sequence
1715 AddEvent("ENABLE_EXT2", "B:1", kStateIdle)
1716 (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kExt2))
1717 ("Switch on the triggers through the second external line"
1718 "|Enable[bool]:Enable ext2 trigger (yes/no)");
1719
1720 AddEvent("ENABLE_VETO", "B:1", kStateIdle)
1721 (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kVeto))
1722 ("Enable veto line"
1723 "|Enable[bool]:Enable veto (yes/no)");
1724
1725 AddEvent("ENABLE_CLOCK_CONDITIONER", "B:1", kStateIdle)
1726 (boost::bind(&StateMachineFTM::Enable, this, _1, FTM::StaticData::kClockConditioner))
1727 ("Enable clock conidtioner output in favor of time marker output"
1728 "|Enable[bool]:Enable clock conditioner (yes/no)");
1729
1730 AddEvent("SET_TRIGGER_SEQUENCE", "S:3", kStateIdle)
1731 (boost::bind(&StateMachineFTM::SetTriggerSeq, this, _1))
1732 ("Setup the sequence of artificial triggers produced by the FTM"
1733 "|Ped[short]:number of pedestal triggers in a row"
1734 "|LPext[short]:number of triggers of the external light pulser"
1735 "|LPint[short]:number of triggers of the internal light pulser");
1736
1737 AddEvent("SET_TRIGGER_MULTIPLICITY", "S:1", kStateIdle)
1738 (boost::bind(&StateMachineFTM::SetTriggerMultiplicity, this, _1))
1739 ("Setup the Multiplicity condition for physcis triggers"
1740 "|N[int]:Number of requirered coincident triggers from sum-patches (1-40)");
1741
1742 AddEvent("SET_TRIGGER_WINDOW", "S:1", kStateIdle)
1743 (boost::bind(&StateMachineFTM::SetTriggerWindow, this, _1))
1744 ("");
1745
1746 AddEvent("SET_CALIBRATION_MULTIPLICITY", "S:1", kStateIdle)
1747 (boost::bind(&StateMachineFTM::SetCalibMultiplicity, this, _1))
1748 ("Setup the Multiplicity condition for artificial (calibration) triggers"
1749 "|N[int]:Number of requirered coincident triggers from sum-patches (1-40)");
1750
1751 AddEvent("SET_CALIBRATION_WINDOW", "S:1", kStateIdle)
1752 (boost::bind(&StateMachineFTM::SetCalibWindow, this, _1))
1753 ("");
1754
1755 AddEvent("SET_CLOCK_FREQUENCY", "I:1", kStateIdle)
1756 (boost::bind(&StateMachineFTM::SetClockFrequency, this, _1))
1757 ("");
1758
1759 AddEvent("SET_CLOCK_REGISTER", "X:8", kStateIdle)
1760 (boost::bind(&StateMachineFTM::SetClockRegister, this, _1))
1761 ("");
1762
1763
1764
1765 AddEvent("RESET_CRATE", "S:1", kStateIdle)
1766 (boost::bind(&StateMachineFTM::ResetCrate, this, _1))
1767 ("Reset one of the crates 0-3"
1768 "|crate[short]:Crate number to be reseted (0-3)");
1769
1770 AddEvent("RESET_CAMERA", kStateIdle)
1771 (Wrapper(boost::bind(&ConnectionFTM::CmdResetCamera, &fFTM)))
1772 ("Reset all crates. The commands are sent in the order 0,1,2,3");
1773
1774
1775 // Load/save static data block
1776 T::AddEvent("SAVE", "C", kStateIdle)
1777 (boost::bind(&StateMachineFTM::SaveStaticData, this, _1))
1778 ("Saves the static data (FTM configuration) from memory to a file"
1779 "|filename[string]:Filename (can include a path), .bin is automatically added");
1780
1781 T::AddEvent("LOAD", "C", kStateIdle)
1782 (boost::bind(&StateMachineFTM::LoadStaticData, this, _1))
1783 ("Loads the static data (FTM configuration) from a file into memory and sends it to the FTM"
1784 "|filename[string]:Filename (can include a path), .bin is automatically added");
1785
1786
1787
1788 // Verbosity commands
1789 T::AddEvent("SET_VERBOSE", "B")
1790 (boost::bind(&StateMachineFTM::SetVerbosity, this, _1))
1791 ("set verbosity state"
1792 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
1793
1794 T::AddEvent("SET_HEX_OUTPUT", "B")
1795 (boost::bind(&StateMachineFTM::SetHexOutput, this, _1))
1796 ("enable or disable hex output for received data"
1797 "|hexout[bool]:disable or enable hex output for received data (yes/no)");
1798
1799 T::AddEvent("SET_DYNAMIC_OUTPUT", "B")
1800 (boost::bind(&StateMachineFTM::SetDynamicOut, this, _1))
1801 ("enable or disable output for received dynamic data (data is still broadcasted via Dim)"
1802 "|dynout[bool]:disable or enable output for dynamic data (yes/no)");
1803
1804
1805 // Conenction commands
1806 AddEvent("DISCONNECT", kStateConnected, kStateIdle)
1807 (boost::bind(&StateMachineFTM::Disconnect, this))
1808 ("disconnect from ethernet");
1809
1810 AddEvent("RECONNECT", "O", kStateDisconnected, kStateConnected, kStateIdle)
1811 (boost::bind(&StateMachineFTM::Reconnect, this, _1))
1812 ("(Re)connect ethernet connection to FTM, a new address can be given"
1813 "|[host][string]:new ethernet address in the form <host:port>");
1814
1815 fFTM.StartConnect();
1816 }
1817
1818 void SetEndpoint(const string &url)
1819 {
1820 fFTM.SetEndpoint(url);
1821 }
1822
1823 int EvalConfiguration(const Configuration &conf)
1824 {
1825 SetEndpoint(conf.Get<string>("addr"));
1826
1827 fFTM.SetVerbose(!conf.Get<bool>("quiet"));
1828 fFTM.SetHexOutput(conf.Get<bool>("hex-out"));
1829 fFTM.SetDynamicOut(conf.Get<bool>("dynamic-out"));
1830
1831// fFTM.SetDefaultSetup(conf.Get<string>("default-setup"));
1832
1833 return -1;
1834 }
1835};
1836
1837// ------------------------------------------------------------------------
1838
1839#include "Main.h"
1840
1841/*
1842void RunThread(StateMachineImp *io_service)
1843{
1844 // This is necessary so that the StateMachien Thread can signal the
1845 // Readline to exit
1846 io_service->Run();
1847 Readline::Stop();
1848}
1849*/
1850/*
1851template<class S, class T>
1852int RunDim(Configuration &conf)
1853{
1854 WindowLog wout;
1855
1856 ReadlineColor::PrintBootMsg(wout, conf.GetName(), false);
1857
1858 if (conf.Has("log"))
1859 if (!wout.OpenLogFile(conf.Get<string>("log")))
1860 wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
1861
1862 // Start io_service.Run to use the StateMachineImp::Run() loop
1863 // Start io_service.run to only use the commandHandler command detaching
1864 StateMachineFTM<S, T> io_service(wout);
1865 if (!io_service.EvalConfiguration(conf))
1866 return -1;
1867
1868 io_service.Run();
1869
1870 return 0;
1871}
1872*/
1873
1874template<class T, class S, class R>
1875int RunShell(Configuration &conf)
1876{
1877 return Main<T, StateMachineFTM<S, R>>(conf);
1878/*
1879 static T shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
1880
1881 WindowLog &win = shell.GetStreamIn();
1882 WindowLog &wout = shell.GetStreamOut();
1883
1884 if (conf.Has("log"))
1885 if (!wout.OpenLogFile(conf.Get<string>("log")))
1886 win << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
1887
1888 StateMachineFTM<S, R> io_service(wout);
1889 if (!io_service.EvalConfiguration(conf))
1890 return -1;
1891
1892 shell.SetReceiver(io_service);
1893
1894 boost::thread t(boost::bind(RunThread, &io_service));
1895 // boost::thread t(boost::bind(&StateMachineFTM<S>::Run, &io_service));
1896
1897 if (conf.Has("cmd"))
1898 {
1899 const vector<string> v = conf.Get<vector<string>>("cmd");
1900 for (vector<string>::const_iterator it=v.begin(); it!=v.end(); it++)
1901 shell.ProcessLine(*it);
1902 }
1903
1904 if (conf.Has("exec"))
1905 {
1906 const vector<string> v = conf.Get<vector<string>>("exec");
1907 for (vector<string>::const_iterator it=v.begin(); it!=v.end(); it++)
1908 shell.Execute(*it);
1909 }
1910
1911 if (conf.Get<bool>("quit"))
1912 shell.Stop();
1913
1914 shell.Run(); // Run the shell
1915 io_service.Stop(); // Signal Loop-thread to stop
1916 // io_service.Close(); // Obsolete, done by the destructor
1917
1918 // Wait until the StateMachine has finished its thread
1919 // before returning and destroying the dim objects which might
1920 // still be in use.
1921 t.join();
1922
1923 return 0;
1924 */
1925}
1926
1927void SetupConfiguration(Configuration &conf)
1928{
1929 const string n = conf.GetName()+".log";
1930
1931 po::options_description config("Program options");
1932 config.add_options()
1933 ("dns", var<string>("localhost"), "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
1934 ("log,l", var<string>(n), "Write log-file")
1935 ("no-dim,d", po_bool(), "Disable dim services")
1936 ("console,c", var<int>(), "Use console (0=shell, 1=simple buffered, X=simple unbuffered)")
1937 ("cmd", vars<string>(), "Execute one or more commands at startup")
1938 ("exec,e", vars<string>(), "Execute one or more scrips at startup")
1939 ("quit", po_switch(), "Quit after startup");
1940 ;
1941
1942 po::options_description control("FTM control options");
1943 control.add_options()
1944 ("addr,a", var<string>("localhost:5000"), "Network address of FTM")
1945 ("quiet,q", po_bool(), "Disable printing contents of all received messages (except dynamic data) in clear text.")
1946 ("hex-out", po_bool(), "Enable printing contents of all printed messages also as hex data.")
1947 ("dynamic-out", po_bool(), "Enable printing received dynamic data.")
1948// ("default-setup", var<string>(), "Binary file with static data loaded whenever a connection to the FTM was established.")
1949 ;
1950
1951 conf.AddEnv("dns", "DIM_DNS_NODE");
1952
1953 conf.AddOptions(config);
1954 conf.AddOptions(control);
1955}
1956
1957/*
1958 Extract usage clause(s) [if any] for SYNOPSIS.
1959 Translators: "Usage" and "or" here are patterns (regular expressions) which
1960 are used to match the usage synopsis in program output. An example from cp
1961 (GNU coreutils) which contains both strings:
1962 Usage: cp [OPTION]... [-T] SOURCE DEST
1963 or: cp [OPTION]... SOURCE... DIRECTORY
1964 or: cp [OPTION]... -t DIRECTORY SOURCE...
1965 */
1966void PrintUsage()
1967{
1968 cout <<
1969 "The ftmctrl controls the FTM (FACT Trigger Master) board.\n"
1970 "\n"
1971 "The default is that the program is started without user intercation. "
1972 "All actions are supposed to arrive as DimCommands. Using the -c "
1973 "option, a local shell can be initialized. With h or help a short "
1974 "help message about the usuage can be brought to the screen.\n"
1975 "\n"
1976 "Usage: ftmctrl [-c type] [OPTIONS]\n"
1977 " or: ftmctrl [OPTIONS]\n";
1978 cout << endl;
1979}
1980
1981void PrintHelp()
1982{
1983 /* Additional help text which is printed after the configuration
1984 options goes here */
1985
1986 /*
1987 cout << "bla bla bla" << endl << endl;
1988 cout << endl;
1989 cout << "Environment:" << endl;
1990 cout << "environment" << endl;
1991 cout << endl;
1992 cout << "Examples:" << endl;
1993 cout << "test exam" << endl;
1994 cout << endl;
1995 cout << "Files:" << endl;
1996 cout << "files" << endl;
1997 cout << endl;
1998 */
1999}
2000
2001int main(int argc, const char* argv[])
2002{
2003 Configuration conf(argv[0]);
2004 conf.SetPrintUsage(PrintUsage);
2005 SetupConfiguration(conf);
2006
2007 po::variables_map vm;
2008 try
2009 {
2010 vm = conf.Parse(argc, argv);
2011 }
2012#if BOOST_VERSION > 104000
2013 catch (po::multiple_occurrences &e)
2014 {
2015 cerr << "Program options invalid due to: " << e.what() << " of '" << e.get_option_name() << "'." << endl;
2016 return -1;
2017 }
2018#endif
2019 catch (exception& e)
2020 {
2021 cerr << "Program options invalid due to: " << e.what() << endl;
2022 return -1;
2023 }
2024
2025 if (conf.HasVersion() || conf.HasPrint())
2026 return -1;
2027
2028 if (conf.HasHelp())
2029 {
2030 PrintHelp();
2031 return -1;
2032 }
2033
2034 Dim::Setup(conf.Get<string>("dns"));
2035
2036 //try
2037 {
2038 // No console access at all
2039 if (!conf.Has("console"))
2040 {
2041 if (conf.Get<bool>("no-dim"))
2042 return RunShell<LocalStream, StateMachine, ConnectionFTM>(conf);
2043 else
2044 return RunShell<LocalStream, StateMachineDim, ConnectionDimFTM>(conf);
2045 }
2046 // Cosole access w/ and w/o Dim
2047 if (conf.Get<bool>("no-dim"))
2048 {
2049 if (conf.Get<int>("console")==0)
2050 return RunShell<LocalShell, StateMachine, ConnectionFTM>(conf);
2051 else
2052 return RunShell<LocalConsole, StateMachine, ConnectionFTM>(conf);
2053 }
2054 else
2055 {
2056 if (conf.Get<int>("console")==0)
2057 return RunShell<LocalShell, StateMachineDim, ConnectionDimFTM>(conf);
2058 else
2059 return RunShell<LocalConsole, StateMachineDim, ConnectionDimFTM>(conf);
2060 }
2061 }
2062 /*catch (std::exception& e)
2063 {
2064 cerr << "Exception: " << e.what() << endl;
2065 return -1;
2066 }*/
2067
2068 return 0;
2069}
Note: See TracBrowser for help on using the repository browser.