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

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