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

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