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

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