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

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