Skip to content
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/workflows/build_cmake.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ jobs:
cc: "gcc-9", cxx: "g++-9",
glibc_version: "2_31",
cmake_generator: '-G "Ninja"',
build_type: RelWithDebInfo
build_type: RelWithDebInfo,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made these build config changes in order to get nidaqmx_library.cpp to successfully compile on Ubuntu. As far as I can tell, the problem is that after I added the new library functions in functions.py, the nidaqmx_library.cpp became too large to compile with the original settings. It was either timing out or running out of memory or something.

I'm not sure this is the best way to fix the issue, however. Changing the optimization from O2 to O1 means the grpc device server will be less optimized for everyone on linux, right? Another approach that might work is splitting nidaqmx_library.cpp into multiple smaller .cpp files somehow. What do the reviewers think of that?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you build it locally, does it print any more output, such as

note: variable tracking size limit exceeded with -fvar-tracking-assignments, retrying without

In the past I've sometimes had to use -fno-var-tracking-assignments to compile large code-generated files. I don't know if this option is still relevant or there is a different option nowadays.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, how long does it take to build locally with -O2? Does it eventually succeed?

Copy link
Contributor Author

@mikeprosserni mikeprosserni Oct 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have a linux machine to build locally on, I've been relying on the CI build for this. All I can see is this, after 33 minutes:

[2601/3669] Building CXX object CMakeFiles/IntegrationTestsRunner.dir/generated/nidaqmx/nidaqmx_library.cpp.o
ninja: build stopped: interrupted by user.
Error: Process completed with exit code 143.

https://github.com/ni/grpc-device/actions/runs/18659129011/job/53195445860

or, when I added --verbose:

[2601/3669] /usr/bin/g++-9 -DCARES_STATICLIB -DTEST_API_BUILDING -DTestApi -D_CRT_SECURE_NO_WARNINGS -D_WINSOCK_DEPRECATED_NO_WARNINGS -Iproto -I.././generated -I.././imports/include -I.././source -I.././third_party/grpc-sideband/src -I.././third_party/grpc-sideband/moniker_src -I../third_party/grpc/include -I../third_party/grpc/third_party/abseil-cpp -I../third_party/grpc/third_party/re2 -Igrpc/third_party/cares/cares -I../third_party/grpc/third_party/cares/cares -I../third_party/grpc/third_party/cares/cares/include -I../third_party/grpc/third_party/boringssl-with-bazel/src/include -I../third_party/grpc/third_party/protobuf/src -I../third_party/utfcpp/source -I../third_party/grpc-sideband/src -I../third_party/grpc-sideband/moniker_src -I../third_party/json/include -isystem ../third_party/googletest/googlemock/include -isystem ../third_party/googletest/googlemock -isystem ../third_party/googletest/googletest/include -isystem ../third_party/googletest/googletest -O2 -g -DNDEBUG -std=c++17 -MD -MT CMakeFiles/IntegrationTestsRunner.dir/generated/nidaqmx/nidaqmx_library.cpp.o -MF CMakeFiles/IntegrationTestsRunner.dir/generated/nidaqmx/nidaqmx_library.cpp.o.d -o CMakeFiles/IntegrationTestsRunner.dir/generated/nidaqmx/nidaqmx_library.cpp.o -c ../generated/nidaqmx/nidaqmx_library.cpp
ninja: build stopped: interrupted by user.
Error: Process completed with exit code 143.

https://github.com/ni/grpc-device/actions/runs/18663525332/job/53209586512

I did some googling and some guessing, and figured resource exhaustion was the most likely explanation for exit code 143. So I changed the build parameters to see if that would get the CI to build successfully, and it did. That's all I know at this point.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VTA is a potential cause of resource exhaustion. This feature tracks variable locations for each line of code in order to produce debug info that accurately shows the variable values when you step through the function, even if it's inlined. However, when your code has hundreds of variable assignments in the same function, this feature can take a lot of CPU and memory. I don't know exactly why.

VTA only affects the debugging experience, not execution speed, so if turning it off solves your problem, then it's a better solution than using -O1 and turning off a bunch of optimizations.

Please try updating https://github.com/ni/grpc-device/blob/main/source/codegen/templates/service.cpp.mako to use #pragma GCC optimize to scope the -fno-var-tracking-assignments or -O1 to *_library.cpp. You will need to guard this pragma with #ifdef __GNUC__ or similar.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this PR, I've reverted the changes to build_cmake and implemented your suggested changes to service.cpp.mako, and nidaqmx_library.cpp is still compiling without crashing.

