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

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