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

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