Remove system dependency on nidaqmx

This commit is contained in:
Rokas Puzonas 2025-02-07 20:49:25 +02:00
parent 4db4b9fa81
commit 6eea7329c8
6 changed files with 156 additions and 95 deletions

View File

@ -27,11 +27,6 @@ pub fn build(b: *std.Build) !void {
const external_compiler_support_dir = try std.process.getEnvVarOwned(b.allocator, "NIEXTCCOMPILERSUPP");
exe.addSystemIncludePath(.{ .cwd_relative = try std.fs.path.join(b.allocator, &.{ external_compiler_support_dir, "include" }) });
const lib_folder_name = if (target.result.ptrBitWidth() == 64) "lib64" else "lib32";
exe.addLibraryPath(.{ .cwd_relative = try std.fs.path.join(b.allocator, &.{ external_compiler_support_dir, lib_folder_name, "msvc" }) });
exe.linkSystemLibrary("nidaqmx");
// TODO: Emebed all assets using build.zig
// https://github.com/ziglang/zig/issues/14637#issuecomment-1428689051

View File

@ -5,7 +5,7 @@ const UI = @import("./ui.zig");
const Platform = @import("./platform.zig");
const Assets = @import("./assets.zig");
const Graph = @import("./graph.zig");
const NIDaq = @import("ni-daq.zig");
const NIDaq = @import("ni-daq/root.zig");
const rect_utils = @import("./rect-utils.zig");
const remap = @import("./utils.zig").remap;
const TaskPool = @import("./task-pool.zig");

View File

@ -153,7 +153,7 @@ pub fn main() !void {
defer app.deinit();
if (builtin.mode == .Debug) {
try app.appendChannelFromDevice("Dev1/ai0");
// try app.appendChannelFromDevice("Dev1/ai0");
// try app.appendChannelFromFile("samples/HeLa Cx37_ 40nM GFX + 35uM Propofol_18-Sep-2024_0003_I.bin");
// try app.appendChannelFromFile("samples/HeLa Cx37_ 40nM GFX + 35uM Propofol_18-Sep-2024_0003_IjStim.bin");
}
@ -191,5 +191,5 @@ pub fn main() !void {
}
test {
_ = @import("./ni-daq.zig");
_ = @import("./ni-daq/root.zig");
}

59
src/ni-daq/api.zig Normal file
View File

@ -0,0 +1,59 @@
const std = @import("std");
pub const c = @cImport({
@cInclude("stdint.h");
@cDefine("__int64", "long long");
@cInclude("NIDAQmx.h");
});
const Api = @This();
const log = std.log.scoped(.ni_daq_api);
lib: std.DynLib, // This MUST be the first field of `Api` struct
DAQmxGetSysNIDAQMajorVersion: *const @TypeOf(c.DAQmxGetSysNIDAQMajorVersion),
DAQmxGetSysNIDAQMinorVersion: *const @TypeOf(c.DAQmxGetSysNIDAQMinorVersion),
DAQmxGetSysNIDAQUpdateVersion: *const @TypeOf(c.DAQmxGetSysNIDAQUpdateVersion),
DAQmxGetErrorString: *const @TypeOf(c.DAQmxGetErrorString),
DAQmxStopTask: *const @TypeOf(c.DAQmxStopTask),
DAQmxStartTask: *const @TypeOf(c.DAQmxStartTask),
DAQmxClearTask: *const @TypeOf(c.DAQmxClearTask),
DAQmxGetTaskName: *const @TypeOf(c.DAQmxGetTaskName),
DAQmxCfgSampClkTiming: *const @TypeOf(c.DAQmxCfgSampClkTiming),
DAQmxCreateTask: *const @TypeOf(c.DAQmxCreateTask),
DAQmxCreateAIVoltageChan: *const @TypeOf(c.DAQmxCreateAIVoltageChan),
DAQmxGetSysDevNames: *const @TypeOf(c.DAQmxGetSysDevNames),
DAQmxGetDevAIVoltageRngs: *const @TypeOf(c.DAQmxGetDevAIVoltageRngs),
DAQmxGetDevAOVoltageRngs: *const @TypeOf(c.DAQmxGetDevAOVoltageRngs),
DAQmxGetDevAIMaxSingleChanRate: *const @TypeOf(c.DAQmxGetDevAIMaxSingleChanRate),
DAQmxGetDevAOMaxRate: *const @TypeOf(c.DAQmxGetDevAOMaxRate),
DAQmxGetDevAIMinRate: *const @TypeOf(c.DAQmxGetDevAIMinRate),
DAQmxGetDevAOMinRate: *const @TypeOf(c.DAQmxGetDevAOMinRate),
DAQmxGetDevAISupportedMeasTypes: *const @TypeOf(c.DAQmxGetDevAISupportedMeasTypes),
DAQmxGetDevAOSupportedOutputTypes: *const @TypeOf(c.DAQmxGetDevAOSupportedOutputTypes),
DAQmxGetDevProductCategory: *const @TypeOf(c.DAQmxGetDevProductCategory),
DAQmxGetDevAIPhysicalChans: *const @TypeOf(c.DAQmxGetDevAIPhysicalChans),
DAQmxGetDevAOPhysicalChans: *const @TypeOf(c.DAQmxGetDevAOPhysicalChans),
DAQmxReadAnalogF64: *const @TypeOf(c.DAQmxReadAnalogF64),
pub fn init() !Api {
var api: Api = undefined;
api.lib = try std.DynLib.open("nicaiu");
errdefer api.lib.close();
inline for (@typeInfo(Api).Struct.fields[1..]) |field| {
const name = std.fmt.comptimePrint("{s}\x00", .{field.name});
const name_z = name[0 .. (name.len - 1) :0];
@field(api, field.name) = api.lib.lookup(field.type, name_z) orelse {
log.err("Symbol lookup failed for {s}", .{name});
return error.SymbolLookup;
};
}
return api;
}
pub fn deinit(self: *Api) void {
self.lib.close();
}

View File

@ -1,9 +1,6 @@
const std = @import("std");
pub const c = @cImport({
@cInclude("stdint.h");
@cDefine("__int64", "long long");
@cInclude("NIDAQmx.h");
});
const Api = @import("./api.zig");
pub const c = Api.c;
const assert = std.debug.assert;
const log = std.log.scoped(.ni_daq);
@ -38,6 +35,7 @@ pub const Options = struct {
};
pub const Task = struct {
ni_daq: *NIDaq,
handle: TaskHandle,
name_buffer: [max_task_name_size]u8 = undefined,
@ -45,19 +43,23 @@ pub const Task = struct {
dropped_samples: u32 = 0,
pub fn clear(self: Task) void {
logDAQmxError(c.DAQmxClearTask(self.handle));
// Ignore error
const api = self.ni_daq.api;
self.ni_daq.logDAQmxError(api.DAQmxClearTask(self.handle));
}
pub fn name(self: *Task) ![]const u8 {
const required_size = c.DAQmxGetTaskName(self.handle, null, 0);
const api = self.ni_daq.api;
const required_size = api.DAQmxGetTaskName(self.handle, null, 0);
assert(required_size >= 0);
if (required_size > self.name_buffer.len) {
return error.BufferTooSmall;
}
try checkDAQmxError(
c.DAQmxGetTaskName(
try self.ni_daq.checkDAQmxError(
api.DAQmxGetTaskName(
self.handle,
&self.name_buffer,
self.name_buffer.len
@ -69,29 +71,33 @@ pub const Task = struct {
}
pub fn start(self: Task) !void {
try checkDAQmxError(
c.DAQmxStartTask(self.handle),
const api = self.ni_daq.api;
try self.ni_daq.checkDAQmxError(
api.DAQmxStartTask(self.handle),
error.DAQmxStartTask
);
}
pub fn stop(self: Task) !void {
try checkDAQmxError(
c.DAQmxStopTask(self.handle),
const api = self.ni_daq.api;
try self.ni_daq.checkDAQmxError(
api.DAQmxStopTask(self.handle),
error.DAQmxStopTask
);
}
pub fn setContinousSampleRate(self: Task, sample_rate: f64) !void {
try checkDAQmxError(
c.DAQmxCfgSampClkTiming(self.handle, null, sample_rate, c.DAQmx_Val_Rising, c.DAQmx_Val_ContSamps, 0),
const api = self.ni_daq.api;
try self.ni_daq.checkDAQmxError(
api.DAQmxCfgSampClkTiming(self.handle, null, sample_rate, c.DAQmx_Val_Rising, c.DAQmx_Val_ContSamps, 0),
error.DAQmxCfgSampClkTiming
);
}
pub fn setFiniteSampleRate(self: Task, sample_rate: f64, samples_per_channel: u64) !void {
try checkDAQmxError(
c.DAQmxCfgSampClkTiming(self.handle, null, sample_rate, c.DAQmx_Val_Rising, c.DAQmx_Val_FiniteSamps, samples_per_channel),
const api = self.ni_daq.api;
try self.ni_daq.checkDAQmxError(
api.DAQmxCfgSampClkTiming(self.handle, null, sample_rate, c.DAQmx_Val_Rising, c.DAQmx_Val_FiniteSamps, samples_per_channel),
error.DAQmxCfgSampClkTiming
);
}
@ -107,8 +113,9 @@ pub const Task = struct {
};
pub fn createAIVoltageChannel(self: Task, options: AIVoltageChannelOptions) !void {
try checkDAQmxError(
c.DAQmxCreateAIVoltageChan(
const api = self.ni_daq.api;
try self.ni_daq.checkDAQmxError(
api.DAQmxCreateAIVoltageChan(
self.handle,
options.channel,
options.assigned_name,
@ -132,7 +139,7 @@ pub const Task = struct {
};
pub fn createAOVoltageChannel(self: Task, options: AOVoltageChannelOptions) !void {
try checkDAQmxError(
try self.ni_daq.checkDAQmxError(
c.DAQmxCreateAOVoltageChan(
self.handle,
options.channel,
@ -155,8 +162,9 @@ pub const Task = struct {
};
pub fn readAnalog(self: *Task, options: ReadAnalogOptions) !u32 {
const api = self.ni_daq.api;
var samples_per_channel: i32 = 0;
const err = c.DAQmxReadAnalogF64(
const err = api.DAQmxReadAnalogF64(
self.handle,
options.samples_per_channel,
options.timeout,
@ -171,7 +179,7 @@ pub const Task = struct {
self.dropped_samples += 1;
log.err("Dropped samples, not reading samples fast enough.", .{});
} else if (err < 0) {
try checkDAQmxError(err, error.DAQmxReadAnalogF64);
try self.ni_daq.checkDAQmxError(err, error.DAQmxReadAnalogF64);
}
return @intCast(samples_per_channel);
@ -179,7 +187,7 @@ pub const Task = struct {
pub fn isDone(self: Task) !bool {
var result: c.bool32 = 0;
try checkDAQmxError(
try self.ni_daq.checkDAQmxError(
c.DAQmxIsTaskDone(self.handle, &result),
error.DAQmxIsTaskDone
);
@ -365,12 +373,16 @@ const DeviceBuffers = struct {
};
options: Options,
api: Api,
device_names_buffer: []u8,
device_names: StringArrayListUnmanaged,
device_buffers: []DeviceBuffers,
pub fn init(allocator: std.mem.Allocator, options: Options) !NIDaq {
var api = try Api.init();
errdefer api.deinit();
const device_names_buffer_size = options.max_devices * (max_device_name_size + 2);
const device_names_buffer = try allocator.alloc(u8, device_names_buffer_size);
errdefer allocator.free(device_names_buffer);
@ -388,6 +400,7 @@ pub fn init(allocator: std.mem.Allocator, options: Options) !NIDaq {
return NIDaq{
.options = options,
.api = api,
.device_names_buffer = device_names_buffer,
.device_names = device_names,
.device_buffers = device_buffers
@ -395,6 +408,8 @@ pub fn init(allocator: std.mem.Allocator, options: Options) !NIDaq {
}
pub fn deinit(self: *NIDaq, allocator: std.mem.Allocator) void {
self.api.deinit();
self.device_names.deinit(allocator);
allocator.free(self.device_names_buffer);
@ -423,33 +438,33 @@ test {
try std.testing.expectEqual(3, maxIndexStringLength(101));
}
pub fn logDAQmxError(error_code: i32) void {
pub fn logDAQmxError(self: NIDaq, error_code: i32) void {
if (error_code == 0) {
return;
}
var msg: [512:0]u8 = .{ 0 } ** 512;
if (c.DAQmxGetErrorString(error_code, &msg, msg.len) == 0) {
if (self.api.DAQmxGetErrorString(error_code, &msg, msg.len) == 0) {
log.err("DAQmx ({}): {s}", .{error_code, msg});
} else {
log.err("DAQmx ({}): Unknown (Buffer too small for message)", .{error_code});
}
}
pub fn checkDAQmxError(error_code: i32, err: anyerror) !void {
logDAQmxError(error_code);
pub fn checkDAQmxError(self: NIDaq, error_code: i32, err: anyerror) !void {
self.logDAQmxError(error_code);
if (error_code < 0) {
return err;
}
}
pub fn checkDAQmxErrorIgnoreWarnings(error_code: i32, err: anyerror) !void {
pub fn checkDAQmxErrorIgnoreWarnings(self: NIDaq, error_code: i32, err: anyerror) !void {
if (error_code > 0) {
return;
}
try checkDAQmxError(error_code, err);
try self.checkDAQmxError(error_code, err);
}
fn splitCommaDelimitedList(array_list: *std.ArrayListUnmanaged([:0]const u8), buffer: []u8) !void {
@ -471,22 +486,22 @@ fn splitCommaDelimitedList(array_list: *std.ArrayListUnmanaged([:0]const u8), bu
}
}
pub fn version() !std.SemanticVersion {
pub fn version(self: NIDaq) !std.SemanticVersion {
var major: u32 = 0;
try checkDAQmxError(
c.DAQmxGetSysNIDAQMajorVersion(&major),
try self.checkDAQmxError(
self.api.DAQmxGetSysNIDAQMajorVersion(&major),
error.GetMajorVersion
);
var minor: u32 = 0;
try checkDAQmxError(
c.DAQmxGetSysNIDAQMinorVersion(&minor),
try self.checkDAQmxError(
self.api.DAQmxGetSysNIDAQMinorVersion(&minor),
error.GetMinorVersion
);
var update: u32 = 0;
try checkDAQmxError(
c.DAQmxGetSysNIDAQUpdateVersion(&update),
try self.checkDAQmxError(
self.api.DAQmxGetSysNIDAQUpdateVersion(&update),
error.GetUpdateVersion
);
@ -501,8 +516,8 @@ pub fn listDeviceNames(self: *NIDaq) ![]const [:0]const u8 {
self.device_names.clearRetainingCapacity();
self.clearAllDeviceBuffers();
const required_size = c.DAQmxGetSysDevNames(null, 0);
try checkDAQmxErrorIgnoreWarnings(required_size, error.DAQmxGetSysDevNames);
const required_size = self.api.DAQmxGetSysDevNames(null, 0);
try self.checkDAQmxErrorIgnoreWarnings(required_size, error.DAQmxGetSysDevNames);
if (required_size == 0) {
return self.device_names.items;
}
@ -511,8 +526,8 @@ pub fn listDeviceNames(self: *NIDaq) ![]const [:0]const u8 {
return error.BufferTooSmall;
}
try checkDAQmxError(
c.DAQmxGetSysDevNames(self.device_names_buffer.ptr, @intCast(self.device_names_buffer.len)),
try self.checkDAQmxError(
self.api.DAQmxGetSysDevNames(self.device_names_buffer.ptr, @intCast(self.device_names_buffer.len)),
error.GetDeviceNames
);
@ -549,6 +564,7 @@ fn clearAllDeviceBuffers(self: *NIDaq) void {
}
fn listDevicePhysicalChannels(
self: NIDaq,
getPhysicalChannels: anytype,
device: [:0]const u8,
channel_names: *DeviceBuffers.ChannelNames,
@ -559,7 +575,7 @@ fn listDevicePhysicalChannels(
array_list.clearRetainingCapacity();
const required_size = getPhysicalChannels(device, null, 0);
try checkDAQmxErrorIgnoreWarnings(required_size, error.GetPhysicalChannels);
try self.checkDAQmxErrorIgnoreWarnings(required_size, error.GetPhysicalChannels);
if (required_size == 0) {
return array_list.items;
}
@ -568,7 +584,7 @@ fn listDevicePhysicalChannels(
return error.BufferTooSmall;
}
try checkDAQmxError(
try self.checkDAQmxError(
getPhysicalChannels(device, buffer.ptr, @intCast(buffer.len)),
error.GetPhysicalChannels
);
@ -584,8 +600,8 @@ fn listDevicePhysicalChannels(
pub fn listDeviceAIPhysicalChannels(self: *NIDaq, device: [:0]const u8) ![]const [:0]const u8 {
var device_buffers = try self.getDeviceBuffers(device);
return listDevicePhysicalChannels(
c.DAQmxGetDevAIPhysicalChans,
return self.listDevicePhysicalChannels(
self.api.DAQmxGetDevAIPhysicalChans,
device,
&device_buffers.analog_input_names
);
@ -594,8 +610,8 @@ pub fn listDeviceAIPhysicalChannels(self: *NIDaq, device: [:0]const u8) ![]const
pub fn listDeviceAOPhysicalChannels(self: *NIDaq, device: [:0]const u8) ![]const [:0]const u8 {
var device_buffers = try self.getDeviceBuffers(device);
return listDevicePhysicalChannels(
c.DAQmxGetDevAOPhysicalChans,
return self.listDevicePhysicalChannels(
self.api.DAQmxGetDevAOPhysicalChans,
device,
&device_buffers.analog_output_names
);
@ -604,7 +620,7 @@ pub fn listDeviceAOPhysicalChannels(self: *NIDaq, device: [:0]const u8) ![]const
pub fn listDeviceCOPhysicalChannels(self: *NIDaq, device: [:0]const u8) ![]const [:0]const u8 {
var device_buffers = try self.getDeviceBuffers(device);
return listDevicePhysicalChannels(
return self.listDevicePhysicalChannels(
c.DAQmxGetDevCOPhysicalChans,
device,
&device_buffers.counter_output_names
@ -614,7 +630,7 @@ pub fn listDeviceCOPhysicalChannels(self: *NIDaq, device: [:0]const u8) ![]const
pub fn listDeviceCIPhysicalChannels(self: *NIDaq, device: [:0]const u8) ![]const [:0]const u8 {
var device_buffers = try self.getDeviceBuffers(device);
return listDevicePhysicalChannels(
return self.listDevicePhysicalChannels(
c.DAQmxGetDevCIPhysicalChans,
device,
&device_buffers.counter_input_names
@ -646,21 +662,19 @@ fn getChannelType(device: [:0]const u8) ?ChannelType {
}
pub fn getMinSampleRate(self: NIDaq, channel: [:0]const u8) !f64 {
_ = self;
var result: f64 = 0;
const channel_type = getChannelType(channel) orelse return error.UnknownChannelType;
switch (channel_type) {
.analog_input => {
try checkDAQmxError(
c.DAQmxGetDevAIMinRate(channel, &result),
try self.checkDAQmxError(
self.api.DAQmxGetDevAIMinRate(channel, &result),
error.DAQmxGetDevAIMinRate
);
},
.analog_output => {
try checkDAQmxError(
c.DAQmxGetDevAOMinRate(channel, &result),
try self.checkDAQmxError(
self.api.DAQmxGetDevAOMinRate(channel, &result),
error.DAQmxGetDevAOMinRate
);
},
@ -674,21 +688,19 @@ pub fn getMinSampleRate(self: NIDaq, channel: [:0]const u8) !f64 {
}
pub fn getMaxSampleRate(self: NIDaq, channel: [:0]const u8) !f64 {
_ = self;
var result: f64 = 0;
const channel_type = getChannelType(channel) orelse return error.UnknownChannelType;
switch (channel_type) {
.analog_input => {
try checkDAQmxError(
c.DAQmxGetDevAIMaxSingleChanRate(channel, &result),
try self.checkDAQmxError(
self.api.DAQmxGetDevAIMaxSingleChanRate(channel, &result),
error.DAQmxGetDevAIMaxSingleChanRate
);
},
.analog_output => {
try checkDAQmxError(
c.DAQmxGetDevAOMaxRate(channel, &result),
try self.checkDAQmxError(
self.api.DAQmxGetDevAOMaxRate(channel, &result),
error.DAQmxGetDevAOMaxRate
);
},
@ -702,6 +714,7 @@ pub fn getMaxSampleRate(self: NIDaq, channel: [:0]const u8) !f64 {
}
fn listDeviceVoltageRanges(
self: NIDaq,
getVoltageRanges: anytype,
device: [:0]const u8,
voltage_ranges: *std.ArrayListUnmanaged(Range)
@ -709,7 +722,7 @@ fn listDeviceVoltageRanges(
voltage_ranges.clearRetainingCapacity();
const count = getVoltageRanges(device, null, 0);
try checkDAQmxErrorIgnoreWarnings(count, error.GetVoltageRanges);
try self.checkDAQmxErrorIgnoreWarnings(count, error.GetVoltageRanges);
if (count == 0) {
return voltage_ranges.items;
}
@ -722,7 +735,7 @@ fn listDeviceVoltageRanges(
return error.BufferTooSmall;
}
try checkDAQmxError(
try self.checkDAQmxError(
getVoltageRanges(device, buffer, @intCast(buffer_len)),
error.GetVoltageRanges
);
@ -735,8 +748,8 @@ fn listDeviceVoltageRanges(
pub fn listDeviceAIVoltageRanges(self: *NIDaq, device: [:0]const u8) ![]Range {
var device_buffers = try self.getDeviceBuffers(device);
return listDeviceVoltageRanges(
c.DAQmxGetDevAIVoltageRngs,
return self.listDeviceVoltageRanges(
self.api.DAQmxGetDevAIVoltageRngs,
device,
&device_buffers.analog_input_voltage_ranges
);
@ -745,36 +758,33 @@ pub fn listDeviceAIVoltageRanges(self: *NIDaq, device: [:0]const u8) ![]Range {
pub fn listDeviceAOVoltageRanges(self: *NIDaq, device: [:0]const u8) ![]Range {
var device_buffers = try self.getDeviceBuffers(device);
return listDeviceVoltageRanges(
c.DAQmxGetDevAOVoltageRngs,
return self.listDeviceVoltageRanges(
self.api.DAQmxGetDevAOVoltageRngs,
device,
&device_buffers.analog_output_voltage_ranges
);
}
pub fn createTask(self: NIDaq, name: ?[:0]const u8) !Task {
_ = self;
pub fn createTask(self: *NIDaq, name: ?[:0]const u8) !Task {
var handle: TaskHandle = undefined;
try checkDAQmxError(
c.DAQmxCreateTask(name orelse "", &handle),
try self.checkDAQmxError(
self.api.DAQmxCreateTask(name orelse "", &handle),
error.DAQmxCreateTask
);
return Task{ .handle = handle };
return Task{ .ni_daq = self, .handle = handle };
}
pub fn listDeviceAIMeasurementTypes(self: NIDaq, device: [:0]const u8) !AIMeasurementTypeList {
var result = AIMeasurementTypeList.init(0) catch unreachable;
_ = self;
const count = c.DAQmxGetDevAISupportedMeasTypes(device, null, 0);
try checkDAQmxErrorIgnoreWarnings(count, error.DAQmxGetDevAISupportedMeasTypes);
const count = self.api.DAQmxGetDevAISupportedMeasTypes(device, null, 0);
try self.checkDAQmxErrorIgnoreWarnings(count, error.DAQmxGetDevAISupportedMeasTypes);
assert(count <= result.buffer.len);
try checkDAQmxError(
c.DAQmxGetDevAISupportedMeasTypes(device, @as([*c]c_int, @ptrCast(&result.buffer)), result.buffer.len),
try self.checkDAQmxError(
self.api.DAQmxGetDevAISupportedMeasTypes(device, @as([*c]c_int, @ptrCast(&result.buffer)), result.buffer.len),
error.DAQmxGetDevAISupportedMeasTypes
);
@ -790,14 +800,13 @@ pub fn checkDeviceAIMeasurementType(self: NIDaq, device: [:0]const u8, measureme
pub fn listDeviceAOOutputTypes(self: NIDaq, device: [:0]const u8) !AOOutputTypeList {
var result = AOOutputTypeList.init(0) catch unreachable;
_ = self;
const count = c.DAQmxGetDevAOSupportedOutputTypes(device, null, 0);
try checkDAQmxErrorIgnoreWarnings(count, error.DAQmxGetDevAOSupportedOutputTypes);
const count = self.api.DAQmxGetDevAOSupportedOutputTypes(device, null, 0);
try self.checkDAQmxErrorIgnoreWarnings(count, error.DAQmxGetDevAOSupportedOutputTypes);
assert(count <= result.buffer.len);
try checkDAQmxError(
c.DAQmxGetDevAOSupportedOutputTypes(device, @as([*c]c_int, @ptrCast(&result.buffer)), result.buffer.len),
try self.checkDAQmxError(
self.api.DAQmxGetDevAOSupportedOutputTypes(device, @as([*c]c_int, @ptrCast(&result.buffer)), result.buffer.len),
error.DAQmxGetDevAOSupportedOutputTypes
);
@ -812,11 +821,9 @@ pub fn checkDeviceAOOutputType(self: NIDaq, device: [:0]const u8, output_type: A
}
pub fn getDeviceProductCategory(self: NIDaq, device: [:0]const u8) !ProductCategory {
_ = self;
var product_category = ProductCategory.Unknown;
try checkDAQmxError(
c.DAQmxGetDevProductCategory(device, @ptrCast(&product_category)),
try self.checkDAQmxError(
self.api.DAQmxGetDevProductCategory(device, @ptrCast(&product_category)),
error.DAQmxGetDevProductCategory
);

View File

@ -1,5 +1,5 @@
const std = @import("std");
const NIDaq = @import("./ni-daq.zig");
const NIDaq = @import("./ni-daq/root.zig");
const assert = std.debug.assert;
const log = std.log.scoped(.task_pool);