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

Last change on this file since 18117 was 18116, checked in by tbretz, 10 years ago
What is called 'breakdown voltage' here is actually the 'operation voltage' as we got it from hamamatsu. To avoid confusion, it has been renamed. Unfortunately old BIAS_CONTROL/NOMINAL files will obviously still call it wrongly Ubr
File size: 71.0 KB
Line 
1#include <functional>
2
3#include <boost/bind.hpp>
4
5#include "Dim.h"
6#include "Event.h"
7#include "Shell.h"
8#include "StateMachineDim.h"
9#include "StateMachineAsio.h"
10#include "ConnectionUSB.h"
11#include "Configuration.h"
12#include "Console.h"
13#include "externals/PixelMap.h"
14
15#include "tools.h"
16
17#include "LocalControl.h"
18#include "HeadersBIAS.h"
19
20namespace ba = boost::asio;
21namespace bs = boost::system;
22namespace dummy = ba::placeholders;
23
24using namespace std::placeholders;
25using namespace std;
26
27// We can do that because we do not include other headers than HeadersBIAS
28using namespace BIAS;
29
30// ------------------------------------------------------------------------
31
32class ConnectionBias : public ConnectionUSB
33{
34 boost::asio::deadline_timer fSyncTimer;
35 boost::asio::deadline_timer fRampTimer;
36 boost::asio::deadline_timer fUpdateTimer;
37
38 vector<uint8_t> fBuffer;
39 vector<uint8_t> fBufferRamp;
40 vector<uint8_t> fBufferUpdate;
41
42 bool fIsVerbose;
43 bool fIsDummyMode;
44
45 vector<bool> fPresent;
46
47 int64_t fWrapCounter;
48 int64_t fSendCounter;
49
50 int16_t fGlobalDacCmd; // Command value to be reached
51
52 int16_t fRampStep;
53 int16_t fRampTime;
54
55 uint32_t fUpdateTime;
56 uint16_t fSyncTime;
57 uint32_t fReconnectDelay;
58
59 int fIsInitializing;
60 bool fIsRamping;
61 int fWaitingForAnswer;
62
63 vector<uint64_t> fCounter;
64
65 Time fLastConnect;
66
67protected:
68
69 vector<int16_t> fCurrent; // Current in ADC units (12bit = 5mA)
70
71 virtual void 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> fOperationVoltage; // Operation 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 fOperationVoltage(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 (fOperationVoltage[ch]<=0)
891 return true;
892
893 if (volt>fOperationVoltage[ch]+fVoltageMaxRel) // FIXME: fVoltageMaxRel!!!
894 {
895 ostringstream msg;
896 msg << "CheckChannelVoltage - Set voltage " << volt << "V of channel " << ch << " exceeds limit of " << fVoltageMaxRel << "V above operation voltage " << fOperationVoltage[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 fOperationVoltage = 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) << fOperationVoltage[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(), fOperationVoltage.begin(), fOperationVoltage.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 "|Uop[V]:Nominal operation 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.