Skip to content

Commit 1b79dde

Browse files
authored
fix read issue with multiple channel types in a single task (#196)
* fix read issue with multiple channel types in a single task * update changelog * updated issue name * remove duplicated test
1 parent e4afcf4 commit 1b79dde

File tree

7 files changed

+106
-40
lines changed

7 files changed

+106
-40
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ All notable changes to this project will be documented in this file.
2121
* ### Merged Pull Requests
2222
* ...
2323
* ### Resolved Issues
24-
* ...
24+
* [194: Multiple Voltage Measurement Types in the same task causes errors on Read](https://github.com/ni/nidaqmx-python/pull/194)
2525
* ### Major Changes
2626
* ...
2727

nidaqmx/task.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -620,8 +620,14 @@ def read(self, number_of_samples_per_channel=NUM_SAMPLES_UNSET,
620620

621621
# Analog Input
622622
if read_chan_type == ChannelType.ANALOG_INPUT:
623-
meas_type = channels_to_read.ai_meas_type
624-
if meas_type == UsageTypeAI.POWER:
623+
has_power_chan = False
624+
for chan in channels_to_read:
625+
meas_type = chan.ai_meas_type
626+
has_power_chan = meas_type == UsageTypeAI.POWER
627+
if has_power_chan:
628+
break
629+
630+
if has_power_chan:
625631
voltages = numpy.zeros(array_shape, dtype=numpy.float64)
626632
currents = numpy.zeros(array_shape, dtype=numpy.float64)
627633

nidaqmx/tests/fixtures.py

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,34 +78,50 @@ def bridge_device():
7878

7979

8080
@pytest.fixture(scope="module")
81-
def sim_power_device():
81+
def sim_ts_power_device():
8282
system = nidaqmx.system.System.local()
8383

8484
for device in system.devices:
85-
if device.dev_is_simulated and UsageTypeAI.POWER in device.ai_meas_types:
85+
if device.dev_is_simulated and device.product_category == ProductCategory.TEST_SCALE_MODULE and UsageTypeAI.POWER in device.ai_meas_types:
8686
return device
8787

8888
pytest.skip(
89-
"Could not detect a device that meets the requirements to be a simulated power device. "
89+
"Could not detect a device that meets the requirements to be a TestScale simulated power device. "
9090
"Cannot proceed to run tests. Import the NI MAX configuration file located at "
9191
"nidaqmx\\tests\\max_config\\nidaqmxMaxConfig.ini to create these devices."
9292
)
9393
return None
9494

9595

9696
@pytest.fixture(scope="module")
97-
def sim_power_devices():
97+
def sim_ts_voltage_device():
98+
system = nidaqmx.system.System.local()
99+
100+
for device in system.devices:
101+
if device.dev_is_simulated and device.product_category == ProductCategory.TEST_SCALE_MODULE and UsageTypeAI.VOLTAGE in device.ai_meas_types:
102+
return device
103+
104+
pytest.skip(
105+
"Could not detect a device that meets the requirements to be a TestScale simulated voltage device. "
106+
"Cannot proceed to run tests. Import the NI MAX configuration file located at "
107+
"nidaqmx\\tests\\max_config\\nidaqmxMaxConfig.ini to create these devices."
108+
)
109+
return None
110+
111+
112+
@pytest.fixture(scope="module")
113+
def sim_ts_power_devices():
98114
system = nidaqmx.system.System.local()
99115

100116
devices = []
101117
for device in system.devices:
102-
if device.dev_is_simulated and UsageTypeAI.POWER in device.ai_meas_types:
118+
if device.dev_is_simulated and device.product_category == ProductCategory.TEST_SCALE_MODULE and UsageTypeAI.POWER in device.ai_meas_types:
103119
devices.append(device)
104120
if len(devices) == 2:
105121
return devices
106122

107123
pytest.skip(
108-
"Could not detect two or more devices that meets the requirements to be a simulated power "
124+
"Could not detect two or more devices that meets the requirements to be a TestScale simulated power "
109125
"device. Cannot proceed to run tests. Import the NI MAX configuration file located at "
110126
"nidaqmx\\tests\\max_config\\nidaqmxMaxConfig.ini to create these devices."
111127
)

nidaqmx/tests/max_config/nidaqmxMaxConfig.ini

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,10 @@ DevIsSimulated = 1
8787
CompactDAQ.ChassisDevName = tsChassisTester
8888
CompactDAQ.SlotNum = 2
8989

90+
[DAQmxCDAQModule tsVoltageTester1]
91+
ProductType = TS-15100
92+
DevSerialNum = 0x0
93+
DevIsSimulated = 1
94+
CompactDAQ.ChassisDevName = tsChassisTester
95+
CompactDAQ.SlotNum = 3
96+

nidaqmx/tests/test_channel_creation.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
CurrentShuntResistorLocation, TemperatureUnits, RTDType,
1010
ResistanceConfiguration, ExcitationSource, ResistanceUnits, StrainUnits,
1111
StrainGageBridgeType, BridgeConfiguration)
12-
from nidaqmx.tests.fixtures import sim_power_device, any_x_series_device
12+
from nidaqmx.tests.fixtures import sim_ts_power_device, any_x_series_device
1313
from nidaqmx.tests.helpers import generate_random_seed
1414

1515

@@ -268,11 +268,11 @@ def test_create_ai_voltage_chan_with_excit(self, any_x_series_device, seed):
268268
assert not ai_channel.ai_excit_use_for_scaling
269269

270270
@pytest.mark.parametrize('seed', [generate_random_seed()])
271-
def test_create_ai_power_chan(self, sim_power_device, seed):
271+
def test_create_ai_power_chan(self, sim_ts_power_device, seed):
272272
# Reset the pseudorandom number generator with seed.
273273
random.seed(seed)
274274

275-
pwr_phys_chan = f"{sim_power_device.name}/power"
275+
pwr_phys_chan = f"{sim_ts_power_device.name}/power"
276276
voltage_setpoint = random.random() * 6.0
277277
current_setpoint = random.random() * 3.0
278278
output_enable = random.choice([True, False])

nidaqmx/tests/test_read_write.py

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from nidaqmx.constants import (
1212
Edge, TriggerType, AcquisitionType, LineGrouping, Level, TaskMode)
1313
from nidaqmx.utils import flatten_channel_string
14-
from nidaqmx.tests.fixtures import sim_power_device, sim_power_devices, real_x_series_device
14+
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
1515
from nidaqmx.tests.helpers import generate_random_seed, POWER_ABS_EPSILON
1616

1717

@@ -613,7 +613,7 @@ class TestPowerRead(TestDAQmxIOBase):
613613
(generate_random_seed(), False)
614614
]
615615
)
616-
def test_power_1_chan_1_samp(self, sim_power_device, seed, output_enable):
616+
def test_power_1_chan_1_samp(self, sim_ts_power_device, seed, output_enable):
617617
# Reset the pseudorandom number generator with seed.
618618
random.seed(seed)
619619

