ref: 77eb1803c4620ff1362e03faa8a8d674dbe11b2f
dir: /textimg.c/
#include <u.h> #include <libc.h> #include <draw.h> #include <memdraw.h> #include <bio.h> void usage(void) { sysfatal("usage: %s [-f subfont] [-p reformfs/] [-m ms] [-h y] [-w x] < text", argv0); } // Stolen from `iconv -u`. void writeuncompressed(int fd, Memimage *m); // Scroll text in two lines across the MNT Reform (v2) keyboard OLED display. void main(int argc, char **argv) { char *s, *path, *bufbot, *buftop; Memsubfont *f; Point p; int fd, i, w, h, ms, lineh; Biobufhdr *in; int ncharspline; long n; w = 126; h = 32; ms = 100; s = "/lib/font/bit/vga/vga.0000-007F"; f = nil; path = "/mnt/reform/kbdoled"; in = Bfdopen(0, OREAD); ARGBEGIN{ case 'f': s = EARGF(usage()); break; case 'p': path = EARGF(usage()); break; case 'm': ms = atoi(EARGF(usage())); break; case 'w': w = atoi(EARGF(usage())); break; case 'h': h = atoi(EARGF(usage())); break; }ARGEND; // I'm not convinced this is mandatory. if(memimageinit()) sysfatal("memimageinit failed: %r"); if(s) f = openmemsubfont(s); if(!f){ fprint(2, "cannot load subfont. Falling back to memdraw default.\n"); f = getmemdefont(); } /* Read text in - one OLED line width at a time. 2 lines on the OLED display @ height 8 font, like vga. p.x = max(?) width of one character in pixels. 126 x 32 oled. Q is arbitrary. */ p = memsubfontwidth(f, "Q"); if (p.x == 0) sysfatal("font has no width, not wide enough to ride"); // The height of the text line ≡ the font's height lineh = f->height; // Number of characters that can be on a line. ncharspline = w / p.x; // Initialize our buffers. bufbot = calloc(ncharspline, sizeof (char)); n = Bread(in, bufbot, ncharspline-1); if(n <= 0) sysfatal("no bread in the bread box"); bufbot[n] = '\0'; for(i = 0; i < n; i++) if(bufbot[i] == '\n' || bufbot[i] == '\r') bufbot[i] = ' '; buftop = calloc(ncharspline, sizeof (char)); memset(buftop, ' ', ncharspline*sizeof (char)); buftop[n] = '\0'; // Primary loop routine. for(;;){ Memimage *img; char c; // Not entirely sure if open/close every time is necessary. fd = open(path, OWRITE); if(fd < 0){ sysfatal("could not open kbdoled file → %r"); } // White background for the whole OLED. // This might be incorrect, but it works cosmetically. img = allocmemimage(Rect(0, 0, p.x*ncharspline, f->height+lineh), GREY1); if (!img) sysfatal("cannot allocate memimage: %r"); memfillcolor(img, DWhite); // Top line memimagestring(img, Pt(0, 0), memblack, ZP, f, buftop); // Bottom line memimagestring(img, Pt(0, h/2), memblack, ZP, f, bufbot); // Reform/pm requires an uncompressed plan9 bitmap image writeuncompressed(fd, img); close(fd); // Read one character at a time in for 'text scroll' effect. c = Bgetc(in); // EOF if(c <= 0) break; // Don't print whitespace symbols other than spaces. if(c == '\n' || c == '\r') c = ' '; // Shift the top values in from the bottom row. for(i = 0; i < n-1; i++) buftop[i] = buftop[i+1]; buftop[n-1] = bufbot[0]; // Shift the bottom values over and the new char in. for(i = 0; i < n-1; i++) bufbot[i] = bufbot[i+1]; bufbot[n-1] = c; freememimage(img); sleep(ms); } free(bufbot); free(buftop); } void writeuncompressed(int fd, Memimage *m) { char chanstr[32]; int bpl, y, j; uchar *buf; if(chantostr(chanstr, m->chan) == nil) sysfatal("can't convert channel descriptor: %r"); fprint(fd, "%11s %11d %11d %11d %11d ", chanstr, m->r.min.x, m->r.min.y, m->r.max.x, m->r.max.y); bpl = bytesperline(m->r, m->depth); buf = malloc(bpl+1); if(buf == nil) sysfatal("malloc failed: %r"); for(y=m->r.min.y; y<m->r.max.y; y++){ j = unloadmemimage(m, Rect(m->r.min.x, y, m->r.max.x, y+1), buf, bpl); if(j != bpl) sysfatal("image unload failed: %r"); if(write(fd, buf, bpl) != bpl) sysfatal("write failed: %r"); } free(buf); }