Skip to content

Commit ba42d15

Browse files
authored
Add Unit test for cfg_time_start_trig (#488)
1 parent 6acaca7 commit ba42d15

File tree

14 files changed

+183
-19
lines changed

14 files changed

+183
-19
lines changed

generated/nidaqmx/_grpc_interpreter.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from typing import Callable, Generic, Optional, TypeVar
99

1010
import google.protobuf.message
11+
from google.protobuf.timestamp_pb2 import Timestamp as GrpcTimestamp
1112
import grpc
1213
import numpy
1314

generated/nidaqmx/_grpc_time.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@
1414
_YS_PER_FS = 10**9
1515

1616

17-
def convert_time_to_timestamp(dt: Union[std_datetime, ht_datetime], ts: GrpcTimestamp) -> None:
17+
def convert_time_to_timestamp(dt: Union[std_datetime, ht_datetime], ts: Optional[GrpcTimestamp] = None) -> GrpcTimestamp:
1818
utc_dt = dt.astimezone(tz=timezone.utc)
1919
seconds = int(utc_dt.timestamp())
20+
if ts is None:
21+
ts = GrpcTimestamp()
2022

2123
if isinstance(dt, ht_datetime):
2224
total_yoctoseconds = dt.yoctosecond
@@ -30,6 +32,7 @@ def convert_time_to_timestamp(dt: Union[std_datetime, ht_datetime], ts: GrpcTime
3032
nanos = utc_dt.microsecond * _NS_PER_US
3133

3234
ts.FromNanoseconds(seconds * _NS_PER_S + nanos)
35+
return ts
3336

3437

3538
def convert_timestamp_to_time(ts: GrpcTimestamp, tzinfo: Optional[timezone] = None) -> ht_datetime:
@@ -47,4 +50,4 @@ def convert_timestamp_to_time(ts: GrpcTimestamp, tzinfo: Optional[timezone] = No
4750
# Add in precision
4851
dt = dt.replace(microsecond=microsecond, femtosecond=femtosecond, yoctosecond=yoctosecond)
4952
# Then convert to requested timezone
50-
return dt.astimezone(tz=tzinfo)
53+
return dt.astimezone(tz=tzinfo)

generated/nidaqmx/_lib_time.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,4 @@ def __lt__(self, other) -> bool:
9696
if self.msb == other.msb:
9797
return self.lsb < other.lsb
9898
else:
99-
return self.msb < other.msb
99+
return self.msb < other.msb

generated/nidaqmx/_library_interpreter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3684,7 +3684,7 @@ def get_trig_attribute_timestamp(self, task, attribute):
36843684
error_code = cfunc(
36853685
task, attribute, ctypes.byref(value))
36863686
self.check_for_error(error_code)
3687-
return value
3687+
return value.to_datetime()
36883688

36893689
def get_trig_attribute_uint32(self, task, attribute):
36903690
value = ctypes.c_uint32()

src/codegen/templates/_grpc_interpreter.py.mako

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import warnings
2424
from typing import Callable, Generic, Optional, TypeVar
2525

2626
import google.protobuf.message
27+
from google.protobuf.timestamp_pb2 import Timestamp as GrpcTimestamp
2728
import grpc
2829
import numpy
2930

src/codegen/utilities/interpreter_helpers.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,8 +447,10 @@ def get_return_values(func):
447447
return_values.append(param.parameter_name)
448448
else:
449449
return_values.append(f"{param.parameter_name}.tolist()")
450-
elif param.type == "TaskHandle" or param.type == "CVIAbsoluteTime":
450+
elif param.type == "TaskHandle":
451451
return_values.append(param.parameter_name)
452+
elif param.type == "CVIAbsoluteTime":
453+
return_values.append(f"{param.parameter_name}.to_datetime()")
452454
else:
453455
return_values.append(f"{param.parameter_name}.value")
454456
if func.is_init_method:

src/handwritten/_grpc_time.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@
1414
_YS_PER_FS = 10**9
1515

1616

17-
def convert_time_to_timestamp(dt: Union[std_datetime, ht_datetime], ts: GrpcTimestamp) -> None:
17+
def convert_time_to_timestamp(dt: Union[std_datetime, ht_datetime], ts: Optional[GrpcTimestamp] = None) -> GrpcTimestamp:
1818
utc_dt = dt.astimezone(tz=timezone.utc)
1919
seconds = int(utc_dt.timestamp())
20+
if ts is None:
21+
ts = GrpcTimestamp()
2022

2123
if isinstance(dt, ht_datetime):
2224
total_yoctoseconds = dt.yoctosecond
@@ -30,6 +32,7 @@ def convert_time_to_timestamp(dt: Union[std_datetime, ht_datetime], ts: GrpcTime
3032
nanos = utc_dt.microsecond * _NS_PER_US
3133

3234
ts.FromNanoseconds(seconds * _NS_PER_S + nanos)
35+
return ts
3336

3437

3538
def convert_timestamp_to_time(ts: GrpcTimestamp, tzinfo: Optional[timezone] = None) -> ht_datetime:
@@ -47,4 +50,4 @@ def convert_timestamp_to_time(ts: GrpcTimestamp, tzinfo: Optional[timezone] = No
4750
# Add in precision
4851
dt = dt.replace(microsecond=microsecond, femtosecond=femtosecond, yoctosecond=yoctosecond)
4952
# Then convert to requested timezone
50-
return dt.astimezone(tz=tzinfo)
53+
return dt.astimezone(tz=tzinfo)

src/handwritten/_lib_time.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,4 @@ def __lt__(self, other) -> bool:
9696
if self.msb == other.msb:
9797
return self.lsb < other.lsb
9898
else:
99-
return self.msb < other.msb
99+
return self.msb < other.msb
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
from datetime import timedelta
2+
3+
import pytest
4+
from hightime import datetime as ht_datetime
5+
6+
from nidaqmx.constants import Timescale
7+
from nidaqmx.task import Task
8+
9+
10+
@pytest.fixture()
11+
def ai_voltage_field_daq_task(task, sim_field_daq_device):
12+
"""Gets AI voltage task."""
13+
task.ai_channels.add_ai_voltage_chan(sim_field_daq_device.ai_physical_chans[0].name)
14+
yield task
15+
16+
17+
def test___default_arguments___cfg_time_start_trig___no_errors(
18+
ai_voltage_field_daq_task: Task,
19+
):
20+
ai_voltage_field_daq_task.timing.cfg_samp_clk_timing(1000)
21+
trigger_time = ht_datetime.now() + timedelta(seconds=10)
22+
23+
ai_voltage_field_daq_task.triggers.start_trigger.cfg_time_start_trig(trigger_time)
24+
25+
when_value = ai_voltage_field_daq_task.triggers.start_trigger.trig_when
26+
timescale_value = ai_voltage_field_daq_task.triggers.start_trigger.timestamp_timescale
27+
assert timescale_value == Timescale.USE_HOST
28+
assert when_value.year == trigger_time.year
29+
assert when_value.month == trigger_time.month
30+
assert when_value.day == trigger_time.day
31+
assert when_value.hour == trigger_time.hour
32+
assert when_value.minute == trigger_time.minute
33+
assert when_value.second == trigger_time.second
34+
35+
36+
def test___arguments_provided___cfg_time_start_trig___no_errors(
37+
ai_voltage_field_daq_task: Task,
38+
):
39+
ai_voltage_field_daq_task.timing.cfg_samp_clk_timing(1000)
40+
trigger_time = ht_datetime.now() + timedelta(seconds=10)
41+
# simulated devices don't support setting timescale to USE_IO_DEVICE
42+
timescale = Timescale.USE_HOST
43+
44+
ai_voltage_field_daq_task.triggers.start_trigger.cfg_time_start_trig(trigger_time, timescale)
45+
46+
when_value = ai_voltage_field_daq_task.triggers.start_trigger.trig_when
47+
assert when_value.year == trigger_time.year
48+
assert when_value.month == trigger_time.month
49+
assert when_value.day == trigger_time.day
50+
assert when_value.hour == trigger_time.hour
51+
assert when_value.minute == trigger_time.minute
52+
assert when_value.second == trigger_time.second
53+
assert ai_voltage_field_daq_task.triggers.start_trigger.timestamp_timescale == timescale

tests/component/_task_modules/test_triggers_properties.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1+
from datetime import timezone
2+
13
import pytest
4+
from hightime import datetime as ht_datetime
25

36
from nidaqmx.constants import TaskMode, TriggerType
47
from nidaqmx.error_codes import DAQmxErrors
58
from nidaqmx.errors import DaqError
69
from nidaqmx.task import Task
10+
from tests.unit._time_utils import JAN_01_1904_HIGHTIME, JAN_01_2002_HIGHTIME
711

812

913
@pytest.fixture()
@@ -13,6 +17,20 @@ def ai_voltage_task(task, sim_6363_device):
1317
yield task
1418

1519

20+
@pytest.fixture()
21+
def ai_voltage_field_daq_task(task, sim_field_daq_device):
22+
"""Gets AI voltage task."""
23+
task.ai_channels.add_ai_voltage_chan(sim_field_daq_device.ai_physical_chans[0].name)
24+
yield task
25+
26+
27+
def convert_to_local_timezone(expected_time_utc):
28+
current_time_utc = ht_datetime.now(timezone.utc)
29+
local_timezone_offset = current_time_utc.astimezone().utcoffset()
30+
local_expected_time = expected_time_utc + local_timezone_offset
31+
return local_expected_time
32+
33+
1634
def test___ai_task___get_float_property___returns_default_value(ai_voltage_task: Task):
1735
assert ai_voltage_task.triggers.start_trigger.dig_edge_dig_fltr_timebase_rate == 0.0
1836

@@ -99,3 +117,57 @@ def test___ai_task___reset_uint32_property___returns_default_value(ai_voltage_ta
99117
del ai_voltage_task.triggers.reference_trigger.pretrig_samples
100118

101119
assert ai_voltage_task.triggers.reference_trigger.pretrig_samples == 2
120+
121+
122+
@pytest.mark.xfail(reason="Timestamp conversion doesn't work on dates before 1970", raises=OSError)
123+
def test___ai_voltage_field_daq_task___get_timestamp_property___returns_default_value(
124+
ai_voltage_field_daq_task: Task,
125+
):
126+
ai_voltage_field_daq_task.timing.cfg_samp_clk_timing(1000)
127+
128+
when_value = ai_voltage_field_daq_task.triggers.start_trigger.trig_when
129+
130+
localized_default_value = convert_to_local_timezone(JAN_01_1904_HIGHTIME)
131+
assert when_value.year == localized_default_value.year
132+
assert when_value.month == localized_default_value.month
133+
assert when_value.day == localized_default_value.day
134+
assert when_value.hour == localized_default_value.hour
135+
assert when_value.minute == localized_default_value.minute
136+
assert when_value.second == localized_default_value.second
137+
138+
139+
def test___ai_voltage_field_daq_task___set_timestamp_property___returns_assigned_value(
140+
ai_voltage_field_daq_task: Task,
141+
):
142+
value_to_test = JAN_01_2002_HIGHTIME
143+
ai_voltage_field_daq_task.timing.cfg_samp_clk_timing(1000)
144+
145+
ai_voltage_field_daq_task.triggers.start_trigger.trig_when = value_to_test
146+
147+
when_value = ai_voltage_field_daq_task.triggers.start_trigger.trig_when
148+
localized_value_to_test = convert_to_local_timezone(value_to_test)
149+
assert when_value.year == localized_value_to_test.year
150+
assert when_value.month == localized_value_to_test.month
151+
assert when_value.day == localized_value_to_test.day
152+
assert when_value.hour == localized_value_to_test.hour
153+
assert when_value.minute == localized_value_to_test.minute
154+
assert when_value.second == localized_value_to_test.second
155+
156+
157+
@pytest.mark.xfail(reason="Timestamp conversion doesn't work on dates before 1970", raises=OSError)
158+
def test___ai_voltage_field_daq_task___reset_timestamp_property___returns_default_value(
159+
ai_voltage_field_daq_task: Task,
160+
):
161+
ai_voltage_field_daq_task.timing.cfg_samp_clk_timing(1000)
162+
ai_voltage_field_daq_task.triggers.start_trigger.trig_when = JAN_01_2002_HIGHTIME
163+
164+
del ai_voltage_field_daq_task.triggers.start_trigger.trig_when
165+
166+
when_value = ai_voltage_field_daq_task.triggers.start_trigger.trig_when
167+
localized_default_value = convert_to_local_timezone(JAN_01_1904_HIGHTIME)
168+
assert when_value.year == localized_default_value.year
169+
assert when_value.month == localized_default_value.month
170+
assert when_value.day == localized_default_value.day
171+
assert when_value.hour == localized_default_value.hour
172+
assert when_value.minute == localized_default_value.minute
173+
assert when_value.second == localized_default_value.second

tests/conftest.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ def _device_by_product_type(
123123
device_type == DeviceType.ANY
124124
or (device_type == DeviceType.REAL and not device.is_simulated)
125125
or (device_type == DeviceType.SIMULATED and device.is_simulated)
126+
and len(device.ai_physical_chans) >= 1
126127
)
127128
if device_type_match and device.product_type == product_type:
128129
return device
@@ -147,6 +148,12 @@ def sim_6363_device(system: nidaqmx.system.System) -> nidaqmx.system.Device:
147148
return _device_by_product_type("PCIe-6363", DeviceType.SIMULATED, system)
148149

149150

151+
@pytest.fixture(scope="function")
152+
def sim_field_daq_device(system):
153+
"""Gets simulated Field DAQ device information."""
154+
return _device_by_product_type("FD-11601", DeviceType.SIMULATED, system)
155+
156+
150157
@pytest.fixture(scope="function")
151158
def sim_ts_chassis(system: nidaqmx.system.System) -> nidaqmx.system.Device:
152159
"""Gets simulated TestScale chassis information."""

tests/max_config/nidaqmxMaxConfig.ini

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,3 +257,27 @@ DevIsSimulated = 1
257257
CompactDAQ.ChassisDevName = cdaqChassisTester
258258
CompactDAQ.SlotNum = 1
259259

260+
[DAQmxFieldDAQ FieldDAQ1]
261+
ProductType = FD-11601
262+
DevSerialNum = 0x0
263+
DevIsSimulated = 1
264+
BusType = TCP/IP
265+
TCPIP.Hostname =
266+
TCPIP.EthernetIP = 0.0.0.0
267+
TCPIP.EthernetMAC = 00:00:00:00:00:00
268+
TCPIP.EthernetMDNSServiceInstance =
269+
TCPIP.DevIsReserved = 0
270+
271+
[DAQmxFieldDAQBank FieldDAQ1-Bank1]
272+
ProductType = FD-11601
273+
DevSerialNum = 0x0
274+
DevIsSimulated = 1
275+
FieldDAQ.BankNum = 1
276+
FieldDAQ.DevName = FieldDAQ1
277+
278+
[DAQmxFieldDAQBank FieldDAQ1-Bank2]
279+
ProductType = FD-11601
280+
DevSerialNum = 0x0
281+
DevIsSimulated = 1
282+
FieldDAQ.BankNum = 2
283+
FieldDAQ.DevName = FieldDAQ1

tests/unit/_time_utils.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@
1010

1111
JAN_01_2002_DATETIME = std_datetime(2002, 1, 1, tzinfo=timezone.utc)
1212
JAN_01_2002_HIGHTIME = ht_datetime(2002, 1, 1, tzinfo=timezone.utc)
13+
JAN_01_1904_DATETIME = std_datetime(1904, 1, 1, tzinfo=timezone.utc)
14+
JAN_01_1904_HIGHTIME = ht_datetime(1904, 1, 1, tzinfo=timezone.utc)

tests/unit/test_grpc_time.py

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
from datetime import datetime as std_datetime
2-
from datetime import timedelta, timezone
1+
from datetime import datetime as std_datetime, timedelta, timezone
32

43
import pytest
54
from hightime import datetime as ht_datetime
65

76
from tests.unit._time_utils import (
8-
JAN_01_2002_TIMESTAMP_1970_EPOCH,
97
JAN_01_2002_DATETIME,
108
JAN_01_2002_HIGHTIME,
9+
JAN_01_2002_TIMESTAMP_1970_EPOCH,
1110
)
1211

1312
try:
1413
from google.protobuf.timestamp_pb2 import Timestamp as GrpcTimestamp
14+
1515
import nidaqmx._grpc_time as grpc_time
1616
import nidaqmx._stubs.nidaqmx_pb2 as nidaqmx_pb2
1717
except ImportError:
@@ -22,8 +22,7 @@
2222

2323
@pytest.mark.parametrize("from_dt", [(JAN_01_2002_DATETIME), (JAN_01_2002_HIGHTIME)])
2424
def test___utc_datetime___convert_to_timestamp___is_reversible(from_dt):
25-
to_ts = GrpcTimestamp()
26-
grpc_time.convert_time_to_timestamp(from_dt, to_ts)
25+
to_ts = grpc_time.convert_time_to_timestamp(from_dt)
2726
roundtrip_dt = grpc_time.convert_timestamp_to_time(to_ts, tzinfo=timezone.utc)
2827

2928
total_nanoseconds = to_ts.ToNanoseconds()
@@ -73,8 +72,7 @@ def test___tz_datetime___convert_to_timestamp___is_reversible(
7372
):
7473
from_dt = datetime_cls(2002, 1, 1, tzinfo=tzinfo)
7574

76-
to_ts = GrpcTimestamp()
77-
grpc_time.convert_time_to_timestamp(from_dt, to_ts)
75+
to_ts = grpc_time.convert_time_to_timestamp(from_dt)
7876
roundtrip_dt = grpc_time.convert_timestamp_to_time(to_ts, tzinfo=tzinfo)
7977

8078
assert to_ts.seconds == JAN_01_2002_TIMESTAMP_1970_EPOCH + expected_offset
@@ -104,8 +102,7 @@ def test___datetime_with_microseconds___convert_to_timestamp___is_reversible(
104102
):
105103
from_dt = base_dt.replace(microsecond=microsecond)
106104

107-
to_ts = GrpcTimestamp()
108-
grpc_time.convert_time_to_timestamp(from_dt, to_ts)
105+
to_ts = grpc_time.convert_time_to_timestamp(from_dt)
109106
roundtrip_dt = grpc_time.convert_timestamp_to_time(to_ts, tzinfo=timezone.utc)
110107

111108
assert to_ts.seconds == JAN_01_2002_TIMESTAMP_1970_EPOCH
@@ -135,8 +132,7 @@ def test___datetime_with_femtoseconds___convert_to_timestamp___is_reversible(
135132
):
136133
from_dt = base_dt.replace(femtosecond=femtosecond)
137134

138-
to_ts = GrpcTimestamp()
139-
grpc_time.convert_time_to_timestamp(from_dt, to_ts)
135+
to_ts = grpc_time.convert_time_to_timestamp(from_dt)
140136
roundtrip_dt = grpc_time.convert_timestamp_to_time(to_ts, tzinfo=timezone.utc)
141137

142138
assert to_ts.seconds == JAN_01_2002_TIMESTAMP_1970_EPOCH

0 commit comments

Comments
 (0)