nidaqmx 1.2.0.dev0__tar.gz → 1.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/PKG-INFO +12 -7
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/README.rst +4 -1
- nidaqmx-1.3.0/generated/nidaqmx/__init__.py +31 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/__main__.py +6 -3
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/_base_interpreter.py +108 -2
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/_bitfield_utils.py +8 -11
- nidaqmx-1.3.0/generated/nidaqmx/_dotenvpath.py +73 -0
- nidaqmx-1.3.0/generated/nidaqmx/_feature_toggles.py +162 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/_grpc_interpreter.py +97 -2
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/_grpc_time.py +13 -10
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/_install_daqmx.py +23 -64
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/_installer_metadata.json +6 -6
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/_lib.py +72 -62
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/_lib_time.py +31 -19
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/_library_interpreter.py +781 -5
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/_linux_installation_commands.py +5 -6
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/_stubs/nidaqmx_pb2.py +1 -1
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/_stubs/nidaqmx_pb2.pyi +1 -1
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/_time.py +11 -9
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/constants.py +11 -1
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/errors.py +73 -71
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/grpc_session_options.py +19 -14
- nidaqmx-1.3.0/generated/nidaqmx/stream_readers/__init__.py +37 -0
- nidaqmx-1.3.0/generated/nidaqmx/stream_readers/_analog_multi_channel_reader.py +235 -0
- nidaqmx-1.3.0/generated/nidaqmx/stream_readers/_analog_single_channel_reader.py +193 -0
- nidaqmx-1.3.0/generated/nidaqmx/stream_readers/_analog_unscaled_reader.py +352 -0
- nidaqmx-1.3.0/generated/nidaqmx/stream_readers/_channel_reader_base.py +126 -0
- nidaqmx-1.3.0/generated/nidaqmx/stream_readers/_counter_reader.py +529 -0
- nidaqmx-1.3.0/generated/nidaqmx/stream_readers/_digital_multi_channel_reader.py +581 -0
- nidaqmx-1.3.0/generated/nidaqmx/stream_readers/_digital_single_channel_reader.py +472 -0
- nidaqmx-1.3.0/generated/nidaqmx/stream_readers/_power_readers.py +397 -0
- nidaqmx-1.3.0/generated/nidaqmx/stream_writers/__init__.py +34 -0
- nidaqmx-1.3.0/generated/nidaqmx/stream_writers/_analog_multi_channel_writer.py +137 -0
- nidaqmx-1.3.0/generated/nidaqmx/stream_writers/_analog_single_channel_writer.py +119 -0
- nidaqmx-1.3.0/generated/nidaqmx/stream_writers/_analog_unscaled_writer.py +185 -0
- nidaqmx-1.3.0/generated/nidaqmx/stream_writers/_channel_writer_base.py +170 -0
- nidaqmx-1.3.0/generated/nidaqmx/stream_writers/_counter_writer.py +254 -0
- nidaqmx-1.3.0/generated/nidaqmx/stream_writers/_digital_multi_channel_writer.py +365 -0
- nidaqmx-1.3.0/generated/nidaqmx/stream_writers/_digital_single_channel_writer.py +322 -0
- nidaqmx-1.3.0/generated/nidaqmx/system/__init__.py +19 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/system/_collections/device_collection.py +27 -26
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/system/_collections/persisted_channel_collection.py +36 -29
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/system/_collections/persisted_scale_collection.py +30 -26
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/system/_collections/persisted_task_collection.py +30 -25
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/system/_collections/physical_channel_collection.py +86 -75
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/system/_watchdog_modules/expiration_states_collection.py +14 -12
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/system/storage/__init__.py +3 -1
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/system/storage/persisted_channel.py +27 -34
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/system/storage/persisted_scale.py +28 -36
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/system/storage/persisted_task.py +28 -36
- nidaqmx-1.3.0/generated/nidaqmx/task/__init__.py +15 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/task/_in_stream.py +18 -2
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/task/_task.py +718 -331
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/task/_timing.py +454 -39
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/task/channels/__init__.py +12 -2
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/task/collections/__init__.py +12 -2
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/task/collections/_channel_collection.py +30 -34
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/task/triggering/__init__.py +11 -2
- nidaqmx-1.3.0/generated/nidaqmx/types.py +71 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/utils.py +41 -39
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/pyproject.toml +79 -37
- nidaqmx-1.2.0.dev0/generated/nidaqmx/__init__.py +0 -17
- nidaqmx-1.2.0.dev0/generated/nidaqmx/_stubs/session_pb2.py +0 -52
- nidaqmx-1.2.0.dev0/generated/nidaqmx/_stubs/session_pb2.pyi +0 -240
- nidaqmx-1.2.0.dev0/generated/nidaqmx/_stubs/session_pb2_grpc.py +0 -204
- nidaqmx-1.2.0.dev0/generated/nidaqmx/_stubs/session_pb2_grpc.pyi +0 -130
- nidaqmx-1.2.0.dev0/generated/nidaqmx/stream_readers.py +0 -2454
- nidaqmx-1.2.0.dev0/generated/nidaqmx/stream_writers.py +0 -1401
- nidaqmx-1.2.0.dev0/generated/nidaqmx/system/__init__.py +0 -9
- nidaqmx-1.2.0.dev0/generated/nidaqmx/task/__init__.py +0 -9
- nidaqmx-1.2.0.dev0/generated/nidaqmx/types.py +0 -69
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/LICENSE +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/_stubs/__init__.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/_stubs/data_moniker_pb2.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/_stubs/data_moniker_pb2.pyi +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/_stubs/data_moniker_pb2_grpc.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/_stubs/data_moniker_pb2_grpc.pyi +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/_stubs/nidaqmx_pb2_grpc.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/_stubs/nidaqmx_pb2_grpc.pyi +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/error_codes.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/scale.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/system/_collections/__init__.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/system/_watchdog_modules/__init__.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/system/_watchdog_modules/expiration_state.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/system/device.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/system/physical_channel.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/system/system.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/system/watchdog.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/task/_export_signals.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/task/_out_stream.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/task/channels/_ai_channel.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/task/channels/_ao_channel.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/task/channels/_channel.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/task/channels/_ci_channel.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/task/channels/_co_channel.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/task/channels/_di_channel.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/task/channels/_do_channel.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/task/collections/_ai_channel_collection.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/task/collections/_ao_channel_collection.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/task/collections/_ci_channel_collection.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/task/collections/_co_channel_collection.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/task/collections/_di_channel_collection.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/task/collections/_do_channel_collection.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/task/triggering/_arm_start_trigger.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/task/triggering/_handshake_trigger.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/task/triggering/_pause_trigger.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/task/triggering/_reference_trigger.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/task/triggering/_start_trigger.py +0 -0
- {nidaqmx-1.2.0.dev0 → nidaqmx-1.3.0}/generated/nidaqmx/task/triggering/_triggers.py +0 -0
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: nidaqmx
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: NI-DAQmx Python API
|
|
5
|
-
Home-page: https://github.com/ni/nidaqmx-python
|
|
6
5
|
License: MIT
|
|
7
6
|
Keywords: nidaqmx,nidaq,daqmx,daq
|
|
8
7
|
Author: NI
|
|
@@ -23,6 +22,7 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
23
22
|
Classifier: Programming Language :: Python :: 3.11
|
|
24
23
|
Classifier: Programming Language :: Python :: 3.12
|
|
25
24
|
Classifier: Programming Language :: Python :: 3.13
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
26
26
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
27
27
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
28
28
|
Classifier: Topic :: System :: Hardware :: Hardware Drivers
|
|
@@ -31,13 +31,15 @@ Requires-Dist: click (>=8.0.0)
|
|
|
31
31
|
Requires-Dist: deprecation (>=2.1)
|
|
32
32
|
Requires-Dist: distro (>=1.9.0) ; sys_platform == "linux"
|
|
33
33
|
Requires-Dist: grpcio (>=1.49.0,<2.0) ; extra == "grpc"
|
|
34
|
-
Requires-Dist: hightime (>=0.2.2
|
|
35
|
-
Requires-Dist:
|
|
36
|
-
Requires-Dist:
|
|
34
|
+
Requires-Dist: hightime (>=0.2.2)
|
|
35
|
+
Requires-Dist: ni-grpcdevice-v1-proto (>=1.0.0) ; extra == "grpc"
|
|
36
|
+
Requires-Dist: nitypes (>=0.1.0dev10)
|
|
37
|
+
Requires-Dist: numpy (>=1.22) ; python_version >= "3.9" and python_version < "3.13"
|
|
37
38
|
Requires-Dist: numpy (>=2.1) ; python_version >= "3.13" and python_version < "4.0"
|
|
38
39
|
Requires-Dist: protobuf (>=4.21) ; extra == "grpc"
|
|
39
40
|
Requires-Dist: python-decouple (>=3.8)
|
|
40
41
|
Requires-Dist: requests (>=2.25.0)
|
|
42
|
+
Requires-Dist: typing_extensions (>=4.0.0)
|
|
41
43
|
Requires-Dist: tzlocal (>=5.0,<6.0)
|
|
42
44
|
Project-URL: Documentation, https://nidaqmx-python.readthedocs.io
|
|
43
45
|
Project-URL: Repository, https://github.com/ni/nidaqmx-python
|
|
@@ -100,7 +102,10 @@ system.
|
|
|
100
102
|
Python Version Support
|
|
101
103
|
----------------------
|
|
102
104
|
|
|
103
|
-
**nidaqmx** supports CPython 3.9
|
|
105
|
+
**nidaqmx** supports CPython 3.9+.
|
|
106
|
+
|
|
107
|
+
**nidaqmx** supports PyPy3 for non-gRPC use cases. For the status of PyPy support for gRPC,
|
|
108
|
+
see `PyPy support (grpc/grpc#4221) <https://github.com/grpc/grpc/issues/4221>`_.
|
|
104
109
|
|
|
105
110
|
Installation
|
|
106
111
|
============
|
|
@@ -55,7 +55,10 @@ system.
|
|
|
55
55
|
Python Version Support
|
|
56
56
|
----------------------
|
|
57
57
|
|
|
58
|
-
**nidaqmx** supports CPython 3.9
|
|
58
|
+
**nidaqmx** supports CPython 3.9+.
|
|
59
|
+
|
|
60
|
+
**nidaqmx** supports PyPy3 for non-gRPC use cases. For the status of PyPy support for gRPC,
|
|
61
|
+
see `PyPy support (grpc/grpc#4221) <https://github.com/grpc/grpc/issues/4221>`_.
|
|
59
62
|
|
|
60
63
|
Installation
|
|
61
64
|
============
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""The NI-DAQmx API for Python."""
|
|
2
|
+
|
|
3
|
+
from nidaqmx.errors import (
|
|
4
|
+
DaqError,
|
|
5
|
+
DaqReadError,
|
|
6
|
+
DaqResourceWarning,
|
|
7
|
+
DaqWarning,
|
|
8
|
+
DaqWriteError,
|
|
9
|
+
)
|
|
10
|
+
from nidaqmx.grpc_session_options import * # noqa: F403 - 'from nidaqmx.grpc_session_options import *' used; unable to detect undefined names (auto-generated noqa)
|
|
11
|
+
from nidaqmx.scale import Scale
|
|
12
|
+
from nidaqmx.task import Task
|
|
13
|
+
from nidaqmx.types import CtrFreq, CtrTick, CtrTime
|
|
14
|
+
|
|
15
|
+
try:
|
|
16
|
+
from importlib.metadata import version
|
|
17
|
+
except ImportError:
|
|
18
|
+
from importlib_metadata import version # type: ignore[no-redef]
|
|
19
|
+
|
|
20
|
+
__version__ = version(__name__)
|
|
21
|
+
|
|
22
|
+
__all__ = [ # noqa: F405 - 'errors' may be undefined, or defined from star imports: nidaqmx.grpc_session_options (auto-generated noqa)
|
|
23
|
+
"errors",
|
|
24
|
+
"scale",
|
|
25
|
+
"stream_readers",
|
|
26
|
+
"stream_writers",
|
|
27
|
+
"task",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
# Do not add a null logging handler. If the application has not configured logging, the
|
|
31
|
+
# default behavior is to log warnings and errors to stderr.
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
"""'nidaqmx' command line utility."""
|
|
2
|
+
|
|
1
3
|
from __future__ import annotations
|
|
2
4
|
|
|
3
5
|
import logging
|
|
4
|
-
from typing import Optional
|
|
5
6
|
|
|
6
7
|
import click
|
|
7
8
|
|
|
@@ -16,12 +17,14 @@ from . import _install_daqmx
|
|
|
16
17
|
count=True,
|
|
17
18
|
help="Enable verbose logging. Repeat to increase verbosity.",
|
|
18
19
|
)
|
|
19
|
-
def main(
|
|
20
|
+
def main( # noqa: D103 - Missing docstring in public function (auto-generated noqa)
|
|
21
|
+
verbosity: int,
|
|
22
|
+
) -> None:
|
|
20
23
|
_configure_logging(verbosity)
|
|
21
24
|
|
|
22
25
|
|
|
23
26
|
@main.command()
|
|
24
|
-
def installdriver():
|
|
27
|
+
def installdriver(): # noqa: D103 - Missing docstring in public function (auto-generated noqa)
|
|
25
28
|
_install_daqmx.installdriver()
|
|
26
29
|
|
|
27
30
|
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
# Do not edit this file; it was automatically generated.
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
2
4
|
import abc
|
|
3
|
-
|
|
5
|
+
import numpy
|
|
6
|
+
from nitypes.waveform import AnalogWaveform, DigitalWaveform
|
|
7
|
+
from typing import Any, Sequence
|
|
8
|
+
from nidaqmx.constants import WaveformAttributeMode
|
|
4
9
|
|
|
5
10
|
|
|
6
11
|
class BaseEventHandler(abc.ABC):
|
|
@@ -1088,6 +1093,10 @@ class BaseInterpreter(abc.ABC):
|
|
|
1088
1093
|
def get_timing_attribute_string(self, task, attribute):
|
|
1089
1094
|
raise NotImplementedError
|
|
1090
1095
|
|
|
1096
|
+
@abc.abstractmethod
|
|
1097
|
+
def get_timing_attribute_timestamp(self, task, attribute):
|
|
1098
|
+
raise NotImplementedError
|
|
1099
|
+
|
|
1091
1100
|
@abc.abstractmethod
|
|
1092
1101
|
def get_timing_attribute_uint32(self, task, attribute):
|
|
1093
1102
|
raise NotImplementedError
|
|
@@ -1845,4 +1854,101 @@ class BaseInterpreter(abc.ABC):
|
|
|
1845
1854
|
|
|
1846
1855
|
@abc.abstractmethod
|
|
1847
1856
|
def hash_task_handle(self, task_handle):
|
|
1848
|
-
raise NotImplementedError
|
|
1857
|
+
raise NotImplementedError
|
|
1858
|
+
|
|
1859
|
+
@abc.abstractmethod
|
|
1860
|
+
def read_analog_waveform(
|
|
1861
|
+
self,
|
|
1862
|
+
task_handle: object,
|
|
1863
|
+
number_of_samples_per_channel: int,
|
|
1864
|
+
timeout: float,
|
|
1865
|
+
waveform: AnalogWaveform[numpy.float64],
|
|
1866
|
+
waveform_attribute_mode: WaveformAttributeMode
|
|
1867
|
+
) -> int:
|
|
1868
|
+
raise NotImplementedError
|
|
1869
|
+
|
|
1870
|
+
@abc.abstractmethod
|
|
1871
|
+
def read_analog_waveforms(
|
|
1872
|
+
self,
|
|
1873
|
+
task_handle: object,
|
|
1874
|
+
number_of_samples_per_channel: int,
|
|
1875
|
+
timeout: float,
|
|
1876
|
+
waveforms: Sequence[AnalogWaveform[numpy.float64]],
|
|
1877
|
+
waveform_attribute_mode: WaveformAttributeMode
|
|
1878
|
+
) -> int:
|
|
1879
|
+
raise NotImplementedError
|
|
1880
|
+
|
|
1881
|
+
@abc.abstractmethod
|
|
1882
|
+
def read_digital_waveform(
|
|
1883
|
+
self,
|
|
1884
|
+
task_handle: object,
|
|
1885
|
+
number_of_samples_per_channel: int,
|
|
1886
|
+
timeout: float,
|
|
1887
|
+
waveform: DigitalWaveform[Any],
|
|
1888
|
+
waveform_attribute_mode: WaveformAttributeMode
|
|
1889
|
+
) -> int:
|
|
1890
|
+
raise NotImplementedError
|
|
1891
|
+
|
|
1892
|
+
@abc.abstractmethod
|
|
1893
|
+
def read_digital_waveforms(
|
|
1894
|
+
self,
|
|
1895
|
+
task_handle: object,
|
|
1896
|
+
channel_count: int,
|
|
1897
|
+
number_of_samples_per_channel: int,
|
|
1898
|
+
number_of_signals_per_sample: int,
|
|
1899
|
+
timeout: float,
|
|
1900
|
+
waveforms: Sequence[DigitalWaveform[Any]],
|
|
1901
|
+
waveform_attribute_mode: WaveformAttributeMode,
|
|
1902
|
+
) -> int:
|
|
1903
|
+
raise NotImplementedError
|
|
1904
|
+
|
|
1905
|
+
@abc.abstractmethod
|
|
1906
|
+
def read_new_digital_waveforms(
|
|
1907
|
+
self,
|
|
1908
|
+
task_handle: object,
|
|
1909
|
+
channel_count: int,
|
|
1910
|
+
number_of_samples_per_channel: int,
|
|
1911
|
+
number_of_signals_per_sample: int,
|
|
1912
|
+
timeout: float,
|
|
1913
|
+
waveform_attribute_mode: WaveformAttributeMode,
|
|
1914
|
+
) -> Sequence[DigitalWaveform[numpy.uint8]]:
|
|
1915
|
+
raise NotImplementedError
|
|
1916
|
+
|
|
1917
|
+
@abc.abstractmethod
|
|
1918
|
+
def write_analog_waveform(
|
|
1919
|
+
self,
|
|
1920
|
+
task_handle: object,
|
|
1921
|
+
waveform: AnalogWaveform[Any],
|
|
1922
|
+
auto_start: bool,
|
|
1923
|
+
timeout: float
|
|
1924
|
+
) -> int:
|
|
1925
|
+
raise NotImplementedError
|
|
1926
|
+
|
|
1927
|
+
@abc.abstractmethod
|
|
1928
|
+
def write_analog_waveforms(
|
|
1929
|
+
self,
|
|
1930
|
+
task_handle: object,
|
|
1931
|
+
waveforms: Sequence[AnalogWaveform[Any]],
|
|
1932
|
+
auto_start: bool,
|
|
1933
|
+
timeout: float
|
|
1934
|
+
) -> int:
|
|
1935
|
+
raise NotImplementedError
|
|
1936
|
+
|
|
1937
|
+
@abc.abstractmethod
|
|
1938
|
+
def write_digital_waveform(
|
|
1939
|
+
self,
|
|
1940
|
+
task_handle: object,
|
|
1941
|
+
waveform: DigitalWaveform[Any],
|
|
1942
|
+
auto_start: bool,
|
|
1943
|
+
timeout: float,
|
|
1944
|
+
) -> int:
|
|
1945
|
+
raise NotImplementedError
|
|
1946
|
+
|
|
1947
|
+
def write_digital_waveforms(
|
|
1948
|
+
self,
|
|
1949
|
+
task_handle: object,
|
|
1950
|
+
waveform: Sequence[DigitalWaveform[Any]],
|
|
1951
|
+
auto_start: bool,
|
|
1952
|
+
timeout: float,
|
|
1953
|
+
) -> int:
|
|
1954
|
+
raise NotImplementedError
|
|
@@ -1,41 +1,38 @@
|
|
|
1
|
-
def enum_bitfield_to_list(bitfield_value, bitfield_enum_type,
|
|
2
|
-
|
|
3
|
-
"""
|
|
4
|
-
Converts a bitfield value to a list of enums.
|
|
1
|
+
def enum_bitfield_to_list(bitfield_value, bitfield_enum_type, actual_enum_type):
|
|
2
|
+
"""Converts a bitfield value to a list of enums.
|
|
5
3
|
|
|
6
4
|
Args:
|
|
7
5
|
bitfield_value (int): Specifies the value of the bitfield.
|
|
8
6
|
bitfield_enum_type (enum.Enum): Specifies the bitfield enum type
|
|
9
7
|
from which to mask and extract the enum values.
|
|
10
8
|
actual_enum_type (enum.Enum): Specifies the actual enum type.
|
|
9
|
+
|
|
11
10
|
Returns:
|
|
12
11
|
List[enum.Enum]: Indicates the converted list of enums.
|
|
13
12
|
"""
|
|
14
13
|
supported_values = []
|
|
15
14
|
for bitfield_mask in bitfield_enum_type:
|
|
16
15
|
if bitfield_value & bitfield_mask.value:
|
|
17
|
-
enum_value = next(
|
|
18
|
-
e for e in actual_enum_type if e.name == bitfield_mask.name)
|
|
16
|
+
enum_value = next(e for e in actual_enum_type if e.name == bitfield_mask.name)
|
|
19
17
|
supported_values.append(enum_value)
|
|
20
18
|
|
|
21
19
|
return supported_values
|
|
22
20
|
|
|
23
21
|
|
|
24
22
|
def enum_list_to_bitfield(enum_list, bitfield_enum_type):
|
|
25
|
-
"""
|
|
26
|
-
Converts a list of enums to a bitfield value.
|
|
23
|
+
"""Converts a list of enums to a bitfield value.
|
|
27
24
|
|
|
28
25
|
Args:
|
|
29
26
|
enum_list (List[enum.Enum]): Specifies the list of enums.
|
|
30
27
|
bitfield_enum_type (enum.Enum): Specifies the bitfield enum type
|
|
31
28
|
from which to mask and extract the enum values.
|
|
29
|
+
|
|
32
30
|
Returns:
|
|
33
31
|
int: Indicates the value of the bitfield.
|
|
34
32
|
"""
|
|
35
33
|
bitfield_value = 0
|
|
36
34
|
for enum_value in enum_list:
|
|
37
|
-
bitfield_mask = next(
|
|
38
|
-
b for b in bitfield_enum_type if b.name == enum_value.name)
|
|
35
|
+
bitfield_mask = next(b for b in bitfield_enum_type if b.name == enum_value.name)
|
|
39
36
|
bitfield_value |= bitfield_mask.value
|
|
40
37
|
|
|
41
|
-
return bitfield_value
|
|
38
|
+
return bitfield_value
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import inspect
|
|
4
|
+
import sys
|
|
5
|
+
import traceback
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_dotenv_search_path() -> Path:
|
|
10
|
+
"""Get the search path for loading the `.env` file."""
|
|
11
|
+
# Prefer to load the `.env` file from the current directory or its parents.
|
|
12
|
+
# If the current directory doesn't have a `.env` file, fall back to the
|
|
13
|
+
# script/EXE path or the TestStand code module path.
|
|
14
|
+
cwd = Path.cwd()
|
|
15
|
+
if not _has_dotenv_file(cwd):
|
|
16
|
+
if script_or_exe_path := _get_script_or_exe_path():
|
|
17
|
+
return script_or_exe_path.resolve().parent
|
|
18
|
+
if caller_path := _get_caller_path():
|
|
19
|
+
return caller_path.resolve().parent
|
|
20
|
+
return cwd
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _has_dotenv_file(dir: Path) -> bool:
|
|
24
|
+
"""Check whether the dir or its parents contains a `.env` file."""
|
|
25
|
+
return (dir / ".env").exists() or any((p / ".env").exists() for p in dir.parents)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _get_script_or_exe_path() -> Path | None:
|
|
29
|
+
"""Get the path of the top-level script or PyInstaller EXE, if possible."""
|
|
30
|
+
if getattr(sys, "frozen", False):
|
|
31
|
+
return Path(sys.executable)
|
|
32
|
+
|
|
33
|
+
main_module = sys.modules.get("__main__")
|
|
34
|
+
if main_module:
|
|
35
|
+
script_path = getattr(main_module, "__file__", "")
|
|
36
|
+
if script_path:
|
|
37
|
+
return Path(script_path)
|
|
38
|
+
|
|
39
|
+
return None
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _get_caller_path() -> Path | None:
|
|
43
|
+
"""Get the path of the module calling into this package, if possible."""
|
|
44
|
+
package_path = _get_package_path()
|
|
45
|
+
for frame, _ in traceback.walk_stack(inspect.currentframe()):
|
|
46
|
+
if frame.f_code.co_filename:
|
|
47
|
+
module_path = Path(frame.f_code.co_filename)
|
|
48
|
+
if _exists(module_path) and not module_path.is_relative_to(package_path):
|
|
49
|
+
return module_path
|
|
50
|
+
|
|
51
|
+
return None
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
# Path.exists() throws OSError when the path has invalid file characters.
|
|
55
|
+
# https://github.com/python/cpython/issues/79487
|
|
56
|
+
if sys.version_info >= (3, 10):
|
|
57
|
+
|
|
58
|
+
def _exists(path: Path) -> bool:
|
|
59
|
+
return path.exists()
|
|
60
|
+
|
|
61
|
+
else:
|
|
62
|
+
|
|
63
|
+
def _exists(path: Path) -> bool:
|
|
64
|
+
import os
|
|
65
|
+
|
|
66
|
+
return os.path.exists(path)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _get_package_path() -> Path:
|
|
70
|
+
"""Get the path of this package."""
|
|
71
|
+
module = sys.modules[__package__]
|
|
72
|
+
assert module.__file__ and module.__file__.endswith("__init__.py")
|
|
73
|
+
return Path(module.__file__).parent
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"""nidaqmx feature toggles."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import functools
|
|
6
|
+
import sys
|
|
7
|
+
from enum import Enum
|
|
8
|
+
from typing import TYPE_CHECKING, Callable, TypeVar
|
|
9
|
+
|
|
10
|
+
from decouple import AutoConfig, Undefined, undefined
|
|
11
|
+
|
|
12
|
+
from nidaqmx._dotenvpath import get_dotenv_search_path
|
|
13
|
+
from nidaqmx.errors import FeatureNotSupportedError
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
if sys.version_info >= (3, 10):
|
|
17
|
+
from typing import ParamSpec
|
|
18
|
+
else:
|
|
19
|
+
from typing_extensions import ParamSpec
|
|
20
|
+
|
|
21
|
+
if sys.version_info >= (3, 11):
|
|
22
|
+
from typing import Self
|
|
23
|
+
else:
|
|
24
|
+
from typing_extensions import Self
|
|
25
|
+
|
|
26
|
+
_P = ParamSpec("_P")
|
|
27
|
+
_T = TypeVar("_T")
|
|
28
|
+
|
|
29
|
+
_PREFIX = "NIDAQMX"
|
|
30
|
+
|
|
31
|
+
_config = AutoConfig(str(get_dotenv_search_path()))
|
|
32
|
+
|
|
33
|
+
if TYPE_CHECKING:
|
|
34
|
+
# Work around decouple's lack of type hints.
|
|
35
|
+
def _config(
|
|
36
|
+
option: str,
|
|
37
|
+
default: _T | Undefined = undefined,
|
|
38
|
+
cast: Callable[[str], _T] | Undefined = undefined,
|
|
39
|
+
) -> _T: ...
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# Based on the recipe at https://docs.python.org/3/howto/enum.html
|
|
43
|
+
class _OrderedEnum(Enum):
|
|
44
|
+
def __ge__(self, other: Self) -> bool:
|
|
45
|
+
if self.__class__ is other.__class__:
|
|
46
|
+
return self.value >= other.value
|
|
47
|
+
return NotImplemented
|
|
48
|
+
|
|
49
|
+
def __gt__(self, other: Self) -> bool:
|
|
50
|
+
if self.__class__ is other.__class__:
|
|
51
|
+
return self.value > other.value
|
|
52
|
+
return NotImplemented
|
|
53
|
+
|
|
54
|
+
def __le__(self, other: Self) -> bool:
|
|
55
|
+
if self.__class__ is other.__class__:
|
|
56
|
+
return self.value <= other.value
|
|
57
|
+
return NotImplemented
|
|
58
|
+
|
|
59
|
+
def __lt__(self, other: Self) -> bool:
|
|
60
|
+
if self.__class__ is other.__class__:
|
|
61
|
+
return self.value < other.value
|
|
62
|
+
return NotImplemented
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class CodeReadiness(_OrderedEnum):
|
|
66
|
+
"""Indicates whether code is ready to be supported."""
|
|
67
|
+
|
|
68
|
+
RELEASE = 0
|
|
69
|
+
NEXT_RELEASE = 1
|
|
70
|
+
INCOMPLETE = 2
|
|
71
|
+
PROTOTYPE = 3
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _init_code_readiness_level() -> CodeReadiness:
|
|
75
|
+
if _config(f"{_PREFIX}_ALLOW_INCOMPLETE", default=False, cast=bool):
|
|
76
|
+
return CodeReadiness.INCOMPLETE
|
|
77
|
+
elif _config(f"{_PREFIX}_ALLOW_NEXT_RELEASE", default=False, cast=bool):
|
|
78
|
+
return CodeReadiness.NEXT_RELEASE
|
|
79
|
+
else:
|
|
80
|
+
return CodeReadiness.RELEASE
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# This is not public because `from _feature_toggles import CODE_READINESS_LEVEL`
|
|
84
|
+
# is incompatible with the patching performed by the use_code_readiness mark.
|
|
85
|
+
_CODE_READINESS_LEVEL = _init_code_readiness_level()
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def get_code_readiness_level() -> CodeReadiness:
|
|
89
|
+
"""Get the current code readiness level.
|
|
90
|
+
|
|
91
|
+
You can override this in tests by specifying the ``use_code_readiness``
|
|
92
|
+
mark.
|
|
93
|
+
"""
|
|
94
|
+
return _CODE_READINESS_LEVEL
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class FeatureToggle:
|
|
98
|
+
"""A run-time feature toggle."""
|
|
99
|
+
|
|
100
|
+
name: str
|
|
101
|
+
"""The name of the feature."""
|
|
102
|
+
|
|
103
|
+
readiness: CodeReadiness
|
|
104
|
+
"""The code readiness at which this feature is enabled."""
|
|
105
|
+
|
|
106
|
+
def __init__(self, name: str, readiness: CodeReadiness) -> None:
|
|
107
|
+
"""Initialize the feature toggle."""
|
|
108
|
+
assert name == name.upper()
|
|
109
|
+
self.name = name
|
|
110
|
+
self.readiness = readiness
|
|
111
|
+
self._is_enabled_override = None
|
|
112
|
+
# Only read the env var at initialization time.
|
|
113
|
+
if _config(f"{_PREFIX}_ENABLE_{name}", default=False, cast=bool):
|
|
114
|
+
self._is_enabled_override = True
|
|
115
|
+
|
|
116
|
+
@property
|
|
117
|
+
def is_enabled(self) -> bool:
|
|
118
|
+
"""Indicates whether the feature is currently enabled.
|
|
119
|
+
|
|
120
|
+
You can enable/disable features in tests by specifying the
|
|
121
|
+
``enable_feature_toggle`` or ``disable_feature_toggle`` marks.
|
|
122
|
+
"""
|
|
123
|
+
if self._is_enabled_override is not None:
|
|
124
|
+
return self._is_enabled_override
|
|
125
|
+
return self.readiness <= get_code_readiness_level()
|
|
126
|
+
|
|
127
|
+
def raise_if_disabled(self) -> None:
|
|
128
|
+
"""Raises an error if the feature is disabled."""
|
|
129
|
+
if self.is_enabled:
|
|
130
|
+
return
|
|
131
|
+
|
|
132
|
+
env_vars = f"{_PREFIX}_ENABLE_{self.name}"
|
|
133
|
+
if self.readiness in [CodeReadiness.NEXT_RELEASE, CodeReadiness.INCOMPLETE]:
|
|
134
|
+
env_vars += f" or {_PREFIX}_ALLOW_{self.readiness.name}"
|
|
135
|
+
message = (
|
|
136
|
+
f"The {self.name} feature is not supported at the current code readiness level. "
|
|
137
|
+
f" To enable it, set {env_vars}."
|
|
138
|
+
)
|
|
139
|
+
raise FeatureNotSupportedError(message)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def requires_feature(
|
|
143
|
+
feature_toggle: FeatureToggle,
|
|
144
|
+
) -> Callable[[Callable[_P, _T]], Callable[_P, _T]]:
|
|
145
|
+
"""Decorator specifying that the function requires the specified feature toggle."""
|
|
146
|
+
|
|
147
|
+
def decorator(func: Callable[_P, _T]) -> Callable[_P, _T]:
|
|
148
|
+
@functools.wraps(func)
|
|
149
|
+
def wrapper(*args: _P.args, **kwargs: _P.kwargs) -> _T:
|
|
150
|
+
feature_toggle.raise_if_disabled()
|
|
151
|
+
return func(*args, **kwargs)
|
|
152
|
+
|
|
153
|
+
return wrapper
|
|
154
|
+
|
|
155
|
+
return decorator
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
# --------------------------------------
|
|
159
|
+
# Define feature toggle constants here:
|
|
160
|
+
# --------------------------------------
|
|
161
|
+
|
|
162
|
+
WAVEFORM_SUPPORT = FeatureToggle("WAVEFORM_SUPPORT", CodeReadiness.INCOMPLETE)
|
|
@@ -5,7 +5,8 @@ import logging
|
|
|
5
5
|
import threading
|
|
6
6
|
import typing
|
|
7
7
|
import warnings
|
|
8
|
-
from
|
|
8
|
+
from nitypes.waveform import AnalogWaveform, DigitalWaveform
|
|
9
|
+
from typing import Any, Callable, Generic, Sequence, TypeVar
|
|
9
10
|
|
|
10
11
|
import google.protobuf.message
|
|
11
12
|
from google.protobuf.timestamp_pb2 import Timestamp as GrpcTimestamp
|
|
@@ -16,7 +17,7 @@ from . import errors as errors
|
|
|
16
17
|
from nidaqmx._base_interpreter import BaseEventHandler, BaseInterpreter
|
|
17
18
|
from nidaqmx._stubs import nidaqmx_pb2 as grpc_types
|
|
18
19
|
from nidaqmx._stubs import nidaqmx_pb2_grpc as nidaqmx_grpc
|
|
19
|
-
from nidaqmx.
|
|
20
|
+
from nidaqmx.constants import WaveformAttributeMode
|
|
20
21
|
from nidaqmx.error_codes import DAQmxErrors
|
|
21
22
|
from nidaqmx._grpc_time import convert_time_to_timestamp, convert_timestamp_to_time
|
|
22
23
|
|
|
@@ -2179,6 +2180,12 @@ class GrpcStubInterpreter(BaseInterpreter):
|
|
|
2179
2180
|
grpc_types.GetTimingAttributeStringRequest(task=task, attribute_raw=attribute))
|
|
2180
2181
|
return response.value
|
|
2181
2182
|
|
|
2183
|
+
def get_timing_attribute_timestamp(self, task, attribute):
|
|
2184
|
+
response = self._invoke(
|
|
2185
|
+
self._client.GetTimingAttributeTimestamp,
|
|
2186
|
+
grpc_types.GetTimingAttributeTimestampRequest(task=task, attribute_raw=attribute))
|
|
2187
|
+
return convert_timestamp_to_time(response.value)
|
|
2188
|
+
|
|
2182
2189
|
def get_timing_attribute_uint32(self, task, attribute):
|
|
2183
2190
|
response = self._invoke(
|
|
2184
2191
|
self._client.GetTimingAttributeUInt32,
|
|
@@ -3600,6 +3607,94 @@ class GrpcStubInterpreter(BaseInterpreter):
|
|
|
3600
3607
|
def internal_get_last_created_chan(self):
|
|
3601
3608
|
raise NotImplementedError
|
|
3602
3609
|
|
|
3610
|
+
def read_analog_waveform(
|
|
3611
|
+
self,
|
|
3612
|
+
task_handle: object,
|
|
3613
|
+
number_of_samples_per_channel: int,
|
|
3614
|
+
timeout: float,
|
|
3615
|
+
waveform: AnalogWaveform[numpy.float64],
|
|
3616
|
+
waveform_attribute_mode: WaveformAttributeMode
|
|
3617
|
+
) -> int:
|
|
3618
|
+
raise NotImplementedError
|
|
3619
|
+
|
|
3620
|
+
def read_analog_waveforms(
|
|
3621
|
+
self,
|
|
3622
|
+
task_handle: object,
|
|
3623
|
+
number_of_samples_per_channel: int,
|
|
3624
|
+
timeout: float,
|
|
3625
|
+
waveforms: Sequence[AnalogWaveform[numpy.float64]],
|
|
3626
|
+
waveform_attribute_mode: WaveformAttributeMode
|
|
3627
|
+
) -> int:
|
|
3628
|
+
raise NotImplementedError
|
|
3629
|
+
|
|
3630
|
+
def read_digital_waveform(
|
|
3631
|
+
self,
|
|
3632
|
+
task_handle: object,
|
|
3633
|
+
number_of_samples_per_channel: int,
|
|
3634
|
+
timeout: float,
|
|
3635
|
+
waveform: DigitalWaveform[Any],
|
|
3636
|
+
waveform_attribute_mode: WaveformAttributeMode
|
|
3637
|
+
) -> int:
|
|
3638
|
+
raise NotImplementedError
|
|
3639
|
+
|
|
3640
|
+
def read_digital_waveforms(
|
|
3641
|
+
self,
|
|
3642
|
+
task_handle: object,
|
|
3643
|
+
channel_count: int,
|
|
3644
|
+
number_of_samples_per_channel: int,
|
|
3645
|
+
number_of_signals_per_sample: int,
|
|
3646
|
+
timeout: float,
|
|
3647
|
+
waveforms: Sequence[DigitalWaveform[Any]],
|
|
3648
|
+
waveform_attribute_mode: WaveformAttributeMode,
|
|
3649
|
+
) -> int:
|
|
3650
|
+
raise NotImplementedError
|
|
3651
|
+
|
|
3652
|
+
def read_new_digital_waveforms(
|
|
3653
|
+
self,
|
|
3654
|
+
task_handle: object,
|
|
3655
|
+
channel_count: int,
|
|
3656
|
+
number_of_samples_per_channel: int,
|
|
3657
|
+
number_of_signals_per_sample: int,
|
|
3658
|
+
timeout: float,
|
|
3659
|
+
waveform_attribute_mode: WaveformAttributeMode,
|
|
3660
|
+
) -> Sequence[DigitalWaveform[numpy.uint8]]:
|
|
3661
|
+
raise NotImplementedError
|
|
3662
|
+
|
|
3663
|
+
def write_analog_waveform(
|
|
3664
|
+
self,
|
|
3665
|
+
task_handle: object,
|
|
3666
|
+
waveform: AnalogWaveform[typing.Any],
|
|
3667
|
+
auto_start: bool,
|
|
3668
|
+
timeout: float
|
|
3669
|
+
) -> int:
|
|
3670
|
+
raise NotImplementedError
|
|
3671
|
+
|
|
3672
|
+
def write_analog_waveforms(
|
|
3673
|
+
self,
|
|
3674
|
+
task_handle: object,
|
|
3675
|
+
waveforms: Sequence[AnalogWaveform[typing.Any]],
|
|
3676
|
+
auto_start: bool,
|
|
3677
|
+
timeout: float
|
|
3678
|
+
) -> int:
|
|
3679
|
+
raise NotImplementedError
|
|
3680
|
+
|
|
3681
|
+
def write_digital_waveform(
|
|
3682
|
+
self,
|
|
3683
|
+
task_handle: object,
|
|
3684
|
+
waveform: DigitalWaveform[Any],
|
|
3685
|
+
auto_start: bool,
|
|
3686
|
+
timeout: float,
|
|
3687
|
+
) -> int:
|
|
3688
|
+
raise NotImplementedError
|
|
3689
|
+
|
|
3690
|
+
def write_digital_waveforms(
|
|
3691
|
+
self,
|
|
3692
|
+
task_handle: object,
|
|
3693
|
+
waveform: Sequence[DigitalWaveform[Any]],
|
|
3694
|
+
auto_start: bool,
|
|
3695
|
+
timeout: float,
|
|
3696
|
+
) -> int:
|
|
3697
|
+
raise NotImplementedError
|
|
3603
3698
|
|
|
3604
3699
|
def _assign_numpy_array(numpy_array, grpc_array):
|
|
3605
3700
|
"""
|