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

Last change on this file since 11257 was 11257, checked in by tbretz, 13 years ago
Removed the --no-dim option, because it won't work anyway at the moment.
File size: 57.5 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 SetFileFormat(const EventImp &evt)
809 {
810 if (!CheckEventSize(evt.GetSize(), "SetFileFormat", 2))
811 return T::kSM_FatalError;
812
813 const uint16_t fmt = evt.GetUShort();
814
815 switch (fmt)
816 {
817 case 0: SetOutputFormat(kNone); break;
818 case 1: SetOutputFormat(kDebug); break;
819 case 2: SetOutputFormat(kFits); break;
820 case 3: SetOutputFormat(kRaw); break;
821 default:
822 T::Error("File format unknonw.");
823 return false;
824 }
825
826 return T::GetCurrentState();
827 }
828
829 int Test(const EventImp &evt)
830 {
831 if (!CheckEventSize(evt.GetSize(), "Test", 2))
832 return T::kSM_FatalError;
833
834
835 SetMode(evt.GetShort());
836
837 return T::GetCurrentState();
838 }
839
840
841 int SetVerbosity(const EventImp &evt)
842 {
843 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
844 return T::kSM_FatalError;
845
846 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
847 i->second->SetVerbose(evt.GetBool());
848
849 return T::GetCurrentState();
850 }
851
852 int SetHexOutput(const EventImp &evt)
853 {
854 if (!CheckEventSize(evt.GetSize(), "SetHexOutput", 1))
855 return T::kSM_FatalError;
856
857 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
858 i->second->SetHexOutput(evt.GetBool());
859
860 return T::GetCurrentState();
861 }
862
863 int SetDataOutput(const EventImp &evt)
864 {
865 if (!CheckEventSize(evt.GetSize(), "SetDataOutput", 1))
866 return T::kSM_FatalError;
867
868 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
869 i->second->SetDataOutput(evt.GetBool());
870
871 return T::GetCurrentState();
872 }
873
874 int SetDebugTx(const EventImp &evt)
875 {
876 if (!CheckEventSize(evt.GetSize(), "SetDebugTx", 1))
877 return T::kSM_FatalError;
878
879 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
880 i->second->SetDebugTx(evt.GetBool());
881
882 return T::GetCurrentState();
883 }
884
885 const BoardList::iterator GetSlot(uint16_t slot)
886 {
887 const BoardList::iterator it=fBoards.find(slot);
888 if (it==fBoards.end())
889 {
890 ostringstream str;
891 str << "Slot " << slot << " not found.";
892 T::Warn(str);
893 }
894
895 return it;
896 }
897
898 int PrintEvent(const EventImp &evt)
899 {
900 if (!CheckEventSize(evt.GetSize(), "PrintEvent", 2))
901 return T::kSM_FatalError;
902
903 const int16_t slot = evt.Get<int16_t>();
904
905 if (slot<0)
906 {
907 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
908 i->second->PrintEvent();
909 }
910 else
911 {
912 const BoardList::iterator it=GetSlot(slot);
913 if (it!=fBoards.end())
914 it->second->PrintEvent();
915 }
916
917 return T::GetCurrentState();
918 }
919
920 int SetBlockTransmission(const EventImp &evt)
921 {
922 if (!CheckEventSize(evt.GetSize(), "SetBlockTransmission", 3))
923 return T::kSM_FatalError;
924
925 const int16_t slot = evt.Get<int32_t>();
926
927 const BoardList::iterator it=GetSlot(slot);
928 if (it!=fBoards.end())
929 it->second->SetBlockTransmission(evt.Get<uint8_t>(2));
930
931 return T::GetCurrentState();
932 }
933
934 int SetBlockTransmissionRange(const EventImp &evt)
935 {
936 if (!CheckEventSize(evt.GetSize(), "SetBlockTransmissionRange", 5))
937 return T::kSM_FatalError;
938
939 const int16_t *slot = evt.Ptr<int16_t>();
940 const bool block = evt.Get<uint8_t>(4);
941
942 for (int i=slot[0]; i<=slot[1]; i++)
943 {
944 const BoardList::iterator it=GetSlot(i);
945 if (it!=fBoards.end())
946 it->second->SetBlockTransmission(block);
947 }
948
949 return T::GetCurrentState();
950 }
951
952 int SetIgnoreSlot(const EventImp &evt)
953 {
954 if (!CheckEventSize(evt.GetSize(), "SetIgnoreSlot", 3))
955 return T::kSM_FatalError;
956
957 const uint16_t slot = evt.Get<uint16_t>();
958
959 if (slot>39)
960 {
961 T::Warn("Slot out of range (0-39).");
962 return T::GetCurrentState();
963 }
964
965 SetIgnore(slot, evt.Get<uint8_t>(2));
966
967 return T::GetCurrentState();
968 }
969
970 int SetIgnoreSlots(const EventImp &evt)
971 {
972 if (!CheckEventSize(evt.GetSize(), "SetIgnoreSlots", 5))
973 return T::kSM_FatalError;
974
975 const int16_t *slot = evt.Ptr<int16_t>();
976 const bool block = evt.Get<uint8_t>(4);
977
978 if (slot[0]<0 || slot[1]>39 || slot[0]>slot[1])
979 {
980 T::Warn("Slot out of range.");
981 return T::GetCurrentState();
982 }
983
984 for (int i=slot[0]; i<=slot[1]; i++)
985 SetIgnore(i, block);
986
987 return T::GetCurrentState();
988 }
989
990 int SetDumpStream(const EventImp &evt)
991 {
992 if (!CheckEventSize(evt.GetSize(), "SetDumpStream", 1))
993 return T::kSM_FatalError;
994
995 SetDebugStream(evt.Get<uint8_t>());
996
997 return T::GetCurrentState();
998 }
999
1000 int SetDumpRecv(const EventImp &evt)
1001 {
1002 if (!CheckEventSize(evt.GetSize(), "SetDumpRecv", 1))
1003 return T::kSM_FatalError;
1004
1005 SetDebugRead(evt.Get<uint8_t>());
1006
1007 return T::GetCurrentState();
1008 }
1009
1010 int AddAddress(const EventImp &evt)
1011 {
1012 const string addr = Tools::Trim(evt.GetText());
1013
1014 const tcp::endpoint endpoint = GetEndpoint(addr);
1015 if (endpoint==tcp::endpoint())
1016 return T::GetCurrentState();
1017
1018 for (BoardList::const_iterator i=fBoards.begin(); i!=fBoards.end(); i++)
1019 {
1020 if (i->second->GetEndpoint()==endpoint)
1021 {
1022 T::Warn("Address "+addr+" already known.... ignored.");
1023 return T::GetCurrentState();
1024 }
1025 }
1026
1027 AddEndpoint(endpoint);
1028
1029 return T::GetCurrentState();
1030 }
1031
1032 int RemoveSlot(const EventImp &evt)
1033 {
1034 if (!CheckEventSize(evt.GetSize(), "RemoveSlot", 2))
1035 return T::kSM_FatalError;
1036
1037 const int16_t slot = evt.GetShort();
1038
1039 const BoardList::iterator it = GetSlot(slot);
1040
1041 if (it==fBoards.end())
1042 return T::GetCurrentState();
1043
1044 ConnectSlot(slot, tcp::endpoint());
1045
1046 delete it->second;
1047 fBoards.erase(it);
1048
1049 return T::GetCurrentState();
1050 }
1051
1052 int ListSlots()
1053 {
1054 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
1055 {
1056 const int &idx = i->first;
1057 const ConnectionFAD *fad = i->second;
1058
1059 ostringstream str;
1060 str << "Slot " << setw(2) << idx << ": " << fad->GetEndpoint();
1061
1062 if (fad->IsConnecting())
1063 str << " (0:connecting, ";
1064 else
1065 {
1066 if (fad->IsClosed())
1067 str << " (0:disconnected, ";
1068 if (fad->IsConnected())
1069 str << " (0:connected, ";
1070 }
1071
1072 switch (fStatus2[idx])
1073 {
1074 case 0: str << "1-7:not connected)"; break;
1075 case 8: str << "1-7:connected)"; break;
1076 default: str << "1-7:connecting [" << (int)(fStatus2[idx]-1) << "])"; break;
1077 }
1078
1079 if (fad->IsTransmissionBlocked())
1080 str << " [cmd_blocked]";
1081
1082 if (fStatus2[idx]==8 && IsIgnored(idx))
1083 str << " [data_ignored]";
1084
1085 T::Out() << str.str() << endl;
1086 }
1087
1088 T::Out() << "Event builder thread:";
1089 if (!IsThreadRunning())
1090 T::Out() << " not";
1091 T::Out() << " running" << endl;
1092
1093 // FIXME: Output state
1094
1095 return T::GetCurrentState();
1096 }
1097
1098 void EnableConnection(ConnectionFAD *ptr, bool enable=true)
1099 {
1100 if (!enable)
1101 {
1102 ptr->PostClose(false);
1103 return;
1104 }
1105
1106 if (!ptr->IsDisconnected())
1107 {
1108 ostringstream str;
1109 str << ptr->GetEndpoint();
1110
1111 T::Warn("Connection to "+str.str()+" already in progress.");
1112 return;
1113 }
1114
1115 ptr->StartConnect();
1116 }
1117
1118 void EnableAll(bool enable=true)
1119 {
1120 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
1121 EnableConnection(i->second, enable);
1122 }
1123
1124 int CloseOpenFiles()
1125 {
1126 EventBuilderWrapper::CloseOpenFiles();
1127 return T::GetCurrentState();
1128 }
1129
1130 int EnableSlot(const EventImp &evt, bool enable)
1131 {
1132 if (!CheckEventSize(evt.GetSize(), "EnableSlot", 2))
1133 return T::kSM_FatalError;
1134
1135 const int16_t slot = evt.GetShort();
1136
1137 const BoardList::iterator it = GetSlot(slot);
1138 if (it==fBoards.end())
1139 return T::GetCurrentState();
1140
1141 EnableConnection(it->second, enable);
1142 ConnectSlot(it->first, enable ? it->second->GetEndpoint() : tcp::endpoint());
1143
1144 return T::GetCurrentState();
1145 }
1146
1147 int ToggleSlot(const EventImp &evt)
1148 {
1149 if (!CheckEventSize(evt.GetSize(), "ToggleSlot", 2))
1150 return T::kSM_FatalError;
1151
1152 const int16_t slot = evt.GetShort();
1153
1154 const BoardList::iterator it = GetSlot(slot);
1155 if (it==fBoards.end())
1156 return T::GetCurrentState();
1157
1158 const bool enable = it->second->IsDisconnected();
1159
1160 EnableConnection(it->second, enable);
1161 ConnectSlot(it->first, enable ? it->second->GetEndpoint() : tcp::endpoint());
1162
1163 return T::GetCurrentState();
1164 }
1165
1166 int StartConnection()
1167 {
1168 vector<tcp::endpoint> addr(40);
1169
1170 for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++)
1171 addr[i->first] = i->second->GetEndpoint();
1172
1173 StartThread(addr);
1174 EnableAll(true);
1175
1176 return T::GetCurrentState();
1177 }
1178
1179 int StopConnection()
1180 {
1181 Exit();
1182 EnableAll(false);
1183 return T::GetCurrentState();
1184 }
1185
1186 int AbortConnection()
1187 {
1188 Abort();
1189 EnableAll(false);
1190 return T::GetCurrentState();
1191 }
1192
1193 vector<uint8_t> fStatus1;
1194 vector<uint8_t> fStatus2;
1195 bool fStatusT;
1196
1197 int Execute()
1198 {
1199 // Dispatch (execute) at most one handler from the queue. In contrary
1200 // to run_one(), it doesn't wait until a handler is available
1201 // which can be dispatched, so poll_one() might return with 0
1202 // handlers dispatched. The handlers are always dispatched/executed
1203 // synchronously, i.e. within the call to poll_one()
1204 poll_one();
1205
1206 // ===== Evaluate connection status =====
1207
1208 uint16_t nclosed1 = 0;
1209 uint16_t nconnecting1 = 0;
1210 uint16_t nconnecting2 = 0;
1211 uint16_t nconnected1 = 0;
1212 uint16_t nconnected2 = 0;
1213
1214 vector<uint8_t> stat1(40);
1215 vector<uint8_t> stat2(40);
1216
1217 int cnt = 0; // counter for enabled board
1218
1219 const bool runs = IsThreadRunning();
1220
1221 for (int idx=0; idx<40; idx++)
1222 {
1223 // ----- Command socket -----
1224 const BoardList::const_iterator &slot = fBoards.find(idx);
1225 if (slot!=fBoards.end())
1226 {
1227 const ConnectionFAD *c = slot->second;
1228 if (c->IsDisconnected())
1229 {
1230 stat1[idx] = 0;
1231 nclosed1++;
1232
1233 //DisconnectSlot(idx);
1234 }
1235 if (c->IsConnecting())
1236 {
1237 stat1[idx] = 1;
1238 nconnecting1++;
1239 }
1240 if (c->IsConnected())
1241 {
1242 stat1[idx] = 2;
1243 nconnected1++;
1244 }
1245
1246 cnt++;
1247 }
1248
1249 // ----- Event builder -----
1250
1251 if (!runs)
1252 continue;
1253
1254 stat2[idx] = GetNumConnected(idx);
1255
1256 if (IsConnecting(idx))
1257 {
1258 nconnecting2++;
1259 stat2[idx]++;
1260 }
1261
1262 if (IsConnected(idx))
1263 {
1264 stat2[idx]++;
1265 nconnected2++;
1266 }
1267 }
1268
1269 // ===== Send connection status via dim =====
1270
1271 if (fStatus1!=stat1 || fStatus2!=stat2 || fStatusT!=IsThreadRunning())
1272 {
1273 fStatus1 = stat1;
1274 fStatus2 = stat2;
1275 fStatusT = runs;
1276 UpdateConnectionStatus(stat1, stat2, IsThreadRunning());
1277 }
1278
1279 // ===== Return connection status =====
1280
1281 // fadctrl: Always connecting if not disabled
1282 // event builder:
1283 if (nconnecting1==0 && nconnected1>0 &&
1284 nconnected2==nconnected1)
1285 return FAD::kConnected;
1286
1287 if (nconnecting1>0 || nconnecting2>0 || nconnected1!=nconnected2)
1288 return FAD::kConnecting;
1289
1290 // nconnected1 == nconnected2 == 0
1291 return IsThreadRunning() ? FAD::kDisconnected : FAD::kOffline;
1292 }
1293
1294 void AddEndpoint(const tcp::endpoint &addr)
1295 {
1296 int i=0;
1297 while (i<40)
1298 {
1299 if (fBoards.find(i)==fBoards.end())
1300 break;
1301 i++;
1302 }
1303
1304 if (i==40)
1305 {
1306 T::Warn("Not more than 40 slots allowed.");
1307 return;
1308 }
1309
1310 ConnectionFAD *fad = new ConnectionFAD(*this, *this, i);
1311
1312 fad->SetEndpoint(addr);
1313 fad->SetVerbose(fIsVerbose);
1314 fad->SetHexOutput(fIsHexOutput);
1315 fad->SetDataOutput(fIsDataOutput);
1316 fad->SetDebugTx(fDebugTx);
1317
1318 fBoards[i] = fad;
1319 }
1320
1321
1322 DimDescribedService fDimConnection;
1323
1324 void UpdateConnectionStatus(const vector<uint8_t> &stat1, const vector<uint8_t> &stat2, bool thread)
1325 {
1326 vector<uint8_t> stat(41);
1327
1328 for (int i=0; i<40; i++)
1329 stat[i] = stat1[i]|(stat2[i]<<3);
1330
1331 stat[40] = thread;
1332
1333 fDimConnection.setData(stat.data(), 41);
1334 fDimConnection.updateService();
1335 }
1336
1337public:
1338 StateMachineFAD(ostream &out=cout) :
1339 T(out, "FAD_CONTROL"), EventBuilderWrapper(*static_cast<MessageImp*>(this)), ba::io_service::work(static_cast<ba::io_service&>(*this)),
1340 fStatus1(40), fStatus2(40), fStatusT(false),
1341 fDimConnection("FAD_CONTROL/CONNECTIONS", "C:40;C:1", "")
1342 {
1343 // ba::io_service::work is a kind of keep_alive for the loop.
1344 // It prevents the io_service to go to stopped state, which
1345 // would prevent any consecutive calls to run()
1346 // or poll() to do nothing. reset() could also revoke to the
1347 // previous state but this might introduce some overhead of
1348 // deletion and creation of threads and more.
1349
1350 // State names
1351 T::AddStateName(FAD::kOffline, "Disengaged",
1352 "All enabled FAD boards are disconnected and the event-builer thread is not running.");
1353
1354 T::AddStateName(FAD::kDisconnected, "Disconnected",
1355 "All enabled FAD boards are disconnected, but the event-builder thread is running.");
1356
1357 T::AddStateName(FAD::kConnecting, "Connecting",
1358 "Only some enabled FAD boards are connected.");
1359
1360 T::AddStateName(FAD::kConnected, "Connected",
1361 "All enabled FAD boards are connected..");
1362
1363 // FAD Commands
1364 T::AddEvent("SEND_CMD", "I:1")
1365 (boost::bind(&StateMachineFAD::SendCmd, this, _1))
1366 ("Send a command to the FADs. Values between 0 and 0xffff are allowed."
1367 "|command[uint16]:Command to be transmittted.");
1368 T::AddEvent("SEND_DATA", "I:2")
1369 (boost::bind(&StateMachineFAD::SendCmdData, this, _1))
1370 ("Send a command with data to the FADs. Values between 0 and 0xffff are allowed."
1371 "|command[uint16]:Command to be transmittted."
1372 "|data[uint16]:Data to be sent with the command.");
1373
1374 T::AddEvent("ENABLE_SRCLK", "B:1")
1375 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdSrclk))
1376 ("Set SRCLK");
1377 T::AddEvent("ENABLE_BUSY", "B:1")
1378 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdBusy))
1379 ("Set BUSY");
1380 T::AddEvent("ENABLE_SCLK", "B:1")
1381 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdSclk))
1382 ("Set SCLK");
1383 T::AddEvent("ENABLE_DRS", "B:1")
1384 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdDrsEnable))
1385 ("Switch Domino wave");
1386 T::AddEvent("ENABLE_DWRITE", "B:1")
1387 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdDwrite))
1388 ("Set Dwrite (possibly high / always low)");
1389 T::AddEvent("ENABLE_CONTINOUS_TRIGGER", "B:1")
1390 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdContTrigger))
1391 ("Enable continous (internal) trigger.");
1392 T::AddEvent("ENABLE_TRIGGER_LINE", "B:1")
1393 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdTriggerLine))
1394 ("Incoming triggers can be accepted/will not be accepted");
1395 T::AddEvent("SET_DEBUG_MODE", "B:1")
1396 (boost::bind(&StateMachineFAD::CmdEnable, this, _1, FAD::kCmdSocket))
1397 ("Set debug mode (yes: dump events through command socket, no=dump events through other sockets)");
1398
1399 T::AddEvent("SET_TRIGGER_RATE", "I:1")
1400 (boost::bind(&StateMachineFAD::SetTriggerRate, this, _1))
1401 ("Enable continous trigger");
1402 T::AddEvent("SEND_SINGLE_TRIGGER")
1403 (boost::bind(&StateMachineFAD::Trigger, this, 1))
1404 ("Issue software triggers");
1405 T::AddEvent("SEND_N_TRIGGERS", "I")
1406 (boost::bind(&StateMachineFAD::SendTriggers, this, _1))
1407 ("Issue software triggers");
1408 T::AddEvent("START_RUN", "")
1409 (boost::bind(&StateMachineFAD::StartRun, this, _1, true))
1410 ("Set FAD DAQ mode. when started, no configurations must be send.");
1411 T::AddEvent("STOP_RUN")
1412 (boost::bind(&StateMachineFAD::StartRun, this, _1, false))
1413 ("");
1414 T::AddEvent("PHASE_SHIFT", "S:1")
1415 (boost::bind(&StateMachineFAD::PhaseShift, this, _1))
1416 ("Adjust ADC phase (in 'steps')");
1417
1418 T::AddEvent("RESET_TRIGGER_ID")
1419 (boost::bind(&StateMachineFAD::Cmd, this, FAD::kCmdResetTriggerId))
1420 ("");
1421
1422 T::AddEvent("SET_RUN_NUMBER", "X:1")
1423 (boost::bind(&StateMachineFAD::SetRunNumber, this, _1))
1424 ("");
1425
1426 T::AddEvent("SET_MAX_MEMORY", "S:1")
1427 (boost::bind(&StateMachineFAD::SetMaxMemoryBuffer, this, _1))
1428 ("Set maximum memory buffer size allowed to be consumed by the EventBuilder to buffer events."
1429 "|memory[short]:Buffer size in Mega-bytes.");
1430
1431 T::AddEvent("SET_REGISTER", "I:2")
1432 (boost::bind(&StateMachineFAD::SetRegister, this, _1))
1433 ("set register to value"
1434 "|addr[short]:Address of register"
1435 "|val[short]:Value to be set");
1436
1437 // FIXME: Maybe add a mask which channels should be set?
1438 T::AddEvent("SET_REGION_OF_INTEREST", "I:2")
1439 (boost::bind(&StateMachineFAD::SetRoi, this, _1))
1440 ("Set region-of-interest to value"
1441 "|addr[short]:Address of register"
1442 "|val[short]:Value to be set");
1443
1444 // FIXME: Maybe add a mask which channels should be set?
1445 T::AddEvent("SET_DAC_VALUE", "I:2")
1446 (boost::bind(&StateMachineFAD::SetDac, this, _1))
1447 ("Set DAC numbers in range to value"
1448 "|addr[short]:Address of register"
1449 "|val[short]:Value to be set");
1450
1451 // Verbosity commands
1452 T::AddEvent("SET_VERBOSE", "B:1")
1453 (boost::bind(&StateMachineFAD::SetVerbosity, this, _1))
1454 ("Set verbosity state"
1455 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
1456
1457 T::AddEvent("SET_HEX_OUTPUT", "B:1")
1458 (boost::bind(&StateMachineFAD::SetHexOutput, this, _1))
1459 ("Enable or disable hex output for received data"
1460 "|hexout[bool]:disable or enable hex output for received data (yes/no)");
1461
1462 T::AddEvent("SET_DATA_OUTPUT", "B:1")
1463 (boost::bind(&StateMachineFAD::SetDataOutput, this, _1))
1464 ("");
1465
1466 T::AddEvent("SET_DEBUG_TX", "B:1")
1467 (boost::bind(&StateMachineFAD::SetDebugTx, this, _1))
1468 ("Enable or disable the output of messages in case of successfull data transmission to the boards."
1469 "|debug[bool]:disable or enable debug output for transmitted data (yes/no)");
1470
1471 T::AddEvent("PRINT_EVENT", "S:1")
1472 (boost::bind(&StateMachineFAD::PrintEvent, this, _1))
1473 ("Print (last) event"
1474 "|board[short]:slot from which the event should be printed (-1 for all)");
1475
1476 T::AddEvent("DUMP_STREAM", "B:1")
1477 (boost::bind(&StateMachineFAD::SetDumpStream, this, _1))
1478 ("For debugging purpose: the binary data stream read from the sockets 0-7 can be dumped to files."
1479 "|switch[bool]:Enable (yes) or disable (no)");
1480
1481 T::AddEvent("DUMP_RECV", "B:1")
1482 (boost::bind(&StateMachineFAD::SetDumpRecv, this, _1))
1483 ("For debugging purpose: the times when data has been receives are dumped to a file."
1484 "|switch[bool]:Enable (yes) or disable (no)");
1485
1486 T::AddEvent("BLOCK_TRANSMISSION", "S:1;B:1")
1487 (boost::bind(&StateMachineFAD::SetBlockTransmission, this, _1))
1488 ("Blocks the transmission of commands to the given slot. Use with care! For debugging pupose only!"
1489 "|slot[short]:Slot to which the command transmission should be blocked (0-39)"
1490 "|enable[bool]:Whether the command transmission should be blockes (yes) or allowed (no)");
1491
1492 T::AddEvent("BLOCK_TRANSMISSION_RANGE", "S:2;B:1")
1493 (boost::bind(&StateMachineFAD::SetBlockTransmissionRange, this, _1))
1494 ("Blocks the transmission of commands to the given range of slots. Use with care! For debugging pupose only!"
1495 "|first[short]:First slot to which the command transmission should be blocked (0-39)"
1496 "|last[short]:Last slot to which the command transmission should be blocked (0-39)"
1497 "|enable[bool]:Whether the command transmission should be blockes (yes) or allowed (no)");
1498
1499 T::AddEvent("IGNORE_EVENTS", "S:1;B:1")
1500 (boost::bind(&StateMachineFAD::SetIgnoreSlot, this, _1))
1501 ("Instructs the event-builder to ignore events from the given slot but still read the data from the socket."
1502 "|slot[short]:Slot from which the data should be ignored when building events"
1503 "|enable[bool]:Whether the event builder should ignore data from this slot (yes) or allowed (no)");
1504
1505 T::AddEvent("IGNORE_EVENTS_RANGE", "S:2;B:1")
1506 (boost::bind(&StateMachineFAD::SetIgnoreSlots, this, _1))
1507 ("Instructs the event-builder to ignore events from the given slot but still read the data from the socket."
1508 "|first[short]:First slot from which the data should be ignored when building events"
1509 "|last[short]:Last slot from which the data should be ignored when building events"
1510 "|enable[bool]:Whether the event builder should ignore data from this slot (yes) or allowed (no)");
1511
1512 T::AddEvent("CLOSE_OPEN_FILES", FAD::kConnecting, FAD::kConnected)
1513 (boost::bind(&StateMachineFAD::CloseOpenFiles, this))
1514 ("Close all run files opened by the EventBuilder.");
1515
1516 T::AddEvent("TEST", "S:1")
1517 (boost::bind(&StateMachineFAD::Test, this, _1))
1518 ("");
1519
1520
1521
1522 // Conenction commands
1523 T::AddEvent("START", FAD::kOffline)
1524 (boost::bind(&StateMachineFAD::StartConnection, this))
1525 ("Start EventBuilder thread and connect all valid slots.");
1526
1527 T::AddEvent("STOP", FAD::kDisconnected, FAD::kConnecting, FAD::kConnected)
1528 (boost::bind(&StateMachineFAD::StopConnection, this))
1529 ("Stop EventBuilder thread (still write buffered events) and disconnect all slots.");
1530
1531 T::AddEvent("ABORT", FAD::kDisconnected, FAD::kConnecting, FAD::kConnected)
1532 (boost::bind(&StateMachineFAD::AbortConnection, this))
1533 ("Immediately abort EventBuilder thread and disconnect all slots.");
1534
1535 T::AddEvent("CONNECT", "S:1", FAD::kDisconnected, FAD::kConnecting, FAD::kConnected)
1536 (boost::bind(&StateMachineFAD::EnableSlot, this, _1, true))
1537 ("Connect a disconnected slot.");
1538
1539 T::AddEvent("DISCONNECT", "S:1", FAD::kConnecting, FAD::kConnected)
1540 (boost::bind(&StateMachineFAD::EnableSlot, this, _1, false))
1541 ("Disconnect a connected slot.");
1542
1543 T::AddEvent("TOGGLE", "S:1", FAD::kDisconnected, FAD::kConnecting, FAD::kConnected)
1544 (boost::bind(&StateMachineFAD::ToggleSlot, this, _1))
1545 ("");
1546
1547 T::AddEvent("SET_FILE_FORMAT", "S:1")
1548 (boost::bind(&StateMachineFAD::SetFileFormat, this, _1))
1549 ("");
1550
1551
1552 T::AddEvent("ADD_ADDRESS", "C", FAD::kOffline)
1553 (boost::bind(&StateMachineFAD::AddAddress, this, _1))
1554 ("Add the address of a DRS4 board to the first free slot"
1555 "|IP[string]:address in the format <address:port>");
1556 T::AddEvent("REMOVE_SLOT", "S:1", FAD::kOffline)
1557 (boost::bind(&StateMachineFAD::RemoveSlot, this, _1))
1558 ("Remove the Iaddress in slot n. For a list see LIST"
1559 "|slot[short]:Remove the address in slot n from the list");
1560 T::AddEvent("LIST_SLOTS")
1561 (boost::bind(&StateMachineFAD::ListSlots, this))
1562 ("Print a list of all available board addressesa and whether they are enabled");
1563 }
1564
1565 ~StateMachineFAD()
1566 {
1567 for (BoardList::const_iterator i=fBoards.begin(); i!=fBoards.end(); i++)
1568 delete i->second;
1569 fBoards.clear();
1570 }
1571
1572 tcp::endpoint GetEndpoint(const string &base)
1573 {
1574 const size_t p0 = base.find_first_of(':');
1575 const size_t p1 = base.find_last_of(':');
1576
1577 if (p0==string::npos || p0!=p1)
1578 {
1579 T::Out() << kRed << "GetEndpoint - Wrong format ('host:port' expected)" << endl;
1580 return tcp::endpoint();
1581 }
1582
1583 tcp::resolver resolver(get_io_service());
1584
1585 boost::system::error_code ec;
1586
1587 const tcp::resolver::query query(base.substr(0, p0), base.substr(p0+1));
1588 const tcp::resolver::iterator iterator = resolver.resolve(query, ec);
1589
1590 if (ec)
1591 {
1592 T::Out() << kRed << "GetEndpoint - Couldn't resolve endpoint '" << base << "': " << ec.message();
1593 return tcp::endpoint();
1594 }
1595
1596 return *iterator;
1597 }
1598
1599 int EvalConfiguration(const Configuration &conf)
1600 {
1601 fIsVerbose = !conf.Get<bool>("quiet");
1602 fIsHexOutput = conf.Get<bool>("hex-out");
1603 fIsDataOutput = conf.Get<bool>("data-out");
1604 fDebugTx = conf.Get<bool>("debug-tx");
1605
1606 SetMaxMemory(conf.Get<unsigned int>("max-mem"));
1607
1608 // vvvvv for debugging vvvvv
1609 if (conf.Has("debug-addr"))
1610 {
1611 const string addr = conf.Get<string>("debug-addr");
1612 const int num = conf.Get<unsigned int>("debug-num");
1613
1614 const tcp::endpoint endpoint = GetEndpoint(addr);
1615 if (endpoint==tcp::endpoint())
1616 return 1;
1617
1618 for (int i=0; i<num; i++)
1619 AddEndpoint(tcp::endpoint(endpoint.address(), endpoint.port()+8*i));
1620
1621 StartConnection();
1622 return -1;
1623 }
1624 // ^^^^^ for debugging ^^^^^
1625
1626 if (!(conf.Has("base-addr") ^ conf.Has("addr")))
1627 {
1628 T::Out() << kRed << "EvalConfiguration - Only --base-addr or --addr allowed." << endl;
1629 return 2;
1630 }
1631
1632 if (conf.Has("base-addr"))
1633 {
1634 string base = conf.Get<string>("base-addr");
1635
1636 if (base=="def" || base =="default")
1637 base = "10.0.128.128:31919";
1638
1639 const tcp::endpoint endpoint = GetEndpoint(base);
1640 if (endpoint==tcp::endpoint())
1641 return 1;
1642
1643 const ba::ip::address_v4::bytes_type ip = endpoint.address().to_v4().to_bytes();
1644
1645 if (ip[2]>250 || ip[3]>244)
1646 {
1647 T::Out() << kRed << "EvalConfiguration - IP address given by --base-addr out-of-range." << endl;
1648 return 3;
1649 }
1650
1651 for (int crate=0; crate<4; crate++)
1652 for (int board=0; board<10; board++)
1653 {
1654 ba::ip::address_v4::bytes_type target = endpoint.address().to_v4().to_bytes();
1655 target[2] += crate;
1656 target[3] += board;
1657
1658 AddEndpoint(tcp::endpoint(ba::ip::address_v4(target), endpoint.port()));
1659 }
1660 }
1661
1662 if (conf.Has("addr"))
1663 {
1664 const vector<string> addrs = conf.Get<vector<string>>("addr");
1665 for (vector<string>::const_iterator i=addrs.begin(); i<addrs.end(); i++)
1666 {
1667 const tcp::endpoint endpoint = GetEndpoint(*i);
1668 if (endpoint==tcp::endpoint())
1669 return 1;
1670
1671 AddEndpoint(endpoint);
1672 }
1673 }
1674
1675 StartConnection();
1676
1677 return -1;
1678 }
1679
1680};
1681
1682// ------------------------------------------------------------------------
1683
1684#include "Main.h"
1685
1686/*
1687void RunThread(StateMachineImp *io_service)
1688{
1689 // This is necessary so that the StateMachien Thread can signal the
1690 // Readline to exit
1691 io_service->Run();
1692 Readline::Stop();
1693}
1694*/
1695/*
1696template<class S>
1697int RunDim(Configuration &conf)
1698{
1699 WindowLog wout;
1700
1701 ReadlineColor::PrintBootMsg(wout, conf.GetName(), false);
1702
1703 if (conf.Has("log"))
1704 if (!wout.OpenLogFile(conf.Get<string>("log")))
1705 wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
1706
1707 // Start io_service.Run to use the StateMachineImp::Run() loop
1708 // Start io_service.run to only use the commandHandler command detaching
1709 StateMachineFAD<S> io_service(wout);
1710 if (!io_service.EvalConfiguration(conf))
1711 return -1;
1712
1713 io_service.Run();
1714
1715 return 0;
1716}
1717*/
1718
1719template<class T, class S>
1720int RunShell(Configuration &conf)
1721{
1722 return Main<T, StateMachineFAD<S>>(conf);
1723/*
1724 static T shell(conf.GetName().c_str(), conf.Get<int>("console")!=1);
1725
1726 WindowLog &win = shell.GetStreamIn();
1727 WindowLog &wout = shell.GetStreamOut();
1728
1729 if (conf.Has("log"))
1730 if (!wout.OpenLogFile(conf.Get<string>("log")))
1731 win << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl;
1732
1733 StateMachineFAD<S> io_service(wout);
1734 if (!io_service.EvalConfiguration(conf))
1735 return -1;
1736
1737 shell.SetReceiver(io_service);
1738
1739 boost::thread t(boost::bind(RunThread, &io_service));
1740 //boost::thread t(boost::bind(&StateMachineFAD<S>::Run, &io_service));
1741
1742 if (conf.Has("cmd"))
1743 {
1744 const vector<string> v = conf.Get<vector<string>>("cmd");
1745 for (vector<string>::const_iterator it=v.begin(); it!=v.end(); it++)
1746 shell.ProcessLine(*it);
1747 }
1748
1749 if (conf.Has("exec"))
1750 {
1751 const vector<string> v = conf.Get<vector<string>>("exec");
1752 for (vector<string>::const_iterator it=v.begin(); it!=v.end(); it++)
1753 shell.Execute(*it);
1754 }
1755
1756 if (conf.Get<bool>("quit"))
1757 shell.Stop();
1758
1759 shell.Run(); // Run the shell
1760 io_service.Stop(); // Signal Loop-thread to stop
1761
1762 // Wait until the StateMachine has finished its thread
1763 // before returning and destroying the dim objects which might
1764 // still be in use.
1765 t.join();
1766
1767 return 0;
1768 */
1769}
1770
1771void SetupConfiguration(Configuration &conf)
1772{
1773 const string n = conf.GetName()+".log";
1774
1775 po::options_description config("Program options");
1776 config.add_options()
1777 ("dns", var<string>("localhost"), "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)")
1778 ("log,l", var<string>(n), "Write log-file")
1779// ("no-dim,d", po_switch(), "Disable dim services")
1780 ("console,c", var<int>(), "Use console (0=shell, 1=simple buffered, X=simple unbuffered)")
1781 ("cmd", vars<string>(), "Execute one or more commands at startup")
1782 ("exec,e", vars<string>(), "Execute one or more scrips at startup")
1783 ("quit", po_switch(), "Quit after startup");
1784 ;
1785
1786 po::options_description control("FAD control options");
1787 control.add_options()
1788 ("quiet,q", po_bool(), "Disable printing contents of all received messages in clear text.")
1789 ("hex-out", po_bool(), "Enable printing contents of all printed messages also as hex data.")
1790 ("data-out", po_bool(), "Enable printing received event data.")
1791 ("debug-tx", po_bool(), "Enable debugging of ethernet transmission.")
1792 ;
1793
1794 po::options_description builder("Event builder options");
1795 builder.add_options()
1796 ("max-mem,m", var<unsigned int>(100), "Maximum memory the event builder thread is allowed to consume for its event buffer")
1797 ;
1798
1799 po::options_description connect("FAD connection options");
1800 connect.add_options()
1801 ("addr", vars<string>(), "Network address of FAD")
1802 ("base-addr", var<string>(), "Base address of all FAD")
1803 ("debug-num,n", var<unsigned int>(40), "Sets the number of fake boards to be connected locally")
1804 ("debug-addr", var<string>(), "")
1805 ;
1806
1807 conf.AddEnv("dns", "DIM_DNS_NODE");
1808
1809 conf.AddOptions(config);
1810 conf.AddOptions(control);
1811 conf.AddOptions(builder);
1812 conf.AddOptions(connect);
1813}
1814
1815void PrintUsage()
1816{
1817 cout <<
1818 "The fadctrl controls the FAD boards.\n"
1819 "\n"
1820 "The default is that the program is started without user intercation. "
1821 "All actions are supposed to arrive as DimCommands. Using the -c "
1822 "option, a local shell can be initialized. With h or help a short "
1823 "help message about the usuage can be brought to the screen.\n"
1824 "\n"
1825 "Usage: fadctrl [-c type] [OPTIONS]\n"
1826 " or: fadctrl [OPTIONS]\n";
1827 cout << endl;
1828}
1829
1830void PrintHelp()
1831{
1832 /* Additional help text which is printed after the configuration
1833 options goes here */
1834}
1835
1836int main(int argc, const char* argv[])
1837{
1838 Configuration conf(argv[0]);
1839 conf.SetPrintUsage(PrintUsage);
1840 SetupConfiguration(conf);
1841
1842 po::variables_map vm;
1843 try
1844 {
1845 vm = conf.Parse(argc, argv);
1846 }
1847#if BOOST_VERSION > 104000
1848 catch (po::multiple_occurrences &e)
1849 {
1850 cerr << "Program options invalid due to: " << e.what() << " of '" << e.get_option_name() << "'." << endl;
1851 return -1;
1852 }
1853#endif
1854 catch (exception& e)
1855 {
1856 cerr << "Program options invalid due to: " << e.what() << endl;
1857 return -1;
1858 }
1859
1860 if (conf.HasVersion() || conf.HasPrint())
1861 return -1;
1862
1863 if (conf.HasHelp())
1864 {
1865 PrintHelp();
1866 return -1;
1867 }
1868
1869 Dim::Setup(conf.Get<string>("dns"));
1870
1871// try
1872 {
1873 // No console access at all
1874 if (!conf.Has("console"))
1875 {
1876// if (conf.Get<bool>("no-dim"))
1877// return RunShell<LocalStream, StateMachine>(conf);
1878// else
1879 return RunShell<LocalStream, StateMachineDim>(conf);
1880 }
1881 // Cosole access w/ and w/o Dim
1882/* if (conf.Get<bool>("no-dim"))
1883 {
1884 if (conf.Get<int>("console")==0)
1885 return RunShell<LocalShell, StateMachine>(conf);
1886 else
1887 return RunShell<LocalConsole, StateMachine>(conf);
1888 }
1889 else
1890*/ {
1891 if (conf.Get<int>("console")==0)
1892 return RunShell<LocalShell, StateMachineDim>(conf);
1893 else
1894 return RunShell<LocalConsole, StateMachineDim>(conf);
1895 }
1896 }
1897/* catch (std::exception& e)
1898 {
1899 cerr << "Exception: " << e.what() << endl;
1900 return -1;
1901 }*/
1902
1903 return 0;
1904}
Note: See TracBrowser for help on using the repository browser.