From 19c5abcaa4c4a59c0cfa85a217fa4ed5e743970d Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Tue, 12 Nov 2019 09:52:33 -0600 Subject: [PATCH 01/31] Add template for fancy_fetch_capture_waveform --- .../fancy_fetch_capture_waveform.py.mako | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 src/nidigital/templates/session.py/fancy_fetch_capture_waveform.py.mako diff --git a/src/nidigital/templates/session.py/fancy_fetch_capture_waveform.py.mako b/src/nidigital/templates/session.py/fancy_fetch_capture_waveform.py.mako new file mode 100644 index 000000000..7d9b0ef45 --- /dev/null +++ b/src/nidigital/templates/session.py/fancy_fetch_capture_waveform.py.mako @@ -0,0 +1,62 @@ +<%page args="f, config, method_template"/>\ +<% + '''Dispatches to the appropriate "fetch waveform into" method based on the waveform type.''' + import build.helper as helper + suffix = method_template['method_python_name_suffix'] +%>\ + def _fetch_capture_waveform(self, site_list, waveform_name, samples_to_read, timeout): + # This is slightly modified codegen from the function + vi_ctype = _visatype.ViSession(self._vi) # case S110 + site_list_ctype = ctypes.create_string_buffer(site_list.encode(self._encoding)) # case C020 + waveform_name_ctype = ctypes.create_string_buffer(waveform_name.encode(self._encoding)) # case C020 + samples_to_read_ctype = _visatype.ViInt32(samples_to_read) # case S150 + timeout_ctype = _visatype.ViReal64(timeout) # case S150 + data_buffer_size_ctype = _visatype.ViInt32(0) # case S190 + data_ctype = None # case B610 + actual_num_waveforms_ctype = _visatype.ViInt32() # case S220 + actual_samples_per_waveform_ctype = _visatype.ViInt32() # case S220 + error_code = self._library.niDigital_FetchCaptureWaveformU32(vi_ctype, site_list_ctype, waveform_name_ctype, samples_to_read_ctype, timeout_ctype, data_buffer_size_ctype, data_ctype, None if actual_num_waveforms_ctype is None else (ctypes.pointer(actual_num_waveforms_ctype)), None if actual_samples_per_waveform_ctype is None else (ctypes.pointer(actual_samples_per_waveform_ctype))) + errors.handle_error(self, error_code, ignore_warnings=True, is_error_handling=False) + data_buffer_size_ctype = _visatype.ViInt32(actual_num_waveforms_ctype.value) # case S200 + data_size = actual_num_waveforms_ctype.value * actual_samples_per_waveform_ctype.value # case B620 (modified) + data_array = array.array("L", [0] * data_size) # case B620 + data_ctype = get_ctypes_pointer_for_buffer(value=data_array, library_type=_visatype.ViUInt32) # case B620 + error_code = self._library.niDigital_FetchCaptureWaveformU32(vi_ctype, site_list_ctype, waveform_name_ctype, samples_to_read_ctype, timeout_ctype, data_buffer_size_ctype, data_ctype, None if actual_num_waveforms_ctype is None else (ctypes.pointer(actual_num_waveforms_ctype)), None if actual_samples_per_waveform_ctype is None else (ctypes.pointer(actual_samples_per_waveform_ctype))) + errors.handle_error(self, error_code, ignore_warnings=False, is_error_handling=False) + return data_array, actual_num_waveforms_ctype.value, actual_samples_per_waveform_ctype.value + + def ${f['python_name']}${suffix}(${helper.get_params_snippet(f, helper.ParameterUsageOptions.SESSION_NUMPY_INTO_METHOD_DECLARATION)}): + '''${f['python_name']} + + ${helper.get_function_docstring(f, False, config, indent=8)} + ''' + import collections + import sys + + timeout_secs = _converters.convert_timedelta_to_seconds(timeout, _visatype.ViReal64) + data, actual_num_waveforms, actual_samples_per_waveform = self._fetch_capture_waveform(site_list, waveform_name, samples_to_read, timeout_secs) + + # Get the site list + site_list = self.get_site_results_site_numbers(site_list, enums.SiteType.CAPTURE_WAVEFORM) + assert len(site_list) == actual_num_waveforms + + Waveform = collections.namedtuple('Waveform', ['site', 'data']) + + waveforms = [] + + if sys.version_info.major >= 3: + # In Python 3 and newer we can use memoryview objects to give us pieces of the underlying array. This is much faster + mv = memoryview(data) + + for i in range(actual_num_waveforms): + start = i * actual_samples_per_waveform + end = start + actual_samples_per_waveform + if sys.version_info.major >= 3: + waveforms.append(Waveform(site=site_list[i], data=mv[start:end])) + else: + # memoryview in Python 2 doesn't support numeric types, so we copy into an array.array to put in the wfm. :( You should be using Python 3! + # Or use the _into version. memoryview in Python 2 only supports string and bytearray, not array.array or numpy.ndarray of arbitrary types. + waveforms.append(Waveform(site=site_list[i], data=array.array('L', data[start:end]))) + + return waveforms + From f0b1c523f64b2c7f1f5d5a754f03551554811745 Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Tue, 12 Nov 2019 09:52:57 -0600 Subject: [PATCH 02/31] Add FetchCaptureWaveformU32 back and make 'library-only' --- src/nidigital/metadata/functions.py | 63 +++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/src/nidigital/metadata/functions.py b/src/nidigital/metadata/functions.py index cea263fc8..60c94551e 100644 --- a/src/nidigital/metadata/functions.py +++ b/src/nidigital/metadata/functions.py @@ -1297,6 +1297,69 @@ 'python_name': 'self_test', 'returns': 'ViStatus' }, + 'FetchCaptureWaveformU32': { + 'codegen_method': 'library-only', + 'documentation': { + 'description': 'TBD' + }, + 'parameters': [ + { + 'direction': 'in', + 'name': 'vi', + 'type': 'ViSession' + }, + { + 'direction': 'in', + 'name': 'siteList', + 'type': 'ViConstString' + }, + { + 'direction': 'in', + 'name': 'waveformName', + 'type': 'ViConstString' + }, + { + 'direction': 'in', + 'name': 'samplesToRead', + 'type': 'ViInt32' + }, + { + 'direction': 'in', + 'name': 'timeout', + 'type': 'ViReal64' + }, + { + 'direction': 'in', + 'name': 'dataBufferSize', + 'type': 'ViInt32' + }, + { + 'direction': 'out', + 'name': 'data', + 'use_array': True, + 'size': { + 'mechanism': 'ivi-dance-with-a-twist', + 'value': 'dataBufferSize', + # Should be 'actualNumWaveforms*ActualSamplesPerWaveform' but codegen doesn't handle that properly + # The actual call is in a "fancy" function so change so the library call can be generated (doesn't + # depend on this value) + 'value_twist': 'actualNumWaveforms', + }, + 'type': 'ViUInt32[]', + }, + { + 'direction': 'out', + 'name': 'actualNumWaveforms', + 'type': 'ViInt32' + }, + { + 'direction': 'out', + 'name': 'actualSamplesPerWaveform', + 'type': 'ViInt32' + } + ], + 'returns': 'ViStatus' + }, 'FetchHistoryRAMCycleInformation': { 'documentation': { 'description': 'TBD' From 1ec0cf9f48763d9023e4d21fcd4c6793371945f6 Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Tue, 12 Nov 2019 09:53:29 -0600 Subject: [PATCH 03/31] Add FancyFetchCaptureWaveform --- src/nidigital/metadata/functions_addon.py | 59 ++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/src/nidigital/metadata/functions_addon.py b/src/nidigital/metadata/functions_addon.py index 926a0303b..a0c1cc3fe 100644 --- a/src/nidigital/metadata/functions_addon.py +++ b/src/nidigital/metadata/functions_addon.py @@ -4,4 +4,61 @@ functions_override_metadata = { } - +functions_additional_fetch_capture_waveform = { + 'FancyFetchCaptureWaveform': { + 'python_name': 'fetch_capture_waveform', + 'codegen_method': 'python-only', + 'method_templates': [ + { + 'documentation_filename': 'default_method', + 'method_python_name_suffix': '', + 'session_filename': 'fancy_fetch_capture_waveform', + } + ], + 'documentation': { + 'description': '\nReturns a list of named tuples (Waveform) that \n\nFields in Waveform:\n\n- **site** (int)\n- **data** (array.array of int)\n\n', + }, + 'parameters': [ + { + 'direction': 'in', + 'name': 'vi', + 'type': 'ViSession' + }, + { + 'direction': 'in', + 'name': 'siteList', + 'type': 'ViConstString' + }, + { + 'direction': 'in', + 'name': 'waveformName', + 'type': 'ViConstString' + }, + { + 'direction': 'in', + 'name': 'samplesToRead', + 'type': 'ViInt32' + }, + { + 'direction': 'in', + 'name': 'timeout', + 'type': 'ViReal64', + 'python_api_converter_name': 'convert_timedelta_to_seconds', + 'python_type': 'float or datetime.timedelta', + }, + { + 'direction': 'out', + 'documentation': { + 'description': '\nList of named tuples with fields:\n\n- **site** (int)\n- **data** (array.array of int)\n' + }, + 'name': 'waveform', + 'python_type': 'Waveform', + 'size': { + 'mechanism': 'python-code', + 'value': None + }, + 'type': 'ViUInt32[]' + }, + ], + }, +} From c4016521f1f996cab95d421aa39201d97329875e Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Tue, 12 Nov 2019 09:54:13 -0600 Subject: [PATCH 04/31] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8ec7a856..318223f3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,6 +54,7 @@ All notable changes to this project will be documented in this file. * #### Removed * ### NI-Digital Pattern Driver * #### Added + * `fetch_capture_waveform()` - returns namedtuple `Waveform(site, data)` * #### Changed * Fix get/set properties - [#1062](https://github.com/ni/nimi-python/issues/1062) * Removed array-size parameter from apply_tdr_offsets() and write_source_waveform_broadcast_u32() methods - [#1070](https://github.com/ni/nimi-python/issues/1070) From 3d304653915100becf331f67d950cb51c508c8fc Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Tue, 12 Nov 2019 09:54:22 -0600 Subject: [PATCH 05/31] Update generated files --- docs/nidigital/class.rst | 60 +++++++++++++++++++++++++ generated/nidigital/_library.py | 9 ++++ generated/nidigital/session.py | 79 +++++++++++++++++++++++++++++++++ 3 files changed, 148 insertions(+) diff --git a/docs/nidigital/class.rst b/docs/nidigital/class.rst index f70a7ad3e..456a35bc5 100644 --- a/docs/nidigital/class.rst +++ b/docs/nidigital/class.rst @@ -1550,6 +1550,66 @@ export_signal :type output_terminal: str +fetch_capture_waveform +---------------------- + + .. py:currentmodule:: nidigital.Session + + .. py:method:: fetch_capture_waveform(site_list, waveform_name, samples_to_read, timeout) + + Returns a list of named tuples (Waveform) that + + Fields in Waveform: + + - **site** (int) + - **data** (array.array of int) + + + + + + :param site_list: + + + + + + :type site_list: str + :param waveform_name: + + + + + + :type waveform_name: str + :param samples_to_read: + + + + + + :type samples_to_read: int + :param timeout: + + + + + + :type timeout: float or datetime.timedelta + + :rtype: list of Waveform + :return: + + + List of named tuples with fields: + + - **site** (int) + - **data** (array.array of int) + + + + + fetch_history_ram_cycle_information ----------------------------------- diff --git a/generated/nidigital/_library.py b/generated/nidigital/_library.py index 8e2d0c301..fbbdc88be 100644 --- a/generated/nidigital/_library.py +++ b/generated/nidigital/_library.py @@ -66,6 +66,7 @@ def __init__(self, ctypes_library): self.niDigital_EnableSites_cfunc = None self.niDigital_EndChannelMap_cfunc = None self.niDigital_ExportSignal_cfunc = None + self.niDigital_FetchCaptureWaveformU32_cfunc = None self.niDigital_FetchHistoryRAMCycleInformation_cfunc = None self.niDigital_FetchHistoryRAMCyclePinData_cfunc = None self.niDigital_FetchHistoryRAMScanCycleNumber_cfunc = None @@ -526,6 +527,14 @@ def niDigital_ExportSignal(self, vi, signal, signal_identifier, output_terminal) self.niDigital_ExportSignal_cfunc.restype = ViStatus # noqa: F405 return self.niDigital_ExportSignal_cfunc(vi, signal, signal_identifier, output_terminal) + def niDigital_FetchCaptureWaveformU32(self, vi, site_list, waveform_name, samples_to_read, timeout, data_buffer_size, data, actual_num_waveforms, actual_samples_per_waveform): # noqa: N802 + with self._func_lock: + if self.niDigital_FetchCaptureWaveformU32_cfunc is None: + self.niDigital_FetchCaptureWaveformU32_cfunc = self._library.niDigital_FetchCaptureWaveformU32 + self.niDigital_FetchCaptureWaveformU32_cfunc.argtypes = [ViSession, ctypes.POINTER(ViChar), ctypes.POINTER(ViChar), ViInt32, ViReal64, ViInt32, ctypes.POINTER(ViUInt32), ctypes.POINTER(ViInt32), ctypes.POINTER(ViInt32)] # noqa: F405 + self.niDigital_FetchCaptureWaveformU32_cfunc.restype = ViStatus # noqa: F405 + return self.niDigital_FetchCaptureWaveformU32_cfunc(vi, site_list, waveform_name, samples_to_read, timeout, data_buffer_size, data, actual_num_waveforms, actual_samples_per_waveform) + def niDigital_FetchHistoryRAMCycleInformation(self, vi, site, sample_index, pattern_index, time_set_index, vector_number, cycle_number, num_dut_cycles): # noqa: N802 with self._func_lock: if self.niDigital_FetchHistoryRAMCycleInformation_cfunc is None: diff --git a/generated/nidigital/session.py b/generated/nidigital/session.py index 93282faf5..ab944f41c 100644 --- a/generated/nidigital/session.py +++ b/generated/nidigital/session.py @@ -2676,6 +2676,85 @@ def export_signal(self, signal, signal_identifier, output_terminal): errors.handle_error(self, error_code, ignore_warnings=False, is_error_handling=False) return + @ivi_synchronized + def _fetch_capture_waveform(self, site_list, waveform_name, samples_to_read, timeout): + # This is slightly modified codegen from the function + vi_ctype = _visatype.ViSession(self._vi) # case S110 + site_list_ctype = ctypes.create_string_buffer(site_list.encode(self._encoding)) # case C020 + waveform_name_ctype = ctypes.create_string_buffer(waveform_name.encode(self._encoding)) # case C020 + samples_to_read_ctype = _visatype.ViInt32(samples_to_read) # case S150 + timeout_ctype = _visatype.ViReal64(timeout) # case S150 + data_buffer_size_ctype = _visatype.ViInt32(0) # case S190 + data_ctype = None # case B610 + actual_num_waveforms_ctype = _visatype.ViInt32() # case S220 + actual_samples_per_waveform_ctype = _visatype.ViInt32() # case S220 + error_code = self._library.niDigital_FetchCaptureWaveformU32(vi_ctype, site_list_ctype, waveform_name_ctype, samples_to_read_ctype, timeout_ctype, data_buffer_size_ctype, data_ctype, None if actual_num_waveforms_ctype is None else (ctypes.pointer(actual_num_waveforms_ctype)), None if actual_samples_per_waveform_ctype is None else (ctypes.pointer(actual_samples_per_waveform_ctype))) + errors.handle_error(self, error_code, ignore_warnings=True, is_error_handling=False) + data_buffer_size_ctype = _visatype.ViInt32(actual_num_waveforms_ctype.value) # case S200 + data_size = actual_num_waveforms_ctype.value * actual_samples_per_waveform_ctype.value # case B620 (modified) + data_array = array.array("L", [0] * data_size) # case B620 + data_ctype = get_ctypes_pointer_for_buffer(value=data_array, library_type=_visatype.ViUInt32) # case B620 + error_code = self._library.niDigital_FetchCaptureWaveformU32(vi_ctype, site_list_ctype, waveform_name_ctype, samples_to_read_ctype, timeout_ctype, data_buffer_size_ctype, data_ctype, None if actual_num_waveforms_ctype is None else (ctypes.pointer(actual_num_waveforms_ctype)), None if actual_samples_per_waveform_ctype is None else (ctypes.pointer(actual_samples_per_waveform_ctype))) + errors.handle_error(self, error_code, ignore_warnings=False, is_error_handling=False) + return data_array, actual_num_waveforms_ctype.value, actual_samples_per_waveform_ctype.value + + def fetch_capture_waveform(self, site_list, waveform_name, samples_to_read, timeout): + '''fetch_capture_waveform + + Returns a list of named tuples (Waveform) that + + Fields in Waveform: + + - **site** (int) + - **data** (array.array of int) + + Args: + site_list (str): + + waveform_name (str): + + samples_to_read (int): + + timeout (float or datetime.timedelta): + + + Returns: + waveform (list of Waveform): List of named tuples with fields: + + - **site** (int) + - **data** (array.array of int) + + ''' + import collections + import sys + + timeout_secs = _converters.convert_timedelta_to_seconds(timeout, _visatype.ViReal64) + data, actual_num_waveforms, actual_samples_per_waveform = self._fetch_capture_waveform(site_list, waveform_name, samples_to_read, timeout_secs) + + # Get the site list + site_list = self.get_site_results_site_numbers(site_list, enums.SiteType.CAPTURE_WAVEFORM) + assert len(site_list) == actual_num_waveforms + + Waveform = collections.namedtuple('Waveform', ['site', 'data']) + + waveforms = [] + + if sys.version_info.major >= 3: + # In Python 3 and newer we can use memoryview objects to give us pieces of the underlying array. This is much faster + mv = memoryview(data) + + for i in range(actual_num_waveforms): + start = i * actual_samples_per_waveform + end = start + actual_samples_per_waveform + if sys.version_info.major >= 3: + waveforms.append(Waveform(site=site_list[i], data=mv[start:end])) + else: + # memoryview in Python 2 doesn't support numeric types, so we copy into an array.array to put in the wfm. :( You should be using Python 3! + # Or use the _into version. memoryview in Python 2 only supports string and bytearray, not array.array or numpy.ndarray of arbitrary types. + waveforms.append(Waveform(site=site_list[i], data=array.array('L', data[start:end]))) + + return waveforms + @ivi_synchronized def self_test(self): '''self_test From 650ab9356ca9df428eb98995690cb0b6f217a8f3 Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Tue, 12 Nov 2019 10:13:21 -0600 Subject: [PATCH 06/31] Expand on comments --- .../session.py/fancy_fetch_capture_waveform.py.mako | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/nidigital/templates/session.py/fancy_fetch_capture_waveform.py.mako b/src/nidigital/templates/session.py/fancy_fetch_capture_waveform.py.mako index 7d9b0ef45..c394c1d8f 100644 --- a/src/nidigital/templates/session.py/fancy_fetch_capture_waveform.py.mako +++ b/src/nidigital/templates/session.py/fancy_fetch_capture_waveform.py.mako @@ -6,6 +6,10 @@ %>\ def _fetch_capture_waveform(self, site_list, waveform_name, samples_to_read, timeout): # This is slightly modified codegen from the function + # We cannot use codegen without major modifications to the code generator + # This function uses two 'ivi-dance' parameters and then multiplies them together - see + # the (modified) line below + # Also, we want to return the two sized that normally wouldn't be returned vi_ctype = _visatype.ViSession(self._vi) # case S110 site_list_ctype = ctypes.create_string_buffer(site_list.encode(self._encoding)) # case C020 waveform_name_ctype = ctypes.create_string_buffer(waveform_name.encode(self._encoding)) # case C020 @@ -23,7 +27,7 @@ data_ctype = get_ctypes_pointer_for_buffer(value=data_array, library_type=_visatype.ViUInt32) # case B620 error_code = self._library.niDigital_FetchCaptureWaveformU32(vi_ctype, site_list_ctype, waveform_name_ctype, samples_to_read_ctype, timeout_ctype, data_buffer_size_ctype, data_ctype, None if actual_num_waveforms_ctype is None else (ctypes.pointer(actual_num_waveforms_ctype)), None if actual_samples_per_waveform_ctype is None else (ctypes.pointer(actual_samples_per_waveform_ctype))) errors.handle_error(self, error_code, ignore_warnings=False, is_error_handling=False) - return data_array, actual_num_waveforms_ctype.value, actual_samples_per_waveform_ctype.value + return data_array, actual_num_waveforms_ctype.value, actual_samples_per_waveform_ctype.value # (modified) def ${f['python_name']}${suffix}(${helper.get_params_snippet(f, helper.ParameterUsageOptions.SESSION_NUMPY_INTO_METHOD_DECLARATION)}): '''${f['python_name']} From 9d6f7a2cf04b148976a7f637028c7160e4957799 Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Tue, 12 Nov 2019 10:13:56 -0600 Subject: [PATCH 07/31] Remove old comment --- .../templates/session.py/fancy_fetch_capture_waveform.py.mako | 1 - 1 file changed, 1 deletion(-) diff --git a/src/nidigital/templates/session.py/fancy_fetch_capture_waveform.py.mako b/src/nidigital/templates/session.py/fancy_fetch_capture_waveform.py.mako index c394c1d8f..d6a4266e3 100644 --- a/src/nidigital/templates/session.py/fancy_fetch_capture_waveform.py.mako +++ b/src/nidigital/templates/session.py/fancy_fetch_capture_waveform.py.mako @@ -1,6 +1,5 @@ <%page args="f, config, method_template"/>\ <% - '''Dispatches to the appropriate "fetch waveform into" method based on the waveform type.''' import build.helper as helper suffix = method_template['method_python_name_suffix'] %>\ From bc53d04ca9bd59f6e23476e3aa62dd99f66e4bb4 Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Tue, 12 Nov 2019 11:12:59 -0600 Subject: [PATCH 08/31] Move conversion to "code generated" method --- .../session.py/fancy_fetch_capture_waveform.py.mako | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/nidigital/templates/session.py/fancy_fetch_capture_waveform.py.mako b/src/nidigital/templates/session.py/fancy_fetch_capture_waveform.py.mako index d6a4266e3..64ea3a427 100644 --- a/src/nidigital/templates/session.py/fancy_fetch_capture_waveform.py.mako +++ b/src/nidigital/templates/session.py/fancy_fetch_capture_waveform.py.mako @@ -13,7 +13,7 @@ site_list_ctype = ctypes.create_string_buffer(site_list.encode(self._encoding)) # case C020 waveform_name_ctype = ctypes.create_string_buffer(waveform_name.encode(self._encoding)) # case C020 samples_to_read_ctype = _visatype.ViInt32(samples_to_read) # case S150 - timeout_ctype = _visatype.ViReal64(timeout) # case S150 + timeout_ctype = _converters.convert_timedelta_to_seconds(timeout, _visatype.ViReal64) # case S140 data_buffer_size_ctype = _visatype.ViInt32(0) # case S190 data_ctype = None # case B610 actual_num_waveforms_ctype = _visatype.ViInt32() # case S220 @@ -36,8 +36,7 @@ import collections import sys - timeout_secs = _converters.convert_timedelta_to_seconds(timeout, _visatype.ViReal64) - data, actual_num_waveforms, actual_samples_per_waveform = self._fetch_capture_waveform(site_list, waveform_name, samples_to_read, timeout_secs) + data, actual_num_waveforms, actual_samples_per_waveform = self._fetch_capture_waveform(site_list, waveform_name, samples_to_read, timeout) # Get the site list site_list = self.get_site_results_site_numbers(site_list, enums.SiteType.CAPTURE_WAVEFORM) From 6f12d64a32b132521b56d9bbc12d38a55e3f87b5 Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Tue, 12 Nov 2019 11:13:16 -0600 Subject: [PATCH 09/31] Update generated files --- generated/nidigital/session.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/generated/nidigital/session.py b/generated/nidigital/session.py index ab944f41c..e710c815f 100644 --- a/generated/nidigital/session.py +++ b/generated/nidigital/session.py @@ -2679,11 +2679,15 @@ def export_signal(self, signal, signal_identifier, output_terminal): @ivi_synchronized def _fetch_capture_waveform(self, site_list, waveform_name, samples_to_read, timeout): # This is slightly modified codegen from the function + # We cannot use codegen without major modifications to the code generator + # This function uses two 'ivi-dance' parameters and then multiplies them together - see + # the (modified) line below + # Also, we want to return the two sized that normally wouldn't be returned vi_ctype = _visatype.ViSession(self._vi) # case S110 site_list_ctype = ctypes.create_string_buffer(site_list.encode(self._encoding)) # case C020 waveform_name_ctype = ctypes.create_string_buffer(waveform_name.encode(self._encoding)) # case C020 samples_to_read_ctype = _visatype.ViInt32(samples_to_read) # case S150 - timeout_ctype = _visatype.ViReal64(timeout) # case S150 + timeout_ctype = _converters.convert_timedelta_to_seconds(timeout, _visatype.ViReal64) # case S140 data_buffer_size_ctype = _visatype.ViInt32(0) # case S190 data_ctype = None # case B610 actual_num_waveforms_ctype = _visatype.ViInt32() # case S220 @@ -2696,7 +2700,7 @@ def _fetch_capture_waveform(self, site_list, waveform_name, samples_to_read, tim data_ctype = get_ctypes_pointer_for_buffer(value=data_array, library_type=_visatype.ViUInt32) # case B620 error_code = self._library.niDigital_FetchCaptureWaveformU32(vi_ctype, site_list_ctype, waveform_name_ctype, samples_to_read_ctype, timeout_ctype, data_buffer_size_ctype, data_ctype, None if actual_num_waveforms_ctype is None else (ctypes.pointer(actual_num_waveforms_ctype)), None if actual_samples_per_waveform_ctype is None else (ctypes.pointer(actual_samples_per_waveform_ctype))) errors.handle_error(self, error_code, ignore_warnings=False, is_error_handling=False) - return data_array, actual_num_waveforms_ctype.value, actual_samples_per_waveform_ctype.value + return data_array, actual_num_waveforms_ctype.value, actual_samples_per_waveform_ctype.value # (modified) def fetch_capture_waveform(self, site_list, waveform_name, samples_to_read, timeout): '''fetch_capture_waveform @@ -2728,8 +2732,7 @@ def fetch_capture_waveform(self, site_list, waveform_name, samples_to_read, time import collections import sys - timeout_secs = _converters.convert_timedelta_to_seconds(timeout, _visatype.ViReal64) - data, actual_num_waveforms, actual_samples_per_waveform = self._fetch_capture_waveform(site_list, waveform_name, samples_to_read, timeout_secs) + data, actual_num_waveforms, actual_samples_per_waveform = self._fetch_capture_waveform(site_list, waveform_name, samples_to_read, timeout) # Get the site list site_list = self.get_site_results_site_numbers(site_list, enums.SiteType.CAPTURE_WAVEFORM) From c51afc610e8af9fa681bca962936dc7cabf3bd7b Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Tue, 12 Nov 2019 15:58:26 -0600 Subject: [PATCH 10/31] Fix setting size parameter --- .../templates/session.py/fancy_fetch_capture_waveform.py.mako | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nidigital/templates/session.py/fancy_fetch_capture_waveform.py.mako b/src/nidigital/templates/session.py/fancy_fetch_capture_waveform.py.mako index 64ea3a427..4eb30ed38 100644 --- a/src/nidigital/templates/session.py/fancy_fetch_capture_waveform.py.mako +++ b/src/nidigital/templates/session.py/fancy_fetch_capture_waveform.py.mako @@ -20,7 +20,7 @@ actual_samples_per_waveform_ctype = _visatype.ViInt32() # case S220 error_code = self._library.niDigital_FetchCaptureWaveformU32(vi_ctype, site_list_ctype, waveform_name_ctype, samples_to_read_ctype, timeout_ctype, data_buffer_size_ctype, data_ctype, None if actual_num_waveforms_ctype is None else (ctypes.pointer(actual_num_waveforms_ctype)), None if actual_samples_per_waveform_ctype is None else (ctypes.pointer(actual_samples_per_waveform_ctype))) errors.handle_error(self, error_code, ignore_warnings=True, is_error_handling=False) - data_buffer_size_ctype = _visatype.ViInt32(actual_num_waveforms_ctype.value) # case S200 + data_buffer_size_ctype = _visatype.ViInt32(actual_num_waveforms_ctype.value * actual_samples_per_waveform_ctype.value) # case S200 (modified) data_size = actual_num_waveforms_ctype.value * actual_samples_per_waveform_ctype.value # case B620 (modified) data_array = array.array("L", [0] * data_size) # case B620 data_ctype = get_ctypes_pointer_for_buffer(value=data_array, library_type=_visatype.ViUInt32) # case B620 From 619c0cd907f5c4f4dd5fd8584e40c2f5c207c3a9 Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Tue, 12 Nov 2019 15:58:45 -0600 Subject: [PATCH 11/31] Set enum type --- src/nidigital/metadata/functions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nidigital/metadata/functions.py b/src/nidigital/metadata/functions.py index 60c94551e..a9136039c 100644 --- a/src/nidigital/metadata/functions.py +++ b/src/nidigital/metadata/functions.py @@ -2162,6 +2162,7 @@ }, { 'direction': 'in', + 'enum': 'SiteResult', 'name': 'siteResultType', 'type': 'ViInt32' }, From 72a01b0670b6502f749e2c8b787b9da7608f3b10 Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Tue, 12 Nov 2019 15:59:20 -0600 Subject: [PATCH 12/31] Update generated files --- docs/nidigital/class.rst | 2 +- docs/nidigital/enums.rst | 13 +++++++++++++ generated/nidigital/enums.py | 5 +++++ generated/nidigital/session.py | 8 +++++--- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/docs/nidigital/class.rst b/docs/nidigital/class.rst index 456a35bc5..ac2b99331 100644 --- a/docs/nidigital/class.rst +++ b/docs/nidigital/class.rst @@ -2167,7 +2167,7 @@ get_site_results_site_numbers - :type site_result_type: int + :type site_result_type: :py:data:`nidigital.SiteResult` :rtype: list of int :return: diff --git a/docs/nidigital/enums.rst b/docs/nidigital/enums.rst index dcc6a92f8..ef767e130 100644 --- a/docs/nidigital/enums.rst +++ b/docs/nidigital/enums.rst @@ -83,6 +83,19 @@ Signal +SiteResult +---------- + +.. py:class:: SiteResult + + .. py:attribute:: SiteResult.PASS_FAIL + + + + .. py:attribute:: SiteResult.CAPTURE_WAVEFORM + + + TDREndpointTermination ---------------------- diff --git a/generated/nidigital/enums.py b/generated/nidigital/enums.py index 8cce093a4..50fba68de 100644 --- a/generated/nidigital/enums.py +++ b/generated/nidigital/enums.py @@ -32,6 +32,11 @@ class Signal(Enum): REF_CLOCK = 2003 +class SiteResult(Enum): + PASS_FAIL = 3300 + CAPTURE_WAVEFORM = 3301 + + class TDREndpointTermination(Enum): OPEN = 3600 SHORT_TO_GROUND = 3601 diff --git a/generated/nidigital/session.py b/generated/nidigital/session.py index e710c815f..a4d52a9e7 100644 --- a/generated/nidigital/session.py +++ b/generated/nidigital/session.py @@ -2694,7 +2694,7 @@ def _fetch_capture_waveform(self, site_list, waveform_name, samples_to_read, tim actual_samples_per_waveform_ctype = _visatype.ViInt32() # case S220 error_code = self._library.niDigital_FetchCaptureWaveformU32(vi_ctype, site_list_ctype, waveform_name_ctype, samples_to_read_ctype, timeout_ctype, data_buffer_size_ctype, data_ctype, None if actual_num_waveforms_ctype is None else (ctypes.pointer(actual_num_waveforms_ctype)), None if actual_samples_per_waveform_ctype is None else (ctypes.pointer(actual_samples_per_waveform_ctype))) errors.handle_error(self, error_code, ignore_warnings=True, is_error_handling=False) - data_buffer_size_ctype = _visatype.ViInt32(actual_num_waveforms_ctype.value) # case S200 + data_buffer_size_ctype = _visatype.ViInt32(actual_num_waveforms_ctype.value * actual_samples_per_waveform_ctype.value) # case S200 (modified) data_size = actual_num_waveforms_ctype.value * actual_samples_per_waveform_ctype.value # case B620 (modified) data_array = array.array("L", [0] * data_size) # case B620 data_ctype = get_ctypes_pointer_for_buffer(value=data_array, library_type=_visatype.ViUInt32) # case B620 @@ -3092,16 +3092,18 @@ def get_site_results_site_numbers(self, site_list, site_result_type): Args: site_list (str): - site_result_type (int): + site_result_type (enums.SiteResult): Returns: site_numbers (list of int): ''' + if type(site_result_type) is not enums.SiteResult: + raise TypeError('Parameter mode must be of type ' + str(enums.SiteResult)) vi_ctype = _visatype.ViSession(self._vi) # case S110 site_list_ctype = ctypes.create_string_buffer(site_list.encode(self._encoding)) # case C020 - site_result_type_ctype = _visatype.ViInt32(site_result_type) # case S150 + site_result_type_ctype = _visatype.ViInt32(site_result_type.value) # case S130 site_numbers_buffer_size_ctype = _visatype.ViInt32(0) # case S190 site_numbers_ctype = None # case B610 actual_num_site_numbers_ctype = _visatype.ViInt32() # case S220 From 39ce0d227385c3f68e479a3b80c6040e7e1f7209 Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Wed, 13 Nov 2019 13:44:56 -0600 Subject: [PATCH 13/31] Don't worry about Python 2 --- .../session.py/fancy_fetch_capture_waveform.py.mako | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/nidigital/templates/session.py/fancy_fetch_capture_waveform.py.mako b/src/nidigital/templates/session.py/fancy_fetch_capture_waveform.py.mako index 4eb30ed38..919817ce8 100644 --- a/src/nidigital/templates/session.py/fancy_fetch_capture_waveform.py.mako +++ b/src/nidigital/templates/session.py/fancy_fetch_capture_waveform.py.mako @@ -34,7 +34,6 @@ ${helper.get_function_docstring(f, False, config, indent=8)} ''' import collections - import sys data, actual_num_waveforms, actual_samples_per_waveform = self._fetch_capture_waveform(site_list, waveform_name, samples_to_read, timeout) @@ -46,19 +45,11 @@ waveforms = [] - if sys.version_info.major >= 3: - # In Python 3 and newer we can use memoryview objects to give us pieces of the underlying array. This is much faster - mv = memoryview(data) + mv = memoryview(data) for i in range(actual_num_waveforms): start = i * actual_samples_per_waveform end = start + actual_samples_per_waveform - if sys.version_info.major >= 3: - waveforms.append(Waveform(site=site_list[i], data=mv[start:end])) - else: - # memoryview in Python 2 doesn't support numeric types, so we copy into an array.array to put in the wfm. :( You should be using Python 3! - # Or use the _into version. memoryview in Python 2 only supports string and bytearray, not array.array or numpy.ndarray of arbitrary types. - waveforms.append(Waveform(site=site_list[i], data=array.array('L', data[start:end]))) return waveforms From 650c31fc08b7613eb08086edbd438cb72047e6a3 Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Wed, 13 Nov 2019 13:45:20 -0600 Subject: [PATCH 14/31] Return a dict instead of a namedtupe --- .../session.py/fancy_fetch_capture_waveform.py.mako | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/nidigital/templates/session.py/fancy_fetch_capture_waveform.py.mako b/src/nidigital/templates/session.py/fancy_fetch_capture_waveform.py.mako index 919817ce8..ccca40769 100644 --- a/src/nidigital/templates/session.py/fancy_fetch_capture_waveform.py.mako +++ b/src/nidigital/templates/session.py/fancy_fetch_capture_waveform.py.mako @@ -33,23 +33,20 @@ ${helper.get_function_docstring(f, False, config, indent=8)} ''' - import collections - data, actual_num_waveforms, actual_samples_per_waveform = self._fetch_capture_waveform(site_list, waveform_name, samples_to_read, timeout) # Get the site list site_list = self.get_site_results_site_numbers(site_list, enums.SiteType.CAPTURE_WAVEFORM) assert len(site_list) == actual_num_waveforms - Waveform = collections.namedtuple('Waveform', ['site', 'data']) - - waveforms = [] + waveforms = {} mv = memoryview(data) for i in range(actual_num_waveforms): start = i * actual_samples_per_waveform end = start + actual_samples_per_waveform + waveforms[site_list[i]] = mv[start:end] return waveforms From a068305d8348efc6b06897ce9be2e431faf44ea1 Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Wed, 13 Nov 2019 13:45:28 -0600 Subject: [PATCH 15/31] Update documentation --- src/nidigital/metadata/functions_addon.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/nidigital/metadata/functions_addon.py b/src/nidigital/metadata/functions_addon.py index a0c1cc3fe..60d5cb81a 100644 --- a/src/nidigital/metadata/functions_addon.py +++ b/src/nidigital/metadata/functions_addon.py @@ -16,7 +16,7 @@ } ], 'documentation': { - 'description': '\nReturns a list of named tuples (Waveform) that \n\nFields in Waveform:\n\n- **site** (int)\n- **data** (array.array of int)\n\n', + 'description': '\nReturns dictionary where each key is the site number and the value is array.array of unsigned int\n\n', }, 'parameters': [ { @@ -49,15 +49,15 @@ { 'direction': 'out', 'documentation': { - 'description': '\nList of named tuples with fields:\n\n- **site** (int)\n- **data** (array.array of int)\n' + 'description': '\nDictionary where each key is the site number and the value is array.array of unsigned int\n' }, 'name': 'waveform', - 'python_type': 'Waveform', 'size': { 'mechanism': 'python-code', 'value': None }, - 'type': 'ViUInt32[]' + 'type': 'ViUInt32', + 'type_in_documentation': '{ site: data, site: data, ... }', }, ], }, From 3b37be1db1862fc10b54a736574b58f5ac1567d2 Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Wed, 13 Nov 2019 13:45:51 -0600 Subject: [PATCH 16/31] Add test stub that will only run on Python 3+ --- src/nidigital/system_tests/test_system_nidigital.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/nidigital/system_tests/test_system_nidigital.py b/src/nidigital/system_tests/test_system_nidigital.py index f8e7c67e2..113f0b06f 100644 --- a/src/nidigital/system_tests/test_system_nidigital.py +++ b/src/nidigital/system_tests/test_system_nidigital.py @@ -1,5 +1,6 @@ import nidigital import pytest +import sys instr = ['PXI1Slot2', 'PXI1Slot5'] @@ -59,3 +60,8 @@ def test_tdr_some_channels(multi_instrument_session): fetched_offsets = [multi_instrument_session.channels[i].tdr_offset for i in channels] assert fetched_offsets == applied_offsets + +def test_fetch_capture_waveform(multi_instrument_session): + if sys.version_info.major >= 3: + pass + From f0395da4dc5544b5e8b2eb49bf6ca92e39b53a48 Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Wed, 13 Nov 2019 13:46:06 -0600 Subject: [PATCH 17/31] Update generated files --- docs/nidigital/class.rst | 14 +++----------- generated/nidigital/session.py | 30 +++++------------------------- 2 files changed, 8 insertions(+), 36 deletions(-) diff --git a/docs/nidigital/class.rst b/docs/nidigital/class.rst index ac2b99331..24412ba00 100644 --- a/docs/nidigital/class.rst +++ b/docs/nidigital/class.rst @@ -1557,12 +1557,7 @@ fetch_capture_waveform .. py:method:: fetch_capture_waveform(site_list, waveform_name, samples_to_read, timeout) - Returns a list of named tuples (Waveform) that - - Fields in Waveform: - - - **site** (int) - - **data** (array.array of int) + Returns dictionary where each key is the site number and the value is array.array of unsigned int @@ -1597,14 +1592,11 @@ fetch_capture_waveform :type timeout: float or datetime.timedelta - :rtype: list of Waveform + :rtype: { site: data, site: data, ... } :return: - List of named tuples with fields: - - - **site** (int) - - **data** (array.array of int) + Dictionary where each key is the site number and the value is array.array of unsigned int diff --git a/generated/nidigital/session.py b/generated/nidigital/session.py index a4d52a9e7..677552184 100644 --- a/generated/nidigital/session.py +++ b/generated/nidigital/session.py @@ -2705,12 +2705,7 @@ def _fetch_capture_waveform(self, site_list, waveform_name, samples_to_read, tim def fetch_capture_waveform(self, site_list, waveform_name, samples_to_read, timeout): '''fetch_capture_waveform - Returns a list of named tuples (Waveform) that - - Fields in Waveform: - - - **site** (int) - - **data** (array.array of int) + Returns dictionary where each key is the site number and the value is array.array of unsigned int Args: site_list (str): @@ -2723,38 +2718,23 @@ def fetch_capture_waveform(self, site_list, waveform_name, samples_to_read, time Returns: - waveform (list of Waveform): List of named tuples with fields: - - - **site** (int) - - **data** (array.array of int) + waveform ({ site: data, site: data, ... }): Dictionary where each key is the site number and the value is array.array of unsigned int ''' - import collections - import sys - data, actual_num_waveforms, actual_samples_per_waveform = self._fetch_capture_waveform(site_list, waveform_name, samples_to_read, timeout) # Get the site list site_list = self.get_site_results_site_numbers(site_list, enums.SiteType.CAPTURE_WAVEFORM) assert len(site_list) == actual_num_waveforms - Waveform = collections.namedtuple('Waveform', ['site', 'data']) - - waveforms = [] + waveforms = {} - if sys.version_info.major >= 3: - # In Python 3 and newer we can use memoryview objects to give us pieces of the underlying array. This is much faster - mv = memoryview(data) + mv = memoryview(data) for i in range(actual_num_waveforms): start = i * actual_samples_per_waveform end = start + actual_samples_per_waveform - if sys.version_info.major >= 3: - waveforms.append(Waveform(site=site_list[i], data=mv[start:end])) - else: - # memoryview in Python 2 doesn't support numeric types, so we copy into an array.array to put in the wfm. :( You should be using Python 3! - # Or use the _into version. memoryview in Python 2 only supports string and bytearray, not array.array or numpy.ndarray of arbitrary types. - waveforms.append(Waveform(site=site_list[i], data=array.array('L', data[start:end]))) + waveforms[site_list[i]] = mv[start:end] return waveforms From ca37af23f81b9690fd4b5872ae2385a9d46de25a Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Wed, 13 Nov 2019 14:07:18 -0600 Subject: [PATCH 18/31] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 318223f3d..67e04a3e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,7 +54,7 @@ All notable changes to this project will be documented in this file. * #### Removed * ### NI-Digital Pattern Driver * #### Added - * `fetch_capture_waveform()` - returns namedtuple `Waveform(site, data)` + * `fetch_capture_waveform()` - returns dictionary { site: data, site: data, ... } * #### Changed * Fix get/set properties - [#1062](https://github.com/ni/nimi-python/issues/1062) * Removed array-size parameter from apply_tdr_offsets() and write_source_waveform_broadcast_u32() methods - [#1070](https://github.com/ni/nimi-python/issues/1070) From 13a518715e9728b702faecb2e1ec4e3b835ead1c Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Wed, 13 Nov 2019 15:37:37 -0600 Subject: [PATCH 19/31] Add fancy wrapper for write_source_waveform_site_unique() --- src/nidigital/metadata/functions.py | 7 +--- src/nidigital/metadata/functions_addon.py | 38 ++++++++++++++++++ ..._write_source_waveform_site_unique.py.mako | 40 +++++++++++++++++++ 3 files changed, 80 insertions(+), 5 deletions(-) create mode 100644 src/nidigital/templates/session.py/fancy_write_source_waveform_site_unique.py.mako diff --git a/src/nidigital/metadata/functions.py b/src/nidigital/metadata/functions.py index a9136039c..4b5d17664 100644 --- a/src/nidigital/metadata/functions.py +++ b/src/nidigital/metadata/functions.py @@ -3768,7 +3768,7 @@ 'returns': 'ViStatus' }, 'WriteSourceWaveformSiteUniqueU32': { - 'codegen_method': 'no', + 'codegen_method': 'private', 'documentation': { 'description': 'TBD' }, @@ -3801,10 +3801,7 @@ { 'direction': 'in', 'name': 'waveformData', - 'size': { - 'mechanism': 'custom', - 'value': None - }, + 'use_array': True, 'type': 'ViUInt32[]' } ], diff --git a/src/nidigital/metadata/functions_addon.py b/src/nidigital/metadata/functions_addon.py index 60d5cb81a..346fdbbcf 100644 --- a/src/nidigital/metadata/functions_addon.py +++ b/src/nidigital/metadata/functions_addon.py @@ -4,6 +4,44 @@ functions_override_metadata = { } +functions_additional_write_source_waveform_site_unique = { + 'FancyWriteSourceWaveformSiteUnique': { + 'python_name': 'write_source_waveform_site_unique', + 'codegen_method': 'python-only', + 'method_templates': [ + { + 'documentation_filename': 'default_method', + 'method_python_name_suffix': '', + 'session_filename': 'fancy_write_source_waveform_site_unique', + } + ], + 'documentation': { + 'description': 'TBD' + }, + 'parameters': [ + { + 'direction': 'in', + 'name': 'vi', + 'type': 'ViSession' + }, + { + 'direction': 'in', + 'name': 'waveformName', + 'type': 'ViConstString' + }, + { + 'direction': 'in', + 'documentation': { + 'description': '\nDictionary where each key is the site number and the value is array.array of unsigned int\n' + }, + 'name': 'waveform_data', + 'type': 'ViUInt32', + 'type_in_documentation': '{ site: data, site: data, ... }', + }, + ], + }, +} + functions_additional_fetch_capture_waveform = { 'FancyFetchCaptureWaveform': { 'python_name': 'fetch_capture_waveform', diff --git a/src/nidigital/templates/session.py/fancy_write_source_waveform_site_unique.py.mako b/src/nidigital/templates/session.py/fancy_write_source_waveform_site_unique.py.mako new file mode 100644 index 000000000..46ddf315c --- /dev/null +++ b/src/nidigital/templates/session.py/fancy_write_source_waveform_site_unique.py.mako @@ -0,0 +1,40 @@ +<%page args="f, config, method_template"/>\ +<% + import build.helper as helper + suffix = method_template['method_python_name_suffix'] +%>\ + def ${f['python_name']}${suffix}(${helper.get_params_snippet(f, helper.ParameterUsageOptions.SESSION_METHOD_DECLARATION)}): + '''${f['python_name']} + + ${helper.get_function_docstring(f, False, config, indent=8)} + ''' + if len(waveform_data) == 0: + # Nothing to do + return + + site_list = [] + # We assume all the entries are the same length (we'll check later) to make the array the correct size + # Get an entry from the dictionary from https://stackoverflow.com/questions/30362391/how-do-you-find-the-first-key-in-a-dictionary + actual_samples_per_waveform = len(waveform_data[next(iter(waveform_data))]) + data = array.array('L', [0] * (len(waveform_data) * actual_samples_per_waveform)) + mv = memoryview(data) + + i = 0 + for site in waveform_data: + if len(waveform_data[site]) != actual_samples_per_waveform: + raise ValueError('Mismatched length of waveforms. All must be the same length.') + if waveform_data[site].typecode != 'L': + raise ValueError('Wrong array element type. Must be unsigned 32 bit int "l", was {}'.format(waveform_data[site].typecode)) + + site_list.append(str(site)) + + start = i * actual_samples_per_waveform + end = start + actual_samples_per_waveform + mv[start:end] = waveform_data[site] + + i += 1 + + site_list_str = ','.join(site_list) + + self._write_source_waveform_site_unique(site_list_str, waveform_name, len(waveform_data), actual_samples_per_waveform, data) + From 113ea7003574eea4a3586a78273265a9a1839628 Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Wed, 13 Nov 2019 15:37:52 -0600 Subject: [PATCH 20/31] Add stub test for Python 3 only --- src/nidigital/system_tests/test_system_nidigital.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/nidigital/system_tests/test_system_nidigital.py b/src/nidigital/system_tests/test_system_nidigital.py index 113f0b06f..4cf7ab513 100644 --- a/src/nidigital/system_tests/test_system_nidigital.py +++ b/src/nidigital/system_tests/test_system_nidigital.py @@ -65,3 +65,8 @@ def test_fetch_capture_waveform(multi_instrument_session): if sys.version_info.major >= 3: pass +def test_write_source_waveform_site_unique(multi_instrument_session): + if sys.version_info.major >= 3: + pass + + From 1252d0066b3bb3cd3d3f4ec1ab951f74faf217f6 Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Wed, 13 Nov 2019 15:37:56 -0600 Subject: [PATCH 21/31] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 67e04a3e3..508bca270 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,7 @@ All notable changes to this project will be documented in this file. * ### NI-Digital Pattern Driver * #### Added * `fetch_capture_waveform()` - returns dictionary { site: data, site: data, ... } + * `write_source_waveform_site_unique()` - takes waveform_name and dictionary { site: data, site: data, ... } * #### Changed * Fix get/set properties - [#1062](https://github.com/ni/nimi-python/issues/1062) * Removed array-size parameter from apply_tdr_offsets() and write_source_waveform_broadcast_u32() methods - [#1070](https://github.com/ni/nimi-python/issues/1070) From 8b8a6f7dbf83eea4643f3c8c9e74e4ddd5ef3606 Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Wed, 13 Nov 2019 15:38:07 -0600 Subject: [PATCH 22/31] Update generated files --- docs/nidigital/class.rst | 30 ++++++++ generated/nidigital/_library.py | 9 +++ generated/nidigital/session.py | 71 +++++++++++++++++++ .../nidigital/unit_tests/_mock_helper.py | 9 +++ 4 files changed, 119 insertions(+) diff --git a/docs/nidigital/class.rst b/docs/nidigital/class.rst index 24412ba00..4cdc3bdda 100644 --- a/docs/nidigital/class.rst +++ b/docs/nidigital/class.rst @@ -3373,6 +3373,36 @@ write_source_waveform_data_from_file_tdms :type waveform_file_path: str +write_source_waveform_site_unique +--------------------------------- + + .. py:currentmodule:: nidigital.Session + + .. py:method:: write_source_waveform_site_unique(waveform_name, waveform_data) + + TBD + + + + + + :param waveform_name: + + + + + + :type waveform_name: str + :param waveform_data: + + + Dictionary where each key is the site number and the value is array.array of unsigned int + + + + + :type waveform_data: { site: data, site: data, ... } + write_static ------------ diff --git a/generated/nidigital/_library.py b/generated/nidigital/_library.py index fbbdc88be..71bed689e 100644 --- a/generated/nidigital/_library.py +++ b/generated/nidigital/_library.py @@ -137,6 +137,7 @@ def __init__(self, ctypes_library): self.niDigital_WriteSequencerRegister_cfunc = None self.niDigital_WriteSourceWaveformBroadcastU32_cfunc = None self.niDigital_WriteSourceWaveformDataFromFileTDMS_cfunc = None + self.niDigital_WriteSourceWaveformSiteUniqueU32_cfunc = None self.niDigital_WriteStatic_cfunc = None self.niDigital_close_cfunc = None self.niDigital_error_message_cfunc = None @@ -1095,6 +1096,14 @@ def niDigital_WriteSourceWaveformDataFromFileTDMS(self, vi, waveform_name, wavef self.niDigital_WriteSourceWaveformDataFromFileTDMS_cfunc.restype = ViStatus # noqa: F405 return self.niDigital_WriteSourceWaveformDataFromFileTDMS_cfunc(vi, waveform_name, waveform_file_path) + def niDigital_WriteSourceWaveformSiteUniqueU32(self, vi, site_list, waveform_name, num_waveforms, samples_per_waveform, waveform_data): # noqa: N802 + with self._func_lock: + if self.niDigital_WriteSourceWaveformSiteUniqueU32_cfunc is None: + self.niDigital_WriteSourceWaveformSiteUniqueU32_cfunc = self._library.niDigital_WriteSourceWaveformSiteUniqueU32 + self.niDigital_WriteSourceWaveformSiteUniqueU32_cfunc.argtypes = [ViSession, ctypes.POINTER(ViChar), ctypes.POINTER(ViChar), ViInt32, ViInt32, ctypes.POINTER(ViUInt32)] # noqa: F405 + self.niDigital_WriteSourceWaveformSiteUniqueU32_cfunc.restype = ViStatus # noqa: F405 + return self.niDigital_WriteSourceWaveformSiteUniqueU32_cfunc(vi, site_list, waveform_name, num_waveforms, samples_per_waveform, waveform_data) + def niDigital_WriteStatic(self, vi, channel_list, state): # noqa: N802 with self._func_lock: if self.niDigital_WriteStatic_cfunc is None: diff --git a/generated/nidigital/session.py b/generated/nidigital/session.py index 677552184..c057cb5fb 100644 --- a/generated/nidigital/session.py +++ b/generated/nidigital/session.py @@ -2749,6 +2749,48 @@ def self_test(self): raise errors.SelfTestError(code, msg) return None + @ivi_synchronized + def write_source_waveform_site_unique(self, waveform_name, waveform_data): + '''write_source_waveform_site_unique + + TBD + + Args: + waveform_name (str): + + waveform_data ({ site: data, site: data, ... }): Dictionary where each key is the site number and the value is array.array of unsigned int + + ''' + if len(waveform_data) == 0: + # Nothing to do + return + + site_list = [] + # We assume all the entries are the same length (we'll check later) to make the array the correct size + # Get an entry from the dictionary from https://stackoverflow.com/questions/30362391/how-do-you-find-the-first-key-in-a-dictionary + actual_samples_per_waveform = len(waveform_data[next(iter(waveform_data))]) + data = array.array('L', [0] * (len(waveform_data) * actual_samples_per_waveform)) + mv = memoryview(data) + + i = 0 + for site in waveform_data: + if len(waveform_data[site]) != actual_samples_per_waveform: + raise ValueError('Mismatched length of waveforms. All must be the same length.') + if waveform_data[site].typecode != 'L': + raise ValueError('Wrong array element type. Must be unsigned 32 bit int "l", was {}'.format(waveform_data[site].typecode)) + + site_list.append(str(site)) + + start = i * actual_samples_per_waveform + end = start + actual_samples_per_waveform + mv[start:end] = waveform_data[site] + + i += 1 + + site_list_str = ','.join(site_list) + + self._write_source_waveform_site_unique(site_list_str, waveform_name, len(waveform_data), actual_samples_per_waveform, data) + @ivi_synchronized def fetch_history_ram_cycle_information(self, site, sample_index): r'''fetch_history_ram_cycle_information @@ -3582,6 +3624,35 @@ def write_source_waveform_data_from_file_tdms(self, waveform_name, waveform_file errors.handle_error(self, error_code, ignore_warnings=False, is_error_handling=False) return + @ivi_synchronized + def _write_source_waveform_site_unique_u32(self, site_list, waveform_name, num_waveforms, samples_per_waveform, waveform_data): + r'''_write_source_waveform_site_unique_u32 + + TBD + + Args: + site_list (str): + + waveform_name (str): + + num_waveforms (int): + + samples_per_waveform (int): + + waveform_data (array.array("L")): + + ''' + vi_ctype = _visatype.ViSession(self._vi) # case S110 + site_list_ctype = ctypes.create_string_buffer(site_list.encode(self._encoding)) # case C020 + waveform_name_ctype = ctypes.create_string_buffer(waveform_name.encode(self._encoding)) # case C020 + num_waveforms_ctype = _visatype.ViInt32(num_waveforms) # case S150 + samples_per_waveform_ctype = _visatype.ViInt32(samples_per_waveform) # case S150 + waveform_data_array = get_ctypes_and_array(value=waveform_data, array_type="L") # case B550 + waveform_data_ctype = get_ctypes_pointer_for_buffer(value=waveform_data_array, library_type=_visatype.ViUInt32) # case B550 + error_code = self._library.niDigital_WriteSourceWaveformSiteUniqueU32(vi_ctype, site_list_ctype, waveform_name_ctype, num_waveforms_ctype, samples_per_waveform_ctype, waveform_data_ctype) + errors.handle_error(self, error_code, ignore_warnings=False, is_error_handling=False) + return + def _close(self): r'''_close diff --git a/generated/nidigital/unit_tests/_mock_helper.py b/generated/nidigital/unit_tests/_mock_helper.py index f439791f4..f96623ebe 100644 --- a/generated/nidigital/unit_tests/_mock_helper.py +++ b/generated/nidigital/unit_tests/_mock_helper.py @@ -307,6 +307,8 @@ def __init__(self): self._defaults['WriteSourceWaveformBroadcastU32']['return'] = 0 self._defaults['WriteSourceWaveformDataFromFileTDMS'] = {} self._defaults['WriteSourceWaveformDataFromFileTDMS']['return'] = 0 + self._defaults['WriteSourceWaveformSiteUniqueU32'] = {} + self._defaults['WriteSourceWaveformSiteUniqueU32']['return'] = 0 self._defaults['WriteStatic'] = {} self._defaults['WriteStatic']['return'] = 0 self._defaults['close'] = {} @@ -1262,6 +1264,11 @@ def niDigital_WriteSourceWaveformDataFromFileTDMS(self, vi, waveform_name, wavef return self._defaults['WriteSourceWaveformDataFromFileTDMS']['return'] return self._defaults['WriteSourceWaveformDataFromFileTDMS']['return'] + def niDigital_WriteSourceWaveformSiteUniqueU32(self, vi, site_list, waveform_name, num_waveforms, samples_per_waveform, waveform_data): # noqa: N802 + if self._defaults['WriteSourceWaveformSiteUniqueU32']['return'] != 0: + return self._defaults['WriteSourceWaveformSiteUniqueU32']['return'] + return self._defaults['WriteSourceWaveformSiteUniqueU32']['return'] + def niDigital_WriteStatic(self, vi, channel_list, state): # noqa: N802 if self._defaults['WriteStatic']['return'] != 0: return self._defaults['WriteStatic']['return'] @@ -1548,6 +1555,8 @@ def set_side_effects_and_return_values(self, mock_library): mock_library.niDigital_WriteSourceWaveformBroadcastU32.return_value = 0 mock_library.niDigital_WriteSourceWaveformDataFromFileTDMS.side_effect = MockFunctionCallError("niDigital_WriteSourceWaveformDataFromFileTDMS") mock_library.niDigital_WriteSourceWaveformDataFromFileTDMS.return_value = 0 + mock_library.niDigital_WriteSourceWaveformSiteUniqueU32.side_effect = MockFunctionCallError("niDigital_WriteSourceWaveformSiteUniqueU32") + mock_library.niDigital_WriteSourceWaveformSiteUniqueU32.return_value = 0 mock_library.niDigital_WriteStatic.side_effect = MockFunctionCallError("niDigital_WriteStatic") mock_library.niDigital_WriteStatic.return_value = 0 mock_library.niDigital_close.side_effect = MockFunctionCallError("niDigital_close") From e28b8cc8e490b76e3371649bc52174d046360286 Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Fri, 15 Nov 2019 10:23:23 -0600 Subject: [PATCH 23/31] Fix exception message --- .../session.py/fancy_write_source_waveform_site_unique.py.mako | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nidigital/templates/session.py/fancy_write_source_waveform_site_unique.py.mako b/src/nidigital/templates/session.py/fancy_write_source_waveform_site_unique.py.mako index 46ddf315c..0bc4835df 100644 --- a/src/nidigital/templates/session.py/fancy_write_source_waveform_site_unique.py.mako +++ b/src/nidigital/templates/session.py/fancy_write_source_waveform_site_unique.py.mako @@ -24,7 +24,7 @@ if len(waveform_data[site]) != actual_samples_per_waveform: raise ValueError('Mismatched length of waveforms. All must be the same length.') if waveform_data[site].typecode != 'L': - raise ValueError('Wrong array element type. Must be unsigned 32 bit int "l", was {}'.format(waveform_data[site].typecode)) + raise ValueError('Wrong array element type. Must be unsigned 32 bit int ("L"), was {}'.format(waveform_data[site].typecode)) site_list.append(str(site)) From 93b36bfe09c1f75a38353cd9cf4f7ad8c82e14b7 Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Fri, 15 Nov 2019 10:23:43 -0600 Subject: [PATCH 24/31] Use 'siteN' for sites in string passed into the driver --- .../session.py/fancy_write_source_waveform_site_unique.py.mako | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nidigital/templates/session.py/fancy_write_source_waveform_site_unique.py.mako b/src/nidigital/templates/session.py/fancy_write_source_waveform_site_unique.py.mako index 0bc4835df..19fc8fa64 100644 --- a/src/nidigital/templates/session.py/fancy_write_source_waveform_site_unique.py.mako +++ b/src/nidigital/templates/session.py/fancy_write_source_waveform_site_unique.py.mako @@ -26,7 +26,7 @@ if waveform_data[site].typecode != 'L': raise ValueError('Wrong array element type. Must be unsigned 32 bit int ("L"), was {}'.format(waveform_data[site].typecode)) - site_list.append(str(site)) + site_list.append('site' + str(site)) start = i * actual_samples_per_waveform end = start + actual_samples_per_waveform From 48e894b01ed387095ec8c54b66bfe612999f5da7 Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Fri, 15 Nov 2019 10:24:02 -0600 Subject: [PATCH 25/31] Update generated files --- generated/nidigital/session.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/generated/nidigital/session.py b/generated/nidigital/session.py index c057cb5fb..b03884bef 100644 --- a/generated/nidigital/session.py +++ b/generated/nidigital/session.py @@ -2777,9 +2777,9 @@ def write_source_waveform_site_unique(self, waveform_name, waveform_data): if len(waveform_data[site]) != actual_samples_per_waveform: raise ValueError('Mismatched length of waveforms. All must be the same length.') if waveform_data[site].typecode != 'L': - raise ValueError('Wrong array element type. Must be unsigned 32 bit int "l", was {}'.format(waveform_data[site].typecode)) + raise ValueError('Wrong array element type. Must be unsigned 32 bit int "L", was {}'.format(waveform_data[site].typecode)) - site_list.append(str(site)) + site_list.append('site' + str(site)) start = i * actual_samples_per_waveform end = start + actual_samples_per_waveform From 0115a85b42bade17035d054f1f4a2e894c4faa54 Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Mon, 18 Nov 2019 16:14:20 -0600 Subject: [PATCH 26/31] Let driver error on empty list of waveforms --- .../fancy_write_source_waveform_site_unique.py.mako | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/nidigital/templates/session.py/fancy_write_source_waveform_site_unique.py.mako b/src/nidigital/templates/session.py/fancy_write_source_waveform_site_unique.py.mako index 19fc8fa64..febcad21f 100644 --- a/src/nidigital/templates/session.py/fancy_write_source_waveform_site_unique.py.mako +++ b/src/nidigital/templates/session.py/fancy_write_source_waveform_site_unique.py.mako @@ -8,14 +8,13 @@ ${helper.get_function_docstring(f, False, config, indent=8)} ''' - if len(waveform_data) == 0: - # Nothing to do - return - site_list = [] # We assume all the entries are the same length (we'll check later) to make the array the correct size # Get an entry from the dictionary from https://stackoverflow.com/questions/30362391/how-do-you-find-the-first-key-in-a-dictionary - actual_samples_per_waveform = len(waveform_data[next(iter(waveform_data))]) + if len(waveform_data) == 0: + actual_samples_per_waveform = 0 + else: + actual_samples_per_waveform = len(waveform_data[next(iter(waveform_data))]) data = array.array('L', [0] * (len(waveform_data) * actual_samples_per_waveform)) mv = memoryview(data) From 0ebad6460337663ff7e77a5e4ea8f8858a7eb749 Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Mon, 18 Nov 2019 16:14:34 -0600 Subject: [PATCH 27/31] Update generated files --- generated/nidigital/session.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/generated/nidigital/session.py b/generated/nidigital/session.py index a06db6357..5183344f4 100644 --- a/generated/nidigital/session.py +++ b/generated/nidigital/session.py @@ -2762,14 +2762,13 @@ def write_source_waveform_site_unique(self, waveform_name, waveform_data): waveform_data ({ site: data, site: data, ... }): Dictionary where each key is the site number and the value is array.array of unsigned int ''' - if len(waveform_data) == 0: - # Nothing to do - return - site_list = [] # We assume all the entries are the same length (we'll check later) to make the array the correct size # Get an entry from the dictionary from https://stackoverflow.com/questions/30362391/how-do-you-find-the-first-key-in-a-dictionary - actual_samples_per_waveform = len(waveform_data[next(iter(waveform_data))]) + if len(waveform_data) == 0: + actual_samples_per_waveform = 0 + else: + actual_samples_per_waveform = len(waveform_data[next(iter(waveform_data))]) data = array.array('L', [0] * (len(waveform_data) * actual_samples_per_waveform)) mv = memoryview(data) From edec3c965e2be2934c0fa87065cf5231b34ec005 Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Tue, 19 Nov 2019 09:23:17 -0600 Subject: [PATCH 28/31] Fix function name we call --- .../session.py/fancy_write_source_waveform_site_unique.py.mako | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nidigital/templates/session.py/fancy_write_source_waveform_site_unique.py.mako b/src/nidigital/templates/session.py/fancy_write_source_waveform_site_unique.py.mako index febcad21f..503f244ec 100644 --- a/src/nidigital/templates/session.py/fancy_write_source_waveform_site_unique.py.mako +++ b/src/nidigital/templates/session.py/fancy_write_source_waveform_site_unique.py.mako @@ -35,5 +35,5 @@ site_list_str = ','.join(site_list) - self._write_source_waveform_site_unique(site_list_str, waveform_name, len(waveform_data), actual_samples_per_waveform, data) + self._write_source_waveform_site_unique_u32(site_list_str, waveform_name, len(waveform_data), actual_samples_per_waveform, data) From 3974bc2576324a14309659b0c1990c059aeb5108 Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Tue, 19 Nov 2019 09:28:34 -0600 Subject: [PATCH 29/31] Update generated files --- generated/nidigital/session.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generated/nidigital/session.py b/generated/nidigital/session.py index 3e1a50d43..3fc28d309 100644 --- a/generated/nidigital/session.py +++ b/generated/nidigital/session.py @@ -2884,7 +2884,7 @@ def write_source_waveform_site_unique(self, waveform_name, waveform_data): site_list_str = ','.join(site_list) - self._write_source_waveform_site_unique(site_list_str, waveform_name, len(waveform_data), actual_samples_per_waveform, data) + self._write_source_waveform_site_unique_u32(site_list_str, waveform_name, len(waveform_data), actual_samples_per_waveform, data) @ivi_synchronized def fetch_history_ram_cycle_information(self, site, sample_index): From 2ea9eecb30300a4d32f4a9f8838952ec01bf300a Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Tue, 19 Nov 2019 10:01:22 -0600 Subject: [PATCH 30/31] Force rebuild --- src/nidigital/metadata/functions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nidigital/metadata/functions.py b/src/nidigital/metadata/functions.py index 872ed881c..bfd452f5b 100644 --- a/src/nidigital/metadata/functions.py +++ b/src/nidigital/metadata/functions.py @@ -3951,3 +3951,4 @@ 'returns': 'ViStatus' } } + From df4d284a95e768e7a164b6b7bcf44ee523b053db Mon Sep 17 00:00:00 2001 From: Mark Silva Date: Tue, 19 Nov 2019 10:21:34 -0600 Subject: [PATCH 31/31] Add comment about the type being ignored --- src/nidigital/metadata/functions_addon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nidigital/metadata/functions_addon.py b/src/nidigital/metadata/functions_addon.py index 0eabdd13f..eb0d03aa2 100644 --- a/src/nidigital/metadata/functions_addon.py +++ b/src/nidigital/metadata/functions_addon.py @@ -35,7 +35,7 @@ 'description': '\nDictionary where each key is the site number and the value is array.array of unsigned int\n' }, 'name': 'waveform_data', - 'type': 'ViUInt32', + 'type': 'ViUInt32', # This type is ignored since this function isn't code generated 'type_in_documentation': '{ site: data, site: data, ... }', }, ],