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

Last change on this file since 12266 was 12254, checked in by tbretz, 14 years ago
Added the possibility to change the update interval online.
File size: 66.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
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 if (!IsConnected() || fIsInitializing)
1317 return;
1318
1319 fUpdateTimer.cancel();
1320
1321 if (fUpdateTime>0)
1322 ScheduleUpdate(fUpdateTime);
1323 }
1324
1325 void SetSyncDelay(uint16_t val)
1326 {
1327 fSyncTime = val;
1328 }
1329
1330 void SetVoltMaxAbs(float max)
1331 {
1332 fVoltMaxAbs = max*4096/90;
1333 if (fVoltMaxAbs>4095)
1334 fVoltMaxAbs = 4095;
1335 if (max<0)
1336 fVoltMaxAbs = 0;
1337 }
1338
1339 void SetVoltMaxRel(float max)
1340 {
1341 fVoltMaxRel = max*4096/90;
1342 if (fVoltMaxRel>4095)
1343 fVoltMaxRel = 4095;
1344 if (max<0)
1345 fVoltMaxRel = 0;
1346 }
1347
1348 uint16_t GetVoltMaxAbs() const
1349 {
1350 return fVoltMaxAbs * 90./4096;
1351 }
1352
1353 uint16_t GetVoltMaxRel() const
1354 {
1355 return fVoltMaxRel * 90./4096;
1356 }
1357
1358/*
1359 void AdaptVoltages()
1360 {
1361 // Correct voltages according to current
1362 for (int i=0; i<kNumChannels; i++)
1363 {
1364 if (fVoltRef[i]==0 || fCurrent[i]<0 || fRefCurrent[i]<0)
1365 continue;
1366
1367 // Calculate difference and convert ADC units to Amp
1368 // const double diffcur = (fRefCurrent[i]-fCurrent[i])*5000/4096
1369 //const int32_t diffcur = int32_t(fRefCurrent[i]-fCurrent[i])*5000;
1370
1371 // Calculate voltage difference
1372 // #define RESISTOR 1000 // Ohm
1373 //const double diffvolt = diffcur*RESISTOR/1e6;
1374
1375 // Calculate new vlaue by onverting voltage difference to DAC units
1376 //const int32_t dac = fRefVolt[i] + diffvolt*4096/90.0;
1377 SetVoltage(i, fRefVolt[i] + (fRefCurrent[i]-fCurrent[i])/18);
1378 }
1379 }
1380
1381 void SetReferenceCurrent()
1382 {
1383 fRefCurrent = fCurrent;
1384 }
1385 */
1386
1387 States_t GetStatus()
1388 {
1389 if (!IsConnected())
1390 return BIAS::kDisconnected;
1391
1392 if (IsConnecting())
1393 return BIAS::kConnecting;
1394
1395 if (fIsInitializing)
1396 return BIAS::kInitializing;
1397
1398 if (fIsRamping)
1399 return BIAS::kRamping;
1400
1401 for (int ch=0; ch<kNumChannels; ch++)
1402 if (fPresent[ch/kNumChannelsPerBoard] && fCurrent[ch]<0)
1403 return BIAS::kOverCurrent;
1404
1405 bool isoff = true;
1406 for (int ch=0; ch<kNumChannels; ch++)
1407 if (fPresent[ch/kNumChannelsPerBoard] && fVolt[ch]!=0)
1408 isoff = false;
1409 if (isoff)
1410 return BIAS::kVoltageOff;
1411
1412 for (int ch=0; ch<kNumChannels; ch++)
1413 if (fPresent[ch/kNumChannelsPerBoard] && fVolt[ch]!=fVoltRef[ch])
1414 return BIAS::kNotReferenced;
1415
1416 return BIAS::kVoltageOn;
1417 }
1418};
1419
1420// ------------------------------------------------------------------------
1421
1422#include "DimDescriptionService.h"
1423
1424class ConnectionDimBias : public ConnectionBias
1425{
1426private:
1427
1428 DimDescribedService fDimCurrent;
1429 DimDescribedService fDimVoltage;
1430 DimDescribedService fDimGapd;
1431
1432 void UpdateA()
1433 {
1434 fDimCurrent.Update(fCurrent);
1435 }
1436
1437 void UpdateV()
1438 {
1439 vector<uint16_t> vec;
1440 vec.insert(vec.end(), fVolt.begin(), fVolt.end());
1441 vec.insert(vec.end(), fVoltRef.begin(), fVoltRef.end());
1442 fDimVoltage.Update(vec);
1443 }
1444
1445 void UpdateVgapd()
1446 {
1447 fDimGapd.Update(fVoltGapd);
1448 }
1449
1450public:
1451 ConnectionDimBias(ba::io_service& ioservice, MessageImp &imp) :
1452 ConnectionBias(ioservice, imp),
1453 fDimCurrent("BIAS_CONTROL/CURRENT", "S:416", "|I[uA]:Bias current"),
1454 fDimVoltage("BIAS_CONTROL/VOLTAGE", "S:416;S:416", "|U[V]:Applied bias voltage|Uref[V]:Reference bias voltage"),
1455 fDimGapd( "BIAS_CONTROL/NOMINAL", "S:416", "|U[V]:Nominal G-APD voltage at 25deg C")
1456 {
1457 }
1458
1459 // 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
1460};
1461
1462// ------------------------------------------------------------------------
1463
1464template <class T, class S>
1465class StateMachineBias : public T, public ba::io_service, public ba::io_service::work
1466{
1467 int Wrap(boost::function<void()> f)
1468 {
1469 f();
1470 return T::GetCurrentState();
1471 }
1472
1473 function<int(const EventImp &)> Wrapper(function<void()> func)
1474 {
1475 return bind(&StateMachineBias::Wrap, this, func);
1476 }
1477
1478 bool CheckEventSize(size_t has, const char *name, size_t size)
1479 {
1480 if (has==size)
1481 return true;
1482
1483 ostringstream msg;
1484 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
1485 T::Fatal(msg);
1486 return false;
1487 }
1488
1489private:
1490 S fBias;
1491
1492 bool fExpertMode;
1493
1494 // --------------------------------------------------------------------
1495
1496 int SetGapdVoltage(const EventImp &evt)
1497 {
1498 if (!CheckEventSize(evt.GetSize(), "SetGapdVoltage", 4))
1499 return false;
1500
1501 fBias.SetGapdVoltage(evt.GetFloat());
1502
1503 return T::GetCurrentState();
1504 }
1505
1506 // --------------------------------------------------------------------
1507
1508 int SetGlobalVolt(const EventImp &evt)
1509 {
1510 if (!CheckEventSize(evt.GetSize(), "SetGlobalVolt", 4))
1511 return false;
1512
1513 fBias.GlobalSetVolt(evt.GetFloat());
1514
1515 return T::GetCurrentState();
1516 }
1517
1518 int SetGlobalDac(const EventImp &evt)
1519 {
1520 if (!CheckEventSize(evt.GetSize(), "SetGlobalDac", 2))
1521 return false;
1522
1523 fBias.GlobalSetDac(evt.GetUShort());
1524
1525 return T::GetCurrentState();
1526 }
1527
1528 int IncGlobalVolt(const EventImp &evt)
1529 {
1530 if (!CheckEventSize(evt.GetSize(), "IncGlobalVolt", 4))
1531 return false;
1532
1533 fBias.GlobalAddVolt(evt.GetFloat());
1534
1535 return T::GetCurrentState();
1536 }
1537
1538 int IncGlobalDac(const EventImp &evt)
1539 {
1540 if (!CheckEventSize(evt.GetSize(), "IncGlobalDac", 2))
1541 return false;
1542
1543 fBias.GlobalAddDac(evt.GetShort());
1544
1545 return T::GetCurrentState();
1546 }
1547
1548 int DecGlobalVolt(const EventImp &evt)
1549 {
1550 if (!CheckEventSize(evt.GetSize(), "DecGlobalVolt", 4))
1551 return false;
1552
1553 fBias.GlobalAddVolt(-evt.GetFloat());
1554
1555 return T::GetCurrentState();
1556 }
1557
1558 int DecGlobalDac(const EventImp &evt)
1559 {
1560 if (!CheckEventSize(evt.GetSize(), "DecGlobalDac", 2))
1561 return false;
1562
1563 fBias.GlobalAddDac(-evt.GetShort());
1564
1565 return T::GetCurrentState();
1566 }
1567
1568 int SetChannelVolt(const EventImp &evt)
1569 {
1570 if (!CheckEventSize(evt.GetSize(), "SetChannelVolt", 6))
1571 return false;
1572
1573 fBias.ChannelSetVolt(evt.GetUShort(), evt.Get<float>(2));
1574
1575 return T::GetCurrentState();
1576 }
1577
1578 int SetChannelDac(const EventImp &evt)
1579 {
1580 if (!CheckEventSize(evt.GetSize(), "SetChannelDac", 4))
1581 return false;
1582
1583 fBias.ChannelSetDac(evt.Get<uint16_t>(), evt.Get<uint16_t>(2));
1584
1585 return T::GetCurrentState();
1586 }
1587
1588 int SetGapdReferenceCh(const EventImp &evt)
1589 {
1590 if (!CheckEventSize(evt.GetSize(), "SetGapdReferenceCh", 2))
1591 return false;
1592
1593 fBias.SetGapdReferenceCh(evt.GetUShort());
1594
1595 return T::GetCurrentState();
1596 }
1597
1598
1599 // --------------------------------------------------------------------
1600
1601 int AddReferenceDac(const EventImp &evt)
1602 {
1603 if (!CheckEventSize(evt.GetSize(), "AddReferenceDac", 2*kNumChannels))
1604 return false;
1605
1606 const int16_t *ptr = evt.Ptr<int16_t>();
1607 fBias.AddDac(vector<int16_t>(ptr, ptr+416));
1608
1609 return T::GetCurrentState();
1610 }
1611
1612 int AddReferenceVolt(const EventImp &evt)
1613 {
1614 if (!CheckEventSize(evt.GetSize(), "AddReferenceVolt", 4*kNumChannels))
1615 return false;
1616
1617 const float_t *ptr = evt.Ptr<float>();
1618 fBias.AddVolt(vector<float>(ptr, ptr+416));
1619
1620 return T::GetCurrentState();
1621 }
1622
1623 int SetReferenceDac(const EventImp &evt)
1624 {
1625 if (!CheckEventSize(evt.GetSize(), "SetReferenceDac", 2*kNumChannels))
1626 return false;
1627
1628 const int16_t *ptr = evt.Ptr<int16_t>();
1629 fBias.SetDac(vector<int16_t>(ptr, ptr+416));
1630
1631 return T::GetCurrentState();
1632 }
1633
1634 int SetReferenceVolt(const EventImp &evt)
1635 {
1636 if (!CheckEventSize(evt.GetSize(), "SetReferenceVolt", 4*kNumChannels))
1637 return false;
1638
1639 const float_t *ptr = evt.Ptr<float>();
1640 fBias.SetVolt(vector<float>(ptr, ptr+416));
1641
1642 return T::GetCurrentState();
1643 }
1644
1645 // --------------------------------------------------------------------
1646
1647 int ExpertSetGlobalVolt(const EventImp &evt)
1648 {
1649 if (!CheckEventSize(evt.GetSize(), "ExpertSetGlobalVolt", 4))
1650 return false;
1651
1652 fBias.ExpertGlobalSetVolt(evt.GetFloat());
1653
1654 return T::GetCurrentState();
1655 }
1656
1657 int ExpertSetGlobalDac(const EventImp &evt)
1658 {
1659 if (!CheckEventSize(evt.GetSize(), "ExpertSetGlobalDac", 2))
1660 return false;
1661
1662 fBias.ExpertGlobalSetDac(evt.GetUShort());
1663
1664 return T::GetCurrentState();
1665 }
1666
1667 int ExpertSetChannelVolt(const EventImp &evt)
1668 {
1669 if (!CheckEventSize(evt.GetSize(), "ExpertSetChannelVolt", 6))
1670 return false;
1671
1672 fBias.ExpertChannelSetVolt(evt.GetUShort(), evt.Get<float>(2));
1673
1674 return T::GetCurrentState();
1675 }
1676
1677 int ExpertSetChannelDac(const EventImp &evt)
1678 {
1679 if (!CheckEventSize(evt.GetSize(), "ExpertSetChannelDac", 4))
1680 return false;
1681
1682 fBias.ExpertChannelSetDac(evt.Get<uint16_t>(), evt.Get<uint16_t>(2));
1683
1684 return T::GetCurrentState();
1685 }
1686
1687 // --------------------------------------------------------------------
1688
1689 int SetUpdateInterval(const EventImp &evt)
1690 {
1691 if (!CheckEventSize(evt.GetSize(), "SetUpdateInterval", 2))
1692 return false;
1693
1694 fBias.SetUpdateInterval(evt.Get<int16_t>()<0 ? 0 : evt.Get<int16_t>());
1695
1696 return T::GetCurrentState();
1697 }
1698
1699 int Disconnect()
1700 {
1701 // Close all connections
1702 fBias.PostClose(false);
1703
1704 /*
1705 // Now wait until all connection have been closed and
1706 // all pending handlers have been processed
1707 poll();
1708 */
1709
1710 return T::GetCurrentState();
1711 }
1712
1713 int Reconnect(const EventImp &evt)
1714 {
1715 // Close all connections to supress the warning in SetEndpoint
1716 fBias.PostClose(false);
1717
1718 // Now wait until all connection have been closed and
1719 // all pending handlers have been processed
1720 poll();
1721
1722 if (evt.GetBool())
1723 fBias.SetEndpoint(evt.GetString());
1724
1725 // Now we can reopen the connection
1726 fBias.PostClose(true);
1727
1728 return T::GetCurrentState();
1729 }
1730
1731 int SetVerbosity(const EventImp &evt)
1732 {
1733 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
1734 return T::kSM_FatalError;
1735
1736 fBias.SetVerbose(evt.GetBool());
1737
1738 return T::GetCurrentState();
1739 }
1740
1741 int SetExpertMode(const EventImp &evt)
1742 {
1743 if (!CheckEventSize(evt.GetSize(), "SetExpertMode", 1))
1744 return T::kSM_FatalError;
1745
1746 fExpertMode = evt.GetBool();
1747
1748 if (fExpertMode)
1749 T::Warn("Expert commands enabled -- please ensure that you EXACTLY know what you do. These commands can destroy the system.");
1750
1751 return T::GetCurrentState();
1752 }
1753
1754 int Execute()
1755 {
1756 // Dispatch (execute) at most one handler from the queue. In contrary
1757 // to run_one(), it doesn't wait until a handler is available
1758 // which can be dispatched, so poll_one() might return with 0
1759 // handlers dispatched. The handlers are always dispatched/executed
1760 // synchronously, i.e. within the call to poll_one()
1761 poll_one();
1762
1763 return fExpertMode && fBias.GetStatus()>=kConnected ?
1764 kExpertMode : fBias.GetStatus();
1765 }
1766
1767public:
1768 StateMachineBias(ostream &out=cout) :
1769 T(out, "BIAS_CONTROL"), ba::io_service::work(static_cast<ba::io_service&>(*this)),
1770 fBias(*this, *this), fExpertMode(false)
1771 {
1772 // ba::io_service::work is a kind of keep_alive for the loop.
1773 // It prevents the io_service to go to stopped state, which
1774 // would prevent any consecutive calls to run()
1775 // or poll() to do nothing. reset() could also revoke to the
1776 // previous state but this might introduce some overhead of
1777 // deletion and creation of threads and more.
1778
1779 // State names
1780 T::AddStateName(kDisconnected, "Disconnected",
1781 "Bias-power supply not connected via USB.");
1782
1783 T::AddStateName(kConnecting, "Connecting",
1784 "Trying to establish USB connection to bias-power supply.");
1785
1786 T::AddStateName(kInitializing, "Initializing",
1787 "USB connection to bias-power supply established, synchronizing USB stream.");
1788
1789 T::AddStateName(kConnected, "Connected",
1790 "USB connection to bias-power supply established.");
1791
1792 T::AddStateName(kNotReferenced, "NotReferenced",
1793 "Internal reference voltage does not match last sent voltage.");
1794
1795 T::AddStateName(kVoltageOff, "VoltageOff",
1796 "All voltages are supposed to be switched off.");
1797
1798 T::AddStateName(kVoltageOn, "VoltageOn",
1799 "At least one voltage is switched on and all are at reference.");
1800
1801 T::AddStateName(kOverCurrent, "OverCurrent",
1802 "At least one channel is in over current state.");
1803
1804 T::AddStateName(kExpertMode, "ExpertMode",
1805 "Special (risky!) mode to directly send command to the bias-power supply.");
1806
1807 T::AddStateName(kRamping, "Ramping",
1808 "Voltage ramping in progress.");
1809
1810 // Verbosity commands
1811 T::AddEvent("SET_VERBOSE", "B")
1812 (bind(&StateMachineBias::SetVerbosity, this, placeholders::_1))
1813 ("set verbosity state"
1814 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
1815
1816 // Conenction commands
1817 T::AddEvent("DISCONNECT", kConnected, kVoltageOff)
1818 (bind(&StateMachineBias::Disconnect, this))
1819 ("disconnect from USB");
1820
1821 T::AddEvent("RECONNECT", "O", kDisconnected, kConnected, kVoltageOff)
1822 (bind(&StateMachineBias::Reconnect, this, placeholders::_1))
1823 ("(Re)connect USB connection to Bias power supply, a new address can be given"
1824 "|tty[string]:new USB address");
1825
1826
1827 T::AddEvent("SET_UPDATE_INTERVAL", "S:1")
1828 (bind(&StateMachineBias::SetUpdateInterval, this, placeholders::_1))
1829 ("Set the updat einterval how often the currents are requested"
1830 "|interval[ms]:Update interval in milliseconds");
1831
1832
1833
1834 T::AddEvent("REQUEST_STATUS", kConnected, kVoltageOn, kVoltageOff, kNotReferenced, kOverCurrent)
1835 (Wrapper(bind(&ConnectionBias::ReadAllChannels, &fBias, false)))
1836 ("Asynchronously request the status (current) of all channels.");
1837
1838 T::AddEvent("RESET_OVER_CURRENT_STATUS", kOverCurrent)
1839 (Wrapper(bind(&ConnectionBias::OverCurrentReset, &fBias)))
1840 ("Set all channels in over current state to 0V and send a system reset to reset the over current flags.");
1841
1842
1843
1844 T::AddEvent("SET_GLOBAL_VOLTAGE", "F:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1845 (bind(&StateMachineBias::SetGlobalVolt, this, placeholders::_1))
1846 ("Set all channels to a new reference voltage. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
1847 "|voltage[V]:Global target voltage in volts (will be converted to DAC units)");
1848
1849 T::AddEvent("SET_GLOBAL_DAC", "S:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1850 (bind(&StateMachineBias::SetGlobalDac, this, placeholders::_1))
1851 ("Set all channels to a new DAC reference. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
1852 "|voltage[dac]:Global target voltage as DAC counts.");
1853
1854 T::AddEvent("INCREASE_GLOBAL_VOLTAGE", "F:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1855 (bind(&StateMachineBias::IncGlobalVolt, this, placeholders::_1))
1856 ("Set all channels to a new reference voltage. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
1857 "|offset[V]:Offset to be added to all channels (will be converted to DAC counts)");
1858
1859 T::AddEvent("INCREASE_GLOBAL_DAC", "S:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1860 (bind(&StateMachineBias::IncGlobalDac, this, placeholders::_1))
1861 ("Set all channels to a new DAC reference. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
1862 "|offset[dac]:Offset to be added to all channels as DAC counts");
1863
1864 T::AddEvent("DECREASE_GLOBAL_VOLTAGE", "F:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1865 (bind(&StateMachineBias::DecGlobalVolt, this, placeholders::_1))
1866 ("Set all channels to a new reference voltage. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
1867 "|offset[V]:Offset to be subtracted from all channels (will be converted to DAC counts)");
1868
1869 T::AddEvent("DECREASE_GLOBAL_DAC", "S:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1870 (bind(&StateMachineBias::DecGlobalDac, this, placeholders::_1))
1871 ("Set all channels to a new DAC reference. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
1872 "|offset[dac]:Offset to be subtracted from all channels as DAC counts");
1873
1874 T::AddEvent("SET_CHANNEL_VOLTAGE", "S:1;F:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1875 (bind(&StateMachineBias::SetChannelVolt, this, placeholders::_1))
1876 ("Set a single channel to a new reference voltage. Starts ramping if necessary."
1877 "|channel[short]:Channel for which to set the target voltage [0-416]"
1878 "|voltage[V]:Target voltage in volts for the given channel (will be converted to DAC units)");
1879
1880 T::AddEvent("SET_CHANNEL_DAC", "S:1;S:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1881 (bind(&StateMachineBias::SetChannelDac, this, placeholders::_1))
1882 ("Set a single channel to a new DAC reference value. Starts ramping if necessary."
1883 "|channel[short]:Channel for which to set the target voltage [0-416]"
1884 "|voltage[dac]:Target voltage in DAC units for the given channel");
1885
1886 T::AddEvent("SET_GLOBAL_GAPD_REFERENCE_VOLTAGE", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1887 (Wrapper(bind(&ConnectionBias::SetGapdVoltage, &fBias, 0.)))
1888 ("Set all channels to their G-APD reference voltage. Starts ramping if necessary.");
1889
1890 T::AddEvent("SET_CHANNEL_GAPD_REFERENCE_VOLTAGE", "S:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1891 (bind(&StateMachineBias::SetGapdReferenceCh, this, placeholders::_1))
1892 ("Set a single channel channels to its G-APD reference voltage. Starts ramping if necessary."
1893 "|channel[short]:Channel for which to set the target voltage [0-416]");
1894
1895 T::AddEvent("SET_GAPD_REFERENCE_OFFSET", "F:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1896 (bind(&StateMachineBias::SetGapdVoltage, this, placeholders::_1))
1897 ("Set all channels to their G-APD reference voltage plus the given offset. Starts ramping if necessary."
1898 "|offset[V]:Offset to be added to teh G-APD reference voltage globally");
1899
1900 T::AddEvent("SET_ZERO_VOLTAGE", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1901 (Wrapper(bind(&ConnectionBias::SetZero, &fBias)))
1902 ("Set all channels to a zero reference voltage. Starts ramping if necessary.");
1903
1904 T::AddEvent("SET_REFERENCE_VOLTAGES", "F:416", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1905 (bind(&StateMachineBias::SetReferenceVolt, this, placeholders::_1))
1906 ("Set all channels to the given new reference voltage. Starts ramping if necessary."
1907 "voltage[V]:New reference voltage for all channels");
1908
1909 T::AddEvent("SET_REFERENCE_DACS", "S:416", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1910 (bind(&StateMachineBias::SetReferenceDac, this, placeholders::_1))
1911 ("Set all channels to the given new reference voltage. Starts ramping if necessary."
1912 "voltage[dac]:New reference voltage for all channels in DAC units");
1913
1914 T::AddEvent("ADD_REFERENCE_VOLTAGES", "F:416", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1915 (bind(&StateMachineBias::AddReferenceVolt, this, placeholders::_1))
1916 ("Add the given voltages to the current reference voltages. Starts ramping if necessary."
1917 "offset[V]:Offsets to be added to the reference voltage of all channels in volts");
1918
1919 T::AddEvent("ADD_REFERENCE_DACS", "S:416", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1920 (bind(&StateMachineBias::AddReferenceDac, this, placeholders::_1))
1921 ("Add the given voltages to the current reference voltages. Starts ramping if necessary."
1922 "offset[dac]:Offsets to be added to the reference voltage of all channels in DAC units");
1923
1924
1925
1926
1927 T::AddEvent("STOP", kConnected, kRamping)
1928 (Wrapper(bind(&ConnectionBias::RampStop, &fBias)))
1929 ("Stop an on-going ramping");
1930
1931 T::AddEvent("START", kConnected, kNotReferenced)
1932 (Wrapper(bind(&ConnectionBias::RampStart, &fBias)))
1933 ("Start a ramping if no ramping is in progress and if reference values differ from current voltages");
1934
1935
1936
1937 T::AddEvent("PRINT_INFO")
1938 (Wrapper(bind(&ConnectionBias::PrintInfo, &fBias)))
1939 ("Print a table with all current read back with the last request operation");
1940 T::AddEvent("PRINT_CURRENTS")
1941 (Wrapper(bind(&ConnectionBias::PrintA, &fBias)))
1942 ("Print a table with all current read back with the last request operation");
1943 T::AddEvent("PRINT_VOLTAGES")
1944 (Wrapper(bind(&ConnectionBias::PrintV, &fBias)))
1945 ("Print a table with all voltages (current and reference voltages as currently in memory)");
1946 T::AddEvent("PRINT_GAPD_REFERENCE_VOLTAGES")
1947 (Wrapper(bind(&ConnectionBias::PrintGapd, &fBias)))
1948 ("Print the G-APD reference values obtained from file");
1949
1950
1951 T::AddEvent("EXPERT_MODE", "B:1")
1952 (bind(&StateMachineBias::SetExpertMode, this, placeholders::_1))
1953 ("Enable usage of expert commands (note that for safty reasons the are exclusive with the standard commands)");
1954
1955 T::AddEvent("EXPERT_RESET", kExpertMode)
1956 (Wrapper(bind(&ConnectionBias::ExpertReset, &fBias, true)))
1957 ("Send the RESET command (note that this is possibly harmfull command)");
1958
1959 T::AddEvent("EXPERT_SET_GLOBAL_VOLTAGE", "F:1", kExpertMode)
1960 (bind(&StateMachineBias::ExpertSetGlobalVolt, this, placeholders::_1))
1961 ("Send the global set command. The given voltage is converted to DAC counts.");
1962
1963 T::AddEvent("EXPERT_SET_GLOBAL_DAC", "S:1", kExpertMode)
1964 (bind(&StateMachineBias::ExpertSetGlobalDac, this, placeholders::_1))
1965 ("Send the global set command.");
1966
1967 T::AddEvent("EXPERT_SET_CHANNEL_VOLTAGE", "S:1;F:1", kExpertMode)
1968 (bind(&StateMachineBias::ExpertSetChannelVolt, this, placeholders::_1))
1969 ("Send a single channel set command. The given voltage is converted to DAC commands.");
1970
1971 T::AddEvent("EXPERT_SET_CHANNEL_DAC", "S:1;S:1", kExpertMode)
1972 (bind(&StateMachineBias::ExpertSetChannelDac, this, placeholders::_1))
1973 ("Send a single channel set command.");
1974 }
1975
1976 ~StateMachineBias() { T::Warn("TODO: Implement rampming at shutdown!"); }
1977
1978 int EvalOptions(Configuration &conf)
1979 {
1980 // FIXME: Read calib_offset
1981 // FIXME: Check calib offset being smaller than +/-0.25V
1982
1983 fBias.SetVerbose(!conf.Get<bool>("quiet"));
1984
1985 fBias.SetEndpoint(conf.Get<string>("dev"));
1986 T::Message("Setting device to "+fBias.URL());
1987
1988 const uint16_t step = conf.Get<uint16_t>("ramp-step");
1989 const uint16_t time = conf.Get<uint16_t>("ramp-time");
1990
1991 if (step>230) // 5V
1992 {
1993 T::Error("ramp-step exceeds allowed range.");
1994 return 1;
1995 }
1996
1997 fBias.SetRampStep(step);
1998 fBias.SetRampTime(time);
1999 fBias.SetUpdateInterval(conf.Get<uint16_t>("update-interval"));
2000 fBias.SetSyncDelay(conf.Get<uint16_t>("sync-delay"));
2001
2002 ostringstream str1, str2;
2003 str1 << "Ramping in effective steps of " << fBias.GetRampStepVolt() << "V";
2004 str2 << "Ramping with a delay per step of " << time << "ms";
2005 T::Message(str1);
2006 T::Message(str2);
2007
2008 // --------------------------------------------------------------------------
2009
2010 const float maxabsv = conf.Get<float>("volt-max-abs");
2011 const float maxrelv = conf.Get<float>("volt-max-rel");
2012 if (maxabsv>90)
2013 {
2014 T::Error("volt-max exceeds 90V.");
2015 return 2;
2016 }
2017 if (maxabsv>75)
2018 T::Warn("volt-max exceeds 75V.");
2019 if (maxabsv<70)
2020 T::Warn("volt-max below 70V.");
2021 if (maxabsv<0)
2022 {
2023 T::Error("volt-max negative.");
2024 return 3;
2025 }
2026
2027 fBias.SetVoltMaxAbs(maxabsv);
2028 fBias.SetVoltMaxRel(maxrelv);
2029
2030 ostringstream str3, str4;
2031 str3 << "Effective maximum allowed absolute voltage: " << fBias.GetVoltMaxAbs() << "V";
2032 str4 << "Effective maximum difference w.r.t to G-APD reference: " << fBias.GetVoltMaxRel() << "V";
2033 T::Message(str3);
2034 T::Message(str4);
2035
2036 // --------------------------------------------------------------------------
2037
2038 PixelMap map;
2039 if (!map.Read(conf.Get<string>("pixel-map-file")))
2040 {
2041 T::Error("Reading reference voltages from "+conf.Get<string>("pixel-map-file")+" failed.");
2042 return 5;
2043 }
2044
2045 if (!fBias.SetNewGapdVoltage(map.Vgapd()))
2046 {
2047 T::Error("Setting reference voltages failed.");
2048 return 6;
2049 }
2050
2051 // --------------------------------------------------------------------------
2052
2053 fBias.Connect();
2054
2055 return -1;
2056 }
2057};
2058
2059// ------------------------------------------------------------------------
2060
2061#include "Main.h"
2062
2063template<class T, class S, class R>
2064int RunShell(Configuration &conf)
2065{
2066 return Main::execute<T, StateMachineBias<S, R>>(conf);
2067}
2068
2069void SetupConfiguration(Configuration &conf)
2070{
2071 po::options_description control("BIAS control options");
2072 control.add_options()
2073 ("no-dim,d", po_bool(), "Disable dim services")
2074 ("dev", var<string>("FTE00FOH"), "Device address of USB port to bias-power supply")
2075 ("quiet,q", po_bool(), "Disable printing contents of all received messages (except dynamic data) in clear text.")
2076 ("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.")
2077 ("ramp-step", var<uint16_t>(46), "Maximum step in DAC counts during ramping (Volt = DAC*90/4096)")
2078 ("update-interval", var<uint16_t>(3000), "Interval between two current requests in milliseconds")
2079 ("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")
2080 ("volt-max-abs", var<float>(75), "Absolte upper limit for the voltage (in Volts)")
2081 ("volt-max-rel", var<float>(2.5), "Relative upper limit for the voltage w.r.t. the G-APD reference voltage (in Volts)")
2082 ("pixel-map-file", var<string>("FACTmapV5a.txt"), "Pixel mapping file. Used here to get the default reference voltage.")
2083 ;
2084
2085 conf.AddOptions(control);
2086}
2087
2088/*
2089 Extract usage clause(s) [if any] for SYNOPSIS.
2090 Translators: "Usage" and "or" here are patterns (regular expressions) which
2091 are used to match the usage synopsis in program output. An example from cp
2092 (GNU coreutils) which contains both strings:
2093 Usage: cp [OPTION]... [-T] SOURCE DEST
2094 or: cp [OPTION]... SOURCE... DIRECTORY
2095 or: cp [OPTION]... -t DIRECTORY SOURCE...
2096 */
2097void PrintUsage()
2098{
2099 cout <<
2100 "The biasctrl program controls the bias-power supply boards.\n"
2101 "\n"
2102 "Note: At default the program is started without a command line (user) "
2103 "interface. In this case Actions/Commands are available via Dim "
2104 "exclusively.\n"
2105 "Use the -c option to start the program with a command line interface.\n"
2106 "\n"
2107 "In the running application:\n"
2108 "Use h or help to print a short help message about its usage.\n"
2109 "\n"
2110 "Usage: biasctrl [-c type] [OPTIONS]\n"
2111 " or: biasctrl [OPTIONS]\n";
2112 cout << endl;
2113}
2114
2115void PrintHelp()
2116{
2117 Main::PrintHelp<StateMachineBias<StateMachine,ConnectionBias>>();
2118
2119 /* Additional help text which is printed after the configuration
2120 options goes here */
2121
2122 /*
2123 cout << "bla bla bla" << endl << endl;
2124 cout << endl;
2125 cout << "Environment:" << endl;
2126 cout << "environment" << endl;
2127 cout << endl;
2128 cout << "Examples:" << endl;
2129 cout << "test exam" << endl;
2130 cout << endl;
2131 cout << "Files:" << endl;
2132 cout << "files" << endl;
2133 cout << endl;
2134 */
2135}
2136
2137int main(int argc, const char* argv[])
2138{
2139 Configuration conf(argv[0]);
2140 conf.SetPrintUsage(PrintUsage);
2141 Main::SetupConfiguration(conf);
2142 SetupConfiguration(conf);
2143
2144 if (!conf.DoParse(argc, argv, PrintHelp))
2145 return -1;
2146
2147 //try
2148 {
2149 // No console access at all
2150 if (!conf.Has("console"))
2151 {
2152 if (conf.Get<bool>("no-dim"))
2153 return RunShell<LocalStream, StateMachine, ConnectionBias>(conf);
2154 else
2155 return RunShell<LocalStream, StateMachineDim, ConnectionDimBias>(conf);
2156 }
2157 // Cosole access w/ and w/o Dim
2158 if (conf.Get<bool>("no-dim"))
2159 {
2160 if (conf.Get<int>("console")==0)
2161 return RunShell<LocalShell, StateMachine, ConnectionBias>(conf);
2162 else
2163 return RunShell<LocalConsole, StateMachine, ConnectionBias>(conf);
2164 }
2165 else
2166 {
2167 if (conf.Get<int>("console")==0)
2168 return RunShell<LocalShell, StateMachineDim, ConnectionDimBias>(conf);
2169 else
2170 return RunShell<LocalConsole, StateMachineDim, ConnectionDimBias>(conf);
2171 }
2172 }
2173 /*catch (std::exception& e)
2174 {
2175 cerr << "Exception: " << e.what() << endl;
2176 return -1;
2177 }*/
2178
2179 return 0;
2180}
Note: See TracBrowser for help on using the repository browser.