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

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