diff --git a/CHANGELOG.md b/CHANGELOG.md index 58a831f0..a7baca9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,7 +21,7 @@ All notable changes to this project will be documented in this file. * ### Merged Pull Requests * ... * ### Resolved Issues - * ... + * [194: Multiple Voltage Measurement Types in the same task causes errors on Read](https://github.com/ni/nidaqmx-python/pull/194) * ### Major Changes * ... diff --git a/nidaqmx/task.py b/nidaqmx/task.py index 4f301287..f57d8a4c 100644 --- a/nidaqmx/task.py +++ b/nidaqmx/task.py @@ -620,8 +620,14 @@ def read(self, number_of_samples_per_channel=NUM_SAMPLES_UNSET, # Analog Input if read_chan_type == ChannelType.ANALOG_INPUT: - meas_type = channels_to_read.ai_meas_type - if meas_type == UsageTypeAI.POWER: + has_power_chan = False + for chan in channels_to_read: + meas_type = chan.ai_meas_type + has_power_chan = meas_type == UsageTypeAI.POWER + if has_power_chan: + break + + if has_power_chan: voltages = numpy.zeros(array_shape, dtype=numpy.float64) currents = numpy.zeros(array_shape, dtype=numpy.float64) diff --git a/nidaqmx/tests/fixtures.py b/nidaqmx/tests/fixtures.py index 5f6b9bf8..8f8c5fc6 100644 --- a/nidaqmx/tests/fixtures.py +++ b/nidaqmx/tests/fixtures.py @@ -78,15 +78,15 @@ def bridge_device(): @pytest.fixture(scope="module") -def sim_power_device(): +def sim_ts_power_device(): system = nidaqmx.system.System.local() for device in system.devices: - if device.dev_is_simulated and UsageTypeAI.POWER in device.ai_meas_types: + if device.dev_is_simulated and device.product_category == ProductCategory.TEST_SCALE_MODULE and UsageTypeAI.POWER in device.ai_meas_types: return device pytest.skip( - "Could not detect a device that meets the requirements to be a simulated power device. " + "Could not detect a device that meets the requirements to be a TestScale simulated power device. " "Cannot proceed to run tests. Import the NI MAX configuration file located at " "nidaqmx\\tests\\max_config\\nidaqmxMaxConfig.ini to create these devices." ) @@ -94,18 +94,34 @@ def sim_power_device(): @pytest.fixture(scope="module") -def sim_power_devices(): +def sim_ts_voltage_device(): + system = nidaqmx.system.System.local() + + for device in system.devices: + if device.dev_is_simulated and device.product_category == ProductCategory.TEST_SCALE_MODULE and UsageTypeAI.VOLTAGE in device.ai_meas_types: + return device + + pytest.skip( + "Could not detect a device that meets the requirements to be a TestScale simulated voltage device. " + "Cannot proceed to run tests. Import the NI MAX configuration file located at " + "nidaqmx\\tests\\max_config\\nidaqmxMaxConfig.ini to create these devices." + ) + return None + + +@pytest.fixture(scope="module") +def sim_ts_power_devices(): system = nidaqmx.system.System.local() devices = [] for device in system.devices: - if device.dev_is_simulated and UsageTypeAI.POWER in device.ai_meas_types: + if device.dev_is_simulated and device.product_category == ProductCategory.TEST_SCALE_MODULE and UsageTypeAI.POWER in device.ai_meas_types: devices.append(device) if len(devices) == 2: return devices pytest.skip( - "Could not detect two or more devices that meets the requirements to be a simulated power " + "Could not detect two or more devices that meets the requirements to be a TestScale simulated power " "device. Cannot proceed to run tests. Import the NI MAX configuration file located at " "nidaqmx\\tests\\max_config\\nidaqmxMaxConfig.ini to create these devices." ) diff --git a/nidaqmx/tests/max_config/nidaqmxMaxConfig.ini b/nidaqmx/tests/max_config/nidaqmxMaxConfig.ini index b8e850c7..7c687ee1 100644 --- a/nidaqmx/tests/max_config/nidaqmxMaxConfig.ini +++ b/nidaqmx/tests/max_config/nidaqmxMaxConfig.ini @@ -87,3 +87,10 @@ DevIsSimulated = 1 CompactDAQ.ChassisDevName = tsChassisTester CompactDAQ.SlotNum = 2 +[DAQmxCDAQModule tsVoltageTester1] +ProductType = TS-15100 +DevSerialNum = 0x0 +DevIsSimulated = 1 +CompactDAQ.ChassisDevName = tsChassisTester +CompactDAQ.SlotNum = 3 + diff --git a/nidaqmx/tests/test_channel_creation.py b/nidaqmx/tests/test_channel_creation.py index 3af4440a..9c9c69b5 100644 --- a/nidaqmx/tests/test_channel_creation.py +++ b/nidaqmx/tests/test_channel_creation.py @@ -9,7 +9,7 @@ CurrentShuntResistorLocation, TemperatureUnits, RTDType, ResistanceConfiguration, ExcitationSource, ResistanceUnits, StrainUnits, StrainGageBridgeType, BridgeConfiguration) -from nidaqmx.tests.fixtures import sim_power_device, any_x_series_device +from nidaqmx.tests.fixtures import sim_ts_power_device, any_x_series_device from nidaqmx.tests.helpers import generate_random_seed @@ -268,11 +268,11 @@ def test_create_ai_voltage_chan_with_excit(self, any_x_series_device, seed): assert not ai_channel.ai_excit_use_for_scaling @pytest.mark.parametrize('seed', [generate_random_seed()]) - def test_create_ai_power_chan(self, sim_power_device, seed): + def test_create_ai_power_chan(self, sim_ts_power_device, seed): # Reset the pseudorandom number generator with seed. random.seed(seed) - pwr_phys_chan = f"{sim_power_device.name}/power" + pwr_phys_chan = f"{sim_ts_power_device.name}/power" voltage_setpoint = random.random() * 6.0 current_setpoint = random.random() * 3.0 output_enable = random.choice([True, False]) diff --git a/nidaqmx/tests/test_read_write.py b/nidaqmx/tests/test_read_write.py index 33757bef..dbe2d0fd 100644 --- a/nidaqmx/tests/test_read_write.py +++ b/nidaqmx/tests/test_read_write.py @@ -11,7 +11,7 @@ from nidaqmx.constants import ( Edge, TriggerType, AcquisitionType, LineGrouping, Level, TaskMode) from nidaqmx.utils import flatten_channel_string -from nidaqmx.tests.fixtures import sim_power_device, sim_power_devices, real_x_series_device +from nidaqmx.tests.fixtures import sim_ts_power_device, sim_ts_power_devices, sim_ts_voltage_device, sim_x_series_device, real_x_series_device from nidaqmx.tests.helpers import generate_random_seed, POWER_ABS_EPSILON @@ -613,7 +613,7 @@ class TestPowerRead(TestDAQmxIOBase): (generate_random_seed(), False) ] ) - def test_power_1_chan_1_samp(self, sim_power_device, seed, output_enable): + def test_power_1_chan_1_samp(self, sim_ts_power_device, seed, output_enable): # Reset the pseudorandom number generator with seed. random.seed(seed) @@ -622,7 +622,7 @@ def test_power_1_chan_1_samp(self, sim_power_device, seed, output_enable): with nidaqmx.Task() as read_task: read_task.ai_channels.add_ai_power_chan( - f"{sim_power_device.name}/power", + f"{sim_ts_power_device.name}/power", voltage_setpoint, current_setpoint, output_enable) read_task.start() @@ -644,7 +644,7 @@ def test_power_1_chan_1_samp(self, sim_power_device, seed, output_enable): (generate_random_seed(), [False, False]) ] ) - def test_power_n_chan_1_samp(self, sim_power_devices, seed, output_enables): + def test_power_n_chan_1_samp(self, sim_ts_power_devices, seed, output_enables): # Reset the pseudorandom number generator with seed. random.seed(seed) @@ -652,7 +652,7 @@ def test_power_n_chan_1_samp(self, sim_power_devices, seed, output_enables): current_setpoint = 0.03 with nidaqmx.Task() as read_task: - for device, output_enable in zip(sim_power_devices, output_enables): + for device, output_enable in zip(sim_ts_power_devices, output_enables): read_task.ai_channels.add_ai_power_chan( f"{device.name}/power", voltage_setpoint, current_setpoint, output_enable) @@ -675,7 +675,7 @@ def test_power_n_chan_1_samp(self, sim_power_devices, seed, output_enables): (generate_random_seed(), False) ] ) - def test_power_1_chan_n_samp(self, sim_power_device, seed, output_enable): + def test_power_1_chan_n_samp(self, sim_ts_power_device, seed, output_enable): # Reset the pseudorandom number generator with seed. random.seed(seed) @@ -684,7 +684,7 @@ def test_power_1_chan_n_samp(self, sim_power_device, seed, output_enable): with nidaqmx.Task() as read_task: read_task.ai_channels.add_ai_power_chan( - f"{sim_power_device.name}/power", + f"{sim_ts_power_device.name}/power", voltage_setpoint, current_setpoint, output_enable) read_task.start() @@ -706,7 +706,7 @@ def test_power_1_chan_n_samp(self, sim_power_device, seed, output_enable): (generate_random_seed(), [False, False]) ] ) - def test_power_n_chan_n_samp(self, sim_power_devices, seed, output_enables): + def test_power_n_chan_n_samp(self, sim_ts_power_devices, seed, output_enables): # Reset the pseudorandom number generator with seed. random.seed(seed) @@ -714,7 +714,7 @@ def test_power_n_chan_n_samp(self, sim_power_devices, seed, output_enables): current_setpoint = 0.03 with nidaqmx.Task() as read_task: - for device, output_enable in zip(sim_power_devices, output_enables): + for device, output_enable in zip(sim_ts_power_devices, output_enables): read_task.ai_channels.add_ai_power_chan( f"{device.name}/power", voltage_setpoint, current_setpoint, output_enable) @@ -731,3 +731,40 @@ def test_power_n_chan_n_samp(self, sim_power_devices, seed, output_enables): else: assert all(math.isnan(sample.voltage) for sample in channel_values) assert all(math.isnan(sample.current) for sample in channel_values) + + @pytest.mark.parametrize('seed', [generate_random_seed()]) + def test_mixed_chans(self, sim_x_series_device, seed): + # Reset the pseudorandom number generator with seed. + random.seed(seed) + + with nidaqmx.Task() as read_task: + read_task.ai_channels.add_ai_voltage_chan( + f"{sim_x_series_device.name}/ai0", max_val=10, min_val=-10) + read_task.ai_channels.add_ai_current_chan( + f"{sim_x_series_device.name}/ai1", max_val=0.01, min_val=-0.01) + + read_task.start() + # We aren't validating data, just assuring that it doesn't fail. + values_read = read_task.read(number_of_samples_per_channel=10) + + @pytest.mark.parametrize('seed', [generate_random_seed()]) + def test_mixed_chans_with_power(self, sim_ts_power_device, sim_ts_voltage_device, seed): + # Reset the pseudorandom number generator with seed. + random.seed(seed) + + voltage_setpoint = 0.0 + current_setpoint = 0.03 + output_enable = False + + with nidaqmx.Task() as read_task: + read_task.ai_channels.add_ai_power_chan( + f"{sim_ts_power_device.name}/power", + voltage_setpoint, current_setpoint, output_enable) + read_task.ai_channels.add_ai_voltage_chan( + f"{sim_ts_voltage_device.name}/ai0", max_val=10, min_val=-10) + + read_task.start() + # We aren't validating data, just assuring that it fails. The error + # code is currently not very good, so we'll ignore that for now. + with pytest.raises(nidaqmx.errors.DaqReadError): + values_read = read_task.read(number_of_samples_per_channel=10) diff --git a/nidaqmx/tests/test_stream_power_readers.py b/nidaqmx/tests/test_stream_power_readers.py index 20662229..eca3db43 100644 --- a/nidaqmx/tests/test_stream_power_readers.py +++ b/nidaqmx/tests/test_stream_power_readers.py @@ -10,7 +10,7 @@ import nidaqmx from nidaqmx.stream_readers import ( PowerSingleChannelReader, PowerMultiChannelReader, PowerBinaryReader) -from nidaqmx.tests.fixtures import sim_power_device, sim_power_devices +from nidaqmx.tests.fixtures import sim_ts_power_device, sim_ts_power_devices from nidaqmx.tests.helpers import generate_random_seed, POWER_ABS_EPSILON from nidaqmx.tests.test_read_write import TestDAQmxIOBase @@ -31,7 +31,7 @@ class TestPowerSingleChannelReader(TestDAQmxIOBase): (generate_random_seed(), False) ] ) - def test_power_1_chan_1_samp(self, sim_power_device, seed, output_enable): + def test_power_1_chan_1_samp(self, sim_ts_power_device, seed, output_enable): # Reset the pseudorandom number generator with seed. random.seed(seed) @@ -40,7 +40,7 @@ def test_power_1_chan_1_samp(self, sim_power_device, seed, output_enable): with nidaqmx.Task() as read_task: read_task.ai_channels.add_ai_power_chan( - f"{sim_power_device.name}/power", + f"{sim_ts_power_device.name}/power", voltage_setpoint, current_setpoint, output_enable) reader = PowerSingleChannelReader(read_task.in_stream) @@ -62,7 +62,7 @@ def test_power_1_chan_1_samp(self, sim_power_device, seed, output_enable): (generate_random_seed(), False) ] ) - def test_power_1_chan_n_samp(self, sim_power_device, seed, output_enable): + def test_power_1_chan_n_samp(self, sim_ts_power_device, seed, output_enable): # Reset the pseudorandom number generator with seed. random.seed(seed) @@ -76,7 +76,7 @@ def test_power_1_chan_n_samp(self, sim_power_device, seed, output_enable): with nidaqmx.Task() as read_task: read_task.ai_channels.add_ai_power_chan( - f"{sim_power_device.name}/power", + f"{sim_ts_power_device.name}/power", voltage_setpoint, current_setpoint, output_enable) reader = PowerSingleChannelReader(read_task.in_stream) @@ -111,7 +111,7 @@ class TestPowerMultiChannelReader(TestDAQmxIOBase): (generate_random_seed(), [False, False]) ] ) - def test_power_n_chan_1_samp(self, sim_power_devices, seed, output_enables): + def test_power_n_chan_1_samp(self, sim_ts_power_devices, seed, output_enables): # Reset the pseudorandom number generator with seed. random.seed(seed) @@ -119,11 +119,11 @@ def test_power_n_chan_1_samp(self, sim_power_devices, seed, output_enables): current_setpoint = 0.03 # Fill with bad data to ensure its overwritten by read. - voltage_data = numpy.full(len(sim_power_devices), -1.0, dtype=numpy.float64) - current_data = numpy.full(len(sim_power_devices), -1.0, dtype=numpy.float64) + voltage_data = numpy.full(len(sim_ts_power_devices), -1.0, dtype=numpy.float64) + current_data = numpy.full(len(sim_ts_power_devices), -1.0, dtype=numpy.float64) with nidaqmx.Task() as read_task: - for device, output_enable in zip(sim_power_devices, output_enables): + for device, output_enable in zip(sim_ts_power_devices, output_enables): read_task.ai_channels.add_ai_power_chan( f"{device.name}/power", voltage_setpoint, current_setpoint, output_enable) @@ -150,7 +150,7 @@ def test_power_n_chan_1_samp(self, sim_power_devices, seed, output_enables): (generate_random_seed(), [False, False]) ] ) - def test_power_n_chan_n_samp(self, sim_power_devices, seed, output_enables): + def test_power_n_chan_n_samp(self, sim_ts_power_devices, seed, output_enables): # Reset the pseudorandom number generator with seed. random.seed(seed) @@ -159,11 +159,11 @@ def test_power_n_chan_n_samp(self, sim_power_devices, seed, output_enables): number_of_samples_per_channel = 10 # Fill with bad data to ensure its overwritten by read. - voltage_data = numpy.full((len(sim_power_devices), number_of_samples_per_channel), -1.0, dtype=numpy.float64) - current_data = numpy.full((len(sim_power_devices), number_of_samples_per_channel), -1.0, dtype=numpy.float64) + voltage_data = numpy.full((len(sim_ts_power_devices), number_of_samples_per_channel), -1.0, dtype=numpy.float64) + current_data = numpy.full((len(sim_ts_power_devices), number_of_samples_per_channel), -1.0, dtype=numpy.float64) with nidaqmx.Task() as read_task: - for device, output_enable in zip(sim_power_devices, output_enables): + for device, output_enable in zip(sim_ts_power_devices, output_enables): read_task.ai_channels.add_ai_power_chan( f"{device.name}/power", voltage_setpoint, current_setpoint, output_enable) @@ -203,7 +203,7 @@ class TestPowerBinaryReader(TestDAQmxIOBase): (generate_random_seed(), False) ] ) - def test_power_1_chan_n_samp_binary(self, sim_power_device, seed, output_enable): + def test_power_1_chan_n_samp_binary(self, sim_ts_power_device, seed, output_enable): # Reset the pseudorandom number generator with seed. random.seed(seed) @@ -217,7 +217,7 @@ def test_power_1_chan_n_samp_binary(self, sim_power_device, seed, output_enable) with nidaqmx.Task() as read_task: read_task.ai_channels.add_ai_power_chan( - f"{sim_power_device.name}/power", + f"{sim_ts_power_device.name}/power", voltage_setpoint, current_setpoint, output_enable) reader = PowerBinaryReader(read_task.in_stream) @@ -247,7 +247,7 @@ def test_power_1_chan_n_samp_binary(self, sim_power_device, seed, output_enable) (generate_random_seed(), [False, False]) ] ) - def test_power_n_chan_many_sample_binary(self, sim_power_devices, seed, output_enables): + def test_power_n_chan_many_sample_binary(self, sim_ts_power_devices, seed, output_enables): # Reset the pseudorandom number generator with seed. random.seed(seed) @@ -256,11 +256,11 @@ def test_power_n_chan_many_sample_binary(self, sim_power_devices, seed, output_e number_of_samples_per_channel = 10 # Fill with bad data to ensure its overwritten by read. - voltage_data = numpy.full((len(sim_power_devices), number_of_samples_per_channel), -32768, dtype=numpy.int16) - current_data = numpy.full((len(sim_power_devices), number_of_samples_per_channel), -32768, dtype=numpy.int16) + voltage_data = numpy.full((len(sim_ts_power_devices), number_of_samples_per_channel), -32768, dtype=numpy.int16) + current_data = numpy.full((len(sim_ts_power_devices), number_of_samples_per_channel), -32768, dtype=numpy.int16) with nidaqmx.Task() as read_task: - for device, output_enable in zip(sim_power_devices, output_enables): + for device, output_enable in zip(sim_ts_power_devices, output_enables): read_task.ai_channels.add_ai_power_chan( f"{device.name}/power", voltage_setpoint, current_setpoint, output_enable)