Skip to content

Commit c69b58f

Browse files
authored
Add get_channel_names to niscope API (#1957)
* add get_channel_names to niscope api * Mention addition in changelog * Remove unnecessary line from metadata * Update metadata from internal dev export * Do not render in SessionBase. * Add test_get_channel_names_with_single_instrument_session * Correct single_instrument test
1 parent 195ac33 commit c69b58f

File tree

9 files changed

+189
-1
lines changed

9 files changed

+189
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ All notable changes to this project will be documented in this file.
5959
* #### Removed
6060
* ### `niscope` (NI-SCOPE)
6161
* #### Added
62+
* `get_channel_names()`
6263
* #### Changed
6364
* #### Removed
6465
* ### `niswitch` (NI-SWITCH)

docs/niscope/class.rst

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1894,6 +1894,45 @@ fetch_measurement_stats
18941894
18951895
18961896
1897+
get_channel_names
1898+
-----------------
1899+
1900+
.. py:currentmodule:: niscope.Session
1901+
1902+
.. py:method:: get_channel_names(indices)
1903+
1904+
Returns a list of channel names for given channel indices.
1905+
1906+
1907+
1908+
1909+
1910+
:param indices:
1911+
1912+
1913+
Index list for the channels in the session. Valid values are from zero to the total number of channels in the session minus one. The index string can be one of the following formats:
1914+
1915+
- A comma-separated listfor example, "0,2,3,1"
1916+
- A range using a hyphen—for example, "0-3"
1917+
- A range using a colon—for example, "0:3 "
1918+
1919+
You can combine comma-separated lists and ranges that use a hyphen or colon. Both out-of-order and repeated indices are supported ("2,3,0," "1,2,2,3"). White space characters, including spaces, tabs, feeds, and carriage returns, are allowed between characters. Ranges can be incrementing or decrementing.
1920+
1921+
1922+
1923+
1924+
:type indices: basic sequence types or str or int
1925+
1926+
:rtype: list of str
1927+
:return:
1928+
1929+
1930+
The channel name(s) at the specified indices.
1931+
1932+
1933+
1934+
1935+
18971936
get_equalization_filter_coefficients
18981937
------------------------------------
18991938

generated/niscope/niscope/_grpc_stub_interpreter.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,13 @@ def get_attribute_vi_string(self, channel_list, attribute_id): # noqa: N802
307307
)
308308
return response.value
309309

