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 | |
---|
13 | #include "FACT.h" |
---|
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 "Timers.h" |
---|
21 | #include "Console.h" |
---|
22 | #include "Converter.h" |
---|
23 | #include "LocalControl.h" |
---|
24 | #include "HeadersFAD.h" |
---|
25 | |
---|
26 | #include "tools.h" |
---|
27 | |
---|
28 | namespace ba = boost::asio; |
---|
29 | namespace bs = boost::system; |
---|
30 | |
---|
31 | using ba::ip::tcp; |
---|
32 | |
---|
33 | using namespace std; |
---|
34 | |
---|
35 | #undef FAKE |
---|
36 | |
---|
37 | // ------------------------------------------------------------------------ |
---|
38 | |
---|
39 | class ConnectionFAD : public Connection |
---|
40 | { |
---|
41 | vector<uint16_t> fBuffer; |
---|
42 | |
---|
43 | protected: |
---|
44 | FAD::EventHeader fEventHeader; |
---|
45 | FAD::ChannelHeader fChannelHeader[FAD::kNumChannels]; |
---|
46 | |
---|
47 | private: |
---|
48 | bool fIsVerbose; |
---|
49 | bool fIsHexOutput; |
---|
50 | bool fIsDataOutput; |
---|
51 | |
---|
52 | uint64_t fCounter; |
---|
53 | |
---|
54 | protected: |
---|
55 | virtual void UpdateFirstHeader() |
---|
56 | { |
---|
57 | } |
---|
58 | |
---|
59 | virtual void UpdateEventHeader() |
---|
60 | { |
---|
61 | // emit service with trigger counter from header |
---|
62 | if (!fIsVerbose) |
---|
63 | return; |
---|
64 | |
---|
65 | Out() << endl << kBold << "Header received (N=" << dec << fCounter << "):" << endl; |
---|
66 | Out() << fEventHeader; |
---|
67 | if (fIsHexOutput) |
---|
68 | Out() << Converter::GetHex<uint16_t>(fEventHeader, 16) << endl; |
---|
69 | } |
---|
70 | |
---|
71 | virtual void UpdateChannelHeader(int i) |
---|
72 | { |
---|
73 | // emit service with trigger counter from header |
---|
74 | if (!fIsVerbose) |
---|
75 | return; |
---|
76 | |
---|
77 | Out() << endl << kBold << "Channel " << i << " received:" << endl; |
---|
78 | Out() << fChannelHeader[i]; |
---|
79 | if (fIsHexOutput) |
---|
80 | Out() << Converter::GetHex<uint16_t>(fChannelHeader, 16) << endl; |
---|
81 | } |
---|
82 | |
---|
83 | virtual void UpdateData(const uint16_t *data, size_t sz) |
---|
84 | { |
---|
85 | // emit service with trigger counter from header |
---|
86 | if (fIsVerbose && fIsDataOutput) |
---|
87 | Out() << Converter::GetHex<uint16_t>(data, sz, 16, true) << endl; |
---|
88 | } |
---|
89 | |
---|
90 | private: |
---|
91 | void HandleReceivedData(const bs::error_code& err, size_t bytes_received, int/* type*/) |
---|
92 | { |
---|
93 | // Do not schedule a new read if the connection failed. |
---|
94 | if (bytes_received==0 || err) |
---|
95 | { |
---|
96 | if (err==ba::error::eof) |
---|
97 | Warn("Connection closed by remote host (FTM)."); |
---|
98 | |
---|
99 | // 107: Transport endpoint is not connected (bs::error_code(107, bs::system_category)) |
---|
100 | // 125: Operation canceled |
---|
101 | if (err && err!=ba::error::eof && // Connection closed by remote host |
---|
102 | err!=ba::error::basic_errors::not_connected && // Connection closed by remote host |
---|
103 | err!=ba::error::basic_errors::operation_aborted) // Connection closed by us |
---|
104 | { |
---|
105 | stringstream str; |
---|
106 | str << "Reading from " << URL() << ": " << err.message() << " (" << err << ")";// << endl; |
---|
107 | Error(str); |
---|
108 | } |
---|
109 | PostClose(err!=ba::error::basic_errors::operation_aborted); |
---|
110 | return; |
---|
111 | } |
---|
112 | |
---|
113 | if (bytes_received == sizeof(FAD::EventHeader)) |
---|
114 | { |
---|
115 | fEventHeader = fBuffer; |
---|
116 | |
---|
117 | if (fEventHeader.fStartDelimiter!=FAD::kDelimiterStart) |
---|
118 | { |
---|
119 | stringstream str; |
---|
120 | str << "Invalid header received: start delimiter wrong, received "; |
---|
121 | str << hex << fEventHeader.fStartDelimiter << ", expected " << FAD::kDelimiterStart << "."; |
---|
122 | Error(str); |
---|
123 | PostClose(false); |
---|
124 | return; |
---|
125 | } |
---|
126 | |
---|
127 | if (fCounter==0) |
---|
128 | UpdateFirstHeader(); |
---|
129 | |
---|
130 | UpdateEventHeader(); |
---|
131 | |
---|
132 | fCounter++; |
---|
133 | |
---|
134 | fBuffer.resize(fEventHeader.fPackageLength-sizeof(FAD::EventHeader)/2); |
---|
135 | AsyncRead(ba::buffer(fBuffer)); |
---|
136 | |
---|
137 | return; |
---|
138 | } |
---|
139 | |
---|
140 | if (ntohs(fBuffer.back())!=FAD::kDelimiterEnd) |
---|
141 | { |
---|
142 | stringstream str; |
---|
143 | str << "Invalid data received: end delimiter wrong, received "; |
---|
144 | str << hex << ntohs(fBuffer.back()) << ", expected " << FAD::kDelimiterEnd << "."; |
---|
145 | Error(str); |
---|
146 | PostClose(false); |
---|
147 | return; |
---|
148 | } |
---|
149 | |
---|
150 | /* |
---|
151 | uint8_t *ptr = reinterpret_cast<uint8_t*>(fBuffer.data()); |
---|
152 | for (unsigned int i=0; i<FAD::kNumChannels; i++) |
---|
153 | { |
---|
154 | if (ptr+sizeof(FAD::ChannelHeader)/2 > reinterpret_cast<uint8_t*>(fBuffer.data())+fBuffer.size()*2) |
---|
155 | { |
---|
156 | Error("WRONG SIZE1"); |
---|
157 | break; |
---|
158 | } |
---|
159 | |
---|
160 | // FIXME: Size consistency check!!!! |
---|
161 | fChannelHeader[i] = vector<uint16_t>((uint16_t*)ptr, (uint16_t*)ptr+sizeof(FAD::ChannelHeader)/2); |
---|
162 | ptr += sizeof(FAD::ChannelHeader); |
---|
163 | |
---|
164 | // FIXME CHECK: Event Size vs ROI |
---|
165 | |
---|
166 | UpdateChannelHeader(i); |
---|
167 | |
---|
168 | if (ptr+fChannelHeader[i].fRegionOfInterest*2 > reinterpret_cast<uint8_t*>(fBuffer.data())+fBuffer.size()*2) |
---|
169 | { |
---|
170 | Error("WRONG SIZE2"); |
---|
171 | break; |
---|
172 | } |
---|
173 | |
---|
174 | uint16_t *data = reinterpret_cast<uint16_t*>(ptr); |
---|
175 | for (uint16_t *d=data; d<data+fChannelHeader[i].fRegionOfInterest; d++) |
---|
176 | { |
---|
177 | const bool sign = *d & 0x2000; |
---|
178 | const bool overflow = *d & 0x1000; |
---|
179 | |
---|
180 | if (sign) |
---|
181 | *d |= 0xf000; // no overflow, nagative |
---|
182 | else |
---|
183 | *d &= 0x07ff; // no overlow, positive |
---|
184 | |
---|
185 | // max = [-2047;2048] |
---|
186 | |
---|
187 | if (overflow) |
---|
188 | { |
---|
189 | if (sign) |
---|
190 | *d = 0xF800; // overflow, negative |
---|
191 | else |
---|
192 | *d = 0x0800; // overflow, positive |
---|
193 | } |
---|
194 | } |
---|
195 | |
---|
196 | UpdateData(data, fChannelHeader[i].fRegionOfInterest*2); |
---|
197 | ptr += fChannelHeader[i].fRegionOfInterest*2; |
---|
198 | }*/ |
---|
199 | |
---|
200 | fBuffer.resize(sizeof(FAD::EventHeader)/2); |
---|
201 | AsyncRead(ba::buffer(fBuffer)); |
---|
202 | } |
---|
203 | |
---|
204 | // This is called when a connection was established |
---|
205 | void ConnectionEstablished() |
---|
206 | { |
---|
207 | fEventHeader.clear(); |
---|
208 | for (unsigned int i=0; i<FAD::kNumChannels; i++) |
---|
209 | fChannelHeader[i].clear(); |
---|
210 | |
---|
211 | fCounter = 0; |
---|
212 | |
---|
213 | fBuffer.resize(sizeof(FAD::EventHeader)/2); |
---|
214 | AsyncRead(ba::buffer(fBuffer)); |
---|
215 | |
---|
216 | // for (int i=0; i<36; i++) |
---|
217 | // CmdSetRoi(i, 100); |
---|
218 | |
---|
219 | Cmd(ConnectionFAD::kCmdTriggerLine, true); |
---|
220 | Cmd(ConnectionFAD::kCmdSingleTrigger); |
---|
221 | } |
---|
222 | |
---|
223 | void HandleReadTimeout(const bs::error_code &error) |
---|
224 | { |
---|
225 | /* |
---|
226 | return; |
---|
227 | Warn("Reading header timed-out... restarting."); |
---|
228 | StartReadHeader(); |
---|
229 | return; |
---|
230 | */ |
---|
231 | if (error && error!=ba::error::basic_errors::operation_aborted) |
---|
232 | { |
---|
233 | stringstream str; |
---|
234 | str << "Read timeout of " << URL() << ": " << error.message() << " (" << error << ")";// << endl; |
---|
235 | Error(str); |
---|
236 | |
---|
237 | PostClose(); |
---|
238 | return; |
---|
239 | |
---|
240 | } |
---|
241 | |
---|
242 | if (!is_open()) |
---|
243 | { |
---|
244 | // For example: Here we could schedule a new accept if we |
---|
245 | // would not want to allow two connections at the same time. |
---|
246 | return; |
---|
247 | } |
---|
248 | |
---|
249 | // Check whether the deadline has passed. We compare the deadline |
---|
250 | // against the current time since a new asynchronous operation |
---|
251 | // may have moved the deadline before this actor had a chance |
---|
252 | // to run. |
---|
253 | if (fInTimeout.expires_at() > ba::deadline_timer::traits_type::now()) |
---|
254 | return; |
---|
255 | |
---|
256 | Error("Timeout reading data from "+URL()); |
---|
257 | |
---|
258 | PostClose(); |
---|
259 | } |
---|
260 | |
---|
261 | void PostCmd(std::vector<uint16_t> cmd) |
---|
262 | { |
---|
263 | stringstream msg; |
---|
264 | msg << "Sending command:" << hex; |
---|
265 | msg << " 0x" << setw(4) << setfill('0') << cmd[0]; |
---|
266 | Message(msg); |
---|
267 | |
---|
268 | transform(cmd.begin(), cmd.end(), cmd.begin(), htons); |
---|
269 | |
---|
270 | PostMessage(cmd); |
---|
271 | } |
---|
272 | |
---|
273 | void PostCmd(uint16_t cmd) |
---|
274 | { |
---|
275 | stringstream msg; |
---|
276 | msg << "Sending command:" << hex; |
---|
277 | msg << " 0x" << setw(4) << setfill('0') << cmd; |
---|
278 | Message(msg); |
---|
279 | |
---|
280 | cmd = htons(cmd); |
---|
281 | PostMessage(&cmd, sizeof(uint16_t)); |
---|
282 | } |
---|
283 | |
---|
284 | void PostCmd(uint16_t cmd, uint16_t data) |
---|
285 | { |
---|
286 | stringstream msg; |
---|
287 | msg << "Sending command:" << hex; |
---|
288 | msg << " 0x" << setw(4) << setfill('0') << cmd; |
---|
289 | msg << " 0x" << setw(4) << setfill('0') << data; |
---|
290 | Message(msg); |
---|
291 | |
---|
292 | const uint16_t d[2] = { htons(cmd), htons(data) }; |
---|
293 | PostMessage(d, sizeof(d)); |
---|
294 | } |
---|
295 | |
---|
296 | public: |
---|
297 | enum Enable_t |
---|
298 | { |
---|
299 | kCmdDrsEnable = 0x0600, // CMD_DENABLE/CMD_DISABLE |
---|
300 | kCmdDwrite = 0x0800, // CMD_DWRITE_RUN/CMD_DWRITE_STOP |
---|
301 | kCmdSclk = 0x1000, // CMD_SCLK_ON/OFF |
---|
302 | kCmdSrclk = 0x1500, // CMD_SRCLK_ON/OFF |
---|
303 | kCmdTriggerLine = 0x1800, // CMD_TRIGGERS_ON/CMD_TRIGGERS_OFF |
---|
304 | //kCmdContTrigger = 0x1f00, |
---|
305 | kCmdContTriggerOff = 0x2000, |
---|
306 | kCmdRun = 0x2200, // CMD_Start/Stop |
---|
307 | kCmdResetTriggerId = 0x2A00, // |
---|
308 | kCmdSocket = 0x3000, // CMD_mode_command/CMD_mode_all_sockets |
---|
309 | kCmdSingleTrigger = 0xA000, // CMD_Trigger |
---|
310 | kCmdContTriggerOn = 0xB000, |
---|
311 | }; |
---|
312 | |
---|
313 | private: |
---|
314 | enum |
---|
315 | { |
---|
316 | kCmdWrite = 0x0500, // write to Config-RAM |
---|
317 | kCmdWriteRoi = kCmdWrite|0x00, // Baseaddress ROI-Values |
---|
318 | kCmdWriteDac = kCmdWrite|0x24, // Baseaddress DAC-Values |
---|
319 | |
---|
320 | kCmdWriteRate = kCmdWrite|0x2c, // Continous trigger rate |
---|
321 | kCmdWriteRunNumber = kCmdWrite|0x2d, // |
---|
322 | |
---|
323 | /* |
---|
324 | kCmdRead = 0x0a00, // read from Config-RAM |
---|
325 | kCmdReadRoi = kCmdRead|0x00, // Baseaddress ROI-Values |
---|
326 | kCmdReadDac = kCmdRead|0x24, // Baseaddress DAC-Values |
---|
327 | */ |
---|
328 | |
---|
329 | kCmdPhaseIncrease = 0x1200, // CMD_PS_DIRINC |
---|
330 | kCmdPhaseDecrease = 0x1300, // CMD_PS_DIRDEC |
---|
331 | kCmdPhaseApply = 0x1400, // CMD_PS_DO |
---|
332 | kCmdPhaseReset = 0x1700, // CMD_PS_RESET |
---|
333 | }; |
---|
334 | |
---|
335 | public: |
---|
336 | ConnectionFAD(ba::io_service& ioservice, MessageImp &imp) : |
---|
337 | Connection(ioservice, imp()), |
---|
338 | fIsVerbose(true), fIsHexOutput(false), fIsDataOutput(false), fCounter(0) |
---|
339 | |
---|
340 | { |
---|
341 | SetLogStream(&imp); |
---|
342 | |
---|
343 | #ifdef FAKE |
---|
344 | for (int i=0; i<7; i++) |
---|
345 | fake[i] = new Connection(ioservice, imp()); |
---|
346 | #endif |
---|
347 | } |
---|
348 | #ifdef FAKE |
---|
349 | Connection *fake[7]; |
---|
350 | |
---|
351 | ~ConnectionFAD() |
---|
352 | { |
---|
353 | // WORKAROUND |
---|
354 | for (int i=0; i<7; i++) |
---|
355 | delete fake[i]; |
---|
356 | } |
---|
357 | void StartConnect() |
---|
358 | { |
---|
359 | // WORKAROUND |
---|
360 | Connection::StartConnect(); |
---|
361 | for (int i=0; i<7; i++) |
---|
362 | fake[i]->StartConnect(); |
---|
363 | } |
---|
364 | void SetEndpoint(const string &addr) |
---|
365 | { |
---|
366 | // WORKAROUND |
---|
367 | Connection::SetEndpoint(addr); |
---|
368 | for (int i=0; i<7; i++) |
---|
369 | { |
---|
370 | const size_t p0 = addr.find_first_of(':'); |
---|
371 | |
---|
372 | ostringstream p; |
---|
373 | p << addr.substr(0, p0+1) << atoi(addr.substr(p0+1).c_str())+i+1; |
---|
374 | fake[i]->SetEndpoint(p.str()); |
---|
375 | } |
---|
376 | // ==========================================WORKAROUND |
---|
377 | } |
---|
378 | #endif |
---|
379 | |
---|
380 | void Cmd(Enable_t cmd, bool on=true) |
---|
381 | { |
---|
382 | PostCmd(cmd + (on ? 0 : 0x100)); |
---|
383 | } |
---|
384 | |
---|
385 | // ------------------------------ |
---|
386 | |
---|
387 | // IMPLEMENT: Abs/Rel |
---|
388 | void CmdPhaseShift(int16_t val) |
---|
389 | { |
---|
390 | vector<uint16_t> cmd(abs(val)+2, kCmdPhaseApply); |
---|
391 | cmd[0] = kCmdPhaseReset; |
---|
392 | cmd[1] = val<0 ? kCmdPhaseDecrease : kCmdPhaseIncrease; |
---|
393 | PostCmd(cmd); |
---|
394 | } |
---|
395 | |
---|
396 | bool CmdSetTriggerRate(int32_t val) |
---|
397 | { |
---|
398 | if (val<0 || val>0xffff) |
---|
399 | return false; |
---|
400 | |
---|
401 | PostCmd(kCmdWriteRate, val);//uint8_t(1000./val/12.5)); |
---|
402 | //PostCmd(kCmdContTriggerRate, uint8_t(80/val)); |
---|
403 | |
---|
404 | return true; |
---|
405 | } |
---|
406 | |
---|
407 | void CmdSetRegister(uint8_t addr, uint16_t val) |
---|
408 | { |
---|
409 | // Allowed addr: [0, MAX_ADDR] |
---|
410 | // Allowed value: [0, MAX_VAL] |
---|
411 | PostCmd(kCmdWrite + addr, val); |
---|
412 | } |
---|
413 | |
---|
414 | bool CmdSetDacValue(uint8_t addr, uint16_t val) |
---|
415 | { |
---|
416 | if (addr>FAD::kMaxDacAddr) // NDAC |
---|
417 | return false; |
---|
418 | |
---|
419 | PostCmd(kCmdWriteDac + addr, val); |
---|
420 | return true; |
---|
421 | } |
---|
422 | |
---|
423 | bool CmdSetRoi(int8_t addr, uint16_t val) |
---|
424 | { |
---|
425 | if (addr>FAD::kMaxRoiAddr) |
---|
426 | return false; |
---|
427 | |
---|
428 | if (val>FAD::kMaxRoiValue) |
---|
429 | return false; |
---|
430 | |
---|
431 | if (addr<0) |
---|
432 | for (int i=0; i<FAD::kMaxRoiAddr; i++) |
---|
433 | PostCmd(kCmdWriteRoi + i, val); |
---|
434 | else |
---|
435 | PostCmd(kCmdWriteRoi + addr, val); |
---|
436 | |
---|
437 | return true; |
---|
438 | } |
---|
439 | |
---|
440 | bool CmdSetRoi(uint16_t val) { return CmdSetRoi(-1, val); } |
---|
441 | |
---|
442 | void AmplitudeCalibration() |
---|
443 | { |
---|
444 | // ------------- case baseline ----------------- |
---|
445 | |
---|
446 | CmdSetRoi(-1, FAD::kMaxBins); |
---|
447 | |
---|
448 | CmdSetDacValue(1, 0); |
---|
449 | CmdSetDacValue(2, 0); |
---|
450 | CmdSetDacValue(3, 0); |
---|
451 | |
---|
452 | // Take N events |
---|
453 | |
---|
454 | /* |
---|
455 | // ====== Part B: Baseline calibration ===== |
---|
456 | |
---|
457 | // Loop over all channels(ch) and time-slices (t) |
---|
458 | T0 = TriggerCell[chip] |
---|
459 | Sum[ch][(t+T0) % kMaxBins] += Data[ch][t]; |
---|
460 | // FIXME: Determine median instead of average |
---|
461 | |
---|
462 | Baseline[ch][slice] = MEDIAN( sum[ch][slice] ) |
---|
463 | */ |
---|
464 | |
---|
465 | // --------------- case gain ------------------- |
---|
466 | |
---|
467 | // Set new DAC values and start accumulation |
---|
468 | CmdSetDacValue(1, 50000); |
---|
469 | CmdSetDacValue(2, 50000); |
---|
470 | CmdSetDacValue(3, 50000); |
---|
471 | |
---|
472 | // Take N events |
---|
473 | |
---|
474 | /* |
---|
475 | // ====== Part C: Gain calibration ===== |
---|
476 | |
---|
477 | T0 = TriggerCell[chip] |
---|
478 | Sum[ch][(t+T0) % kMaxBins] += Data[ch][t]; |
---|
479 | // FIXME: Determine median instead of average |
---|
480 | |
---|
481 | Gain[ch][slice] = MEDIAN( sum[ch][slice] ) - Baseline[ch][slice] |
---|
482 | */ |
---|
483 | |
---|
484 | // --------------- secondary ------------------ |
---|
485 | |
---|
486 | // FIXME: Can most probably be done together with the baseline calibration |
---|
487 | // FIXME: Why does the secondary baseline not influence the baseline? |
---|
488 | |
---|
489 | CmdSetDacValue(1, 0); |
---|
490 | CmdSetDacValue(2, 0); |
---|
491 | CmdSetDacValue(3, 0); |
---|
492 | |
---|
493 | // Take N events |
---|
494 | |
---|
495 | /* |
---|
496 | // ====== Part D: Secondary calibration ===== |
---|
497 | |
---|
498 | T0 = TriggerCell[chip] |
---|
499 | Sum[ch][t] = Data[ch][t] - Baseline[ch][(i-T0) % kMaxBins]; |
---|
500 | |
---|
501 | // Determine secondary baseline if integration finished |
---|
502 | SecondaryBaseline[ch][t] = MEDIAN( Sum[ch][t] ) |
---|
503 | */ |
---|
504 | } |
---|
505 | |
---|
506 | void SetVerbose(bool b) |
---|
507 | { |
---|
508 | fIsVerbose = b; |
---|
509 | } |
---|
510 | |
---|
511 | void SetHexOutput(bool b) |
---|
512 | { |
---|
513 | fIsHexOutput = b; |
---|
514 | } |
---|
515 | |
---|
516 | void SetDataOutput(bool b) |
---|
517 | { |
---|
518 | fIsDataOutput = b; |
---|
519 | } |
---|
520 | |
---|
521 | }; |
---|
522 | |
---|
523 | // ------------------------------------------------------------------------ |
---|
524 | /* |
---|
525 | #include "DimDescriptionService.h" |
---|
526 | |
---|
527 | class ConnectionDimFAD : public ConnectionFAD |
---|
528 | { |
---|
529 | private: |
---|
530 | |
---|
531 | DimDescribedService fDimPassport; |
---|
532 | DimDescribedService fDimTemperatures; |
---|
533 | DimDescribedService fDimSetup; |
---|
534 | DimDescribedService fDimEventHeader; |
---|
535 | |
---|
536 | template<class T> |
---|
537 | void Update(DimDescribedService &svc, const T &data) const |
---|
538 | { |
---|
539 | //cout << "Update: " << svc.getName() << " (" << sizeof(T) << ")" << endl; |
---|
540 | svc.setData(const_cast<T*>(&data), sizeof(T)); |
---|
541 | svc.updateService(); |
---|
542 | } |
---|
543 | |
---|
544 | void UpdateFirstHeader() |
---|
545 | { |
---|
546 | ConnectionFAD::UpdateFirstHeader(); |
---|
547 | |
---|
548 | const FAD::DimPassport data(fEventHeader); |
---|
549 | Update(fDimPassport, data); |
---|
550 | } |
---|
551 | |
---|
552 | void UpdateEventHeader() |
---|
553 | { |
---|
554 | ConnectionFAD::UpdateEventHeader(); |
---|
555 | |
---|
556 | const FAD::DimTemperatures data0(fEventHeader); |
---|
557 | const FAD::DimSetup data1(fEventHeader); |
---|
558 | const FAD::DimEventHeader data2(fEventHeader); |
---|
559 | |
---|
560 | Update(fDimTemperatures, data0); |
---|
561 | Update(fDimSetup, data1); |
---|
562 | Update(fDimEventHeader, data2); |
---|
563 | } |
---|
564 | |
---|
565 | public: |
---|
566 | ConnectionDimFAD(ba::io_service& ioservice, MessageImp &imp) : |
---|
567 | ConnectionFAD(ioservice, imp), |
---|
568 | fDimPassport ("FAD_CONTROL/PASSPORT", "I:1;S:2;X:1", ""), |
---|
569 | fDimTemperatures("FAD_CONTROL/TEMPERATURES", "I:1;F:4", ""), |
---|
570 | fDimSetup ("FAD_CONTROL/SETUP", "I:2;S:12", ""), |
---|
571 | fDimEventHeader ("FAD_CONTROL/EVENT_HEADER", "C", "") |
---|
572 | { |
---|
573 | } |
---|
574 | |
---|
575 | // A B [C] [D] E [F] G H [I] J K [L] M N O P Q R [S] T U V W [X] Y Z |
---|
576 | }; |
---|
577 | */ |
---|
578 | // ------------------------------------------------------------------------ |
---|
579 | extern "C" |
---|
580 | { |
---|
581 | extern void *readFAD(void*); |
---|
582 | extern void *procEvt(void*); |
---|
583 | extern void *writeEvt(void*); |
---|
584 | extern void initReadFAD(); |
---|
585 | }; |
---|
586 | |
---|
587 | #include "EventBuilder.h" |
---|
588 | |
---|
589 | class EventBuilderWrapper |
---|
590 | { |
---|
591 | boost::thread fThread; |
---|
592 | |
---|
593 | enum CommandStates_t // g_runStat |
---|
594 | { |
---|
595 | kAbort = -2, // quit as soon as possible ('abort') |
---|
596 | kExit = -1, // stop reading, quit when buffered events done ('exit') |
---|
597 | kInitialize = 0, // 'initialize' (e.g. dim not yet started) |
---|
598 | kHybernate = 1, // do nothing for long time ('hybernate') [wakeup within ~1sec] |
---|
599 | kSleep = 2, // do nothing ('sleep') [wakeup within ~10msec] |
---|
600 | kModeFlush = 10, // read data from camera, but skip them ('flush') |
---|
601 | kModeTest = 20, // read data and process them, but do not write to disk ('test') |
---|
602 | kModeFlag = 30, // read data, process and write all to disk ('flag') |
---|
603 | kModeRun = 40, // read data, process and write selected to disk ('run') |
---|
604 | }; |
---|
605 | |
---|
606 | MessageImp &fMsg; |
---|
607 | |
---|
608 | public: |
---|
609 | EventBuilderWrapper(MessageImp &msg) : fMsg(msg) |
---|
610 | { |
---|
611 | Start(); |
---|
612 | } |
---|
613 | |
---|
614 | void Start() |
---|
615 | { |
---|
616 | if (fThread.joinable()) |
---|
617 | { |
---|
618 | fMsg.Warn("Start - EventBuilder still running"); |
---|
619 | return; |
---|
620 | } |
---|
621 | |
---|
622 | fMsg.Message("Initializing EventBuilder"); |
---|
623 | initReadFAD(); |
---|
624 | |
---|
625 | g_runStat = kHybernate; |
---|
626 | fThread = boost::thread(readFAD, (void*)NULL); |
---|
627 | |
---|
628 | fMsg.Message("EventBuilder started"); |
---|
629 | } |
---|
630 | void Abort() |
---|
631 | { |
---|
632 | fMsg.Message("Waiting for EventBuilder to abort..."); |
---|
633 | g_runStat = kAbort; |
---|
634 | fThread.join(); |
---|
635 | fMsg.Message("EventBuilder stopped."); |
---|
636 | } |
---|
637 | |
---|
638 | void Exit() |
---|
639 | { |
---|
640 | fMsg.Message("Waiting for EventBuilder to exit - be patient..."); |
---|
641 | g_runStat = kExit; |
---|
642 | } |
---|
643 | |
---|
644 | void Wait() |
---|
645 | { |
---|
646 | fThread.join(); |
---|
647 | fMsg.Message("EventBuilder stopped."); |
---|
648 | } |
---|
649 | |
---|
650 | void Hybernate() { g_runStat = kHybernate; } |
---|
651 | void Sleep() { g_runStat = kSleep; } |
---|
652 | void FlushMode() { g_runStat = kModeFlush; } |
---|
653 | void TestMode() { g_runStat = kModeTest; } |
---|
654 | void FlagMode() { g_runStat = kModeFlag; } |
---|
655 | void RunMode() { g_runStat = kModeRun; } |
---|
656 | |
---|
657 | // FIXME: To be removed |
---|
658 | void SetMode(int mode) { g_runStat = mode; } |
---|
659 | |
---|
660 | bool IsConnected(int i) const { return gi_NumConnect[i]==7; } |
---|
661 | bool IsDisconnected(int i) const { return gi_NumConnect[i]==0; } |
---|
662 | int GetNumConnected(int i) const { return gi_NumConnect[i]; } |
---|
663 | |
---|
664 | void Restart() |
---|
665 | { |
---|
666 | Abort(); |
---|
667 | Start(); |
---|
668 | } |
---|
669 | |
---|
670 | ~EventBuilderWrapper() |
---|
671 | { |
---|
672 | Abort(); |
---|
673 | } |
---|
674 | |
---|
675 | }; |
---|
676 | |
---|
677 | // ------------------------------------------------------------------------ |
---|
678 | |
---|
679 | template <class T> |
---|
680 | class StateMachineFAD : public T, public EventBuilderWrapper, public ba::io_service, public ba::io_service::work |
---|
681 | { |
---|
682 | private: |
---|
683 | typedef pair<string, ConnectionFAD*> Connection; |
---|
684 | typedef pair<const uint8_t, Connection> Board; |
---|
685 | typedef map<uint8_t, Connection> BoardList; |
---|
686 | |
---|
687 | BoardList fBoards; |
---|
688 | |
---|
689 | bool fIsVerbose; |
---|
690 | bool fIsHexOutput; |
---|
691 | bool fIsDataOutput; |
---|
692 | |
---|
693 | bool CheckEventSize(size_t has, const char *name, size_t size) |
---|
694 | { |
---|
695 | if (has==size) |
---|
696 | return true; |
---|
697 | |
---|
698 | stringstream msg; |
---|
699 | msg << name << " - Received event has " << has << " bytes, but expected " << size << "."; |
---|
700 | T::Fatal(msg); |
---|
701 | return false; |
---|
702 | } |
---|
703 | |
---|
704 | int Cmd(ConnectionFAD::Enable_t command) |
---|
705 | { |
---|
706 | for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++) |
---|
707 | i->second.second->Cmd(command); |
---|
708 | |
---|
709 | return T::GetCurrentState(); |
---|
710 | } |
---|
711 | |
---|
712 | int CmdEnable(const EventImp &evt, ConnectionFAD::Enable_t command) |
---|
713 | { |
---|
714 | if (!CheckEventSize(evt.GetSize(), "CmdEnable", 1)) |
---|
715 | return T::kSM_FatalError; |
---|
716 | |
---|
717 | for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++) |
---|
718 | i->second.second->Cmd(command, evt.GetBool()); |
---|
719 | |
---|
720 | return T::GetCurrentState(); |
---|
721 | } |
---|
722 | |
---|
723 | bool Check(const uint32_t *dat, uint32_t maxaddr, uint32_t maxval) |
---|
724 | { |
---|
725 | if (dat[0]>FAD::kMaxRegAddr) |
---|
726 | { |
---|
727 | stringstream msg; |
---|
728 | msg << hex << "Address " << dat[0] << " out of range, max=" << maxaddr << "."; |
---|
729 | T::Error(msg); |
---|
730 | return false; |
---|
731 | } |
---|
732 | |
---|
733 | if (dat[1]>FAD::kMaxRegValue) |
---|
734 | { |
---|
735 | stringstream msg; |
---|
736 | msg << hex << "Value " << dat[1] << " out of range, max=" << maxval << "."; |
---|
737 | T::Error(msg); |
---|
738 | return false; |
---|
739 | } |
---|
740 | |
---|
741 | return true; |
---|
742 | } |
---|
743 | |
---|
744 | int SetRegister(const EventImp &evt) |
---|
745 | { |
---|
746 | if (!CheckEventSize(evt.GetSize(), "SetRegister", 8)) |
---|
747 | return T::kSM_FatalError; |
---|
748 | |
---|
749 | const uint32_t *dat = reinterpret_cast<const uint32_t*>(evt.GetData()); |
---|
750 | |
---|
751 | if (!Check(dat, FAD::kMaxRegAddr, FAD::kMaxRegValue)) |
---|
752 | return T::GetCurrentState(); |
---|
753 | |
---|
754 | for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++) |
---|
755 | i->second.second->CmdSetRegister(dat[0], dat[1]); |
---|
756 | |
---|
757 | return T::GetCurrentState(); |
---|
758 | } |
---|
759 | |
---|
760 | int SetRoi(const EventImp &evt) |
---|
761 | { |
---|
762 | if (!CheckEventSize(evt.GetSize(), "SetRoi", 8)) |
---|
763 | return T::kSM_FatalError; |
---|
764 | |
---|
765 | // ---- was uint32_t |
---|
766 | const int32_t *dat = reinterpret_cast<const int32_t*>(evt.GetData()); |
---|
767 | |
---|
768 | // ---- -1 for all |
---|
769 | //if (!Check(dat, FAD::kMaxRoiAddr, FAD::kMaxRoiValue)) |
---|
770 | // return T::GetCurrentState(); |
---|
771 | |
---|
772 | for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++) |
---|
773 | i->second.second->CmdSetRoi(dat[0], dat[1]); |
---|
774 | |
---|
775 | return T::GetCurrentState(); |
---|
776 | } |
---|
777 | |
---|
778 | int SetDac(const EventImp &evt) |
---|
779 | { |
---|
780 | if (!CheckEventSize(evt.GetSize(), "SetDac", 8)) |
---|
781 | return T::kSM_FatalError; |
---|
782 | |
---|
783 | const uint32_t *dat = reinterpret_cast<const uint32_t*>(evt.GetData()); |
---|
784 | |
---|
785 | if (!Check(dat, FAD::kMaxDacAddr, FAD::kMaxDacValue)) |
---|
786 | return T::GetCurrentState(); |
---|
787 | |
---|
788 | for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++) |
---|
789 | i->second.second->CmdSetDacValue(dat[0], dat[1]); |
---|
790 | |
---|
791 | return T::GetCurrentState(); |
---|
792 | } |
---|
793 | |
---|
794 | int Trigger(int n) |
---|
795 | { |
---|
796 | for (int nn=0; nn<n; nn++) |
---|
797 | for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++) |
---|
798 | i->second.second->Cmd(ConnectionFAD::kCmdSingleTrigger); |
---|
799 | |
---|
800 | return T::GetCurrentState(); |
---|
801 | } |
---|
802 | |
---|
803 | int SendTriggers(const EventImp &evt) |
---|
804 | { |
---|
805 | if (!CheckEventSize(evt.GetSize(), "SendTriggers", 4)) |
---|
806 | return T::kSM_FatalError; |
---|
807 | |
---|
808 | Trigger(evt.GetUInt()); |
---|
809 | |
---|
810 | return T::GetCurrentState(); |
---|
811 | } |
---|
812 | |
---|
813 | int StartRun(const EventImp &evt, bool start) |
---|
814 | { |
---|
815 | if (!CheckEventSize(evt.GetSize(), "StartRun", 0)) |
---|
816 | return T::kSM_FatalError; |
---|
817 | |
---|
818 | for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++) |
---|
819 | i->second.second->Cmd(ConnectionFAD::kCmdRun, start); |
---|
820 | |
---|
821 | return T::GetCurrentState(); |
---|
822 | } |
---|
823 | |
---|
824 | int PhaseShift(const EventImp &evt) |
---|
825 | { |
---|
826 | if (!CheckEventSize(evt.GetSize(), "PhaseShift", 2)) |
---|
827 | return T::kSM_FatalError; |
---|
828 | |
---|
829 | for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++) |
---|
830 | i->second.second->CmdPhaseShift(evt.GetShort()); |
---|
831 | |
---|
832 | return T::GetCurrentState(); |
---|
833 | } |
---|
834 | |
---|
835 | int SetTriggerRate(const EventImp &evt) |
---|
836 | { |
---|
837 | if (!CheckEventSize(evt.GetSize(), "SetTriggerRate", 4)) |
---|
838 | return T::kSM_FatalError; |
---|
839 | |
---|
840 | if (evt.GetUShort()>0xff) |
---|
841 | { |
---|
842 | stringstream msg; |
---|
843 | msg << hex << "Value " << evt.GetUShort() << " out of range, max=" << 0xff << "(?)"; |
---|
844 | T::Error(msg); |
---|
845 | return false; |
---|
846 | } |
---|
847 | |
---|
848 | for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++) |
---|
849 | i->second.second->CmdSetTriggerRate(evt.GetUInt()); |
---|
850 | |
---|
851 | return T::GetCurrentState(); |
---|
852 | } |
---|
853 | |
---|
854 | int Test(const EventImp &evt) |
---|
855 | { |
---|
856 | if (!CheckEventSize(evt.GetSize(), "Test", 2)) |
---|
857 | return T::kSM_FatalError; |
---|
858 | |
---|
859 | |
---|
860 | SetMode(evt.GetShort()); |
---|
861 | |
---|
862 | return T::GetCurrentState(); |
---|
863 | } |
---|
864 | |
---|
865 | |
---|
866 | int SetVerbosity(const EventImp &evt) |
---|
867 | { |
---|
868 | if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1)) |
---|
869 | return T::kSM_FatalError; |
---|
870 | |
---|
871 | for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++) |
---|
872 | i->second.second->SetVerbose(evt.GetText()[0]!=0); |
---|
873 | |
---|
874 | return T::GetCurrentState(); |
---|
875 | } |
---|
876 | |
---|
877 | int SetHexOutput(const EventImp &evt) |
---|
878 | { |
---|
879 | if (!CheckEventSize(evt.GetSize(), "SetHexOutput", 1)) |
---|
880 | return T::kSM_FatalError; |
---|
881 | |
---|
882 | for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++) |
---|
883 | i->second.second->SetHexOutput(evt.GetText()[0]!=0); |
---|
884 | |
---|
885 | return T::GetCurrentState(); |
---|
886 | } |
---|
887 | |
---|
888 | int SetDataOutput(const EventImp &evt) |
---|
889 | { |
---|
890 | if (!CheckEventSize(evt.GetSize(), "SetDataOutput", 1)) |
---|
891 | return T::kSM_FatalError; |
---|
892 | |
---|
893 | for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++) |
---|
894 | i->second.second->SetDataOutput(evt.GetText()[0]!=0); |
---|
895 | |
---|
896 | return T::GetCurrentState(); |
---|
897 | } |
---|
898 | |
---|
899 | const BoardList::iterator GetSlot(int slot) |
---|
900 | { |
---|
901 | const BoardList::iterator i = fBoards.find(slot); |
---|
902 | if (i!=fBoards.end()) |
---|
903 | return i; |
---|
904 | |
---|
905 | ostringstream str; |
---|
906 | str << "Slot " << slot << " not found."; |
---|
907 | T::Warn(str.str()); |
---|
908 | return fBoards.end(); |
---|
909 | } |
---|
910 | |
---|
911 | int AddAddress(const EventImp &evt) |
---|
912 | { |
---|
913 | const string addr = Tools::Trim(evt.GetText()); |
---|
914 | |
---|
915 | for (BoardList::const_iterator i=fBoards.begin(); i!=fBoards.end(); i++) |
---|
916 | { |
---|
917 | if (i->second.first==addr) |
---|
918 | { |
---|
919 | T::Warn("Address "+addr+" already known.... ignored."); |
---|
920 | return T::GetCurrentState(); |
---|
921 | } |
---|
922 | } |
---|
923 | |
---|
924 | AddEndpoint(addr); |
---|
925 | |
---|
926 | return T::GetCurrentState(); |
---|
927 | } |
---|
928 | |
---|
929 | int RemoveSlot(const EventImp &evt) |
---|
930 | { |
---|
931 | if (!CheckEventSize(evt.GetSize(), "RemoveSlot", 2)) |
---|
932 | return T::kSM_FatalError; |
---|
933 | |
---|
934 | const int16_t slot = evt.GetShort(); |
---|
935 | |
---|
936 | const BoardList::iterator v = GetSlot(slot); |
---|
937 | if (v!=fBoards.end()) |
---|
938 | { |
---|
939 | delete v->second.second; |
---|
940 | fBoards.erase(v); |
---|
941 | } |
---|
942 | |
---|
943 | return T::GetCurrentState(); |
---|
944 | } |
---|
945 | |
---|
946 | int ListSlots() |
---|
947 | { |
---|
948 | for (BoardList::const_iterator i=fBoards.begin(); i!=fBoards.end(); i++) |
---|
949 | { |
---|
950 | ostringstream str; |
---|
951 | str << "Slot " << setw(2) << (int)i->first << ": " << i->second.first; |
---|
952 | |
---|
953 | const ConnectionFAD *c = i->second.second; |
---|
954 | |
---|
955 | if (c->IsConnecting()) |
---|
956 | str << " (0:connecting, "; |
---|
957 | else |
---|
958 | { |
---|
959 | if (c->IsClosed()) |
---|
960 | str << " (0:disconnected, "; |
---|
961 | if (c->IsConnected()) |
---|
962 | str << " (0:connected, "; |
---|
963 | } |
---|
964 | |
---|
965 | switch (fStatus2[i->first]) |
---|
966 | { |
---|
967 | case 0: str << "1-7:disconnected)"; break; |
---|
968 | case 1: str << "1-7:connecting [" << GetNumConnected(i->first) << "])"; break; |
---|
969 | case 2: str << "1-7:connected)"; break; |
---|
970 | } |
---|
971 | |
---|
972 | T::Message(str.str()); |
---|
973 | } |
---|
974 | |
---|
975 | return T::GetCurrentState(); |
---|
976 | } |
---|
977 | |
---|
978 | void EnableSlot(BoardList::iterator i, bool enable=true) |
---|
979 | { |
---|
980 | if (i==fBoards.end()) |
---|
981 | return; |
---|
982 | |
---|
983 | ConnectionFAD* &ptr = i->second.second; |
---|
984 | |
---|
985 | if (!enable) |
---|
986 | ptr->PostClose(false); |
---|
987 | else |
---|
988 | { |
---|
989 | ptr->SetEndpoint(i->second.first); |
---|
990 | ptr->StartConnect(); |
---|
991 | } |
---|
992 | } |
---|
993 | |
---|
994 | void EnableAll(bool enable=true) |
---|
995 | { |
---|
996 | for (BoardList::iterator i=fBoards.begin(); i!=fBoards.end(); i++) |
---|
997 | EnableSlot(i, enable); |
---|
998 | } |
---|
999 | |
---|
1000 | /* |
---|
1001 | int Enable(const EventImp &evt) |
---|
1002 | { |
---|
1003 | if (!CheckEventSize(evt.GetSize(), "Enable", 3)) |
---|
1004 | return T::kSM_FatalError; |
---|
1005 | |
---|
1006 | const int16_t slot = evt.GetShort(); |
---|
1007 | const bool enable = evt.GetText()[2]>0; |
---|
1008 | |
---|
1009 | if (slot<0) |
---|
1010 | { |
---|
1011 | EnableAll(enable); |
---|
1012 | return T::GetCurrentState(); |
---|
1013 | } |
---|
1014 | |
---|
1015 | EnableSlot(GetSlot(slot), enable); |
---|
1016 | |
---|
1017 | return T::GetCurrentState(); |
---|
1018 | }*/ |
---|
1019 | |
---|
1020 | int Disconnect() |
---|
1021 | { |
---|
1022 | Exit(); |
---|
1023 | EnableAll(false); |
---|
1024 | return T::GetCurrentState(); |
---|
1025 | } |
---|
1026 | |
---|
1027 | int Connect() |
---|
1028 | { |
---|
1029 | T::Error("FIXME - Propagate IP Addresses to EventBuilder"); |
---|
1030 | |
---|
1031 | Start(); |
---|
1032 | EnableAll(true); |
---|
1033 | |
---|
1034 | return T::GetCurrentState(); |
---|
1035 | } |
---|
1036 | |
---|
1037 | /* |
---|
1038 | int Reconnect(const EventImp &evt) |
---|
1039 | { |
---|
1040 | if (!CheckEventSize(evt.GetSize(), "Reconnect", 2)) |
---|
1041 | return T::kSM_FatalError; |
---|
1042 | |
---|
1043 | const int16_t slot = evt.GetShort(); |
---|
1044 | |
---|
1045 | if (slot<0) |
---|
1046 | { |
---|
1047 | // Close all connections to supress the warning in SetEndpoint |
---|
1048 | for (BoardList::const_iterator i=fBoards.begin(); i!=fBoards.end(); i++) |
---|
1049 | i->second.second->PostClose(false); |
---|
1050 | |
---|
1051 | // Now wait until all connection have been closed and |
---|
1052 | // all pending handlers have been processed |
---|
1053 | poll(); |
---|
1054 | |
---|
1055 | // Now we can reopen the connection |
---|
1056 | for (BoardList::const_iterator i=fBoards.begin(); i!=fBoards.end(); i++) |
---|
1057 | i->second.second->PostClose(true); |
---|
1058 | |
---|
1059 | return T::GetCurrentState(); |
---|
1060 | } |
---|
1061 | |
---|
1062 | const BoardList::const_iterator v = GetSlot(slot); |
---|
1063 | if (v==fBoards.end()) |
---|
1064 | return T::GetCurrentState(); |
---|
1065 | |
---|
1066 | // Close all connections to supress the warning in SetEndpoint |
---|
1067 | v->second.second->PostClose(false); |
---|
1068 | |
---|
1069 | // Now wait until all connection have been closed and |
---|
1070 | // all pending handlers have been processed |
---|
1071 | poll(); |
---|
1072 | |
---|
1073 | // Now we can reopen the connection |
---|
1074 | v->second.second->PostClose(true); |
---|
1075 | |
---|
1076 | return T::GetCurrentState(); |
---|
1077 | }*/ |
---|
1078 | |
---|
1079 | virtual void UpdateConnectionStatus() |
---|
1080 | { |
---|
1081 | //cout << "Connection Status changed prop to Dim." << endl; |
---|
1082 | } |
---|
1083 | |
---|
1084 | vector<char> fStatus1; |
---|
1085 | vector<char> fStatus2; |
---|
1086 | |
---|
1087 | int Execute() |
---|
1088 | { |
---|
1089 | // Dispatch (execute) at most one handler from the queue. In contrary |
---|
1090 | // to run_one(), it doesn't wait until a handler is available |
---|
1091 | // which can be dispatched, so poll_one() might return with 0 |
---|
1092 | // handlers dispatched. The handlers are always dispatched/executed |
---|
1093 | // synchronously, i.e. within the call to poll_one() |
---|
1094 | poll_one(); |
---|
1095 | |
---|
1096 | // ===== Evaluate connection status ===== |
---|
1097 | |
---|
1098 | uint16_t nconnecting1 = 0; |
---|
1099 | uint16_t nconnecting2 = 0; |
---|
1100 | uint16_t nconnected1 = 0; |
---|
1101 | uint16_t nconnected2 = 0; |
---|
1102 | |
---|
1103 | vector<char> stat1(40); |
---|
1104 | vector<char> stat2(40); |
---|
1105 | for (BoardList::const_iterator i=fBoards.begin(); i!=fBoards.end(); i++) |
---|
1106 | { |
---|
1107 | const ConnectionFAD &c = *i->second.second; |
---|
1108 | |
---|
1109 | const int &idx = i->first; |
---|
1110 | |
---|
1111 | // FIXME: There is a difference between |
---|
1112 | // "connecting" and "disconnected" |
---|
1113 | |
---|
1114 | // Check conistency eb/fadctrl |
---|
1115 | |
---|
1116 | // ----- Command socket ----- |
---|
1117 | if (c.IsConnecting()) |
---|
1118 | { |
---|
1119 | stat1[idx] = 1; |
---|
1120 | nconnecting1++; |
---|
1121 | } |
---|
1122 | if (c.IsConnected()) |
---|
1123 | { |
---|
1124 | stat1[idx] = 2; |
---|
1125 | nconnected1++; |
---|
1126 | } |
---|
1127 | |
---|
1128 | // ----- Event builder ----- |
---|
1129 | if (!IsConnected(idx) && !IsDisconnected(idx)) |
---|
1130 | { |
---|
1131 | stat2[idx] = 1; |
---|
1132 | nconnecting2++; |
---|
1133 | } |
---|
1134 | |
---|
1135 | if (IsConnected(idx)) |
---|
1136 | { |
---|
1137 | stat2[idx] = 2; |
---|
1138 | nconnected2++; |
---|
1139 | } |
---|
1140 | } |
---|
1141 | |
---|
1142 | // ===== Send connection status via dim ===== |
---|
1143 | |
---|
1144 | if (fStatus1!=stat1 || fStatus2!=stat2) |
---|
1145 | { |
---|
1146 | fStatus1 = stat1; |
---|
1147 | fStatus2 = stat2; |
---|
1148 | UpdateConnectionStatus(); |
---|
1149 | } |
---|
1150 | |
---|
1151 | // ===== Return connection status ===== |
---|
1152 | |
---|
1153 | if (nconnected1==fBoards.size() && nconnected2==fBoards.size()) |
---|
1154 | return FAD::kConnected; |
---|
1155 | |
---|
1156 | if (nconnected1==0 && nconnected2==0) |
---|
1157 | return FAD::kDisconnected; |
---|
1158 | |
---|
1159 | // FIXME: Evaluate event builder status |
---|
1160 | return FAD::kConnecting; |
---|
1161 | } |
---|
1162 | |
---|
1163 | void AddEndpoint(const string &addr) |
---|
1164 | { |
---|
1165 | if (fBoards.size()==40) |
---|
1166 | { |
---|
1167 | T::Warn("Not more than 40 slots allowed."); |
---|
1168 | return; |
---|
1169 | } |
---|
1170 | |
---|
1171 | int i=0; |
---|
1172 | while (1) |
---|
1173 | { |
---|
1174 | const BoardList::const_iterator v = fBoards.find(i); |
---|
1175 | if (v==fBoards.end()) |
---|
1176 | break; |
---|
1177 | i++; |
---|
1178 | } |
---|
1179 | |
---|
1180 | fBoards[i] = make_pair(addr, new ConnectionFAD(*this, *this)); |
---|
1181 | fBoards[i].second->SetVerbose(fIsVerbose); |
---|
1182 | fBoards[i].second->SetHexOutput(fIsHexOutput); |
---|
1183 | fBoards[i].second->SetDataOutput(fIsDataOutput); |
---|
1184 | } |
---|
1185 | |
---|
1186 | |
---|
1187 | |
---|
1188 | public: |
---|
1189 | StateMachineFAD(ostream &out=cout) : |
---|
1190 | T(out, "FAD_CONTROL"), EventBuilderWrapper(static_cast<MessageImp&>(*this)), ba::io_service::work(static_cast<ba::io_service&>(*this)), |
---|
1191 | fStatus1(40), fStatus2(40) |
---|
1192 | { |
---|
1193 | // ba::io_service::work is a kind of keep_alive for the loop. |
---|
1194 | // It prevents the io_service to go to stopped state, which |
---|
1195 | // would prevent any consecutive calls to run() |
---|
1196 | // or poll() to do nothing. reset() could also revoke to the |
---|
1197 | // previous state but this might introduce some overhead of |
---|
1198 | // deletion and creation of threads and more. |
---|
1199 | |
---|
1200 | // State names |
---|
1201 | T::AddStateName(FAD::kDisconnected, "Disconnected", |
---|
1202 | "All enabled FAD boards are disconnected."); |
---|
1203 | |
---|
1204 | T::AddStateName(FAD::kConnected, "Connected", |
---|
1205 | "All enabled FAD boards are connected.."); |
---|
1206 | |
---|
1207 | T::AddStateName(FAD::kConnecting, "Connecting", |
---|
1208 | "Only some enabled FAD boards are connected."); |
---|
1209 | |
---|
1210 | // FAD Commands |
---|
1211 | T::AddEvent("ENABLE_SRCLK", "B:1") |
---|
1212 | (boost::bind(&StateMachineFAD::CmdEnable, this, _1, ConnectionFAD::kCmdSrclk)) |
---|
1213 | ("Set SRCLK"); |
---|
1214 | T::AddEvent("ENABLE_SCLK", "B:1") |
---|
1215 | (boost::bind(&StateMachineFAD::CmdEnable, this, _1, ConnectionFAD::kCmdSclk)) |
---|
1216 | ("Set SCLK"); |
---|
1217 | T::AddEvent("ENABLE_DRS", "B:1") |
---|
1218 | (boost::bind(&StateMachineFAD::CmdEnable, this, _1, ConnectionFAD::kCmdDrsEnable)) |
---|
1219 | ("Switch Domino wave"); |
---|
1220 | T::AddEvent("ENABLE_DWRITE", "B:1") |
---|
1221 | (boost::bind(&StateMachineFAD::CmdEnable, this, _1, ConnectionFAD::kCmdDwrite)) |
---|
1222 | ("Set Dwrite (possibly high / always low)"); |
---|
1223 | T::AddEvent("SET_DEBUG_MODE", "B:1") |
---|
1224 | (boost::bind(&StateMachineFAD::CmdEnable, this, _1, ConnectionFAD::kCmdSocket)) |
---|
1225 | ("Set debug mode (yes: dump events through command socket, no=dump events through other sockets)"); |
---|
1226 | T::AddEvent("ENABLE_TRIGGER_LINE", "B:1") |
---|
1227 | (boost::bind(&StateMachineFAD::CmdEnable, this, _1, ConnectionFAD::kCmdTriggerLine)) |
---|
1228 | ("Incoming triggers can be accepted/will not be accepted"); |
---|
1229 | T::AddEvent("SET_TRIGGER_RATE", "I:1") |
---|
1230 | (boost::bind(&StateMachineFAD::SetTriggerRate, this, _1)) |
---|
1231 | ("Enable continous trigger"); |
---|
1232 | T::AddEvent("SEND_SINGLE_TRIGGER") |
---|
1233 | (boost::bind(&StateMachineFAD::Trigger, this, 1)) |
---|
1234 | ("Issue software triggers"); |
---|
1235 | T::AddEvent("SEND_N_TRIGGERS", "I") |
---|
1236 | (boost::bind(&StateMachineFAD::SendTriggers, this, _1)) |
---|
1237 | ("Issue software triggers"); |
---|
1238 | T::AddEvent("START", "") |
---|
1239 | (boost::bind(&StateMachineFAD::StartRun, this, _1, true)) |
---|
1240 | ("Set FAD DAQ mode. when started, no configurations must be send."); |
---|
1241 | T::AddEvent("STOP") |
---|
1242 | (boost::bind(&StateMachineFAD::StartRun, this, _1, false)) |
---|
1243 | (""); |
---|
1244 | T::AddEvent("PHASE_SHIFT", "S:1") |
---|
1245 | (boost::bind(&StateMachineFAD::PhaseShift, this, _1)) |
---|
1246 | ("Adjust ADC phase (in 'steps')"); |
---|
1247 | |
---|
1248 | T::AddEvent("CONTINOUS_TRIGGER_ON") |
---|
1249 | (boost::bind(&StateMachineFAD::Cmd, this, ConnectionFAD::kCmdContTriggerOn)) |
---|
1250 | (""); |
---|
1251 | T::AddEvent("CONTINOUS_TRIGGER_OFF") |
---|
1252 | (boost::bind(&StateMachineFAD::Cmd, this, ConnectionFAD::kCmdContTriggerOff)) |
---|
1253 | (""); |
---|
1254 | |
---|
1255 | T::AddEvent("RESET_TRIGGER_ID") |
---|
1256 | (boost::bind(&StateMachineFAD::Cmd, this, ConnectionFAD::kCmdResetTriggerId)) |
---|
1257 | (""); |
---|
1258 | |
---|
1259 | T::AddEvent("SET_REGISTER", "I:2") |
---|
1260 | (boost::bind(&StateMachineFAD::SetRegister, this, _1)) |
---|
1261 | ("set register to value" |
---|
1262 | "|addr[short]:Address of register" |
---|
1263 | "|val[short]:Value to be set"); |
---|
1264 | |
---|
1265 | // FIXME: Maybe add a mask which channels should be set? |
---|
1266 | T::AddEvent("SET_REGION_OF_INTEREST", "I:2") |
---|
1267 | (boost::bind(&StateMachineFAD::SetRoi, this, _1)) |
---|
1268 | ("Set region-of-interest to value" |
---|
1269 | "|addr[short]:Address of register" |
---|
1270 | "|val[short]:Value to be set"); |
---|
1271 | |
---|
1272 | // FIXME: Maybe add a mask which channels should be set? |
---|
1273 | T::AddEvent("SET_DAC_VALUE", "I:2") |
---|
1274 | (boost::bind(&StateMachineFAD::SetDac, this, _1)) |
---|
1275 | ("Set DAC numbers in range to value" |
---|
1276 | "|addr[short]:Address of register" |
---|
1277 | "|val[short]:Value to be set"); |
---|
1278 | |
---|
1279 | // Verbosity commands |
---|
1280 | T::AddEvent("SET_VERBOSE", "B") |
---|
1281 | (boost::bind(&StateMachineFAD::SetVerbosity, this, _1)) |
---|
1282 | ("set verbosity state" |
---|
1283 | "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data"); |
---|
1284 | |
---|
1285 | T::AddEvent("SET_HEX_OUTPUT", "B") |
---|
1286 | (boost::bind(&StateMachineFAD::SetHexOutput, this, _1)) |
---|
1287 | ("enable or disable hex output for received data" |
---|
1288 | "|hexout[bool]:disable or enable hex output for received data (yes/no)"); |
---|
1289 | |
---|
1290 | T::AddEvent("SET_DATA_OUTPUT", "B") |
---|
1291 | (boost::bind(&StateMachineFAD::SetDataOutput, this, _1)) |
---|
1292 | (""); |
---|
1293 | |
---|
1294 | // Conenction commands |
---|
1295 | /* |
---|
1296 | T::AddEvent("ENABLE", "S:1;B:1", FAD::kDisconnected) |
---|
1297 | (boost::bind(&StateMachineFAD::Enable, this, _1)) |
---|
1298 | ("");*/ |
---|
1299 | |
---|
1300 | T::AddEvent("CONNECT", FAD::kDisconnected) |
---|
1301 | (boost::bind(&StateMachineFAD::Connect, this)) |
---|
1302 | (""); |
---|
1303 | |
---|
1304 | T::AddEvent("DISCONNECT") |
---|
1305 | (boost::bind(&StateMachineFAD::Disconnect, this)) |
---|
1306 | (""); |
---|
1307 | |
---|
1308 | T::AddEvent("TEST", "S:1") |
---|
1309 | (boost::bind(&StateMachineFAD::Test, this, _1)) |
---|
1310 | (""); |
---|
1311 | |
---|
1312 | T::AddEvent("ADD_ADDRESS", "C", FAD::kDisconnected) |
---|
1313 | (boost::bind(&StateMachineFAD::AddAddress, this, _1)) |
---|
1314 | ("Add the address of a DRS4 board to the first free slot" |
---|
1315 | "|IP[string]:address in the format <address:port>"); |
---|
1316 | T::AddEvent("REMOVE_SLOT", "S:1", FAD::kDisconnected) |
---|
1317 | (boost::bind(&StateMachineFAD::RemoveSlot, this, _1)) |
---|
1318 | ("Remove the Iaddress in slot n. For a list see LIST" |
---|
1319 | "|slot[int]:Remove the address in slot n from the list"); |
---|
1320 | T::AddEvent("LIST_SLOTS") |
---|
1321 | (boost::bind(&StateMachineFAD::ListSlots, this)) |
---|
1322 | ("Print a list of all available board addressesa and whether they are enabled"); |
---|
1323 | } |
---|
1324 | |
---|
1325 | ~StateMachineFAD() |
---|
1326 | { |
---|
1327 | for (BoardList::const_iterator i=fBoards.begin(); i!=fBoards.end(); i++) |
---|
1328 | delete i->second.second; |
---|
1329 | fBoards.clear(); |
---|
1330 | } |
---|
1331 | |
---|
1332 | bool SetConfiguration(const Configuration &conf) |
---|
1333 | { |
---|
1334 | fIsVerbose = !conf.Get<bool>("quiet"); |
---|
1335 | fIsHexOutput = conf.Get<bool>("hex-out"); |
---|
1336 | fIsDataOutput = conf.Get<bool>("data-out"); |
---|
1337 | |
---|
1338 | if (!(conf.Has("base-addr") ^ conf.Has("addr"))) |
---|
1339 | { |
---|
1340 | T::Out() << kRed << "SetConfiguration - Only --base-addr or --addr allowed." << endl; |
---|
1341 | return false; |
---|
1342 | } |
---|
1343 | |
---|
1344 | if (conf.Has("base-addr")) |
---|
1345 | { |
---|
1346 | const string base = conf.Get<string>("base-addr"); |
---|
1347 | |
---|
1348 | const size_t p0 = base.find_first_of(':'); |
---|
1349 | const size_t p1 = base.find_last_of(':'); |
---|
1350 | |
---|
1351 | if (p0==string::npos || p0!=p1) |
---|
1352 | { |
---|
1353 | T::Out() << kRed << "SetConfiguration - Wrong format of argument --base-addr ('host:port' expected)" << endl; |
---|
1354 | return false; |
---|
1355 | } |
---|
1356 | |
---|
1357 | tcp::resolver resolver(get_io_service()); |
---|
1358 | |
---|
1359 | boost::system::error_code ec; |
---|
1360 | |
---|
1361 | const tcp::resolver::query query(base.substr(0, p0), base.substr(p0+1)); |
---|
1362 | const tcp::resolver::iterator iterator = resolver.resolve(query, ec); |
---|
1363 | |
---|
1364 | if (ec) |
---|
1365 | { |
---|
1366 | T::Out() << " " << ec.message() << " (" << ec << ")"; |
---|
1367 | return false; |
---|
1368 | } |
---|
1369 | |
---|
1370 | const tcp::endpoint endpoint = *iterator; |
---|
1371 | |
---|
1372 | const ba::ip::address_v4::bytes_type ip = endpoint.address().to_v4().to_bytes(); |
---|
1373 | |
---|
1374 | if (ip[2]>250 || ip[3]>244) |
---|
1375 | { |
---|
1376 | T::Out() << kRed << "SetConfiguration - IP address given by --base-addr out-of-range." << endl; |
---|
1377 | return false; |
---|
1378 | } |
---|
1379 | |
---|
1380 | for (int crate=0; crate<2; crate++) |
---|
1381 | for (int board=0; board<10; board++) |
---|
1382 | { |
---|
1383 | //if (crate==0 && board==2) |
---|
1384 | // continue; |
---|
1385 | |
---|
1386 | ostringstream str; |
---|
1387 | str << (int)ip[0] << "." << (int)ip[1] << "."; |
---|
1388 | str << (int)(ip[2]+crate) << "." << (int)(ip[3]+board) << ":"; |
---|
1389 | str << endpoint.port(); |
---|
1390 | |
---|
1391 | AddEndpoint(str.str()); |
---|
1392 | } |
---|
1393 | } |
---|
1394 | |
---|
1395 | if (conf.Has("addr")) |
---|
1396 | { |
---|
1397 | const vector<string> addrs = conf.Get<vector<string>>("addr"); |
---|
1398 | for (vector<string>::const_iterator i=addrs.begin(); i<addrs.end(); i++) |
---|
1399 | AddEndpoint(*i); |
---|
1400 | } |
---|
1401 | |
---|
1402 | EnableAll(); |
---|
1403 | |
---|
1404 | return true; |
---|
1405 | } |
---|
1406 | |
---|
1407 | }; |
---|
1408 | |
---|
1409 | // ------------------------------------------------------------------------ |
---|
1410 | |
---|
1411 | |
---|
1412 | void RunThread(StateMachineImp *io_service) |
---|
1413 | { |
---|
1414 | // This is necessary so that the StateMachien Thread can signal the |
---|
1415 | // Readline to exit |
---|
1416 | io_service->Run(); |
---|
1417 | Readline::Stop(); |
---|
1418 | } |
---|
1419 | |
---|
1420 | template<class S> |
---|
1421 | int RunDim(Configuration &conf) |
---|
1422 | { |
---|
1423 | /* |
---|
1424 | initscr(); // Start curses mode |
---|
1425 | cbreak(); // Line buffering disabled, Pass on |
---|
1426 | intrflush(stdscr, FALSE); |
---|
1427 | start_color(); // Initialize ncurses colors |
---|
1428 | use_default_colors(); // Assign terminal default colors to -1 |
---|
1429 | for (int i=1; i<8; i++) |
---|
1430 | init_pair(i, i, -1); // -1: def background |
---|
1431 | scrollok(stdscr, true); |
---|
1432 | */ |
---|
1433 | |
---|
1434 | WindowLog wout; |
---|
1435 | |
---|
1436 | //log.SetWindow(stdscr); |
---|
1437 | if (conf.Has("log")) |
---|
1438 | if (!wout.OpenLogFile(conf.Get<string>("log"))) |
---|
1439 | wout << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl; |
---|
1440 | |
---|
1441 | // Start io_service.Run to use the StateMachineImp::Run() loop |
---|
1442 | // Start io_service.run to only use the commandHandler command detaching |
---|
1443 | StateMachineFAD<S> io_service(wout); |
---|
1444 | if (!io_service.SetConfiguration(conf)) |
---|
1445 | return -1; |
---|
1446 | |
---|
1447 | io_service.Run(); |
---|
1448 | |
---|
1449 | return 0; |
---|
1450 | } |
---|
1451 | |
---|
1452 | template<class T, class S> |
---|
1453 | int RunShell(Configuration &conf) |
---|
1454 | { |
---|
1455 | static T shell(conf.GetName().c_str(), conf.Get<int>("console")!=1); |
---|
1456 | |
---|
1457 | WindowLog &win = shell.GetStreamIn(); |
---|
1458 | WindowLog &wout = shell.GetStreamOut(); |
---|
1459 | |
---|
1460 | if (conf.Has("log")) |
---|
1461 | if (!wout.OpenLogFile(conf.Get<string>("log"))) |
---|
1462 | win << kRed << "ERROR - Couldn't open log-file " << conf.Get<string>("log") << ": " << strerror(errno) << endl; |
---|
1463 | |
---|
1464 | StateMachineFAD<S> io_service(wout); |
---|
1465 | if (!io_service.SetConfiguration(conf)) |
---|
1466 | return -1; |
---|
1467 | |
---|
1468 | shell.SetReceiver(io_service); |
---|
1469 | |
---|
1470 | boost::thread t(boost::bind(RunThread, &io_service)); |
---|
1471 | //boost::thread t(boost::bind(&StateMachineFAD<S>::Run, &io_service)); |
---|
1472 | |
---|
1473 | shell.Run(); // Run the shell |
---|
1474 | io_service.Stop(); // Signal Loop-thread to stop |
---|
1475 | |
---|
1476 | // Wait until the StateMachine has finished its thread |
---|
1477 | // before returning and destroying the dim objects which might |
---|
1478 | // still be in use. |
---|
1479 | t.join(); |
---|
1480 | |
---|
1481 | return 0; |
---|
1482 | } |
---|
1483 | |
---|
1484 | void SetupConfiguration(Configuration &conf) |
---|
1485 | { |
---|
1486 | const string n = conf.GetName()+".log"; |
---|
1487 | |
---|
1488 | po::options_description config("Program options"); |
---|
1489 | config.add_options() |
---|
1490 | ("dns", var<string>("localhost"), "Dim nameserver host name (Overwites DIM_DNS_NODE environment variable)") |
---|
1491 | ("log,l", var<string>(n), "Write log-file") |
---|
1492 | ("no-dim,d", po_switch(), "Disable dim services") |
---|
1493 | ("console,c", var<int>(), "Use console (0=shell, 1=simple buffered, X=simple unbuffered)") |
---|
1494 | ; |
---|
1495 | |
---|
1496 | po::options_description control("FTM control options"); |
---|
1497 | control.add_options() |
---|
1498 | // ("addr,a", var<string>("localhost:5000"), "Network address of FTM") |
---|
1499 | ("quiet,q", po_bool(), "Disable printing contents of all received messages in clear text.") |
---|
1500 | ("hex-out", po_bool(), "Enable printing contents of all printed messages also as hex data.") |
---|
1501 | ("data-out", po_bool(), "Enable printing received event data.") |
---|
1502 | ("addr", vars<string>(), "Network address of FAD") |
---|
1503 | ("base-addr", var<string>(), "Base address of all FAD") |
---|
1504 | ; |
---|
1505 | |
---|
1506 | conf.AddEnv("dns", "DIM_DNS_NODE"); |
---|
1507 | |
---|
1508 | conf.AddOptions(config); |
---|
1509 | conf.AddOptions(control); |
---|
1510 | } |
---|
1511 | |
---|
1512 | void PrintUsage() |
---|
1513 | { |
---|
1514 | cout << |
---|
1515 | "The fadctrl controls the FAD boards.\n" |
---|
1516 | "\n" |
---|
1517 | "The default is that the program is started without user intercation. " |
---|
1518 | "All actions are supposed to arrive as DimCommands. Using the -c " |
---|
1519 | "option, a local shell can be initialized. With h or help a short " |
---|
1520 | "help message about the usuage can be brought to the screen.\n" |
---|
1521 | "\n" |
---|
1522 | "Usage: fadctrl [-c type] [OPTIONS]\n" |
---|
1523 | " or: fadctrl [OPTIONS]\n"; |
---|
1524 | cout << endl; |
---|
1525 | } |
---|
1526 | |
---|
1527 | void PrintHelp() |
---|
1528 | { |
---|
1529 | /* Additional help text which is printed after the configuration |
---|
1530 | options goes here */ |
---|
1531 | } |
---|
1532 | |
---|
1533 | int main(int argc, const char* argv[]) |
---|
1534 | { |
---|
1535 | Configuration conf(argv[0]); |
---|
1536 | SetupConfiguration(conf); |
---|
1537 | |
---|
1538 | po::variables_map vm; |
---|
1539 | try |
---|
1540 | { |
---|
1541 | vm = conf.Parse(argc, argv); |
---|
1542 | } |
---|
1543 | #if BOOST_VERSION > 104000 |
---|
1544 | catch (po::multiple_occurrences &e) |
---|
1545 | { |
---|
1546 | cout << "Error: " << e.what() << " of '" << e.get_option_name() << "' option." << endl; |
---|
1547 | cout << endl; |
---|
1548 | return -1; |
---|
1549 | } |
---|
1550 | #endif |
---|
1551 | catch (std::exception &e) |
---|
1552 | { |
---|
1553 | cout << "Error: " << e.what() << endl; |
---|
1554 | cout << endl; |
---|
1555 | |
---|
1556 | return -1; |
---|
1557 | } |
---|
1558 | |
---|
1559 | if (conf.HasPrint()) |
---|
1560 | return -1; |
---|
1561 | |
---|
1562 | if (conf.HasVersion()) |
---|
1563 | { |
---|
1564 | FACT::PrintVersion(argv[0]); |
---|
1565 | return -1; |
---|
1566 | } |
---|
1567 | |
---|
1568 | if (conf.HasHelp()) |
---|
1569 | { |
---|
1570 | PrintHelp(); |
---|
1571 | return -1; |
---|
1572 | } |
---|
1573 | |
---|
1574 | Dim::Setup(conf.Get<string>("dns")); |
---|
1575 | |
---|
1576 | // try |
---|
1577 | { |
---|
1578 | // No console access at all |
---|
1579 | if (!conf.Has("console")) |
---|
1580 | { |
---|
1581 | if (conf.Get<bool>("no-dim")) |
---|
1582 | return RunDim<StateMachine>(conf); |
---|
1583 | else |
---|
1584 | return RunDim<StateMachineDim>(conf); |
---|
1585 | } |
---|
1586 | // Cosole access w/ and w/o Dim |
---|
1587 | if (conf.Get<bool>("no-dim")) |
---|
1588 | { |
---|
1589 | if (conf.Get<int>("console")==0) |
---|
1590 | return RunShell<LocalShell, StateMachine>(conf); |
---|
1591 | else |
---|
1592 | return RunShell<LocalConsole, StateMachine>(conf); |
---|
1593 | } |
---|
1594 | else |
---|
1595 | { |
---|
1596 | if (conf.Get<int>("console")==0) |
---|
1597 | return RunShell<LocalShell, StateMachineDim>(conf); |
---|
1598 | else |
---|
1599 | return RunShell<LocalConsole, StateMachineDim>(conf); |
---|
1600 | } |
---|
1601 | } |
---|
1602 | /* catch (std::exception& e) |
---|
1603 | { |
---|
1604 | cerr << "Exception: " << e.what() << endl; |
---|
1605 | return -1; |
---|
1606 | }*/ |
---|
1607 | |
---|
1608 | return 0; |
---|
1609 | } |
---|