@@ -622,7 +622,7 @@ def test_power_1_chan_1_samp(self, sim_power_device, seed, output_enable):
622622

623623
with nidaqmx.Task() as read_task:
624624
read_task.ai_channels.add_ai_power_chan(
625-
f"{sim_power_device.name}/power",
625+
f"{sim_ts_power_device.name}/power",
626626
voltage_setpoint, current_setpoint, output_enable)
627627

628628
read_task.start()
@@ -644,15 +644,15 @@ def test_power_1_chan_1_samp(self, sim_power_device, seed, output_enable):
644644
(generate_random_seed(), [False, False])
645645
]
646646
)
647-
def test_power_n_chan_1_samp(self, sim_power_devices, seed, output_enables):
647+
def test_power_n_chan_1_samp(self, sim_ts_power_devices, seed, output_enables):
648648
# Reset the pseudorandom number generator with seed.
649649
random.seed(seed)
650650

651651
voltage_setpoint = 0.0
652652
current_setpoint = 0.03
653653

654654
with nidaqmx.Task() as read_task:
655-
for device, output_enable in zip(sim_power_devices, output_enables):
655+
for device, output_enable in zip(sim_ts_power_devices, output_enables):
656656
read_task.ai_channels.add_ai_power_chan(
657657
f"{device.name}/power",
658658
voltage_setpoint, current_setpoint, output_enable)
@@ -675,7 +675,7 @@ def test_power_n_chan_1_samp(self, sim_power_devices, seed, output_enables):
675675
(generate_random_seed(), False)
676676
]
677677
)
678-
def test_power_1_chan_n_samp(self, sim_power_device, seed, output_enable):
678+
def test_power_1_chan_n_samp(self, sim_ts_power_device, seed, output_enable):
679679
# Reset the pseudorandom number generator with seed.
680680
random.seed(seed)
681681

