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);
}