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

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