rotctl: do range validation

This is at the interface layer though it should arguably be done at the
controller layer. Oh well.
This commit is contained in:
torque 2024-07-06 12:59:37 -07:00
parent 7105775426
commit 7fbfe1c5f7
Signed by: torque
SSH Key Fingerprint: SHA256:nCrXefBNo6EbjNSQhv0nXmEg/VuNq3sMF5b8zETw3Tk
2 changed files with 38 additions and 1 deletions

View File

@ -37,6 +37,15 @@ rotctl: RotControlConfig = .{
labjack: LabjackConfig = .{
.device = .autodetect,
.feedback_calibration = .{
// NOTE: these min and max angles are treated as hardware limits. This serves
// two purposes: first, it means that feedback is always interpolated,
// never extrapolated (though with a two point calibration, that doesn't
// matter much). Second, it prevents having a redundant set of bounds
// values that could potentially desync from these and cause problems.
//
// The functional min and max are these plus the angle offset values. For
// example, given controller.angle_offset.azimuth = -6, the practical minimum
// azimuth would be -6 deg and the practical maximum would be 444 deg.
.azimuth = .{
.minimum = .{ .voltage = 0.0, .angle = 0.0 },
.maximum = .{ .voltage = 5.0, .angle = 450.0 },

View File

@ -1,6 +1,7 @@
const std = @import("std");
const config = @import("./Config.zig").global;
const Config = @import("./Config.zig");
const config = Config.global;
const LabjackYaesu = @import("./LabjackYaesu.zig");
const RotCtl = @This();
@ -113,6 +114,27 @@ fn getPosition(self: *RotCtl, _: []const u8, tokens: *TokenIter) CommandError!vo
self.printReply("{d:.1}\n{d:.1}", .{ pos.azimuth, pos.elevation }) catch return error.BadOutput;
}
fn inRange(request: f64, comptime dof: enum { azimuth, elevation }) bool {
return switch (dof) {
// zig fmt: off
.azimuth => request >= (
config.labjack.feedback_calibration.azimuth.minimum.angle
+ config.controller.angle_offset.azimuth
) and request <= (
config.labjack.feedback_calibration.azimuth.maximum.angle
+ config.controller.angle_offset.azimuth
),
.elevation => request >= (
config.labjack.feedback_calibration.elevation.minimum.angle
+ config.controller.angle_offset.elevation
) and request <= (
config.labjack.feedback_calibration.elevation.maximum.angle
+ config.controller.angle_offset.elevation
),
// zig fmt: on
};
}
fn setPosition(self: *RotCtl, _: []const u8, tokens: *TokenIter) CommandError!void {
const azimuth = std.fmt.parseFloat(f64, tokens.next() orelse {
return self.replyStatus(.invalid_parameter) catch error.BadOutput;
@ -120,12 +142,18 @@ fn setPosition(self: *RotCtl, _: []const u8, tokens: *TokenIter) CommandError!vo
return self.replyStatus(.invalid_parameter) catch error.BadOutput;
};
if (!inRange(azimuth, .azimuth))
return self.replyStatus(.invalid_parameter) catch error.BadOutput;
const elevation = std.fmt.parseFloat(f64, tokens.next() orelse {
return self.replyStatus(.invalid_parameter) catch error.BadOutput;
}) catch {
return self.replyStatus(.invalid_parameter) catch error.BadOutput;
};
if (!inRange(elevation, .elevation))
return self.replyStatus(.invalid_parameter) catch error.BadOutput;
self.rotator.setTarget(.{ .azimuth = azimuth, .elevation = elevation });
return self.replyStatus(.okay) catch error.BadOutput;
}