main: add configurable poll/command rates
These are coupled in a somewhat nonintuitive manner. Previously, we would send a command every other request. Due to an oversight, we were only sending a request once per second, which meant we were reading position once every two seconds and writing position once every two seconds. However, this seemed to work pretty well (at least the radio performance was largely improved and qualitatively it seemed like the controller was doing a better job of keeping up with the pointing target). I wanted the UI to update the position more frequently, so we keep the scheme of sending a command every N requests, but we send significantly more get position requests. These can be adjusted on the fly in order to get an idea of how much the communication pattern actually impacts the pointing performance.
This commit is contained in:
parent
8c6d9431c8
commit
e1c54fec91
125
src/main.zig
125
src/main.zig
@ -24,7 +24,9 @@ pub const RotInt = struct {
|
|||||||
offsets: AzEl = .{ .az = 0, .el = 0 },
|
offsets: AzEl = .{ .az = 0, .el = 0 },
|
||||||
requested_posture: AzEl = .{ .az = 0, .el = 0 },
|
requested_posture: AzEl = .{ .az = 0, .el = 0 },
|
||||||
current_posture: AzEl = .{ .az = 0, .el = 0 },
|
current_posture: AzEl = .{ .az = 0, .el = 0 },
|
||||||
flipflop: bool = false,
|
poll_interval: u64 = 100,
|
||||||
|
command_freq: u8 = 10,
|
||||||
|
pollcount: u9 = 0,
|
||||||
state: State = .initial,
|
state: State = .initial,
|
||||||
|
|
||||||
termbuffer: std.io.BufferedWriter(4096, std.io.AnyWriter),
|
termbuffer: std.io.BufferedWriter(4096, std.io.AnyWriter),
|
||||||
@ -38,8 +40,6 @@ pub const RotInt = struct {
|
|||||||
poller: xev.Timer,
|
poller: xev.Timer,
|
||||||
poll_completion: xev.Completion = undefined,
|
poll_completion: xev.Completion = undefined,
|
||||||
|
|
||||||
const poll_interval: u64 = 1000;
|
|
||||||
|
|
||||||
pub const State = enum {
|
pub const State = enum {
|
||||||
initial,
|
initial,
|
||||||
rotator_connected,
|
rotator_connected,
|
||||||
@ -99,7 +99,11 @@ pub const RotInt = struct {
|
|||||||
return .disarm;
|
return .disarm;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (self.flipflop) {
|
// pre-increment so that this does not try to command when pollcount = 0 on the
|
||||||
|
// first call
|
||||||
|
self.pollcount = (self.pollcount + 1) % self.command_freq;
|
||||||
|
|
||||||
|
if (self.pollcount == 0) {
|
||||||
const mangled: AzEl = .{
|
const mangled: AzEl = .{
|
||||||
.az = self.requested_posture.az + self.offsets.az,
|
.az = self.requested_posture.az + self.offsets.az,
|
||||||
.el = self.requested_posture.el + self.offsets.el,
|
.el = self.requested_posture.el + self.offsets.el,
|
||||||
@ -108,7 +112,6 @@ pub const RotInt = struct {
|
|||||||
} else {
|
} else {
|
||||||
self.sendRotatorCommand(.get_position);
|
self.sendRotatorCommand(.get_position);
|
||||||
}
|
}
|
||||||
self.flipflop = !self.flipflop;
|
|
||||||
|
|
||||||
return .disarm;
|
return .disarm;
|
||||||
}
|
}
|
||||||
@ -136,7 +139,7 @@ pub const RotInt = struct {
|
|||||||
.status => |code| if (code != .okay)
|
.status => |code| if (code != .okay)
|
||||||
self.warn("rotctl error {s}", .{@tagName(code)}),
|
self.warn("rotctl error {s}", .{@tagName(code)}),
|
||||||
}
|
}
|
||||||
self.poller.run(self.loop, &self.poll_completion, poll_interval, RotInt, self, poll);
|
self.poller.run(self.loop, &self.poll_completion, self.poll_interval, RotInt, self, poll);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn warn(_: *RotInt, comptime fmt: []const u8, args: anytype) void {
|
pub fn warn(_: *RotInt, comptime fmt: []const u8, args: anytype) void {
|
||||||
@ -178,7 +181,7 @@ pub const RotInt = struct {
|
|||||||
const win = self.vx.window();
|
const win = self.vx.window();
|
||||||
win.clear();
|
win.clear();
|
||||||
|
|
||||||
var lines: [3][128]u8 = undefined;
|
var lines: [4][128]u8 = undefined;
|
||||||
const offsets: vaxis.Segment = .{ .text = try std.fmt.bufPrint(
|
const offsets: vaxis.Segment = .{ .text = try std.fmt.bufPrint(
|
||||||
lines[0][0..],
|
lines[0][0..],
|
||||||
"Offsets: Az: {d: >6.1}, El: {d: >6.1}",
|
"Offsets: Az: {d: >6.1}, El: {d: >6.1}",
|
||||||
@ -194,13 +197,28 @@ pub const RotInt = struct {
|
|||||||
"Current: Az: {d: >6.1}, El: {d: >6.1}",
|
"Current: Az: {d: >6.1}, El: {d: >6.1}",
|
||||||
.{ self.current_posture.az, self.current_posture.el },
|
.{ self.current_posture.az, self.current_posture.el },
|
||||||
) };
|
) };
|
||||||
|
const pollinfo: vaxis.Segment = .{ .text = try std.fmt.bufPrint(
|
||||||
|
lines[3][0..],
|
||||||
|
"Poll: {d} ms, Command: {d} ms",
|
||||||
|
.{ self.poll_interval, self.command_freq * self.poll_interval },
|
||||||
|
) };
|
||||||
|
|
||||||
const center = vaxis.widgets.alignment.center(win, offsets.text.len, 1);
|
const center = vaxis.widgets.alignment.center(win, offsets.text.len, 1);
|
||||||
_ = try center.printSegment(offsets, .{});
|
_ = try center.printSegment(offsets, .{});
|
||||||
const center_up = win.initChild(center.x_off, center.y_off + 1, .{ .limit = requested.text.len }, .{ .limit = 1 });
|
const center_up = win.initChild(center.x_off, center.y_off - 1, .{ .limit = requested.text.len }, .{ .limit = 1 });
|
||||||
_ = try center_up.printSegment(requested, .{});
|
_ = try center_up.printSegment(requested, .{});
|
||||||
const center_down = win.initChild(center.x_off, center.y_off - 1, .{ .limit = current.text.len }, .{ .limit = 1 });
|
const center_down = win.initChild(center.x_off, center.y_off + 1, .{ .limit = current.text.len }, .{ .limit = 1 });
|
||||||
_ = try center_down.printSegment(current, .{});
|
_ = try center_down.printSegment(current, .{});
|
||||||
|
const poll_win = win.initChild(center.x_off, center.y_off + 3, .{ .limit = pollinfo.text.len }, .{ .limit = 1 });
|
||||||
|
_ = try poll_win.printSegment(pollinfo, .{});
|
||||||
|
|
||||||
|
const help: vaxis.Segment = .{
|
||||||
|
.text = "Keys: q/^c - quit, ↑/↓ - el +/- 1° (+shift - 0.1°), ←/→ - az -/+ 1° (+shift - 0.1°), ⏎ - reset offsets, ^l - redraw, w/a/s/d - poll rates",
|
||||||
|
.style = .{ .fg = .{ .index = 245 } },
|
||||||
|
};
|
||||||
|
|
||||||
|
const helpwin = win.child(.{ .x_off = 0, .y_off = 0 });
|
||||||
|
_ = try helpwin.printSegment(help, .{ .wrap = .word });
|
||||||
|
|
||||||
try self.vx.render(self.termbuffer.writer().any());
|
try self.vx.render(self.termbuffer.writer().any());
|
||||||
try self.termbuffer.flush();
|
try self.termbuffer.flush();
|
||||||
@ -214,44 +232,67 @@ pub const RotInt = struct {
|
|||||||
) xev.CallbackAction {
|
) xev.CallbackAction {
|
||||||
const self = self_.?;
|
const self = self_.?;
|
||||||
switch (event) {
|
switch (event) {
|
||||||
.key_press => |key| keyp: {
|
.key_press => |key| {
|
||||||
var mods = key.mods;
|
var mods = key.mods;
|
||||||
mods.caps_lock = false;
|
mods.caps_lock = false;
|
||||||
mods.num_lock = false;
|
mods.num_lock = false;
|
||||||
const scale: f64 = if (std.meta.eql(mods, .{ .shift = true })) 1 else 10;
|
|
||||||
|
|
||||||
const delta: AzEl = switch (key.codepoint) {
|
switch (key.codepoint) {
|
||||||
vaxis.Key.left, vaxis.Key.kp_left => .{ .az = -0.1 * scale, .el = 0 },
|
vaxis.Key.left,
|
||||||
vaxis.Key.right, vaxis.Key.kp_right => .{ .az = 0.1 * scale, .el = 0 },
|
vaxis.Key.kp_left,
|
||||||
vaxis.Key.up, vaxis.Key.kp_up => .{ .az = 0, .el = 0.1 * scale },
|
vaxis.Key.right,
|
||||||
vaxis.Key.down, vaxis.Key.kp_down => .{ .az = 0 * scale, .el = -0.1 * scale },
|
vaxis.Key.kp_right,
|
||||||
'l' => {
|
vaxis.Key.up,
|
||||||
if (std.meta.eql(mods, .{ .ctrl = true }))
|
vaxis.Key.kp_up,
|
||||||
self.vx.queueRefresh();
|
vaxis.Key.down,
|
||||||
break :keyp;
|
vaxis.Key.kp_down,
|
||||||
},
|
vaxis.Key.enter,
|
||||||
'c' => {
|
vaxis.Key.kp_enter,
|
||||||
if (std.meta.eql(mods, .{ .ctrl = true })) {
|
=> |arrow| {
|
||||||
loop.stop();
|
const scale: f64 = if (std.meta.eql(mods, .{ .shift = true })) 1 else 10;
|
||||||
return .disarm;
|
const delta: AzEl = switch (arrow) {
|
||||||
}
|
vaxis.Key.left, vaxis.Key.kp_left => .{ .az = -0.1 * scale, .el = 0 },
|
||||||
break :keyp;
|
vaxis.Key.right, vaxis.Key.kp_right => .{ .az = 0.1 * scale, .el = 0 },
|
||||||
},
|
vaxis.Key.up, vaxis.Key.kp_up => .{ .az = 0, .el = 0.1 * scale },
|
||||||
'q' => {
|
vaxis.Key.down, vaxis.Key.kp_down => .{ .az = 0 * scale, .el = -0.1 * scale },
|
||||||
if (std.meta.eql(mods, .{})) {
|
vaxis.Key.enter, vaxis.Key.kp_enter => .{ .az = -self.offsets.az, .el = -self.offsets.el },
|
||||||
loop.stop();
|
else => unreachable,
|
||||||
return .disarm;
|
};
|
||||||
}
|
|
||||||
break :keyp;
|
|
||||||
},
|
|
||||||
else => break :keyp,
|
|
||||||
};
|
|
||||||
|
|
||||||
self.offsets.az += delta.az;
|
self.offsets.az += delta.az;
|
||||||
self.offsets.el += delta.el;
|
self.offsets.el += delta.el;
|
||||||
self.draw() catch {
|
self.draw() catch {
|
||||||
self.warn("draw failure", .{});
|
self.warn("draw failure", .{});
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
'w', 'a', 's', 'd' => |wasd| {
|
||||||
|
switch (wasd) {
|
||||||
|
'w' => self.poll_interval += 100,
|
||||||
|
'a' => if (self.command_freq > 2) {
|
||||||
|
self.command_freq -= 1;
|
||||||
|
},
|
||||||
|
's' => if (self.poll_interval > 100) {
|
||||||
|
self.poll_interval -= 100;
|
||||||
|
},
|
||||||
|
'd' => self.command_freq += 1,
|
||||||
|
else => unreachable,
|
||||||
|
}
|
||||||
|
self.draw() catch {};
|
||||||
|
},
|
||||||
|
'l' => if (std.meta.eql(mods, .{ .ctrl = true })) {
|
||||||
|
self.vx.queueRefresh();
|
||||||
|
self.draw() catch {};
|
||||||
|
},
|
||||||
|
'c' => if (std.meta.eql(mods, .{ .ctrl = true })) {
|
||||||
|
loop.stop();
|
||||||
|
return .disarm;
|
||||||
|
},
|
||||||
|
'q' => if (std.meta.eql(mods, .{})) {
|
||||||
|
loop.stop();
|
||||||
|
return .disarm;
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
},
|
},
|
||||||
.winsize => |ws| {
|
.winsize => |ws| {
|
||||||
watcher.vx.resize(self.allocator, watcher.tty.anyWriter(), ws) catch
|
watcher.vx.resize(self.allocator, watcher.tty.anyWriter(), ws) catch
|
||||||
|
Loading…
x
Reference in New Issue
Block a user