FACT++  1.0
biasctrl.cc
Go to the documentation of this file.
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 "StateMachineAsio.h"
10 #include "ConnectionUSB.h"
11 #include "Configuration.h"
12 #include "Console.h"
13 #include "externals/PixelMap.h"
14 
15 #include "tools.h"
16 
17 #include "LocalControl.h"
18 #include "HeadersBIAS.h"
19 
20 namespace ba = boost::asio;
21 namespace bs = boost::system;
22 namespace dummy = ba::placeholders;
23 
24 using namespace std::placeholders;
25 using namespace std;
26 
27 // We can do that because we do not include other headers than HeadersBIAS
28 using namespace BIAS;
29 
30 // ------------------------------------------------------------------------
31 
33 {
34  boost::asio::deadline_timer fSyncTimer;
35  boost::asio::deadline_timer fRampTimer;
36  boost::asio::deadline_timer fUpdateTimer;
37 
38  vector<uint8_t> fBuffer;
39  vector<uint8_t> fBufferRamp;
40  vector<uint8_t> fBufferUpdate;
41 
42  bool fIsVerbose;
44 
45  vector<bool> fPresent;
46 
47  int64_t fWrapCounter;
48  int64_t fSendCounter;
49 
50  int16_t fGlobalDacCmd; // Command value to be reached
51 
52  int16_t fRampStep;
53  int16_t fRampTime;
54 
55  uint32_t fUpdateTime;
56  uint16_t fSyncTime;
57  uint32_t fReconnectDelay;
58 
60  bool fIsRamping;
62 
63  vector<uint64_t> fCounter;
64 
66 
67  int32_t fEmergencyLimit;
69 
70 protected:
71 
72  vector<int16_t> fCurrent; // Current in ADC units (12bit = 5mA)
73 
74  virtual void UpdateV(const Time = Time())
75  {
76  }
77 
78  virtual void UpdateVgapd()
79  {
80  }
81 
82 public:
83  virtual void UpdateVA()
84  {
85  }
86 
87  // ====================================================
88 
89 protected:
90  vector<float> fOperationVoltage; // Operation voltage of GAPDs
91  //vector<float> fChannelOffset; // User defined channel offset
92 
93  vector<float> fCalibrationOffset; // Bias crate channel offset
94  vector<float> fCalibrationSlope; // Bias crate channel slope
95 
96  float fVoltageMaxAbs; // Maximum voltage
97  float fVoltageMaxRel; // Maximum voltgage above (what?)
98 
99  vector<uint16_t> fDacTarget; // Target values
100  vector<uint16_t> fDacCommand; // Last sent command value
101  vector<uint16_t> fDacActual; // Actual value
102 
103  // ====================================================
104 
105 private:
106  vector<char> GetCmd(uint16_t board, uint16_t channel, Command_t cmd, uint16_t dac=0)
107  {
108  vector<char> data(3);
109 
110  /*
111  if (board>kNumBoards)
112  return;
113  if (channel>kNumChannelsPerBoard)
114  return;
115  if (dac>0xfff)
116  return;
117  */
118 
119  data[0] = (cmd<<5) | (board<<1) | (((channel&16)>>4) & 1);
120  data[1] = (channel<<4) | (dac>>8);
121  data[2] = dac&0xff;
122 
123  return data;
124  }
125 
126  vector<char> GetCmd(Command_t cmd, uint16_t id=0, uint16_t dac=0)
127  {
128  const unsigned int board = id/kNumChannelsPerBoard;
129  const unsigned int channel = id%kNumChannelsPerBoard;
130 
131  return GetCmd(board, channel, cmd, dac);
132  }
133 
134  bool CheckMessageLength(int received, int expected, const string &msg)
135  {
136  if (received==expected)
137  return true;
138 
139  ostringstream str;
140  str << msg << ": Expected " << expected << " bytes in answer, but got " << received << endl;
141  Error(str);
142 
143  return false;
144  }
145 
146  bool EvalAnswer(const uint8_t *answer, uint16_t id, int command)
147  {
148  answer += id*3;
149 
150  const uint16_t status = (answer[0]>>7)&1;
151  const uint16_t wrap = (answer[0]>>4)&7;
152  const uint16_t ddd = ((uint16_t(answer[0])&0xf)<<8) | answer[1];
153  const uint16_t error = (answer[2]>>4)&0xf;
154  const uint16_t board = answer[2]&0xf;
155 
156  // 0x10 00 7f
157  // status = 0
158  // wrap = 1
159  // ddd = 0
160  // error = not present
161  // board = 15
162 
163  /*
164  Out() << dec << setw(2) << board << '|' << wrap << " ";
165  if (id%8==7)
166  Out() << endl;
167  */
168 
169  if (fWrapCounter>=0)
170  {
171  if ((fWrapCounter+1)%8 != wrap)
172  {
173  ostringstream msg;
174  msg << "Corrupted answer (id=" << id << "): received wrap counter " << wrap << " doesn't match last one " << fWrapCounter << " ";
175  msg << " (fSendCounter=" << fSendCounter << ")";
176  Error(msg);
177  return false;
178  }
179  }
180 
181  fWrapCounter = wrap;
182 
183  if (command==kSynchronize)
184  {
185  ostringstream msg;
186  msg << hex << setfill('0');
187  msg << "Initial answer received: 0x";
188  msg << setw(2) << (int)answer[2];
189  msg << setw(2) << (int)answer[1];
190  msg << setw(2) << (int)answer[0];
191  Message(msg);
192 
193  if (status!=0 || ddd!=0 || error!=0 || board!=0)
194  {
195  Warn("Initial answer doesn't seem to be a reset as naively expected.");
196 
197  //ostringstream msg;
198  //msg << hex << setfill('0');
199  //msg << "S=" << status << " D=" << ddd << " E=" << error << " B=" << board;
200  //Message(msg);
201  }
202 
203  fSendCounter = wrap;
204 
205  msg.str("");
206  msg << "Setting fSendCounter to " << wrap;
207  Info(msg);
208 
209  return true;
210  }
211 
212  if (error==0x8) // No device
213  {
214  Message("Reset button on crate pressed!");
215  RampAllDacs(0);
216  return true;
217  }
218 
219  if (command==kCmdReset)
220  {
221  if (status==0 && ddd==0 && error==0 && board==0)
222  {
223  Message("Reset successfully executed.");
224  return true;
225  }
226 
227  Warn("Answer to 'reset' command contains unexpected data.");
228  return false;
229  }
230 
231  if (command==kCmdGlobalSet)
232  {
233  if (status==0 && ddd==0 && error==0 && board==0)
234  {
235  for (int i=0; i<kNumChannels; i++)
236  fDacActual[i] = fGlobalDacCmd;
237 
238  fGlobalDacCmd = -1;
239 
240  return true;
241  }
242 
243  Warn("Answer to 'global set' command contains unexpected data.");
244  return false;
245  }
246 
247  if ((command&0xff)==kExpertChannelSet)
248  id = command>>8;
249 
250  const int cmd = command&3;
251 
252  if (cmd==kCmdRead || cmd==kCmdChannelSet)
253  {
254  if (board!=id/kNumChannelsPerBoard)
255  {
256  ostringstream out;
257  out << "Talked to board " << id/kNumChannelsPerBoard << ", but got answer from board " << board << " (fSendCounter=" << fSendCounter << ")";
258  Error(out);
259  return false;
260  }
261 
262  // Not present
263  if (error==0x7 || error==0xf)
264  {
265  fPresent[board] = false;
266  fCurrent[id] = 0x8000;
267  return true;
268  }
269 
270  // There is no -0 therefore we make a trick and replace it by -1.
271  // This is not harmfull, because typical zero currents are in the
272  // order of one to three bits anyway and they are never stable.
273  fCurrent[id] = status ? -(ddd==0?1:ddd) : ddd;
274  fPresent[board] = true;
275 
276  if (!fEmergencyShutdown)
277  {
278  if (fCurrent[id]<0)
279  {
280  Warn("OverCurrent detected.");
281  fEmergencyShutdown = true;
282  }
283 
284  if (fEmergencyLimit>0 && fCurrent[id]>fEmergencyLimit && !fEmergencyShutdown)
285  {
286  Warn("Emergency limit exceeded.");
287  fEmergencyShutdown = true;
288  }
289 
290  if (fEmergencyShutdown)
291  {
292  Error("Emergency ramp down initiated.");
293  Dim::SendCommandNB("MCP/STOP");
294  RampAllDacs(0);
295  }
296  }
297  }
298 
299  if (cmd==kCmdChannelSet)
300  fDacActual[id] = fDacCommand[id];
301 
302  return true;
303 
304  }
305 
306 private:
308  {
309  const Time now;
310 
311  // If we have been connected without a diconnect for at least 60s
312  // we can reset the delay.
313  if (now-fLastConnect>boost::posix_time::seconds(60))
314  fReconnectDelay = 1;
315 
316  ostringstream msg;
317  msg << "Automatic reconnect in " << fReconnectDelay << "s after being connected for ";
318  msg << (now-fLastConnect).seconds() << "s";
319  Info(msg);
320 
321  CloseImp(fReconnectDelay);
322  fReconnectDelay *= 2;
323  }
324 
325  void HandleReceivedData(const vector<uint8_t> &buf, size_t bytes_received, int command, int send_counter)
326  {
327 #ifdef DEBUG
328  ofstream fout("received.txt", ios::app);
329  fout << Time() << ": ";
330  for (unsigned int i=0; i<bytes_received; i++)
331  fout << hex << setfill('0') << setw(2) << (uint16_t)buf[i];
332  fout << endl;
333 #endif
334 
335  // Now print the received message if requested by the user
336  if (fIsVerbose/* && command!=kUpdate*/)
337  {
338  Out() << endl << kBold << dec << "Data received (size=" << bytes_received << "):" << endl;
339  Out() << " Command=" << command << " fWrapCounter=" << fWrapCounter << " fSendCounter=" << fSendCounter << " fIsInitializing=" << fIsInitializing << " fIsRamping=" << fIsRamping;
340  Out() << hex << setfill('0');
341 
342  for (size_t i=0; i<bytes_received/3; i++)
343  {
344  if (i%8==0)
345  Out() << '\n' << setw(2) << bytes_received/24 << "| ";
346 
347  Out() << setw(2) << uint16_t(buf[i*3+2]);
348  Out() << setw(2) << uint16_t(buf[i*3+1]);
349  Out() << setw(2) << uint16_t(buf[i*3+0]) << " ";
350  }
351  Out() << endl;
352  }
353 
354  const int cmd = command&0xf;
355 
356  // Check the number of received_byted according to the answer expected
357  if ((cmd==kSynchronize && !CheckMessageLength(bytes_received, 3, "Synchronization")) ||
358  (cmd==kCmdReset && !CheckMessageLength(bytes_received, 3, "CmdReset")) ||
359  (cmd==kCmdRead && !CheckMessageLength(bytes_received, 3*kNumChannels, "CmdRead")) ||
360  (cmd==kCmdChannelSet && !CheckMessageLength(bytes_received, 3*kNumChannels, "CmdChannelSet")) ||
361  (cmd==kExpertChannelSet && !CheckMessageLength(bytes_received, 3, "CmdExpertChannelSet")))
362  {
363  CloseImp(-1);
364  return;
365  }
366 
367  // Now evaluate the whole bunch of messages
368  for (size_t i=0; i<bytes_received/3; i++)
369  {
370  if (!EvalAnswer(buf.data(), i, command))
371  {
372  DelayedReconnect();
373  return;
374  }
375  }
376 
377  if (command==kSynchronize)
378  {
379  Message("Stream successfully synchronized.");
380  fIsInitializing = 2;
381 
382  // Cancel sending of the next 0
383  fSyncTimer.cancel();
384  fCounter[0]++;
385 
386  // Start continous reading of all channels
387  ScheduleUpdate(100);
388  return;
389  }
390 
391  if (send_counter%8 != fWrapCounter)
392  {
393  ostringstream msg;
394  msg << "Corrupted answer: received wrap counter " << fWrapCounter << " is not send counter " << send_counter << "%8.";
395  Error(msg);
396 
397  DelayedReconnect();
398  }
399 
400 
401  // Check if new values have been received
402  if (cmd==kCmdRead || cmd==kCmdChannelSet || cmd==kExpertChannelSet)
403  UpdateVA();
404 
405  // ----- Take action depending on what is going on -----
406 
407  if (command==kCmdReset)
408  {
409  Message("Reset command successfully answered...");
410 
411  fCounter[1]++;
412 
413  // Re-start cyclic reading of values after a short time
414  // to allow the currents to become stable. This ensures that
415  // we get an update soon but wait long enough to get reasonable
416  // values
417  fUpdateTimer.cancel();
418 
419  if (fUpdateTime==0)
420  ReadAllChannels(true);
421  else
422  {
423  Message("...restarting automatic readout.");
424  ScheduleUpdate(100);
425  }
426  }
427 
428  if (command==kResetChannels)
429  {
430  ExpertReset(false);
431  fCounter[5]++;
432  }
433 
434  if (command==kUpdate)
435  {
436  ScheduleUpdate(fUpdateTime);
437  fCounter[2]++;
438  }
439 
440  // If we are ramping, schedule a new ramp step
441  if (command==kCmdChannelSet && fIsRamping)
442  {
443  bool oc = false;
444  for (int ch=0; ch<kNumChannels; ch++)
445  if (fPresent[ch/kNumChannelsPerBoard] && fCurrent[ch]<0)
446  oc = true;
447 
448  if (oc)
449  {
450  if (!fEmergencyShutdown)
451  {
452  Warn("OverCurrent detected - emergency ramp down initiated.");
453  Dim::SendCommandNB("MCP/STOP");
454  RampAllDacs(0);
455  fEmergencyShutdown = true;
456  }
457  }
458  else
459  ScheduleRampStep();
460 
461  fCounter[3]++;
462  }
463 
464  if (command==kCmdRead)
465  fCounter[4]++;
466 
467  if ((command&0xff)==kExpertChannelSet)
468  fCounter[6]++;
469 
470  if (command==kCmdGlobalSet)
471  fCounter[7]++;
472  }
473 
474  void HandleReceivedData(const bs::error_code& err, size_t bytes_received, int command, int send_counter)
475  {
476  // Do not schedule a new read if the connection failed.
477  if (bytes_received==0 || err)
478  {
479  if (err==ba::error::eof)
480  {
481  ostringstream msg;
482  msg << "Connection closed by remote host (BIAS, fSendCounter=" << fSendCounter << ")";
483  Warn(msg);
484  }
485 
486  // 107: Transport endpoint is not connected (bs::error_code(107, bs::system_category))
487  // 125: Operation canceled
488  if (err && err!=ba::error::eof && // Connection closed by remote host
489  err!=ba::error::basic_errors::not_connected && // Connection closed by remote host
490  err!=ba::error::basic_errors::operation_aborted) // Connection closed by us
491  {
492  ostringstream str;
493  str << "Reading from " << URL() << ": " << err.message() << " (" << err << ")";// << endl;
494  Error(str);
495  }
496  CloseImp(-1);//err!=ba::error::basic_errors::operation_aborted);
497  return;
498  }
499 
500  // Check if the number of received bytes is correctly dividable by 3
501  // This check should never fail - just for sanity
502  if (bytes_received%3)
503  {
504  Error("Number of received bytes not a multiple of 3, can't read data.");
505  CloseImp(-1);
506  return;
507  }
508 
509  // We have three different parallel streams:
510  // 1) The setting of voltages due to ramping
511  // 2) The cynclic request of the currents
512  // 3) Answers to commands
513  // For each of these three streams an own buffer is needed, otherwise
514  // a buffer which is filled in the background might overwrite
515  // a buffer which is currently evaluated. In all other programs
516  // this is no problem because the boards don't answer and if
517  // they do the answer identifies itself. Consequently,
518  // there is always only one async_read in progress. Here we have
519  // three streams which need to be connected somehow to the
520  // commands.
521 
522  // Maybe a better possibility would be to setup a command
523  // queue (each command will be queued in a buffer)
524  // and whenever an answer has been received, a new async_read is
525  // scheduled.
526  // Build a command queue<pair<command, vector<char>>>
528  // in handleReceivedData
529 
530  switch (command&0xff)
531  {
532  case kSynchronize:
533  case kCmdReset:
534  case kExpertChannelSet:
535  case kCmdGlobalSet:
536  case kResetChannels:
537  case kCmdRead:
538  HandleReceivedData(fBuffer, bytes_received, command, send_counter);
539  fWaitingForAnswer = -1;
540  return;
541 
542  case kCmdChannelSet:
543  HandleReceivedData(fBufferRamp, bytes_received, command, send_counter);
544  return;
545 
546  case kUpdate:
547  HandleReceivedData(fBufferUpdate, bytes_received, command, send_counter);
548  return;
549  }
550  }
551 
552  // --------------------------------------------------------------------
553 
554  void HandleSyncTimer(int counter, const bs::error_code &error)
555  {
556  if (error==ba::error::basic_errors::operation_aborted)
557  {
558  if (fIsInitializing==1)
559  Warn("Synchronization aborted...");
560  // case 0 and 2 should not happen
561  return;
562  }
563 
564  if (error)
565  {
566  ostringstream str;
567  str << "Synchronization timer: " << error.message() << " (" << error << ")";// << endl;
568  Error(str);
569 
570  CloseImp(-1);
571  return;
572  }
573 
574  if (!is_open())
575  {
576  Warn("Synchronization in progress, but disconnected.");
577  return;
578  }
579 
580  ostringstream msg;
581  msg << "Synchronization time expired (" << counter << ")";
582  Info(msg);
583 
584  if (fIsInitializing)
585  {
586  PostMessage("\0", 1);
587 
588  if (counter==2)
589  {
590  Error("Synchronization attempt timed out.");
591  CloseImp(-1);
592  return;
593  }
594 
595  ScheduleSync(counter+1);
596  return;
597  }
598 
599  Info("Synchronisation successfull.");
600  }
601 
602  void ScheduleSync(int counter=0)
603  {
604  fSyncTimer.expires_from_now(boost::posix_time::milliseconds(fSyncTime));
605  fSyncTimer.async_wait(boost::bind(&ConnectionBias::HandleSyncTimer, this, counter, dummy::error));
606  }
607 
608  // This is called when a connection was established
610  {
611  // We connect for the first time or haven't received
612  // a valid warp counter yet... this procedure also sets
613  // our volatges to 0 if we have connected but never received
614  // any answer.
615  if (fWrapCounter<0)
616  {
617  fDacTarget.assign(kNumChannels, 0);
618  fDacCommand.assign(kNumChannels, 0);
619  fDacActual.assign(kNumChannels, 0);
620  }
621 
622  // Reset everything....
623  fSendCounter = -1;
624  fWrapCounter = -1;
625  fGlobalDacCmd = -1;
626  fIsInitializing = 1;
627  fIsRamping = false;
628 
629  fLastConnect = Time();
630 
631  // Send a single 0 (and possible two consecutive 0's
632  // to make sure we are in sync with the device)
633  PostMessage("\0", 1);
634  AsyncRead(ba::buffer(fBuffer, 3), kSynchronize, 0);//++fSendCounter);
635  fWaitingForAnswer = kSynchronize;
636 
637  // Wait for some time before sending the next 0
638  ScheduleSync();
639  }
640 
641  // --------------------------------------------------------------------
642 
643  void HandleUpdateTimer(const bs::error_code &error)
644  {
645  if (error==ba::error::basic_errors::operation_aborted)
646  {
647  Warn("Update timer aborted...");
648  fIsRamping = false;
649  return;
650  }
651 
652  if (error)
653  {
654  ostringstream str;
655  str << "Update timer: " << error.message() << " (" << error << ")";// << endl;
656  Error(str);
657 
658  CloseImp(-1);
659  return;
660  }
661 
662  if (!is_open())
663  return;
664 
665  if (fUpdateTime==0 && fIsInitializing!=2)
666  return;
667 
668  if (fIsRamping)
669  ScheduleUpdate(fUpdateTime);
670  else
671  ReadAllChannels(true);
672 
673  fIsInitializing = 0;
674  }
675 
676  void ScheduleUpdate(int millisec)
677  {
678  fUpdateTimer.expires_from_now(boost::posix_time::milliseconds(millisec));
679  fUpdateTimer.async_wait(boost::bind(&ConnectionBias::HandleUpdateTimer, this, dummy::error));
680  }
681 
682  // --------------------------------------------------------------------
683 
684  void PrintLineCmdDac(int b, int ch, const vector<uint16_t> &dac)
685  {
686  Out() << setw(2) << b << "|";
687 
688  for (int c=ch; c<ch+4; c++)
689  {
690  const int id = c+kNumChannelsPerBoard*b;
691  Out() << " " << setw(4) << int32_t(dac[id])<<"/"<<fDacActual[id] << ":" << setw(5) << ConvertDacToVolt(id, fDacTarget[id]);
692  }
693  Out() << endl;
694  }
695 
696  void PrintCommandDac(const vector<uint16_t> &dac)
697  {
698  Out() << dec << setprecision(2) << fixed << setfill(' ');
699  for (int b=0; b<kNumBoards; b++)
700  {
701  if (!fPresent[b])
702  {
703  Out() << setw(2) << b << "-" << endl;
704  continue;
705  }
706 
707  PrintLineCmdDac(b, 0, dac);
708  PrintLineCmdDac(b, 4, dac);
709  PrintLineCmdDac(b, 8, dac);
710  PrintLineCmdDac(b, 12, dac);
711  PrintLineCmdDac(b, 16, dac);
712  PrintLineCmdDac(b, 20, dac);
713  PrintLineCmdDac(b, 24, dac);
714  PrintLineCmdDac(b, 28, dac);
715  }
716  }
717 
718  void SetAllChannels(const vector<uint16_t> &dac, bool special=false)
719  {
720  if (fIsDummyMode)
721  {
722  PrintCommandDac(dac);
723  return;
724  }
725 
726  vector<char> data;
727  data.reserve(kNumChannels*3);
728 
729  for (int ch=0; ch<kNumChannels; ch++)
730  {
731  // FIXME: dac[ch] += calib_offset
732  const vector<char> cmd = GetCmd(kCmdChannelSet, ch, dac[ch]);
733  data.insert(data.end(), cmd.begin(), cmd.end());
734 
735  fDacCommand[ch] = dac[ch];
736  }
737 
738  fSendCounter += kNumChannels;
739 
740  PostMessage(data);
741  AsyncRead(ba::buffer(special ? fBuffer : fBufferRamp, kNumChannels*3),
742  special ? kResetChannels : kCmdChannelSet, fSendCounter);
743 
744  if (special)
745  fWaitingForAnswer = kResetChannels;
746  }
747 
748  uint16_t RampOneStep(uint16_t ch)
749  {
750  if (fDacTarget[ch]>fDacActual[ch])
751  return fDacActual[ch]+fRampStep>fDacTarget[ch] ? fDacTarget[ch] : fDacActual[ch]+fRampStep;
752 
753  if (fDacTarget[ch]<fDacActual[ch])
754  return fDacActual[ch]-fRampStep<fDacTarget[ch] ? fDacTarget[ch] : fDacActual[ch]-fRampStep;
755 
756  return fDacActual[ch];
757  }
758 
759  bool RampOneStep()
760  {
761  if (fRampTime<0)
762  {
763  Warn("Ramping step time not yet set... ramping not started.");
764  return false;
765  }
766  if (fRampStep<0)
767  {
768  Warn("Ramping step not yet set... ramping not started.");
769  return false;
770  }
771 
772  vector<uint16_t> dac(kNumChannels);
773 
774  bool identical = true;
775  for (int ch=0; ch<kNumChannels; ch++)
776  {
777  dac[ch] = RampOneStep(ch);
778  if (dac[ch]!=fDacActual[ch] && fPresent[ch/kNumChannelsPerBoard])
779  identical = false;
780  }
781 
782  if (identical)
783  {
784  Info("Ramping: target values reached.");
785  return false;
786  }
787 
788  if (fWaitingForAnswer<0)
789  {
790  SetAllChannels(dac);
791  return true;
792  }
793 
794  ostringstream msg;
795  msg << "RampOneStep while waiting for answer to last command (id=" << fWaitingForAnswer << ")... ramp step delayed.";
796  Warn(msg);
797 
798  // Delay ramping
799  ScheduleRampStep();
800  return true;
801  }
802 
803  void HandleRampTimer(const bs::error_code &error)
804  {
805  if (error==ba::error::basic_errors::operation_aborted)
806  {
807  Warn("Ramping aborted...");
808  fIsRamping = false;
809  return;
810  }
811 
812  if (error)
813  {
814  ostringstream str;
815  str << "Ramping timer: " << error.message() << " (" << error << ")";// << endl;
816  Error(str);
817 
818  fIsRamping = false;
819  CloseImp(-1);
820  return;
821  }
822 
823  if (!is_open())
824  {
825  Warn("Ramping in progress, but disconnected.");
826  fIsRamping = false;
827  return;
828  }
829 
830  if (!fIsRamping)
831  {
832  Error("Ramp handler called although no ramping in progress.");
833  return;
834  }
835 
836  // Check whether the deadline has passed. We compare the deadline
837  // against the current time since a new asynchronous operation
838  // may have moved the deadline before this actor had a chance
839  // to run.
840  if (fRampTimer.expires_at() > ba::deadline_timer::traits_type::now())
841  return;
842 
843  fIsRamping = RampOneStep();
844  }
845 
847  {
848  fRampTimer.expires_from_now(boost::posix_time::milliseconds(fRampTime));
849  fRampTimer.async_wait(boost::bind(&ConnectionBias::HandleRampTimer, this, dummy::error));
850  }
851 
852 public:
853  ConnectionBias(ba::io_service& ioservice, MessageImp &imp) : ConnectionUSB(ioservice, imp()),
854  fSyncTimer(ioservice),
855  fRampTimer(ioservice),
856  fUpdateTimer(ioservice),
857  fBuffer(3*kNumChannels),
858  fBufferRamp(3*kNumChannels),
859  fBufferUpdate(3*kNumChannels),
860  fIsVerbose(false),
861  fIsDummyMode(false),
862  fPresent(kNumBoards),
863  fWrapCounter(-1),
864  fRampStep(-1),
865  fRampTime(-1),
866  fUpdateTime(3000),
867  fSyncTime(333),
868  fReconnectDelay(1),
869  fIsRamping(false),
870  fWaitingForAnswer(-1),
871  fCounter(8),
872  fEmergencyLimit(0),
873  fEmergencyShutdown(false),
874  fCurrent(kNumChannels),
875  fOperationVoltage(kNumChannels, 0),
876  //fChannelOffset(kNumChannels),
877  fCalibrationOffset(kNumChannels),
878  fCalibrationSlope(kNumChannels, 90000),
879  fVoltageMaxAbs(75),
880  fVoltageMaxRel(2),
881  fDacTarget(kNumChannels),
882  fDacCommand(kNumChannels),
883  fDacActual(kNumChannels)
884  {
885  SetLogStream(&imp);
886  }
887 
888  // --------------------------------------------------------------------
889 
890  bool CheckDac(uint16_t dac)
891  {
892  if (dac<4096)
893  return true;
894 
895  ostringstream msg;
896  msg << "CheckDac - Dac value of " << dac << " exceeds maximum of 4095.";
897  Error(msg);
898  return false;
899  }
900 
901  bool CheckChannel(uint16_t ch)
902  {
903  if (ch<kNumChannels)
904  return true;
905 
906  ostringstream msg;
907  msg << "CheckChannel - Channel " << ch << " out of range [0;" << kNumChannels-1 << "].";
908  Error(msg);
909  return false;
910  }
911 
912  bool CheckChannelVoltage(uint16_t ch, float volt)
913  {
914  if (volt>fVoltageMaxAbs)
915  {
916  ostringstream msg;
917  msg << "CheckChannelVoltage - Set voltage " << volt << "V of channel " << ch << " exceeds absolute limit of " << fVoltageMaxAbs << "V.";
918  Warn(msg);
919  return false;
920  }
921 
922  if (fOperationVoltage[ch]<=0)
923  return true;
924 
925  if (volt>fOperationVoltage[ch]+fVoltageMaxRel) // FIXME: fVoltageMaxRel!!!
926  {
927  ostringstream msg;
928  msg << "CheckChannelVoltage - Set voltage " << volt << "V of channel " << ch << " exceeds limit of " << fVoltageMaxRel << "V above operation voltage " << fOperationVoltage[ch] << "V + limit " << fVoltageMaxRel << "V.";
929  Error(msg);
930  return false;
931  }
932 
933  return true;
934  }
935 
936  // --------------------------------------------------------------------
937 
938  bool RampSingleChannelDac(uint16_t ch, uint16_t dac)
939  {
940  if (!CheckChannel(ch))
941  return false;
942 
943  if (!CheckDac(dac))
944  return false;
945 
946  fDacTarget[ch] = dac;
947  UpdateV();
948 
949  if (!fIsRamping)
950  fIsRamping = RampOneStep();
951 
952  return true;
953  }
954 
955  bool RampAllChannelsDac(const vector<uint16_t> &dac)
956  {
957  for (int ch=0; ch<kNumChannels; ch++)
958  if (!CheckDac(dac[ch]))
959  return false;
960 
961  fDacTarget = dac;
962  UpdateV();
963 
964  if (!fIsRamping)
965  fIsRamping = RampOneStep();
966 
967  return true;
968  }
969 
970  bool RampAllDacs(uint16_t dac)
971  {
972  return RampAllChannelsDac(vector<uint16_t>(kNumChannels, dac));
973  }
974 
975  // --------------------------------------------------------------------
976 
977  uint16_t ConvertVoltToDac(uint16_t ch, double volt)
978  {
979  if (fCalibrationSlope[ch]<=0)
980  return 0;
981 
982  const double current = (volt-fCalibrationOffset[ch])/fCalibrationSlope[ch];
983  return current<0 ? 0 : nearbyint(current*4096000); // Current [A] to dac [ /= 1mA/4096]
984  }
985 
986  double ConvertDacToVolt(uint16_t ch, uint16_t dac)
987  {
988  if (fCalibrationSlope[ch]<=0)
989  return 0;
990 
991  const double current = dac/4096000.; // Convert dac to current [A] [ *= 1mA/4096]
992  return current*fCalibrationSlope[ch] + fCalibrationOffset[ch];
993  }
994 
995  // --------------------------------------------------------------------
996 
997  bool RampSingleChannelVoltage(uint16_t ch, float volt)
998  {
999  if (!CheckChannel(ch))
1000  return false;
1001 
1002  if (!CheckChannelVoltage(ch, volt))
1003  return false;
1004 
1005  const uint16_t dac = ConvertVoltToDac(ch, volt);
1006  return RampSingleChannelDac(ch, dac);
1007  }
1008 
1009  bool RampAllChannelsVoltage(const vector<float> &volt)
1010  {
1011  vector<uint16_t> dac(kNumChannels);
1012  for (size_t ch=0; ch<kNumChannels; ch++)
1013  {
1014  if (!CheckChannelVoltage(ch, volt[ch]))
1015  return false;
1016 
1017  dac[ch] = ConvertVoltToDac(ch, volt[ch]);
1018  }
1019 
1020  return RampAllChannelsDac(dac);
1021  }
1022 
1023  bool RampAllVoltages(float volt)
1024  {
1025  return RampAllChannelsVoltage(vector<float>(kNumChannels, volt));
1026  }
1027 
1028  // --------------------------------------------------------------------
1029 
1030  /*
1031  bool RampSingleChannelOffset(uint16_t ch, float offset, bool relative)
1032  {
1033  if (!CheckChannel(ch))
1034  return false;
1035 
1036 // if (relative)
1037 // offset += fDacActual[ch]*90./4096 - fBreakdownVoltage[ch];
1038 
1039  const float volt = fBreakdownVoltage[ch]>0 ? fBreakdownVoltage[ch] + offset : 0;
1040 
1041  if (!RampSingleChannelVoltage(ch, volt))
1042  return false;
1043 
1044  fChannelOffset[ch] = offset;
1045 
1046  return true;
1047  }
1048 
1049  bool RampAllChannelsOffset(vector<float> offset, bool relative)
1050  {
1051  vector<float> volt(kNumChannels);
1052 
1053 // if (relative)
1054 // for (size_t ch=0; ch<kNumChannels; ch++)
1055 // offset[ch] += fDacActual[ch]*90./4096 - fBreakdownVoltage[ch];
1056 
1057  for (size_t ch=0; ch<kNumChannels; ch++)
1058  volt[ch] = fBreakdownVoltage[ch]>0 ? fBreakdownVoltage[ch] + offset[ch] : 0;
1059 
1060  if (!RampAllChannelsVoltage(volt))
1061  return false;
1062 
1063  fChannelOffset = offset;
1064 
1065  return true;
1066  }
1067 
1068  bool RampAllOffsets(float offset, bool relative)
1069  {
1070  return RampAllChannelsOffset(vector<float>(kNumChannels, offset), relative);
1071  }
1072  */
1073 
1074  /*
1075  bool RampSingleChannelOvervoltage(float offset)
1076  {
1077  return RampAllChannelsOvervoltage(vector<float>(kNumChannels, offset));
1078  }
1079  bool RampAllOvervoltages(const vector<float> &overvoltage)
1080  {
1081  vector<float> volt(kNumChannels);
1082 
1083  for (size_t ch=0; ch<kNumChannels; ch++)
1084  volt[ch] = fBreakdownVoltage[ch] + fOvervoltage[ch] + fChannelOffset[ch];
1085 
1086 #warning What about empty channels?
1087 
1088  if (!RampAllChannelsVoltage(volt))
1089  return false;
1090 
1091  for (size_t ch=0; ch<kNumChannels; ch++)
1092  fOvervoltage[ch] = overvoltage[ch];
1093 
1094  return true;
1095  }*/
1096 
1097  // --------------------------------------------------------------------
1098 
1100  {
1101  if (fWaitingForAnswer>=0)
1102  {
1103  ostringstream msg;
1104  msg << "OverCurrentReset - Answer on last command (id=" << fWaitingForAnswer << ") not yet received.";
1105  Error(msg);
1106  return;
1107  }
1108 
1109  if (fIsRamping)
1110  {
1111  Warn("OverCurrentReset - Ramping in progres.");
1112  RampStop();
1113  }
1114 
1115  vector<uint16_t> dac(fDacActual);
1116 
1117  for (int ch=0; ch<kNumChannels; ch++)
1118  if (fCurrent[ch]<0)
1119  dac[ch] = 0;
1120 
1121  SetAllChannels(dac, true);
1122  }
1123 
1124  void ReadAllChannels(bool special = false)
1125  {
1126  if (!special && fWaitingForAnswer>=0)
1127  {
1128  ostringstream msg;
1129  msg << "ReadAllChannels - Answer on last command (id=" << fWaitingForAnswer << ") not yet received.";
1130  Error(msg);
1131  return;
1132  }
1133 
1134  vector<char> data;
1135  data.reserve(kNumChannels*3);
1136 
1137  for (int ch=0; ch<kNumChannels; ch++)
1138  {
1139  const vector<char> cmd = GetCmd(kCmdRead, ch);
1140  data.insert(data.end(), cmd.begin(), cmd.end());
1141  }
1142 
1143  fSendCounter += kNumChannels;
1144 
1145  PostMessage(data);
1146  AsyncRead(ba::buffer(special ? fBufferUpdate : fBuffer, kNumChannels*3),
1147  special ? kUpdate : kCmdRead, fSendCounter);
1148 
1149  if (!special)
1150  fWaitingForAnswer = kCmdRead;
1151  }
1152 
1153  bool SetReferences(const vector<float> &volt, const vector<float> &offset, const vector<float> &slope)
1154  {
1155  if (volt.size()!=kNumChannels)
1156  {
1157  ostringstream out;
1158  out << "SetReferences - Given vector has " << volt.size() << " elements - expected " << kNumChannels << endl;
1159  Error(out);
1160  return false;
1161  }
1162  if (offset.size()!=kNumChannels)
1163  {
1164  ostringstream out;
1165  out << "SetReferences - Given vector has " << offset.size() << " elements - expected " << kNumChannels << endl;
1166  Error(out);
1167  return false;
1168  }
1169  if (slope.size()!=kNumChannels)
1170  {
1171  ostringstream out;
1172  out << "SetReferences - Given vector has " << slope.size() << " elements - expected " << kNumChannels << endl;
1173  Error(out);
1174  return false;
1175  }
1176 
1177  fOperationVoltage = volt;
1178  fCalibrationOffset = offset;
1179  fCalibrationSlope = slope;
1180 
1181  UpdateVgapd();
1182 
1183  return true;
1184  }
1185 
1186  // --------------------------------------------------------------------
1187 
1188  void RampStop()
1189  {
1190  fRampTimer.cancel();
1191  fIsRamping = false;
1192 
1193  Message("Ramping stopped.");
1194  }
1195 
1196  void RampStart()
1197  {
1198  if (fIsRamping)
1199  {
1200  Warn("RampStart - Ramping already in progress... ignored.");
1201  return;
1202  }
1203 
1204  fIsRamping = RampOneStep();
1205  }
1206 
1207  void SetRampTime(uint16_t val)
1208  {
1209  fRampTime = val;
1210  }
1211 
1212  void SetRampStep(uint16_t val)
1213  {
1214  fRampStep = val;
1215  }
1216 
1217  uint16_t GetRampStepVolt() const
1218  {
1219  return fRampStep*90./4096;
1220  }
1221 
1222  bool IsRamping() const { return fIsRamping; }
1223 
1224  // -------------------------------------------------------------------
1225 
1226  void ExpertReset(bool expert_mode=true)
1227  {
1228  if (expert_mode && fWaitingForAnswer>=0)
1229  {
1230  ostringstream msg;
1231  msg << "ExpertReset - Answer on last command (id=" << fWaitingForAnswer << ") not yet received.";
1232  Error(msg);
1233  return;
1234  }
1235 
1236  if (expert_mode)
1237  Warn("EXPERT MODE: Sending reset.");
1238 
1239  PostMessage(GetCmd(kCmdReset));
1240  AsyncRead(ba::buffer(fBuffer, 3), kCmdReset, ++fSendCounter);
1241  fWaitingForAnswer = kCmdReset;
1242  }
1243 
1244 
1245  bool ExpertChannelSetDac(uint16_t ch, uint16_t dac)
1246  {
1247  if (fWaitingForAnswer>=0)
1248  {
1249  ostringstream msg;
1250  msg << "ExpertChannelSetDac - Answer on last command (id=" << fWaitingForAnswer << ") not yet received.";
1251  Error(msg);
1252  return false;
1253  }
1254 
1255  if (!CheckDac(dac))
1256  return false;
1257 
1258  fDacCommand[ch] = dac;
1259 
1260  ostringstream msg;
1261  msg << "EXPERT MODE: Sending 'ChannelSet' (set ch " << ch << " to DAC=" << dac << ")";
1262  Warn(msg);
1263 
1264  // FIXME: dac += calib_offset
1265  PostMessage(GetCmd(kCmdChannelSet, ch, dac));
1266  AsyncRead(ba::buffer(fBuffer, 3), kExpertChannelSet|(ch<<8), ++fSendCounter);
1267  fWaitingForAnswer = kExpertChannelSet|(ch<<8);
1268 
1269  return true;
1270  }
1271 
1272  bool ExpertChannelSetVolt(uint16_t ch, double volt)
1273  {
1274  return ExpertChannelSetDac(ch, volt*4096/90.);
1275  }
1276 
1277  bool ExpertGlobalSetDac(uint16_t dac)
1278  {
1279  if (fWaitingForAnswer>=0)
1280  {
1281  ostringstream msg;
1282  msg << "ExpertGlobalSetDac - Answer on last command (id=" << fWaitingForAnswer << ") not yet received.";
1283  Error(msg);
1284  return false;
1285  }
1286 
1287  if (!CheckDac(dac))
1288  return false;
1289 
1290  if (fGlobalDacCmd>=0)
1291  {
1292  Error("ExpertGlobalSetDac - Still waiting for previous answer to 'GlobalSet'");
1293  return false;
1294  }
1295 
1296  fGlobalDacCmd = dac;
1297 
1298  ostringstream msg;
1299  msg << "EXPERT MODE: Sending 'GlobalSet' (DAC=" << dac << ")";
1300  Warn(msg);
1301 
1302  PostMessage(GetCmd(kCmdGlobalSet, 0, dac));
1303  AsyncRead(ba::buffer(fBuffer, 3), kCmdGlobalSet, ++fSendCounter);
1304  fWaitingForAnswer = kCmdGlobalSet;
1305 
1306  return true;
1307  }
1308 
1309  bool ExpertGlobalSetVolt(float volt)
1310  {
1311  return ExpertGlobalSetDac(volt*4096/90);
1312  }
1313 
1314  // --------------------------------------------------------------------
1315 
1316  void SetVerbose(bool b)
1317  {
1318  fIsVerbose = b;
1319  }
1320 
1321  void SetDummyMode(bool b)
1322  {
1323  fIsDummyMode = b;
1324  }
1325 
1326  void PrintInfo()
1327  {
1328  Out() << endl << kBold << dec << '\n';
1329  Out() << "fWrapCounter = " << fWrapCounter << '\n';
1330  Out() << "fSendCounter = " << fSendCounter%8 << " (" << fSendCounter << ")" << '\n';
1331  Out() << "fIsInitializing = " << fIsInitializing << '\n';
1332  Out() << "fIsRamping = " << fIsRamping << '\n';
1333  Out() << "Answer counter:" << '\n';
1334  Out() << " - Synchronization: " << fCounter[0] << '\n';
1335  Out() << " - Reset: " << fCounter[1] << '\n';
1336  Out() << " - Request update: " << fCounter[2] << '\n';
1337  Out() << " - Ramp step: " << fCounter[3] << '\n';
1338  Out() << " - Read: " << fCounter[4] << '\n';
1339  Out() << " - Reset channels: " << fCounter[5] << '\n';
1340  Out() << " - Global set: " << fCounter[7] << '\n';
1341  Out() << " - Channel set: " << fCounter[6] << '\n' << endl;
1342  }
1343 
1344  void PrintLineA(int b, int ch)
1345  {
1346  Out() << setw(2) << b << "|";
1347 
1348  for (int c=ch; c<ch+8; c++)
1349  {
1350  const int id = c+kNumChannelsPerBoard*b;
1351  Out() << (fCurrent[id]<0?kRed:kGreen);
1352  Out() << " " << setw(7) << abs(fCurrent[id])*5000/4096.;
1353  }
1354  Out() << endl;
1355 
1356  }
1357 
1358  void PrintA()
1359  {
1360  Out() << dec << setprecision(2) << fixed << setfill(' ');
1361  for (int b=0; b<kNumBoards; b++)
1362  {
1363  if (!fPresent[b])
1364  {
1365  Out() << setw(2) << b << "-" << endl;
1366  continue;
1367  }
1368 
1369  PrintLineA(b, 0);
1370  PrintLineA(b, 8);
1371  PrintLineA(b, 16);
1372  PrintLineA(b, 24);
1373  }
1374  }
1375 
1376  void PrintLineV(int b, int ch)
1377  {
1378  Out() << setw(2) << b << "|";
1379 
1380  for (int c=ch; c<ch+4; c++)
1381  {
1382  const int id = c+kNumChannelsPerBoard*b;
1383  Out() << " ";
1384  Out() << (fDacActual[id]==fDacTarget[id]?kGreen:kRed);
1385  //Out() << setw(5) << fDacActual[id]*90/4096. << '/';
1386  //Out() << setw(5) << fDacTarget[id]*90/4096.;
1387 
1388  Out() << setw(5) << ConvertDacToVolt(id, fDacActual[id]) << '/';
1389  Out() << setw(5) << ConvertDacToVolt(id, fDacTarget[id]);
1390  }
1391  Out() << endl;
1392  }
1393 
1394  void PrintV()
1395  {
1396  Out() << dec << setprecision(2) << fixed << setfill(' ');
1397  for (int b=0; b<kNumBoards; b++)
1398  {
1399  if (!fPresent[b])
1400  {
1401  Out() << setw(2) << b << "-" << endl;
1402  continue;
1403  }
1404 
1405  PrintLineV(b, 0);
1406  PrintLineV(b, 4);
1407  PrintLineV(b, 8);
1408  PrintLineV(b, 12);
1409  PrintLineV(b, 16);
1410  PrintLineV(b, 20);
1411  PrintLineV(b, 24);
1412  PrintLineV(b, 28);
1413  }
1414  }
1415 
1416  void PrintLineGapd(int b, int ch)
1417  {
1418  Out() << setw(2) << b << "|";
1419 
1420  for (int c=ch; c<ch+8; c++)
1421  {
1422  const int id = c+kNumChannelsPerBoard*b;
1423  Out() << " " << setw(5) << fOperationVoltage[id];
1424  }
1425  Out() << endl;
1426  }
1427 
1429  {
1430  Out() << dec << setprecision(2) << fixed << setfill(' ');
1431  for (int b=0; b<kNumBoards; b++)
1432  {
1433  if (!fPresent[b])
1434  {
1435  Out() << setw(2) << b << "-" << endl;
1436  continue;
1437  }
1438 
1439  PrintLineGapd(b, 0);
1440  PrintLineGapd(b, 8);
1441  PrintLineGapd(b, 16);
1442  PrintLineGapd(b, 24);
1443  }
1444  }
1445 
1446  // -------------------------------------------------------------------
1447 
1448  void SetUpdateInterval(uint32_t val)
1449  {
1450  fUpdateTime = val;
1451 
1452  if (!IsConnected() || fIsInitializing)
1453  return;
1454 
1455  fUpdateTimer.cancel();
1456 
1457  if (fUpdateTime>0)
1458  ScheduleUpdate(fUpdateTime);
1459  }
1460 
1461  void SetSyncDelay(uint16_t val)
1462  {
1463  fSyncTime = val;
1464  }
1465 
1466  void SetVoltMaxAbs(float max)
1467  {
1468  if (max>90)
1469  max = 90;
1470  if (max<0)
1471  max = 0;
1472 
1473  fVoltageMaxAbs = max;
1474  }
1475 
1476  void SetVoltMaxRel(float max)
1477  {
1478  if (max>90)
1479  max = 90;
1480  if (max<0)
1481  max = 0;
1482 
1483  fVoltageMaxRel = max;
1484  }
1485 
1486  uint16_t GetVoltMaxAbs() const
1487  {
1488  return fVoltageMaxAbs;
1489  }
1490 
1491  uint16_t GetVoltMaxRel() const
1492  {
1493  return fVoltageMaxRel;
1494  }
1495 
1497  {
1498  if (!IsConnected())
1499  return State::kDisconnected;
1500 
1501  if (IsConnecting())
1502  return State::kConnecting;
1503 
1504  if (fIsInitializing)
1505  return State::kInitializing;
1506 
1507  if (fIsRamping)
1508  return State::kRamping;
1509 
1510  for (int ch=0; ch<kNumChannels; ch++)
1511  if (fPresent[ch/kNumChannelsPerBoard] && fCurrent[ch]<0)
1512  return State::kOverCurrent;
1513 
1514  bool isoff = true;
1515  for (int ch=0; ch<kNumChannels; ch++)
1516  if (fPresent[ch/kNumChannelsPerBoard] && fDacActual[ch]!=0)
1517  isoff = false;
1518  if (isoff)
1519  return State::kVoltageOff;
1520 
1521  for (int ch=0; ch<kNumChannels; ch++)
1522  if (fPresent[ch/kNumChannelsPerBoard] && fDacActual[ch]!=fDacTarget[ch])
1523  return State::kNotReferenced;
1524 
1525  return State::kVoltageOn;
1526  }
1527 
1528  void SetReconnectDelay(uint32_t delay=1)
1529  {
1530  fReconnectDelay = delay;
1531  }
1532 
1533  void SetEmergencyLimit(int32_t limit=0)
1534  {
1535  fEmergencyLimit = limit;
1536  }
1537 
1539  {
1540  fEmergencyShutdown = false;
1541  }
1542 
1543  bool IsEmergencyShutdown() const
1544  {
1545  return fEmergencyShutdown;
1546  }
1547 };
1548 
1549 // ------------------------------------------------------------------------
1550 
1551 #include "DimDescriptionService.h"
1552 
1554 {
1555 private:
1556 
1561 
1562 public:
1563  void UpdateVA()
1564  {
1565  const Time now;
1566 
1567  UpdateV(now);
1568 
1569  fDimCurrent.setTime(now);
1570  fDimCurrent.Update(fCurrent);
1571  }
1572 
1573 private:
1574  void UpdateV(const Time now=Time())
1575  {
1576  const bool rc = !memcmp(fDacActual.data(), fDacTarget.data(), kNumChannels*2);
1577 
1578  vector<uint16_t> val(2*kNumChannels);
1579  memcpy(val.data(), fDacActual.data(), kNumChannels*2);
1580  memcpy(val.data()+kNumChannels, fDacTarget.data(), kNumChannels*2);
1581  fDimDac.setTime(now);
1582  fDimDac.setQuality(rc);
1583  fDimDac.Update(val);
1584 
1585  vector<float> volt(kNumChannels);
1586  for (float ch=0; ch<kNumChannels; ch++)
1587  volt[ch] = ConvertDacToVolt(ch, fDacActual[ch]);
1588  fDimVolt.setTime(now);
1589  fDimVolt.setQuality(rc);
1590  fDimVolt.Update(volt);
1591  }
1592 
1594  {
1595  vector<float> volt;
1596  volt.reserve(3*kNumChannels);
1597  volt.insert(volt.end(), fOperationVoltage.begin(), fOperationVoltage.end());
1598  volt.insert(volt.end(), fCalibrationOffset.begin(), fCalibrationOffset.end());
1599  volt.insert(volt.end(), fCalibrationSlope.begin(), fCalibrationSlope.end());
1600  fDimGapd.Update(volt);
1601  }
1602 
1603 public:
1604  ConnectionDimBias(ba::io_service& ioservice, MessageImp &imp) :
1605  ConnectionBias(ioservice, imp),
1606  fDimCurrent("BIAS_CONTROL/CURRENT", "S:416",
1607  "|I[dac]:Bias current (conversion: 5000uA/4096dac)"),
1608  fDimDac("BIAS_CONTROL/DAC", "S:416;S:416",
1609  "|U[dac]:Current dac setting"
1610  "|Uref[dac]:Reference dac setting"),
1611  fDimVolt("BIAS_CONTROL/VOLTAGE", "F:416",
1612  "|Uout[V]:Output voltage"),
1613  fDimGapd("BIAS_CONTROL/NOMINAL", "F:416;F:416;F:416",
1614  "|Uop[V]:Nominal operation voltage at 25deg C"
1615  "|Uoff[V]:Bias crate channel calibration offsets"
1616  "|Rcal[Ohm]:Bias crate channel calibration slope")
1617  {
1618  }
1619 
1620  // 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
1621 };
1622 
1623 // ------------------------------------------------------------------------
1624 
1625 template <class T, class S>
1627 {
1628  int Wrap(boost::function<void()> f)
1629  {
1630  f();
1631  return T::GetCurrentState();
1632  }
1633 
1634  function<int(const EventImp &)> Wrapper(function<void()> func)
1635  {
1636  return bind(&StateMachineBias::Wrap, this, func);
1637  }
1638 
1639  bool CheckEventSize(size_t has, const char *name, size_t size)
1640  {
1641  if (has==size)
1642  return true;
1643 
1644  ostringstream msg;
1645  msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
1646  T::Fatal(msg);
1647  return false;
1648  }
1649 
1650 private:
1652 
1654 
1656 
1657  // --------------------------------------------------------------------
1658 
1659  // SET_GLOBAL_DAC_VALUE
1660  int SetGlobalDac(const EventImp &evt)
1661  {
1662  if (!CheckEventSize(evt.GetSize(), "SetGlobalDac", 2))
1663  return false;
1664 
1665  fBias.RampAllDacs(evt.GetUShort());
1666 
1667  return T::GetCurrentState();
1668  }
1669 
1670  // SET_ALL_CHANNELS_DAC
1671  int SetAllChannelsDac(const EventImp &evt)
1672  {
1673  if (!CheckEventSize(evt.GetSize(), "SetAllChannelsDac", 2*416))
1674  return false;
1675 
1676  const uint16_t *ptr = evt.Ptr<uint16_t>();
1677 
1678  fBias.RampAllChannelsDac(vector<uint16_t>(ptr, ptr+416));
1679 
1680  return T::GetCurrentState();
1681  }
1682 
1683  // SET_CHANNEL_DAC_VALUE
1684  int SetChannelDac(const EventImp &evt)
1685  {
1686  if (!CheckEventSize(evt.GetSize(), "SetChannelDac", 4))
1687  return false;
1688 
1689  fBias.RampSingleChannelDac(evt.Get<uint16_t>(), evt.Get<uint16_t>(2));
1690 
1691  return T::GetCurrentState();
1692  }
1693 
1694  // --------------------------------------------------------------------
1695 
1696  // SET_CHANNEL_VOLTAGE
1697  int SetChannelVolt(const EventImp &evt)
1698  {
1699  if (!CheckEventSize(evt.GetSize(), "SetChannelVolt", 6))
1700  return false;
1701 
1702  fBias.RampSingleChannelVoltage(evt.GetUShort(), evt.Get<float>(2));
1703 
1704  return T::GetCurrentState();
1705  }
1706 
1707  // SET_GLOBAL_VOLTAGE
1708  int SetGlobalVolt(const EventImp &evt)
1709  {
1710  if (!CheckEventSize(evt.GetSize(), "SetGlobalVolt", 4))
1711  return false;
1712 
1713  fBias.RampAllVoltages(evt.GetFloat());
1714 
1715  return T::GetCurrentState();
1716  }
1717 
1718  // SET_ALL_CHANNELS_VOLTAGES
1720  {
1721  if (!CheckEventSize(evt.GetSize(), "SetAllChannelsVolt", 4*kNumChannels))
1722  return false;
1723 
1724  const float *ptr = evt.Ptr<float>();
1725  fBias.RampAllChannelsVoltage(vector<float>(ptr, ptr+kNumChannels));
1726 
1727  return T::GetCurrentState();
1728  }
1729 
1730  // --------------------------------------------------------------------
1731 
1732 /* // INCREASE_GLOBAL_VOLTAGE
1733  int IncGlobalVolt(const EventImp &evt)
1734  {
1735  if (!CheckEventSize(evt.GetSize(), "IncGlobalVolt", 4))
1736  return false;
1737 
1738  fBias.RampAllOffsets(evt.GetFloat(), true);
1739 
1740  return T::GetCurrentState();
1741  }
1742 
1743  // INCREASE_CHANNEL_VOLTAGE
1744  int IncChannelVolt(const EventImp &evt)
1745  {
1746  if (!CheckEventSize(evt.GetSize(), "IncChannelVolt", 6))
1747  return false;
1748 
1749  fBias.RampSingleChannelOffset(evt.Get<uint16_t>(), evt.Get<float>(2), true);
1750 
1751  return T::GetCurrentState();
1752  }
1753 
1754  // INCREASE_ALL_CHANNELS_VOLTAGES
1755  int IncAllChannelsVolt(const EventImp &evt)
1756  {
1757  if (!CheckEventSize(evt.GetSize(), "IncAllChannelsVolt", 4*kNumChannels))
1758  return false;
1759 
1760  const float *ptr = evt.Ptr<float>();
1761  fBias.RampAllChannelsOffset(vector<float>(ptr, ptr+416), true);
1762 
1763  return T::GetCurrentState();
1764  }
1765 */
1766  // --------------------------------------------------------------------
1767 
1769  {
1770  if (!CheckEventSize(evt.GetSize(), "ExpertSetGlobalVolt", 4))
1771  return false;
1772 
1773  fBias.ExpertGlobalSetVolt(evt.GetFloat());
1774 
1775  return T::GetCurrentState();
1776  }
1777 
1779  {
1780  if (!CheckEventSize(evt.GetSize(), "ExpertSetGlobalDac", 2))
1781  return false;
1782 
1783  fBias.ExpertGlobalSetDac(evt.GetUShort());
1784 
1785  return T::GetCurrentState();
1786  }
1787 
1789  {
1790  if (!CheckEventSize(evt.GetSize(), "ExpertSetChannelVolt", 6))
1791  return false;
1792 
1793  fBias.ExpertChannelSetVolt(evt.GetUShort(), evt.Get<float>(2));
1794 
1795  return T::GetCurrentState();
1796  }
1797 
1799  {
1800  if (!CheckEventSize(evt.GetSize(), "ExpertSetChannelDac", 4))
1801  return false;
1802 
1803  fBias.ExpertChannelSetDac(evt.Get<uint16_t>(), evt.Get<uint16_t>(2));
1804 
1805  return T::GetCurrentState();
1806  }
1807 
1808  int ExpertLoadMapFile(const EventImp &evt)
1809  {
1810  if (evt.GetSize()==0)
1811  {
1812  T::Warn("ExpertLoadMapFile - No file name given.");
1813  return T::GetCurrentState();
1814  }
1815 
1816  if (fBias.GetStatus()!=State::kVoltageOff)
1817  {
1818  T::Warn("ExpertLoadMapFile - Voltage must have been turned off.");
1819  return T::GetCurrentState();
1820  }
1821 
1822  BiasMap map;
1823 
1824  try
1825  {
1826  map.Read(evt.GetText());
1827  }
1828  catch (const runtime_error &e)
1829  {
1830  T::Warn("Getting reference voltages failed: "+string(e.what()));
1831  return T::GetCurrentState();
1832  }
1833 
1834  if (!fBias.SetReferences(map.Vgapd(), map.Voffset(), map.Vslope()))
1835  {
1836  T::Warn("Setting reference voltages failed.");
1837  return T::GetCurrentState();
1838  }
1839 
1840  fBias.UpdateVA();
1841 
1842  T::Info("Successfully loaded new mapping '"+evt.GetString()+"'");
1843 
1844  return T::GetCurrentState();
1845  }
1846 
1847  // --------------------------------------------------------------------
1848 
1849  int SetUpdateInterval(const EventImp &evt)
1850  {
1851  if (!CheckEventSize(evt.GetSize(), "SetUpdateInterval", 4))
1852  return false;
1853 
1854  fBias.SetUpdateInterval(evt.Get<int32_t>()<0 ? 0 : evt.Get<uint32_t>());
1855 
1856  return T::GetCurrentState();
1857  }
1858 
1860  {
1861  // Close all connections
1862  fBias.PostClose(-1);
1863 
1864  /*
1865  // Now wait until all connection have been closed and
1866  // all pending handlers have been processed
1867  poll();
1868  */
1869 
1870  return T::GetCurrentState();
1871  }
1872 
1873  int Reconnect(const EventImp &evt)
1874  {
1875  // Close all connections to supress the warning in SetEndpoint
1876  fBias.PostClose(-1);
1877 
1878  // Now wait until all connection have been closed and
1879  // all pending handlers have been processed
1880  ba::io_service::poll();
1881 
1882  if (evt.GetBool())
1883  fBias.SetEndpoint(evt.GetString());
1884 
1885  // Now we can reopen the connection
1886  fBias.SetReconnectDelay();
1887  fBias.PostClose(0);
1888 
1889  return T::GetCurrentState();
1890  }
1891 
1892  int SetVerbosity(const EventImp &evt)
1893  {
1894  if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
1895  return T::kSM_FatalError;
1896 
1897  fBias.SetVerbose(evt.GetBool());
1898 
1899  return T::GetCurrentState();
1900  }
1901 
1902  int SetDummyMode(const EventImp &evt)
1903  {
1904  if (!CheckEventSize(evt.GetSize(), "SetDummyMode", 1))
1905  return T::kSM_FatalError;
1906 
1907  fBias.SetDummyMode(evt.GetBool());
1908 
1909  return T::GetCurrentState();
1910  }
1911 
1912  int SetExpertMode(const EventImp &evt)
1913  {
1914  if (!CheckEventSize(evt.GetSize(), "SetExpertMode", 1))
1915  return T::kSM_FatalError;
1916 
1917  fExpertMode = evt.GetBool();
1918 
1919  if (fExpertMode)
1920  T::Warn("Expert commands enabled -- please ensure that you EXACTLY know what you do. These commands can destroy the system.");
1921 
1922  return T::GetCurrentState();
1923  }
1924 
1925  int Shutdown(const string &reason)
1926  {
1927  fBias.RampAllDacs(0);
1928  T::Info("Emergency shutdown initiated ["+reason+"].");
1929  return State::kLocked;
1930  }
1931 
1932  int Unlock()
1933  {
1934  fBias.ResetEmergencyShutdown();
1935  return fBias.GetStatus();
1936  }
1937 
1938  int Execute()
1939  {
1940  const int state = fBias.GetStatus();
1941 
1942  if (fBias.IsEmergencyShutdown()/* && state>State::kInitializing && state<State::kExpertMode*/)
1943  {
1944  // This needs to be repeated for the case that in between a different command was processed
1945  fBias.RampAllDacs(0);
1946  return State::kLocked;
1947  }
1948 
1949  const Time now;
1950  if (now>fSunRise)
1951  {
1952  const bool shutdown =
1953  state==State::kRamping ||
1954  state==State::kVoltageOn ||
1955  state==State::kNotReferenced ||
1956  state==State::kOverCurrent;
1957 
1958  if (shutdown)
1959  Shutdown("beginning of civil twilight");
1960 
1961  fSunRise = now.GetNextSunRise(-6);
1962 
1963  ostringstream msg;
1964  msg << "During next sun-rise nautical twilight will end at " << fSunRise;
1965  T::Info(msg);
1966 
1967  if (shutdown)
1968  return State::kLocked;
1969  }
1970 
1971  if (T::GetCurrentState()==State::kLocked)
1972  return T::GetCurrentState();
1973 
1974  if (fExpertMode && state>=State::kConnected)
1975  return State::kExpertMode;
1976 
1977  return state;
1978  }
1979 
1980 public:
1981  StateMachineBias(ostream &out=cout) :
1982  StateMachineAsio<T>(out, "BIAS_CONTROL"), fBias(*this, *this),
1983  fExpertMode(false), fSunRise(Time().GetNextSunRise(-6))
1984  {
1985  // State names
1986  T::AddStateName(State::kDisconnected, "Disconnected",
1987  "Bias-power supply not connected via USB.");
1988 
1989  T::AddStateName(State::kConnecting, "Connecting",
1990  "Trying to establish USB connection to bias-power supply.");
1991 
1992  T::AddStateName(State::kInitializing, "Initializing",
1993  "USB connection to bias-power supply established, synchronizing USB stream.");
1994 
1995  T::AddStateName(State::kConnected, "Connected",
1996  "USB connection to bias-power supply established.");
1997 
1998  T::AddStateName(State::kNotReferenced, "NotReferenced",
1999  "Internal reference voltage does not match last sent voltage.");
2000 
2001  T::AddStateName(State::kVoltageOff, "VoltageOff",
2002  "All voltages are supposed to be switched off.");
2003 
2004  T::AddStateName(State::kVoltageOn, "VoltageOn",
2005  "At least one voltage is switched on and all are at reference.");
2006 
2007  T::AddStateName(State::kOverCurrent, "OverCurrent",
2008  "At least one channel is in over current state.");
2009 
2010  T::AddStateName(State::kExpertMode, "ExpertMode",
2011  "Special (risky!) mode to directly send command to the bias-power supply.");
2012 
2013  T::AddStateName(State::kRamping, "Ramping",
2014  "Voltage ramping in progress.");
2015 
2016  T::AddStateName(State::kLocked, "Locked",
2017  "Locked due to emergency shutdown, no commands accepted except UNLOCK.");
2018 
2019  // Verbosity commands
2020  T::AddEvent("SET_VERBOSE", "B:1")
2021  (bind(&StateMachineBias::SetVerbosity, this, placeholders::_1))
2022  ("set verbosity state"
2023  "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
2024 
2025  T::AddEvent("ENABLE_DUMMY_MODE", "B:1")
2026  (bind(&StateMachineBias::SetDummyMode, this, placeholders::_1))
2027  ("Enable dummy mode. In this mode SetAllChannels prints informations instead of sending anything to the bias crate."
2028  "|enable[bool]:disable or enable dummy mode");
2029 
2030  // Conenction commands
2031  T::AddEvent("DISCONNECT", State::kConnected, State::kVoltageOff)
2032  (bind(&StateMachineBias::Disconnect, this))
2033  ("disconnect from USB");
2034  T::AddEvent("RECONNECT", "O", State::kDisconnected, State::kConnected, State::kVoltageOff)
2035  (bind(&StateMachineBias::Reconnect, this, placeholders::_1))
2036  ("(Re)connect USB connection to Bias power supply, a new address can be given"
2037  "|tty[string]:new USB address");
2038 
2039 
2040  T::AddEvent("SET_UPDATE_INTERVAL", "I:1")
2041  (bind(&StateMachineBias::SetUpdateInterval, this, placeholders::_1))
2042  ("Set the updat einterval how often the currents are requested"
2043  "|interval[ms]:Update interval in milliseconds");
2044 
2045 
2046 
2048  (Wrapper(bind(&ConnectionBias::ReadAllChannels, &fBias, false)))
2049  ("Asynchronously request the status (current) of all channels.");
2050 
2051  T::AddEvent("RESET_OVER_CURRENT_STATUS", State::kOverCurrent)
2052  (Wrapper(bind(&ConnectionBias::OverCurrentReset, &fBias)))
2053  ("Set all channels in over current state to 0V and send a system reset to reset the over current flags.");
2054 
2055 
2057  (bind(&StateMachineBias::SetChannelDac, this, placeholders::_1))
2058  ("Set a new target value in DAC counts for a single channel. Starts ramping if necessary."
2059  "|channel[short]:Channel for which to set the target voltage [0-415]"
2060  "|voltage[dac]:Target voltage in DAC units for the given channel");
2062  (bind(&StateMachineBias::SetGlobalDac, this, placeholders::_1))
2063  ("Set a new target value for all channels in DAC counts. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
2064  "|voltage[dac]:Global target voltage in DAC counts.");
2066  (bind(&StateMachineBias::SetAllChannelsDac, this, placeholders::_1))
2067  ("Set a new target value for all channels in DAC counts. Starts ramping if necessary."
2068  "|voltage[dac]:Global target voltage in DAC counts for all channels");
2069 
2070 
2072  (bind(&StateMachineBias::SetChannelVolt, this, placeholders::_1))
2073  ("Set a new target voltage for a single channel. Starts ramping if necessary."
2074  "|channel[short]:Channel for which to set the target voltage [0-415]"
2075  "|voltage[V]:Target voltage in volts for the given channel (will be converted to DAC units)");
2077  (bind(&StateMachineBias::SetGlobalVolt, this, placeholders::_1))
2078  ("Set a new target voltage for all channels. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
2079  "|voltage[V]:Global target voltage in volts (will be converted to DAC units)");
2081  (bind(&StateMachineBias::SetAllChannelsVolt, this, placeholders::_1))
2082  ("Set all channels to the given new reference voltage. Starts ramping if necessary."
2083  "|voltage[V]:New reference voltage for all channels");
2084 
2085 /*
2086  T::AddEvent("INCREASE_CHANNEL_VOLTAGE", "S:1;F:1", State::kConnected, State::kVoltageOff, State::kVoltageOn, State::kNotReferenced, State::kOverCurrent)
2087  (bind(&StateMachineBias::IncChannelVolt, this, placeholders::_1))
2088  ("Increases the voltage of all channels by the given offset. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
2089  "|channel[short]:Channel for which to adapt the voltage [0-415]"
2090  "|offset[V]:Offset to be added to all channels (will be converted to DAC counts)");
2091  T::AddEvent("INCREASE_GLOBAL_VOLTAGE", "F:1", State::kConnected, State::kVoltageOff, State::kVoltageOn, State::kNotReferenced, State::kOverCurrent)
2092  (bind(&StateMachineBias::IncGlobalVolt, this, placeholders::_1))
2093  ("Increases the voltage of all channels by the given offset. Starts ramping if necessary. (This command is not realized with the GLOBAL SET command.)"
2094  "|offset[V]:Offset to be added to all channels (will be converted to DAC counts)");
2095  T::AddEvent("INCREASE_ALL_CHANNELS_VOLTAGE", "F:416", State::kConnected, State::kVoltageOff, State::kVoltageOn, State::kNotReferenced, State::kOverCurrent)
2096  (bind(&StateMachineBias::IncAllChannelsVolt, this, placeholders::_1))
2097  ("Add the given voltages to the current reference voltages. Starts ramping if necessary."
2098  "offset[V]:Offsets to be added to the reference voltage of all channels in volts");
2099 */
2100 
2101 
2102 
2104  (Wrapper(bind(&ConnectionBias::RampAllDacs, &fBias, 0)))
2105  ("Set all channels to a zero reference voltage. Starts ramping if necessary.");
2107  (bind(&StateMachineBias::Shutdown, this, "user request"))
2108  ("Same as SET_ZERO_VOLTAGE; but goes to locked state afterwards.");
2109 
2110  T::AddEvent("UNLOCK", State::kLocked)
2111  (bind(&StateMachineBias::Unlock, this))
2112  ("Unlock if in locked state.");
2113 
2114 
2115 
2116 
2117 
2118  T::AddEvent("STOP", State::kConnected, State::kRamping)
2119  (Wrapper(bind(&ConnectionBias::RampStop, &fBias)))
2120  ("Stop an on-going ramping");
2121 
2122  T::AddEvent("START", State::kConnected, State::kNotReferenced)
2123  (Wrapper(bind(&ConnectionBias::RampStart, &fBias)))
2124  ("Start a ramping if no ramping is in progress and if reference values differ from current voltages");
2125 
2126 
2127 
2128  T::AddEvent("PRINT_INFO")
2129  (Wrapper(bind(&ConnectionBias::PrintInfo, &fBias)))
2130  ("Print a table with all current read back with the last request operation");
2131  T::AddEvent("PRINT_CURRENTS")
2132  (Wrapper(bind(&ConnectionBias::PrintA, &fBias)))
2133  ("Print a table with all current read back with the last request operation");
2134  T::AddEvent("PRINT_VOLTAGES")
2135  (Wrapper(bind(&ConnectionBias::PrintV, &fBias)))
2136  ("Print a table with all voltages (current and reference voltages as currently in memory)");
2137  T::AddEvent("PRINT_GAPD_REFERENCE_VOLTAGES")
2138  (Wrapper(bind(&ConnectionBias::PrintReferenceVoltage, &fBias)))
2139  ("Print the G-APD reference values (breakdown voltage + overvoltage) obtained from file");
2140 
2141 
2142  T::AddEvent("EXPERT_MODE", "B:1")
2143  (bind(&StateMachineBias::SetExpertMode, this, placeholders::_1))
2144  ("Enable usage of expert commands (note that for safty reasons the are exclusive with the standard commands)");
2145 
2146  T::AddEvent("EXPERT_RESET", State::kExpertMode)
2147  (Wrapper(bind(&ConnectionBias::ExpertReset, &fBias, true)))
2148  ("Send the RESET command (note that this is possibly harmfull command)");
2149 
2150  T::AddEvent("EXPERT_SET_GLOBAL_VOLTAGE", "F:1", State::kExpertMode)
2151  (bind(&StateMachineBias::ExpertSetGlobalVolt, this, placeholders::_1))
2152  ("Send the global set command. The given voltage is converted to DAC counts.");
2153 
2154  T::AddEvent("EXPERT_SET_GLOBAL_DAC", "S:1", State::kExpertMode)
2155  (bind(&StateMachineBias::ExpertSetGlobalDac, this, placeholders::_1))
2156  ("Send the global set command.");
2157 
2158  T::AddEvent("EXPERT_SET_CHANNEL_VOLTAGE", "S:1;F:1", State::kExpertMode)
2159  (bind(&StateMachineBias::ExpertSetChannelVolt, this, placeholders::_1))
2160  ("Send a single channel set command. The given voltage is converted to DAC commands.");
2161 
2162  T::AddEvent("EXPERT_SET_CHANNEL_DAC", "S:1;S:1", State::kExpertMode)
2163  (bind(&StateMachineBias::ExpertSetChannelDac, this, placeholders::_1))
2164  ("Send a single channel set command.");
2165 
2166  T::AddEvent("EXPERT_LOAD_MAP_FILE", "C", State::kExpertMode)
2167  (bind(&StateMachineBias::ExpertLoadMapFile, this, placeholders::_1))
2168  ("Load a new mapping file.");
2169  }
2170 
2171  ~StateMachineBias() { T::Warn("TODO: Implement rampming at shutdown!"); }
2172 
2174  {
2175  // FIXME: Read calib_offset
2176  // FIXME: Check calib offset being smaller than +/-0.25V
2177 
2178  fBias.SetVerbose(!conf.Get<bool>("quiet"));
2179  fBias.SetDummyMode(conf.Get<bool>("dummy-mode"));
2180 
2181  if (conf.Has("dev"))
2182  {
2183  fBias.SetEndpoint(conf.Get<string>("dev"));
2184  T::Message("Setting device to "+fBias.URL());
2185  }
2186 
2187  const uint16_t step = conf.Get<uint16_t>("ramp-step");
2188  const uint16_t time = conf.Get<uint16_t>("ramp-delay");
2189 
2190  if (step>230) // 5V
2191  {
2192  T::Error("ramp-step exceeds allowed range.");
2193  return 1;
2194  }
2195 
2196  fBias.SetRampStep(step);
2197  fBias.SetRampTime(time);
2198  fBias.SetUpdateInterval(conf.Get<uint32_t>("update-interval"));
2199  fBias.SetEmergencyLimit(conf.Get<uint16_t>("emergency-limit"));
2200  fBias.SetSyncDelay(conf.Get<uint16_t>("sync-delay"));
2201 
2202  ostringstream str1, str2;
2203  str1 << "Ramping in effective steps of " << fBias.GetRampStepVolt() << "V";
2204  str2 << "Ramping with a delay per step of " << time << "ms";
2205  T::Message(str1);
2206  T::Message(str2);
2207 
2208  // --------------------------------------------------------------------------
2209 
2210  const float maxabsv = conf.Get<float>("volt-max-abs");
2211  const float maxrelv = conf.Get<float>("volt-max-rel");
2212  if (maxabsv>90)
2213  {
2214  T::Error("volt-max exceeds 90V.");
2215  return 2;
2216  }
2217  if (maxabsv>75)
2218  T::Warn("volt-max exceeds 75V.");
2219  if (maxabsv<70)
2220  T::Warn("volt-max below 70V.");
2221  if (maxabsv<0)
2222  {
2223  T::Error("volt-max negative.");
2224  return 3;
2225  }
2226 
2227  fBias.SetVoltMaxAbs(maxabsv);
2228  fBias.SetVoltMaxRel(maxrelv);
2229 
2230  ostringstream str3, str4;
2231  str3 << "Effective maximum allowed absolute voltage: " << fBias.GetVoltMaxAbs() << "V";
2232  str4 << "Effective maximum difference w.r.t to G-APD reference: " << fBias.GetVoltMaxRel() << "V";
2233  T::Message(str3);
2234  T::Message(str4);
2235 
2236  // --------------------------------------------------------------------------
2237 
2238  BiasMap map;
2239 
2240  if (!conf.Has("bias-map-file") && !conf.Has("bias-database"))
2241  {
2242  T::Error("Neither bias-map-file not bias-database specified.");
2243  return 5;
2244  }
2245 
2246  try
2247  {
2248  if (conf.Has("bias-map-file"))
2249  map.Read(conf.Get<string>("bias-map-file"));
2250 
2251  //if (conf.Has("bias-database"))
2252  // map.Retrieve(conf.Get<string>("bias-database"));
2253  }
2254  catch (const runtime_error &e)
2255  {
2256  T::Error("Getting reference voltages failed: "+string(e.what()));
2257  return 7;
2258  }
2259 
2260  if (!fBias.SetReferences(map.Vgapd(), map.Voffset(), map.Vslope()))
2261  {
2262  T::Error("Setting reference voltages failed.");
2263  return 8;
2264  }
2265 
2266  // --------------------------------------------------------------------------
2267 
2268  if (conf.Has("dev"))
2269  fBias.Connect();
2270 
2271  return -1;
2272  }
2273 };
2274 
2275 // ------------------------------------------------------------------------
2276 
2277 #include "Main.h"
2278 
2279 template<class T, class S, class R>
2281 {
2282  return Main::execute<T, StateMachineBias<S, R>>(conf);
2283 }
2284 
2286 {
2287  po::options_description control("BIAS control options");
2288  control.add_options()
2289  ("no-dim,d", po_bool(), "Disable dim services")
2290  ("dev", var<string>(), "Device address of USB port to bias-power supply")
2291  ("quiet,q", po_bool(true), "Disable printing contents of all received messages (except dynamic data) in clear text.")
2292  ("dummy-mode", po_bool(), "Dummy mode - SetAllChannels prints info instead of sending new values.")
2293  ("ramp-delay", var<uint16_t>(15), "Delay between the answer of one ramping step and sending the next ramp command to all channels in milliseconds.")
2294  ("ramp-step", var<uint16_t>(46), "Maximum step in DAC counts during ramping (Volt = DAC*90/4096)")
2295  ("update-interval", var<uint32_t>(3000), "Interval between two current requests in milliseconds")
2296  ("sync-delay", var<uint16_t>(500), "Delay between sending the inital 0's after a newly established connection to synchronize the output stream in milliseconds")
2297  ("volt-max-abs", var<float>(75), "Absolte upper limit for the voltage (in Volts)")
2298  ("volt-max-rel", var<float>(3.5), "Relative upper limit for the voltage w.r.t. the G-APD reference voltage (in Volts)")
2299  ("bias-map-file", var<string>(), "File with nominal and offset voltages for each channel.")
2300  ("bias-database", var<string>(), "")
2301  ("emergency-limit", var<uint16_t>(2200), "A current limit in ADC counts which, if exceeded, will initiate an emergency shutdown (0=off)")
2302  ;
2303 
2304  conf.AddOptions(control);
2305 }
2306 
2307 /*
2308  Extract usage clause(s) [if any] for SYNOPSIS.
2309  Translators: "Usage" and "or" here are patterns (regular expressions) which
2310  are used to match the usage synopsis in program output. An example from cp
2311  (GNU coreutils) which contains both strings:
2312  Usage: cp [OPTION]... [-T] SOURCE DEST
2313  or: cp [OPTION]... SOURCE... DIRECTORY
2314  or: cp [OPTION]... -t DIRECTORY SOURCE...
2315  */
2317 {
2318  cout <<
2319  "The biasctrl program controls the bias-power supply boards.\n"
2320  "\n"
2321  "Note: At default the program is started without a command line (user) "
2322  "interface. In this case Actions/Commands are available via Dim "
2323  "exclusively.\n"
2324  "Use the -c option to start the program with a command line interface.\n"
2325  "\n"
2326  "In the running application:\n"
2327  "Use h or help to print a short help message about its usage.\n"
2328  "\n"
2329  "Usage: biasctrl [-c type] [OPTIONS]\n"
2330  " or: biasctrl [OPTIONS]\n";
2331  cout << endl;
2332 }
2333 
2335 {
2336  Main::PrintHelp<StateMachineBias<StateMachine,ConnectionBias>>();
2337 
2338  /* Additional help text which is printed after the configuration
2339  options goes here */
2340 
2341  /*
2342  cout << "bla bla bla" << endl << endl;
2343  cout << endl;
2344  cout << "Environment:" << endl;
2345  cout << "environment" << endl;
2346  cout << endl;
2347  cout << "Examples:" << endl;
2348  cout << "test exam" << endl;
2349  cout << endl;
2350  cout << "Files:" << endl;
2351  cout << "files" << endl;
2352  cout << endl;
2353  */
2354 }
2355 
2356 int main(int argc, const char* argv[])
2357 {
2358  Configuration conf(argv[0]);
2359  conf.SetPrintUsage(PrintUsage);
2361  SetupConfiguration(conf);
2362 
2363  if (!conf.DoParse(argc, argv, PrintHelp))
2364  return 127;
2365 
2366  //try
2367  {
2368  // No console access at all
2369  if (!conf.Has("console"))
2370  {
2371  if (conf.Get<bool>("no-dim"))
2372  return RunShell<LocalStream, StateMachine, ConnectionBias>(conf);
2373  else
2374  return RunShell<LocalStream, StateMachineDim, ConnectionDimBias>(conf);
2375  }
2376  // Cosole access w/ and w/o Dim
2377  if (conf.Get<bool>("no-dim"))
2378  {
2379  if (conf.Get<int>("console")==0)
2380  return RunShell<LocalShell, StateMachine, ConnectionBias>(conf);
2381  else
2382  return RunShell<LocalConsole, StateMachine, ConnectionBias>(conf);
2383  }
2384  else
2385  {
2386  if (conf.Get<int>("console")==0)
2387  return RunShell<LocalShell, StateMachineDim, ConnectionDimBias>(conf);
2388  else
2389  return RunShell<LocalConsole, StateMachineDim, ConnectionDimBias>(conf);
2390  }
2391  }
2392  /*catch (std::exception& e)
2393  {
2394  cerr << "Exception: " << e.what() << endl;
2395  return -1;
2396  }*/
2397 
2398  return 0;
2399 }
vector< uint64_t > fCounter
Definition: biasctrl.cc:63
std::vector< float > Vslope() const
Definition: PixelMap.h:354
vector< float > fCalibrationOffset
Definition: biasctrl.cc:93
int received
uint16_t fSyncTime
Definition: biasctrl.cc:56
vector< int16_t > fCurrent
Definition: biasctrl.cc:72
virtual void UpdateVA()
Definition: biasctrl.cc:83
void RampStop()
Definition: biasctrl.cc:1188
void SetVoltMaxRel(float max)
Definition: biasctrl.cc:1476
DimDescribedService fDimCurrent
Definition: biasctrl.cc:1557
int Wrap(boost::function< void()> f)
Definition: biasctrl.cc:1628
void HandleSyncTimer(int counter, const bs::error_code &error)
Definition: biasctrl.cc:554
void PrintCommandDac(const vector< uint16_t > &dac)
Definition: biasctrl.cc:696
uint16_t GetVoltMaxRel() const
Definition: biasctrl.cc:1491
float GetFloat() const
Definition: EventImp.h:97
A general base-class describing events issues in a state machine.
Definition: EventImp.h:11
bool IsRamping() const
Definition: biasctrl.cc:1222
void SetRampTime(uint16_t val)
Definition: biasctrl.cc:1207
const char * GetText() const
Definition: EventImp.h:88
void ScheduleRampStep()
Definition: biasctrl.cc:846
vector< uint8_t > fBuffer
Definition: biasctrl.cc:38
int ExpertSetGlobalVolt(const EventImp &evt)
Definition: biasctrl.cc:1768
virtual void UpdateVgapd()
Definition: biasctrl.cc:78
void SetupConfiguration(Configuration &conf)
Definition: Main.h:25
vector< char > GetCmd(uint16_t board, uint16_t channel, Command_t cmd, uint16_t dac=0)
Definition: biasctrl.cc:106
int64_t fWrapCounter
Definition: biasctrl.cc:47
int i
Definition: db_dim_client.c:21
void setQuality(int quality)
Definition: discpp.cxx:1256
Set color Green.
Definition: WindowLog.h:18
The base implementation of a distributed messaging system.
Definition: MessageImp.h:10
void PrintReferenceVoltage()
Definition: biasctrl.cc:1428
int16_t fGlobalDacCmd
Definition: biasctrl.cc:50
Adds some functionality to boost::posix_time::ptime for our needs.
Definition: Time.h:30
char str[80]
Definition: test_client.c:7
void SetPrintUsage(const std::function< void(void)> &func)
T Get(const std::string &var)
void SetAllChannels(const vector< uint16_t > &dac, bool special=false)
Definition: biasctrl.cc:718
void ResetEmergencyShutdown()
Definition: biasctrl.cc:1538
State::states_t GetStatus()
Definition: biasctrl.cc:1496
Set color Red.
Definition: WindowLog.h:17
void PrintInfo()
Definition: biasctrl.cc:1326
vector< uint8_t > fBufferRamp
Definition: biasctrl.cc:39
int EvalOptions(Configuration &conf)
Definition: biasctrl.cc:2173
Time GetNextSunRise(double horizon) const
Definition: Time.cc:346
int ExpertSetChannelDac(const EventImp &evt)
Definition: biasctrl.cc:1798
DimDescribedService fDimDac
Definition: biasctrl.cc:1558
STL namespace.
Command_t
Definition: HeadersBIAS.h:13
void SetReconnectDelay(uint32_t delay=1)
Definition: biasctrl.cc:1528
bool fIsDummyMode
Definition: biasctrl.cc:43
int main(int argc, const char *argv[])
Definition: biasctrl.cc:2356
void PrintLineA(int b, int ch)
Definition: biasctrl.cc:1344
vector< float > fCalibrationSlope
Definition: biasctrl.cc:94
char id[4]
Definition: FITS.h:71
ConnectionDimBias(ba::io_service &ioservice, MessageImp &imp)
Definition: biasctrl.cc:1604
bool RampSingleChannelVoltage(uint16_t ch, float volt)
Definition: biasctrl.cc:997
bool fEmergencyShutdown
Definition: biasctrl.cc:68
int32_t fEmergencyLimit
Definition: biasctrl.cc:67
vector< uint8_t > fBufferUpdate
Definition: biasctrl.cc:40
std::string GetString() const
Definition: EventImp.cc:194
int SetExpertMode(const EventImp &evt)
Definition: biasctrl.cc:1912
bool CheckChannelVoltage(uint16_t ch, float volt)
Definition: biasctrl.cc:912
bool ExpertChannelSetVolt(uint16_t ch, double volt)
Definition: biasctrl.cc:1272
uint16_t ConvertVoltToDac(uint16_t ch, double volt)
Definition: biasctrl.cc:977
bool RampAllDacs(uint16_t dac)
Definition: biasctrl.cc:970
bool IsEmergencyShutdown() const
Definition: biasctrl.cc:1543
void RampStart()
Definition: biasctrl.cc:1196
int SetChannelVolt(const EventImp &evt)
Definition: biasctrl.cc:1697
void PrintLineGapd(int b, int ch)
Definition: biasctrl.cc:1416
void SetupConfiguration(Configuration &conf)
Definition: biasctrl.cc:2285
bool SetReferences(const vector< float > &volt, const vector< float > &offset, const vector< float > &slope)
Definition: biasctrl.cc:1153
int64_t fSendCounter
Definition: biasctrl.cc:48
bool RampAllChannelsVoltage(const vector< float > &volt)
Definition: biasctrl.cc:1009
void HandleReceivedData(const bs::error_code &err, size_t bytes_received, int command, int send_counter)
Definition: biasctrl.cc:474
uint16_t GetUShort() const
Definition: EventImp.h:92
bool RampOneStep()
Definition: biasctrl.cc:759
bool fIsVerbose
Definition: biasctrl.cc:42
void SetVerbose(bool b)
Definition: biasctrl.cc:1316
DimDescribedService fDimVolt
Definition: biasctrl.cc:1559
bool Has(const std::string &var)
int ExpertLoadMapFile(const EventImp &evt)
Definition: biasctrl.cc:1808
void SetRampStep(uint16_t val)
Definition: biasctrl.cc:1212
void HandleRampTimer(const bs::error_code &error)
Definition: biasctrl.cc:803
int SetDummyMode(const EventImp &evt)
Definition: biasctrl.cc:1902
int SetAllChannelsVolt(const EventImp &evt)
Definition: biasctrl.cc:1719
void setTime(const Time &t)
void HandleReceivedData(const vector< uint8_t > &buf, size_t bytes_received, int command, int send_counter)
Definition: biasctrl.cc:325
void AddOptions(const po::options_description &opt, bool visible=true)
Definition: Configuration.h:92
int RunShell(Configuration &conf)
Definition: biasctrl.cc:2280
void PrintUsage()
Definition: biasctrl.cc:2316
int SetChannelDac(const EventImp &evt)
Definition: biasctrl.cc:1684
void OverCurrentReset()
Definition: biasctrl.cc:1099
bool ExpertGlobalSetDac(uint16_t dac)
Definition: biasctrl.cc:1277
void DelayedReconnect()
Definition: biasctrl.cc:307
int SetGlobalDac(const EventImp &evt)
Definition: biasctrl.cc:1660
uint16_t GetVoltMaxAbs() const
Definition: biasctrl.cc:1486
int ExpertSetChannelVolt(const EventImp &evt)
Definition: biasctrl.cc:1788
vector< char > GetCmd(Command_t cmd, uint16_t id=0, uint16_t dac=0)
Definition: biasctrl.cc:126
float fVoltageMaxRel
Definition: biasctrl.cc:97
void SendCommandNB(const std::string &command)
Definition: Dim.h:30
void PrintLineV(int b, int ch)
Definition: biasctrl.cc:1376
Warning because the service this data corrsponds to might have been last updated longer ago than Local time
Definition: smartfact.txt:92
void HandleUpdateTimer(const bs::error_code &error)
Definition: biasctrl.cc:643
void SetUpdateInterval(uint32_t val)
Definition: biasctrl.cc:1448
double ConvertDacToVolt(uint16_t ch, uint16_t dac)
Definition: biasctrl.cc:986
void PrintHelp()
Definition: biasctrl.cc:2334
int SetGlobalVolt(const EventImp &evt)
Definition: biasctrl.cc:1708
Commandline parsing, resource file parsing and database access.
Definition: Configuration.h:9
std::vector< float > Voffset() const
Definition: PixelMap.h:341
virtual void UpdateV(const Time=Time())
Definition: biasctrl.cc:74
void UpdateV(const Time now=Time())
Definition: biasctrl.cc:1574
bool fIsRamping
Definition: biasctrl.cc:60
function< int(const EventImp &)> Wrapper(function< void()> func)
Definition: biasctrl.cc:1634
int buffer[BUFFSIZE]
Definition: db_dim_client.c:14
int fIsInitializing
Definition: biasctrl.cc:59
DimDescribedService fDimGapd
Definition: biasctrl.cc:1560
int16_t fRampStep
Definition: biasctrl.cc:52
std::vector< float > Vgapd() const
Definition: PixelMap.h:329
bool RampAllChannelsDac(const vector< uint16_t > &dac)
Definition: biasctrl.cc:955
int size
Definition: db_dim_server.c:17
float data[4 *1440]
bool CheckDac(uint16_t dac)
Definition: biasctrl.cc:890
bool RampSingleChannelDac(uint16_t ch, uint16_t dac)
Definition: biasctrl.cc:938
void PrintLineCmdDac(int b, int ch, const vector< uint16_t > &dac)
Definition: biasctrl.cc:684
bool CheckEventSize(size_t has, const char *name, size_t size)
Definition: biasctrl.cc:1639
int counter
Definition: db_dim_client.c:19
Time fLastConnect
Definition: biasctrl.cc:65
bool Read(const std::string &fname)
Definition: PixelMap.h:226
void ScheduleUpdate(int millisec)
Definition: biasctrl.cc:676
uint32_t fUpdateTime
Definition: biasctrl.cc:55
bool GetBool() const
Definition: EventImp.h:90
int Shutdown(const string &reason)
Definition: biasctrl.cc:1925
uint32_t fReconnectDelay
Definition: biasctrl.cc:57
Error()
Definition: HeadersFTM.h:197
void SetDummyMode(bool b)
Definition: biasctrl.cc:1321
boost::asio::deadline_timer fUpdateTimer
Definition: biasctrl.cc:36
void SetEmergencyLimit(int32_t limit=0)
Definition: biasctrl.cc:1533
StateMachineBias(ostream &out=cout)
Definition: biasctrl.cc:1981
int fWaitingForAnswer
Definition: biasctrl.cc:61
void ScheduleSync(int counter=0)
Definition: biasctrl.cc:602
bool RampAllVoltages(float volt)
Definition: biasctrl.cc:1023
bool CheckChannel(uint16_t ch)
Definition: biasctrl.cc:901
vector< bool > fPresent
Definition: biasctrl.cc:45
po::typed_value< bool > * po_bool(bool def=false)
ConnectionBias(ba::io_service &ioservice, MessageImp &imp)
Definition: biasctrl.cc:853
void ExpertReset(bool expert_mode=true)
Definition: biasctrl.cc:1226
int SetAllChannelsDac(const EventImp &evt)
Definition: biasctrl.cc:1671
int ExpertSetGlobalDac(const EventImp &evt)
Definition: biasctrl.cc:1778
int Reconnect(const EventImp &evt)
Definition: biasctrl.cc:1873
void ConnectionEstablished()
Definition: biasctrl.cc:609
int SetUpdateInterval(const EventImp &evt)
Definition: biasctrl.cc:1849
boost::asio::deadline_timer fRampTimer
Definition: biasctrl.cc:35
T Get(size_t offset=0) const
Definition: EventImp.h:66
float fVoltageMaxAbs
Definition: biasctrl.cc:96
bool CheckMessageLength(int received, int expected, const string &msg)
Definition: biasctrl.cc:134
uint16_t GetRampStepVolt() const
Definition: biasctrl.cc:1217
bool DoParse(int argc, const char **argv, const std::function< void()> &func=std::function< void()>())
bool ExpertGlobalSetVolt(float volt)
Definition: biasctrl.cc:1309
vector< uint16_t > fDacTarget
Definition: biasctrl.cc:99
bool EvalAnswer(const uint8_t *answer, uint16_t id, int command)
Definition: biasctrl.cc:146
int SetVerbosity(const EventImp &evt)
Definition: biasctrl.cc:1892
int16_t fRampTime
Definition: biasctrl.cc:53
const T * Ptr(size_t offset=0) const
Definition: EventImp.h:74
uint16_t RampOneStep(uint16_t ch)
Definition: biasctrl.cc:748
void ReadAllChannels(bool special=false)
Definition: biasctrl.cc:1124
vector< uint16_t > fDacActual
Definition: biasctrl.cc:101
void SetVoltMaxAbs(float max)
Definition: biasctrl.cc:1466
boost::asio::deadline_timer fSyncTimer
Definition: biasctrl.cc:34
Set attribute Bold.
Definition: WindowLog.h:36
void SetSyncDelay(uint16_t val)
Definition: biasctrl.cc:1461
bool ExpertChannelSetDac(uint16_t ch, uint16_t dac)
Definition: biasctrl.cc:1245
vector< float > fOperationVoltage
Definition: biasctrl.cc:90
virtual size_t GetSize() const
Definition: EventImp.h:55
vector< uint16_t > fDacCommand
Definition: biasctrl.cc:100