Skip to content

Commit

Permalink
Add Offset Nulling Calibration API support for nidaqmx-python
Browse files Browse the repository at this point in the history
  • Loading branch information
Deborah Ooi Yee Hui committed Jan 5, 2024
1 parent eca4e38 commit be865e9
Show file tree
Hide file tree
Showing 8 changed files with 281 additions and 0 deletions.
14 changes: 14 additions & 0 deletions generated/nidaqmx/_base_interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -1140,6 +1140,20 @@ def is_task_done(self, task):
def load_task(self, session_name):
raise NotImplementedError

@abc.abstractmethod
def perform_bridge_offset_nulling_cal(self, task, channel):
raise NotImplementedError

@abc.abstractmethod
def perform_bridge_offset_nulling_cal_ex(
self, task, channel, skip_unsupported_channels):
raise NotImplementedError

@abc.abstractmethod
def perform_thrmcpl_lead_offset_nulling_cal(
self, task, channel, skip_unsupported_channels):
raise NotImplementedError

@abc.abstractmethod
def read_analog_f64(
self, task, num_samps_per_chan, timeout, fill_mode, read_array):
Expand Down
21 changes: 21 additions & 0 deletions generated/nidaqmx/_grpc_interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2260,6 +2260,27 @@ def load_task(self, session_name):
metadata=metadata)
return response.task, response.new_session_initialized

def perform_bridge_offset_nulling_cal(self, task, channel):
response = self._invoke(
self._client.PerformBridgeOffsetNullingCal,
grpc_types.PerformBridgeOffsetNullingCalRequest(task=task, channel=channel))

def perform_bridge_offset_nulling_cal_ex(
self, task, channel, skip_unsupported_channels):
response = self._invoke(
self._client.PerformBridgeOffsetNullingCalEx,
grpc_types.PerformBridgeOffsetNullingCalExRequest(
task=task, channel=channel,
skip_unsupported_channels=skip_unsupported_channels))

def perform_thrmcpl_lead_offset_nulling_cal(
self, task, channel, skip_unsupported_channels):
response = self._invoke(
self._client.PerformThrmcplLeadOffsetNullingCal,
grpc_types.PerformThrmcplLeadOffsetNullingCalRequest(
task=task, channel=channel,
skip_unsupported_channels=skip_unsupported_channels))

def read_analog_f64(
self, task, num_samps_per_chan, timeout, fill_mode, read_array):
_validate_array_dtype(read_array, numpy.float64)
Expand Down
40 changes: 40 additions & 0 deletions generated/nidaqmx/_library_interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -3877,6 +3877,46 @@ def load_task(self, session_name):
self.check_for_error(error_code)
return task, new_session_initialized

def perform_bridge_offset_nulling_cal(self, task, channel):
cfunc = lib_importer.windll.DAQmxPerformBridgeOffsetNullingCal
if cfunc.argtypes is None:
with cfunc.arglock:
if cfunc.argtypes is None:
cfunc.argtypes = [
lib_importer.task_handle, ctypes_byte_str]

error_code = cfunc(
task, channel)
self.check_for_error(error_code)

def perform_bridge_offset_nulling_cal_ex(
self, task, channel, skip_unsupported_channels):
cfunc = lib_importer.windll.DAQmxPerformBridgeOffsetNullingCalEx
if cfunc.argtypes is None:
with cfunc.arglock:
if cfunc.argtypes is None:
cfunc.argtypes = [
lib_importer.task_handle, ctypes_byte_str,
ctypes.c_uint32]

error_code = cfunc(
task, channel, skip_unsupported_channels)
self.check_for_error(error_code)

def perform_thrmcpl_lead_offset_nulling_cal(
self, task, channel, skip_unsupported_channels):
cfunc = lib_importer.windll.DAQmxPerformThrmcplLeadOffsetNullingCal
if cfunc.argtypes is None:
with cfunc.arglock:
if cfunc.argtypes is None:
cfunc.argtypes = [
lib_importer.task_handle, ctypes_byte_str,
ctypes.c_uint32]

error_code = cfunc(
task, channel, skip_unsupported_channels)
self.check_for_error(error_code)

def read_analog_f64(
self, task, num_samps_per_chan, timeout, fill_mode, read_array):
samps_per_chan_read = ctypes.c_int()
Expand Down
33 changes: 33 additions & 0 deletions generated/nidaqmx/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,39 @@ def is_task_done(self):

return is_task_done

def perform_bridge_offset_nulling_cal(self, channel=""):
"""
Performs a bridge offset nulling calibration on the channels in the task.
If the task measures both bridge-based sensors and non-bridge-based sensors,
use the channels input to specify the names of the channels that measure
bridge-based sensors.
"""

