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

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