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

Last change on this file since 13137 was 13136, checked in by tbretz, 13 years ago
Made sure that the first automatic status request at connection also happens when the automatic updates are switched off; do not send a voltage set command when the voltages are already set.
File size: 68.1 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> fDacCmd; // 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 fGlobalDacCmd; // 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 uint32_t fUpdateTime;
58 uint16_t fSyncTime;
59
60 int fIsInitializing;
61 bool fIsRamping;
62 int fWaitingForAnswer;
63
64 vector<uint64_t> fCounter;
65
66protected:
67 vector<uint16_t> fDac; // Current voltage in DAC units (12bit = 90V)
68 vector<uint16_t> fDacRef; // Current reference voltage in DAC units (12bit = 90V)
69 vector<uint16_t> fDacGapd; // Nominal G-APD voltages at 25deg C
70
71 vector<int16_t> fCurrent; // Current in ADC units (12bit = 5mA)
72
73 uint16_t fDacMaxAbs;
74 uint16_t fDacMaxRel;
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>fDacMaxAbs)
108 {
109 str << "DAC value " << dac << " exceeds allowed absolute maximum of " << fDacMaxAbs;
110 Error(str);
111 return false;
112 }
113 if (dac>fDacGapd[ch]+fDacMaxRel)
114 {
115 str << "DAC value " << dac << " exceeds allowed channel maximum of " << fDacGapd[ch] << " + " << fDacMaxRel;
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 fDac[i] = fGlobalDacCmd;
254
255 fGlobalDacCmd = -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 fDac[id] = fDacCmd[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 = 2;
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 HandleReceivedData(fBuffer, bytes_received, command, send_counter);
507 fWaitingForAnswer = -1;
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==1)
527 Warn("Synchronization aborted...");
528 // case 0 and 2 should not happen
529 return;
530 }
531
532 if (error)
533 {
534 ostringstream str;
535 str << "Synchronization timer: " << error.message() << " (" << error << ")";// << endl;
536 Error(str);
537
538 CloseImp(false);
539 return;
540 }
541
542 if (!is_open())
543 {
544 Warn("Synchronization in progress, but disconnected.");
545 return;
546 }
547
548 ostringstream msg;
549 msg << "Synchronization time expired (" << counter << ")";
550 Info(msg);
551
552 if (fIsInitializing)
553 {
554 PostMessage("\0", 1);
555
556 if (counter==2)
557 {
558 Error("Synchronization attempt timed out.");
559 CloseImp(false);
560 return;
561 }
562
563 ScheduleSync(counter+1);
564 return;
565 }
566
567 Info("Synchronisation successfull.");
568 }
569
570 void ScheduleSync(int counter=0)
571 {
572 fSyncTimer.expires_from_now(boost::posix_time::milliseconds(fSyncTime));
573 fSyncTimer.async_wait(boost::bind(&ConnectionBias::HandleSyncTimer, this, counter, dummy::error));
574 }
575
576 // This is called when a connection was established
577 void ConnectionEstablished()
578 {
579 // We connect for the first time or haven't received
580 // a valid warp counter yet... this procedure also sets
581 // our volatges to 0 if we have connected but never received
582 // any answer.
583 if (fWrapCounter<0)
584 {
585 fDac.assign( kNumChannels, 0);
586 fDacRef.assign(kNumChannels, 0);
587 fDacCmd.assign(kNumChannels, 0);
588 }
589
590 // Reset everything....
591 fSendCounter = -1;
592 fWrapCounter = -1;
593 fGlobalDacCmd = -1;
594 fIsInitializing = 1;
595 fIsRamping = false;
596
597 // Send a single 0 (and possible two consecutive 0's
598 // to make sure we are in sync with the device)
599 PostMessage("\0", 1);
600 AsyncRead(ba::buffer(fBuffer, 3), kSynchronize, 0);//++fSendCounter);
601 fWaitingForAnswer = kSynchronize;
602
603 // Wait for some time before sending the next 0
604 ScheduleSync();
605 }
606
607 // --------------------------------------------------------------------
608
609 void HandleUpdateTimer(const bs::error_code &error)
610 {
611 if (error==ba::error::basic_errors::operation_aborted)
612 {
613 Warn("Update timer aborted...");
614 fIsRamping = false;
615 return;
616 }
617
618 if (error)
619 {
620 ostringstream str;
621 str << "Update timer: " << error.message() << " (" << error << ")";// << endl;
622 Error(str);
623
624 PostClose(false);
625 return;
626 }
627
628 if (!is_open())
629 return;
630
631 if (fUpdateTime==0 && fIsInitializing!=2)
632 return;
633
634 if (fIsRamping)
635 ScheduleUpdate(fUpdateTime);
636 else
637 ReadAllChannels(true);
638
639 fIsInitializing = 0;
640 }
641
642 void ScheduleUpdate(int millisec)
643 {
644 fUpdateTimer.expires_from_now(boost::posix_time::milliseconds(millisec));
645 fUpdateTimer.async_wait(boost::bind(&ConnectionBias::HandleUpdateTimer, this, dummy::error));
646 }
647
648 // --------------------------------------------------------------------
649
650 void SetAllChannels(const vector<uint16_t> &dac, bool special=false)
651 {
652 vector<char> data;
653 data.reserve(kNumChannels*3);
654
655 for (int ch=0; ch<kNumChannels; ch++)
656 {
657 // FIXME: dac[ch] += calib_offset
658 const vector<char> cmd = GetCmd(kCmdChannelSet, ch, dac[ch]);
659 data.insert(data.end(), cmd.begin(), cmd.end());
660
661 fDacCmd[ch] = dac[ch];
662 }
663
664 fSendCounter += kNumChannels;
665
666 if (fWaitingForAnswer>=0)
667 {
668 ostringstream msg;
669 msg << "SetAllChannels while waiting for answer to last command (id=" << fWaitingForAnswer << ")";
670 Warn(msg);
671 }
672
673 PostMessage(data);
674 AsyncRead(ba::buffer(special ? fBuffer : fBufferRamp, kNumChannels*3),
675 special ? kResetChannels : kCmdChannelSet, fSendCounter);
676
677 if (special)
678 fWaitingForAnswer = kResetChannels;
679 }
680
681 uint16_t RampOneStep(uint16_t ch)
682 {
683 if (fDacRef[ch]>fDac[ch])
684 return fDac[ch]+fRampStep>fDacRef[ch] ? fDacRef[ch] : fDac[ch]+fRampStep;
685
686 if (fDacRef[ch]<fDac[ch])
687 return fDac[ch]-fRampStep<fDacRef[ch] ? fDacRef[ch] : fDac[ch]-fRampStep;
688
689 return fDac[ch];
690 }
691
692 bool RampOneStep()
693 {
694 if (fRampTime<0)
695 {
696 Warn("Ramping step time not yet set... ramping not started.");
697 return false;
698 }
699 if (fRampStep<0)
700 {
701 Warn("Ramping step not yet set... ramping not started.");
702 return false;
703 }
704
705 vector<uint16_t> dac(kNumChannels);
706
707 bool identical = true;
708 for (int ch=0; ch<kNumChannels; ch++)
709 {
710 dac[ch] = RampOneStep(ch);
711 if (dac[ch]!=fDac[ch] && fPresent[ch/kNumChannelsPerBoard])
712 identical = false;
713 }
714
715 if (identical)
716 Info("Ramping: target values reached.");
717 else
718 SetAllChannels(dac);
719
720 return !identical;
721 }
722
723 void HandleRampTimer(const bs::error_code &error)
724 {
725 if (error==ba::error::basic_errors::operation_aborted)
726 {
727 Warn("Ramping aborted...");
728 fIsRamping = false;
729 return;
730 }
731
732 if (error)
733 {
734 ostringstream str;
735 str << "Ramping timer: " << error.message() << " (" << error << ")";// << endl;
736 Error(str);
737
738 PostClose(false);
739 return;
740 }
741
742 if (!is_open())
743 {
744 Warn("Ramping in progress, but disconnected.");
745 return;
746 }
747
748 if (!fIsRamping)
749 {
750 Error("Ramp handler called although no ramping in progress.");
751 return;
752 }
753
754 // Check whether the deadline has passed. We compare the deadline
755 // against the current time since a new asynchronous operation
756 // may have moved the deadline before this actor had a chance
757 // to run.
758 if (fRampTimer.expires_at() > ba::deadline_timer::traits_type::now())
759 return;
760
761 fIsRamping = RampOneStep();
762 }
763
764 void ScheduleRampStep()
765 {
766 fRampTimer.expires_from_now(boost::posix_time::milliseconds(fRampTime));
767 fRampTimer.async_wait(boost::bind(&ConnectionBias::HandleRampTimer, this, dummy::error));
768 }
769
770public:
771 ConnectionBias(ba::io_service& ioservice, MessageImp &imp) : ConnectionUSB(ioservice, imp()),
772 fSyncTimer(ioservice),
773 fRampTimer(ioservice),
774 fUpdateTimer(ioservice),
775 fBuffer(3*kNumChannels),
776 fBufferRamp(3*kNumChannels),
777 fBufferUpdate(3*kNumChannels),
778 fIsVerbose(false),
779 fDacCmd(kNumChannels),
780 fPresent(kNumBoards),
781 fWrapCounter(-1),
782 fRampStep(-1),
783 fRampTime(-1),
784 fUpdateTime(3000),
785 fSyncTime(333),
786 fIsRamping(false),
787 fWaitingForAnswer(-1),
788 fCounter(8),
789 fDac(kNumChannels),
790 fDacRef(kNumChannels),
791 fDacGapd(kNumChannels),
792 fCurrent(kNumChannels)
793 {
794 SetLogStream(&imp);
795 }
796
797 void OverCurrentReset()
798 {
799 if (fWaitingForAnswer>=0)
800 {
801 ostringstream msg;
802 msg << "OverCurrentReset - Answer on last command (id=" << fWaitingForAnswer << ") not yet received.";
803 Error(msg);
804 return;
805 }
806
807 if (fIsRamping)
808 {
809 Warn("OverCurrentReset - Ramping in progres.");
810 RampStop();
811 }
812
813 vector<uint16_t> dac(kNumChannels);
814
815 for (int ch=0; ch<kNumChannels; ch++)
816 dac[ch] = fCurrent[ch]<0 ? 0 : fDac[ch];
817
818 SetAllChannels(dac, true);
819 }
820
821 void ReadAllChannels(bool special = false)
822 {
823 if (!special && fWaitingForAnswer>=0)
824 {
825 ostringstream msg;
826 msg << "ReadAllChannels - Answer on last command (id=" << fWaitingForAnswer << ") not yet received.";
827 Error(msg);
828 return;
829 }
830
831 vector<char> data;
832 data.reserve(kNumChannels*3);
833
834 for (int ch=0; ch<kNumChannels; ch++)
835 {
836 const vector<char> cmd = GetCmd(kCmdRead, ch);
837 data.insert(data.end(), cmd.begin(), cmd.end());
838 }
839
840 fSendCounter += kNumChannels;
841
842 PostMessage(data);
843 AsyncRead(ba::buffer(special ? fBufferUpdate : fBuffer, kNumChannels*3),
844 special ? kUpdate : kCmdRead, fSendCounter);
845
846 if (!special)
847 fWaitingForAnswer = kCmdRead;
848 }
849
850 // --------------------------------------------------------------------
851
852 bool ChannelSetDac(uint16_t ch, uint16_t dac)
853 {
854 if (!CheckChDac("ChannelSetDac", dac, ch))
855 return false;
856
857 fDacRef[ch] = dac;
858
859 if (!fIsRamping)
860 fIsRamping = RampOneStep();
861
862 return true;
863 }
864
865 bool ChannelSetVolt(uint16_t ch, double volt)
866 {
867 if (volt<0 || volt>90)
868 {
869 ostringstream msg;
870 msg << "ChannelSetVolt - Given voltage " << volt << "V out of range [0V,90V].";
871 Error(msg);
872 return false;
873 }
874
875 return ChannelSetDac(ch, volt*4096/90.);
876 }
877/*
878 bool GlobalSetDac(uint16_t dac)
879 {
880 if (!CheckChDac("GlobalSetDac", dac))
881 return false;
882
883 for (size_t ch=0; ch<kNumChannels; ch++)
884 fVoltRef[ch] = dac;
885
886 if (!fIsRamping)
887 fIsRamping = RampOneStep();
888
889 return true;
890 }
891
892 bool GlobalSetVolt(float volt)
893 {
894 if (volt<0 || volt>90)
895 {
896 Error("GlobalSetVolt - Voltage out of range [0V,90V].");
897 return false;
898 }
899
900 return GlobalSetDac(volt*4096/90);
901 }
902*/
903 bool AddDac(const vector<int16_t> &dac)
904 {
905 if (dac.size()!=kNumChannels)
906 {
907 Error("AddDac - Wrong size of array.");
908 return false;
909 }
910
911 for (size_t ch=0; ch<kNumChannels; ch++)
912 {
913 if (fDacRef[ch]+dac[ch]>kMaxDac)
914 {
915 ostringstream msg;
916 msg << "AddDac - New voltage reference " << fDacRef[ch] << "+" << dac[ch] << " out of range [0," << kMaxDac << " for channel " << ch << ".";
917 Error(msg);
918 return false;
919 }
920
921 if (fDacRef[ch]+dac[ch]<0)
922 fDacRef[ch] = 0;
923 else
924 fDacRef[ch] += dac[ch];
925 }
926
927 if (!fIsRamping)
928 fIsRamping = RampOneStep();
929
930 return true;
931 }
932
933 bool AddVolt(const vector<float> &offset)
934 {
935 vector<int16_t> dac(offset.size());
936
937 for (size_t ch=0; ch<offset.size(); ch++)
938 {
939 if (offset[ch]<-90 || offset[ch]>90)
940 {
941 ostringstream msg;
942 msg << "AddVolt - Offset voltage " << offset[ch] << "V for channel " << ch << " out of range [-90V,90V].";
943 Error(msg);
944 return false;
945 }
946 dac[ch] = offset[ch]*4096/90;
947 }
948
949 return AddDac(dac);
950 }
951
952 bool GlobalAddDac(int16_t offset)
953 {
954 return AddDac(vector<int16_t>(kNumChannels, offset));
955 }
956
957 bool GlobalAddVolt(float offset)
958 {
959 return AddVolt(vector<float>(kNumChannels, offset));
960 }
961
962 bool SetDac(const vector<int16_t> &dac)
963 {
964 if (dac.size()!=kNumChannels)
965 {
966 Error("SetDac - Wrong size of array.");
967 return false;
968 }
969
970 for (size_t ch=0; ch<kNumChannels; ch++)
971 {
972 if (!CheckChDac("SetDac", dac[ch]))
973 return false;
974
975 fDacRef[ch] = dac[ch];
976 }
977
978 if (!fIsRamping)
979 fIsRamping = RampOneStep();
980
981 return true;
982 }
983
984 bool SetVolt(const vector<float> &volt)
985 {
986 vector<int16_t> dac(volt.size());
987
988 for (size_t ch=0; ch<volt.size(); ch++)
989 {
990 if (volt[ch]<0 || volt[ch]>90)
991 {
992 ostringstream msg;
993 msg << "SetVolt - Voltage " << volt[ch] << "V out of range [0V,90V] for channel " << ch << ".";
994 Error(msg);
995 return false;
996 }
997 dac[ch] = volt[ch]*4096/90;
998 }
999
1000 return SetDac(dac);
1001 }
1002
1003 bool GlobalSetDac(int16_t dac)
1004 {
1005 return SetDac(vector<int16_t>(kNumChannels, dac));
1006 }
1007
1008 bool GlobalSetVolt(float volt)
1009 {
1010 return SetVolt(vector<float>(kNumChannels, volt));
1011 }
1012
1013
1014 // --------------------------------------------------------------------
1015
1016 bool SetGapdVoltage(float offset)
1017 {
1018 if (offset<-90 || offset>90)
1019 {
1020 ostringstream msg;
1021 msg << "SetGapdVoltage - Offset voltage " << offset << "V out of range [-90V,90V].";
1022 Error(msg);
1023 return false;
1024 }
1025
1026 const int16_t dac = offset*4096/90;
1027
1028 for (size_t ch=0; ch<kNumChannels; ch++)
1029 if (fDacGapd[ch]+dac>kMaxDac)
1030 {
1031 ostringstream msg;
1032 msg << "SetGapdVoltage - New voltage reference " << fDacGapd[ch] << "+" << dac << " out of range [0," << kMaxDac << " for channel " << ch << ".";
1033 Error(msg);
1034 return false;
1035 }
1036
1037 for (size_t ch=0; ch<kNumChannels; ch++)
1038 fDacRef[ch] = fDacGapd[ch]+dac<0 ? 0 : fDacGapd[ch]+dac;
1039
1040 if (!fIsRamping)
1041 fIsRamping = RampOneStep();
1042
1043 return true;
1044 }
1045
1046 bool SetGapdReferenceCh(uint16_t ch)
1047 {
1048 if (!CheckChDac("SetGapdReferenceCh", fDacGapd[ch], ch))
1049 return false;
1050
1051 fDacRef[ch] = fDacGapd[ch];
1052
1053 if (!fIsRamping)
1054 fIsRamping = RampOneStep();
1055
1056 return true;
1057 }
1058
1059
1060 void SetZero()
1061 {
1062 for (size_t ch=0; ch<kNumChannels; ch++)
1063 fDacRef[ch] = 0;
1064
1065 if (!fIsRamping)
1066 fIsRamping = RampOneStep();
1067 }
1068
1069 bool SetNewGapdVoltage(const vector<float> &volt)
1070 {
1071 if (volt.size()!=kNumChannels)
1072 {
1073 ostringstream out;
1074 out << "SetNewGapdVoltage - Given vector has " << volt.size() << " elements - expected " << kNumChannels << endl;
1075 Error(out);
1076 return false;
1077 }
1078
1079 for (size_t i=0; i<kNumChannels; i++)
1080 fDacGapd[i] = volt[i]*4096/90;
1081
1082 UpdateVgapd();
1083
1084 return true;
1085 }
1086
1087 // --------------------------------------------------------------------
1088
1089 void RampStop()
1090 {
1091 fRampTimer.cancel();
1092 fIsRamping = false;
1093
1094 Message("Ramping stopped.");
1095 }
1096
1097 void RampStart()
1098 {
1099 if (fIsRamping)
1100 {
1101 Warn("RampStart - Ramping already in progress... ignored.");
1102 return;
1103 }
1104
1105 fIsRamping = RampOneStep();
1106 }
1107
1108 void SetRampTime(uint16_t val)
1109 {
1110 fRampTime = val;
1111 }
1112
1113 void SetRampStep(uint16_t val)
1114 {
1115 fRampStep = val;
1116 }
1117
1118 uint16_t GetRampStepVolt() const
1119 {
1120 return fRampStep*90./4096;
1121 }
1122
1123 bool IsRamping() const { return fIsRamping; }
1124
1125 // -------------------------------------------------------------------
1126
1127 void ExpertReset(bool expert_mode=true)
1128 {
1129 if (expert_mode && fWaitingForAnswer>=0)
1130 {
1131 ostringstream msg;
1132 msg << "ExpertReset - Answer on last command (id=" << fWaitingForAnswer << ") not yet received.";
1133 Error(msg);
1134 return;
1135 }
1136
1137 if (expert_mode)
1138 Warn("EXPERT MODE: Sending reset.");
1139
1140 PostMessage(GetCmd(kCmdReset));
1141 AsyncRead(ba::buffer(fBuffer, 3), kCmdReset, ++fSendCounter);
1142 fWaitingForAnswer = kCmdReset;
1143 }
1144
1145
1146 bool ExpertChannelSetDac(uint16_t ch, uint16_t dac)
1147 {
1148 if (fWaitingForAnswer>=0)
1149 {
1150 ostringstream msg;
1151 msg << "ExpertChannelSetDac - Answer on last command (id=" << fWaitingForAnswer << ") not yet received.";
1152 Error(msg);
1153 return false;
1154 }
1155
1156 if (!CheckChDac("ExpertChannelSetDac", dac, ch))
1157 return false;
1158
1159 fDacCmd[ch] = dac;
1160
1161 ostringstream msg;
1162 msg << "EXPERT MODE: Sending 'ChannelSet' (set ch " << ch << " to DAC=" << dac << ")";
1163 Warn(msg);
1164
1165 // FIXME: dac += calib_offset
1166 PostMessage(GetCmd(kCmdChannelSet, ch, dac));
1167 AsyncRead(ba::buffer(fBuffer, 3), kExpertChannelSet|(ch<<8), ++fSendCounter);
1168 fWaitingForAnswer = kExpertChannelSet|(ch<<8);
1169
1170 return true;
1171 }
1172
1173 bool ExpertChannelSetVolt(uint16_t ch, double volt)
1174 {
1175 return ExpertChannelSetDac(ch, volt*4096/90.);
1176 }
1177
1178 bool ExpertGlobalSetDac(uint16_t dac)
1179 {
1180 if (fWaitingForAnswer>=0)
1181 {
1182 ostringstream msg;
1183 msg << "ExpertGlobalSetDac - Answer on last command (id=" << fWaitingForAnswer << ") not yet received.";
1184 Error(msg);
1185 return false;
1186 }
1187
1188 if (!CheckChDac("ExpertGlobalSetDac", dac))
1189 return false;
1190
1191 if (fGlobalDacCmd>=0)
1192 {
1193 Error("ExpertGlobalSetDac - Still waiting for previous answer to 'GlobalSet'");
1194 return false;
1195 }
1196
1197 fGlobalDacCmd = dac;
1198
1199 ostringstream msg;
1200 msg << "EXPERT MODE: Sending 'GlobalSet' (DAC=" << dac << ")";
1201 Warn(msg);
1202
1203 PostMessage(GetCmd(kCmdGlobalSet, 0, dac));
1204 AsyncRead(ba::buffer(fBuffer, 3), kCmdGlobalSet, ++fSendCounter);
1205 fWaitingForAnswer = kCmdGlobalSet;
1206
1207 return true;
1208 }
1209
1210 bool ExpertGlobalSetVolt(float volt)
1211 {
1212 return ExpertGlobalSetDac(volt*4096/90);
1213 }
1214
1215 // --------------------------------------------------------------------
1216
1217 void SetVerbose(bool b)
1218 {
1219 fIsVerbose = b;
1220 }
1221
1222 void PrintInfo()
1223 {
1224 Out() << endl << kBold << dec << '\n';
1225 Out() << "fWrapCounter = " << fWrapCounter << '\n';
1226 Out() << "fSendCounter = " << fSendCounter%8 << " (" << fSendCounter << ")" << '\n';
1227 Out() << "fIsInitializing = " << fIsInitializing << '\n';
1228 Out() << "fIsRamping = " << fIsRamping << '\n';
1229 Out() << "Answer counter:" << '\n';
1230 Out() << " - Synchronization: " << fCounter[0] << '\n';
1231 Out() << " - Reset: " << fCounter[1] << '\n';
1232 Out() << " - Request update: " << fCounter[2] << '\n';
1233 Out() << " - Ramp step: " << fCounter[3] << '\n';
1234 Out() << " - Read: " << fCounter[4] << '\n';
1235 Out() << " - Reset channels: " << fCounter[5] << '\n';
1236 Out() << " - Global set: " << fCounter[7] << '\n';
1237 Out() << " - Channel set: " << fCounter[6] << '\n' << endl;
1238 }
1239
1240 void PrintLineA(int b, int ch)
1241 {
1242 Out() << setw(2) << b << "|";
1243
1244 for (int c=ch; c<ch+8; c++)
1245 {
1246 const int id = c+kNumChannelsPerBoard*b;
1247 Out() << (fCurrent[id]<0?kRed:kGreen);
1248 Out() << " " << setw(7) << abs(fCurrent[id])*5000/4096.;
1249 }
1250 Out() << endl;
1251
1252 }
1253
1254 void PrintA()
1255 {
1256 Out() << dec << setprecision(2) << fixed << setfill(' ');
1257 for (int b=0; b<kNumBoards; b++)
1258 {
1259 if (!fPresent[b])
1260 {
1261 Out() << setw(2) << b << "-" << endl;
1262 continue;
1263 }
1264
1265 PrintLineA(b, 0);
1266 PrintLineA(b, 8);
1267 PrintLineA(b, 16);
1268 PrintLineA(b, 24);
1269 }
1270 }
1271
1272 void PrintLineV(int b, int ch)
1273 {
1274 Out() << setw(2) << b << "|";
1275
1276 for (int c=ch; c<ch+4; c++)
1277 {
1278 const int id = c+kNumChannelsPerBoard*b;
1279 Out() << " ";
1280 Out() << (fDac[id]==fDacRef[id]?kGreen:kRed);
1281 Out() << setw(5) << fDac[id]*90/4096. << '/';
1282 Out() << setw(5) << fDacRef[id]*90/4096.;
1283 }
1284 Out() << endl;
1285 }
1286
1287 void PrintV()
1288 {
1289 Out() << dec << setprecision(2) << fixed << setfill(' ');
1290 for (int b=0; b<kNumBoards; b++)
1291 {
1292 if (!fPresent[b])
1293 {
1294 Out() << setw(2) << b << "-" << endl;
1295 continue;
1296 }
1297
1298 PrintLineV(b, 0);
1299 PrintLineV(b, 4);
1300 PrintLineV(b, 8);
1301 PrintLineV(b, 12);
1302 PrintLineV(b, 16);
1303 PrintLineV(b, 20);
1304 PrintLineV(b, 24);
1305 PrintLineV(b, 28);
1306 }
1307 }
1308
1309 void PrintLineGapd(int b, int ch)
1310 {
1311 Out() << setw(2) << b << "|";
1312
1313 for (int c=ch; c<ch+8; c++)
1314 {
1315 const int id = c+kNumChannelsPerBoard*b;
1316 Out() << " " << setw(5) << fDacGapd[id]*90/4096.;
1317 }
1318 Out() << endl;
1319 }
1320
1321 void PrintGapd()
1322 {
1323 Out() << dec << setprecision(2) << fixed << setfill(' ');
1324 for (int b=0; b<kNumBoards; b++)
1325 {
1326 if (!fPresent[b])
1327 {
1328 Out() << setw(2) << b << "-" << endl;
1329 continue;
1330 }
1331
1332 PrintLineGapd(b, 0);
1333 PrintLineGapd(b, 8);
1334 PrintLineGapd(b, 16);
1335 PrintLineGapd(b, 24);
1336 }
1337 }
1338
1339 // -------------------------------------------------------------------
1340
1341 void SetUpdateInterval(uint32_t val)
1342 {
1343 fUpdateTime = val;
1344
1345 if (!IsConnected() || fIsInitializing)
1346 return;
1347
1348 fUpdateTimer.cancel();
1349
1350 if (fUpdateTime>0)
1351 ScheduleUpdate(fUpdateTime);
1352 }
1353
1354 void SetSyncDelay(uint16_t val)
1355 {
1356 fSyncTime = val;
1357 }
1358
1359 void SetVoltMaxAbs(float max)
1360 {
1361 fDacMaxAbs = max*4096/90;
1362 if (fDacMaxAbs>4095)
1363 fDacMaxAbs = 4095;
1364 if (max<0)
1365 fDacMaxAbs = 0;
1366 }
1367
1368 void SetVoltMaxRel(float max)
1369 {
1370 fDacMaxRel = max*4096/90;
1371 if (fDacMaxRel>4095)
1372 fDacMaxRel = 4095;
1373 if (max<0)
1374 fDacMaxRel = 0;
1375 }
1376
1377 uint16_t GetVoltMaxAbs() const
1378 {
1379 return fDacMaxAbs * 90./4096;
1380 }
1381
1382 uint16_t GetVoltMaxRel() const
1383 {
1384 return fDacMaxRel * 90./4096;
1385 }
1386
1387/*
1388 void AdaptVoltages()
1389 {
1390 // Correct voltages according to current
1391 for (int i=0; i<kNumChannels; i++)
1392 {
1393 if (fVoltRef[i]==0 || fCurrent[i]<0 || fRefCurrent[i]<0)
1394 continue;
1395
1396 // Calculate difference and convert ADC units to Amp
1397 // const double diffcur = (fRefCurrent[i]-fCurrent[i])*5000/4096
1398 //const int32_t diffcur = int32_t(fRefCurrent[i]-fCurrent[i])*5000;
1399
1400 // Calculate voltage difference
1401 // #define RESISTOR 1000 // Ohm
1402 //const double diffvolt = diffcur*RESISTOR/1e6;
1403
1404 // Calculate new vlaue by onverting voltage difference to DAC units
1405 //const int32_t dac = fRefVolt[i] + diffvolt*4096/90.0;
1406 SetVoltage(i, fRefVolt[i] + (fRefCurrent[i]-fCurrent[i])/18);
1407 }
1408 }
1409
1410 void SetReferenceCurrent()
1411 {
1412 fRefCurrent = fCurrent;
1413 }
1414 */
1415
1416 States_t GetStatus()
1417 {
1418 if (!IsConnected())
1419 return BIAS::kDisconnected;
1420
1421 if (IsConnecting())
1422 return BIAS::kConnecting;
1423
1424 if (fIsInitializing)
1425 return BIAS::kInitializing;
1426
1427 if (fIsRamping)
1428 return BIAS::kRamping;
1429
1430 for (int ch=0; ch<kNumChannels; ch++)
1431 if (fPresent[ch/kNumChannelsPerBoard] && fCurrent[ch]<0)
1432 return BIAS::kOverCurrent;
1433
1434 bool isoff = true;
1435 for (int ch=0; ch<kNumChannels; ch++)
1436 if (fPresent[ch/kNumChannelsPerBoard] && fDac[ch]!=0)
1437 isoff = false;
1438 if (isoff)
1439 return BIAS::kVoltageOff;
1440
1441 for (int ch=0; ch<kNumChannels; ch++)
1442 if (fPresent[ch/kNumChannelsPerBoard] && fDac[ch]!=fDacRef[ch])
1443 return BIAS::kNotReferenced;
1444
1445 return BIAS::kVoltageOn;
1446 }
1447};
1448
1449// ------------------------------------------------------------------------
1450
1451#include "DimDescriptionService.h"
1452
1453class ConnectionDimBias : public ConnectionBias
1454{
1455private:
1456
1457 DimDescribedService fDimCurrent;
1458 DimDescribedService fDimVoltage;
1459 DimDescribedService fDimGapd;
1460
1461 void UpdateA()
1462 {
1463 fDimCurrent.Update(fCurrent);
1464 }
1465
1466 void UpdateV()
1467 {
1468 vector<uint16_t> vec;
1469 vec.insert(vec.end(), fDac.begin(), fDac.end());
1470 vec.insert(vec.end(), fDacRef.begin(), fDacRef.end());
1471 fDimVoltage.Update(vec);
1472 }
1473
1474 void UpdateVgapd()
1475 {
1476 fDimGapd.Update(fDacGapd);
1477 }
1478
1479public:
1480 ConnectionDimBias(ba::io_service& ioservice, MessageImp &imp) :
1481 ConnectionBias(ioservice, imp),
1482 fDimCurrent("BIAS_CONTROL/CURRENT", "S:416", "|I[uA]:Bias current"),
1483 fDimVoltage("BIAS_CONTROL/VOLTAGE", "S:416;S:416", "|U[V]:Applied bias voltage|Uref[V]:Reference bias voltage"),
1484 fDimGapd( "BIAS_CONTROL/NOMINAL", "S:416", "|U[V]:Nominal G-APD voltage at 25deg C")
1485 {
1486 }
1487
1488 // 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
1489};
1490
1491// ------------------------------------------------------------------------
1492
1493template <class T, class S>
1494class StateMachineBias : public T, public ba::io_service, public ba::io_service::work
1495{
1496 int Wrap(boost::function<void()> f)
1497 {
1498 f();
1499 return T::GetCurrentState();
1500 }
1501
1502 function<int(const EventImp &)> Wrapper(function<void()> func)
1503 {
1504 return bind(&StateMachineBias::Wrap, this, func);
1505 }
1506
1507 bool CheckEventSize(size_t has, const char *name, size_t size)
1508 {
1509 if (has==size)
1510 return true;
1511
1512 ostringstream msg;
1513 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
1514 T::Fatal(msg);
1515 return false;
1516 }
1517
1518private:
1519 S fBias;
1520
1521 bool fExpertMode;
1522
1523 // --------------------------------------------------------------------
1524
1525 int SetGapdVoltage(const EventImp &evt)
1526 {
1527 if (!CheckEventSize(evt.GetSize(), "SetGapdVoltage", 4))
1528 return false;
1529
1530 fBias.SetGapdVoltage(evt.GetFloat());
1531
1532 return T::GetCurrentState();
1533 }
1534
1535 // --------------------------------------------------------------------
1536
1537 int SetGlobalVolt(const EventImp &evt)
1538 {
1539 if (!CheckEventSize(evt.GetSize(), "SetGlobalVolt", 4))
1540 return false;
1541
1542 fBias.GlobalSetVolt(evt.GetFloat());
1543
1544 return T::GetCurrentState();
1545 }
1546
1547 int SetGlobalDac(const EventImp &evt)
1548 {
1549 if (!CheckEventSize(evt.GetSize(), "SetGlobalDac", 2))
1550 return false;
1551
1552 fBias.GlobalSetDac(evt.GetUShort());
1553
1554 return T::GetCurrentState();
1555 }
1556
1557 int IncGlobalVolt(const EventImp &evt)
1558 {
1559 if (!CheckEventSize(evt.GetSize(), "IncGlobalVolt", 4))
1560 return false;
1561
1562 fBias.GlobalAddVolt(evt.GetFloat());
1563
1564 return T::GetCurrentState();
1565 }
1566
1567 int IncGlobalDac(const EventImp &evt)
1568 {
1569 if (!CheckEventSize(evt.GetSize(), "IncGlobalDac", 2))
1570 return false;
1571
1572 fBias.GlobalAddDac(evt.GetShort());
1573
1574 return T::GetCurrentState();
1575 }
1576
1577 int DecGlobalVolt(const EventImp &evt)
1578 {
1579 if (!CheckEventSize(evt.GetSize(), "DecGlobalVolt", 4))
1580 return false;
1581
1582 fBias.GlobalAddVolt(-evt.GetFloat());
1583
1584 return T::GetCurrentState();
1585 }
1586
1587 int DecGlobalDac(const EventImp &evt)
1588 {
1589 if (!CheckEventSize(evt.GetSize(), "DecGlobalDac", 2))
1590 return false;
1591
1592 fBias.GlobalAddDac(-evt.GetShort());
1593
1594 return T::GetCurrentState();
1595 }
1596
1597 int SetChannelVolt(const EventImp &evt)
1598 {
1599 if (!CheckEventSize(evt.GetSize(), "SetChannelVolt", 6))
1600 return false;
1601
1602 fBias.ChannelSetVolt(evt.GetUShort(), evt.Get<float>(2));
1603
1604 return T::GetCurrentState();
1605 }
1606
1607 int SetChannelDac(const EventImp &evt)
1608 {
1609 if (!CheckEventSize(evt.GetSize(), "SetChannelDac", 4))
1610 return false;
1611
1612 fBias.ChannelSetDac(evt.Get<uint16_t>(), evt.Get<uint16_t>(2));
1613
1614 return T::GetCurrentState();
1615 }
1616
1617 int SetGapdReferenceCh(const EventImp &evt)
1618 {
1619 if (!CheckEventSize(evt.GetSize(), "SetGapdReferenceCh", 2))
1620 return false;
1621
1622 fBias.SetGapdReferenceCh(evt.GetUShort());
1623
1624 return T::GetCurrentState();
1625 }
1626
1627
1628 // --------------------------------------------------------------------
1629
1630 int AddReferenceDac(const EventImp &evt)
1631 {
1632 if (!CheckEventSize(evt.GetSize(), "AddReferenceDac", 2*kNumChannels))
1633 return false;
1634
1635 const int16_t *ptr = evt.Ptr<int16_t>();
1636 fBias.AddDac(vector<int16_t>(ptr, ptr+416));
1637
1638 return T::GetCurrentState();
1639 }
1640
1641 int AddReferenceVolt(const EventImp &evt)
1642 {
1643 if (!CheckEventSize(evt.GetSize(), "AddReferenceVolt", 4*kNumChannels))
1644 return false;
1645
1646 const float_t *ptr = evt.Ptr<float>();
1647 fBias.AddVolt(vector<float>(ptr, ptr+416));
1648
1649 return T::GetCurrentState();
1650 }
1651
1652 int SetReferenceDac(const EventImp &evt)
1653 {
1654 if (!CheckEventSize(evt.GetSize(), "SetReferenceDac", 2*kNumChannels))
1655 return false;
1656
1657 const int16_t *ptr = evt.Ptr<int16_t>();
1658 fBias.SetDac(vector<int16_t>(ptr, ptr+416));
1659
1660 return T::GetCurrentState();
1661 }
1662
1663 int SetReferenceVolt(const EventImp &evt)
1664 {
1665 if (!CheckEventSize(evt.GetSize(), "SetReferenceVolt", 4*kNumChannels))
1666 return false;
1667
1668 const float_t *ptr = evt.Ptr<float>();
1669 fBias.SetVolt(vector<float>(ptr, ptr+416));
1670
1671 return T::GetCurrentState();
1672 }
1673
1674 // --------------------------------------------------------------------
1675
1676 int ExpertSetGlobalVolt(const EventImp &evt)
1677 {
1678 if (!CheckEventSize(evt.GetSize(), "ExpertSetGlobalVolt", 4))
1679 return false;
1680
1681 fBias.ExpertGlobalSetVolt(evt.GetFloat());
1682
1683 return T::GetCurrentState();
1684 }
1685
1686 int ExpertSetGlobalDac(const EventImp &evt)
1687 {
1688 if (!CheckEventSize(evt.GetSize(), "ExpertSetGlobalDac", 2))
1689 return false;
1690
1691 fBias.ExpertGlobalSetDac(evt.GetUShort());
1692
1693 return T::GetCurrentState();
1694 }
1695
1696 int ExpertSetChannelVolt(const EventImp &evt)
1697 {
1698 if (!CheckEventSize(evt.GetSize(), "ExpertSetChannelVolt", 6))
1699 return false;
1700
1701 fBias.ExpertChannelSetVolt(evt.GetUShort(), evt.Get<float>(2));
1702
1703 return T::GetCurrentState();
1704 }
1705
1706 int ExpertSetChannelDac(const EventImp &evt)
1707 {
1708 if (!CheckEventSize(evt.GetSize(), "ExpertSetChannelDac", 4))
1709 return false;
1710
1711 fBias.ExpertChannelSetDac(evt.Get<uint16_t>(), evt.Get<uint16_t>(2));
1712
1713 return T::GetCurrentState();
1714 }
1715
1716 // --------------------------------------------------------------------
1717
1718 int SetUpdateInterval(const EventImp &evt)
1719 {
1720 if (!CheckEventSize(evt.GetSize(), "SetUpdateInterval", 4))
1721 return false;
1722
1723 fBias.SetUpdateInterval(evt.Get<int32_t>()<0 ? 0 : evt.Get<uint32_t>());
1724
1725 return T::GetCurrentState();
1726 }
1727
1728 int Disconnect()
1729 {
1730 // Close all connections
1731 fBias.PostClose(false);
1732
1733 /*
1734 // Now wait until all connection have been closed and
1735 // all pending handlers have been processed
1736 poll();
1737 */
1738
1739 return T::GetCurrentState();
1740 }
1741
1742 int Reconnect(const EventImp &evt)
1743 {
1744 // Close all connections to supress the warning in SetEndpoint
1745 fBias.PostClose(false);
1746
1747 // Now wait until all connection have been closed and
1748 // all pending handlers have been processed
1749 poll();
1750
1751 if (evt.GetBool())
1752 fBias.SetEndpoint(evt.GetString());
1753
1754 // Now we can reopen the connection
1755 fBias.PostClose(true);
1756
1757 return T::GetCurrentState();
1758 }
1759
1760 int SetVerbosity(const EventImp &evt)
1761 {
1762 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
1763 return T::kSM_FatalError;
1764
1765 fBias.SetVerbose(evt.GetBool());
1766
1767 return T::GetCurrentState();
1768 }
1769
1770 int SetExpertMode(const EventImp &evt)
1771 {
1772 if (!CheckEventSize(evt.GetSize(), "SetExpertMode", 1))
1773 return T::kSM_FatalError;
1774
1775 fExpertMode = evt.GetBool();
1776
1777 if (fExpertMode)
1778 T::Warn("Expert commands enabled -- please ensure that you EXACTLY know what you do. These commands can destroy the system.");
1779
1780 return T::GetCurrentState();
1781 }
1782
1783 int Execute()
1784 {
1785 // Dispatch (execute) at most one handler from the queue. In contrary
1786 // to run_one(), it doesn't wait until a handler is available
1787 // which can be dispatched, so poll_one() might return with 0
1788 // handlers dispatched. The handlers are always dispatched/executed
1789 // synchronously, i.e. within the call to poll_one()
1790 poll_one();
1791
1792 return fExpertMode && fBias.GetStatus()>=kConnected ?
1793 kExpertMode : fBias.GetStatus();
1794 }
1795
1796public:
1797 StateMachineBias(ostream &out=cout) :
1798 T(out, "BIAS_CONTROL"), ba::io_service::work(static_cast<ba::io_service&>(*this)),
1799 fBias(*this, *this), fExpertMode(false)
1800 {
1801 // ba::io_service::work is a kind of keep_alive for the loop.
1802 // It prevents the io_service to go to stopped state, which
1803 // would prevent any consecutive calls to run()
1804 // or poll() to do nothing. reset() could also revoke to the
1805 // previous state but this might introduce some overhead of
1806 // deletion and creation of threads and more.
1807
1808 // State names
1809 T::AddStateName(kDisconnected, "Disconnected",
1810 "Bias-power supply not connected via USB.");
1811
1812 T::AddStateName(kConnecting, "Connecting",
1813 "Trying to establish USB connection to bias-power supply.");
1814
1815 T::AddStateName(kInitializing, "Initializing",
1816 "USB connection to bias-power supply established, synchronizing USB stream.");
1817
1818 T::AddStateName(kConnected, "Connected",
1819 "USB connection to bias-power supply established.");
1820
1821 T::AddStateName(kNotReferenced, "NotReferenced",
1822 "Internal reference voltage does not match last sent voltage.");
1823
1824 T::AddStateName(kVoltageOff, "VoltageOff",
1825 "All voltages are supposed to be switched off.");
1826
1827 T::AddStateName(kVoltageOn, "VoltageOn",
1828 "At least one voltage is switched on and all are at reference.");
1829
1830 T::AddStateName(kOverCurrent, "OverCurrent",
1831 "At least one channel is in over current state.");
1832
1833 T::AddStateName(kExpertMode, "ExpertMode",
1834 "Special (risky!) mode to directly send command to the bias-power supply.");
1835
1836 T::AddStateName(kRamping, "Ramping",
1837 "Voltage ramping in progress.");
1838
1839 // Verbosity commands
1840 T::AddEvent("SET_VERBOSE", "B")
1841 (bind(&StateMachineBias::SetVerbosity, this, placeholders::_1))
1842 ("set verbosity state"
1843 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
1844
1845 // Conenction commands
1846 T::AddEvent("DISCONNECT", kConnected, kVoltageOff)
1847 (bind(&StateMachineBias::Disconnect, this))
1848 ("disconnect from USB");
1849
1850 T::AddEvent("RECONNECT", "O", kDisconnected, kConnected, kVoltageOff)
1851 (bind(&StateMachineBias::Reconnect, this, placeholders::_1))
1852 ("(Re)connect USB connection to Bias power supply, a new address can be given"
1853 "|tty[string]:new USB address");
1854
1855
1856 T::AddEvent("SET_UPDATE_INTERVAL", "I:1")
1857 (bind(&StateMachineBias::SetUpdateInterval, this, placeholders::_1))
1858 ("Set the updat einterval how often the currents are requested"
1859 "|interval[ms]:Update interval in milliseconds");
1860
1861
1862
1863 T::AddEvent("REQUEST_STATUS", kConnected, kVoltageOn, kVoltageOff, kNotReferenced, kOverCurrent)
1864 (Wrapper(bind(&ConnectionBias::ReadAllChannels, &fBias, false)))
1865 ("Asynchronously request the status (current) of all channels.");
1866
1867 T::AddEvent("RESET_OVER_CURRENT_STATUS", kOverCurrent)
1868 (Wrapper(bind(&ConnectionBias::OverCurrentReset, &fBias)))
1869 ("Set all channels in over current state to 0V and send a system reset to reset the over current flags.");
1870
1871
1872
1873 T::AddEvent("SET_GLOBAL_VOLTAGE", "F:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1874 (bind(&StateMachineBias::SetGlobalVolt, this, placeholders::_1))
1875 ("Set all channels to a new reference voltage. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
1876 "|voltage[V]:Global target voltage in volts (will be converted to DAC units)");
1877
1878 T::AddEvent("SET_GLOBAL_DAC", "S:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1879 (bind(&StateMachineBias::SetGlobalDac, this, placeholders::_1))
1880 ("Set all channels to a new DAC reference. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
1881 "|voltage[dac]:Global target voltage as DAC counts.");
1882
1883 T::AddEvent("INCREASE_GLOBAL_VOLTAGE", "F:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1884 (bind(&StateMachineBias::IncGlobalVolt, this, placeholders::_1))
1885 ("Set all channels to a new reference voltage. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
1886 "|offset[V]:Offset to be added to all channels (will be converted to DAC counts)");
1887
1888 T::AddEvent("INCREASE_GLOBAL_DAC", "S:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1889 (bind(&StateMachineBias::IncGlobalDac, this, placeholders::_1))
1890 ("Set all channels to a new DAC reference. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
1891 "|offset[dac]:Offset to be added to all channels as DAC counts");
1892
1893 T::AddEvent("DECREASE_GLOBAL_VOLTAGE", "F:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1894 (bind(&StateMachineBias::DecGlobalVolt, this, placeholders::_1))
1895 ("Set all channels to a new reference voltage. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
1896 "|offset[V]:Offset to be subtracted from all channels (will be converted to DAC counts)");
1897
1898 T::AddEvent("DECREASE_GLOBAL_DAC", "S:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1899 (bind(&StateMachineBias::DecGlobalDac, this, placeholders::_1))
1900 ("Set all channels to a new DAC reference. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
1901 "|offset[dac]:Offset to be subtracted from all channels as DAC counts");
1902
1903 T::AddEvent("SET_CHANNEL_VOLTAGE", "S:1;F:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1904 (bind(&StateMachineBias::SetChannelVolt, this, placeholders::_1))
1905 ("Set a single channel to a new reference voltage. Starts ramping if necessary."
1906 "|channel[short]:Channel for which to set the target voltage [0-416]"
1907 "|voltage[V]:Target voltage in volts for the given channel (will be converted to DAC units)");
1908
1909 T::AddEvent("SET_CHANNEL_DAC", "S:1;S:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1910 (bind(&StateMachineBias::SetChannelDac, this, placeholders::_1))
1911 ("Set a single channel to a new DAC reference value. Starts ramping if necessary."
1912 "|channel[short]:Channel for which to set the target voltage [0-416]"
1913 "|voltage[dac]:Target voltage in DAC units for the given channel");
1914
1915 T::AddEvent("SET_GLOBAL_GAPD_REFERENCE_VOLTAGE", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1916 (Wrapper(bind(&ConnectionBias::SetGapdVoltage, &fBias, 0.)))
1917 ("Set all channels to their G-APD reference voltage. Starts ramping if necessary.");
1918
1919 T::AddEvent("SET_CHANNEL_GAPD_REFERENCE_VOLTAGE", "S:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1920 (bind(&StateMachineBias::SetGapdReferenceCh, this, placeholders::_1))
1921 ("Set a single channel channels to its G-APD reference voltage. Starts ramping if necessary."
1922 "|channel[short]:Channel for which to set the target voltage [0-416]");
1923
1924 T::AddEvent("SET_GAPD_REFERENCE_OFFSET", "F:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1925 (bind(&StateMachineBias::SetGapdVoltage, this, placeholders::_1))
1926 ("Set all channels to their G-APD reference voltage plus the given offset. Starts ramping if necessary."
1927 "|offset[V]:Offset to be added to teh G-APD reference voltage globally");
1928
1929 T::AddEvent("SET_ZERO_VOLTAGE", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1930 (Wrapper(bind(&ConnectionBias::SetZero, &fBias)))
1931 ("Set all channels to a zero reference voltage. Starts ramping if necessary.");
1932
1933 T::AddEvent("SET_REFERENCE_VOLTAGES", "F:416", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1934 (bind(&StateMachineBias::SetReferenceVolt, this, placeholders::_1))
1935 ("Set all channels to the given new reference voltage. Starts ramping if necessary."
1936 "voltage[V]:New reference voltage for all channels");
1937
1938 T::AddEvent("SET_REFERENCE_DACS", "S:416", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1939 (bind(&StateMachineBias::SetReferenceDac, this, placeholders::_1))
1940 ("Set all channels to the given new reference voltage. Starts ramping if necessary."
1941 "voltage[dac]:New reference voltage for all channels in DAC units");
1942
1943 T::AddEvent("ADD_REFERENCE_VOLTAGES", "F:416", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1944 (bind(&StateMachineBias::AddReferenceVolt, this, placeholders::_1))
1945 ("Add the given voltages to the current reference voltages. Starts ramping if necessary."
1946 "offset[V]:Offsets to be added to the reference voltage of all channels in volts");
1947
1948 T::AddEvent("ADD_REFERENCE_DACS", "S:416", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1949 (bind(&StateMachineBias::AddReferenceDac, this, placeholders::_1))
1950 ("Add the given voltages to the current reference voltages. Starts ramping if necessary."
1951 "offset[dac]:Offsets to be added to the reference voltage of all channels in DAC units");
1952
1953
1954
1955
1956 T::AddEvent("STOP", kConnected, kRamping)
1957 (Wrapper(bind(&ConnectionBias::RampStop, &fBias)))
1958 ("Stop an on-going ramping");
1959
1960 T::AddEvent("START", kConnected, kNotReferenced)
1961 (Wrapper(bind(&ConnectionBias::RampStart, &fBias)))
1962 ("Start a ramping if no ramping is in progress and if reference values differ from current voltages");
1963
1964
1965
1966 T::AddEvent("PRINT_INFO")
1967 (Wrapper(bind(&ConnectionBias::PrintInfo, &fBias)))
1968 ("Print a table with all current read back with the last request operation");
1969 T::AddEvent("PRINT_CURRENTS")
1970 (Wrapper(bind(&ConnectionBias::PrintA, &fBias)))
1971 ("Print a table with all current read back with the last request operation");
1972 T::AddEvent("PRINT_VOLTAGES")
1973 (Wrapper(bind(&ConnectionBias::PrintV, &fBias)))
1974 ("Print a table with all voltages (current and reference voltages as currently in memory)");
1975 T::AddEvent("PRINT_GAPD_REFERENCE_VOLTAGES")
1976 (Wrapper(bind(&ConnectionBias::PrintGapd, &fBias)))
1977 ("Print the G-APD reference values obtained from file");
1978
1979
1980 T::AddEvent("EXPERT_MODE", "B:1")
1981 (bind(&StateMachineBias::SetExpertMode, this, placeholders::_1))
1982 ("Enable usage of expert commands (note that for safty reasons the are exclusive with the standard commands)");
1983
1984 T::AddEvent("EXPERT_RESET", kExpertMode)
1985 (Wrapper(bind(&ConnectionBias::ExpertReset, &fBias, true)))
1986 ("Send the RESET command (note that this is possibly harmfull command)");
1987
1988 T::AddEvent("EXPERT_SET_GLOBAL_VOLTAGE", "F:1", kExpertMode)
1989 (bind(&StateMachineBias::ExpertSetGlobalVolt, this, placeholders::_1))
1990 ("Send the global set command. The given voltage is converted to DAC counts.");
1991
1992 T::AddEvent("EXPERT_SET_GLOBAL_DAC", "S:1", kExpertMode)
1993 (bind(&StateMachineBias::ExpertSetGlobalDac, this, placeholders::_1))
1994 ("Send the global set command.");
1995
1996 T::AddEvent("EXPERT_SET_CHANNEL_VOLTAGE", "S:1;F:1", kExpertMode)
1997 (bind(&StateMachineBias::ExpertSetChannelVolt, this, placeholders::_1))
1998 ("Send a single channel set command. The given voltage is converted to DAC commands.");
1999
2000 T::AddEvent("EXPERT_SET_CHANNEL_DAC", "S:1;S:1", kExpertMode)
2001 (bind(&StateMachineBias::ExpertSetChannelDac, this, placeholders::_1))
2002 ("Send a single channel set command.");
2003 }
2004
2005 ~StateMachineBias() { T::Warn("TODO: Implement rampming at shutdown!"); }
2006
2007 int EvalOptions(Configuration &conf)
2008 {
2009 // FIXME: Read calib_offset
2010 // FIXME: Check calib offset being smaller than +/-0.25V
2011
2012 fBias.SetVerbose(!conf.Get<bool>("quiet"));
2013
2014 if (conf.Has("dev"))
2015 {
2016 fBias.SetEndpoint(conf.Get<string>("dev"));
2017 T::Message("Setting device to "+fBias.URL());
2018 }
2019
2020 const uint16_t step = conf.Get<uint16_t>("ramp-step");
2021 const uint16_t time = conf.Get<uint16_t>("ramp-delay");
2022
2023 if (step>230) // 5V
2024 {
2025 T::Error("ramp-step exceeds allowed range.");
2026 return 1;
2027 }
2028
2029 fBias.SetRampStep(step);
2030 fBias.SetRampTime(time);
2031 fBias.SetUpdateInterval(conf.Get<uint32_t>("update-interval"));
2032 fBias.SetSyncDelay(conf.Get<uint16_t>("sync-delay"));
2033
2034 ostringstream str1, str2;
2035 str1 << "Ramping in effective steps of " << fBias.GetRampStepVolt() << "V";
2036 str2 << "Ramping with a delay per step of " << time << "ms";
2037 T::Message(str1);
2038 T::Message(str2);
2039
2040 // --------------------------------------------------------------------------
2041
2042 const float maxabsv = conf.Get<float>("volt-max-abs");
2043 const float maxrelv = conf.Get<float>("volt-max-rel");
2044 if (maxabsv>90)
2045 {
2046 T::Error("volt-max exceeds 90V.");
2047 return 2;
2048 }
2049 if (maxabsv>75)
2050 T::Warn("volt-max exceeds 75V.");
2051 if (maxabsv<70)
2052 T::Warn("volt-max below 70V.");
2053 if (maxabsv<0)
2054 {
2055 T::Error("volt-max negative.");
2056 return 3;
2057 }
2058
2059 fBias.SetVoltMaxAbs(maxabsv);
2060 fBias.SetVoltMaxRel(maxrelv);
2061
2062 ostringstream str3, str4;
2063 str3 << "Effective maximum allowed absolute voltage: " << fBias.GetVoltMaxAbs() << "V";
2064 str4 << "Effective maximum difference w.r.t to G-APD reference: " << fBias.GetVoltMaxRel() << "V";
2065 T::Message(str3);
2066 T::Message(str4);
2067
2068 // --------------------------------------------------------------------------
2069
2070 BiasMap map;
2071
2072 if (!conf.Has("bias-map-file") && !conf.Has("bias-database"))
2073 {
2074 T::Error("Neither bias-map-file not bias-dtabase specified.");
2075 return 5;
2076 }
2077
2078 try
2079 {
2080 if (conf.Has("bias-map-file"))
2081 map.Read(conf.Get<string>("bias-map-file"));
2082
2083 //if (conf.Has("bias-database"))
2084 // map.Retrieve(conf.Get<string>("bias-database"));
2085 }
2086 catch (const runtime_error &e)
2087 {
2088 T::Error("Getting reference voltages failed: "+string(e.what()));
2089 return 7;
2090 }
2091
2092 if (!fBias.SetNewGapdVoltage(map.Vgapd()))
2093 {
2094 T::Error("Setting reference voltages failed.");
2095 return 8;
2096 }
2097
2098 // --------------------------------------------------------------------------
2099
2100 if (conf.Has("dev"))
2101 fBias.Connect();
2102
2103 return -1;
2104 }
2105};
2106
2107// ------------------------------------------------------------------------
2108
2109#include "Main.h"
2110
2111template<class T, class S, class R>
2112int RunShell(Configuration &conf)
2113{
2114 return Main::execute<T, StateMachineBias<S, R>>(conf);
2115}
2116
2117void SetupConfiguration(Configuration &conf)
2118{
2119 po::options_description control("BIAS control options");
2120 control.add_options()
2121 ("no-dim,d", po_bool(), "Disable dim services")
2122 ("dev", var<string>(), "Device address of USB port to bias-power supply")
2123 ("quiet,q", po_bool(), "Disable printing contents of all received messages (except dynamic data) in clear text.")
2124 ("ramp-delay", var<uint16_t>(15), "Delay between the answer of one ramping step and sending the next ramp command to all channels in milliseconds.")
2125 ("ramp-step", var<uint16_t>(46), "Maximum step in DAC counts during ramping (Volt = DAC*90/4096)")
2126 ("update-interval", var<uint32_t>(3000), "Interval between two current requests in milliseconds")
2127 ("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")
2128 ("volt-max-abs", var<float>(75), "Absolte upper limit for the voltage (in Volts)")
2129 ("volt-max-rel", var<float>(2.5), "Relative upper limit for the voltage w.r.t. the G-APD reference voltage (in Volts)")
2130 ("bias-map-file", var<string>("GAPDmap.txt"), "File with nominal and offset voltages for each channel.")
2131 ("bias-database", var<string>(""), "")
2132 ;
2133
2134 conf.AddOptions(control);
2135}
2136
2137/*
2138 Extract usage clause(s) [if any] for SYNOPSIS.
2139 Translators: "Usage" and "or" here are patterns (regular expressions) which
2140 are used to match the usage synopsis in program output. An example from cp
2141 (GNU coreutils) which contains both strings:
2142 Usage: cp [OPTION]... [-T] SOURCE DEST
2143 or: cp [OPTION]... SOURCE... DIRECTORY
2144 or: cp [OPTION]... -t DIRECTORY SOURCE...
2145 */
2146void PrintUsage()
2147{
2148 cout <<
2149 "The biasctrl program controls the bias-power supply boards.\n"
2150 "\n"
2151 "Note: At default the program is started without a command line (user) "
2152 "interface. In this case Actions/Commands are available via Dim "
2153 "exclusively.\n"
2154 "Use the -c option to start the program with a command line interface.\n"
2155 "\n"
2156 "In the running application:\n"
2157 "Use h or help to print a short help message about its usage.\n"
2158 "\n"
2159 "Usage: biasctrl [-c type] [OPTIONS]\n"
2160 " or: biasctrl [OPTIONS]\n";
2161 cout << endl;
2162}
2163
2164void PrintHelp()
2165{
2166 Main::PrintHelp<StateMachineBias<StateMachine,ConnectionBias>>();
2167
2168 /* Additional help text which is printed after the configuration
2169 options goes here */
2170
2171 /*
2172 cout << "bla bla bla" << endl << endl;
2173 cout << endl;
2174 cout << "Environment:" << endl;
2175 cout << "environment" << endl;
2176 cout << endl;
2177 cout << "Examples:" << endl;
2178 cout << "test exam" << endl;
2179 cout << endl;
2180 cout << "Files:" << endl;
2181 cout << "files" << endl;
2182 cout << endl;
2183 */
2184}
2185
2186int main(int argc, const char* argv[])
2187{
2188 Configuration conf(argv[0]);
2189 conf.SetPrintUsage(PrintUsage);
2190 Main::SetupConfiguration(conf);
2191 SetupConfiguration(conf);
2192
2193 if (!conf.DoParse(argc, argv, PrintHelp))
2194 return -1;
2195
2196 //try
2197 {
2198 // No console access at all
2199 if (!conf.Has("console"))
2200 {
2201 if (conf.Get<bool>("no-dim"))
2202 return RunShell<LocalStream, StateMachine, ConnectionBias>(conf);
2203 else
2204 return RunShell<LocalStream, StateMachineDim, ConnectionDimBias>(conf);
2205 }
2206 // Cosole access w/ and w/o Dim
2207 if (conf.Get<bool>("no-dim"))
2208 {
2209 if (conf.Get<int>("console")==0)
2210 return RunShell<LocalShell, StateMachine, ConnectionBias>(conf);
2211 else
2212 return RunShell<LocalConsole, StateMachine, ConnectionBias>(conf);
2213 }
2214 else
2215 {
2216 if (conf.Get<int>("console")==0)
2217 return RunShell<LocalShell, StateMachineDim, ConnectionDimBias>(conf);
2218 else
2219 return RunShell<LocalConsole, StateMachineDim, ConnectionDimBias>(conf);
2220 }
2221 }
2222 /*catch (std::exception& e)
2223 {
2224 cerr << "Exception: " << e.what() << endl;
2225 return -1;
2226 }*/
2227
2228 return 0;
2229}
Note: See TracBrowser for help on using the repository browser.