As another data point, I tried a different strategy in a different PR, where I reverted the other changes in build_cmake, and just used -j ${{ runner.os == 'Linux' && '2' || steps.cpu-cores.outputs.count }}, which also allwed nidaqmx_library.cpp to compile without crashing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked out your branch on my laptop, commented out the -fno-var-tracking-assignments, and ran time cmake --build . -j 16 --config RelWithDebInfo on WSL:

real    21m28.891s
user    298m4.721s
sys     30m30.097s

Running .ninja_log through https://github.com/nico/ninjatracing shows

image

It seems like all of the DAQmx files are problem files, taking >3 minutes to compile.

cmake_flags: '"-DCMAKE_CXX_FLAGS_RELWITHDEBINFO=-O1 -g -DNDEBUG"'
}

steps:
Expand Down Expand Up @@ -82,6 +83,7 @@ jobs:
-B build
-D CMAKE_BUILD_TYPE=${{ matrix.config.build_type }}
${{ matrix.config.cmake_generator }}
${{ matrix.config.cmake_flags }}

# It is preferable to do a clean build to ensure all object files are
# deleted and then rebuilt from scratch, which can help resolve
Expand All @@ -92,7 +94,7 @@ jobs:
--build build
--clean-first
--config ${{ matrix.config.build_type }}
-j ${{ steps.cpu-cores.outputs.count }}
-j 2

# The generated source in git must match the output of workflow builds.
# If this step fails, something is changing during build. Either:
Expand Down
62 changes: 60 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,8 @@ get_filename_component(deviceid_restricted_proto "source/protobuf_restricted/dev
get_filename_component(debugsessionproperties_restricted_proto "source/protobuf_restricted/debugsessionproperties_restricted.proto" ABSOLUTE)
get_filename_component(calibrationoperations_restricted_proto "source/protobuf_restricted/calibrationoperations_restricted.proto" ABSOLUTE)
get_filename_component(data_moniker_proto "imports/protobuf/data_moniker.proto" ABSOLUTE)
get_filename_component(precision_timestamp_proto "third_party/ni-apis/ni/protobuf/types/precision_timestamp.proto" ABSOLUTE)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to your last PR, I think you'll need to update stage_client_files.py to get these proto files included in GitHub releases and the AzDo consumed adhoc exports.

get_filename_component(waveform_proto "third_party/ni-apis/ni/protobuf/types/waveform.proto" ABSOLUTE)
get_filename_component(session_proto_path "${session_proto}" PATH)

#----------------------------------------------------------------------
Expand All @@ -303,8 +305,9 @@ function(GenerateGrpcSources)
set(proto_file "${GENERATE_ARGS_PROTO}")
if(USE_SUBMODULE_LIBS)
set(protobuf_includes_arg
-I ${CMAKE_SOURCE_DIR}/third_party/grpc/third_party/protobuf/src/
-I ${CMAKE_SOURCE_DIR}/third_party/ni-apis/ni/grpcdevice/v1/) # for session.proto
-I ${CMAKE_SOURCE_DIR}/third_party/grpc/third_party/protobuf/src/
-I ${CMAKE_SOURCE_DIR}/third_party/ni-apis/ni/grpcdevice/v1/ # for session.proto
-I ${CMAKE_SOURCE_DIR}/third_party/ni-apis/)
endif()
get_filename_component(proto_name "${proto_file}" NAME)
get_filename_component(proto_path "${proto_file}" PATH)
Expand Down Expand Up @@ -346,6 +349,34 @@ function(GenerateGrpcSources)
endif()
endfunction()

