Skip to content

Commit 2175cc8

Browse files
author
RbChip
committed
NI-DAQmx-wait-changes: More flexible NI DAQmx wait monitor functionality.
- In the case that there are waits, analog input, but no wait monitor, raise an exception. - Allow the wait monitor timeout device to de a different NI DAQmx device. - Allow there to be no timeout device. These changes are to be compatible with labscript changes that make wait monitors and wait timeouts optional. The timeout device being allowed to be a different device allows for the case where one device has counters but no unbuffered DO ports, whereas another one has unbuffered DO ports but no counters. I am not sure if the latter exists, but this was motivated by an NI DAQmx device with unreliable counter input. We were not able to figure out what made the counter input unreliable, but switching to a different device fixed the problem (though the device we switched to lacks unbuffered DO ports, so we cannot use it as the timeout device).
1 parent e3cb50e commit 2175cc8

File tree

3 files changed

+46
-21
lines changed

3 files changed

+46
-21
lines changed

NI_DAQmx/blacs_tabs.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
from blacs.device_base_class import DeviceTab
2424
from .utils import split_conn_AO, split_conn_DO
25+
from . import models
2526

2627

2728
class NI_DAQmxTab(DeviceTab):
@@ -155,10 +156,18 @@ def initialise_GUI(self):
155156
self.primary_worker = "main_worker"
156157

157158
if wait_acq_device == self.device_name:
158-
if wait_timeout_device != self.device_name:
159-
msg = """The wait monitor acquisition device must be the same as the
160-
wait timeout device."""
161-
raise RuntimeError(msg)
159+
if wait_timeout_device:
160+
wait_timeout_device = connection_table.find_by_name(wait_timeout_device)
161+
if not hasattr(models, wait_timeout_device.device_class):
162+
msg = """If using an NI DAQmx device as a wait monitor input, then
163+
the wait monitor timeout device must also be an NI DAQmx device,
164+
not {}.""".format(
165+
wait_timeout_device.device_class
166+
)
167+
raise RuntimeError(dedent(msg))
168+
wait_timeout_MAX_name = wait_timeout_device.properties['MAX_name']
169+
else:
170+
wait_timeout_MAX_name = None
162171

163172
if num_CI == 0:
164173
msg = "Device cannot be a wait monitor as it has no counter inputs"
@@ -170,6 +179,7 @@ def initialise_GUI(self):
170179
{
171180
'MAX_name': self.MAX_name,
172181
'wait_acq_connection': wait_acq_connection,
182+
'wait_timeout_MAX_name': wait_timeout_MAX_name,
173183
'wait_timeout_connection': wait_timeout_connection,
174184
'timeout_trigger_type': timeout_trigger_type,
175185
'min_semiperiod_measurement': min_semiperiod_measurement,

NI_DAQmx/blacs_workers.py

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -763,14 +763,21 @@ def wait_monitor(self):
763763
semiperiods = self.read_edges(2, timeout)
764764
# Did the wait finish of its own accord, or time out?
765765
if semiperiods is None:
766-
# It timed out. Better trigger the clock to resume!
767-
msg = """Wait timed out; retriggering clock with {:.3e} s pulse
768-
({} edge)"""
769-
msg = dedent(msg).format(pulse_width, self.timeout_trigger_type)
770-
self.logger.debug(msg)
771-
self.send_resume_trigger(pulse_width)
772-
# Wait for it to respond to that:
773-
self.logger.debug('Waiting for pulse indicating end of wait')
766+
# It timed out. If there is a timeout device, send a trigger to
767+
# resume the clock!
768+
if self.DO_task is not None:
769+
msg = """Wait timed out; retriggering clock with {:.3e} s
770+
pulse ({} edge)"""
771+
msg = msg.format(pulse_width, self.timeout_trigger_type)
772+
self.logger.debug(dedent(msg))
773+
self.send_resume_trigger(pulse_width)
774+
else:
775+
msg = """Specified wait timeout exceeded, but there is no
776+
timeout device with which to resume the experiment.
777+
Continuing to wait."""
778+
self.logger.warning(dedent(msg))
779+
# Keep waiting for the clock to resume:
780+
self.logger.info('Waiting for pulse indicating end of wait')
774781
semiperiods = self.read_edges(2, timeout=None)
775782
# Alright, now we're at the end of the wait.
776783
self.semiperiods.extend(semiperiods)
@@ -853,15 +860,16 @@ def start_tasks(self):
853860
self.CI_task.StartTask()
854861

855862
# The timeout task:
856-
self.DO_task = Task()
857-
DO_chan = self.MAX_name + '/' + self.wait_timeout_connection
858-
self.DO_task.CreateDOChan(DO_chan, "", DAQmx_Val_ChanForAllLines)
859-
# Ensure timeout trigger is armed:
860-
written = int32()
861-
# Writing autostarts the task:
862-
self.DO_task.WriteDigitalLines(
863-
1, True, 1, DAQmx_Val_GroupByChannel, self.timeout_rearm, written, None
864-
)
863+
if self.wait_timeout_MAX_name is not None:
864+
self.DO_task = Task()
865+
DO_chan = self.wait_timeout_MAX_name + '/' + self.wait_timeout_connection
866+
self.DO_task.CreateDOChan(DO_chan, "", DAQmx_Val_ChanForAllLines)
867+
# Ensure timeout trigger is armed:
868+
written = int32()
869+
# Writing autostarts the task:
870+
self.DO_task.WriteDigitalLines(
871+
1, True, 1, DAQmx_Val_GroupByChannel, self.timeout_rearm, written, None
872+
)
865873

866874
def transition_to_buffered(self, device_name, h5file, initial_values, fresh):
867875
self.logger.debug('transition_to_buffered')

NI_DAQmx/labscript_devices.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
AnalogIn,
3232
bitfield,
3333
config,
34+
compiler,
3435
LabscriptError,
3536
set_passed_properties,
3637
)
@@ -319,6 +320,12 @@ def _make_analog_out_table(self, analogs, times):
319320
"""Collect analog output data and create the output array"""
320321
if not analogs:
321322
return None
323+
if compiler.wait_table and compiler.wait_monitor is None:
324+
msg = """Cannot do analog input on an NI DAQmx device in an experiment that
325+
uses waits without a wait monitor. This is because input data cannot be
326+
'chunked' into requested segments without knowledge of the durations of
327+
the waits. See labscript.WaitMonitor for details."""
328+
raise LabscriptError(dedent(msg))
322329
n_timepoints = 1 if self.static_AO else len(times)
323330
connections = sorted(analogs, key=split_conn_AO)
324331
dtypes = [(c, np.float32) for c in connections]

0 commit comments

Comments
 (0)