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

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