diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b4bb2013..b74473d79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ All notable changes to this project will be documented in this file. * ### Resolved Issues * [843: read methods use task.in_stream.channels_to_read, which is slow](https://github.com/ni/nidaqmx-python/issues/843) + * [639: first_samp_timestamp_val property does not work because LibraryInterpreter is missing a method](https://github.com/ni/nidaqmx-python/issues/639) * ### Major Changes * (IN PROGRESS behind "WAVEFORM_SUPPORT" feature toggle) Added support for reading and writing Waveform data. diff --git a/generated/nidaqmx/_base_interpreter.py b/generated/nidaqmx/_base_interpreter.py index 420b1bd69..bd6f14541 100644 --- a/generated/nidaqmx/_base_interpreter.py +++ b/generated/nidaqmx/_base_interpreter.py @@ -1093,6 +1093,10 @@ def get_timing_attribute_int32(self, task, attribute): def get_timing_attribute_string(self, task, attribute): raise NotImplementedError + @abc.abstractmethod + def get_timing_attribute_timestamp(self, task, attribute): + raise NotImplementedError + @abc.abstractmethod def get_timing_attribute_uint32(self, task, attribute): raise NotImplementedError diff --git a/generated/nidaqmx/_grpc_interpreter.py b/generated/nidaqmx/_grpc_interpreter.py index 4960c2f0f..4bb9871c9 100644 --- a/generated/nidaqmx/_grpc_interpreter.py +++ b/generated/nidaqmx/_grpc_interpreter.py @@ -2181,6 +2181,12 @@ def get_timing_attribute_string(self, task, attribute): grpc_types.GetTimingAttributeStringRequest(task=task, attribute_raw=attribute)) return response.value + def get_timing_attribute_timestamp(self, task, attribute): + response = self._invoke( + self._client.GetTimingAttributeTimestamp, + grpc_types.GetTimingAttributeTimestampRequest(task=task, attribute_raw=attribute)) + return convert_timestamp_to_time(response.value) + def get_timing_attribute_uint32(self, task, attribute): response = self._invoke( self._client.GetTimingAttributeUInt32, diff --git a/generated/nidaqmx/_library_interpreter.py b/generated/nidaqmx/_library_interpreter.py index 277cfadae..7f4f98cff 100644 --- a/generated/nidaqmx/_library_interpreter.py +++ b/generated/nidaqmx/_library_interpreter.py @@ -3730,6 +3730,21 @@ def get_timing_attribute_string(self, task, attribute): self.check_for_error(size_or_code) return value.value.decode(lib_importer.encoding) + def get_timing_attribute_timestamp(self, task, attribute): + value = AbsoluteTime() + + cfunc = lib_importer.cdll.DAQmxGetTimingAttribute + if cfunc.argtypes is None: + with cfunc.arglock: + if cfunc.argtypes is None: + cfunc.argtypes = [ + lib_importer.task_handle, ctypes.c_int32] + + error_code = cfunc( + task, attribute, ctypes.byref(value)) + self.check_for_error(error_code) + return value.to_datetime() + def get_timing_attribute_uint32(self, task, attribute): value = ctypes.c_uint32() diff --git a/src/codegen/utilities/interpreter_helpers.py b/src/codegen/utilities/interpreter_helpers.py index a47c8436f..911de7cdb 100644 --- a/src/codegen/utilities/interpreter_helpers.py +++ b/src/codegen/utilities/interpreter_helpers.py @@ -44,6 +44,8 @@ "SetRealTimeAttributeUInt32", "WaitForNextSampleClock", # Time triggers + # Single-attribute get/set functions are not used + # Generic Get/SetTimingAttribute{Type} functions are used instead "GetArmStartTrigTimestampVal", "GetArmStartTrigTrigWhen", "GetFirstSampClkWhen", @@ -53,7 +55,6 @@ "GetStartTrigTrigWhen", "GetSyncPulseTimeWhen", "GetTimingAttributeExTimestamp", - "GetTimingAttributeTimestamp", "SetArmStartTrigTrigWhen", "SetFirstSampClkWhen", "SetStartTrigTrigWhen", diff --git a/tests/component/task/test_timing_properties.py b/tests/component/task/test_timing_properties.py index ec352fa18..1ccaecfc0 100644 --- a/tests/component/task/test_timing_properties.py +++ b/tests/component/task/test_timing_properties.py @@ -1,3 +1,5 @@ +from datetime import datetime as std_datetime + import pytest from nidaqmx import DaqError @@ -470,3 +472,30 @@ def test___timing___set_unint64_property_out_of_range_value___throws_daqerror( with pytest.raises(DaqError) as e: _ = task.timing.samp_quant_samp_per_chan assert e.value.error_type == DAQmxErrors.INVALID_ATTRIBUTE_VALUE + + +def test___timing___get_timestamp_property___returns_value(task, sim_9205_device): + task.ai_channels.add_ai_voltage_chan(sim_9205_device.ai_physical_chans[0].name) + task.timing.cfg_samp_clk_timing(1000, samps_per_chan=100) + + task.start() + timestamp = task.timing.first_samp_timestamp_val + + assert isinstance(timestamp, std_datetime) + + task.stop() + + +def test___timing___get_timestamp_property_with_device_context___throws_daqerror( + task, sim_9205_device +): + task.ai_channels.add_ai_voltage_chan(sim_9205_device.ai_physical_chans[0].name) + task.timing.cfg_samp_clk_timing(1000, samps_per_chan=100) + task.start() + + with pytest.raises(DaqError) as e: + _ = task.timing[sim_9205_device].first_samp_timestamp_val + + assert e.value.error_type == DAQmxErrors.M_STUDIO_OPERATION_DOES_NOT_SUPPORT_DEVICE_CONTEXT + + task.stop()