From 419bdc4bb71479c2bc4a567cd36b48a797d02f68 Mon Sep 17 00:00:00 2001 From: flamingcow Date: Sat, 25 Jul 2026 19:41:53 -0700 Subject: [PATCH] Render the live status to the framebuffer in Atkinson Hyperlegible Mono --- fb.go | 168 ++++++++++++++++++++++ font/AtkinsonHyperlegibleMono-Bold.ttf | Bin 0 -> 53544 bytes font/AtkinsonHyperlegibleMono-Regular.ttf | Bin 0 -> 52020 bytes go.mod | 6 +- go.sum | 4 + main.go | 79 +++++++--- text.go | 108 ++++++++++++++ ui.go | 165 +++++++++++++++++++++ 8 files changed, 506 insertions(+), 24 deletions(-) create mode 100644 fb.go create mode 100644 font/AtkinsonHyperlegibleMono-Bold.ttf create mode 100644 font/AtkinsonHyperlegibleMono-Regular.ttf create mode 100644 text.go create mode 100644 ui.go diff --git a/fb.go b/fb.go new file mode 100644 index 0000000..04d65f4 --- /dev/null +++ b/fb.go @@ -0,0 +1,168 @@ +package main + +import ( + "fmt" + "os" + "unsafe" + + "golang.org/x/sys/unix" +) + +const ( + fbioGetVScreenInfo = 0x4600 + fbioBlank = 0x4611 + fbBlankUnblank = 0 +) + +// The variable screen info is a flat run of 40 u32s, so it is read as an array +// rather than a struct to sidestep any question of padding. +const ( + viXres = 0 + viYres = 1 + viBitsPerPixel = 6 + viRedOffset = 8 + viGreenOffset = 11 + viBlueOffset = 14 + viScreenInfoLen = 40 +) + +type framebuffer struct { + file *os.File + mem []byte + back []byte + w int + h int + stride int + rShift uint + gShift uint + bShift uint +} + +func openFramebuffer(path string) (*framebuffer, error) { + f, err := os.OpenFile(path, os.O_RDWR, 0) + if err != nil { + return nil, err + } + + var vi [viScreenInfoLen]uint32 + if _, _, errno := unix.Syscall(unix.SYS_IOCTL, f.Fd(), + fbioGetVScreenInfo, uintptr(unsafe.Pointer(&vi[0]))); errno != 0 { + f.Close() + return nil, fmt.Errorf("get screen info: %w", errno) + } + if vi[viBitsPerPixel] != 32 { + f.Close() + return nil, fmt.Errorf("only 32bpp supported, got %d", vi[viBitsPerPixel]) + } + + // Wake the panel; the console blanks it after a timeout. + unix.Syscall(unix.SYS_IOCTL, f.Fd(), fbioBlank, fbBlankUnblank) + + stride, ok := readUint("/sys/class/graphics/fb0/stride") + if !ok { + f.Close() + return nil, fmt.Errorf("cannot read framebuffer stride") + } + + fb := &framebuffer{ + file: f, + w: int(vi[viXres]), + h: int(vi[viYres]), + stride: int(stride), + rShift: uint(vi[viRedOffset]), + gShift: uint(vi[viGreenOffset]), + bShift: uint(vi[viBlueOffset]), + } + + fb.mem, err = unix.Mmap(int(f.Fd()), 0, fb.stride*fb.h, + unix.PROT_READ|unix.PROT_WRITE, unix.MAP_SHARED) + if err != nil { + f.Close() + return nil, fmt.Errorf("mmap: %w", err) + } + fb.back = make([]byte, fb.stride*fb.h) + return fb, nil +} + +func (fb *framebuffer) close() { + unix.Munmap(fb.mem) + fb.file.Close() +} + +func (fb *framebuffer) pixel(c rgb) uint32 { + return uint32(c.r)<> 8) + row[x+2] = byte(v >> 16) + row[x+3] = byte(v >> 24) + } + for y := 0; y < fb.h; y++ { + copy(fb.back[y*fb.stride:], row) + } +} + +func (fb *framebuffer) rect(x0, y0, w, h int, c rgb) { + v := fb.pixel(c) + for y := y0; y < y0+h; y++ { + if y < 0 || y >= fb.h { + continue + } + base := y * fb.stride + for x := x0; x < x0+w; x++ { + if x < 0 || x >= fb.w { + continue + } + o := base + x*4 + fb.back[o+0] = byte(v) + fb.back[o+1] = byte(v >> 8) + fb.back[o+2] = byte(v >> 16) + fb.back[o+3] = byte(v >> 24) + } + } +} + +// Blends src over the existing pixel, with cov as 0-255 coverage. +func (fb *framebuffer) blend(x, y int, c rgb, cov uint8) { + if x < 0 || y < 0 || x >= fb.w || y >= fb.h || cov == 0 { + return + } + o := y*fb.stride + x*4 + if cov == 255 { + v := fb.pixel(c) + fb.back[o+0] = byte(v) + fb.back[o+1] = byte(v >> 8) + fb.back[o+2] = byte(v >> 16) + fb.back[o+3] = byte(v >> 24) + return + } + a := uint32(cov) + old := uint32(fb.back[o+0]) | uint32(fb.back[o+1])<<8 | + uint32(fb.back[o+2])<<16 | uint32(fb.back[o+3])<<24 + orr := uint8(old >> fb.rShift) + og := uint8(old >> fb.gShift) + ob := uint8(old >> fb.bShift) + mix := rgb{ + r: uint8((uint32(c.r)*a + uint32(orr)*(255-a)) / 255), + g: uint8((uint32(c.g)*a + uint32(og)*(255-a)) / 255), + b: uint8((uint32(c.b)*a + uint32(ob)*(255-a)) / 255), + } + v := fb.pixel(mix) + fb.back[o+0] = byte(v) + fb.back[o+1] = byte(v >> 8) + fb.back[o+2] = byte(v >> 16) + fb.back[o+3] = byte(v >> 24) +} + +func (fb *framebuffer) flush() { + copy(fb.mem, fb.back) +} diff --git a/font/AtkinsonHyperlegibleMono-Bold.ttf b/font/AtkinsonHyperlegibleMono-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..0cd144b21bcb698c32dd230281d1ca9a4308c121 GIT binary patch literal 53544 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 K?`&h={XYTS0r%tp literal 0 HcmV?d00001 diff --git a/font/AtkinsonHyperlegibleMono-Regular.ttf b/font/AtkinsonHyperlegibleMono-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..a55ce8b42877d04efc0d3b85b2477c06217f0f44 GIT binary patch literal 52020 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

