Skip to content

Commit 5161201

Browse files
NI_DAQmx: Write all DO at once instead of iterating over ports.
This resolves an issue raised in the mailing list: https://groups.google.com/forum/#!topic/labscriptsuite/pO6CGa4GsRI in which some devices are unhappy about the explicit buffer configuration required when making multiple writes of data to the same task. By making a single write only, we allow the DAQmx driver to make decisions about buffers itself, which the NI-PCI-DIO-32HS seems to require.
1 parent 40b674f commit 5161201

File tree

1 file changed

+33
-35
lines changed

1 file changed

+33
-35
lines changed

NI_DAQmx/blacs_workers.py

Lines changed: 33 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
from PyDAQmx.DAQmxCallBack import *
3232

3333
import numpy as np
34+
from numpy.lib.recfunctions import structured_to_unstructured
3435
import labscript_utils.h5_lock
3536
import h5py
3637
from zprocess import Event
@@ -196,6 +197,11 @@ def program_buffered_DO(self, DO_table):
196197
line_final_value = bool((1 << line) & port_final_value)
197198
final_values['%s/line%d' % (port_str, line)] = int(line_final_value)
198199

200+
# Convert DO table to a regular array and ensure it is C continguous:
201+
DO_table = np.ascontiguousarray(
202+
structured_to_unstructured(DO_table, dtype=np.uint32)
203+
)
204+
199205
# Check if DOs are all zero for the whole shot. If they are this triggers a
200206
# bug in NI-DAQmx that throws a cryptic error for buffered output. In this
201207
# case, run it as a non-buffered task.
@@ -208,20 +214,17 @@ def program_buffered_DO(self, DO_table):
208214
if self.static_DO or self.DO_all_zero:
209215
# Static DO. Start the task and write data, no timing configuration.
210216
self.DO_task.StartTask()
211-
# Write data for each port:
212-
for port_str in ports:
213-
# See the comment in self.program_manual as to why we are using uint32
214-
# instead of the native size of the port
215-
data = DO_table[port_str].astype(np.uint32, order='C')
216-
self.DO_task.WriteDigitalU32(
217-
1, # npts
218-
False, # autostart
219-
10.0, # timeout
220-
DAQmx_Val_GroupByChannel,
221-
data,
222-
written,
223-
None,
224-
)
217+
# Write data. See the comment in self.program_manual as to why we are using
218+
# uint32 instead of the native size of each port
219+
self.DO_task.WriteDigitalU32(
220+
1, # npts
221+
False, # autostart
222+
10.0, # timeout
223+
DAQmx_Val_GroupByScanNumber,
224+
DO_table,
225+
written,
226+
None,
227+
)
225228
else:
226229
# We use all but the last sample (which is identical to the second last
227230
# sample) in order to ensure there is one more clock tick than there are
@@ -237,23 +240,18 @@ def program_buffered_DO(self, DO_table):
237240
DAQmx_Val_FiniteSamps,
238241
npts,
239242
)
240-
self.DO_task.CfgOutputBuffer(npts)
241-
242-
# Write data for each port:
243-
for port_str in ports:
244-
# Use all but the last sample as mentioned above. See the comment in
245-
# self.program_manual as to why we are using uint32 instead of the native
246-
# size of the port.
247-
data = DO_table[port_str][:-1].astype(np.uint32, order='C')
248-
self.DO_task.WriteDigitalU32(
249-
npts,
250-
False, # autostart
251-
10.0, # timeout
252-
DAQmx_Val_GroupByChannel,
253-
data,
254-
written,
255-
None,
256-
)
243+
244+
# Write data. See the comment in self.program_manual as to why we are using
245+
# uint32 instead of the native size of each port.
246+
self.DO_task.WriteDigitalU32(
247+
npts,
248+
False, # autostart
249+
10.0, # timeout
250+
DAQmx_Val_GroupByScanNumber,
251+
DO_table[:-1], # All but the last sample as mentioned above
252+
written,
253+
None,
254+
)
257255

258256
# Go!
259257
self.DO_task.StartTask()
@@ -273,10 +271,10 @@ def program_buffered_AO(self, AO_table):
273271
# Collect the final values of the analog outs:
274272
final_values = dict(zip(AO_table.dtype.names, AO_table[-1]))
275273

276-
# Obtain a view that is a regular array:
277-
AO_table = AO_table.view((AO_table.dtype[0], len(AO_table.dtype.names)))
278-
# And convert to 64 bit floats:
279-
AO_table = AO_table.astype(np.float64)
274+
# Convert AO table to a regular array and ensure it is C continguous:
275+
AO_table = np.ascontiguousarray(
276+
structured_to_unstructured(AO_table, dtype=np.float64)
277+
)
280278

281279
# Check if AOs are all zero for the whole shot. If they are this triggers a
282280
# bug in NI-DAQmx that throws a cryptic error for buffered output. In this

0 commit comments

Comments
 (0)