const std = @import("std"); const rl = @import("raylib"); const builtin = @import("builtin"); const Application = @import("./app.zig"); const Assets = @import("./assets.zig"); const Profiler = @import("./profiler.zig"); const raylib_h = @cImport({ @cInclude("stdio.h"); @cInclude("raylib.h"); }); const log = std.log; const profiler_enabled = builtin.mode == .Debug; // TODO: Maybe move this to a config.zig or options.zig file. // Have all of the contstants in a single file. pub const version = std.SemanticVersion{ .major = 0, .minor = 1, .patch = 0 }; fn toRaylibLogLevel(log_level: log.Level) rl.TraceLogLevel { return switch (log_level) { .err => rl.TraceLogLevel.log_error, .warn => rl.TraceLogLevel.log_warning, .info => rl.TraceLogLevel.log_info, .debug => rl.TraceLogLevel.log_trace, }; } fn toZigLogLevel(log_type: c_int) ?log.Level { return switch (log_type) { @intFromEnum(rl.TraceLogLevel.log_trace) => log.Level.debug, @intFromEnum(rl.TraceLogLevel.log_debug) => log.Level.debug, @intFromEnum(rl.TraceLogLevel.log_info) => log.Level.info, @intFromEnum(rl.TraceLogLevel.log_warning) => log.Level.warn, @intFromEnum(rl.TraceLogLevel.log_error) => log.Level.err, @intFromEnum(rl.TraceLogLevel.log_fatal) => log.Level.err, else => null }; } fn raylibTraceLogCallback(logType: c_int, text: [*c]const u8, args: raylib_h.va_list) callconv(.C) void { const log_level = toZigLogLevel(logType) orelse return; const scope = .raylib; const raylib_log = std.log.scoped(scope); const max_tracelog_msg_length = 256; // from utils.c in raylib var buffer: [max_tracelog_msg_length:0]u8 = undefined; inline for (std.meta.fields(std.log.Level)) |field| { const message_level: std.log.Level = @enumFromInt(field.value); if (std.log.logEnabled(message_level, scope) and log_level == message_level) { @memset(&buffer, 0); const text_length = raylib_h.vsnprintf(&buffer, buffer.len, text, args); const formatted_text = buffer[0..@intCast(text_length)]; const log_function = @field(raylib_log, field.name); @call(.auto, log_function, .{ "{s}", .{formatted_text} }); } } } pub fn main() !void { // TODO: Setup logging to a file raylib_h.SetTraceLogCallback(raylibTraceLogCallback); rl.setTraceLogLevel(toRaylibLogLevel(std.options.log_level)); var gpa = std.heap.GeneralPurposeAllocator(.{}){}; const allocator = gpa.allocator(); defer _ = gpa.deinit(); // const devices = try ni_daq.listDeviceNames(); // for (devices) |device| { // if (try ni_daq.checkDeviceAIMeasurementType(device, .Voltage)) { // const voltage_ranges = try ni_daq.listDeviceAIVoltageRanges(device); // assert(voltage_ranges.len > 0); // const min_sample = voltage_ranges[0].low; // const max_sample = voltage_ranges[0].high; // for (try ni_daq.listDeviceAIPhysicalChannels(device)) |channel_name| { // var channel = try app.appendChannel(); // channel.min_sample = min_sample; // channel.max_sample = max_sample; // try app.task_pool.createAIVoltageChannel(ni_daq, .{ // .channel = channel_name, // .min_value = min_sample, // .max_value = max_sample, // }); // break; // } // } // if (try ni_daq.checkDeviceAOOutputType(device, .Voltage)) { // const voltage_ranges = try ni_daq.listDeviceAOVoltageRanges(device); // assert(voltage_ranges.len > 0); // const min_sample = voltage_ranges[0].low; // const max_sample = voltage_ranges[0].high; // for (try ni_daq.listDeviceAOPhysicalChannels(device)) |channel_name| { // var channel = try app.appendChannel(); // channel.min_sample = min_sample; // channel.max_sample = max_sample; // try app.task_pool.createAOVoltageChannel(ni_daq, .{ // .channel = channel_name, // .min_value = min_sample, // .max_value = max_sample, // }); // } // } // } // for (0.., app.channels.items) |i, *channel| { // channel.color = rl.Color.fromHSV(@as(f32, @floatFromInt(i)) / @as(f32, @floatFromInt(app.channels.items.len)) * 360, 0.75, 0.8); // } // const sample_rate: f64 = 5000; // try app.task_pool.setContinousSampleRate(sample_rate); // var channel_samples = try app.task_pool.start(0.01, allocator); // defer channel_samples.deinit(); // defer app.task_pool.stop() catch @panic("stop task failed"); // app.channel_samples = channel_samples; const icon_png = @embedFile("./assets/icon.png"); var icon_image = rl.loadImageFromMemory(".png", icon_png); defer icon_image.unload(); rl.initWindow(800, 450, "DAQ view"); defer rl.closeWindow(); rl.setWindowState(.{ .window_resizable = true, .vsync_hint = true }); rl.setWindowMinSize(256, 256); rl.setWindowIcon(icon_image); const target_fps = 60; rl.setTargetFPS(target_fps); if (builtin.mode != .Debug) { rl.setExitKey(.key_null); } try Assets.init(allocator); defer Assets.deinit(allocator); var app: Application = undefined; try Application.init(&app, allocator); defer app.deinit(); if (builtin.mode == .Debug) { 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"); } var profiler: ?Profiler = null; defer if (profiler) |p| p.deinit(); var profiler_shown = false; if (profiler_enabled) { const font_face = Assets.font(.text); profiler = try Profiler.init(allocator, 10 * target_fps, @divFloor(std.time.ns_per_s, target_fps), font_face); } while (!rl.windowShouldClose()) { rl.beginDrawing(); defer rl.endDrawing(); if (profiler) |*p| { p.start(); } try app.tick(); if (profiler) |*p| { p.stop(); if (rl.isKeyPressed(.key_p) and rl.isKeyDown(.key_left_control)) { profiler_shown = !profiler_shown; } if (profiler_shown) { try p.showResults(); } } } } test { _ = @import("./ni-daq.zig"); }