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

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