@@ -684,7 +684,7 @@ def test_power_1_chan_n_samp(self, sim_power_device, seed, output_enable):
684684

685685
with nidaqmx.Task() as read_task:
686686
read_task.ai_channels.add_ai_power_chan(
687-
f"{sim_power_device.name}/power",
687+
f"{sim_ts_power_device.name}/power",
688688
voltage_setpoint, current_setpoint, output_enable)
689689

690690
read_task.start()
@@ -706,15 +706,15 @@ def test_power_1_chan_n_samp(self, sim_power_device, seed, output_enable):
706706
(generate_random_seed(), [False, False])
707707
]
708708
)
709-
def test_power_n_chan_n_samp(self, sim_power_devices, seed, output_enables):
709+
def test_power_n_chan_n_samp(self, sim_ts_power_devices, seed, output_enables):
710710
# Reset the pseudorandom number generator with seed.
711711
random.seed(seed)
712712

713713
voltage_setpoint = 0.0
714714
current_setpoint = 0.03
715715

716716
with nidaqmx.Task() as read_task:
717-
for device, output_enable in zip(sim_power_devices, output_enables):
717+
for device, output_enable in zip(sim_ts_power_devices, output_enables):
718718
read_task.ai_channels.add_ai_power_chan(
719719
f"{device.name}/power",
720720
voltage_setpoint, current_setpoint, output_enable)
@@ -731,3 +731,40 @@ def test_power_n_chan_n_samp(self, sim_power_devices, seed, output_enables):
731731
else:
732732
assert all(math.isnan(sample.voltage) for sample in channel_values)
733733
assert all(math.isnan(sample.current) for sample in channel_values)
734+
735+
@pytest.mark.parametrize('seed', [generate_random_seed()])
736+
def test_mixed_chans(self, sim_x_series_device, seed):
737+
# Reset the pseudorandom number generator with seed.
738+
random.seed(seed)
739+
740+
with nidaqmx.Task() as read_task:
741+
read_task.ai_channels.add_ai_voltage_chan(
742+
f"{sim_x_series_device.name}/ai0", max_val=10, min_val=-10)
743+
read_task.ai_channels.add_ai_current_chan(
744+
f"{sim_x_series_device.name}/ai1", max_val=0.01, min_val=-0.01)
745+
746+
read_task.start()
747+
# We aren't validating data, just assuring that it doesn't fail.
748+
values_read = read_task.read(number_of_samples_per_channel=10)
749+
750+
@pytest.mark.parametrize('seed', [generate_random_seed()])
751+
def test_mixed_chans_with_power(self, sim_ts_power_device, sim_ts_voltage_device, seed):
752+
# Reset the pseudorandom number generator with seed.
753+
random.seed(seed)
754+
755+
voltage_setpoint = 0.0
756+
current_setpoint = 0.03
757+
output_enable = False
758+
759+
with nidaqmx.Task() as read_task:
760+
read_task.ai_channels.add_ai_power_chan(
761+
f"{sim_ts_power_device.name}/power",
762+
voltage_setpoint, current_setpoint, output_enable)
763+
read_task.ai_channels.add_ai_voltage_chan(
764+
f"{sim_ts_voltage_device.name}/ai0", max_val=10, min_val=-10)
765+
766+
read_task.start()
767+
# We aren't validating data, just assuring that it fails. The error
768+
# code is currently not very good, so we'll ignore that for now.
769+
with pytest.raises(nidaqmx.errors.DaqReadError):
770+
values_read = read_task.read(number_of_samples_per_channel=10)

