source: trunk/FACT++/src/fadctrl.cc@ 11197

Last change on this file since 11197 was 11197, checked in by tbretz, 13 years ago
Changed the fStatus2 array to support also an 'all diconnected but switched on' state.
File size: 56.4 KB
Line 
1#include <boost/bind.hpp>
2#include <boost/array.hpp>
3#if BOOST_VERSION < 104400
4#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 4))
5#undef BOOST_HAS_RVALUE_REFS
6#endif
7#endif
8#include <boost/thread.hpp>
9//#include <boost/foreach.hpp>
10#include <boost/asio/error.hpp>
11#include <boost/asio/deadline_timer.hpp>
12#include <boost/date_time/posix_time/posix_time_types.hpp>
13
14#include "Dim.h"
15#include "Event.h"
16#include "Shell.h"
17#include "StateMachineDim.h"
18#include "Connection.h"
19#include "Configuration.h"
20#include "Console.h"
21#include "Converter.h"
22#include "LocalControl.h"
23#include "HeadersFAD.h"
24
25#include "tools.h"
26
27#include "DimDescriptionService.h"
28#include "EventBuilderWrapper.h"
29
30namespace ba = boost::asio;
31namespace bs = boost::system;
32
33using ba::ip::tcp;
34
35using namespace std;
36
37// ------------------------------------------------------------------------
38
39class ConnectionFAD : public Connection
40{
41 uint16_t fSlot;
42// tcp::endpoint fEndpoint;
43
44 vector<uint16_t> fBuffer;
45
46protected:
47 FAD::EventHeader fEventHeader;
48 FAD::ChannelHeader fChannelHeader[FAD::kNumChannels];
49
50private:
51 bool fIsVerbose;
52 bool fIsHexOutput;
53 bool fIsDataOutput;
54 bool fBlockTransmission;
55
56 uint64_t fCounter;
57
58protected:
59 void PrintEventHeader()
60 {
61 Out() << endl << kBold << "Header received (N=" << dec << fCounter << "):" << endl;
62 Out() << fEventHeader;
63 if (fIsHexOutput)
64 Out() << Converter::GetHex<uint16_t>(fEventHeader, 16) << endl;
65 }
66
67 void PrintChannelHeaders()
68 {
69 Out() << dec << endl;
70
71 for (unsigned int c=0; c<FAD::kNumChips; c++)
72 {
73 Out() << "ROI|" << fEventHeader.Crate() << ":" << fEventHeader.Board() << ":" << c << ":";
74 for (unsigned int ch=0; ch<FAD::kNumChannelsPerChip; ch++)
75 Out() << " " << setw(4) << fChannelHeader[c+ch*FAD::kNumChips].fRegionOfInterest;
76 Out() << endl;
77 }
78
79 Out() << "CEL|" << fEventHeader.Crate() << ":" <<fEventHeader.Board() << ": ";
80 for (unsigned int c=0; c<FAD::kNumChips; c++)
81 {
82 if (0)//fIsFullChannelHeader)
83 {
84 for (unsigned int ch=0; ch<FAD::kNumChannelsPerChip; ch++)
85 Out() << " " << setw(4) << fChannelHeader[c+ch*FAD::kNumChips].fStartCell;
86 Out() << endl;
87 }
88 else
89 {
90 Out() << " ";
91 const uint16_t cel = fChannelHeader[c*FAD::kNumChannelsPerChip].fStartCell;
92 for (unsigned int ch=1; ch<FAD::kNumChannelsPerChip; ch++)
93 if (cel!=fChannelHeader[c+ch*FAD::kNumChips].fStartCell)
94 {
95 Out() << "!";
96 break;
97 }
98 Out() << cel;
99 }
100 }
101 Out() << endl;
102
103 if (fIsHexOutput)
104 Out() << Converter::GetHex<uint16_t>(fChannelHeader, 16) << endl;
105
106 }
107
108 virtual void UpdateFirstHeader()
109 {
110 }
111
112 virtual void UpdateEventHeader()
113 {
114 // emit service with trigger counter from header
115 if (fIsVerbose)
116 PrintEventHeader();
117 }
118
119 virtual void UpdateChannelHeaders()
120 {
121 // emit service with trigger counter from header
122 if (fIsVerbose)
123 PrintChannelHeaders();
124
125 }
126
127 virtual void UpdateData(const uint16_t *data, size_t sz)
128 {
129 // emit service with trigger counter from header
130 if (fIsVerbose && fIsDataOutput)
131 Out() << Converter::GetHex<uint16_t>(data, sz, 16, true) << endl;
132 }
133
134private:
135 enum
136 {
137 kReadHeader = 1,
138 kReadData = 2,
139 };
140
141 void HandleReceivedData(const bs::error_code& err, size_t bytes_received, int type)
142 {
143 // Do not schedule a new read if the connection failed.
144 if (bytes_received==0 || err)
145 {
146 if (err==ba::error::eof)
147 Warn("Connection closed by remote host (FAD).");
148
149 // 107: Transport endpoint is not connected (bs::error_code(107, bs::system_category))
150 // 125: Operation canceled
151 if (err && err!=ba::error::eof && // Connection closed by remote host
152 err!=ba::error::basic_errors::not_connected && // Connection closed by remote host
153 err!=ba::error::basic_errors::operation_aborted) // Connection closed by us
154 {
155 ostringstream str;
156 str << "Reading from " << URL() << ": " << err.message() << " (" << err << ")";// << endl;
157 Error(str);
158 }
159 PostClose(err!=ba::error::basic_errors::operation_aborted);
160 return;
161 }
162
163 EventBuilderWrapper::This->debugStream(fSlot*7, fBuffer.data(), bytes_received);
164
165 if (type==kReadHeader)
166 {
167 if (bytes_received!=sizeof(FAD::EventHeader))
168 {
169 ostringstream str;
170 str << "Bytes received (" << bytes_received << " don't match header size " << sizeof(FAD::EventHeader);
171 Error(str);
172 PostClose(false);
173 return;
174 }
175
176 fEventHeader = fBuffer;
177
178 if (fEventHeader.fStartDelimiter!=FAD::kDelimiterStart)
179 {
180 ostringstream str;
181 str << "Invalid header received: start delimiter wrong, received ";
182 str << hex << fEventHeader.fStartDelimiter << ", expected " << FAD::kDelimiterStart << ".";
183 Error(str);
184 PostClose(false);
185 return;
186 }
187
188 if (fCounter==0)
189 UpdateFirstHeader();
190
191 UpdateEventHeader();
192
193 EventBuilderWrapper::This->debugHead(fSlot*7, fEventHeader);
194
195 fBuffer.resize(fEventHeader.fPackageLength-sizeof(FAD::EventHeader)/2);
196 AsyncRead(ba::buffer(fBuffer), kReadData);
197 AsyncWait(fInTimeout, 2000, &Connection::HandleReadTimeout);
198
199 return;
200 }
201
202 fInTimeout.cancel();
203
204 if (ntohs(fBuffer.back())!=FAD::kDelimiterEnd)
205 {
206 ostringstream str;
207 str << "Invalid data received: end delimiter wrong, received ";
208 str << hex << ntohs(fBuffer.back()) << ", expected " << FAD::kDelimiterEnd << ".";
209 Error(str);
210 PostClose(false);
211 return;
212 }
213
214 uint8_t *ptr = reinterpret_cast<uint8_t*>(fBuffer.data());
215 uint8_t *end = ptr + fBuffer.size()*2;
216 for (unsigned int i=0; i<FAD::kNumChannels; i++)
217 {
218 if (ptr+sizeof(FAD::ChannelHeader) > end)
219 {
220 Error("Channel header exceeds buffer size.");
221 PostClose(false);
222 return;
223 }
224
225 fChannelHeader[i] = vector<uint16_t>((uint16_t*)ptr, (uint16_t*)ptr+sizeof(FAD::ChannelHeader)/2);
226 ptr += sizeof(FAD::ChannelHeader);
227
228 //UpdateChannelHeader(i);
229
230 if (ptr+fChannelHeader[i].fRegionOfInterest*2 > end)
231 {
232 Error("Data block exceeds buffer size.");
233 PostClose(false);
234 return;
235 }
236
237 const uint16_t *data = reinterpret_cast<uint16_t*>(ptr);
238 UpdateData(data, fChannelHeader[i].fRegionOfInterest*2);
239 ptr += fChannelHeader[i].fRegionOfInterest*2;
240 }
241
242 if (fIsVerbose)
243 UpdateChannelHeaders();
244
245 fCounter++;
246
247 fBuffer.resize(sizeof(FAD::EventHeader)/2);
248 AsyncRead(ba::buffer(fBuffer), kReadHeader);
249 }
250
251 void HandleReadTimeout(const bs::error_code &error)
252 {
253 if (error==ba::error::basic_errors::operation_aborted)
254 return;
255
256 if (error)
257 {
258 ostringstream str;
259 str << "Read timeout of " << URL() << ": " << error.message() << " (" << error << ")";// << endl;
260 Error(str);
261
262 PostClose();
263 return;
264
265 }
266
267 if (!is_open())
268 {
269 // For example: Here we could schedule a new accept if we
270 // would not want to allow two connections at the same time.
271 return;
272 }
273
274 // Check whether the deadline has passed. We compare the deadline
275 // against the current time since a new asynchronous operation
276 // may have moved the deadline before this actor had a chance
277 // to run.
278 if (fInTimeout.expires_at() > ba::deadline_timer::traits_type::now())
279 return;
280
281 Error("Timeout reading data from "+URL());
282 PostClose();
283 }
284
285 // This is called when a connection was established
286 void ConnectionEstablished()
287 {
288 fEventHeader.clear();
289 for (unsigned int i=0; i<FAD::kNumChannels; i++)
290 fChannelHeader[i].clear();
291
292 fCounter = 0;
293
294 fBuffer.resize(sizeof(FAD::EventHeader)/2);
295 AsyncRead(ba::buffer(fBuffer), kReadHeader);
296
297// for (int i=0; i<36; i++)
298// CmdSetRoi(i, 100);
299
300// Cmd(FAD::kCmdTriggerLine, true);
301// Cmd(FAD::kCmdSingleTrigger);
302 }
303
304public:
305 void PostCmd(std::vector<uint16_t> cmd)
306 {
307 if (fBlockTransmission || !IsConnected())
308 return;
309
310#ifdef DEBUG_TX
311 ostringstream msg;
312 msg << "Sending command:" << hex;
313 msg << " 0x" << setw(4) << setfill('0') << cmd[0];
314 msg << " (+ " << cmd.size()-1 << " bytes data)";
315 Message(msg);
316#endif
317 transform(cmd.begin(), cmd.end(), cmd.begin(), htons);
318
319 PostMessage(cmd);
320 }
321
322 void PostCmd(uint16_t cmd)
323 {
324 if (fBlockTransmission || !IsConnected())
325 return;
326
327#ifdef DEBUG_TX
328 ostringstream msg;
329 msg << "Sending command:" << hex;
330 msg << " 0x" << setw(4) << setfill('0') << cmd;
331 Message(msg);
332#endif
333 cmd = htons(cmd);
334 PostMessage(&cmd, sizeof(uint16_t));
335 }
336
337 void PostCmd(uint16_t cmd, uint16_t data)
338 {
339 if (fBlockTransmission || !IsConnected())
340 return;
341
342#ifdef DEBUG_TX
343 ostringstream msg;
344 msg << "Sending command:" << hex;
345 msg << " 0x" << setw(4) << setfill('0') << cmd;
346 msg << " 0x" << setw(4) << setfill('0') << data;
347 Message(msg);
348#endif
349 const uint16_t d[2] = { htons(cmd), htons(data) };
350 PostMessage(d, sizeof(d));
351 }
352
353public:
354 ConnectionFAD(ba::io_service& ioservice, MessageImp &imp, uint16_t slot) :
355 Connection(ioservice, imp()), fSlot(slot),
356 fIsVerbose(false), fIsHexOutput(false), fIsDataOutput(false),
357 fBlockTransmission(false), fCounter(0)
358 {
359 // Maximum possible needed space:
360 // The full header, all channels with all DRS bins
361 // Two trailing shorts
362 fBuffer.reserve(sizeof(FAD::EventHeader) + FAD::kNumChannels*(sizeof(FAD::ChannelHeader) + FAD::kMaxBins*sizeof(uint16_t)) + 2*sizeof(uint16_t));
363
364 SetLogStream(&imp);
365 }
366
367// void SetTcpEndpoint(const tcp::endpoint &ep) { fEndpoint = ep; }
368// const tcp::endpoint &GetTcpEndpoint() const { return fEndpoint; }
369
370 void Cmd(FAD::Enable cmd, bool on=true)
371 {
372 PostCmd(cmd + (on ? 0 : 0x100));
373 }
374
375 // ------------------------------
376
377 // IMPLEMENT: Abs/Rel
378 void CmdPhaseShift(int16_t val)
379 {
380 vector<uint16_t> cmd(abs(val)+2, FAD::kCmdPhaseApply);
381 cmd[0] = FAD::kCmdPhaseReset;
382 cmd[1] = val<0 ? FAD::kCmdPhaseDecrease : FAD::kCmdPhaseIncrease;
383 PostCmd(cmd);
384 }
385
386 bool CmdSetTriggerRate(int32_t val)
387 {
388 if (val<0 || val>0xffff)
389 return false;
390
391 PostCmd(FAD::kCmdWriteRate, val);//uint8_t(1000./val/12.5));
392 //PostCmd(FAD::kCmdWriteExecute);
393
394 return true;
395 }
396
397 void CmdSetRunNumber(uint32_t num)
398 {
399 PostCmd(FAD::kCmdWriteRunNumberLSW, num&0xffff);
400 PostCmd(FAD::kCmdWriteRunNumberMSW, num>>16);
401 PostCmd(FAD::kCmdWriteExecute);
402 }
403
404 void CmdSetRegister(uint8_t addr, uint16_t val)
405 {
406 // Allowed addr: [0, MAX_ADDR]
407 // Allowed value: [0, MAX_VAL]
408 PostCmd(FAD::kCmdWrite + addr, val);
409 PostCmd(FAD::kCmdWriteExecute);
410 }
411
412 bool CmdSetDacValue(uint8_t addr, uint16_t val)
413 {
414 if (addr>FAD::kMaxDacAddr) // NDAC
415 return false;
416
417 PostCmd(FAD::kCmdWriteDac + addr, val);
418 PostCmd(FAD::kCmdWriteExecute);
419 return true;
420 }
421
422 bool CmdSetRoi(int8_t addr, uint16_t val)
423 {
424 if (val>FAD::kMaxRoiValue)
425 return false;
426
427 if (addr<0)
428 {
429 for (unsigned int i=0; i<=FAD::kMaxRoiAddr; i++)
430 PostCmd(FAD::kCmdWriteRoi + i, val);
431 PostCmd(FAD::kCmdWriteExecute);
432 return true;
433 }
434
435 if (uint8_t(addr)>FAD::kMaxRoiAddr)
436 return false;
437
438 PostCmd(FAD::kCmdWriteRoi + addr, val);
439 PostCmd(FAD::kCmdWriteExecute);
440 return true;
441 }
442
443 bool CmdSetRoi(uint16_t val) { return CmdSetRoi(-1, val); }
444
445 void AmplitudeCalibration()
446 {
447 // ------------- case baseline -----------------
448
449 CmdSetRoi(-1, FAD::kMaxBins);
450
451 CmdSetDacValue(1, 0);
452 CmdSetDacValue(2, 0);
453 CmdSetDacValue(3, 0);
454
455 // Take N events
456
457 /*
458 // ====== Part B: Baseline calibration =====
459
460 // Loop over all channels(ch) and time-slices (t)
461 T0 = TriggerCell[chip]
462 Sum[ch][(t+T0) % kMaxBins] += Data[ch][t];
463 // FIXME: Determine median instead of average
464
465 Baseline[ch][slice] = MEDIAN( sum[ch][slice] )
466 */
467
468 // --------------- case gain -------------------
469
470 // Set new DAC values and start accumulation
471 CmdSetDacValue(1, 50000);
472 CmdSetDacValue(2, 50000);
473 CmdSetDacValue(3, 50000);
474
475 // Take N events
476
477 /*
478 // ====== Part C: Gain calibration =====
479
480 T0 = TriggerCell[chip]
481 Sum[ch][(t+T0) % kMaxBins] += Data[ch][t];
482 // FIXME: Determine median instead of average
483
484 Gain[ch][slice] = MEDIAN( sum[ch][slice] ) - Baseline[ch][slice]
485 */
486
487 // --------------- secondary ------------------
488
489 // FIXME: Can most probably be done together with the baseline calibration
490 // FIXME: Why does the secondary baseline not influence the baseline?
491
492 CmdSetDacValue(1, 0);
493 CmdSetDacValue(2, 0);
494 CmdSetDacValue(3, 0);
495
496 // Take N events
497
498 /*
499 // ====== Part D: Secondary calibration =====
500
501 T0 = TriggerCell[chip]
502 Sum[ch][t] = Data[ch][t] - Baseline[ch][(i-T0) % kMaxBins];
503
504 // Determine secondary baseline if integration finished
505 SecondaryBaseline[ch][t] = MEDIAN( Sum[ch][t] )
506 */
507 }
508
509 void SetVerbose(bool b)
510 {
511 fIsVerbose = b;
512 }
513
514 void SetHexOutput(bool b)
515 {
516 fIsHexOutput = b;
517 }
518
519 void SetDataOutput(bool b)
520 {
521 fIsDataOutput = b;
522 }
523
524 void SetBlockTransmission(bool b)
525 {
526 fBlockTransmission = b;
527 }
528
529 bool IsTransmissionBlocked() const
530 {
531 return fBlockTransmission;
532 }
533
534 void PrintEvent()
535 {
536 if (fCounter>0)
537 {
538 PrintEventHeader();
539 PrintChannelHeaders();
540 }
541 else
542 Out() << "No event received yet." << endl;
543 }
544
545};
546
547// ------------------------------------------------------------------------
548
549template <class T>
550class StateMachineFAD : public T, public EventBuilderWrapper, public ba::io_service, public ba::io_service::work
551{
552private:
553 typedef map<uint8_t, ConnectionFAD*> BoardList;
554
555 BoardList fBoards;
556
557 bool fIsVerbose;
558 bool fIsHexOutput;
559 bool fIsDataOutput;
560 bool fDebugTx;
561
562 bool CheckEventSize(size_t has, const char *name, size_t size)
563 {
564 if (has==size)
565 return true;
566
567 ostringstream msg;
568 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
569 T::Fatal(msg);
570 return false;
571 }
572
573 int Cmd(FAD::Enable command)
574 {
575 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
576 i->second->Cmd(command);
577
578 return T::GetCurrentState();
579 }
580
581 int SendCmd(const EventImp &evt)
582 {
583 if (!CheckEventSize(evt.GetSize(), "SendCmd", 4))
584 return T::kSM_FatalError;
585
586 if (evt.GetUInt()>0xffff)
587 {
588 T::Warn("Command value out of range (0-65535).");
589 return T::GetCurrentState();
590 }
591
592 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
593 i->second->PostCmd(evt.GetUInt());
594
595 return T::GetCurrentState();
596 }
597
598 int SendCmdData(const EventImp &evt)
599 {
600 if (!CheckEventSize(evt.GetSize(), "SendCmdData", 8))
601 return T::kSM_FatalError;
602
603 const uint32_t *ptr = evt.Ptr<uint32_t>();
604
605 if (ptr[0]>0xffff)
606 {
607 T::Warn("Command value out of range (0-65535).");
608 return T::GetCurrentState();
609 }
610
611 if (ptr[1]>0xffff)
612 {
613 T::Warn("Data value out of range (0-65535).");
614 return T::GetCurrentState();
615 }
616
617 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
618 i->second->PostCmd(ptr[0], ptr[1]);
619
620 return T::GetCurrentState();
621 }
622
623 int CmdEnable(const EventImp &evt, FAD::Enable command)
624 {
625 if (!CheckEventSize(evt.GetSize(), "CmdEnable", 1))
626 return T::kSM_FatalError;
627
628 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
629 i->second->Cmd(command, evt.GetBool());
630
631 return T::GetCurrentState();
632 }
633
634 bool Check(const uint32_t *dat, uint32_t maxaddr, uint32_t maxval)
635 {
636 if (dat[0]>maxaddr)
637 {
638 ostringstream msg;
639 msg << hex << "Address " << dat[0] << " out of range, max=" << maxaddr << ".";
640 T::Error(msg);
641 return false;
642 }
643
644 if (dat[1]>maxval)
645 {
646 ostringstream msg;
647 msg << hex << "Value " << dat[1] << " out of range, max=" << maxval << ".";
648 T::Error(msg);
649 return false;
650 }
651
652 return true;
653 }
654
655 int SetRegister(const EventImp &evt)
656 {
657 if (!CheckEventSize(evt.GetSize(), "SetRegister", 8))
658 return T::kSM_FatalError;
659
660 const uint32_t *dat = evt.Ptr<uint32_t>();
661
662 if (!Check(dat, FAD::kMaxRegAddr, FAD::kMaxRegValue))
663 return T::GetCurrentState();
664
665 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
666 i->second->CmdSetRegister(dat[0], dat[1]);
667
668 return T::GetCurrentState();
669 }
670
671 int SetRoi(const EventImp &evt)
672 {
673 if (!CheckEventSize(evt.GetSize(), "SetRoi", 8))
674 return T::kSM_FatalError;
675
676 const int32_t *dat = evt.Ptr<int32_t>();
677
678 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
679 if (!i->second->CmdSetRoi(dat[0], dat[1]))
680 {
681 ostringstream msg;
682 msg << hex << "Channel " << dat[0] << " or Value " << dat[1] << " out of range.";
683 T::Error(msg);
684 return false;
685 }
686
687
688 return T::GetCurrentState();
689 }
690
691 int SetDac(const EventImp &evt)
692 {
693 if (!CheckEventSize(evt.GetSize(), "SetDac", 8))
694 return T::kSM_FatalError;
695
696 const uint32_t *dat = evt.Ptr<uint32_t>();
697
698 if (!Check(dat, FAD::kMaxDacAddr, FAD::kMaxDacValue))
699 return T::GetCurrentState();
700
701 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
702 i->second->CmdSetDacValue(dat[0], dat[1]);
703
704 return T::GetCurrentState();
705 }
706
707 int Trigger(int n)
708 {
709 for (int nn=0; nn<n; nn++)
710 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
711 i->second->Cmd(FAD::kCmdSingleTrigger);
712
713 return T::GetCurrentState();
714 }
715
716 int SendTriggers(const EventImp &evt)
717 {
718 if (!CheckEventSize(evt.GetSize(), "SendTriggers", 4))
719 return T::kSM_FatalError;
720
721 Trigger(evt.GetUInt());
722
723 return T::GetCurrentState();
724 }
725
726 int StartRun(const EventImp &evt, bool start)
727 {
728 if (!CheckEventSize(evt.GetSize(), "StartRun", 0))
729 return T::kSM_FatalError;
730
731 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
732 i->second->Cmd(FAD::kCmdRun, start);
733
734 return T::GetCurrentState();
735 }
736
737 int PhaseShift(const EventImp &evt)
738 {
739 if (!CheckEventSize(evt.GetSize(), "PhaseShift", 2))
740 return T::kSM_FatalError;
741
742 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
743 i->second->CmdPhaseShift(evt.GetShort());
744
745 return T::GetCurrentState();
746 }
747
748 int SetTriggerRate(const EventImp &evt)
749 {
750 if (!CheckEventSize(evt.GetSize(), "SetTriggerRate", 4))
751 return T::kSM_FatalError;
752
753 if (evt.GetUShort()>0xff)
754 {
755 ostringstream msg;
756 msg << hex << "Value " << evt.GetUShort() << " out of range, max=" << 0xff << "(?)";
757 T::Error(msg);
758 return false;
759 }
760
761 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
762 i->second->CmdSetTriggerRate(evt.GetUInt());
763
764 return T::GetCurrentState();
765 }
766
767 int SetRunNumber(const EventImp &evt)
768 {
769 if (!CheckEventSize(evt.GetSize(), "SetRunNumber", 8))
770 return T::kSM_FatalError;
771
772 const uint64_t num = evt.GetUXtra();
773
774 if (num>FAD::kMaxRunNumber)
775 {
776 ostringstream msg;
777 msg << hex << "Value " << num << " out of range, max=" << FAD::kMaxRunNumber;
778 T::Error(msg);
779 return false;
780 }
781
782 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
783 i->second->CmdSetRunNumber(num);
784
785 return T::GetCurrentState();
786 }
787
788 int SetMaxMemoryBuffer(const EventImp &evt)
789 {
790 if (!CheckEventSize(evt.GetSize(), "SetMaxMemoryBuffer", 2))
791 return T::kSM_FatalError;
792
793 const int16_t mem = evt.GetShort();
794
795 if (mem<=0)
796 {
797 ostringstream msg;
798 msg << hex << "Value " << mem << " out of range.";
799 T::Error(msg);
800 return false;
801 }
802
803 SetMaxMemory(mem);
804
805 return T::GetCurrentState();
806 }
807
808 int Test(const EventImp &evt)
809 {
810 if (!CheckEventSize(evt.GetSize(), "Test", 2))
811 return T::kSM_FatalError;
812
813
814 SetMode(evt.GetShort());
815
816 return T::GetCurrentState();
817 }
818
819
820 int SetVerbosity(const EventImp &evt)
821 {
822 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
823 return T::kSM_FatalError;
824
825 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
826 i->second->SetVerbose(evt.GetBool());
827
828 return T::GetCurrentState();
829 }
830
831 int SetHexOutput(const EventImp &evt)
832 {
833 if (!CheckEventSize(evt.GetSize(), "SetHexOutput", 1))
834 return T::kSM_FatalError;
835
836 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
837 i->second->SetHexOutput(evt.GetBool());
838
839 return T::GetCurrentState();
840 }
841
842 int SetDataOutput(const EventImp &evt)
843 {
844 if (!CheckEventSize(evt.GetSize(), "SetDataOutput", 1))
845 return T::kSM_FatalError;
846
847 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
848 i->second->SetDataOutput(evt.GetBool());
849
850 return T::GetCurrentState();
851 }
852
853 int SetDebugTx(const EventImp &evt)
854 {
855 if (!CheckEventSize(evt.GetSize(), "SetDebugTx", 1))
856 return T::kSM_FatalError;
857
858 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
859 i->second->SetDebugTx(evt.GetBool());
860
861 return T::GetCurrentState();
862 }
863
864 const BoardList::iterator GetSlot(uint16_t slot)
865 {
866 const BoardList::iterator it=fBoards.find(slot);
867 if (it==fBoards.end())
868 {
869 ostringstream str;
870 str << "Slot " << slot << " not found.";
871 T::Warn(str);
872 }
873
874 return it;
875 }
876
877 int PrintEvent(const EventImp &evt)
878 {
879 if (!CheckEventSize(evt.GetSize(), "PrintEvent", 2))
880 return T::kSM_FatalError;
881
882 const int16_t slot = evt.Get<int16_t>();
883
884 if (slot<0)
885 {
886 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
887 i->second->PrintEvent();
888 }
889 else
890 {
891 const BoardList::iterator it=GetSlot(slot);
892 if (it!=fBoards.end())
893 it->second->PrintEvent();
894 }
895
896 return T::GetCurrentState();
897 }
898
899 int SetBlockTransmission(const EventImp &evt)
900 {
901 if (!CheckEventSize(evt.GetSize(), "SetBlockTransmission", 3))
902 return T::kSM_FatalError;
903
904 const int16_t slot = evt.Get<int32_t>();
905
906 const BoardList::iterator it=GetSlot(slot);
907 if (it!=fBoards.end())
908 it->second->SetBlockTransmission(evt.Get<uint8_t>(2));
909
910 return T::GetCurrentState();
911 }
912
913 int SetBlockTransmissionRange(const EventImp &evt)
914 {
915 if (!CheckEventSize(evt.GetSize(), "SetBlockTransmissionRange", 5))
916 return T::kSM_FatalError;
917
918 const int16_t *slot = evt.Ptr<int16_t>();
919 const bool block = evt.Get<uint8_t>(4);
920
921 for (int i=slot[0]; i<=slot[1]; i++)
922 {
923 const BoardList::iterator it=GetSlot(i);
924 if (it!=fBoards.end())
925 it->second->SetBlockTransmission(block);
926 }
927
928 return T::GetCurrentState();
929 }
930
931 int SetIgnoreSlot(const EventImp &evt)
932 {
933 if (!CheckEventSize(evt.GetSize(), "SetIgnoreSlot", 3))
934 return T::kSM_FatalError;
935
936 const uint16_t slot = evt.Get<uint16_t>();
937
938 if (slot>39)
939 {
940 T::Warn("Slot out of range (0-39).");
941 return T::GetCurrentState();
942 }
943
944 SetIgnore(slot, evt.Get<uint8_t>(2));
945
946 return T::GetCurrentState();
947 }
948
949 int SetIgnoreSlots(const EventImp &evt)
950 {
951 if (!CheckEventSize(evt.GetSize(), "SetIgnoreSlots", 5))
952 return T::kSM_FatalError;
953
954 const int16_t *slot = evt.Ptr<int16_t>();
955 const bool block = evt.Get<uint8_t>(4);
956
957 if (slot[0]<0 || slot[1]>39 || slot[0]>slot[1])
958 {
959 T::Warn("Slot out of range.");
960 return T::GetCurrentState();
961 }
962
963 for (int i=slot[0]; i<=slot[1]; i++)
964 SetIgnore(i, block);
965
966 return T::GetCurrentState();
967 }
968
969 int SetDumpStream(const EventImp &evt)
970 {
971 if (!CheckEventSize(evt.GetSize(), "SetDumpStream", 1))
972 return T::kSM_FatalError;
973
974 SetDebugStream(evt.Get<uint8_t>());
975
976 return T::GetCurrentState();
977 }
978
979 int SetDumpRecv(const EventImp &evt)
980 {
981 if (!CheckEventSize(evt.GetSize(), "SetDumpRecv", 1))
982 return T::kSM_FatalError;
983
984 SetDebugRead(evt.Get<uint8_t>());
985
986 return T::GetCurrentState();
987 }
988
989 int AddAddress(const EventImp &evt)
990 {
991 const string addr = Tools::Trim(evt.GetText());
992
993 const tcp::endpoint endpoint = GetEndpoint(addr);
994 if (endpoint==tcp::endpoint())
995 return T::GetCurrentState();
996
997 for (BoardList::const_iterator i=fBoards.begin(); i!=fBoards.end(); i++)
998 {
999 if (i->second->GetEndpoint()==endpoint)
1000 {
1001 T::Warn("Address "+addr+" already known.... ignored.");
1002 return T::GetCurrentState();
1003 }
1004 }
1005
1006 AddEndpoint(endpoint);
1007
1008 return T::GetCurrentState();
1009 }
1010
1011 int RemoveSlot(const EventImp &evt)
1012 {
1013 if (!CheckEventSize(evt.GetSize(), "RemoveSlot", 2))
1014 return T::kSM_FatalError;
1015
1016 const int16_t slot = evt.GetShort();
1017
1018 const BoardList::iterator it = GetSlot(slot);
1019
1020 if (it==fBoards.end())
1021 return T::GetCurrentState();
1022
1023 ConnectSlot(slot, tcp::endpoint());
1024
1025 delete it->second;
1026 fBoards.erase(it);
1027
1028 return T::GetCurrentState();
1029 }
1030
1031 int ListSlots()
1032 {
1033 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
1034 {
1035 const int &idx = i->first;
1036 const ConnectionFAD *fad = i->second;
1037
1038 ostringstream str;
1039 str << "Slot " << setw(2) << idx << ": " << fad->GetEndpoint();
1040
1041 if (fad->IsConnecting())
1042 str << " (0:connecting, ";
1043 else
1044 {
1045 if (fad->IsClosed())
1046 str << " (0:disconnected, ";
1047 if (fad->IsConnected())
1048 str << " (0:connected, ";
1049 }
1050
1051 switch (fStatus2[idx])
1052 {
1053 case 0: str << "1-7:not connected)"; break;
1054 case 8: str << "1-7:connected)"; break;
1055 default: str << "1-7:connecting [" << (int)(fStatus2[idx]-1) << "])"; break;
1056 }
1057
1058 if (fad->IsTransmissionBlocked())
1059 str << " [cmd_blocked]";
1060
1061 if (fStatus2[idx]==8 && IsIgnored(idx))
1062 str << " [data_ignored]";
1063
1064 T::Out() << str.str() << endl;
1065 }
1066
1067 T::Out() << "Event builder thread:";
1068 if (!IsThreadRunning())
1069 T::Out() << " not";
1070 T::Out() << " running" << endl;
1071
1072 // FIXME: Output state
1073
1074 return T::GetCurrentState();
1075 }
1076
1077 void EnableConnection(ConnectionFAD *ptr, bool enable=true)
1078 {
1079 if (!enable)
1080 {
1081 ptr->PostClose(false);
1082 return;
1083 }
1084
1085 if (!ptr->IsDisconnected())
1086 {
1087 ostringstream str;
1088 str << ptr->GetEndpoint();
1089
1090 T::Warn("Connection to "+str.str()+" already in progress.");
1091 return;
1092 }
1093
1094 ptr->StartConnect();
1095 }
1096
1097 void EnableAll(bool enable=true)
1098 {
1099 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
1100 EnableConnection(i->second, enable);
1101 }
1102
1103 int CloseOpenFiles()
1104 {
1105 EventBuilderWrapper::CloseOpenFiles();
1106 return T::GetCurrentState();
1107 }
1108
1109 int EnableSlot(const EventImp &evt, bool enable)
1110 {
1111 if (!CheckEventSize(evt.GetSize(), "EnableSlot", 2))
1112 return T::kSM_FatalError;
1113
1114 const int16_t slot = evt.GetShort();
1115
1116 const BoardList::iterator it = GetSlot(slot);
1117 if (it==fBoards.end())
1118 return T::GetCurrentState();
1119
1120 EnableConnection(it->second, enable);
1121 ConnectSlot(it->first, enable ? it->second->GetEndpoint() : tcp::endpoint());
1122
1123 return T::GetCurrentState();
1124 }
1125
1126 int ToggleSlot(const EventImp &evt)
1127 {
1128 if (!CheckEventSize(evt.GetSize(), "ToggleSlot", 2))
1129 return T::kSM_FatalError;
1130
1131 const int16_t slot = evt.GetShort();
1132
1133 const BoardList::iterator it = GetSlot(slot);
1134 if (it==fBoards.end())
1135 return T::GetCurrentState();
1136
1137 const bool enable = it->second->IsDisconnected();
1138
1139 EnableConnection(it->second, enable);
1140 ConnectSlot(it->first, enable ? it->second->GetEndpoint() : tcp::endpoint());
1141
1142 return T::GetCurrentState();
1143 }
1144
1145 int StartConnection()
1146 {
1147 vector<tcp::endpoint> addr(40);
1148
1149 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
1150 addr[i->first] = i->second->GetEndpoint();
1151
1152 StartThread(addr);
1153 EnableAll(true);
1154
1155 return T::GetCurrentState();
1156 }
1157
1158 int StopConnection()
1159 {
1160 Exit();
1161 EnableAll(false);
1162 return T::GetCurrentState();
1163 }
1164
1165 int AbortConnection()
1166 {
1167 Abort();
1168 EnableAll(false);
1169 return T::GetCurrentState();
1170 }
1171
1172 vector<uint8_t> fStatus1;
1173 vector<uint8_t> fStatus2;
1174 bool fStatusT;
1175
1176 int Execute()
1177 {
1178 // Dispatch (execute) at most one handler from the queue. In contrary
1179 // to run_one(), it doesn't wait until a handler is available
1180 // which can be dispatched, so poll_one() might return with 0
1181 // handlers dispatched. The handlers are always dispatched/executed
1182 // synchronously, i.e. within the call to poll_one()
1183 poll_one();
1184
1185 // ===== Evaluate connection status =====
1186
1187 uint16_t nclosed1 = 0;
1188 uint16_t nconnecting1 = 0;
1189 uint16_t nconnecting2 = 0;
1190 uint16_t nconnected1 = 0;
1191 uint16_t nconnected2 = 0;
1192
1193 vector<uint8_t> stat1(40);
1194 vector<uint8_t> stat2(40);
1195
1196 int cnt = 0; // counter for enabled board
1197
1198 const bool runs = IsThreadRunning();
1199
1200 for (int idx=0; idx<40; idx++)
1201 {
1202 // ----- Command socket -----
1203 const BoardList::const_iterator &slot = fBoards.find(idx);
1204 if (slot!=fBoards.end())
1205 {
1206 const ConnectionFAD *c = slot->second;
1207 if (c->IsDisconnected())
1208 {
1209 stat1[idx] = 0;
1210 nclosed1++;
1211
1212 //DisconnectSlot(idx);
1213 }
1214 if (c->IsConnecting())
1215 {
1216 stat1[idx] = 1;
1217 nconnecting1++;
1218 }
1219 if (c->IsConnected())
1220 {
1221 stat1[idx] = 2;
1222 nconnected1++;
1223 }
1224
1225 cnt++;
1226 }
1227
1228 // ----- Event builder -----
1229
1230 if (!runs)
1231 continue;
1232
1233 stat2[idx] = GetNumConnected(idx);
1234
1235 if (IsConnecting(idx))
1236 {
1237 nconnecting2++;
1238 stat2[idx]++;
1239 }
1240
1241 if (IsConnected(idx))
1242 {
1243 stat2[idx]++;
1244 nconnected2++;
1245 }
1246 }
1247
1248 // ===== Send connection status via dim =====
1249
1250 if (fStatus1!=stat1 || fStatus2!=stat2 || fStatusT!=IsThreadRunning())
1251 {
1252 fStatus1 = stat1;
1253 fStatus2 = stat2;
1254 fStatusT = runs;
1255 UpdateConnectionStatus(stat1, stat2, IsThreadRunning());
1256 }
1257
1258 // ===== Return connection status =====
1259
1260 // fadctrl: Always connecting if not disabled
1261 // event builder:
1262 if (nconnecting1==0 && nconnected1>0 &&
1263 nconnected2==nconnected1)
1264 return FAD::kConnected;
1265
1266 if (nconnecting1>0 || nconnecting2>0 || nconnected1!=nconnected2)
1267 return FAD::kConnecting;
1268
1269 // nconnected1 == nconnected2 == 0
1270 return IsThreadRunning() ? FAD::kDisconnected : FAD::kOffline;
1271 }
1272
1273 void AddEndpoint(const tcp::endpoint &addr)
1274 {
1275 int i=0;
1276 while (i<40)
1277 {
1278 if (fBoards.find(i)==fBoards.end())
1279 break;
1280 i++;
1281 }
1282
1283 if (i==40)
1284 {
1285 T::Warn("Not more than 40 slots allowed.");
1286 return;
1287 }
1288
1289 ConnectionFAD *fad = new ConnectionFAD(*this, *this, i);
1290
1291 fad->SetEndpoint(addr);
1292 fad->SetVerbose(fIsVerbose);
1293 fad->SetHexOutput(fIsHexOutput);
1294 fad->SetDataOutput(fIsDataOutput);
1295 fad->SetDebugTx(fDebugTx);
1296
1297 fBoards[i] = fad;
1298 }
1299
1300
1301 DimDescribedService fDimConnection;
1302
1303 void UpdateConnectionStatus(const vector<uint8_t> &stat1, const vector<uint8_t> &stat2, bool thread)
1304 {
1305 vector<uint8_t> stat(41);
1306
1307 for (int i=0; i<40; i++)
1308 stat[i] = stat1[i]|(stat2[i]<<3);
1309
1310 stat[40] = thread;
1311
1312 fDimConnection.setData(stat.data(), 41);
1313 fDimConnection.updateService();
1314 }
1315
1316public:
1317 StateMachineFAD(ostream &out=cout) :
1318 T(out, "FAD_CONTROL"), EventBuilderWrapper(*static_cast<MessageImp*>(this)), ba::io_service::work(static_cast<ba::io_service&>(*this)),
1319 fStatus1(40), fStatus2(40), fStatusT(false),
1320 fDimConnection("FAD_CONTROL/CONNECTIONS", "C:40;C:1", "")
1321 {
1322 // ba::io_service::work is a kind of keep_alive for the loop.
1323 // It prevents the io_service to go to stopped state, which
1324 // would prevent any consecutive calls to run()
1325 // or poll() to do nothing. reset() could also revoke to the
1326 // previous state but this might introduce some overhead of
1327 // deletion and creation of threads and more.
1328
1329 // State names
1330 T::AddStateName(FAD::kOffline, "Disengaged",
1331 "All enabled FAD boards are disconnected and the event-builer thread is not running.");
1332
1333 T::AddStateName(FAD::kDisconnected, "Disconnected",
1334 "All enabled FAD boards are disconnected, but the event-builder thread is running.");
1335
1336 T::AddStateName(FAD::kConnecting, "Connecting",
1337 "Only some enabled FAD boards are connected.");
1338
1339 T::AddStateName(FAD::kConnected, "Connected",
1340 "All enabled FAD boards are connected..");
1341
1342 // FAD Commands
1343 T::AddEvent("SEND_CMD", "I:1")
1344 (boost::bind(&StateMachineFAD::SendCmd, this, _1))
1345 ("Send a command to the FADs. Values between 0 and 0xffff are allowed."
1346 "|command[uint16]:Command to be transmittted.");
1347 T::AddEvent("SEND_DATA", "I:2")
1348 (boost::bind(&StateMachineFAD::SendCmdData, this, _1))
1349 ("Send a command with data to the FADs. Values between 0 and 0xffff are allowed."
1350 "|command[uint16]:Command to be transmittted."
1351 "|data[uint16]:Data to be sent with the command.");
1352
1353 T::AddEvent("ENABLE_SRCLK", "B:1")
1354 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdSrclk))
1355 ("Set SRCLK");
1356 T::AddEvent("ENABLE_BUSY", "B:1")
1357 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdBusy))
1358 ("Set BUSY");
1359 T::AddEvent("ENABLE_SCLK", "B:1")
1360 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdSclk))
1361 ("Set SCLK");
1362 T::AddEvent("ENABLE_DRS", "B:1")
1363 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdDrsEnable))
1364 ("Switch Domino wave");
1365 T::AddEvent("ENABLE_DWRITE", "B:1")
1366 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdDwrite))
1367 ("Set Dwrite (possibly high / always low)");
1368 T::AddEvent("ENABLE_CONTINOUS_TRIGGER", "B:1")
1369 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdContTrigger))
1370 ("Enable continous (internal) trigger.");
1371 T::AddEvent("ENABLE_TRIGGER_LINE", "B:1")
1372 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdTriggerLine))
1373 ("Incoming triggers can be accepted/will not be accepted");
1374 T::AddEvent("SET_DEBUG_MODE", "B:1")
1375 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdSocket))
1376 ("Set debug mode (yes: dump events through command socket, no=dump events through other sockets)");
1377
1378 T::AddEvent("SET_TRIGGER_RATE", "I:1")
1379 (boost::bind(&StateMachineFAD::SetTriggerRate, this, _1))
1380 ("Enable continous trigger");
1381 T::AddEvent("SEND_SINGLE_TRIGGER")
1382 (boost::bind(&StateMachineFAD::Trigger, this, 1))
1383 ("Issue software triggers");
1384 T::AddEvent("SEND_N_TRIGGERS", "I")
1385 (boost::bind(&StateMachineFAD::SendTriggers, this, _1))
1386 ("Issue software triggers");
1387 T::AddEvent("START_RUN", "")
1388 (boost::bind(&StateMachineFAD::StartRun, this, _1, true))
1389 ("Set FAD DAQ mode. when started, no configurations must be send.");
1390 T::AddEvent("STOP_RUN")
1391 (boost::bind(&StateMachineFAD::StartRun, this, _1, false))
1392 ("");
1393 T::AddEvent("PHASE_SHIFT", "S:1")
1394 (boost::bind(&StateMachineFAD::PhaseShift, this, _1))
1395 ("Adjust ADC phase (in 'steps')");
1396
1397 T::AddEvent("RESET_TRIGGER_ID")
1398 (boost::bind(&StateMachineFAD::Cmd, this, FAD::kCmdResetTriggerId))
1399 ("");
1400
1401 T::AddEvent("SET_RUN_NUMBER", "X:1")
1402 (boost::bind(&StateMachineFAD::SetRunNumber, this, _1))
1403 ("");
1404
1405 T::AddEvent("SET_MAX_MEMORY", "S:1")
1406 (boost::bind(&StateMachineFAD::SetMaxMemoryBuffer, this, _1))
1407 ("Set maximum memory buffer size allowed to be consumed by the EventBuilder to buffer events."
1408 "|memory[short]:Buffer size in Mega-bytes.");
1409
1410 T::AddEvent("SET_REGISTER", "I:2")
1411 (boost::bind(&StateMachineFAD::SetRegister, this, _1))
1412 ("set register to value"
1413 "|addr[short]:Address of register"
1414 "|val[short]:Value to be set");
1415
1416 // FIXME: Maybe add a mask which channels should be set?
1417 T::AddEvent("SET_REGION_OF_INTEREST", "I:2")
1418 (boost::bind(&StateMachineFAD::SetRoi, this, _1))
1419 ("Set region-of-interest to value"
1420 "|addr[short]:Address of register"
1421 "|val[short]:Value to be set");
1422
1423 // FIXME: Maybe add a mask which channels should be set?
1424 T::AddEvent("SET_DAC_VALUE", "I:2")
1425 (boost::bind(&StateMachineFAD::SetDac, this, _1))
1426 ("Set DAC numbers in range to value"
1427 "|addr[short]:Address of register"
1428 "|val[short]:Value to be set");
1429
1430 // Verbosity commands
1431 T::AddEvent("SET_VERBOSE", "B:1")
1432 (boost::bind(&StateMachineFAD::SetVerbosity, this, _1))
1433 ("Set verbosity state"
1434 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
1435
1436 T::AddEvent("SET_HEX_OUTPUT", "B:1")
1437 (boost::bind(&StateMachineFAD::SetHexOutput, this, _1))
1438 ("Enable or disable hex output for received data"
1439 "|hexout[bool]:disable or enable hex output for received data (yes/no)");
1440
1441 T::AddEvent("SET_DATA_OUTPUT", "B:1")
1442 (boost::bind(&StateMachineFAD::SetDataOutput, this, _1))
1443 ("");
1444
1445 T::AddEvent("SET_DEBUG_TX", "B:1")
1446 (boost::bind(&StateMachineFAD::SetDebugTx, this, _1))
1447 ("Enable or disable the output of messages in case of successfull data transmission to the boards."
1448 "|debug[bool]:disable or enable debug output for transmitted data (yes/no)");
1449
1450 T::AddEvent("PRINT_EVENT", "S:1")
1451 (boost::bind(&StateMachineFAD::PrintEvent, this, _1))
1452 ("Print (last) event"
1453 "|board[short]:slot from which the event should be printed (-1 for all)");
1454
1455 T::AddEvent("DUMP_STREAM", "B:1")
1456 (boost::bind(&StateMachineFAD::SetDumpStream, this, _1))
1457 ("For debugging purpose: the binary data stream read from the sockets 0-7 can be dumped to files."
1458 "|switch[bool]:Enable (yes) or disable (no)");
1459
1460 T::AddEvent("DUMP_RECV", "B:1")
1461 (boost::bind(&StateMachineFAD::SetDumpRecv, this, _1))
1462 ("For debugging purpose: the times when data has been receives are dumped to a file."
1463 "|switch[bool]:Enable (yes) or disable (no)");
1464
1465 T::AddEvent("BLOCK_TRANSMISSION", "S:1;B:1")
1466 (boost::bind(&StateMachineFAD::SetBlockTransmission, this, _1))
1467 ("Blocks the transmission of commands to the given slot. Use with care! For debugging pupose only!"
1468 "|slot[short]:Slot to which the command transmission should be blocked (0-39)"
1469 "|enable[bool]:Whether the command transmission should be blockes (yes) or allowed (no)");
1470
1471 T::AddEvent("BLOCK_TRANSMISSION_RANGE", "S:2;B:1")
1472 (boost::bind(&StateMachineFAD::SetBlockTransmissionRange, this, _1))
1473 ("Blocks the transmission of commands to the given range of slots. Use with care! For debugging pupose only!"
1474 "|first[short]:First slot to which the command transmission should be blocked (0-39)"
1475 "|last[short]:Last slot to which the command transmission should be blocked (0-39)"
1476 "|enable[bool]:Whether the command transmission should be blockes (yes) or allowed (no)");
1477
1478 T::AddEvent("IGNORE_EVENTS", "S:1;B:1")
1479 (boost::bind(&StateMachineFAD::SetIgnoreSlot, this, _1))
1480 ("Instructs the event-builder to ignore events from the given slot but still read the data from the socket."
1481 "|slot[short]:Slot from which the data should be ignored when building events"
1482 "|enable[bool]:Whether the event builder should ignore data from this slot (yes) or allowed (no)");
1483
1484 T::AddEvent("IGNORE_EVENTS_RANGE", "S:2;B:1")
1485 (boost::bind(&StateMachineFAD::SetIgnoreSlots, this, _1))
1486 ("Instructs the event-builder to ignore events from the given slot but still read the data from the socket."
1487 "|first[short]:First slot from which the data should be ignored when building events"
1488 "|last[short]:Last slot from which the data should be ignored when building events"
1489 "|enable[bool]:Whether the event builder should ignore data from this slot (yes) or allowed (no)");
1490
1491 T::AddEvent("CLOSE_OPEN_FILES", FAD::kConnecting, FAD::kConnected)
1492 (boost::bind(&StateMachineFAD::CloseOpenFiles, this))
1493 ("Close all run files opened by the EventBuilder.");
1494
1495 T::AddEvent("TEST", "S:1")
1496 (boost::bind(&StateMachineFAD::Test, this, _1))
1497 ("");
1498
1499
1500
1501 // Conenction commands
1502 T::AddEvent("START", FAD::kOffline)
1503 (boost::bind(&StateMachineFAD::StartConnection, this))
1504 ("Start EventBuilder thread and connect all valid slots.");
1505
1506 T::AddEvent("STOP", FAD::kDisconnected, FAD::kConnecting, FAD::kConnected)
1507 (boost::bind(&StateMachineFAD::StopConnection, this))
1508 ("Stop EventBuilder thread (still write buffered events) and disconnect all slots.");
1509
1510 T::AddEvent("ABORT", FAD::kDisconnected, FAD::kConnecting, FAD::kConnected)
1511 (boost::bind(&StateMachineFAD::AbortConnection, this))
1512 ("Immediately abort EventBuilder thread and disconnect all slots.");
1513
1514 T::AddEvent("CONNECT", "S:1", FAD::kDisconnected, FAD::kConnecting, FAD::kConnected)
1515 (boost::bind(&StateMachineFAD::EnableSlot, this, _1, true))
1516 ("Connect a disconnected slot.");
1517
1518 T::AddEvent("DISCONNECT", "S:1", FAD::kConnecting, FAD::kConnected)
1519 (boost::bind(&StateMachineFAD::EnableSlot, this, _1, false))
1520 ("Disconnect a connected slot.");
1521
1522 T::AddEvent("TOGGLE", "S:1", FAD::kDisconnected, FAD::kConnecting, FAD::kConnected)
1523 (boost::bind(&StateMachineFAD::ToggleSlot, this, _1))
1524 ("");
1525
1526
1527 T::AddEvent("ADD_ADDRESS", "C", FAD::kOffline)
1528 (boost::bind(&StateMachineFAD::AddAddress, this, _1))
1529 ("Add the address of a DRS4 board to the first free slot"
1530 "|IP[string]:address in the format <address:port>");
1531 T::AddEvent("REMOVE_SLOT", "S:1", FAD::kOffline)
1532 (boost::bind(&StateMachineFAD::RemoveSlot, this, _1))
1533 ("Remove the Iaddress in slot n. For a list see LIST"
1534 "|slot[short]:Remove the address in slot n from the list");
1535 T::AddEvent("LIST_SLOTS")
1536 (boost::bind(&StateMachineFAD::ListSlots, this))
1537 ("Print a list of all available board addressesa and whether they are enabled");
1538 }
1539
1540 ~StateMachineFAD()
1541 {
1542 for (BoardList::const_iterator i=fBoards.begin(); i!=fBoards.end(); i++)
1543 delete i->second;
1544 fBoards.clear();
1545 }
1546
1547 tcp::endpoint GetEndpoint(const string &base)
1548 {
1549 const size_t p0 = base.find_first_of(':');
1550 const size_t p1 = base.find_last_of(':');
1551
1552 if (p0==string::npos || p0!=p1)
1553 {
1554 T::Out() << kRed << "GetEndpoint - Wrong format ('host:port' expected)" << endl;
1555 return tcp::endpoint();
1556 }
1557
1558 tcp::resolver resolver(get_io_service());
1559
1560 boost::system::error_code ec;
1561
1562 const tcp::resolver::query query(base.substr(0, p0), base.substr(p0+1));
1563 const tcp::resolver::iterator iterator = resolver.resolve(query, ec);
1564
1565 if (ec)
1566 {
1567 T::Out() << kRed << "GetEndpoint - Couldn't resolve endpoint '" << base << "': " << ec.message();
1568 return tcp::endpoint();
1569 }
1570
1571 return *iterator;
1572 }
1573
1574 bool SetConfiguration(const Configuration &conf)
1575 {
1576 fIsVerbose = !conf.Get<bool>("quiet");
1577 fIsHexOutput = conf.Get<bool>("hex-out");
1578 fIsDataOutput = conf.Get<bool>("data-out");
1579 fDebugTx = conf.Get<bool>("debug-tx");
1580
1581 SetMaxMemory(conf.Get<unsigned int>("max-mem"));
1582
1583 // vvvvv for debugging vvvvv
1584 if (conf.Has("debug-addr"))
1585 {
1586 const string addr = conf.Get<string>("debug-addr");
1587 const int num = conf.Get<unsigned int>("debug-num");
1588
1589 const tcp::endpoint endpoint = GetEndpoint(addr);
1590 if (endpoint==tcp::endpoint())
1591 return false;
1592
1593 for (int i=0; i<num; i++)
1594 AddEndpoint(tcp::endpoint(endpoint.address(), endpoint.port()+8*i));
1595
1596 StartConnection();
1597 return true;
1598 }
1599 // ^^^^^ for debugging ^^^^^
1600
1601 if (!(conf.Has("base-addr") ^ conf.Has("addr")))
1602 {
1603 T::Out() << kRed << "SetConfiguration - Only --base-addr or --addr allowed." << endl;
1604 return false;
1605 }
1606
1607 if (conf.Has("base-addr"))
1608 {
1609 string base = conf.Get<string>("base-addr");
1610
1611 if (base=="def" || base =="default")
1612 base = "10.0.128.128:31919";
1613
1614 const tcp::endpoint endpoint = GetEndpoint(base);
1615 if (endpoint==tcp::endpoint())
1616 return false;
1617
1618 const ba::ip::address_v4::bytes_type ip = endpoint.address().to_v4().to_bytes();
1619
1620 if (ip[2]>250 || ip[3]>244)
1621 {
1622 T::Out() << kRed << "SetConfiguration - IP address given by --base-addr out-of-range." << endl;
1623 return false;
1624 }
1625
1626 for (int crate=0; crate<4; crate++)
1627 for (int board=0; board<10; board++)
1628 {
1629 ba::ip::address_v4::bytes_type target = endpoint.address().to_v4().to_bytes();
1630 target[2] += crate;
1631 target[3] += board;
1632
1633 AddEndpoint(tcp::endpoint(ba::ip::address_v4(target), endpoint.port()));
1634 }
1635 }
1636
1637 if (conf.Has("addr"))
1638 {
1639 const vector<string> addrs = conf.Get<vector<string>>("addr");
1640 for (vector<string>::const_iterator i=addrs.begin(); i<addrs.end(); i++)
1641 {
1642 const tcp::endpoint endpoint = GetEndpoint(*i);
1643 if (endpoint==tcp::endpoint())
1644 return false;
1645
1646 AddEndpoint(endpoint);
1647 }
1648 }
1649
1650 StartConnection();
1651
1652 return true;
1653 }
1654
1655};
1656
1657// ------------------------------------------------------------------------
1658
1659
1660void RunThread(StateMachineImp *io_service)
1661{
1662 // This is necessary so that the StateMachien Thread can signal the
1663 // Readline to exit
1664 io_service->Run();
1665 Readline::Stop();
1666}
1667
1668/*
1669template<class S>
1670int RunDim(Configuration &conf)
1671{
1672 WindowLog wout;
1673
1674 ReadlineColor::PrintBootMsg(wout, conf.GetName(), false);
1675
1676 if (conf.Has("log"))
1677 if (!wout.OpenLogFile(conf.Get<string>("log")))
1678 wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
1679
1680 // Start io_service.Run to use the StateMachineImp::Run() loop
1681 // Start io_service.run to only use the commandHandler command detaching
1682 StateMachineFAD<S> io_service(wout);
1683 if (!io_service.SetConfiguration(conf))
1684 return -1;
1685
1686 io_service.Run();
1687
1688 return 0;
1689}
1690*/
1691
1692template<class T, class S>
1693int RunShell(Configuration &conf)
1694{
1695 static T shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
1696
1697 WindowLog &win = shell.GetStreamIn();
1698 WindowLog &wout = shell.GetStreamOut();
1699
1700 if (conf.Has("log"))
1701 if (!wout.OpenLogFile(conf.Get<string>("log")))
1702 win << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
1703
1704 StateMachineFAD<S> io_service(wout);
1705 if (!io_service.SetConfiguration(conf))
1706 return -1;
1707
1708 shell.SetReceiver(io_service);
1709
1710 boost::thread t(boost::bind(RunThread, &io_service));
1711 //boost::thread t(boost::bind(&StateMachineFAD<S>::Run, &io_service));
1712
1713 if (conf.Has("exec"))
1714 {
1715 const vector<string> v = conf.Get<vector<string>>("exec");
1716 for (vector<string>::const_iterator it=v.begin(); it!=v.end(); it++)
1717 shell.Execute(*it);
1718 }
1719
1720 shell.Run(); // Run the shell
1721 io_service.Stop(); // Signal Loop-thread to stop
1722
1723 // Wait until the StateMachine has finished its thread
1724 // before returning and destroying the dim objects which might
1725 // still be in use.
1726 t.join();
1727
1728 return 0;
1729}
1730
1731void SetupConfiguration(Configuration &conf)
1732{
1733 const string n = conf.GetName()+".log";
1734
1735 po::options_description config("Program options");
1736 config.add_options()
1737 ("dns", var<string>("localhost"), "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
1738 ("log,l", var<string>(n), "Write log-file")
1739 ("no-dim,d", po_switch(), "Disable dim services")
1740 ("console,c", var<int>(), "Use console (0=shell, 1=simple buffered, X=simple unbuffered)")
1741 ("exec,e", vars<string>(), "Execute one or more scrips at startup")
1742 ;
1743
1744 po::options_description control("FAD control options");
1745 control.add_options()
1746 ("quiet,q", po_bool(), "Disable printing contents of all received messages in clear text.")
1747 ("hex-out", po_bool(), "Enable printing contents of all printed messages also as hex data.")
1748 ("data-out", po_bool(), "Enable printing received event data.")
1749 ("debug-tx", po_bool(), "Enable debugging of ethernet transmission.")
1750 ;
1751
1752 po::options_description builder("Event builder options");
1753 builder.add_options()
1754 ("max-mem,m", var<unsigned int>(100), "Maximum memory the event builder thread is allowed to consume for its event buffer")
1755 ;
1756
1757 po::options_description connect("FAD connection options");
1758 connect.add_options()
1759 ("addr", vars<string>(), "Network address of FAD")
1760 ("base-addr", var<string>(), "Base address of all FAD")
1761 ("debug-num,n", var<unsigned int>(40), "Sets the number of fake boards to be connected locally")
1762 ("debug-addr", var<string>(), "")
1763 ;
1764
1765 conf.AddEnv("dns", "DIM_DNS_NODE");
1766
1767 conf.AddOptions(config);
1768 conf.AddOptions(control);
1769 conf.AddOptions(builder);
1770 conf.AddOptions(connect);
1771}
1772
1773void PrintUsage()
1774{
1775 cout <<
1776 "The fadctrl controls the FAD boards.\n"
1777 "\n"
1778 "The default is that the program is started without user intercation. "
1779 "All actions are supposed to arrive as DimCommands. Using the -c "
1780 "option, a local shell can be initialized. With h or help a short "
1781 "help message about the usuage can be brought to the screen.\n"
1782 "\n"
1783 "Usage: fadctrl [-c type] [OPTIONS]\n"
1784 " or: fadctrl [OPTIONS]\n";
1785 cout << endl;
1786}
1787
1788void PrintHelp()
1789{
1790 /* Additional help text which is printed after the configuration
1791 options goes here */
1792}
1793
1794int main(int argc, const char* argv[])
1795{
1796 Configuration conf(argv[0]);
1797 conf.SetPrintUsage(PrintUsage);
1798 SetupConfiguration(conf);
1799
1800 po::variables_map vm;
1801 try
1802 {
1803 vm = conf.Parse(argc, argv);
1804 }
1805#if BOOST_VERSION > 104000
1806 catch (po::multiple_occurrences &e)
1807 {
1808 cerr << "Program options invalid due to: " << e.what() << " of '" << e.get_option_name() << "'." << endl;
1809 return -1;
1810 }
1811#endif
1812 catch (exception& e)
1813 {
1814 cerr << "Program options invalid due to: " << e.what() << endl;
1815 return -1;
1816 }
1817
1818 if (conf.HasVersion() || conf.HasPrint())
1819 return -1;
1820
1821 if (conf.HasHelp())
1822 {
1823 PrintHelp();
1824 return -1;
1825 }
1826
1827 Dim::Setup(conf.Get<string>("dns"));
1828
1829// try
1830 {
1831 // No console access at all
1832 if (!conf.Has("console"))
1833 {
1834 if (conf.Get<bool>("no-dim"))
1835 return RunShell<LocalStream, StateMachine>(conf);
1836 else
1837 return RunShell<LocalStream, StateMachineDim>(conf);
1838 }
1839 // Cosole access w/ and w/o Dim
1840 if (conf.Get<bool>("no-dim"))
1841 {
1842 if (conf.Get<int>("console")==0)
1843 return RunShell<LocalShell, StateMachine>(conf);
1844 else
1845 return RunShell<LocalConsole, StateMachine>(conf);
1846 }
1847 else
1848 {
1849 if (conf.Get<int>("console")==0)
1850 return RunShell<LocalShell, StateMachineDim>(conf);
1851 else
1852 return RunShell<LocalConsole, StateMachineDim>(conf);
1853 }
1854 }
1855/* catch (std::exception& e)
1856 {
1857 cerr << "Exception: " << e.what() << endl;
1858 return -1;
1859 }*/
1860
1861 return 0;
1862}
Note: See TracBrowser for help on using the repository browser.