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

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