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

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