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

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