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

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