nidaqmx/tests/test_stream_power_readers.py

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import nidaqmx
1111
from nidaqmx.stream_readers import (
1212
PowerSingleChannelReader, PowerMultiChannelReader, PowerBinaryReader)
13-
from nidaqmx.tests.fixtures import sim_power_device, sim_power_devices
13+
from nidaqmx.tests.fixtures import sim_ts_power_device, sim_ts_power_devices
1414
from nidaqmx.tests.helpers import generate_random_seed, POWER_ABS_EPSILON
1515
from nidaqmx.tests.test_read_write import TestDAQmxIOBase
1616

@@ -31,7 +31,7 @@ class TestPowerSingleChannelReader(TestDAQmxIOBase):
3131
(generate_random_seed(), False)
3232
]
3333
)
34-
def test_power_1_chan_1_samp(self, sim_power_device, seed, output_enable):
34+
def test_power_1_chan_1_samp(self, sim_ts_power_device, seed, output_enable):
3535
# Reset the pseudorandom number generator with seed.
3636
random.seed(seed)
3737

@@ -40,7 +40,7 @@ def test_power_1_chan_1_samp(self, sim_power_device, seed, output_enable):
4040

4141
with nidaqmx.Task() as read_task:
4242
read_task.ai_channels.add_ai_power_chan(
43-
f"{sim_power_device.name}/power",
43+
f"{sim_ts_power_device.name}/power",
4444
voltage_setpoint, current_setpoint, output_enable)
4545

4646
reader = PowerSingleChannelReader(read_task.in_stream)
@@ -62,7 +62,7 @@ def test_power_1_chan_1_samp(self, sim_power_device, seed, output_enable):
6262
(generate_random_seed(), False)
6363
]
6464
)
65-
def test_power_1_chan_n_samp(self, sim_power_device, seed, output_enable):
65+
def test_power_1_chan_n_samp(self, sim_ts_power_device, seed, output_enable):
6666
# Reset the pseudorandom number generator with seed.
6767
random.seed(seed)
6868

@@ -76,7 +76,7 @@ def test_power_1_chan_n_samp(self, sim_power_device, seed, output_enable):
7676

7777
with nidaqmx.Task() as read_task:
7878
read_task.ai_channels.add_ai_power_chan(
79-
f"{sim_power_device.name}/power",
79+
f"{sim_ts_power_device.name}/power",
8080
voltage_setpoint, current_setpoint, output_enable)
8181

8282
reader = PowerSingleChannelReader(read_task.in_stream)
@@ -111,19 +111,19 @@ class TestPowerMultiChannelReader(TestDAQmxIOBase):
111111
(generate_random_seed(), [False, False])
112112
]
113113
)
114-
def test_power_n_chan_1_samp(self, sim_power_devices, seed, output_enables):
114+
def test_power_n_chan_1_samp(self, sim_ts_power_devices, seed, output_enables):
115115
# Reset the pseudorandom number generator with seed.
116116
random.seed(seed)
117117

118118
voltage_setpoint = 0.0
119119
current_setpoint = 0.03
120120

121121
# Fill with bad data to ensure its overwritten by read.
122-
voltage_data = numpy.full(len(sim_power_devices), -1.0, dtype=numpy.float64)
123-
current_data = numpy.full(len(sim_power_devices), -1.0, dtype=numpy.float64)
122+
voltage_data = numpy.full(len(sim_ts_power_devices), -1.0, dtype=numpy.float64)
123+
current_data = numpy.full(len(sim_ts_power_devices), -1.0, dtype=numpy.float64)
124124

