summaryrefslogtreecommitdiff
path: root/src/pardes
diff options
context:
space:
mode:
Diffstat (limited to 'src/pardes')
-rw-r--r--src/pardes/app.zig34
1 files changed, 32 insertions, 2 deletions
diff --git a/src/pardes/app.zig b/src/pardes/app.zig
index 8b43791..17bef83 100644
--- a/src/pardes/app.zig
+++ b/src/pardes/app.zig
@@ -64,6 +64,10 @@ const uart = @import("uart.zig");
/// How the editor emits bytes. Called with finished runs of ANSI, many times per frame.
const WriteFn = *const fn (ctx: ?*anyopaque, ptr: [*]const u8, len: usize) callconv(.c) void;
+/// The board's pads, offered to the editor. Optional on the wire so a firmware with nothing to
+/// toggle passes null and the `Gpio` word reports that rather than the object guessing.
+const GpioFn = *const fn (ctx: ?*anyopaque, pin: u16, was: *u8, now: *u8) callconv(.c) bool;
+
/// This board's allocator, handed across as plain function pointers. `log2_align` is a log2 value,
/// which is exactly how `std.mem.Alignment` represents itself, so neither side needs a conversion
/// table.
@@ -81,7 +85,7 @@ const Allocator = extern struct {
/// The one number both sides must agree on. Linkers do not type-check C symbols, so a signature
/// that drifts on one side of this seam links cleanly and then corrupts the stack; checking this
/// before calling anything else turns that into a refusal to boot.
-const abi_version: u32 = 1;
+const abi_version: u32 = 2;
extern fn pardes_p4_abi_version() callconv(.c) u32;
/// Hand over the allocator and the output sink, and state the initial window size. Returns 0, or a
@@ -89,6 +93,7 @@ extern fn pardes_p4_abi_version() callconv(.c) u32;
extern fn pardes_p4_init(
alloc: *const Allocator,
write: WriteFn,
+ gpio: ?GpioFn,
ctx: ?*anyopaque,
cols: u16,
rows: u16,
@@ -124,6 +129,31 @@ fn writeOut(_: ?*anyopaque, ptr: [*]const u8, len: usize) callconv(.c) void {
uart.write(ptr[0..len]);
}
+/// Flip one pad and report the level before and after. The editor's `Gpio` word calls this; the
+/// editor has no register of its own for it, deliberately.
+///
+/// THIS IS WHY THE SEAM IS HERE. A toggle is not a write to GPIO_OUT: `configureOutput` points the
+/// pad's IO MUX at the GPIO function, routes the GPIO matrix's output to it, sets the drive strength
+/// and input buffer and clears the pulls, and only then enables the driver - four register files,
+/// indexed by a per-pin table. That code already exists in `hal/gpio.zig`, it is the same call
+/// `src/main.zig` blinks with, and its register numbers are checked against ESP-IDF's own headers by
+/// `zig build diff`. A second copy inside the editor object would be a second copy under no test.
+///
+/// `getDrivenLevel` rather than `getLevel`: the answer is the level this board is DRIVING, which is
+/// defined for every pin. The pad's own level is what the outside world says, and on an unconnected
+/// header pin that is noise. The input buffer is enabled anyway, so `Peek` of GPIO_IN_REG shows the
+/// pad for anyone who wants to compare the two.
+fn gpioToggle(_: ?*anyopaque, pin: u16, was: *u8, now: *u8) callconv(.c) bool {
+ if (pin > hal.gpio.max_pin) return false;
+ const p: u8 = @intCast(pin);
+ hal.gpio.configureOutput(p, .{ .readback = true });
+ const before = hal.gpio.getDrivenLevel(p);
+ if (before == 1) hal.gpio.setLow(p) else hal.gpio.setHigh(p);
+ was.* = before;
+ now.* = hal.gpio.getDrivenLevel(p);
+ return true;
+}
+
// ------------------------------------------------------------------------------------- the heap
/// The span the linker script hands over, from `l2high`'s ORIGIN and LENGTH.
@@ -221,7 +251,7 @@ export fn zig_main() noreturn {
// Ask for more than any grid this board will ever render, so the SHELL's own ceiling is what
// governs - it clamps to `-Dp4-cols`/`-Dp4-rows` and reports the result. Naming 80x24 here made
// the firmware a second opinion about the geometry, which is one opinion too many.
- const rc = pardes_p4_init(&editor_allocator, writeOut, null, 255, 255);
+ const rc = pardes_p4_init(&editor_allocator, writeOut, gpioToggle, null, 255, 255);
if (rc != 0) {
soc.rom.print("MARK PARDES_INIT_FAIL rc=%u\r\n", .{rc});