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

Last change on this file since 11969 was 11965, checked in by tbretz, 14 years ago
Replaced reading of the FACTmapV5 by the PixelMap class.
File size: 56.3 KB
Line 
1#include <functional>
2
3#include <boost/bind.hpp>
4
5#include "Dim.h"
6#include "Event.h"
7#include "Shell.h"
8#include "StateMachineDim.h"
9#include "ConnectionUSB.h"
10#include "Configuration.h"
11#include "Console.h"
12#include "Converter.h"
13#include "PixelMap.h"
14
15#include "tools.h"
16
17#include "LocalControl.h"
18#include "HeadersBIAS.h"
19
20namespace ba = boost::asio;
21namespace bs = boost::system;
22namespace dummy = ba::placeholders;
23
24using namespace std::placeholders;
25using namespace std;
26using namespace BIAS;
27
28// ------------------------------------------------------------------------
29
30class ConnectionBias : public ConnectionUSB
31{
32 boost::asio::deadline_timer fSyncTimer;
33 boost::asio::deadline_timer fRampTimer;
34 boost::asio::deadline_timer fUpdateTimer;
35
36 vector<uint8_t> fBuffer;
37 vector<uint8_t> fBufferRamp;
38 vector<uint8_t> fBufferUpdate;
39
40 bool fIsVerbose;
41
42 vector<uint16_t> fVoltCmd; // Current command voltage in DAC units (12bit = 90V)
43 vector<uint16_t> fVoltGapd;
44
45 vector<bool> fPresent;
46
47 int64_t fWrapCounter;
48 int64_t fSendCounter;
49
50 int16_t fGlobalVoltCmd; // Command value to be reached
51// uint16_t fExpertVoltRef; // Command value to be reached
52
53 int16_t fRampStep;
54 int16_t fRampTime;
55
56 uint16_t fUpdateTime;
57 uint16_t fSyncTime;
58
59 bool fIsInitializing;
60 bool fIsRamping;
61 bool fWaitingForAnswer;
62
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 Error("AddDac - New voltage reference out of range.");
809 return false;
810 }
811
812 if (fVoltRef[ch]+dac[ch]<0)
813 fVoltRef[ch] = 0;
814 else
815 fVoltRef[ch] += dac[ch];
816 }
817
818 if (!fIsRamping)
819 fIsRamping = RampOneStep();
820
821 return true;
822 }
823
824 bool AddVolt(const vector<float> &offset)
825 {
826 vector<int16_t> dac(offset.size());
827
828 for (size_t ch=0; ch<offset.size(); ch++)
829 {
830 if (offset[ch]<-90 || offset[ch]>90)
831 {
832 Error("AddVolt - Offset out of range [-90V,90V].");
833 return false;
834 }
835 dac[ch] = offset[ch]*4096/90;
836 }
837
838 return AddDac(dac);
839 }
840
841 bool GlobalAddDac(int16_t offset)
842 {
843 return AddDac(vector<int16_t>(kNumChannels, offset));
844 }
845
846 bool GlobalAddVolt(float offset)
847 {
848 return AddVolt(vector<float>(kNumChannels, offset));
849 }
850
851 bool SetDac(const vector<int16_t> &dac)
852 {
853 if (dac.size()!=kNumChannels)
854 {
855 Error("SetDac - Wrong size of array.");
856 return false;
857 }
858
859 for (size_t ch=0; ch<kNumChannels; ch++)
860 {
861 if (!CheckChDac("SetDac", dac[ch]))
862 return false;
863
864 fVoltRef[ch] = dac[ch];
865 }
866
867 if (!fIsRamping)
868 fIsRamping = RampOneStep();
869
870 return true;
871 }
872
873 bool SetVolt(const vector<float> &volt)
874 {
875 vector<int16_t> dac(volt.size());
876
877 for (size_t ch=0; ch<volt.size(); ch++)
878 {
879 if (volt[ch]<0 || volt[ch]>90)
880 {
881 Error("SetVolt - Voltage out of range [0V,90V].");
882 return false;
883 }
884 dac[ch] = volt[ch]*4096/90;
885 }
886
887 return SetDac(dac);
888 }
889
890 bool GlobalSetDac(int16_t dac)
891 {
892 return SetDac(vector<int16_t>(kNumChannels, dac));
893 }
894
895 bool GlobalSetVolt(float volt)
896 {
897 return SetVolt(vector<float>(kNumChannels, volt));
898 }
899
900
901 // --------------------------------------------------------------------
902
903 bool SetGapdVoltage(float offset)
904 {
905 if (offset<-90 || offset>90)
906 {
907 Error("SetGapdVoltage - Offset out of range [-90V,90V].");
908 return false;
909 }
910
911 const int16_t dac = offset*4096/90;
912
913 for (size_t ch=0; ch<kNumChannels; ch++)
914 if (fVoltGapd[ch]+dac>kMaxDac)
915 {
916 Error("SetGapdVoltage - New voltage reference out of range.");
917 return false;
918 }
919
920 for (size_t ch=0; ch<kNumChannels; ch++)
921 fVoltRef[ch] = fVoltGapd[ch]+dac<0 ? 0 : fVoltGapd[ch]+dac;
922
923 if (!fIsRamping)
924 fIsRamping = RampOneStep();
925
926 return true;
927 }
928
929 void SetZero()
930 {
931 for (size_t ch=0; ch<kNumChannels; ch++)
932 fVoltRef[ch] = 0;
933
934 if (!fIsRamping)
935 fIsRamping = RampOneStep();
936 }
937
938 bool SetNewGapdVoltage(const vector<float> &volt)
939 {
940 if (volt.size()!=kNumChannels)
941 {
942 ostringstream out;
943 out << "SetNewGapdVoltage - Given vector has " << volt.size() << " elements - expected " << kNumChannels << endl;
944 Error(out);
945 return false;
946 }
947
948 for (size_t i=0; i<kNumChannels; i++)
949 fVoltGapd[i] = volt[i]*4096/90;
950
951 return true;
952 }
953
954 // --------------------------------------------------------------------
955
956 void RampStop()
957 {
958 fRampTimer.cancel();
959 fIsRamping = false;
960
961 Message("Ramping stopped.");
962 }
963
964 void RampStart()
965 {
966 if (fIsRamping)
967 {
968 Warn("RampStart - Ramping in progress... ignored.");
969 return;
970 }
971
972 fIsRamping = RampOneStep();
973 }
974
975 void SetRampTime(uint16_t val)
976 {
977 fRampTime = val;
978 }
979
980 void SetRampStep(uint16_t val)
981 {
982 fRampStep = val;
983 }
984
985 bool IsRamping() const { return fIsRamping; }
986
987 // -------------------------------------------------------------------
988
989 void ExpertReset()
990 {
991 if (fWaitingForAnswer)
992 {
993 Error("Answer on last command not yet received.");
994 return;
995 }
996
997 Warn("EXPERT MODE: Sending reset.");
998 PostMessage(GetCmd(kCmdReset));
999 AsyncRead(ba::buffer(fBuffer, 3), kCmdReset, ++fSendCounter);
1000 fWaitingForAnswer = true;
1001 }
1002
1003
1004 bool ExpertChannelSetDac(uint16_t ch, uint16_t dac)
1005 {
1006 if (fWaitingForAnswer)
1007 {
1008 Error("Answer on last command not yet received.");
1009 return false;
1010 }
1011
1012 if (!CheckChDac("ExpertChannelSetDac", dac, ch))
1013 return false;
1014
1015 fVoltCmd[ch] = dac;
1016
1017 ostringstream msg;
1018 msg << "EXPERT MODE: Sending 'ChannelSet' (set ch " << ch << " to DAC=" << dac << ")";
1019 Warn(msg);
1020
1021 PostMessage(GetCmd(kCmdChannelSet, ch, dac));
1022 AsyncRead(ba::buffer(fBuffer, 3), kExpertChannelSet|(ch<<8), ++fSendCounter);
1023 fWaitingForAnswer = true;
1024
1025 return true;
1026 }
1027
1028 bool ExpertChannelSetVolt(uint16_t ch, double volt)
1029 {
1030 return ExpertChannelSetDac(ch, volt*4096/90.);
1031 }
1032
1033 bool ExpertGlobalSetDac(uint16_t dac)
1034 {
1035 if (fWaitingForAnswer)
1036 {
1037 Error("Answer on last command not yet received.");
1038 return false;
1039 }
1040
1041 if (!CheckChDac("ExpertGlobalSetDac", dac))
1042 return false;
1043
1044 if (fGlobalVoltCmd>=0)
1045 {
1046 Error("ExpertGlobalSetDac - Still waiting for previous global-set's answer.");
1047 return false;
1048 }
1049
1050 fGlobalVoltCmd = dac;
1051
1052 ostringstream msg;
1053 msg << "EXPERT MODE: Sending 'GlobalSet' (DAC=" << dac << ")";
1054 Warn(msg);
1055
1056 PostMessage(GetCmd(kCmdGlobalSet, 0, dac));
1057 AsyncRead(ba::buffer(fBuffer, 3), kCmdGlobalSet, ++fSendCounter);
1058 fWaitingForAnswer = true;
1059
1060 return true;
1061 }
1062
1063 bool ExpertGlobalSetVolt(float volt)
1064 {
1065 return ExpertGlobalSetDac(volt*4096/90);
1066 }
1067
1068 // --------------------------------------------------------------------
1069
1070 void SetVerbose(bool b)
1071 {
1072 fIsVerbose = b;
1073 }
1074
1075 void PrintLineA(int b, int ch)
1076 {
1077 Out() << setw(2) << b << "|";
1078
1079 for (int c=ch; c<ch+8; c++)
1080 {
1081 const int id = c+kNumChannelsPerBoard*b;
1082 Out() << (fCurrent[id]<0?kRed:kGreen);
1083 Out() << " " << setw(7) << abs(fCurrent[id])*5000/4096.;
1084 }
1085 Out() << endl;
1086
1087 }
1088
1089 void PrintA()
1090 {
1091 Out() << dec << setprecision(2) << fixed << setfill(' ');
1092 for (int b=0; b<kNumBoards; b++)
1093 {
1094 if (!fPresent[b])
1095 {
1096 Out() << setw(2) << b << "-" << endl;
1097 continue;
1098 }
1099
1100 PrintLineA(b, 0);
1101 PrintLineA(b, 8);
1102 PrintLineA(b, 16);
1103 PrintLineA(b, 24);
1104 }
1105 }
1106
1107 void PrintLineV(int b, int ch)
1108 {
1109 Out() << setw(2) << b << "|";
1110
1111 for (int c=ch; c<ch+4; c++)
1112 {
1113 const int id = c+kNumChannelsPerBoard*b;
1114 Out() << " ";
1115 Out() << (fVolt[id]==fVoltRef[id]?kGreen:kRed);
1116 Out() << setw(5) << fVolt[id]*90/4096. << '/';
1117 Out() << setw(5) << fVoltRef[id]*90/4096.;
1118 }
1119 Out() << endl;
1120 }
1121
1122 void PrintV()
1123 {
1124 Out() << dec << setprecision(2) << fixed << setfill(' ');
1125 for (int b=0; b<kNumBoards; b++)
1126 {
1127 if (!fPresent[b])
1128 {
1129 Out() << setw(2) << b << "-" << endl;
1130 continue;
1131 }
1132
1133 PrintLineV(b, 0);
1134 PrintLineV(b, 4);
1135 PrintLineV(b, 8);
1136 PrintLineV(b, 12);
1137 PrintLineV(b, 16);
1138 PrintLineV(b, 20);
1139 PrintLineV(b, 24);
1140 PrintLineV(b, 28);
1141 }
1142 }
1143
1144 void PrintLineGapd(int b, int ch)
1145 {
1146 Out() << setw(2) << b << "|";
1147
1148 for (int c=ch; c<ch+8; c++)
1149 {
1150 const int id = c+kNumChannelsPerBoard*b;
1151 Out() << " " << setw(5) << fVoltGapd[id]*90/4096.;
1152 }
1153 Out() << endl;
1154 }
1155
1156 void PrintGapd()
1157 {
1158 Out() << dec << setprecision(2) << fixed << setfill(' ');
1159 for (int b=0; b<kNumBoards; b++)
1160 {
1161 if (!fPresent[b])
1162 {
1163 Out() << setw(2) << b << "-" << endl;
1164 continue;
1165 }
1166
1167 PrintLineGapd(b, 0);
1168 PrintLineGapd(b, 8);
1169 PrintLineGapd(b, 16);
1170 PrintLineGapd(b, 24);
1171 }
1172 }
1173
1174 // -------------------------------------------------------------------
1175
1176 void SetUpdateInterval(uint16_t val)
1177 {
1178 fUpdateTime = val;
1179 }
1180
1181 void SetSyncDelay(uint16_t val)
1182 {
1183 fSyncTime = val;
1184 }
1185
1186 void SetVoltMax(float max)
1187 {
1188 fVoltMax = max*4096/90;
1189 if (fVoltMax>4095)
1190 fVoltMax = 4095;
1191 if (max<0)
1192 fVoltMax = 0;
1193 }
1194
1195
1196/*
1197 void AdaptVoltages()
1198 {
1199 // Correct voltages according to current
1200 for (int i=0; i<kNumChannels; i++)
1201 {
1202 if (fVoltRef[i]==0 || fCurrent[i]<0 || fRefCurrent[i]<0)
1203 continue;
1204
1205 // Calculate difference and convert ADC units to Amp
1206 // const double diffcur = (fRefCurrent[i]-fCurrent[i])*5000/4096
1207 //const int32_t diffcur = int32_t(fRefCurrent[i]-fCurrent[i])*5000;
1208
1209 // Calculate voltage difference
1210 // #define RESISTOR 1000 // Ohm
1211 //const double diffvolt = diffcur*RESISTOR/1e6;
1212
1213 // Calculate new vlaue by onverting voltage difference to DAC units
1214 //const int32_t dac = fRefVolt[i] + diffvolt*4096/90.0;
1215 SetVoltage(i, fRefVolt[i] + (fRefCurrent[i]-fCurrent[i])/18);
1216 }
1217 }
1218
1219 void SetReferenceCurrent()
1220 {
1221 fRefCurrent = fCurrent;
1222 }
1223 */
1224
1225 States_t GetStatus()
1226 {
1227 if (!IsConnected())
1228 return BIAS::kDisconnected;
1229
1230 if (IsConnecting())
1231 return BIAS::kConnecting;
1232
1233 if (fIsInitializing)
1234 return BIAS::kInitializing;
1235
1236 if (fIsRamping)
1237 return BIAS::kRamping;
1238
1239 for (int ch=0; ch<kNumChannels; ch++)
1240 if (fPresent[ch/kNumChannelsPerBoard] && fCurrent[ch]<0)
1241 return BIAS::kOverCurrent;
1242
1243 for (int ch=0; ch<kNumChannels; ch++)
1244 if (fPresent[ch/kNumChannelsPerBoard] && fVolt[ch]!=fVoltRef[ch])
1245 return BIAS::kConnected;
1246
1247 return BIAS::kAtReference;
1248 }
1249};
1250
1251// ------------------------------------------------------------------------
1252
1253#include "DimDescriptionService.h"
1254
1255class ConnectionDimBias : public ConnectionBias
1256{
1257private:
1258
1259 DimDescribedService fDimCurrent;
1260 DimDescribedService fDimVoltage;
1261
1262 void UpdateA()
1263 {
1264 fDimCurrent.Update(fCurrent);
1265 }
1266
1267 void UpdateV()
1268 {
1269 vector<uint16_t> vec;
1270 vec.insert(vec.end(), fVolt.begin(), fVolt.end());
1271 vec.insert(vec.end(), fVoltRef.begin(), fVoltRef.end());
1272 fDimVoltage.Update(vec);
1273 }
1274
1275
1276public:
1277 ConnectionDimBias(ba::io_service& ioservice, MessageImp &imp) :
1278 ConnectionBias(ioservice, imp),
1279 fDimCurrent("BIAS_CONTROL/CURRENT", "S:416", ""),
1280 fDimVoltage("BIAS_CONTROL/VOLTAGE", "S:416;S:416", "")
1281 {
1282 }
1283
1284 // 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
1285};
1286
1287// ------------------------------------------------------------------------
1288
1289template <class T, class S>
1290class StateMachineBias : public T, public ba::io_service, public ba::io_service::work
1291{
1292 int Wrap(boost::function<void()> f)
1293 {
1294 f();
1295 return T::GetCurrentState();
1296 }
1297
1298 function<int(const EventImp &)> Wrapper(function<void()> func)
1299 {
1300 return bind(&StateMachineBias::Wrap, this, func);
1301 }
1302
1303 bool CheckEventSize(size_t has, const char *name, size_t size)
1304 {
1305 if (has==size)
1306 return true;
1307
1308 ostringstream msg;
1309 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
1310 T::Fatal(msg);
1311 return false;
1312 }
1313
1314private:
1315 S fBias;
1316
1317 bool fExpertMode;
1318
1319 // --------------------------------------------------------------------
1320
1321 int SetGapdVoltage(const EventImp &evt)
1322 {
1323 if (!CheckEventSize(evt.GetSize(), "SetGapdVoltage", 4))
1324 return false;
1325
1326 fBias.SetGapdVoltage(evt.GetFloat());
1327
1328 return T::GetCurrentState();
1329 }
1330
1331 // --------------------------------------------------------------------
1332
1333 int SetGlobalVolt(const EventImp &evt)
1334 {
1335 if (!CheckEventSize(evt.GetSize(), "SetGlobalVolt", 4))
1336 return false;
1337
1338 fBias.GlobalSetVolt(evt.GetFloat());
1339
1340 return T::GetCurrentState();
1341 }
1342
1343 int SetGlobalDac(const EventImp &evt)
1344 {
1345 if (!CheckEventSize(evt.GetSize(), "SetGlobalDac", 2))
1346 return false;
1347
1348 fBias.GlobalSetDac(evt.GetUShort());
1349
1350 return T::GetCurrentState();
1351 }
1352
1353 int IncGlobalVolt(const EventImp &evt)
1354 {
1355 if (!CheckEventSize(evt.GetSize(), "IncGlobalVolt", 4))
1356 return false;
1357
1358 fBias.GlobalAddVolt(evt.GetFloat());
1359
1360 return T::GetCurrentState();
1361 }
1362
1363 int IncGlobalDac(const EventImp &evt)
1364 {
1365 if (!CheckEventSize(evt.GetSize(), "IncGlobalDac", 2))
1366 return false;
1367
1368 fBias.GlobalAddDac(evt.GetShort());
1369
1370 return T::GetCurrentState();
1371 }
1372
1373 int DecGlobalVolt(const EventImp &evt)
1374 {
1375 if (!CheckEventSize(evt.GetSize(), "DecGlobalVolt", 4))
1376 return false;
1377
1378 fBias.GlobalAddVolt(-evt.GetFloat());
1379
1380 return T::GetCurrentState();
1381 }
1382
1383 int DecGlobalDac(const EventImp &evt)
1384 {
1385 if (!CheckEventSize(evt.GetSize(), "DecGlobalDac", 2))
1386 return false;
1387
1388 fBias.GlobalAddDac(-evt.GetShort());
1389
1390 return T::GetCurrentState();
1391 }
1392
1393 int SetChannelVolt(const EventImp &evt)
1394 {
1395 if (!CheckEventSize(evt.GetSize(), "SetChannelVolt", 6))
1396 return false;
1397
1398 fBias.ChannelSetVolt(evt.GetUShort(), evt.Get<float>(2));
1399
1400 return T::GetCurrentState();
1401 }
1402
1403 int SetChannelDac(const EventImp &evt)
1404 {
1405 if (!CheckEventSize(evt.GetSize(), "SetChannelDac", 4))
1406 return false;
1407
1408 fBias.ChannelSetDac(evt.Get<uint16_t>(), evt.Get<uint16_t>(2));
1409
1410 return T::GetCurrentState();
1411 }
1412
1413 // --------------------------------------------------------------------
1414
1415 int AddReferenceDac(const EventImp &evt)
1416 {
1417 if (!CheckEventSize(evt.GetSize(), "AddReferenceDac", 2*kNumChannels))
1418 return false;
1419
1420 const int16_t *ptr = evt.Ptr<int16_t>();
1421 fBias.AddDac(vector<int16_t>(ptr, ptr+416));
1422
1423 return T::GetCurrentState();
1424 }
1425
1426 int AddReferenceVolt(const EventImp &evt)
1427 {
1428 if (!CheckEventSize(evt.GetSize(), "AddReferenceVolt", 4*kNumChannels))
1429 return false;
1430
1431 const float_t *ptr = evt.Ptr<float>();
1432 fBias.AddVolt(vector<float>(ptr, ptr+416));
1433
1434 return T::GetCurrentState();
1435 }
1436
1437 int SetReferenceDac(const EventImp &evt)
1438 {
1439 if (!CheckEventSize(evt.GetSize(), "SetReferenceDac", 2*kNumChannels))
1440 return false;
1441
1442 const int16_t *ptr = evt.Ptr<int16_t>();
1443 fBias.SetDac(vector<int16_t>(ptr, ptr+416));
1444
1445 return T::GetCurrentState();
1446 }
1447
1448 int SetReferenceVolt(const EventImp &evt)
1449 {
1450 if (!CheckEventSize(evt.GetSize(), "SetReferenceVolt", 4*kNumChannels))
1451 return false;
1452
1453 const float_t *ptr = evt.Ptr<float>();
1454 fBias.SetVolt(vector<float>(ptr, ptr+416));
1455
1456 return T::GetCurrentState();
1457 }
1458
1459 // --------------------------------------------------------------------
1460
1461 int ExpertSetGlobalVolt(const EventImp &evt)
1462 {
1463 if (!CheckEventSize(evt.GetSize(), "ExpertSetGlobalVolt", 4))
1464 return false;
1465
1466 fBias.ExpertGlobalSetVolt(evt.GetFloat());
1467
1468 return T::GetCurrentState();
1469 }
1470
1471 int ExpertSetGlobalDac(const EventImp &evt)
1472 {
1473 if (!CheckEventSize(evt.GetSize(), "ExpertSetGlobalDac", 2))
1474 return false;
1475
1476 fBias.ExpertGlobalSetDac(evt.GetUShort());
1477
1478 return T::GetCurrentState();
1479 }
1480
1481 int ExpertSetChannelVolt(const EventImp &evt)
1482 {
1483 if (!CheckEventSize(evt.GetSize(), "ExpertSetChannelVolt", 6))
1484 return false;
1485
1486 fBias.ExpertChannelSetVolt(evt.GetUShort(), evt.Get<float>(2));
1487
1488 return T::GetCurrentState();
1489 }
1490
1491 int ExpertSetChannelDac(const EventImp &evt)
1492 {
1493 if (!CheckEventSize(evt.GetSize(), "ExpertSetChannelDac", 4))
1494 return false;
1495
1496 fBias.ExpertChannelSetDac(evt.Get<uint16_t>(), evt.Get<uint16_t>(2));
1497
1498 return T::GetCurrentState();
1499 }
1500
1501 // --------------------------------------------------------------------
1502
1503 int Disconnect()
1504 {
1505 // Close all connections
1506 fBias.PostClose(false);
1507
1508 /*
1509 // Now wait until all connection have been closed and
1510 // all pending handlers have been processed
1511 poll();
1512 */
1513
1514 return T::GetCurrentState();
1515 }
1516
1517 int Reconnect(const EventImp &evt)
1518 {
1519 // Close all connections to supress the warning in SetEndpoint
1520 fBias.PostClose(false);
1521
1522 // Now wait until all connection have been closed and
1523 // all pending handlers have been processed
1524 poll();
1525
1526 if (evt.GetBool())
1527 fBias.SetEndpoint(evt.GetString());
1528
1529 // Now we can reopen the connection
1530 fBias.PostClose(true);
1531
1532 return T::GetCurrentState();
1533 }
1534
1535 int SetVerbosity(const EventImp &evt)
1536 {
1537 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
1538 return T::kSM_FatalError;
1539
1540 fBias.SetVerbose(evt.GetBool());
1541
1542 return T::GetCurrentState();
1543 }
1544
1545 int SetExpertMode(const EventImp &evt)
1546 {
1547 if (!CheckEventSize(evt.GetSize(), "SetExpertMode", 1))
1548 return T::kSM_FatalError;
1549
1550 fExpertMode = evt.GetBool();
1551
1552 if (fExpertMode)
1553 T::Warn("Expert commands enabled -- please ensure that you EXACTLY know what you do. These commands can destroy the system.");
1554
1555 return T::GetCurrentState();
1556 }
1557
1558 int Execute()
1559 {
1560 // Dispatch (execute) at most one handler from the queue. In contrary
1561 // to run_one(), it doesn't wait until a handler is available
1562 // which can be dispatched, so poll_one() might return with 0
1563 // handlers dispatched. The handlers are always dispatched/executed
1564 // synchronously, i.e. within the call to poll_one()
1565 poll_one();
1566
1567 return fExpertMode && fBias.GetStatus()>=kConnected ?
1568 kExpertMode : fBias.GetStatus();
1569 }
1570
1571public:
1572 StateMachineBias(ostream &out=cout) :
1573 T(out, "BIAS_CONTROL"), ba::io_service::work(static_cast<ba::io_service&>(*this)),
1574 fBias(*this, *this), fExpertMode(false)
1575 {
1576 // ba::io_service::work is a kind of keep_alive for the loop.
1577 // It prevents the io_service to go to stopped state, which
1578 // would prevent any consecutive calls to run()
1579 // or poll() to do nothing. reset() could also revoke to the
1580 // previous state but this might introduce some overhead of
1581 // deletion and creation of threads and more.
1582
1583 // State names
1584 T::AddStateName(kDisconnected, "Disconnected",
1585 "Bias-power supply not connected via USB.");
1586
1587 T::AddStateName(kConnecting, "Connecting",
1588 "Trying to establish USB connection to bias-power supply.");
1589
1590 T::AddStateName(kInitializing, "Initializing",
1591 "USB connection to bias-power supply established, synchronizing USB stream.");
1592
1593 T::AddStateName(kConnected, "Connected",
1594 "USB connection to bias-power supply established.");
1595
1596 T::AddStateName(kAtReference, "Referenced",
1597 "Internal reference voltage matches last sent voltage.");
1598
1599 T::AddStateName(kOverCurrent, "OverCurrent",
1600 "At least one channel is in over current state.");
1601
1602 T::AddStateName(kExpertMode, "ExpertMode",
1603 "Special (risky!) mode to directly send command to the bias-power supply.");
1604
1605 T::AddStateName(kRamping, "Ramping",
1606 "Voltage ramping in progress.");
1607
1608 // Verbosity commands
1609 T::AddEvent("SET_VERBOSE", "B")
1610 (bind(&StateMachineBias::SetVerbosity, this, placeholders::_1))
1611 ("set verbosity state"
1612 "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
1613
1614 // Conenction commands
1615 T::AddEvent("DISCONNECT", kConnected, kAtReference)
1616 (bind(&StateMachineBias::Disconnect, this))
1617 ("disconnect from USB");
1618
1619 T::AddEvent("RECONNECT", "O", kDisconnected, kConnected, kAtReference)
1620 (bind(&StateMachineBias::Reconnect, this, placeholders::_1))
1621 ("(Re)connect USB connection to Bias power supply, a new address can be given"
1622 "|tty[string]:new USB address");
1623
1624
1625
1626 T::AddEvent("REQUEST_STATUS", kConnected, kAtReference, kOverCurrent)
1627 (Wrapper(bind(&ConnectionBias::ReadAllChannels, &fBias, false)))
1628 ("Asynchronously request the status (current) of all channels.");
1629
1630 T::AddEvent("RESET_OVER_CURRENT_STATUS", kOverCurrent)
1631 (Wrapper(bind(&ConnectionBias::OverCurrentReset, &fBias)))
1632 ("NOT YET TESTED");
1633
1634
1635
1636 T::AddEvent("SET_GLOBAL_VOLTAGE", "F:1", kConnected, kAtReference, kOverCurrent)
1637 (bind(&StateMachineBias::SetGlobalVolt, this, placeholders::_1))
1638 ("Set all channels to a new reference voltage. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)");
1639
1640 T::AddEvent("SET_GLOBAL_DAC", "S:1", kConnected, kAtReference, kOverCurrent)
1641 (bind(&StateMachineBias::SetGlobalDac, this, placeholders::_1))
1642 ("Set all channels to a new DAC reference. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)");
1643
1644 T::AddEvent("INCREASE_GLOBAL_VOLTAGE", "F:1", kConnected, kAtReference, kOverCurrent)
1645 (bind(&StateMachineBias::IncGlobalVolt, this, placeholders::_1))
1646 ("Set all channels to a new reference voltage. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)");
1647
1648 T::AddEvent("INCREASE_GLOBAL_DAC", "S:1", kConnected, kAtReference, kOverCurrent)
1649 (bind(&StateMachineBias::IncGlobalDac, this, placeholders::_1))
1650 ("Set all channels to a new DAC reference. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)");
1651
1652 T::AddEvent("DECREASE_GLOBAL_VOLTAGE", "F:1", kConnected, kAtReference, kOverCurrent)
1653 (bind(&StateMachineBias::DecGlobalVolt, this, placeholders::_1))
1654 ("Set all channels to a new reference voltage. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)");
1655
1656 T::AddEvent("DECREASE_GLOBAL_DAC", "S:1", kConnected, kAtReference, kOverCurrent)
1657 (bind(&StateMachineBias::DecGlobalDac, this, placeholders::_1))
1658 ("Set all channels to a new DAC reference. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)");
1659
1660 T::AddEvent("SET_CHANNEL_VOLTAGE", "S:1;F:1", kConnected, kAtReference, kOverCurrent)
1661 (bind(&StateMachineBias::SetChannelVolt, this, placeholders::_1))
1662 ("Set a single channel a new reference voltage. Starts ramping if necessary.");
1663
1664 T::AddEvent("SET_CHANNEL_DAC", "S:1;S:1", kConnected, kAtReference, kOverCurrent)
1665 (bind(&StateMachineBias::SetChannelDac, this, placeholders::_1))
1666 ("Set a single channel a new DAC reference value. Starts ramping if necessary.");
1667
1668 T::AddEvent("SET_GAPD_REFERENCE_VOLTAGE", kConnected, kAtReference, kOverCurrent)
1669 (Wrapper(bind(&ConnectionBias::SetGapdVoltage, &fBias, 0.)))
1670 ("Set all channels to their G-APD reference voltage. Starts ramping if necessary.");
1671
1672 T::AddEvent("SET_GAPD_REFERENCE_OFFSET", "F:1", kConnected, kAtReference, kOverCurrent)
1673 (bind(&StateMachineBias::SetGapdVoltage, this, placeholders::_1))
1674 ("Set all channels to their G-APD reference voltage plus the given offset. Starts ramping if necessary.");
1675
1676 T::AddEvent("SET_ZERO_VOLTAGE", kConnected, kAtReference, kOverCurrent)
1677 (Wrapper(bind(&ConnectionBias::SetZero, &fBias)))
1678 ("Set all channels to a zero reference voltage. Starts ramping if necessary.");
1679
1680 T::AddEvent("SET_REFERENCE_VOLTAGES", "F:416", kConnected, kAtReference, kOverCurrent)
1681 (bind(&StateMachineBias::SetReferenceVolt, this, placeholders::_1))
1682 ("");
1683
1684 T::AddEvent("SET_REFERENCE_DACS", "S:416", kConnected, kAtReference, kOverCurrent)
1685 (bind(&StateMachineBias::SetReferenceDac, this, placeholders::_1))
1686 ("");
1687
1688 T::AddEvent("ADD_REFERENCE_VOLTAGES", "F:416", kConnected, kAtReference, kOverCurrent)
1689 (bind(&StateMachineBias::AddReferenceVolt, this, placeholders::_1))
1690 ("");
1691
1692 T::AddEvent("ADD_REFERENCE_DACS", "S:416", kConnected, kAtReference, kOverCurrent)
1693 (bind(&StateMachineBias::AddReferenceDac, this, placeholders::_1))
1694 ("");
1695
1696
1697
1698
1699 T::AddEvent("STOP", kConnected, kRamping, kAtReference, kOverCurrent)
1700 (Wrapper(bind(&ConnectionBias::RampStop, &fBias)))
1701 ("Stop an on-going ramping");
1702
1703 T::AddEvent("START", kConnected, kOverCurrent)
1704 (Wrapper(bind(&ConnectionBias::RampStart, &fBias)))
1705 ("Start a ramping if no ramping is in progress and if reference values differ from current voltages");
1706
1707
1708
1709 T::AddEvent("PRINT_CURRENTS")
1710 (Wrapper(bind(&ConnectionBias::PrintA, &fBias)))
1711 ("Print a table with all current read back with the last request operation");
1712 T::AddEvent("PRINT_VOLTAGES")
1713 (Wrapper(bind(&ConnectionBias::PrintV, &fBias)))
1714 ("Print a table with all voltages (current and reference voltages as currently in memory)");
1715 T::AddEvent("PRINT_GAPD_REFERENCE_VOLTAGES")
1716 (Wrapper(bind(&ConnectionBias::PrintGapd, &fBias)))
1717 ("Print the G-APD reference values obtained from file");
1718
1719
1720 T::AddEvent("EXPERT_MODE", "B:1")
1721 (bind(&StateMachineBias::SetExpertMode, this, placeholders::_1))
1722 ("Enable usage of expert commands (note that for safty reasons the are exclusive with the standard commands)");
1723
1724 T::AddEvent("EXPERT_RESET", kExpertMode)
1725 (Wrapper(bind(&ConnectionBias::ExpertReset, &fBias)))
1726 ("Send the RESET command (note that this is possibly harmfull command)");
1727
1728 T::AddEvent("EXPERT_SET_GLOBAL_VOLTAGE", "F:1", kExpertMode)
1729 (bind(&StateMachineBias::ExpertSetGlobalVolt, this, placeholders::_1))
1730 ("Send the global set command. The given voltage is converted to DAC counts.");
1731
1732 T::AddEvent("EXPERT_SET_GLOBAL_DAC", "S:1", kExpertMode)
1733 (bind(&StateMachineBias::ExpertSetGlobalDac, this, placeholders::_1))
1734 ("Send the global set command.");
1735
1736 T::AddEvent("EXPERT_SET_CHANNEL_VOLTAGE", "S:1;F:1", kExpertMode)
1737 (bind(&StateMachineBias::ExpertSetChannelVolt, this, placeholders::_1))
1738 ("Send a single channel set command. The given voltage is converted to DAC commands.");
1739
1740 T::AddEvent("EXPERT_SET_CHANNEL_DAC", "S:1;S:1", kExpertMode)
1741 (bind(&StateMachineBias::ExpertSetChannelDac, this, placeholders::_1))
1742 ("Send a single channel set command.");
1743 }
1744
1745 ~StateMachineBias() { T::Warn("TODO: Implement rampming at shutdown!"); }
1746
1747 int EvalOptions(Configuration &conf)
1748 {
1749 fBias.SetVerbose(!conf.Get<bool>("quiet"));
1750
1751 fBias.SetEndpoint(conf.Get<string>("dev"));
1752 T::Message("Setting device to "+fBias.URL());
1753
1754 const uint16_t step = conf.Get<uint16_t>("ramp-step");
1755 const uint16_t time = conf.Get<uint16_t>("ramp-time");
1756
1757 if (step>230) // 5V
1758 {
1759 T::Error("ramp-step exceeds allowed range.");
1760 return 1;
1761 }
1762
1763 fBias.SetRampStep(step);
1764 fBias.SetRampTime(time);
1765 fBias.SetUpdateInterval(conf.Get<uint16_t>("update-interval"));
1766 fBias.SetSyncDelay(conf.Get<uint16_t>("sync-delay"));
1767
1768 const float maxv = conf.Get<float>("volt-max");
1769 if (maxv>90)
1770 {
1771 T::Error("volt-max exceeds 90V.");
1772 return 2;
1773 }
1774 if (maxv>75)
1775 T::Warn("volt-max exceeds 75V.");
1776 if (maxv<70)
1777 T::Warn("volt-max below 70V.");
1778 if (maxv<0)
1779 {
1780 T::Error("volt-max negative.");
1781 return 3;
1782 }
1783
1784 fBias.SetVoltMax(maxv);
1785
1786 // --------------------------------------------------------------------------
1787
1788 PixelMap map;
1789 if (!map.Read("FACTmapV5.txt"))
1790 {
1791 T::Error("Reading reference voltages from FACTmapV5.txt failed.");
1792 return 5;
1793 }
1794
1795 if (!fBias.SetNewGapdVoltage(map.Vgapd()))
1796 {
1797 T::Error("Setting reference voltages failed.");
1798 return 6;
1799 }
1800
1801 // --------------------------------------------------------------------------
1802
1803 fBias.Connect();
1804
1805 return -1;
1806 }
1807};
1808
1809// ------------------------------------------------------------------------
1810
1811#include "Main.h"
1812
1813template<class T, class S, class R>
1814int RunShell(Configuration &conf)
1815{
1816 return Main::execute<T, StateMachineBias<S, R>>(conf);
1817}
1818
1819void SetupConfiguration(Configuration &conf)
1820{
1821 po::options_description control("BIAS control options");
1822 control.add_options()
1823 ("no-dim,d", po_bool(), "Disable dim services")
1824 ("dev", var<string>("FTE00FOH"), "Device address of USB port to bias-power supply")
1825 ("quiet,q", po_bool(), "Disable printing contents of all received messages (except dynamic data) in clear text.")
1826 ("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.")
1827 ("ramp-step", var<uint16_t>(46), "Maximum step in DAC counts during ramping (Volt = DAC*90/4096)")
1828 ("update-interval", var<uint16_t>(3000), "Interval between two current requests in milliseconds")
1829 ("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")
1830 ("volt-max", var<float>(75), "Upper limit for the voltage which can be applied in Volts")
1831 ;
1832 // FIXME: Add a bit for OC... there is no -0
1833
1834 conf.AddOptions(control);
1835}
1836
1837/*
1838 Extract usage clause(s) [if any] for SYNOPSIS.
1839 Translators: "Usage" and "or" here are patterns (regular expressions) which
1840 are used to match the usage synopsis in program output. An example from cp
1841 (GNU coreutils) which contains both strings:
1842 Usage: cp [OPTION]... [-T] SOURCE DEST
1843 or: cp [OPTION]... SOURCE... DIRECTORY
1844 or: cp [OPTION]... -t DIRECTORY SOURCE...
1845 */
1846void PrintUsage()
1847{
1848 cout <<
1849 "The biasctrl program controls the bias-power supply boards.\n"
1850 "\n"
1851 "Note: At default the program is started without a command line (user) "
1852 "interface. In this case Actions/Commands are available via Dim "
1853 "exclusively.\n"
1854 "Use the -c option to start the program with a command line interface.\n"
1855 "\n"
1856 "In the running application:\n"
1857 "Use h or help to print a short help message about its usage.\n"
1858 "\n"
1859 "Usage: biasctrl [-c type] [OPTIONS]\n"
1860 " or: biasctrl [OPTIONS]\n";
1861 cout << endl;
1862}
1863
1864void PrintHelp()
1865{
1866 /* Additional help text which is printed after the configuration
1867 options goes here */
1868
1869 /*
1870 cout << "bla bla bla" << endl << endl;
1871 cout << endl;
1872 cout << "Environment:" << endl;
1873 cout << "environment" << endl;
1874 cout << endl;
1875 cout << "Examples:" << endl;
1876 cout << "test exam" << endl;
1877 cout << endl;
1878 cout << "Files:" << endl;
1879 cout << "files" << endl;
1880 cout << endl;
1881 */
1882}
1883
1884int main(int argc, const char* argv[])
1885{
1886 Configuration conf(argv[0]);
1887 conf.SetPrintUsage(PrintUsage);
1888 Main::SetupConfiguration(conf);
1889 SetupConfiguration(conf);
1890
1891 if (!conf.DoParse(argc, argv, PrintHelp))
1892 return -1;
1893
1894 //try
1895 {
1896 // No console access at all
1897 if (!conf.Has("console"))
1898 {
1899 if (conf.Get<bool>("no-dim"))
1900 return RunShell<LocalStream, StateMachine, ConnectionBias>(conf);
1901 else
1902 return RunShell<LocalStream, StateMachineDim, ConnectionDimBias>(conf);
1903 }
1904 // Cosole access w/ and w/o Dim
1905 if (conf.Get<bool>("no-dim"))
1906 {
1907 if (conf.Get<int>("console")==0)
1908 return RunShell<LocalShell, StateMachine, ConnectionBias>(conf);
1909 else
1910 return RunShell<LocalConsole, StateMachine, ConnectionBias>(conf);
1911 }
1912 else
1913 {
1914 if (conf.Get<int>("console")==0)
1915 return RunShell<LocalShell, StateMachineDim, ConnectionDimBias>(conf);
1916 else
1917 return RunShell<LocalConsole, StateMachineDim, ConnectionDimBias>(conf);
1918 }
1919 }
1920 /*catch (std::exception& e)
1921 {
1922 cerr << "Exception: " << e.what() << endl;
1923 return -1;
1924 }*/
1925
1926 return 0;
1927}
Note: See TracBrowser for help on using the repository browser.