self._interpreter.perform_bridge_offset_nulling_cal(
self._handle, channel)

def perform_bridge_offset_nulling_cal_ex(self, channel="", skip_unsupported_channels=False):
"""
Performs a bridge offset nulling calibration on the channels in the task.
If the task measures both bridge-based sensors and non-bridge-based sensors,
use the channels input to specify the names of the channels that measure
bridge-based sensors.
"""

self._interpreter.perform_bridge_offset_nulling_cal_ex(
self._handle, channel, skip_unsupported_channels)

def perform_thrmcpl_lead_offset_nulling_cal(self, channel="", skip_unsupported_channels=False):
"""
Performs thermocouple lead offset nulling calibration on the channels in
the task to compensate for offsets introduced by open thermocouple detection.
Keep the measured temperature as constant as possible while performing this
adjustment.
"""

self._interpreter.perform_thrmcpl_lead_offset_nulling_cal(
self._handle, channel, skip_unsupported_channels)

def read(self, number_of_samples_per_channel=NUM_SAMPLES_UNSET,
timeout=10.0):
"""
Expand Down
106 changes: 106 additions & 0 deletions src/codegen/metadata/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -20150,6 +20150,112 @@
'python_description': 'Measures the onboard reference voltage of the device and adjusts the self-calibration constants to account for any errors caused by short-term fluctuations in the operating environment. When you self-calibrate a device, no external signal connections are necessary.',
'returns': 'int32'
},
'PerformBridgeOffsetNullingCal': {
'calling_convention': 'StdCall',
'handle_parameter': {
'ctypes_data_type': 'lib_importer.task_handle',
'cvi_name': 'taskHandle',
'python_accessor': 'self._handle'
},
'parameters': [
{
'ctypes_data_type': 'ctypes.TaskHandle',
'direction': 'in',
'is_optional_in_python': False,
'name': 'task',
'python_data_type': 'TaskHandle',
'type': 'TaskHandle'
},
{
'ctypes_data_type': 'ctypes.c_char_p',
'direction': 'in',
'is_optional_in_python': True,
'name': 'channel',
'python_data_type': 'str',
'type': 'const char[]'
}
],
'python_class_name': 'Task',
'python_codegen_method': 'CustomCode',
'python_description': 'Performs a bridge offset nulling calibration on the channels in the task. If the task measures both bridge-based sensors and non-bridge-based sensors, use the channels input to specify the names of the channels that measure bridge-based sensors.',
'returns': 'int32'
},
'PerformBridgeOffsetNullingCalEx': {
'calling_convention': 'StdCall',
'handle_parameter': {
'ctypes_data_type': 'lib_importer.task_handle',
'cvi_name': 'taskHandle',
'python_accessor': 'self._handle'
},
'parameters': [
{
'ctypes_data_type': 'ctypes.TaskHandle',
'direction': 'in',
'is_optional_in_python': False,
'name': 'task',
'python_data_type': 'TaskHandle',
'type': 'TaskHandle'
},
{
'ctypes_data_type': 'ctypes.c_char_p',
'direction': 'in',
'is_optional_in_python': True,
'name': 'channel',
'python_data_type': 'str',
'type': 'const char[]'
},
{
'ctypes_data_type': 'ctypes.c_uint32',
'direction': 'in',
'is_optional_in_python': True,
'name': 'skipUnsupportedChannels',
'python_data_type': 'int',
'type': 'uInt32'
},
],
'python_class_name': 'Task',
'python_codegen_method': 'CustomCode',
'python_description': 'Performs a bridge offset nulling calibration on the channels in the task. If the task measures both bridge-based sensors and non-bridge-based sensors, use the channels input to specify the names of the channels that measure bridge-based sensors.',
'returns': 'int32'
},
'PerformThrmcplLeadOffsetNullingCal': {
'calling_convention': 'StdCall',
'handle_parameter': {
'ctypes_data_type': 'lib_importer.task_handle',
'cvi_name': 'taskHandle',
'python_accessor': 'self._handle'
},
'parameters': [
{
'ctypes_data_type': 'ctypes.TaskHandle',
'direction': 'in',
'is_optional_in_python': False,
'name': 'task',
'python_data_type': 'TaskHandle',
'type': 'TaskHandle'
},
{
'ctypes_data_type': 'ctypes.c_char_p',
'direction': 'in',
'is_optional_in_python': True,
'name': 'channel',
'python_data_type': 'str',
'type': 'const char[]'
},
{
'ctypes_data_type': 'ctypes.c_uint32',
'direction': 'in',
'is_optional_in_python': True,
'name': 'skipUnsupportedChannels',
'python_data_type': 'int',
'type': 'uInt32'
},
],
'python_class_name': 'Task',
'python_codegen_method': 'CustomCode',
'python_description': 'Performs thermocouple lead offset nulling calibration on the channels in the task to compensate for offsets introduced by open thermocouple detection. Keep the measured temperature as constant as possible while performing this adjustment.',
'returns': 'int32'
},
'SelfTestDevice': {
'calling_convention': 'StdCall',
'handle_parameter': {
Expand Down
33 changes: 33 additions & 0 deletions src/handwritten/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,39 @@ def is_task_done(self):

return is_task_done

def perform_bridge_offset_nulling_cal(self, channel=""):
"""
Performs a bridge offset nulling calibration on the channels in the task.
If the task measures both bridge-based sensors and non-bridge-based sensors,
use the channels input to specify the names of the channels that measure
bridge-based sensors.
"""

self._interpreter.perform_bridge_offset_nulling_cal(
self._handle, channel)

def perform_bridge_offset_nulling_cal_ex(self, channel="", skip_unsupported_channels=False):
"""
Performs a bridge offset nulling calibration on the channels in the task.
If the task measures both bridge-based sensors and non-bridge-based sensors,
use the channels input to specify the names of the channels that measure
bridge-based sensors.
"""

self._interpreter.perform_bridge_offset_nulling_cal_ex(
self._handle, channel, skip_unsupported_channels)

def perform_thrmcpl_lead_offset_nulling_cal(self, channel="", skip_unsupported_channels=False):
"""
Performs thermocouple lead offset nulling calibration on the channels in
the task to compensate for offsets introduced by open thermocouple detection.
Keep the measured temperature as constant as possible while performing this
adjustment.
"""

self._interpreter.perform_thrmcpl_lead_offset_nulling_cal(
self._handle, channel, skip_unsupported_channels)

def read(self, number_of_samples_per_channel=NUM_SAMPLES_UNSET,
timeout=10.0):
"""
Expand Down
27 changes: 27 additions & 0 deletions tests/component/test_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@
import nidaqmx
from nidaqmx.error_codes import DAQmxErrors

