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

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