Compare commits

..

3 Commits

Author SHA1 Message Date
dbbb5c1748
rotctl: hook up P interface
This appears to work. Now all that remains is doing the rest of the
work.
2024-07-03 17:44:26 -07:00
c8bec6a7c5
start writing control and config functionality
In theory, this will poll the feedback lines, but in practice, it
probably crashes or catches on fire or something.
2024-07-03 16:06:49 -07:00
be819363b9
deps.labjack: fiddle with Windows support a little
I will probably spend more time on this than I plan to, though I am not
really writing this to run on Windows. At this point, Windows
compilation works but when the driver attempts to read the HID
descriptor, the response is only 45 bytes instead of the expected 75
(which is what it gets when run on Linux). I was under the impression
that this response was just raw data from the device itself, but it's
clearly handled differently on the different platforms, so I think it
will be somewhat interesting to dig into what is different between the
two and why. It's possible I may actually learn something along the
way, unfortunately.
2024-07-03 16:06:49 -07:00
4 changed files with 35 additions and 19 deletions

View File

@ -45,9 +45,6 @@
#define MIN_U6_FIRMWARE_MAJOR 0
#define MIN_U6_FIRMWARE_MINOR 81
// Set to 0 for no debug logging or 1 for logging.
#define LJ_DEBUG 0
static bool gIsLibUSBInitialized = false;
static struct libusb_context *gLJContext = NULL;
@ -505,7 +502,7 @@ static HANDLE LJUSB_OpenSpecificDevice(libusb_device *dev, const struct libusb_d
return NULL;
}
#if defined(_WIN32)
#if !defined(_WIN32)
// Test if the kernel driver has the U12.
if (desc->idProduct == U12_PRODUCT_ID && libusb_kernel_driver_active(devh, 0)) {
#if LJ_DEBUG

View File

@ -55,6 +55,7 @@ controller: ControllerConfig = .{
.loop_interval_ns = 50_000_000,
.parking_posture = .{ .azimuth = 180, .elevation = 90 },
.angle_tolerance = .{ .azimuth = 1, .elevation = 1 },
.angle_offset = .{ .azimuth = 0, .elevation = 0 },
},
pub const VoltAngle = struct { voltage: f64, angle: f64 };
@ -104,6 +105,7 @@ const ControllerConfig = struct {
loop_interval_ns: u64,
parking_posture: AzEl,
angle_tolerance: AzEl,
angle_offset: AzEl,
const OutPair = struct {
increase: lj.DigitalOutputChannel,

View File

@ -44,6 +44,13 @@ pub fn setTarget(self: LabjackYaesu, target: AzEl) void {
controller.requested_state = .running;
}
pub fn position(self: LabjackYaesu) AzEl {
self.lock.lock();
defer self.lock.unlock();
return self.controller.position;
}
pub fn startCalibration(self: LabjackYaesu) void {
// there are two different types of calibration:
// 1. feedback calibration, running to the extents of the rotator

View File

@ -51,7 +51,9 @@ pub fn run(allocator: std.mem.Allocator) !void {
while (interface.running) : (fbs.reset()) {
reader.streamUntilDelimiter(fbs.writer(), '\n', readbuffer.len) catch break;
try interface.handleHamlibCommand(fbs.getWritten());
try interface.handleHamlibCommand(
std.mem.trim(u8, fbs.getWritten(), &std.ascii.whitespace),
);
}
}
}
@ -65,6 +67,11 @@ fn replyStatus(self: *RotCtl, comptime status: HamlibErrorCode) !void {
try self.write(comptime status.replyFrame() ++ "\n");
}
fn printReply(self: *RotCtl, comptime fmt: []const u8, args: anytype) !void {
try self.writer.writer().print(fmt ++ "\n", args);
try self.writer.flush();
}
fn handleHamlibCommand(
self: *RotCtl,
command: []const u8,
@ -74,25 +81,26 @@ fn handleHamlibCommand(
const first = tokens.next().?;
if (first.len == 1 or first[0] == '\\') {
switch (first[0]) {
'q' => {
'q', 'Q' => {
self.running = false;
self.replyStatus(.okay) catch return;
self.replyStatus(.okay) catch {};
self.rotator.stop();
},
'P' => {
const pos = self.rotator.position();
try self.printReply("{d:.1} {d:.1}", .{ pos.azimuth, pos.elevation });
},
'\\' => {
return try self.parseLongCommand(first[1..], &tokens);
try self.parseLongCommand(first[1..], &tokens);
},
else => |cmd| {
log.err("unknown command {}", .{cmd});
else => {
log.err("unknown short command '{s}'", .{command});
try self.replyStatus(.not_implemented);
},
}
} else if (std.mem.eql(u8, first, "AOS")) {
// gpredict just kind of shoves this message in on top of the HamLib
// protocol.
try self.replyStatus(.okay);
} else if (std.mem.eql(u8, first, "LOS")) {
try self.replyStatus(.okay);
} else try self.replyStatus(.not_supported);
} else {
try self.parseLongCommand(first, &tokens);
}
}
fn parseLongCommand(
@ -105,12 +113,12 @@ fn parseLongCommand(
for (rotctl_commands) |check| {
if (check.long) |long| {
if (command.len >= long.len and std.mem.eql(u8, long, command)) {
log.warn("Unsupported command {s}", .{command});
log.warn("Unsupported long command {s}", .{command});
break;
}
}
} else {
log.warn("Unknown command {s}", .{command});
log.warn("Unknown long command '{s}'", .{command});
}
return self.replyStatus(.not_supported);
}
@ -154,6 +162,8 @@ const HamlibCommand = struct {
const rotctl_commands = [_]HamlibCommand{
.{ .short = 'q' }, // quit
.{ .short = 'Q' }, // quit
.{ .long = "AOS" },
.{ .long = "LOS" },
.{ .short = 'P', .long = "set_pos" }, // azimuth: f64, elevation: f64
.{ .short = 'p', .long = "get_pos" }, // return az: f64, el: f64
.{ .short = 'M', .long = "move" }, // direction: enum { up=2, down=4, left=8, right=16 }, speed: i8 (0-100 or -1)