Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
9f9e12e
Added Proto file for RFSG
abhising-NI Aug 7, 2025
551cef7
Implemented Codegen for grpc complex to numpy read
abhising-NI Aug 7, 2025
dfe5ff0
Added Read Numpy
abhising-NI Aug 7, 2025
8e5ef5a
Added Write numpy to NIComplex over gRPC
abhising-NI Aug 8, 2025
de1fbe5
Linked GRPC Service for system tests
abhising-NI Aug 8, 2025
fb17c84
Added grpc names for some APIs
abhising-NI Aug 11, 2025
c2e8dc0
Added snakecase for grpc_name
abhising-NI Aug 11, 2025
8da7fe7
Removed useless file
abhising-NI Aug 11, 2025
2d89870
Added metadata for gRPC enums
abhising-NI Aug 11, 2025
afd26c2
Fixed Syntax Error
abhising-NI Aug 11, 2025
e8163d8
Resolved the numpy interleaved problem in int16
abhising-NI Aug 12, 2025
71bf864
Added Size Parameter for CreateDeembeddingSparameterTableArray API
abhising-NI Aug 14, 2025
b976cb7
Skipped test_set_get_deembedding_sparameters for gRPC in System Tests
abhising-NI Aug 19, 2025
23e81ce
TEMP:Try removing single len parameter force
abhising-NI Aug 20, 2025
9ac402b
TEMP1:Try removing single len parameter force
abhising-NI Aug 20, 2025
5906d3a
TEMP2:Try removing single len parameter force
abhising-NI Aug 20, 2025
113c70a
TEMP3:Try removing single len parameter force
abhising-NI Aug 20, 2025
2e29792
TEMP4:Try removing single len parameter force
abhising-NI Aug 20, 2025
a3533b7
TEMP5:Try removing single len parameter force
abhising-NI Aug 21, 2025
5211265
Added restricted API calls in gRPC
abhising-NI Aug 22, 2025
1f6a58d
Added restricted API calls in gRPC.
abhising-NI Aug 22, 2025
ba15ccd
Added restricted API calls in gRPC..
abhising-NI Aug 22, 2025
559e69f
Added some corrections
abhising-NI Aug 22, 2025
10de869
Added some corrections.
abhising-NI Aug 22, 2025
e6f8070
Added restricted proto file force compile
abhising-NI Aug 22, 2025
52d7cd4
Modified some system tests to run on hardware
abhising-NI Aug 22, 2025
3480df1
Removed gRPC numpy read write tests NotImplemented Error
abhising-NI Aug 25, 2025
d086b78
Added new proto file
abhising-NI Aug 28, 2025
a45cd20
Modified numpy read codegen
abhising-NI Aug 28, 2025
c8c7750
Added generated files
abhising-NI Sep 4, 2025
461be13
Reduced redundant lines of codegenerated code
abhising-NI Sep 10, 2025
6d3e059
Added changes according to the newer grpc-device repo to accomodate a…
abhising-NI Sep 11, 2025
2275b57
Added changes according to the newer grpc-device repo to accomodate a…
abhising-NI Sep 11, 2025
1f02999
Added changes according to the newer grpc-device repo to accomodate a…
abhising-NI Sep 12, 2025
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
6 changes: 4 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 Expand Up @@ -370,6 +370,8 @@ def _get_ctype_variable_definition_snippet_for_scalar(parameter, parameters, ivi
# This is used for complex waveforms, where the real and imaginary parts are interleaved in the array.
if corresponding_buffer_parameters[0]['complex_type'] == 'interleaved':
definitions.append(parameter['ctypes_variable_name'] + ' = {0}.{1}(0 if {2} is None else len({2}) // 2) # case S160'.format(module_name, parameter['ctypes_type'], corresponding_buffer_parameters[0]['python_name']))
elif corresponding_buffer_parameters[0]['complex_type'] == 'ndim-numpy':
definitions.append(parameter['ctypes_variable_name'] + ' = {0}.{1}(0 if {2} is None else {2}.size) # case S160'.format(module_name, parameter['ctypes_type'], corresponding_buffer_parameters[0]['python_name']))
else:
definitions.append(parameter['ctypes_variable_name'] + ' = {0}.{1}(0 if {2} is None else len({2})) # case S160'.format(module_name, parameter['ctypes_type'], corresponding_buffer_parameters[0]['python_name']))
else:
Expand Down
29 changes: 17 additions & 12 deletions build/helper/metadata_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,23 +348,31 @@ def filter_parameters(parameters, parameter_usage_options):
parameters_to_use = []

# Filter based on options
size_parameter = None
ivi_dance_size_parameter = None
len_size_parameter_names = set()
size_twist_parameter = None
# If we are being called looking for the ivi-dance, len or code param, we do not care about the size param so we do
# not call back into ourselves, to avoid infinite recursion
if parameter_usage_options not in [ParameterUsageOptions.IVI_DANCE_PARAMETER, ParameterUsageOptions.LEN_PARAMETER]:
# Find the size parameter - we are assuming there can only be one type, either from ivi-dance or len
size_parameter = find_size_parameter(filter_ivi_dance_parameters(parameters), parameters)
if size_parameter is None:
size_parameter = find_size_parameter(filter_len_parameters(parameters), parameters)
# Determine any size parameters that should be skipped based on the presence of ivi-dance or len-sized buffers.
# For ivi-dance, there is a single shared size parameter; for len, there may be multiple independent size parameters.
ivi_dance_size_parameter = find_size_parameter(filter_ivi_dance_parameters(parameters), parameters)
# Collect all size parameter names referenced by len-sized parameters
len_params = filter_len_parameters(parameters)
for p in len_params:
sp = find_size_parameter(p, parameters)
if sp is not None:
len_size_parameter_names.add(sp['name'])
size_twist_parameter = find_size_parameter(filter_ivi_dance_twist_parameters(parameters), parameters, key='value_twist')
for x in parameters:
skip = False
if x['direction'] == 'out' and options_to_use['skip_output_parameters']:
skip = True
if x['direction'] == 'in' and options_to_use['skip_input_parameters']:
skip = True
if x == size_parameter and options_to_use['skip_size_parameter']:
if ivi_dance_size_parameter is not None and x == ivi_dance_size_parameter and options_to_use['skip_size_parameter']:
skip = True
if len_size_parameter_names and x['name'] in len_size_parameter_names and options_to_use['skip_size_parameter']:
skip = True
if size_twist_parameter is not None and x == size_twist_parameter and options_to_use['skip_size_parameter']:
skip = True
Expand Down Expand Up @@ -443,18 +451,15 @@ def filter_ivi_dance_twist_parameters(parameters):
def filter_len_parameters(parameters):
'''Returns the len parameters of a session method if there are any. These are the parameters whose size is determined at runtime using the value of a different parameter.

asserts all parameters that use len reference the same parameter
Note: Multiple len parameters may reference different size parameters.
Args:
parameters: parameters to be checked

Return:
None if no len parameter found
Parameters dict if one is found
Empty list if no len parameter found
List of parameters if any are found
'''
params = filter_parameters(parameters, ParameterUsageOptions.LEN_PARAMETER)
if len(params) > 0:
size_param = params[0]['size']['value']
assert all(x['size']['value'] == size_param for x in params)
return params


Expand Down
16 changes: 15 additions & 1 deletion build/templates/_grpc_stub_interpreter.py.mako
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@ from . import enums as enums # noqa: F401
from . import errors as errors
from . import ${proto_name}_pb2 as grpc_types
from . import ${proto_name}_pb2_grpc as ${module_name}_grpc
% if 'restricted_proto' in config:
from . import ${config['restricted_proto']}_pb2 as restricted_grpc_types
from . import ${config['restricted_proto']}_pb2_grpc as restricted_grpc
% endif
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 All @@ -35,6 +40,9 @@ class GrpcStubInterpreter(object):
self._grpc_options = grpc_options
self._lock = threading.RLock()
self._client = ${module_name}_grpc.${service_class_prefix}Stub(grpc_options.grpc_channel)
% if 'restricted_proto' in config:
self._restricted_client = restricted_grpc.${service_class_prefix}RestrictedStub(grpc_options.grpc_channel)
% endif
self.set_session_handle()

def set_session_handle(self, value=session_grpc_types.Session()):
Expand Down Expand Up @@ -87,7 +95,13 @@ class GrpcStubInterpreter(object):
% for func_name in sorted(functions):
% for method_template in functions[func_name]['method_templates']:
% if method_template['library_interpreter_filename'] != '/none':
<%include file="${'/_grpc_stub_interpreter.py' + method_template['library_interpreter_filename'] + '.py.mako'}" args="f=functions[func_name], config=config, method_template=method_template" />\
<%
# Determine which grpc types and client to use for this function
f = functions[func_name]
grpc_types_var = 'restricted_grpc_types' if f.get('grpc_type') == 'restricted' else 'grpc_types'
grpc_client_var = 'restricted_grpc' if f.get('grpc_type') == 'restricted' else module_name + '_grpc'
%>
<%include file="${'/_grpc_stub_interpreter.py' + method_template['library_interpreter_filename'] + '.py.mako'}" args="f=f, config=config, method_template=method_template, grpc_types_var=grpc_types_var, grpc_client_var=grpc_client_var" />\
% endif
% endfor
% endfor
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<%page args="f, config, method_template"/>\
<%page args="f, config, method_template, grpc_types_var, grpc_client_var"/>\
<%
'''Renders a GrpcStubInterpreter method corresponding to the passed-in function metadata.'''
import build.helper as helper
Expand All @@ -10,14 +10,15 @@
if return_statement == 'return':
return_statement = None
capture_response = 'response = ' if return_statement else ''
client = 'self._restricted_client' if grpc_client_var == 'restricted_grpc' else 'self._client'
included_in_proto = f.get('included_in_proto', True)
%>\

def ${full_func_name}(${method_decl_params}): # noqa: N802
% if included_in_proto:
${capture_response}self._invoke(
self._client.${grpc_name},
grpc_types.${grpc_name}Request(${grpc_request_args}),
${client}.${grpc_name},
${grpc_types_var}.${grpc_name}Request(${grpc_request_args}),
)
% if return_statement:
${return_statement}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<%page args="f, config, method_template"/>\
<%page args="f, config, method_template, grpc_types_var, grpc_client_var"/>\
<%
'''Renders a GrpcStubInterpreter initialization method, adding proto-specific fields to the passed-in function metadata.'''

Expand Down
2 changes: 1 addition & 1 deletion build/templates/_grpc_stub_interpreter.py/lock.py.mako
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<%page args="f, config, method_template"/>\
<%page args="f, config, method_template, grpc_types_var, grpc_client_var"/>\
<%
import build.helper as helper

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@
%>\

def ${full_func_name}(${method_decl_params}): # noqa: N802
raise NotImplementedError('numpy-specific methods are not supported over gRPC')
raise NotImplementedError('numpy-specific methods are not supported over gRPC')
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<%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" />\
<%include file="/_grpc_stub_interpreter.py/numpy_read_method.py.mako" args="f=f, config=config, method_template=method_template" />\
2 changes: 1 addition & 1 deletion build/templates/_grpc_stub_interpreter.py/unlock.py.mako
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<%page args="f, config, method_template"/>\
<%page args="f, config, method_template, grpc_types_var, grpc_client_var"/>\
<%
import build.helper as helper

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
ivi_dance_parameters = helper.filter_ivi_dance_parameters(parameters)
ivi_dance_size_parameter = helper.find_size_parameter(ivi_dance_parameters, parameters)
len_parameters = helper.filter_len_parameters(parameters)
len_size_parameter = helper.find_size_parameter(len_parameters, parameters)
assert ivi_dance_size_parameter is None or len_size_parameter is None
assert ivi_dance_size_parameter is None or len(len_parameters) == 0

full_func_name = f['interpreter_name'] + method_template['method_python_name_suffix']
c_func_name = config['c_function_prefix'] + f['name']
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
ivi_dance_parameters = helper.filter_ivi_dance_parameters(parameters)
ivi_dance_size_parameter = helper.find_size_parameter(ivi_dance_parameters, parameters)
len_parameters = helper.filter_len_parameters(parameters)
len_size_parameter = helper.find_size_parameter(len_parameters, parameters)
assert ivi_dance_size_parameter is None or len_size_parameter is None
assert ivi_dance_size_parameter is None or len(len_parameters) == 0

full_func_name = f['interpreter_name'] + method_template['method_python_name_suffix']
c_func_name = config['c_function_prefix'] + f['name']
Expand Down
49 changes: 45 additions & 4 deletions docs/nirfsg/class.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Session
=======

.. py:class:: Session(self, resource_name, id_query=False, reset_device=False, options={})
.. py:class:: Session(self, resource_name, id_query=False, reset_device=False, options={}, *, grpc_options=None)



Expand Down Expand Up @@ -111,6 +111,16 @@ Session

:type options: dict

:param grpc_options:


MeasurementLink gRPC session options




:type grpc_options: nirfsg.GrpcSessionOptions


Methods
=======
Expand Down Expand Up @@ -1679,7 +1689,7 @@ get_deembedding_sparameters

.. py:currentmodule:: nirfsg.Session

.. py:method:: get_deembedding_sparameters()
.. py:method:: get_deembedding_sparameters(sparameters_array_size)

Returns the S-parameters used for de-embedding a measurement on the selected port.

Expand All @@ -1695,15 +1705,46 @@ get_deembedding_sparameters



:rtype: numpy.array(dtype=numpy.complex128)
:return:
:param sparameters_array_size:


Specifies the size of the array that is returned by the :py:attr:`nirfsg.Session.SPARAMETERS` output.



.. note:: One or more of the referenced properties are not in the Python API for this driver.


:type sparameters_array_size: int

:rtype: tuple (sparameters, number_of_sparameters, number_of_ports)

WHERE

sparameters (numpy.array(dtype=numpy.complex128)):


Returns an array of S-parameters. The S-parameters are returned in the following order: s11, s12, s21, s22.




number_of_sparameters (int):


Returns the number of S-parameters.




number_of_ports (int):


Returns the number of S-parameter ports. The **sparameter** array is always *n* x *n*, where span *n* is the number of ports.





get_error
---------
Expand Down
10 changes: 10 additions & 0 deletions docs/nirfsg/errors.rst
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,16 @@ SelfTestError
An error due to a failed self-test


RpcError
--------

.. py:currentmodule:: nirfsg.errors

.. exception:: RpcError

An error specific to sessions to the NI gRPC Device Server


DriverWarning
-------------

Expand Down
91 changes: 91 additions & 0 deletions docs/nirfsg/grpc_session_options.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
gRPC Support
============

Support for using NI-RFSG over gRPC

.. py:currentmodule:: nirfsg



SessionInitializationBehavior
-----------------------------

.. py:class:: SessionInitializationBehavior

.. py:attribute:: SessionInitializationBehavior.AUTO


The NI gRPC Device Server will attach to an existing session with the specified name if it exists,
otherwise the server will initialize a new session.

.. note:: When using the Session as a context manager and the context exits, the behavior depends on what happened when the constructor
was called. If it resulted in a new session being initialized on the NI gRPC Device Server, then it will automatically close the
server session. If it instead attached to an existing session, then it will detach from the server session and leave it open.


.. py:attribute:: SessionInitializationBehavior.INITIALIZE_SERVER_SESSION


Require the NI gRPC Device Server to initialize a new session with the specified name.

.. note:: When using the Session as a context manager and the context exits, it will automatically close the
server session.


.. py:attribute:: SessionInitializationBehavior.ATTACH_TO_SERVER_SESSION


Require the NI gRPC Device Server to attach to an existing session with the specified name.

.. note:: When using the Session as a context manager and the context exits, it will detach from the server session
and leave it open.



GrpcSessionOptions
------------------


.. py:class:: GrpcSessionOptions(self, grpc_channel, session_name, initialization_behavior=SessionInitializationBehavior.AUTO)


Collection of options that specifies session behaviors related to gRPC.

Creates and returns an object you can pass to a Session constructor.


:param grpc_channel:


Specifies the channel to the NI gRPC Device Server.



:type grpc_channel: grpc.Channel


:param session_name:


User-specified name that identifies the driver session on the NI gRPC Device Server.

This is different from the resource name parameter many APIs take as a separate
parameter. Specifying a name makes it easy to share sessions across multiple gRPC clients.
You can use an empty string if you want to always initialize a new session on the server.
To attach to an existing session, you must specify the session name it was initialized with.



:type session_name: str


:param initialization_behavior:


Specifies whether it is acceptable to initialize a new session or attach to an existing one, or if only one of the behaviors is desired.

The driver session exists on the NI gRPC Device Server.



:type initialization_behavior: :py:data:`nirfsg.SessionInitializationBehavior`
1 change: 1 addition & 0 deletions docs/nirfsg/toc.inc
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ API Reference
enums
errors
examples
grpc_session_options

Loading