14 #include "nidaqmxdriver.h"
15 #if !defined __WIN32__ && !defined WINDOWS && !defined _WIN32
16 #include <sys/errno.h>
21 inline int unsigned gcd(
unsigned int a,
unsigned int b){
25 inline unsigned int lcm(
unsigned int a,
unsigned int b){
26 return a * b / gcd(a,b);
39 XNIDAQmxInterface::sc_productInfoList[] = {
40 {
"PCI-6110",
"S", 0, 5000uL, 1000uL, 0, 0},
41 {
"PXI-6110",
"S", 0, 5000uL, 1000uL, 0, 0},
42 {
"PCI-6111",
"S", 0, 5000uL, 1000uL, 0, 0},
43 {
"PXI-6111",
"S", 0, 5000uL, 1000uL, 0, 0},
44 {
"PCI-6115",
"S", 0, 10000uL, 2500uL, 10000uL, 10000uL},
45 {
"PXI-6115",
"S", 0, 10000uL, 2500uL, 10000uL, 10000uL},
46 {
"PCI-6120",
"S", 0, 800uL, 2500uL, 5000uL, 5000uL},
47 {
"PCI-6220",
"M", 0, 250uL, 0, 1000uL, 1000uL},
48 {
"PXI-6220",
"M", 0, 250uL, 0, 1000uL, 1000uL},
49 {
"PCI-6221",
"M", 0, 250uL, 740uL, 1000uL, 1000uL},
50 {
"PXI-6221",
"M", 0, 250uL, 740uL, 1000uL, 1000uL},
51 {
"PCI-6224",
"M", 0, 250uL, 0, 1000uL, 1000uL},
52 {
"PXI-6224",
"M", 0, 250uL, 0, 1000uL, 1000uL},
53 {
"PCI-6229",
"M", 0, 250uL, 625uL, 1000uL, 1000uL},
54 {
"PXI-6229",
"M", 0, 250uL, 625uL, 1000uL, 1000uL},
55 {
"PCI-6250",
"M", 0, 1000uL, 0uL, 5000uL, 5000uL},
56 {
"PXI-6250",
"M", 0, 1000uL, 0uL, 5000uL, 5000uL},
57 {
"PCI-6251",
"M", 0, 1000uL, 1000uL, 5000uL, 5000uL},
58 {
"PCIe-6251",
"M", 0, 1000uL, 1000uL, 5000uL, 5000uL},
59 {
"PXI-6251",
"M", 0, 1000uL, 1000uL, 5000uL, 5000uL},
60 {
"PCI-6254",
"M", 0, 1000uL, 0uL, 5000uL, 5000uL},
61 {
"PXI-6254",
"M", 0, 1000uL, 0uL, 5000uL, 5000uL},
62 {
"PCI-6255",
"M", 0, 750uL, 1000uL, 5000uL, 5000uL},
63 {
"PXI-6255",
"M", 0, 750uL, 1000uL, 5000uL, 5000uL},
64 {
"PCI-6255",
"M", 0, 1000uL, 1000uL, 5000uL, 5000uL},
65 {
"PCIe-6255",
"M", 0, 1000uL, 1000uL, 5000uL, 5000uL},
66 {
"PXI-6255",
"M", 0, 1000uL, 1000uL, 5000uL, 5000uL},
67 {
"PCIe-6321",
"X", 0, 250uL, 900uL, 1000uL, 1000uL},
68 {
"PCIe-6323",
"X", 0, 250uL, 900uL, 1000uL, 1000uL},
69 {
"PCIe-6341",
"X", 0, 500uL, 900uL, 1000uL, 1000uL},
70 {
"PCIe-6343",
"X", 0, 500uL, 900uL, 1000uL, 1000uL},
71 {
"PCIe-6351",
"X", 0, 1000uL, 1000uL, 5000uL, 5000uL},
72 {
"PCIe-6353",
"X", 0, 1000uL, 1000uL, 5000uL, 5000uL},
73 {
"PCIe-6361",
"X", 0, 1000uL, 1000uL, 5000uL, 5000uL},
74 {
"PCIe-6363",
"X", 0, 1000uL, 1000uL, 5000uL, 5000uL},
75 {0, 0, 0, 0, 0, 0, 0},
79 static XString g_pciClockMaster;
80 static float64 g_pciClockMasterRate = 0.0;
81 static XString g_pciClockExtRefTerm;
82 static float64 g_pciClockExtRefRate;
83 static TaskHandle g_pciClockMasterTask = (TaskHandle)-1;
84 static int g_daqmx_open_cnt;
85 static XMutex g_daqmx_mutex;
86 static std::deque<shared_ptr<XNIDAQmxInterface::XNIDAQmxRoute> > g_daqmx_sync_routes;
89 XNIDAQmxInterface::SoftwareTrigger::s_virtualTrigList(
new XNIDAQmxInterface::SoftwareTrigger::SoftwareTriggerList);
92 shared_ptr<XNIDAQmxInterface::SoftwareTrigger>
93 XNIDAQmxInterface::SoftwareTrigger::create(
const char *label,
unsigned int bits) {
94 shared_ptr<SoftwareTrigger> p(
new SoftwareTrigger(label, bits));
99 new_list->push_back(p);
106 XNIDAQmxInterface::SoftwareTrigger::SoftwareTrigger(
const char *label,
unsigned int bits)
107 : m_label(label), m_bits(bits),
108 m_risingEdgeMask(0u), m_fallingEdgeMask(0u) {
110 m_isPersistentCoherent =
false;
113 XNIDAQmxInterface::SoftwareTrigger::unregister(
const shared_ptr<SoftwareTrigger> &p) {
117 new_list->erase(std::find(new_list->begin(), new_list->end(), p));
123 XNIDAQmxInterface::SoftwareTrigger::clear_() {
125 while(FastQueue::key t = m_fastQueue.atomicFront(&x)) {
126 m_fastQueue.atomicPop(t);
132 XNIDAQmxInterface::SoftwareTrigger::stamp(uint64_t cnt) {
134 if(cnt < m_endOfBlank)
return;
137 m_fastQueue.push(cnt);
139 catch (FastQueue::nospace_error&) {
141 fprintf(stderr,
"Slow queue!\n");
142 m_slowQueue.push_back(cnt);
143 if(m_slowQueue.size() > 100000u)
144 m_slowQueue.pop_front();
148 m_endOfBlank = cnt + m_blankTerm;
151 XNIDAQmxInterface::SoftwareTrigger::start(float64 freq) {
155 if(!m_blankTerm) m_blankTerm = lrint(0.02 * freq);
159 onStart().talk(shared_from_this());
163 XNIDAQmxInterface::SoftwareTrigger::stop() {
166 m_endOfBlank = (uint64_t)-1LL;
169 XNIDAQmxInterface::SoftwareTrigger::connect(uint32_t rising_edge_mask,
173 if(m_risingEdgeMask || m_fallingEdgeMask)
175 i18n_noncontext(
"Duplicated connection to virtual trigger is not supported."), __FILE__, __LINE__);
176 m_risingEdgeMask = rising_edge_mask;
177 m_fallingEdgeMask = falling_edge_mask;
180 XNIDAQmxInterface::SoftwareTrigger::disconnect() {
183 m_risingEdgeMask = 0;
184 m_fallingEdgeMask = 0;
188 unsigned int freq_em = lrint(freq());
189 unsigned int freq_rc = lrint(freq__);
190 unsigned int gcd__ = gcd(freq_em, freq_rc);
193 if(m_slowQueueSize) {
195 if(FastQueue::key t = m_fastQueue.atomicFront(&cnt)) {
196 if((cnt < m_slowQueue.front()) || !m_slowQueueSize) {
197 cnt = (cnt * (freq_rc / gcd__)) / (freq_em / gcd__);
200 if(m_fastQueue.atomicPop(t))
205 if( !m_slowQueueSize)
207 cnt = m_slowQueue.front();
208 cnt = (cnt * (freq_rc / gcd__)) / (freq_em / gcd__);
211 m_slowQueue.pop_front();
215 if(FastQueue::key t = m_fastQueue.atomicFront(&cnt)) {
216 cnt = (cnt * (freq_rc / gcd__)) / (freq_em / gcd__);
219 if(m_fastQueue.atomicPop(t))
233 unsigned int freq_em= lrint(freq());
234 unsigned int freq_rc = lrint(freq__);
235 unsigned int gcd__ = gcd(freq_em, freq_rc);
236 now = (now * (freq_em / gcd__)) / (freq_rc / gcd__);
240 while(FastQueue::key t = m_fastQueue.atomicFront(&x)) {
242 m_fastQueue.atomicPop(t);
246 while(m_slowQueue.size() && (m_slowQueue.front() <= now)) {
247 m_slowQueue.pop_front();
252 XNIDAQmxInterface::SoftwareTrigger::forceStamp(uint64_t now, float64 freq__) {
253 unsigned int freq_em= lrint(freq());
254 unsigned int freq_rc = lrint(freq__);
255 unsigned int gcd__ = gcd(freq_em, freq_rc);
256 now = (now * (freq_em / gcd__)) / (freq_rc / gcd__);
260 m_slowQueue.push_front(now);
261 std::sort(m_slowQueue.begin(), m_slowQueue.end());
268 DAQmxGetDevBusType(
devName(), &bus);
283 #endif //HAVE_NI_DAQMX
286 XNIDAQmxInterface::synchronizeClock(TaskHandle task) {
287 float64 rate = g_pciClockMasterRate;
289 if(
devName() == g_pciClockMaster) {
290 src = g_pciClockExtRefTerm;
291 rate = g_pciClockExtRefRate;
298 CHECK_DAQMX_RET(DAQmxSetRefClkSrc(task, src.c_str()));
299 CHECK_DAQMX_RET(DAQmxSetRefClkRate(task, rate));
302 CHECK_DAQMX_RET(DAQmxSetRefClkSrc(task,
"PXI_Clk10"));
303 CHECK_DAQMX_RET(DAQmxSetRefClkRate(task, 10e6));
308 CHECK_DAQMX_RET(DAQmxSetMasterTimebaseSrc(task, src.c_str()));
309 CHECK_DAQMX_RET(DAQmxSetMasterTimebaseRate(task, rate));
312 CHECK_DAQMX_RET(DAQmxSetMasterTimebaseSrc(task,
"PXI_Clk10"));
313 CHECK_DAQMX_RET(DAQmxSetMasterTimebaseRate(task, 10e6));
319 XNIDAQmxInterface::getNIDAQmxErrMessage()
323 DAQmxGetExtendedErrorInfo(str,
sizeof(str));
328 #endif //HAVE_NI_DAQMX
331 XNIDAQmxInterface::getNIDAQmxErrMessage(
int status) {
334 DAQmxGetErrorString(status, str,
sizeof(str));
339 #endif //HAVE_NI_DAQMX
342 XNIDAQmxInterface::checkDAQmxError(
int ret,
const char*file,
int line) {
343 if(ret >= 0)
return ret;
354 const char *del =
", \t";
355 for(
int pos = 0; pos != std::string::npos; ) {
356 int spos = org.find_first_not_of(del, pos);
357 if(spos == std::string::npos)
break;
358 pos = org.find_first_of(del, spos);
359 if(pos == std::string::npos)
360 list.push_back(org.substr(spos));
362 list.push_back(org.substr(spos, pos - spos));
367 XNIDAQmxInterface::XNIDAQmxInterface(
const char *name,
bool runtime,
const shared_ptr<XDriver> &driver) :
372 CHECK_DAQMX_RET(DAQmxGetSysDevNames(buf,
sizeof(buf)));
373 std::deque<XString> list;
376 for(
auto it = list.cbegin(); it != list.cend(); ++it) {
377 CHECK_DAQMX_RET(DAQmxGetDevProductType(it->c_str(), buf,
sizeof(buf)));
378 tr[ *
device()].add(*it +
" [" + buf +
"]");
381 #endif //HAVE_NI_DAQMX
383 XNIDAQmxInterface::XNIDAQmxRoute::XNIDAQmxRoute(
const char*src,
const char*dst,
int *pret)
384 : m_src(src), m_dst(dst) {
388 ret = DAQmxConnectTerms(src, dst, DAQmx_Val_DoNotInvertPolarity);
395 CHECK_DAQMX_ERROR(DAQmxConnectTerms(src, dst, DAQmx_Val_DoNotInvertPolarity));
396 dbgPrint(QString(
"Connect route from %1 to %2.").arg(src).arg(dst));
403 #endif //HAVE_NI_DAQMX
405 XNIDAQmxInterface::XNIDAQmxRoute::~XNIDAQmxRoute() {
406 if(!m_src.length())
return;
408 CHECK_DAQMX_RET(DAQmxDisconnectTerms(m_src.c_str(), m_dst.c_str()));
409 dbgPrint(QString(
"Disconnect route from %1 to %2.").arg(m_src).arg(m_dst));
416 XNIDAQmxInterface::open() throw (XInterfaceError &) {
421 if(sscanf(shot[ *
device()].to_str().c_str(),
"%255s", buf) != 1)
422 throw XOpenInterfaceError(__FILE__, __LINE__);
425 if(g_daqmx_open_cnt == 0) {
427 g_pciClockExtRefTerm.clear();
430 CHECK_DAQMX_RET(DAQmxGetSysDevNames(buf,
sizeof(buf)));
431 std::deque<XString> list;
433 std::deque<XString> pcidevs;
434 for(std::deque<XString>::iterator it = list.begin(); it != list.end(); ++it) {
436 DAQmxResetDevice(it->c_str());
439 DAQmxGetDevBusType(it->c_str(), &bus);
440 if((bus == DAQmx_Val_PCI) || (bus == DAQmx_Val_PCIe)) {
441 pcidevs.push_back(*it);
444 if(pcidevs.size() > 1) {
445 for(std::deque<XString>::iterator it = pcidevs.begin(); it != pcidevs.end(); ++it) {
447 CHECK_DAQMX_RET(DAQmxGetDevProductType(it->c_str(), buf,
sizeof(buf)));
449 for(
const ProductInfo *pit = sc_productInfoList; pit->type; pit++) {
450 if((pit->type == type) && ((pit->series ==
XString(
"M")) || (pit->series ==
XString(
"X")) )) {
451 XString inp_term = formatString(
"/%s/PFI0", it->c_str());
454 fprintf(stderr,
"Reference Clock for PLL Set to %s\n", inp_term.c_str());
455 g_pciClockMaster = *it;
457 pcidevs.push_back(g_pciClockMaster);
462 if(g_pciClockMaster.length())
465 for(std::deque<XString>::iterator it = pcidevs.begin(); it != pcidevs.end(); ++it) {
468 CHECK_DAQMX_RET(DAQmxGetDevProductType(it->c_str(), buf,
sizeof(buf)));
470 for(
const ProductInfo *pit = sc_productInfoList; pit->type; ++pit) {
471 if((pit->type == type) && (pit->series ==
XString(
"S"))) {
473 shared_ptr<XNIDAQmxInterface::XNIDAQmxRoute> route;
474 float64 freq = 20.0e6;
476 formatString(
"/%s/20MHzTimebase", it->c_str()).c_str(),
477 formatString(
"/%s/RTSI7", it->c_str()).c_str()));
478 g_daqmx_sync_routes.push_back(route);
479 fprintf(stderr,
"20MHz Reference Clock exported from %s\n", it->c_str());
480 g_pciClockMaster = *it;
481 g_pciClockMasterRate = freq;
486 if(g_pciClockMaster.length())
489 for(std::deque<XString>::iterator it = pcidevs.begin(); it != pcidevs.end(); ++it) {
491 CHECK_DAQMX_RET(DAQmxGetDevProductType(it->c_str(), buf,
sizeof(buf)));
493 for(
const ProductInfo *pit = sc_productInfoList; pit->type; pit++) {
494 if((pit->type == type) && ((pit->series ==
XString(
"M")) || (pit->series ==
XString(
"X")) )) {
496 fprintf(stderr,
"20MHz Reference Clock exported from %s\n", it->c_str());
498 XString ctrdev = formatString(
"%s/ctr1", it->c_str());
500 CHECK_DAQMX_RET(DAQmxCreateTask(
"", &g_pciClockMasterTask));
502 CHECK_DAQMX_RET(DAQmxCreateCOPulseChanFreq(g_pciClockMasterTask,
503 ctrdev.c_str(),
"", DAQmx_Val_Hz, DAQmx_Val_Low, 0.0,
505 CHECK_DAQMX_RET(DAQmxCfgImplicitTiming(g_pciClockMasterTask, DAQmx_Val_ContSamps, 1000));
506 CHECK_DAQMX_RET(DAQmxSetCOPulseTerm(g_pciClockMasterTask, ctrdev.c_str(), formatString(
"/%s/RTSI7", it->c_str()).c_str()));
507 if(g_pciClockExtRefTerm.length()) {
508 CHECK_DAQMX_RET(DAQmxSetRefClkSrc(g_pciClockMasterTask, g_pciClockExtRefTerm.c_str()));
509 CHECK_DAQMX_RET(DAQmxSetRefClkRate(g_pciClockMasterTask, g_pciClockExtRefRate));
511 CHECK_DAQMX_RET(DAQmxStartTask(g_pciClockMasterTask));
512 g_pciClockMaster = *it;
513 g_pciClockMasterRate = freq;
518 if(g_pciClockMaster.length())
526 CHECK_DAQMX_RET(DAQmxGetDevProductType(devname.c_str(), buf,
sizeof(buf)));
529 m_productInfo = NULL;
530 for(
const ProductInfo *it = sc_productInfoList; it->type; it++) {
531 if(it->type == type) {
537 throw XInterfaceError(i18n(
"No device info. for product [%1].").arg(type), __FILE__, __LINE__);
538 #endif //HAVE_NI_DAQMX
543 XString ctrdev = formatString(
"/%s/ctr0", dev);
544 TaskHandle taskCounting = 0;
546 CHECK_DAQMX_RET(DAQmxCreateTask(
"",&taskCounting));
547 CHECK_DAQMX_RET(DAQmxCreateCIFreqChan(taskCounting,
548 ctrdev.c_str(),
"", 1000000, 25000000, DAQmx_Val_Hz,
549 DAQmx_Val_Rising, DAQmx_Val_LargeRng2Ctr, 0.01, 100, NULL));
550 CHECK_DAQMX_RET(DAQmxCfgImplicitTiming(taskCounting, DAQmx_Val_ContSamps, 1000));
551 CHECK_DAQMX_RET(DAQmxSetCIFreqTerm(taskCounting, ctrdev.c_str(), inp_term));
553 CHECK_DAQMX_RET(DAQmxStartTask(taskCounting));
556 int32 ret = DAQmxReadCounterF64(taskCounting, 1000, 0.05, data,1000, &cnt, 0);
558 for(
int i = cnt / 2; i < cnt; ++i)
560 freq /= cnt - cnt / 2;
561 DAQmxStopTask(taskCounting);
562 DAQmxClearTask(taskCounting);
565 fprintf(stderr,
"%.5g Hz detected at the counter input term %s.\n", (
double)freq, inp_term);
567 uint64_t freq_cand[] = {10000000, 20000000, 0};
568 for(uint64_t *f = freq_cand; *f; ++f) {
569 if(fabs(freq - *f) < *f * 0.001) {
570 g_pciClockExtRefTerm = inp_term;
571 g_pciClockExtRefRate = *f;
575 #endif //HAVE_NI_DAQMX
581 m_productInfo = NULL;
582 if(m_devname.length()) {
587 if(g_daqmx_open_cnt == 0) {
588 if(g_pciClockMasterTask != (TaskHandle)-1) {
589 CHECK_DAQMX_RET(DAQmxClearTask(g_pciClockMasterTask));
591 g_pciClockMasterTask = (TaskHandle)-1;
592 g_daqmx_sync_routes.clear();