Compare commits
5 Commits
011f300f0a
...
8d9fee7796
Author | SHA1 | Date | |
---|---|---|---|
8d9fee7796 | |||
b12a44b88b | |||
8ccd292fed | |||
2afb88ef5f | |||
e5d8a716b0 |
22
build.zig
22
build.zig
@ -4,12 +4,24 @@ pub fn build(b: *std.Build) void {
|
|||||||
const target = b.standardTargetOptions(.{});
|
const target = b.standardTargetOptions(.{});
|
||||||
const optimize = b.standardOptimizeOption(.{});
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
const use_udev = b.option(
|
const libusb_use_udev = b.option(
|
||||||
bool,
|
bool,
|
||||||
"use_udev",
|
"use_udev",
|
||||||
"link and use udev (Linux only. Default: false)",
|
"link and use udev (Linux only. Default: false)",
|
||||||
) orelse false;
|
) orelse false;
|
||||||
|
|
||||||
|
const libusb_enable_logging = b.option(
|
||||||
|
bool,
|
||||||
|
"libusb_enable_logging",
|
||||||
|
"enable libusb's built-in logging (Default: false)",
|
||||||
|
) orelse false;
|
||||||
|
|
||||||
|
const libusb_enable_debug_logging = b.option(
|
||||||
|
bool,
|
||||||
|
"libusb_enable_debug_logging",
|
||||||
|
"enable libusb's debug logging (Default: false)",
|
||||||
|
) orelse false;
|
||||||
|
|
||||||
const exe = b.addExecutable(.{
|
const exe = b.addExecutable(.{
|
||||||
.name = "yaes",
|
.name = "yaes",
|
||||||
.root_source_file = b.path("src/main.zig"),
|
.root_source_file = b.path("src/main.zig"),
|
||||||
@ -38,7 +50,13 @@ pub fn build(b: *std.Build) void {
|
|||||||
} else {
|
} else {
|
||||||
const ljacklm_dep = b.dependency(
|
const ljacklm_dep = b.dependency(
|
||||||
"ljacklm",
|
"ljacklm",
|
||||||
.{ .target = target, .optimize = optimize, .use_udev = use_udev },
|
.{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.libusb_use_udev = libusb_use_udev,
|
||||||
|
.libusb_enable_logging = libusb_enable_logging,
|
||||||
|
.libusb_enable_debug_logging = libusb_enable_debug_logging,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
exe.linkLibrary(ljacklm_dep.artifact("ljacklm"));
|
exe.linkLibrary(ljacklm_dep.artifact("ljacklm"));
|
||||||
}
|
}
|
||||||
|
26
deps/labjack/exodriver/build.zig
vendored
26
deps/labjack/exodriver/build.zig
vendored
@ -4,10 +4,22 @@ pub fn build(b: *std.Build) !void {
|
|||||||
const target = b.standardTargetOptions(.{});
|
const target = b.standardTargetOptions(.{});
|
||||||
const optimize = b.standardOptimizeOption(.{});
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
const use_udev = b.option(
|
const libusb_use_udev = b.option(
|
||||||
bool,
|
bool,
|
||||||
"use_udev",
|
"libusb_use_udev",
|
||||||
"link and use udev (Linux only. Default: false)",
|
"libusb: link and use udev (Linux only. Default: false)",
|
||||||
|
) orelse false;
|
||||||
|
|
||||||
|
const libusb_enable_logging = b.option(
|
||||||
|
bool,
|
||||||
|
"libusb_enable_logging",
|
||||||
|
"enable libusb's built-in logging (Default: false)",
|
||||||
|
) orelse false;
|
||||||
|
|
||||||
|
const libusb_enable_debug_logging = b.option(
|
||||||
|
bool,
|
||||||
|
"libusb_enable_debug_logging",
|
||||||
|
"enable libusb's debug logging (Default: false)",
|
||||||
) orelse false;
|
) orelse false;
|
||||||
|
|
||||||
const liblabjackusb = b.addStaticLibrary(.{
|
const liblabjackusb = b.addStaticLibrary(.{
|
||||||
@ -31,7 +43,13 @@ pub fn build(b: *std.Build) !void {
|
|||||||
|
|
||||||
const usb_dep = b.dependency(
|
const usb_dep = b.dependency(
|
||||||
"usb",
|
"usb",
|
||||||
.{ .target = target, .optimize = optimize, .use_udev = use_udev },
|
.{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.use_udev = libusb_use_udev,
|
||||||
|
.enable_logging = libusb_enable_logging,
|
||||||
|
.enable_debug_logging = libusb_enable_debug_logging,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
liblabjackusb.linkLibrary(usb_dep.artifact("usb"));
|
liblabjackusb.linkLibrary(usb_dep.artifact("usb"));
|
||||||
|
|
||||||
|
26
deps/labjack/ljacklm/build.zig
vendored
26
deps/labjack/ljacklm/build.zig
vendored
@ -4,10 +4,22 @@ pub fn build(b: *std.Build) !void {
|
|||||||
const target = b.standardTargetOptions(.{});
|
const target = b.standardTargetOptions(.{});
|
||||||
const optimize = b.standardOptimizeOption(.{});
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
const use_udev = b.option(
|
const libusb_use_udev = b.option(
|
||||||
bool,
|
bool,
|
||||||
"use_udev",
|
"libusb_use_udev",
|
||||||
"link and use udev (Linux only. Default: false)",
|
"libusb: link and use udev (Linux only. Default: false)",
|
||||||
|
) orelse false;
|
||||||
|
|
||||||
|
const libusb_enable_logging = b.option(
|
||||||
|
bool,
|
||||||
|
"libusb_enable_logging",
|
||||||
|
"enable libusb's built-in logging (Default: false)",
|
||||||
|
) orelse false;
|
||||||
|
|
||||||
|
const libusb_enable_debug_logging = b.option(
|
||||||
|
bool,
|
||||||
|
"libusb_enable_debug_logging",
|
||||||
|
"enable libusb's debug logging (Default: false)",
|
||||||
) orelse false;
|
) orelse false;
|
||||||
|
|
||||||
const libljacklm = b.addStaticLibrary(.{
|
const libljacklm = b.addStaticLibrary(.{
|
||||||
@ -30,7 +42,13 @@ pub fn build(b: *std.Build) !void {
|
|||||||
|
|
||||||
const usb_dep = b.dependency(
|
const usb_dep = b.dependency(
|
||||||
"labjackusb",
|
"labjackusb",
|
||||||
.{ .target = target, .optimize = optimize, .use_udev = use_udev },
|
.{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.libusb_use_udev = libusb_use_udev,
|
||||||
|
.libusb_enable_logging = libusb_enable_logging,
|
||||||
|
.libusb_enable_debug_logging = libusb_enable_debug_logging,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
libljacklm.linkLibrary(usb_dep.artifact("labjackusb"));
|
libljacklm.linkLibrary(usb_dep.artifact("labjackusb"));
|
||||||
|
|
||||||
|
16
deps/libusb/build.zig
vendored
16
deps/libusb/build.zig
vendored
@ -10,6 +10,18 @@ pub fn build(b: *std.Build) !void {
|
|||||||
"link and use udev (Linux only. Default: false)",
|
"link and use udev (Linux only. Default: false)",
|
||||||
) orelse false;
|
) orelse false;
|
||||||
|
|
||||||
|
const enable_logging = b.option(
|
||||||
|
bool,
|
||||||
|
"enable_logging",
|
||||||
|
"enable libusb's built-in logging (Default: false)",
|
||||||
|
) orelse false;
|
||||||
|
|
||||||
|
const enable_debug_logging = b.option(
|
||||||
|
bool,
|
||||||
|
"enable_debug_logging",
|
||||||
|
"enable libusb's debug logging (Default: false)",
|
||||||
|
) orelse false;
|
||||||
|
|
||||||
const libusb = b.addStaticLibrary(.{
|
const libusb = b.addStaticLibrary(.{
|
||||||
.name = "usb",
|
.name = "usb",
|
||||||
.target = target,
|
.target = target,
|
||||||
@ -59,8 +71,8 @@ pub fn build(b: *std.Build) !void {
|
|||||||
.{ .style = .{ .autoconf = b.path("config.h.in") } },
|
.{ .style = .{ .autoconf = b.path("config.h.in") } },
|
||||||
.{
|
.{
|
||||||
.DEFAULT_VISIBILITY = .@"__attribute__ ((visibility (\"default\")))",
|
.DEFAULT_VISIBILITY = .@"__attribute__ ((visibility (\"default\")))",
|
||||||
.ENABLE_DEBUG_LOGGING = oneOrNull(optimize == .Debug),
|
.ENABLE_DEBUG_LOGGING = oneOrNull(enable_debug_logging),
|
||||||
.ENABLE_LOGGING = oneOrNull(optimize == .Debug),
|
.ENABLE_LOGGING = oneOrNull(enable_logging),
|
||||||
.HAVE_ASM_TYPES_H = null,
|
.HAVE_ASM_TYPES_H = null,
|
||||||
.HAVE_CLOCK_GETTIME = oneOrNull(linux_target),
|
.HAVE_CLOCK_GETTIME = oneOrNull(linux_target),
|
||||||
.HAVE_DECL_EFD_CLOEXEC = oneOrNull(linux_target),
|
.HAVE_DECL_EFD_CLOEXEC = oneOrNull(linux_target),
|
||||||
|
@ -1,35 +1,41 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
const AzEl = @import("./LabjackYaesu.zig").AzEl;
|
const AzEl = @import("./YaesuController.zig").AzEl;
|
||||||
const lj = @import("./labjack.zig");
|
const lj = @import("./labjack.zig");
|
||||||
|
|
||||||
const Config = @This();
|
const Config = @This();
|
||||||
|
|
||||||
var global_internal: Config = undefined;
|
var global_internal: std.json.Parsed(Config) = undefined;
|
||||||
pub const global: *const Config = &global_internal;
|
pub const global: *const Config = &global_internal.value;
|
||||||
|
|
||||||
pub fn load(allocator: std.mem.Allocator, reader: anytype, err_writer: anytype) !void {
|
pub fn load(allocator: std.mem.Allocator, reader: anytype, err_writer: anytype) !void {
|
||||||
var jread = std.json.Reader(1024, @TypeOf(reader)).init(allocator, reader);
|
var jread = std.json.Reader(1024, @TypeOf(reader)).init(allocator, reader);
|
||||||
defer jread.deinit();
|
defer jread.deinit();
|
||||||
|
|
||||||
global_internal = try std.json.parseFromTokenSourceLeaky(
|
global_internal = try std.json.parseFromTokenSource(
|
||||||
Config,
|
Config,
|
||||||
allocator,
|
allocator,
|
||||||
&jread,
|
&jread,
|
||||||
.{},
|
.{},
|
||||||
);
|
);
|
||||||
|
|
||||||
try global_internal.validate(err_writer);
|
try global.validate(err_writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn loadDefault(allocator: std.mem.Allocator) void {
|
pub fn loadDefault(allocator: std.mem.Allocator) void {
|
||||||
_ = allocator;
|
const arena = allocator.create(std.heap.ArenaAllocator) catch unreachable;
|
||||||
global_internal = .{};
|
arena.* = std.heap.ArenaAllocator.init(allocator);
|
||||||
|
global_internal = .{
|
||||||
|
.arena = arena,
|
||||||
|
.value = .{},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn destroy(allocator: std.mem.Allocator) void {
|
pub fn deinit() void {
|
||||||
// TODO: implement this probably
|
// TODO: implement this probably
|
||||||
_ = allocator;
|
const allocator = global_internal.arena.child_allocator;
|
||||||
|
global_internal.arena.deinit();
|
||||||
|
allocator.destroy(global_internal.arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validate(self: Config, err_writer: anytype) !void {
|
pub fn validate(self: Config, err_writer: anytype) !void {
|
||||||
|
@ -2,7 +2,7 @@ const std = @import("std");
|
|||||||
|
|
||||||
const Config = @import("./Config.zig");
|
const Config = @import("./Config.zig");
|
||||||
const config = Config.global;
|
const config = Config.global;
|
||||||
const LabjackYaesu = @import("./LabjackYaesu.zig");
|
const YaesuController = @import("./YaesuController.zig");
|
||||||
|
|
||||||
const RotCtl = @This();
|
const RotCtl = @This();
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ const log = std.log.scoped(.RotCtl);
|
|||||||
|
|
||||||
writer: std.io.BufferedWriter(512, std.net.Stream.Writer),
|
writer: std.io.BufferedWriter(512, std.net.Stream.Writer),
|
||||||
running: bool,
|
running: bool,
|
||||||
rotator: LabjackYaesu,
|
rotator: YaesuController,
|
||||||
|
|
||||||
pub fn run(allocator: std.mem.Allocator) !void {
|
pub fn run(allocator: std.mem.Allocator) !void {
|
||||||
// var server = std.net.StreamServer.init(.{ .reuse_address = true });
|
// var server = std.net.StreamServer.init(.{ .reuse_address = true });
|
||||||
@ -30,7 +30,7 @@ pub fn run(allocator: std.mem.Allocator) !void {
|
|||||||
var interface: RotCtl = .{
|
var interface: RotCtl = .{
|
||||||
.writer = undefined,
|
.writer = undefined,
|
||||||
.running = true,
|
.running = true,
|
||||||
.rotator = try LabjackYaesu.init(allocator),
|
.rotator = try YaesuController.init(allocator),
|
||||||
};
|
};
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -4,9 +4,9 @@ const lj = @import("./labjack.zig");
|
|||||||
const Config = @import("./Config.zig");
|
const Config = @import("./Config.zig");
|
||||||
const config = Config.global;
|
const config = Config.global;
|
||||||
|
|
||||||
const log = std.log.scoped(.labjack_yaesu);
|
const log = std.log.scoped(.yaesu_controller);
|
||||||
|
|
||||||
const LabjackYaesu = @This();
|
const YaesuController = @This();
|
||||||
|
|
||||||
control_thread: std.Thread,
|
control_thread: std.Thread,
|
||||||
lock: *std.Thread.Mutex,
|
lock: *std.Thread.Mutex,
|
||||||
@ -17,7 +17,25 @@ pub const AzEl = struct {
|
|||||||
elevation: f64,
|
elevation: f64,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn init(allocator: std.mem.Allocator) !LabjackYaesu {
|
pub const CalibrationRoutine = enum {
|
||||||
|
feedback,
|
||||||
|
orientation,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn calibrate(allocator: std.mem.Allocator, routine: CalibrationRoutine) !void {
|
||||||
|
const controller = try YaesuController.init(allocator);
|
||||||
|
defer {
|
||||||
|
controller.quit();
|
||||||
|
controller.control_thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (routine) {
|
||||||
|
.feedback => try controller.calibrate_feedback(),
|
||||||
|
.orientation => try controller.calibrate_orientation(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(allocator: std.mem.Allocator) !YaesuController {
|
||||||
const lock = try allocator.create(std.Thread.Mutex);
|
const lock = try allocator.create(std.Thread.Mutex);
|
||||||
errdefer allocator.destroy(lock);
|
errdefer allocator.destroy(lock);
|
||||||
lock.* = .{};
|
lock.* = .{};
|
||||||
@ -56,7 +74,7 @@ fn inRange(request: f64, comptime dof: enum { azimuth, elevation }) bool {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setTarget(self: LabjackYaesu, target: AzEl) error{OutOfRange}!void {
|
pub fn setTarget(self: YaesuController, target: AzEl) error{OutOfRange}!void {
|
||||||
self.lock.lock();
|
self.lock.lock();
|
||||||
defer self.lock.unlock();
|
defer self.lock.unlock();
|
||||||
|
|
||||||
@ -76,14 +94,14 @@ pub fn setTarget(self: LabjackYaesu, target: AzEl) error{OutOfRange}!void {
|
|||||||
controller.requested_state = .running;
|
controller.requested_state = .running;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn currentPosition(self: LabjackYaesu) AzEl {
|
pub fn currentPosition(self: YaesuController) AzEl {
|
||||||
self.lock.lock();
|
self.lock.lock();
|
||||||
defer self.lock.unlock();
|
defer self.lock.unlock();
|
||||||
|
|
||||||
return self.controller.position;
|
return self.controller.position;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn startCalibration(self: LabjackYaesu) void {
|
pub fn startCalibration(self: YaesuController) void {
|
||||||
// there are two different types of calibration:
|
// there are two different types of calibration:
|
||||||
// 1. feedback calibration, running to the extents of the rotator
|
// 1. feedback calibration, running to the extents of the rotator
|
||||||
// 2. sun calibration, which determines the azimuth and elevation angle
|
// 2. sun calibration, which determines the azimuth and elevation angle
|
||||||
@ -95,7 +113,7 @@ pub fn startCalibration(self: LabjackYaesu) void {
|
|||||||
_ = self;
|
_ = self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn quit(self: LabjackYaesu) void {
|
pub fn quit(self: YaesuController) void {
|
||||||
self.lock.lock();
|
self.lock.lock();
|
||||||
defer self.lock.unlock();
|
defer self.lock.unlock();
|
||||||
|
|
||||||
@ -103,7 +121,7 @@ pub fn quit(self: LabjackYaesu) void {
|
|||||||
controller.requested_state = .stopped;
|
controller.requested_state = .stopped;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stop(self: LabjackYaesu) void {
|
pub fn stop(self: YaesuController) void {
|
||||||
self.lock.lock();
|
self.lock.lock();
|
||||||
defer self.lock.unlock();
|
defer self.lock.unlock();
|
||||||
|
|
||||||
@ -112,14 +130,26 @@ pub fn stop(self: LabjackYaesu) void {
|
|||||||
controller.requested_state = .idle;
|
controller.requested_state = .idle;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn startPark(self: LabjackYaesu) void {
|
pub fn startPark(self: YaesuController) void {
|
||||||
self.setTarget(config.controller.parking_posture) catch unreachable;
|
self.setTarget(config.controller.parking_posture) catch unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn calibrate_feedback(self: YaesuController) !void {
|
||||||
|
_ = self;
|
||||||
|
log.err("this isn't implemented yet, sorry.", .{});
|
||||||
|
return error.NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn calibrate_orientation(self: YaesuController) !void {
|
||||||
|
_ = self;
|
||||||
|
log.err("this isn't implemented yet, sorry.", .{});
|
||||||
|
return error.NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
fn runController(controller: *Controller) void {
|
fn runController(controller: *Controller) void {
|
||||||
controller.run() catch {
|
controller.run() catch {
|
||||||
log.err(
|
log.err(
|
||||||
"the labjack control loop has terminated unexpectedly!!!!",
|
"the rotator control loop has terminated unexpectedly!!!!",
|
||||||
.{},
|
.{},
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -180,7 +210,21 @@ const Controller = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn signDeadzone(offset: f64, deadzone: f64) enum { negative, zero, positive } {
|
const Sign = enum {
|
||||||
|
negative,
|
||||||
|
zero,
|
||||||
|
positive,
|
||||||
|
|
||||||
|
pub fn symbol(self: Sign) u8 {
|
||||||
|
return switch (self) {
|
||||||
|
.negative => '-',
|
||||||
|
.zero => '=',
|
||||||
|
.positive => '+',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fn signDeadzone(offset: f64, deadzone: f64) Sign {
|
||||||
return if (@abs(offset) < deadzone)
|
return if (@abs(offset) < deadzone)
|
||||||
.zero
|
.zero
|
||||||
else if (offset < 0)
|
else if (offset < 0)
|
||||||
@ -224,11 +268,23 @@ const Controller = struct {
|
|||||||
drive_signal[config.controller.elevation_outputs.increase.io] = elsign == .positive;
|
drive_signal[config.controller.elevation_outputs.increase.io] = elsign == .positive;
|
||||||
drive_signal[config.controller.elevation_outputs.decrease.io] = elsign == .negative;
|
drive_signal[config.controller.elevation_outputs.decrease.io] = elsign == .negative;
|
||||||
|
|
||||||
log.info("drive: az = {s}, el = {s}. outputs: {any}", .{ @tagName(azsign), @tagName(elsign), drive_signal });
|
|
||||||
|
|
||||||
const raw = try self.labjack.readAnalogWriteDigital(2, inputs, drive_signal, true);
|
const raw = try self.labjack.readAnalogWriteDigital(2, inputs, drive_signal, true);
|
||||||
|
const angles = lerpAndOffsetAngles(raw);
|
||||||
|
|
||||||
return lerpAndOffsetAngles(raw);
|
log.info(
|
||||||
|
"az: {d:.1}° ({d:.2} V) {d:.1}° => {c}, el: {d:.1}° ({d:.2} V) {d:.1}° => {c}",
|
||||||
|
.{
|
||||||
|
angles.azimuth,
|
||||||
|
raw[0].voltage,
|
||||||
|
pos_error.azimuth,
|
||||||
|
azsign.symbol(),
|
||||||
|
angles.elevation,
|
||||||
|
raw[1].voltage,
|
||||||
|
pos_error.elevation,
|
||||||
|
elsign.symbol(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return angles;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(self: *Controller) !void {
|
fn run(self: *Controller) !void {
|
62
src/main.zig
62
src/main.zig
@ -3,6 +3,7 @@ const std = @import("std");
|
|||||||
const Config = @import("./Config.zig");
|
const Config = @import("./Config.zig");
|
||||||
const lj = @import("./labjack.zig");
|
const lj = @import("./labjack.zig");
|
||||||
const RotCtl = @import("./RotCtl.zig");
|
const RotCtl = @import("./RotCtl.zig");
|
||||||
|
const YaesuController = @import("./YaesuController.zig");
|
||||||
|
|
||||||
const udev = @import("udev_rules");
|
const udev = @import("udev_rules");
|
||||||
|
|
||||||
@ -47,37 +48,42 @@ pub fn main() !u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Config.loadDefault(allocator);
|
Config.loadDefault(allocator);
|
||||||
|
defer Config.deinit();
|
||||||
return writeDefaultConfig(if (args.len == 3) args[2] else null);
|
return writeDefaultConfig(if (args.len == 3) args[2] else null);
|
||||||
} else if (std.mem.eql(u8, args[1], commands.run)) {
|
} else if (std.mem.eql(u8, args[1], commands.run)) {
|
||||||
if (args.len > 3) {
|
if (args.len > 3) {
|
||||||
printHelp(exename, .run);
|
printHelp(exename, .run);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
blk: {
|
loadConfigOrDefault(allocator, if (args.len == 3) args[2] else null) catch
|
||||||
const confpath = if (args.len == 3) args[2] else "yaes.json";
|
return 1;
|
||||||
const conf_file = std.fs.cwd().openFile(confpath, .{}) catch {
|
|
||||||
log.warn("Could not load config file '{s}'. Using default config.", .{confpath});
|
|
||||||
Config.loadDefault(allocator);
|
|
||||||
break :blk;
|
|
||||||
};
|
|
||||||
defer conf_file.close();
|
|
||||||
|
|
||||||
Config.load(allocator, conf_file.reader(), std.io.getStdErr().writer()) catch |err| {
|
defer Config.deinit();
|
||||||
log.err("Could not parse config file '{s}': {s}.", .{ confpath, @errorName(err) });
|
|
||||||
return 1;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
defer Config.destroy(allocator);
|
|
||||||
|
|
||||||
const ver = lj.getDriverVersion();
|
|
||||||
std.debug.print("Driver version: {d}\n", .{ver});
|
|
||||||
|
|
||||||
RotCtl.run(allocator) catch |err| {
|
RotCtl.run(allocator) catch |err| {
|
||||||
log.err("rotator controller ceased unexpectedly! {s}", .{@errorName(err)});
|
log.err("rotator controller ceased unexpectedly! {s}", .{@errorName(err)});
|
||||||
return 1;
|
return 1;
|
||||||
};
|
};
|
||||||
|
} else if (std.mem.eql(u8, args[1], commands.calibrate)) {
|
||||||
|
if (args.len < 3 or args.len > 4) {
|
||||||
|
printHelp(exename, .calibrate);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
loadConfigOrDefault(allocator, if (args.len == 4) args[3] else null) catch
|
||||||
|
return 1;
|
||||||
|
defer Config.deinit();
|
||||||
|
|
||||||
|
const routine = std.meta.stringToEnum(YaesuController.CalibrationRoutine, args[2]) orelse {
|
||||||
|
log.err("{s} is not a known calibration routine.", .{args[2]});
|
||||||
|
printHelp(exename, .calibrate);
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
YaesuController.calibrate(allocator, routine) catch |err| {
|
||||||
|
log.err("Calibration failed: {s}", .{@errorName(err)});
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
} else if (std.mem.eql(u8, args[1], commands.help)) {
|
} else if (std.mem.eql(u8, args[1], commands.help)) {
|
||||||
if (args.len != 3) {
|
if (args.len != 3) {
|
||||||
printHelp(exename, .help);
|
printHelp(exename, .help);
|
||||||
@ -97,6 +103,24 @@ pub fn main() !u8 {
|
|||||||
printHelp(exename, .main);
|
printHelp(exename, .main);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn loadConfigOrDefault(allocator: std.mem.Allocator, path: ?[]const u8) !void {
|
||||||
|
const confpath = path orelse "yaes.json";
|
||||||
|
const conf_file = std.fs.cwd().openFile(confpath, .{}) catch {
|
||||||
|
log.warn("Could not load config file '{s}'. Using default config.", .{confpath});
|
||||||
|
Config.loadDefault(allocator);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
defer conf_file.close();
|
||||||
|
|
||||||
|
Config.load(allocator, conf_file.reader(), std.io.getStdErr().writer()) catch |err| {
|
||||||
|
log.err("Could not parse config file '{s}': {s}.", .{ confpath, @errorName(err) });
|
||||||
|
return error.InvalidConfig;
|
||||||
|
};
|
||||||
|
log.info("Loaded config from '{s}'.", .{confpath});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn installUdevRules(outpath: ?[]const u8) u8 {
|
fn installUdevRules(outpath: ?[]const u8) u8 {
|
||||||
@ -261,7 +285,7 @@ const command_help = .{
|
|||||||
\\ Perform a calibration routine and write an updated configuration with its results.
|
\\ Perform a calibration routine and write an updated configuration with its results.
|
||||||
\\
|
\\
|
||||||
\\Arguments:
|
\\Arguments:
|
||||||
\\ routine Must be one of `feedback` or `orientation`. The different calibration routines have
|
\\ routine Must be either `feedback` or `orientation`. The different calibration routines have
|
||||||
\\ different requirements. `orientation` calibration is a sun-pointing-based routine and
|
\\ different requirements. `orientation` calibration is a sun-pointing-based routine and
|
||||||
\\ should be performed after `feedback` calibration is complete.
|
\\ should be performed after `feedback` calibration is complete.
|
||||||
\\ config_file [Optional] the path of a config file to load. This file will be updated with the
|
\\ config_file [Optional] the path of a config file to load. This file will be updated with the
|
||||||
|
Loading…
x
Reference in New Issue
Block a user