Skip to content

Commit 0045510

Browse files
author
Michael Johansen
committed
Move new converters into existing protobuf_types file. Move tests, too.
1 parent 3e2a147 commit 0045510

File tree

4 files changed

+264
-271
lines changed

4 files changed

+264
-271
lines changed

src/nipanel/converters/double_analog_waveform.py

Lines changed: 0 additions & 140 deletions
This file was deleted.

src/nipanel/converters/protobuf_types.py

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,21 @@
11
"""Classes to convert between measurement specific protobuf types and containers."""
22

3+
import collections.abc
4+
import datetime as dt
35
from typing import Type, Union
46

7+
import numpy
58
from ni.protobuf.types import scalar_pb2
9+
from ni_measurement_plugin_sdk_service._internal.stubs.ni.protobuf.types.precision_timestamp_pb2 import (
10+
PrecisionTimestamp,
11+
)
12+
from ni_measurement_plugin_sdk_service._internal.stubs.ni.protobuf.types.waveform_pb2 import (
13+
DoubleAnalogWaveform,
14+
WaveformAttributeValue,
15+
)
16+
from nitypes.bintime import DateTime, TimeDelta
617
from nitypes.scalar import Scalar
18+
from nitypes.waveform import AnalogWaveform, ExtendedPropertyDictionary, NoneScaleMode, Timing
719
from typing_extensions import TypeAlias
820

921
from nipanel.converters import Converter
@@ -17,6 +29,128 @@
1729
}
1830

1931

32+
class DoubleAnalogWaveformConverter(Converter[AnalogWaveform[numpy.float64], DoubleAnalogWaveform]):
33+
"""A converter for AnalogWaveform types with scaled data (double)."""
34+
35+
@property
36+
def python_typename(self) -> str:
37+
"""The Python type that this converter handles."""
38+
return AnalogWaveform.__name__
39+
40+
@property
41+
def protobuf_message(self) -> Type[DoubleAnalogWaveform]:
42+
"""The type-specific protobuf message for the Python type."""
43+
return DoubleAnalogWaveform
44+
45+
def to_protobuf_message(
46+
self, python_value: AnalogWaveform[numpy.float64]
47+
) -> DoubleAnalogWaveform:
48+
"""Convert the Python AnalogWaveform to a protobuf DoubleAnalogWaveform."""
49+
if python_value.timing.has_timestamp:
50+
pt_converter = PrecisionTimestampConverter()
51+
bin_datetime = DateTime(python_value.timing.start_time)
52+
precision_timestamp = pt_converter.to_protobuf_message(bin_datetime)
53+
else:
54+
precision_timestamp = PrecisionTimestamp(seconds=0, fractional_seconds=0)
55+
56+
# TODO: Replace with .has_sample_interval once available.
57+
if python_value.timing._sample_interval is not None:
58+
time_interval = python_value.timing.sample_interval.total_seconds()
59+
else:
60+
time_interval = 0
61+
62+
attributes = self._extended_properties_to_attributes(python_value.extended_properties)
63+
64+
return self.protobuf_message(
65+
t0=precision_timestamp,
66+
dt=time_interval,
67+
y_data=python_value.scaled_data,
68+
attributes=attributes,
69+
)
70+
71+
def _extended_properties_to_attributes(
72+
self,
73+
extended_properties: ExtendedPropertyDictionary,
74+
) -> collections.abc.Mapping[str, WaveformAttributeValue]:
75+
attributes = {}
76+
for key, value in extended_properties.items():
77+
attr_value = WaveformAttributeValue()
78+
if isinstance(value, bool):
79+
attr_value.bool_value = value
80+
elif isinstance(value, int):
81+
attr_value.integer_value = value
82+
elif isinstance(value, float):
83+
attr_value.double_value = value
84+
elif isinstance(value, str):
85+
attr_value.string_value = value
86+
else:
87+
raise TypeError(f"Unexpected type for extended property value {type(value)}")
88+
89+
attributes[key] = attr_value
90+
91+
return attributes
92+
93+
def to_python_value(
94+
self, protobuf_value: DoubleAnalogWaveform
95+
) -> AnalogWaveform[numpy.float64]:
96+
"""Convert the protobuf DoubleAnalogWaveform to a Python AnalogWaveform."""
97+
pt_converter = PrecisionTimestampConverter()
98+
bin_datetime = pt_converter.to_python_value(protobuf_value.t0)
99+
timestamp = bin_datetime._to_datetime_datetime()
100+
sample_interval = dt.timedelta(seconds=protobuf_value.dt)
101+
timing = Timing.create_with_regular_interval(
102+
sample_interval,
103+
timestamp,
104+
)
105+
106+
extended_properties = {}
107+
for key, value in protobuf_value.attributes.items():
108+
attr_type = value.WhichOneof("attribute")
109+
extended_properties[key] = getattr(value, str(attr_type))
110+
111+
data_list = list(protobuf_value.y_data)
112+
return AnalogWaveform(
113+
sample_count=len(data_list),
114+
dtype=numpy.float64,
115+
raw_data=numpy.array(data_list),
116+
start_index=0,
117+
capacity=len(data_list),
118+
extended_properties=extended_properties,
119+
copy_extended_properties=True,
120+
timing=timing,
121+
scale_mode=NoneScaleMode(),
122+
)
123+
124+
125+
class PrecisionTimestampConverter(Converter[DateTime, PrecisionTimestamp]):
126+
"""A converter for bintime.DateTime types."""
127+
128+
@property
129+
def python_typename(self) -> str:
130+
"""The Python type that this converter handles."""
131+
return DateTime.__name__
132+
133+
@property
134+
def protobuf_message(self) -> Type[PrecisionTimestamp]:
135+
"""The type-specific protobuf message for the Python type."""
136+
return PrecisionTimestamp
137+
138+
def to_protobuf_message(self, python_value: DateTime) -> PrecisionTimestamp:
139+
"""Convert the Python DateTime to a protobuf PrecisionTimestamp."""
140+
time_delta: TimeDelta = DateTime._to_offset(python_value._to_datetime_datetime())
141+
# TODO: Replace with Datetime.to_tuple once available
142+
ticks = TimeDelta._to_ticks(time_delta.total_seconds())
143+
seconds = ticks >> 64
144+
frac_seconds = ticks & ((1 << 64) - 1)
145+
return self.protobuf_message(seconds=seconds, fractional_seconds=frac_seconds)
146+
147+
def to_python_value(self, protobuf_value: PrecisionTimestamp) -> DateTime:
148+
"""Convert the protobuf PrecisionTimestamp to a Python DateTime."""
149+
ticks = (protobuf_value.seconds << 64) | protobuf_value.fractional_seconds
150+
# TODO: Replace with Datetime.from_tuple() once available
151+
return DateTime.from_ticks(ticks)
152+
153+
20154
class ScalarConverter(Converter[Scalar[_AnyScalarType], scalar_pb2.ScalarData]):
21155
"""A converter for Scalar objects."""
22156

0 commit comments

Comments
 (0)