113 lines
3.1 KiB
Zig
113 lines
3.1 KiB
Zig
|
const std = @import("std");
|
||
|
|
||
|
const AzEl = @import("./LabjackYaesu.zig").AzEl;
|
||
|
const lj = @import("./labjack.zig");
|
||
|
|
||
|
const Config = @This();
|
||
|
|
||
|
var global_internal: Config = undefined;
|
||
|
pub const global: *const Config = &global_internal;
|
||
|
|
||
|
pub fn load(allocator: std.mem.Allocator, reader: anytype) !void {
|
||
|
var jread = std.json.Reader(1024, @TypeOf(reader)).init(allocator, reader);
|
||
|
defer jread.deinit();
|
||
|
|
||
|
global_internal = try std.json.parseFromTokenSourceLeaky(
|
||
|
Config,
|
||
|
allocator,
|
||
|
&jread,
|
||
|
.{},
|
||
|
);
|
||
|
}
|
||
|
|
||
|
pub fn loadDefault(allocator: std.mem.Allocator) void {
|
||
|
_ = allocator;
|
||
|
global_internal = .{};
|
||
|
}
|
||
|
|
||
|
pub fn destroy(allocator: std.mem.Allocator) void {
|
||
|
// TODO: implement this probably
|
||
|
_ = allocator;
|
||
|
}
|
||
|
|
||
|
rotctl: RotControlConfig = .{
|
||
|
.listen_address = "127.0.0.1",
|
||
|
.listen_port = 5432,
|
||
|
},
|
||
|
labjack: LabjackConfig = .{
|
||
|
.device = .autodetect,
|
||
|
.feedback_calibration = .{
|
||
|
.azimuth = .{
|
||
|
.minimum = .{ .voltage = 0.0, .angle = 0.0 },
|
||
|
.maximum = .{ .voltage = 5.0, .angle = 450.0 },
|
||
|
},
|
||
|
.elevation = .{
|
||
|
.minimum = .{ .voltage = 0.0, .angle = 0.0 },
|
||
|
.maximum = .{ .voltage = 5.0, .angle = 180.0 },
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
controller: ControllerConfig = .{
|
||
|
.azimuth_input = .{ .channel = .diff_01, .gain_index = 2 },
|
||
|
.elevation_input = .{ .channel = .diff_23, .gain_index = 2 },
|
||
|
.azimuth_outputs = .{ .increase = .{ .io = 0 }, .decrease = .{ .io = 1 } },
|
||
|
.elevation_outputs = .{ .increase = .{ .io = 2 }, .decrease = .{ .io = 3 } },
|
||
|
.loop_interval_ns = 50_000_000,
|
||
|
.parking_posture = .{ .azimuth = 180, .elevation = 90 },
|
||
|
.angle_tolerance = .{ .azimuth = 1, .elevation = 1 },
|
||
|
},
|
||
|
|
||
|
pub const VoltAngle = struct { voltage: f64, angle: f64 };
|
||
|
pub const MinMax = struct {
|
||
|
minimum: VoltAngle,
|
||
|
maximum: VoltAngle,
|
||
|
|
||
|
pub inline fn slope(self: MinMax) f64 {
|
||
|
return self.angleDiff() / self.voltDiff();
|
||
|
}
|
||
|
|
||
|
pub inline fn voltDiff(self: MinMax) f64 {
|
||
|
return self.maximum.voltage - self.minimum.voltage;
|
||
|
}
|
||
|
|
||
|
pub inline fn angleDiff(self: MinMax) f64 {
|
||
|
return self.maximum.angle - self.minimum.angle;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
const RotControlConfig = struct {
|
||
|
listen_address: []const u8,
|
||
|
listen_port: u16,
|
||
|
};
|
||
|
|
||
|
const LabjackConfig = struct {
|
||
|
device: union(enum) {
|
||
|
autodetect,
|
||
|
serial_number: i32,
|
||
|
},
|
||
|
// Very basic two-point calibration for each degree of freedom. All other angles are
|
||
|
// linearly interpolated from these two points. This assumes the feedback is linear,
|
||
|
// which seems to be a mostly reasonable assumption in practice.
|
||
|
feedback_calibration: struct {
|
||
|
azimuth: MinMax,
|
||
|
elevation: MinMax,
|
||
|
},
|
||
|
};
|
||
|
|
||
|
const ControllerConfig = struct {
|
||
|
azimuth_input: lj.AnalogInput,
|
||
|
elevation_input: lj.AnalogInput,
|
||
|
|
||
|
azimuth_outputs: OutPair,
|
||
|
elevation_outputs: OutPair,
|
||
|
|
||
|
loop_interval_ns: u64,
|
||
|
parking_posture: AzEl,
|
||
|
angle_tolerance: AzEl,
|
||
|
|
||
|
const OutPair = struct {
|
||
|
increase: lj.DigitalOutputChannel,
|
||
|
decrease: lj.DigitalOutputChannel,
|
||
|
};
|
||
|
};
|