Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions build/helper/codegen_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,9 @@ def get_library_interpreter_method_return_snippet(parameters, config, use_numpy_
return ('return ' + ', '.join(snippets)).strip()


def get_grpc_interpreter_method_return_snippet(parameters, config):
def get_grpc_interpreter_method_return_snippet(parameters, config, use_numpy_array=False):
'''Returns a string suitable to use as the return argument of a _gprc.LibraryInterpreter method'''
parameters_to_use = filter_parameters(parameters, ParameterUsageOptions.API_OUTPUT_PARAMETERS)
parameters_to_use = filter_parameters(parameters, ParameterUsageOptions.API_NUMPY_OUTPUT_PARAMETERS if use_numpy_array else ParameterUsageOptions.API_OUTPUT_PARAMETERS)
snippets = [_get_grpc_interpreter_output_param_return_snippet(p, parameters, config) for p in parameters_to_use]
return ('return ' + ', '.join(snippets)).strip()

Expand Down
1 change: 1 addition & 0 deletions build/templates/_grpc_stub_interpreter.py.mako
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ from . import errors as errors
from . import ${proto_name}_pb2 as grpc_types
from . import ${proto_name}_pb2_grpc as ${module_name}_grpc
from . import session_pb2 as session_grpc_types
from . import nidevice_pb2 as grpc_complex_types
% for c in config['custom_types']:

from . import ${c['file_name']} as ${c['file_name']} # noqa: F401
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,42 @@
<%page args="f, config, method_template"/>\
<%
'''Renders a NotImplemented method for to the passed-in function metadata, because numpy is not supported over grpc.'''

'''Renders a GrpcStubInterpreter method for reading repeated NIComplex proto fields into numpy arrays.'''
import build.helper as helper

parameters = f['parameters']
param_names_method = helper.get_params_snippet(f, helper.ParameterUsageOptions.INTERPRETER_NUMPY_INTO_METHOD_DECLARATION)
grpc_name = f.get('grpc_name', f['name'])
grpc_request_args = helper.get_params_snippet(f, helper.ParameterUsageOptions.GRPC_REQUEST_PARAMETERS)
return_statement = helper.get_grpc_interpreter_method_return_snippet(parameters, config, use_numpy_array=True)
if return_statement == 'return':
return_statement = None
capture_response = 'response = ' if return_statement else ''
included_in_proto = f.get('included_in_proto', True)
full_func_name = f['interpreter_name'] + method_template['method_python_name_suffix']
method_decl_params = helper.get_params_snippet(f, helper.ParameterUsageOptions.INTERPRETER_METHOD_DECLARATION)
numpy_complex_params = [p for p in helper.filter_parameters(parameters, helper.ParameterUsageOptions.NUMPY_PARAMETERS) if p['complex_type'] is not None]
%>\

def ${full_func_name}(${method_decl_params}): # noqa: N802
raise NotImplementedError('numpy-specific methods are not supported over gRPC')
def ${full_func_name}(${param_names_method}): # noqa: N802
% if numpy_complex_params:
import numpy
% endif
% if included_in_proto:
${capture_response}self._invoke(
self._client.${grpc_name},
grpc_types.${grpc_name}Request(${grpc_request_args}),
)
% for p in numpy_complex_params:
% if p['original_type'] == 'NIComplexNumber[]':
temp_array = numpy.array([(c.real, c.imag) for c in response.${p['python_name']}], dtype=numpy.complex128)
% elif p['original_type'] == 'NIComplexNumberF32[]':
temp_array = numpy.array([(c.real, c.imag) for c in response.${p['python_name']}], dtype=numpy.complex64)
% elif p['original_type'] == 'NIComplexI16[]':
temp_array = numpy.array([(c.real, c.imag) for c in response.${p['python_name']}], dtype=numpy.dtype([('real', numpy.int16), ('imag', numpy.int16)]))
% endif
numpy.copyto(${p['python_name']}, temp_array.view(${p['python_name']}.dtype).reshape(${p['python_name']}.shape))
% endfor
% if return_statement:
${return_statement}
% endif
% else:
raise NotImplementedError('${full_func_name} is not supported over gRPC')
% endif
Original file line number Diff line number Diff line change
@@ -1,3 +1,59 @@
<%page args="f, config, method_template"/>\
## numpy_read and numpy_write are identical for gRPC -- both return a NotImplementedError
<%include file="/_grpc_stub_interpreter.py/numpy_read_method.py.mako" args="f=f, config=config, method_template=method_template" />\
<%
'''Renders a GrpcStubInterpreter method corresponding to the passed-in function metadata.'''
import build.helper as helper
parameters = f['parameters']
full_func_name = f['interpreter_name'] + method_template['method_python_name_suffix']
method_decl_params = helper.get_params_snippet(f, helper.ParameterUsageOptions.INTERPRETER_METHOD_DECLARATION)
grpc_name = f.get('grpc_name', f['name'])
grpc_request_args = helper.get_params_snippet(f, helper.ParameterUsageOptions.GRPC_REQUEST_PARAMETERS)
return_statement = helper.get_grpc_interpreter_method_return_snippet(f['parameters'], config)
if return_statement == 'return':
return_statement = None
capture_response = 'response = ' if return_statement else ''
included_in_proto = f.get('included_in_proto', True)
numpy_complex_params = [
p for p in helper.filter_parameters(parameters, helper.ParameterUsageOptions.NUMPY_PARAMETERS)
if p['complex_type'] is not None and p.get('original_type') in ('NIComplexNumber[]', 'NIComplexNumberF32[]', 'NIComplexI16[]')
]

# For numpy complex inputs, create NIComplex message lists and map them in the request args
for p in numpy_complex_params:
# Replace occurrences like "field=python_name" with "field=python_name_list"
grpc_request_args = grpc_request_args.replace(
p['grpc_name'] + '=' + p['python_name'],
p['grpc_name'] + '=' + p['python_name'] + '_list'
)

%>\

def ${full_func_name}(${method_decl_params}): # noqa: N802
% if included_in_proto:
% for p in numpy_complex_params:
% if p['original_type'] == 'NIComplexNumber[]':
${p['python_name']}_list = [
grpc_complex_types.NIComplexNumber(real=val.real, imaginary=val.imag)
for val in ${p['python_name']}.ravel()
]
% elif p['original_type'] == 'NIComplexNumberF32[]':
${p['python_name']}_list = [
grpc_complex_types.NIComplexNumberF32(real=val.real, imaginary=val.imag)
for val in ${p['python_name']}.ravel()
]
% elif p['original_type'] == 'NIComplexI16[]':
${p['python_name']}_list = [
grpc_complex_types.NIComplexI16(real=int(val['real']), imaginary=int(val['imag']))
for val in ${p['python_name']}.ravel()
]
% endif
% endfor
${capture_response}self._invoke(
self._client.${grpc_name},
grpc_types.${grpc_name}Request(${grpc_request_args}),
)
% if return_statement:
${return_statement}
% endif
% else:
raise NotImplementedError('${full_func_name} is not supported over gRPC')
% endif
11 changes: 11 additions & 0 deletions src/nirfsg/metadata/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -1020,6 +1020,7 @@
},
'is_repeated_capability': True,
'name': 'triggerId',
'grpc_enum': 'DigitalEdgeScriptTriggerIdentifier',
'repeated_capability_type': 'script_triggers',
'type': 'ViConstString',
'use_array': False,
Expand All @@ -1031,6 +1032,7 @@
'description': 'Specifies the source terminal for the digital edge Script Trigger. NI-RFSG sets the NIRFSG_ATTR_DIGITAL_EDGE_SCRIPT_TRIGGER_SOURCE attribute to this value.'
},
'name': 'source',
'grpc_enum': 'TriggerSource',
'type': 'ViConstString',
'use_array': False,
'use_in_python_api': True
Expand Down Expand Up @@ -1083,6 +1085,7 @@
'description': 'Specifies the source terminal for the digital edge trigger. NI-RFSG sets the NIRFSG_ATTR_DIGITAL_EDGE_START_TRIGGER_SOURCE attribute to this value.'
},
'name': 'source',
'grpc_enum': 'TriggerSource',
'type': 'ViConstString',
'use_array': False,
'use_in_python_api': True
Expand Down Expand Up @@ -1135,6 +1138,7 @@
},
'is_repeated_capability': True,
'name': 'triggerId',
'grpc_enum': 'DigitalEdgeScriptTriggerIdentifier',
'repeated_capability_type': 'script_triggers',
'type': 'ViConstString',
'use_array': False,
Expand Down Expand Up @@ -1413,6 +1417,7 @@
},
'is_repeated_capability': True,
'name': 'triggerId',
'grpc_enum': 'DigitalEdgeScriptTriggerIdentifier',
'repeated_capability_type': 'script_triggers',
'type': 'ViConstString',
'use_array': False,
Expand Down Expand Up @@ -1804,6 +1809,7 @@
},
'is_repeated_capability': True,
'name': 'triggerId',
'grpc_enum': 'DigitalEdgeScriptTriggerIdentifier',
'repeated_capability_type': 'script_triggers',
'type': 'ViConstString',
'use_array': False,
Expand Down Expand Up @@ -3289,6 +3295,7 @@
]
},
'name': 'signalIdentifier',
'grpc_enum': 'SignalIdentifier',
'type': 'ViConstString',
'use_array': False,
'use_in_python_api': True
Expand Down Expand Up @@ -4574,6 +4581,7 @@
]
},
'name': 'triggerIdentifier',
'grpc_enum': 'SignalIdentifier',
'type': 'ViConstString',
'use_array': False,
'use_in_python_api': True
Expand Down Expand Up @@ -5341,6 +5349,7 @@
'description': 'Specifies the array of data to load into the waveform. The array must have at least as many elements as the value in the **size_in_samples** parameter in the nirfsg_AllocateArbWaveform function.'
},
'name': 'waveformDataArray',
'grpc_name': 'wfm_data',
'numpy': True,
'size': {
'mechanism': 'len',
Expand Down Expand Up @@ -5416,6 +5425,7 @@
'description': 'Specifies the array of data to load into the waveform. The array must have at least as many elements as the value in the **size_in_samples** parameter in the nirfsg_AllocateArbWaveform function.'
},
'name': 'waveformDataArray',
'grpc_name': 'wfm_data',
'numpy': True,
'size': {
'mechanism': 'len',
Expand Down Expand Up @@ -5491,6 +5501,7 @@
'description': 'Specifies the array of data to load into the waveform. The array must have at least as many elements as the value in the **size_in_samples** parameter in the nirfsg_AllocateArbWaveform function.'
},
'name': 'waveformDataArray',
'grpc_name': 'wfm_data',
'numpy': True,
'size': {
'mechanism': 'len',
Expand Down
Loading
Loading