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

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