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

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