show axis units on ruler
This commit is contained in:
parent
de2941c5bf
commit
d8867cb3d6
206
src/app.zig
206
src/app.zig
@ -60,6 +60,8 @@ pub const ChannelView = struct {
|
|||||||
|
|
||||||
x_range: RangeF64,
|
x_range: RangeF64,
|
||||||
y_range: RangeF64,
|
y_range: RangeF64,
|
||||||
|
sample_rate: ?f64 = null,
|
||||||
|
unit: ?NIDaq.Unit = null,
|
||||||
|
|
||||||
source: union(enum) {
|
source: union(enum) {
|
||||||
file: usize,
|
file: usize,
|
||||||
@ -227,110 +229,32 @@ fn readSamplesFromFile(allocator: std.mem.Allocator, file: std.fs.File) ![]f64 {
|
|||||||
return samples;
|
return samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn appendChannelFromFile(self: *App, path: []const u8) !void {
|
|
||||||
const path_dupe = try self.allocator.dupe(u8, path);
|
|
||||||
errdefer self.allocator.free(path_dupe);
|
|
||||||
|
|
||||||
const file = try std.fs.cwd().openFile(path, .{});
|
|
||||||
defer file.close();
|
|
||||||
|
|
||||||
const samples = try readSamplesFromFile(self.allocator, file);
|
|
||||||
errdefer self.allocator.free(samples);
|
|
||||||
|
|
||||||
var min_value: f64 = 0;
|
|
||||||
var max_value: f64 = 0;
|
|
||||||
if (samples.len > 0) {
|
|
||||||
min_value = samples[0];
|
|
||||||
max_value = samples[0];
|
|
||||||
|
|
||||||
for (samples) |sample| {
|
|
||||||
min_value = @min(min_value, sample);
|
|
||||||
max_value = @max(max_value, sample);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const loaded_file_index = findFreeSlot(FileChannel, &self.loaded_files) orelse return error.FileLimitReached;
|
|
||||||
|
|
||||||
self.loaded_files[loaded_file_index] = FileChannel{
|
|
||||||
.path = path_dupe,
|
|
||||||
.samples = samples
|
|
||||||
};
|
|
||||||
errdefer self.loaded_files[loaded_file_index] = null;
|
|
||||||
|
|
||||||
const from: f64 = 0;
|
|
||||||
const to = @max(@as(f64, @floatFromInt(samples.len)) - 1, 0);
|
|
||||||
self.channel_views.appendAssumeCapacity(ChannelView{
|
|
||||||
.view_rect = .{
|
|
||||||
.x_range = RangeF64.init(from, to),
|
|
||||||
.y_range = RangeF64.init(max_value, min_value)
|
|
||||||
},
|
|
||||||
.x_range = RangeF64.init(from, to),
|
|
||||||
.y_range = RangeF64.init(max_value, min_value),
|
|
||||||
.source = .{ .file = loaded_file_index }
|
|
||||||
});
|
|
||||||
errdefer _ = self.channel_views.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn appendChannelFromDevice(self: *App, channel_name: []const u8) !void {
|
|
||||||
const ni_daq = &(self.ni_daq orelse return);
|
|
||||||
|
|
||||||
const device_channel_index = findFreeSlot(DeviceChannel, &self.device_channels) orelse return error.DeviceChannelLimitReached;
|
|
||||||
|
|
||||||
const name_buff = try DeviceChannel.Name.fromSlice(channel_name);
|
|
||||||
const channel_name_z = name_buff.buffer[0..name_buff.len :0];
|
|
||||||
|
|
||||||
const device = NIDaq.getDeviceNameFromChannel(channel_name) orelse return error.InvalidChannelName;
|
|
||||||
const device_buff = try NIDaq.BoundedDeviceName.fromSlice(device);
|
|
||||||
const device_z = device_buff.buffer[0..device_buff.len :0];
|
|
||||||
|
|
||||||
var min_value: f64 = 0;
|
|
||||||
var max_value: f64 = 1;
|
|
||||||
const voltage_ranges = try ni_daq.listDeviceAOVoltageRanges(device_z);
|
|
||||||
if (voltage_ranges.len > 0) {
|
|
||||||
min_value = voltage_ranges[0].low;
|
|
||||||
max_value = voltage_ranges[0].high;
|
|
||||||
}
|
|
||||||
|
|
||||||
const max_sample_rate = try ni_daq.getMaxSampleRate(channel_name_z);
|
|
||||||
|
|
||||||
self.device_channels[device_channel_index] = DeviceChannel{
|
|
||||||
.name = name_buff,
|
|
||||||
.min_sample_rate = ni_daq.getMinSampleRate(channel_name_z) catch max_sample_rate,
|
|
||||||
.max_sample_rate = max_sample_rate,
|
|
||||||
.min_value = min_value,
|
|
||||||
.max_value = max_value,
|
|
||||||
.samples = std.ArrayList(f64).init(self.allocator)
|
|
||||||
};
|
|
||||||
errdefer self.device_channels[device_channel_index] = null;
|
|
||||||
|
|
||||||
self.channel_views.appendAssumeCapacity(ChannelView{
|
|
||||||
.view_rect = .{
|
|
||||||
.x_range = RangeF64.init(0, 0),
|
|
||||||
.y_range = RangeF64.init(max_value, min_value)
|
|
||||||
},
|
|
||||||
.x_range = RangeF64.init(0, 0),
|
|
||||||
.y_range = RangeF64.init(max_value, min_value),
|
|
||||||
.source = .{ .device = device_channel_index }
|
|
||||||
});
|
|
||||||
errdefer _ = self.channel_views.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn listChannelViews(self: *App) []ChannelView {
|
pub fn listChannelViews(self: *App) []ChannelView {
|
||||||
return self.channel_views.slice();
|
return self.channel_views.slice();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick(self: *App) !void {
|
pub fn tick(self: *App) !void {
|
||||||
|
var ui = &self.ui;
|
||||||
rl.clearBackground(srcery.black);
|
rl.clearBackground(srcery.black);
|
||||||
|
|
||||||
var ui = &self.ui;
|
|
||||||
{
|
|
||||||
ui.begin();
|
|
||||||
defer ui.end();
|
|
||||||
|
|
||||||
|
{
|
||||||
self.channel_mutex.lock();
|
self.channel_mutex.lock();
|
||||||
defer self.channel_mutex.unlock();
|
defer self.channel_mutex.unlock();
|
||||||
|
|
||||||
try self.screen.tick();
|
for (self.listChannelViews()) |*channel_view| {
|
||||||
|
const device_channel = self.getChannelSourceDevice(channel_view) orelse continue;
|
||||||
|
const sample_count: f32 = @floatFromInt(device_channel.samples.items.len);
|
||||||
|
|
||||||
|
channel_view.x_range = RangeF64.init(0, sample_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ui.begin();
|
||||||
|
defer ui.end();
|
||||||
|
|
||||||
|
try self.screen.tick();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.draw();
|
ui.draw();
|
||||||
@ -390,12 +314,13 @@ pub fn startDeviceChannelReading(self: *App, channel_view: *ChannelView) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const channel_name = device_channel.name.buffer[0..device_channel.name.len :0];
|
const channel_name = device_channel.name.buffer[0..device_channel.name.len :0];
|
||||||
|
const sample_rate = device_channel.max_sample_rate;
|
||||||
|
|
||||||
const task = self.task_pool.launchAIVoltageChannel(
|
const task = self.task_pool.launchAIVoltageChannel(
|
||||||
ni_daq,
|
ni_daq,
|
||||||
&device_channel.samples,
|
&device_channel.samples,
|
||||||
.{
|
.{
|
||||||
.continous = .{ .sample_rate = device_channel.max_sample_rate }
|
.sample_rate = sample_rate
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.min_value = device_channel.min_value,
|
.min_value = device_channel.min_value,
|
||||||
@ -413,4 +338,97 @@ pub fn startDeviceChannelReading(self: *App, channel_view: *ChannelView) void {
|
|||||||
};
|
};
|
||||||
|
|
||||||
device_channel.active_task = task;
|
device_channel.active_task = task;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn appendChannelFromFile(self: *App, path: []const u8) !void {
|
||||||
|
const path_dupe = try self.allocator.dupe(u8, path);
|
||||||
|
errdefer self.allocator.free(path_dupe);
|
||||||
|
|
||||||
|
const file = try std.fs.cwd().openFile(path, .{});
|
||||||
|
defer file.close();
|
||||||
|
|
||||||
|
const samples = try readSamplesFromFile(self.allocator, file);
|
||||||
|
errdefer self.allocator.free(samples);
|
||||||
|
|
||||||
|
var min_value: f64 = 0;
|
||||||
|
var max_value: f64 = 0;
|
||||||
|
if (samples.len > 0) {
|
||||||
|
min_value = samples[0];
|
||||||
|
max_value = samples[0];
|
||||||
|
|
||||||
|
for (samples) |sample| {
|
||||||
|
min_value = @min(min_value, sample);
|
||||||
|
max_value = @max(max_value, sample);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const loaded_file_index = findFreeSlot(FileChannel, &self.loaded_files) orelse return error.FileLimitReached;
|
||||||
|
|
||||||
|
self.loaded_files[loaded_file_index] = FileChannel{
|
||||||
|
.path = path_dupe,
|
||||||
|
.samples = samples
|
||||||
|
};
|
||||||
|
errdefer self.loaded_files[loaded_file_index] = null;
|
||||||
|
|
||||||
|
const from: f64 = 0;
|
||||||
|
const to = @max(@as(f64, @floatFromInt(samples.len)) - 1, 0);
|
||||||
|
self.channel_views.appendAssumeCapacity(ChannelView{
|
||||||
|
.view_rect = .{
|
||||||
|
.x_range = RangeF64.init(from, to),
|
||||||
|
.y_range = RangeF64.init(max_value, min_value)
|
||||||
|
},
|
||||||
|
.x_range = RangeF64.init(from, to),
|
||||||
|
.y_range = RangeF64.init(max_value, min_value),
|
||||||
|
.source = .{ .file = loaded_file_index }
|
||||||
|
});
|
||||||
|
errdefer _ = self.channel_views.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn appendChannelFromDevice(self: *App, channel_name: []const u8) !void {
|
||||||
|
const ni_daq = &(self.ni_daq orelse return);
|
||||||
|
|
||||||
|
const device_channel_index = findFreeSlot(DeviceChannel, &self.device_channels) orelse return error.DeviceChannelLimitReached;
|
||||||
|
|
||||||
|
const name_buff = try DeviceChannel.Name.fromSlice(channel_name);
|
||||||
|
const channel_name_z = name_buff.buffer[0..name_buff.len :0];
|
||||||
|
|
||||||
|
const device = NIDaq.getDeviceNameFromChannel(channel_name) orelse return error.InvalidChannelName;
|
||||||
|
const device_buff = try NIDaq.BoundedDeviceName.fromSlice(device);
|
||||||
|
const device_z = device_buff.buffer[0..device_buff.len :0];
|
||||||
|
|
||||||
|
// TODO: Add support for other measurement types
|
||||||
|
const unit = NIDaq.Unit.Voltage;
|
||||||
|
|
||||||
|
var min_value: f64 = 0;
|
||||||
|
var max_value: f64 = 1;
|
||||||
|
const voltage_ranges = try ni_daq.listDeviceAOVoltageRanges(device_z);
|
||||||
|
if (voltage_ranges.len > 0) {
|
||||||
|
min_value = voltage_ranges[0].low;
|
||||||
|
max_value = voltage_ranges[0].high;
|
||||||
|
}
|
||||||
|
|
||||||
|
const max_sample_rate = try ni_daq.getMaxSampleRate(channel_name_z);
|
||||||
|
|
||||||
|
self.device_channels[device_channel_index] = DeviceChannel{
|
||||||
|
.name = name_buff,
|
||||||
|
.min_sample_rate = ni_daq.getMinSampleRate(channel_name_z) catch max_sample_rate,
|
||||||
|
.max_sample_rate = max_sample_rate,
|
||||||
|
.min_value = min_value,
|
||||||
|
.max_value = max_value,
|
||||||
|
.samples = std.ArrayList(f64).init(self.allocator)
|
||||||
|
};
|
||||||
|
errdefer self.device_channels[device_channel_index] = null;
|
||||||
|
|
||||||
|
self.channel_views.appendAssumeCapacity(ChannelView{
|
||||||
|
.view_rect = .{
|
||||||
|
.x_range = RangeF64.init(0, 0),
|
||||||
|
.y_range = RangeF64.init(max_value, min_value)
|
||||||
|
},
|
||||||
|
.x_range = RangeF64.init(0, 0),
|
||||||
|
.y_range = RangeF64.init(max_value, min_value),
|
||||||
|
.source = .{ .device = device_channel_index },
|
||||||
|
.sample_rate = max_sample_rate,
|
||||||
|
.unit = unit
|
||||||
|
});
|
||||||
|
errdefer _ = self.channel_views.pop();
|
||||||
}
|
}
|
@ -195,7 +195,7 @@ pub const Task = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const AIMeasurementType = enum(i32) {
|
pub const Unit = enum(i32) {
|
||||||
Voltage = c.DAQmx_Val_Voltage,
|
Voltage = c.DAQmx_Val_Voltage,
|
||||||
VoltageRMS = c.DAQmx_Val_VoltageRMS,
|
VoltageRMS = c.DAQmx_Val_VoltageRMS,
|
||||||
Current = c.DAQmx_Val_Current,
|
Current = c.DAQmx_Val_Current,
|
||||||
@ -227,7 +227,7 @@ pub const AIMeasurementType = enum(i32) {
|
|||||||
Power = c.DAQmx_Val_Power,
|
Power = c.DAQmx_Val_Power,
|
||||||
_,
|
_,
|
||||||
|
|
||||||
pub fn name(self: AIMeasurementType) []const u8 {
|
pub fn name(self: Unit) ?[]const u8 {
|
||||||
return switch (self) {
|
return switch (self) {
|
||||||
.Voltage => "Voltage",
|
.Voltage => "Voltage",
|
||||||
.VoltageRMS => "Voltage RMS",
|
.VoltageRMS => "Voltage RMS",
|
||||||
@ -258,11 +258,49 @@ pub const AIMeasurementType = enum(i32) {
|
|||||||
.TEDS_Sensor => "TEDS",
|
.TEDS_Sensor => "TEDS",
|
||||||
.Charge => "Charge",
|
.Charge => "Charge",
|
||||||
.Power => "Power source",
|
.Power => "Power source",
|
||||||
_ => "Unknown"
|
_ => null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
pub const AIMeasurementType = enum(i32) {
|
||||||
|
Voltage = @intFromEnum(Unit.Voltage),
|
||||||
|
VoltageRMS = @intFromEnum(Unit.VoltageRMS),
|
||||||
|
Current = @intFromEnum(Unit.Current),
|
||||||
|
CurrentRMS = @intFromEnum(Unit.CurrentRMS),
|
||||||
|
Voltage_CustomWithExcitation = @intFromEnum(Unit.Voltage_CustomWithExcitation),
|
||||||
|
Bridge = @intFromEnum(Unit.Bridge),
|
||||||
|
Freq_Voltage = @intFromEnum(Unit.Freq_Voltage),
|
||||||
|
Resistance = @intFromEnum(Unit.Resistance),
|
||||||
|
Temp_TC = @intFromEnum(Unit.Temp_TC),
|
||||||
|
Temp_Thrmstr = @intFromEnum(Unit.Temp_Thrmstr),
|
||||||
|
Temp_RTD = @intFromEnum(Unit.Temp_RTD),
|
||||||
|
Temp_BuiltInSensor = @intFromEnum(Unit.Temp_BuiltInSensor),
|
||||||
|
Strain_Gage = @intFromEnum(Unit.Strain_Gage),
|
||||||
|
Rosette_Strain_Gage = @intFromEnum(Unit.Rosette_Strain_Gage),
|
||||||
|
Position_LVDT = @intFromEnum(Unit.Position_LVDT),
|
||||||
|
Position_RVDT = @intFromEnum(Unit.Position_RVDT),
|
||||||
|
Position_EddyCurrentProximityProbe = @intFromEnum(Unit.Position_EddyCurrentProximityProbe),
|
||||||
|
Accelerometer = @intFromEnum(Unit.Accelerometer),
|
||||||
|
Acceleration_Charge = @intFromEnum(Unit.Acceleration_Charge),
|
||||||
|
Acceleration_4WireDCVoltage = @intFromEnum(Unit.Acceleration_4WireDCVoltage),
|
||||||
|
Velocity_IEPESensor = @intFromEnum(Unit.Velocity_IEPESensor),
|
||||||
|
Force_Bridge = @intFromEnum(Unit.Force_Bridge),
|
||||||
|
Force_IEPESensor = @intFromEnum(Unit.Force_IEPESensor),
|
||||||
|
Pressure_Bridge = @intFromEnum(Unit.Pressure_Bridge),
|
||||||
|
SoundPressure_Microphone = @intFromEnum(Unit.SoundPressure_Microphone),
|
||||||
|
Torque_Bridge = @intFromEnum(Unit.Torque_Bridge),
|
||||||
|
TEDS_Sensor = @intFromEnum(Unit.TEDS_Sensor),
|
||||||
|
Charge = @intFromEnum(Unit.Charge),
|
||||||
|
Power = @intFromEnum(Unit.Power),
|
||||||
|
_,
|
||||||
|
|
||||||
|
pub fn name(self: AIMeasurementType) ?[]const u8 {
|
||||||
|
return Unit.name(self);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
pub const max_ai_measurement_type_list_len = @typeInfo(AIMeasurementType).Enum.fields.len;
|
pub const max_ai_measurement_type_list_len = @typeInfo(AIMeasurementType).Enum.fields.len;
|
||||||
pub const AIMeasurementTypeList = std.BoundedArray(AIMeasurementType, max_ai_measurement_type_list_len);
|
pub const AIMeasurementTypeList = std.BoundedArray(AIMeasurementType, max_ai_measurement_type_list_len);
|
||||||
|
|
||||||
|
@ -7,14 +7,9 @@ const log = std.log.scoped(.task_pool);
|
|||||||
const TaskPool = @This();
|
const TaskPool = @This();
|
||||||
const max_tasks = 32;
|
const max_tasks = 32;
|
||||||
|
|
||||||
pub const Sampling = union(enum) {
|
pub const Sampling = struct {
|
||||||
finite: struct {
|
sample_rate: f64,
|
||||||
sample_rate: f64,
|
sample_count: ?u64 = null
|
||||||
sample_count: u64
|
|
||||||
},
|
|
||||||
continous: struct {
|
|
||||||
sample_rate: f64
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Entry = struct {
|
pub const Entry = struct {
|
||||||
@ -80,13 +75,10 @@ fn readAnalog(task_pool: *TaskPool, entry: *Entry, timeout: f64) !void {
|
|||||||
defer task_pool.mutex.unlock();
|
defer task_pool.mutex.unlock();
|
||||||
|
|
||||||
|
|
||||||
switch (entry.sampling) {
|
if (entry.sampling.sample_count) |sample_count| {
|
||||||
.finite => |args| {
|
try entry.samples.ensureTotalCapacity(sample_count);
|
||||||
try entry.samples.ensureTotalCapacity(args.sample_count);
|
} else {
|
||||||
},
|
try entry.samples.ensureUnusedCapacity(@intFromFloat(@ceil(entry.sampling.sample_rate)));
|
||||||
.continous => |args| {
|
|
||||||
try entry.samples.ensureUnusedCapacity(@intFromFloat(@ceil(args.sample_rate)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const unused_capacity = entry.samples.unusedCapacitySlice();
|
const unused_capacity = entry.samples.unusedCapacitySlice();
|
||||||
@ -144,13 +136,10 @@ pub fn launchAIVoltageChannel(
|
|||||||
errdefer entry.in_use = false;
|
errdefer entry.in_use = false;
|
||||||
|
|
||||||
try task.createAIVoltageChannel(options);
|
try task.createAIVoltageChannel(options);
|
||||||
switch (sampling) {
|
if (sampling.sample_count) |sample_count| {
|
||||||
.continous => |args| {
|
try task.setFiniteSampleRate(sampling.sample_rate, sample_count);
|
||||||
try task.setContinousSampleRate(args.sample_rate);
|
} else {
|
||||||
},
|
try task.setContinousSampleRate(sampling.sample_rate);
|
||||||
.finite => |args| {
|
|
||||||
try task.setFiniteSampleRate(args.sample_rate, args.sample_count);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
samples.clearRetainingCapacity();
|
samples.clearRetainingCapacity();
|
||||||
|
@ -275,6 +275,14 @@ fn showRulerTicks(self: *MainScreen, channel_view: *ChannelView, axis: UI.Axis)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (view_range.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (full_range.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const ideal_pixels_per_division = 150;
|
const ideal_pixels_per_division = 150;
|
||||||
var subdivisions: f32 = 20;
|
var subdivisions: f32 = 20;
|
||||||
subdivisions = 20;
|
subdivisions = 20;
|
||||||
@ -284,8 +292,6 @@ fn showRulerTicks(self: *MainScreen, channel_view: *ChannelView, axis: UI.Axis)
|
|||||||
const pixels_per_division = step / view_range.size() * ruler_rect_size_along_axis;
|
const pixels_per_division = step / view_range.size() * ruler_rect_size_along_axis;
|
||||||
assert(pixels_per_division > 0);
|
assert(pixels_per_division > 0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (pixels_per_division > ideal_pixels_per_division*2) {
|
if (pixels_per_division > ideal_pixels_per_division*2) {
|
||||||
subdivisions *= 2;
|
subdivisions *= 2;
|
||||||
} else if (pixels_per_division < ideal_pixels_per_division/2) {
|
} else if (pixels_per_division < ideal_pixels_per_division/2) {
|
||||||
@ -392,13 +398,21 @@ fn showRuler(self: *MainScreen, ruler: *UI.Box, graph_box: *UI.Box, channel_view
|
|||||||
is_zooming = axis_zoom.channel == channel_view and axis_zoom.axis == axis;
|
is_zooming = axis_zoom.channel == channel_view and axis_zoom.axis == axis;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signal.hot) {
|
if (signal.hot and view_range.size() > 0) {
|
||||||
const mouse_tooltip = ui.mouseTooltip();
|
const mouse_tooltip = ui.mouseTooltip();
|
||||||
mouse_tooltip.beginChildren();
|
mouse_tooltip.beginChildren();
|
||||||
defer mouse_tooltip.endChildren();
|
defer mouse_tooltip.endChildren();
|
||||||
|
|
||||||
if (channel_view.getSampleRange(axis).hasInclusive(mouse_position_on_graph)) {
|
if (channel_view.getSampleRange(axis).hasInclusive(mouse_position_on_graph)) {
|
||||||
_ = ui.label("{d:.3}", .{mouse_position_on_graph});
|
if (axis == .Y and channel_view.unit != null) {
|
||||||
|
const unit_name = channel_view.unit.?.name() orelse "Unknown";
|
||||||
|
_ = ui.label("{s}: {d:.3}", .{unit_name, mouse_position_on_graph});
|
||||||
|
} else if (axis == .X and channel_view.sample_rate != null) {
|
||||||
|
const sample_rate = channel_view.sample_rate.?;
|
||||||
|
_ = ui.label("{d:.3}s", .{mouse_position_on_graph / sample_rate});
|
||||||
|
} else {
|
||||||
|
_ = ui.label("{d:.3}", .{mouse_position_on_graph});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
zoom_start = mouse_position_on_graph;
|
zoom_start = mouse_position_on_graph;
|
||||||
@ -632,7 +646,7 @@ pub fn tick(self: *MainScreen) !void {
|
|||||||
for (self.app.listChannelViews()) |*channel_view| {
|
for (self.app.listChannelViews()) |*channel_view| {
|
||||||
const device_channel = self.app.getChannelSourceDevice(channel_view) orelse continue;
|
const device_channel = self.app.getChannelSourceDevice(channel_view) orelse continue;
|
||||||
|
|
||||||
const sample_rate = device_channel.active_task.?.sampling.continous.sample_rate;
|
const sample_rate = device_channel.active_task.?.sampling.sample_rate;
|
||||||
const samples = device_channel.samples.items;
|
const samples = device_channel.samples.items;
|
||||||
const sample_count: f32 = @floatFromInt(samples.len);
|
const sample_count: f32 = @floatFromInt(samples.len);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user