@pytest.fixture
def ai_bridge_task(task: nidaqmx.Task, device) -> nidaqmx.Task:
task.ai_channels.add_ai_bridge_chan(device.ai_physical_chans[0].name)
return task

@pytest.fixture
def ai_thermocouple_task(task: nidaqmx.Task, device) -> nidaqmx.Task:
task.ai_channels.add_ai_thrmcpl_chan(device.ai_physical_chans[0].name)
return task

@pytest.mark.library_only(reason="Default gRPC initialization behavior is auto (create or attach)")
def test___task___create_task_with_same_name___raises_duplicate_task(init_kwargs):
Expand All @@ -26,3 +35,21 @@ def test___tasks_with_different_names___hash___not_equal(generate_task):
task2 = generate_task("MyTask2")

assert hash(task1) != hash(task2)

@pytest.mark.device_name("bridgeTester")
def test___perform_bridge_offset_nulling_cal___no_errors(ai_bridge_task: nidaqmx.Task) -> None:
ai_bridge_task.perform_bridge_offset_nulling_cal(ai_bridge_task.channels.name)

@pytest.mark.device_name("bridgeTester")
@pytest.mark.parametrize(
'skip_unsupported_channels',[True, False]
)
def test___perform_bridge_offset_nulling_cal_ex___no_errors(ai_bridge_task: nidaqmx.Task, skip_unsupported_channels) -> None:
ai_bridge_task.perform_bridge_offset_nulling_cal_ex(ai_bridge_task.channels.name, skip_unsupported_channels)

@pytest.mark.device_name("cDAQ1Mod2")
@pytest.mark.parametrize(
'skip_unsupported_channels',[True, False]
)
def test___perform_thrmcpl_lead_offset_nulling_cal___no_errors(ai_thermocouple_task: nidaqmx.Task, skip_unsupported_channels) -> None:
ai_thermocouple_task.perform_thrmcpl_lead_offset_nulling_cal(ai_thermocouple_task.channels.name, skip_unsupported_channels)
7 changes: 7 additions & 0 deletions tests/max_config/examplesMaxConfig.ini
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ DevIsSimulated = 1
CompactDAQ.ChassisDevName = cDAQ1
CompactDAQ.SlotNum = 1

[DAQmxCDAQModule cDAQ1Mod2]
ProductType = NI 9214
DevSerialNum = 0x0
DevIsSimulated = 1
CompactDAQ.ChassisDevName = cDAQ1
CompactDAQ.SlotNum = 2

[DAQmxDevice Dev1]
ProductType = PCIe-6363
DevSerialNum = 0x0
Expand Down

0 comments on commit be865e9

Please sign in to comment.