Compare commits
6 Commits
adc2997f0d
...
master
Author | SHA1 | Date | |
---|---|---|---|
ddbfb9746d
|
|||
db55a5081d
|
|||
b6caab906a
|
|||
511f2ca903
|
|||
1a541c71ea
|
|||
7bdea9644c
|
47
src/Config.zig
Normal file
47
src/Config.zig
Normal file
@@ -0,0 +1,47 @@
|
||||
const std = @import("std");
|
||||
|
||||
const Config = @This();
|
||||
|
||||
elevation_mask: f64 = 19,
|
||||
rotctld: AddressPort = .{ .address = "127.0.0.1", .port = 4533 },
|
||||
listen: AddressPort = .{ .address = "127.0.0.1", .port = 42069 },
|
||||
|
||||
const confdir = "rotint";
|
||||
const conffile = "config.json";
|
||||
|
||||
pub fn default() Config {
|
||||
return .{};
|
||||
}
|
||||
|
||||
pub fn load(allocator: std.mem.Allocator, env: *const std.process.EnvMap) !Config {
|
||||
if (env.get("XDG_CONFIG_HOME")) |cfg|
|
||||
if (cfg.len > 0) {
|
||||
return try loadPath(allocator, try std.fs.path.join(
|
||||
allocator,
|
||||
&.{ cfg, confdir, conffile },
|
||||
));
|
||||
};
|
||||
|
||||
if (env.get("HOME")) |home|
|
||||
if (home.len > 0) {
|
||||
return try loadPath(allocator, try std.fs.path.join(
|
||||
allocator,
|
||||
&.{ home, ".config", confdir, conffile },
|
||||
));
|
||||
};
|
||||
|
||||
return error.ConfigHomeMissing;
|
||||
}
|
||||
|
||||
fn loadPath(allocator: std.mem.Allocator, path: []const u8) !Config {
|
||||
defer allocator.free(path);
|
||||
const data = try std.fs.cwd().readFileAlloc(allocator, path, 1024);
|
||||
defer allocator.free(data);
|
||||
|
||||
return try std.json.parseFromSliceLeaky(Config, allocator, data, .{});
|
||||
}
|
||||
|
||||
const AddressPort = struct {
|
||||
address: []const u8,
|
||||
port: u16,
|
||||
};
|
65
src/main.zig
65
src/main.zig
@@ -6,6 +6,7 @@ const xev = @import("xev");
|
||||
|
||||
const networking = @import("./networking.zig");
|
||||
const rotctl = @import("./rotctl.zig");
|
||||
const Config = @import("./Config.zig");
|
||||
|
||||
const log = std.log.scoped(.rotint);
|
||||
|
||||
@@ -80,10 +81,11 @@ pub const RotInt = struct {
|
||||
offsets: AzEl = .{ .az = 0, .el = 0 },
|
||||
requested_posture: AzEl = .{ .az = 0, .el = 0 },
|
||||
current_posture: AzEl = .{ .az = 0, .el = 0 },
|
||||
poll_interval: u64 = 100,
|
||||
command_freq: u8 = 10,
|
||||
poll_interval: u64 = 500,
|
||||
command_freq: u8 = 4,
|
||||
pollcount: u9 = 0,
|
||||
state: State = .initial,
|
||||
conf: Config,
|
||||
|
||||
termbuffer: std.io.BufferedWriter(4096, std.io.AnyWriter),
|
||||
vx: *vaxis.Vaxis,
|
||||
@@ -110,8 +112,18 @@ pub const RotInt = struct {
|
||||
self.rotator.rotint = self;
|
||||
self.log = try Log.init();
|
||||
|
||||
const connect_addr = try std.net.Address.parseIp("127.0.0.1", 4533);
|
||||
try self.rotator.connect(self.loop, connect_addr);
|
||||
const rotctld_addr = std.net.Address.parseIp(
|
||||
self.conf.rotctld.address,
|
||||
self.conf.rotctld.port,
|
||||
) catch |err| {
|
||||
log.err("could not parse rotctld address {s}:{d}: {s}", .{
|
||||
self.conf.rotctld.address,
|
||||
self.conf.rotctld.port,
|
||||
@errorName(err),
|
||||
});
|
||||
return err;
|
||||
};
|
||||
try self.rotator.connect(self.loop, rotctld_addr);
|
||||
}
|
||||
|
||||
pub fn stateEvent(self: *RotInt, event: State) void {
|
||||
@@ -121,15 +133,20 @@ pub const RotInt = struct {
|
||||
self.warn("rotator connected", .{});
|
||||
self.sendRotatorCommand(.get_position);
|
||||
self.state = .rotator_connected;
|
||||
self.vx.queueRefresh();
|
||||
self.draw() catch {};
|
||||
},
|
||||
.rotator_ready => if (self.state == .rotator_connected) {
|
||||
self.warn("rotator ready", .{});
|
||||
const listen_addr = std.net.Address.parseIp("127.0.0.1", 42069) catch {
|
||||
self.warn("bogus listen address", .{});
|
||||
const listen_addr = std.net.Address.parseIp(
|
||||
self.conf.listen.address,
|
||||
self.conf.listen.port,
|
||||
) catch |err| {
|
||||
self.showError("bogus listen address: {s}", .{@errorName(err)});
|
||||
return;
|
||||
};
|
||||
self.server.listen(self.loop, listen_addr) catch {
|
||||
self.warn("listen problem", .{});
|
||||
self.server.listen(self.loop, listen_addr) catch |err| {
|
||||
self.showError("listen problem: {s}", .{@errorName(err)});
|
||||
return;
|
||||
};
|
||||
// demangle here to avoid causing initial moves
|
||||
@@ -163,10 +180,27 @@ pub const RotInt = struct {
|
||||
self.pollcount = (self.pollcount + 1) % self.command_freq;
|
||||
|
||||
if (self.pollcount == 0) {
|
||||
const mangled: AzEl = .{
|
||||
var mangled: AzEl = .{
|
||||
.az = self.requested_posture.az + self.offsets.az,
|
||||
.el = self.requested_posture.el + self.offsets.el,
|
||||
.el = self.requested_posture.el,
|
||||
};
|
||||
mangled.el = if (mangled.el > 90)
|
||||
@max(
|
||||
@min(
|
||||
@min(mangled.el, 180 - self.conf.elevation_mask) - self.offsets.el,
|
||||
180 - self.conf.elevation_mask,
|
||||
),
|
||||
90,
|
||||
)
|
||||
else
|
||||
@min(
|
||||
@max(
|
||||
@max(mangled.el, self.conf.elevation_mask) + self.offsets.el,
|
||||
self.conf.elevation_mask,
|
||||
),
|
||||
90,
|
||||
);
|
||||
|
||||
self.sendRotatorCommand(.{ .set_position = mangled });
|
||||
} else {
|
||||
self.sendRotatorCommand(.get_position);
|
||||
@@ -207,6 +241,10 @@ pub const RotInt = struct {
|
||||
log.warn(fmt, args);
|
||||
}
|
||||
|
||||
pub fn showError(_: *RotInt, comptime fmt: []const u8, args: anytype) void {
|
||||
log.err(fmt, args);
|
||||
}
|
||||
|
||||
pub fn handleControlRequest(self: *RotInt, req: []const u8) void {
|
||||
const command = self.parser.parseCommand(req) catch |err| switch (err) {
|
||||
error.Incomplete => return,
|
||||
@@ -385,8 +423,15 @@ pub fn main() !void {
|
||||
});
|
||||
defer loop.deinit();
|
||||
|
||||
var env = try std.process.getEnvMap(alloc);
|
||||
defer env.deinit();
|
||||
|
||||
var app: RotInt = .{
|
||||
.allocator = alloc,
|
||||
.conf = Config.load(alloc, &env) catch cfg: {
|
||||
log.warn("Could not load config file. Using defaults.", .{});
|
||||
break :cfg Config.default();
|
||||
},
|
||||
.termbuffer = tty.bufferedWriter(),
|
||||
.vx = &vx,
|
||||
.loop = &loop,
|
||||
|
@@ -218,7 +218,9 @@ pub const Client = struct {
|
||||
|
||||
_ = result catch |err| {
|
||||
self.rotint.warn("connect failed {}", .{err});
|
||||
// retry bayeb
|
||||
// Note: this loops instantaneously if the target address is on localhost
|
||||
// and is not being listened on. Actually just straight up crashes on macOS.
|
||||
// Probably need to use a timer to handle this better
|
||||
return .rearm;
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user