we#qMmEo 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 target*rateGreenFrac: + return uiGreen + case gb >= target*rateYellowFrac: + return uiYellow + default: + return uiRed + } +} + +func (d *display) render(dirs []*direction, views []view, elapsed time.Duration, target float64) { + fb := d.fb + fb.fill(uiBg) + + d.small.draw(fb, 16, 12, "cabletest", uiCyan) + if len(dirs) > 0 { + d.small.draw(fb, 16+11*d.small.cellW, 12, + fmt.Sprintf("%s %s %s %s", dirs[0].tx.tag, dirs[0].tx.name, + dirs[0].rx.tag, dirs[0].rx.name), uiDim) + } + d.right(d.small, fb.w-16, 12, uptime(elapsed), uiDim) + + var total uint64 + for _, v := range views { + total += v.errors + } + + // Status band, readable from across the room. + bandY, bandH := 44, 74 + fb.rect(0, bandY, fb.w, bandH, uiPanel) + fb.rect(0, bandY, 6, bandH, errColor(total)) + word, wc := "NO ERRORS", uiGreen + if total > 0 { + word, wc = fmt.Sprintf("%s ERRORS", commas(total)), uiRed + } + d.center(d.huge, 0, fb.w, bandY+(bandH-d.huge.cellH)/2+2, word, wc) + + panelY := bandY + bandH + 12 + footerH := d.small.cellH + 16 + panelH := (fb.h - panelY - footerH) / max(len(dirs), 1) + for i, dir := range dirs { + d.renderDirection(dir, views[i], 12, panelY+i*panelH, fb.w-24, panelH-10, target) + } + d.footer(fb.h - footerH + 4) + fb.flush() +} + +func (d *display) renderDirection(dir *direction, v view, x, y, w, h int, target float64) { + fb := d.fb + fb.rect(x, y, w, h, uiPanel) + + // The font has no arrow glyph, so the direction marker is drawn. + d.big.draw(fb, x+14, y+12, dir.tx.tag, uiCyan) + d.arrow(x+14+2*d.big.cellW, y+12+d.big.cellH/2, 22, uiDim) + d.big.draw(fb, x+14+2*d.big.cellW+30, y+12, dir.rx.tag, uiCyan) + + col := x + 110 + d.rateBlock(col, y+10, "TX", v.txPPS, v.txGbps, target) + d.rateBlock(col+300, y+10, "RX", v.rxPPS, v.rxGbps, target) + + ex := col + 620 + d.errLine(ex, y+10, "lost", v.lost) + d.errLine(ex, y+10+d.small.cellH+2, "crc", v.crc) + d.errLine(ex, y+10+2*(d.small.cellH+2), "kdrop", v.kdrop) + d.errLine(ex, y+10+3*(d.small.cellH+2), "late", v.late) + + totals := fmt.Sprintf("sent %s frames %s received %s frames %s", + commas(v.txFrames), humanBytes(v.txSent), + commas(v.rxFrames), humanBytes(v.rxGot)) + d.small.draw(fb, x+14, y+h-d.small.cellH-8, totals, uiDim) +} + +func (d *display) arrow(x, y, w int, c rgb) { + d.fb.rect(x, y-1, w-6, 3, c) + for i := 0; i < 7; i++ { + d.fb.rect(x+w-7+i, y-6+i, 1, 13-2*i, c) + } +} + +func (d *display) rateBlock(x, y int, label string, pps, gb, target float64) { + d.small.draw(d.fb, x, y, label, uiDim) + d.big.draw(d.fb, x+3*d.small.cellW, y-2, + fmt.Sprintf("%6.2f Gb/s", gb), d.rateColor(gb, target)) + d.small.draw(d.fb, x+3*d.small.cellW, y+d.big.cellH, + fmt.Sprintf("%s pps", commas(uint64(pps))), uiFg) +} + +func (d *display) footer(y int) { + d.small.draw(d.fb, 16, y, d.config, uiDim) + d.right(d.small, d.fb.w-16, y, "space resets counts", uiDim) +} + +func (d *display) errLine(x, y int, label string, n uint64) { + d.small.draw(d.fb, x, y, label, uiDim) + d.small.draw(d.fb, x+7*d.small.cellW, y, commas(n), errColor(n)) +}