125125
with nidaqmx.Task() as read_task:
126-
for device, output_enable in zip(sim_power_devices, output_enables):
126+
for device, output_enable in zip(sim_ts_power_devices, output_enables):
127127
read_task.ai_channels.add_ai_power_chan(
128128
f"{device.name}/power",
129129
voltage_setpoint, current_setpoint, output_enable)
@@ -150,7 +150,7 @@ def test_power_n_chan_1_samp(self, sim_power_devices, seed, output_enables):
150150
(generate_random_seed(), [False, False])
151151
]
152152
)
153-
def test_power_n_chan_n_samp(self, sim_power_devices, seed, output_enables):
153+
def test_power_n_chan_n_samp(self, sim_ts_power_devices, seed, output_enables):
154154
# Reset the pseudorandom number generator with seed.
155155
random.seed(seed)
156156

@@ -159,11 +159,11 @@ def test_power_n_chan_n_samp(self, sim_power_devices, seed, output_enables):
159159
number_of_samples_per_channel = 10
160160

161161
# Fill with bad data to ensure its overwritten by read.
162-
voltage_data = numpy.full((len(sim_power_devices), number_of_samples_per_channel), -1.0, dtype=numpy.float64)
163-
current_data = numpy.full((len(sim_power_devices), number_of_samples_per_channel), -1.0, dtype=numpy.float64)
162+
voltage_data = numpy.full((len(sim_ts_power_devices), number_of_samples_per_channel), -1.0, dtype=numpy.float64)
163+
current_data = numpy.full((len(sim_ts_power_devices), number_of_samples_per_channel), -1.0, dtype=numpy.float64)
164164

165165
with nidaqmx.Task() as read_task:
166-
for device, output_enable in zip(sim_power_devices, output_enables):
166+
for device, output_enable in zip(sim_ts_power_devices, output_enables):
167167
read_task.ai_channels.add_ai_power_chan(
168168
f"{device.name}/power",
169169
voltage_setpoint, current_setpoint, output_enable)
@@ -203,7 +203,7 @@ class TestPowerBinaryReader(TestDAQmxIOBase):
203203
(generate_random_seed(), False)
204204
]
205205
)
206-
def test_power_1_chan_n_samp_binary(self, sim_power_device, seed, output_enable):
206+
def test_power_1_chan_n_samp_binary(self, sim_ts_power_device, seed, output_enable):
207207
# Reset the pseudorandom number generator with seed.
208208
random.seed(seed)
209209

@@ -217,7 +217,7 @@ def test_power_1_chan_n_samp_binary(self, sim_power_device, seed, output_enable)
217217

218218
with nidaqmx.Task() as read_task:
219219
read_task.ai_channels.add_ai_power_chan(
220-
f"{sim_power_device.name}/power",
220+
f"{sim_ts_power_device.name}/power",
221221
voltage_setpoint, current_setpoint, output_enable)
222222

223223
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)
247247
(generate_random_seed(), [False, False])
248248
]
249249
)
250-
def test_power_n_chan_many_sample_binary(self, sim_power_devices, seed, output_enables):
250+
def test_power_n_chan_many_sample_binary(self, sim_ts_power_devices, seed, output_enables):
251251
# Reset the pseudorandom number generator with seed.
252252
random.seed(seed)
253253

@@ -256,11 +256,11 @@ def test_power_n_chan_many_sample_binary(self, sim_power_devices, seed, output_e
256256
number_of_samples_per_channel = 10
257257

258258
# Fill with bad data to ensure its overwritten by read.
259-
voltage_data = numpy.full((len(sim_power_devices), number_of_samples_per_channel), -32768, dtype=numpy.int16)
260-
current_data = numpy.full((len(sim_power_devices), number_of_samples_per_channel), -32768, dtype=numpy.int16)
259+
voltage_data = numpy.full((len(sim_ts_power_devices), number_of_samples_per_channel), -32768, dtype=numpy.int16)
260+
current_data = numpy.full((len(sim_ts_power_devices), number_of_samples_per_channel), -32768, dtype=numpy.int16)
261261

262262
with nidaqmx.Task() as read_task:
263-
for device, output_enable in zip(sim_power_devices, output_enables):
263+
for device, output_enable in zip(sim_ts_power_devices, output_enables):
264264
read_task.ai_channels.add_ai_power_chan(
265265
f"{device.name}/power",
266266
voltage_setpoint, current_setpoint, output_enable)

0 commit comments

Comments
 (0)