source: trunk/FACT++/src/biasctrl.cc@ 12253

Last change on this file since 12253 was 12249, checked in by tbretz, 14 years ago
Added some Dim descriptions and a new service propagating the nominal voltages.
File size: 65.7 KB
Line 
1#include <functional>
2
3#include <boost/bind.hpp>
4
5#include "Dim.h"
6#include "Event.h"
7#include "Shell.h"
8#include "StateMachineDim.h"
9#include "ConnectionUSB.h"
10#include "Configuration.h"
11#include "Console.h"
12#include "Converter.h"
13#include "PixelMap.h"
14
15#include "tools.h"
16
17#include "LocalControl.h"
18#include "HeadersBIAS.h"
19
20namespace ba = boost::asio;
21namespace bs = boost::system;
22namespace dummy = ba::placeholders;
23
24using namespace std::placeholders;
25using namespace std;
26using namespace BIAS;
27
28//#define DEBUG
29
30// ------------------------------------------------------------------------
31
32class ConnectionBias : public ConnectionUSB
33{
34 boost::asio::deadline_timer fSyncTimer;
35 boost::asio::deadline_timer fRampTimer;
36 boost::asio::deadline_timer fUpdateTimer;
37
38 vector<uint8_t> fBuffer;
39 vector<uint8_t> fBufferRamp;
40 vector<uint8_t> fBufferUpdate;
41
42 bool fIsVerbose;
43
44 vector<uint16_t> fVoltCmd; // Current command voltage in DAC units (12bit = 90V)
45
46 vector<bool> fPresent;
47
48 int64_t fWrapCounter;
49 int64_t fSendCounter;
50
51 int16_t fGlobalVoltCmd; // Command value to be reached
52// uint16_t fExpertVoltRef; // Command value to be reached
53
54 int16_t fRampStep;
55 int16_t fRampTime;
56
57 uint16_t fUpdateTime;
58 uint16_t fSyncTime;
59
60 bool fIsInitializing;
61 bool fIsRamping;
62 bool fWaitingForAnswer;
63
64 vector<uint64_t> fCounter;
65
66protected:
67 vector<uint16_t> fVolt; // Current voltage in DAC units (12bit = 90V)
68 vector<uint16_t> fVoltRef; // Current reference voltage in DAC units (12bit = 90V)
69 vector<uint16_t> fVoltGapd; // Nominal G-APD voltages at 25deg C
70
71 vector<int16_t> fCurrent; // Current in ADC units (12bit = 5mA)
72
73 uint16_t fVoltMaxAbs;
74 uint16_t fVoltMaxRel;
75
76 virtual void UpdateA()
77 {
78 }
79
80 virtual void UpdateV()
81 {
82 }
83
84 virtual void UpdateVgapd()
85 {
86 }
87
88private:
89 bool CheckChDac(const string &cmd, uint16_t dac, uint16_t ch=0)
90 {
91 ostringstream str;
92 str << cmd << " - ";
93
94 if (ch>=kNumChannels)
95 {
96 str << "Channel " << ch << " out of range [0,416].";
97 Error(str);
98 return false;
99 }
100
101 if (dac>kMaxDac)
102 {
103 str << "DAC value " << dac << " out of range [0,4095].";
104 Error(str);
105 return false;
106 }
107 if (dac>fVoltMaxAbs)
108 {
109 str << "DAC value " << dac << " exceeds allowed absolute maximum of " << fVoltMaxAbs;
110 Error(str);
111 return false;
112 }
113 if (dac>fVoltGapd[ch]+fVoltMaxRel)
114 {
115 str << "DAC value " << dac << " exceeds allowed channel maximum of " << fVoltGapd[ch] << " + " << fVoltMaxRel;
116 Error(str);
117 return false;
118 }
119
120 return true;
121 }
122
123 vector<char> GetCmd(uint16_t board, uint16_t channel, Command_t cmd, uint16_t dac=0)
124 {
125 vector<char> data(3);
126
127 /*
128 if (board>kNumBoards)
129 return;
130 if (channel>kNumChannelsPerBoard)
131 return;
132 if (dac>0xfff)
133 return;
134 */
135
136 data[0] = (cmd<<5) | (board<<1) | (((channel&16)>>4) & 1);
137 data[1] = (channel<<4) | (dac>>8);
138 data[2] = dac&0xff;
139
140 return data;
141 }
142
143 vector<char> GetCmd(Command_t cmd, uint16_t id=0, uint16_t dac=0)
144 {
145 const unsigned int board = id/kNumChannelsPerBoard;
146 const unsigned int channel = id%kNumChannelsPerBoard;
147
148 return GetCmd(board, channel, cmd, dac);
149 }
150
151 bool CheckMessageLength(int received, int expected, const string &msg)
152 {
153 if (received==expected)
154 return true;
155
156 ostringstream str;
157 str << msg << ": Expected " << expected << " bytes in answer, but got " << received << endl;
158 Error(str);
159
160 return false;
161 }
162
163 bool EvalAnswer(const uint8_t *answer, uint16_t id, int command)
164 {
165 answer += id*3;
166
167 const uint16_t status = (answer[0]>>7)&1;
168 const uint16_t wrap = (answer[0]>>4)&7;
169 const uint16_t ddd = ((uint16_t(answer[0])&0xf)<<8) | answer[1];
170 const uint16_t error = (answer[2]>>4)&0xf;
171 const uint16_t board = answer[2]&0xf;
172
173 // 0x10 00 7f
174 // status = 0
175 // wrap = 1
176 // ddd = 0
177 // error = not present
178 // board = 15
179
180 /*
181 Out() << dec << setw(2) << board << '|' << wrap << " ";
182 if (id%8==7)
183 Out() << endl;
184 */
185
186 if (fWrapCounter>=0)
187 {
188 if ((fWrapCounter+1)%8 != wrap)
189 {
190 ostringstream msg;
191 msg << "Corrupted answer (id=" << id << "): received wrap counter " << wrap << " doesn't match last one " << fWrapCounter << " ";
192 msg << " (fSendCounter=" << fSendCounter << ")";
193 Error(msg);
194 return false;
195 }
196 }
197
198 fWrapCounter = wrap;
199
200 if (command==kSynchronize)
201 {
202 ostringstream msg;
203 msg << hex << setfill('0');
204 msg << "Initial answer received: 0x";
205 msg << setw(2) << (int)answer[2];
206 msg << setw(2) << (int)answer[1];
207 msg << setw(2) << (int)answer[0];
208 Message(msg);
209
210 if (status!=0 || ddd!=0 || error!=0 || board!=0)
211 {
212 Warn("Initial answer doesn't seem to be a reset as naively expected.");
213
214 //ostringstream msg;
215 //msg << hex << setfill('0');
216 //msg << "S=" << status << " D=" << ddd << " E=" << error << " B=" << board;
217 //Message(msg);
218 }
219
220 fSendCounter = wrap;
221
222 msg.str("");
223 msg << "Setting fSendCounter to " << wrap;
224 Info(msg);
225
226 return true;
227 }
228
229 if (error==0x8) // No device
230 {
231 Message("Reset button on crate pressed!");
232 SetZero();
233 return true;
234 }
235
236 if (command==kCmdReset)
237 {
238 if (status==0 && ddd==0 && error==0 && board==0)
239 {
240 Message("Reset successfully executed.");
241 return true;
242 }
243
244 Warn("Answer to 'reset' command contains unexpected data.");
245 return false;
246 }
247
248 if (command==kCmdGlobalSet)
249 {
250 if (status==0 && ddd==0 && error==0 && board==0)
251 {
252 for (int i=0; i<kNumChannels; i++)
253 fVolt[i] = fGlobalVoltCmd;
254
255 fGlobalVoltCmd = -1;
256
257 return true;
258 }
259
260 Warn("Answer to 'global set' command contains unexpected data.");
261 return false;
262 }
263
264 if ((command&0xff)==kExpertChannelSet)
265 id = command>>8;
266
267 const int cmd = command&3;
268
269 if (cmd==kCmdRead || cmd==kCmdChannelSet)
270 {
271 if (board!=id/kNumChannelsPerBoard)
272 {
273 ostringstream out;
274 out << "Talked to board " << id/kNumChannelsPerBoard << ", but got answer from board " << board << " (fSendCounter=" << fSendCounter << ")";
275 Error(out);
276 return false;
277 }
278
279 // Not present
280 if (error==0x7 || error==0xf)
281 {
282 fPresent[board] = false;
283 fCurrent[id] = 0x8000;
284 return true;
285 }
286
287 // There is no -0 therefore we make a trick and replace it by -1.
288 // This is not harmfull, because typical zero currents are in the
289 // order of one to three bits anyway and they are never stable.
290 fCurrent[id] = status ? -(ddd==0?1:ddd) : ddd;
291 fPresent[board] = true;
292 }
293
294 if (cmd==kCmdChannelSet)
295 fVolt[id] = fVoltCmd[id];
296
297 return true;
298
299 }
300
301private:
302 void HandleReceivedData(const vector<uint8_t> &buf, size_t bytes_received, int command, int send_counter)
303 {
304#ifdef DEBUG
305 ofstream fout("received.txt", ios::app);
306 fout << Time() << ": ";
307 for (unsigned int i=0; i<bytes_received; i++)
308 fout << hex << setfill('0') << setw(2) << (uint16_t)buf[i];
309 fout << endl;
310#endif
311
312 // Now print the received message if requested by the user
313 if (fIsVerbose/* && command!=kUpdate*/)
314 {
315 Out() << endl << kBold << dec << "Data received (size=" << bytes_received << "):" << endl;
316 Out() << " Command=" << command << " fWrapCounter=" << fWrapCounter << " fSendCounter=" << fSendCounter << " fIsInitializing=" << fIsInitializing << " fIsRamping=" << fIsRamping;
317 Out() << hex << setfill('0');
318
319 for (size_t i=0; i<bytes_received/3; i++)
320 {
321 if (i%8==0)
322 Out() << '\n' << setw(2) << bytes_received/24 << "| ";
323
324 Out() << setw(2) << uint16_t(buf[i*3+2]);
325 Out() << setw(2) << uint16_t(buf[i*3+1]);
326 Out() << setw(2) << uint16_t(buf[i*3+0]) << " ";
327 }
328 Out() << endl;
329 }
330
331 const int cmd = command&0xf;
332
333 // Check the number of received_byted according to the answer expected
334 if ((cmd==kSynchronize && !CheckMessageLength(bytes_received, 3, "Synchronization")) ||
335 (cmd==kCmdReset && !CheckMessageLength(bytes_received, 3, "CmdReset")) ||
336 (cmd==kCmdRead && !CheckMessageLength(bytes_received, 3*kNumChannels, "CmdRead")) ||
337 (cmd==kCmdChannelSet && !CheckMessageLength(bytes_received, 3*kNumChannels, "CmdChannelSet")) ||
338 (cmd==kExpertChannelSet && !CheckMessageLength(bytes_received, 3, "CmdExpertChannelSet")))
339 {
340 CloseImp(false);
341 return;
342 }
343
344 // Now evaluate the whole bunch of messages
345 for (size_t i=0; i<bytes_received/3; i++)
346 {
347 if (!EvalAnswer(buf.data(), i, command))
348 {
349 CloseImp(false);
350 return;
351 }
352 }
353
354 if (command==kSynchronize)
355 {
356 Message("Stream successfully synchronized.");
357 fIsInitializing = false;
358
359 // Cancel sending of the next 0
360 fSyncTimer.cancel();
361 fCounter[0]++;
362
363 // Start continous reading of all channels
364 ScheduleUpdate(100);
365 return;
366 }
367
368 if (send_counter%8 != fWrapCounter)
369 {
370 ostringstream msg;
371 msg << "Corrupted answer: received wrap counter " << fWrapCounter << " is not send counter " << send_counter << "%8.";
372 Error(msg);
373 CloseImp(false);
374 }
375
376
377 // Check if new values have been received
378 if (cmd==kCmdRead || cmd==kCmdChannelSet || cmd==kExpertChannelSet)
379 {
380 UpdateV();
381 UpdateA();
382 }
383
384 // ----- Take action depending on what is going on -----
385
386 if (command==kCmdReset)
387 {
388 Message("Reset command successfully answered... restarting automatic readout.");
389
390 fCounter[1]++;
391
392 // Re-start cyclic reading of values after a short time
393 // to allow the currents to become stable. This ensures that
394 // we get an update soon but wait long enough to get reasonable
395 // values
396 fUpdateTimer.cancel();
397 ScheduleUpdate(100);
398 }
399
400 if (command==kResetChannels)
401 {
402 ExpertReset(false);
403 fCounter[5]++;
404 }
405
406 if (command==kUpdate)
407 {
408 ScheduleUpdate(fUpdateTime);
409 fCounter[2]++;
410 }
411
412 // If we are ramping, schedule a new ramp step
413 if (command==kCmdChannelSet && fIsRamping)
414 {
415 bool oc = false;
416 for (int ch=0; ch<kNumChannels; ch++)
417 if (fPresent[ch/kNumChannelsPerBoard] && fCurrent[ch]<0)
418 oc = true;
419
420 if (oc)
421 {
422 Warn("OverCurrent detected - ramping stopped.");
423 fIsRamping = false;
424 }
425 else
426 ScheduleRampStep();
427
428 fCounter[3]++;
429 }
430
431 if (command==kCmdRead)
432 fCounter[4]++;
433
434 if ((command&0xff)==kExpertChannelSet)
435 fCounter[6]++;
436
437 if (command==kCmdGlobalSet)
438 fCounter[7]++;
439
440 }
441
442 void HandleReceivedData(const bs::error_code& err, size_t bytes_received, int command, int send_counter)
443 {
444 // Do not schedule a new read if the connection failed.
445 if (bytes_received==0 || err)
446 {
447 if (err==ba::error::eof)
448 {
449 ostringstream msg;
450 msg << "Connection closed by remote host (BIAS, fSendCounter=" << fSendCounter << ")";
451 Warn(msg);
452 }
453
454 // 107: Transport endpoint is not connected (bs::error_code(107, bs::system_category))
455 // 125: Operation canceled
456 if (err && err!=ba::error::eof && // Connection closed by remote host
457 err!=ba::error::basic_errors::not_connected && // Connection closed by remote host
458 err!=ba::error::basic_errors::operation_aborted) // Connection closed by us
459 {
460 ostringstream str;
461 str << "Reading from " << URL() << ": " << err.message() << " (" << err << ")";// << endl;
462 Error(str);
463 }
464 CloseImp(false);//err!=ba::error::basic_errors::operation_aborted);
465 return;
466 }
467
468 // Check if the number of received bytes is correctly dividable by 3
469 // This check should never fail - just for sanity
470 if (bytes_received%3)
471 {
472 Error("Number of received bytes not a multiple of 3, can't read data.");
473 CloseImp(false);
474 return;
475 }
476
477 // We have three different parallel streams:
478 // 1) The setting of voltages due to ramping
479 // 2) The cynclic request of the currents
480 // 3) Answers to commands
481 // For each of these three streams an own buffer is needed, otherwise
482 // a buffer which is filled in the background might overwrite
483 // a buffer which is currently evaluated. In all other programs
484 // this is no problem because the boards don't answer and if
485 // they do the answer identifies itself. Consequently,
486 // there is always only one async_read in progress. Here we have
487 // three streams which need to be connected somehow to the
488 // commands.
489
490 // Maybe a better possibility would be to setup a command
491 // queue (each command will be queued in a buffer)
492 // and whenever an answer has been received, a new async_read is
493 // scheduled.
494 // Build a command queue<pair<command, vector<char>>>
495 /// This replaces the send counter and the command argument
496 // in handleReceivedData
497
498 switch (command&0xff)
499 {
500 case kSynchronize:
501 case kCmdReset:
502 case kExpertChannelSet:
503 case kCmdGlobalSet:
504 case kResetChannels:
505 case kCmdRead:
506 fWaitingForAnswer = false;
507 HandleReceivedData(fBuffer, bytes_received, command, send_counter);
508 return;
509
510 case kCmdChannelSet:
511 HandleReceivedData(fBufferRamp, bytes_received, command, send_counter);
512 return;
513
514 case kUpdate:
515 HandleReceivedData(fBufferUpdate, bytes_received, command, send_counter);
516 return;
517 }
518 }
519
520 // --------------------------------------------------------------------
521
522 void HandleSyncTimer(int counter, const bs::error_code &error)
523 {
524 if (error==ba::error::basic_errors::operation_aborted)
525 {
526 if (fIsInitializing)
527 Warn("Synchronization aborted...");
528 else
529 Info("Synchronization successfull.");
530 return;
531 }
532
533 if (error)
534 {
535 ostringstream str;
536 str << "Synchronization timer: " << error.message() << " (" << error << ")";// << endl;
537 Error(str);
538
539 CloseImp(false);
540 return;
541 }
542
543 if (!is_open())
544 {
545 Warn("Synchronization in progress, but disconnected.");
546 return;
547 }
548
549 ostringstream msg;
550 msg << "Synchronization time expired (" << counter << ")";
551 Info(msg);
552
553 if (fIsInitializing)
554 {
555 PostMessage("\0", 1);
556
557 if (counter==2)
558 {
559 Error("Synchronization attempt timed out.");
560 CloseImp(false);
561 return;
562 }
563
564 ScheduleSync(counter+1);
565 return;
566 }
567
568 Info("Synchronisation successfull.");
569 }
570
571 void ScheduleSync(int counter=0)
572 {
573 fSyncTimer.expires_from_now(boost::posix_time::milliseconds(fSyncTime));
574 fSyncTimer.async_wait(boost::bind(&ConnectionBias::HandleSyncTimer, this, counter, dummy::error));
575 }
576
577 // This is called when a connection was established
578 void ConnectionEstablished()
579 {
580 // Reset everything....
581 fSendCounter = -1;
582 fWrapCounter = -1;
583 fGlobalVoltCmd = -1;
584 fIsInitializing = true;
585
586 fVolt.assign( kNumChannels, 0);
587 fVoltRef.assign(kNumChannels, 0);
588 fVoltCmd.assign(kNumChannels, 0);
589
590 // Send a single 0 (and possible two consecutive 0's
591 // to make sure we are in sync with the device)
592 PostMessage("\0", 1);
593 AsyncRead(ba::buffer(fBuffer, 3), kSynchronize, 0);//++fSendCounter);
594 fWaitingForAnswer = true;
595
596 // Wait for some time before sending the next 0
597 ScheduleSync();
598 }
599
600 // --------------------------------------------------------------------
601
602 void HandleUpdateTimer(const bs::error_code &error)
603 {
604 if (error==ba::error::basic_errors::operation_aborted)
605 {
606 Warn("Update timer aborted...");
607 fIsRamping = false;
608 return;
609 }
610
611 if (error)
612 {
613 ostringstream str;
614 str << "Update timer: " << error.message() << " (" << error << ")";// << endl;
615 Error(str);
616
617 PostClose(false);
618 return;
619 }
620
621 if (!is_open())
622 return;
623
624 if (fIsRamping)
625 ScheduleUpdate(fUpdateTime);
626 else
627 ReadAllChannels(true);
628 }
629
630 void ScheduleUpdate(int millisec)
631 {
632 fUpdateTimer.expires_from_now(boost::posix_time::milliseconds(millisec));
633 fUpdateTimer.async_wait(boost::bind(&ConnectionBias::HandleUpdateTimer, this, dummy::error));
634 }
635
636 // --------------------------------------------------------------------
637
638 void SetAllChannels(const vector<uint16_t> &dac, bool special=false)
639 {
640 vector<char> data;
641 data.reserve(kNumChannels*3);
642
643 for (int ch=0; ch<kNumChannels; ch++)
644 {
645 // FIXME: dac[ch] += calib_offset
646 const vector<char> cmd = GetCmd(kCmdChannelSet, ch, dac[ch]);
647 data.insert(data.end(), cmd.begin(), cmd.end());
648
649 fVoltCmd[ch] = dac[ch];
650 }
651
652 fSendCounter += kNumChannels;
653
654 PostMessage(data);
655 AsyncRead(ba::buffer(special ? fBuffer : fBufferRamp, kNumChannels*3),
656 special ? kResetChannels : kCmdChannelSet, fSendCounter);
657
658 if (special)
659 fWaitingForAnswer = true;
660 }
661
662 uint16_t RampOneStep(uint16_t ch)
663 {
664 if (fVoltRef[ch]>fVolt[ch])
665 return fVolt[ch]+fRampStep>fVoltRef[ch] ? fVoltRef[ch] : fVolt[ch]+fRampStep;
666
667 if (fVoltRef[ch]<fVolt[ch])
668 return fVolt[ch]-fRampStep<fVoltRef[ch] ? fVoltRef[ch] : fVolt[ch]-fRampStep;
669
670 return fVolt[ch];
671 }
672
673 bool RampOneStep()
674 {
675 if (fRampTime<0)
676 {
677 Warn("Ramping step time not yet set... ramping not started.");
678 return false;
679 }
680 if (fRampStep<0)
681 {
682 Warn("Ramping step not yet set... ramping not started.");
683 return false;
684 }
685
686 vector<uint16_t> dac(kNumChannels);
687
688 bool identical = true;
689 for (int ch=0; ch<kNumChannels; ch++)
690 {
691 dac[ch] = RampOneStep(ch);
692 if (dac[ch]!=fVolt[ch] && fPresent[ch/kNumChannelsPerBoard])
693 identical = false;
694 }
695
696 SetAllChannels(dac);
697
698 if (identical)
699 Info("Ramping: target values reached.");
700
701 return !identical;
702 }
703
704 void HandleRampTimer(const bs::error_code &error)
705 {
706 if (error==ba::error::basic_errors::operation_aborted)
707 {
708 Warn("Ramping aborted...");
709 fIsRamping = false;
710 return;
711 }
712
713 if (error)
714 {
715 ostringstream str;
716 str << "Ramping timer: " << error.message() << " (" << error << ")";// << endl;
717 Error(str);
718
719 PostClose(false);
720 return;
721 }
722
723 if (!is_open())
724 {
725 Warn("Ramping in progress, but disconnected.");
726 return;
727 }
728
729 if (!fIsRamping)
730 {
731 Error("Ramp handler called although no ramping in progress.");
732 return;
733 }
734
735 // Check whether the deadline has passed. We compare the deadline
736 // against the current time since a new asynchronous operation
737 // may have moved the deadline before this actor had a chance
738 // to run.
739 if (fRampTimer.expires_at() > ba::deadline_timer::traits_type::now())
740 return;
741
742 fIsRamping = RampOneStep();
743 }
744
745 void ScheduleRampStep()
746 {
747 fRampTimer.expires_from_now(boost::posix_time::milliseconds(fRampTime));
748 fRampTimer.async_wait(boost::bind(&ConnectionBias::HandleRampTimer, this, dummy::error));
749 }
750
751public:
752 ConnectionBias(ba::io_service& ioservice, MessageImp &imp) : ConnectionUSB(ioservice, imp()),
753 fSyncTimer(ioservice),
754 fRampTimer(ioservice),
755 fUpdateTimer(ioservice),
756 fBuffer(3*kNumChannels),
757 fBufferRamp(3*kNumChannels),
758 fBufferUpdate(3*kNumChannels),
759 fIsVerbose(false),
760 fVoltCmd(kNumChannels),
761 //fRefCurrent(kNumChannels),
762 fPresent(kNumBoards),
763 fRampStep(-1),
764 fRampTime(-1),
765 fUpdateTime(3000),
766 fSyncTime(333),
767 fIsRamping(false),
768 fWaitingForAnswer(false),
769 fCounter(8),
770 fVolt(kNumChannels),
771 fVoltRef(kNumChannels),
772 fVoltGapd(kNumChannels),
773 fCurrent(kNumChannels)
774 {
775 SetLogStream(&imp);
776 }
777
778 void OverCurrentReset()
779 {
780 if (fWaitingForAnswer)
781 {
782 Error("Answer on last command not yet received.");
783 return;
784 }
785
786 if (fIsRamping)
787 {
788 Warn("OverCurrentReset - Ramping in progres.");
789 RampStop();
790 }
791
792 vector<uint16_t> dac(kNumChannels);
793
794 for (int ch=0; ch<kNumChannels; ch++)
795 dac[ch] = fCurrent[ch]<0 ? 0 : fVolt[ch];
796
797 SetAllChannels(dac, true);
798 }
799
800 void ReadAllChannels(bool special = false)
801 {
802 if (!special && fWaitingForAnswer)
803 {
804 Error("Answer on last command not yet received.");
805 return;
806 }
807
808 vector<char> data;
809 data.reserve(kNumChannels*3);
810
811 for (int ch=0; ch<kNumChannels; ch++)
812 {
813 const vector<char> cmd = GetCmd(kCmdRead, ch);
814 data.insert(data.end(), cmd.begin(), cmd.end());
815 }
816
817 fSendCounter += kNumChannels;
818
819 PostMessage(data);
820 AsyncRead(ba::buffer(special ? fBufferUpdate : fBuffer, kNumChannels*3),
821 special ? kUpdate : kCmdRead, fSendCounter);
822
823 if (!special)
824 fWaitingForAnswer = true;
825 }
826
827 // --------------------------------------------------------------------
828
829 bool ChannelSetDac(uint16_t ch, uint16_t dac)
830 {
831 if (!CheckChDac("ChannelSetDac", dac, ch))
832 return false;
833
834 fVoltRef[ch] = dac;
835
836 if (!fIsRamping)
837 fIsRamping = RampOneStep();
838
839 return true;
840 }
841
842 bool ChannelSetVolt(uint16_t ch, double volt)
843 {
844 if (volt<0 || volt>90)
845 {
846 ostringstream msg;
847 msg << "ChannelSetVolt - Given voltage " << volt << "V out of range [0V,90V].";
848 Error(msg);
849 return false;
850 }
851
852 return ChannelSetDac(ch, volt*4096/90.);
853 }
854/*
855 bool GlobalSetDac(uint16_t dac)
856 {
857 if (!CheckChDac("GlobalSetDac", dac))
858 return false;
859
860 for (size_t ch=0; ch<kNumChannels; ch++)
861 fVoltRef[ch] = dac;
862
863 if (!fIsRamping)
864 fIsRamping = RampOneStep();
865
866 return true;
867 }
868
869 bool GlobalSetVolt(float volt)
870 {
871 if (volt<0 || volt>90)
872 {
873 Error("GlobalSetVolt - Voltage out of range [0V,90V].");
874 return false;
875 }
876
877 return GlobalSetDac(volt*4096/90);
878 }
879*/
880 bool AddDac(const vector<int16_t> &dac)
881 {
882 if (dac.size()!=kNumChannels)
883 {
884 Error("AddDac - Wrong size of array.");
885 return false;
886 }
887
888 for (size_t ch=0; ch<kNumChannels; ch++)
889 {
890 if (fVoltRef[ch]+dac[ch]>kMaxDac)
891 {
892 ostringstream msg;
893 msg << "AddDac - New voltage reference " << fVoltRef[ch] << "+" << dac[ch] << " out of range [0," << kMaxDac << " for channel " << ch << ".";
894 Error(msg);
895 return false;
896 }
897
898 if (fVoltRef[ch]+dac[ch]<0)
899 fVoltRef[ch] = 0;
900 else
901 fVoltRef[ch] += dac[ch];
902 }
903
904 if (!fIsRamping)
905 fIsRamping = RampOneStep();
906
907 return true;
908 }
909
910 bool AddVolt(const vector<float> &offset)
911 {
912 vector<int16_t> dac(offset.size());
913
914 for (size_t ch=0; ch<offset.size(); ch++)
915 {
916 if (offset[ch]<-90 || offset[ch]>90)
917 {
918 ostringstream msg;
919 msg << "AddVolt - Offset voltage " << offset[ch] << "V for channel " << ch << " out of range [-90V,90V].";
920 Error(msg);
921 return false;
922 }
923 dac[ch] = offset[ch]*4096/90;
924 }
925
926 return AddDac(dac);
927 }
928
929 bool GlobalAddDac(int16_t offset)
930 {
931 return AddDac(vector<int16_t>(kNumChannels, offset));
932 }
933
934 bool GlobalAddVolt(float offset)
935 {
936 return AddVolt(vector<float>(kNumChannels, offset));
937 }
938
939 bool SetDac(const vector<int16_t> &dac)
940 {
941 if (dac.size()!=kNumChannels)
942 {
943 Error("SetDac - Wrong size of array.");
944 return false;
945 }
946
947 for (size_t ch=0; ch<kNumChannels; ch++)
948 {
949 if (!CheckChDac("SetDac", dac[ch]))
950 return false;
951
952 fVoltRef[ch] = dac[ch];
953 }
954
955 if (!fIsRamping)
956 fIsRamping = RampOneStep();
957
958 return true;
959 }
960
961 bool SetVolt(const vector<float> &volt)
962 {
963 vector<int16_t> dac(volt.size());
964
965 for (size_t ch=0; ch<volt.size(); ch++)
966 {
967 if (volt[ch]<0 || volt[ch]>90)
968 {
969 ostringstream msg;
970 msg << "SetVolt - Voltage " << volt[ch] << "V out of range [0V,90V] for channel " << ch << ".";
971 Error(msg);
972 return false;
973 }
974 dac[ch] = volt[ch]*4096/90;
975 }
976
977 return SetDac(dac);
978 }
979
980 bool GlobalSetDac(int16_t dac)
981 {
982 return SetDac(vector<int16_t>(kNumChannels, dac));
983 }
984
985 bool GlobalSetVolt(float volt)
986 {
987 return SetVolt(vector<float>(kNumChannels, volt));
988 }
989
990
991 // --------------------------------------------------------------------
992
993 bool SetGapdVoltage(float offset)
994 {
995 if (offset<-90 || offset>90)
996 {
997 ostringstream msg;
998 msg << "SetGapdVoltage - Offset voltage " << offset << "V out of range [-90V,90V].";
999 Error(msg);
1000 return false;
1001 }
1002
1003 const int16_t dac = offset*4096/90;
1004
1005 for (size_t ch=0; ch<kNumChannels; ch++)
1006 if (fVoltGapd[ch]+dac>kMaxDac)
1007 {
1008 ostringstream msg;
1009 msg << "SetGapdVoltage - New voltage reference " << fVoltGapd[ch] << "+" << dac << " out of range [0," << kMaxDac << " for channel " << ch << ".";
1010 Error(msg);
1011 return false;
1012 }
1013
1014 for (size_t ch=0; ch<kNumChannels; ch++)
1015 fVoltRef[ch] = fVoltGapd[ch]+dac<0 ? 0 : fVoltGapd[ch]+dac;
1016
1017 if (!fIsRamping)
1018 fIsRamping = RampOneStep();
1019
1020 return true;
1021 }
1022
1023 bool SetGapdReferenceCh(uint16_t ch)
1024 {
1025 if (!CheckChDac("SetGapdReferenceCh", fVoltGapd[ch], ch))
1026 return false;
1027
1028 fVoltRef[ch] = fVoltGapd[ch];
1029
1030 if (!fIsRamping)
1031 fIsRamping = RampOneStep();
1032
1033 return true;
1034 }
1035
1036
1037 void SetZero()
1038 {
1039 for (size_t ch=0; ch<kNumChannels; ch++)
1040 fVoltRef[ch] = 0;
1041
1042 if (!fIsRamping)
1043 fIsRamping = RampOneStep();
1044 }
1045
1046 bool SetNewGapdVoltage(const vector<float> &volt)
1047 {
1048 if (volt.size()!=kNumChannels)
1049 {
1050 ostringstream out;
1051 out << "SetNewGapdVoltage - Given vector has " << volt.size() << " elements - expected " << kNumChannels << endl;
1052 Error(out);
1053 return false;
1054 }
1055
1056 for (size_t i=0; i<kNumChannels; i++)
1057 fVoltGapd[i] = volt[i]*4096/90;
1058
1059 UpdateVgapd();
1060
1061 return true;
1062 }
1063
1064 // --------------------------------------------------------------------
1065
1066 void RampStop()
1067 {
1068 fRampTimer.cancel();
1069 fIsRamping = false;
1070
1071 Message("Ramping stopped.");
1072 }
1073
1074 void RampStart()
1075 {
1076 if (fIsRamping)
1077 {
1078 Warn("RampStart - Ramping already in progress... ignored.");
1079 return;
1080 }
1081
1082 fIsRamping = RampOneStep();
1083 }
1084
1085 void SetRampTime(uint16_t val)
1086 {
1087 fRampTime = val;
1088 }
1089
1090 void SetRampStep(uint16_t val)
1091 {
1092 fRampStep = val;
1093 }
1094
1095 uint16_t GetRampStepVolt() const
1096 {
1097 return fRampStep*90./4096;
1098 }
1099
1100 bool IsRamping() const { return fIsRamping; }
1101
1102 // -------------------------------------------------------------------
1103
1104 void ExpertReset(bool expert_mode=true)
1105 {
1106 if (fWaitingForAnswer)
1107 {
1108 Error("Answer on last command not yet received.");
1109 return;
1110 }
1111
1112 if (expert_mode)
1113 Warn("EXPERT MODE: Sending reset.");
1114
1115 PostMessage(GetCmd(kCmdReset));
1116 AsyncRead(ba::buffer(fBuffer, 3), kCmdReset, ++fSendCounter);
1117 fWaitingForAnswer = true;
1118 }
1119
1120
1121 bool ExpertChannelSetDac(uint16_t ch, uint16_t dac)
1122 {
1123 if (fWaitingForAnswer)
1124 {
1125 Error("Answer on last command not yet received.");
1126 return false;
1127 }
1128
1129 if (!CheckChDac("ExpertChannelSetDac", dac, ch))
1130 return false;
1131
1132 fVoltCmd[ch] = dac;
1133
1134 ostringstream msg;
1135 msg << "EXPERT MODE: Sending 'ChannelSet' (set ch " << ch << " to DAC=" << dac << ")";
1136 Warn(msg);
1137
1138 // FIXME: dac += calib_offset
1139 PostMessage(GetCmd(kCmdChannelSet, ch, dac));
1140 AsyncRead(ba::buffer(fBuffer, 3), kExpertChannelSet|(ch<<8), ++fSendCounter);
1141 fWaitingForAnswer = true;
1142
1143 return true;
1144 }
1145
1146 bool ExpertChannelSetVolt(uint16_t ch, double volt)
1147 {
1148 return ExpertChannelSetDac(ch, volt*4096/90.);
1149 }
1150
1151 bool ExpertGlobalSetDac(uint16_t dac)
1152 {
1153 if (fWaitingForAnswer)
1154 {
1155 Error("Answer on last command not yet received.");
1156 return false;
1157 }
1158
1159 if (!CheckChDac("ExpertGlobalSetDac", dac))
1160 return false;
1161
1162 if (fGlobalVoltCmd>=0)
1163 {
1164 Error("ExpertGlobalSetDac - Still waiting for previous answer to 'GlobalSet'");
1165 return false;
1166 }
1167
1168 fGlobalVoltCmd = dac;
1169
1170 ostringstream msg;
1171 msg << "EXPERT MODE: Sending 'GlobalSet' (DAC=" << dac << ")";
1172 Warn(msg);
1173
1174 PostMessage(GetCmd(kCmdGlobalSet, 0, dac));
1175 AsyncRead(ba::buffer(fBuffer, 3), kCmdGlobalSet, ++fSendCounter);
1176 fWaitingForAnswer = true;
1177
1178 return true;
1179 }
1180
1181 bool ExpertGlobalSetVolt(float volt)
1182 {
1183 return ExpertGlobalSetDac(volt*4096/90);
1184 }
1185
1186 // --------------------------------------------------------------------
1187
1188 void SetVerbose(bool b)
1189 {
1190 fIsVerbose = b;
1191 }
1192
1193 void PrintInfo()
1194 {
1195 Out() << endl << kBold << dec << '\n';
1196 Out() << "fWrapCounter = " << fWrapCounter << '\n';
1197 Out() << "fSendCounter = " << fSendCounter%8 << " (" << fSendCounter << ")" << '\n';
1198 Out() << "fIsInitializing = " << fIsInitializing << '\n';
1199 Out() << "fIsRamping = " << fIsRamping << '\n';
1200 Out() << "Answer counter:" << '\n';
1201 Out() << " - Synchronization: " << fCounter[0] << '\n';
1202 Out() << " - Reset: " << fCounter[1] << '\n';
1203 Out() << " - Request update: " << fCounter[2] << '\n';
1204 Out() << " - Ramp step: " << fCounter[3] << '\n';
1205 Out() << " - Read: " << fCounter[4] << '\n';
1206 Out() << " - Reset channels: " << fCounter[5] << '\n';
1207 Out() << " - Global set: " << fCounter[7] << '\n';
1208 Out() << " - Channel set: " << fCounter[6] << '\n' << endl;
1209 }
1210
1211 void PrintLineA(int b, int ch)
1212 {
1213 Out() << setw(2) << b << "|";
1214
1215 for (int c=ch; c<ch+8; c++)
1216 {
1217 const int id = c+kNumChannelsPerBoard*b;
1218 Out() << (fCurrent[id]<0?kRed:kGreen);
1219 Out() << " " << setw(7) << abs(fCurrent[id])*5000/4096.;
1220 }
1221 Out() << endl;
1222
1223 }
1224
1225 void PrintA()
1226 {
1227 Out() << dec << setprecision(2) << fixed << setfill(' ');
1228 for (int b=0; b<kNumBoards; b++)
1229 {
1230 if (!fPresent[b])
1231 {
1232 Out() << setw(2) << b << "-" << endl;
1233 continue;
1234 }
1235
1236 PrintLineA(b, 0);
1237 PrintLineA(b, 8);
1238 PrintLineA(b, 16);
1239 PrintLineA(b, 24);
1240 }
1241 }
1242
1243 void PrintLineV(int b, int ch)
1244 {
1245 Out() << setw(2) << b << "|";
1246
1247 for (int c=ch; c<ch+4; c++)
1248 {
1249 const int id = c+kNumChannelsPerBoard*b;
1250 Out() << " ";
1251 Out() << (fVolt[id]==fVoltRef[id]?kGreen:kRed);
1252 Out() << setw(5) << fVolt[id]*90/4096. << '/';
1253 Out() << setw(5) << fVoltRef[id]*90/4096.;
1254 }
1255 Out() << endl;
1256 }
1257
1258 void PrintV()
1259 {
1260 Out() << dec << setprecision(2) << fixed << setfill(' ');
1261 for (int b=0; b<kNumBoards; b++)
1262 {
1263 if (!fPresent[b])
1264 {
1265 Out() << setw(2) << b << "-" << endl;
1266 continue;
1267 }
1268
1269 PrintLineV(b, 0);
1270 PrintLineV(b, 4);
1271 PrintLineV(b, 8);
1272 PrintLineV(b, 12);
1273 PrintLineV(b, 16);
1274 PrintLineV(b, 20);
1275 PrintLineV(b, 24);
1276 PrintLineV(b, 28);
1277 }
1278 }
1279
1280 void PrintLineGapd(int b, int ch)
1281 {
1282 Out() << setw(2) << b << "|";
1283
1284 for (int c=ch; c<ch+8; c++)
1285 {
1286 const int id = c+kNumChannelsPerBoard*b;
1287 Out() << " " << setw(5) << fVoltGapd[id]*90/4096.;
1288 }
1289 Out() << endl;
1290 }
1291
1292 void PrintGapd()
1293 {
1294 Out() << dec << setprecision(2) << fixed << setfill(' ');
1295 for (int b=0; b<kNumBoards; b++)
1296 {
1297 if (!fPresent[b])
1298 {
1299 Out() << setw(2) << b << "-" << endl;
1300 continue;
1301 }
1302
1303 PrintLineGapd(b, 0);
1304 PrintLineGapd(b, 8);
1305 PrintLineGapd(b, 16);
1306 PrintLineGapd(b, 24);
1307 }
1308 }
1309
1310 // -------------------------------------------------------------------
1311
1312 void SetUpdateInterval(uint16_t val)
1313 {
1314 fUpdateTime = val;
1315 }
1316
1317 void SetSyncDelay(uint16_t val)
1318 {
1319 fSyncTime = val;
1320 }
1321
1322 void SetVoltMaxAbs(float max)
1323 {
1324 fVoltMaxAbs = max*4096/90;
1325 if (fVoltMaxAbs>4095)
1326 fVoltMaxAbs = 4095;
1327 if (max<0)
1328 fVoltMaxAbs = 0;
1329 }
1330
1331 void SetVoltMaxRel(float max)
1332 {
1333 fVoltMaxRel = max*4096/90;
1334 if (fVoltMaxRel>4095)
1335 fVoltMaxRel = 4095;
1336 if (max<0)
1337 fVoltMaxRel = 0;
1338 }
1339
1340 uint16_t GetVoltMaxAbs() const
1341 {
1342 return fVoltMaxAbs * 90./4096;
1343 }
1344
1345 uint16_t GetVoltMaxRel() const
1346 {
1347 return fVoltMaxRel * 90./4096;
1348 }
1349
1350/*
1351 void AdaptVoltages()
1352 {
1353 // Correct voltages according to current
1354 for (int i=0; i<kNumChannels; i++)
1355 {
1356 if (fVoltRef[i]==0 || fCurrent[i]<0 || fRefCurrent[i]<0)
1357 continue;
1358
1359 // Calculate difference and convert ADC units to Amp
1360 // const double diffcur = (fRefCurrent[i]-fCurrent[i])*5000/4096
1361 //const int32_t diffcur = int32_t(fRefCurrent[i]-fCurrent[i])*5000;
1362
1363 // Calculate voltage difference
1364 // #define RESISTOR 1000 // Ohm
1365 //const double diffvolt = diffcur*RESISTOR/1e6;
1366
1367 // Calculate new vlaue by onverting voltage difference to DAC units
1368 //const int32_t dac = fRefVolt[i] + diffvolt*4096/90.0;
1369 SetVoltage(i, fRefVolt[i] + (fRefCurrent[i]-fCurrent[i])/18);
1370 }
1371 }
1372
1373 void SetReferenceCurrent()
1374 {
1375 fRefCurrent = fCurrent;
1376 }
1377 */
1378
1379 States_t GetStatus()
1380 {
1381 if (!IsConnected())
1382 return BIAS::kDisconnected;
1383
1384 if (IsConnecting())
1385 return BIAS::kConnecting;
1386
1387 if (fIsInitializing)
1388 return BIAS::kInitializing;
1389
1390 if (fIsRamping)
1391 return BIAS::kRamping;
1392
1393 for (int ch=0; ch<kNumChannels; ch++)
1394 if (fPresent[ch/kNumChannelsPerBoard] && fCurrent[ch]<0)
1395 return BIAS::kOverCurrent;
1396
1397 bool isoff = true;
1398 for (int ch=0; ch<kNumChannels; ch++)
1399 if (fPresent[ch/kNumChannelsPerBoard] && fVolt[ch]!=0)
1400 isoff = false;
1401 if (isoff)
1402 return BIAS::kVoltageOff;
1403
1404 for (int ch=0; ch<kNumChannels; ch++)
1405 if (fPresent[ch/kNumChannelsPerBoard] && fVolt[ch]!=fVoltRef[ch])
1406 return BIAS::kNotReferenced;
1407
1408 return BIAS::kVoltageOn;
1409 }
1410};
1411
1412// ------------------------------------------------------------------------
1413
1414#include "DimDescriptionService.h"
1415
1416class ConnectionDimBias : public ConnectionBias
1417{
1418private:
1419
1420 DimDescribedService fDimCurrent;
1421 DimDescribedService fDimVoltage;
1422 DimDescribedService fDimGapd;
1423
1424 void UpdateA()
1425 {
1426 fDimCurrent.Update(fCurrent);
1427 }
1428
1429 void UpdateV()
1430 {
1431 vector<uint16_t> vec;
1432 vec.insert(vec.end(), fVolt.begin(), fVolt.end());
1433 vec.insert(vec.end(), fVoltRef.begin(), fVoltRef.end());
1434 fDimVoltage.Update(vec);
1435 }
1436
1437 void UpdateVgapd()
1438 {
1439 fDimGapd.Update(fVoltGapd);
1440 }
1441
1442public:
1443 ConnectionDimBias(ba::io_service& ioservice, MessageImp &imp) :
1444 ConnectionBias(ioservice, imp),
1445 fDimCurrent("BIAS_CONTROL/CURRENT", "S:416", "|I[uA]:Bias current"),
1446 fDimVoltage("BIAS_CONTROL/VOLTAGE", "S:416;S:416", "|U[V]:Applied bias voltage|Uref[V]:Reference bias voltage"),
1447 fDimGapd( "BIAS_CONTROL/NOMINAL", "S:416", "|U[V]:Nominal G-APD voltage at 25deg C")
1448 {
1449 }
1450
1451 // 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
1452};
1453
1454// ------------------------------------------------------------------------
1455
1456template <class T, class S>
1457class StateMachineBias : public T, public ba::io_service, public ba::io_service::work
1458{
1459 int Wrap(boost::function<void()> f)
1460 {
1461 f();
1462 return T::GetCurrentState();
1463 }
1464
1465 function<int(const EventImp &)> Wrapper(function<void()> func)
1466 {
1467 return bind(&StateMachineBias::Wrap, this, func);
1468 }
1469
1470 bool CheckEventSize(size_t has, const char *name, size_t size)
1471 {
1472 if (has==size)
1473 return true;
1474
1475 ostringstream msg;
1476 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
1477 T::Fatal(msg);
1478 return false;
1479 }
1480
1481private:
1482 S fBias;
1483
1484 bool fExpertMode;
1485
1486 // --------------------------------------------------------------------
1487
1488 int SetGapdVoltage(const EventImp &evt)
1489 {
1490 if (!CheckEventSize(evt.GetSize(), "SetGapdVoltage", 4))
1491 return false;
1492
1493 fBias.SetGapdVoltage(evt.GetFloat());
1494
1495 return T::GetCurrentState();
1496 }
1497
1498 // --------------------------------------------------------------------
1499
1500 int SetGlobalVolt(const EventImp &evt)
1501 {
1502 if (!CheckEventSize(evt.GetSize(), "SetGlobalVolt", 4))
1503 return false;
1504
1505 fBias.GlobalSetVolt(evt.GetFloat());
1506
1507 return T::GetCurrentState();
1508 }
1509
1510 int SetGlobalDac(const EventImp &evt)
1511 {
1512 if (!CheckEventSize(evt.GetSize(), "SetGlobalDac", 2))
1513 return false;
1514
1515 fBias.GlobalSetDac(evt.GetUShort());
1516
1517 return T::GetCurrentState();
1518 }
1519
1520 int IncGlobalVolt(const EventImp &evt)
1521 {
1522 if (!CheckEventSize(evt.GetSize(), "IncGlobalVolt", 4))
1523 return false;
1524
1525 fBias.GlobalAddVolt(evt.GetFloat());
1526
1527 return T::GetCurrentState();
1528 }
1529
1530 int IncGlobalDac(const EventImp &evt)
1531 {
1532 if (!CheckEventSize(evt.GetSize(), "IncGlobalDac", 2))
1533 return false;
1534
1535 fBias.GlobalAddDac(evt.GetShort());
1536
1537 return T::GetCurrentState();
1538 }
1539
1540 int DecGlobalVolt(const EventImp &evt)
1541 {
1542 if (!CheckEventSize(evt.GetSize(), "DecGlobalVolt", 4))
1543 return false;
1544
1545 fBias.GlobalAddVolt(-evt.GetFloat());
1546
1547 return T::GetCurrentState();
1548 }
1549
1550 int DecGlobalDac(const EventImp &evt)
1551 {
1552 if (!CheckEventSize(evt.GetSize(), "DecGlobalDac", 2))
1553 return false;
1554
1555 fBias.GlobalAddDac(-evt.GetShort());
1556
1557 return T::GetCurrentState();
1558 }
1559
1560 int SetChannelVolt(const EventImp &evt)
1561 {
1562 if (!CheckEventSize(evt.GetSize(), "SetChannelVolt", 6))
1563 return false;
1564
1565 fBias.ChannelSetVolt(evt.GetUShort(), evt.Get<float>(2));
1566
1567 return T::GetCurrentState();
1568 }
1569
1570 int SetChannelDac(const EventImp &evt)
1571 {
1572 if (!CheckEventSize(evt.GetSize(), "SetChannelDac", 4))
1573 return false;
1574
1575 fBias.ChannelSetDac(evt.Get<uint16_t>(), evt.Get<uint16_t>(2));
1576
1577 return T::GetCurrentState();
1578 }
1579
1580 int SetGapdReferenceCh(const EventImp &evt)
1581 {
1582 if (!CheckEventSize(evt.GetSize(), "SetGapdReferenceCh", 2))
1583 return false;
1584
1585 fBias.SetGapdReferenceCh(evt.GetUShort());
1586
1587 return T::GetCurrentState();
1588 }
1589
1590
1591 // --------------------------------------------------------------------
1592
1593 int AddReferenceDac(const EventImp &evt)
1594 {
1595 if (!CheckEventSize(evt.GetSize(), "AddReferenceDac", 2*kNumChannels))
1596 return false;
1597
1598 const int16_t *ptr = evt.Ptr<int16_t>();
1599 fBias.AddDac(vector<int16_t>(ptr, ptr+416));
1600
1601 return T::GetCurrentState();
1602 }
1603
1604 int AddReferenceVolt(const EventImp &evt)
1605 {
1606 if (!CheckEventSize(evt.GetSize(), "AddReferenceVolt", 4*kNumChannels))
1607 return false;
1608
1609 const float_t *ptr = evt.Ptr<float>();
1610 fBias.AddVolt(vector<float>(ptr, ptr+416));
1611
1612 return T::GetCurrentState();
1613 }
1614
1615 int SetReferenceDac(const EventImp &evt)
1616 {
1617 if (!CheckEventSize(evt.GetSize(), "SetReferenceDac", 2*kNumChannels))
1618 return false;
1619
1620 const int16_t *ptr = evt.Ptr<int16_t>();
1621 fBias.SetDac(vector<int16_t>(ptr, ptr+416));
1622
1623 return T::GetCurrentState();
1624 }
1625
1626 int SetReferenceVolt(const EventImp &evt)
1627 {
1628 if (!CheckEventSize(evt.GetSize(), "SetReferenceVolt", 4*kNumChannels))
1629 return false;
1630
1631 const float_t *ptr = evt.Ptr<float>();
1632 fBias.SetVolt(vector<float>(ptr, ptr+416));
1633
1634 return T::GetCurrentState();
1635 }
1636
1637 // --------------------------------------------------------------------
1638
1639 int ExpertSetGlobalVolt(const EventImp &evt)
1640 {
1641 if (!CheckEventSize(evt.GetSize(), "ExpertSetGlobalVolt", 4))
1642 return false;
1643
1644 fBias.ExpertGlobalSetVolt(evt.GetFloat());
1645
1646 return T::GetCurrentState();
1647 }
1648
1649 int ExpertSetGlobalDac(const EventImp &evt)
1650 {
1651 if (!CheckEventSize(evt.GetSize(), "ExpertSetGlobalDac", 2))
1652 return false;
1653
1654 fBias.ExpertGlobalSetDac(evt.GetUShort());
1655
1656 return T::GetCurrentState();
1657 }
1658
1659 int ExpertSetChannelVolt(const EventImp &evt)
1660 {
1661 if (!CheckEventSize(evt.GetSize(), "ExpertSetChannelVolt", 6))
1662 return false;
1663
1664 fBias.ExpertChannelSetVolt(evt.GetUShort(), evt.Get<float>(2));
1665
1666 return T::GetCurrentState();
1667 }
1668
1669 int ExpertSetChannelDac(const EventImp &evt)
1670 {
1671 if (!CheckEventSize(evt.GetSize(), "ExpertSetChannelDac", 4))
1672 return false;
1673
1674 fBias.ExpertChannelSetDac(evt.Get<uint16_t>(), evt.Get<uint16_t>(2));
1675
1676 return T::GetCurrentState();
1677 }
1678
1679 // --------------------------------------------------------------------
1680
1681 int Disconnect()
1682 {
1683 // Close all connections
1684 fBias.PostClose(false);
1685
1686 /*
1687 // Now wait until all connection have been closed and
1688 // all pending handlers have been processed
1689 poll();
1690 */
1691
1692 return T::GetCurrentState();
1693 }
1694
1695 int Reconnect(const EventImp &evt)
1696 {
1697 // Close all connections to supress the warning in SetEndpoint
1698 fBias.PostClose(false);
1699
1700 // Now wait until all connection have been closed and
1701 // all pending handlers have been processed
1702 poll();
1703
1704 if (evt.GetBool())
1705 fBias.SetEndpoint(evt.GetString());
1706
1707 // Now we can reopen the connection
1708 fBias.PostClose(true);
1709
1710 return T::GetCurrentState();
1711 }
1712
1713 int SetVerbosity(const EventImp &evt)
1714 {
1715 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
1716 return T::kSM_FatalError;
1717
1718 fBias.SetVerbose(evt.GetBool());
1719
1720 return T::GetCurrentState();
1721 }
1722
1723 int SetExpertMode(const EventImp &evt)
1724 {
1725 if (!CheckEventSize(evt.GetSize(), "SetExpertMode", 1))
1726 return T::kSM_FatalError;
1727
1728 fExpertMode = evt.GetBool();
1729
1730 if (fExpertMode)
1731 T::Warn("Expert commands enabled -- please ensure that you EXACTLY know what you do. These commands can destroy the system.");
1732
1733 return T::GetCurrentState();
1734 }
1735
1736 int Execute()
1737 {
1738 // Dispatch (execute) at most one handler from the queue. In contrary
1739 // to run_one(), it doesn't wait until a handler is available
1740 // which can be dispatched, so poll_one() might return with 0
1741 // handlers dispatched. The handlers are always dispatched/executed
1742 // synchronously, i.e. within the call to poll_one()
1743 poll_one();
1744
1745 return fExpertMode && fBias.GetStatus()>=kConnected ?
1746 kExpertMode : fBias.GetStatus();
1747 }
1748
1749public:
1750 StateMachineBias(ostream &out=cout) :
1751 T(out, "BIAS_CONTROL"), ba::io_service::work(static_cast<ba::io_service&>(*this)),
1752 fBias(*this, *this), fExpertMode(false)
1753 {
1754 // ba::io_service::work is a kind of keep_alive for the loop.
1755 // It prevents the io_service to go to stopped state, which
1756 // would prevent any consecutive calls to run()
1757 // or poll() to do nothing. reset() could also revoke to the
1758 // previous state but this might introduce some overhead of
1759 // deletion and creation of threads and more.
1760
1761 // State names
1762 T::AddStateName(kDisconnected, "Disconnected",
1763 "Bias-power supply not connected via USB.");
1764
1765 T::AddStateName(kConnecting, "Connecting",
1766 "Trying to establish USB connection to bias-power supply.");
1767
1768 T::AddStateName(kInitializing, "Initializing",
1769 "USB connection to bias-power supply established, synchronizing USB stream.");
1770
1771 T::AddStateName(kConnected, "Connected",
1772 "USB connection to bias-power supply established.");
1773
1774 T::AddStateName(kNotReferenced, "NotReferenced",
1775 "Internal reference voltage does not match last sent voltage.");
1776
1777 T::AddStateName(kVoltageOff, "VoltageOff",
1778 "All voltages are supposed to be switched off.");
1779
1780 T::AddStateName(kVoltageOn, "VoltageOn",
1781 "At least one voltage is switched on and all are at reference.");
1782
1783 T::AddStateName(kOverCurrent, "OverCurrent",
1784 "At least one channel is in over current state.");
1785
1786 T::AddStateName(kExpertMode, "ExpertMode",
1787 "Special (risky!) mode to directly send command to the bias-power supply.");
1788
1789 T::AddStateName(kRamping, "Ramping",
1790 "Voltage ramping in progress.");
1791
1792 // Verbosity commands
1793 T::AddEvent("SET_VERBOSE", "B")
1794 (bind(&StateMachineBias::SetVerbosity, this, placeholders::_1))
1795 ("set verbosity state"
1796 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
1797
1798 // Conenction commands
1799 T::AddEvent("DISCONNECT", kConnected, kVoltageOff)
1800 (bind(&StateMachineBias::Disconnect, this))
1801 ("disconnect from USB");
1802
1803 T::AddEvent("RECONNECT", "O", kDisconnected, kConnected, kVoltageOff)
1804 (bind(&StateMachineBias::Reconnect, this, placeholders::_1))
1805 ("(Re)connect USB connection to Bias power supply, a new address can be given"
1806 "|tty[string]:new USB address");
1807
1808
1809
1810 T::AddEvent("REQUEST_STATUS", kConnected, kVoltageOn, kVoltageOff, kNotReferenced, kOverCurrent)
1811 (Wrapper(bind(&ConnectionBias::ReadAllChannels, &fBias, false)))
1812 ("Asynchronously request the status (current) of all channels.");
1813
1814 T::AddEvent("RESET_OVER_CURRENT_STATUS", kOverCurrent)
1815 (Wrapper(bind(&ConnectionBias::OverCurrentReset, &fBias)))
1816 ("Set all channels in over current state to 0V and send a system reset to reset the over current flags.");
1817
1818
1819
1820 T::AddEvent("SET_GLOBAL_VOLTAGE", "F:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1821 (bind(&StateMachineBias::SetGlobalVolt, this, placeholders::_1))
1822 ("Set all channels to a new reference voltage. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
1823 "|voltage[V]:Global target voltage in volts (will be converted to DAC units)");
1824
1825 T::AddEvent("SET_GLOBAL_DAC", "S:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1826 (bind(&StateMachineBias::SetGlobalDac, this, placeholders::_1))
1827 ("Set all channels to a new DAC reference. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
1828 "|voltage[dac]:Global target voltage as DAC counts.");
1829
1830 T::AddEvent("INCREASE_GLOBAL_VOLTAGE", "F:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1831 (bind(&StateMachineBias::IncGlobalVolt, this, placeholders::_1))
1832 ("Set all channels to a new reference voltage. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
1833 "|offset[V]:Offset to be added to all channels (will be converted to DAC counts)");
1834
1835 T::AddEvent("INCREASE_GLOBAL_DAC", "S:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1836 (bind(&StateMachineBias::IncGlobalDac, this, placeholders::_1))
1837 ("Set all channels to a new DAC reference. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
1838 "|offset[dac]:Offset to be added to all channels as DAC counts");
1839
1840 T::AddEvent("DECREASE_GLOBAL_VOLTAGE", "F:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1841 (bind(&StateMachineBias::DecGlobalVolt, this, placeholders::_1))
1842 ("Set all channels to a new reference voltage. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
1843 "|offset[V]:Offset to be subtracted from all channels (will be converted to DAC counts)");
1844
1845 T::AddEvent("DECREASE_GLOBAL_DAC", "S:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1846 (bind(&StateMachineBias::DecGlobalDac, this, placeholders::_1))
1847 ("Set all channels to a new DAC reference. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
1848 "|offset[dac]:Offset to be subtracted from all channels as DAC counts");
1849
1850 T::AddEvent("SET_CHANNEL_VOLTAGE", "S:1;F:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1851 (bind(&StateMachineBias::SetChannelVolt, this, placeholders::_1))
1852 ("Set a single channel to a new reference voltage. Starts ramping if necessary."
1853 "|channel[short]:Channel for which to set the target voltage [0-416]"
1854 "|voltage[V]:Target voltage in volts for the given channel (will be converted to DAC units)");
1855
1856 T::AddEvent("SET_CHANNEL_DAC", "S:1;S:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1857 (bind(&StateMachineBias::SetChannelDac, this, placeholders::_1))
1858 ("Set a single channel to a new DAC reference value. Starts ramping if necessary."
1859 "|channel[short]:Channel for which to set the target voltage [0-416]"
1860 "|voltage[dac]:Target voltage in DAC units for the given channel");
1861
1862 T::AddEvent("SET_GLOBAL_GAPD_REFERENCE_VOLTAGE", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1863 (Wrapper(bind(&ConnectionBias::SetGapdVoltage, &fBias, 0.)))
1864 ("Set all channels to their G-APD reference voltage. Starts ramping if necessary.");
1865
1866 T::AddEvent("SET_CHANNEL_GAPD_REFERENCE_VOLTAGE", "S:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1867 (bind(&StateMachineBias::SetGapdReferenceCh, this, placeholders::_1))
1868 ("Set a single channel channels to its G-APD reference voltage. Starts ramping if necessary."
1869 "|channel[short]:Channel for which to set the target voltage [0-416]");
1870
1871 T::AddEvent("SET_GAPD_REFERENCE_OFFSET", "F:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1872 (bind(&StateMachineBias::SetGapdVoltage, this, placeholders::_1))
1873 ("Set all channels to their G-APD reference voltage plus the given offset. Starts ramping if necessary."
1874 "|offset[V]:Offset to be added to teh G-APD reference voltage globally");
1875
1876 T::AddEvent("SET_ZERO_VOLTAGE", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1877 (Wrapper(bind(&ConnectionBias::SetZero, &fBias)))
1878 ("Set all channels to a zero reference voltage. Starts ramping if necessary.");
1879
1880 T::AddEvent("SET_REFERENCE_VOLTAGES", "F:416", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1881 (bind(&StateMachineBias::SetReferenceVolt, this, placeholders::_1))
1882 ("Set all channels to the given new reference voltage. Starts ramping if necessary."
1883 "voltage[V]:New reference voltage for all channels");
1884
1885 T::AddEvent("SET_REFERENCE_DACS", "S:416", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1886 (bind(&StateMachineBias::SetReferenceDac, this, placeholders::_1))
1887 ("Set all channels to the given new reference voltage. Starts ramping if necessary."
1888 "voltage[dac]:New reference voltage for all channels in DAC units");
1889
1890 T::AddEvent("ADD_REFERENCE_VOLTAGES", "F:416", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1891 (bind(&StateMachineBias::AddReferenceVolt, this, placeholders::_1))
1892 ("Add the given voltages to the current reference voltages. Starts ramping if necessary."
1893 "offset[V]:Offsets to be added to the reference voltage of all channels in volts");
1894
1895 T::AddEvent("ADD_REFERENCE_DACS", "S:416", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1896 (bind(&StateMachineBias::AddReferenceDac, this, placeholders::_1))
1897 ("Add the given voltages to the current reference voltages. Starts ramping if necessary."
1898 "offset[dac]:Offsets to be added to the reference voltage of all channels in DAC units");
1899
1900
1901
1902
1903 T::AddEvent("STOP", kConnected, kRamping)
1904 (Wrapper(bind(&ConnectionBias::RampStop, &fBias)))
1905 ("Stop an on-going ramping");
1906
1907 T::AddEvent("START", kConnected, kNotReferenced)
1908 (Wrapper(bind(&ConnectionBias::RampStart, &fBias)))
1909 ("Start a ramping if no ramping is in progress and if reference values differ from current voltages");
1910
1911
1912
1913 T::AddEvent("PRINT_INFO")
1914 (Wrapper(bind(&ConnectionBias::PrintInfo, &fBias)))
1915 ("Print a table with all current read back with the last request operation");
1916 T::AddEvent("PRINT_CURRENTS")
1917 (Wrapper(bind(&ConnectionBias::PrintA, &fBias)))
1918 ("Print a table with all current read back with the last request operation");
1919 T::AddEvent("PRINT_VOLTAGES")
1920 (Wrapper(bind(&ConnectionBias::PrintV, &fBias)))
1921 ("Print a table with all voltages (current and reference voltages as currently in memory)");
1922 T::AddEvent("PRINT_GAPD_REFERENCE_VOLTAGES")
1923 (Wrapper(bind(&ConnectionBias::PrintGapd, &fBias)))
1924 ("Print the G-APD reference values obtained from file");
1925
1926
1927 T::AddEvent("EXPERT_MODE", "B:1")
1928 (bind(&StateMachineBias::SetExpertMode, this, placeholders::_1))
1929 ("Enable usage of expert commands (note that for safty reasons the are exclusive with the standard commands)");
1930
1931 T::AddEvent("EXPERT_RESET", kExpertMode)
1932 (Wrapper(bind(&ConnectionBias::ExpertReset, &fBias, true)))
1933 ("Send the RESET command (note that this is possibly harmfull command)");
1934
1935 T::AddEvent("EXPERT_SET_GLOBAL_VOLTAGE", "F:1", kExpertMode)
1936 (bind(&StateMachineBias::ExpertSetGlobalVolt, this, placeholders::_1))
1937 ("Send the global set command. The given voltage is converted to DAC counts.");
1938
1939 T::AddEvent("EXPERT_SET_GLOBAL_DAC", "S:1", kExpertMode)
1940 (bind(&StateMachineBias::ExpertSetGlobalDac, this, placeholders::_1))
1941 ("Send the global set command.");
1942
1943 T::AddEvent("EXPERT_SET_CHANNEL_VOLTAGE", "S:1;F:1", kExpertMode)
1944 (bind(&StateMachineBias::ExpertSetChannelVolt, this, placeholders::_1))
1945 ("Send a single channel set command. The given voltage is converted to DAC commands.");
1946
1947 T::AddEvent("EXPERT_SET_CHANNEL_DAC", "S:1;S:1", kExpertMode)
1948 (bind(&StateMachineBias::ExpertSetChannelDac, this, placeholders::_1))
1949 ("Send a single channel set command.");
1950 }
1951
1952 ~StateMachineBias() { T::Warn("TODO: Implement rampming at shutdown!"); }
1953
1954 int EvalOptions(Configuration &conf)
1955 {
1956 // FIXME: Read calib_offset
1957 // FIXME: Check calib offset being smaller than +/-0.25V
1958
1959 fBias.SetVerbose(!conf.Get<bool>("quiet"));
1960
1961 fBias.SetEndpoint(conf.Get<string>("dev"));
1962 T::Message("Setting device to "+fBias.URL());
1963
1964 const uint16_t step = conf.Get<uint16_t>("ramp-step");
1965 const uint16_t time = conf.Get<uint16_t>("ramp-time");
1966
1967 if (step>230) // 5V
1968 {
1969 T::Error("ramp-step exceeds allowed range.");
1970 return 1;
1971 }
1972
1973 fBias.SetRampStep(step);
1974 fBias.SetRampTime(time);
1975 fBias.SetUpdateInterval(conf.Get<uint16_t>("update-interval"));
1976 fBias.SetSyncDelay(conf.Get<uint16_t>("sync-delay"));
1977
1978 ostringstream str1, str2;
1979 str1 << "Ramping in effective steps of " << fBias.GetRampStepVolt() << "V";
1980 str2 << "Ramping with a delay per step of " << time << "ms";
1981 T::Message(str1);
1982 T::Message(str2);
1983
1984 // --------------------------------------------------------------------------
1985
1986 const float maxabsv = conf.Get<float>("volt-max-abs");
1987 const float maxrelv = conf.Get<float>("volt-max-rel");
1988 if (maxabsv>90)
1989 {
1990 T::Error("volt-max exceeds 90V.");
1991 return 2;
1992 }
1993 if (maxabsv>75)
1994 T::Warn("volt-max exceeds 75V.");
1995 if (maxabsv<70)
1996 T::Warn("volt-max below 70V.");
1997 if (maxabsv<0)
1998 {
1999 T::Error("volt-max negative.");
2000 return 3;
2001 }
2002
2003 fBias.SetVoltMaxAbs(maxabsv);
2004 fBias.SetVoltMaxRel(maxrelv);
2005
2006 ostringstream str3, str4;
2007 str3 << "Effective maximum allowed absolute voltage: " << fBias.GetVoltMaxAbs() << "V";
2008 str4 << "Effective maximum difference w.r.t to G-APD reference: " << fBias.GetVoltMaxRel() << "V";
2009 T::Message(str3);
2010 T::Message(str4);
2011
2012 // --------------------------------------------------------------------------
2013
2014 PixelMap map;
2015 if (!map.Read(conf.Get<string>("pixel-map-file")))
2016 {
2017 T::Error("Reading reference voltages from "+conf.Get<string>("pixel-map-file")+" failed.");
2018 return 5;
2019 }
2020
2021 if (!fBias.SetNewGapdVoltage(map.Vgapd()))
2022 {
2023 T::Error("Setting reference voltages failed.");
2024 return 6;
2025 }
2026
2027 // --------------------------------------------------------------------------
2028
2029 fBias.Connect();
2030
2031 return -1;
2032 }
2033};
2034
2035// ------------------------------------------------------------------------
2036
2037#include "Main.h"
2038
2039template<class T, class S, class R>
2040int RunShell(Configuration &conf)
2041{
2042 return Main::execute<T, StateMachineBias<S, R>>(conf);
2043}
2044
2045void SetupConfiguration(Configuration &conf)
2046{
2047 po::options_description control("BIAS control options");
2048 control.add_options()
2049 ("no-dim,d", po_bool(), "Disable dim services")
2050 ("dev", var<string>("FTE00FOH"), "Device address of USB port to bias-power supply")
2051 ("quiet,q", po_bool(), "Disable printing contents of all received messages (except dynamic data) in clear text.")
2052 ("ramp-time", var<uint16_t>(15), "Delay between the answer of one ramping step and sending the next ramp command to all channels in milliseconds.")
2053 ("ramp-step", var<uint16_t>(46), "Maximum step in DAC counts during ramping (Volt = DAC*90/4096)")
2054 ("update-interval", var<uint16_t>(3000), "Interval between two current requests in milliseconds")
2055 ("sync-delay", var<uint16_t>(500), "Delay between sending the inital 0's after a newly established connection to synchronize the output stream in milliseconds")
2056 ("volt-max-abs", var<float>(75), "Absolte upper limit for the voltage (in Volts)")
2057 ("volt-max-rel", var<float>(2.5), "Relative upper limit for the voltage w.r.t. the G-APD reference voltage (in Volts)")
2058 ("pixel-map-file", var<string>("FACTmapV5a.txt"), "Pixel mapping file. Used here to get the default reference voltage.")
2059 ;
2060
2061 conf.AddOptions(control);
2062}
2063
2064/*
2065 Extract usage clause(s) [if any] for SYNOPSIS.
2066 Translators: "Usage" and "or" here are patterns (regular expressions) which
2067 are used to match the usage synopsis in program output. An example from cp
2068 (GNU coreutils) which contains both strings:
2069 Usage: cp [OPTION]... [-T] SOURCE DEST
2070 or: cp [OPTION]... SOURCE... DIRECTORY
2071 or: cp [OPTION]... -t DIRECTORY SOURCE...
2072 */
2073void PrintUsage()
2074{
2075 cout <<
2076 "The biasctrl program controls the bias-power supply boards.\n"
2077 "\n"
2078 "Note: At default the program is started without a command line (user) "
2079 "interface. In this case Actions/Commands are available via Dim "
2080 "exclusively.\n"
2081 "Use the -c option to start the program with a command line interface.\n"
2082 "\n"
2083 "In the running application:\n"
2084 "Use h or help to print a short help message about its usage.\n"
2085 "\n"
2086 "Usage: biasctrl [-c type] [OPTIONS]\n"
2087 " or: biasctrl [OPTIONS]\n";
2088 cout << endl;
2089}
2090
2091void PrintHelp()
2092{
2093 Main::PrintHelp<StateMachineBias<StateMachine,ConnectionBias>>();
2094
2095 /* Additional help text which is printed after the configuration
2096 options goes here */
2097
2098 /*
2099 cout << "bla bla bla" << endl << endl;
2100 cout << endl;
2101 cout << "Environment:" << endl;
2102 cout << "environment" << endl;
2103 cout << endl;
2104 cout << "Examples:" << endl;
2105 cout << "test exam" << endl;
2106 cout << endl;
2107 cout << "Files:" << endl;
2108 cout << "files" << endl;
2109 cout << endl;
2110 */
2111}
2112
2113int main(int argc, const char* argv[])
2114{
2115 Configuration conf(argv[0]);
2116 conf.SetPrintUsage(PrintUsage);
2117 Main::SetupConfiguration(conf);
2118 SetupConfiguration(conf);
2119
2120 if (!conf.DoParse(argc, argv, PrintHelp))
2121 return -1;
2122
2123 //try
2124 {
2125 // No console access at all
2126 if (!conf.Has("console"))
2127 {
2128 if (conf.Get<bool>("no-dim"))
2129 return RunShell<LocalStream, StateMachine, ConnectionBias>(conf);
2130 else
2131 return RunShell<LocalStream, StateMachineDim, ConnectionDimBias>(conf);
2132 }
2133 // Cosole access w/ and w/o Dim
2134 if (conf.Get<bool>("no-dim"))
2135 {
2136 if (conf.Get<int>("console")==0)
2137 return RunShell<LocalShell, StateMachine, ConnectionBias>(conf);
2138 else
2139 return RunShell<LocalConsole, StateMachine, ConnectionBias>(conf);
2140 }
2141 else
2142 {
2143 if (conf.Get<int>("console")==0)
2144 return RunShell<LocalShell, StateMachineDim, ConnectionDimBias>(conf);
2145 else
2146 return RunShell<LocalConsole, StateMachineDim, ConnectionDimBias>(conf);
2147 }
2148 }
2149 /*catch (std::exception& e)
2150 {
2151 cerr << "Exception: " << e.what() << endl;
2152 return -1;
2153 }*/
2154
2155 return 0;
2156}
Note: See TracBrowser for help on using the repository browser.