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

Last change on this file since 11944 was 11943, checked in by tbretz, 14 years ago
Added explanatory strings for command line options and events.
File size: 49.7 KB
Line 
1#include <functional>
2
3#include <boost/bind.hpp>
4
5#include "Dim.h"
6#include "Event.h"
7#include "Shell.h"
8#include "StateMachineDim.h"
9#include "ConnectionUSB.h"
10#include "Configuration.h"
11#include "Console.h"
12#include "Converter.h"
13
14#include "tools.h"
15
16#include "LocalControl.h"
17#include "HeadersBIAS.h"
18
19namespace ba = boost::asio;
20namespace bs = boost::system;
21namespace dummy = ba::placeholders;
22
23using namespace std::placeholders;
24using namespace std;
25using namespace BIAS;
26
27// ------------------------------------------------------------------------
28
29class ConnectionBias : public ConnectionUSB
30{
31 boost::asio::deadline_timer fSyncTimer;
32 boost::asio::deadline_timer fRampTimer;
33 boost::asio::deadline_timer fUpdateTimer;
34
35 vector<uint8_t> fBuffer;
36 vector<uint8_t> fBufferRamp;
37 vector<uint8_t> fBufferUpdate;
38
39 bool fIsVerbose;
40
41 vector<uint16_t> fVoltCmd; // Current command voltage in DAC units (12bit = 90V)
42 vector<uint16_t> fVoltGapd;
43
44 vector<bool> fPresent;
45
46 int64_t fWrapCounter;
47 int64_t fSendCounter;
48
49 int16_t fGlobalVoltCmd; // Command value to be reached
50// uint16_t fExpertVoltRef; // Command value to be reached
51
52 int16_t fRampStep;
53 int16_t fRampTime;
54
55 uint16_t fUpdateTime;
56 uint16_t fSyncTime;
57
58 bool fIsInitializing;
59 bool fIsRamping;
60 bool fWaitingForAnswer;
61
62protected:
63 vector<uint16_t> fVolt; // Current voltage in DAC units (12bit = 90V)
64 vector<uint16_t> fVoltRef; // Current reference voltage in DAC units (12bit = 90V)
65
66 vector<int16_t> fCurrent; // Current in ADC units (12bit = 5mA)
67
68 uint16_t fVoltMax;
69
70 virtual void UpdateA()
71 {
72 }
73
74 virtual void UpdateV()
75 {
76 }
77
78private:
79 bool CheckChDac(const string &cmd, uint16_t dac, uint16_t ch=0)
80 {
81 if (dac>kMaxDac)
82 {
83 Error(cmd+" - DAC value out of range.");
84 return false;
85 }
86 if (dac>fVoltMax)
87 {
88 Error(cmd+" - DAC value exceeds fVoltMax.");
89 return false;
90 }
91
92 if (ch>=kNumChannels)
93 {
94 Error(cmd+" - Channel out of range.");
95 return false;
96 }
97
98 return true;
99 }
100
101 vector<char> GetCmd(uint16_t board, uint16_t channel, Command_t cmd, uint16_t dac=0)
102 {
103 vector<char> data(3);
104
105 /*
106 if (board>kNumBoards)
107 return;
108 if (channel>kNumChannelsPerBoard)
109 return;
110 if (dac>0xfff)
111 return;
112 */
113
114 data[0] = (cmd<<5) | (board<<1) | (((channel&16)>>4) & 1);
115 data[1] = (channel<<4) | (dac>>8);
116 data[2] = dac&0xff;
117
118 return data;
119 }
120
121 vector<char> GetCmd(Command_t cmd, uint16_t id=0, uint16_t dac=0)
122 {
123 const unsigned int board = id/kNumChannelsPerBoard;
124 const unsigned int channel = id%kNumChannelsPerBoard;
125
126 return GetCmd(board, channel, cmd, dac);
127 }
128
129 bool CheckMessageLength(int received, int expected, const string &msg)
130 {
131 if (received==expected)
132 return true;
133
134 ostringstream str;
135 str << msg << ": Expected " << expected << " bytes in answer, but got " << received << endl;
136 Error(str);
137
138 PostClose(false);
139 return false;
140 }
141
142 bool EvalAnswer(const uint8_t *answer, uint16_t id, int command)
143 {
144 answer += id*3;
145
146 const uint16_t status = (answer[0]>>7)&1;
147 const uint16_t wrap = (answer[0]>>4)&7;
148 const uint16_t ddd = ((uint16_t(answer[0])&0xf)<<8) | answer[1];
149 const uint16_t error = (answer[2]>>4)&0xf;
150 const uint16_t board = answer[2]&0xf;
151
152 /*
153 Out() << dec << setw(2) << board << '|' << wrap << " ";
154 if (id%8==7)
155 Out() << endl;
156 */
157
158 if (fWrapCounter>=0)
159 {
160 if ((fWrapCounter+1)%8 != wrap)
161 {
162 ostringstream msg;
163 msg << "Corrupted answer (id=" << id << "): received wrap counter " << wrap << " doesn't match last received counter " << fWrapCounter << ".";
164 Error(msg);
165 return false;
166 }
167 }
168
169 fWrapCounter = wrap;
170
171 if (command==kSynchronize)
172 {
173 ostringstream msg;
174 msg << hex << setfill('0');
175 msg << "Initial answer received: 0x";
176 msg << setw(2) << (int)answer[2];
177 msg << setw(2) << (int)answer[1];
178 msg << setw(2) << (int)answer[0];
179 Message(msg);
180
181 if (status!=0 || ddd!=0 || error!=0 || board!=0)
182 {
183 Warn("Initial answer doesn't seem to be a reset as naively expected.");
184
185 //ostringstream msg;
186 //msg << hex << setfill('0');
187 //msg << "S=" << status << " D=" << ddd << " E=" << error << " B=" << board;
188 //Message(msg);
189 }
190
191 fSendCounter = wrap;
192
193 msg.str("");
194 msg << "Setting fSendCounter to " << wrap;
195 Info(msg);
196
197 return true;
198 }
199
200 if (error==0x8) // No device
201 {
202 Message("Reset button on crate pressed!");
203 SetZero();
204 return true;
205 }
206
207 if (command==kCmdReset)
208 {
209 if (status==0 && ddd==0 && error==0 && board==0)
210 {
211 Message("Reset successfully executed.");
212 return true;
213 }
214
215 Warn("Answer to 'reset' command contains unexpected data.");
216 return false;
217 }
218
219 if (command==kCmdGlobalSet)
220 {
221 if (status==0 && ddd==0 && error==0 && board==0)
222 {
223 for (int i=0; i<kNumChannels; i++)
224 fVolt[i] = fGlobalVoltCmd;
225
226 fGlobalVoltCmd = -1;
227
228 return true;
229 }
230
231 Warn("Answer to 'global set' command contains unexpected data.");
232 return false;
233 }
234
235 if ((command&0xff)==kExpertChannelSet)
236 id = command>>8;
237
238 const int cmd = command&3;
239
240 if (cmd==kCmdRead || cmd==kCmdChannelSet)
241 {
242 if (board!=id/kNumChannelsPerBoard)
243 {
244 ostringstream out;
245 out << "Talked to board " << id/kNumChannelsPerBoard << ", but got answer from board " << board << ".";
246 Error(out);
247 return false;
248 }
249
250 // Not present
251 if (error==0x7 || error==0xf)
252 {
253 fPresent[board] = false;
254 fCurrent[id] = 0x8000;
255 return true;
256 }
257
258 fCurrent[id] = status ? -ddd : ddd;
259 fPresent[board] = true;
260 }
261
262 if (cmd==kCmdChannelSet)
263 fVolt[id] = fVoltCmd[id];
264
265 return true;
266
267 }
268
269private:
270 void HandleReceivedData(const vector<uint8_t> &buf, size_t bytes_received, int command, int send_counter)
271 {
272 // Now print the received message if requested by the user
273 if (fIsVerbose/* && command!=kUpdate*/)
274 {
275 Out() << endl << kBold << dec << "Data received (size=" << bytes_received << "):" << endl;
276 Out() << " Command=" << command << " fWrapCounter=" << fWrapCounter << " fSendCounter=" << fSendCounter << " fIsInitializing=" << fIsInitializing << " fIsRamping=" << fIsRamping;
277 Out() << hex << setfill('0');
278
279 for (size_t i=0; i<bytes_received/3; i++)
280 {
281 if (i%8==0)
282 Out() << '\n' << setw(2) << bytes_received/24 << "| ";
283
284 Out() << setw(2) << uint16_t(buf[i*3+2]);
285 Out() << setw(2) << uint16_t(buf[i*3+1]);
286 Out() << setw(2) << uint16_t(buf[i*3+0]) << " ";
287 }
288 Out() << endl;
289 }
290
291 const int cmd = command&0xf;
292
293 // Check the number of received_byted according to the answer expected
294 if ((cmd==kSynchronize && !CheckMessageLength(bytes_received, 3, "Synchronization")) ||
295 (cmd==kCmdReset && !CheckMessageLength(bytes_received, 3, "CmdReset")) ||
296 (cmd==kCmdRead && !CheckMessageLength(bytes_received, 3*kNumChannels, "CmdRead")) ||
297 (cmd==kCmdChannelSet && !CheckMessageLength(bytes_received, 3*kNumChannels, "CmdChannelSet")) ||
298 (cmd==kExpertChannelSet && !CheckMessageLength(bytes_received, 3, "CmdExpertChannelSet")))
299 return;
300
301 // Now evaluate the whole bunch of messages
302 for (size_t i=0; i<bytes_received/3; i++)
303 {
304 if (!EvalAnswer(buf.data(), i, command))
305 {
306 PostClose(false);
307 return;
308 }
309 }
310
311 if (command==kSynchronize)
312 {
313 Message("Stream successfully synchronized.");
314 fIsInitializing = false;
315
316 // Cancel sending of the next 0
317 fSyncTimer.cancel();
318
319 // Start continous reading of all channels
320 ScheduleUpdate(100);
321 return;
322 }
323
324 if (send_counter%8 != fWrapCounter)
325 {
326 ostringstream msg;
327 msg << "Corrupted answer: received wrap counter " << fWrapCounter << " is not send counter " << send_counter << "%8.";
328 Error(msg);
329 PostClose(false);
330 }
331
332
333 // Take action depending on what is going on
334 if (command==kCmdReset)
335 Message("Reset command successfully answered.");
336
337 if (cmd==kCmdRead || cmd==kCmdChannelSet || cmd==kExpertChannelSet)
338 {
339 UpdateV();
340 UpdateA();
341 }
342
343 if (cmd==kCmdReset || command==kResetChannels)
344 {
345 // Re-start cyclic reading of values after a short time
346 // to allow the currents to become stable
347 fUpdateTimer.cancel();
348 ScheduleUpdate(100);
349 }
350
351 if (command==kUpdate)
352 ScheduleUpdate(fUpdateTime);
353
354 // If we are ramping, schedule a new ramp step
355 if (command==kCmdChannelSet && fIsRamping)
356 {
357 ScheduleRampStep();
358 return;
359 }
360 }
361
362 void HandleReceivedData(const bs::error_code& err, size_t bytes_received, int command, int send_counter)
363 {
364 // Do not schedule a new read if the connection failed.
365 if (bytes_received==0 || err)
366 {
367 if (err==ba::error::eof)
368 Warn("Connection closed by remote host (BIAS).");
369
370 // 107: Transport endpoint is not connected (bs::error_code(107, bs::system_category))
371 // 125: Operation canceled
372 if (err && err!=ba::error::eof && // Connection closed by remote host
373 err!=ba::error::basic_errors::not_connected && // Connection closed by remote host
374 err!=ba::error::basic_errors::operation_aborted) // Connection closed by us
375 {
376 ostringstream str;
377 str << "Reading from " << URL() << ": " << err.message() << " (" << err << ")";// << endl;
378 Error(str);
379 }
380 PostClose(false);//err!=ba::error::basic_errors::operation_aborted);
381 return;
382 }
383
384 // Check if the number of received bytes is correctly dividable by 3
385 // This check should never fail - just for sanity
386 if (bytes_received%3)
387 {
388 Error("Number of received bytes not a multiple of 3, can't read data.");
389 PostClose(false);
390 return;
391 }
392
393 // We have three different parallel streams:
394 // 1) The setting of voltages due to ramping
395 // 2) The cynclic request of the currents
396 // 3) Answers to commands
397 // For each of these three streams an own buffer is needed, otherwise
398 // a buffer which is filled in the background might overwrite
399 // a buffer which is currently evaluated. In all other programs
400 // this is no problem because the boards don't answer and if
401 // they do the answer identifies itself. Consequently,
402 // there is always only one async_read in progress. Here we have
403 // three streams which need to be connected somehow to the
404 // commands.
405
406 // Maybe a better possibility would be to setup a command
407 // queue (each command will be queued in a buffer)
408 // and whenever an answer has been received, a new async_read is
409 // scheduled.
410 // Build a command queue<pair<command, vector<char>>>
411 /// This replaces the send counter and the command argument
412 // in handleReceivedData
413
414 switch (command&0xff)
415 {
416 case kSynchronize:
417 case kCmdReset:
418 case kExpertChannelSet:
419 case kCmdGlobalSet:
420 case kResetChannels:
421 case kCmdRead:
422 HandleReceivedData(fBuffer, bytes_received, command, send_counter);
423 fWaitingForAnswer = false;
424 return;
425
426 case kCmdChannelSet:
427 HandleReceivedData(fBufferRamp, bytes_received, command, send_counter);
428 return;
429
430 case kUpdate:
431 HandleReceivedData(fBufferUpdate, bytes_received, command, send_counter);
432 return;
433 }
434 }
435
436 // --------------------------------------------------------------------
437
438 void HandleSyncTimer(int counter, const bs::error_code &error)
439 {
440 if (error==ba::error::basic_errors::operation_aborted)
441 {
442 if (fIsInitializing)
443 Warn("Synchronization aborted...");
444 else
445 Info("Synchronization successfull.");
446 return;
447 }
448
449 if (error)
450 {
451 ostringstream str;
452 str << "Synchronization timer: " << error.message() << " (" << error << ")";// << endl;
453 Error(str);
454
455 PostClose(false);
456 return;
457 }
458
459 if (!is_open())
460 {
461 Warn("Synchronization in progress, but disconnected.");
462 return;
463 }
464
465 ostringstream msg;
466 msg << "Synchronization time expired (" << counter << ")";
467 Info(msg);
468
469 if (fIsInitializing)
470 {
471 PostMessage("\0", 1);
472
473 if (counter==2)
474 {
475 Error("Synchronization attempt timed out.");
476 PostClose(false);
477 return;
478 }
479
480 ScheduleSync(counter+1);
481 return;
482 }
483
484 Info("Synchronisation successfull.");
485 }
486
487 void ScheduleSync(int counter=0)
488 {
489 fSyncTimer.expires_from_now(boost::posix_time::milliseconds(fSyncTime));
490 fSyncTimer.async_wait(boost::bind(&ConnectionBias::HandleSyncTimer, this, counter, dummy::error));
491 }
492
493 // This is called when a connection was established
494 void ConnectionEstablished()
495 {
496 // Reset everything....
497 fSendCounter = -1;
498 fWrapCounter = -1;
499 fGlobalVoltCmd = -1;
500 fIsInitializing = true;
501
502 fVolt.assign( kNumChannels, 0);
503 fVoltRef.assign(kNumChannels, 0);
504 fVoltCmd.assign(kNumChannels, 0);
505
506 // Send a single 0 (and possible two consecutive 0's
507 // to make sure we are in sync with the device)
508 PostMessage("\0", 1);
509 AsyncRead(ba::buffer(fBuffer, 3), kSynchronize, 0);//++fSendCounter);
510 fWaitingForAnswer = true;
511
512 // Wait for some time before sending the next 0
513 ScheduleSync();
514 }
515
516 // --------------------------------------------------------------------
517
518 void HandleUpdateTimer(const bs::error_code &error)
519 {
520 if (error==ba::error::basic_errors::operation_aborted)
521 {
522 Warn("Update timer aborted...");
523 fIsRamping = false;
524 return;
525 }
526
527 if (error)
528 {
529 ostringstream str;
530 str << "Update timer: " << error.message() << " (" << error << ")";// << endl;
531 Error(str);
532
533 PostClose(false);
534 return;
535 }
536
537 if (!is_open())
538 return;
539
540 if (fIsRamping)
541 ScheduleUpdate(fUpdateTime);
542 else
543 ReadAllChannels(true);
544 }
545
546 void ScheduleUpdate(int millisec)
547 {
548 fUpdateTimer.expires_from_now(boost::posix_time::milliseconds(millisec));
549 fUpdateTimer.async_wait(boost::bind(&ConnectionBias::HandleUpdateTimer, this, dummy::error));
550 }
551
552 // --------------------------------------------------------------------
553
554 void SetAllChannels(const vector<uint16_t> &dac, bool special=false)
555 {
556 vector<char> data;
557 data.reserve(kNumChannels*3);
558
559 for (int ch=0; ch<kNumChannels; ch++)
560 {
561 const vector<char> cmd = GetCmd(kCmdChannelSet, ch, dac[ch]);
562 data.insert(data.end(), cmd.begin(), cmd.end());
563
564 fVoltCmd[ch] = dac[ch];
565 }
566
567 fSendCounter += kNumChannels;
568
569 PostMessage(data);
570 AsyncRead(ba::buffer(special ? fBuffer : fBufferRamp, kNumChannels*3),
571 special ? kResetChannels : kCmdChannelSet, fSendCounter);
572
573 if (special)
574 fWaitingForAnswer = true;
575 }
576
577 uint16_t RampOneStep(uint16_t ch)
578 {
579 if (fVoltRef[ch]>fVolt[ch])
580 return fVolt[ch]+fRampStep>fVoltRef[ch] ? fVoltRef[ch] : fVolt[ch]+fRampStep;
581
582 if (fVoltRef[ch]<fVolt[ch])
583 return fVolt[ch]-fRampStep<fVoltRef[ch] ? fVoltRef[ch] : fVolt[ch]-fRampStep;
584
585 return fVolt[ch];
586 }
587
588 bool RampOneStep()
589 {
590 if (fRampTime<0)
591 {
592 Warn("Ramping step time not yet set... ramping not started.");
593 return false;
594 }
595 if (fRampStep<0)
596 {
597 Warn("Ramping step not yet set... ramping not started.");
598 return false;
599 }
600
601 vector<uint16_t> dac(kNumChannels);
602
603 bool identical = true;
604 for (int ch=0; ch<kNumChannels; ch++)
605 {
606 dac[ch] = RampOneStep(ch);
607 if (dac[ch]!=fVolt[ch] && fPresent[ch/kNumChannelsPerBoard])
608 identical = false;
609 }
610
611 SetAllChannels(dac);
612
613 if (identical)
614 Info("Ramping: target values reached.");
615
616 return !identical;
617 }
618
619 void HandleRampTimer(const bs::error_code &error)
620 {
621 if (error==ba::error::basic_errors::operation_aborted)
622 {
623 Warn("Ramping aborted...");
624 fIsRamping = false;
625 return;
626 }
627
628 if (error)
629 {
630 ostringstream str;
631 str << "Ramping timer: " << error.message() << " (" << error << ")";// << endl;
632 Error(str);
633
634 PostClose(false);
635 return;
636 }
637
638 if (!is_open())
639 {
640 Warn("Ramping in progress, but disconnected.");
641 return;
642 }
643
644 if (!fIsRamping)
645 {
646 Error("Ramp handler called although no ramping in progress.");
647 return;
648 }
649
650 // Check whether the deadline has passed. We compare the deadline
651 // against the current time since a new asynchronous operation
652 // may have moved the deadline before this actor had a chance
653 // to run.
654 if (fRampTimer.expires_at() > ba::deadline_timer::traits_type::now())
655 return;
656
657 fIsRamping = RampOneStep();
658 }
659
660 void ScheduleRampStep()
661 {
662 fRampTimer.expires_from_now(boost::posix_time::milliseconds(fRampTime));
663 fRampTimer.async_wait(boost::bind(&ConnectionBias::HandleRampTimer, this, dummy::error));
664 }
665
666public:
667 ConnectionBias(ba::io_service& ioservice, MessageImp &imp) : ConnectionUSB(ioservice, imp()),
668 fSyncTimer(ioservice),
669 fRampTimer(ioservice),
670 fUpdateTimer(ioservice),
671 fBuffer(3*kNumChannels),
672 fBufferRamp(3*kNumChannels),
673 fBufferUpdate(3*kNumChannels),
674 fIsVerbose(false),
675 fVoltCmd(kNumChannels),
676 fVoltGapd(kNumChannels),
677 //fRefCurrent(kNumChannels),
678 fPresent(kNumBoards),
679 fRampStep(-1),
680 fRampTime(-1),
681 fUpdateTime(3000),
682 fSyncTime(333),
683 fIsRamping(false),
684 fWaitingForAnswer(false),
685 fVolt(kNumChannels),
686 fVoltRef(kNumChannels),
687 fCurrent(kNumChannels)
688 {
689 SetLogStream(&imp);
690 }
691
692 void OverCurrentReset()
693 {
694 if (fWaitingForAnswer)
695 {
696 Error("Answer on last command not yet received.");
697 return;
698 }
699
700 if (fIsRamping)
701 {
702 Warn("OverCurrentReset - Ramping in progres.");
703 RampStop();
704 }
705
706 vector<uint16_t> dac(kNumChannels);
707
708 for (int ch=0; ch<kNumChannels; ch++)
709 dac[ch] = fCurrent[ch]<0 ? 0 : fVolt[ch];
710
711 SetAllChannels(dac, true);
712 }
713
714 void ReadAllChannels(bool special = false)
715 {
716 if (!special && fWaitingForAnswer)
717 {
718 Error("Answer on last command not yet received.");
719 return;
720 }
721
722 vector<char> data;
723 data.reserve(kNumChannels*3);
724
725 for (int ch=0; ch<kNumChannels; ch++)
726 {
727 const vector<char> cmd = GetCmd(kCmdRead, ch);
728 data.insert(data.end(), cmd.begin(), cmd.end());
729 }
730
731 fSendCounter += kNumChannels;
732
733 PostMessage(data);
734 AsyncRead(ba::buffer(special ? fBufferUpdate : fBuffer, kNumChannels*3),
735 special ? kUpdate : kCmdRead, fSendCounter);
736
737 if (!special)
738 fWaitingForAnswer = true;
739 }
740
741 // --------------------------------------------------------------------
742
743 bool ChannelSetDac(uint16_t ch, uint16_t dac)
744 {
745 if (!CheckChDac("ChannelSetDac", dac, ch))
746 return false;
747
748 fVoltRef[ch] = dac;
749
750 if (!fIsRamping)
751 fIsRamping = RampOneStep();
752
753 return true;
754 }
755
756 bool ChannelSetVolt(uint16_t ch, double volt)
757 {
758 return ChannelSetDac(ch, volt*4096/90.);
759 }
760
761 bool GlobalSetDac(uint16_t dac)
762 {
763 if (!CheckChDac("GlobalSetDac", dac))
764 return false;
765
766 for (size_t ch=0; ch<kNumChannels; ch++)
767 fVoltRef[ch] = dac;
768
769 if (!fIsRamping)
770 fIsRamping = RampOneStep();
771
772 return true;
773 }
774
775 bool GlobalSetVolt(float volt)
776 {
777 return GlobalSetDac(volt*4096/90);
778 }
779
780 // --------------------------------------------------------------------
781
782 bool SetGapdVoltage()
783 {
784 for (size_t ch=0; ch<kNumChannels; ch++)
785 if (fVoltGapd[ch]>kMaxDac)
786 {
787 Error("SetGapdVoltage - Voltage reference for G-APD channel out of range.");
788 return false;
789 }
790
791 for (size_t ch=0; ch<kNumChannels; ch++)
792 fVoltRef[ch] = fVoltGapd[ch];
793
794 if (!fIsRamping)
795 fIsRamping = RampOneStep();
796
797 return true;
798 }
799
800 void SetZero()
801 {
802 for (size_t ch=0; ch<kNumChannels; ch++)
803 fVoltRef[ch] = 0;
804
805 if (!fIsRamping)
806 fIsRamping = RampOneStep();
807 }
808
809 bool SetNewGapdVoltage(const vector<float> &volt)
810 {
811 if (volt.size()!=kNumChannels)
812 {
813 ostringstream out;
814 out << "SetNewGapdVoltage - Given vector has " << volt.size() << " elements - expected " << kNumChannels << endl;
815 Error(out);
816 return false;
817 }
818
819 for (size_t i=0; i<kNumChannels; i++)
820 fVoltGapd[i] = volt[i]*4096/90;
821
822 return true;
823 }
824
825 // --------------------------------------------------------------------
826
827 void RampStop()
828 {
829 fRampTimer.cancel();
830 fIsRamping = false;
831
832 Message("Ramping stopped.");
833 }
834
835 void RampStart()
836 {
837 if (fIsRamping)
838 {
839 Warn("RampStart - Ramping in progress... ignored.");
840 return;
841 }
842
843 fIsRamping = RampOneStep();
844 }
845
846 void SetRampTime(uint16_t val)
847 {
848 fRampTime = val;
849 }
850
851 void SetRampStep(uint16_t val)
852 {
853 fRampStep = val;
854 }
855
856 bool IsRamping() const { return fIsRamping; }
857
858 // -------------------------------------------------------------------
859
860 void ExpertReset()
861 {
862 if (fWaitingForAnswer)
863 {
864 Error("Answer on last command not yet received.");
865 return;
866 }
867
868 Warn("EXPERT MODE: Sending reset.");
869 PostMessage(GetCmd(kCmdReset));
870 AsyncRead(ba::buffer(fBuffer, 3), kCmdReset, ++fSendCounter);
871 fWaitingForAnswer = true;
872 }
873
874
875 bool ExpertChannelSetDac(uint16_t ch, uint16_t dac)
876 {
877 if (fWaitingForAnswer)
878 {
879 Error("Answer on last command not yet received.");
880 return false;
881 }
882
883 if (!CheckChDac("ExpertChannelSetDac", dac, ch))
884 return false;
885
886 fVoltCmd[ch] = dac;
887
888 ostringstream msg;
889 msg << "EXPERT MODE: Sending 'ChannelSet' (set ch " << ch << " to DAC=" << dac << ")";
890 Warn(msg);
891
892 PostMessage(GetCmd(kCmdChannelSet, ch, dac));
893 AsyncRead(ba::buffer(fBuffer, 3), kExpertChannelSet|(ch<<8), ++fSendCounter);
894 fWaitingForAnswer = true;
895
896 return true;
897 }
898
899 bool ExpertChannelSetVolt(uint16_t ch, double volt)
900 {
901 return ExpertChannelSetDac(ch, volt*4096/90.);
902 }
903
904 bool ExpertGlobalSetDac(uint16_t dac)
905 {
906 if (fWaitingForAnswer)
907 {
908 Error("Answer on last command not yet received.");
909 return false;
910 }
911
912 if (!CheckChDac("ExpertGlobalSetDac", dac))
913 return false;
914
915 if (fGlobalVoltCmd>=0)
916 {
917 Error("ExpertGlobalSetDac - Still waiting for previous global-set's answer.");
918 return false;
919 }
920
921 fGlobalVoltCmd = dac;
922
923 ostringstream msg;
924 msg << "EXPERT MODE: Sending 'GlobalSet' (DAC=" << dac << ")";
925 Warn(msg);
926
927 PostMessage(GetCmd(kCmdGlobalSet, 0, dac));
928 AsyncRead(ba::buffer(fBuffer, 3), kCmdGlobalSet, ++fSendCounter);
929 fWaitingForAnswer = true;
930
931 return true;
932 }
933
934 bool ExpertGlobalSetVolt(float volt)
935 {
936 return ExpertGlobalSetDac(volt*4096/90);
937 }
938
939 // --------------------------------------------------------------------
940
941 void SetVerbose(bool b)
942 {
943 fIsVerbose = b;
944 }
945
946 void PrintLineA(int b, int ch)
947 {
948 Out() << setw(2) << b << "|";
949
950 for (int c=ch; c<ch+8; c++)
951 {
952 const int id = c+kNumChannelsPerBoard*b;
953 Out() << " " << setw(7) << abs(fCurrent[id])*5000/4096.;
954 if (fCurrent[id]<0)
955 Out() << "!";
956 else
957 Out() << " ";
958 }
959 Out() << endl;
960
961 }
962
963 void PrintA()
964 {
965 Out() << dec << setprecision(2) << fixed << setfill(' ');
966 for (int b=0; b<kNumBoards; b++)
967 {
968 if (!fPresent[b])
969 {
970 Out() << setw(2) << b << "-" << endl;
971 continue;
972 }
973
974 PrintLineA(b, 0);
975 PrintLineA(b, 8);
976 PrintLineA(b, 16);
977 PrintLineA(b, 24);
978 }
979 }
980
981 void PrintLineV(int b, int ch)
982 {
983 Out() << setw(2) << b << "|";
984
985 for (int c=ch; c<ch+4; c++)
986 {
987 const int id = c+kNumChannelsPerBoard*b;
988 Out() << " ";
989 Out() << setw(5) << fVolt[id]*90/4096. << '/';
990 Out() << setw(5) << fVoltRef[id]*90/4096.;
991 }
992 Out() << endl;
993 }
994
995 void PrintV()
996 {
997 Out() << dec << setprecision(2) << fixed << setfill(' ');
998 for (int b=0; b<kNumBoards; b++)
999 {
1000 if (!fPresent[b])
1001 {
1002 Out() << setw(2) << b << "-" << endl;
1003 continue;
1004 }
1005
1006 PrintLineV(b, 0);
1007 PrintLineV(b, 4);
1008 PrintLineV(b, 8);
1009 PrintLineV(b, 12);
1010 PrintLineV(b, 16);
1011 PrintLineV(b, 20);
1012 PrintLineV(b, 24);
1013 PrintLineV(b, 28);
1014 }
1015 }
1016
1017 void PrintLineGapd(int b, int ch)
1018 {
1019 Out() << setw(2) << b << "|";
1020
1021 for (int c=ch; c<ch+8; c++)
1022 {
1023 const int id = c+kNumChannelsPerBoard*b;
1024 Out() << " " << setw(5) << fVoltGapd[id]*90/4096.;
1025 }
1026 Out() << endl;
1027 }
1028
1029 void PrintGapd()
1030 {
1031 Out() << dec << setprecision(2) << fixed << setfill(' ');
1032 for (int b=0; b<kNumBoards; b++)
1033 {
1034 if (!fPresent[b])
1035 {
1036 Out() << setw(2) << b << "-" << endl;
1037 continue;
1038 }
1039
1040 PrintLineGapd(b, 0);
1041 PrintLineGapd(b, 8);
1042 PrintLineGapd(b, 16);
1043 PrintLineGapd(b, 24);
1044 }
1045 }
1046
1047 // -------------------------------------------------------------------
1048
1049 void SetUpdateInterval(uint16_t val)
1050 {
1051 fUpdateTime = val;
1052 }
1053
1054 void SetSyncDelay(uint16_t val)
1055 {
1056 fSyncTime = val;
1057 }
1058
1059 void SetVoltMax(float max)
1060 {
1061 fVoltMax = max*4096/90;
1062 if (fVoltMax>4095)
1063 fVoltMax = 4095;
1064 if (max<0)
1065 fVoltMax = 0;
1066 }
1067
1068
1069/*
1070 void AdaptVoltages()
1071 {
1072 // Correct voltages according to current
1073 for (int i=0; i<kNumChannels; i++)
1074 {
1075 if (fVoltRef[i]==0 || fCurrent[i]<0 || fRefCurrent[i]<0)
1076 continue;
1077
1078 // Calculate difference and convert ADC units to Amp
1079 // const double diffcur = (fRefCurrent[i]-fCurrent[i])*5000/4096
1080 //const int32_t diffcur = int32_t(fRefCurrent[i]-fCurrent[i])*5000;
1081
1082 // Calculate voltage difference
1083 // #define RESISTOR 1000 // Ohm
1084 //const double diffvolt = diffcur*RESISTOR/1e6;
1085
1086 // Calculate new vlaue by onverting voltage difference to DAC units
1087 //const int32_t dac = fRefVolt[i] + diffvolt*4096/90.0;
1088 SetVoltage(i, fRefVolt[i] + (fRefCurrent[i]-fCurrent[i])/18);
1089 }
1090 }
1091
1092 void SetReferenceCurrent()
1093 {
1094 fRefCurrent = fCurrent;
1095 }
1096 */
1097
1098 States_t GetStatus()
1099 {
1100 if (!IsConnected())
1101 return BIAS::kDisconnected;
1102
1103 if (IsConnecting())
1104 return BIAS::kConnecting;
1105
1106 if (fIsInitializing)
1107 return BIAS::kInitializing;
1108
1109 if (fIsRamping)
1110 return BIAS::kRamping;
1111
1112 for (int ch=0; ch<kNumChannels; ch++)
1113 if (fPresent[ch/kNumChannelsPerBoard] && fCurrent[ch]<0)
1114 return BIAS::kOverCurrent;
1115
1116 for (int ch=0; ch<kNumChannels; ch++)
1117 if (fPresent[ch/kNumChannelsPerBoard] && fVolt[ch]!=fVoltRef[ch])
1118 return BIAS::kConnected;
1119
1120 return BIAS::kAtReference;
1121 }
1122};
1123
1124// ------------------------------------------------------------------------
1125
1126#include "DimDescriptionService.h"
1127
1128class ConnectionDimBias : public ConnectionBias
1129{
1130private:
1131
1132 DimDescribedService fDimCurrent;
1133 DimDescribedService fDimVoltage;
1134
1135 void UpdateA()
1136 {
1137 fDimCurrent.Update(fCurrent);
1138 }
1139
1140 void UpdateV()
1141 {
1142 vector<uint16_t> vec;
1143 vec.insert(vec.end(), fVolt.begin(), fVolt.end());
1144 vec.insert(vec.end(), fVoltRef.begin(), fVoltRef.end());
1145 fDimVoltage.Update(vec);
1146 }
1147
1148
1149public:
1150 ConnectionDimBias(ba::io_service& ioservice, MessageImp &imp) :
1151 ConnectionBias(ioservice, imp),
1152 fDimCurrent("BIAS_CONTROL/CURRENT", "S:416", ""),
1153 fDimVoltage("BIAS_CONTROL/VOLTAGE", "S:416;S:416", "")
1154 {
1155 }
1156
1157 // 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
1158};
1159
1160// ------------------------------------------------------------------------
1161
1162template <class T, class S>
1163class StateMachineBias : public T, public ba::io_service, public ba::io_service::work
1164{
1165 int Wrap(boost::function<void()> f)
1166 {
1167 f();
1168 return T::GetCurrentState();
1169 }
1170
1171 function<int(const EventImp &)> Wrapper(function<void()> func)
1172 {
1173 return bind(&StateMachineBias::Wrap, this, func);
1174 }
1175
1176 bool CheckEventSize(size_t has, const char *name, size_t size)
1177 {
1178 if (has==size)
1179 return true;
1180
1181 ostringstream msg;
1182 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
1183 T::Fatal(msg);
1184 return false;
1185 }
1186
1187private:
1188 S fBias;
1189
1190 bool fExpertMode;
1191
1192 // --------------------------------------------------------------------
1193
1194 int SetGlobalVolt(const EventImp &evt)
1195 {
1196 if (!CheckEventSize(evt.GetSize(), "SetGlobalVolt", 4))
1197 return false;
1198
1199 if (!fBias.GlobalSetVolt(evt.GetFloat()))
1200 T::Error("Supplied voltage out of range (0-90)");
1201
1202 return T::GetCurrentState();
1203 }
1204
1205 int SetGlobalDac(const EventImp &evt)
1206 {
1207 if (!CheckEventSize(evt.GetSize(), "SetGlobalDac", 2))
1208 return false;
1209
1210 if (!fBias.GlobalSetDac(evt.GetUShort()))
1211 T::Error("Supplied voltage out of range (0-90)");
1212
1213 return T::GetCurrentState();
1214 }
1215
1216 int SetChannelVolt(const EventImp &evt)
1217 {
1218 if (!CheckEventSize(evt.GetSize(), "SetChannelVolt", 6))
1219 return false;
1220
1221 if (!fBias.ChannelSetVolt(evt.GetUShort(), evt.Get<float>(2)))
1222 T::Error("Value out of range");
1223
1224 return T::GetCurrentState();
1225 }
1226
1227 int SetChannelDac(const EventImp &evt)
1228 {
1229 if (!CheckEventSize(evt.GetSize(), "SetChannelDac", 4))
1230 return false;
1231
1232 if (!fBias.ChannelSetDac(evt.Get<uint16_t>(), evt.Get<uint16_t>(2)))
1233 T::Error("Value out of range");
1234
1235 return T::GetCurrentState();
1236 }
1237
1238 // --------------------------------------------------------------------
1239
1240 int ExpertSetGlobalVolt(const EventImp &evt)
1241 {
1242 if (!CheckEventSize(evt.GetSize(), "ExpertSetGlobalVolt", 4))
1243 return false;
1244
1245 if (!fBias.ExpertGlobalSetVolt(evt.GetFloat()))
1246 T::Error("Supplied voltage out of range (0-90)");
1247
1248 return T::GetCurrentState();
1249 }
1250
1251 int ExpertSetGlobalDac(const EventImp &evt)
1252 {
1253 if (!CheckEventSize(evt.GetSize(), "ExpertSetGlobalDac", 2))
1254 return false;
1255
1256 if (!fBias.ExpertGlobalSetDac(evt.GetUShort()))
1257 T::Error("Supplied voltage out of range (0-90)");
1258
1259 return T::GetCurrentState();
1260 }
1261
1262 int ExpertSetChannelVolt(const EventImp &evt)
1263 {
1264 if (!CheckEventSize(evt.GetSize(), "ExpertSetChannelVolt", 6))
1265 return false;
1266
1267 if (!fBias.ExpertChannelSetVolt(evt.GetUShort(), evt.Get<float>(2)))
1268 T::Error("Value out of range");
1269
1270 return T::GetCurrentState();
1271 }
1272
1273 int ExpertSetChannelDac(const EventImp &evt)
1274 {
1275 if (!CheckEventSize(evt.GetSize(), "ExpertSetChannelDac", 4))
1276 return false;
1277
1278 if (!fBias.ExpertChannelSetDac(evt.Get<uint16_t>(), evt.Get<uint16_t>(2)))
1279 T::Error("Value out of range");
1280
1281 return T::GetCurrentState();
1282 }
1283
1284 // --------------------------------------------------------------------
1285
1286 int Disconnect()
1287 {
1288 // Close all connections
1289 fBias.PostClose(false);
1290
1291 /*
1292 // Now wait until all connection have been closed and
1293 // all pending handlers have been processed
1294 poll();
1295 */
1296
1297 return T::GetCurrentState();
1298 }
1299
1300 int Reconnect(const EventImp &evt)
1301 {
1302 // Close all connections to supress the warning in SetEndpoint
1303 fBias.PostClose(false);
1304
1305 // Now wait until all connection have been closed and
1306 // all pending handlers have been processed
1307 poll();
1308
1309 if (evt.GetBool())
1310 fBias.SetEndpoint(evt.GetString());
1311
1312 // Now we can reopen the connection
1313 fBias.PostClose(true);
1314
1315 return T::GetCurrentState();
1316 }
1317
1318 int SetVerbosity(const EventImp &evt)
1319 {
1320 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
1321 return T::kSM_FatalError;
1322
1323 fBias.SetVerbose(evt.GetBool());
1324
1325 return T::GetCurrentState();
1326 }
1327
1328 int SetExpertMode(const EventImp &evt)
1329 {
1330 if (!CheckEventSize(evt.GetSize(), "SetExpertMode", 1))
1331 return T::kSM_FatalError;
1332
1333 fExpertMode = evt.GetBool();
1334
1335 if (fExpertMode)
1336 T::Warn("Expert commands enabled -- please ensure that you EXACTLY know what you do. These commands can destroy the system.");
1337
1338 return T::GetCurrentState();
1339 }
1340
1341 int Execute()
1342 {
1343 // Dispatch (execute) at most one handler from the queue. In contrary
1344 // to run_one(), it doesn't wait until a handler is available
1345 // which can be dispatched, so poll_one() might return with 0
1346 // handlers dispatched. The handlers are always dispatched/executed
1347 // synchronously, i.e. within the call to poll_one()
1348 poll_one();
1349
1350 return fExpertMode && fBias.GetStatus()>=kConnected ?
1351 kExpertMode : fBias.GetStatus();
1352 }
1353
1354public:
1355 StateMachineBias(ostream &out=cout) :
1356 T(out, "BIAS_CONTROL"), ba::io_service::work(static_cast<ba::io_service&>(*this)),
1357 fBias(*this, *this), fExpertMode(false)
1358 {
1359 // ba::io_service::work is a kind of keep_alive for the loop.
1360 // It prevents the io_service to go to stopped state, which
1361 // would prevent any consecutive calls to run()
1362 // or poll() to do nothing. reset() could also revoke to the
1363 // previous state but this might introduce some overhead of
1364 // deletion and creation of threads and more.
1365
1366 // State names
1367 T::AddStateName(kDisconnected, "Disconnected",
1368 "Bias-power supply not connected via USB.");
1369
1370 T::AddStateName(kConnecting, "Connecting",
1371 "Trying to establish USB connection to bias-power supply.");
1372
1373 T::AddStateName(kInitializing, "Initializing",
1374 "USB connection to bias-power supply established, synchronizing USB stream.");
1375
1376 T::AddStateName(kConnected, "Connected",
1377 "USB connection to bias-power supply established.");
1378
1379 T::AddStateName(kAtReference, "Referenced",
1380 "Internal reference voltage matches last sent voltage.");
1381
1382 T::AddStateName(kOverCurrent, "OverCurrent",
1383 "At least one channel is in over current state.");
1384
1385 T::AddStateName(kExpertMode, "ExpertMode",
1386 "Special (risky!) mode to directly send command to the bias-power supply.");
1387
1388 T::AddStateName(kRamping, "Ramping",
1389 "Voltage ramping in progress.");
1390
1391 // Verbosity commands
1392 T::AddEvent("SET_VERBOSE", "B")
1393 (bind(&StateMachineBias::SetVerbosity, this, placeholders::_1))
1394 ("set verbosity state"
1395 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
1396
1397 // Conenction commands
1398 T::AddEvent("DISCONNECT", kConnected, kAtReference)
1399 (bind(&StateMachineBias::Disconnect, this))
1400 ("disconnect from USB");
1401
1402 T::AddEvent("RECONNECT", "O", kDisconnected, kConnected, kAtReference)
1403 (bind(&StateMachineBias::Reconnect, this, placeholders::_1))
1404 ("(Re)connect USB connection to Bias power supply, a new address can be given"
1405 "|tty[string]:new USB address");
1406
1407
1408
1409 T::AddEvent("REQUEST_STATUS", kConnected, kAtReference, kOverCurrent)
1410 (Wrapper(bind(&ConnectionBias::ReadAllChannels, &fBias, false)))
1411 ("Asynchronously request the status (current) of all channels.");
1412
1413 T::AddEvent("RESET_OVER_CURRENT_STATUS", kOverCurrent)
1414 (Wrapper(bind(&ConnectionBias::OverCurrentReset, &fBias)))
1415 ("NOT YET TESTED");
1416
1417
1418
1419 T::AddEvent("SET_GLOBAL_VOLTAGE", "F:1", kConnected, kAtReference, kOverCurrent)
1420 (bind(&StateMachineBias::SetGlobalVolt, this, placeholders::_1))
1421 ("Set all channels to a new reference voltage. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)");
1422
1423 T::AddEvent("SET_GLOBAL_DAC", "S:1", kConnected, kAtReference, kOverCurrent)
1424 (bind(&StateMachineBias::SetGlobalDac, this, placeholders::_1))
1425 ("Set all channels to a new DAC reference. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)");
1426
1427 T::AddEvent("SET_CHANNEL_VOLTAGE", "S:1;F:1", kConnected, kAtReference, kOverCurrent)
1428 (bind(&StateMachineBias::SetChannelVolt, this, placeholders::_1))
1429 ("Set a single channel a new reference voltage. Starts ramping if necessary.");
1430
1431 T::AddEvent("SET_CHANNEL_DAC", "S:1;S:1", kConnected, kAtReference, kOverCurrent)
1432 (bind(&StateMachineBias::SetChannelDac, this, placeholders::_1))
1433 ("Set a single channel a new DAC reference value. Starts ramping if necessary.");
1434
1435 T::AddEvent("SET_GAPD_REFERENCE_VOLTAGE", kConnected, kAtReference, kOverCurrent)
1436 (Wrapper(bind(&ConnectionBias::SetGapdVoltage, &fBias)))
1437 ("Set all channels to their G-APD reference voltage. Starts ramping if necessary.");
1438
1439 T::AddEvent("SET_ZERO_VOLTAGE", kConnected, kAtReference, kOverCurrent)
1440 (Wrapper(bind(&ConnectionBias::SetZero, &fBias)))
1441 ("Set all channels to a zero reference voltage. Starts ramping if necessary.");
1442
1443
1444
1445 T::AddEvent("STOP", kConnected, kRamping, kAtReference, kOverCurrent)
1446 (Wrapper(bind(&ConnectionBias::RampStop, &fBias)))
1447 ("Stop an on-going ramping");
1448
1449 T::AddEvent("START", kConnected, kOverCurrent)
1450 (Wrapper(bind(&ConnectionBias::RampStart, &fBias)))
1451 ("Start a ramping if no ramping is in progress and if reference values differ from current voltages");
1452
1453
1454
1455 T::AddEvent("PRINT_CURRENTS")
1456 (Wrapper(bind(&ConnectionBias::PrintA, &fBias)))
1457 ("Print a table with all current read back with the last request operation");
1458 T::AddEvent("PRINT_VOLTAGES")
1459 (Wrapper(bind(&ConnectionBias::PrintV, &fBias)))
1460 ("Print a table with all voltages (current and reference voltages as currently in memory)");
1461 T::AddEvent("PRINT_GAPD_REFERENCE_VOLTAGES")
1462 (Wrapper(bind(&ConnectionBias::PrintGapd, &fBias)))
1463 ("Print the G-APD reference values obtained from file");
1464
1465
1466 T::AddEvent("EXPERT_MODE", "B:1")
1467 (bind(&StateMachineBias::SetExpertMode, this, placeholders::_1))
1468 ("Enable usage of expert commands (note that for safty reasons the are exclusive with the standard commands)");
1469
1470 T::AddEvent("EXPERT_RESET", kExpertMode)
1471 (Wrapper(bind(&ConnectionBias::ExpertReset, &fBias)))
1472 ("Send the RESET command (note that this is possibly harmfull command)");
1473
1474 T::AddEvent("EXPERT_SET_GLOBAL_VOLTAGE", "F:1", kExpertMode)
1475 (bind(&StateMachineBias::ExpertSetGlobalVolt, this, placeholders::_1))
1476 ("Send the global set command. The given voltage is converted to DAC counts.");
1477
1478 T::AddEvent("EXPERT_SET_GLOBAL_DAC", "S:1", kExpertMode)
1479 (bind(&StateMachineBias::ExpertSetGlobalDac, this, placeholders::_1))
1480 ("Send the global set command.");
1481
1482 T::AddEvent("EXPERT_SET_CHANNEL_VOLTAGE", "S:1;F:1", kExpertMode)
1483 (bind(&StateMachineBias::ExpertSetChannelVolt, this, placeholders::_1))
1484 ("Send a single channel set command. The given voltage is converted to DAC commands.");
1485
1486 T::AddEvent("EXPERT_SET_CHANNEL_DAC", "S:1;S:1", kExpertMode)
1487 (bind(&StateMachineBias::ExpertSetChannelDac, this, placeholders::_1))
1488 ("Send a single channel set command.");
1489 }
1490
1491 ~StateMachineBias() { T::Warn("TODO: Implement rampming at shutdown!"); }
1492
1493 int EvalOptions(Configuration &conf)
1494 {
1495 fBias.SetVerbose(!conf.Get<bool>("quiet"));
1496
1497 fBias.SetEndpoint(conf.Get<string>("dev"));
1498 T::Message("Setting device to "+fBias.URL());
1499
1500 const uint16_t step = conf.Get<uint16_t>("ramp-step");
1501 const uint16_t time = conf.Get<uint16_t>("ramp-time");
1502
1503 if (step>230) // 5V
1504 {
1505 T::Error("ramp-step exceeds allowed range.");
1506 return 1;
1507 }
1508
1509 fBias.SetRampStep(step);
1510 fBias.SetRampTime(time);
1511 fBias.SetUpdateInterval(conf.Get<uint16_t>("update-interval"));
1512 fBias.SetSyncDelay(conf.Get<uint16_t>("sync-delay"));
1513
1514 const float maxv = conf.Get<float>("volt-max");
1515 if (maxv>90)
1516 {
1517 T::Error("volt-max exceeds 90V.");
1518 return 2;
1519 }
1520 if (maxv>75)
1521 T::Warn("volt-max exceeds 75V.");
1522 if (maxv<70)
1523 T::Warn("volt-max below 70V.");
1524 if (maxv<0)
1525 {
1526 T::Error("volt-max negative.");
1527 return 3;
1528 }
1529
1530 fBias.SetVoltMax(maxv);
1531
1532 // --------------------------------------------------------------------------
1533
1534 ifstream fin("FACTmapV5.txt");
1535
1536 int l = 0;
1537
1538 vector<float> vec(kNumChannels);
1539
1540 string buf;
1541 while (getline(fin, buf, '\n'))
1542 {
1543 if (l>1439)
1544 break;
1545
1546 buf = Tools::Trim(buf);
1547 if (buf[0]=='#')
1548 continue;
1549
1550 stringstream str(buf);
1551
1552 int idummy, board, channel;
1553 float fdummy, volt;
1554
1555 str >> idummy >> idummy >> idummy >> idummy >> idummy;
1556 str >> volt;
1557 str >> board;
1558 str >> channel;
1559 str >> fdummy >> fdummy >> fdummy;
1560
1561 if (channel+32*board>=kNumChannels)
1562 {
1563 T::Error("Invalid board/channel read from FACTmapV5.txt.");
1564 return 4;
1565 }
1566
1567 vec[channel+32*board] = volt;
1568 l++;
1569 }
1570
1571 if (l!=1440)
1572 {
1573 T::Error("Reading reference voltages from FACTmapV5.txt failed.");
1574 return 5;
1575 }
1576
1577 if (!fBias.SetNewGapdVoltage(vec))
1578 {
1579 T::Error("Setting reference voltages failed.");
1580 return 6;
1581 }
1582
1583 // --------------------------------------------------------------------------
1584
1585 fBias.Connect();
1586
1587 return -1;
1588 }
1589};
1590
1591// ------------------------------------------------------------------------
1592
1593#include "Main.h"
1594
1595template<class T, class S, class R>
1596int RunShell(Configuration &conf)
1597{
1598 return Main::execute<T, StateMachineBias<S, R>>(conf);
1599}
1600
1601void SetupConfiguration(Configuration &conf)
1602{
1603 po::options_description control("BIAS control options");
1604 control.add_options()
1605 ("no-dim,d", po_bool(), "Disable dim services")
1606 ("dev", var<string>("FTE00FOH"), "Device address of USB port to bias-power supply")
1607 ("quiet,q", po_bool(), "Disable printing contents of all received messages (except dynamic data) in clear text.")
1608 ("ramp-time", var<uint16_t>(15), "Delay between the answer of one ramping steps and sending the next ramp command to all channels in milliseconds.")
1609 ("ramp-step", var<uint16_t>(46), "Maximum step in DAC counts during ramping (Volt = DAC*90/4096)")
1610 ("update-interval", var<uint16_t>(3000), "Interval between two current requests in milliseconds")
1611 ("sync-delay", var<uint16_t>(333), "Delay between sending the inital 0's after a newly established connection to synchronize the output stream in milliseconds")
1612 ("volt-max", var<float>(75), "Upper limit for the voltage which can be applied in Volts")
1613 ;
1614 // FIXME: Make sure ramping / request and commands are
1615 // not sent at the same time.
1616
1617 conf.AddOptions(control);
1618}
1619
1620/*
1621 Extract usage clause(s) [if any] for SYNOPSIS.
1622 Translators: "Usage" and "or" here are patterns (regular expressions) which
1623 are used to match the usage synopsis in program output. An example from cp
1624 (GNU coreutils) which contains both strings:
1625 Usage: cp [OPTION]... [-T] SOURCE DEST
1626 or: cp [OPTION]... SOURCE... DIRECTORY
1627 or: cp [OPTION]... -t DIRECTORY SOURCE...
1628 */
1629void PrintUsage()
1630{
1631 cout <<
1632 "The biasctrl controls the bias-power supply boards.\n"
1633 "\n"
1634 "The default is that the program is started without user intercation. "
1635 "All actions are supposed to arrive as DimCommands. Using the -c "
1636 "option, a local shell can be initialized. With h or help a short "
1637 "help message about the usuage can be brought to the screen.\n"
1638 "\n"
1639 "Usage: biasctrl [-c type] [OPTIONS]\n"
1640 " or: biasctrl [OPTIONS]\n";
1641 cout << endl;
1642}
1643
1644void PrintHelp()
1645{
1646 /* Additional help text which is printed after the configuration
1647 options goes here */
1648
1649 /*
1650 cout << "bla bla bla" << endl << endl;
1651 cout << endl;
1652 cout << "Environment:" << endl;
1653 cout << "environment" << endl;
1654 cout << endl;
1655 cout << "Examples:" << endl;
1656 cout << "test exam" << endl;
1657 cout << endl;
1658 cout << "Files:" << endl;
1659 cout << "files" << endl;
1660 cout << endl;
1661 */
1662}
1663
1664int main(int argc, const char* argv[])
1665{
1666 Configuration conf(argv[0]);
1667 conf.SetPrintUsage(PrintUsage);
1668 Main::SetupConfiguration(conf);
1669 SetupConfiguration(conf);
1670
1671 if (!conf.DoParse(argc, argv, PrintHelp))
1672 return -1;
1673
1674 //try
1675 {
1676 // No console access at all
1677 if (!conf.Has("console"))
1678 {
1679 if (conf.Get<bool>("no-dim"))
1680 return RunShell<LocalStream, StateMachine, ConnectionBias>(conf);
1681 else
1682 return RunShell<LocalStream, StateMachineDim, ConnectionDimBias>(conf);
1683 }
1684 // Cosole access w/ and w/o Dim
1685 if (conf.Get<bool>("no-dim"))
1686 {
1687 if (conf.Get<int>("console")==0)
1688 return RunShell<LocalShell, StateMachine, ConnectionBias>(conf);
1689 else
1690 return RunShell<LocalConsole, StateMachine, ConnectionBias>(conf);
1691 }
1692 else
1693 {
1694 if (conf.Get<int>("console")==0)
1695 return RunShell<LocalShell, StateMachineDim, ConnectionDimBias>(conf);
1696 else
1697 return RunShell<LocalConsole, StateMachineDim, ConnectionDimBias>(conf);
1698 }
1699 }
1700 /*catch (std::exception& e)
1701 {
1702 cerr << "Exception: " << e.what() << endl;
1703 return -1;
1704 }*/
1705
1706 return 0;
1707}
Note: See TracBrowser for help on using the repository browser.