310+
def get_channel_names(self, indices): # noqa: N802
311+
response = self._invoke(
312+
self._client.GetChannelNameFromString,
313+
grpc_types.GetChannelNameFromStringRequest(vi=self._vi, index=indices),
314+
)
315+
return response.name
316+
310317
def get_equalization_filter_coefficients(self, channel, number_of_coefficients): # noqa: N802
311318
response = self._invoke(
312319
self._client.GetEqualizationFilterCoefficients,

generated/niscope/niscope/_library.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ def __init__(self, ctypes_library):
6161
self.niScope_GetAttributeViInt64_cfunc = None
6262
self.niScope_GetAttributeViReal64_cfunc = None
6363
self.niScope_GetAttributeViString_cfunc = None
64+
self.niScope_GetChannelNameFromString_cfunc = None
6465
self.niScope_GetEqualizationFilterCoefficients_cfunc = None
6566
self.niScope_GetError_cfunc = None
6667
self.niScope_ImportAttributeConfigurationBuffer_cfunc = None
@@ -396,6 +397,14 @@ def niScope_GetAttributeViString(self, vi, channel_list, attribute_id, buf_size,
396397
self.niScope_GetAttributeViString_cfunc.restype = ViStatus # noqa: F405
397398
return self.niScope_GetAttributeViString_cfunc(vi, channel_list, attribute_id, buf_size, value)
398399

400+
def niScope_GetChannelNameFromString(self, vi, indices, buffer_size, names): # noqa: N802
401+
with self._func_lock:
402+
if self.niScope_GetChannelNameFromString_cfunc is None:
403+
self.niScope_GetChannelNameFromString_cfunc = self._get_library_function('niScope_GetChannelNameFromString')
404+
self.niScope_GetChannelNameFromString_cfunc.argtypes = [ViSession, ctypes.POINTER(ViChar), ViInt32, ctypes.POINTER(ViChar)] # noqa: F405
405+
self.niScope_GetChannelNameFromString_cfunc.restype = ViStatus # noqa: F405
406+
return self.niScope_GetChannelNameFromString_cfunc(vi, indices, buffer_size, names)
407+
399408
def niScope_GetEqualizationFilterCoefficients(self, vi, channel, number_of_coefficients, coefficients): # noqa: N802
400409
with self._func_lock:
401410
if self.niScope_GetEqualizationFilterCoefficients_cfunc is None:

generated/niscope/niscope/_library_interpreter.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,19 @@ def get_attribute_vi_string(self, channel_list, attribute_id): # noqa: N802
486486
errors.handle_error(self, error_code, ignore_warnings=False, is_error_handling=False)
487487
return value_ctype.value.decode(self._encoding)
488488

489+
def get_channel_names(self, indices): # noqa: N802
490+
vi_ctype = _visatype.ViSession(self._vi) # case S110
491+
indices_ctype = ctypes.create_string_buffer(indices.encode(self._encoding)) # case C020
492+
buffer_size_ctype = _visatype.ViInt32() # case S170
493+
names_ctype = None # case C050
494+
error_code = self._library.niScope_GetChannelNameFromString(vi_ctype, indices_ctype, buffer_size_ctype, names_ctype)
495+
errors.handle_error(self, error_code, ignore_warnings=True, is_error_handling=False)
496+
buffer_size_ctype = _visatype.ViInt32(error_code) # case S180
497+
names_ctype = (_visatype.ViChar * buffer_size_ctype.value)() # case C060
498+
error_code = self._library.niScope_GetChannelNameFromString(vi_ctype, indices_ctype, buffer_size_ctype, names_ctype)
499+
errors.handle_error(self, error_code, ignore_warnings=False, is_error_handling=False)
500+
return names_ctype.value.decode(self._encoding)
501+
489502
def get_equalization_filter_coefficients(self, channel, number_of_coefficients): # noqa: N802
490503
vi_ctype = _visatype.ViSession(self._vi) # case S110
491504
channel_ctype = ctypes.create_string_buffer(channel.encode(self._encoding)) # case C010

generated/niscope/niscope/session.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4822,6 +4822,30 @@ def get_self_cal_last_temp(self):
48224822

48234823
return self._cal_fetch_temperature(enums._CalibrationTypes.SELF.value)
48244824

4825+
@ivi_synchronized
4826+
def get_channel_names(self, indices):
4827+
r'''get_channel_names
4828+
4829+
Returns a list of channel names for given channel indices.
4830+
4831+
Args:
4832+
indices (basic sequence types or str or int): Index list for the channels in the session. Valid values are from zero to the total number of channels in the session minus one. The index string can be one of the following formats:
4833+
4834+
- A comma-separated list—for example, "0,2,3,1"
4835+
- A range using a hyphen—for example, "0-3"
4836+
- A range using a colon—for example, "0:3 "
4837+
4838+
You can combine comma-separated lists and ranges that use a hyphen or colon. Both out-of-order and repeated indices are supported ("2,3,0," "1,2,2,3"). White space characters, including spaces, tabs, feeds, and carriage returns, are allowed between characters. Ranges can be incrementing or decrementing.
4839+
4840+
4841+
Returns:
4842+
names (list of str): The channel name(s) at the specified indices.
4843+
4844+
'''
4845+
indices = _converters.convert_repeated_capabilities_without_prefix(indices)
4846+
names = self._interpreter.get_channel_names(indices)
4847+
return _converters.convert_comma_separated_string_to_list(names)
4848+
48254849
@ivi_synchronized
48264850
def import_attribute_configuration_buffer(self, configuration):
48274851
r'''import_attribute_configuration_buffer

generated/niscope/niscope/unit_tests/_mock_helper.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@ def __init__(self):
121121
self._defaults['GetAttributeViString'] = {}
122122
self._defaults['GetAttributeViString']['return'] = 0
123123
self._defaults['GetAttributeViString']['value'] = None
124+
self._defaults['GetChannelNameFromString'] = {}
125+
self._defaults['GetChannelNameFromString']['return'] = 0
126+
self._defaults['GetChannelNameFromString']['name'] = None
124127
self._defaults['GetEqualizationFilterCoefficients'] = {}
125128
self._defaults['GetEqualizationFilterCoefficients']['return'] = 0
126129
self._defaults['GetEqualizationFilterCoefficients']['coefficients'] = None
@@ -623,6 +626,17 @@ def niScope_GetAttributeViString(self, vi, channel_list, attribute_id, buf_size,
623626
value.value = self._defaults['GetAttributeViString']['value'].encode('ascii')
624627
return self._defaults['GetAttributeViString']['return']
625628

629+
def niScope_GetChannelNameFromString(self, vi, indices, buffer_size, names): # noqa: N802
630+
if self._defaults['GetChannelNameFromString']['return'] != 0:
631+
return self._defaults['GetChannelNameFromString']['return']
632+
# names
633+
if self._defaults['GetChannelNameFromString']['name'] is None:
634+
raise MockFunctionCallError("niScope_GetChannelNameFromString", param='name')
635+
if buffer_size.value == 0:
636+
return len(self._defaults['GetChannelNameFromString']['name'])
637+
names.value = self._defaults['GetChannelNameFromString']['name'].encode('ascii')
638+
return self._defaults['GetChannelNameFromString']['return']
639+
626640
def niScope_GetEqualizationFilterCoefficients(self, vi, channel, number_of_coefficients, coefficients): # noqa: N802
627641
if self._defaults['GetEqualizationFilterCoefficients']['return'] != 0:
628642
return self._defaults['GetEqualizationFilterCoefficients']['return']
@@ -898,6 +912,8 @@ def set_side_effects_and_return_values(self, mock_library):
898912
mock_library.niScope_GetAttributeViReal64.return_value = 0
899913
mock_library.niScope_GetAttributeViString.side_effect = MockFunctionCallError("niScope_GetAttributeViString")
900914
mock_library.niScope_GetAttributeViString.return_value = 0
915+
mock_library.niScope_GetChannelNameFromString.side_effect = MockFunctionCallError("niScope_GetChannelNameFromString")
916+
mock_library.niScope_GetChannelNameFromString.return_value = 0
901917
mock_library.niScope_GetEqualizationFilterCoefficients.side_effect = MockFunctionCallError("niScope_GetEqualizationFilterCoefficients")
902918
mock_library.niScope_GetEqualizationFilterCoefficients.return_value = 0
903919
mock_library.niScope_GetError.side_effect = MockFunctionCallError("niScope_GetError")

src/niscope/metadata/functions_addon.py

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,62 @@
1414
]
1515
}
1616
}
17-
17+
functions_additional_get_channel_name = {
18+
'GetChannelNameFromString': {
19+
'documentation': {
20+
'description': 'Returns a list of channel names for given channel indices.\n'
21+
},
22+
'included_in_proto': True,
23+
'parameters': [
24+
{
25+
'direction': 'in',
26+
'documentation': {
27+
'description': '\nThe instrument handle you obtain from niScope_init that identifies a\nparticular instrument session.\n'
28+
},
29+
'name': 'vi',
30+
'type': 'ViSession'
31+
},
32+
{
33+
'direction': 'in',
34+
'documentation': {
35+
'description': 'Index list for the channels in the session. Valid values are from zero to the total number of channels in the session minus one. The index string can be one of the following formats:\n\n- A comma-separated list—for example, "0,2,3,1"\n- A range using a hyphen—for example, "0-3"\n- A range using a colon—for example, "0:3 "\n\nYou can combine comma-separated lists and ranges that use a hyphen or colon. Both out-of-order and repeated indices are supported ("2,3,0," "1,2,2,3"). White space characters, including spaces, tabs, feeds, and carriage returns, are allowed between characters. Ranges can be incrementing or decrementing.\n'
36+
},
37+
'grpc_name': 'index',
38+
'name': 'index',
39+
'python_api_converter_name': 'convert_repeated_capabilities_without_prefix',
40+
'python_name': 'indices',
41+
'type': 'ViConstString',
42+
'type_in_documentation': 'basic sequence types or str or int'
43+
},
44+
{
45+
'direction': 'in',
46+
'documentation': {
47+
'description': 'The number of elements in the ViChar array you specify for name.\n'
48+
},
49+
'name': 'bufferSize',
50+
'type': 'ViInt32'
51+
},
52+
{
53+
'direction': 'out',
54+
'documentation': {
55+
'description': 'The channel name(s) at the specified indices.\n'
56+
},
57+
'grpc_name': 'name',
58+
'name': 'name',
59+
'python_api_converter_name': 'convert_comma_separated_string_to_list',
60+
'python_name': 'names',
61+
'size': {
62+
'mechanism': 'ivi-dance',
63+
'value': 'bufferSize'
64+
},
65+
'type': 'ViChar[]',
66+
'type_in_documentation': 'list of str'
67+
}
68+
],
69+
'python_name': 'get_channel_names',
70+
'returns': 'ViStatus'
71+
},
72+
}
1873
functions_additional_fetch_array_measurement = {
1974
'FancyFetchArrayMeasurement': {
2075
'codegen_method': 'python-only',

src/niscope/system_tests/test_system_niscope.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,21 @@ def single_instrument_session(self, session_creation_kwargs):
7474
with niscope.Session('FakeDevice', False, True, 'Simulate=1, DriverSetup=Model:5164; BoardType:PXIe', **session_creation_kwargs) as simulated_session:
7575
yield simulated_session
7676

77+
@pytest.fixture(scope='function')
78+
def single_instrument_session_5171(self, session_creation_kwargs): # High channel-count session for get_channel_names testing
79+
with niscope.Session('FakeDevice', False, True, 'Simulate=1, DriverSetup=Model:5171R (8CH); BoardType:PXIe', **session_creation_kwargs) as simulated_session:
80+
yield simulated_session
81+
7782
@pytest.fixture(scope='function')
7883
def multi_instrument_session(self, session_creation_kwargs):
7984
with niscope.Session(','.join(instruments), False, True, 'Simulate=1, DriverSetup=Model:5164; BoardType:PXIe', **session_creation_kwargs) as simulated_session:
8085
yield simulated_session
8186

87+
@pytest.fixture(scope='function')
88+
def multi_instrument_session_5171(self, session_creation_kwargs): # High channel-count session for get_channel_names testing
89+
with niscope.Session(','.join(instruments), False, True, 'Simulate=1, DriverSetup=Model:5171R (8CH); BoardType:PXIe', **session_creation_kwargs) as simulated_session:
90+
yield simulated_session
91+
8292
@pytest.fixture(scope='function')
8393
def session_5124(self, session_creation_kwargs):
8494
with daqmx_sim_5124_lock:
@@ -103,6 +113,20 @@ def test_vi_string_attribute(self, multi_instrument_session):
103113
assert trigger_source == multi_instrument_session.acq_arm_source
104114

105115
# Basic usability tests
116+
def test_get_channel_names_with_single_instrument_session(self, single_instrument_session_5171):
117+
expected_string = [f'{x}' for x in range(8)]
118+
# Sanity test few different types of input. No need for test to be exhaustive
119+
# since all the various types are covered by converter unit tests.
120+
channel_indices = ['0-1, 2, 3:4', 5, range(6, 7), slice(7, 8)]
121+
assert single_instrument_session_5171.get_channel_names(indices=channel_indices) == expected_string
122+
123+
def test_get_channel_names_with_multi_instrument_session(self, multi_instrument_session_5171):
124+
expected_string = [f'{instruments[0]}/{x}' for x in range(8)] + [f'{instruments[1]}/{x}' for x in range(4)]
125+
# Sanity test few different types of input. No need for test to be exhaustive
126+
# since all the various types are covered by converter unit tests.
127+
channel_indices = ['0-1, 2, 3:4', 5, (6, 7), range(8, 10), slice(10, 12)]
128+
assert multi_instrument_session_5171.get_channel_names(indices=channel_indices) == expected_string
129+
106130
@pytest.mark.parametrize(
107131
"test_channels,test_channels_expanded",
108132
[

0 commit comments

Comments
 (0)