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"); 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" }) }); 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 // TODO: Emebed all assets using build.zig
// https://github.com/ziglang/zig/issues/14637#issuecomment-1428689051 // 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 Platform = @import("./platform.zig");
const Assets = @import("./assets.zig"); const Assets = @import("./assets.zig");
const Graph = @import("./graph.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 rect_utils = @import("./rect-utils.zig");
const remap = @import("./utils.zig").remap; const remap = @import("./utils.zig").remap;
const TaskPool = @import("./task-pool.zig"); const TaskPool = @import("./task-pool.zig");

View File

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

View File

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