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

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