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

Last change on this file since 12167 was 12108, checked in by tbretz, 13 years ago
Added states for the status of the voltage.
File size: 64.1 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]==0)
1364 return BIAS::kVoltageOff;
1365
1366 for (int ch=0; ch<kNumChannels; ch++)
1367 if (fPresent[ch/kNumChannelsPerBoard] && fVolt[ch]!=fVoltRef[ch])
1368 return BIAS::kNotReferenced;
1369
1370 return BIAS::kVoltageOn;
1371 }
1372};
1373
1374// ------------------------------------------------------------------------
1375
1376#include "DimDescriptionService.h"
1377
1378class ConnectionDimBias : public ConnectionBias
1379{
1380private:
1381
1382 DimDescribedService fDimCurrent;
1383 DimDescribedService fDimVoltage;
1384
1385 void UpdateA()
1386 {
1387 fDimCurrent.Update(fCurrent);
1388 }
1389
1390 void UpdateV()
1391 {
1392 vector<uint16_t> vec;
1393 vec.insert(vec.end(), fVolt.begin(), fVolt.end());
1394 vec.insert(vec.end(), fVoltRef.begin(), fVoltRef.end());
1395 fDimVoltage.Update(vec);
1396 }
1397
1398
1399public:
1400 ConnectionDimBias(ba::io_service& ioservice, MessageImp &imp) :
1401 ConnectionBias(ioservice, imp),
1402 fDimCurrent("BIAS_CONTROL/CURRENT", "S:416", ""),
1403 fDimVoltage("BIAS_CONTROL/VOLTAGE", "S:416;S:416", "")
1404 {
1405 }
1406
1407 // 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
1408};
1409
1410// ------------------------------------------------------------------------
1411
1412template <class T, class S>
1413class StateMachineBias : public T, public ba::io_service, public ba::io_service::work
1414{
1415 int Wrap(boost::function<void()> f)
1416 {
1417 f();
1418 return T::GetCurrentState();
1419 }
1420
1421 function<int(const EventImp &)> Wrapper(function<void()> func)
1422 {
1423 return bind(&StateMachineBias::Wrap, this, func);
1424 }
1425
1426 bool CheckEventSize(size_t has, const char *name, size_t size)
1427 {
1428 if (has==size)
1429 return true;
1430
1431 ostringstream msg;
1432 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
1433 T::Fatal(msg);
1434 return false;
1435 }
1436
1437private:
1438 S fBias;
1439
1440 bool fExpertMode;
1441
1442 // --------------------------------------------------------------------
1443
1444 int SetGapdVoltage(const EventImp &evt)
1445 {
1446 if (!CheckEventSize(evt.GetSize(), "SetGapdVoltage", 4))
1447 return false;
1448
1449 fBias.SetGapdVoltage(evt.GetFloat());
1450
1451 return T::GetCurrentState();
1452 }
1453
1454 // --------------------------------------------------------------------
1455
1456 int SetGlobalVolt(const EventImp &evt)
1457 {
1458 if (!CheckEventSize(evt.GetSize(), "SetGlobalVolt", 4))
1459 return false;
1460
1461 fBias.GlobalSetVolt(evt.GetFloat());
1462
1463 return T::GetCurrentState();
1464 }
1465
1466 int SetGlobalDac(const EventImp &evt)
1467 {
1468 if (!CheckEventSize(evt.GetSize(), "SetGlobalDac", 2))
1469 return false;
1470
1471 fBias.GlobalSetDac(evt.GetUShort());
1472
1473 return T::GetCurrentState();
1474 }
1475
1476 int IncGlobalVolt(const EventImp &evt)
1477 {
1478 if (!CheckEventSize(evt.GetSize(), "IncGlobalVolt", 4))
1479 return false;
1480
1481 fBias.GlobalAddVolt(evt.GetFloat());
1482
1483 return T::GetCurrentState();
1484 }
1485
1486 int IncGlobalDac(const EventImp &evt)
1487 {
1488 if (!CheckEventSize(evt.GetSize(), "IncGlobalDac", 2))
1489 return false;
1490
1491 fBias.GlobalAddDac(evt.GetShort());
1492
1493 return T::GetCurrentState();
1494 }
1495
1496 int DecGlobalVolt(const EventImp &evt)
1497 {
1498 if (!CheckEventSize(evt.GetSize(), "DecGlobalVolt", 4))
1499 return false;
1500
1501 fBias.GlobalAddVolt(-evt.GetFloat());
1502
1503 return T::GetCurrentState();
1504 }
1505
1506 int DecGlobalDac(const EventImp &evt)
1507 {
1508 if (!CheckEventSize(evt.GetSize(), "DecGlobalDac", 2))
1509 return false;
1510
1511 fBias.GlobalAddDac(-evt.GetShort());
1512
1513 return T::GetCurrentState();
1514 }
1515
1516 int SetChannelVolt(const EventImp &evt)
1517 {
1518 if (!CheckEventSize(evt.GetSize(), "SetChannelVolt", 6))
1519 return false;
1520
1521 fBias.ChannelSetVolt(evt.GetUShort(), evt.Get<float>(2));
1522
1523 return T::GetCurrentState();
1524 }
1525
1526 int SetChannelDac(const EventImp &evt)
1527 {
1528 if (!CheckEventSize(evt.GetSize(), "SetChannelDac", 4))
1529 return false;
1530
1531 fBias.ChannelSetDac(evt.Get<uint16_t>(), evt.Get<uint16_t>(2));
1532
1533 return T::GetCurrentState();
1534 }
1535
1536 int SetGapdReferenceCh(const EventImp &evt)
1537 {
1538 if (!CheckEventSize(evt.GetSize(), "SetGapdReferenceCh", 2))
1539 return false;
1540
1541 fBias.SetGapdReferenceCh(evt.GetUShort());
1542
1543 return T::GetCurrentState();
1544 }
1545
1546
1547 // --------------------------------------------------------------------
1548
1549 int AddReferenceDac(const EventImp &evt)
1550 {
1551 if (!CheckEventSize(evt.GetSize(), "AddReferenceDac", 2*kNumChannels))
1552 return false;
1553
1554 const int16_t *ptr = evt.Ptr<int16_t>();
1555 fBias.AddDac(vector<int16_t>(ptr, ptr+416));
1556
1557 return T::GetCurrentState();
1558 }
1559
1560 int AddReferenceVolt(const EventImp &evt)
1561 {
1562 if (!CheckEventSize(evt.GetSize(), "AddReferenceVolt", 4*kNumChannels))
1563 return false;
1564
1565 const float_t *ptr = evt.Ptr<float>();
1566 fBias.AddVolt(vector<float>(ptr, ptr+416));
1567
1568 return T::GetCurrentState();
1569 }
1570
1571 int SetReferenceDac(const EventImp &evt)
1572 {
1573 if (!CheckEventSize(evt.GetSize(), "SetReferenceDac", 2*kNumChannels))
1574 return false;
1575
1576 const int16_t *ptr = evt.Ptr<int16_t>();
1577 fBias.SetDac(vector<int16_t>(ptr, ptr+416));
1578
1579 return T::GetCurrentState();
1580 }
1581
1582 int SetReferenceVolt(const EventImp &evt)
1583 {
1584 if (!CheckEventSize(evt.GetSize(), "SetReferenceVolt", 4*kNumChannels))
1585 return false;
1586
1587 const float_t *ptr = evt.Ptr<float>();
1588 fBias.SetVolt(vector<float>(ptr, ptr+416));
1589
1590 return T::GetCurrentState();
1591 }
1592
1593 // --------------------------------------------------------------------
1594
1595 int ExpertSetGlobalVolt(const EventImp &evt)
1596 {
1597 if (!CheckEventSize(evt.GetSize(), "ExpertSetGlobalVolt", 4))
1598 return false;
1599
1600 fBias.ExpertGlobalSetVolt(evt.GetFloat());
1601
1602 return T::GetCurrentState();
1603 }
1604
1605 int ExpertSetGlobalDac(const EventImp &evt)
1606 {
1607 if (!CheckEventSize(evt.GetSize(), "ExpertSetGlobalDac", 2))
1608 return false;
1609
1610 fBias.ExpertGlobalSetDac(evt.GetUShort());
1611
1612 return T::GetCurrentState();
1613 }
1614
1615 int ExpertSetChannelVolt(const EventImp &evt)
1616 {
1617 if (!CheckEventSize(evt.GetSize(), "ExpertSetChannelVolt", 6))
1618 return false;
1619
1620 fBias.ExpertChannelSetVolt(evt.GetUShort(), evt.Get<float>(2));
1621
1622 return T::GetCurrentState();
1623 }
1624
1625 int ExpertSetChannelDac(const EventImp &evt)
1626 {
1627 if (!CheckEventSize(evt.GetSize(), "ExpertSetChannelDac", 4))
1628 return false;
1629
1630 fBias.ExpertChannelSetDac(evt.Get<uint16_t>(), evt.Get<uint16_t>(2));
1631
1632 return T::GetCurrentState();
1633 }
1634
1635 // --------------------------------------------------------------------
1636
1637 int Disconnect()
1638 {
1639 // Close all connections
1640 fBias.PostClose(false);
1641
1642 /*
1643 // Now wait until all connection have been closed and
1644 // all pending handlers have been processed
1645 poll();
1646 */
1647
1648 return T::GetCurrentState();
1649 }
1650
1651 int Reconnect(const EventImp &evt)
1652 {
1653 // Close all connections to supress the warning in SetEndpoint
1654 fBias.PostClose(false);
1655
1656 // Now wait until all connection have been closed and
1657 // all pending handlers have been processed
1658 poll();
1659
1660 if (evt.GetBool())
1661 fBias.SetEndpoint(evt.GetString());
1662
1663 // Now we can reopen the connection
1664 fBias.PostClose(true);
1665
1666 return T::GetCurrentState();
1667 }
1668
1669 int SetVerbosity(const EventImp &evt)
1670 {
1671 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
1672 return T::kSM_FatalError;
1673
1674 fBias.SetVerbose(evt.GetBool());
1675
1676 return T::GetCurrentState();
1677 }
1678
1679 int SetExpertMode(const EventImp &evt)
1680 {
1681 if (!CheckEventSize(evt.GetSize(), "SetExpertMode", 1))
1682 return T::kSM_FatalError;
1683
1684 fExpertMode = evt.GetBool();
1685
1686 if (fExpertMode)
1687 T::Warn("Expert commands enabled -- please ensure that you EXACTLY know what you do. These commands can destroy the system.");
1688
1689 return T::GetCurrentState();
1690 }
1691
1692 int Execute()
1693 {
1694 // Dispatch (execute) at most one handler from the queue. In contrary
1695 // to run_one(), it doesn't wait until a handler is available
1696 // which can be dispatched, so poll_one() might return with 0
1697 // handlers dispatched. The handlers are always dispatched/executed
1698 // synchronously, i.e. within the call to poll_one()
1699 poll_one();
1700
1701 return fExpertMode && fBias.GetStatus()>=kConnected ?
1702 kExpertMode : fBias.GetStatus();
1703 }
1704
1705public:
1706 StateMachineBias(ostream &out=cout) :
1707 T(out, "BIAS_CONTROL"), ba::io_service::work(static_cast<ba::io_service&>(*this)),
1708 fBias(*this, *this), fExpertMode(false)
1709 {
1710 // ba::io_service::work is a kind of keep_alive for the loop.
1711 // It prevents the io_service to go to stopped state, which
1712 // would prevent any consecutive calls to run()
1713 // or poll() to do nothing. reset() could also revoke to the
1714 // previous state but this might introduce some overhead of
1715 // deletion and creation of threads and more.
1716
1717 // State names
1718 T::AddStateName(kDisconnected, "Disconnected",
1719 "Bias-power supply not connected via USB.");
1720
1721 T::AddStateName(kConnecting, "Connecting",
1722 "Trying to establish USB connection to bias-power supply.");
1723
1724 T::AddStateName(kInitializing, "Initializing",
1725 "USB connection to bias-power supply established, synchronizing USB stream.");
1726
1727 T::AddStateName(kConnected, "Connected",
1728 "USB connection to bias-power supply established.");
1729
1730 T::AddStateName(kNotReferenced, "NotReferenced",
1731 "Internal reference voltage does not match last sent voltage.");
1732
1733 T::AddStateName(kVoltageOff, "VoltageOff",
1734 "All voltages are supposed to be switched off.");
1735
1736 T::AddStateName(kVoltageOn, "VoltageOn",
1737 "At least one voltage is switched on and all are at reference.");
1738
1739 T::AddStateName(kOverCurrent, "OverCurrent",
1740 "At least one channel is in over current state.");
1741
1742 T::AddStateName(kExpertMode, "ExpertMode",
1743 "Special (risky!) mode to directly send command to the bias-power supply.");
1744
1745 T::AddStateName(kRamping, "Ramping",
1746 "Voltage ramping in progress.");
1747
1748 // Verbosity commands
1749 T::AddEvent("SET_VERBOSE", "B")
1750 (bind(&StateMachineBias::SetVerbosity, this, placeholders::_1))
1751 ("set verbosity state"
1752 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
1753
1754 // Conenction commands
1755 T::AddEvent("DISCONNECT", kConnected, kVoltageOff)
1756 (bind(&StateMachineBias::Disconnect, this))
1757 ("disconnect from USB");
1758
1759 T::AddEvent("RECONNECT", "O", kDisconnected, kConnected, kVoltageOff)
1760 (bind(&StateMachineBias::Reconnect, this, placeholders::_1))
1761 ("(Re)connect USB connection to Bias power supply, a new address can be given"
1762 "|tty[string]:new USB address");
1763
1764
1765
1766 T::AddEvent("REQUEST_STATUS", kConnected, kVoltageOn, kVoltageOff, kNotReferenced, kOverCurrent)
1767 (Wrapper(bind(&ConnectionBias::ReadAllChannels, &fBias, false)))
1768 ("Asynchronously request the status (current) of all channels.");
1769
1770 T::AddEvent("RESET_OVER_CURRENT_STATUS", kOverCurrent)
1771 (Wrapper(bind(&ConnectionBias::OverCurrentReset, &fBias)))
1772 ("Set all channels in over current state to 0V and send a system reset to reset the over current flags.");
1773
1774
1775
1776 T::AddEvent("SET_GLOBAL_VOLTAGE", "F:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1777 (bind(&StateMachineBias::SetGlobalVolt, 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 "|voltage[V]:Global target voltage in volts (will be converted to DAC units)");
1780
1781 T::AddEvent("SET_GLOBAL_DAC", "S:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1782 (bind(&StateMachineBias::SetGlobalDac, 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 "|voltage[dac]:Global target voltage as DAC counts.");
1785
1786 T::AddEvent("INCREASE_GLOBAL_VOLTAGE", "F:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1787 (bind(&StateMachineBias::IncGlobalVolt, 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 added to all channels (will be converted to DAC counts)");
1790
1791 T::AddEvent("INCREASE_GLOBAL_DAC", "S:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1792 (bind(&StateMachineBias::IncGlobalDac, 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 added to all channels as DAC counts");
1795
1796 T::AddEvent("DECREASE_GLOBAL_VOLTAGE", "F:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1797 (bind(&StateMachineBias::DecGlobalVolt, this, placeholders::_1))
1798 ("Set all channels to a new reference voltage. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
1799 "|offset[V]:Offset to be subtracted from all channels (will be converted to DAC counts)");
1800
1801 T::AddEvent("DECREASE_GLOBAL_DAC", "S:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1802 (bind(&StateMachineBias::DecGlobalDac, this, placeholders::_1))
1803 ("Set all channels to a new DAC reference. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
1804 "|offset[dac]:Offset to be subtracted from all channels as DAC counts");
1805
1806 T::AddEvent("SET_CHANNEL_VOLTAGE", "S:1;F:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1807 (bind(&StateMachineBias::SetChannelVolt, this, placeholders::_1))
1808 ("Set a single channel to a new reference voltage. Starts ramping if necessary."
1809 "|channel[short]:Channel for which to set the target voltage [0-416]"
1810 "|voltage[V]:Target voltage in volts for the given channel (will be converted to DAC units)");
1811
1812 T::AddEvent("SET_CHANNEL_DAC", "S:1;S:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1813 (bind(&StateMachineBias::SetChannelDac, this, placeholders::_1))
1814 ("Set a single channel to a new DAC reference value. Starts ramping if necessary."
1815 "|channel[short]:Channel for which to set the target voltage [0-416]"
1816 "|voltage[dac]:Target voltage in DAC units for the given channel");
1817
1818 T::AddEvent("SET_GLOBAL_GAPD_REFERENCE_VOLTAGE", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1819 (Wrapper(bind(&ConnectionBias::SetGapdVoltage, &fBias, 0.)))
1820 ("Set all channels to their G-APD reference voltage. Starts ramping if necessary.");
1821
1822 T::AddEvent("SET_CHANNEL_GAPD_REFERENCE_VOLTAGE", "S:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1823 (bind(&StateMachineBias::SetGapdReferenceCh, this, placeholders::_1))
1824 ("Set a single channel channels to its G-APD reference voltage. Starts ramping if necessary."
1825 "|channel[short]:Channel for which to set the target voltage [0-416]");
1826
1827 T::AddEvent("SET_GAPD_REFERENCE_OFFSET", "F:1", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1828 (bind(&StateMachineBias::SetGapdVoltage, this, placeholders::_1))
1829 ("Set all channels to their G-APD reference voltage plus the given offset. Starts ramping if necessary."
1830 "|offset[V]:Offset to be added to teh G-APD reference voltage globally");
1831
1832 T::AddEvent("SET_ZERO_VOLTAGE", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1833 (Wrapper(bind(&ConnectionBias::SetZero, &fBias)))
1834 ("Set all channels to a zero reference voltage. Starts ramping if necessary.");
1835
1836 T::AddEvent("SET_REFERENCE_VOLTAGES", "F:416", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1837 (bind(&StateMachineBias::SetReferenceVolt, this, placeholders::_1))
1838 ("Set all channels to the given new reference voltage. Starts ramping if necessary."
1839 "voltage[V]:New reference voltage for all channels");
1840
1841 T::AddEvent("SET_REFERENCE_DACS", "S:416", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1842 (bind(&StateMachineBias::SetReferenceDac, this, placeholders::_1))
1843 ("Set all channels to the given new reference voltage. Starts ramping if necessary."
1844 "voltage[dac]:New reference voltage for all channels in DAC units");
1845
1846 T::AddEvent("ADD_REFERENCE_VOLTAGES", "F:416", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1847 (bind(&StateMachineBias::AddReferenceVolt, this, placeholders::_1))
1848 ("Add the given voltages to the current reference voltages. Starts ramping if necessary."
1849 "offset[V]:Offsets to be added to the reference voltage of all channels in volts");
1850
1851 T::AddEvent("ADD_REFERENCE_DACS", "S:416", kConnected, kVoltageOff, kVoltageOn, kNotReferenced, kOverCurrent)
1852 (bind(&StateMachineBias::AddReferenceDac, this, placeholders::_1))
1853 ("Add the given voltages to the current reference voltages. Starts ramping if necessary."
1854 "offset[dac]:Offsets to be added to the reference voltage of all channels in DAC units");
1855
1856
1857
1858
1859 T::AddEvent("STOP", kConnected, kRamping)
1860 (Wrapper(bind(&ConnectionBias::RampStop, &fBias)))
1861 ("Stop an on-going ramping");
1862
1863 T::AddEvent("START", kConnected, kNotReferenced)
1864 (Wrapper(bind(&ConnectionBias::RampStart, &fBias)))
1865 ("Start a ramping if no ramping is in progress and if reference values differ from current voltages");
1866
1867
1868
1869 T::AddEvent("PRINT_INFO")
1870 (Wrapper(bind(&ConnectionBias::PrintInfo, &fBias)))
1871 ("Print a table with all current read back with the last request operation");
1872 T::AddEvent("PRINT_CURRENTS")
1873 (Wrapper(bind(&ConnectionBias::PrintA, &fBias)))
1874 ("Print a table with all current read back with the last request operation");
1875 T::AddEvent("PRINT_VOLTAGES")
1876 (Wrapper(bind(&ConnectionBias::PrintV, &fBias)))
1877 ("Print a table with all voltages (current and reference voltages as currently in memory)");
1878 T::AddEvent("PRINT_GAPD_REFERENCE_VOLTAGES")
1879 (Wrapper(bind(&ConnectionBias::PrintGapd, &fBias)))
1880 ("Print the G-APD reference values obtained from file");
1881
1882
1883 T::AddEvent("EXPERT_MODE", "B:1")
1884 (bind(&StateMachineBias::SetExpertMode, this, placeholders::_1))
1885 ("Enable usage of expert commands (note that for safty reasons the are exclusive with the standard commands)");
1886
1887 T::AddEvent("EXPERT_RESET", kExpertMode)
1888 (Wrapper(bind(&ConnectionBias::ExpertReset, &fBias, true)))
1889 ("Send the RESET command (note that this is possibly harmfull command)");
1890
1891 T::AddEvent("EXPERT_SET_GLOBAL_VOLTAGE", "F:1", kExpertMode)
1892 (bind(&StateMachineBias::ExpertSetGlobalVolt, this, placeholders::_1))
1893 ("Send the global set command. The given voltage is converted to DAC counts.");
1894
1895 T::AddEvent("EXPERT_SET_GLOBAL_DAC", "S:1", kExpertMode)
1896 (bind(&StateMachineBias::ExpertSetGlobalDac, this, placeholders::_1))
1897 ("Send the global set command.");
1898
1899 T::AddEvent("EXPERT_SET_CHANNEL_VOLTAGE", "S:1;F:1", kExpertMode)
1900 (bind(&StateMachineBias::ExpertSetChannelVolt, this, placeholders::_1))
1901 ("Send a single channel set command. The given voltage is converted to DAC commands.");
1902
1903 T::AddEvent("EXPERT_SET_CHANNEL_DAC", "S:1;S:1", kExpertMode)
1904 (bind(&StateMachineBias::ExpertSetChannelDac, this, placeholders::_1))
1905 ("Send a single channel set command.");
1906 }
1907
1908 ~StateMachineBias() { T::Warn("TODO: Implement rampming at shutdown!"); }
1909
1910 int EvalOptions(Configuration &conf)
1911 {
1912 // FIXME: Read calib_offset
1913 // FIXME: Check calib offset being smaller than +/-0.25V
1914
1915 fBias.SetVerbose(!conf.Get<bool>("quiet"));
1916
1917 fBias.SetEndpoint(conf.Get<string>("dev"));
1918 T::Message("Setting device to "+fBias.URL());
1919
1920 const uint16_t step = conf.Get<uint16_t>("ramp-step");
1921 const uint16_t time = conf.Get<uint16_t>("ramp-time");
1922
1923 if (step>230) // 5V
1924 {
1925 T::Error("ramp-step exceeds allowed range.");
1926 return 1;
1927 }
1928
1929 fBias.SetRampStep(step);
1930 fBias.SetRampTime(time);
1931 fBias.SetUpdateInterval(conf.Get<uint16_t>("update-interval"));
1932 fBias.SetSyncDelay(conf.Get<uint16_t>("sync-delay"));
1933
1934 ostringstream str1, str2;
1935 str1 << "Ramping in effective steps of " << fBias.GetRampStepVolt() << "V";
1936 str2 << "Ramping with a delay per step of " << time << "ms";
1937 T::Message(str1);
1938 T::Message(str2);
1939
1940 // --------------------------------------------------------------------------
1941
1942 const float maxabsv = conf.Get<float>("volt-max-abs");
1943 const float maxrelv = conf.Get<float>("volt-max-rel");
1944 if (maxabsv>90)
1945 {
1946 T::Error("volt-max exceeds 90V.");
1947 return 2;
1948 }
1949 if (maxabsv>75)
1950 T::Warn("volt-max exceeds 75V.");
1951 if (maxabsv<70)
1952 T::Warn("volt-max below 70V.");
1953 if (maxabsv<0)
1954 {
1955 T::Error("volt-max negative.");
1956 return 3;
1957 }
1958
1959 fBias.SetVoltMaxAbs(maxabsv);
1960 fBias.SetVoltMaxRel(maxrelv);
1961
1962 ostringstream str3, str4;
1963 str3 << "Effective maximum allowed absolute voltage: " << fBias.GetVoltMaxAbs() << "V";
1964 str4 << "Effective maximum difference w.r.t to G-APD reference: " << fBias.GetVoltMaxRel() << "V";
1965 T::Message(str3);
1966 T::Message(str4);
1967
1968 // --------------------------------------------------------------------------
1969
1970 PixelMap map;
1971 if (!map.Read(conf.Get<string>("pixel-map-file")))
1972 {
1973 T::Error("Reading reference voltages from "+conf.Get<string>("pixel-map-file")+" failed.");
1974 return 5;
1975 }
1976
1977 if (!fBias.SetNewGapdVoltage(map.Vgapd()))
1978 {
1979 T::Error("Setting reference voltages failed.");
1980 return 6;
1981 }
1982
1983 // --------------------------------------------------------------------------
1984
1985 fBias.Connect();
1986
1987 return -1;
1988 }
1989};
1990
1991// ------------------------------------------------------------------------
1992
1993#include "Main.h"
1994
1995template<class T, class S, class R>
1996int RunShell(Configuration &conf)
1997{
1998 return Main::execute<T, StateMachineBias<S, R>>(conf);
1999}
2000
2001void SetupConfiguration(Configuration &conf)
2002{
2003 po::options_description control("BIAS control options");
2004 control.add_options()
2005 ("no-dim,d", po_bool(), "Disable dim services")
2006 ("dev", var<string>("FTE00FOH"), "Device address of USB port to bias-power supply")
2007 ("quiet,q", po_bool(), "Disable printing contents of all received messages (except dynamic data) in clear text.")
2008 ("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.")
2009 ("ramp-step", var<uint16_t>(46), "Maximum step in DAC counts during ramping (Volt = DAC*90/4096)")
2010 ("update-interval", var<uint16_t>(3000), "Interval between two current requests in milliseconds")
2011 ("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")
2012 ("volt-max-abs", var<float>(75), "Absolte upper limit for the voltage (in Volts)")
2013 ("volt-max-rel", var<float>(2.5), "Relative upper limit for the voltage w.r.t. the G-APD reference voltage (in Volts)")
2014 ("pixel-map-file", var<string>("FACTmapV5a.txt"), "Pixel mapping file. Used here to get the default reference voltage.")
2015 ;
2016
2017 conf.AddOptions(control);
2018}
2019
2020/*
2021 Extract usage clause(s) [if any] for SYNOPSIS.
2022 Translators: "Usage" and "or" here are patterns (regular expressions) which
2023 are used to match the usage synopsis in program output. An example from cp
2024 (GNU coreutils) which contains both strings:
2025 Usage: cp [OPTION]... [-T] SOURCE DEST
2026 or: cp [OPTION]... SOURCE... DIRECTORY
2027 or: cp [OPTION]... -t DIRECTORY SOURCE...
2028 */
2029void PrintUsage()
2030{
2031 cout <<
2032 "The biasctrl program controls the bias-power supply boards.\n"
2033 "\n"
2034 "Note: At default the program is started without a command line (user) "
2035 "interface. In this case Actions/Commands are available via Dim "
2036 "exclusively.\n"
2037 "Use the -c option to start the program with a command line interface.\n"
2038 "\n"
2039 "In the running application:\n"
2040 "Use h or help to print a short help message about its usage.\n"
2041 "\n"
2042 "Usage: biasctrl [-c type] [OPTIONS]\n"
2043 " or: biasctrl [OPTIONS]\n";
2044 cout << endl;
2045}
2046
2047void PrintHelp()
2048{
2049 Main::PrintHelp<StateMachineBias<StateMachine,ConnectionBias>>();
2050
2051 /* Additional help text which is printed after the configuration
2052 options goes here */
2053
2054 /*
2055 cout << "bla bla bla" << endl << endl;
2056 cout << endl;
2057 cout << "Environment:" << endl;
2058 cout << "environment" << endl;
2059 cout << endl;
2060 cout << "Examples:" << endl;
2061 cout << "test exam" << endl;
2062 cout << endl;
2063 cout << "Files:" << endl;
2064 cout << "files" << endl;
2065 cout << endl;
2066 */
2067}
2068
2069int main(int argc, const char* argv[])
2070{
2071 Configuration conf(argv[0]);
2072 conf.SetPrintUsage(PrintUsage);
2073 Main::SetupConfiguration(conf);
2074 SetupConfiguration(conf);
2075
2076 if (!conf.DoParse(argc, argv, PrintHelp))
2077 return -1;
2078
2079 //try
2080 {
2081 // No console access at all
2082 if (!conf.Has("console"))
2083 {
2084 if (conf.Get<bool>("no-dim"))
2085 return RunShell<LocalStream, StateMachine, ConnectionBias>(conf);
2086 else
2087 return RunShell<LocalStream, StateMachineDim, ConnectionDimBias>(conf);
2088 }
2089 // Cosole access w/ and w/o Dim
2090 if (conf.Get<bool>("no-dim"))
2091 {
2092 if (conf.Get<int>("console")==0)
2093 return RunShell<LocalShell, StateMachine, ConnectionBias>(conf);
2094 else
2095 return RunShell<LocalConsole, StateMachine, ConnectionBias>(conf);
2096 }
2097 else
2098 {
2099 if (conf.Get<int>("console")==0)
2100 return RunShell<LocalShell, StateMachineDim, ConnectionDimBias>(conf);
2101 else
2102 return RunShell<LocalConsole, StateMachineDim, ConnectionDimBias>(conf);
2103 }
2104 }
2105 /*catch (std::exception& e)
2106 {
2107 cerr << "Exception: " << e.what() << endl;
2108 return -1;
2109 }*/
2110
2111 return 0;
2112}
Note: See TracBrowser for help on using the repository browser.