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

Last change on this file since 11942 was 11940, checked in by tbretz, 14 years ago
Implemented three different receive buffers and blocked sending of several commands before an answer is received to avoid that a buffer is written to before the previous handler has finished.
File size: 49.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#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:";
176 msg << " 0x" << setw(2) << (int)answer[0];
177 msg << " 0x" << setw(2) << (int)answer[1];
178 msg << " 0x" << setw(2) << (int)answer[2];
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 ethernet");
1401
1402 T::AddEvent("RECONNECT", "O", kDisconnected, kConnected, kAtReference)
1403 (bind(&StateMachineBias::Reconnect, this, placeholders::_1))
1404 ("(Re)connect ethernet connection to FTM, a new address can be given"
1405 "|[host][string]:new ethernet address in the form <host:port>");
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 ("");
1448
1449 T::AddEvent("START", kConnected, kOverCurrent)
1450 (Wrapper(bind(&ConnectionBias::RampStart, &fBias)))
1451 ("");
1452
1453
1454
1455 T::AddEvent("PRINT_CURRENTS")
1456 (Wrapper(bind(&ConnectionBias::PrintA, &fBias)))
1457 ("");
1458 T::AddEvent("PRINT_VOLTAGES")
1459 (Wrapper(bind(&ConnectionBias::PrintV, &fBias)))
1460 ("");
1461 T::AddEvent("PRINT_GAPD_REFERENCE_VOLTAGES")
1462 (Wrapper(bind(&ConnectionBias::PrintGapd, &fBias)))
1463 ("");
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("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), "")
1609 ("ramp-step", var<uint16_t>(46), "")
1610 ("update-interval", var<uint16_t>(3000), "")
1611 ("sync-delay", var<uint16_t>(333), "")
1612 ("volt-max", var<float>(75), "")
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.