#----------------------------------------------------------------------
# Generate sources from ni-apis proto files
# Usage: GenerateNiApisProtoSources(PROTO_PATH <relative_path> OUTPUT_SRCS <var> OUTPUT_HDRS <var> [DEPENDS <dependency>...])
#----------------------------------------------------------------------
function(GenerateNiApisProtoSources)
set(oneValueArgs PROTO_PATH OUTPUT_SRCS OUTPUT_HDRS)
set(multiValueArgs DEPENDS)
cmake_parse_arguments(GEN_ARGS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

set(proto_srcs "${proto_srcs_dir}/${GEN_ARGS_PROTO_PATH}.pb.cc")
set(proto_hdrs "${proto_srcs_dir}/${GEN_ARGS_PROTO_PATH}.pb.h")

add_custom_command(
OUTPUT "${proto_srcs}" "${proto_hdrs}"
COMMAND ${_PROTOBUF_PROTOC}
ARGS --cpp_out ${proto_srcs_dir}
-I ${CMAKE_SOURCE_DIR}/third_party/ni-apis/
-I ${CMAKE_SOURCE_DIR}/third_party/grpc/third_party/protobuf/src/
${GEN_ARGS_PROTO_PATH}.proto
DEPENDS "${CMAKE_SOURCE_DIR}/third_party/ni-apis/${GEN_ARGS_PROTO_PATH}.proto" ${GEN_ARGS_DEPENDS}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/third_party/ni-apis/
VERBATIM
)

set(${GEN_ARGS_OUTPUT_SRCS} "${proto_srcs}" PARENT_SCOPE)
set(${GEN_ARGS_OUTPUT_HDRS} "${proto_hdrs}" PARENT_SCOPE)
endfunction()

set(session_proto_srcs "${proto_srcs_dir}/session.pb.cc")
set(session_proto_hdrs "${proto_srcs_dir}/session.pb.h")
set(session_grpc_srcs "${proto_srcs_dir}/session.grpc.pb.cc")
Expand All @@ -372,6 +403,10 @@ set(data_moniker_proto_srcs "${proto_srcs_dir}/data_moniker.pb.cc")
set(data_moniker_proto_hdrs "${proto_srcs_dir}/data_moniker.pb.h")
set(data_moniker_grpc_srcs "${proto_srcs_dir}/data_moniker.grpc.pb.cc")
set(data_moniker_grpc_hdrs "${proto_srcs_dir}/data_moniker.grpc.pb.h")
set(precision_timestamp_proto_srcs "${proto_srcs_dir}/ni/protobuf/types/precision_timestamp.pb.cc")
set(precision_timestamp_proto_hdrs "${proto_srcs_dir}/ni/protobuf/types/precision_timestamp.pb.h")
set(waveform_proto_srcs "${proto_srcs_dir}/ni/protobuf/types/waveform.pb.cc")
set(waveform_proto_hdrs "${proto_srcs_dir}/ni/protobuf/types/waveform.pb.h")

GenerateGrpcSources(
PROTO
Expand Down Expand Up @@ -441,6 +476,19 @@ GenerateGrpcSources(
"${data_moniker_grpc_hdrs}"
)

GenerateNiApisProtoSources(
PROTO_PATH "ni/protobuf/types/precision_timestamp"
OUTPUT_SRCS precision_timestamp_proto_srcs
OUTPUT_HDRS precision_timestamp_proto_hdrs
)

GenerateNiApisProtoSources(
PROTO_PATH "ni/protobuf/types/waveform"
OUTPUT_SRCS waveform_proto_srcs
OUTPUT_HDRS waveform_proto_hdrs
DEPENDS "${precision_timestamp_proto_hdrs}"
)

set(nidriver_service_library_hdrs
${nidriver_service_library_hdrs}
"${session_proto_hdrs}"
Expand All @@ -454,6 +502,8 @@ set(nidriver_service_library_hdrs
"${debugsessionproperties_restricted_grpc_hdrs}"
"${calibrationoperations_restricted_proto_hdrs}"
"${calibrationoperations_restricted_grpc_hdrs}"
"${precision_timestamp_proto_hdrs}"
"${waveform_proto_hdrs}"
)

foreach(api ${nidrivers})
Expand Down Expand Up @@ -514,6 +564,8 @@ add_executable(ni_grpc_device_server
${calibrationoperations_restricted_grpc_srcs}
${data_moniker_proto_srcs}
${data_moniker_grpc_srcs}
${precision_timestamp_proto_srcs}
${waveform_proto_srcs}
${nidriver_service_srcs})

# Enable warnings only on source that we own, not generated code or dependencies
Expand Down Expand Up @@ -655,6 +707,8 @@ add_executable(IntegrationTestsRunner
${calibrationoperations_restricted_grpc_srcs}
${data_moniker_proto_srcs}
${data_moniker_grpc_srcs}
${precision_timestamp_proto_srcs}
${waveform_proto_srcs}
${nidriver_service_srcs}
"${proto_srcs_dir}/nifake.pb.cc"
"${proto_srcs_dir}/nifake.grpc.pb.cc"
Expand Down Expand Up @@ -742,6 +796,8 @@ add_executable(UnitTestsRunner
${calibrationoperations_restricted_grpc_srcs}
${data_moniker_proto_srcs}
${data_moniker_grpc_srcs}
${precision_timestamp_proto_srcs}
${waveform_proto_srcs}
"${proto_srcs_dir}/nifake.pb.cc"
"${proto_srcs_dir}/nifake.grpc.pb.cc"
"${proto_srcs_dir}/nifake_extension.pb.cc"
Expand Down Expand Up @@ -879,6 +935,8 @@ set(system_test_runner_sources
${calibrationoperations_restricted_grpc_srcs}
${data_moniker_proto_srcs}
${data_moniker_grpc_srcs}
${precision_timestamp_proto_srcs}
${waveform_proto_srcs}
${nidriver_service_srcs}
${nidriver_client_srcs}
)
Expand Down
12 changes: 12 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,18 @@ Build a release build for use in a production environment:
> cmake --build . --config Release
```

### Build with Ninja

Build faster by using Ninja:

```
> "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
> mkdir build
> cd build
> cmake .. -G "Ninja Multi-Config"
> cmake --build .
```

## Building on Linux

### Prerequisites
Expand Down
23 changes: 23 additions & 0 deletions generated/nidaqmx/nidaqmx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package nidaqmx_grpc;

import "session.proto";
import "data_moniker.proto";
import "ni/protobuf/types/waveform.proto";
import "google/protobuf/timestamp.proto";

service NiDAQmx {
Expand Down Expand Up @@ -465,6 +466,7 @@ service NiDAQmx {
rpc BeginWriteRaw(BeginWriteRawRequest) returns (BeginWriteRawResponse);
rpc WriteToTEDSFromArray(WriteToTEDSFromArrayRequest) returns (WriteToTEDSFromArrayResponse);
rpc WriteToTEDSFromFile(WriteToTEDSFromFileRequest) returns (WriteToTEDSFromFileResponse);
rpc ReadAnalogWaveforms(ReadAnalogWaveformsRequest) returns (ReadAnalogWaveformsResponse);
}

enum BufferUInt32Attribute {
Expand Down Expand Up @@ -3558,6 +3560,12 @@ enum WriteBasicTEDSOptions {
WRITE_BASIC_TEDS_OPTIONS_DO_NOT_WRITE = 12540;
}

enum WaveformAttributeMode {
WAVEFORM_ATTRIBUTE_MODE_NONE = 0;
WAVEFORM_ATTRIBUTE_MODE_TIMING = 1;
WAVEFORM_ATTRIBUTE_MODE_EXTENDED_PROPERTIES = 2;
}

enum ChannelInt32AttributeValues {
option allow_alias = true;
CHANNEL_INT32_UNSPECIFIED = 0;
Expand Down Expand Up @@ -11511,3 +11519,18 @@ message WriteToTEDSFromFileResponse {
int32 status = 1;
}

message ReadAnalogWaveformsRequest {
nidevice_grpc.Session task = 1;
int32 number_of_samples_per_channel = 2;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ReadAnalogF64 calls this num_samps_per_chan. Nothing in nidaqmx.proto spells out "number_of_samples".

double timeout = 3;
oneof waveform_attribute_mode_enum {
WaveformAttributeMode waveform_attribute_mode = 4;
int32 waveform_attribute_mode_raw = 5;
}
}

message ReadAnalogWaveformsResponse {
int32 status = 1;
repeated ni.protobuf.types.DoubleAnalogWaveform waveforms = 2;
}

27 changes: 27 additions & 0 deletions generated/nidaqmx/nidaqmx_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12414,5 +12414,32 @@ write_to_teds_from_file(const StubPtr& stub, const std::string& physical_channel
return response;
}

ReadAnalogWaveformsResponse
read_analog_waveforms(const StubPtr& stub, const nidevice_grpc::Session& task, const pb::int32& number_of_samples_per_channel, const double& timeout, const simple_variant<WaveformAttributeMode, pb::int32>& waveform_attribute_mode)
{
::grpc::ClientContext context;

auto request = ReadAnalogWaveformsRequest{};
request.mutable_task()->CopyFrom(task);
request.set_number_of_samples_per_channel(number_of_samples_per_channel);
request.set_timeout(timeout);
const auto waveform_attribute_mode_ptr = waveform_attribute_mode.get_if<WaveformAttributeMode>();
const auto waveform_attribute_mode_raw_ptr = waveform_attribute_mode.get_if<pb::int32>();
if (waveform_attribute_mode_ptr) {
request.set_waveform_attribute_mode(*waveform_attribute_mode_ptr);
}
else if (waveform_attribute_mode_raw_ptr) {
request.set_waveform_attribute_mode_raw(*waveform_attribute_mode_raw_ptr);
}

auto response = ReadAnalogWaveformsResponse{};

raise_if_error(
stub->ReadAnalogWaveforms(&context, request, &response),
context);

return response;
}


} // namespace nidaqmx_grpc::experimental::client
1 change: 1 addition & 0 deletions generated/nidaqmx/nidaqmx_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,7 @@ WriteRawResponse write_raw(const StubPtr& stub, const nidevice_grpc::Session& ta
BeginWriteRawResponse begin_write_raw(const StubPtr& stub, const nidevice_grpc::Session& task, const pb::int32& num_samps, const bool& auto_start, const double& timeout);
WriteToTEDSFromArrayResponse write_to_teds_from_array(const StubPtr& stub, const std::string& physical_channel, const std::string& bit_stream, const simple_variant<WriteBasicTEDSOptions, pb::int32>& basic_teds_options);
WriteToTEDSFromFileResponse write_to_teds_from_file(const StubPtr& stub, const std::string& physical_channel, const std::string& file_path, const simple_variant<WriteBasicTEDSOptions, pb::int32>& basic_teds_options);
ReadAnalogWaveformsResponse read_analog_waveforms(const StubPtr& stub, const nidevice_grpc::Session& task, const pb::int32& number_of_samples_per_channel, const double& timeout, const simple_variant<WaveformAttributeMode, pb::int32>& waveform_attribute_mode);

} // namespace nidaqmx_grpc::experimental::client

Expand Down
45 changes: 45 additions & 0 deletions generated/nidaqmx/nidaqmx_library.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,11 @@ NiDAQmxLibrary::NiDAQmxLibrary(std::shared_ptr<nidevice_grpc::SharedLibraryInter
function_pointers_.GetWriteAttributeString = reinterpret_cast<GetWriteAttributeStringPtr>(shared_library_->get_function_pointer("DAQmxGetWriteAttribute"));
function_pointers_.GetWriteAttributeUInt32 = reinterpret_cast<GetWriteAttributeUInt32Ptr>(shared_library_->get_function_pointer("DAQmxGetWriteAttribute"));
function_pointers_.GetWriteAttributeUInt64 = reinterpret_cast<GetWriteAttributeUInt64Ptr>(shared_library_->get_function_pointer("DAQmxGetWriteAttribute"));
function_pointers_.InternalGetLastCreatedChan = reinterpret_cast<InternalGetLastCreatedChanPtr>(shared_library_->get_function_pointer("DAQmxInternalGetLastCreatedChan"));
function_pointers_.InternalReadAnalogWaveformPerChan = reinterpret_cast<InternalReadAnalogWaveformPerChanPtr>(shared_library_->get_function_pointer("DAQmxInternalReadAnalogWaveformPerChan"));
function_pointers_.InternalReadDigitalWaveform = reinterpret_cast<InternalReadDigitalWaveformPtr>(shared_library_->get_function_pointer("DAQmxInternalReadDigitalWaveform"));
function_pointers_.InternalWriteAnalogWaveformPerChan = reinterpret_cast<InternalWriteAnalogWaveformPerChanPtr>(shared_library_->get_function_pointer("DAQmxInternalWriteAnalogWaveformPerChan"));
function_pointers_.InternalWriteDigitalWaveform = reinterpret_cast<InternalWriteDigitalWaveformPtr>(shared_library_->get_function_pointer("DAQmxInternalWriteDigitalWaveform"));
function_pointers_.IsTaskDone = reinterpret_cast<IsTaskDonePtr>(shared_library_->get_function_pointer("DAQmxIsTaskDone"));
function_pointers_.LoadTask = reinterpret_cast<LoadTaskPtr>(shared_library_->get_function_pointer("DAQmxLoadTask"));
function_pointers_.PerformBridgeOffsetNullingCalEx = reinterpret_cast<PerformBridgeOffsetNullingCalExPtr>(shared_library_->get_function_pointer("DAQmxPerformBridgeOffsetNullingCalEx"));
Expand Down Expand Up @@ -2368,6 +2373,46 @@ int32 NiDAQmxLibrary::GetWriteAttributeUInt64(TaskHandle task, int32 attribute,
return function_pointers_.GetWriteAttributeUInt64(task, attribute, value);
}

int32 NiDAQmxLibrary::InternalGetLastCreatedChan(char value[], uInt32 size)
{
if (!function_pointers_.InternalGetLastCreatedChan) {
throw nidevice_grpc::LibraryLoadException("Could not find DAQmxInternalGetLastCreatedChan.");
}
return function_pointers_.InternalGetLastCreatedChan(value, size);
}

int32 NiDAQmxLibrary::InternalReadAnalogWaveformPerChan(TaskHandle task, int32 numSampsPerChan, float64 timeout, int64 t0Array[], int64 dtArray[], uInt32 timingArraySize, DAQmxSetWfmAttrCallbackPtr setWfmAttrCallback, void* setWfmAttrCallbackData, float64 * readArrayPtrs[], uInt32 readArrayCount, uInt32 arraySizeInSampsPerChan, int32* sampsPerChanRead, bool32* reserved)
{
if (!function_pointers_.InternalReadAnalogWaveformPerChan) {
throw nidevice_grpc::LibraryLoadException("Could not find DAQmxInternalReadAnalogWaveformPerChan.");
}
return function_pointers_.InternalReadAnalogWaveformPerChan(task, numSampsPerChan, timeout, t0Array, dtArray, timingArraySize, setWfmAttrCallback, setWfmAttrCallbackData, readArrayPtrs, readArrayCount, arraySizeInSampsPerChan, sampsPerChanRead, reserved);
}

int32 NiDAQmxLibrary::InternalReadDigitalWaveform(TaskHandle task, int32 numSampsPerChan, float64 timeout, bool32 fillMode, int64 t0Array[], int64 dtArray[], uInt32 timingArraySize, DAQmxSetWfmAttrCallbackPtr setWfmAttrCallback, void* setWfmAttrCallbackData, uInt8 readArray[], uInt32 arraySizeInBytes, int32* sampsPerChanRead, int32* numBytesPerSamp, uInt32 bytesPerChanArray[], uInt32 bytesPerChanArraySize, bool32* reserved)
{
if (!function_pointers_.InternalReadDigitalWaveform) {
throw nidevice_grpc::LibraryLoadException("Could not find DAQmxInternalReadDigitalWaveform.");
}
return function_pointers_.InternalReadDigitalWaveform(task, numSampsPerChan, timeout, fillMode, t0Array, dtArray, timingArraySize, setWfmAttrCallback, setWfmAttrCallbackData, readArray, arraySizeInBytes, sampsPerChanRead, numBytesPerSamp, bytesPerChanArray, bytesPerChanArraySize, reserved);
}

int32 NiDAQmxLibrary::InternalWriteAnalogWaveformPerChan(TaskHandle task, int32 numSampsPerChan, bool32 autoStart, float64 timeout, const float64 * const writeArrayPtrs[], uInt32 writeArrayCount, int32* sampsPerChanWritten, bool32* reserved)
{
if (!function_pointers_.InternalWriteAnalogWaveformPerChan) {
throw nidevice_grpc::LibraryLoadException("Could not find DAQmxInternalWriteAnalogWaveformPerChan.");
}
return function_pointers_.InternalWriteAnalogWaveformPerChan(task, numSampsPerChan, autoStart, timeout, writeArrayPtrs, writeArrayCount, sampsPerChanWritten, reserved);
}

int32 NiDAQmxLibrary::InternalWriteDigitalWaveform(TaskHandle task, int32 numSampsPerChan, bool32 autoStart, float64 timeout, bool32 dataLayout, const uInt8 writeArray[], const uInt32 bytesPerChanArray[], uInt32 bytesPerChanArraySize, int32* sampsPerChanWritten, bool32* reserved)
{
if (!function_pointers_.InternalWriteDigitalWaveform) {
throw nidevice_grpc::LibraryLoadException("Could not find DAQmxInternalWriteDigitalWaveform.");
}
return function_pointers_.InternalWriteDigitalWaveform(task, numSampsPerChan, autoStart, timeout, dataLayout, writeArray, bytesPerChanArray, bytesPerChanArraySize, sampsPerChanWritten, reserved);
}

int32 NiDAQmxLibrary::IsTaskDone(TaskHandle task, bool32* isTaskDone)
{
if (!function_pointers_.IsTaskDone) {
Expand Down
Loading