Skip to content

Commit acc0c1d

Browse files
Merged in NI_DAQmx (pull request #87)
Add NI-PCI-DIO-32HS and bugfix its buffered DO.
2 parents 2348b1e + 8b8ee99 commit acc0c1d

File tree

3 files changed

+141
-39
lines changed

3 files changed

+141
-39
lines changed

NI_DAQmx/blacs_workers.py

Lines changed: 35 additions & 39 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,32 +197,32 @@ 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.
202-
self.DO_all_zero = all(
203-
DO_table[port].sum() == 0 for port in DO_table.dtype.names
204-
)
208+
self.DO_all_zero = not np.any(DO_table)
205209
if self.DO_all_zero:
206210
DO_table = DO_table[0:1]
207211

208212
if self.static_DO or self.DO_all_zero:
209213
# Static DO. Start the task and write data, no timing configuration.
210214
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-
)
215+
# Write data. See the comment in self.program_manual as to why we are using
216+
# uint32 instead of the native size of each port
217+
self.DO_task.WriteDigitalU32(
218+
1, # npts
219+
False, # autostart
220+
10.0, # timeout
221+
DAQmx_Val_GroupByScanNumber,
222+
DO_table,
223+
written,
224+
None,
225+
)
225226
else:
226227
# We use all but the last sample (which is identical to the second last
227228
# sample) in order to ensure there is one more clock tick than there are
@@ -237,23 +238,18 @@ def program_buffered_DO(self, DO_table):
237238
DAQmx_Val_FiniteSamps,
238239
npts,
239240
)
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-
)
241+
242+
# Write data. See the comment in self.program_manual as to why we are using
243+
# uint32 instead of the native size of each port.
244+
self.DO_task.WriteDigitalU32(
245+
npts,
246+
False, # autostart
247+
10.0, # timeout
248+
DAQmx_Val_GroupByScanNumber,
249+
DO_table[:-1], # All but the last sample as mentioned above
250+
written,
251+
None,
252+
)
257253

258254
# Go!
259255
self.DO_task.StartTask()
@@ -273,15 +269,15 @@ def program_buffered_AO(self, AO_table):
273269
# Collect the final values of the analog outs:
274270
final_values = dict(zip(AO_table.dtype.names, AO_table[-1]))
275271

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)
272+
# Convert AO table to a regular array and ensure it is C continguous:
273+
AO_table = np.ascontiguousarray(
274+
structured_to_unstructured(AO_table, dtype=np.float64)
275+
)
280276

281277
# Check if AOs are all zero for the whole shot. If they are this triggers a
282278
# bug in NI-DAQmx that throws a cryptic error for buffered output. In this
283279
# case, run it as a non-buffered task.
284-
self.AO_all_zero = all(AO_table.flatten() == 0)
280+
self.AO_all_zero = not np.any(AO_table)
285281
if self.AO_all_zero:
286282
AO_table = AO_table[0:1]
287283

NI_DAQmx/models/NI_PCI_DIO_32HS.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#####################################################################
2+
# #
3+
# /NI_DAQmx/models/_subclass_template.py #
4+
# #
5+
# Copyright 2018, Christopher Billington #
6+
# #
7+
# This file is part of the module labscript_devices, in the #
8+
# labscript suite (see http://labscriptsuite.org), and is #
9+
# licensed under the Simplified BSD License. See the license.txt #
10+
# file in the root of the project for the full license. #
11+
# #
12+
#####################################################################
13+
14+
#####################################################################
15+
# WARNING #
16+
# #
17+
# This file is auto-generated, any modifications may be #
18+
# overwritten. See README.txt in this folder for details #
19+
# #
20+
#####################################################################
21+
22+
23+
from __future__ import division, unicode_literals, print_function, absolute_import
24+
from labscript_utils import PY2
25+
26+
if PY2:
27+
str = unicode
28+
29+
from labscript_devices.NI_DAQmx.labscript_devices import NI_DAQmx
30+
31+
CAPABILITIES = {
32+
'AI_range': None,
33+
'AI_start_delay': None,
34+
'AO_range': None,
35+
'max_AI_multi_chan_rate': None,
36+
'max_AI_single_chan_rate': None,
37+
'max_AO_sample_rate': None,
38+
'max_DO_sample_rate': 20000000.0,
39+
'min_semiperiod_measurement': None,
40+
'num_AI': 0,
41+
'num_AO': 0,
42+
'num_CI': 0,
43+
'ports': {
44+
'port0': {'num_lines': 8, 'supports_buffered': True},
45+
'port1': {'num_lines': 8, 'supports_buffered': True},
46+
'port2': {'num_lines': 8, 'supports_buffered': True},
47+
'port3': {'num_lines': 8, 'supports_buffered': True},
48+
'port4': {'num_lines': 0, 'supports_buffered': False},
49+
'port5': {'num_lines': 4, 'supports_buffered': False},
50+
},
51+
'supports_buffered_AO': False,
52+
'supports_buffered_DO': True,
53+
'supports_semiperiod_measurement': False,
54+
}
55+
56+
57+
class NI_PCI_DIO_32HS(NI_DAQmx):
58+
description = 'NI-PCI-DIO-32HS'
59+
60+
def __init__(self, *args, **kwargs):
61+
# Any provided kwargs take precedent over capabilities
62+
combined_kwargs = CAPABILITIES.copy()
63+
combined_kwargs.update(kwargs)
64+
NI_DAQmx.__init__(self, *args, **combined_kwargs)

NI_DAQmx/models/capabilities.json

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,48 @@
127127
"supports_buffered_DO": true,
128128
"supports_semiperiod_measurement": true
129129
},
130+
"PCI-DIO-32HS": {
131+
"AI_range": null,
132+
"AI_start_delay": null,
133+
"AO_range": null,
134+
"max_AI_multi_chan_rate": null,
135+
"max_AI_single_chan_rate": null,
136+
"max_AO_sample_rate": null,
137+
"max_DO_sample_rate": 20000000.0,
138+
"min_semiperiod_measurement": null,
139+
"num_AI": 0,
140+
"num_AO": 0,
141+
"num_CI": 0,
142+
"ports": {
143+
"port0": {
144+
"num_lines": 8,
145+
"supports_buffered": true
146+
},
147+
"port1": {
148+
"num_lines": 8,
149+
"supports_buffered": true
150+
},
151+
"port2": {
152+
"num_lines": 8,
153+
"supports_buffered": true
154+
},
155+
"port3": {
156+
"num_lines": 8,
157+
"supports_buffered": true
158+
},
159+
"port4": {
160+
"num_lines": 0,
161+
"supports_buffered": false
162+
},
163+
"port5": {
164+
"num_lines": 4,
165+
"supports_buffered": false
166+
}
167+
},
168+
"supports_buffered_AO": false,
169+
"supports_buffered_DO": true,
170+
"supports_semiperiod_measurement": false
171+
},
130172
"PCIe-6363": {
131173
"AI_range": [
132174
-10.0,

0 commit comments

Comments
 (0)