source: branches/FACT++_lidctrl_usb/src/biasctrl.cc@ 19582

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