add saving of project settings
This commit is contained in:
parent
d2b4942fa0
commit
293d220b34
@ -2,13 +2,20 @@
|
|||||||
.name = "Baigiamasis projektas",
|
.name = "Baigiamasis projektas",
|
||||||
.version = "0.1.0",
|
.version = "0.1.0",
|
||||||
|
|
||||||
.dependencies = .{ .@"raylib-zig" = .{ .url = "https://github.com/Not-Nik/raylib-zig/archive/43d15b05c2b97cab30103fa2b46cff26e91619ec.tar.gz", .hash = "12204a223b19043e17b79300413d02f60fc8004c0d9629b8d8072831e352a78bf212" }, .@"known-folders" = .{
|
.dependencies = .{
|
||||||
.url = "git+https://github.com/ziglibs/known-folders.git#1cceeb70e77dec941a4178160ff6c8d05a74de6f",
|
.@"raylib-zig" = .{
|
||||||
.hash = "12205f5e7505c96573f6fc5144592ec38942fb0a326d692f9cddc0c7dd38f9028f29",
|
.url = "https://github.com/Not-Nik/raylib-zig/archive/43d15b05c2b97cab30103fa2b46cff26e91619ec.tar.gz",
|
||||||
}, .ini = .{
|
.hash = "12204a223b19043e17b79300413d02f60fc8004c0d9629b8d8072831e352a78bf212"
|
||||||
.url = "https://github.com/ziglibs/ini/archive/e18d36665905c1e7ba0c1ce3e8780076b33e3002.tar.gz",
|
},
|
||||||
.hash = "1220b0979ea9891fa4aeb85748fc42bc4b24039d9c99a4d65d893fb1c83e921efad8",
|
.@"known-folders" = .{
|
||||||
}, .@"profiler.zig" = .{
|
.url = "git+https://github.com/ziglibs/known-folders.git#1cceeb70e77dec941a4178160ff6c8d05a74de6f",
|
||||||
|
.hash = "12205f5e7505c96573f6fc5144592ec38942fb0a326d692f9cddc0c7dd38f9028f29",
|
||||||
|
},
|
||||||
|
.ini = .{
|
||||||
|
.url = "https://github.com/ziglibs/ini/archive/e18d36665905c1e7ba0c1ce3e8780076b33e3002.tar.gz",
|
||||||
|
.hash = "1220b0979ea9891fa4aeb85748fc42bc4b24039d9c99a4d65d893fb1c83e921efad8",
|
||||||
|
},
|
||||||
|
.@"profiler.zig" = .{
|
||||||
.url = "git+https://github.com/lassade/profiler.zig.git#d066d066c36c4eebd494babf15c1cdbd2d512b12",
|
.url = "git+https://github.com/lassade/profiler.zig.git#d066d066c36c4eebd494babf15c1cdbd2d512b12",
|
||||||
.hash = "122097461acc2064f5f89b85d76d2a02232579864b17604617a333789c892f2d262f",
|
.hash = "122097461acc2064f5f89b85d76d2a02232579864b17604617a333789c892f2d262f",
|
||||||
},
|
},
|
||||||
|
313
src/app.zig
313
src/app.zig
@ -28,6 +28,10 @@ pub const Id = packed struct {
|
|||||||
return @bitCast(self);
|
return @bitCast(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn fromInt(self: u32) Id {
|
||||||
|
return @bitCast(self);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn eql(self: Id, other: Id) bool {
|
pub fn eql(self: Id, other: Id) bool {
|
||||||
return @as(u32, @bitCast(self)) == @as(u32, @bitCast(other));
|
return @as(u32, @bitCast(self)) == @as(u32, @bitCast(other));
|
||||||
}
|
}
|
||||||
@ -78,6 +82,16 @@ fn GenerationalArray(Item: type) type {
|
|||||||
used: UsedBitSet = UsedBitSet.initFull(),
|
used: UsedBitSet = UsedBitSet.initFull(),
|
||||||
items: [Id.max_items]GenerationalItem = undefined,
|
items: [Id.max_items]GenerationalItem = undefined,
|
||||||
|
|
||||||
|
pub fn insertUndefinedAt(self: *Self, id: Id) !void {
|
||||||
|
if (!self.used.isSet(id.index)) {
|
||||||
|
return error.NotEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.used.unset(id.index);
|
||||||
|
|
||||||
|
self.items[id.index].generation = id.generation;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn insertUndefined(self: *Self) !Id {
|
pub fn insertUndefined(self: *Self) !Id {
|
||||||
const index: Id.Index = @intCast(self.used.findFirstSet() orelse return error.OutOfMemory);
|
const index: Id.Index = @intCast(self.used.findFirstSet() orelse return error.OutOfMemory);
|
||||||
|
|
||||||
@ -96,11 +110,11 @@ fn GenerationalArray(Item: type) type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove(self: *Self, id: Id) void {
|
pub fn remove(self: *Self, id: Id) void {
|
||||||
if (self.used.isSet(id.generation)) {
|
if (self.used.isSet(id.index)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.used.set(id.generation);
|
self.used.set(id.index);
|
||||||
self.items[id.index].generation += 1;
|
self.items[id.index].generation += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,7 +127,7 @@ fn GenerationalArray(Item: type) type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn has(self: *Self, id: Id) bool {
|
pub fn has(self: *Self, id: Id) bool {
|
||||||
if (self.used.isSet(id.generation)) {
|
if (self.used.isSet(id.index)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,9 +166,9 @@ pub const Channel = struct {
|
|||||||
|
|
||||||
// Persistent
|
// Persistent
|
||||||
name: Name = .{},
|
name: Name = .{},
|
||||||
device: Device = .{},
|
|
||||||
|
|
||||||
// Runtime
|
// Runtime
|
||||||
|
device: Device = .{},
|
||||||
allowed_sample_values: ?RangeF64 = null,
|
allowed_sample_values: ?RangeF64 = null,
|
||||||
allowed_sample_rates: ?RangeF64 = null,
|
allowed_sample_rates: ?RangeF64 = null,
|
||||||
collected_samples: std.ArrayListUnmanaged(f64) = .{},
|
collected_samples: std.ArrayListUnmanaged(f64) = .{},
|
||||||
@ -263,6 +277,10 @@ pub const View = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const Project = struct {
|
pub const Project = struct {
|
||||||
|
const file_endian = std.builtin.Endian.big;
|
||||||
|
const file_format_version: u8 = 0;
|
||||||
|
|
||||||
|
save_location: ?[]u8 = null,
|
||||||
sample_rate: ?f64 = null,
|
sample_rate: ?f64 = null,
|
||||||
|
|
||||||
channels: GenerationalArray(Channel) = .{},
|
channels: GenerationalArray(Channel) = .{},
|
||||||
@ -307,6 +325,215 @@ pub const Project = struct {
|
|||||||
while (channel_iter.next()) |channel| {
|
while (channel_iter.next()) |channel| {
|
||||||
channel.deinit(allocator);
|
channel.deinit(allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (self.save_location) |str| {
|
||||||
|
allocator.free(str);
|
||||||
|
self.save_location = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------- Serialization ------------------ //
|
||||||
|
|
||||||
|
pub fn initFromFile(allocator: Allocator, save_location: []const u8) !Project {
|
||||||
|
var self = Project{};
|
||||||
|
|
||||||
|
const f = try std.fs.cwd().openFile(save_location, .{});
|
||||||
|
defer f.close();
|
||||||
|
|
||||||
|
const reader = f.reader();
|
||||||
|
|
||||||
|
const version = try readInt(reader, u8);
|
||||||
|
if (version != file_format_version) {
|
||||||
|
return error.VersionMismatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.sample_rate = try readFloat(reader, f64);
|
||||||
|
if (self.sample_rate == 0) {
|
||||||
|
self.sample_rate = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // Channels
|
||||||
|
const channel_count = try readInt(reader, u32);
|
||||||
|
for (0..channel_count) |_| {
|
||||||
|
const id = try readId(reader);
|
||||||
|
|
||||||
|
try self.channels.insertUndefinedAt(id);
|
||||||
|
|
||||||
|
const channel_name = try readString(reader, allocator);
|
||||||
|
defer allocator.free(channel_name);
|
||||||
|
|
||||||
|
const channel = self.channels.get(id).?;
|
||||||
|
channel.* = Channel{
|
||||||
|
.name = try utils.initBoundedStringZ(Channel.Name, channel_name)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // Files
|
||||||
|
const file_count = try readInt(reader, u32);
|
||||||
|
for (0..file_count) |_| {
|
||||||
|
const id = try readId(reader);
|
||||||
|
|
||||||
|
try self.files.insertUndefinedAt(id);
|
||||||
|
|
||||||
|
const path = try readString(reader, allocator);
|
||||||
|
errdefer allocator.free(path);
|
||||||
|
|
||||||
|
const file = self.files.get(id).?;
|
||||||
|
file.* = File{
|
||||||
|
.path = path
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // Views
|
||||||
|
const view_count = try readInt(reader, u32);
|
||||||
|
for (0..view_count) |_| {
|
||||||
|
const id = try readId(reader);
|
||||||
|
|
||||||
|
try self.views.insertUndefinedAt(id);
|
||||||
|
|
||||||
|
const reference_tag = try readInt(reader, u8);
|
||||||
|
var reference: View.Reference = undefined;
|
||||||
|
if (reference_tag == @intFromEnum(View.Reference.file)) {
|
||||||
|
reference = .{
|
||||||
|
.file = try readId(reader)
|
||||||
|
};
|
||||||
|
} else if (reference_tag == @intFromEnum(View.Reference.channel)) {
|
||||||
|
reference = .{
|
||||||
|
.channel = try readId(reader)
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return error.InvalidReferenceTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
const view = self.views.get(id).?;
|
||||||
|
view.* = View{
|
||||||
|
.reference = reference,
|
||||||
|
};
|
||||||
|
|
||||||
|
view.graph_opts.x_range = try readRangeF64(reader);
|
||||||
|
view.graph_opts.y_range = try readRangeF64(reader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.save_location = try allocator.dupe(u8, save_location);
|
||||||
|
errdefer allocator.free(self.save_location);
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn save(self: *Project) !void {
|
||||||
|
const save_location = self.save_location orelse return error.NoSaveLocation;
|
||||||
|
|
||||||
|
const f = try std.fs.cwd().createFile(save_location, .{});
|
||||||
|
defer f.close();
|
||||||
|
|
||||||
|
const writer = f.writer();
|
||||||
|
|
||||||
|
try writeInt(writer, u8, file_format_version);
|
||||||
|
try writeFloat(writer, f64, self.sample_rate orelse 0);
|
||||||
|
|
||||||
|
{ // Channels
|
||||||
|
try writeInt(writer, u32, @intCast(self.channels.count()));
|
||||||
|
var channel_iter = self.channels.idIterator();
|
||||||
|
while (channel_iter.next()) |channel_id| {
|
||||||
|
const channel = self.channels.get(channel_id).?;
|
||||||
|
const channel_name = utils.getBoundedStringZ(&channel.name);
|
||||||
|
|
||||||
|
try writeId(writer, channel_id);
|
||||||
|
try writeString(writer, channel_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // Files
|
||||||
|
try writeInt(writer, u32, @intCast(self.files.count()));
|
||||||
|
var file_iter = self.files.idIterator();
|
||||||
|
while (file_iter.next()) |file_id| {
|
||||||
|
const file = self.files.get(file_id).?;
|
||||||
|
|
||||||
|
try writeId(writer, file_id);
|
||||||
|
try writeString(writer, file.path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // Views
|
||||||
|
try writeInt(writer, u32, @intCast(self.views.count()));
|
||||||
|
var view_iter = self.views.idIterator();
|
||||||
|
while (view_iter.next()) |view_id| {
|
||||||
|
const view = self.views.get(view_id).?;
|
||||||
|
|
||||||
|
try writeId(writer, view_id);
|
||||||
|
try writeInt(writer, u8, @intFromEnum(view.reference));
|
||||||
|
switch (view.reference) {
|
||||||
|
.channel => |channel_id| {
|
||||||
|
try writeInt(writer, u32, channel_id.asInt());
|
||||||
|
},
|
||||||
|
.file => |file_id| {
|
||||||
|
try writeInt(writer, u32, file_id.asInt());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try writeRangeF64(writer, view.graph_opts.x_range);
|
||||||
|
try writeRangeF64(writer, view.graph_opts.y_range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn writeRangeF64(writer: anytype, range: RangeF64) !void {
|
||||||
|
try writeFloat(writer, f64, range.lower);
|
||||||
|
try writeFloat(writer, f64, range.upper);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readRangeF64(writer: anytype) !RangeF64 {
|
||||||
|
var range: RangeF64 = undefined;
|
||||||
|
|
||||||
|
range.lower = try readFloat(writer, f64);
|
||||||
|
range.upper = try readFloat(writer, f64);
|
||||||
|
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readInt(reader: anytype, T: type) !T {
|
||||||
|
return try reader.readInt(T, file_endian);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn writeInt(writer: anytype, T: type, value: T) !void {
|
||||||
|
try writer.writeInt(T, value, file_endian);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readId(reader: anytype) !Id {
|
||||||
|
const id_u32 = try readInt(reader, u32);
|
||||||
|
return Id.fromInt(id_u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn writeId(writer: anytype, value: Id) !void {
|
||||||
|
try writer.writeInt(u32, value.asInt(), file_endian);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn writeFloat(writer: anytype, T: type, value: T) !void {
|
||||||
|
const bytes = std.mem.asBytes(&value);
|
||||||
|
try writer.writeAll(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readFloat(reader: anytype, T: type) !T {
|
||||||
|
var buff: [@sizeOf(T)]u8 = undefined;
|
||||||
|
try reader.readNoEof(&buff);
|
||||||
|
return std.mem.bytesToValue(T, &buff);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn writeString(writer: anytype, text: []const u8) !void {
|
||||||
|
try writeInt(writer, u32, @intCast(text.len));
|
||||||
|
try writer.writeAll(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn readString(reader: anytype, allocator: Allocator) ![]u8 {
|
||||||
|
// TODO: This could be risky. `str_len` can be a really large number and in turn request a really large allocation.
|
||||||
|
const str_len = try readInt(reader, u32);
|
||||||
|
const buff = try allocator.alloc(u8, str_len);
|
||||||
|
errdefer allocator.free(buff);
|
||||||
|
try reader.readNoEof(buff);
|
||||||
|
return buff;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -314,6 +541,7 @@ pub const Command = union(enum) {
|
|||||||
start_collection,
|
start_collection,
|
||||||
stop_collection,
|
stop_collection,
|
||||||
save_project,
|
save_project,
|
||||||
|
load_project,
|
||||||
stop_output: Id, // Channel id
|
stop_output: Id, // Channel id
|
||||||
start_output: Id, // Channel id
|
start_output: Id, // Channel id
|
||||||
add_file_from_picker
|
add_file_from_picker
|
||||||
@ -390,11 +618,14 @@ pub fn init(self: *App, allocator: Allocator) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *App) void {
|
pub fn deinit(self: *App) void {
|
||||||
self.stopCollection();
|
self.deinitProject();
|
||||||
|
|
||||||
|
self.should_close = true;
|
||||||
|
self.collection_condition.signal();
|
||||||
|
self.collection_thread.join();
|
||||||
|
|
||||||
self.ui.deinit();
|
self.ui.deinit();
|
||||||
self.main_screen.deinit();
|
self.main_screen.deinit();
|
||||||
self.project.deinit(self.allocator);
|
|
||||||
|
|
||||||
if (self.ni_daq) |*ni_daq| {
|
if (self.ni_daq) |*ni_daq| {
|
||||||
ni_daq.deinit(self.allocator);
|
ni_daq.deinit(self.allocator);
|
||||||
@ -405,9 +636,50 @@ pub fn deinit(self: *App) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn loadProject(self: *App, project_file: []const u8) !void {
|
pub fn deinitProject(self: *App) void {
|
||||||
_ = self;
|
self.stopCollection();
|
||||||
_ = project_file;
|
self.project.deinit(self.allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn loadProject(self: *App) !void {
|
||||||
|
const save_location = self.project.save_location orelse return error.MissingSaveLocation;
|
||||||
|
|
||||||
|
log.info("Load project from: {s}", .{save_location});
|
||||||
|
|
||||||
|
const loaded = try Project.initFromFile(self.allocator, save_location);
|
||||||
|
errdefer loaded.deinit(self.allocator);
|
||||||
|
|
||||||
|
self.deinitProject();
|
||||||
|
self.project = loaded;
|
||||||
|
|
||||||
|
var file_iter = self.project.files.idIterator();
|
||||||
|
while (file_iter.next()) |file_id| {
|
||||||
|
self.loadFile(file_id) catch |e| {
|
||||||
|
log.err("Failed to load file: {}", .{ e });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var channel_iter = self.project.channels.idIterator();
|
||||||
|
while (channel_iter.next()) |channel_id| {
|
||||||
|
self.loadChannel(channel_id) catch |e| {
|
||||||
|
log.err("Failed to load channel: {}", .{ e });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var view_iter = self.project.views.idIterator();
|
||||||
|
while (view_iter.next()) |view_id| {
|
||||||
|
self.loadView(view_id) catch |e| {
|
||||||
|
log.err("Failed to load view: {}", .{ e });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn saveProject(self: *App) !void {
|
||||||
|
const save_location = self.project.save_location orelse return error.MissingSaveLocation;
|
||||||
|
|
||||||
|
log.info("Save project to: {s}", .{save_location});
|
||||||
|
|
||||||
|
try self.project.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick(self: *App) !void {
|
pub fn tick(self: *App) !void {
|
||||||
@ -415,6 +687,15 @@ pub fn tick(self: *App) !void {
|
|||||||
self.command_queue.len = 0;
|
self.command_queue.len = 0;
|
||||||
|
|
||||||
ui.pullOsEvents();
|
ui.pullOsEvents();
|
||||||
|
|
||||||
|
if (ui.isCtrlDown() and ui.isKeyboardPressed(.key_s)) {
|
||||||
|
self.pushCommand(.save_project);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ui.isCtrlDown() and ui.isKeyboardPressed(.key_l)) {
|
||||||
|
self.pushCommand(.load_project);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
self.collection_samples_mutex.lock();
|
self.collection_samples_mutex.lock();
|
||||||
defer self.collection_samples_mutex.unlock();
|
defer self.collection_samples_mutex.unlock();
|
||||||
@ -447,10 +728,6 @@ pub fn tick(self: *App) !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ui.isCtrlDown() and ui.isKeyboardPressed(.key_s)) {
|
|
||||||
self.pushCommand(.save_project);
|
|
||||||
}
|
|
||||||
|
|
||||||
ui.begin();
|
ui.begin();
|
||||||
defer ui.end();
|
defer ui.end();
|
||||||
|
|
||||||
@ -473,7 +750,15 @@ pub fn tick(self: *App) !void {
|
|||||||
self.stopCollection();
|
self.stopCollection();
|
||||||
},
|
},
|
||||||
.save_project => {
|
.save_project => {
|
||||||
// TODO:
|
self.saveProject() catch |e| {
|
||||||
|
log.err("Failed to save project: {}", .{e});
|
||||||
|
};
|
||||||
|
},
|
||||||
|
.load_project => {
|
||||||
|
self.loadProject() catch |e| {
|
||||||
|
log.err("Failed to load project: {}", .{e});
|
||||||
|
utils.dumpErrorTrace();
|
||||||
|
};
|
||||||
},
|
},
|
||||||
.add_file_from_picker => {
|
.add_file_from_picker => {
|
||||||
self.addFileFromPicker() catch |e| {
|
self.addFileFromPicker() catch |e| {
|
||||||
|
12
src/main.zig
12
src/main.zig
@ -102,10 +102,6 @@ pub fn main() !void {
|
|||||||
defer app.deinit();
|
defer app.deinit();
|
||||||
|
|
||||||
if (builtin.mode == .Debug) {
|
if (builtin.mode == .Debug) {
|
||||||
// const cwd_path = try std.fs.cwd().realpathAlloc(allocator, ".");
|
|
||||||
// defer allocator.free(cwd_path);
|
|
||||||
// try app.loadProject(cwd_path);
|
|
||||||
|
|
||||||
_ = try app.addView(.{
|
_ = try app.addView(.{
|
||||||
.channel = try app.addChannel("Dev1/ai0")
|
.channel = try app.addChannel("Dev1/ai0")
|
||||||
});
|
});
|
||||||
@ -116,6 +112,14 @@ pub fn main() !void {
|
|||||||
.file = try app.addFile("samples/HeLa Cx37_ 40nM GFX + 35uM Propofol_18-Sep-2024_0003_I.bin")
|
.file = try app.addFile("samples/HeLa Cx37_ 40nM GFX + 35uM Propofol_18-Sep-2024_0003_I.bin")
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var cwd_realpath_buff: [std.fs.MAX_PATH_BYTES]u8 = undefined;
|
||||||
|
const cwd_realpath = try std.fs.cwd().realpath(".", &cwd_realpath_buff);
|
||||||
|
|
||||||
|
const save_location = try std.fs.path.join(allocator, &.{ cwd_realpath, "project.proj" });
|
||||||
|
errdefer allocator.free(allocator);
|
||||||
|
|
||||||
|
app.project.save_location = save_location;
|
||||||
|
|
||||||
// try app.appendChannelFromDevice("Dev1/ai0");
|
// try app.appendChannelFromDevice("Dev1/ai0");
|
||||||
// try app.appendChannelFromDevice("Dev3/ao0");
|
// try app.appendChannelFromDevice("Dev3/ao0");
|
||||||
// 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");
|
||||||
|
@ -76,4 +76,10 @@ pub fn initBoundedStringZ(comptime BoundedString: type, text: []const u8) !Bound
|
|||||||
|
|
||||||
pub fn getBoundedStringZ(bounded_array: anytype) [:0]const u8 {
|
pub fn getBoundedStringZ(bounded_array: anytype) [:0]const u8 {
|
||||||
return bounded_array.buffer[0..(bounded_array.len-1) :0];
|
return bounded_array.buffer[0..(bounded_array.len-1) :0];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn dumpErrorTrace() void {
|
||||||
|
if (@errorReturnTrace()) |trace| {
|
||||||
|
std.debug.dumpStackTrace(trace.*);
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user