Skip to content

Commit 8ecc458

Browse files
update Stream_Device IO and STM32 uart (#702)
* Refactor Stream_Device: Update io.Reader/Writer * Remove timeout as an error on STM32 uart * optimize read buffer usage * update comments
1 parent 32ffff4 commit 8ecc458

File tree

3 files changed

+122
-29
lines changed

3 files changed

+122
-29
lines changed

drivers/base/Stream_Device.zig

Lines changed: 103 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -59,22 +59,12 @@ pub fn readv(sd: Stream_Device, bytes_vec: []const []u8) ReadError!usize {
5959
return readv_fn(sd.ptr, bytes_vec);
6060
}
6161

62-
pub const Reader = std.io.Reader(Stream_Device, ReadError, reader_read);
63-
pub fn reader(sd: Stream_Device) Reader {
64-
return .{ .context = sd };
62+
pub fn writer(self: Stream_Device, buf: []u8) Writer {
63+
return .init(self, buf);
6564
}
6665

67-
fn reader_read(sd: Stream_Device, buf: []u8) ReadError!usize {
68-
return sd.read(buf);
69-
}
70-
71-
pub const Writer = std.io.Reader(Stream_Device, WriteError, writer_write);
72-
pub fn writer(sd: Stream_Device) Writer {
73-
return .{ .context = sd };
74-
}
75-
76-
fn writer_write(sd: Stream_Device, buf: []const u8) WriteError!usize {
77-
return sd.write(buf);
66+
pub fn reader(self: Stream_Device, buf: []u8) Reader {
67+
return .init(self, buf);
7868
}
7969

8070
pub const VTable = struct {
@@ -84,6 +74,105 @@ pub const VTable = struct {
8474
readv_fn: ?*const fn (*anyopaque, datagram: []const []u8) ReadError!usize,
8575
};
8676

77+
/// microzig already has this function in SliceVector, but no other base driver include microzig as a dependency
78+
/// so we duplicate it here for now
79+
fn byte_sum(data: []const []const u8) usize {
80+
var sum: usize = 0;
81+
for (data) |bytes| {
82+
sum += bytes.len;
83+
}
84+
return sum;
85+
}
86+
87+
pub const Writer = struct {
88+
dev: Stream_Device,
89+
interface: std.Io.Writer,
90+
err: ?WriteError = null,
91+
92+
fn drain(w: *std.Io.Writer, data: []const []const u8, splat: usize) std.Io.Writer.Error!usize {
93+
const wt: *Writer = @alignCast(@fieldParentPtr("interface", w));
94+
const total_size = byte_sum(data);
95+
var ret: usize = 0;
96+
97+
const n = wt.dev.write(w.buffered()) catch |err| {
98+
wt.err = err;
99+
return error.WriteFailed;
100+
};
101+
_ = w.consume(n);
102+
103+
ret = wt.dev.writev(data) catch |err| {
104+
wt.err = err;
105+
return error.WriteFailed;
106+
};
107+
108+
// NOTE: maybe check if ret is 0 across multiple calls to detect broken stream?
109+
// check if we wrote everything we wanted before splatting
110+
if (ret != total_size) {
111+
return ret;
112+
}
113+
114+
const pattern = data[data.len - 1];
115+
for (0..splat) |_| {
116+
const s_len = wt.dev.write(pattern) catch |err| {
117+
wt.err = err;
118+
return error.WriteFailed;
119+
};
120+
ret += s_len;
121+
if (s_len < pattern.len) break; // if the previous pattern was not fully written, break the loop
122+
}
123+
124+
return ret;
125+
}
126+
127+
pub fn init(dev: Stream_Device, buf: []u8) Writer {
128+
return Writer{
129+
.dev = dev,
130+
.interface = .{
131+
.buffer = buf,
132+
.vtable = &.{
133+
.drain = drain,
134+
},
135+
},
136+
};
137+
}
138+
};
139+
140+
pub const Reader = struct {
141+
dev: Stream_Device,
142+
interface: std.Io.Reader,
143+
err: ?ReadError = null,
144+
145+
fn stream(r: *std.Io.Reader, w: *std.Io.Writer, limit: std.Io.Limit) std.Io.Reader.StreamError!usize {
146+
const rd: *Reader = @alignCast(@fieldParentPtr("interface", r));
147+
const w_buf = limit.slice(try w.writableSliceGreedy(1));
148+
149+
const n = rd.dev.read(w_buf) catch |err| {
150+
rd.err = err;
151+
return error.ReadFailed;
152+
};
153+
154+
// NOTE: should we treat 0 as an EOF or check if 0 across multiple calls before returning EOF?
155+
if (n == 0) return error.EndOfStream;
156+
157+
w.advance(n);
158+
return n;
159+
}
160+
161+
pub fn init(dev: Stream_Device, buf: []u8) Reader {
162+
return Reader{
163+
.dev = dev,
164+
.interface = .{
165+
.buffer = buf,
166+
.seek = 0,
167+
.end = 0,
168+
.vtable = &.{
169+
.stream = stream,
170+
},
171+
},
172+
};
173+
}
174+
};
175+
87176
/// A device implementation that can be used to write unit tests for datagram devices.
88177
pub const Test_Device = struct {
89178
input: ?std.io.FixedBufferStream([]const u8),

examples/stmicro/stm32/src/stm32f1xx/uart_echo.zig

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,17 @@ pub fn main() !void {
2828
var byte: [100]u8 = undefined;
2929

3030
//simple USART echo
31-
try uart.write_blocking("START UART ECHO\n", null);
31+
_ = try uart.write_blocking("START UART ECHO\n", null);
3232
while (true) {
3333
@memset(&byte, 0);
34-
uart.read_blocking(&byte, Duration.from_ms(100)) catch |err| {
34+
const len = uart.read_blocking(&byte, Duration.from_ms(100)) catch |err| {
3535
if (err != error.Timeout) {
3636
uart.writer().print("Got error {any}\n", .{err}) catch unreachable;
3737
uart.clear_errors();
38-
continue;
3938
}
39+
continue;
4040
};
4141

42-
uart.write_blocking(&byte, null) catch unreachable;
42+
_ = uart.write_blocking(byte[0..len], null) catch unreachable;
4343
}
4444
}

port/stmicro/stm32/src/hals/STM32F103/uart.zig

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -225,26 +225,30 @@ pub const UART = struct {
225225
return (0 != uart.regs.SR.read().TXE);
226226
}
227227

228-
pub fn writev_blocking(uart: *const UART, payloads: []const []const u8, timeout: ?Duration) TransmitError!void {
228+
pub fn writev_blocking(uart: *const UART, payloads: []const []const u8, timeout: ?Duration) TransmitError!usize {
229229
const deadline = Deadline.init_relative(time.get_time_since_boot(), timeout);
230230
const regs = uart.regs;
231+
var n: usize = 0;
231232
for (payloads) |pkgs| {
232233
for (pkgs) |byte| {
233234
while (!uart.is_writeable()) {
234235
if (deadline.is_reached_by(time.get_time_since_boot())) return error.Timeout;
235236
}
236237
regs.DR.raw = @intCast(byte);
238+
n += 1;
237239
}
238240
}
241+
return n;
239242
}
240243

241-
pub fn readv_blocking(uart: *const UART, buffers: []const []u8, timeout: ?Duration) ReceiveError!void {
244+
pub fn readv_blocking(uart: *const UART, buffers: []const []u8, timeout: ?Duration) ReceiveError!usize {
242245
const deadline = Deadline.init_relative(time.get_time_since_boot(), timeout);
243246
const regs = uart.regs;
247+
var n: usize = 0;
244248
for (buffers) |buf| {
245249
for (buf) |*bytes| {
246250
while (!uart.is_readable()) {
247-
if (deadline.is_reached_by(time.get_time_since_boot())) return error.Timeout;
251+
if (deadline.is_reached_by(time.get_time_since_boot())) return n;
248252
}
249253
const SR = regs.SR.read();
250254

@@ -260,8 +264,10 @@ pub const UART = struct {
260264
const rx = regs.DR.raw;
261265

262266
bytes.* = @intCast(0xFF & rx);
267+
n += 1;
263268
}
264269
}
270+
return n;
265271
}
266272

267273
pub fn get_errors(uart: *const UART) ErrorStates {
@@ -281,12 +287,12 @@ pub const UART = struct {
281287
std.mem.doNotOptimizeAway(regs.DR.raw);
282288
}
283289

284-
pub fn write_blocking(uart: *const UART, data: []const u8, timeout: ?Duration) TransmitError!void {
285-
try uart.writev_blocking(&.{data}, timeout);
290+
pub fn write_blocking(uart: *const UART, data: []const u8, timeout: ?Duration) TransmitError!usize {
291+
return uart.writev_blocking(&.{data}, timeout);
286292
}
287293

288-
pub fn read_blocking(uart: *const UART, data: []u8, timeout: ?Duration) ReceiveError!void {
289-
try uart.readv_blocking(&.{data}, timeout);
294+
pub fn read_blocking(uart: *const UART, data: []u8, timeout: ?Duration) ReceiveError!usize {
295+
return uart.readv_blocking(&.{data}, timeout);
290296
}
291297

292298
pub fn writer(uart: *const UART) Writer {
@@ -297,13 +303,11 @@ pub const UART = struct {
297303
return .{ .context = uart };
298304
}
299305
fn generic_writer_fn(uart: *const UART, buffer: []const u8) TransmitError!usize {
300-
try uart.write_blocking(buffer, null);
301-
return buffer.len;
306+
return uart.write_blocking(buffer, null);
302307
}
303308

304309
fn generic_reader_fn(uart: *const UART, buffer: []u8) ReceiveError!usize {
305-
try uart.read_blocking(buffer, null);
306-
return buffer.len;
310+
return uart.read_blocking(buffer, null);
307311
}
308312

309313
pub fn init(comptime uart: Instances) UART {

0 commit comments

Comments
 (0)