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

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