From b43b15f672edb3da138194ebb0d110aad7a99a55 Mon Sep 17 00:00:00 2001 From: Pablo Collado Soto Date: Tue, 25 Aug 2026 10:51:52 +0200 Subject: [PATCH 01/10] feat: support timeouts and deadlines This commit adds support for specifying deadlines for read and write operations over UARTs in one of two ways: 1. By providing a deadline as an absolute time in the future as was done before. These deadlines can be 'refreshed' through the `set_deadline` methods. 2. By providing a timeout with which a new deadline will be computed upon performing a read or write operation. This allows for a precise handling of deadlines when leveraging the std.Io.{Reader,Writer} interface semantics. --- port/raspberrypi/rp2xxx/src/hal/uart.zig | 45 ++++++++++++++++++------ 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/port/raspberrypi/rp2xxx/src/hal/uart.zig b/port/raspberrypi/rp2xxx/src/hal/uart.zig index 359f55a69..6117eefa7 100644 --- a/port/raspberrypi/rp2xxx/src/hal/uart.zig +++ b/port/raspberrypi/rp2xxx/src/hal/uart.zig @@ -135,6 +135,8 @@ pub const instance = struct { } }; +pub const TimeFrontier = union(enum) { timeout_us: u64, deadline: mdf.time.Deadline }; + /// An API for interacting with the RP2040's UART driver. /// /// Note: Assumes proper GPIO configuration, does NOT configure GPIO pins. @@ -148,20 +150,28 @@ pub const UART = enum(u1) { pub const Writer = struct { uart: UART, - deadline: mdf.time.Deadline, + timeFrontier: TimeFrontier, interface: std.Io.Writer, + + pub fn set_deadline(self: *Writer, deadline: mdf.time.Deadline) void { + self.*.timeFrontier = TimeFrontier{.deadline = deadline}; + } }; pub const Reader = struct { uart: UART, - deadline: mdf.time.Deadline, + timeFrontier: TimeFrontier, interface: std.Io.Reader, + + pub fn set_deadline(self: *Reader, deadline: mdf.time.Deadline) void { + self.*.timeFrontier = TimeFrontier{.deadline = deadline}; + } }; - pub fn writer(uart: UART, deadline: mdf.time.Deadline, buffer: []u8) Writer { + pub fn writer(uart: UART, timeFrontier: TimeFrontier, buffer: []u8) Writer { return .{ .uart = uart, - .deadline = deadline, + .timeFrontier = timeFrontier, .interface = .{ .buffer = buffer, .vtable = &.{ @@ -171,10 +181,10 @@ pub const UART = enum(u1) { }; } - pub fn reader(uart: UART, deadline: mdf.time.Deadline, buffer: []u8) Reader { + pub fn reader(uart: UART, timeFrontier: TimeFrontier, buffer: []u8) Reader { return .{ .uart = uart, - .deadline = deadline, + .timeFrontier = timeFrontier, .interface = .{ .buffer = buffer, .seek = 0, @@ -190,18 +200,24 @@ pub const UART = enum(u1) { const uart_writer: *Writer = @alignCast(@fieldParentPtr("interface", w)); const uart = uart_writer.uart; + var deadline: mdf.time.Deadline = undefined; + switch (uart_writer.timeFrontier) { + .deadline => |d| deadline = d, + .timeout_us => |t| deadline = time.deadline_in_us(t) + } + // bytes from buffer are not included in count. - w.end -= uart.write_blocking(w.buffer[0..w.end], uart_writer.deadline) catch |err| switch (err) { + w.end -= uart.write_blocking(w.buffer[0..w.end], deadline) catch |err| switch (err) { error.Timeout => unreachable, }; assert(w.end == 0); var n: usize = 0; - n += uart.writev_blocking(data[0 .. data.len - 1], uart_writer.deadline) catch |err| switch (err) { + n += uart.writev_blocking(data[0 .. data.len - 1], deadline) catch |err| switch (err) { error.Timeout => unreachable, }; for (0..splat) |_| - n += uart.write_blocking(data[data.len - 1], uart_writer.deadline) catch |err| switch (err) { + n += uart.write_blocking(data[data.len - 1], deadline) catch |err| switch (err) { error.Timeout => unreachable, }; @@ -211,10 +227,17 @@ pub const UART = enum(u1) { fn stream(r: *std.Io.Reader, w: *std.Io.Writer, limit: std.Io.Limit) std.Io.Reader.StreamError!usize { const uart_reader: *Reader = @alignCast(@fieldParentPtr("interface", r)); const uart = uart_reader.uart; + + var deadline: mdf.time.Deadline = undefined; + switch (uart_reader.timeFrontier) { + .deadline => |d| deadline = d, + .timeout_us => |t| deadline = time.deadline_in_us(t) + } + return switch (limit) { .nothing => 0, else => { - const b = uart.read_word_blocking(uart_reader.deadline) catch return error.ReadFailed; + const b = uart.read_word_blocking(deadline) catch return error.ReadFailed; try w.writeByte(b); return 1; }, @@ -559,7 +582,7 @@ var uart_logger: ?UART.Writer = null; /// .logFn = hal.uart.log, /// }; pub fn init_logger(uart: UART) void { - uart_logger = uart.writer(.no_deadline, &.{}); + uart_logger = uart.writer(.{.deadline = .no_deadline}, &.{}); uart_logger.?.interface.writeAll("\r\n================ STARTING NEW LOGGER ================\r\n") catch {}; } From 83e1bde38513878d60462594557a91f163d155ac Mon Sep 17 00:00:00 2001 From: Pablo Collado Soto Date: Fri, 28 Aug 2026 18:31:05 +0200 Subject: [PATCH 02/10] chore(squash): apply `zig fmt` --- port/raspberrypi/rp2xxx/src/hal/uart.zig | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/port/raspberrypi/rp2xxx/src/hal/uart.zig b/port/raspberrypi/rp2xxx/src/hal/uart.zig index 6117eefa7..c0c1fc45e 100644 --- a/port/raspberrypi/rp2xxx/src/hal/uart.zig +++ b/port/raspberrypi/rp2xxx/src/hal/uart.zig @@ -154,7 +154,7 @@ pub const UART = enum(u1) { interface: std.Io.Writer, pub fn set_deadline(self: *Writer, deadline: mdf.time.Deadline) void { - self.*.timeFrontier = TimeFrontier{.deadline = deadline}; + self.*.timeFrontier = TimeFrontier{ .deadline = deadline }; } }; @@ -164,7 +164,7 @@ pub const UART = enum(u1) { interface: std.Io.Reader, pub fn set_deadline(self: *Reader, deadline: mdf.time.Deadline) void { - self.*.timeFrontier = TimeFrontier{.deadline = deadline}; + self.*.timeFrontier = TimeFrontier{ .deadline = deadline }; } }; @@ -203,8 +203,9 @@ pub const UART = enum(u1) { var deadline: mdf.time.Deadline = undefined; switch (uart_writer.timeFrontier) { .deadline => |d| deadline = d, - .timeout_us => |t| deadline = time.deadline_in_us(t) + .timeout_us => |t| deadline = time.deadline_in_us(t), } + // logg.debug("hello from drain with deadline {any}", .{deadline}); // bytes from buffer are not included in count. w.end -= uart.write_blocking(w.buffer[0..w.end], deadline) catch |err| switch (err) { @@ -231,8 +232,9 @@ pub const UART = enum(u1) { var deadline: mdf.time.Deadline = undefined; switch (uart_reader.timeFrontier) { .deadline => |d| deadline = d, - .timeout_us => |t| deadline = time.deadline_in_us(t) + .timeout_us => |t| deadline = time.deadline_in_us(t), } + // logg.debug("hello from stream with deadline {any}", .{deadline}); return switch (limit) { .nothing => 0, @@ -582,7 +584,7 @@ var uart_logger: ?UART.Writer = null; /// .logFn = hal.uart.log, /// }; pub fn init_logger(uart: UART) void { - uart_logger = uart.writer(.{.deadline = .no_deadline}, &.{}); + uart_logger = uart.writer(.{ .deadline = .no_deadline }, &.{}); uart_logger.?.interface.writeAll("\r\n================ STARTING NEW LOGGER ================\r\n") catch {}; } From 5177846fde9d14d1b63e97d5dbcbbcf895a49439 Mon Sep 17 00:00:00 2001 From: Pablo Collado Soto Date: Fri, 28 Aug 2026 18:32:59 +0200 Subject: [PATCH 03/10] refactor: define no_deadline for ease of use --- port/raspberrypi/rp2xxx/src/hal/uart.zig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/port/raspberrypi/rp2xxx/src/hal/uart.zig b/port/raspberrypi/rp2xxx/src/hal/uart.zig index c0c1fc45e..f0789e193 100644 --- a/port/raspberrypi/rp2xxx/src/hal/uart.zig +++ b/port/raspberrypi/rp2xxx/src/hal/uart.zig @@ -137,6 +137,8 @@ pub const instance = struct { pub const TimeFrontier = union(enum) { timeout_us: u64, deadline: mdf.time.Deadline }; +pub const no_deadline: TimeFrontier = .{ .deadline = .no_deadline }; + /// An API for interacting with the RP2040's UART driver. /// /// Note: Assumes proper GPIO configuration, does NOT configure GPIO pins. @@ -584,7 +586,7 @@ var uart_logger: ?UART.Writer = null; /// .logFn = hal.uart.log, /// }; pub fn init_logger(uart: UART) void { - uart_logger = uart.writer(.{ .deadline = .no_deadline }, &.{}); + uart_logger = uart.writer(.no_deadline, &.{}); uart_logger.?.interface.writeAll("\r\n================ STARTING NEW LOGGER ================\r\n") catch {}; } From 123a5d1ea6a05048c396e9eadeeed2bdb4706111 Mon Sep 17 00:00:00 2001 From: Pablo Collado Soto Date: Fri, 28 Aug 2026 18:38:15 +0200 Subject: [PATCH 04/10] refactor(squash): adhere to naming convention --- port/raspberrypi/rp2xxx/src/hal/uart.zig | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/port/raspberrypi/rp2xxx/src/hal/uart.zig b/port/raspberrypi/rp2xxx/src/hal/uart.zig index f0789e193..fe2165a89 100644 --- a/port/raspberrypi/rp2xxx/src/hal/uart.zig +++ b/port/raspberrypi/rp2xxx/src/hal/uart.zig @@ -152,28 +152,28 @@ pub const UART = enum(u1) { pub const Writer = struct { uart: UART, - timeFrontier: TimeFrontier, + time_frontier: TimeFrontier, interface: std.Io.Writer, pub fn set_deadline(self: *Writer, deadline: mdf.time.Deadline) void { - self.*.timeFrontier = TimeFrontier{ .deadline = deadline }; + self.*.time_frontier = TimeFrontier{ .deadline = deadline }; } }; pub const Reader = struct { uart: UART, - timeFrontier: TimeFrontier, + time_frontier: TimeFrontier, interface: std.Io.Reader, pub fn set_deadline(self: *Reader, deadline: mdf.time.Deadline) void { - self.*.timeFrontier = TimeFrontier{ .deadline = deadline }; + self.*.time_frontier = TimeFrontier{ .deadline = deadline }; } }; - pub fn writer(uart: UART, timeFrontier: TimeFrontier, buffer: []u8) Writer { + pub fn writer(uart: UART, time_frontier: TimeFrontier, buffer: []u8) Writer { return .{ .uart = uart, - .timeFrontier = timeFrontier, + .time_frontier = time_frontier, .interface = .{ .buffer = buffer, .vtable = &.{ @@ -183,10 +183,10 @@ pub const UART = enum(u1) { }; } - pub fn reader(uart: UART, timeFrontier: TimeFrontier, buffer: []u8) Reader { + pub fn reader(uart: UART, time_frontier: TimeFrontier, buffer: []u8) Reader { return .{ .uart = uart, - .timeFrontier = timeFrontier, + .time_frontier = time_frontier, .interface = .{ .buffer = buffer, .seek = 0, @@ -203,7 +203,7 @@ pub const UART = enum(u1) { const uart = uart_writer.uart; var deadline: mdf.time.Deadline = undefined; - switch (uart_writer.timeFrontier) { + switch (uart_writer.time_frontier) { .deadline => |d| deadline = d, .timeout_us => |t| deadline = time.deadline_in_us(t), } @@ -232,7 +232,7 @@ pub const UART = enum(u1) { const uart = uart_reader.uart; var deadline: mdf.time.Deadline = undefined; - switch (uart_reader.timeFrontier) { + switch (uart_reader.time_frontier) { .deadline => |d| deadline = d, .timeout_us => |t| deadline = time.deadline_in_us(t), } From a24ae4f2bf21beb06c580cc5d045206f056f85a9 Mon Sep 17 00:00:00 2001 From: Pablo Collado Soto Date: Fri, 28 Aug 2026 18:39:10 +0200 Subject: [PATCH 05/10] refactor(squash): skip unnecessary explicit dereference --- port/raspberrypi/rp2xxx/src/hal/uart.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/port/raspberrypi/rp2xxx/src/hal/uart.zig b/port/raspberrypi/rp2xxx/src/hal/uart.zig index fe2165a89..808e91fc5 100644 --- a/port/raspberrypi/rp2xxx/src/hal/uart.zig +++ b/port/raspberrypi/rp2xxx/src/hal/uart.zig @@ -156,7 +156,7 @@ pub const UART = enum(u1) { interface: std.Io.Writer, pub fn set_deadline(self: *Writer, deadline: mdf.time.Deadline) void { - self.*.time_frontier = TimeFrontier{ .deadline = deadline }; + self.time_frontier = TimeFrontier{ .deadline = deadline }; } }; @@ -166,7 +166,7 @@ pub const UART = enum(u1) { interface: std.Io.Reader, pub fn set_deadline(self: *Reader, deadline: mdf.time.Deadline) void { - self.*.time_frontier = TimeFrontier{ .deadline = deadline }; + self.time_frontier = TimeFrontier{ .deadline = deadline }; } }; From 7c4500f436c76563fd05802a8a2281331c3dc090 Mon Sep 17 00:00:00 2001 From: Pablo Collado Soto Date: Fri, 28 Aug 2026 18:41:31 +0200 Subject: [PATCH 06/10] refactor(squash): leverage switch expressions --- port/raspberrypi/rp2xxx/src/hal/uart.zig | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/port/raspberrypi/rp2xxx/src/hal/uart.zig b/port/raspberrypi/rp2xxx/src/hal/uart.zig index 808e91fc5..626d5f7fe 100644 --- a/port/raspberrypi/rp2xxx/src/hal/uart.zig +++ b/port/raspberrypi/rp2xxx/src/hal/uart.zig @@ -202,11 +202,10 @@ pub const UART = enum(u1) { const uart_writer: *Writer = @alignCast(@fieldParentPtr("interface", w)); const uart = uart_writer.uart; - var deadline: mdf.time.Deadline = undefined; - switch (uart_writer.time_frontier) { - .deadline => |d| deadline = d, - .timeout_us => |t| deadline = time.deadline_in_us(t), - } + const deadline: mdf.time.Deadline = switch (uart_writer.time_frontier) { + .deadline => |d| d, + .timeout_us => |t| time.deadline_in_us(t), + }; // logg.debug("hello from drain with deadline {any}", .{deadline}); // bytes from buffer are not included in count. @@ -231,11 +230,10 @@ pub const UART = enum(u1) { const uart_reader: *Reader = @alignCast(@fieldParentPtr("interface", r)); const uart = uart_reader.uart; - var deadline: mdf.time.Deadline = undefined; - switch (uart_reader.time_frontier) { - .deadline => |d| deadline = d, - .timeout_us => |t| deadline = time.deadline_in_us(t), - } + const deadline: mdf.time.Deadline = switch (uart_reader.time_frontier) { + .deadline => |d| d, + .timeout_us => |t| time.deadline_in_us(t), + }; // logg.debug("hello from stream with deadline {any}", .{deadline}); return switch (limit) { From c9eea0b21d3cfb5c7699096ed96dccfc8e6aeb83 Mon Sep 17 00:00:00 2001 From: Pablo Collado Soto Date: Fri, 28 Aug 2026 18:42:25 +0200 Subject: [PATCH 07/10] refactor(squash): remove remaining logg definitions --- port/raspberrypi/rp2xxx/src/hal/uart.zig | 2 -- 1 file changed, 2 deletions(-) diff --git a/port/raspberrypi/rp2xxx/src/hal/uart.zig b/port/raspberrypi/rp2xxx/src/hal/uart.zig index 626d5f7fe..b8c2eeb2f 100644 --- a/port/raspberrypi/rp2xxx/src/hal/uart.zig +++ b/port/raspberrypi/rp2xxx/src/hal/uart.zig @@ -206,7 +206,6 @@ pub const UART = enum(u1) { .deadline => |d| d, .timeout_us => |t| time.deadline_in_us(t), }; - // logg.debug("hello from drain with deadline {any}", .{deadline}); // bytes from buffer are not included in count. w.end -= uart.write_blocking(w.buffer[0..w.end], deadline) catch |err| switch (err) { @@ -234,7 +233,6 @@ pub const UART = enum(u1) { .deadline => |d| d, .timeout_us => |t| time.deadline_in_us(t), }; - // logg.debug("hello from stream with deadline {any}", .{deadline}); return switch (limit) { .nothing => 0, From 3ded65e52567f6ad018b6feb27ba57a2eb8501a9 Mon Sep 17 00:00:00 2001 From: Pablo Collado Soto Date: Fri, 28 Aug 2026 19:22:27 +0200 Subject: [PATCH 08/10] fix(squash): use the no_deadline constant --- port/raspberrypi/rp2xxx/src/hal/uart.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/port/raspberrypi/rp2xxx/src/hal/uart.zig b/port/raspberrypi/rp2xxx/src/hal/uart.zig index b8c2eeb2f..0d13c8add 100644 --- a/port/raspberrypi/rp2xxx/src/hal/uart.zig +++ b/port/raspberrypi/rp2xxx/src/hal/uart.zig @@ -582,7 +582,7 @@ var uart_logger: ?UART.Writer = null; /// .logFn = hal.uart.log, /// }; pub fn init_logger(uart: UART) void { - uart_logger = uart.writer(.no_deadline, &.{}); + uart_logger = uart.writer(no_deadline, &.{}); uart_logger.?.interface.writeAll("\r\n================ STARTING NEW LOGGER ================\r\n") catch {}; } From 11ef45ee3fc965b7eaadf393696a576a841d8b4b Mon Sep 17 00:00:00 2001 From: Pablo Collado Soto Date: Mon, 31 Aug 2026 09:36:04 +0200 Subject: [PATCH 09/10] refactor(squash): format TimeFrontier definition on multiple lines --- port/raspberrypi/rp2xxx/src/hal/uart.zig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/port/raspberrypi/rp2xxx/src/hal/uart.zig b/port/raspberrypi/rp2xxx/src/hal/uart.zig index 0d13c8add..5c8086f51 100644 --- a/port/raspberrypi/rp2xxx/src/hal/uart.zig +++ b/port/raspberrypi/rp2xxx/src/hal/uart.zig @@ -135,7 +135,10 @@ pub const instance = struct { } }; -pub const TimeFrontier = union(enum) { timeout_us: u64, deadline: mdf.time.Deadline }; +pub const TimeFrontier = union(enum) { + timeout_us: u64, + deadline: mdf.time.Deadline, +}; pub const no_deadline: TimeFrontier = .{ .deadline = .no_deadline }; From 2ad6fe004b02b88faf3e24bb3c0205dd8996e2fd Mon Sep 17 00:00:00 2001 From: Pablo Collado Soto Date: Mon, 31 Aug 2026 14:07:05 +0200 Subject: [PATCH 10/10] refactor(squash): define `no_deadline` within the `TimeFrontier` namespace --- port/raspberrypi/rp2xxx/src/hal/uart.zig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/port/raspberrypi/rp2xxx/src/hal/uart.zig b/port/raspberrypi/rp2xxx/src/hal/uart.zig index 5c8086f51..e5bd5ca69 100644 --- a/port/raspberrypi/rp2xxx/src/hal/uart.zig +++ b/port/raspberrypi/rp2xxx/src/hal/uart.zig @@ -138,9 +138,9 @@ pub const instance = struct { pub const TimeFrontier = union(enum) { timeout_us: u64, deadline: mdf.time.Deadline, -}; -pub const no_deadline: TimeFrontier = .{ .deadline = .no_deadline }; + pub const no_deadline: TimeFrontier = .{ .deadline = .no_deadline }; +}; /// An API for interacting with the RP2040's UART driver. /// @@ -585,7 +585,7 @@ var uart_logger: ?UART.Writer = null; /// .logFn = hal.uart.log, /// }; pub fn init_logger(uart: UART) void { - uart_logger = uart.writer(no_deadline, &.{}); + uart_logger = uart.writer(.no_deadline, &.{}); uart_logger.?.interface.writeAll("\r\n================ STARTING NEW LOGGER ================\r\n") catch {}; }