14 #include "pulserdrivernidaqmx.h"
22 #define PAUSING_BLANK_BEFORE 1u
23 #define PAUSING_BLANK_AFTER 1u
25 #include "interface.h"
27 #define TASK_UNDEF ((TaskHandle)-1)
28 #define RESOLUTION_UNDEF 1e-5
31 inline T *fastFill(T* p, T x,
unsigned int cnt);
33 XNIDAQmxPulser::XNIDAQmxPulser(
const char *name,
bool runtime,
34 Transaction &tr_meas,
const shared_ptr<XMeasure> &meas):
36 m_pausingBit(0), m_pausingCount(0),
38 m_resolutionDO(RESOLUTION_UNDEF),
39 m_resolutionAO(RESOLUTION_UNDEF),
42 m_taskDOCtr(TASK_UNDEF),
43 m_taskGateCtr(TASK_UNDEF) {
46 for(
unsigned int i = 0; i < NUM_DO_PORTS; i++)
47 tr[ *portSel(i)].add(
"Pausing(PFI4)");
49 PORTSEL_GATE, PORTSEL_PREGATE, PORTSEL_TRIG1, PORTSEL_TRIG2,
50 PORTSEL_GATE3, PORTSEL_COMB, PORTSEL_QSW, PORTSEL_ASW
52 for(
unsigned int i = 0; i <
sizeof(ports)/
sizeof(
int); i++) {
53 tr[ *portSel(i)] = ports[i];
57 m_softwareTrigger = XNIDAQmxInterface::SoftwareTrigger::create(name, NUM_DO_PORTS);
59 m_pausingCount = (PAUSING_BLANK_BEFORE + PAUSING_BLANK_AFTER) * 47;
62 if(isMemLockAvailable()) {
63 const void *FIRST_OF_MLOCK_MEMBER = &m_genPatternList;
64 const void *LAST_OF_MLOCK_MEMBER = &m_lowerLimAO[NUM_AO_CH];
65 mlock(FIRST_OF_MLOCK_MEMBER, (
size_t)LAST_OF_MLOCK_MEMBER - (
size_t)FIRST_OF_MLOCK_MEMBER);
69 XNIDAQmxPulser::~XNIDAQmxPulser() {
71 XNIDAQmxInterface::SoftwareTrigger::unregister(m_softwareTrigger);
75 XNIDAQmxPulser::openDO(
bool use_ao_clock)
throw (
XKameError &) {
78 if(intfDO()->maxDORate(1) == 0)
81 if(m_resolutionDO == RESOLUTION_UNDEF)
82 m_resolutionDO = 1.0 / intfDO()->maxDORate(1);
83 fprintf(stderr,
"Using DO rate = %f[kHz]\n", 1.0/m_resolutionDO);
84 setupTasksDO(use_ao_clock);
88 XNIDAQmxPulser::openAODO() throw (
XKameError &) {
91 if(intfDO()->maxDORate(1) == 0)
93 if(intfAO()->maxAORate(2) == 0)
96 if((m_resolutionDO == RESOLUTION_UNDEF) || (m_resolutionAO == RESOLUTION_UNDEF))
98 double do_rate = intfDO()->maxDORate(1);
99 double ao_rate = intfAO()->maxAORate(2);
100 if(ao_rate <= do_rate)
105 ao_rate = do_rate * oversamp;
107 m_resolutionDO = 1.0 / do_rate;
108 m_resolutionAO = 1.0 / ao_rate;
110 fprintf(stderr,
"Using AO rate = %f[kHz]\n", 1.0/m_resolutionAO);
129 m_resolutionDO = RESOLUTION_UNDEF;
130 m_resolutionAO = RESOLUTION_UNDEF;
138 XNIDAQmxPulser::clearTasks() {
139 if(m_taskAO != TASK_UNDEF)
140 CHECK_DAQMX_RET(DAQmxClearTask(m_taskAO));
141 if(m_taskDO != TASK_UNDEF)
142 CHECK_DAQMX_RET(DAQmxClearTask(m_taskDO));
143 if(m_taskDOCtr != TASK_UNDEF)
144 CHECK_DAQMX_RET(DAQmxClearTask(m_taskDOCtr));
145 if(m_taskGateCtr != TASK_UNDEF)
146 CHECK_DAQMX_RET(DAQmxClearTask(m_taskGateCtr));
147 m_taskAO = TASK_UNDEF;
148 m_taskDO = TASK_UNDEF;
149 m_taskDOCtr = TASK_UNDEF;
150 m_taskGateCtr = TASK_UNDEF;
154 XNIDAQmxPulser::setupTasksDO(
bool use_ao_clock) {
155 if(m_taskDO != TASK_UNDEF)
156 CHECK_DAQMX_RET(DAQmxClearTask(m_taskDO));
157 if(m_taskDOCtr != TASK_UNDEF)
158 CHECK_DAQMX_RET(DAQmxClearTask(m_taskDOCtr));
159 if(m_taskGateCtr != TASK_UNDEF)
160 CHECK_DAQMX_RET(DAQmxClearTask(m_taskGateCtr));
164 CHECK_DAQMX_RET(DAQmxCreateTask(
"", &m_taskDO));
165 CHECK_DAQMX_RET(DAQmxCreateDOChan(m_taskDO,
166 formatString(
"%s/port0", intfDO()->devName()).c_str(),
167 "", DAQmx_Val_ChanForAllLines));
168 CHECK_DAQMX_RET(DAQmxRegisterDoneEvent(m_taskDO, 0, &XNIDAQmxPulser::onTaskDone_,
this));
173 do_clk_src = formatString(
"/%s/ao/SampleClock", intfAO()->devName());
174 fprintf(stderr,
"Using ao/SampleClock for DO.\n");
177 do_clk_src = formatString(
"/%s/Ctr0InternalOutput", intfCtr()->devName());
178 XString ctrdev = formatString(
"%s/ctr0", intfCtr()->devName());
180 CHECK_DAQMX_RET(DAQmxCreateTask(
"", &m_taskDOCtr));
181 CHECK_DAQMX_RET(DAQmxCreateCOPulseChanFreq(m_taskDOCtr,
182 ctrdev.c_str(),
"", DAQmx_Val_Hz, DAQmx_Val_Low, 0.0,
184 CHECK_DAQMX_RET(DAQmxRegisterDoneEvent(m_taskDOCtr, 0, &XNIDAQmxPulser::onTaskDone_,
this));
185 CHECK_DAQMX_RET(DAQmxCfgImplicitTiming(m_taskDOCtr, DAQmx_Val_ContSamps, 1000));
186 intfCtr()->synchronizeClock(m_taskDOCtr);
187 m_softwareTrigger->setArmTerm(do_clk_src.c_str());
190 unsigned int buf_size_hint = (
unsigned int)lrint(1.0 * freq);
192 CHECK_DAQMX_RET(DAQmxCfgSampClkTiming(m_taskDO,
194 freq, DAQmx_Val_Rising, DAQmx_Val_ContSamps, buf_size_hint));
197 uInt32 onbrdsize, bufsize;
198 CHECK_DAQMX_RET(DAQmxGetBufOutputOnbrdBufSize(m_taskDO, &onbrdsize));
199 fprintf(stderr,
"DO On-board bufsize = %d\n", (
int)onbrdsize);
202 CHECK_DAQMX_RET(DAQmxGetBufOutputBufSize(m_taskDO, &bufsize));
203 if(bufsize < buf_size_hint)
204 CHECK_DAQMX_RET(DAQmxCfgOutputBuffer(m_taskDO, std::max((uInt32)buf_size_hint, onbrdsize / 4)));
205 CHECK_DAQMX_RET(DAQmxGetBufOutputBufSize(m_taskDO, &bufsize));
206 fprintf(stderr,
"DO Using bufsize = %d, freq = %f\n", (
int)bufsize, freq);
209 CHECK_DAQMX_RET(DAQmxSetWriteRegenMode(m_taskDO, DAQmx_Val_DoNotAllowRegen));
215 CHECK_DAQMX_RET(DAQmxGetTaskChannels(m_taskDO, ch,
sizeof(ch)));
216 if(intfDO()->productFlags() & XNIDAQmxInterface::FLAG_BUGGY_DMA_DO) {
217 CHECK_DAQMX_RET(DAQmxSetDODataXferMech(m_taskDO, ch,
218 DAQmx_Val_Interrupts));
220 if(intfDO()->productFlags() & XNIDAQmxInterface::FLAG_BUGGY_XFER_COND_DO) {
221 CHECK_DAQMX_RET(DAQmxSetDODataXferReqCond(m_taskDO, ch,
222 DAQmx_Val_OnBrdMemNotFull));
227 m_pausingGateTerm = formatString(
"/%s/PFI4", intfDO()->devName());
228 unsigned int ctr_no = use_ao_clock ? 0 : 1;
229 m_pausingCh = formatString(
"%s/ctr%u", intfCtr()->devName(), ctr_no);
230 m_pausingSrcTerm = formatString(
"/%s/Ctr%uInternalOutput", intfCtr()->devName(), ctr_no);
232 CHECK_DAQMX_RET(DAQmxCreateTask(
"", &m_taskGateCtr));
233 CHECK_DAQMX_RET(DAQmxCreateCOPulseChanTime(m_taskGateCtr,
234 m_pausingCh.c_str(),
"", DAQmx_Val_Seconds, DAQmx_Val_Low,
238 CHECK_DAQMX_RET(DAQmxCfgImplicitTiming(m_taskGateCtr,
239 DAQmx_Val_FiniteSamps, 1));
240 CHECK_DAQMX_RET(DAQmxSetCOCtrTimebaseActiveEdge(m_taskGateCtr,
241 m_pausingCh.c_str(), DAQmx_Val_Rising));
242 intfCtr()->synchronizeClock(m_taskGateCtr);
244 CHECK_DAQMX_RET(DAQmxCfgDigEdgeStartTrig(m_taskGateCtr,
245 m_pausingGateTerm.c_str(),
247 CHECK_DAQMX_RET(DAQmxSetStartTrigRetriggerable(m_taskGateCtr,
true));
251 CHECK_DAQMX_RET(DAQmxGetTaskChannels(m_taskDOCtr, doch, 256));
252 CHECK_DAQMX_RET(DAQmxSetCOCtrTimebaseActiveEdge(m_taskDOCtr,
253 doch, DAQmx_Val_Falling));
254 CHECK_DAQMX_RET(DAQmxSetPauseTrigType(m_taskDOCtr, DAQmx_Val_DigLvl));
255 CHECK_DAQMX_RET(DAQmxSetDigLvlPauseTrigSrc(m_taskDOCtr, m_pausingSrcTerm.c_str()));
256 CHECK_DAQMX_RET(DAQmxSetDigLvlPauseTrigWhen(m_taskDOCtr, DAQmx_Val_High));
262 XNIDAQmxPulser::setupTasksAODO() {
263 if(m_taskAO != TASK_UNDEF)
264 CHECK_DAQMX_RET(DAQmxClearTask(m_taskAO));
266 CHECK_DAQMX_RET(DAQmxCreateTask(
"", &m_taskAO));
267 CHECK_DAQMX_RET(DAQmxCreateAOVoltageChan(m_taskAO,
268 formatString(
"%s/ao0:1", intfAO()->devName()).c_str(),
"",
269 -1.0, 1.0, DAQmx_Val_Volts, NULL));
270 CHECK_DAQMX_RET(DAQmxRegisterDoneEvent(m_taskAO, 0, &XNIDAQmxPulser::onTaskDone_,
this));
272 float64 freq = 1e3 / resolutionQAM();
273 unsigned int buf_size_hint = (
unsigned int)lrint(1.0 * freq);
275 CHECK_DAQMX_RET(DAQmxCfgSampClkTiming(m_taskAO,
"",
276 freq, DAQmx_Val_Rising, DAQmx_Val_ContSamps, buf_size_hint));
277 intfAO()->synchronizeClock(m_taskAO);
279 int oversamp = lrint(
resolution() / resolutionQAM());
280 setupTasksDO(oversamp == 1);
284 CHECK_DAQMX_RET(DAQmxSetArmStartTrigType(m_taskDOCtr, DAQmx_Val_DigEdge));
285 CHECK_DAQMX_RET(DAQmxSetDigEdgeArmStartTrigSrc(m_taskDOCtr,
286 formatString(
"/%s/ao/StartTrigger", intfAO()->devName()).c_str()));
287 CHECK_DAQMX_RET(DAQmxSetDigEdgeArmStartTrigEdge(m_taskDOCtr,
291 CHECK_DAQMX_RET(DAQmxCfgDigEdgeStartTrig(m_taskDOCtr,
292 formatString(
"/%s/ao/StartTrigger", intfAO()->devName()).c_str(),
298 CHECK_DAQMX_RET(DAQmxSetSampClkTimebaseActiveEdge(m_taskAO, DAQmx_Val_Rising));
299 CHECK_DAQMX_RET(DAQmxSetPauseTrigType(m_taskAO, DAQmx_Val_DigLvl));
300 CHECK_DAQMX_RET(DAQmxSetDigLvlPauseTrigSrc(m_taskAO, m_pausingSrcTerm.c_str()));
301 CHECK_DAQMX_RET(DAQmxSetDigLvlPauseTrigWhen(m_taskAO, DAQmx_Val_High));
304 m_softwareTrigger->setArmTerm(
305 formatString(
"/%s/ao/SampleClock", intfAO()->devName()).c_str());
308 uInt32 onbrdsize, bufsize;
310 CHECK_DAQMX_RET(DAQmxGetBufOutputOnbrdBufSize(m_taskAO, &onbrdsize));
311 fprintf(stderr,
"AO On-board bufsize = %d\n", (
int)onbrdsize);
314 CHECK_DAQMX_RET(DAQmxGetBufOutputBufSize(m_taskAO, &bufsize));
315 if(bufsize < buf_size_hint)
316 CHECK_DAQMX_RET(DAQmxCfgOutputBuffer(m_taskAO, std::max((uInt32)buf_size_hint, onbrdsize / 4)));
317 CHECK_DAQMX_RET(DAQmxGetBufOutputBufSize(m_taskAO, &bufsize));
318 fprintf(stderr,
"AO Using bufsize = %d\n", (
int)bufsize);
321 CHECK_DAQMX_RET(DAQmxSetWriteRegenMode(m_taskAO, DAQmx_Val_DoNotAllowRegen));
327 CHECK_DAQMX_RET(DAQmxGetTaskChannels(m_taskAO, ch,
sizeof(ch)));
328 if(intfAO()->productFlags() & XNIDAQmxInterface::FLAG_BUGGY_DMA_AO) {
329 CHECK_DAQMX_RET(DAQmxSetAODataXferMech(m_taskAO, ch,
330 DAQmx_Val_Interrupts));
332 if(intfAO()->productFlags() & XNIDAQmxInterface::FLAG_BUGGY_XFER_COND_AO) {
333 CHECK_DAQMX_RET(DAQmxSetAODataXferReqCond(m_taskAO, ch,
334 DAQmx_Val_OnBrdMemNotFull));
339 for(
unsigned int ch = 0; ch < NUM_AO_CH; ch++) {
341 for(
unsigned int i = 0; i < CAL_POLY_ORDER; i++)
342 m_coeffAODev[ch][i] = 0.0;
343 CHECK_DAQMX_RET(DAQmxGetAODevScalingCoeff(m_taskAO,
344 formatString(
"%s/ao%d", intfAO()->devName(), ch).c_str(),
345 m_coeffAODev[ch], CAL_POLY_ORDER));
346 CHECK_DAQMX_RET(DAQmxGetAODACRngHigh(m_taskAO,
347 formatString(
"%s/ao%d", intfAO()->devName(), ch).c_str(),
349 CHECK_DAQMX_RET(DAQmxGetAODACRngLow(m_taskAO,
350 formatString(
"%s/ao%d", intfAO()->devName(), ch).c_str(),
360 XNIDAQmxPulser::onTaskDone_(TaskHandle task, int32 status,
void *data) {
362 obj->onTaskDone(task, status);
366 XNIDAQmxPulser::onTaskDone(TaskHandle task, int32 status) {
369 if(task == m_taskDO) { str =
"DO"; }
370 if(task == m_taskDOCtr) { str =
"DOCtr"; }
371 if(task == m_taskAO) { str =
"AO"; }
372 if(task == m_taskGateCtr) { str =
"GateCtr"; }
373 gErrPrint(
getLabel() +
"\n" + str +
"\n" + XNIDAQmxInterface::getNIDAQmxErrMessage(status));
382 template <
typename T>
384 fastFill(T* p, T x,
unsigned int cnt) {
386 for(;(intptr_t)p % (
sizeof(uint64_t) /
sizeof(T)); cnt--)
388 uint64_t *pp = (uint64_t *)p;
390 uint64_t dw; T w[
sizeof(uint64_t) /
sizeof(T)];
392 for(
unsigned int i = 0; i < (
sizeof(uint64_t) /
sizeof(T)); i++)
394 unsigned int pcnt = cnt / (
sizeof(uint64_t) /
sizeof(T));
395 cnt = cnt % (
sizeof(uint64_t) /
sizeof(T));
396 for(
unsigned int i = 0; i < pcnt; i++)
400 for(
unsigned int i = 0; i < cnt; i++)
406 XNIDAQmxPulser::preparePatternGen(
const Snapshot &shot,
407 bool use_dummypattern,
unsigned int blankpattern) {
408 if(use_dummypattern) {
410 shared_ptr<std::vector<GenPattern> > patlist_dummy(
new std::vector<GenPattern>());
411 patlist_dummy->push_back(GenPattern(blankpattern, 100000));
412 patlist_dummy->push_back(GenPattern(blankpattern, 100000));
413 m_genPatternList = patlist_dummy;
414 for(
unsigned int j = 0; j < PAT_QAM_MASK / PAT_QAM_PHASE; j++) {
415 m_genPulseWaveAO[j].reset();
420 m_genPatternList = shot[ *
this].m_genPatternListNext;
421 for(
unsigned int j = 0; j < PAT_QAM_MASK / PAT_QAM_PHASE; j++) {
422 m_genPulseWaveAO[j] = shot[ *
this].m_genPulseWaveNextAO[j];
424 m_genAOZeroLevel = shot[ *
this].m_genAOZeroLevelNext;
428 m_genLastPatIt = m_genPatternList->begin();
432 if(m_taskAO != TASK_UNDEF) {
441 XNIDAQmxPulser::startPulseGen(
const Snapshot &shot)
throw (XKameError &) {
443 if(m_running && m_softwareTrigger->isPersistentCoherentMode()) {
444 startPulseGenFromFreeRun(shot);
450 unsigned int pausingbit = selectedPorts(shot, PORTSEL_PAUSING);
451 m_aswBit = selectedPorts(shot, PORTSEL_ASW);
453 if((m_taskDO == TASK_UNDEF) ||
454 (m_pausingBit != pausingbit)) {
455 m_pausingBit = pausingbit;
464 CHECK_DAQMX_RET(DAQmxGetBufOutputOnbrdBufSize(m_taskDO, &bufsize));
465 if( !m_pausingBit & (bufsize < 2047uL))
467 i18n(
"Use the pausing feature for a cheap DAQmx board.") +
"\n"
468 + i18n(
"Look at the port-selection table."), __FILE__, __LINE__);
470 if(m_taskAO != TASK_UNDEF) {
472 CHECK_DAQMX_RET(DAQmxGetBufOutputOnbrdBufSize(m_taskAO, &bufsize));
473 if( !m_pausingBit & (bufsize < 8192uL))
475 i18n(
"Use the pausing feature for a cheap DAQmx board.") +
"\n"
476 + i18n(
"Look at the port-selection table."), __FILE__, __LINE__);
482 const unsigned int cnt_prezeros = 1000;
483 m_genTotalCount += cnt_prezeros;
484 m_genTotalSamps += cnt_prezeros;
486 const unsigned int oversamp_ao = lrint(resolution() / resolutionQAM());
487 if(m_taskAO != TASK_UNDEF) {
489 CHECK_DAQMX_RET(DAQmxSetWriteRelativeTo(m_taskAO, DAQmx_Val_FirstSample));
490 CHECK_DAQMX_RET(DAQmxSetWriteOffset(m_taskAO, 0));
491 const unsigned int cnt_prezeros_ao = cnt_prezeros * oversamp_ao - 0;
492 m_genAOZeroLevel = shot[ *
this].m_genAOZeroLevelNext;
493 std::vector<tRawAOSet> zeros(cnt_prezeros_ao, m_genAOZeroLevel);
495 CHECK_DAQMX_RET(DAQmxWriteBinaryI16(m_taskAO, cnt_prezeros_ao,
497 DAQmx_Val_GroupByScanNumber,
500 CHECK_DAQMX_RET(DAQmxSetWriteRelativeTo(m_taskAO, DAQmx_Val_CurrWritePos));
501 CHECK_DAQMX_RET(DAQmxSetWriteOffset(m_taskAO, 0));
504 std::vector<tRawDO> zeros(cnt_prezeros, 0);
506 CHECK_DAQMX_RET(DAQmxSetWriteRelativeTo(m_taskDO, DAQmx_Val_FirstSample));
507 CHECK_DAQMX_RET(DAQmxSetWriteOffset(m_taskDO, 0));
509 CHECK_DAQMX_RET(DAQmxWriteDigitalU16(m_taskDO, cnt_prezeros,
511 DAQmx_Val_GroupByScanNumber,
514 CHECK_DAQMX_RET(DAQmxSetWriteRelativeTo(m_taskDO, DAQmx_Val_CurrWritePos));
515 CHECK_DAQMX_RET(DAQmxSetWriteOffset(m_taskDO, 0));
518 m_softwareTrigger->start(1e3 / resolution());
520 m_totalWrittenSampsDO = cnt_prezeros;
521 m_totalWrittenSampsAO = cnt_prezeros * oversamp_ao;
523 m_isThreadWriterReady =
false;
525 preparePatternGen(shot,
false, 0);
527 CHECK_DAQMX_RET(DAQmxTaskControl(m_taskDO, DAQmx_Val_Task_Commit));
528 if(m_taskDOCtr != TASK_UNDEF)
529 CHECK_DAQMX_RET(DAQmxTaskControl(m_taskDOCtr, DAQmx_Val_Task_Commit));
530 if(m_taskGateCtr != TASK_UNDEF)
531 CHECK_DAQMX_RET(DAQmxTaskControl(m_taskGateCtr, DAQmx_Val_Task_Commit));
532 if(m_taskAO != TASK_UNDEF)
533 CHECK_DAQMX_RET(DAQmxTaskControl(m_taskAO, DAQmx_Val_Task_Commit));
536 XTime wait_since(XTime::now());
537 while( !m_isThreadWriterReady) {
538 if(m_threadWriter->isTerminated())
541 if(XTime::now() - wait_since > 1.0)
543 i18n(
"Buffer filling encountered time out."), __FILE__, __LINE__);
548 CHECK_DAQMX_RET(DAQmxGetTaskChannels(m_taskDO, ch,
sizeof(ch)));
549 CHECK_DAQMX_RET(DAQmxSetDOTristate(m_taskDO, ch,
false));
553 CHECK_DAQMX_RET(DAQmxStartTask(m_taskDO));
554 if(m_taskGateCtr != TASK_UNDEF)
555 CHECK_DAQMX_RET(DAQmxStartTask(m_taskGateCtr));
556 if(m_taskDOCtr != TASK_UNDEF)
557 CHECK_DAQMX_RET(DAQmxStartTask(m_taskDOCtr));
559 if(m_taskAO != TASK_UNDEF)
560 CHECK_DAQMX_RET(DAQmxStartTask(m_taskAO));
564 XNIDAQmxPulser::startBufWriter() {
567 &XNIDAQmxPulser::executeWriter));
568 m_threadWriter->resume();
571 XNIDAQmxPulser::stopBufWriter() {
574 m_threadWriter->terminate();
575 m_threadWriter->waitFor();
576 m_threadWriter.reset();
580 XNIDAQmxPulser::stopPulseGen() {
586 XNIDAQmxPulser::abortPulseGen() {
589 m_softwareTrigger->stop();
593 CHECK_DAQMX_RET(DAQmxGetTaskChannels(m_taskDO, ch,
sizeof(ch)));
595 CHECK_DAQMX_RET(DAQmxGetDONumLines(m_taskDO, ch, &num_lines));
598 for(
unsigned int i = 0; i < num_lines; i++) {
604 chtri = chtri + formatString(
"%s/line%u", ch, i);
606 CHECK_DAQMX_RET(DAQmxSetDOTristate(m_taskDO, chtri.c_str(),
true));
608 if(m_taskAO != TASK_UNDEF)
609 CHECK_DAQMX_RET(DAQmxStopTask(m_taskAO));
610 if(m_taskDOCtr != TASK_UNDEF)
611 CHECK_DAQMX_RET(DAQmxStopTask(m_taskDOCtr));
612 CHECK_DAQMX_RET(DAQmxStopTask(m_taskDO));
613 if(m_taskGateCtr != TASK_UNDEF) {
615 CHECK_DAQMX_RET(DAQmxWaitUntilTaskDone(m_taskGateCtr, 0.1));
618 CHECK_DAQMX_ERROR(DAQmxStopTask(m_taskGateCtr));
620 if(m_taskAO != TASK_UNDEF)
621 CHECK_DAQMX_RET(DAQmxTaskControl(m_taskAO, DAQmx_Val_Task_Unreserve));
622 if(m_taskDOCtr != TASK_UNDEF)
623 CHECK_DAQMX_RET(DAQmxTaskControl(m_taskDOCtr, DAQmx_Val_Task_Unreserve));
624 CHECK_DAQMX_RET(DAQmxTaskControl(m_taskDO, DAQmx_Val_Task_Unreserve));
625 if(m_taskGateCtr != TASK_UNDEF)
626 CHECK_DAQMX_RET(DAQmxTaskControl(m_taskGateCtr, DAQmx_Val_Task_Unreserve));
634 XNIDAQmxPulser::rewindBufPos(
double ms_from_gen_pos) {
635 int32 cnt_from_gen_pos = lrint(ms_from_gen_pos /
resolution());
636 const unsigned int oversamp_ao = lrint(
resolution() / resolutionQAM());
638 CHECK_DAQMX_RET(DAQmxGetWriteTotalSampPerChanGenerated(m_taskDO, &samp_gen));
639 if(m_taskAO != TASK_UNDEF) {
640 uInt64 samp_gen_ao, currpos_ao;
641 CHECK_DAQMX_RET(DAQmxGetWriteTotalSampPerChanGenerated(m_taskAO, &samp_gen_ao));
642 samp_gen = std::max(samp_gen_ao / oversamp_ao, samp_gen);
648 if(it->second > samp_gen) {
649 count_gen = it->first;
654 if(it->first > count_gen + cnt_from_gen_pos) {
661 uint64_t currsamps = m_totalWrittenSampsDO;
662 if(m_taskAO != TASK_UNDEF)
667 if(rit->second <= currsamps) {
681 CHECK_DAQMX_RET(DAQmxSetWriteOffset(m_taskDO, -(int32_t)(m_totalWrittenSampsDO -
m_genTotalSamps)));
682 if(m_taskAO != TASK_UNDEF) {
685 fprintf(stderr,
"Rewind: %g,%g,%g,%g,%g\n", (
double)samp_gen, (
double)m_totalWrittenSampsDO,
692 const unsigned int cnt_prezeros = 1000;
695 m_genTotalCount += cnt_prezeros;
698 if(m_taskAO != TASK_UNDEF) {
700 const unsigned int oversamp_ao = lrint(
resolution() / resolutionQAM());
701 const unsigned int cnt_prezeros_ao = cnt_prezeros * oversamp_ao - 0;
702 std::vector<tRawAOSet> zeros(cnt_prezeros_ao, m_genAOZeroLevel);
704 CHECK_DAQMX_RET(DAQmxWriteBinaryI16(m_taskAO, cnt_prezeros_ao,
706 DAQmx_Val_GroupByScanNumber,
709 CHECK_DAQMX_RET(DAQmxSetWriteRelativeTo(m_taskAO, DAQmx_Val_CurrWritePos));
710 CHECK_DAQMX_RET(DAQmxSetWriteOffset(m_taskAO, 0));
713 std::vector<tRawDO> zeros(cnt_prezeros, 0);
716 CHECK_DAQMX_RET(DAQmxWriteDigitalU16(m_taskDO, cnt_prezeros,
718 DAQmx_Val_GroupByScanNumber,
721 CHECK_DAQMX_RET(DAQmxSetWriteRelativeTo(m_taskDO, DAQmx_Val_CurrWritePos));
722 CHECK_DAQMX_RET(DAQmxSetWriteOffset(m_taskDO, 0));
724 m_totalWrittenSampsDO += cnt_prezeros;
728 XNIDAQmxPulser::stopPulseGenFreeRunning(
unsigned int blankpattern) {
732 m_softwareTrigger->clear();
737 preparePatternGen(
Snapshot( *
this),
true, blankpattern);
741 XNIDAQmxPulser::startPulseGenFromFreeRun(
const Snapshot &shot) {
743 m_softwareTrigger->clear();
748 preparePatternGen(shot,
false, 0);
753 const double volts[] = {volt.real(), volt.imag()};
755 for(
unsigned int ch = 0; ch < NUM_AO_CH; ch++) {
758 const double *pco = poly_coeff[ch];
759 for(
unsigned int i = 0; i < CAL_POLY_ORDER; i++) {
769 XNIDAQmxPulser::executeWriter(
const atomic<bool> &terminating) {
771 double dma_ao_period = resolutionQAM();
772 uint64_t written_total_ao = 0, written_total_do = 0;
776 &XNIDAQmxPulser::executeFillBuffer);
779 while( !terminating) {
782 const tRawAOSet *pAO = NULL;
783 ssize_t samps_ao = 0;
784 if(m_taskAO != TASK_UNDEF) {
788 if( !samps_do && !samps_ao) {
790 m_transferSizeHintAO * dma_ao_period) / 2));
795 if(samps_ao > samps_do) {
796 written = writeToDAQmxAO(pAO, std::min(samps_ao, (ssize_t)m_transferSizeHintAO));
798 written_total_ao += written;
803 written_total_do += written;
805 if((written_total_do >
m_preFillSizeDO) && ( !pAO || (written_total_ao > m_preFillSizeAO)))
811 m_threadWriter->terminate();
824 m_totalWrittenSampsDO += written_total_do;
827 th_genbuf.terminate();
833 XNIDAQmxPulser::writeToDAQmxAO(
const tRawAOSet *pAO, ssize_t samps) {
835 CHECK_DAQMX_RET(DAQmxGetWriteSpaceAvail(m_taskAO, &space));
836 if(space < (uInt32)samps)
839 CHECK_DAQMX_RET(DAQmxWriteBinaryI16(m_taskAO, samps,
false, 0.0,
840 DAQmx_Val_GroupByScanNumber,
841 const_cast<tRawAOSet *>(pAO)->ch,
848 CHECK_DAQMX_RET(DAQmxGetWriteSpaceAvail(m_taskDO, &space));
849 if(space < (uInt32)samps)
852 CHECK_DAQMX_RET(DAQmxWriteDigitalU16(m_taskDO, samps,
false, 0.0,
853 DAQmx_Val_GroupByScanNumber,
854 const_cast<tRawDO *>(pDO),
859 template <
bool UseAO>
862 unsigned int oversamp_ao = lrint(
resolution() / resolutionQAM());
864 GenPatternIterator it = m_genLastPatIt;
865 uint32_t pat = it->pattern;
870 tRawDO aswbit = m_aswBit;
871 uint64_t pausing_cnt = m_pausingCount;
872 uint64_t pausing_cnt_blank_before = PAUSING_BLANK_BEFORE + PAUSING_BLANK_AFTER;
873 uint64_t pausing_cnt_blank_after = 1;
874 uint64_t pausing_period = pausing_cnt + pausing_cnt_blank_before + pausing_cnt_blank_after;
875 uint64_t pausing_cost = std::max(16uLL, pausing_cnt_blank_before + pausing_cnt_blank_after);
877 shared_ptr<XNIDAQmxInterface::SoftwareTrigger> &vt = m_softwareTrigger;
880 tRawDO *pDOorg = pDO;
889 capacity = std::min(capacity,
m_patBufAO.chunkSize() / (ssize_t)oversamp_ao);
890 for(
unsigned int samps_rest = capacity; samps_rest;) {
891 unsigned int pidx = (pat & PAT_QAM_PULSE_IDX_MASK) / PAT_QAM_PULSE_IDX;
893 tRawDO patDO = PAT_DO_MASK & pat;
895 if(pausingbit && (pidx == 0) && !(pat & aswbit)) {
898 unsigned int lps = (
unsigned int)std::min(
899 (uint64_t)(samps_rest / pausing_cost), (tonext - 1) / pausing_period);
900 patDO &= ~pausingbit;
902 tonext -= lps * pausing_period;
903 samps_rest -= lps * pausing_cost;
904 tRawDO patDO_or_p = patDO | pausingbit;
905 for(
unsigned int lp = 0; lp < lps; lp++) {
906 for(
int i = 0; i < pausing_cnt_blank_before; i++)
908 for(
int i = 0; i < pausing_cnt_blank_after; i++)
912 pAO = fastFill(pAO, raw_zero, lps * oversamp_ao * (pausing_cnt_blank_before + pausing_cnt_blank_after));
915 if(samps_rest < pausing_cost)
919 unsigned int gen_cnt = std::min((uint64_t)samps_rest, tonext);
921 pDO = fastFill(pDO, patDO, gen_cnt);
927 pAO = fastFill(pAO, raw_zero, gen_cnt * oversamp_ao);
930 unsigned int pnum = (pat & PAT_QAM_MASK) / PAT_QAM_PHASE - (PAT_QAM_PULSE_IDX/PAT_QAM_PHASE);
931 assert(pnum < PAT_QAM_PULSE_IDX_MASK / PAT_QAM_PULSE_IDX);
932 if( !m_genPulseWaveAO[pnum].
get() ||
933 (m_genPulseWaveAO[pnum]->size() < gen_cnt * oversamp_ao + aoidx))
935 tRawAOSet *pGenAO = &m_genPulseWaveAO[pnum]->at(aoidx);
936 memcpy(pAO, pGenAO, gen_cnt * oversamp_ao *
sizeof(
tRawAOSet));
937 pAO += gen_cnt * oversamp_ao;
938 aoidx += gen_cnt * oversamp_ao;
942 samps_rest -= gen_cnt;
945 if(it == m_genPatternList->end()) {
946 it = m_genPatternList->begin();
950 vt->changeValue(pat, it->pattern, total);
958 m_genTotalCount = total;
967 XNIDAQmxPulser::executeFillBuffer(
const atomic<bool> &terminating) {
970 while( !terminating) {
971 bool buffer_not_full;
972 if(m_taskAO != TASK_UNDEF) {
973 buffer_not_full = fillBuffer<true>();
976 buffer_not_full = fillBuffer<false>();
986 if( !buffer_not_full) {
996 e.print(
getLabel() +
": ", __FILE__, __LINE__, 0);
1003 tr[ *
this].m_genPatternListNext.reset(
new std::vector<GenPattern>);
1004 uint32_t pat = shot[ *
this].relPatList().back().pattern;
1005 for(Payload::RelPatList::const_iterator it = shot[ *
this].relPatList().begin();
1006 it != shot[ *
this].relPatList().end(); it++) {
1007 uint64_t tonext = it->toappear;
1010 tr[ *
this].m_genPatternListNext->push_back(genpat);
1015 double offset[] = { shot[ *qamOffset1()], shot[ *
qamOffset2()]};
1016 double level[] = { shot[ *qamLevel1()], shot[ *
qamLevel2()]};
1017 double coeffAO[NUM_AO_CH][CAL_POLY_ORDER];
1019 for(
unsigned int ch = 0; ch < NUM_AO_CH; ch++) {
1022 for(
unsigned int i = 0; i < CAL_POLY_ORDER; i++) {
1023 coeffAO[ch][i] = m_coeffAODev[ch][i] * x
1024 + ((i == 0) ? offset[ch] : 0);
1028 tr[ *
this].m_genAOZeroLevelNext =
aoVoltToRaw(coeffAO, std::complex<double>(0.0));
1029 std::complex<double> c(pow(10.0, shot[ *
this].
masterLevel() / 20.0), 0);
1030 for(
unsigned int i = 0; i < PAT_QAM_PULSE_IDX_MASK/PAT_QAM_PULSE_IDX; i++) {
1031 for(
unsigned int qpsk = 0; qpsk < 4; qpsk++) {
1032 const unsigned int pnum = i * (PAT_QAM_PULSE_IDX/PAT_QAM_PHASE) + qpsk;
1033 tr[ *
this].m_genPulseWaveNextAO[pnum].reset(
new std::vector<tRawAOSet>);
1034 for(std::vector<std::complex<double> >::const_iterator it =
1035 shot[ *
this].qamWaveForm(i).begin(); it != shot[ *
this].qamWaveForm(i).end(); it++) {
1036 std::complex<double> z( *it * c);
1037 tr[ *
this].m_genPulseWaveNextAO[pnum]->push_back(
aoVoltToRaw(coeffAO, z));
1039 c *= std::complex<double>(0,1);
1049 if( !interface()->isOpened())
1053 if( !shot[ *
this].m_genPatternListNext || shot[ *
this].m_genPatternListNext->empty() )
1055 startPulseGen(shot);
1058 if(m_running && m_softwareTrigger->isPersistentCoherentMode())
1059 stopPulseGenFreeRunning(blankpattern);