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

Last change on this file since 12064 was 12061, checked in by tbretz, 13 years ago
Added command descriptions.
File size: 63.0 KB
Line 
1#include <functional>
2
3#include <boost/bind.hpp>
4
5#include "Dim.h"
6#include "Event.h"
7#include "Shell.h"
8#include "StateMachineDim.h"
9#include "ConnectionUSB.h"
10#include "Configuration.h"
11#include "Console.h"
12#include "Converter.h"
13#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 const vector<char> cmd = GetCmd(kCmdChannelSet, ch, dac[ch]);
625 data.insert(data.end(), cmd.begin(), cmd.end());
626
627 fVoltCmd[ch] = dac[ch];
628 }
629
630 fSendCounter += kNumChannels;
631
632 PostMessage(data);
633 AsyncRead(ba::buffer(special ? fBuffer : fBufferRamp, kNumChannels*3),
634 special ? kResetChannels : kCmdChannelSet, fSendCounter);
635
636 if (special)
637 fWaitingForAnswer = true;
638 }
639
640 uint16_t RampOneStep(uint16_t ch)
641 {
642 if (fVoltRef[ch]>fVolt[ch])
643 return fVolt[ch]+fRampStep>fVoltRef[ch] ? fVoltRef[ch] : fVolt[ch]+fRampStep;
644
645 if (fVoltRef[ch]<fVolt[ch])
646 return fVolt[ch]-fRampStep<fVoltRef[ch] ? fVoltRef[ch] : fVolt[ch]-fRampStep;
647
648 return fVolt[ch];
649 }
650
651 bool RampOneStep()
652 {
653 if (fRampTime<0)
654 {
655 Warn("Ramping step time not yet set... ramping not started.");
656 return false;
657 }
658 if (fRampStep<0)
659 {
660 Warn("Ramping step not yet set... ramping not started.");
661 return false;
662 }
663
664 vector<uint16_t> dac(kNumChannels);
665
666 bool identical = true;
667 for (int ch=0; ch<kNumChannels; ch++)
668 {
669 dac[ch] = RampOneStep(ch);
670 if (dac[ch]!=fVolt[ch] && fPresent[ch/kNumChannelsPerBoard])
671 identical = false;
672 }
673
674 SetAllChannels(dac);
675
676 if (identical)
677 Info("Ramping: target values reached.");
678
679 return !identical;
680 }
681
682 void HandleRampTimer(const bs::error_code &error)
683 {
684 if (error==ba::error::basic_errors::operation_aborted)
685 {
686 Warn("Ramping aborted...");
687 fIsRamping = false;
688 return;
689 }
690
691 if (error)
692 {
693 ostringstream str;
694 str << "Ramping timer: " << error.message() << " (" << error << ")";// << endl;
695 Error(str);
696
697 PostClose(false);
698 return;
699 }
700
701 if (!is_open())
702 {
703 Warn("Ramping in progress, but disconnected.");
704 return;
705 }
706
707 if (!fIsRamping)
708 {
709 Error("Ramp handler called although no ramping in progress.");
710 return;
711 }
712
713 // Check whether the deadline has passed. We compare the deadline
714 // against the current time since a new asynchronous operation
715 // may have moved the deadline before this actor had a chance
716 // to run.
717 if (fRampTimer.expires_at() > ba::deadline_timer::traits_type::now())
718 return;
719
720 fIsRamping = RampOneStep();
721 }
722
723 void ScheduleRampStep()
724 {
725 fRampTimer.expires_from_now(boost::posix_time::milliseconds(fRampTime));
726 fRampTimer.async_wait(boost::bind(&ConnectionBias::HandleRampTimer, this, dummy::error));
727 }
728
729public:
730 ConnectionBias(ba::io_service& ioservice, MessageImp &imp) : ConnectionUSB(ioservice, imp()),
731 fSyncTimer(ioservice),
732 fRampTimer(ioservice),
733 fUpdateTimer(ioservice),
734 fBuffer(3*kNumChannels),
735 fBufferRamp(3*kNumChannels),
736 fBufferUpdate(3*kNumChannels),
737 fIsVerbose(false),
738 fVoltCmd(kNumChannels),
739 fVoltGapd(kNumChannels),
740 //fRefCurrent(kNumChannels),
741 fPresent(kNumBoards),
742 fRampStep(-1),
743 fRampTime(-1),
744 fUpdateTime(3000),
745 fSyncTime(333),
746 fIsRamping(false),
747 fWaitingForAnswer(false),
748 fCounter(8),
749 fVolt(kNumChannels),
750 fVoltRef(kNumChannels),
751 fCurrent(kNumChannels)
752 {
753 SetLogStream(&imp);
754 }
755
756 void OverCurrentReset()
757 {
758 if (fWaitingForAnswer)
759 {
760 Error("Answer on last command not yet received.");
761 return;
762 }
763
764 if (fIsRamping)
765 {
766 Warn("OverCurrentReset - Ramping in progres.");
767 RampStop();
768 }
769
770 vector<uint16_t> dac(kNumChannels);
771
772 for (int ch=0; ch<kNumChannels; ch++)
773 dac[ch] = fCurrent[ch]<0 ? 0 : fVolt[ch];
774
775 SetAllChannels(dac, true);
776 }
777
778 void ReadAllChannels(bool special = false)
779 {
780 if (!special && fWaitingForAnswer)
781 {
782 Error("Answer on last command not yet received.");
783 return;
784 }
785
786 vector<char> data;
787 data.reserve(kNumChannels*3);
788
789 for (int ch=0; ch<kNumChannels; ch++)
790 {
791 const vector<char> cmd = GetCmd(kCmdRead, ch);
792 data.insert(data.end(), cmd.begin(), cmd.end());
793 }
794
795 fSendCounter += kNumChannels;
796
797 PostMessage(data);
798 AsyncRead(ba::buffer(special ? fBufferUpdate : fBuffer, kNumChannels*3),
799 special ? kUpdate : kCmdRead, fSendCounter);
800
801 if (!special)
802 fWaitingForAnswer = true;
803 }
804
805 // --------------------------------------------------------------------
806
807 bool ChannelSetDac(uint16_t ch, uint16_t dac)
808 {
809 if (!CheckChDac("ChannelSetDac", dac, ch))
810 return false;
811
812 fVoltRef[ch] = dac;
813
814 if (!fIsRamping)
815 fIsRamping = RampOneStep();
816
817 return true;
818 }
819
820 bool ChannelSetVolt(uint16_t ch, double volt)
821 {
822 if (volt<0 || volt>90)
823 {
824 Error("ChannelSetVolt - Voltage out of range [0V,90V].");
825 return false;
826 }
827
828 return ChannelSetDac(ch, volt*4096/90.);
829 }
830/*
831 bool GlobalSetDac(uint16_t dac)
832 {
833 if (!CheckChDac("GlobalSetDac", dac))
834 return false;
835
836 for (size_t ch=0; ch<kNumChannels; ch++)
837 fVoltRef[ch] = dac;
838
839 if (!fIsRamping)
840 fIsRamping = RampOneStep();
841
842 return true;
843 }
844
845 bool GlobalSetVolt(float volt)
846 {
847 if (volt<0 || volt>90)
848 {
849 Error("GlobalSetVolt - Voltage out of range [0V,90V].");
850 return false;
851 }
852
853 return GlobalSetDac(volt*4096/90);
854 }
855*/
856 bool AddDac(const vector<int16_t> &dac)
857 {
858 if (dac.size()!=kNumChannels)
859 {
860 Error("AddDac - Wrong size of array.");
861 return false;
862 }
863
864 for (size_t ch=0; ch<kNumChannels; ch++)
865 {
866 if (fVoltRef[ch]+dac[ch]>kMaxDac)
867 {
868 Error("AddDac - New voltage reference out of range.");
869 return false;
870 }
871
872 if (fVoltRef[ch]+dac[ch]<0)
873 fVoltRef[ch] = 0;
874 else
875 fVoltRef[ch] += dac[ch];
876 }
877
878 if (!fIsRamping)
879 fIsRamping = RampOneStep();
880
881 return true;
882 }
883
884 bool AddVolt(const vector<float> &offset)
885 {
886 vector<int16_t> dac(offset.size());
887
888 for (size_t ch=0; ch<offset.size(); ch++)
889 {
890 if (offset[ch]<-90 || offset[ch]>90)
891 {
892 Error("AddVolt - Offset out of range [-90V,90V].");
893 return false;
894 }
895 dac[ch] = offset[ch]*4096/90;
896 }
897
898 return AddDac(dac);
899 }
900
901 bool GlobalAddDac(int16_t offset)
902 {
903 return AddDac(vector<int16_t>(kNumChannels, offset));
904 }
905
906 bool GlobalAddVolt(float offset)
907 {
908 return AddVolt(vector<float>(kNumChannels, offset));
909 }
910
911 bool SetDac(const vector<int16_t> &dac)
912 {
913 if (dac.size()!=kNumChannels)
914 {
915 Error("SetDac - Wrong size of array.");
916 return false;
917 }
918
919 for (size_t ch=0; ch<kNumChannels; ch++)
920 {
921 if (!CheckChDac("SetDac", dac[ch]))
922 return false;
923
924 fVoltRef[ch] = dac[ch];
925 }
926
927 if (!fIsRamping)
928 fIsRamping = RampOneStep();
929
930 return true;
931 }
932
933 bool SetVolt(const vector<float> &volt)
934 {
935 vector<int16_t> dac(volt.size());
936
937 for (size_t ch=0; ch<volt.size(); ch++)
938 {
939 if (volt[ch]<0 || volt[ch]>90)
940 {
941 Error("SetVolt - Voltage out of range [0V,90V].");
942 return false;
943 }
944 dac[ch] = volt[ch]*4096/90;
945 }
946
947 return SetDac(dac);
948 }
949
950 bool GlobalSetDac(int16_t dac)
951 {
952 return SetDac(vector<int16_t>(kNumChannels, dac));
953 }
954
955 bool GlobalSetVolt(float volt)
956 {
957 return SetVolt(vector<float>(kNumChannels, volt));
958 }
959
960
961 // --------------------------------------------------------------------
962
963 bool SetGapdVoltage(float offset)
964 {
965 if (offset<-90 || offset>90)
966 {
967 Error("SetGapdVoltage - Offset out of range [-90V,90V].");
968 return false;
969 }
970
971 const int16_t dac = offset*4096/90;
972
973 for (size_t ch=0; ch<kNumChannels; ch++)
974 if (fVoltGapd[ch]+dac>kMaxDac)
975 {
976 Error("SetGapdVoltage - New voltage reference out of range.");
977 return false;
978 }
979
980 for (size_t ch=0; ch<kNumChannels; ch++)
981 fVoltRef[ch] = fVoltGapd[ch]+dac<0 ? 0 : fVoltGapd[ch]+dac;
982
983 if (!fIsRamping)
984 fIsRamping = RampOneStep();
985
986 return true;
987 }
988
989 bool SetGapdReferenceCh(uint16_t ch)
990 {
991 if (!CheckChDac("SetGapdReferenceCh", fVoltGapd[ch], ch))
992 return false;
993
994 fVoltRef[ch] = fVoltGapd[ch];
995
996 if (!fIsRamping)
997 fIsRamping = RampOneStep();
998
999 return true;
1000 }
1001
1002
1003 void SetZero()
1004 {
1005 for (size_t ch=0; ch<kNumChannels; ch++)
1006 fVoltRef[ch] = 0;
1007
1008 if (!fIsRamping)
1009 fIsRamping = RampOneStep();
1010 }
1011
1012 bool SetNewGapdVoltage(const vector<float> &volt)
1013 {
1014 if (volt.size()!=kNumChannels)
1015 {
1016 ostringstream out;
1017 out << "SetNewGapdVoltage - Given vector has " << volt.size() << " elements - expected " << kNumChannels << endl;
1018 Error(out);
1019 return false;
1020 }
1021
1022 for (size_t i=0; i<kNumChannels; i++)
1023 fVoltGapd[i] = volt[i]*4096/90;
1024
1025 return true;
1026 }
1027
1028 // --------------------------------------------------------------------
1029
1030 void RampStop()
1031 {
1032 fRampTimer.cancel();
1033 fIsRamping = false;
1034
1035 Message("Ramping stopped.");
1036 }
1037
1038 void RampStart()
1039 {
1040 if (fIsRamping)
1041 {
1042 Warn("RampStart - Ramping in progress... ignored.");
1043 return;
1044 }
1045
1046 fIsRamping = RampOneStep();
1047 }
1048
1049 void SetRampTime(uint16_t val)
1050 {
1051 fRampTime = val;
1052 }
1053
1054 void SetRampStep(uint16_t val)
1055 {
1056 fRampStep = val;
1057 }
1058
1059 uint16_t GetRampStepVolt() const
1060 {
1061 return fRampStep*90./4096;
1062 }
1063
1064 bool IsRamping() const { return fIsRamping; }
1065
1066 // -------------------------------------------------------------------
1067
1068 void ExpertReset(bool expert_mode=true)
1069 {
1070 if (fWaitingForAnswer)
1071 {
1072 Error("Answer on last command not yet received.");
1073 return;
1074 }
1075
1076 if (expert_mode)
1077 Warn("EXPERT MODE: Sending reset.");
1078
1079 PostMessage(GetCmd(kCmdReset));
1080 AsyncRead(ba::buffer(fBuffer, 3), kCmdReset, ++fSendCounter);
1081 fWaitingForAnswer = true;
1082 }
1083
1084
1085 bool ExpertChannelSetDac(uint16_t ch, uint16_t dac)
1086 {
1087 if (fWaitingForAnswer)
1088 {
1089 Error("Answer on last command not yet received.");
1090 return false;
1091 }
1092
1093 if (!CheckChDac("ExpertChannelSetDac", dac, ch))
1094 return false;
1095
1096 fVoltCmd[ch] = dac;
1097
1098 ostringstream msg;
1099 msg << "EXPERT MODE: Sending 'ChannelSet' (set ch " << ch << " to DAC=" << dac << ")";
1100 Warn(msg);
1101
1102 PostMessage(GetCmd(kCmdChannelSet, ch, dac));
1103 AsyncRead(ba::buffer(fBuffer, 3), kExpertChannelSet|(ch<<8), ++fSendCounter);
1104 fWaitingForAnswer = true;
1105
1106 return true;
1107 }
1108
1109 bool ExpertChannelSetVolt(uint16_t ch, double volt)
1110 {
1111 return ExpertChannelSetDac(ch, volt*4096/90.);
1112 }
1113
1114 bool ExpertGlobalSetDac(uint16_t dac)
1115 {
1116 if (fWaitingForAnswer)
1117 {
1118 Error("Answer on last command not yet received.");
1119 return false;
1120 }
1121
1122 if (!CheckChDac("ExpertGlobalSetDac", dac))
1123 return false;
1124
1125 if (fGlobalVoltCmd>=0)
1126 {
1127 Error("ExpertGlobalSetDac - Still waiting for previous global-set's answer.");
1128 return false;
1129 }
1130
1131 fGlobalVoltCmd = dac;
1132
1133 ostringstream msg;
1134 msg << "EXPERT MODE: Sending 'GlobalSet' (DAC=" << dac << ")";
1135 Warn(msg);
1136
1137 PostMessage(GetCmd(kCmdGlobalSet, 0, dac));
1138 AsyncRead(ba::buffer(fBuffer, 3), kCmdGlobalSet, ++fSendCounter);
1139 fWaitingForAnswer = true;
1140
1141 return true;
1142 }
1143
1144 bool ExpertGlobalSetVolt(float volt)
1145 {
1146 return ExpertGlobalSetDac(volt*4096/90);
1147 }
1148
1149 // --------------------------------------------------------------------
1150
1151 void SetVerbose(bool b)
1152 {
1153 fIsVerbose = b;
1154 }
1155
1156 void PrintInfo()
1157 {
1158 Out() << endl << kBold << dec << '\n';
1159 Out() << "fWrapCounter = " << fWrapCounter << '\n';
1160 Out() << "fSendCounter = " << fSendCounter%8 << " (" << fSendCounter << ")" << '\n';
1161 Out() << "fIsInitializing = " << fIsInitializing << '\n';
1162 Out() << "fIsRamping = " << fIsRamping << '\n';
1163 Out() << "Answer counter:" << '\n';
1164 Out() << " - Synchronization: " << fCounter[0] << '\n';
1165 Out() << " - Reset: " << fCounter[1] << '\n';
1166 Out() << " - Request update: " << fCounter[2] << '\n';
1167 Out() << " - Ramp step: " << fCounter[3] << '\n';
1168 Out() << " - Read: " << fCounter[4] << '\n';
1169 Out() << " - Reset channels: " << fCounter[5] << '\n';
1170 Out() << " - Global set: " << fCounter[7] << '\n';
1171 Out() << " - Channel set: " << fCounter[6] << '\n' << endl;
1172 }
1173
1174 void PrintLineA(int b, int ch)
1175 {
1176 Out() << setw(2) << b << "|";
1177
1178 for (int c=ch; c<ch+8; c++)
1179 {
1180 const int id = c+kNumChannelsPerBoard*b;
1181 Out() << (fCurrent[id]<0?kRed:kGreen);
1182 Out() << " " << setw(7) << abs(fCurrent[id])*5000/4096.;
1183 }
1184 Out() << endl;
1185
1186 }
1187
1188 void PrintA()
1189 {
1190 Out() << dec << setprecision(2) << fixed << setfill(' ');
1191 for (int b=0; b<kNumBoards; b++)
1192 {
1193 if (!fPresent[b])
1194 {
1195 Out() << setw(2) << b << "-" << endl;
1196 continue;
1197 }
1198
1199 PrintLineA(b, 0);
1200 PrintLineA(b, 8);
1201 PrintLineA(b, 16);
1202 PrintLineA(b, 24);
1203 }
1204 }
1205
1206 void PrintLineV(int b, int ch)
1207 {
1208 Out() << setw(2) << b << "|";
1209
1210 for (int c=ch; c<ch+4; c++)
1211 {
1212 const int id = c+kNumChannelsPerBoard*b;
1213 Out() << " ";
1214 Out() << (fVolt[id]==fVoltRef[id]?kGreen:kRed);
1215 Out() << setw(5) << fVolt[id]*90/4096. << '/';
1216 Out() << setw(5) << fVoltRef[id]*90/4096.;
1217 }
1218 Out() << endl;
1219 }
1220
1221 void PrintV()
1222 {
1223 Out() << dec << setprecision(2) << fixed << setfill(' ');
1224 for (int b=0; b<kNumBoards; b++)
1225 {
1226 if (!fPresent[b])
1227 {
1228 Out() << setw(2) << b << "-" << endl;
1229 continue;
1230 }
1231
1232 PrintLineV(b, 0);
1233 PrintLineV(b, 4);
1234 PrintLineV(b, 8);
1235 PrintLineV(b, 12);
1236 PrintLineV(b, 16);
1237 PrintLineV(b, 20);
1238 PrintLineV(b, 24);
1239 PrintLineV(b, 28);
1240 }
1241 }
1242
1243 void PrintLineGapd(int b, int ch)
1244 {
1245 Out() << setw(2) << b << "|";
1246
1247 for (int c=ch; c<ch+8; c++)
1248 {
1249 const int id = c+kNumChannelsPerBoard*b;
1250 Out() << " " << setw(5) << fVoltGapd[id]*90/4096.;
1251 }
1252 Out() << endl;
1253 }
1254
1255 void PrintGapd()
1256 {
1257 Out() << dec << setprecision(2) << fixed << setfill(' ');
1258 for (int b=0; b<kNumBoards; b++)
1259 {
1260 if (!fPresent[b])
1261 {
1262 Out() << setw(2) << b << "-" << endl;
1263 continue;
1264 }
1265
1266 PrintLineGapd(b, 0);
1267 PrintLineGapd(b, 8);
1268 PrintLineGapd(b, 16);
1269 PrintLineGapd(b, 24);
1270 }
1271 }
1272
1273 // -------------------------------------------------------------------
1274
1275 void SetUpdateInterval(uint16_t val)
1276 {
1277 fUpdateTime = val;
1278 }
1279
1280 void SetSyncDelay(uint16_t val)
1281 {
1282 fSyncTime = val;
1283 }
1284
1285 void SetVoltMaxAbs(float max)
1286 {
1287 fVoltMaxAbs = max*4096/90;
1288 if (fVoltMaxAbs>4095)
1289 fVoltMaxAbs = 4095;
1290 if (max<0)
1291 fVoltMaxAbs = 0;
1292 }
1293
1294 void SetVoltMaxRel(float max)
1295 {
1296 fVoltMaxRel = max*4096/90;
1297 if (fVoltMaxRel>4095)
1298 fVoltMaxRel = 4095;
1299 if (max<0)
1300 fVoltMaxRel = 0;
1301 }
1302
1303 uint16_t GetVoltMaxAbs() const
1304 {
1305 return fVoltMaxAbs * 90./4096;
1306 }
1307
1308 uint16_t GetVoltMaxRel() const
1309 {
1310 return fVoltMaxRel * 90./4096;
1311 }
1312
1313/*
1314 void AdaptVoltages()
1315 {
1316 // Correct voltages according to current
1317 for (int i=0; i<kNumChannels; i++)
1318 {
1319 if (fVoltRef[i]==0 || fCurrent[i]<0 || fRefCurrent[i]<0)
1320 continue;
1321
1322 // Calculate difference and convert ADC units to Amp
1323 // const double diffcur = (fRefCurrent[i]-fCurrent[i])*5000/4096
1324 //const int32_t diffcur = int32_t(fRefCurrent[i]-fCurrent[i])*5000;
1325
1326 // Calculate voltage difference
1327 // #define RESISTOR 1000 // Ohm
1328 //const double diffvolt = diffcur*RESISTOR/1e6;
1329
1330 // Calculate new vlaue by onverting voltage difference to DAC units
1331 //const int32_t dac = fRefVolt[i] + diffvolt*4096/90.0;
1332 SetVoltage(i, fRefVolt[i] + (fRefCurrent[i]-fCurrent[i])/18);
1333 }
1334 }
1335
1336 void SetReferenceCurrent()
1337 {
1338 fRefCurrent = fCurrent;
1339 }
1340 */
1341
1342 States_t GetStatus()
1343 {
1344 if (!IsConnected())
1345 return BIAS::kDisconnected;
1346
1347 if (IsConnecting())
1348 return BIAS::kConnecting;
1349
1350 if (fIsInitializing)
1351 return BIAS::kInitializing;
1352
1353 if (fIsRamping)
1354 return BIAS::kRamping;
1355
1356 for (int ch=0; ch<kNumChannels; ch++)
1357 if (fPresent[ch/kNumChannelsPerBoard] && fCurrent[ch]<0)
1358 return BIAS::kOverCurrent;
1359
1360 for (int ch=0; ch<kNumChannels; ch++)
1361 if (fPresent[ch/kNumChannelsPerBoard] && fVolt[ch]!=fVoltRef[ch])
1362 return BIAS::kConnected;
1363
1364 return BIAS::kAtReference;
1365 }
1366};
1367
1368// ------------------------------------------------------------------------
1369
1370#include "DimDescriptionService.h"
1371
1372class ConnectionDimBias : public ConnectionBias
1373{
1374private:
1375
1376 DimDescribedService fDimCurrent;
1377 DimDescribedService fDimVoltage;
1378
1379 void UpdateA()
1380 {
1381 fDimCurrent.Update(fCurrent);
1382 }
1383
1384 void UpdateV()
1385 {
1386 vector<uint16_t> vec;
1387 vec.insert(vec.end(), fVolt.begin(), fVolt.end());
1388 vec.insert(vec.end(), fVoltRef.begin(), fVoltRef.end());
1389 fDimVoltage.Update(vec);
1390 }
1391
1392
1393public:
1394 ConnectionDimBias(ba::io_service& ioservice, MessageImp &imp) :
1395 ConnectionBias(ioservice, imp),
1396 fDimCurrent("BIAS_CONTROL/CURRENT", "S:416", ""),
1397 fDimVoltage("BIAS_CONTROL/VOLTAGE", "S:416;S:416", "")
1398 {
1399 }
1400
1401 // 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
1402};
1403
1404// ------------------------------------------------------------------------
1405
1406template <class T, class S>
1407class StateMachineBias : public T, public ba::io_service, public ba::io_service::work
1408{
1409 int Wrap(boost::function<void()> f)
1410 {
1411 f();
1412 return T::GetCurrentState();
1413 }
1414
1415 function<int(const EventImp &)> Wrapper(function<void()> func)
1416 {
1417 return bind(&StateMachineBias::Wrap, this, func);
1418 }
1419
1420 bool CheckEventSize(size_t has, const char *name, size_t size)
1421 {
1422 if (has==size)
1423 return true;
1424
1425 ostringstream msg;
1426 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
1427 T::Fatal(msg);
1428 return false;
1429 }
1430
1431private:
1432 S fBias;
1433
1434 bool fExpertMode;
1435
1436 // --------------------------------------------------------------------
1437
1438 int SetGapdVoltage(const EventImp &evt)
1439 {
1440 if (!CheckEventSize(evt.GetSize(), "SetGapdVoltage", 4))
1441 return false;
1442
1443 fBias.SetGapdVoltage(evt.GetFloat());
1444
1445 return T::GetCurrentState();
1446 }
1447
1448 // --------------------------------------------------------------------
1449
1450 int SetGlobalVolt(const EventImp &evt)
1451 {
1452 if (!CheckEventSize(evt.GetSize(), "SetGlobalVolt", 4))
1453 return false;
1454
1455 fBias.GlobalSetVolt(evt.GetFloat());
1456
1457 return T::GetCurrentState();
1458 }
1459
1460 int SetGlobalDac(const EventImp &evt)
1461 {
1462 if (!CheckEventSize(evt.GetSize(), "SetGlobalDac", 2))
1463 return false;
1464
1465 fBias.GlobalSetDac(evt.GetUShort());
1466
1467 return T::GetCurrentState();
1468 }
1469
1470 int IncGlobalVolt(const EventImp &evt)
1471 {
1472 if (!CheckEventSize(evt.GetSize(), "IncGlobalVolt", 4))
1473 return false;
1474
1475 fBias.GlobalAddVolt(evt.GetFloat());
1476
1477 return T::GetCurrentState();
1478 }
1479
1480 int IncGlobalDac(const EventImp &evt)
1481 {
1482 if (!CheckEventSize(evt.GetSize(), "IncGlobalDac", 2))
1483 return false;
1484
1485 fBias.GlobalAddDac(evt.GetShort());
1486
1487 return T::GetCurrentState();
1488 }
1489
1490 int DecGlobalVolt(const EventImp &evt)
1491 {
1492 if (!CheckEventSize(evt.GetSize(), "DecGlobalVolt", 4))
1493 return false;
1494
1495 fBias.GlobalAddVolt(-evt.GetFloat());
1496
1497 return T::GetCurrentState();
1498 }
1499
1500 int DecGlobalDac(const EventImp &evt)
1501 {
1502 if (!CheckEventSize(evt.GetSize(), "DecGlobalDac", 2))
1503 return false;
1504
1505 fBias.GlobalAddDac(-evt.GetShort());
1506
1507 return T::GetCurrentState();
1508 }
1509
1510 int SetChannelVolt(const EventImp &evt)
1511 {
1512 if (!CheckEventSize(evt.GetSize(), "SetChannelVolt", 6))
1513 return false;
1514
1515 fBias.ChannelSetVolt(evt.GetUShort(), evt.Get<float>(2));
1516
1517 return T::GetCurrentState();
1518 }
1519
1520 int SetChannelDac(const EventImp &evt)
1521 {
1522 if (!CheckEventSize(evt.GetSize(), "SetChannelDac", 4))
1523 return false;
1524
1525 fBias.ChannelSetDac(evt.Get<uint16_t>(), evt.Get<uint16_t>(2));
1526
1527 return T::GetCurrentState();
1528 }
1529
1530 int SetGapdReferenceCh(const EventImp &evt)
1531 {
1532 if (!CheckEventSize(evt.GetSize(), "SetGapdReferenceCh", 2))
1533 return false;
1534
1535 fBias.SetGapdReferenceCh(evt.GetUShort());
1536
1537 return T::GetCurrentState();
1538 }
1539
1540
1541 // --------------------------------------------------------------------
1542
1543 int AddReferenceDac(const EventImp &evt)
1544 {
1545 if (!CheckEventSize(evt.GetSize(), "AddReferenceDac", 2*kNumChannels))
1546 return false;
1547
1548 const int16_t *ptr = evt.Ptr<int16_t>();
1549 fBias.AddDac(vector<int16_t>(ptr, ptr+416));
1550
1551 return T::GetCurrentState();
1552 }
1553
1554 int AddReferenceVolt(const EventImp &evt)
1555 {
1556 if (!CheckEventSize(evt.GetSize(), "AddReferenceVolt", 4*kNumChannels))
1557 return false;
1558
1559 const float_t *ptr = evt.Ptr<float>();
1560 fBias.AddVolt(vector<float>(ptr, ptr+416));
1561
1562 return T::GetCurrentState();
1563 }
1564
1565 int SetReferenceDac(const EventImp &evt)
1566 {
1567 if (!CheckEventSize(evt.GetSize(), "SetReferenceDac", 2*kNumChannels))
1568 return false;
1569
1570 const int16_t *ptr = evt.Ptr<int16_t>();
1571 fBias.SetDac(vector<int16_t>(ptr, ptr+416));
1572
1573 return T::GetCurrentState();
1574 }
1575
1576 int SetReferenceVolt(const EventImp &evt)
1577 {
1578 if (!CheckEventSize(evt.GetSize(), "SetReferenceVolt", 4*kNumChannels))
1579 return false;
1580
1581 const float_t *ptr = evt.Ptr<float>();
1582 fBias.SetVolt(vector<float>(ptr, ptr+416));
1583
1584 return T::GetCurrentState();
1585 }
1586
1587 // --------------------------------------------------------------------
1588
1589 int ExpertSetGlobalVolt(const EventImp &evt)
1590 {
1591 if (!CheckEventSize(evt.GetSize(), "ExpertSetGlobalVolt", 4))
1592 return false;
1593
1594 fBias.ExpertGlobalSetVolt(evt.GetFloat());
1595
1596 return T::GetCurrentState();
1597 }
1598
1599 int ExpertSetGlobalDac(const EventImp &evt)
1600 {
1601 if (!CheckEventSize(evt.GetSize(), "ExpertSetGlobalDac", 2))
1602 return false;
1603
1604 fBias.ExpertGlobalSetDac(evt.GetUShort());
1605
1606 return T::GetCurrentState();
1607 }
1608
1609 int ExpertSetChannelVolt(const EventImp &evt)
1610 {
1611 if (!CheckEventSize(evt.GetSize(), "ExpertSetChannelVolt", 6))
1612 return false;
1613
1614 fBias.ExpertChannelSetVolt(evt.GetUShort(), evt.Get<float>(2));
1615
1616 return T::GetCurrentState();
1617 }
1618
1619 int ExpertSetChannelDac(const EventImp &evt)
1620 {
1621 if (!CheckEventSize(evt.GetSize(), "ExpertSetChannelDac", 4))
1622 return false;
1623
1624 fBias.ExpertChannelSetDac(evt.Get<uint16_t>(), evt.Get<uint16_t>(2));
1625
1626 return T::GetCurrentState();
1627 }
1628
1629 // --------------------------------------------------------------------
1630
1631 int Disconnect()
1632 {
1633 // Close all connections
1634 fBias.PostClose(false);
1635
1636 /*
1637 // Now wait until all connection have been closed and
1638 // all pending handlers have been processed
1639 poll();
1640 */
1641
1642 return T::GetCurrentState();
1643 }
1644
1645 int Reconnect(const EventImp &evt)
1646 {
1647 // Close all connections to supress the warning in SetEndpoint
1648 fBias.PostClose(false);
1649
1650 // Now wait until all connection have been closed and
1651 // all pending handlers have been processed
1652 poll();
1653
1654 if (evt.GetBool())
1655 fBias.SetEndpoint(evt.GetString());
1656
1657 // Now we can reopen the connection
1658 fBias.PostClose(true);
1659
1660 return T::GetCurrentState();
1661 }
1662
1663 int SetVerbosity(const EventImp &evt)
1664 {
1665 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
1666 return T::kSM_FatalError;
1667
1668 fBias.SetVerbose(evt.GetBool());
1669
1670 return T::GetCurrentState();
1671 }
1672
1673 int SetExpertMode(const EventImp &evt)
1674 {
1675 if (!CheckEventSize(evt.GetSize(), "SetExpertMode", 1))
1676 return T::kSM_FatalError;
1677
1678 fExpertMode = evt.GetBool();
1679
1680 if (fExpertMode)
1681 T::Warn("Expert commands enabled -- please ensure that you EXACTLY know what you do. These commands can destroy the system.");
1682
1683 return T::GetCurrentState();
1684 }
1685
1686 int Execute()
1687 {
1688 // Dispatch (execute) at most one handler from the queue. In contrary
1689 // to run_one(), it doesn't wait until a handler is available
1690 // which can be dispatched, so poll_one() might return with 0
1691 // handlers dispatched. The handlers are always dispatched/executed
1692 // synchronously, i.e. within the call to poll_one()
1693 poll_one();
1694
1695 return fExpertMode && fBias.GetStatus()>=kConnected ?
1696 kExpertMode : fBias.GetStatus();
1697 }
1698
1699public:
1700 StateMachineBias(ostream &out=cout) :
1701 T(out, "BIAS_CONTROL"), ba::io_service::work(static_cast<ba::io_service&>(*this)),
1702 fBias(*this, *this), fExpertMode(false)
1703 {
1704 // ba::io_service::work is a kind of keep_alive for the loop.
1705 // It prevents the io_service to go to stopped state, which
1706 // would prevent any consecutive calls to run()
1707 // or poll() to do nothing. reset() could also revoke to the
1708 // previous state but this might introduce some overhead of
1709 // deletion and creation of threads and more.
1710
1711 // State names
1712 T::AddStateName(kDisconnected, "Disconnected",
1713 "Bias-power supply not connected via USB.");
1714
1715 T::AddStateName(kConnecting, "Connecting",
1716 "Trying to establish USB connection to bias-power supply.");
1717
1718 T::AddStateName(kInitializing, "Initializing",
1719 "USB connection to bias-power supply established, synchronizing USB stream.");
1720
1721 T::AddStateName(kConnected, "Connected",
1722 "USB connection to bias-power supply established.");
1723
1724 T::AddStateName(kAtReference, "Referenced",
1725 "Internal reference voltage matches last sent voltage.");
1726
1727 T::AddStateName(kOverCurrent, "OverCurrent",
1728 "At least one channel is in over current state.");
1729
1730 T::AddStateName(kExpertMode, "ExpertMode",
1731 "Special (risky!) mode to directly send command to the bias-power supply.");
1732
1733 T::AddStateName(kRamping, "Ramping",
1734 "Voltage ramping in progress.");
1735
1736 // Verbosity commands
1737 T::AddEvent("SET_VERBOSE", "B")
1738 (bind(&StateMachineBias::SetVerbosity, this, placeholders::_1))
1739 ("set verbosity state"
1740 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
1741
1742 // Conenction commands
1743 T::AddEvent("DISCONNECT", kConnected, kAtReference)
1744 (bind(&StateMachineBias::Disconnect, this))
1745 ("disconnect from USB");
1746
1747 T::AddEvent("RECONNECT", "O", kDisconnected, kConnected, kAtReference)
1748 (bind(&StateMachineBias::Reconnect, this, placeholders::_1))
1749 ("(Re)connect USB connection to Bias power supply, a new address can be given"
1750 "|tty[string]:new USB address");
1751
1752
1753
1754 T::AddEvent("REQUEST_STATUS", kConnected, kAtReference, kOverCurrent)
1755 (Wrapper(bind(&ConnectionBias::ReadAllChannels, &fBias, false)))
1756 ("Asynchronously request the status (current) of all channels.");
1757
1758 T::AddEvent("RESET_OVER_CURRENT_STATUS", kOverCurrent)
1759 (Wrapper(bind(&ConnectionBias::OverCurrentReset, &fBias)))
1760 ("Set all channels in over current state to 0V and send a system reset to reset the over current flags.");
1761
1762
1763
1764 T::AddEvent("SET_GLOBAL_VOLTAGE", "F:1", kConnected, kAtReference, kOverCurrent)
1765 (bind(&StateMachineBias::SetGlobalVolt, this, placeholders::_1))
1766 ("Set all channels to a new reference voltage. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
1767 "|voltage[V]:Global target voltage in volts (will be converted to DAC units)");
1768
1769 T::AddEvent("SET_GLOBAL_DAC", "S:1", kConnected, kAtReference, kOverCurrent)
1770 (bind(&StateMachineBias::SetGlobalDac, this, placeholders::_1))
1771 ("Set all channels to a new DAC reference. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
1772 "|voltage[dac]:Global target voltage as DAC counts.");
1773
1774 T::AddEvent("INCREASE_GLOBAL_VOLTAGE", "F:1", kConnected, kAtReference, kOverCurrent)
1775 (bind(&StateMachineBias::IncGlobalVolt, this, placeholders::_1))
1776 ("Set all channels to a new reference voltage. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
1777 "|offset[V]:Offset to be added to all channels (will be converted to DAC counts)");
1778
1779 T::AddEvent("INCREASE_GLOBAL_DAC", "S:1", kConnected, kAtReference, kOverCurrent)
1780 (bind(&StateMachineBias::IncGlobalDac, this, placeholders::_1))
1781 ("Set all channels to a new DAC reference. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
1782 "|offset[dac]:Offset to be added to all channels as DAC counts");
1783
1784 T::AddEvent("DECREASE_GLOBAL_VOLTAGE", "F:1", kConnected, kAtReference, kOverCurrent)
1785 (bind(&StateMachineBias::DecGlobalVolt, this, placeholders::_1))
1786 ("Set all channels to a new reference voltage. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
1787 "|offset[V]:Offset to be subtracted from all channels (will be converted to DAC counts)");
1788
1789 T::AddEvent("DECREASE_GLOBAL_DAC", "S:1", kConnected, kAtReference, kOverCurrent)
1790 (bind(&StateMachineBias::DecGlobalDac, this, placeholders::_1))
1791 ("Set all channels to a new DAC reference. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
1792 "|offset[dac]:Offset to be subtracted from all channels as DAC counts");
1793
1794 T::AddEvent("SET_CHANNEL_VOLTAGE", "S:1;F:1", kConnected, kAtReference, kOverCurrent)
1795 (bind(&StateMachineBias::SetChannelVolt, this, placeholders::_1))
1796 ("Set a single channel to a new reference voltage. Starts ramping if necessary."
1797 "|channel[short]:Channel for which to set the target voltage [0-416]"
1798 "|voltage[V]:Target voltage in volts for the given channel (will be converted to DAC units)");
1799
1800 T::AddEvent("SET_CHANNEL_DAC", "S:1;S:1", kConnected, kAtReference, kOverCurrent)
1801 (bind(&StateMachineBias::SetChannelDac, this, placeholders::_1))
1802 ("Set a single channel to a new DAC reference value. Starts ramping if necessary."
1803 "|channel[short]:Channel for which to set the target voltage [0-416]"
1804 "|voltage[dac]:Target voltage in DAC units for the given channel");
1805
1806 T::AddEvent("SET_GLOBAL_GAPD_REFERENCE_VOLTAGE", kConnected, kAtReference, kOverCurrent)
1807 (Wrapper(bind(&ConnectionBias::SetGapdVoltage, &fBias, 0.)))
1808 ("Set all channels to their G-APD reference voltage. Starts ramping if necessary.");
1809
1810 T::AddEvent("SET_CHANNEL_GAPD_REFERENCE_VOLTAGE", "S:1", kConnected, kAtReference, kOverCurrent)
1811 (bind(&StateMachineBias::SetGapdReferenceCh, this, placeholders::_1))
1812 ("Set a single channel channels to its G-APD reference voltage. Starts ramping if necessary."
1813 "|channel[short]:Channel for which to set the target voltage [0-416]");
1814
1815 T::AddEvent("SET_GAPD_REFERENCE_OFFSET", "F:1", kConnected, kAtReference, kOverCurrent)
1816 (bind(&StateMachineBias::SetGapdVoltage, this, placeholders::_1))
1817 ("Set all channels to their G-APD reference voltage plus the given offset. Starts ramping if necessary."
1818 "|offset[V]:Offset to be added to teh G-APD reference voltage globally");
1819
1820 T::AddEvent("SET_ZERO_VOLTAGE", kConnected, kAtReference, kOverCurrent)
1821 (Wrapper(bind(&ConnectionBias::SetZero, &fBias)))
1822 ("Set all channels to a zero reference voltage. Starts ramping if necessary.");
1823
1824 T::AddEvent("SET_REFERENCE_VOLTAGES", "F:416", kConnected, kAtReference, kOverCurrent)
1825 (bind(&StateMachineBias::SetReferenceVolt, this, placeholders::_1))
1826 ("Set all channels to the given new reference voltage. Starts ramping if necessary."
1827 "voltage[V]:New reference voltage for all channels");
1828
1829 T::AddEvent("SET_REFERENCE_DACS", "S:416", kConnected, kAtReference, kOverCurrent)
1830 (bind(&StateMachineBias::SetReferenceDac, this, placeholders::_1))
1831 ("Set all channels to the given new reference voltage. Starts ramping if necessary."
1832 "voltage[dac]:New reference voltage for all channels in DAC units");
1833
1834 T::AddEvent("ADD_REFERENCE_VOLTAGES", "F:416", kConnected, kAtReference, kOverCurrent)
1835 (bind(&StateMachineBias::AddReferenceVolt, this, placeholders::_1))
1836 ("Add the given voltages to the current reference voltages. Starts ramping if necessary."
1837 "offset[V]:Offsets to be added to the reference voltage of all channels in volts");
1838
1839 T::AddEvent("ADD_REFERENCE_DACS", "S:416", kConnected, kAtReference, kOverCurrent)
1840 (bind(&StateMachineBias::AddReferenceDac, this, placeholders::_1))
1841 ("Add the given voltages to the current reference voltages. Starts ramping if necessary."
1842 "offset[dac]:Offsets to be added to the reference voltage of all channels in DAC units");
1843
1844
1845
1846
1847 T::AddEvent("STOP", kConnected, kRamping, kAtReference, kOverCurrent)
1848 (Wrapper(bind(&ConnectionBias::RampStop, &fBias)))
1849 ("Stop an on-going ramping");
1850
1851 T::AddEvent("START", kConnected, kOverCurrent)
1852 (Wrapper(bind(&ConnectionBias::RampStart, &fBias)))
1853 ("Start a ramping if no ramping is in progress and if reference values differ from current voltages");
1854
1855
1856
1857 T::AddEvent("PRINT_INFO")
1858 (Wrapper(bind(&ConnectionBias::PrintInfo, &fBias)))
1859 ("Print a table with all current read back with the last request operation");
1860 T::AddEvent("PRINT_CURRENTS")
1861 (Wrapper(bind(&ConnectionBias::PrintA, &fBias)))
1862 ("Print a table with all current read back with the last request operation");
1863 T::AddEvent("PRINT_VOLTAGES")
1864 (Wrapper(bind(&ConnectionBias::PrintV, &fBias)))
1865 ("Print a table with all voltages (current and reference voltages as currently in memory)");
1866 T::AddEvent("PRINT_GAPD_REFERENCE_VOLTAGES")
1867 (Wrapper(bind(&ConnectionBias::PrintGapd, &fBias)))
1868 ("Print the G-APD reference values obtained from file");
1869
1870
1871 T::AddEvent("EXPERT_MODE", "B:1")
1872 (bind(&StateMachineBias::SetExpertMode, this, placeholders::_1))
1873 ("Enable usage of expert commands (note that for safty reasons the are exclusive with the standard commands)");
1874
1875 T::AddEvent("EXPERT_RESET", kExpertMode)
1876 (Wrapper(bind(&ConnectionBias::ExpertReset, &fBias, true)))
1877 ("Send the RESET command (note that this is possibly harmfull command)");
1878
1879 T::AddEvent("EXPERT_SET_GLOBAL_VOLTAGE", "F:1", kExpertMode)
1880 (bind(&StateMachineBias::ExpertSetGlobalVolt, this, placeholders::_1))
1881 ("Send the global set command. The given voltage is converted to DAC counts.");
1882
1883 T::AddEvent("EXPERT_SET_GLOBAL_DAC", "S:1", kExpertMode)
1884 (bind(&StateMachineBias::ExpertSetGlobalDac, this, placeholders::_1))
1885 ("Send the global set command.");
1886
1887 T::AddEvent("EXPERT_SET_CHANNEL_VOLTAGE", "S:1;F:1", kExpertMode)
1888 (bind(&StateMachineBias::ExpertSetChannelVolt, this, placeholders::_1))
1889 ("Send a single channel set command. The given voltage is converted to DAC commands.");
1890
1891 T::AddEvent("EXPERT_SET_CHANNEL_DAC", "S:1;S:1", kExpertMode)
1892 (bind(&StateMachineBias::ExpertSetChannelDac, this, placeholders::_1))
1893 ("Send a single channel set command.");
1894 }
1895
1896 ~StateMachineBias() { T::Warn("TODO: Implement rampming at shutdown!"); }
1897
1898 int EvalOptions(Configuration &conf)
1899 {
1900 fBias.SetVerbose(!conf.Get<bool>("quiet"));
1901
1902 fBias.SetEndpoint(conf.Get<string>("dev"));
1903 T::Message("Setting device to "+fBias.URL());
1904
1905 const uint16_t step = conf.Get<uint16_t>("ramp-step");
1906 const uint16_t time = conf.Get<uint16_t>("ramp-time");
1907
1908 if (step>230) // 5V
1909 {
1910 T::Error("ramp-step exceeds allowed range.");
1911 return 1;
1912 }
1913
1914 fBias.SetRampStep(step);
1915 fBias.SetRampTime(time);
1916 fBias.SetUpdateInterval(conf.Get<uint16_t>("update-interval"));
1917 fBias.SetSyncDelay(conf.Get<uint16_t>("sync-delay"));
1918
1919 ostringstream str1, str2;
1920 str1 << "Ramping in effective steps of " << fBias.GetRampStepVolt() << "V";
1921 str2 << "Ramping with a delay per step of " << time << "ms";
1922 T::Message(str1);
1923 T::Message(str2);
1924
1925 // --------------------------------------------------------------------------
1926
1927 const float maxabsv = conf.Get<float>("volt-max-abs");
1928 const float maxrelv = conf.Get<float>("volt-max-rel");
1929 if (maxabsv>90)
1930 {
1931 T::Error("volt-max exceeds 90V.");
1932 return 2;
1933 }
1934 if (maxabsv>75)
1935 T::Warn("volt-max exceeds 75V.");
1936 if (maxabsv<70)
1937 T::Warn("volt-max below 70V.");
1938 if (maxabsv<0)
1939 {
1940 T::Error("volt-max negative.");
1941 return 3;
1942 }
1943
1944 fBias.SetVoltMaxAbs(maxabsv);
1945 fBias.SetVoltMaxRel(maxrelv);
1946
1947 ostringstream str3, str4;
1948 str3 << "Effective maximum allowed absolute voltage: " << fBias.GetVoltMaxAbs() << "V";
1949 str4 << "Effective maximum difference w.r.t to G-APD reference: " << fBias.GetVoltMaxRel() << "V";
1950 T::Message(str3);
1951 T::Message(str4);
1952
1953 // --------------------------------------------------------------------------
1954
1955 PixelMap map;
1956 if (!map.Read(conf.Get<string>("pixel-map-file")))
1957 {
1958 T::Error("Reading reference voltages from "+conf.Get<string>("pixel-map-file")+" failed.");
1959 return 5;
1960 }
1961
1962 if (!fBias.SetNewGapdVoltage(map.Vgapd()))
1963 {
1964 T::Error("Setting reference voltages failed.");
1965 return 6;
1966 }
1967
1968 // --------------------------------------------------------------------------
1969
1970 fBias.Connect();
1971
1972 return -1;
1973 }
1974};
1975
1976// ------------------------------------------------------------------------
1977
1978#include "Main.h"
1979
1980template<class T, class S, class R>
1981int RunShell(Configuration &conf)
1982{
1983 return Main::execute<T, StateMachineBias<S, R>>(conf);
1984}
1985
1986void SetupConfiguration(Configuration &conf)
1987{
1988 po::options_description control("BIAS control options");
1989 control.add_options()
1990 ("no-dim,d", po_bool(), "Disable dim services")
1991 ("dev", var<string>("FTE00FOH"), "Device address of USB port to bias-power supply")
1992 ("quiet,q", po_bool(), "Disable printing contents of all received messages (except dynamic data) in clear text.")
1993 ("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.")
1994 ("ramp-step", var<uint16_t>(46), "Maximum step in DAC counts during ramping (Volt = DAC*90/4096)")
1995 ("update-interval", var<uint16_t>(3000), "Interval between two current requests in milliseconds")
1996 ("sync-delay", var<uint16_t>(333), "Delay between sending the inital 0's after a newly established connection to synchronize the output stream in milliseconds")
1997 ("volt-max-abs", var<float>(75), "Absolte upper limit for the voltage (in Volts)")
1998 ("volt-max-rel", var<float>(2.5), "Relative upper limit for the voltage w.r.t. the G-APD reference voltage (in Volts)")
1999 ("pixel-map-file", var<string>("FACTmapV5a.txt"), "Pixel mapping file. Used here to get the default reference voltage.")
2000 ;
2001
2002 conf.AddOptions(control);
2003}
2004
2005/*
2006 Extract usage clause(s) [if any] for SYNOPSIS.
2007 Translators: "Usage" and "or" here are patterns (regular expressions) which
2008 are used to match the usage synopsis in program output. An example from cp
2009 (GNU coreutils) which contains both strings:
2010 Usage: cp [OPTION]... [-T] SOURCE DEST
2011 or: cp [OPTION]... SOURCE... DIRECTORY
2012 or: cp [OPTION]... -t DIRECTORY SOURCE...
2013 */
2014void PrintUsage()
2015{
2016 cout <<
2017 "The biasctrl program controls the bias-power supply boards.\n"
2018 "\n"
2019 "Note: At default the program is started without a command line (user) "
2020 "interface. In this case Actions/Commands are available via Dim "
2021 "exclusively.\n"
2022 "Use the -c option to start the program with a command line interface.\n"
2023 "\n"
2024 "In the running application:\n"
2025 "Use h or help to print a short help message about its usage.\n"
2026 "\n"
2027 "Usage: biasctrl [-c type] [OPTIONS]\n"
2028 " or: biasctrl [OPTIONS]\n";
2029 cout << endl;
2030}
2031
2032void PrintHelp()
2033{
2034 /* Additional help text which is printed after the configuration
2035 options goes here */
2036
2037 /*
2038 cout << "bla bla bla" << endl << endl;
2039 cout << endl;
2040 cout << "Environment:" << endl;
2041 cout << "environment" << endl;
2042 cout << endl;
2043 cout << "Examples:" << endl;
2044 cout << "test exam" << endl;
2045 cout << endl;
2046 cout << "Files:" << endl;
2047 cout << "files" << endl;
2048 cout << endl;
2049 */
2050}
2051
2052int main(int argc, const char* argv[])
2053{
2054 Configuration conf(argv[0]);
2055 conf.SetPrintUsage(PrintUsage);
2056 Main::SetupConfiguration(conf);
2057 SetupConfiguration(conf);
2058
2059 if (!conf.DoParse(argc, argv, PrintHelp))
2060 return -1;
2061
2062 //try
2063 {
2064 // No console access at all
2065 if (!conf.Has("console"))
2066 {
2067 if (conf.Get<bool>("no-dim"))
2068 return RunShell<LocalStream, StateMachine, ConnectionBias>(conf);
2069 else
2070 return RunShell<LocalStream, StateMachineDim, ConnectionDimBias>(conf);
2071 }
2072 // Cosole access w/ and w/o Dim
2073 if (conf.Get<bool>("no-dim"))
2074 {
2075 if (conf.Get<int>("console")==0)
2076 return RunShell<LocalShell, StateMachine, ConnectionBias>(conf);
2077 else
2078 return RunShell<LocalConsole, StateMachine, ConnectionBias>(conf);
2079 }
2080 else
2081 {
2082 if (conf.Get<int>("console")==0)
2083 return RunShell<LocalShell, StateMachineDim, ConnectionDimBias>(conf);
2084 else
2085 return RunShell<LocalConsole, StateMachineDim, ConnectionDimBias>(conf);
2086 }
2087 }
2088 /*catch (std::exception& e)
2089 {
2090 cerr << "Exception: " << e.what() << endl;
2091 return -1;
2092 }*/
2093
2094 return 0;
2095}
Note: See TracBrowser for help on using the repository browser.