nidaqmxdriver.h
1 /***************************************************************************
2  Copyright (C) 2002-2015 Kentaro Kitagawa
3  kitagawa@phys.s.u-tokyo.ac.jp
4 
5  This program is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License as published by the Free Software Foundation; either
8  version 2 of the License, or (at your option) any later version.
9 
10  You should have received a copy of the GNU Library General
11  Public License and a list of authors along with this program;
12  see the files COPYING and AUTHORS.
13 ***************************************************************************/
14 #ifndef NIDAQMXDRIVER_H_
15 #define NIDAQMXDRIVER_H_
16 
17 #include "interface.h"
18 #include "driver.h"
19 #include "atomic_queue.h"
20 
21 #ifdef HAVE_NI_DAQMX
22  #include <NIDAQmx.h>
23  #define CHECK_DAQMX_ERROR(ret) XNIDAQmxInterface::checkDAQmxError(ret, __FILE__, __LINE__)
24 
25  /*#define CHECK_DAQMX_RET(ret, msg) {dbgPrint(# ret);\
26  if(CHECK_DAQMX_ERROR(ret, msg) > 0) {gWarnPrint(QString(msg) + " " + XNIDAQmxInterface::getNIDAQmxErrMessage()); } }
27  */
28  #define CHECK_DAQMX_RET(ret) {int code__ = ret; \
29  if(CHECK_DAQMX_ERROR(code__) > 0) {gWarnPrint(XNIDAQmxInterface::getNIDAQmxErrMessage(code__)); } }
30 #else
31  #define CHECK_DAQMX_ERROR(ret) (0)
32  #define CHECK_DAQMX_RET(ret)
33  typedef unsigned int TaskHandle;
34  typedef int64_t int64;
35  typedef uint64_t uInt64;
36  typedef int32_t int32;
37  typedef uint32_t uInt32;
38  typedef int16_t int16;
39  typedef uint16_t uInt16;
40  typedef int8_t int8;
41  typedef uint8_t uInt8;
42  typedef double float64;
43 #endif //HAVE_NI_DAQMX
44 
45 class XNIDAQmxTask;
46 
47 class XNIDAQmxInterface : public XInterface {
48 public:
49  XNIDAQmxInterface(const char *name, bool runtime, const shared_ptr<XDriver> &driver);
50  virtual ~XNIDAQmxInterface() {}
51 
52  static XString getNIDAQmxErrMessage();
53  static XString getNIDAQmxErrMessage(int status);
54  static int checkDAQmxError(int ret, const char*file, int line);
55 
56  virtual bool isOpened() const {return m_devname.length();}
57 
58  //! e.g. "Dev1".
59  const char*devName() const {return m_devname.c_str();}
60  //! Split camma-separated strings.
61  static void parseList(const char *list, std::deque<XString> &buf);
62 
63  void synchronizeClock(TaskHandle task);
64 
65  class XNIDAQmxRoute {
66  public:
67  XNIDAQmxRoute(const char*src, const char*dst, int *ret = NULL);
68  ~XNIDAQmxRoute();
69  private:
70  XString m_src, m_dst;
71  };
72 
73  //! e.g. "PCI-6111".
74  const char* productType() const {
75  const ProductInfo* p = m_productInfo;
76  return p ? p->type : 0L;
77  }
78  //! e.g. "S", "M".
79  const char* productSeries() const {
80  const ProductInfo* p = m_productInfo;
81  return p ? p->series : 0L;
82  }
83  //! e.g. "PCI", "PXI". Never "PCIe" or "PXIe".
84  const char* busArchType() const;
85 
86  enum FLAGS {
87  FLAG_BUGGY_DMA_AO = 0x10u, FLAG_BUGGY_DMA_AI = 0x20u,
88  FLAG_BUGGY_DMA_DI = 0x40u, FLAG_BUGGY_DMA_DO = 0x80u,
89  FLAG_BUGGY_XFER_COND_AO = 0x100u, FLAG_BUGGY_XFER_COND_AI = 0x200u,
90  FLAG_BUGGY_XFER_COND_DI = 0x400u, FLAG_BUGGY_XFER_COND_DO = 0x800u};
91  //! e.g. FLAG_BUGGY_DMA_AO.
92  int productFlags() const {return m_productInfo->flags;}
93  //! \return 0 if hw timed transfer is not supported.
94  double maxAIRate(unsigned int /*num_scans*/) const {return m_productInfo->ai_max_rate;}
95  double maxAORate(unsigned int /*num_scans*/) const {return m_productInfo->ao_max_rate;}
96  double maxDIRate(unsigned int /*num_scans*/) const {return m_productInfo->di_max_rate;}
97  double maxDORate(unsigned int /*num_scans*/) const {return m_productInfo->do_max_rate;}
98 
99  //! Stores and reads time stamps between synchronized devices.
100  class SoftwareTrigger : public enable_shared_from_this<SoftwareTrigger> {
101  protected:
102  SoftwareTrigger(const char *label, unsigned int bits);
103  public:
104  static shared_ptr<SoftwareTrigger> create(const char *label, unsigned int bits);
105  static void unregister(const shared_ptr<SoftwareTrigger> &);
106  const char *label() const {return m_label.c_str();}
107  void setArmTerm(const char *arm_term) {m_armTerm = arm_term;}
108  const char *armTerm() const {return m_armTerm.c_str();}
109  bool isPersistentCoherentMode() const {return m_isPersistentCoherent;}
110  void setPersistentCoherentMode(bool x) {m_isPersistentCoherent = x;}
111  void start(float64 freq);
112  float64 freq() const {return m_freq;} //!< [Hz].
113  unsigned int bits() const {return m_bits;}
114  void stop();
115  void forceStamp(uint64_t now, float64 freq);
116  void stamp(uint64_t cnt);
117  //! \param time unit in 1/freq().
118  template <typename T>
119  void changeValue(T oldval, T val, uint64_t time) {
120  if(((m_risingEdgeMask & val) & (m_risingEdgeMask & ~oldval))
121  || ((m_fallingEdgeMask & ~val) & (m_fallingEdgeMask & oldval))) {
122  if(time < m_endOfBlank) return;
123  stamp(time);
124  }
125  }
126 
127  void connect(uint32_t rising_edge_mask,
128  uint32_t falling_edge_mask) throw (XInterface::XInterfaceError &);
129  void disconnect();
130  //! \param blankterm in seconds, not to stamp so frequently.
131  void setBlankTerm(float64 blankterm) {
132  m_blankTerm = llrint(blankterm * freq());
133  memoryBarrier();
134  }
136  //! for restarting connected task.
137  STRGTalker &onStart() {return m_onStart;}
138  //! for changing list.
139  static STRGTalker &onChange() {return s_onChange;}
140  //! clears all time stamps.
141  void clear();
142  //! clears past time stamps.
143  void clear(uint64_t now, float64 freq);
144  //! \return if not, zero will be returned.
145  //! \param freq frequency of reader.
146  //! \param threshold upper bound to be pop, unit in 1/\a freq (2nd param.).
147  uint64_t tryPopFront(uint64_t threshold, float64 freq);
148 
149  typedef std::deque<shared_ptr<XNIDAQmxInterface::SoftwareTrigger> > SoftwareTriggerList;
150  typedef SoftwareTriggerList::iterator SoftwareTriggerList_it;
151  static const atomic_shared_ptr<SoftwareTriggerList> &virtualTrigList() {
152  return s_virtualTrigList;
153  }
154  private:
155  void clear_();
156  const XString m_label;
157  XString m_armTerm;
158  unsigned int m_bits;
159  uint32_t m_risingEdgeMask, m_fallingEdgeMask;
160  uint64_t m_blankTerm;
161  uint64_t m_endOfBlank; //!< next stamp must not be less than this.
162  float64 m_freq; //!< [Hz].
163  enum {QUEUE_SIZE = 8192};
165  FastQueue m_fastQueue; //!< recorded stamps.
166  typedef std::deque<uint64_t> SlowQueue;
167  SlowQueue m_slowQueue; //!< recorded stamps, when \a m_fastQueue is full.
168  atomic<unsigned int> m_slowQueueSize;
169  XMutex m_mutex; //!< for \a m_slowQueue.
170  STRGTalker m_onStart;
171  static STRGTalker s_onChange;
172  static atomic_shared_ptr<SoftwareTriggerList> s_virtualTrigList;
173  bool m_isPersistentCoherent;
174  };
175 protected:
176  virtual void open() throw (XInterfaceError &);
177  //! This can be called even if has already closed.
178  virtual void close() throw (XInterfaceError &);
179 private:
180  //! \return true if an external source is detected and rounted.
181  bool routeExternalClockSource(const char *dev, const char *inp_term);
182 
183  struct ProductInfo {
184  const char *type;
185  const char *series;
186  int flags;
187  unsigned long ai_max_rate; //!< [kHz]
188  unsigned long ao_max_rate; //!< [kHz]
189  unsigned long di_max_rate; //!< [kHz]
190  unsigned long do_max_rate; //!< [kHz]
191  };
192  friend class SoftwareTrigger;
193  XString m_devname;
194  const ProductInfo* m_productInfo;
195  static const ProductInfo sc_productInfoList[];
196 };
197 
198 template<class tDriver>
199 class XNIDAQmxDriver : public tDriver {
200 public:
201  XNIDAQmxDriver(const char *name, bool runtime,
202  Transaction &tr_meas, const shared_ptr<XMeasure> &meas);
203  virtual ~XNIDAQmxDriver() {}
204 protected:
205  const shared_ptr<XNIDAQmxInterface> &interface() const {return m_interface;}
206  //! Be called just after opening interface. Call start() inside this routine appropriately.
207  virtual void open() throw (XKameError &) {this->start();}
208  //! Be called during stopping driver. Call interface()->stop() inside this routine.
209  virtual void close() throw (XKameError &) {interface()->stop();}
210  void onOpen(const Snapshot &shot, XInterface *);
211  void onClose(const Snapshot &shot, XInterface *);
212  //! This should not cause an exception.
213  virtual void closeInterface();
214 private:
215  shared_ptr<XListener> m_lsnOnOpen, m_lsnOnClose;
216 
217  const shared_ptr<XNIDAQmxInterface> m_interface;
218 };
219 template<class tDriver>
220 XNIDAQmxDriver<tDriver>::XNIDAQmxDriver(const char *name, bool runtime,
221  Transaction &tr_meas, const shared_ptr<XMeasure> &meas) :
222  tDriver(name, runtime, ref(tr_meas), meas),
223  m_interface(XNode::create<XNIDAQmxInterface>("Interface", false,
224  dynamic_pointer_cast<XDriver>(this->shared_from_this()))) {
225  meas->interfaces()->insert(tr_meas, m_interface);
226  this->iterate_commit([=](Transaction &tr){
227  m_lsnOnOpen = tr[ *interface()].onOpen().connectWeakly(
228  this->shared_from_this(), &XNIDAQmxDriver<tDriver>::onOpen);
229  m_lsnOnClose = tr[ *interface()].onClose().connectWeakly(
230  this->shared_from_this(), &XNIDAQmxDriver<tDriver>::onClose);
231  });
232 }
233 template<class tDriver>
234 void
236  try {
237  open();
238  }
239  catch (XInterface::XInterfaceError& e) {
240  e.print(this->getLabel() + i18n(": Opening driver failed, because "));
241  onClose(shot, NULL);
242  }
243 }
244 template<class tDriver>
245 void
247  try {
248  this->stop();
249  }
250  catch (XInterface::XInterfaceError& e) {
251  e.print(this->getLabel() + i18n(": Stopping driver failed, because "));
252  closeInterface();
253  }
254 }
255 template<class tDriver>
256 void
258  try {
259  this->close();
260  }
261  catch (XInterface::XInterfaceError &e) {
262  e.print();
263  }
264 }
265 
266 #endif /*NIDAQMXDRIVER_H_*/

Generated for KAME4 by  doxygen 1.8.3