diff options
Diffstat (limited to 'tools/serial.zig')
| -rw-r--r-- | tools/serial.zig | 28 |
1 files changed, 27 insertions, 1 deletions
diff --git a/tools/serial.zig b/tools/serial.zig index 3398a11..7a740cd 100644 --- a/tools/serial.zig +++ b/tools/serial.zig @@ -81,10 +81,17 @@ pub const Port = struct { file: std.Io.File, io: std.Io, saved: Termios2, + /// The rate currently programmed, kept because the wire's capacity in bytes per second is + /// `rate/10` and anything measuring this link against its ceiling needs that number. The + /// kernel would answer a TCGETS2, but a syscall per sample to re-read a value only this file + /// ever changes is worse than a field. + baud: Baud, // std exposes neither these ioctl numbers nor the TIOCM bits. const TIOCEXCL = 0x540C; const TCFLSH = 0x540B; + /// tcdrain, with a nonzero argument. Zero would transmit a break instead. + const TCSBRK = 0x5409; const TCIFLUSH = 0; const TIOCMGET = 0x5415; const TIOCMSET = 0x5418; @@ -132,7 +139,7 @@ pub const Port = struct { // Drop anything the kernel captured at the previous line rate. _ = linux.ioctl(fd, TCFLSH, TCIFLUSH); - return .{ .file = file, .io = io, .saved = saved }; + return .{ .file = file, .io = io, .saved = saved, .baud = baud }; } /// Re-rate an already-open port, leaving the raw-mode flags and the exclusive claim alone. @@ -153,6 +160,25 @@ pub const Port = struct { t.ospeed = baud.rate(); if (@as(isize, @bitCast(linux.ioctl(p.file.handle, Termios2.TCSETSW2, @intFromPtr(&t)))) < 0) return error.SetAttrFailed; + p.baud = baud; + } + + /// Bytes per second the wire can carry: one 8N1 byte occupies ten bit times. + pub fn capacity(p: *const Port) u32 { + return p.baud.rate() / 10; + } + + /// Block until every byte written has physically left the wire - `tcdrain`, spelled as the + /// ioctl because std exposes neither. + /// + /// Distinct from `drain` above in both direction and meaning, which is worth stating because + /// getting them the wrong way round silently invalidates a measurement: `drain` discards what + /// has ARRIVED, this waits for what is LEAVING. A `write` returns once the kernel has accepted + /// the bytes, so timing a transfer to the write measures a memcpy into a tty buffer - at 115200 + /// that reported 202% of the wire's capacity, which is how the confusion was noticed. + pub fn flushOutput(p: *Port) void { + // TCSBRK with a nonzero argument is tcdrain on Linux; with zero it would send a break. + _ = linux.ioctl(p.file.handle, TCSBRK, 1); } pub fn close(p: *Port) void { |
