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

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