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

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